ttinterp.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  ttinterp.c                                                             */
00004 /*                                                                         */
00005 /*    TrueType bytecode interpreter (body).                                */
00006 /*                                                                         */
00007 /*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */
00008 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00009 /*                                                                         */
00010 /*  This file is part of the FreeType project, and may only be used,       */
00011 /*  modified, and distributed under the terms of the FreeType project      */
00012 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00013 /*  this file you indicate that you have read the license and              */
00014 /*  understand and accept it fully.                                        */
00015 /*                                                                         */
00016 /***************************************************************************/
00017 
00018 
00019 #include <ft2build.h>
00020 #include FT_INTERNAL_DEBUG_H
00021 #include FT_INTERNAL_CALC_H
00022 #include FT_TRIGONOMETRY_H
00023 #include FT_SYSTEM_H
00024 
00025 #include "ttinterp.h"
00026 
00027 #include "tterrors.h"
00028 
00029 
00030 #ifdef TT_USE_BYTECODE_INTERPRETER
00031 
00032 
00033 #define TT_MULFIX           FT_MulFix
00034 #define TT_MULDIV           FT_MulDiv
00035 #define TT_MULDIV_NO_ROUND  FT_MulDiv_No_Round
00036 
00037 
00038   /*************************************************************************/
00039   /*                                                                       */
00040   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
00041   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
00042   /* messages during execution.                                            */
00043   /*                                                                       */
00044 #undef  FT_COMPONENT
00045 #define FT_COMPONENT  trace_ttinterp
00046 
00047   /*************************************************************************/
00048   /*                                                                       */
00049   /* In order to detect infinite loops in the code, we set up a counter    */
00050   /* within the run loop.  A single stroke of interpretation is now        */
00051   /* limited to a maximal number of opcodes defined below.                 */
00052   /*                                                                       */
00053 #define MAX_RUNNABLE_OPCODES  1000000L
00054 
00055 
00056   /*************************************************************************/
00057   /*                                                                       */
00058   /* There are two kinds of implementations:                               */
00059   /*                                                                       */
00060   /* a. static implementation                                              */
00061   /*                                                                       */
00062   /*    The current execution context is a static variable, which fields   */
00063   /*    are accessed directly by the interpreter during execution.  The    */
00064   /*    context is named `cur'.                                            */
00065   /*                                                                       */
00066   /*    This version is non-reentrant, of course.                          */
00067   /*                                                                       */
00068   /* b. indirect implementation                                            */
00069   /*                                                                       */
00070   /*    The current execution context is passed to _each_ function as its  */
00071   /*    first argument, and each field is thus accessed indirectly.        */
00072   /*                                                                       */
00073   /*    This version is fully re-entrant.                                  */
00074   /*                                                                       */
00075   /* The idea is that an indirect implementation may be slower to execute  */
00076   /* on low-end processors that are used in some systems (like 386s or     */
00077   /* even 486s).                                                           */
00078   /*                                                                       */
00079   /* As a consequence, the indirect implementation is now the default, as  */
00080   /* its performance costs can be considered negligible in our context.    */
00081   /* Note, however, that we kept the same source with macros because:      */
00082   /*                                                                       */
00083   /* - The code is kept very close in design to the Pascal code used for   */
00084   /*   development.                                                        */
00085   /*                                                                       */
00086   /* - It's much more readable that way!                                   */
00087   /*                                                                       */
00088   /* - It's still open to experimentation and tuning.                      */
00089   /*                                                                       */
00090   /*************************************************************************/
00091 
00092 
00093 #ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER     /* indirect implementation */
00094 
00095 #define CUR  (*exc)                             /* see ttobjs.h */
00096 
00097   /*************************************************************************/
00098   /*                                                                       */
00099   /* This macro is used whenever `exec' is unused in a function, to avoid  */
00100   /* stupid warnings from pedantic compilers.                              */
00101   /*                                                                       */
00102 #define FT_UNUSED_EXEC  FT_UNUSED( exc )
00103 
00104 #else                                           /* static implementation */
00105 
00106 #define CUR  cur
00107 
00108 #define FT_UNUSED_EXEC  int  __dummy = __dummy
00109 
00110   static
00111   TT_ExecContextRec  cur;   /* static exec. context variable */
00112 
00113   /* apparently, we have a _lot_ of direct indexing when accessing  */
00114   /* the static `cur', which makes the code bigger (due to all the  */
00115   /* four bytes addresses).                                         */
00116 
00117 #endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
00118 
00119 
00120   /*************************************************************************/
00121   /*                                                                       */
00122   /* The instruction argument stack.                                       */
00123   /*                                                                       */
00124 #define INS_ARG  EXEC_OP_ FT_Long*  args    /* see ttobjs.h for EXEC_OP_ */
00125 
00126 
00127   /*************************************************************************/
00128   /*                                                                       */
00129   /* This macro is used whenever `args' is unused in a function, to avoid  */
00130   /* stupid warnings from pedantic compilers.                              */
00131   /*                                                                       */
00132 #define FT_UNUSED_ARG  FT_UNUSED_EXEC; FT_UNUSED( args )
00133 
00134 
00135   /*************************************************************************/
00136   /*                                                                       */
00137   /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to        */
00138   /* increase readability of the code.                                     */
00139   /*                                                                       */
00140   /*************************************************************************/
00141 
00142 
00143 #define SKIP_Code() \
00144           SkipCode( EXEC_ARG )
00145 
00146 #define GET_ShortIns() \
00147           GetShortIns( EXEC_ARG )
00148 
00149 #define NORMalize( x, y, v ) \
00150           Normalize( EXEC_ARG_ x, y, v )
00151 
00152 #define SET_SuperRound( scale, flags ) \
00153           SetSuperRound( EXEC_ARG_ scale, flags )
00154 
00155 #define ROUND_None( d, c ) \
00156           Round_None( EXEC_ARG_ d, c )
00157 
00158 #define INS_Goto_CodeRange( range, ip ) \
00159           Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
00160 
00161 #define CUR_Func_move( z, p, d ) \
00162           CUR.func_move( EXEC_ARG_ z, p, d )
00163 
00164 #define CUR_Func_move_orig( z, p, d ) \
00165           CUR.func_move_orig( EXEC_ARG_ z, p, d )
00166 
00167 #define CUR_Func_round( d, c ) \
00168           CUR.func_round( EXEC_ARG_ d, c )
00169 
00170 #define CUR_Func_read_cvt( index ) \
00171           CUR.func_read_cvt( EXEC_ARG_ index )
00172 
00173 #define CUR_Func_write_cvt( index, val ) \
00174           CUR.func_write_cvt( EXEC_ARG_ index, val )
00175 
00176 #define CUR_Func_move_cvt( index, val ) \
00177           CUR.func_move_cvt( EXEC_ARG_ index, val )
00178 
00179 #define CURRENT_Ratio() \
00180           Current_Ratio( EXEC_ARG )
00181 
00182 #define CURRENT_Ppem() \
00183           Current_Ppem( EXEC_ARG )
00184 
00185 #define CUR_Ppem() \
00186           Cur_PPEM( EXEC_ARG )
00187 
00188 #define INS_SxVTL( a, b, c, d ) \
00189           Ins_SxVTL( EXEC_ARG_ a, b, c, d )
00190 
00191 #define COMPUTE_Funcs() \
00192           Compute_Funcs( EXEC_ARG )
00193 
00194 #define COMPUTE_Round( a ) \
00195           Compute_Round( EXEC_ARG_ a )
00196 
00197 #define COMPUTE_Point_Displacement( a, b, c, d ) \
00198           Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
00199 
00200 #define MOVE_Zp2_Point( a, b, c, t ) \
00201           Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
00202 
00203 
00204 #define CUR_Func_project( v1, v2 )  \
00205           CUR.func_project( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
00206 
00207 #define CUR_Func_dualproj( v1, v2 )  \
00208           CUR.func_dualproj( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
00209 
00210 #define CUR_fast_project( v ) \
00211           CUR.func_project( EXEC_ARG_ (v)->x, (v)->y )
00212 
00213 #define CUR_fast_dualproj( v ) \
00214           CUR.func_dualproj( EXEC_ARG_ (v)->x, (v)->y )
00215 
00216 
00217   /*************************************************************************/
00218   /*                                                                       */
00219   /* Instruction dispatch function, as used by the interpreter.            */
00220   /*                                                                       */
00221   typedef void  (*TInstruction_Function)( INS_ARG );
00222 
00223 
00224   /*************************************************************************/
00225   /*                                                                       */
00226   /* A simple bounds-checking macro.                                       */
00227   /*                                                                       */
00228 #define BOUNDS( x, n )  ( (FT_UInt)(x) >= (FT_UInt)(n) )
00229 
00230 #undef  SUCCESS
00231 #define SUCCESS  0
00232 
00233 #undef  FAILURE
00234 #define FAILURE  1
00235 
00236 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
00237 #define GUESS_VECTOR( V )                                         \
00238   if ( CUR.face->unpatented_hinting )                             \
00239   {                                                               \
00240     CUR.GS.V.x = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0x4000 : 0 ); \
00241     CUR.GS.V.y = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0 : 0x4000 ); \
00242   }
00243 #else
00244 #define GUESS_VECTOR( V )
00245 #endif
00246 
00247   /*************************************************************************/
00248   /*                                                                       */
00249   /*                        CODERANGE FUNCTIONS                            */
00250   /*                                                                       */
00251   /*************************************************************************/
00252 
00253 
00254   /*************************************************************************/
00255   /*                                                                       */
00256   /* <Function>                                                            */
00257   /*    TT_Goto_CodeRange                                                  */
00258   /*                                                                       */
00259   /* <Description>                                                         */
00260   /*    Switches to a new code range (updates the code related elements in */
00261   /*    `exec', and `IP').                                                 */
00262   /*                                                                       */
00263   /* <Input>                                                               */
00264   /*    range :: The new execution code range.                             */
00265   /*                                                                       */
00266   /*    IP    :: The new IP in the new code range.                         */
00267   /*                                                                       */
00268   /* <InOut>                                                               */
00269   /*    exec  :: The target execution context.                             */
00270   /*                                                                       */
00271   /* <Return>                                                              */
00272   /*    FreeType error code.  0 means success.                             */
00273   /*                                                                       */
00274   FT_LOCAL_DEF( FT_Error )
00275   TT_Goto_CodeRange( TT_ExecContext  exec,
00276                      FT_Int          range,
00277                      FT_Long         IP )
00278   {
00279     TT_CodeRange*  coderange;
00280 
00281 
00282     FT_ASSERT( range >= 1 && range <= 3 );
00283 
00284     coderange = &exec->codeRangeTable[range - 1];
00285 
00286     FT_ASSERT( coderange->base != NULL );
00287 
00288     /* NOTE: Because the last instruction of a program may be a CALL */
00289     /*       which will return to the first byte *after* the code    */
00290     /*       range, we test for IP <= Size instead of IP < Size.     */
00291     /*                                                               */
00292     FT_ASSERT( (FT_ULong)IP <= coderange->size );
00293 
00294     exec->code     = coderange->base;
00295     exec->codeSize = coderange->size;
00296     exec->IP       = IP;
00297     exec->curRange = range;
00298 
00299     return TT_Err_Ok;
00300   }
00301 
00302 
00303   /*************************************************************************/
00304   /*                                                                       */
00305   /* <Function>                                                            */
00306   /*    TT_Set_CodeRange                                                   */
00307   /*                                                                       */
00308   /* <Description>                                                         */
00309   /*    Sets a code range.                                                 */
00310   /*                                                                       */
00311   /* <Input>                                                               */
00312   /*    range  :: The code range index.                                    */
00313   /*                                                                       */
00314   /*    base   :: The new code base.                                       */
00315   /*                                                                       */
00316   /*    length :: The range size in bytes.                                 */
00317   /*                                                                       */
00318   /* <InOut>                                                               */
00319   /*    exec   :: The target execution context.                            */
00320   /*                                                                       */
00321   /* <Return>                                                              */
00322   /*    FreeType error code.  0 means success.                             */
00323   /*                                                                       */
00324   FT_LOCAL_DEF( FT_Error )
00325   TT_Set_CodeRange( TT_ExecContext  exec,
00326                     FT_Int          range,
00327                     void*           base,
00328                     FT_Long         length )
00329   {
00330     FT_ASSERT( range >= 1 && range <= 3 );
00331 
00332     exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
00333     exec->codeRangeTable[range - 1].size = length;
00334 
00335     return TT_Err_Ok;
00336   }
00337 
00338 
00339   /*************************************************************************/
00340   /*                                                                       */
00341   /* <Function>                                                            */
00342   /*    TT_Clear_CodeRange                                                 */
00343   /*                                                                       */
00344   /* <Description>                                                         */
00345   /*    Clears a code range.                                               */
00346   /*                                                                       */
00347   /* <Input>                                                               */
00348   /*    range :: The code range index.                                     */
00349   /*                                                                       */
00350   /* <InOut>                                                               */
00351   /*    exec  :: The target execution context.                             */
00352   /*                                                                       */
00353   /* <Return>                                                              */
00354   /*    FreeType error code.  0 means success.                             */
00355   /*                                                                       */
00356   /* <Note>                                                                */
00357   /*    Does not set the Error variable.                                   */
00358   /*                                                                       */
00359   FT_LOCAL_DEF( FT_Error )
00360   TT_Clear_CodeRange( TT_ExecContext  exec,
00361                       FT_Int          range )
00362   {
00363     FT_ASSERT( range >= 1 && range <= 3 );
00364 
00365     exec->codeRangeTable[range - 1].base = NULL;
00366     exec->codeRangeTable[range - 1].size = 0;
00367 
00368     return TT_Err_Ok;
00369   }
00370 
00371 
00372   /*************************************************************************/
00373   /*                                                                       */
00374   /*                   EXECUTION CONTEXT ROUTINES                          */
00375   /*                                                                       */
00376   /*************************************************************************/
00377 
00378 
00379   /*************************************************************************/
00380   /*                                                                       */
00381   /* <Function>                                                            */
00382   /*    TT_Done_Context                                                    */
00383   /*                                                                       */
00384   /* <Description>                                                         */
00385   /*    Destroys a given context.                                          */
00386   /*                                                                       */
00387   /* <Input>                                                               */
00388   /*    exec   :: A handle to the target execution context.                */
00389   /*                                                                       */
00390   /*    memory :: A handle to the parent memory object.                    */
00391   /*                                                                       */
00392   /* <Return>                                                              */
00393   /*    FreeType error code.  0 means success.                             */
00394   /*                                                                       */
00395   /* <Note>                                                                */
00396   /*    Only the glyph loader and debugger should call this function.      */
00397   /*                                                                       */
00398   FT_LOCAL_DEF( FT_Error )
00399   TT_Done_Context( TT_ExecContext  exec )
00400   {
00401     FT_Memory  memory = exec->memory;
00402 
00403 
00404     /* points zone */
00405     exec->maxPoints   = 0;
00406     exec->maxContours = 0;
00407 
00408     /* free stack */
00409     FT_FREE( exec->stack );
00410     exec->stackSize = 0;
00411 
00412     /* free call stack */
00413     FT_FREE( exec->callStack );
00414     exec->callSize = 0;
00415     exec->callTop  = 0;
00416 
00417     /* free glyph code range */
00418     FT_FREE( exec->glyphIns );
00419     exec->glyphSize = 0;
00420 
00421     exec->size = NULL;
00422     exec->face = NULL;
00423 
00424     FT_FREE( exec );
00425 
00426     return TT_Err_Ok;
00427   }
00428 
00429 
00430   /*************************************************************************/
00431   /*                                                                       */
00432   /* <Function>                                                            */
00433   /*    Init_Context                                                       */
00434   /*                                                                       */
00435   /* <Description>                                                         */
00436   /*    Initializes a context object.                                      */
00437   /*                                                                       */
00438   /* <Input>                                                               */
00439   /*    memory :: A handle to the parent memory object.                    */
00440   /*                                                                       */
00441   /* <InOut>                                                               */
00442   /*    exec   :: A handle to the target execution context.                */
00443   /*                                                                       */
00444   /* <Return>                                                              */
00445   /*    FreeType error code.  0 means success.                             */
00446   /*                                                                       */
00447   static FT_Error
00448   Init_Context( TT_ExecContext  exec,
00449                 FT_Memory       memory )
00450   {
00451     FT_Error  error;
00452 
00453 
00454     FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec ));
00455 
00456     exec->memory   = memory;
00457     exec->callSize = 32;
00458 
00459     if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )
00460       goto Fail_Memory;
00461 
00462     /* all values in the context are set to 0 already, but this is */
00463     /* here as a remainder                                         */
00464     exec->maxPoints   = 0;
00465     exec->maxContours = 0;
00466 
00467     exec->stackSize = 0;
00468     exec->glyphSize = 0;
00469 
00470     exec->stack     = NULL;
00471     exec->glyphIns  = NULL;
00472 
00473     exec->face = NULL;
00474     exec->size = NULL;
00475 
00476     return TT_Err_Ok;
00477 
00478   Fail_Memory:
00479     FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n",
00480                (FT_Long)exec ));
00481     TT_Done_Context( exec );
00482 
00483     return error;
00484  }
00485 
00486 
00487   /*************************************************************************/
00488   /*                                                                       */
00489   /* <Function>                                                            */
00490   /*    Update_Max                                                         */
00491   /*                                                                       */
00492   /* <Description>                                                         */
00493   /*    Checks the size of a buffer and reallocates it if necessary.       */
00494   /*                                                                       */
00495   /* <Input>                                                               */
00496   /*    memory     :: A handle to the parent memory object.                */
00497   /*                                                                       */
00498   /*    multiplier :: The size in bytes of each element in the buffer.     */
00499   /*                                                                       */
00500   /*    new_max    :: The new capacity (size) of the buffer.               */
00501   /*                                                                       */
00502   /* <InOut>                                                               */
00503   /*    size       :: The address of the buffer's current size expressed   */
00504   /*                  in elements.                                         */
00505   /*                                                                       */
00506   /*    buff       :: The address of the buffer base pointer.              */
00507   /*                                                                       */
00508   /* <Return>                                                              */
00509   /*    FreeType error code.  0 means success.                             */
00510   /*                                                                       */
00511   static FT_Error
00512   Update_Max( FT_Memory  memory,
00513               FT_ULong*  size,
00514               FT_Long    multiplier,
00515               void*      _pbuff,
00516               FT_ULong   new_max )
00517   {
00518     FT_Error  error;
00519     void**    pbuff = (void**)_pbuff;
00520 
00521 
00522     if ( *size < new_max )
00523     {
00524       if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )
00525         return error;
00526       *size = new_max;
00527     }
00528 
00529     return TT_Err_Ok;
00530   }
00531 
00532 
00533   /*************************************************************************/
00534   /*                                                                       */
00535   /* <Function>                                                            */
00536   /*    TT_Load_Context                                                    */
00537   /*                                                                       */
00538   /* <Description>                                                         */
00539   /*    Prepare an execution context for glyph hinting.                    */
00540   /*                                                                       */
00541   /* <Input>                                                               */
00542   /*    face :: A handle to the source face object.                        */
00543   /*                                                                       */
00544   /*    size :: A handle to the source size object.                        */
00545   /*                                                                       */
00546   /* <InOut>                                                               */
00547   /*    exec :: A handle to the target execution context.                  */
00548   /*                                                                       */
00549   /* <Return>                                                              */
00550   /*    FreeType error code.  0 means success.                             */
00551   /*                                                                       */
00552   /* <Note>                                                                */
00553   /*    Only the glyph loader and debugger should call this function.      */
00554   /*                                                                       */
00555   FT_LOCAL_DEF( FT_Error )
00556   TT_Load_Context( TT_ExecContext  exec,
00557                    TT_Face         face,
00558                    TT_Size         size )
00559   {
00560     FT_Int          i;
00561     FT_ULong        tmp;
00562     TT_MaxProfile*  maxp;
00563     FT_Error        error;
00564 
00565 
00566     exec->face = face;
00567     maxp       = &face->max_profile;
00568     exec->size = size;
00569 
00570     if ( size )
00571     {
00572       exec->numFDefs   = size->num_function_defs;
00573       exec->maxFDefs   = size->max_function_defs;
00574       exec->numIDefs   = size->num_instruction_defs;
00575       exec->maxIDefs   = size->max_instruction_defs;
00576       exec->FDefs      = size->function_defs;
00577       exec->IDefs      = size->instruction_defs;
00578       exec->tt_metrics = size->ttmetrics;
00579       exec->metrics    = size->metrics;
00580 
00581       exec->maxFunc    = size->max_func;
00582       exec->maxIns     = size->max_ins;
00583 
00584       for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
00585         exec->codeRangeTable[i] = size->codeRangeTable[i];
00586 
00587       /* set graphics state */
00588       exec->GS = size->GS;
00589 
00590       exec->cvtSize = size->cvt_size;
00591       exec->cvt     = size->cvt;
00592 
00593       exec->storeSize = size->storage_size;
00594       exec->storage   = size->storage;
00595 
00596       exec->twilight  = size->twilight;
00597     }
00598 
00599     /* XXX: We reserve a little more elements on the stack to deal safely */
00600     /*      with broken fonts like arialbs, courbs, timesbs, etc.         */
00601     tmp = exec->stackSize;
00602     error = Update_Max( exec->memory,
00603                         &tmp,
00604                         sizeof ( FT_F26Dot6 ),
00605                         (void*)&exec->stack,
00606                         maxp->maxStackElements + 32 );
00607     exec->stackSize = (FT_UInt)tmp;
00608     if ( error )
00609       return error;
00610 
00611     tmp = exec->glyphSize;
00612     error = Update_Max( exec->memory,
00613                         &tmp,
00614                         sizeof ( FT_Byte ),
00615                         (void*)&exec->glyphIns,
00616                         maxp->maxSizeOfInstructions );
00617     exec->glyphSize = (FT_UShort)tmp;
00618     if ( error )
00619       return error;
00620 
00621     exec->pts.n_points   = 0;
00622     exec->pts.n_contours = 0;
00623 
00624     exec->zp1 = exec->pts;
00625     exec->zp2 = exec->pts;
00626     exec->zp0 = exec->pts;
00627 
00628     exec->instruction_trap = FALSE;
00629 
00630     return TT_Err_Ok;
00631   }
00632 
00633 
00634   /*************************************************************************/
00635   /*                                                                       */
00636   /* <Function>                                                            */
00637   /*    TT_Save_Context                                                    */
00638   /*                                                                       */
00639   /* <Description>                                                         */
00640   /*    Saves the code ranges in a `size' object.                          */
00641   /*                                                                       */
00642   /* <Input>                                                               */
00643   /*    exec :: A handle to the source execution context.                  */
00644   /*                                                                       */
00645   /* <InOut>                                                               */
00646   /*    size :: A handle to the target size object.                        */
00647   /*                                                                       */
00648   /* <Return>                                                              */
00649   /*    FreeType error code.  0 means success.                             */
00650   /*                                                                       */
00651   /* <Note>                                                                */
00652   /*    Only the glyph loader and debugger should call this function.      */
00653   /*                                                                       */
00654   FT_LOCAL_DEF( FT_Error )
00655   TT_Save_Context( TT_ExecContext  exec,
00656                    TT_Size         size )
00657   {
00658     FT_Int  i;
00659 
00660 
00661     /* XXXX: Will probably disappear soon with all the code range */
00662     /*       management, which is now rather obsolete.            */
00663     /*                                                            */
00664     size->num_function_defs    = exec->numFDefs;
00665     size->num_instruction_defs = exec->numIDefs;
00666 
00667     size->max_func = exec->maxFunc;
00668     size->max_ins  = exec->maxIns;
00669 
00670     for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
00671       size->codeRangeTable[i] = exec->codeRangeTable[i];
00672 
00673     return TT_Err_Ok;
00674   }
00675 
00676 
00677   /*************************************************************************/
00678   /*                                                                       */
00679   /* <Function>                                                            */
00680   /*    TT_Run_Context                                                     */
00681   /*                                                                       */
00682   /* <Description>                                                         */
00683   /*    Executes one or more instructions in the execution context.        */
00684   /*                                                                       */
00685   /* <Input>                                                               */
00686   /*    debug :: A Boolean flag.  If set, the function sets some internal  */
00687   /*             variables and returns immediately, otherwise TT_RunIns()  */
00688   /*             is called.                                                */
00689   /*                                                                       */
00690   /*             This is commented out currently.                          */
00691   /*                                                                       */
00692   /* <Input>                                                               */
00693   /*    exec  :: A handle to the target execution context.                 */
00694   /*                                                                       */
00695   /* <Return>                                                              */
00696   /*    TrueType error code.  0 means success.                             */
00697   /*                                                                       */
00698   /* <Note>                                                                */
00699   /*    Only the glyph loader and debugger should call this function.      */
00700   /*                                                                       */
00701   FT_LOCAL_DEF( FT_Error )
00702   TT_Run_Context( TT_ExecContext  exec,
00703                   FT_Bool         debug )
00704   {
00705     FT_Error  error;
00706 
00707 
00708     if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0  ) )
00709            != TT_Err_Ok )
00710       return error;
00711 
00712     exec->zp0 = exec->pts;
00713     exec->zp1 = exec->pts;
00714     exec->zp2 = exec->pts;
00715 
00716     exec->GS.gep0 = 1;
00717     exec->GS.gep1 = 1;
00718     exec->GS.gep2 = 1;
00719 
00720     exec->GS.projVector.x = 0x4000;
00721     exec->GS.projVector.y = 0x0000;
00722 
00723     exec->GS.freeVector = exec->GS.projVector;
00724     exec->GS.dualVector = exec->GS.projVector;
00725 
00726 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
00727     exec->GS.both_x_axis = TRUE;
00728 #endif
00729 
00730     exec->GS.round_state = 1;
00731     exec->GS.loop        = 1;
00732 
00733     /* some glyphs leave something on the stack. so we clean it */
00734     /* before a new execution.                                  */
00735     exec->top     = 0;
00736     exec->callTop = 0;
00737 
00738 #if 1
00739     FT_UNUSED( debug );
00740 
00741     return exec->face->interpreter( exec );
00742 #else
00743     if ( !debug )
00744       return TT_RunIns( exec );
00745     else
00746       return TT_Err_Ok;
00747 #endif
00748   }
00749 
00750 
00751   /* The default value for `scan_control' is documented as FALSE in the */
00752   /* TrueType specification.  This is confusing since it implies a      */
00753   /* Boolean value.  However, this is not the case, thus both the       */
00754   /* default values of our `scan_type' and `scan_control' fields (which */
00755   /* the documentation's `scan_control' variable is split into) are     */
00756   /* zero.                                                              */
00757 
00758   const TT_GraphicsState  tt_default_graphics_state =
00759   {
00760     0, 0, 0,
00761     { 0x4000, 0 },
00762     { 0x4000, 0 },
00763     { 0x4000, 0 },
00764 
00765 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
00766     TRUE,
00767 #endif
00768 
00769     1, 64, 1,
00770     TRUE, 68, 0, 0, 9, 3,
00771     0, FALSE, 0, 1, 1, 1
00772   };
00773 
00774 
00775   /* documentation is in ttinterp.h */
00776 
00777   FT_EXPORT_DEF( TT_ExecContext )
00778   TT_New_Context( TT_Driver  driver )
00779   {
00780     TT_ExecContext  exec;
00781     FT_Memory       memory;
00782 
00783 
00784     memory = driver->root.root.memory;
00785     exec   = driver->context;
00786 
00787     if ( !driver->context )
00788     {
00789       FT_Error  error;
00790 
00791 
00792       /* allocate object */
00793       if ( FT_NEW( exec ) )
00794         goto Fail;
00795 
00796       /* initialize it; in case of error this deallocates `exec' too */
00797       error = Init_Context( exec, memory );
00798       if ( error )
00799         goto Fail;
00800 
00801       /* store it into the driver */
00802       driver->context = exec;
00803     }
00804 
00805     return driver->context;
00806 
00807   Fail:
00808     return NULL;
00809   }
00810 
00811 
00812   /*************************************************************************/
00813   /*                                                                       */
00814   /* Before an opcode is executed, the interpreter verifies that there are */
00815   /* enough arguments on the stack, with the help of the `Pop_Push_Count'  */
00816   /* table.                                                                */
00817   /*                                                                       */
00818   /* For each opcode, the first column gives the number of arguments that  */
00819   /* are popped from the stack; the second one gives the number of those   */
00820   /* that are pushed in result.                                            */
00821   /*                                                                       */
00822   /* Opcodes which have a varying number of parameters in the data stream  */
00823   /* (NPUSHB, NPUSHW) are handled specially; they have a negative value in */
00824   /* the `opcode_length' table, and the value in `Pop_Push_Count' is set   */
00825   /* to zero.                                                              */
00826   /*                                                                       */
00827   /*************************************************************************/
00828 
00829 
00830 #undef  PACK
00831 #define PACK( x, y )  ( ( x << 4 ) | y )
00832 
00833 
00834   static
00835   const FT_Byte  Pop_Push_Count[256] =
00836   {
00837     /* opcodes are gathered in groups of 16 */
00838     /* please keep the spaces as they are   */
00839 
00840     /*  SVTCA  y  */  PACK( 0, 0 ),
00841     /*  SVTCA  x  */  PACK( 0, 0 ),
00842     /*  SPvTCA y  */  PACK( 0, 0 ),
00843     /*  SPvTCA x  */  PACK( 0, 0 ),
00844     /*  SFvTCA y  */  PACK( 0, 0 ),
00845     /*  SFvTCA x  */  PACK( 0, 0 ),
00846     /*  SPvTL //  */  PACK( 2, 0 ),
00847     /*  SPvTL +   */  PACK( 2, 0 ),
00848     /*  SFvTL //  */  PACK( 2, 0 ),
00849     /*  SFvTL +   */  PACK( 2, 0 ),
00850     /*  SPvFS     */  PACK( 2, 0 ),
00851     /*  SFvFS     */  PACK( 2, 0 ),
00852     /*  GPV       */  PACK( 0, 2 ),
00853     /*  GFV       */  PACK( 0, 2 ),
00854     /*  SFvTPv    */  PACK( 0, 0 ),
00855     /*  ISECT     */  PACK( 5, 0 ),
00856 
00857     /*  SRP0      */  PACK( 1, 0 ),
00858     /*  SRP1      */  PACK( 1, 0 ),
00859     /*  SRP2      */  PACK( 1, 0 ),
00860     /*  SZP0      */  PACK( 1, 0 ),
00861     /*  SZP1      */  PACK( 1, 0 ),
00862     /*  SZP2      */  PACK( 1, 0 ),
00863     /*  SZPS      */  PACK( 1, 0 ),
00864     /*  SLOOP     */  PACK( 1, 0 ),
00865     /*  RTG       */  PACK( 0, 0 ),
00866     /*  RTHG      */  PACK( 0, 0 ),
00867     /*  SMD       */  PACK( 1, 0 ),
00868     /*  ELSE      */  PACK( 0, 0 ),
00869     /*  JMPR      */  PACK( 1, 0 ),
00870     /*  SCvTCi    */  PACK( 1, 0 ),
00871     /*  SSwCi     */  PACK( 1, 0 ),
00872     /*  SSW       */  PACK( 1, 0 ),
00873 
00874     /*  DUP       */  PACK( 1, 2 ),
00875     /*  POP       */  PACK( 1, 0 ),
00876     /*  CLEAR     */  PACK( 0, 0 ),
00877     /*  SWAP      */  PACK( 2, 2 ),
00878     /*  DEPTH     */  PACK( 0, 1 ),
00879     /*  CINDEX    */  PACK( 1, 1 ),
00880     /*  MINDEX    */  PACK( 1, 0 ),
00881     /*  AlignPTS  */  PACK( 2, 0 ),
00882     /*  INS_$28   */  PACK( 0, 0 ),
00883     /*  UTP       */  PACK( 1, 0 ),
00884     /*  LOOPCALL  */  PACK( 2, 0 ),
00885     /*  CALL      */  PACK( 1, 0 ),
00886     /*  FDEF      */  PACK( 1, 0 ),
00887     /*  ENDF      */  PACK( 0, 0 ),
00888     /*  MDAP[0]   */  PACK( 1, 0 ),
00889     /*  MDAP[1]   */  PACK( 1, 0 ),
00890 
00891     /*  IUP[0]    */  PACK( 0, 0 ),
00892     /*  IUP[1]    */  PACK( 0, 0 ),
00893     /*  SHP[0]    */  PACK( 0, 0 ),
00894     /*  SHP[1]    */  PACK( 0, 0 ),
00895     /*  SHC[0]    */  PACK( 1, 0 ),
00896     /*  SHC[1]    */  PACK( 1, 0 ),
00897     /*  SHZ[0]    */  PACK( 1, 0 ),
00898     /*  SHZ[1]    */  PACK( 1, 0 ),
00899     /*  SHPIX     */  PACK( 1, 0 ),
00900     /*  IP        */  PACK( 0, 0 ),
00901     /*  MSIRP[0]  */  PACK( 2, 0 ),
00902     /*  MSIRP[1]  */  PACK( 2, 0 ),
00903     /*  AlignRP   */  PACK( 0, 0 ),
00904     /*  RTDG      */  PACK( 0, 0 ),
00905     /*  MIAP[0]   */  PACK( 2, 0 ),
00906     /*  MIAP[1]   */  PACK( 2, 0 ),
00907 
00908     /*  NPushB    */  PACK( 0, 0 ),
00909     /*  NPushW    */  PACK( 0, 0 ),
00910     /*  WS        */  PACK( 2, 0 ),
00911     /*  RS        */  PACK( 1, 1 ),
00912     /*  WCvtP     */  PACK( 2, 0 ),
00913     /*  RCvt      */  PACK( 1, 1 ),
00914     /*  GC[0]     */  PACK( 1, 1 ),
00915     /*  GC[1]     */  PACK( 1, 1 ),
00916     /*  SCFS      */  PACK( 2, 0 ),
00917     /*  MD[0]     */  PACK( 2, 1 ),
00918     /*  MD[1]     */  PACK( 2, 1 ),
00919     /*  MPPEM     */  PACK( 0, 1 ),
00920     /*  MPS       */  PACK( 0, 1 ),
00921     /*  FlipON    */  PACK( 0, 0 ),
00922     /*  FlipOFF   */  PACK( 0, 0 ),
00923     /*  DEBUG     */  PACK( 1, 0 ),
00924 
00925     /*  LT        */  PACK( 2, 1 ),
00926     /*  LTEQ      */  PACK( 2, 1 ),
00927     /*  GT        */  PACK( 2, 1 ),
00928     /*  GTEQ      */  PACK( 2, 1 ),
00929     /*  EQ        */  PACK( 2, 1 ),
00930     /*  NEQ       */  PACK( 2, 1 ),
00931     /*  ODD       */  PACK( 1, 1 ),
00932     /*  EVEN      */  PACK( 1, 1 ),
00933     /*  IF        */  PACK( 1, 0 ),
00934     /*  EIF       */  PACK( 0, 0 ),
00935     /*  AND       */  PACK( 2, 1 ),
00936     /*  OR        */  PACK( 2, 1 ),
00937     /*  NOT       */  PACK( 1, 1 ),
00938     /*  DeltaP1   */  PACK( 1, 0 ),
00939     /*  SDB       */  PACK( 1, 0 ),
00940     /*  SDS       */  PACK( 1, 0 ),
00941 
00942     /*  ADD       */  PACK( 2, 1 ),
00943     /*  SUB       */  PACK( 2, 1 ),
00944     /*  DIV       */  PACK( 2, 1 ),
00945     /*  MUL       */  PACK( 2, 1 ),
00946     /*  ABS       */  PACK( 1, 1 ),
00947     /*  NEG       */  PACK( 1, 1 ),
00948     /*  FLOOR     */  PACK( 1, 1 ),
00949     /*  CEILING   */  PACK( 1, 1 ),
00950     /*  ROUND[0]  */  PACK( 1, 1 ),
00951     /*  ROUND[1]  */  PACK( 1, 1 ),
00952     /*  ROUND[2]  */  PACK( 1, 1 ),
00953     /*  ROUND[3]  */  PACK( 1, 1 ),
00954     /*  NROUND[0] */  PACK( 1, 1 ),
00955     /*  NROUND[1] */  PACK( 1, 1 ),
00956     /*  NROUND[2] */  PACK( 1, 1 ),
00957     /*  NROUND[3] */  PACK( 1, 1 ),
00958 
00959     /*  WCvtF     */  PACK( 2, 0 ),
00960     /*  DeltaP2   */  PACK( 1, 0 ),
00961     /*  DeltaP3   */  PACK( 1, 0 ),
00962     /*  DeltaCn[0] */ PACK( 1, 0 ),
00963     /*  DeltaCn[1] */ PACK( 1, 0 ),
00964     /*  DeltaCn[2] */ PACK( 1, 0 ),
00965     /*  SROUND    */  PACK( 1, 0 ),
00966     /*  S45Round  */  PACK( 1, 0 ),
00967     /*  JROT      */  PACK( 2, 0 ),
00968     /*  JROF      */  PACK( 2, 0 ),
00969     /*  ROFF      */  PACK( 0, 0 ),
00970     /*  INS_$7B   */  PACK( 0, 0 ),
00971     /*  RUTG      */  PACK( 0, 0 ),
00972     /*  RDTG      */  PACK( 0, 0 ),
00973     /*  SANGW     */  PACK( 1, 0 ),
00974     /*  AA        */  PACK( 1, 0 ),
00975 
00976     /*  FlipPT    */  PACK( 0, 0 ),
00977     /*  FlipRgON  */  PACK( 2, 0 ),
00978     /*  FlipRgOFF */  PACK( 2, 0 ),
00979     /*  INS_$83   */  PACK( 0, 0 ),
00980     /*  INS_$84   */  PACK( 0, 0 ),
00981     /*  ScanCTRL  */  PACK( 1, 0 ),
00982     /*  SDVPTL[0] */  PACK( 2, 0 ),
00983     /*  SDVPTL[1] */  PACK( 2, 0 ),
00984     /*  GetINFO   */  PACK( 1, 1 ),
00985     /*  IDEF      */  PACK( 1, 0 ),
00986     /*  ROLL      */  PACK( 3, 3 ),
00987     /*  MAX       */  PACK( 2, 1 ),
00988     /*  MIN       */  PACK( 2, 1 ),
00989     /*  ScanTYPE  */  PACK( 1, 0 ),
00990     /*  InstCTRL  */  PACK( 2, 0 ),
00991     /*  INS_$8F   */  PACK( 0, 0 ),
00992 
00993     /*  INS_$90  */   PACK( 0, 0 ),
00994     /*  INS_$91  */   PACK( 0, 0 ),
00995     /*  INS_$92  */   PACK( 0, 0 ),
00996     /*  INS_$93  */   PACK( 0, 0 ),
00997     /*  INS_$94  */   PACK( 0, 0 ),
00998     /*  INS_$95  */   PACK( 0, 0 ),
00999     /*  INS_$96  */   PACK( 0, 0 ),
01000     /*  INS_$97  */   PACK( 0, 0 ),
01001     /*  INS_$98  */   PACK( 0, 0 ),
01002     /*  INS_$99  */   PACK( 0, 0 ),
01003     /*  INS_$9A  */   PACK( 0, 0 ),
01004     /*  INS_$9B  */   PACK( 0, 0 ),
01005     /*  INS_$9C  */   PACK( 0, 0 ),
01006     /*  INS_$9D  */   PACK( 0, 0 ),
01007     /*  INS_$9E  */   PACK( 0, 0 ),
01008     /*  INS_$9F  */   PACK( 0, 0 ),
01009 
01010     /*  INS_$A0  */   PACK( 0, 0 ),
01011     /*  INS_$A1  */   PACK( 0, 0 ),
01012     /*  INS_$A2  */   PACK( 0, 0 ),
01013     /*  INS_$A3  */   PACK( 0, 0 ),
01014     /*  INS_$A4  */   PACK( 0, 0 ),
01015     /*  INS_$A5  */   PACK( 0, 0 ),
01016     /*  INS_$A6  */   PACK( 0, 0 ),
01017     /*  INS_$A7  */   PACK( 0, 0 ),
01018     /*  INS_$A8  */   PACK( 0, 0 ),
01019     /*  INS_$A9  */   PACK( 0, 0 ),
01020     /*  INS_$AA  */   PACK( 0, 0 ),
01021     /*  INS_$AB  */   PACK( 0, 0 ),
01022     /*  INS_$AC  */   PACK( 0, 0 ),
01023     /*  INS_$AD  */   PACK( 0, 0 ),
01024     /*  INS_$AE  */   PACK( 0, 0 ),
01025     /*  INS_$AF  */   PACK( 0, 0 ),
01026 
01027     /*  PushB[0]  */  PACK( 0, 1 ),
01028     /*  PushB[1]  */  PACK( 0, 2 ),
01029     /*  PushB[2]  */  PACK( 0, 3 ),
01030     /*  PushB[3]  */  PACK( 0, 4 ),
01031     /*  PushB[4]  */  PACK( 0, 5 ),
01032     /*  PushB[5]  */  PACK( 0, 6 ),
01033     /*  PushB[6]  */  PACK( 0, 7 ),
01034     /*  PushB[7]  */  PACK( 0, 8 ),
01035     /*  PushW[0]  */  PACK( 0, 1 ),
01036     /*  PushW[1]  */  PACK( 0, 2 ),
01037     /*  PushW[2]  */  PACK( 0, 3 ),
01038     /*  PushW[3]  */  PACK( 0, 4 ),
01039     /*  PushW[4]  */  PACK( 0, 5 ),
01040     /*  PushW[5]  */  PACK( 0, 6 ),
01041     /*  PushW[6]  */  PACK( 0, 7 ),
01042     /*  PushW[7]  */  PACK( 0, 8 ),
01043 
01044     /*  MDRP[00]  */  PACK( 1, 0 ),
01045     /*  MDRP[01]  */  PACK( 1, 0 ),
01046     /*  MDRP[02]  */  PACK( 1, 0 ),
01047     /*  MDRP[03]  */  PACK( 1, 0 ),
01048     /*  MDRP[04]  */  PACK( 1, 0 ),
01049     /*  MDRP[05]  */  PACK( 1, 0 ),
01050     /*  MDRP[06]  */  PACK( 1, 0 ),
01051     /*  MDRP[07]  */  PACK( 1, 0 ),
01052     /*  MDRP[08]  */  PACK( 1, 0 ),
01053     /*  MDRP[09]  */  PACK( 1, 0 ),
01054     /*  MDRP[10]  */  PACK( 1, 0 ),
01055     /*  MDRP[11]  */  PACK( 1, 0 ),
01056     /*  MDRP[12]  */  PACK( 1, 0 ),
01057     /*  MDRP[13]  */  PACK( 1, 0 ),
01058     /*  MDRP[14]  */  PACK( 1, 0 ),
01059     /*  MDRP[15]  */  PACK( 1, 0 ),
01060 
01061     /*  MDRP[16]  */  PACK( 1, 0 ),
01062     /*  MDRP[17]  */  PACK( 1, 0 ),
01063     /*  MDRP[18]  */  PACK( 1, 0 ),
01064     /*  MDRP[19]  */  PACK( 1, 0 ),
01065     /*  MDRP[20]  */  PACK( 1, 0 ),
01066     /*  MDRP[21]  */  PACK( 1, 0 ),
01067     /*  MDRP[22]  */  PACK( 1, 0 ),
01068     /*  MDRP[23]  */  PACK( 1, 0 ),
01069     /*  MDRP[24]  */  PACK( 1, 0 ),
01070     /*  MDRP[25]  */  PACK( 1, 0 ),
01071     /*  MDRP[26]  */  PACK( 1, 0 ),
01072     /*  MDRP[27]  */  PACK( 1, 0 ),
01073     /*  MDRP[28]  */  PACK( 1, 0 ),
01074     /*  MDRP[29]  */  PACK( 1, 0 ),
01075     /*  MDRP[30]  */  PACK( 1, 0 ),
01076     /*  MDRP[31]  */  PACK( 1, 0 ),
01077 
01078     /*  MIRP[00]  */  PACK( 2, 0 ),
01079     /*  MIRP[01]  */  PACK( 2, 0 ),
01080     /*  MIRP[02]  */  PACK( 2, 0 ),
01081     /*  MIRP[03]  */  PACK( 2, 0 ),
01082     /*  MIRP[04]  */  PACK( 2, 0 ),
01083     /*  MIRP[05]  */  PACK( 2, 0 ),
01084     /*  MIRP[06]  */  PACK( 2, 0 ),
01085     /*  MIRP[07]  */  PACK( 2, 0 ),
01086     /*  MIRP[08]  */  PACK( 2, 0 ),
01087     /*  MIRP[09]  */  PACK( 2, 0 ),
01088     /*  MIRP[10]  */  PACK( 2, 0 ),
01089     /*  MIRP[11]  */  PACK( 2, 0 ),
01090     /*  MIRP[12]  */  PACK( 2, 0 ),
01091     /*  MIRP[13]  */  PACK( 2, 0 ),
01092     /*  MIRP[14]  */  PACK( 2, 0 ),
01093     /*  MIRP[15]  */  PACK( 2, 0 ),
01094 
01095     /*  MIRP[16]  */  PACK( 2, 0 ),
01096     /*  MIRP[17]  */  PACK( 2, 0 ),
01097     /*  MIRP[18]  */  PACK( 2, 0 ),
01098     /*  MIRP[19]  */  PACK( 2, 0 ),
01099     /*  MIRP[20]  */  PACK( 2, 0 ),
01100     /*  MIRP[21]  */  PACK( 2, 0 ),
01101     /*  MIRP[22]  */  PACK( 2, 0 ),
01102     /*  MIRP[23]  */  PACK( 2, 0 ),
01103     /*  MIRP[24]  */  PACK( 2, 0 ),
01104     /*  MIRP[25]  */  PACK( 2, 0 ),
01105     /*  MIRP[26]  */  PACK( 2, 0 ),
01106     /*  MIRP[27]  */  PACK( 2, 0 ),
01107     /*  MIRP[28]  */  PACK( 2, 0 ),
01108     /*  MIRP[29]  */  PACK( 2, 0 ),
01109     /*  MIRP[30]  */  PACK( 2, 0 ),
01110     /*  MIRP[31]  */  PACK( 2, 0 )
01111   };
01112 
01113 
01114   static
01115   const FT_Char  opcode_length[256] =
01116   {
01117     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
01118     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
01119     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
01120     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
01121 
01122    -1,-2, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
01123     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
01124     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
01125     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
01126 
01127     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
01128     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
01129     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
01130     2, 3, 4, 5,  6, 7, 8, 9,  3, 5, 7, 9, 11,13,15,17,
01131 
01132     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
01133     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
01134     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
01135     1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1
01136   };
01137 
01138 #undef PACK
01139 
01140 #if 1
01141 
01142   static FT_Int32
01143   TT_MulFix14( FT_Int32  a,
01144                FT_Int    b )
01145   {
01146     FT_Int32   sign;
01147     FT_UInt32  ah, al, mid, lo, hi;
01148 
01149 
01150     sign = a ^ b;
01151 
01152     if ( a < 0 )
01153       a = -a;
01154     if ( b < 0 )
01155       b = -b;
01156 
01157     ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU );
01158     al = (FT_UInt32)( a & 0xFFFFU );
01159 
01160     lo    = al * b;
01161     mid   = ah * b;
01162     hi    = mid >> 16;
01163     mid   = ( mid << 16 ) + ( 1 << 13 ); /* rounding */
01164     lo   += mid;
01165     if ( lo < mid )
01166       hi += 1;
01167 
01168     mid = ( lo >> 14 ) | ( hi << 18 );
01169 
01170     return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid;
01171   }
01172 
01173 #else
01174 
01175   /* compute (a*b)/2^14 with maximal accuracy and rounding */
01176   static FT_Int32
01177   TT_MulFix14( FT_Int32  a,
01178                FT_Int    b )
01179   {
01180     FT_Int32   m, s, hi;
01181     FT_UInt32  l, lo;
01182 
01183 
01184     /* compute ax*bx as 64-bit value */
01185     l  = (FT_UInt32)( ( a & 0xFFFFU ) * b );
01186     m  = ( a >> 16 ) * b;
01187 
01188     lo = l + (FT_UInt32)( m << 16 );
01189     hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l );
01190 
01191     /* divide the result by 2^14 with rounding */
01192     s   = hi >> 31;
01193     l   = lo + (FT_UInt32)s;
01194     hi += s + ( l < lo );
01195     lo  = l;
01196 
01197     l   = lo + 0x2000U;
01198     hi += l < lo;
01199 
01200     return ( hi << 18 ) | ( l >> 14 );
01201   }
01202 #endif
01203 
01204 
01205   /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */
01206   static FT_Int32
01207   TT_DotFix14( FT_Int32  ax,
01208                FT_Int32  ay,
01209                FT_Int    bx,
01210                FT_Int    by )
01211   {
01212     FT_Int32   m, s, hi1, hi2, hi;
01213     FT_UInt32  l, lo1, lo2, lo;
01214 
01215 
01216     /* compute ax*bx as 64-bit value */
01217     l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );
01218     m = ( ax >> 16 ) * bx;
01219 
01220     lo1 = l + (FT_UInt32)( m << 16 );
01221     hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l );
01222 
01223     /* compute ay*by as 64-bit value */
01224     l = (FT_UInt32)( ( ay & 0xFFFFU ) * by );
01225     m = ( ay >> 16 ) * by;
01226 
01227     lo2 = l + (FT_UInt32)( m << 16 );
01228     hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l );
01229 
01230     /* add them */
01231     lo = lo1 + lo2;
01232     hi = hi1 + hi2 + ( lo < lo1 );
01233 
01234     /* divide the result by 2^14 with rounding */
01235     s   = hi >> 31;
01236     l   = lo + (FT_UInt32)s;
01237     hi += s + ( l < lo );
01238     lo  = l;
01239 
01240     l   = lo + 0x2000U;
01241     hi += ( l < lo );
01242 
01243     return ( hi << 18 ) | ( l >> 14 );
01244   }
01245 
01246 
01247   /* return length of given vector */
01248 
01249 #if 0
01250 
01251   static FT_Int32
01252   TT_VecLen( FT_Int32  x,
01253              FT_Int32  y )
01254   {
01255     FT_Int32   m, hi1, hi2, hi;
01256     FT_UInt32  l, lo1, lo2, lo;
01257 
01258 
01259     /* compute x*x as 64-bit value */
01260     lo = (FT_UInt32)( x & 0xFFFFU );
01261     hi = x >> 16;
01262 
01263     l  = lo * lo;
01264     m  = hi * lo;
01265     hi = hi * hi;
01266 
01267     lo1 = l + (FT_UInt32)( m << 17 );
01268     hi1 = hi + ( m >> 15 ) + ( lo1 < l );
01269 
01270     /* compute y*y as 64-bit value */
01271     lo = (FT_UInt32)( y & 0xFFFFU );
01272     hi = y >> 16;
01273 
01274     l  = lo * lo;
01275     m  = hi * lo;
01276     hi = hi * hi;
01277 
01278     lo2 = l + (FT_UInt32)( m << 17 );
01279     hi2 = hi + ( m >> 15 ) + ( lo2 < l );
01280 
01281     /* add them to get 'x*x+y*y' as 64-bit value */
01282     lo = lo1 + lo2;
01283     hi = hi1 + hi2 + ( lo < lo1 );
01284 
01285     /* compute the square root of this value */
01286     {
01287       FT_UInt32  root, rem, test_div;
01288       FT_Int     count;
01289 
01290 
01291       root = 0;
01292 
01293       {
01294         rem   = 0;
01295         count = 32;
01296         do
01297         {
01298           rem      = ( rem << 2 ) | ( (FT_UInt32)hi >> 30 );
01299           hi       = (  hi << 2 ) | (            lo >> 30 );
01300           lo     <<= 2;
01301           root   <<= 1;
01302           test_div = ( root << 1 ) + 1;
01303 
01304           if ( rem >= test_div )
01305           {
01306             rem  -= test_div;
01307             root += 1;
01308           }
01309         } while ( --count );
01310       }
01311 
01312       return (FT_Int32)root;
01313     }
01314   }
01315 
01316 #else
01317 
01318   /* this version uses FT_Vector_Length which computes the same value */
01319   /* much, much faster..                                              */
01320   /*                                                                  */
01321   static FT_F26Dot6
01322   TT_VecLen( FT_F26Dot6  X,
01323              FT_F26Dot6  Y )
01324   {
01325     FT_Vector  v;
01326 
01327 
01328     v.x = X;
01329     v.y = Y;
01330 
01331     return FT_Vector_Length( &v );
01332   }
01333 
01334 #endif
01335 
01336 
01337   /*************************************************************************/
01338   /*                                                                       */
01339   /* <Function>                                                            */
01340   /*    Current_Ratio                                                      */
01341   /*                                                                       */
01342   /* <Description>                                                         */
01343   /*    Returns the current aspect ratio scaling factor depending on the   */
01344   /*    projection vector's state and device resolutions.                  */
01345   /*                                                                       */
01346   /* <Return>                                                              */
01347   /*    The aspect ratio in 16.16 format, always <= 1.0 .                  */
01348   /*                                                                       */
01349   static FT_Long
01350   Current_Ratio( EXEC_OP )
01351   {
01352     if ( !CUR.tt_metrics.ratio )
01353     {
01354 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
01355       if ( CUR.face->unpatented_hinting )
01356       {
01357         if ( CUR.GS.both_x_axis )
01358           CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
01359         else
01360           CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
01361       }
01362       else
01363 #endif
01364       {
01365         if ( CUR.GS.projVector.y == 0 )
01366           CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
01367 
01368         else if ( CUR.GS.projVector.x == 0 )
01369           CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
01370 
01371         else
01372         {
01373           FT_Long  x, y;
01374 
01375 
01376           x = TT_MULDIV( CUR.GS.projVector.x,
01377                          CUR.tt_metrics.x_ratio, 0x4000 );
01378           y = TT_MULDIV( CUR.GS.projVector.y,
01379                          CUR.tt_metrics.y_ratio, 0x4000 );
01380           CUR.tt_metrics.ratio = TT_VecLen( x, y );
01381         }
01382       }
01383     }
01384     return CUR.tt_metrics.ratio;
01385   }
01386 
01387 
01388   static FT_Long
01389   Current_Ppem( EXEC_OP )
01390   {
01391     return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );
01392   }
01393 
01394 
01395   /*************************************************************************/
01396   /*                                                                       */
01397   /* Functions related to the control value table (CVT).                   */
01398   /*                                                                       */
01399   /*************************************************************************/
01400 
01401 
01402   FT_CALLBACK_DEF( FT_F26Dot6 )
01403   Read_CVT( EXEC_OP_ FT_ULong  idx )
01404   {
01405     return CUR.cvt[idx];
01406   }
01407 
01408 
01409   FT_CALLBACK_DEF( FT_F26Dot6 )
01410   Read_CVT_Stretched( EXEC_OP_ FT_ULong  idx )
01411   {
01412     return TT_MULFIX( CUR.cvt[idx], CURRENT_Ratio() );
01413   }
01414 
01415 
01416   FT_CALLBACK_DEF( void )
01417   Write_CVT( EXEC_OP_ FT_ULong    idx,
01418                       FT_F26Dot6  value )
01419   {
01420     CUR.cvt[idx] = value;
01421   }
01422 
01423 
01424   FT_CALLBACK_DEF( void )
01425   Write_CVT_Stretched( EXEC_OP_ FT_ULong    idx,
01426                                 FT_F26Dot6  value )
01427   {
01428     CUR.cvt[idx] = FT_DivFix( value, CURRENT_Ratio() );
01429   }
01430 
01431 
01432   FT_CALLBACK_DEF( void )
01433   Move_CVT( EXEC_OP_ FT_ULong    idx,
01434                      FT_F26Dot6  value )
01435   {
01436     CUR.cvt[idx] += value;
01437   }
01438 
01439 
01440   FT_CALLBACK_DEF( void )
01441   Move_CVT_Stretched( EXEC_OP_ FT_ULong    idx,
01442                                FT_F26Dot6  value )
01443   {
01444     CUR.cvt[idx] += FT_DivFix( value, CURRENT_Ratio() );
01445   }
01446 
01447 
01448   /*************************************************************************/
01449   /*                                                                       */
01450   /* <Function>                                                            */
01451   /*    GetShortIns                                                        */
01452   /*                                                                       */
01453   /* <Description>                                                         */
01454   /*    Returns a short integer taken from the instruction stream at       */
01455   /*    address IP.                                                        */
01456   /*                                                                       */
01457   /* <Return>                                                              */
01458   /*    Short read at code[IP].                                            */
01459   /*                                                                       */
01460   /* <Note>                                                                */
01461   /*    This one could become a macro.                                     */
01462   /*                                                                       */
01463   static FT_Short
01464   GetShortIns( EXEC_OP )
01465   {
01466     /* Reading a byte stream so there is no endianess (DaveP) */
01467     CUR.IP += 2;
01468     return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) +
01469                          CUR.code[CUR.IP - 1]      );
01470   }
01471 
01472 
01473   /*************************************************************************/
01474   /*                                                                       */
01475   /* <Function>                                                            */
01476   /*    Ins_Goto_CodeRange                                                 */
01477   /*                                                                       */
01478   /* <Description>                                                         */
01479   /*    Goes to a certain code range in the instruction stream.            */
01480   /*                                                                       */
01481   /* <Input>                                                               */
01482   /*    aRange :: The index of the code range.                             */
01483   /*                                                                       */
01484   /*    aIP    :: The new IP address in the code range.                    */
01485   /*                                                                       */
01486   /* <Return>                                                              */
01487   /*    SUCCESS or FAILURE.                                                */
01488   /*                                                                       */
01489   static FT_Bool
01490   Ins_Goto_CodeRange( EXEC_OP_ FT_Int    aRange,
01491                                FT_ULong  aIP )
01492   {
01493     TT_CodeRange*  range;
01494 
01495 
01496     if ( aRange < 1 || aRange > 3 )
01497     {
01498       CUR.error = TT_Err_Bad_Argument;
01499       return FAILURE;
01500     }
01501 
01502     range = &CUR.codeRangeTable[aRange - 1];
01503 
01504     if ( range->base == NULL )     /* invalid coderange */
01505     {
01506       CUR.error = TT_Err_Invalid_CodeRange;
01507       return FAILURE;
01508     }
01509 
01510     /* NOTE: Because the last instruction of a program may be a CALL */
01511     /*       which will return to the first byte *after* the code    */
01512     /*       range, we test for AIP <= Size, instead of AIP < Size.  */
01513 
01514     if ( aIP > range->size )
01515     {
01516       CUR.error = TT_Err_Code_Overflow;
01517       return FAILURE;
01518     }
01519 
01520     CUR.code     = range->base;
01521     CUR.codeSize = range->size;
01522     CUR.IP       = aIP;
01523     CUR.curRange = aRange;
01524 
01525     return SUCCESS;
01526   }
01527 
01528 
01529   /*************************************************************************/
01530   /*                                                                       */
01531   /* <Function>                                                            */
01532   /*    Direct_Move                                                        */
01533   /*                                                                       */
01534   /* <Description>                                                         */
01535   /*    Moves a point by a given distance along the freedom vector.  The   */
01536   /*    point will be `touched'.                                           */
01537   /*                                                                       */
01538   /* <Input>                                                               */
01539   /*    point    :: The index of the point to move.                        */
01540   /*                                                                       */
01541   /*    distance :: The distance to apply.                                 */
01542   /*                                                                       */
01543   /* <InOut>                                                               */
01544   /*    zone     :: The affected glyph zone.                               */
01545   /*                                                                       */
01546   static void
01547   Direct_Move( EXEC_OP_ TT_GlyphZone  zone,
01548                         FT_UShort     point,
01549                         FT_F26Dot6    distance )
01550   {
01551     FT_F26Dot6  v;
01552 
01553 
01554 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
01555     FT_ASSERT( !CUR.face->unpatented_hinting );
01556 #endif
01557 
01558     v = CUR.GS.freeVector.x;
01559 
01560     if ( v != 0 )
01561     {
01562       zone->cur[point].x += TT_MULDIV( distance,
01563                                        v * 0x10000L,
01564                                        CUR.F_dot_P );
01565 
01566       zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
01567     }
01568 
01569     v = CUR.GS.freeVector.y;
01570 
01571     if ( v != 0 )
01572     {
01573       zone->cur[point].y += TT_MULDIV( distance,
01574                                        v * 0x10000L,
01575                                        CUR.F_dot_P );
01576 
01577       zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
01578     }
01579   }
01580 
01581 
01582   /*************************************************************************/
01583   /*                                                                       */
01584   /* <Function>                                                            */
01585   /*    Direct_Move_Orig                                                   */
01586   /*                                                                       */
01587   /* <Description>                                                         */
01588   /*    Moves the *original* position of a point by a given distance along */
01589   /*    the freedom vector.  Obviously, the point will not be `touched'.   */
01590   /*                                                                       */
01591   /* <Input>                                                               */
01592   /*    point    :: The index of the point to move.                        */
01593   /*                                                                       */
01594   /*    distance :: The distance to apply.                                 */
01595   /*                                                                       */
01596   /* <InOut>                                                               */
01597   /*    zone     :: The affected glyph zone.                               */
01598   /*                                                                       */
01599   static void
01600   Direct_Move_Orig( EXEC_OP_ TT_GlyphZone  zone,
01601                              FT_UShort     point,
01602                              FT_F26Dot6    distance )
01603   {
01604     FT_F26Dot6  v;
01605 
01606 
01607 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
01608     FT_ASSERT( !CUR.face->unpatented_hinting );
01609 #endif
01610 
01611     v = CUR.GS.freeVector.x;
01612 
01613     if ( v != 0 )
01614       zone->org[point].x += TT_MULDIV( distance,
01615                                        v * 0x10000L,
01616                                        CUR.F_dot_P );
01617 
01618     v = CUR.GS.freeVector.y;
01619 
01620     if ( v != 0 )
01621       zone->org[point].y += TT_MULDIV( distance,
01622                                        v * 0x10000L,
01623                                        CUR.F_dot_P );
01624   }
01625 
01626 
01627   /*************************************************************************/
01628   /*                                                                       */
01629   /* Special versions of Direct_Move()                                     */
01630   /*                                                                       */
01631   /*   The following versions are used whenever both vectors are both      */
01632   /*   along one of the coordinate unit vectors, i.e. in 90% of the cases. */
01633   /*                                                                       */
01634   /*************************************************************************/
01635 
01636 
01637   static void
01638   Direct_Move_X( EXEC_OP_ TT_GlyphZone  zone,
01639                           FT_UShort     point,
01640                           FT_F26Dot6    distance )
01641   {
01642     FT_UNUSED_EXEC;
01643 
01644     zone->cur[point].x += distance;
01645     zone->tags[point]  |= FT_CURVE_TAG_TOUCH_X;
01646   }
01647 
01648 
01649   static void
01650   Direct_Move_Y( EXEC_OP_ TT_GlyphZone  zone,
01651                           FT_UShort     point,
01652                           FT_F26Dot6    distance )
01653   {
01654     FT_UNUSED_EXEC;
01655 
01656     zone->cur[point].y += distance;
01657     zone->tags[point]  |= FT_CURVE_TAG_TOUCH_Y;
01658   }
01659 
01660 
01661   /*************************************************************************/
01662   /*                                                                       */
01663   /* Special versions of Direct_Move_Orig()                                */
01664   /*                                                                       */
01665   /*   The following versions are used whenever both vectors are both      */
01666   /*   along one of the coordinate unit vectors, i.e. in 90% of the cases. */
01667   /*                                                                       */
01668   /*************************************************************************/
01669 
01670 
01671   static void
01672   Direct_Move_Orig_X( EXEC_OP_ TT_GlyphZone  zone,
01673                                FT_UShort     point,
01674                                FT_F26Dot6    distance )
01675   {
01676     FT_UNUSED_EXEC;
01677 
01678     zone->org[point].x += distance;
01679   }
01680 
01681 
01682   static void
01683   Direct_Move_Orig_Y( EXEC_OP_ TT_GlyphZone  zone,
01684                                FT_UShort     point,
01685                                FT_F26Dot6    distance )
01686   {
01687     FT_UNUSED_EXEC;
01688 
01689     zone->org[point].y += distance;
01690   }
01691 
01692 
01693   /*************************************************************************/
01694   /*                                                                       */
01695   /* <Function>                                                            */
01696   /*    Round_None                                                         */
01697   /*                                                                       */
01698   /* <Description>                                                         */
01699   /*    Does not round, but adds engine compensation.                      */
01700   /*                                                                       */
01701   /* <Input>                                                               */
01702   /*    distance     :: The distance (not) to round.                       */
01703   /*                                                                       */
01704   /*    compensation :: The engine compensation.                           */
01705   /*                                                                       */
01706   /* <Return>                                                              */
01707   /*    The compensated distance.                                          */
01708   /*                                                                       */
01709   /* <Note>                                                                */
01710   /*    The TrueType specification says very few about the relationship    */
01711   /*    between rounding and engine compensation.  However, it seems from  */
01712   /*    the description of super round that we should add the compensation */
01713   /*    before rounding.                                                   */
01714   /*                                                                       */
01715   static FT_F26Dot6
01716   Round_None( EXEC_OP_ FT_F26Dot6  distance,
01717                        FT_F26Dot6  compensation )
01718   {
01719     FT_F26Dot6  val;
01720 
01721     FT_UNUSED_EXEC;
01722 
01723 
01724     if ( distance >= 0 )
01725     {
01726       val = distance + compensation;
01727       if ( distance && val < 0 )
01728         val = 0;
01729     }
01730     else {
01731       val = distance - compensation;
01732       if ( val > 0 )
01733         val = 0;
01734     }
01735     return val;
01736   }
01737 
01738 
01739   /*************************************************************************/
01740   /*                                                                       */
01741   /* <Function>                                                            */
01742   /*    Round_To_Grid                                                      */
01743   /*                                                                       */
01744   /* <Description>                                                         */
01745   /*    Rounds value to grid after adding engine compensation.             */
01746   /*                                                                       */
01747   /* <Input>                                                               */
01748   /*    distance     :: The distance to round.                             */
01749   /*                                                                       */
01750   /*    compensation :: The engine compensation.                           */
01751   /*                                                                       */
01752   /* <Return>                                                              */
01753   /*    Rounded distance.                                                  */
01754   /*                                                                       */
01755   static FT_F26Dot6
01756   Round_To_Grid( EXEC_OP_ FT_F26Dot6  distance,
01757                           FT_F26Dot6  compensation )
01758   {
01759     FT_F26Dot6  val;
01760 
01761     FT_UNUSED_EXEC;
01762 
01763 
01764     if ( distance >= 0 )
01765     {
01766       val = distance + compensation + 32;
01767       if ( distance && val > 0 )
01768         val &= ~63;
01769       else
01770         val = 0;
01771     }
01772     else
01773     {
01774       val = -FT_PIX_ROUND( compensation - distance );
01775       if ( val > 0 )
01776         val = 0;
01777     }
01778 
01779     return  val;
01780   }
01781 
01782 
01783   /*************************************************************************/
01784   /*                                                                       */
01785   /* <Function>                                                            */
01786   /*    Round_To_Half_Grid                                                 */
01787   /*                                                                       */
01788   /* <Description>                                                         */
01789   /*    Rounds value to half grid after adding engine compensation.        */
01790   /*                                                                       */
01791   /* <Input>                                                               */
01792   /*    distance     :: The distance to round.                             */
01793   /*                                                                       */
01794   /*    compensation :: The engine compensation.                           */
01795   /*                                                                       */
01796   /* <Return>                                                              */
01797   /*    Rounded distance.                                                  */
01798   /*                                                                       */
01799   static FT_F26Dot6
01800   Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6  distance,
01801                                FT_F26Dot6  compensation )
01802   {
01803     FT_F26Dot6  val;
01804 
01805     FT_UNUSED_EXEC;
01806 
01807 
01808     if ( distance >= 0 )
01809     {
01810       val = FT_PIX_FLOOR( distance + compensation ) + 32;
01811       if ( distance && val < 0 )
01812         val = 0;
01813     }
01814     else
01815     {
01816       val = -( FT_PIX_FLOOR( compensation - distance ) + 32 );
01817       if ( val > 0 )
01818         val = 0;
01819     }
01820 
01821     return val;
01822   }
01823 
01824 
01825   /*************************************************************************/
01826   /*                                                                       */
01827   /* <Function>                                                            */
01828   /*    Round_Down_To_Grid                                                 */
01829   /*                                                                       */
01830   /* <Description>                                                         */
01831   /*    Rounds value down to grid after adding engine compensation.        */
01832   /*                                                                       */
01833   /* <Input>                                                               */
01834   /*    distance     :: The distance to round.                             */
01835   /*                                                                       */
01836   /*    compensation :: The engine compensation.                           */
01837   /*                                                                       */
01838   /* <Return>                                                              */
01839   /*    Rounded distance.                                                  */
01840   /*                                                                       */
01841   static FT_F26Dot6
01842   Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6  distance,
01843                                FT_F26Dot6  compensation )
01844   {
01845     FT_F26Dot6  val;
01846 
01847     FT_UNUSED_EXEC;
01848 
01849 
01850     if ( distance >= 0 )
01851     {
01852       val = distance + compensation;
01853       if ( distance && val > 0 )
01854         val &= ~63;
01855       else
01856         val = 0;
01857     }
01858     else
01859     {
01860       val = -( ( compensation - distance ) & -64 );
01861       if ( val > 0 )
01862         val = 0;
01863     }
01864 
01865     return val;
01866   }
01867 
01868 
01869   /*************************************************************************/
01870   /*                                                                       */
01871   /* <Function>                                                            */
01872   /*    Round_Up_To_Grid                                                   */
01873   /*                                                                       */
01874   /* <Description>                                                         */
01875   /*    Rounds value up to grid after adding engine compensation.          */
01876   /*                                                                       */
01877   /* <Input>                                                               */
01878   /*    distance     :: The distance to round.                             */
01879   /*                                                                       */
01880   /*    compensation :: The engine compensation.                           */
01881   /*                                                                       */
01882   /* <Return>                                                              */
01883   /*    Rounded distance.                                                  */
01884   /*                                                                       */
01885   static FT_F26Dot6
01886   Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6  distance,
01887                              FT_F26Dot6  compensation )
01888   {
01889     FT_F26Dot6  val;
01890 
01891     FT_UNUSED_EXEC;
01892 
01893 
01894     if ( distance >= 0 )
01895     {
01896       val = distance + compensation + 63;
01897       if ( distance && val > 0 )
01898         val &= ~63;
01899       else
01900         val = 0;
01901     }
01902     else
01903     {
01904       val = - FT_PIX_CEIL( compensation - distance );
01905       if ( val > 0 )
01906         val = 0;
01907     }
01908 
01909     return val;
01910   }
01911 
01912 
01913   /*************************************************************************/
01914   /*                                                                       */
01915   /* <Function>                                                            */
01916   /*    Round_To_Double_Grid                                               */
01917   /*                                                                       */
01918   /* <Description>                                                         */
01919   /*    Rounds value to double grid after adding engine compensation.      */
01920   /*                                                                       */
01921   /* <Input>                                                               */
01922   /*    distance     :: The distance to round.                             */
01923   /*                                                                       */
01924   /*    compensation :: The engine compensation.                           */
01925   /*                                                                       */
01926   /* <Return>                                                              */
01927   /*    Rounded distance.                                                  */
01928   /*                                                                       */
01929   static FT_F26Dot6
01930   Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6  distance,
01931                                  FT_F26Dot6  compensation )
01932   {
01933     FT_F26Dot6 val;
01934 
01935     FT_UNUSED_EXEC;
01936 
01937 
01938     if ( distance >= 0 )
01939     {
01940       val = distance + compensation + 16;
01941       if ( distance && val > 0 )
01942         val &= ~31;
01943       else
01944         val = 0;
01945     }
01946     else
01947     {
01948       val = -FT_PAD_ROUND( compensation - distance, 32 );
01949       if ( val > 0 )
01950         val = 0;
01951     }
01952 
01953     return val;
01954   }
01955 
01956 
01957   /*************************************************************************/
01958   /*                                                                       */
01959   /* <Function>                                                            */
01960   /*    Round_Super                                                        */
01961   /*                                                                       */
01962   /* <Description>                                                         */
01963   /*    Super-rounds value to grid after adding engine compensation.       */
01964   /*                                                                       */
01965   /* <Input>                                                               */
01966   /*    distance     :: The distance to round.                             */
01967   /*                                                                       */
01968   /*    compensation :: The engine compensation.                           */
01969   /*                                                                       */
01970   /* <Return>                                                              */
01971   /*    Rounded distance.                                                  */
01972   /*                                                                       */
01973   /* <Note>                                                                */
01974   /*    The TrueType specification says very few about the relationship    */
01975   /*    between rounding and engine compensation.  However, it seems from  */
01976   /*    the description of super round that we should add the compensation */
01977   /*    before rounding.                                                   */
01978   /*                                                                       */
01979   static FT_F26Dot6
01980   Round_Super( EXEC_OP_ FT_F26Dot6  distance,
01981                         FT_F26Dot6  compensation )
01982   {
01983     FT_F26Dot6  val;
01984 
01985 
01986     if ( distance >= 0 )
01987     {
01988       val = ( distance - CUR.phase + CUR.threshold + compensation ) &
01989               -CUR.period;
01990       if ( distance && val < 0 )
01991         val = 0;
01992       val += CUR.phase;
01993     }
01994     else
01995     {
01996       val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &
01997                -CUR.period );
01998       if ( val > 0 )
01999         val = 0;
02000       val -= CUR.phase;
02001     }
02002 
02003     return val;
02004   }
02005 
02006 
02007   /*************************************************************************/
02008   /*                                                                       */
02009   /* <Function>                                                            */
02010   /*    Round_Super_45                                                     */
02011   /*                                                                       */
02012   /* <Description>                                                         */
02013   /*    Super-rounds value to grid after adding engine compensation.       */
02014   /*                                                                       */
02015   /* <Input>                                                               */
02016   /*    distance     :: The distance to round.                             */
02017   /*                                                                       */
02018   /*    compensation :: The engine compensation.                           */
02019   /*                                                                       */
02020   /* <Return>                                                              */
02021   /*    Rounded distance.                                                  */
02022   /*                                                                       */
02023   /* <Note>                                                                */
02024   /*    There is a separate function for Round_Super_45() as we may need   */
02025   /*    greater precision.                                                 */
02026   /*                                                                       */
02027   static FT_F26Dot6
02028   Round_Super_45( EXEC_OP_ FT_F26Dot6  distance,
02029                            FT_F26Dot6  compensation )
02030   {
02031     FT_F26Dot6  val;
02032 
02033 
02034     if ( distance >= 0 )
02035     {
02036       val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
02037                 CUR.period ) * CUR.period;
02038       if ( distance && val < 0 )
02039         val = 0;
02040       val += CUR.phase;
02041     }
02042     else
02043     {
02044       val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /
02045                    CUR.period ) * CUR.period );
02046       if ( val > 0 )
02047         val = 0;
02048       val -= CUR.phase;
02049     }
02050 
02051     return val;
02052   }
02053 
02054 
02055   /*************************************************************************/
02056   /*                                                                       */
02057   /* <Function>                                                            */
02058   /*    Compute_Round                                                      */
02059   /*                                                                       */
02060   /* <Description>                                                         */
02061   /*    Sets the rounding mode.                                            */
02062   /*                                                                       */
02063   /* <Input>                                                               */
02064   /*    round_mode :: The rounding mode to be used.                        */
02065   /*                                                                       */
02066   static void
02067   Compute_Round( EXEC_OP_ FT_Byte  round_mode )
02068   {
02069     switch ( round_mode )
02070     {
02071     case TT_Round_Off:
02072       CUR.func_round = (TT_Round_Func)Round_None;
02073       break;
02074 
02075     case TT_Round_To_Grid:
02076       CUR.func_round = (TT_Round_Func)Round_To_Grid;
02077       break;
02078 
02079     case TT_Round_Up_To_Grid:
02080       CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
02081       break;
02082 
02083     case TT_Round_Down_To_Grid:
02084       CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
02085       break;
02086 
02087     case TT_Round_To_Half_Grid:
02088       CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
02089       break;
02090 
02091     case TT_Round_To_Double_Grid:
02092       CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
02093       break;
02094 
02095     case TT_Round_Super:
02096       CUR.func_round = (TT_Round_Func)Round_Super;
02097       break;
02098 
02099     case TT_Round_Super_45:
02100       CUR.func_round = (TT_Round_Func)Round_Super_45;
02101       break;
02102     }
02103   }
02104 
02105 
02106   /*************************************************************************/
02107   /*                                                                       */
02108   /* <Function>                                                            */
02109   /*    SetSuperRound                                                      */
02110   /*                                                                       */
02111   /* <Description>                                                         */
02112   /*    Sets Super Round parameters.                                       */
02113   /*                                                                       */
02114   /* <Input>                                                               */
02115   /*    GridPeriod :: Grid period                                          */
02116   /*    selector   :: SROUND opcode                                        */
02117   /*                                                                       */
02118   static void
02119   SetSuperRound( EXEC_OP_ FT_F26Dot6  GridPeriod,
02120                           FT_Long     selector )
02121   {
02122     switch ( (FT_Int)( selector & 0xC0 ) )
02123     {
02124       case 0:
02125         CUR.period = GridPeriod / 2;
02126         break;
02127 
02128       case 0x40:
02129         CUR.period = GridPeriod;
02130         break;
02131 
02132       case 0x80:
02133         CUR.period = GridPeriod * 2;
02134         break;
02135 
02136       /* This opcode is reserved, but... */
02137 
02138       case 0xC0:
02139         CUR.period = GridPeriod;
02140         break;
02141     }
02142 
02143     switch ( (FT_Int)( selector & 0x30 ) )
02144     {
02145     case 0:
02146       CUR.phase = 0;
02147       break;
02148 
02149     case 0x10:
02150       CUR.phase = CUR.period / 4;
02151       break;
02152 
02153     case 0x20:
02154       CUR.phase = CUR.period / 2;
02155       break;
02156 
02157     case 0x30:
02158       CUR.phase = CUR.period * 3 / 4;
02159       break;
02160     }
02161 
02162     if ( ( selector & 0x0F ) == 0 )
02163       CUR.threshold = CUR.period - 1;
02164     else
02165       CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8;
02166 
02167     CUR.period    /= 256;
02168     CUR.phase     /= 256;
02169     CUR.threshold /= 256;
02170   }
02171 
02172 
02173   /*************************************************************************/
02174   /*                                                                       */
02175   /* <Function>                                                            */
02176   /*    Project                                                            */
02177   /*                                                                       */
02178   /* <Description>                                                         */
02179   /*    Computes the projection of vector given by (v2-v1) along the       */
02180   /*    current projection vector.                                         */
02181   /*                                                                       */
02182   /* <Input>                                                               */
02183   /*    v1 :: First input vector.                                          */
02184   /*    v2 :: Second input vector.                                         */
02185   /*                                                                       */
02186   /* <Return>                                                              */
02187   /*    The distance in F26dot6 format.                                    */
02188   /*                                                                       */
02189   static FT_F26Dot6
02190   Project( EXEC_OP_ FT_Pos  dx,
02191                     FT_Pos  dy )
02192   {
02193 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
02194     FT_ASSERT( !CUR.face->unpatented_hinting );
02195 #endif
02196 
02197     return TT_DotFix14( (FT_UInt32)dx, (FT_UInt32)dy,
02198                         CUR.GS.projVector.x,
02199                         CUR.GS.projVector.y );
02200   }
02201 
02202 
02203   /*************************************************************************/
02204   /*                                                                       */
02205   /* <Function>                                                            */
02206   /*    Dual_Project                                                       */
02207   /*                                                                       */
02208   /* <Description>                                                         */
02209   /*    Computes the projection of the vector given by (v2-v1) along the   */
02210   /*    current dual vector.                                               */
02211   /*                                                                       */
02212   /* <Input>                                                               */
02213   /*    v1 :: First input vector.                                          */
02214   /*    v2 :: Second input vector.                                         */
02215   /*                                                                       */
02216   /* <Return>                                                              */
02217   /*    The distance in F26dot6 format.                                    */
02218   /*                                                                       */
02219   static FT_F26Dot6
02220   Dual_Project( EXEC_OP_ FT_Pos  dx,
02221                          FT_Pos  dy )
02222   {
02223     return TT_DotFix14( (FT_UInt32)dx, (FT_UInt32)dy,
02224                         CUR.GS.dualVector.x,
02225                         CUR.GS.dualVector.y );
02226   }
02227 
02228 
02229   /*************************************************************************/
02230   /*                                                                       */
02231   /* <Function>                                                            */
02232   /*    Project_x                                                          */
02233   /*                                                                       */
02234   /* <Description>                                                         */
02235   /*    Computes the projection of the vector given by (v2-v1) along the   */
02236   /*    horizontal axis.                                                   */
02237   /*                                                                       */
02238   /* <Input>                                                               */
02239   /*    v1 :: First input vector.                                          */
02240   /*    v2 :: Second input vector.                                         */
02241   /*                                                                       */
02242   /* <Return>                                                              */
02243   /*    The distance in F26dot6 format.                                    */
02244   /*                                                                       */
02245   static FT_F26Dot6
02246   Project_x( EXEC_OP_ FT_Pos  dx,
02247                       FT_Pos  dy )
02248   {
02249     FT_UNUSED_EXEC;
02250     FT_UNUSED( dy );
02251 
02252     return dx;
02253   }
02254 
02255 
02256   /*************************************************************************/
02257   /*                                                                       */
02258   /* <Function>                                                            */
02259   /*    Project_y                                                          */
02260   /*                                                                       */
02261   /* <Description>                                                         */
02262   /*    Computes the projection of the vector given by (v2-v1) along the   */
02263   /*    vertical axis.                                                     */
02264   /*                                                                       */
02265   /* <Input>                                                               */
02266   /*    v1 :: First input vector.                                          */
02267   /*    v2 :: Second input vector.                                         */
02268   /*                                                                       */
02269   /* <Return>                                                              */
02270   /*    The distance in F26dot6 format.                                    */
02271   /*                                                                       */
02272   static FT_F26Dot6
02273   Project_y( EXEC_OP_ FT_Pos  dx,
02274                       FT_Pos  dy )
02275   {
02276     FT_UNUSED_EXEC;
02277     FT_UNUSED( dx );
02278 
02279     return dy;
02280   }
02281 
02282 
02283   /*************************************************************************/
02284   /*                                                                       */
02285   /* <Function>                                                            */
02286   /*    Compute_Funcs                                                      */
02287   /*                                                                       */
02288   /* <Description>                                                         */
02289   /*    Computes the projection and movement function pointers according   */
02290   /*    to the current graphics state.                                     */
02291   /*                                                                       */
02292   static void
02293   Compute_Funcs( EXEC_OP )
02294   {
02295 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
02296     if ( CUR.face->unpatented_hinting )
02297     {
02298       /* If both vectors point rightwards along the x axis, set             */
02299       /* `both-x-axis' true, otherwise set it false.  The x values only     */
02300       /* need be tested because the vector has been normalised to a unit    */
02301       /* vector of length 0x4000 = unity.                                   */
02302       CUR.GS.both_x_axis = (FT_Bool)( CUR.GS.projVector.x == 0x4000 &&
02303                                       CUR.GS.freeVector.x == 0x4000 );
02304 
02305       /* Throw away projection and freedom vector information */
02306       /* because the patents don't allow them to be stored.   */
02307       /* The relevant US Patents are 5155805 and 5325479.     */
02308       CUR.GS.projVector.x = 0;
02309       CUR.GS.projVector.y = 0;
02310       CUR.GS.freeVector.x = 0;
02311       CUR.GS.freeVector.y = 0;
02312 
02313       if ( CUR.GS.both_x_axis )
02314       {
02315         CUR.func_project   = Project_x;
02316         CUR.func_move      = Direct_Move_X;
02317         CUR.func_move_orig = Direct_Move_Orig_X;
02318       }
02319       else
02320       {
02321         CUR.func_project   = Project_y;
02322         CUR.func_move      = Direct_Move_Y;
02323         CUR.func_move_orig = Direct_Move_Orig_Y;
02324       }
02325 
02326       if ( CUR.GS.dualVector.x == 0x4000 )
02327         CUR.func_dualproj = Project_x;
02328       else
02329       {
02330         if ( CUR.GS.dualVector.y == 0x4000 )
02331           CUR.func_dualproj = Project_y;
02332         else
02333           CUR.func_dualproj = Dual_Project;
02334       }
02335 
02336       /* Force recalculation of cached aspect ratio */
02337       CUR.tt_metrics.ratio = 0;
02338 
02339       return;
02340     }
02341 #endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING */
02342 
02343     if ( CUR.GS.freeVector.x == 0x4000 )
02344       CUR.F_dot_P       = CUR.GS.projVector.x * 0x10000L;
02345     else
02346     {
02347       if ( CUR.GS.freeVector.y == 0x4000 )
02348         CUR.F_dot_P       = CUR.GS.projVector.y * 0x10000L;
02349       else
02350         CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
02351                       (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
02352     }
02353 
02354     if ( CUR.GS.projVector.x == 0x4000 )
02355       CUR.func_project = (TT_Project_Func)Project_x;
02356     else
02357     {
02358       if ( CUR.GS.projVector.y == 0x4000 )
02359         CUR.func_project = (TT_Project_Func)Project_y;
02360       else
02361         CUR.func_project = (TT_Project_Func)Project;
02362     }
02363 
02364     if ( CUR.GS.dualVector.x == 0x4000 )
02365       CUR.func_dualproj = (TT_Project_Func)Project_x;
02366     else
02367     {
02368       if ( CUR.GS.dualVector.y == 0x4000 )
02369         CUR.func_dualproj = (TT_Project_Func)Project_y;
02370       else
02371         CUR.func_dualproj = (TT_Project_Func)Dual_Project;
02372     }
02373 
02374     CUR.func_move      = (TT_Move_Func)Direct_Move;
02375     CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig;
02376 
02377     if ( CUR.F_dot_P == 0x40000000L )
02378     {
02379       if ( CUR.GS.freeVector.x == 0x4000 )
02380       {
02381         CUR.func_move      = (TT_Move_Func)Direct_Move_X;
02382         CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;
02383       }
02384       else
02385       {
02386         if ( CUR.GS.freeVector.y == 0x4000 )
02387         {
02388           CUR.func_move      = (TT_Move_Func)Direct_Move_Y;
02389           CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
02390         }
02391       }
02392     }
02393 
02394     /* at small sizes, F_dot_P can become too small, resulting   */
02395     /* in overflows and `spikes' in a number of glyphs like `w'. */
02396 
02397     if ( FT_ABS( CUR.F_dot_P ) < 0x4000000L )
02398       CUR.F_dot_P = 0x40000000L;
02399 
02400     /* Disable cached aspect ratio */
02401     CUR.tt_metrics.ratio = 0;
02402   }
02403 
02404 
02405   /*************************************************************************/
02406   /*                                                                       */
02407   /* <Function>                                                            */
02408   /*    Normalize                                                          */
02409   /*                                                                       */
02410   /* <Description>                                                         */
02411   /*    Norms a vector.                                                    */
02412   /*                                                                       */
02413   /* <Input>                                                               */
02414   /*    Vx :: The horizontal input vector coordinate.                      */
02415   /*    Vy :: The vertical input vector coordinate.                        */
02416   /*                                                                       */
02417   /* <Output>                                                              */
02418   /*    R  :: The normed unit vector.                                      */
02419   /*                                                                       */
02420   /* <Return>                                                              */
02421   /*    Returns FAILURE if a vector parameter is zero.                     */
02422   /*                                                                       */
02423   /* <Note>                                                                */
02424   /*    In case Vx and Vy are both zero, Normalize() returns SUCCESS, and  */
02425   /*    R is undefined.                                                    */
02426   /*                                                                       */
02427 
02428 
02429   static FT_Bool
02430   Normalize( EXEC_OP_ FT_F26Dot6      Vx,
02431                       FT_F26Dot6      Vy,
02432                       FT_UnitVector*  R )
02433   {
02434     FT_F26Dot6  W;
02435     FT_Bool     S1, S2;
02436 
02437     FT_UNUSED_EXEC;
02438 
02439 
02440     if ( FT_ABS( Vx ) < 0x10000L && FT_ABS( Vy ) < 0x10000L )
02441     {
02442       Vx *= 0x100;
02443       Vy *= 0x100;
02444 
02445       W = TT_VecLen( Vx, Vy );
02446 
02447       if ( W == 0 )
02448       {
02449         /* XXX: UNDOCUMENTED! It seems that it is possible to try   */
02450         /*      to normalize the vector (0,0).  Return immediately. */
02451         return SUCCESS;
02452       }
02453 
02454       R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W );
02455       R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W );
02456 
02457       return SUCCESS;
02458     }
02459 
02460     W = TT_VecLen( Vx, Vy );
02461 
02462     Vx = FT_MulDiv( Vx, 0x4000L, W );
02463     Vy = FT_MulDiv( Vy, 0x4000L, W );
02464 
02465     W = Vx * Vx + Vy * Vy;
02466 
02467     /* Now, we want that Sqrt( W ) = 0x4000 */
02468     /* Or 0x10000000 <= W < 0x10004000        */
02469 
02470     if ( Vx < 0 )
02471     {
02472       Vx = -Vx;
02473       S1 = TRUE;
02474     }
02475     else
02476       S1 = FALSE;
02477 
02478     if ( Vy < 0 )
02479     {
02480       Vy = -Vy;
02481       S2 = TRUE;
02482     }
02483     else
02484       S2 = FALSE;
02485 
02486     while ( W < 0x10000000L )
02487     {
02488       /* We need to increase W by a minimal amount */
02489       if ( Vx < Vy )
02490         Vx++;
02491       else
02492         Vy++;
02493 
02494       W = Vx * Vx + Vy * Vy;
02495     }
02496 
02497     while ( W >= 0x10004000L )
02498     {
02499       /* We need to decrease W by a minimal amount */
02500       if ( Vx < Vy )
02501         Vx--;
02502       else
02503         Vy--;
02504 
02505       W = Vx * Vx + Vy * Vy;
02506     }
02507 
02508     /* Note that in various cases, we can only  */
02509     /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
02510 
02511     if ( S1 )
02512       Vx = -Vx;
02513 
02514     if ( S2 )
02515       Vy = -Vy;
02516 
02517     R->x = (FT_F2Dot14)Vx;   /* Type conversion */
02518     R->y = (FT_F2Dot14)Vy;   /* Type conversion */
02519 
02520     return SUCCESS;
02521   }
02522 
02523 
02524   /*************************************************************************/
02525   /*                                                                       */
02526   /* Here we start with the implementation of the various opcodes.         */
02527   /*                                                                       */
02528   /*************************************************************************/
02529 
02530 
02531   static FT_Bool
02532   Ins_SxVTL( EXEC_OP_ FT_UShort       aIdx1,
02533                       FT_UShort       aIdx2,
02534                       FT_Int          aOpc,
02535                       FT_UnitVector*  Vec )
02536   {
02537     FT_Long     A, B, C;
02538     FT_Vector*  p1;
02539     FT_Vector*  p2;
02540 
02541 
02542     if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
02543          BOUNDS( aIdx2, CUR.zp1.n_points ) )
02544     {
02545       if ( CUR.pedantic_hinting )
02546         CUR.error = TT_Err_Invalid_Reference;
02547       return FAILURE;
02548     }
02549 
02550     p1 = CUR.zp1.cur + aIdx2;
02551     p2 = CUR.zp2.cur + aIdx1;
02552 
02553     A = p1->x - p2->x;
02554     B = p1->y - p2->y;
02555 
02556     if ( ( aOpc & 1 ) != 0 )
02557     {
02558       C =  B;   /* counter clockwise rotation */
02559       B =  A;
02560       A = -C;
02561     }
02562 
02563     NORMalize( A, B, Vec );
02564 
02565     return SUCCESS;
02566   }
02567 
02568 
02569   /* When not using the big switch statements, the interpreter uses a */
02570   /* call table defined later below in this source.  Each opcode must */
02571   /* thus have a corresponding function, even trivial ones.           */
02572   /*                                                                  */
02573   /* They are all defined there.                                      */
02574 
02575 #define DO_SVTCA                            \
02576   {                                         \
02577     FT_Short  A, B;                         \
02578                                             \
02579                                             \
02580     A = (FT_Short)( CUR.opcode & 1 ) << 14; \
02581     B = A ^ (FT_Short)0x4000;               \
02582                                             \
02583     CUR.GS.freeVector.x = A;                \
02584     CUR.GS.projVector.x = A;                \
02585     CUR.GS.dualVector.x = A;                \
02586                                             \
02587     CUR.GS.freeVector.y = B;                \
02588     CUR.GS.projVector.y = B;                \
02589     CUR.GS.dualVector.y = B;                \
02590                                             \
02591     COMPUTE_Funcs();                        \
02592   }
02593 
02594 
02595 #define DO_SPVTCA                           \
02596   {                                         \
02597     FT_Short  A, B;                         \
02598                                             \
02599                                             \
02600     A = (FT_Short)( CUR.opcode & 1 ) << 14; \
02601     B = A ^ (FT_Short)0x4000;               \
02602                                             \
02603     CUR.GS.projVector.x = A;                \
02604     CUR.GS.dualVector.x = A;                \
02605                                             \
02606     CUR.GS.projVector.y = B;                \
02607     CUR.GS.dualVector.y = B;                \
02608                                             \
02609     GUESS_VECTOR( freeVector );             \
02610                                             \
02611     COMPUTE_Funcs();                        \
02612   }
02613 
02614 
02615 #define DO_SFVTCA                           \
02616   {                                         \
02617     FT_Short  A, B;                         \
02618                                             \
02619                                             \
02620     A = (FT_Short)( CUR.opcode & 1 ) << 14; \
02621     B = A ^ (FT_Short)0x4000;               \
02622                                             \
02623     CUR.GS.freeVector.x = A;                \
02624     CUR.GS.freeVector.y = B;                \
02625                                             \
02626     GUESS_VECTOR( projVector );             \
02627                                             \
02628     COMPUTE_Funcs();                        \
02629   }
02630 
02631 
02632 #define DO_SPVTL                                      \
02633     if ( INS_SxVTL( (FT_UShort)args[1],               \
02634                     (FT_UShort)args[0],               \
02635                     CUR.opcode,                       \
02636                     &CUR.GS.projVector ) == SUCCESS ) \
02637     {                                                 \
02638       CUR.GS.dualVector = CUR.GS.projVector;          \
02639       GUESS_VECTOR( freeVector );                     \
02640       COMPUTE_Funcs();                                \
02641     }
02642 
02643 
02644 #define DO_SFVTL                                      \
02645     if ( INS_SxVTL( (FT_UShort)args[1],               \
02646                     (FT_UShort)args[0],               \
02647                     CUR.opcode,                       \
02648                     &CUR.GS.freeVector ) == SUCCESS ) \
02649     {                                                 \
02650       GUESS_VECTOR( projVector );                     \
02651       COMPUTE_Funcs();                                \
02652     }
02653 
02654 
02655 #define DO_SFVTPV                          \
02656     GUESS_VECTOR( projVector );            \
02657     CUR.GS.freeVector = CUR.GS.projVector; \
02658     COMPUTE_Funcs();
02659 
02660 
02661 #define DO_SPVFS                                \
02662   {                                             \
02663     FT_Short  S;                                \
02664     FT_Long   X, Y;                             \
02665                                                 \
02666                                                 \
02667     /* Only use low 16bits, then sign extend */ \
02668     S = (FT_Short)args[1];                      \
02669     Y = (FT_Long)S;                             \
02670     S = (FT_Short)args[0];                      \
02671     X = (FT_Long)S;                             \
02672                                                 \
02673     NORMalize( X, Y, &CUR.GS.projVector );      \
02674                                                 \
02675     CUR.GS.dualVector = CUR.GS.projVector;      \
02676     GUESS_VECTOR( freeVector );                 \
02677     COMPUTE_Funcs();                            \
02678   }
02679 
02680 
02681 #define DO_SFVFS                                \
02682   {                                             \
02683     FT_Short  S;                                \
02684     FT_Long   X, Y;                             \
02685                                                 \
02686                                                 \
02687     /* Only use low 16bits, then sign extend */ \
02688     S = (FT_Short)args[1];                      \
02689     Y = (FT_Long)S;                             \
02690     S = (FT_Short)args[0];                      \
02691     X = S;                                      \
02692                                                 \
02693     NORMalize( X, Y, &CUR.GS.freeVector );      \
02694     GUESS_VECTOR( projVector );                 \
02695     COMPUTE_Funcs();                            \
02696   }
02697 
02698 
02699 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
02700 #define DO_GPV                                   \
02701     if ( CUR.face->unpatented_hinting )          \
02702     {                                            \
02703       args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
02704       args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
02705     }                                            \
02706     else                                         \
02707     {                                            \
02708       args[0] = CUR.GS.projVector.x;             \
02709       args[1] = CUR.GS.projVector.y;             \
02710     }
02711 #else
02712 #define DO_GPV                                   \
02713     args[0] = CUR.GS.projVector.x;               \
02714     args[1] = CUR.GS.projVector.y;
02715 #endif
02716 
02717 
02718 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
02719 #define DO_GFV                                   \
02720     if ( CUR.face->unpatented_hinting )          \
02721     {                                            \
02722       args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
02723       args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
02724     }                                            \
02725     else                                         \
02726     {                                            \
02727       args[0] = CUR.GS.freeVector.x;             \
02728       args[1] = CUR.GS.freeVector.y;             \
02729     }
02730 #else
02731 #define DO_GFV                                   \
02732     args[0] = CUR.GS.freeVector.x;               \
02733     args[1] = CUR.GS.freeVector.y;
02734 #endif
02735 
02736 
02737 #define DO_SRP0                      \
02738     CUR.GS.rp0 = (FT_UShort)args[0];
02739 
02740 
02741 #define DO_SRP1                      \
02742     CUR.GS.rp1 = (FT_UShort)args[0];
02743 
02744 
02745 #define DO_SRP2                      \
02746     CUR.GS.rp2 = (FT_UShort)args[0];
02747 
02748 
02749 #define DO_RTHG                                         \
02750     CUR.GS.round_state = TT_Round_To_Half_Grid;         \
02751     CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
02752 
02753 
02754 #define DO_RTG                                     \
02755     CUR.GS.round_state = TT_Round_To_Grid;         \
02756     CUR.func_round = (TT_Round_Func)Round_To_Grid;
02757 
02758 
02759 #define DO_RTDG                                           \
02760     CUR.GS.round_state = TT_Round_To_Double_Grid;         \
02761     CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
02762 
02763 
02764 #define DO_RUTG                                       \
02765     CUR.GS.round_state = TT_Round_Up_To_Grid;         \
02766     CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
02767 
02768 
02769 #define DO_RDTG                                         \
02770     CUR.GS.round_state = TT_Round_Down_To_Grid;         \
02771     CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
02772 
02773 
02774 #define DO_ROFF                                 \
02775     CUR.GS.round_state = TT_Round_Off;          \
02776     CUR.func_round = (TT_Round_Func)Round_None;
02777 
02778 
02779 #define DO_SROUND                                \
02780     SET_SuperRound( 0x4000, args[0] );           \
02781     CUR.GS.round_state = TT_Round_Super;         \
02782     CUR.func_round = (TT_Round_Func)Round_Super;
02783 
02784 
02785 #define DO_S45ROUND                                 \
02786     SET_SuperRound( 0x2D41, args[0] );              \
02787     CUR.GS.round_state = TT_Round_Super_45;         \
02788     CUR.func_round = (TT_Round_Func)Round_Super_45;
02789 
02790 
02791 #define DO_SLOOP                       \
02792     if ( args[0] < 0 )                 \
02793       CUR.error = TT_Err_Bad_Argument; \
02794     else                               \
02795       CUR.GS.loop = args[0];
02796 
02797 
02798 #define DO_SMD                         \
02799     CUR.GS.minimum_distance = args[0];
02800 
02801 
02802 #define DO_SCVTCI                                     \
02803     CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
02804 
02805 
02806 #define DO_SSWCI                                     \
02807     CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
02808 
02809 
02810     /* XXX: UNDOCUMENTED! or bug in the Windows engine?   */
02811     /*                                                    */
02812     /*      It seems that the value that is read here is  */
02813     /*      expressed in 16.16 format rather than in font */
02814     /*      units.                                        */
02815     /*                                                    */
02816 #define DO_SSW                                                 \
02817     CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
02818 
02819 
02820 #define DO_FLIPON            \
02821     CUR.GS.auto_flip = TRUE;
02822 
02823 
02824 #define DO_FLIPOFF            \
02825     CUR.GS.auto_flip = FALSE;
02826 
02827 
02828 #define DO_SDB                             \
02829     CUR.GS.delta_base = (FT_Short)args[0];
02830 
02831 
02832 #define DO_SDS                              \
02833     CUR.GS.delta_shift = (FT_Short)args[0];
02834 
02835 
02836 #define DO_MD  /* nothing */
02837 
02838 
02839 #define DO_MPPEM              \
02840     args[0] = CURRENT_Ppem();
02841 
02842 
02843   /* Note: The pointSize should be irrelevant in a given font program; */
02844   /*       we thus decide to return only the ppem.                     */
02845 #if 0
02846 
02847 #define DO_MPS                       \
02848     args[0] = CUR.metrics.pointSize;
02849 
02850 #else
02851 
02852 #define DO_MPS                \
02853     args[0] = CURRENT_Ppem();
02854 
02855 #endif /* 0 */
02856 
02857 
02858 #define DO_DUP         \
02859     args[1] = args[0];
02860 
02861 
02862 #define DO_CLEAR     \
02863     CUR.new_top = 0;
02864 
02865 
02866 #define DO_SWAP        \
02867   {                    \
02868     FT_Long  L;        \
02869                        \
02870                        \
02871     L       = args[0]; \
02872     args[0] = args[1]; \
02873     args[1] = L;       \
02874   }
02875 
02876 
02877 #define DO_DEPTH       \
02878     args[0] = CUR.top;
02879 
02880 
02881 #define DO_CINDEX                           \
02882   {                                         \
02883     FT_Long  L;                             \
02884                                             \
02885                                             \
02886     L = args[0];                            \
02887                                             \
02888     if ( L <= 0 || L > CUR.args )           \
02889       CUR.error = TT_Err_Invalid_Reference; \
02890     else                                    \
02891       args[0] = CUR.stack[CUR.args - L];    \
02892   }
02893 
02894 
02895 #define DO_JROT               \
02896     if ( args[1] != 0 )       \
02897     {                         \
02898       CUR.IP      += args[0]; \
02899       CUR.step_ins = FALSE;   \
02900     }
02901 
02902 
02903 #define DO_JMPR             \
02904     CUR.IP      += args[0]; \
02905     CUR.step_ins = FALSE;
02906 
02907 
02908 #define DO_JROF               \
02909     if ( args[1] == 0 )       \
02910     {                         \
02911       CUR.IP      += args[0]; \
02912       CUR.step_ins = FALSE;   \
02913     }
02914 
02915 
02916 #define DO_LT                        \
02917     args[0] = ( args[0] < args[1] );
02918 
02919 
02920 #define DO_LTEQ                       \
02921     args[0] = ( args[0] <= args[1] );
02922 
02923 
02924 #define DO_GT                        \
02925     args[0] = ( args[0] > args[1] );
02926 
02927 
02928 #define DO_GTEQ                       \
02929     args[0] = ( args[0] >= args[1] );
02930 
02931 
02932 #define DO_EQ                         \
02933     args[0] = ( args[0] == args[1] );
02934 
02935 
02936 #define DO_NEQ                        \
02937     args[0] = ( args[0] != args[1] );
02938 
02939 
02940 #define DO_ODD                                                  \
02941     args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
02942 
02943 
02944 #define DO_EVEN                                                \
02945     args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
02946 
02947 
02948 #define DO_AND                        \
02949     args[0] = ( args[0] && args[1] );
02950 
02951 
02952 #define DO_OR                         \
02953     args[0] = ( args[0] || args[1] );
02954 
02955 
02956 #define DO_NOT          \
02957     args[0] = !args[0];
02958 
02959 
02960 #define DO_ADD          \
02961     args[0] += args[1];
02962 
02963 
02964 #define DO_SUB          \
02965     args[0] -= args[1];
02966 
02967 
02968 #define DO_DIV                                               \
02969     if ( args[1] == 0 )                                      \
02970       CUR.error = TT_Err_Divide_By_Zero;                     \
02971     else                                                     \
02972       args[0] = TT_MULDIV_NO_ROUND( args[0], 64L, args[1] );
02973 
02974 
02975 #define DO_MUL                                    \
02976     args[0] = TT_MULDIV( args[0], args[1], 64L );
02977 
02978 
02979 #define DO_ABS                   \
02980     args[0] = FT_ABS( args[0] );
02981 
02982 
02983 #define DO_NEG          \
02984     args[0] = -args[0];
02985 
02986 
02987 #define DO_FLOOR    \
02988     args[0] = FT_PIX_FLOOR( args[0] );
02989 
02990 
02991 #define DO_CEILING                    \
02992     args[0] = FT_PIX_CEIL( args[0] );
02993 
02994 
02995 #define DO_RS                          \
02996    {                                   \
02997      FT_ULong  I = (FT_ULong)args[0];  \
02998                                        \
02999                                        \
03000      if ( BOUNDS( I, CUR.storeSize ) ) \
03001      {                                 \
03002        if ( CUR.pedantic_hinting )     \
03003        {                               \
03004          ARRAY_BOUND_ERROR;            \
03005        }                               \
03006        else                            \
03007          args[0] = 0;                  \
03008      }                                 \
03009      else                              \
03010        args[0] = CUR.storage[I];       \
03011    }
03012 
03013 
03014 #define DO_WS                          \
03015    {                                   \
03016      FT_ULong  I = (FT_ULong)args[0];  \
03017                                        \
03018                                        \
03019      if ( BOUNDS( I, CUR.storeSize ) ) \
03020      {                                 \
03021        if ( CUR.pedantic_hinting )     \
03022        {                               \
03023          ARRAY_BOUND_ERROR;            \
03024        }                               \
03025      }                                 \
03026      else                              \
03027        CUR.storage[I] = args[1];       \
03028    }
03029 
03030 
03031 #define DO_RCVT                          \
03032    {                                     \
03033      FT_ULong  I = (FT_ULong)args[0];    \
03034                                          \
03035                                          \
03036      if ( BOUNDS( I, CUR.cvtSize ) )     \
03037      {                                   \
03038        if ( CUR.pedantic_hinting )       \
03039        {                                 \
03040          ARRAY_BOUND_ERROR;              \
03041        }                                 \
03042        else                              \
03043          args[0] = 0;                    \
03044      }                                   \
03045      else                                \
03046        args[0] = CUR_Func_read_cvt( I ); \
03047    }
03048 
03049 
03050 #define DO_WCVTP                         \
03051    {                                     \
03052      FT_ULong  I = (FT_ULong)args[0];    \
03053                                          \
03054                                          \
03055      if ( BOUNDS( I, CUR.cvtSize ) )     \
03056      {                                   \
03057        if ( CUR.pedantic_hinting )       \
03058        {                                 \
03059          ARRAY_BOUND_ERROR;              \
03060        }                                 \
03061      }                                   \
03062      else                                \
03063        CUR_Func_write_cvt( I, args[1] ); \
03064    }
03065 
03066 
03067 #define DO_WCVTF                                                \
03068    {                                                            \
03069      FT_ULong  I = (FT_ULong)args[0];                           \
03070                                                                 \
03071                                                                 \
03072      if ( BOUNDS( I, CUR.cvtSize ) )                            \
03073      {                                                          \
03074        if ( CUR.pedantic_hinting )                              \
03075        {                                                        \
03076          ARRAY_BOUND_ERROR;                                     \
03077        }                                                        \
03078      }                                                          \
03079      else                                                       \
03080        CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
03081    }
03082 
03083 
03084 #define DO_DEBUG                     \
03085     CUR.error = TT_Err_Debug_OpCode;
03086 
03087 
03088 #define DO_ROUND                                                   \
03089     args[0] = CUR_Func_round(                                      \
03090                 args[0],                                           \
03091                 CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
03092 
03093 
03094 #define DO_NROUND                                                            \
03095     args[0] = ROUND_None( args[0],                                           \
03096                           CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
03097 
03098 
03099 #define DO_MAX               \
03100     if ( args[1] > args[0] ) \
03101       args[0] = args[1];
03102 
03103 
03104 #define DO_MIN               \
03105     if ( args[1] < args[0] ) \
03106       args[0] = args[1];
03107 
03108 
03109 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
03110 
03111 
03112 #undef  ARRAY_BOUND_ERROR
03113 #define ARRAY_BOUND_ERROR                   \
03114     {                                       \
03115       CUR.error = TT_Err_Invalid_Reference; \
03116       return;                               \
03117     }
03118 
03119 
03120   /*************************************************************************/
03121   /*                                                                       */
03122   /* SVTCA[a]:     Set (F and P) Vectors to Coordinate Axis                */
03123   /* Opcode range: 0x00-0x01                                               */
03124   /* Stack:        -->                                                     */
03125   /*                                                                       */
03126   static void
03127   Ins_SVTCA( INS_ARG )
03128   {
03129     DO_SVTCA
03130   }
03131 
03132 
03133   /*************************************************************************/
03134   /*                                                                       */
03135   /* SPVTCA[a]:    Set PVector to Coordinate Axis                          */
03136   /* Opcode range: 0x02-0x03                                               */
03137   /* Stack:        -->                                                     */
03138   /*                                                                       */
03139   static void
03140   Ins_SPVTCA( INS_ARG )
03141   {
03142     DO_SPVTCA
03143   }
03144 
03145 
03146   /*************************************************************************/
03147   /*                                                                       */
03148   /* SFVTCA[a]:    Set FVector to Coordinate Axis                          */
03149   /* Opcode range: 0x04-0x05                                               */
03150   /* Stack:        -->                                                     */
03151   /*                                                                       */
03152   static void
03153   Ins_SFVTCA( INS_ARG )
03154   {
03155     DO_SFVTCA
03156   }
03157 
03158 
03159   /*************************************************************************/
03160   /*                                                                       */
03161   /* SPVTL[a]:     Set PVector To Line                                     */
03162   /* Opcode range: 0x06-0x07                                               */
03163   /* Stack:        uint32 uint32 -->                                       */
03164   /*                                                                       */
03165   static void
03166   Ins_SPVTL( INS_ARG )
03167   {
03168     DO_SPVTL
03169   }
03170 
03171 
03172   /*************************************************************************/
03173   /*                                                                       */
03174   /* SFVTL[a]:     Set FVector To Line                                     */
03175   /* Opcode range: 0x08-0x09                                               */
03176   /* Stack:        uint32 uint32 -->                                       */
03177   /*                                                                       */
03178   static void
03179   Ins_SFVTL( INS_ARG )
03180   {
03181     DO_SFVTL
03182   }
03183 
03184 
03185   /*************************************************************************/
03186   /*                                                                       */
03187   /* SFVTPV[]:     Set FVector To PVector                                  */
03188   /* Opcode range: 0x0E                                                    */
03189   /* Stack:        -->                                                     */
03190   /*                                                                       */
03191   static void
03192   Ins_SFVTPV( INS_ARG )
03193   {
03194     DO_SFVTPV
03195   }
03196 
03197 
03198   /*************************************************************************/
03199   /*                                                                       */
03200   /* SPVFS[]:      Set PVector From Stack                                  */
03201   /* Opcode range: 0x0A                                                    */
03202   /* Stack:        f2.14 f2.14 -->                                         */
03203   /*                                                                       */
03204   static void
03205   Ins_SPVFS( INS_ARG )
03206   {
03207     DO_SPVFS
03208   }
03209 
03210 
03211   /*************************************************************************/
03212   /*                                                                       */
03213   /* SFVFS[]:      Set FVector From Stack                                  */
03214   /* Opcode range: 0x0B                                                    */
03215   /* Stack:        f2.14 f2.14 -->                                         */
03216   /*                                                                       */
03217   static void
03218   Ins_SFVFS( INS_ARG )
03219   {
03220     DO_SFVFS
03221   }
03222 
03223 
03224   /*************************************************************************/
03225   /*                                                                       */
03226   /* GPV[]:        Get Projection Vector                                   */
03227   /* Opcode range: 0x0C                                                    */
03228   /* Stack:        ef2.14 --> ef2.14                                       */
03229   /*                                                                       */
03230   static void
03231   Ins_GPV( INS_ARG )
03232   {
03233     DO_GPV
03234   }
03235 
03236 
03237   /*************************************************************************/
03238   /* GFV[]:        Get Freedom Vector                                      */
03239   /* Opcode range: 0x0D                                                    */
03240   /* Stack:        ef2.14 --> ef2.14                                       */
03241   /*                                                                       */
03242   static void
03243   Ins_GFV( INS_ARG )
03244   {
03245     DO_GFV
03246   }
03247 
03248 
03249   /*************************************************************************/
03250   /*                                                                       */
03251   /* SRP0[]:       Set Reference Point 0                                   */
03252   /* Opcode range: 0x10                                                    */
03253   /* Stack:        uint32 -->                                              */
03254   /*                                                                       */
03255   static void
03256   Ins_SRP0( INS_ARG )
03257   {
03258     DO_SRP0
03259   }
03260 
03261 
03262   /*************************************************************************/
03263   /*                                                                       */
03264   /* SRP1[]:       Set Reference Point 1                                   */
03265   /* Opcode range: 0x11                                                    */
03266   /* Stack:        uint32 -->                                              */
03267   /*                                                                       */
03268   static void
03269   Ins_SRP1( INS_ARG )
03270   {
03271     DO_SRP1
03272   }
03273 
03274 
03275   /*************************************************************************/
03276   /*                                                                       */
03277   /* SRP2[]:       Set Reference Point 2                                   */
03278   /* Opcode range: 0x12                                                    */
03279   /* Stack:        uint32 -->                                              */
03280   /*                                                                       */
03281   static void
03282   Ins_SRP2( INS_ARG )
03283   {
03284     DO_SRP2
03285   }
03286 
03287 
03288   /*************************************************************************/
03289   /*                                                                       */
03290   /* RTHG[]:       Round To Half Grid                                      */
03291   /* Opcode range: 0x19                                                    */
03292   /* Stack:        -->                                                     */
03293   /*                                                                       */
03294   static void
03295   Ins_RTHG( INS_ARG )
03296   {
03297     DO_RTHG
03298   }
03299 
03300 
03301   /*************************************************************************/
03302   /*                                                                       */
03303   /* RTG[]:        Round To Grid                                           */
03304   /* Opcode range: 0x18                                                    */
03305   /* Stack:        -->                                                     */
03306   /*                                                                       */
03307   static void
03308   Ins_RTG( INS_ARG )
03309   {
03310     DO_RTG
03311   }
03312 
03313 
03314   /*************************************************************************/
03315   /* RTDG[]:       Round To Double Grid                                    */
03316   /* Opcode range: 0x3D                                                    */
03317   /* Stack:        -->                                                     */
03318   /*                                                                       */
03319   static void
03320   Ins_RTDG( INS_ARG )
03321   {
03322     DO_RTDG
03323   }
03324 
03325 
03326   /*************************************************************************/
03327   /* RUTG[]:       Round Up To Grid                                        */
03328   /* Opcode range: 0x7C                                                    */
03329   /* Stack:        -->                                                     */
03330   /*                                                                       */
03331   static void
03332   Ins_RUTG( INS_ARG )
03333   {
03334     DO_RUTG
03335   }
03336 
03337 
03338   /*************************************************************************/
03339   /*                                                                       */
03340   /* RDTG[]:       Round Down To Grid                                      */
03341   /* Opcode range: 0x7D                                                    */
03342   /* Stack:        -->                                                     */
03343   /*                                                                       */
03344   static void
03345   Ins_RDTG( INS_ARG )
03346   {
03347     DO_RDTG
03348   }
03349 
03350 
03351   /*************************************************************************/
03352   /*                                                                       */
03353   /* ROFF[]:       Round OFF                                               */
03354   /* Opcode range: 0x7A                                                    */
03355   /* Stack:        -->                                                     */
03356   /*                                                                       */
03357   static void
03358   Ins_ROFF( INS_ARG )
03359   {
03360     DO_ROFF
03361   }
03362 
03363 
03364   /*************************************************************************/
03365   /*                                                                       */
03366   /* SROUND[]:     Super ROUND                                             */
03367   /* Opcode range: 0x76                                                    */
03368   /* Stack:        Eint8 -->                                               */
03369   /*                                                                       */
03370   static void
03371   Ins_SROUND( INS_ARG )
03372   {
03373     DO_SROUND
03374   }
03375 
03376 
03377   /*************************************************************************/
03378   /*                                                                       */
03379   /* S45ROUND[]:   Super ROUND 45 degrees                                  */
03380   /* Opcode range: 0x77                                                    */
03381   /* Stack:        uint32 -->                                              */
03382   /*                                                                       */
03383   static void
03384   Ins_S45ROUND( INS_ARG )
03385   {
03386     DO_S45ROUND
03387   }
03388 
03389 
03390   /*************************************************************************/
03391   /*                                                                       */
03392   /* SLOOP[]:      Set LOOP variable                                       */
03393   /* Opcode range: 0x17                                                    */
03394   /* Stack:        int32? -->                                              */
03395   /*                                                                       */
03396   static void
03397   Ins_SLOOP( INS_ARG )
03398   {
03399     DO_SLOOP
03400   }
03401 
03402 
03403   /*************************************************************************/
03404   /*                                                                       */
03405   /* SMD[]:        Set Minimum Distance                                    */
03406   /* Opcode range: 0x1A                                                    */
03407   /* Stack:        f26.6 -->                                               */
03408   /*                                                                       */
03409   static void
03410   Ins_SMD( INS_ARG )
03411   {
03412     DO_SMD
03413   }
03414 
03415 
03416   /*************************************************************************/
03417   /*                                                                       */
03418   /* SCVTCI[]:     Set Control Value Table Cut In                          */
03419   /* Opcode range: 0x1D                                                    */
03420   /* Stack:        f26.6 -->                                               */
03421   /*                                                                       */
03422   static void
03423   Ins_SCVTCI( INS_ARG )
03424   {
03425     DO_SCVTCI
03426   }
03427 
03428 
03429   /*************************************************************************/
03430   /*                                                                       */
03431   /* SSWCI[]:      Set Single Width Cut In                                 */
03432   /* Opcode range: 0x1E                                                    */
03433   /* Stack:        f26.6 -->                                               */
03434   /*                                                                       */
03435   static void
03436   Ins_SSWCI( INS_ARG )
03437   {
03438     DO_SSWCI
03439   }
03440 
03441 
03442   /*************************************************************************/
03443   /*                                                                       */
03444   /* SSW[]:        Set Single Width                                        */
03445   /* Opcode range: 0x1F                                                    */
03446   /* Stack:        int32? -->                                              */
03447   /*                                                                       */
03448   static void
03449   Ins_SSW( INS_ARG )
03450   {
03451     DO_SSW
03452   }
03453 
03454 
03455   /*************************************************************************/
03456   /*                                                                       */
03457   /* FLIPON[]:     Set auto-FLIP to ON                                     */
03458   /* Opcode range: 0x4D                                                    */
03459   /* Stack:        -->                                                     */
03460   /*                                                                       */
03461   static void
03462   Ins_FLIPON( INS_ARG )
03463   {
03464     DO_FLIPON
03465   }
03466 
03467 
03468   /*************************************************************************/
03469   /*                                                                       */
03470   /* FLIPOFF[]:    Set auto-FLIP to OFF                                    */
03471   /* Opcode range: 0x4E                                                    */
03472   /* Stack: -->                                                            */
03473   /*                                                                       */
03474   static void
03475   Ins_FLIPOFF( INS_ARG )
03476   {
03477     DO_FLIPOFF
03478   }
03479 
03480 
03481   /*************************************************************************/
03482   /*                                                                       */
03483   /* SANGW[]:      Set ANGle Weight                                        */
03484   /* Opcode range: 0x7E                                                    */
03485   /* Stack:        uint32 -->                                              */
03486   /*                                                                       */
03487   static void
03488   Ins_SANGW( INS_ARG )
03489   {
03490     /* instruction not supported anymore */
03491   }
03492 
03493 
03494   /*************************************************************************/
03495   /*                                                                       */
03496   /* SDB[]:        Set Delta Base                                          */
03497   /* Opcode range: 0x5E                                                    */
03498   /* Stack:        uint32 -->                                              */
03499   /*                                                                       */
03500   static void
03501   Ins_SDB( INS_ARG )
03502   {
03503     DO_SDB
03504   }
03505 
03506 
03507   /*************************************************************************/
03508   /*                                                                       */
03509   /* SDS[]:        Set Delta Shift                                         */
03510   /* Opcode range: 0x5F                                                    */
03511   /* Stack:        uint32 -->                                              */
03512   /*                                                                       */
03513   static void
03514   Ins_SDS( INS_ARG )
03515   {
03516     DO_SDS
03517   }
03518 
03519 
03520   /*************************************************************************/
03521   /*                                                                       */
03522   /* MPPEM[]:      Measure Pixel Per EM                                    */
03523   /* Opcode range: 0x4B                                                    */
03524   /* Stack:        --> Euint16                                             */
03525   /*                                                                       */
03526   static void
03527   Ins_MPPEM( INS_ARG )
03528   {
03529     DO_MPPEM
03530   }
03531 
03532 
03533   /*************************************************************************/
03534   /*                                                                       */
03535   /* MPS[]:        Measure Point Size                                      */
03536   /* Opcode range: 0x4C                                                    */
03537   /* Stack:        --> Euint16                                             */
03538   /*                                                                       */
03539   static void
03540   Ins_MPS( INS_ARG )
03541   {
03542     DO_MPS
03543   }
03544 
03545 
03546   /*************************************************************************/
03547   /*                                                                       */
03548   /* DUP[]:        DUPlicate the top stack's element                       */
03549   /* Opcode range: 0x20                                                    */
03550   /* Stack:        StkElt --> StkElt StkElt                                */
03551   /*                                                                       */
03552   static void
03553   Ins_DUP( INS_ARG )
03554   {
03555     DO_DUP
03556   }
03557 
03558 
03559   /*************************************************************************/
03560   /*                                                                       */
03561   /* POP[]:        POP the stack's top element                             */
03562   /* Opcode range: 0x21                                                    */
03563   /* Stack:        StkElt -->                                              */
03564   /*                                                                       */
03565   static void
03566   Ins_POP( INS_ARG )
03567   {
03568     /* nothing to do */
03569   }
03570 
03571 
03572   /*************************************************************************/
03573   /*                                                                       */
03574   /* CLEAR[]:      CLEAR the entire stack                                  */
03575   /* Opcode range: 0x22                                                    */
03576   /* Stack:        StkElt... -->                                           */
03577   /*                                                                       */
03578   static void
03579   Ins_CLEAR( INS_ARG )
03580   {
03581     DO_CLEAR
03582   }
03583 
03584 
03585   /*************************************************************************/
03586   /*                                                                       */
03587   /* SWAP[]:       SWAP the stack's top two elements                       */
03588   /* Opcode range: 0x23                                                    */
03589   /* Stack:        2 * StkElt --> 2 * StkElt                               */
03590   /*                                                                       */
03591   static void
03592   Ins_SWAP( INS_ARG )
03593   {
03594     DO_SWAP
03595   }
03596 
03597 
03598   /*************************************************************************/
03599   /*                                                                       */
03600   /* DEPTH[]:      return the stack DEPTH                                  */
03601   /* Opcode range: 0x24                                                    */
03602   /* Stack:        --> uint32                                              */
03603   /*                                                                       */
03604   static void
03605   Ins_DEPTH( INS_ARG )
03606   {
03607     DO_DEPTH
03608   }
03609 
03610 
03611   /*************************************************************************/
03612   /*                                                                       */
03613   /* CINDEX[]:     Copy INDEXed element                                    */
03614   /* Opcode range: 0x25                                                    */
03615   /* Stack:        int32 --> StkElt                                        */
03616   /*                                                                       */
03617   static void
03618   Ins_CINDEX( INS_ARG )
03619   {
03620     DO_CINDEX
03621   }
03622 
03623 
03624   /*************************************************************************/
03625   /*                                                                       */
03626   /* EIF[]:        End IF                                                  */
03627   /* Opcode range: 0x59                                                    */
03628   /* Stack:        -->                                                     */
03629   /*                                                                       */
03630   static void
03631   Ins_EIF( INS_ARG )
03632   {
03633     /* nothing to do */
03634   }
03635 
03636 
03637   /*************************************************************************/
03638   /*                                                                       */
03639   /* JROT[]:       Jump Relative On True                                   */
03640   /* Opcode range: 0x78                                                    */
03641   /* Stack:        StkElt int32 -->                                        */
03642   /*                                                                       */
03643   static void
03644   Ins_JROT( INS_ARG )
03645   {
03646     DO_JROT
03647   }
03648 
03649 
03650   /*************************************************************************/
03651   /*                                                                       */
03652   /* JMPR[]:       JuMP Relative                                           */
03653   /* Opcode range: 0x1C                                                    */
03654   /* Stack:        int32 -->                                               */
03655   /*                                                                       */
03656   static void
03657   Ins_JMPR( INS_ARG )
03658   {
03659     DO_JMPR
03660   }
03661 
03662 
03663   /*************************************************************************/
03664   /*                                                                       */
03665   /* JROF[]:       Jump Relative On False                                  */
03666   /* Opcode range: 0x79                                                    */
03667   /* Stack:        StkElt int32 -->                                        */
03668   /*                                                                       */
03669   static void
03670   Ins_JROF( INS_ARG )
03671   {
03672     DO_JROF
03673   }
03674 
03675 
03676   /*************************************************************************/
03677   /*                                                                       */
03678   /* LT[]:         Less Than                                               */
03679   /* Opcode range: 0x50                                                    */
03680   /* Stack:        int32? int32? --> bool                                  */
03681   /*                                                                       */
03682   static void
03683   Ins_LT( INS_ARG )
03684   {
03685     DO_LT
03686   }
03687 
03688 
03689   /*************************************************************************/
03690   /*                                                                       */
03691   /* LTEQ[]:       Less Than or EQual                                      */
03692   /* Opcode range: 0x51                                                    */
03693   /* Stack:        int32? int32? --> bool                                  */
03694   /*                                                                       */
03695   static void
03696   Ins_LTEQ( INS_ARG )
03697   {
03698     DO_LTEQ
03699   }
03700 
03701 
03702   /*************************************************************************/
03703   /*                                                                       */
03704   /* GT[]:         Greater Than                                            */
03705   /* Opcode range: 0x52                                                    */
03706   /* Stack:        int32? int32? --> bool                                  */
03707   /*                                                                       */
03708   static void
03709   Ins_GT( INS_ARG )
03710   {
03711     DO_GT
03712   }
03713 
03714 
03715   /*************************************************************************/
03716   /*                                                                       */
03717   /* GTEQ[]:       Greater Than or EQual                                   */
03718   /* Opcode range: 0x53                                                    */
03719   /* Stack:        int32? int32? --> bool                                  */
03720   /*                                                                       */
03721   static void
03722   Ins_GTEQ( INS_ARG )
03723   {
03724     DO_GTEQ
03725   }
03726 
03727 
03728   /*************************************************************************/
03729   /*                                                                       */
03730   /* EQ[]:         EQual                                                   */
03731   /* Opcode range: 0x54                                                    */
03732   /* Stack:        StkElt StkElt --> bool                                  */
03733   /*                                                                       */
03734   static void
03735   Ins_EQ( INS_ARG )
03736   {
03737     DO_EQ
03738   }
03739 
03740 
03741   /*************************************************************************/
03742   /*                                                                       */
03743   /* NEQ[]:        Not EQual                                               */
03744   /* Opcode range: 0x55                                                    */
03745   /* Stack:        StkElt StkElt --> bool                                  */
03746   /*                                                                       */
03747   static void
03748   Ins_NEQ( INS_ARG )
03749   {
03750     DO_NEQ
03751   }
03752 
03753 
03754   /*************************************************************************/
03755   /*                                                                       */
03756   /* ODD[]:        Is ODD                                                  */
03757   /* Opcode range: 0x56                                                    */
03758   /* Stack:        f26.6 --> bool                                          */
03759   /*                                                                       */
03760   static void
03761   Ins_ODD( INS_ARG )
03762   {
03763     DO_ODD
03764   }
03765 
03766 
03767   /*************************************************************************/
03768   /*                                                                       */
03769   /* EVEN[]:       Is EVEN                                                 */
03770   /* Opcode range: 0x57                                                    */
03771   /* Stack:        f26.6 --> bool                                          */
03772   /*                                                                       */
03773   static void
03774   Ins_EVEN( INS_ARG )
03775   {
03776     DO_EVEN
03777   }
03778 
03779 
03780   /*************************************************************************/
03781   /*                                                                       */
03782   /* AND[]:        logical AND                                             */
03783   /* Opcode range: 0x5A                                                    */
03784   /* Stack:        uint32 uint32 --> uint32                                */
03785   /*                                                                       */
03786   static void
03787   Ins_AND( INS_ARG )
03788   {
03789     DO_AND
03790   }
03791 
03792 
03793   /*************************************************************************/
03794   /*                                                                       */
03795   /* OR[]:         logical OR                                              */
03796   /* Opcode range: 0x5B                                                    */
03797   /* Stack:        uint32 uint32 --> uint32                                */
03798   /*                                                                       */
03799   static void
03800   Ins_OR( INS_ARG )
03801   {
03802     DO_OR
03803   }
03804 
03805 
03806   /*************************************************************************/
03807   /*                                                                       */
03808   /* NOT[]:        logical NOT                                             */
03809   /* Opcode range: 0x5C                                                    */
03810   /* Stack:        StkElt --> uint32                                       */
03811   /*                                                                       */
03812   static void
03813   Ins_NOT( INS_ARG )
03814   {
03815     DO_NOT
03816   }
03817 
03818 
03819   /*************************************************************************/
03820   /*                                                                       */
03821   /* ADD[]:        ADD                                                     */
03822   /* Opcode range: 0x60                                                    */
03823   /* Stack:        f26.6 f26.6 --> f26.6                                   */
03824   /*                                                                       */
03825   static void
03826   Ins_ADD( INS_ARG )
03827   {
03828     DO_ADD
03829   }
03830 
03831 
03832   /*************************************************************************/
03833   /*                                                                       */
03834   /* SUB[]:        SUBtract                                                */
03835   /* Opcode range: 0x61                                                    */
03836   /* Stack:        f26.6 f26.6 --> f26.6                                   */
03837   /*                                                                       */
03838   static void
03839   Ins_SUB( INS_ARG )
03840   {
03841     DO_SUB
03842   }
03843 
03844 
03845   /*************************************************************************/
03846   /*                                                                       */
03847   /* DIV[]:        DIVide                                                  */
03848   /* Opcode range: 0x62                                                    */
03849   /* Stack:        f26.6 f26.6 --> f26.6                                   */
03850   /*                                                                       */
03851   static void
03852   Ins_DIV( INS_ARG )
03853   {
03854     DO_DIV
03855   }
03856 
03857 
03858   /*************************************************************************/
03859   /*                                                                       */
03860   /* MUL[]:        MULtiply                                                */
03861   /* Opcode range: 0x63                                                    */
03862   /* Stack:        f26.6 f26.6 --> f26.6                                   */
03863   /*                                                                       */
03864   static void
03865   Ins_MUL( INS_ARG )
03866   {
03867     DO_MUL
03868   }
03869 
03870 
03871   /*************************************************************************/
03872   /*                                                                       */
03873   /* ABS[]:        ABSolute value                                          */
03874   /* Opcode range: 0x64                                                    */
03875   /* Stack:        f26.6 --> f26.6                                         */
03876   /*                                                                       */
03877   static void
03878   Ins_ABS( INS_ARG )
03879   {
03880     DO_ABS
03881   }
03882 
03883 
03884   /*************************************************************************/
03885   /*                                                                       */
03886   /* NEG[]:        NEGate                                                  */
03887   /* Opcode range: 0x65                                                    */
03888   /* Stack: f26.6 --> f26.6                                                */
03889   /*                                                                       */
03890   static void
03891   Ins_NEG( INS_ARG )
03892   {
03893     DO_NEG
03894   }
03895 
03896 
03897   /*************************************************************************/
03898   /*                                                                       */
03899   /* FLOOR[]:      FLOOR                                                   */
03900   /* Opcode range: 0x66                                                    */
03901   /* Stack:        f26.6 --> f26.6                                         */
03902   /*                                                                       */
03903   static void
03904   Ins_FLOOR( INS_ARG )
03905   {
03906     DO_FLOOR
03907   }
03908 
03909 
03910   /*************************************************************************/
03911   /*                                                                       */
03912   /* CEILING[]:    CEILING                                                 */
03913   /* Opcode range: 0x67                                                    */
03914   /* Stack:        f26.6 --> f26.6                                         */
03915   /*                                                                       */
03916   static void
03917   Ins_CEILING( INS_ARG )
03918   {
03919     DO_CEILING
03920   }
03921 
03922 
03923   /*************************************************************************/
03924   /*                                                                       */
03925   /* RS[]:         Read Store                                              */
03926   /* Opcode range: 0x43                                                    */
03927   /* Stack:        uint32 --> uint32                                       */
03928   /*                                                                       */
03929   static void
03930   Ins_RS( INS_ARG )
03931   {
03932     DO_RS
03933   }
03934 
03935 
03936   /*************************************************************************/
03937   /*                                                                       */
03938   /* WS[]:         Write Store                                             */
03939   /* Opcode range: 0x42                                                    */
03940   /* Stack:        uint32 uint32 -->                                       */
03941   /*                                                                       */
03942   static void
03943   Ins_WS( INS_ARG )
03944   {
03945     DO_WS
03946   }
03947 
03948 
03949   /*************************************************************************/
03950   /*                                                                       */
03951   /* WCVTP[]:      Write CVT in Pixel units                                */
03952   /* Opcode range: 0x44                                                    */
03953   /* Stack:        f26.6 uint32 -->                                        */
03954   /*                                                                       */
03955   static void
03956   Ins_WCVTP( INS_ARG )
03957   {
03958     DO_WCVTP
03959   }
03960 
03961 
03962   /*************************************************************************/
03963   /*                                                                       */
03964   /* WCVTF[]:      Write CVT in Funits                                     */
03965   /* Opcode range: 0x70                                                    */
03966   /* Stack:        uint32 uint32 -->                                       */
03967   /*                                                                       */
03968   static void
03969   Ins_WCVTF( INS_ARG )
03970   {
03971     DO_WCVTF
03972   }
03973 
03974 
03975   /*************************************************************************/
03976   /*                                                                       */
03977   /* RCVT[]:       Read CVT                                                */
03978   /* Opcode range: 0x45                                                    */
03979   /* Stack:        uint32 --> f26.6                                        */
03980   /*                                                                       */
03981   static void
03982   Ins_RCVT( INS_ARG )
03983   {
03984     DO_RCVT
03985   }
03986 
03987 
03988   /*************************************************************************/
03989   /*                                                                       */
03990   /* AA[]:         Adjust Angle                                            */
03991   /* Opcode range: 0x7F                                                    */
03992   /* Stack:        uint32 -->                                              */
03993   /*                                                                       */
03994   static void
03995   Ins_AA( INS_ARG )
03996   {
03997     /* intentionally no longer supported */
03998   }
03999 
04000 
04001   /*************************************************************************/
04002   /*                                                                       */
04003   /* DEBUG[]:      DEBUG.  Unsupported.                                    */
04004   /* Opcode range: 0x4F                                                    */
04005   /* Stack:        uint32 -->                                              */
04006   /*                                                                       */
04007   /* Note: The original instruction pops a value from the stack.           */
04008   /*                                                                       */
04009   static void
04010   Ins_DEBUG( INS_ARG )
04011   {
04012     DO_DEBUG
04013   }
04014 
04015 
04016   /*************************************************************************/
04017   /*                                                                       */
04018   /* ROUND[ab]:    ROUND value                                             */
04019   /* Opcode range: 0x68-0x6B                                               */
04020   /* Stack:        f26.6 --> f26.6                                         */
04021   /*                                                                       */
04022   static void
04023   Ins_ROUND( INS_ARG )
04024   {
04025     DO_ROUND
04026   }
04027 
04028 
04029   /*************************************************************************/
04030   /*                                                                       */
04031   /* NROUND[ab]:   No ROUNDing of value                                    */
04032   /* Opcode range: 0x6C-0x6F                                               */
04033   /* Stack:        f26.6 --> f26.6                                         */
04034   /*                                                                       */
04035   static void
04036   Ins_NROUND( INS_ARG )
04037   {
04038     DO_NROUND
04039   }
04040 
04041 
04042   /*************************************************************************/
04043   /*                                                                       */
04044   /* MAX[]:        MAXimum                                                 */
04045   /* Opcode range: 0x68                                                    */
04046   /* Stack:        int32? int32? --> int32                                 */
04047   /*                                                                       */
04048   static void
04049   Ins_MAX( INS_ARG )
04050   {
04051     DO_MAX
04052   }
04053 
04054 
04055   /*************************************************************************/
04056   /*                                                                       */
04057   /* MIN[]:        MINimum                                                 */
04058   /* Opcode range: 0x69                                                    */
04059   /* Stack:        int32? int32? --> int32                                 */
04060   /*                                                                       */
04061   static void
04062   Ins_MIN( INS_ARG )
04063   {
04064     DO_MIN
04065   }
04066 
04067 
04068 #endif  /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
04069 
04070 
04071   /*************************************************************************/
04072   /*                                                                       */
04073   /* The following functions are called as is within the switch statement. */
04074   /*                                                                       */
04075   /*************************************************************************/
04076 
04077 
04078   /*************************************************************************/
04079   /*                                                                       */
04080   /* MINDEX[]:     Move INDEXed element                                    */
04081   /* Opcode range: 0x26                                                    */
04082   /* Stack:        int32? --> StkElt                                       */
04083   /*                                                                       */
04084   static void
04085   Ins_MINDEX( INS_ARG )
04086   {
04087     FT_Long  L, K;
04088 
04089 
04090     L = args[0];
04091 
04092     if ( L <= 0 || L > CUR.args )
04093     {
04094       CUR.error = TT_Err_Invalid_Reference;
04095       return;
04096     }
04097 
04098     K = CUR.stack[CUR.args - L];
04099 
04100     FT_ARRAY_MOVE( &CUR.stack[CUR.args - L    ],
04101                    &CUR.stack[CUR.args - L + 1],
04102                    ( L - 1 ) );
04103 
04104     CUR.stack[CUR.args - 1] = K;
04105   }
04106 
04107 
04108   /*************************************************************************/
04109   /*                                                                       */
04110   /* ROLL[]:       ROLL top three elements                                 */
04111   /* Opcode range: 0x8A                                                    */
04112   /* Stack:        3 * StkElt --> 3 * StkElt                               */
04113   /*                                                                       */
04114   static void
04115   Ins_ROLL( INS_ARG )
04116   {
04117     FT_Long  A, B, C;
04118 
04119     FT_UNUSED_EXEC;
04120 
04121 
04122     A = args[2];
04123     B = args[1];
04124     C = args[0];
04125 
04126     args[2] = C;
04127     args[1] = A;
04128     args[0] = B;
04129   }
04130 
04131 
04132   /*************************************************************************/
04133   /*                                                                       */
04134   /* MANAGING THE FLOW OF CONTROL                                          */
04135   /*                                                                       */
04136   /*   Instructions appear in the specification's order.                   */
04137   /*                                                                       */
04138   /*************************************************************************/
04139 
04140 
04141   static FT_Bool
04142   SkipCode( EXEC_OP )
04143   {
04144     CUR.IP += CUR.length;
04145 
04146     if ( CUR.IP < CUR.codeSize )
04147     {
04148       CUR.opcode = CUR.code[CUR.IP];
04149 
04150       CUR.length = opcode_length[CUR.opcode];
04151       if ( CUR.length < 0 )
04152       {
04153         if ( CUR.IP + 1 > CUR.codeSize )
04154           goto Fail_Overflow;
04155         CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
04156       }
04157 
04158       if ( CUR.IP + CUR.length <= CUR.codeSize )
04159         return SUCCESS;
04160     }
04161 
04162   Fail_Overflow:
04163     CUR.error = TT_Err_Code_Overflow;
04164     return FAILURE;
04165   }
04166 
04167 
04168   /*************************************************************************/
04169   /*                                                                       */
04170   /* IF[]:         IF test                                                 */
04171   /* Opcode range: 0x58                                                    */
04172   /* Stack:        StkElt -->                                              */
04173   /*                                                                       */
04174   static void
04175   Ins_IF( INS_ARG )
04176   {
04177     FT_Int   nIfs;
04178     FT_Bool  Out;
04179 
04180 
04181     if ( args[0] != 0 )
04182       return;
04183 
04184     nIfs = 1;
04185     Out = 0;
04186 
04187     do
04188     {
04189       if ( SKIP_Code() == FAILURE )
04190         return;
04191 
04192       switch ( CUR.opcode )
04193       {
04194       case 0x58:      /* IF */
04195         nIfs++;
04196         break;
04197 
04198       case 0x1B:      /* ELSE */
04199         Out = FT_BOOL( nIfs == 1 );
04200         break;
04201 
04202       case 0x59:      /* EIF */
04203         nIfs--;
04204         Out = FT_BOOL( nIfs == 0 );
04205         break;
04206       }
04207     } while ( Out == 0 );
04208   }
04209 
04210 
04211   /*************************************************************************/
04212   /*                                                                       */
04213   /* ELSE[]:       ELSE                                                    */
04214   /* Opcode range: 0x1B                                                    */
04215   /* Stack:        -->                                                     */
04216   /*                                                                       */
04217   static void
04218   Ins_ELSE( INS_ARG )
04219   {
04220     FT_Int  nIfs;
04221 
04222     FT_UNUSED_ARG;
04223 
04224 
04225     nIfs = 1;
04226 
04227     do
04228     {
04229       if ( SKIP_Code() == FAILURE )
04230         return;
04231 
04232       switch ( CUR.opcode )
04233       {
04234       case 0x58:    /* IF */
04235         nIfs++;
04236         break;
04237 
04238       case 0x59:    /* EIF */
04239         nIfs--;
04240         break;
04241       }
04242     } while ( nIfs != 0 );
04243   }
04244 
04245 
04246   /*************************************************************************/
04247   /*                                                                       */
04248   /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS                         */
04249   /*                                                                       */
04250   /*   Instructions appear in the specification's order.                   */
04251   /*                                                                       */
04252   /*************************************************************************/
04253 
04254 
04255   /*************************************************************************/
04256   /*                                                                       */
04257   /* FDEF[]:       Function DEFinition                                     */
04258   /* Opcode range: 0x2C                                                    */
04259   /* Stack:        uint32 -->                                              */
04260   /*                                                                       */
04261   static void
04262   Ins_FDEF( INS_ARG )
04263   {
04264     FT_ULong       n;
04265     TT_DefRecord*  rec;
04266     TT_DefRecord*  limit;
04267 
04268 
04269     /* some font programs are broken enough to redefine functions! */
04270     /* We will then parse the current table.                       */
04271 
04272     rec   = CUR.FDefs;
04273     limit = rec + CUR.numFDefs;
04274     n     = args[0];
04275 
04276     for ( ; rec < limit; rec++ )
04277     {
04278       if ( rec->opc == n )
04279         break;
04280     }
04281 
04282     if ( rec == limit )
04283     {
04284       /* check that there is enough room for new functions */
04285       if ( CUR.numFDefs >= CUR.maxFDefs )
04286       {
04287         CUR.error = TT_Err_Too_Many_Function_Defs;
04288         return;
04289       }
04290       CUR.numFDefs++;
04291     }
04292 
04293     /* Although FDEF takes unsigned 32-bit integer,  */
04294     /* func # must be within unsigned 16-bit integer */
04295     if ( n > 0xFFFFU )
04296     {
04297       CUR.error = TT_Err_Too_Many_Function_Defs;
04298       return;
04299     }
04300 
04301     rec->range  = CUR.curRange;
04302     rec->opc    = (FT_UInt16)n;
04303     rec->start  = CUR.IP + 1;
04304     rec->active = TRUE;
04305 
04306     if ( n > CUR.maxFunc )
04307       CUR.maxFunc = (FT_UInt16)n;
04308 
04309     /* Now skip the whole function definition. */
04310     /* We don't allow nested IDEFS & FDEFs.    */
04311 
04312     while ( SKIP_Code() == SUCCESS )
04313     {
04314       switch ( CUR.opcode )
04315       {
04316       case 0x89:    /* IDEF */
04317       case 0x2C:    /* FDEF */
04318         CUR.error = TT_Err_Nested_DEFS;
04319         return;
04320 
04321       case 0x2D:   /* ENDF */
04322         return;
04323       }
04324     }
04325   }
04326 
04327 
04328   /*************************************************************************/
04329   /*                                                                       */
04330   /* ENDF[]:       END Function definition                                 */
04331   /* Opcode range: 0x2D                                                    */
04332   /* Stack:        -->                                                     */
04333   /*                                                                       */
04334   static void
04335   Ins_ENDF( INS_ARG )
04336   {
04337     TT_CallRec*  pRec;
04338 
04339     FT_UNUSED_ARG;
04340 
04341 
04342     if ( CUR.callTop <= 0 )     /* We encountered an ENDF without a call */
04343     {
04344       CUR.error = TT_Err_ENDF_In_Exec_Stream;
04345       return;
04346     }
04347 
04348     CUR.callTop--;
04349 
04350     pRec = &CUR.callStack[CUR.callTop];
04351 
04352     pRec->Cur_Count--;
04353 
04354     CUR.step_ins = FALSE;
04355 
04356     if ( pRec->Cur_Count > 0 )
04357     {
04358       CUR.callTop++;
04359       CUR.IP = pRec->Cur_Restart;
04360     }
04361     else
04362       /* Loop through the current function */
04363       INS_Goto_CodeRange( pRec->Caller_Range,
04364                           pRec->Caller_IP );
04365 
04366     /* Exit the current call frame.                      */
04367 
04368     /* NOTE: If the last instruction of a program is a   */
04369     /*       CALL or LOOPCALL, the return address is     */
04370     /*       always out of the code range.  This is a    */
04371     /*       valid address, and it is why we do not test */
04372     /*       the result of Ins_Goto_CodeRange() here!    */
04373   }
04374 
04375 
04376   /*************************************************************************/
04377   /*                                                                       */
04378   /* CALL[]:       CALL function                                           */
04379   /* Opcode range: 0x2B                                                    */
04380   /* Stack:        uint32? -->                                             */
04381   /*                                                                       */
04382   static void
04383   Ins_CALL( INS_ARG )
04384   {
04385     FT_ULong       F;
04386     TT_CallRec*    pCrec;
04387     TT_DefRecord*  def;
04388 
04389 
04390     /* first of all, check the index */
04391 
04392     F = args[0];
04393     if ( BOUNDS( F, CUR.maxFunc + 1 ) )
04394       goto Fail;
04395 
04396     /* Except for some old Apple fonts, all functions in a TrueType */
04397     /* font are defined in increasing order, starting from 0.  This */
04398     /* means that we normally have                                  */
04399     /*                                                              */
04400     /*    CUR.maxFunc+1 == CUR.numFDefs                             */
04401     /*    CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc             */
04402     /*                                                              */
04403     /* If this isn't true, we need to look up the function table.   */
04404 
04405     def = CUR.FDefs + F;
04406     if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
04407     {
04408       /* look up the FDefs table */
04409       TT_DefRecord*  limit;
04410 
04411 
04412       def   = CUR.FDefs;
04413       limit = def + CUR.numFDefs;
04414 
04415       while ( def < limit && def->opc != F )
04416         def++;
04417 
04418       if ( def == limit )
04419         goto Fail;
04420     }
04421 
04422     /* check that the function is active */
04423     if ( !def->active )
04424       goto Fail;
04425 
04426     /* check the call stack */
04427     if ( CUR.callTop >= CUR.callSize )
04428     {
04429       CUR.error = TT_Err_Stack_Overflow;
04430       return;
04431     }
04432 
04433     pCrec = CUR.callStack + CUR.callTop;
04434 
04435     pCrec->Caller_Range = CUR.curRange;
04436     pCrec->Caller_IP    = CUR.IP + 1;
04437     pCrec->Cur_Count    = 1;
04438     pCrec->Cur_Restart  = def->start;
04439 
04440     CUR.callTop++;
04441 
04442     INS_Goto_CodeRange( def->range,
04443                         def->start );
04444 
04445     CUR.step_ins = FALSE;
04446     return;
04447 
04448   Fail:
04449     CUR.error = TT_Err_Invalid_Reference;
04450   }
04451 
04452 
04453   /*************************************************************************/
04454   /*                                                                       */
04455   /* LOOPCALL[]:   LOOP and CALL function                                  */
04456   /* Opcode range: 0x2A                                                    */
04457   /* Stack:        uint32? Eint16? -->                                     */
04458   /*                                                                       */
04459   static void
04460   Ins_LOOPCALL( INS_ARG )
04461   {
04462     FT_ULong       F;
04463     TT_CallRec*    pCrec;
04464     TT_DefRecord*  def;
04465 
04466 
04467     /* first of all, check the index */
04468     F = args[1];
04469     if ( BOUNDS( F, CUR.maxFunc + 1 ) )
04470       goto Fail;
04471 
04472     /* Except for some old Apple fonts, all functions in a TrueType */
04473     /* font are defined in increasing order, starting from 0.  This */
04474     /* means that we normally have                                  */
04475     /*                                                              */
04476     /*    CUR.maxFunc+1 == CUR.numFDefs                             */
04477     /*    CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc             */
04478     /*                                                              */
04479     /* If this isn't true, we need to look up the function table.   */
04480 
04481     def = CUR.FDefs + F;
04482     if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
04483     {
04484       /* look up the FDefs table */
04485       TT_DefRecord*  limit;
04486 
04487 
04488       def   = CUR.FDefs;
04489       limit = def + CUR.numFDefs;
04490 
04491       while ( def < limit && def->opc != F )
04492         def++;
04493 
04494       if ( def == limit )
04495         goto Fail;
04496     }
04497 
04498     /* check that the function is active */
04499     if ( !def->active )
04500       goto Fail;
04501 
04502     /* check stack */
04503     if ( CUR.callTop >= CUR.callSize )
04504     {
04505       CUR.error = TT_Err_Stack_Overflow;
04506       return;
04507     }
04508 
04509     if ( args[0] > 0 )
04510     {
04511       pCrec = CUR.callStack + CUR.callTop;
04512 
04513       pCrec->Caller_Range = CUR.curRange;
04514       pCrec->Caller_IP    = CUR.IP + 1;
04515       pCrec->Cur_Count    = (FT_Int)args[0];
04516       pCrec->Cur_Restart  = def->start;
04517 
04518       CUR.callTop++;
04519 
04520       INS_Goto_CodeRange( def->range, def->start );
04521 
04522       CUR.step_ins = FALSE;
04523     }
04524     return;
04525 
04526   Fail:
04527     CUR.error = TT_Err_Invalid_Reference;
04528   }
04529 
04530 
04531   /*************************************************************************/
04532   /*                                                                       */
04533   /* IDEF[]:       Instruction DEFinition                                  */
04534   /* Opcode range: 0x89                                                    */
04535   /* Stack:        Eint8 -->                                               */
04536   /*                                                                       */
04537   static void
04538   Ins_IDEF( INS_ARG )
04539   {
04540     TT_DefRecord*  def;
04541     TT_DefRecord*  limit;
04542 
04543 
04544     /*  First of all, look for the same function in our table */
04545 
04546     def   = CUR.IDefs;
04547     limit = def + CUR.numIDefs;
04548 
04549     for ( ; def < limit; def++ )
04550       if ( def->opc == (FT_ULong)args[0] )
04551         break;
04552 
04553     if ( def == limit )
04554     {
04555       /* check that there is enough room for a new instruction */
04556       if ( CUR.numIDefs >= CUR.maxIDefs )
04557       {
04558         CUR.error = TT_Err_Too_Many_Instruction_Defs;
04559         return;
04560       }
04561       CUR.numIDefs++;
04562     }
04563 
04564     /* opcode must be unsigned 8-bit integer */
04565     if ( 0 > args[0] || args[0] > 0x00FF )
04566     {
04567       CUR.error = TT_Err_Too_Many_Instruction_Defs;
04568       return;
04569     }
04570 
04571     def->opc    = (FT_Byte)args[0];
04572     def->start  = CUR.IP+1;
04573     def->range  = CUR.curRange;
04574     def->active = TRUE;
04575 
04576     if ( (FT_ULong)args[0] > CUR.maxIns )
04577       CUR.maxIns = (FT_Byte)args[0];
04578 
04579     /* Now skip the whole function definition. */
04580     /* We don't allow nested IDEFs & FDEFs.    */
04581 
04582     while ( SKIP_Code() == SUCCESS )
04583     {
04584       switch ( CUR.opcode )
04585       {
04586       case 0x89:   /* IDEF */
04587       case 0x2C:   /* FDEF */
04588         CUR.error = TT_Err_Nested_DEFS;
04589         return;
04590       case 0x2D:   /* ENDF */
04591         return;
04592       }
04593     }
04594   }
04595 
04596 
04597   /*************************************************************************/
04598   /*                                                                       */
04599   /* PUSHING DATA ONTO THE INTERPRETER STACK                               */
04600   /*                                                                       */
04601   /*   Instructions appear in the specification's order.                   */
04602   /*                                                                       */
04603   /*************************************************************************/
04604 
04605 
04606   /*************************************************************************/
04607   /*                                                                       */
04608   /* NPUSHB[]:     PUSH N Bytes                                            */
04609   /* Opcode range: 0x40                                                    */
04610   /* Stack:        --> uint32...                                           */
04611   /*                                                                       */
04612   static void
04613   Ins_NPUSHB( INS_ARG )
04614   {
04615     FT_UShort  L, K;
04616 
04617 
04618     L = (FT_UShort)CUR.code[CUR.IP + 1];
04619 
04620     if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
04621     {
04622       CUR.error = TT_Err_Stack_Overflow;
04623       return;
04624     }
04625 
04626     for ( K = 1; K <= L; K++ )
04627       args[K - 1] = CUR.code[CUR.IP + K + 1];
04628 
04629     CUR.new_top += L;
04630   }
04631 
04632 
04633   /*************************************************************************/
04634   /*                                                                       */
04635   /* NPUSHW[]:     PUSH N Words                                            */
04636   /* Opcode range: 0x41                                                    */
04637   /* Stack:        --> int32...                                            */
04638   /*                                                                       */
04639   static void
04640   Ins_NPUSHW( INS_ARG )
04641   {
04642     FT_UShort  L, K;
04643 
04644 
04645     L = (FT_UShort)CUR.code[CUR.IP + 1];
04646 
04647     if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
04648     {
04649       CUR.error = TT_Err_Stack_Overflow;
04650       return;
04651     }
04652 
04653     CUR.IP += 2;
04654 
04655     for ( K = 0; K < L; K++ )
04656       args[K] = GET_ShortIns();
04657 
04658     CUR.step_ins = FALSE;
04659     CUR.new_top += L;
04660   }
04661 
04662 
04663   /*************************************************************************/
04664   /*                                                                       */
04665   /* PUSHB[abc]:   PUSH Bytes                                              */
04666   /* Opcode range: 0xB0-0xB7                                               */
04667   /* Stack:        --> uint32...                                           */
04668   /*                                                                       */
04669   static void
04670   Ins_PUSHB( INS_ARG )
04671   {
04672     FT_UShort  L, K;
04673 
04674 
04675     L = (FT_UShort)( CUR.opcode - 0xB0 + 1 );
04676 
04677     if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
04678     {
04679       CUR.error = TT_Err_Stack_Overflow;
04680       return;
04681     }
04682 
04683     for ( K = 1; K <= L; K++ )
04684       args[K - 1] = CUR.code[CUR.IP + K];
04685   }
04686 
04687 
04688   /*************************************************************************/
04689   /*                                                                       */
04690   /* PUSHW[abc]:   PUSH Words                                              */
04691   /* Opcode range: 0xB8-0xBF                                               */
04692   /* Stack:        --> int32...                                            */
04693   /*                                                                       */
04694   static void
04695   Ins_PUSHW( INS_ARG )
04696   {
04697     FT_UShort  L, K;
04698 
04699 
04700     L = (FT_UShort)( CUR.opcode - 0xB8 + 1 );
04701 
04702     if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
04703     {
04704       CUR.error = TT_Err_Stack_Overflow;
04705       return;
04706     }
04707 
04708     CUR.IP++;
04709 
04710     for ( K = 0; K < L; K++ )
04711       args[K] = GET_ShortIns();
04712 
04713     CUR.step_ins = FALSE;
04714   }
04715 
04716 
04717   /*************************************************************************/
04718   /*                                                                       */
04719   /* MANAGING THE GRAPHICS STATE                                           */
04720   /*                                                                       */
04721   /*  Instructions appear in the specs' order.                             */
04722   /*                                                                       */
04723   /*************************************************************************/
04724 
04725 
04726   /*************************************************************************/
04727   /*                                                                       */
04728   /* GC[a]:        Get Coordinate projected onto                           */
04729   /* Opcode range: 0x46-0x47                                               */
04730   /* Stack:        uint32 --> f26.6                                        */
04731   /*                                                                       */
04732   /* BULLSHIT: Measures from the original glyph must be taken along the    */
04733   /*           dual projection vector!                                     */
04734   /*                                                                       */
04735   static void
04736   Ins_GC( INS_ARG )
04737   {
04738     FT_ULong    L;
04739     FT_F26Dot6  R;
04740 
04741 
04742     L = (FT_ULong)args[0];
04743 
04744     if ( BOUNDS( L, CUR.zp2.n_points ) )
04745     {
04746       if ( CUR.pedantic_hinting )
04747       {
04748         CUR.error = TT_Err_Invalid_Reference;
04749         return;
04750       }
04751       else
04752         R = 0;
04753     }
04754     else
04755     {
04756       if ( CUR.opcode & 1 )
04757         R = CUR_fast_dualproj( &CUR.zp2.org[L] );
04758       else
04759         R = CUR_fast_project( &CUR.zp2.cur[L] );
04760     }
04761 
04762     args[0] = R;
04763   }
04764 
04765 
04766   /*************************************************************************/
04767   /*                                                                       */
04768   /* SCFS[]:       Set Coordinate From Stack                               */
04769   /* Opcode range: 0x48                                                    */
04770   /* Stack:        f26.6 uint32 -->                                        */
04771   /*                                                                       */
04772   /* Formula:                                                              */
04773   /*                                                                       */
04774   /*   OA := OA + ( value - OA.p )/( f.p ) * f                             */
04775   /*                                                                       */
04776   static void
04777   Ins_SCFS( INS_ARG )
04778   {
04779     FT_Long    K;
04780     FT_UShort  L;
04781 
04782 
04783     L = (FT_UShort)args[0];
04784 
04785     if ( BOUNDS( L, CUR.zp2.n_points ) )
04786     {
04787       if ( CUR.pedantic_hinting )
04788         CUR.error = TT_Err_Invalid_Reference;
04789       return;
04790     }
04791 
04792     K = CUR_fast_project( &CUR.zp2.cur[L] );
04793 
04794     CUR_Func_move( &CUR.zp2, L, args[1] - K );
04795 
04796     /* not part of the specs, but here for safety */
04797 
04798     if ( CUR.GS.gep2 == 0 )
04799       CUR.zp2.org[L] = CUR.zp2.cur[L];
04800   }
04801 
04802 
04803   /*************************************************************************/
04804   /*                                                                       */
04805   /* MD[a]:        Measure Distance                                        */
04806   /* Opcode range: 0x49-0x4A                                               */
04807   /* Stack:        uint32 uint32 --> f26.6                                 */
04808   /*                                                                       */
04809   /* BULLSHIT: Measure taken in the original glyph must be along the dual  */
04810   /*           projection vector.                                          */
04811   /*                                                                       */
04812   /* Second BULLSHIT: Flag attributes are inverted!                        */
04813   /*                  0 => measure distance in original outline            */
04814   /*                  1 => measure distance in grid-fitted outline         */
04815   /*                                                                       */
04816   /* Third one: `zp0 - zp1', and not `zp2 - zp1!                           */
04817   /*                                                                       */
04818   static void
04819   Ins_MD( INS_ARG )
04820   {
04821     FT_UShort   K, L;
04822     FT_F26Dot6  D;
04823 
04824 
04825     K = (FT_UShort)args[1];
04826     L = (FT_UShort)args[0];
04827 
04828     if( BOUNDS( L, CUR.zp0.n_points ) ||
04829         BOUNDS( K, CUR.zp1.n_points ) )
04830     {
04831       if ( CUR.pedantic_hinting )
04832       {
04833         CUR.error = TT_Err_Invalid_Reference;
04834         return;
04835       }
04836       D = 0;
04837     }
04838     else
04839     {
04840       if ( CUR.opcode & 1 )
04841         D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
04842       else
04843       {
04844         FT_Vector*  vec1 = CUR.zp0.orus + L;
04845         FT_Vector*  vec2 = CUR.zp1.orus + K;
04846 
04847 
04848         if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
04849         {
04850           /* this should be faster */
04851           D = CUR_Func_dualproj( vec1, vec2 );
04852           D = TT_MULFIX( D, CUR.metrics.x_scale );
04853         }
04854         else
04855         {
04856           FT_Vector  vec;
04857 
04858 
04859           vec.x = TT_MULFIX( vec1->x - vec2->x, CUR.metrics.x_scale );
04860           vec.y = TT_MULFIX( vec1->y - vec2->y, CUR.metrics.y_scale );
04861 
04862           D = CUR_fast_dualproj( &vec );
04863         }
04864       }
04865     }
04866 
04867     args[0] = D;
04868   }
04869 
04870 
04871   /*************************************************************************/
04872   /*                                                                       */
04873   /* SDPVTL[a]:    Set Dual PVector to Line                                */
04874   /* Opcode range: 0x86-0x87                                               */
04875   /* Stack:        uint32 uint32 -->                                       */
04876   /*                                                                       */
04877   static void
04878   Ins_SDPVTL( INS_ARG )
04879   {
04880     FT_Long    A, B, C;
04881     FT_UShort  p1, p2;   /* was FT_Int in pas type ERROR */
04882 
04883 
04884     p1 = (FT_UShort)args[1];
04885     p2 = (FT_UShort)args[0];
04886 
04887     if ( BOUNDS( p2, CUR.zp1.n_points ) ||
04888          BOUNDS( p1, CUR.zp2.n_points ) )
04889     {
04890       if ( CUR.pedantic_hinting )
04891         CUR.error = TT_Err_Invalid_Reference;
04892       return;
04893     }
04894 
04895     {
04896       FT_Vector* v1 = CUR.zp1.org + p2;
04897       FT_Vector* v2 = CUR.zp2.org + p1;
04898 
04899 
04900       A = v1->x - v2->x;
04901       B = v1->y - v2->y;
04902     }
04903 
04904     if ( ( CUR.opcode & 1 ) != 0 )
04905     {
04906       C =  B;   /* counter clockwise rotation */
04907       B =  A;
04908       A = -C;
04909     }
04910 
04911     NORMalize( A, B, &CUR.GS.dualVector );
04912 
04913     {
04914       FT_Vector*  v1 = CUR.zp1.cur + p2;
04915       FT_Vector*  v2 = CUR.zp2.cur + p1;
04916 
04917 
04918       A = v1->x - v2->x;
04919       B = v1->y - v2->y;
04920     }
04921 
04922     if ( ( CUR.opcode & 1 ) != 0 )
04923     {
04924       C =  B;   /* counter clockwise rotation */
04925       B =  A;
04926       A = -C;
04927     }
04928 
04929     NORMalize( A, B, &CUR.GS.projVector );
04930 
04931     GUESS_VECTOR( freeVector );
04932 
04933     COMPUTE_Funcs();
04934   }
04935 
04936 
04937   /*************************************************************************/
04938   /*                                                                       */
04939   /* SZP0[]:       Set Zone Pointer 0                                      */
04940   /* Opcode range: 0x13                                                    */
04941   /* Stack:        uint32 -->                                              */
04942   /*                                                                       */
04943   static void
04944   Ins_SZP0( INS_ARG )
04945   {
04946     switch ( (FT_Int)args[0] )
04947     {
04948     case 0:
04949       CUR.zp0 = CUR.twilight;
04950       break;
04951 
04952     case 1:
04953       CUR.zp0 = CUR.pts;
04954       break;
04955 
04956     default:
04957       if ( CUR.pedantic_hinting )
04958         CUR.error = TT_Err_Invalid_Reference;
04959       return;
04960     }
04961 
04962     CUR.GS.gep0 = (FT_UShort)args[0];
04963   }
04964 
04965 
04966   /*************************************************************************/
04967   /*                                                                       */
04968   /* SZP1[]:       Set Zone Pointer 1                                      */
04969   /* Opcode range: 0x14                                                    */
04970   /* Stack:        uint32 -->                                              */
04971   /*                                                                       */
04972   static void
04973   Ins_SZP1( INS_ARG )
04974   {
04975     switch ( (FT_Int)args[0] )
04976     {
04977     case 0:
04978       CUR.zp1 = CUR.twilight;
04979       break;
04980 
04981     case 1:
04982       CUR.zp1 = CUR.pts;
04983       break;
04984 
04985     default:
04986       if ( CUR.pedantic_hinting )
04987         CUR.error = TT_Err_Invalid_Reference;
04988       return;
04989     }
04990 
04991     CUR.GS.gep1 = (FT_UShort)args[0];
04992   }
04993 
04994 
04995   /*************************************************************************/
04996   /*                                                                       */
04997   /* SZP2[]:       Set Zone Pointer 2                                      */
04998   /* Opcode range: 0x15                                                    */
04999   /* Stack:        uint32 -->                                              */
05000   /*                                                                       */
05001   static void
05002   Ins_SZP2( INS_ARG )
05003   {
05004     switch ( (FT_Int)args[0] )
05005     {
05006     case 0:
05007       CUR.zp2 = CUR.twilight;
05008       break;
05009 
05010     case 1:
05011       CUR.zp2 = CUR.pts;
05012       break;
05013 
05014     default:
05015       if ( CUR.pedantic_hinting )
05016         CUR.error = TT_Err_Invalid_Reference;
05017       return;
05018     }
05019 
05020     CUR.GS.gep2 = (FT_UShort)args[0];
05021   }
05022 
05023 
05024   /*************************************************************************/
05025   /*                                                                       */
05026   /* SZPS[]:       Set Zone PointerS                                       */
05027   /* Opcode range: 0x16                                                    */
05028   /* Stack:        uint32 -->                                              */
05029   /*                                                                       */
05030   static void
05031   Ins_SZPS( INS_ARG )
05032   {
05033     switch ( (FT_Int)args[0] )
05034     {
05035     case 0:
05036       CUR.zp0 = CUR.twilight;
05037       break;
05038 
05039     case 1:
05040       CUR.zp0 = CUR.pts;
05041       break;
05042 
05043     default:
05044       if ( CUR.pedantic_hinting )
05045         CUR.error = TT_Err_Invalid_Reference;
05046       return;
05047     }
05048 
05049     CUR.zp1 = CUR.zp0;
05050     CUR.zp2 = CUR.zp0;
05051 
05052     CUR.GS.gep0 = (FT_UShort)args[0];
05053     CUR.GS.gep1 = (FT_UShort)args[0];
05054     CUR.GS.gep2 = (FT_UShort)args[0];
05055   }
05056 
05057 
05058   /*************************************************************************/
05059   /*                                                                       */
05060   /* INSTCTRL[]:   INSTruction ConTRoL                                     */
05061   /* Opcode range: 0x8e                                                    */
05062   /* Stack:        int32 int32 -->                                         */
05063   /*                                                                       */
05064   static void
05065   Ins_INSTCTRL( INS_ARG )
05066   {
05067     FT_Long  K, L;
05068 
05069 
05070     K = args[1];
05071     L = args[0];
05072 
05073     if ( K < 1 || K > 2 )
05074     {
05075       if ( CUR.pedantic_hinting )
05076         CUR.error = TT_Err_Invalid_Reference;
05077       return;
05078     }
05079 
05080     if ( L != 0 )
05081         L = K;
05082 
05083     CUR.GS.instruct_control = FT_BOOL(
05084       ( (FT_Byte)CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L );
05085   }
05086 
05087 
05088   /*************************************************************************/
05089   /*                                                                       */
05090   /* SCANCTRL[]:   SCAN ConTRoL                                            */
05091   /* Opcode range: 0x85                                                    */
05092   /* Stack:        uint32? -->                                             */
05093   /*                                                                       */
05094   static void
05095   Ins_SCANCTRL( INS_ARG )
05096   {
05097     FT_Int  A;
05098 
05099 
05100     /* Get Threshold */
05101     A = (FT_Int)( args[0] & 0xFF );
05102 
05103     if ( A == 0xFF )
05104     {
05105       CUR.GS.scan_control = TRUE;
05106       return;
05107     }
05108     else if ( A == 0 )
05109     {
05110       CUR.GS.scan_control = FALSE;
05111       return;
05112     }
05113 
05114     if ( ( args[0] & 0x100 ) != 0 && CUR.tt_metrics.ppem <= A )
05115       CUR.GS.scan_control = TRUE;
05116 
05117     if ( ( args[0] & 0x200 ) != 0 && CUR.tt_metrics.rotated )
05118       CUR.GS.scan_control = TRUE;
05119 
05120     if ( ( args[0] & 0x400 ) != 0 && CUR.tt_metrics.stretched )
05121       CUR.GS.scan_control = TRUE;
05122 
05123     if ( ( args[0] & 0x800 ) != 0 && CUR.tt_metrics.ppem > A )
05124       CUR.GS.scan_control = FALSE;
05125 
05126     if ( ( args[0] & 0x1000 ) != 0 && CUR.tt_metrics.rotated )
05127       CUR.GS.scan_control = FALSE;
05128 
05129     if ( ( args[0] & 0x2000 ) != 0 && CUR.tt_metrics.stretched )
05130       CUR.GS.scan_control = FALSE;
05131   }
05132 
05133 
05134   /*************************************************************************/
05135   /*                                                                       */
05136   /* SCANTYPE[]:   SCAN TYPE                                               */
05137   /* Opcode range: 0x8D                                                    */
05138   /* Stack:        uint32? -->                                             */
05139   /*                                                                       */
05140   static void
05141   Ins_SCANTYPE( INS_ARG )
05142   {
05143     if ( args[0] >= 0 )
05144       CUR.GS.scan_type = (FT_Int)args[0];
05145   }
05146 
05147 
05148   /*************************************************************************/
05149   /*                                                                       */
05150   /* MANAGING OUTLINES                                                     */
05151   /*                                                                       */
05152   /*   Instructions appear in the specification's order.                   */
05153   /*                                                                       */
05154   /*************************************************************************/
05155 
05156 
05157   /*************************************************************************/
05158   /*                                                                       */
05159   /* FLIPPT[]:     FLIP PoinT                                              */
05160   /* Opcode range: 0x80                                                    */
05161   /* Stack:        uint32... -->                                           */
05162   /*                                                                       */
05163   static void
05164   Ins_FLIPPT( INS_ARG )
05165   {
05166     FT_UShort  point;
05167 
05168     FT_UNUSED_ARG;
05169 
05170 
05171     if ( CUR.top < CUR.GS.loop )
05172     {
05173       CUR.error = TT_Err_Too_Few_Arguments;
05174       return;
05175     }
05176 
05177     while ( CUR.GS.loop > 0 )
05178     {
05179       CUR.args--;
05180 
05181       point = (FT_UShort)CUR.stack[CUR.args];
05182 
05183       if ( BOUNDS( point, CUR.pts.n_points ) )
05184       {
05185         if ( CUR.pedantic_hinting )
05186         {
05187           CUR.error = TT_Err_Invalid_Reference;
05188           return;
05189         }
05190       }
05191       else
05192         CUR.pts.tags[point] ^= FT_CURVE_TAG_ON;
05193 
05194       CUR.GS.loop--;
05195     }
05196 
05197     CUR.GS.loop = 1;
05198     CUR.new_top = CUR.args;
05199   }
05200 
05201 
05202   /*************************************************************************/
05203   /*                                                                       */
05204   /* FLIPRGON[]:   FLIP RanGe ON                                           */
05205   /* Opcode range: 0x81                                                    */
05206   /* Stack:        uint32 uint32 -->                                       */
05207   /*                                                                       */
05208   static void
05209   Ins_FLIPRGON( INS_ARG )
05210   {
05211     FT_UShort  I, K, L;
05212 
05213 
05214     K = (FT_UShort)args[1];
05215     L = (FT_UShort)args[0];
05216 
05217     if ( BOUNDS( K, CUR.pts.n_points ) ||
05218          BOUNDS( L, CUR.pts.n_points ) )
05219     {
05220       if ( CUR.pedantic_hinting )
05221         CUR.error = TT_Err_Invalid_Reference;
05222       return;
05223     }
05224 
05225     for ( I = L; I <= K; I++ )
05226       CUR.pts.tags[I] |= FT_CURVE_TAG_ON;
05227   }
05228 
05229 
05230   /*************************************************************************/
05231   /*                                                                       */
05232   /* FLIPRGOFF:    FLIP RanGe OFF                                          */
05233   /* Opcode range: 0x82                                                    */
05234   /* Stack:        uint32 uint32 -->                                       */
05235   /*                                                                       */
05236   static void
05237   Ins_FLIPRGOFF( INS_ARG )
05238   {
05239     FT_UShort  I, K, L;
05240 
05241 
05242     K = (FT_UShort)args[1];
05243     L = (FT_UShort)args[0];
05244 
05245     if ( BOUNDS( K, CUR.pts.n_points ) ||
05246          BOUNDS( L, CUR.pts.n_points ) )
05247     {
05248       if ( CUR.pedantic_hinting )
05249         CUR.error = TT_Err_Invalid_Reference;
05250       return;
05251     }
05252 
05253     for ( I = L; I <= K; I++ )
05254       CUR.pts.tags[I] &= ~FT_CURVE_TAG_ON;
05255   }
05256 
05257 
05258   static FT_Bool
05259   Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6*   x,
05260                                        FT_F26Dot6*   y,
05261                                        TT_GlyphZone  zone,
05262                                        FT_UShort*    refp )
05263   {
05264     TT_GlyphZoneRec  zp;
05265     FT_UShort        p;
05266     FT_F26Dot6       d;
05267 
05268 
05269     if ( CUR.opcode & 1 )
05270     {
05271       zp = CUR.zp0;
05272       p  = CUR.GS.rp1;
05273     }
05274     else
05275     {
05276       zp = CUR.zp1;
05277       p  = CUR.GS.rp2;
05278     }
05279 
05280     if ( BOUNDS( p, zp.n_points ) )
05281     {
05282       if ( CUR.pedantic_hinting )
05283         CUR.error = TT_Err_Invalid_Reference;
05284       *refp = 0;
05285       return FAILURE;
05286     }
05287 
05288     *zone = zp;
05289     *refp = p;
05290 
05291     d = CUR_Func_project( zp.cur + p, zp.org + p );
05292 
05293 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
05294     if ( CUR.face->unpatented_hinting )
05295     {
05296       if ( CUR.GS.both_x_axis )
05297       {
05298         *x = d;
05299         *y = 0;
05300       }
05301       else
05302       {
05303         *x = 0;
05304         *y = d;
05305       }
05306     }
05307     else
05308 #endif
05309     {
05310       *x = TT_MULDIV( d,
05311                       (FT_Long)CUR.GS.freeVector.x * 0x10000L,
05312                       CUR.F_dot_P );
05313       *y = TT_MULDIV( d,
05314                       (FT_Long)CUR.GS.freeVector.y * 0x10000L,
05315                       CUR.F_dot_P );
05316     }
05317 
05318     return SUCCESS;
05319   }
05320 
05321 
05322   static void
05323   Move_Zp2_Point( EXEC_OP_ FT_UShort   point,
05324                            FT_F26Dot6  dx,
05325                            FT_F26Dot6  dy,
05326                            FT_Bool     touch )
05327   {
05328 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
05329     if ( CUR.face->unpatented_hinting )
05330     {
05331       if ( CUR.GS.both_x_axis )
05332       {
05333         CUR.zp2.cur[point].x += dx;
05334         if ( touch )
05335           CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
05336       }
05337       else
05338       {
05339         CUR.zp2.cur[point].y += dy;
05340         if ( touch )
05341           CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
05342       }
05343       return;
05344     }
05345 #endif
05346 
05347     if ( CUR.GS.freeVector.x != 0 )
05348     {
05349       CUR.zp2.cur[point].x += dx;
05350       if ( touch )
05351         CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
05352     }
05353 
05354     if ( CUR.GS.freeVector.y != 0 )
05355     {
05356       CUR.zp2.cur[point].y += dy;
05357       if ( touch )
05358         CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
05359     }
05360   }
05361 
05362 
05363   /*************************************************************************/
05364   /*                                                                       */
05365   /* SHP[a]:       SHift Point by the last point                           */
05366   /* Opcode range: 0x32-0x33                                               */
05367   /* Stack:        uint32... -->                                           */
05368   /*                                                                       */
05369   static void
05370   Ins_SHP( INS_ARG )
05371   {
05372     TT_GlyphZoneRec  zp;
05373     FT_UShort        refp;
05374 
05375     FT_F26Dot6       dx,
05376                      dy;
05377     FT_UShort        point;
05378 
05379     FT_UNUSED_ARG;
05380 
05381 
05382     if ( CUR.top < CUR.GS.loop )
05383     {
05384       CUR.error = TT_Err_Invalid_Reference;
05385       return;
05386     }
05387 
05388     if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
05389       return;
05390 
05391     while ( CUR.GS.loop > 0 )
05392     {
05393       CUR.args--;
05394       point = (FT_UShort)CUR.stack[CUR.args];
05395 
05396       if ( BOUNDS( point, CUR.zp2.n_points ) )
05397       {
05398         if ( CUR.pedantic_hinting )
05399         {
05400           CUR.error = TT_Err_Invalid_Reference;
05401           return;
05402         }
05403       }
05404       else
05405         /* XXX: UNDOCUMENTED! SHP touches the points */
05406         MOVE_Zp2_Point( point, dx, dy, TRUE );
05407 
05408       CUR.GS.loop--;
05409     }
05410 
05411     CUR.GS.loop = 1;
05412     CUR.new_top = CUR.args;
05413   }
05414 
05415 
05416   /*************************************************************************/
05417   /*                                                                       */
05418   /* SHC[a]:       SHift Contour                                           */
05419   /* Opcode range: 0x34-35                                                 */
05420   /* Stack:        uint32 -->                                              */
05421   /*                                                                       */
05422   static void
05423   Ins_SHC( INS_ARG )
05424   {
05425     TT_GlyphZoneRec zp;
05426     FT_UShort       refp;
05427     FT_F26Dot6      dx,
05428                     dy;
05429 
05430     FT_Short        contour;
05431     FT_UShort       first_point, last_point, i;
05432 
05433 
05434     contour = (FT_UShort)args[0];
05435 
05436     if ( BOUNDS( contour, CUR.pts.n_contours ) )
05437     {
05438       if ( CUR.pedantic_hinting )
05439         CUR.error = TT_Err_Invalid_Reference;
05440       return;
05441     }
05442 
05443     if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
05444       return;
05445 
05446     if ( contour == 0 )
05447       first_point = 0;
05448     else
05449       first_point = (FT_UShort)( CUR.pts.contours[contour - 1] + 1 -
05450                                  CUR.pts.first_point );
05451 
05452     last_point = (FT_UShort)( CUR.pts.contours[contour] -
05453                               CUR.pts.first_point );
05454 
05455     /* XXX: this is probably wrong... at least it prevents memory */
05456     /*      corruption when zp2 is the twilight zone              */
05457     if ( BOUNDS( last_point, CUR.zp2.n_points ) )
05458     {
05459       if ( CUR.zp2.n_points > 0 )
05460         last_point = (FT_UShort)(CUR.zp2.n_points - 1);
05461       else
05462         last_point = 0;
05463     }
05464 
05465     /* XXX: UNDOCUMENTED! SHC touches the points */
05466     for ( i = first_point; i <= last_point; i++ )
05467     {
05468       if ( zp.cur != CUR.zp2.cur || refp != i )
05469         MOVE_Zp2_Point( i, dx, dy, TRUE );
05470     }
05471   }
05472 
05473 
05474   /*************************************************************************/
05475   /*                                                                       */
05476   /* SHZ[a]:       SHift Zone                                              */
05477   /* Opcode range: 0x36-37                                                 */
05478   /* Stack:        uint32 -->                                              */
05479   /*                                                                       */
05480   static void
05481   Ins_SHZ( INS_ARG )
05482   {
05483     TT_GlyphZoneRec zp;
05484     FT_UShort       refp;
05485     FT_F26Dot6      dx,
05486                     dy;
05487 
05488     FT_UShort       last_point, i;
05489 
05490 
05491     if ( BOUNDS( args[0], 2 ) )
05492     {
05493       if ( CUR.pedantic_hinting )
05494         CUR.error = TT_Err_Invalid_Reference;
05495       return;
05496     }
05497 
05498     if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
05499       return;
05500 
05501     /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points.  */
05502     /*      Twilight zone has no contours, so use `n_points'.   */
05503     /*      Normal zone's `n_points' includes phantoms, so must */
05504     /*      use end of last contour.                            */
05505     if ( CUR.GS.gep2 == 0 && CUR.zp2.n_points > 0 )
05506       last_point = (FT_UShort)( CUR.zp2.n_points - 1 );
05507     else if ( CUR.GS.gep2 == 1 && CUR.zp2.n_contours > 0 )
05508       last_point = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] );
05509     else
05510       last_point = 0;
05511 
05512     /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
05513     for ( i = 0; i <= last_point; i++ )
05514     {
05515       if ( zp.cur != CUR.zp2.cur || refp != i )
05516         MOVE_Zp2_Point( i, dx, dy, FALSE );
05517     }
05518   }
05519 
05520 
05521   /*************************************************************************/
05522   /*                                                                       */
05523   /* SHPIX[]:      SHift points by a PIXel amount                          */
05524   /* Opcode range: 0x38                                                    */
05525   /* Stack:        f26.6 uint32... -->                                     */
05526   /*                                                                       */
05527   static void
05528   Ins_SHPIX( INS_ARG )
05529   {
05530     FT_F26Dot6  dx, dy;
05531     FT_UShort   point;
05532 
05533 
05534     if ( CUR.top < CUR.GS.loop + 1 )
05535     {
05536       CUR.error = TT_Err_Invalid_Reference;
05537       return;
05538     }
05539 
05540 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
05541     if ( CUR.face->unpatented_hinting )
05542     {
05543       if ( CUR.GS.both_x_axis )
05544       {
05545         dx = TT_MulFix14( (FT_UInt32)args[0], 0x4000 );
05546         dy = 0;
05547       }
05548       else
05549       {
05550         dx = 0;
05551         dy = TT_MulFix14( (FT_UInt32)args[0], 0x4000 );
05552       }
05553     }
05554     else
05555 #endif
05556     {
05557       dx = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.x );
05558       dy = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.y );
05559     }
05560 
05561     while ( CUR.GS.loop > 0 )
05562     {
05563       CUR.args--;
05564 
05565       point = (FT_UShort)CUR.stack[CUR.args];
05566 
05567       if ( BOUNDS( point, CUR.zp2.n_points ) )
05568       {
05569         if ( CUR.pedantic_hinting )
05570         {
05571           CUR.error = TT_Err_Invalid_Reference;
05572           return;
05573         }
05574       }
05575       else
05576         MOVE_Zp2_Point( point, dx, dy, TRUE );
05577 
05578       CUR.GS.loop--;
05579     }
05580 
05581     CUR.GS.loop = 1;
05582     CUR.new_top = CUR.args;
05583   }
05584 
05585 
05586   /*************************************************************************/
05587   /*                                                                       */
05588   /* MSIRP[a]:     Move Stack Indirect Relative Position                   */
05589   /* Opcode range: 0x3A-0x3B                                               */
05590   /* Stack:        f26.6 uint32 -->                                        */
05591   /*                                                                       */
05592   static void
05593   Ins_MSIRP( INS_ARG )
05594   {
05595     FT_UShort   point;
05596     FT_F26Dot6  distance;
05597 
05598 
05599     point = (FT_UShort)args[0];
05600 
05601     if ( BOUNDS( point,      CUR.zp1.n_points ) ||
05602          BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
05603     {
05604       if ( CUR.pedantic_hinting )
05605         CUR.error = TT_Err_Invalid_Reference;
05606       return;
05607     }
05608 
05609     /* XXX: UNDOCUMENTED! behaviour */
05610     if ( CUR.GS.gep1 == 0 )   /* if the point that is to be moved */
05611                               /* is in twilight zone              */
05612     {
05613       CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
05614       CUR_Func_move_orig( &CUR.zp1, point, args[1] );
05615       CUR.zp1.cur[point] = CUR.zp1.org[point];
05616     }
05617 
05618     distance = CUR_Func_project( CUR.zp1.cur + point,
05619                                  CUR.zp0.cur + CUR.GS.rp0 );
05620 
05621     CUR_Func_move( &CUR.zp1, point, args[1] - distance );
05622 
05623     CUR.GS.rp1 = CUR.GS.rp0;
05624     CUR.GS.rp2 = point;
05625 
05626     if ( ( CUR.opcode & 1 ) != 0 )
05627       CUR.GS.rp0 = point;
05628   }
05629 
05630 
05631   /*************************************************************************/
05632   /*                                                                       */
05633   /* MDAP[a]:      Move Direct Absolute Point                              */
05634   /* Opcode range: 0x2E-0x2F                                               */
05635   /* Stack:        uint32 -->                                              */
05636   /*                                                                       */
05637   static void
05638   Ins_MDAP( INS_ARG )
05639   {
05640     FT_UShort   point;
05641     FT_F26Dot6  cur_dist,
05642                 distance;
05643 
05644 
05645     point = (FT_UShort)args[0];
05646 
05647     if ( BOUNDS( point, CUR.zp0.n_points ) )
05648     {
05649       if ( CUR.pedantic_hinting )
05650         CUR.error = TT_Err_Invalid_Reference;
05651       return;
05652     }
05653 
05654     /* XXX: Is there some undocumented feature while in the */
05655     /*      twilight zone? ?                                */
05656     if ( ( CUR.opcode & 1 ) != 0 )
05657     {
05658       cur_dist = CUR_fast_project( &CUR.zp0.cur[point] );
05659       distance = CUR_Func_round( cur_dist,
05660                                  CUR.tt_metrics.compensations[0] ) - cur_dist;
05661     }
05662     else
05663       distance = 0;
05664 
05665     CUR_Func_move( &CUR.zp0, point, distance );
05666 
05667     CUR.GS.rp0 = point;
05668     CUR.GS.rp1 = point;
05669   }
05670 
05671 
05672   /*************************************************************************/
05673   /*                                                                       */
05674   /* MIAP[a]:      Move Indirect Absolute Point                            */
05675   /* Opcode range: 0x3E-0x3F                                               */
05676   /* Stack:        uint32 uint32 -->                                       */
05677   /*                                                                       */
05678   static void
05679   Ins_MIAP( INS_ARG )
05680   {
05681     FT_ULong    cvtEntry;
05682     FT_UShort   point;
05683     FT_F26Dot6  distance,
05684                 org_dist;
05685 
05686 
05687     cvtEntry = (FT_ULong)args[1];
05688     point    = (FT_UShort)args[0];
05689 
05690     if ( BOUNDS( point,    CUR.zp0.n_points ) ||
05691          BOUNDS( cvtEntry, CUR.cvtSize )      )
05692     {
05693       if ( CUR.pedantic_hinting )
05694         CUR.error = TT_Err_Invalid_Reference;
05695       return;
05696     }
05697 
05698     /* XXX: UNDOCUMENTED!                                */
05699     /*                                                   */
05700     /* The behaviour of an MIAP instruction is quite     */
05701     /* different when used in the twilight zone.         */
05702     /*                                                   */
05703     /* First, no control value cut-in test is performed  */
05704     /* as it would fail anyway.  Second, the original    */
05705     /* point, i.e. (org_x,org_y) of zp0.point, is set    */
05706     /* to the absolute, unrounded distance found in      */
05707     /* the CVT.                                          */
05708     /*                                                   */
05709     /* This is used in the CVT programs of the Microsoft */
05710     /* fonts Arial, Times, etc., in order to re-adjust   */
05711     /* some key font heights.  It allows the use of the  */
05712     /* IP instruction in the twilight zone, which        */
05713     /* otherwise would be `illegal' according to the     */
05714     /* specification.                                    */
05715     /*                                                   */
05716     /* We implement it with a special sequence for the   */
05717     /* twilight zone.  This is a bad hack, but it seems  */
05718     /* to work.                                          */
05719 
05720     distance = CUR_Func_read_cvt( cvtEntry );
05721 
05722     if ( CUR.GS.gep0 == 0 )   /* If in twilight zone */
05723     {
05724       CUR.zp0.org[point].x = TT_MulFix14( (FT_UInt32)distance, CUR.GS.freeVector.x );
05725       CUR.zp0.org[point].y = TT_MulFix14( (FT_UInt32)distance, CUR.GS.freeVector.y ),
05726       CUR.zp0.cur[point]   = CUR.zp0.org[point];
05727     }
05728 
05729     org_dist = CUR_fast_project( &CUR.zp0.cur[point] );
05730 
05731     if ( ( CUR.opcode & 1 ) != 0 )   /* rounding and control cutin flag */
05732     {
05733       if ( FT_ABS( distance - org_dist ) > CUR.GS.control_value_cutin )
05734         distance = org_dist;
05735 
05736       distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] );
05737     }
05738 
05739     CUR_Func_move( &CUR.zp0, point, distance - org_dist );
05740 
05741     CUR.GS.rp0 = point;
05742     CUR.GS.rp1 = point;
05743   }
05744 
05745 
05746   /*************************************************************************/
05747   /*                                                                       */
05748   /* MDRP[abcde]:  Move Direct Relative Point                              */
05749   /* Opcode range: 0xC0-0xDF                                               */
05750   /* Stack:        uint32 -->                                              */
05751   /*                                                                       */
05752   static void
05753   Ins_MDRP( INS_ARG )
05754   {
05755     FT_UShort   point;
05756     FT_F26Dot6  org_dist, distance;
05757 
05758 
05759     point = (FT_UShort)args[0];
05760 
05761     if ( BOUNDS( point,      CUR.zp1.n_points ) ||
05762          BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
05763     {
05764       if ( CUR.pedantic_hinting )
05765         CUR.error = TT_Err_Invalid_Reference;
05766       return;
05767     }
05768 
05769     /* XXX: Is there some undocumented feature while in the */
05770     /*      twilight zone?                                  */
05771 
05772     /* XXX: UNDOCUMENTED: twilight zone special case */
05773 
05774     if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
05775     {
05776       FT_Vector*  vec1 = &CUR.zp1.org[point];
05777       FT_Vector*  vec2 = &CUR.zp0.org[CUR.GS.rp0];
05778 
05779 
05780       org_dist = CUR_Func_dualproj( vec1, vec2 );
05781     }
05782     else
05783     {
05784       FT_Vector*  vec1 = &CUR.zp1.orus[point];
05785       FT_Vector*  vec2 = &CUR.zp0.orus[CUR.GS.rp0];
05786 
05787 
05788       if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
05789       {
05790         /* this should be faster */
05791         org_dist = CUR_Func_dualproj( vec1, vec2 );
05792         org_dist = TT_MULFIX( org_dist, CUR.metrics.x_scale );
05793       }
05794       else
05795       {
05796         FT_Vector  vec;
05797 
05798 
05799         vec.x = TT_MULFIX( vec1->x - vec2->x, CUR.metrics.x_scale );
05800         vec.y = TT_MULFIX( vec1->y - vec2->y, CUR.metrics.y_scale );
05801 
05802         org_dist = CUR_fast_dualproj( &vec );
05803       }
05804     }
05805 
05806     /* single width cut-in test */
05807 
05808     if ( FT_ABS( org_dist - CUR.GS.single_width_value ) <
05809          CUR.GS.single_width_cutin )
05810     {
05811       if ( org_dist >= 0 )
05812         org_dist = CUR.GS.single_width_value;
05813       else
05814         org_dist = -CUR.GS.single_width_value;
05815     }
05816 
05817     /* round flag */
05818 
05819     if ( ( CUR.opcode & 4 ) != 0 )
05820       distance = CUR_Func_round(
05821                    org_dist,
05822                    CUR.tt_metrics.compensations[CUR.opcode & 3] );
05823     else
05824       distance = ROUND_None(
05825                    org_dist,
05826                    CUR.tt_metrics.compensations[CUR.opcode & 3] );
05827 
05828     /* minimum distance flag */
05829 
05830     if ( ( CUR.opcode & 8 ) != 0 )
05831     {
05832       if ( org_dist >= 0 )
05833       {
05834         if ( distance < CUR.GS.minimum_distance )
05835           distance = CUR.GS.minimum_distance;
05836       }
05837       else
05838       {
05839         if ( distance > -CUR.GS.minimum_distance )
05840           distance = -CUR.GS.minimum_distance;
05841       }
05842     }
05843 
05844     /* now move the point */
05845 
05846     org_dist = CUR_Func_project( CUR.zp1.cur + point,
05847                                  CUR.zp0.cur + CUR.GS.rp0 );
05848 
05849     CUR_Func_move( &CUR.zp1, point, distance - org_dist );
05850 
05851     CUR.GS.rp1 = CUR.GS.rp0;
05852     CUR.GS.rp2 = point;
05853 
05854     if ( ( CUR.opcode & 16 ) != 0 )
05855       CUR.GS.rp0 = point;
05856   }
05857 
05858 
05859   /*************************************************************************/
05860   /*                                                                       */
05861   /* MIRP[abcde]:  Move Indirect Relative Point                            */
05862   /* Opcode range: 0xE0-0xFF                                               */
05863   /* Stack:        int32? uint32 -->                                       */
05864   /*                                                                       */
05865   static void
05866   Ins_MIRP( INS_ARG )
05867   {
05868     FT_UShort   point;
05869     FT_ULong    cvtEntry;
05870 
05871     FT_F26Dot6  cvt_dist,
05872                 distance,
05873                 cur_dist,
05874                 org_dist;
05875 
05876 
05877     point    = (FT_UShort)args[0];
05878     cvtEntry = (FT_ULong)( args[1] + 1 );
05879 
05880     /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
05881 
05882     if ( BOUNDS( point,      CUR.zp1.n_points ) ||
05883          BOUNDS( cvtEntry,   CUR.cvtSize + 1 )  ||
05884          BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
05885     {
05886       if ( CUR.pedantic_hinting )
05887         CUR.error = TT_Err_Invalid_Reference;
05888       return;
05889     }
05890 
05891     if ( !cvtEntry )
05892       cvt_dist = 0;
05893     else
05894       cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
05895 
05896     /* single width test */
05897 
05898     if ( FT_ABS( cvt_dist - CUR.GS.single_width_value ) <
05899          CUR.GS.single_width_cutin )
05900     {
05901       if ( cvt_dist >= 0 )
05902         cvt_dist =  CUR.GS.single_width_value;
05903       else
05904         cvt_dist = -CUR.GS.single_width_value;
05905     }
05906 
05907     /* XXX: UNDOCUMENTED! -- twilight zone */
05908 
05909     if ( CUR.GS.gep1 == 0 )
05910     {
05911       CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +
05912                              TT_MulFix14( (FT_UInt32)cvt_dist,
05913                                           CUR.GS.freeVector.x );
05914 
05915       CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
05916                              TT_MulFix14( (FT_UInt32)cvt_dist,
05917                                           CUR.GS.freeVector.y );
05918 
05919       CUR.zp1.cur[point] = CUR.zp0.cur[point];
05920     }
05921 
05922     org_dist = CUR_Func_dualproj( &CUR.zp1.org[point],
05923                                   &CUR.zp0.org[CUR.GS.rp0] );
05924     cur_dist = CUR_Func_project ( &CUR.zp1.cur[point],
05925                                   &CUR.zp0.cur[CUR.GS.rp0] );
05926 
05927     /* auto-flip test */
05928 
05929     if ( CUR.GS.auto_flip )
05930     {
05931       if ( ( org_dist ^ cvt_dist ) < 0 )
05932         cvt_dist = -cvt_dist;
05933     }
05934 
05935     /* control value cutin and round */
05936 
05937     if ( ( CUR.opcode & 4 ) != 0 )
05938     {
05939       /* XXX: UNDOCUMENTED!  Only perform cut-in test when both points */
05940       /*      refer to the same zone.                                  */
05941 
05942       if ( CUR.GS.gep0 == CUR.GS.gep1 )
05943         if ( FT_ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin )
05944           cvt_dist = org_dist;
05945 
05946       distance = CUR_Func_round(
05947                    cvt_dist,
05948                    CUR.tt_metrics.compensations[CUR.opcode & 3] );
05949     }
05950     else
05951       distance = ROUND_None(
05952                    cvt_dist,
05953                    CUR.tt_metrics.compensations[CUR.opcode & 3] );
05954 
05955     /* minimum distance test */
05956 
05957     if ( ( CUR.opcode & 8 ) != 0 )
05958     {
05959       if ( org_dist >= 0 )
05960       {
05961         if ( distance < CUR.GS.minimum_distance )
05962           distance = CUR.GS.minimum_distance;
05963       }
05964       else
05965       {
05966         if ( distance > -CUR.GS.minimum_distance )
05967           distance = -CUR.GS.minimum_distance;
05968       }
05969     }
05970 
05971     CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
05972 
05973     CUR.GS.rp1 = CUR.GS.rp0;
05974 
05975     if ( ( CUR.opcode & 16 ) != 0 )
05976       CUR.GS.rp0 = point;
05977 
05978     /* XXX: UNDOCUMENTED! */
05979     CUR.GS.rp2 = point;
05980   }
05981 
05982 
05983   /*************************************************************************/
05984   /*                                                                       */
05985   /* ALIGNRP[]:    ALIGN Relative Point                                    */
05986   /* Opcode range: 0x3C                                                    */
05987   /* Stack:        uint32 uint32... -->                                    */
05988   /*                                                                       */
05989   static void
05990   Ins_ALIGNRP( INS_ARG )
05991   {
05992     FT_UShort   point;
05993     FT_F26Dot6  distance;
05994 
05995     FT_UNUSED_ARG;
05996 
05997 
05998     if ( CUR.top < CUR.GS.loop ||
05999          BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
06000     {
06001       if ( CUR.pedantic_hinting )
06002         CUR.error = TT_Err_Invalid_Reference;
06003       return;
06004     }
06005 
06006     while ( CUR.GS.loop > 0 )
06007     {
06008       CUR.args--;
06009 
06010       point = (FT_UShort)CUR.stack[CUR.args];
06011 
06012       if ( BOUNDS( point, CUR.zp1.n_points ) )
06013       {
06014         if ( CUR.pedantic_hinting )
06015         {
06016           CUR.error = TT_Err_Invalid_Reference;
06017           return;
06018         }
06019       }
06020       else
06021       {
06022         distance = CUR_Func_project( CUR.zp1.cur + point,
06023                                      CUR.zp0.cur + CUR.GS.rp0 );
06024 
06025         CUR_Func_move( &CUR.zp1, point, -distance );
06026       }
06027 
06028       CUR.GS.loop--;
06029     }
06030 
06031     CUR.GS.loop = 1;
06032     CUR.new_top = CUR.args;
06033   }
06034 
06035 
06036   /*************************************************************************/
06037   /*                                                                       */
06038   /* ISECT[]:      moves point to InterSECTion                             */
06039   /* Opcode range: 0x0F                                                    */
06040   /* Stack:        5 * uint32 -->                                          */
06041   /*                                                                       */
06042   static void
06043   Ins_ISECT( INS_ARG )
06044   {
06045     FT_UShort   point,
06046                 a0, a1,
06047                 b0, b1;
06048 
06049     FT_F26Dot6  discriminant;
06050 
06051     FT_F26Dot6  dx,  dy,
06052                 dax, day,
06053                 dbx, dby;
06054 
06055     FT_F26Dot6  val;
06056 
06057     FT_Vector   R;
06058 
06059 
06060     point = (FT_UShort)args[0];
06061 
06062     a0 = (FT_UShort)args[1];
06063     a1 = (FT_UShort)args[2];
06064     b0 = (FT_UShort)args[3];
06065     b1 = (FT_UShort)args[4];
06066 
06067     if ( BOUNDS( b0, CUR.zp0.n_points )  ||
06068          BOUNDS( b1, CUR.zp0.n_points )  ||
06069          BOUNDS( a0, CUR.zp1.n_points )  ||
06070          BOUNDS( a1, CUR.zp1.n_points )  ||
06071          BOUNDS( point, CUR.zp2.n_points ) )
06072     {
06073       if ( CUR.pedantic_hinting )
06074         CUR.error = TT_Err_Invalid_Reference;
06075       return;
06076     }
06077 
06078     dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
06079     dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
06080 
06081     dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;
06082     day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;
06083 
06084     dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;
06085     dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;
06086 
06087     CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
06088 
06089     discriminant = TT_MULDIV( dax, -dby, 0x40 ) +
06090                    TT_MULDIV( day, dbx, 0x40 );
06091 
06092     if ( FT_ABS( discriminant ) >= 0x40 )
06093     {
06094       val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 );
06095 
06096       R.x = TT_MULDIV( val, dax, discriminant );
06097       R.y = TT_MULDIV( val, day, discriminant );
06098 
06099       CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
06100       CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
06101     }
06102     else
06103     {
06104       /* else, take the middle of the middles of A and B */
06105 
06106       CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +
06107                                CUR.zp1.cur[a1].x +
06108                                CUR.zp0.cur[b0].x +
06109                                CUR.zp0.cur[b1].x ) / 4;
06110       CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +
06111                                CUR.zp1.cur[a1].y +
06112                                CUR.zp0.cur[b0].y +
06113                                CUR.zp0.cur[b1].y ) / 4;
06114     }
06115   }
06116 
06117 
06118   /*************************************************************************/
06119   /*                                                                       */
06120   /* ALIGNPTS[]:   ALIGN PoinTS                                            */
06121   /* Opcode range: 0x27                                                    */
06122   /* Stack:        uint32 uint32 -->                                       */
06123   /*                                                                       */
06124   static void
06125   Ins_ALIGNPTS( INS_ARG )
06126   {
06127     FT_UShort   p1, p2;
06128     FT_F26Dot6  distance;
06129 
06130 
06131     p1 = (FT_UShort)args[0];
06132     p2 = (FT_UShort)args[1];
06133 
06134     if ( BOUNDS( args[0], CUR.zp1.n_points ) ||
06135          BOUNDS( args[1], CUR.zp0.n_points ) )
06136     {
06137       if ( CUR.pedantic_hinting )
06138         CUR.error = TT_Err_Invalid_Reference;
06139       return;
06140     }
06141 
06142     distance = CUR_Func_project( CUR.zp0.cur + p2,
06143                                  CUR.zp1.cur + p1 ) / 2;
06144 
06145     CUR_Func_move( &CUR.zp1, p1, distance );
06146     CUR_Func_move( &CUR.zp0, p2, -distance );
06147   }
06148 
06149 
06150   /*************************************************************************/
06151   /*                                                                       */
06152   /* IP[]:         Interpolate Point                                       */
06153   /* Opcode range: 0x39                                                    */
06154   /* Stack:        uint32... -->                                           */
06155   /*                                                                       */
06156 
06157   /* SOMETIMES, DUMBER CODE IS BETTER CODE */
06158 
06159   static void
06160   Ins_IP( INS_ARG )
06161   {
06162     FT_F26Dot6  old_range, cur_range;
06163     FT_Vector*  orus_base;
06164     FT_Vector*  cur_base;
06165     FT_Int      twilight;
06166 
06167     FT_UNUSED_ARG;
06168 
06169 
06170     if ( CUR.top < CUR.GS.loop )
06171     {
06172       CUR.error = TT_Err_Invalid_Reference;
06173       return;
06174     }
06175 
06176     /*
06177      * We need to deal in a special way with the twilight zone.
06178      * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0),
06179      * for every n.
06180      */
06181     twilight = CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 || CUR.GS.gep2 == 0;
06182 
06183     if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) )
06184     {
06185       if ( CUR.pedantic_hinting )
06186         CUR.error = TT_Err_Invalid_Reference;
06187       return;
06188     }
06189 
06190     if ( twilight )
06191       orus_base = &CUR.zp0.org[CUR.GS.rp1];
06192     else
06193       orus_base = &CUR.zp0.orus[CUR.GS.rp1];
06194 
06195     cur_base = &CUR.zp0.cur[CUR.GS.rp1];
06196 
06197     /* XXX: There are some glyphs in some braindead but popular */
06198     /*      fonts out there (e.g. [aeu]grave in monotype.ttf)   */
06199     /*      calling IP[] with bad values of rp[12].             */
06200     /*      Do something sane when this odd thing happens.      */
06201     if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
06202          BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
06203     {
06204       old_range = 0;
06205       cur_range = 0;
06206     }
06207     else
06208     {
06209       if ( twilight )
06210         old_range = CUR_Func_dualproj( &CUR.zp1.org[CUR.GS.rp2],
06211                                        orus_base );
06212       else
06213         old_range = CUR_Func_dualproj( &CUR.zp1.orus[CUR.GS.rp2],
06214                                        orus_base );
06215 
06216       cur_range = CUR_Func_project ( &CUR.zp1.cur[CUR.GS.rp2], cur_base );
06217     }
06218 
06219     for ( ; CUR.GS.loop > 0; --CUR.GS.loop )
06220     {
06221       FT_UInt     point = (FT_UInt)CUR.stack[--CUR.args];
06222       FT_F26Dot6  org_dist, cur_dist, new_dist;
06223 
06224 
06225       /* check point bounds */
06226       if ( BOUNDS( point, CUR.zp2.n_points ) )
06227       {
06228         if ( CUR.pedantic_hinting )
06229         {
06230           CUR.error = TT_Err_Invalid_Reference;
06231           return;
06232         }
06233         continue;
06234       }
06235 
06236       if ( twilight )
06237         org_dist = CUR_Func_dualproj( &CUR.zp2.org[point], orus_base );
06238       else
06239         org_dist = CUR_Func_dualproj( &CUR.zp2.orus[point], orus_base );
06240 
06241       cur_dist = CUR_Func_project ( &CUR.zp2.cur[point], cur_base );
06242 
06243       if ( org_dist )
06244         new_dist = ( old_range != 0 )
06245                      ? TT_MULDIV( org_dist, cur_range, old_range )
06246                      : cur_dist;
06247       else
06248         new_dist = 0;
06249 
06250       CUR_Func_move( &CUR.zp2, (FT_UShort)point, new_dist - cur_dist );
06251     }
06252     CUR.GS.loop = 1;
06253     CUR.new_top = CUR.args;
06254   }
06255 
06256 
06257   /*************************************************************************/
06258   /*                                                                       */
06259   /* UTP[a]:       UnTouch Point                                           */
06260   /* Opcode range: 0x29                                                    */
06261   /* Stack:        uint32 -->                                              */
06262   /*                                                                       */
06263   static void
06264   Ins_UTP( INS_ARG )
06265   {
06266     FT_UShort  point;
06267     FT_Byte    mask;
06268 
06269 
06270     point = (FT_UShort)args[0];
06271 
06272     if ( BOUNDS( point, CUR.zp0.n_points ) )
06273     {
06274       if ( CUR.pedantic_hinting )
06275         CUR.error = TT_Err_Invalid_Reference;
06276       return;
06277     }
06278 
06279     mask = 0xFF;
06280 
06281     if ( CUR.GS.freeVector.x != 0 )
06282       mask &= ~FT_CURVE_TAG_TOUCH_X;
06283 
06284     if ( CUR.GS.freeVector.y != 0 )
06285       mask &= ~FT_CURVE_TAG_TOUCH_Y;
06286 
06287     CUR.zp0.tags[point] &= mask;
06288   }
06289 
06290 
06291   /* Local variables for Ins_IUP: */
06292   typedef struct  IUP_WorkerRec_
06293   {
06294     FT_Vector*  orgs;   /* original and current coordinate */
06295     FT_Vector*  curs;   /* arrays                          */
06296     FT_Vector*  orus;
06297     FT_UInt     max_points;
06298 
06299   } IUP_WorkerRec, *IUP_Worker;
06300 
06301 
06302   static void
06303   _iup_worker_shift( IUP_Worker  worker,
06304                      FT_UInt     p1,
06305                      FT_UInt     p2,
06306                      FT_UInt     p )
06307   {
06308     FT_UInt     i;
06309     FT_F26Dot6  dx;
06310 
06311 
06312     dx = worker->curs[p].x - worker->orgs[p].x;
06313     if ( dx != 0 )
06314     {
06315       for ( i = p1; i < p; i++ )
06316         worker->curs[i].x += dx;
06317 
06318       for ( i = p + 1; i <= p2; i++ )
06319         worker->curs[i].x += dx;
06320     }
06321   }
06322 
06323 
06324   static void
06325   _iup_worker_interpolate( IUP_Worker  worker,
06326                            FT_UInt     p1,
06327                            FT_UInt     p2,
06328                            FT_UInt     ref1,
06329                            FT_UInt     ref2 )
06330   {
06331     FT_UInt     i;
06332     FT_F26Dot6  orus1, orus2, org1, org2, delta1, delta2;
06333 
06334 
06335     if ( p1 > p2 )
06336       return;
06337 
06338     if ( BOUNDS( ref1, worker->max_points ) ||
06339          BOUNDS( ref2, worker->max_points ) )
06340       return;
06341 
06342     orus1 = worker->orus[ref1].x;
06343     orus2 = worker->orus[ref2].x;
06344 
06345     if ( orus1 > orus2 )
06346     {
06347       FT_F26Dot6  tmp_o;
06348       FT_UInt     tmp_r;
06349 
06350 
06351       tmp_o = orus1;
06352       orus1 = orus2;
06353       orus2 = tmp_o;
06354 
06355       tmp_r = ref1;
06356       ref1  = ref2;
06357       ref2  = tmp_r;
06358     }
06359 
06360     org1   = worker->orgs[ref1].x;
06361     org2   = worker->orgs[ref2].x;
06362     delta1 = worker->curs[ref1].x - org1;
06363     delta2 = worker->curs[ref2].x - org2;
06364 
06365     if ( orus1 == orus2 )
06366     {
06367       /* simple shift of untouched points */
06368       for ( i = p1; i <= p2; i++ )
06369       {
06370         FT_F26Dot6  x = worker->orgs[i].x;
06371 
06372 
06373         if ( x <= org1 )
06374           x += delta1;
06375         else
06376           x += delta2;
06377 
06378         worker->curs[i].x = x;
06379       }
06380     }
06381     else
06382     {
06383       FT_Fixed  scale       = 0;
06384       FT_Bool   scale_valid = 0;
06385 
06386 
06387       /* interpolation */
06388       for ( i = p1; i <= p2; i++ )
06389       {
06390         FT_F26Dot6  x = worker->orgs[i].x;
06391 
06392 
06393         if ( x <= org1 )
06394           x += delta1;
06395 
06396         else if ( x >= org2 )
06397           x += delta2;
06398 
06399         else
06400         {
06401           if ( !scale_valid )
06402           {
06403             scale_valid = 1;
06404             scale       = TT_MULDIV( org2 + delta2 - ( org1 + delta1 ),
06405                                      0x10000L, orus2 - orus1 );
06406           }
06407 
06408           x = ( org1 + delta1 ) +
06409               TT_MULFIX( worker->orus[i].x - orus1, scale );
06410         }
06411         worker->curs[i].x = x;
06412       }
06413     }
06414   }
06415 
06416 
06417   /*************************************************************************/
06418   /*                                                                       */
06419   /* IUP[a]:       Interpolate Untouched Points                            */
06420   /* Opcode range: 0x30-0x31                                               */
06421   /* Stack:        -->                                                     */
06422   /*                                                                       */
06423   static void
06424   Ins_IUP( INS_ARG )
06425   {
06426     IUP_WorkerRec  V;
06427     FT_Byte        mask;
06428 
06429     FT_UInt   first_point;   /* first point of contour        */
06430     FT_UInt   end_point;     /* end point (last+1) of contour */
06431 
06432     FT_UInt   first_touched; /* first touched point in contour   */
06433     FT_UInt   cur_touched;   /* current touched point in contour */
06434 
06435     FT_UInt   point;         /* current point   */
06436     FT_Short  contour;       /* current contour */
06437 
06438     FT_UNUSED_ARG;
06439 
06440 
06441     /* ignore empty outlines */
06442     if ( CUR.pts.n_contours == 0 )
06443       return;
06444 
06445     if ( CUR.opcode & 1 )
06446     {
06447       mask   = FT_CURVE_TAG_TOUCH_X;
06448       V.orgs = CUR.pts.org;
06449       V.curs = CUR.pts.cur;
06450       V.orus = CUR.pts.orus;
06451     }
06452     else
06453     {
06454       mask   = FT_CURVE_TAG_TOUCH_Y;
06455       V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
06456       V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
06457       V.orus = (FT_Vector*)( (FT_Pos*)CUR.pts.orus + 1 );
06458     }
06459     V.max_points = CUR.pts.n_points;
06460 
06461     contour = 0;
06462     point   = 0;
06463 
06464     do
06465     {
06466       end_point   = CUR.pts.contours[contour] - CUR.pts.first_point;
06467       first_point = point;
06468 
06469       if ( CUR.pts.n_points <= end_point )
06470         end_point = CUR.pts.n_points;
06471 
06472       while ( point <= end_point && ( CUR.pts.tags[point] & mask ) == 0 )
06473         point++;
06474 
06475       if ( point <= end_point )
06476       {
06477         first_touched = point;
06478         cur_touched   = point;
06479 
06480         point++;
06481 
06482         while ( point <= end_point )
06483         {
06484           if ( ( CUR.pts.tags[point] & mask ) != 0 )
06485           {
06486             if ( point > 0 )
06487               _iup_worker_interpolate( &V,
06488                                        cur_touched + 1,
06489                                        point - 1,
06490                                        cur_touched,
06491                                        point );
06492             cur_touched = point;
06493           }
06494 
06495           point++;
06496         }
06497 
06498         if ( cur_touched == first_touched )
06499           _iup_worker_shift( &V, first_point, end_point, cur_touched );
06500         else
06501         {
06502           _iup_worker_interpolate( &V,
06503                                    (FT_UShort)( cur_touched + 1 ),
06504                                    end_point,
06505                                    cur_touched,
06506                                    first_touched );
06507 
06508           if ( first_touched > 0 )
06509             _iup_worker_interpolate( &V,
06510                                      first_point,
06511                                      first_touched - 1,
06512                                      cur_touched,
06513                                      first_touched );
06514         }
06515       }
06516       contour++;
06517     } while ( contour < CUR.pts.n_contours );
06518   }
06519 
06520 
06521   /*************************************************************************/
06522   /*                                                                       */
06523   /* DELTAPn[]:    DELTA exceptions P1, P2, P3                             */
06524   /* Opcode range: 0x5D,0x71,0x72                                          */
06525   /* Stack:        uint32 (2 * uint32)... -->                              */
06526   /*                                                                       */
06527   static void
06528   Ins_DELTAP( INS_ARG )
06529   {
06530     FT_ULong   k, nump;
06531     FT_UShort  A;
06532     FT_ULong   C;
06533     FT_Long    B;
06534 
06535 
06536 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
06537     /* Delta hinting is covered by US Patent 5159668. */
06538     if ( CUR.face->unpatented_hinting )
06539     {
06540       FT_Long  n = args[0] * 2;
06541 
06542 
06543       if ( CUR.args < n )
06544       {
06545         CUR.error = TT_Err_Too_Few_Arguments;
06546         return;
06547       }
06548 
06549       CUR.args -= n;
06550       CUR.new_top = CUR.args;
06551       return;
06552     }
06553 #endif
06554 
06555     nump = (FT_ULong)args[0];   /* some points theoretically may occur more
06556                                    than once, thus UShort isn't enough */
06557 
06558     for ( k = 1; k <= nump; k++ )
06559     {
06560       if ( CUR.args < 2 )
06561       {
06562         CUR.error = TT_Err_Too_Few_Arguments;
06563         return;
06564       }
06565 
06566       CUR.args -= 2;
06567 
06568       A = (FT_UShort)CUR.stack[CUR.args + 1];
06569       B = CUR.stack[CUR.args];
06570 
06571       /* XXX: Because some popular fonts contain some invalid DeltaP */
06572       /*      instructions, we simply ignore them when the stacked   */
06573       /*      point reference is off limit, rather than returning an */
06574       /*      error.  As a delta instruction doesn't change a glyph  */
06575       /*      in great ways, this shouldn't be a problem.            */
06576 
06577       if ( !BOUNDS( A, CUR.zp0.n_points ) )
06578       {
06579         C = ( (FT_ULong)B & 0xF0 ) >> 4;
06580 
06581         switch ( CUR.opcode )
06582         {
06583         case 0x5D:
06584           break;
06585 
06586         case 0x71:
06587           C += 16;
06588           break;
06589 
06590         case 0x72:
06591           C += 32;
06592           break;
06593         }
06594 
06595         C += CUR.GS.delta_base;
06596 
06597         if ( CURRENT_Ppem() == (FT_Long)C )
06598         {
06599           B = ( (FT_ULong)B & 0xF ) - 8;
06600           if ( B >= 0 )
06601             B++;
06602           B = B * 64 / ( 1L << CUR.GS.delta_shift );
06603 
06604           CUR_Func_move( &CUR.zp0, A, B );
06605         }
06606       }
06607       else
06608         if ( CUR.pedantic_hinting )
06609           CUR.error = TT_Err_Invalid_Reference;
06610     }
06611 
06612     CUR.new_top = CUR.args;
06613   }
06614 
06615 
06616   /*************************************************************************/
06617   /*                                                                       */
06618   /* DELTACn[]:    DELTA exceptions C1, C2, C3                             */
06619   /* Opcode range: 0x73,0x74,0x75                                          */
06620   /* Stack:        uint32 (2 * uint32)... -->                              */
06621   /*                                                                       */
06622   static void
06623   Ins_DELTAC( INS_ARG )
06624   {
06625     FT_ULong  nump, k;
06626     FT_ULong  A, C;
06627     FT_Long   B;
06628 
06629 
06630 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
06631     /* Delta hinting is covered by US Patent 5159668. */
06632     if ( CUR.face->unpatented_hinting )
06633     {
06634       FT_Long  n = args[0] * 2;
06635 
06636 
06637       if ( CUR.args < n )
06638       {
06639         CUR.error = TT_Err_Too_Few_Arguments;
06640         return;
06641       }
06642 
06643       CUR.args -= n;
06644       CUR.new_top = CUR.args;
06645       return;
06646     }
06647 #endif
06648 
06649     nump = (FT_ULong)args[0];
06650 
06651     for ( k = 1; k <= nump; k++ )
06652     {
06653       if ( CUR.args < 2 )
06654       {
06655         CUR.error = TT_Err_Too_Few_Arguments;
06656         return;
06657       }
06658 
06659       CUR.args -= 2;
06660 
06661       A = (FT_ULong)CUR.stack[CUR.args + 1];
06662       B = CUR.stack[CUR.args];
06663 
06664       if ( BOUNDS( A, CUR.cvtSize ) )
06665       {
06666         if ( CUR.pedantic_hinting )
06667         {
06668           CUR.error = TT_Err_Invalid_Reference;
06669           return;
06670         }
06671       }
06672       else
06673       {
06674         C = ( (FT_ULong)B & 0xF0 ) >> 4;
06675 
06676         switch ( CUR.opcode )
06677         {
06678         case 0x73:
06679           break;
06680 
06681         case 0x74:
06682           C += 16;
06683           break;
06684 
06685         case 0x75:
06686           C += 32;
06687           break;
06688         }
06689 
06690         C += CUR.GS.delta_base;
06691 
06692         if ( CURRENT_Ppem() == (FT_Long)C )
06693         {
06694           B = ( (FT_ULong)B & 0xF ) - 8;
06695           if ( B >= 0 )
06696             B++;
06697           B = B * 64 / ( 1L << CUR.GS.delta_shift );
06698 
06699           CUR_Func_move_cvt( A, B );
06700         }
06701       }
06702     }
06703 
06704     CUR.new_top = CUR.args;
06705   }
06706 
06707 
06708   /*************************************************************************/
06709   /*                                                                       */
06710   /* MISC. INSTRUCTIONS                                                    */
06711   /*                                                                       */
06712   /*************************************************************************/
06713 
06714 
06715   /*************************************************************************/
06716   /*                                                                       */
06717   /* GETINFO[]:    GET INFOrmation                                         */
06718   /* Opcode range: 0x88                                                    */
06719   /* Stack:        uint32 --> uint32                                       */
06720   /*                                                                       */
06721   static void
06722   Ins_GETINFO( INS_ARG )
06723   {
06724     FT_Long  K;
06725 
06726 
06727     K = 0;
06728 
06729     /* We return MS rasterizer version 1.7 for the font scaler. */
06730     if ( ( args[0] & 1 ) != 0 )
06731       K = 35;
06732 
06733     /* Has the glyph been rotated? */
06734     if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated )
06735       K |= 0x80;
06736 
06737     /* Has the glyph been stretched? */
06738     if ( ( args[0] & 4 ) != 0 && CUR.tt_metrics.stretched )
06739       K |= 1 << 8;
06740 
06741     /* Are we hinting for grayscale? */
06742     if ( ( args[0] & 32 ) != 0 && CUR.grayscale )
06743       K |= 1 << 12;
06744 
06745     args[0] = K;
06746   }
06747 
06748 
06749   static void
06750   Ins_UNKNOWN( INS_ARG )
06751   {
06752     TT_DefRecord*  def   = CUR.IDefs;
06753     TT_DefRecord*  limit = def + CUR.numIDefs;
06754 
06755     FT_UNUSED_ARG;
06756 
06757 
06758     for ( ; def < limit; def++ )
06759     {
06760       if ( (FT_Byte)def->opc == CUR.opcode && def->active )
06761       {
06762         TT_CallRec*  call;
06763 
06764 
06765         if ( CUR.callTop >= CUR.callSize )
06766         {
06767           CUR.error = TT_Err_Stack_Overflow;
06768           return;
06769         }
06770 
06771         call = CUR.callStack + CUR.callTop++;
06772 
06773         call->Caller_Range = CUR.curRange;
06774         call->Caller_IP    = CUR.IP+1;
06775         call->Cur_Count    = 1;
06776         call->Cur_Restart  = def->start;
06777 
06778         INS_Goto_CodeRange( def->range, def->start );
06779 
06780         CUR.step_ins = FALSE;
06781         return;
06782       }
06783     }
06784 
06785     CUR.error = TT_Err_Invalid_Opcode;
06786   }
06787 
06788 
06789 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
06790 
06791 
06792   static
06793   TInstruction_Function  Instruct_Dispatch[256] =
06794   {
06795     /* Opcodes are gathered in groups of 16. */
06796     /* Please keep the spaces as they are.   */
06797 
06798     /*  SVTCA  y  */  Ins_SVTCA,
06799     /*  SVTCA  x  */  Ins_SVTCA,
06800     /*  SPvTCA y  */  Ins_SPVTCA,
06801     /*  SPvTCA x  */  Ins_SPVTCA,
06802     /*  SFvTCA y  */  Ins_SFVTCA,
06803     /*  SFvTCA x  */  Ins_SFVTCA,
06804     /*  SPvTL //  */  Ins_SPVTL,
06805     /*  SPvTL +   */  Ins_SPVTL,
06806     /*  SFvTL //  */  Ins_SFVTL,
06807     /*  SFvTL +   */  Ins_SFVTL,
06808     /*  SPvFS     */  Ins_SPVFS,
06809     /*  SFvFS     */  Ins_SFVFS,
06810     /*  GPV       */  Ins_GPV,
06811     /*  GFV       */  Ins_GFV,
06812     /*  SFvTPv    */  Ins_SFVTPV,
06813     /*  ISECT     */  Ins_ISECT,
06814 
06815     /*  SRP0      */  Ins_SRP0,
06816     /*  SRP1      */  Ins_SRP1,
06817     /*  SRP2      */  Ins_SRP2,
06818     /*  SZP0      */  Ins_SZP0,
06819     /*  SZP1      */  Ins_SZP1,
06820     /*  SZP2      */  Ins_SZP2,
06821     /*  SZPS      */  Ins_SZPS,
06822     /*  SLOOP     */  Ins_SLOOP,
06823     /*  RTG       */  Ins_RTG,
06824     /*  RTHG      */  Ins_RTHG,
06825     /*  SMD       */  Ins_SMD,
06826     /*  ELSE      */  Ins_ELSE,
06827     /*  JMPR      */  Ins_JMPR,
06828     /*  SCvTCi    */  Ins_SCVTCI,
06829     /*  SSwCi     */  Ins_SSWCI,
06830     /*  SSW       */  Ins_SSW,
06831 
06832     /*  DUP       */  Ins_DUP,
06833     /*  POP       */  Ins_POP,
06834     /*  CLEAR     */  Ins_CLEAR,
06835     /*  SWAP      */  Ins_SWAP,
06836     /*  DEPTH     */  Ins_DEPTH,
06837     /*  CINDEX    */  Ins_CINDEX,
06838     /*  MINDEX    */  Ins_MINDEX,
06839     /*  AlignPTS  */  Ins_ALIGNPTS,
06840     /*  INS_0x28  */  Ins_UNKNOWN,
06841     /*  UTP       */  Ins_UTP,
06842     /*  LOOPCALL  */  Ins_LOOPCALL,
06843     /*  CALL      */  Ins_CALL,
06844     /*  FDEF      */  Ins_FDEF,
06845     /*  ENDF      */  Ins_ENDF,
06846     /*  MDAP[0]   */  Ins_MDAP,
06847     /*  MDAP[1]   */  Ins_MDAP,
06848 
06849     /*  IUP[0]    */  Ins_IUP,
06850     /*  IUP[1]    */  Ins_IUP,
06851     /*  SHP[0]    */  Ins_SHP,
06852     /*  SHP[1]    */  Ins_SHP,
06853     /*  SHC[0]    */  Ins_SHC,
06854     /*  SHC[1]    */  Ins_SHC,
06855     /*  SHZ[0]    */  Ins_SHZ,
06856     /*  SHZ[1]    */  Ins_SHZ,
06857     /*  SHPIX     */  Ins_SHPIX,
06858     /*  IP        */  Ins_IP,
06859     /*  MSIRP[0]  */  Ins_MSIRP,
06860     /*  MSIRP[1]  */  Ins_MSIRP,
06861     /*  AlignRP   */  Ins_ALIGNRP,
06862     /*  RTDG      */  Ins_RTDG,
06863     /*  MIAP[0]   */  Ins_MIAP,
06864     /*  MIAP[1]   */  Ins_MIAP,
06865 
06866     /*  NPushB    */  Ins_NPUSHB,
06867     /*  NPushW    */  Ins_NPUSHW,
06868     /*  WS        */  Ins_WS,
06869     /*  RS        */  Ins_RS,
06870     /*  WCvtP     */  Ins_WCVTP,
06871     /*  RCvt      */  Ins_RCVT,
06872     /*  GC[0]     */  Ins_GC,
06873     /*  GC[1]     */  Ins_GC,
06874     /*  SCFS      */  Ins_SCFS,
06875     /*  MD[0]     */  Ins_MD,
06876     /*  MD[1]     */  Ins_MD,
06877     /*  MPPEM     */  Ins_MPPEM,
06878     /*  MPS       */  Ins_MPS,
06879     /*  FlipON    */  Ins_FLIPON,
06880     /*  FlipOFF   */  Ins_FLIPOFF,
06881     /*  DEBUG     */  Ins_DEBUG,
06882 
06883     /*  LT        */  Ins_LT,
06884     /*  LTEQ      */  Ins_LTEQ,
06885     /*  GT        */  Ins_GT,
06886     /*  GTEQ      */  Ins_GTEQ,
06887     /*  EQ        */  Ins_EQ,
06888     /*  NEQ       */  Ins_NEQ,
06889     /*  ODD       */  Ins_ODD,
06890     /*  EVEN      */  Ins_EVEN,
06891     /*  IF        */  Ins_IF,
06892     /*  EIF       */  Ins_EIF,
06893     /*  AND       */  Ins_AND,
06894     /*  OR        */  Ins_OR,
06895     /*  NOT       */  Ins_NOT,
06896     /*  DeltaP1   */  Ins_DELTAP,
06897     /*  SDB       */  Ins_SDB,
06898     /*  SDS       */  Ins_SDS,
06899 
06900     /*  ADD       */  Ins_ADD,
06901     /*  SUB       */  Ins_SUB,
06902     /*  DIV       */  Ins_DIV,
06903     /*  MUL       */  Ins_MUL,
06904     /*  ABS       */  Ins_ABS,
06905     /*  NEG       */  Ins_NEG,
06906     /*  FLOOR     */  Ins_FLOOR,
06907     /*  CEILING   */  Ins_CEILING,
06908     /*  ROUND[0]  */  Ins_ROUND,
06909     /*  ROUND[1]  */  Ins_ROUND,
06910     /*  ROUND[2]  */  Ins_ROUND,
06911     /*  ROUND[3]  */  Ins_ROUND,
06912     /*  NROUND[0] */  Ins_NROUND,
06913     /*  NROUND[1] */  Ins_NROUND,
06914     /*  NROUND[2] */  Ins_NROUND,
06915     /*  NROUND[3] */  Ins_NROUND,
06916 
06917     /*  WCvtF     */  Ins_WCVTF,
06918     /*  DeltaP2   */  Ins_DELTAP,
06919     /*  DeltaP3   */  Ins_DELTAP,
06920     /*  DeltaCn[0] */ Ins_DELTAC,
06921     /*  DeltaCn[1] */ Ins_DELTAC,
06922     /*  DeltaCn[2] */ Ins_DELTAC,
06923     /*  SROUND    */  Ins_SROUND,
06924     /*  S45Round  */  Ins_S45ROUND,
06925     /*  JROT      */  Ins_JROT,
06926     /*  JROF      */  Ins_JROF,
06927     /*  ROFF      */  Ins_ROFF,
06928     /*  INS_0x7B  */  Ins_UNKNOWN,
06929     /*  RUTG      */  Ins_RUTG,
06930     /*  RDTG      */  Ins_RDTG,
06931     /*  SANGW     */  Ins_SANGW,
06932     /*  AA        */  Ins_AA,
06933 
06934     /*  FlipPT    */  Ins_FLIPPT,
06935     /*  FlipRgON  */  Ins_FLIPRGON,
06936     /*  FlipRgOFF */  Ins_FLIPRGOFF,
06937     /*  INS_0x83  */  Ins_UNKNOWN,
06938     /*  INS_0x84  */  Ins_UNKNOWN,
06939     /*  ScanCTRL  */  Ins_SCANCTRL,
06940     /*  SDPVTL[0] */  Ins_SDPVTL,
06941     /*  SDPVTL[1] */  Ins_SDPVTL,
06942     /*  GetINFO   */  Ins_GETINFO,
06943     /*  IDEF      */  Ins_IDEF,
06944     /*  ROLL      */  Ins_ROLL,
06945     /*  MAX       */  Ins_MAX,
06946     /*  MIN       */  Ins_MIN,
06947     /*  ScanTYPE  */  Ins_SCANTYPE,
06948     /*  InstCTRL  */  Ins_INSTCTRL,
06949     /*  INS_0x8F  */  Ins_UNKNOWN,
06950 
06951     /*  INS_0x90  */   Ins_UNKNOWN,
06952     /*  INS_0x91  */   Ins_UNKNOWN,
06953     /*  INS_0x92  */   Ins_UNKNOWN,
06954     /*  INS_0x93  */   Ins_UNKNOWN,
06955     /*  INS_0x94  */   Ins_UNKNOWN,
06956     /*  INS_0x95  */   Ins_UNKNOWN,
06957     /*  INS_0x96  */   Ins_UNKNOWN,
06958     /*  INS_0x97  */   Ins_UNKNOWN,
06959     /*  INS_0x98  */   Ins_UNKNOWN,
06960     /*  INS_0x99  */   Ins_UNKNOWN,
06961     /*  INS_0x9A  */   Ins_UNKNOWN,
06962     /*  INS_0x9B  */   Ins_UNKNOWN,
06963     /*  INS_0x9C  */   Ins_UNKNOWN,
06964     /*  INS_0x9D  */   Ins_UNKNOWN,
06965     /*  INS_0x9E  */   Ins_UNKNOWN,
06966     /*  INS_0x9F  */   Ins_UNKNOWN,
06967 
06968     /*  INS_0xA0  */   Ins_UNKNOWN,
06969     /*  INS_0xA1  */   Ins_UNKNOWN,
06970     /*  INS_0xA2  */   Ins_UNKNOWN,
06971     /*  INS_0xA3  */   Ins_UNKNOWN,
06972     /*  INS_0xA4  */   Ins_UNKNOWN,
06973     /*  INS_0xA5  */   Ins_UNKNOWN,
06974     /*  INS_0xA6  */   Ins_UNKNOWN,
06975     /*  INS_0xA7  */   Ins_UNKNOWN,
06976     /*  INS_0xA8  */   Ins_UNKNOWN,
06977     /*  INS_0xA9  */   Ins_UNKNOWN,
06978     /*  INS_0xAA  */   Ins_UNKNOWN,
06979     /*  INS_0xAB  */   Ins_UNKNOWN,
06980     /*  INS_0xAC  */   Ins_UNKNOWN,
06981     /*  INS_0xAD  */   Ins_UNKNOWN,
06982     /*  INS_0xAE  */   Ins_UNKNOWN,
06983     /*  INS_0xAF  */   Ins_UNKNOWN,
06984 
06985     /*  PushB[0]  */  Ins_PUSHB,
06986     /*  PushB[1]  */  Ins_PUSHB,
06987     /*  PushB[2]  */  Ins_PUSHB,
06988     /*  PushB[3]  */  Ins_PUSHB,
06989     /*  PushB[4]  */  Ins_PUSHB,
06990     /*  PushB[5]  */  Ins_PUSHB,
06991     /*  PushB[6]  */  Ins_PUSHB,
06992     /*  PushB[7]  */  Ins_PUSHB,
06993     /*  PushW[0]  */  Ins_PUSHW,
06994     /*  PushW[1]  */  Ins_PUSHW,
06995     /*  PushW[2]  */  Ins_PUSHW,
06996     /*  PushW[3]  */  Ins_PUSHW,
06997     /*  PushW[4]  */  Ins_PUSHW,
06998     /*  PushW[5]  */  Ins_PUSHW,
06999     /*  PushW[6]  */  Ins_PUSHW,
07000     /*  PushW[7]  */  Ins_PUSHW,
07001 
07002     /*  MDRP[00]  */  Ins_MDRP,
07003     /*  MDRP[01]  */  Ins_MDRP,
07004     /*  MDRP[02]  */  Ins_MDRP,
07005     /*  MDRP[03]  */  Ins_MDRP,
07006     /*  MDRP[04]  */  Ins_MDRP,
07007     /*  MDRP[05]  */  Ins_MDRP,
07008     /*  MDRP[06]  */  Ins_MDRP,
07009     /*  MDRP[07]  */  Ins_MDRP,
07010     /*  MDRP[08]  */  Ins_MDRP,
07011     /*  MDRP[09]  */  Ins_MDRP,
07012     /*  MDRP[10]  */  Ins_MDRP,
07013     /*  MDRP[11]  */  Ins_MDRP,
07014     /*  MDRP[12]  */  Ins_MDRP,
07015     /*  MDRP[13]  */  Ins_MDRP,
07016     /*  MDRP[14]  */  Ins_MDRP,
07017     /*  MDRP[15]  */  Ins_MDRP,
07018 
07019     /*  MDRP[16]  */  Ins_MDRP,
07020     /*  MDRP[17]  */  Ins_MDRP,
07021     /*  MDRP[18]  */  Ins_MDRP,
07022     /*  MDRP[19]  */  Ins_MDRP,
07023     /*  MDRP[20]  */  Ins_MDRP,
07024     /*  MDRP[21]  */  Ins_MDRP,
07025     /*  MDRP[22]  */  Ins_MDRP,
07026     /*  MDRP[23]  */  Ins_MDRP,
07027     /*  MDRP[24]  */  Ins_MDRP,
07028     /*  MDRP[25]  */  Ins_MDRP,
07029     /*  MDRP[26]  */  Ins_MDRP,
07030     /*  MDRP[27]  */  Ins_MDRP,
07031     /*  MDRP[28]  */  Ins_MDRP,
07032     /*  MDRP[29]  */  Ins_MDRP,
07033     /*  MDRP[30]  */  Ins_MDRP,
07034     /*  MDRP[31]  */  Ins_MDRP,
07035 
07036     /*  MIRP[00]  */  Ins_MIRP,
07037     /*  MIRP[01]  */  Ins_MIRP,
07038     /*  MIRP[02]  */  Ins_MIRP,
07039     /*  MIRP[03]  */  Ins_MIRP,
07040     /*  MIRP[04]  */  Ins_MIRP,
07041     /*  MIRP[05]  */  Ins_MIRP,
07042     /*  MIRP[06]  */  Ins_MIRP,
07043     /*  MIRP[07]  */  Ins_MIRP,
07044     /*  MIRP[08]  */  Ins_MIRP,
07045     /*  MIRP[09]  */  Ins_MIRP,
07046     /*  MIRP[10]  */  Ins_MIRP,
07047     /*  MIRP[11]  */  Ins_MIRP,
07048     /*  MIRP[12]  */  Ins_MIRP,
07049     /*  MIRP[13]  */  Ins_MIRP,
07050     /*  MIRP[14]  */  Ins_MIRP,
07051     /*  MIRP[15]  */  Ins_MIRP,
07052 
07053     /*  MIRP[16]  */  Ins_MIRP,
07054     /*  MIRP[17]  */  Ins_MIRP,
07055     /*  MIRP[18]  */  Ins_MIRP,
07056     /*  MIRP[19]  */  Ins_MIRP,
07057     /*  MIRP[20]  */  Ins_MIRP,
07058     /*  MIRP[21]  */  Ins_MIRP,
07059     /*  MIRP[22]  */  Ins_MIRP,
07060     /*  MIRP[23]  */  Ins_MIRP,
07061     /*  MIRP[24]  */  Ins_MIRP,
07062     /*  MIRP[25]  */  Ins_MIRP,
07063     /*  MIRP[26]  */  Ins_MIRP,
07064     /*  MIRP[27]  */  Ins_MIRP,
07065     /*  MIRP[28]  */  Ins_MIRP,
07066     /*  MIRP[29]  */  Ins_MIRP,
07067     /*  MIRP[30]  */  Ins_MIRP,
07068     /*  MIRP[31]  */  Ins_MIRP
07069   };
07070 
07071 
07072 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
07073 
07074 
07075   /*************************************************************************/
07076   /*                                                                       */
07077   /* RUN                                                                   */
07078   /*                                                                       */
07079   /*  This function executes a run of opcodes.  It will exit in the        */
07080   /*  following cases:                                                     */
07081   /*                                                                       */
07082   /*  - Errors (in which case it returns FALSE).                           */
07083   /*                                                                       */
07084   /*  - Reaching the end of the main code range (returns TRUE).            */
07085   /*    Reaching the end of a code range within a function call is an      */
07086   /*    error.                                                             */
07087   /*                                                                       */
07088   /*  - After executing one single opcode, if the flag `Instruction_Trap'  */
07089   /*    is set to TRUE (returns TRUE).                                     */
07090   /*                                                                       */
07091   /*  On exit with TRUE, test IP < CodeSize to know whether it comes from  */
07092   /*  an instruction trap or a normal termination.                         */
07093   /*                                                                       */
07094   /*                                                                       */
07095   /*  Note: The documented DEBUG opcode pops a value from the stack.  This */
07096   /*        behaviour is unsupported; here a DEBUG opcode is always an     */
07097   /*        error.                                                         */
07098   /*                                                                       */
07099   /*                                                                       */
07100   /* THIS IS THE INTERPRETER'S MAIN LOOP.                                  */
07101   /*                                                                       */
07102   /*  Instructions appear in the specification's order.                    */
07103   /*                                                                       */
07104   /*************************************************************************/
07105 
07106 
07107   /* documentation is in ttinterp.h */
07108 
07109   FT_EXPORT_DEF( FT_Error )
07110   TT_RunIns( TT_ExecContext  exc )
07111   {
07112     FT_Long  ins_counter = 0;  /* executed instructions counter */
07113 
07114 
07115 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
07116     cur = *exc;
07117 #endif
07118 
07119     /* set CVT functions */
07120     CUR.tt_metrics.ratio = 0;
07121     if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
07122     {
07123       /* non-square pixels, use the stretched routines */
07124       CUR.func_read_cvt  = Read_CVT_Stretched;
07125       CUR.func_write_cvt = Write_CVT_Stretched;
07126       CUR.func_move_cvt  = Move_CVT_Stretched;
07127     }
07128     else
07129     {
07130       /* square pixels, use normal routines */
07131       CUR.func_read_cvt  = Read_CVT;
07132       CUR.func_write_cvt = Write_CVT;
07133       CUR.func_move_cvt  = Move_CVT;
07134     }
07135 
07136     COMPUTE_Funcs();
07137     COMPUTE_Round( (FT_Byte)exc->GS.round_state );
07138 
07139     do
07140     {
07141       CUR.opcode = CUR.code[CUR.IP];
07142 
07143       if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )
07144       {
07145         if ( CUR.IP + 1 > CUR.codeSize )
07146           goto LErrorCodeOverflow_;
07147 
07148         CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
07149       }
07150 
07151       if ( CUR.IP + CUR.length > CUR.codeSize )
07152         goto LErrorCodeOverflow_;
07153 
07154       /* First, let's check for empty stack and overflow */
07155       CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 );
07156 
07157       /* `args' is the top of the stack once arguments have been popped. */
07158       /* One can also interpret it as the index of the last argument.    */
07159       if ( CUR.args < 0 )
07160       {
07161         CUR.error = TT_Err_Too_Few_Arguments;
07162         goto LErrorLabel_;
07163       }
07164 
07165       CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 );
07166 
07167       /* `new_top' is the new top of the stack, after the instruction's */
07168       /* execution.  `top' will be set to `new_top' after the `switch'  */
07169       /* statement.                                                     */
07170       if ( CUR.new_top > CUR.stackSize )
07171       {
07172         CUR.error = TT_Err_Stack_Overflow;
07173         goto LErrorLabel_;
07174       }
07175 
07176       CUR.step_ins = TRUE;
07177       CUR.error    = TT_Err_Ok;
07178 
07179 #ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
07180 
07181       {
07182         FT_Long*  args   = CUR.stack + CUR.args;
07183         FT_Byte   opcode = CUR.opcode;
07184 
07185 
07186 #undef  ARRAY_BOUND_ERROR
07187 #define ARRAY_BOUND_ERROR  goto Set_Invalid_Ref
07188 
07189 
07190         switch ( opcode )
07191         {
07192         case 0x00:  /* SVTCA y  */
07193         case 0x01:  /* SVTCA x  */
07194         case 0x02:  /* SPvTCA y */
07195         case 0x03:  /* SPvTCA x */
07196         case 0x04:  /* SFvTCA y */
07197         case 0x05:  /* SFvTCA x */
07198           {
07199             FT_Short AA, BB;
07200 
07201 
07202             AA = (FT_Short)( ( opcode & 1 ) << 14 );
07203             BB = (FT_Short)( AA ^ 0x4000 );
07204 
07205             if ( opcode < 4 )
07206             {
07207               CUR.GS.projVector.x = AA;
07208               CUR.GS.projVector.y = BB;
07209 
07210               CUR.GS.dualVector.x = AA;
07211               CUR.GS.dualVector.y = BB;
07212             }
07213             else
07214             {
07215               GUESS_VECTOR( projVector );
07216             }
07217 
07218             if ( ( opcode & 2 ) == 0 )
07219             {
07220               CUR.GS.freeVector.x = AA;
07221               CUR.GS.freeVector.y = BB;
07222             }
07223             else
07224             {
07225               GUESS_VECTOR( freeVector );
07226             }
07227 
07228             COMPUTE_Funcs();
07229           }
07230           break;
07231 
07232         case 0x06:  /* SPvTL // */
07233         case 0x07:  /* SPvTL +  */
07234           DO_SPVTL
07235           break;
07236 
07237         case 0x08:  /* SFvTL // */
07238         case 0x09:  /* SFvTL +  */
07239           DO_SFVTL
07240           break;
07241 
07242         case 0x0A:  /* SPvFS */
07243           DO_SPVFS
07244           break;
07245 
07246         case 0x0B:  /* SFvFS */
07247           DO_SFVFS
07248           break;
07249 
07250         case 0x0C:  /* GPV */
07251           DO_GPV
07252           break;
07253 
07254         case 0x0D:  /* GFV */
07255           DO_GFV
07256           break;
07257 
07258         case 0x0E:  /* SFvTPv */
07259           DO_SFVTPV
07260           break;
07261 
07262         case 0x0F:  /* ISECT  */
07263           Ins_ISECT( EXEC_ARG_ args );
07264           break;
07265 
07266         case 0x10:  /* SRP0 */
07267           DO_SRP0
07268           break;
07269 
07270         case 0x11:  /* SRP1 */
07271           DO_SRP1
07272           break;
07273 
07274         case 0x12:  /* SRP2 */
07275           DO_SRP2
07276           break;
07277 
07278         case 0x13:  /* SZP0 */
07279           Ins_SZP0( EXEC_ARG_ args );
07280           break;
07281 
07282         case 0x14:  /* SZP1 */
07283           Ins_SZP1( EXEC_ARG_ args );
07284           break;
07285 
07286         case 0x15:  /* SZP2 */
07287           Ins_SZP2( EXEC_ARG_ args );
07288           break;
07289 
07290         case 0x16:  /* SZPS */
07291           Ins_SZPS( EXEC_ARG_ args );
07292           break;
07293 
07294         case 0x17:  /* SLOOP */
07295           DO_SLOOP
07296           break;
07297 
07298         case 0x18:  /* RTG */
07299           DO_RTG
07300           break;
07301 
07302         case 0x19:  /* RTHG */
07303           DO_RTHG
07304           break;
07305 
07306         case 0x1A:  /* SMD */
07307           DO_SMD
07308           break;
07309 
07310         case 0x1B:  /* ELSE */
07311           Ins_ELSE( EXEC_ARG_ args );
07312           break;
07313 
07314         case 0x1C:  /* JMPR */
07315           DO_JMPR
07316           break;
07317 
07318         case 0x1D:  /* SCVTCI */
07319           DO_SCVTCI
07320           break;
07321 
07322         case 0x1E:  /* SSWCI */
07323           DO_SSWCI
07324           break;
07325 
07326         case 0x1F:  /* SSW */
07327           DO_SSW
07328           break;
07329 
07330         case 0x20:  /* DUP */
07331           DO_DUP
07332           break;
07333 
07334         case 0x21:  /* POP */
07335           /* nothing :-) */
07336           break;
07337 
07338         case 0x22:  /* CLEAR */
07339           DO_CLEAR
07340           break;
07341 
07342         case 0x23:  /* SWAP */
07343           DO_SWAP
07344           break;
07345 
07346         case 0x24:  /* DEPTH */
07347           DO_DEPTH
07348           break;
07349 
07350         case 0x25:  /* CINDEX */
07351           DO_CINDEX
07352           break;
07353 
07354         case 0x26:  /* MINDEX */
07355           Ins_MINDEX( EXEC_ARG_ args );
07356           break;
07357 
07358         case 0x27:  /* ALIGNPTS */
07359           Ins_ALIGNPTS( EXEC_ARG_ args );
07360           break;
07361 
07362         case 0x28:  /* ???? */
07363           Ins_UNKNOWN( EXEC_ARG_ args );
07364           break;
07365 
07366         case 0x29:  /* UTP */
07367           Ins_UTP( EXEC_ARG_ args );
07368           break;
07369 
07370         case 0x2A:  /* LOOPCALL */
07371           Ins_LOOPCALL( EXEC_ARG_ args );
07372           break;
07373 
07374         case 0x2B:  /* CALL */
07375           Ins_CALL( EXEC_ARG_ args );
07376           break;
07377 
07378         case 0x2C:  /* FDEF */
07379           Ins_FDEF( EXEC_ARG_ args );
07380           break;
07381 
07382         case 0x2D:  /* ENDF */
07383           Ins_ENDF( EXEC_ARG_ args );
07384           break;
07385 
07386         case 0x2E:  /* MDAP */
07387         case 0x2F:  /* MDAP */
07388           Ins_MDAP( EXEC_ARG_ args );
07389           break;
07390 
07391 
07392         case 0x30:  /* IUP */
07393         case 0x31:  /* IUP */
07394           Ins_IUP( EXEC_ARG_ args );
07395           break;
07396 
07397         case 0x32:  /* SHP */
07398         case 0x33:  /* SHP */
07399           Ins_SHP( EXEC_ARG_ args );
07400           break;
07401 
07402         case 0x34:  /* SHC */
07403         case 0x35:  /* SHC */
07404           Ins_SHC( EXEC_ARG_ args );
07405           break;
07406 
07407         case 0x36:  /* SHZ */
07408         case 0x37:  /* SHZ */
07409           Ins_SHZ( EXEC_ARG_ args );
07410           break;
07411 
07412         case 0x38:  /* SHPIX */
07413           Ins_SHPIX( EXEC_ARG_ args );
07414           break;
07415 
07416         case 0x39:  /* IP    */
07417           Ins_IP( EXEC_ARG_ args );
07418           break;
07419 
07420         case 0x3A:  /* MSIRP */
07421         case 0x3B:  /* MSIRP */
07422           Ins_MSIRP( EXEC_ARG_ args );
07423           break;
07424 
07425         case 0x3C:  /* AlignRP */
07426           Ins_ALIGNRP( EXEC_ARG_ args );
07427           break;
07428 
07429         case 0x3D:  /* RTDG */
07430           DO_RTDG
07431           break;
07432 
07433         case 0x3E:  /* MIAP */
07434         case 0x3F:  /* MIAP */
07435           Ins_MIAP( EXEC_ARG_ args );
07436           break;
07437 
07438         case 0x40:  /* NPUSHB */
07439           Ins_NPUSHB( EXEC_ARG_ args );
07440           break;
07441 
07442         case 0x41:  /* NPUSHW */
07443           Ins_NPUSHW( EXEC_ARG_ args );
07444           break;
07445 
07446         case 0x42:  /* WS */
07447           DO_WS
07448           break;
07449 
07450       Set_Invalid_Ref:
07451             CUR.error = TT_Err_Invalid_Reference;
07452           break;
07453 
07454         case 0x43:  /* RS */
07455           DO_RS
07456           break;
07457 
07458         case 0x44:  /* WCVTP */
07459           DO_WCVTP
07460           break;
07461 
07462         case 0x45:  /* RCVT */
07463           DO_RCVT
07464           break;
07465 
07466         case 0x46:  /* GC */
07467         case 0x47:  /* GC */
07468           Ins_GC( EXEC_ARG_ args );
07469           break;
07470 
07471         case 0x48:  /* SCFS */
07472           Ins_SCFS( EXEC_ARG_ args );
07473           break;
07474 
07475         case 0x49:  /* MD */
07476         case 0x4A:  /* MD */
07477           Ins_MD( EXEC_ARG_ args );
07478           break;
07479 
07480         case 0x4B:  /* MPPEM */
07481           DO_MPPEM
07482           break;
07483 
07484         case 0x4C:  /* MPS */
07485           DO_MPS
07486           break;
07487 
07488         case 0x4D:  /* FLIPON */
07489           DO_FLIPON
07490           break;
07491 
07492         case 0x4E:  /* FLIPOFF */
07493           DO_FLIPOFF
07494           break;
07495 
07496         case 0x4F:  /* DEBUG */
07497           DO_DEBUG
07498           break;
07499 
07500         case 0x50:  /* LT */
07501           DO_LT
07502           break;
07503 
07504         case 0x51:  /* LTEQ */
07505           DO_LTEQ
07506           break;
07507 
07508         case 0x52:  /* GT */
07509           DO_GT
07510           break;
07511 
07512         case 0x53:  /* GTEQ */
07513           DO_GTEQ
07514           break;
07515 
07516         case 0x54:  /* EQ */
07517           DO_EQ
07518           break;
07519 
07520         case 0x55:  /* NEQ */
07521           DO_NEQ
07522           break;
07523 
07524         case 0x56:  /* ODD */
07525           DO_ODD
07526           break;
07527 
07528         case 0x57:  /* EVEN */
07529           DO_EVEN
07530           break;
07531 
07532         case 0x58:  /* IF */
07533           Ins_IF( EXEC_ARG_ args );
07534           break;
07535 
07536         case 0x59:  /* EIF */
07537           /* do nothing */
07538           break;
07539 
07540         case 0x5A:  /* AND */
07541           DO_AND
07542           break;
07543 
07544         case 0x5B:  /* OR */
07545           DO_OR
07546           break;
07547 
07548         case 0x5C:  /* NOT */
07549           DO_NOT
07550           break;
07551 
07552         case 0x5D:  /* DELTAP1 */
07553           Ins_DELTAP( EXEC_ARG_ args );
07554           break;
07555 
07556         case 0x5E:  /* SDB */
07557           DO_SDB
07558           break;
07559 
07560         case 0x5F:  /* SDS */
07561           DO_SDS
07562           break;
07563 
07564         case 0x60:  /* ADD */
07565           DO_ADD
07566           break;
07567 
07568         case 0x61:  /* SUB */
07569           DO_SUB
07570           break;
07571 
07572         case 0x62:  /* DIV */
07573           DO_DIV
07574           break;
07575 
07576         case 0x63:  /* MUL */
07577           DO_MUL
07578           break;
07579 
07580         case 0x64:  /* ABS */
07581           DO_ABS
07582           break;
07583 
07584         case 0x65:  /* NEG */
07585           DO_NEG
07586           break;
07587 
07588         case 0x66:  /* FLOOR */
07589           DO_FLOOR
07590           break;
07591 
07592         case 0x67:  /* CEILING */
07593           DO_CEILING
07594           break;
07595 
07596         case 0x68:  /* ROUND */
07597         case 0x69:  /* ROUND */
07598         case 0x6A:  /* ROUND */
07599         case 0x6B:  /* ROUND */
07600           DO_ROUND
07601           break;
07602 
07603         case 0x6C:  /* NROUND */
07604         case 0x6D:  /* NROUND */
07605         case 0x6E:  /* NRRUND */
07606         case 0x6F:  /* NROUND */
07607           DO_NROUND
07608           break;
07609 
07610         case 0x70:  /* WCVTF */
07611           DO_WCVTF
07612           break;
07613 
07614         case 0x71:  /* DELTAP2 */
07615         case 0x72:  /* DELTAP3 */
07616           Ins_DELTAP( EXEC_ARG_ args );
07617           break;
07618 
07619         case 0x73:  /* DELTAC0 */
07620         case 0x74:  /* DELTAC1 */
07621         case 0x75:  /* DELTAC2 */
07622           Ins_DELTAC( EXEC_ARG_ args );
07623           break;
07624 
07625         case 0x76:  /* SROUND */
07626           DO_SROUND
07627           break;
07628 
07629         case 0x77:  /* S45Round */
07630           DO_S45ROUND
07631           break;
07632 
07633         case 0x78:  /* JROT */
07634           DO_JROT
07635           break;
07636 
07637         case 0x79:  /* JROF */
07638           DO_JROF
07639           break;
07640 
07641         case 0x7A:  /* ROFF */
07642           DO_ROFF
07643           break;
07644 
07645         case 0x7B:  /* ???? */
07646           Ins_UNKNOWN( EXEC_ARG_ args );
07647           break;
07648 
07649         case 0x7C:  /* RUTG */
07650           DO_RUTG
07651           break;
07652 
07653         case 0x7D:  /* RDTG */
07654           DO_RDTG
07655           break;
07656 
07657         case 0x7E:  /* SANGW */
07658         case 0x7F:  /* AA    */
07659           /* nothing - obsolete */
07660           break;
07661 
07662         case 0x80:  /* FLIPPT */
07663           Ins_FLIPPT( EXEC_ARG_ args );
07664           break;
07665 
07666         case 0x81:  /* FLIPRGON */
07667           Ins_FLIPRGON( EXEC_ARG_ args );
07668           break;
07669 
07670         case 0x82:  /* FLIPRGOFF */
07671           Ins_FLIPRGOFF( EXEC_ARG_ args );
07672           break;
07673 
07674         case 0x83:  /* UNKNOWN */
07675         case 0x84:  /* UNKNOWN */
07676           Ins_UNKNOWN( EXEC_ARG_ args );
07677           break;
07678 
07679         case 0x85:  /* SCANCTRL */
07680           Ins_SCANCTRL( EXEC_ARG_ args );
07681           break;
07682 
07683         case 0x86:  /* SDPVTL */
07684         case 0x87:  /* SDPVTL */
07685           Ins_SDPVTL( EXEC_ARG_ args );
07686           break;
07687 
07688         case 0x88:  /* GETINFO */
07689           Ins_GETINFO( EXEC_ARG_ args );
07690           break;
07691 
07692         case 0x89:  /* IDEF */
07693           Ins_IDEF( EXEC_ARG_ args );
07694           break;
07695 
07696         case 0x8A:  /* ROLL */
07697           Ins_ROLL( EXEC_ARG_ args );
07698           break;
07699 
07700         case 0x8B:  /* MAX */
07701           DO_MAX
07702           break;
07703 
07704         case 0x8C:  /* MIN */
07705           DO_MIN
07706           break;
07707 
07708         case 0x8D:  /* SCANTYPE */
07709           Ins_SCANTYPE( EXEC_ARG_ args );
07710           break;
07711 
07712         case 0x8E:  /* INSTCTRL */
07713           Ins_INSTCTRL( EXEC_ARG_ args );
07714           break;
07715 
07716         case 0x8F:
07717           Ins_UNKNOWN( EXEC_ARG_ args );
07718           break;
07719 
07720         default:
07721           if ( opcode >= 0xE0 )
07722             Ins_MIRP( EXEC_ARG_ args );
07723           else if ( opcode >= 0xC0 )
07724             Ins_MDRP( EXEC_ARG_ args );
07725           else if ( opcode >= 0xB8 )
07726             Ins_PUSHW( EXEC_ARG_ args );
07727           else if ( opcode >= 0xB0 )
07728             Ins_PUSHB( EXEC_ARG_ args );
07729           else
07730             Ins_UNKNOWN( EXEC_ARG_ args );
07731         }
07732 
07733       }
07734 
07735 #else
07736 
07737       Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );
07738 
07739 #endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
07740 
07741       if ( CUR.error != TT_Err_Ok )
07742       {
07743         switch ( CUR.error )
07744         {
07745         case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
07746           {
07747             TT_DefRecord*  def   = CUR.IDefs;
07748             TT_DefRecord*  limit = def + CUR.numIDefs;
07749 
07750 
07751             for ( ; def < limit; def++ )
07752             {
07753               if ( def->active && CUR.opcode == (FT_Byte)def->opc )
07754               {
07755                 TT_CallRec*  callrec;
07756 
07757 
07758                 if ( CUR.callTop >= CUR.callSize )
07759                 {
07760                   CUR.error = TT_Err_Invalid_Reference;
07761                   goto LErrorLabel_;
07762                 }
07763 
07764                 callrec = &CUR.callStack[CUR.callTop];
07765 
07766                 callrec->Caller_Range = CUR.curRange;
07767                 callrec->Caller_IP    = CUR.IP + 1;
07768                 callrec->Cur_Count    = 1;
07769                 callrec->Cur_Restart  = def->start;
07770 
07771                 if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
07772                   goto LErrorLabel_;
07773 
07774                 goto LSuiteLabel_;
07775               }
07776             }
07777           }
07778 
07779           CUR.error = TT_Err_Invalid_Opcode;
07780           goto LErrorLabel_;
07781 
07782 #if 0
07783           break;   /* Unreachable code warning suppression.             */
07784                    /* Leave to remind in case a later change the editor */
07785                    /* to consider break;                                */
07786 #endif
07787 
07788         default:
07789           goto LErrorLabel_;
07790 
07791 #if 0
07792         break;
07793 #endif
07794         }
07795       }
07796 
07797       CUR.top = CUR.new_top;
07798 
07799       if ( CUR.step_ins )
07800         CUR.IP += CUR.length;
07801 
07802       /* increment instruction counter and check if we didn't */
07803       /* run this program for too long (e.g. infinite loops). */
07804       if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
07805         return TT_Err_Execution_Too_Long;
07806 
07807     LSuiteLabel_:
07808       if ( CUR.IP >= CUR.codeSize )
07809       {
07810         if ( CUR.callTop > 0 )
07811         {
07812           CUR.error = TT_Err_Code_Overflow;
07813           goto LErrorLabel_;
07814         }
07815         else
07816           goto LNo_Error_;
07817       }
07818     } while ( !CUR.instruction_trap );
07819 
07820   LNo_Error_:
07821 
07822 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
07823     *exc = cur;
07824 #endif
07825 
07826     return TT_Err_Ok;
07827 
07828   LErrorCodeOverflow_:
07829     CUR.error = TT_Err_Code_Overflow;
07830 
07831   LErrorLabel_:
07832 
07833 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
07834     *exc = cur;
07835 #endif
07836 
07837     return CUR.error;
07838   }
07839 
07840 
07841 #endif /* TT_USE_BYTECODE_INTERPRETER */
07842 
07843 
07844 /* END */

Generated on Tue Jul 5 14:13:53 2011 for ROOT_528-00b_version by  doxygen 1.5.1