ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

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

Generated on Sat May 26 2012 04:32:58 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.