Commit message: None
CVE: CVE-2018-6942
CWE: CWE-476
Vulnerability description: An issue was discovered in FreeType 2 through 2.9. A NULL pointer dereference in the Ins_GETVARIATION() function within ttinterp.c could lead to DoS via a crafted font file.

Project: savannah

  Compute_Funcs( TT_ExecContext  exc )
  {
    if ( exc->GS.freeVector.x == 0x4000 )
      exc->F_dot_P = exc->GS.projVector.x;
    else if ( exc->GS.freeVector.y == 0x4000 )
      exc->F_dot_P = exc->GS.projVector.y;
    else
      exc->F_dot_P =
        ( (FT_Long)exc->GS.projVector.x * exc->GS.freeVector.x +
          (FT_Long)exc->GS.projVector.y * exc->GS.freeVector.y ) >> 14;

    if ( exc->GS.projVector.x == 0x4000 )
      exc->func_project = (TT_Project_Func)Project_x;
    else if ( exc->GS.projVector.y == 0x4000 )
      exc->func_project = (TT_Project_Func)Project_y;
    else
      exc->func_project = (TT_Project_Func)Project;

    if ( exc->GS.dualVector.x == 0x4000 )
      exc->func_dualproj = (TT_Project_Func)Project_x;
    else if ( exc->GS.dualVector.y == 0x4000 )
      exc->func_dualproj = (TT_Project_Func)Project_y;
    else
      exc->func_dualproj = (TT_Project_Func)Dual_Project;

    exc->func_move      = (TT_Move_Func)Direct_Move;
    exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig;

    if ( exc->F_dot_P == 0x4000L )
    {
      if ( exc->GS.freeVector.x == 0x4000 )
      {
        exc->func_move      = (TT_Move_Func)Direct_Move_X;
        exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;
      }
      else if ( exc->GS.freeVector.y == 0x4000 )
      {
        exc->func_move      = (TT_Move_Func)Direct_Move_Y;
        exc->func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
      }
    }

    /* at small sizes, F_dot_P can become too small, resulting   */
    /* in overflows and `spikes' in a number of glyphs like `w'. */

    if ( FT_ABS( exc->F_dot_P ) < 0x400L )
      exc->F_dot_P = 0x4000L;

    /* Disable cached aspect ratio */
    exc->tt_metrics.ratio = 0;
  }

Project: savannah

  Compute_Point_Displacement( TT_ExecContext  exc,
                              FT_F26Dot6*     x,
                              FT_F26Dot6*     y,
                              TT_GlyphZone    zone,
                              FT_UShort*      refp )
  {
    TT_GlyphZoneRec  zp;
    FT_UShort        p;
    FT_F26Dot6       d;


    if ( exc->opcode & 1 )
    {
      zp = exc->zp0;
      p  = exc->GS.rp1;
    }
    else
    {
      zp = exc->zp1;
      p  = exc->GS.rp2;
    }

    if ( BOUNDS( p, zp.n_points ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      *refp = 0;
      return FAILURE;
    }

    *zone = zp;
    *refp = p;

    d = PROJECT( zp.cur + p, zp.org + p );

    *x = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.x, exc->F_dot_P );
    *y = FT_MulDiv( d, (FT_Long)exc->GS.freeVector.y, exc->F_dot_P );

    return SUCCESS;
  }

Project: savannah

  Compute_Round( TT_ExecContext  exc,
                 FT_Byte         round_mode )
  {
    switch ( round_mode )
    {
    case TT_Round_Off:
      exc->func_round = (TT_Round_Func)Round_None;
      break;

    case TT_Round_To_Grid:
      exc->func_round = (TT_Round_Func)Round_To_Grid;
      break;

    case TT_Round_Up_To_Grid:
      exc->func_round = (TT_Round_Func)Round_Up_To_Grid;
      break;

    case TT_Round_Down_To_Grid:
      exc->func_round = (TT_Round_Func)Round_Down_To_Grid;
      break;

    case TT_Round_To_Half_Grid:
      exc->func_round = (TT_Round_Func)Round_To_Half_Grid;
      break;

    case TT_Round_To_Double_Grid:
      exc->func_round = (TT_Round_Func)Round_To_Double_Grid;
      break;

    case TT_Round_Super:
      exc->func_round = (TT_Round_Func)Round_Super;
      break;

    case TT_Round_Super_45:
      exc->func_round = (TT_Round_Func)Round_Super_45;
      break;
    }
  }

Project: savannah

  Current_Ppem( TT_ExecContext  exc )
  {
    return exc->tt_metrics.ppem;
  }

Project: savannah

  Current_Ppem_Stretched( TT_ExecContext  exc )
  {
    return FT_MulFix( exc->tt_metrics.ppem, Current_Ratio( exc ) );
  }

Project: savannah

  Direct_Move( TT_ExecContext  exc,
               TT_GlyphZone    zone,
               FT_UShort       point,
               FT_F26Dot6      distance )
  {
    FT_F26Dot6  v;


    v = exc->GS.freeVector.x;

    if ( v != 0 )
    {
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
      if ( SUBPIXEL_HINTING_INFINALITY                            &&
           ( !exc->ignore_x_mode                                ||
             ( exc->sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) ) )
        zone->cur[point].x = ADD_LONG( zone->cur[point].x,
                                       FT_MulDiv( distance,
                                                  v,
                                                  exc->F_dot_P ) );
      else
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
      /* Exception to the post-IUP curfew: Allow the x component of */
      /* diagonal moves, but only post-IUP.  DejaVu tries to adjust */
      /* diagonal stems like on `Z' and `z' post-IUP.               */
      if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility )
        zone->cur[point].x = ADD_LONG( zone->cur[point].x,
                                       FT_MulDiv( distance,
                                                  v,
                                                  exc->F_dot_P ) );
      else
#endif

      if ( NO_SUBPIXEL_HINTING )
        zone->cur[point].x = ADD_LONG( zone->cur[point].x,
                                       FT_MulDiv( distance,
                                                  v,
                                                  exc->F_dot_P ) );

      zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
    }

    v = exc->GS.freeVector.y;

    if ( v != 0 )
    {
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
      if ( !( SUBPIXEL_HINTING_MINIMAL    &&
              exc->backward_compatibility &&
              exc->iupx_called            &&
              exc->iupy_called            ) )
#endif
        zone->cur[point].y = ADD_LONG( zone->cur[point].y,
                                       FT_MulDiv( distance,
                                                  v,
                                                  exc->F_dot_P ) );

      zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
    }
  }

Project: savannah

  Direct_Move_Orig_X( TT_ExecContext  exc,
                      TT_GlyphZone    zone,
                      FT_UShort       point,
                      FT_F26Dot6      distance )
  {
    FT_UNUSED( exc );

    zone->org[point].x = ADD_LONG( zone->org[point].x, distance );
  }

Project: savannah

  Direct_Move_X( TT_ExecContext  exc,
                 TT_GlyphZone    zone,
                 FT_UShort       point,
                 FT_F26Dot6      distance )
  {
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    if ( SUBPIXEL_HINTING_INFINALITY && !exc->ignore_x_mode )
      zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );
    else
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
    if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility )
      zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );
    else
#endif

    if ( NO_SUBPIXEL_HINTING )
      zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );

    zone->tags[point]  |= FT_CURVE_TAG_TOUCH_X;
  }

Project: savannah

  Direct_Move_Y( TT_ExecContext  exc,
                 TT_GlyphZone    zone,
                 FT_UShort       point,
                 FT_F26Dot6      distance )
  {
    FT_UNUSED( exc );

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
    if ( !( SUBPIXEL_HINTING_MINIMAL             &&
            exc->backward_compatibility          &&
            exc->iupx_called && exc->iupy_called ) )
#endif
      zone->cur[point].y = ADD_LONG( zone->cur[point].y, distance );

    zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
  }

Project: savannah

  GetShortIns( TT_ExecContext  exc )
  {
    /* Reading a byte stream so there is no endianness (DaveP) */
    exc->IP += 2;
    return (FT_Short)( ( exc->code[exc->IP - 2] << 8 ) +
                         exc->code[exc->IP - 1]      );
  }

Project: savannah

  Init_Context( TT_ExecContext  exec,
                FT_Memory       memory )
  {
    FT_Error  error;


    FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec ));

    exec->memory   = memory;
    exec->callSize = 32;

    if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )
      goto Fail_Memory;

    /* all values in the context are set to 0 already, but this is */
    /* here as a remainder                                         */
    exec->maxPoints   = 0;
    exec->maxContours = 0;

    exec->stackSize = 0;
    exec->glyphSize = 0;

    exec->stack    = NULL;
    exec->glyphIns = NULL;

    exec->face = NULL;
    exec->size = NULL;

    return FT_Err_Ok;

  Fail_Memory:
    FT_ERROR(( "Init_Context: not enough memory for %p\n", exec ));
    TT_Done_Context( exec );

    return error;
 }

Project: savannah

  Ins_AA( void )
  {
    /* intentionally no longer supported */
  }

Project: savannah

  Ins_ABS( FT_Long*  args )
  {
    if ( args[0] < 0 )
      args[0] = NEG_LONG( args[0] );
  }

Project: savannah

  Ins_ADD( FT_Long*  args )
  {
    args[0] = ADD_LONG( args[0], args[1] );
  }

Project: savannah

  Ins_ALIGNPTS( TT_ExecContext  exc,
                FT_Long*        args )
  {
    FT_UShort   p1, p2;
    FT_F26Dot6  distance;


    p1 = (FT_UShort)args[0];
    p2 = (FT_UShort)args[1];

    if ( BOUNDS( p1, exc->zp1.n_points ) ||
         BOUNDS( p2, exc->zp0.n_points ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      return;
    }

    distance = PROJECT( exc->zp0.cur + p2, exc->zp1.cur + p1 ) / 2;

    exc->func_move( exc, &exc->zp1, p1, distance );
    exc->func_move( exc, &exc->zp0, p2, NEG_LONG( distance ) );
  }

Project: savannah

  Ins_ALIGNRP( TT_ExecContext  exc )
  {
    FT_UShort   point;
    FT_F26Dot6  distance;


#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    if ( SUBPIXEL_HINTING_INFINALITY                               &&
         exc->ignore_x_mode                                        &&
         exc->iup_called                                           &&
         ( exc->sph_tweak_flags & SPH_TWEAK_NO_ALIGNRP_AFTER_IUP ) )
    {
      exc->error = FT_THROW( Invalid_Reference );
      goto Fail;
    }
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

    if ( exc->top < exc->GS.loop                  ||
         BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      goto Fail;
    }

    while ( exc->GS.loop > 0 )
    {
      exc->args--;

      point = (FT_UShort)exc->stack[exc->args];

      if ( BOUNDS( point, exc->zp1.n_points ) )
      {
        if ( exc->pedantic_hinting )
        {
          exc->error = FT_THROW( Invalid_Reference );
          return;
        }
      }
      else
      {
        distance = PROJECT( exc->zp1.cur + point,
                            exc->zp0.cur + exc->GS.rp0 );

        exc->func_move( exc, &exc->zp1, point, NEG_LONG( distance ) );
      }

      exc->GS.loop--;
    }

  Fail:
    exc->GS.loop = 1;
    exc->new_top = exc->args;
  }

Project: savannah

  Ins_AND( FT_Long*  args )
  {
    args[0] = ( args[0] && args[1] );
  }

Project: savannah

  Ins_CALL( TT_ExecContext  exc,
            FT_Long*        args )
  {
    FT_ULong       F;
    TT_CallRec*    pCrec;
    TT_DefRecord*  def;


    /* first of all, check the index */

    F = (FT_ULong)args[0];
    if ( BOUNDSL( F, exc->maxFunc + 1 ) )
      goto Fail;

    /* Except for some old Apple fonts, all functions in a TrueType */
    /* font are defined in increasing order, starting from 0.  This */
    /* means that we normally have                                  */
    /*                                                              */
    /*    exc->maxFunc+1 == exc->numFDefs                           */
    /*    exc->FDefs[n].opc == n for n in 0..exc->maxFunc           */
    /*                                                              */
    /* If this isn't true, we need to look up the function table.   */

    def = exc->FDefs + F;
    if ( exc->maxFunc + 1 != exc->numFDefs || def->opc != F )
    {
      /* look up the FDefs table */
      TT_DefRecord*  limit;


      def   = exc->FDefs;
      limit = def + exc->numFDefs;

      while ( def < limit && def->opc != F )
        def++;

      if ( def == limit )
        goto Fail;
    }

    /* check that the function is active */
    if ( !def->active )
      goto Fail;

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    if ( SUBPIXEL_HINTING_INFINALITY                                    &&
         exc->ignore_x_mode                                             &&
         ( ( exc->iup_called                                        &&
             ( exc->sph_tweak_flags & SPH_TWEAK_NO_CALL_AFTER_IUP ) ) ||
           ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 )        ) )
      goto Fail;
    else
      exc->sph_in_func_flags = def->sph_fdef_flags;
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

    /* check the call stack */
    if ( exc->callTop >= exc->callSize )
    {
      exc->error = FT_THROW( Stack_Overflow );
      return;
    }

    pCrec = exc->callStack + exc->callTop;

    pCrec->Caller_Range = exc->curRange;
    pCrec->Caller_IP    = exc->IP + 1;
    pCrec->Cur_Count    = 1;
    pCrec->Def          = def;

    exc->callTop++;

    Ins_Goto_CodeRange( exc, def->range, def->start );

    exc->step_ins = FALSE;

    return;

  Fail:
    exc->error = FT_THROW( Invalid_Reference );
  }

Project: savannah

  Ins_CINDEX( TT_ExecContext  exc,
              FT_Long*        args )
  {
    FT_Long  L;


    L = args[0];

    if ( L <= 0 || L > exc->args )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      args[0] = 0;
    }
    else
      args[0] = exc->stack[exc->args - L];
  }

Project: savannah

  Ins_CLEAR( TT_ExecContext  exc )
  {
    exc->new_top = 0;
  }

Project: savannah

  Ins_DEBUG( TT_ExecContext  exc )
  {
    exc->error = FT_THROW( Debug_OpCode );
  }

Project: savannah

  Ins_DELTAC( TT_ExecContext  exc,
              FT_Long*        args )
  {
    FT_ULong  nump, k;
    FT_ULong  A, C, P;
    FT_Long   B;


    P    = (FT_ULong)exc->func_cur_ppem( exc );
    nump = (FT_ULong)args[0];

    for ( k = 1; k <= nump; k++ )
    {
      if ( exc->args < 2 )
      {
        if ( exc->pedantic_hinting )
          exc->error = FT_THROW( Too_Few_Arguments );
        exc->args = 0;
        goto Fail;
      }

      exc->args -= 2;

      A = (FT_ULong)exc->stack[exc->args + 1];
      B = exc->stack[exc->args];

      if ( BOUNDSL( A, exc->cvtSize ) )
      {
        if ( exc->pedantic_hinting )
        {
          exc->error = FT_THROW( Invalid_Reference );
          return;
        }
      }
      else
      {
        C = ( (FT_ULong)B & 0xF0 ) >> 4;

        switch ( exc->opcode )
        {
        case 0x73:
          break;

        case 0x74:
          C += 16;
          break;

        case 0x75:
          C += 32;
          break;
        }

        C += exc->GS.delta_base;

        if ( P == C )
        {
          B = ( (FT_ULong)B & 0xF ) - 8;
          if ( B >= 0 )
            B++;
          B *= 1L << ( 6 - exc->GS.delta_shift );

          exc->func_move_cvt( exc, A, B );
        }
      }
    }

  Fail:
    exc->new_top = exc->args;
  }

Project: savannah

  Ins_DELTAP( TT_ExecContext  exc,
              FT_Long*        args )
  {
    FT_ULong   nump, k;
    FT_UShort  A;
    FT_ULong   C, P;
    FT_Long    B;
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    FT_UShort  B1, B2;


    if ( SUBPIXEL_HINTING_INFINALITY                              &&
         exc->ignore_x_mode                                       &&
         exc->iup_called                                          &&
         ( exc->sph_tweak_flags & SPH_TWEAK_NO_DELTAP_AFTER_IUP ) )
      goto Fail;
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

    P    = (FT_ULong)exc->func_cur_ppem( exc );
    nump = (FT_ULong)args[0];   /* some points theoretically may occur more
                                   than once, thus UShort isn't enough */

    for ( k = 1; k <= nump; k++ )
    {
      if ( exc->args < 2 )
      {
        if ( exc->pedantic_hinting )
          exc->error = FT_THROW( Too_Few_Arguments );
        exc->args = 0;
        goto Fail;
      }

      exc->args -= 2;

      A = (FT_UShort)exc->stack[exc->args + 1];
      B = exc->stack[exc->args];

      /* XXX: Because some popular fonts contain some invalid DeltaP */
      /*      instructions, we simply ignore them when the stacked   */
      /*      point reference is off limit, rather than returning an */
      /*      error.  As a delta instruction doesn't change a glyph  */
      /*      in great ways, this shouldn't be a problem.            */

      if ( !BOUNDS( A, exc->zp0.n_points ) )
      {
        C = ( (FT_ULong)B & 0xF0 ) >> 4;

        switch ( exc->opcode )
        {
        case 0x5D:
          break;

        case 0x71:
          C += 16;
          break;

        case 0x72:
          C += 32;
          break;
        }

        C += exc->GS.delta_base;

        if ( P == C )
        {
          B = ( (FT_ULong)B & 0xF ) - 8;
          if ( B >= 0 )
            B++;
          B *= 1L << ( 6 - exc->GS.delta_shift );

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY

          if ( SUBPIXEL_HINTING_INFINALITY )
          {
            /*
             *  Allow delta move if
             *
             *  - not using ignore_x_mode rendering,
             *  - glyph is specifically set to allow it, or
             *  - glyph is composite and freedom vector is not in subpixel
             *    direction.
             */
            if ( !exc->ignore_x_mode                                   ||
                 ( exc->sph_tweak_flags & SPH_TWEAK_ALWAYS_DO_DELTAP ) ||
                 ( exc->is_composite && exc->GS.freeVector.y != 0 )    )
              exc->func_move( exc, &exc->zp0, A, B );

            /* Otherwise, apply subpixel hinting and compatibility mode */
            /* rules, always skipping deltas in subpixel direction.     */
            else if ( exc->ignore_x_mode && exc->GS.freeVector.y != 0 )
            {
              /* save the y value of the point now; compare after move */
              B1 = (FT_UShort)exc->zp0.cur[A].y;

              /* Standard subpixel hinting: Allow y move for y-touched */
              /* points.  This messes up DejaVu ...                    */
              if ( !exc->face->sph_compatibility_mode          &&
                   ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) )
                exc->func_move( exc, &exc->zp0, A, B );

              /* compatibility mode */
              else if ( exc->face->sph_compatibility_mode                        &&
                        !( exc->sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) )
              {
                if ( exc->sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
                  B = FT_PIX_ROUND( B1 + B ) - B1;

                /* Allow delta move if using sph_compatibility_mode,   */
                /* IUP has not been called, and point is touched on Y. */
                if ( !exc->iup_called                            &&
                     ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) )
                  exc->func_move( exc, &exc->zp0, A, B );
              }

              B2 = (FT_UShort)exc->zp0.cur[A].y;

              /* Reverse this move if it results in a disallowed move */
              if ( exc->GS.freeVector.y != 0                          &&
                   ( ( exc->face->sph_compatibility_mode          &&
                       ( B1 & 63 ) == 0                           &&
                       ( B2 & 63 ) != 0                           ) ||
                     ( ( exc->sph_tweak_flags                   &
                         SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP ) &&
                       ( B1 & 63 ) != 0                           &&
                       ( B2 & 63 ) != 0                           ) ) )
                exc->func_move( exc, &exc->zp0, A, NEG_LONG( B ) );
            }
          }
          else
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

          {

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
            /* See `ttinterp.h' for details on backward compatibility */
            /* mode.                                                  */
            if ( SUBPIXEL_HINTING_MINIMAL    &&
                 exc->backward_compatibility )
            {
              if ( !( exc->iupx_called && exc->iupy_called )              &&
                   ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
                     ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y )        ) )
                exc->func_move( exc, &exc->zp0, A, B );
            }
            else
#endif
              exc->func_move( exc, &exc->zp0, A, B );
          }
        }
      }
      else
        if ( exc->pedantic_hinting )
          exc->error = FT_THROW( Invalid_Reference );
    }

  Fail:
    exc->new_top = exc->args;
  }

Project: savannah

  Ins_DEPTH( TT_ExecContext  exc,
             FT_Long*        args )
  {
    args[0] = exc->top;
  }

Project: savannah

  Ins_DIV( TT_ExecContext  exc,
           FT_Long*        args )
  {
    if ( args[1] == 0 )
      exc->error = FT_THROW( Divide_By_Zero );
    else
      args[0] = FT_MulDiv_No_Round( args[0], 64L, args[1] );
  }

Project: savannah

  Ins_DUP( FT_Long*  args )
  {
    args[1] = args[0];
  }

Project: savannah

  Ins_EIF( void )
  {
    /* nothing to do */
  }

Project: savannah

  Ins_ELSE( TT_ExecContext  exc )
  {
    FT_Int  nIfs;


    nIfs = 1;

    do
    {
      if ( SkipCode( exc ) == FAILURE )
        return;

      switch ( exc->opcode )
      {
      case 0x58:    /* IF */
        nIfs++;
        break;

      case 0x59:    /* EIF */
        nIfs--;
        break;
      }
    } while ( nIfs != 0 );
  }

Project: savannah

  Ins_ENDF( TT_ExecContext  exc )
  {
    TT_CallRec*  pRec;


#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    exc->sph_in_func_flags = 0x0000;
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

    if ( exc->callTop <= 0 )     /* We encountered an ENDF without a call */
    {
      exc->error = FT_THROW( ENDF_In_Exec_Stream );
      return;
    }

    exc->callTop--;

    pRec = &exc->callStack[exc->callTop];

    pRec->Cur_Count--;

    exc->step_ins = FALSE;

    if ( pRec->Cur_Count > 0 )
    {
      exc->callTop++;
      exc->IP = pRec->Def->start;
    }
    else
      /* Loop through the current function */
      Ins_Goto_CodeRange( exc, pRec->Caller_Range, pRec->Caller_IP );

    /* Exit the current call frame.                      */

    /* NOTE: If the last instruction of a program is a   */
    /*       CALL or LOOPCALL, the return address is     */
    /*       always out of the code range.  This is a    */
    /*       valid address, and it is why we do not test */
    /*       the result of Ins_Goto_CodeRange() here!    */
  }

Project: savannah

  Ins_EQ( FT_Long*  args )
  {
    args[0] = ( args[0] == args[1] );
  }

Project: savannah

  Ins_FDEF( TT_ExecContext  exc,
            FT_Long*        args )
  {
    FT_ULong       n;
    TT_DefRecord*  rec;
    TT_DefRecord*  limit;

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    /* arguments to opcodes are skipped by `SKIP_Code' */
    FT_Byte    opcode_pattern[9][12] = {
                 /* #0 inline delta function 1 */
                 {
                   0x4B, /* PPEM    */
                   0x53, /* GTEQ    */
                   0x23, /* SWAP    */
                   0x4B, /* PPEM    */
                   0x51, /* LTEQ    */
                   0x5A, /* AND     */
                   0x58, /* IF      */
                   0x38, /*   SHPIX */
                   0x1B, /* ELSE    */
                   0x21, /*   POP   */
                   0x21, /*   POP   */
                   0x59  /* EIF     */
                 },
                 /* #1 inline delta function 2 */
                 {
                   0x4B, /* PPEM    */
                   0x54, /* EQ      */
                   0x58, /* IF      */
                   0x38, /*   SHPIX */
                   0x1B, /* ELSE    */
                   0x21, /*   POP   */
                   0x21, /*   POP   */
                   0x59  /* EIF     */
                 },
                 /* #2 diagonal stroke function */
                 {
                   0x20, /* DUP     */
                   0x20, /* DUP     */
                   0xB0, /* PUSHB_1 */
                         /*   1     */
                   0x60, /* ADD     */
                   0x46, /* GC_cur  */
                   0xB0, /* PUSHB_1 */
                         /*   64    */
                   0x23, /* SWAP    */
                   0x42  /* WS      */
                 },
                 /* #3 VacuFormRound function */
                 {
                   0x45, /* RCVT    */
                   0x23, /* SWAP    */
                   0x46, /* GC_cur  */
                   0x60, /* ADD     */
                   0x20, /* DUP     */
                   0xB0  /* PUSHB_1 */
                         /*   38    */
                 },
                 /* #4 TTFautohint bytecode (old) */
                 {
                   0x20, /* DUP     */
                   0x64, /* ABS     */
                   0xB0, /* PUSHB_1 */
                         /*   32    */
                   0x60, /* ADD     */
                   0x66, /* FLOOR   */
                   0x23, /* SWAP    */
                   0xB0  /* PUSHB_1 */
                 },
                 /* #5 spacing function 1 */
                 {
                   0x01, /* SVTCA_x */
                   0xB0, /* PUSHB_1 */
                         /*   24    */
                   0x43, /* RS      */
                   0x58  /* IF      */
                 },
                 /* #6 spacing function 2 */
                 {
                   0x01, /* SVTCA_x */
                   0x18, /* RTG     */
                   0xB0, /* PUSHB_1 */
                         /*   24    */
                   0x43, /* RS      */
                   0x58  /* IF      */
                 },
                 /* #7 TypeMan Talk DiagEndCtrl function */
                 {
                   0x01, /* SVTCA_x */
                   0x20, /* DUP     */
                   0xB0, /* PUSHB_1 */
                         /*   3     */
                   0x25, /* CINDEX  */
                 },
                 /* #8 TypeMan Talk Align */
                 {
                   0x06, /* SPVTL   */
                   0x7D, /* RDTG    */
                 },
               };
    FT_UShort  opcode_patterns   = 9;
    FT_UShort  opcode_pointer[9] = {  0, 0, 0, 0, 0, 0, 0, 0, 0 };
    FT_UShort  opcode_size[9]    = { 12, 8, 8, 6, 7, 4, 5, 4, 2 };
    FT_UShort  i;
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */


    /* FDEF is only allowed in `prep' or `fpgm' */
    if ( exc->curRange == tt_coderange_glyph )
    {
      exc->error = FT_THROW( DEF_In_Glyf_Bytecode );
      return;
    }

    /* some font programs are broken enough to redefine functions! */
    /* We will then parse the current table.                       */

    rec   = exc->FDefs;
    limit = rec + exc->numFDefs;
    n     = (FT_ULong)args[0];

    for ( ; rec < limit; rec++ )
    {
      if ( rec->opc == n )
        break;
    }

    if ( rec == limit )
    {
      /* check that there is enough room for new functions */
      if ( exc->numFDefs >= exc->maxFDefs )
      {
        exc->error = FT_THROW( Too_Many_Function_Defs );
        return;
      }
      exc->numFDefs++;
    }

    /* Although FDEF takes unsigned 32-bit integer,  */
    /* func # must be within unsigned 16-bit integer */
    if ( n > 0xFFFFU )
    {
      exc->error = FT_THROW( Too_Many_Function_Defs );
      return;
    }

    rec->range          = exc->curRange;
    rec->opc            = (FT_UInt16)n;
    rec->start          = exc->IP + 1;
    rec->active         = TRUE;
    rec->inline_delta   = FALSE;
    rec->sph_fdef_flags = 0x0000;

    if ( n > exc->maxFunc )
      exc->maxFunc = (FT_UInt16)n;

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    /* We don't know for sure these are typeman functions, */
    /* however they are only active when RS 22 is called   */
    if ( n >= 64 && n <= 66 )
      rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_STROKES;
#endif

    /* Now skip the whole function definition. */
    /* We don't allow nested IDEFS & FDEFs.    */

    while ( SkipCode( exc ) == SUCCESS )
    {

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY

      if ( SUBPIXEL_HINTING_INFINALITY )
      {
        for ( i = 0; i < opcode_patterns; i++ )
        {
          if ( opcode_pointer[i] < opcode_size[i]                  &&
               exc->opcode == opcode_pattern[i][opcode_pointer[i]] )
          {
            opcode_pointer[i] += 1;

            if ( opcode_pointer[i] == opcode_size[i] )
            {
              FT_TRACE6(( "sph: Function %d, opcode ptrn: %d, %s %s\n",
                          i, n,
                          exc->face->root.family_name,
                          exc->face->root.style_name ));

              switch ( i )
              {
              case 0:
                rec->sph_fdef_flags             |= SPH_FDEF_INLINE_DELTA_1;
                exc->face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_1;
                break;

              case 1:
                rec->sph_fdef_flags             |= SPH_FDEF_INLINE_DELTA_2;
                exc->face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_2;
                break;

              case 2:
                switch ( n )
                {
                  /* needs to be implemented still */
                case 58:
                  rec->sph_fdef_flags             |= SPH_FDEF_DIAGONAL_STROKE;
                  exc->face->sph_found_func_flags |= SPH_FDEF_DIAGONAL_STROKE;
                }
                break;

              case 3:
                switch ( n )
                {
                case 0:
                  rec->sph_fdef_flags             |= SPH_FDEF_VACUFORM_ROUND_1;
                  exc->face->sph_found_func_flags |= SPH_FDEF_VACUFORM_ROUND_1;
                }
                break;

              case 4:
                /* probably not necessary to detect anymore */
                rec->sph_fdef_flags             |= SPH_FDEF_TTFAUTOHINT_1;
                exc->face->sph_found_func_flags |= SPH_FDEF_TTFAUTOHINT_1;
                break;

              case 5:
                switch ( n )
                {
                case 0:
                case 1:
                case 2:
                case 4:
                case 7:
                case 8:
                  rec->sph_fdef_flags             |= SPH_FDEF_SPACING_1;
                  exc->face->sph_found_func_flags |= SPH_FDEF_SPACING_1;
                }
                break;

              case 6:
                switch ( n )
                {
                case 0:
                case 1:
                case 2:
                case 4:
                case 7:
                case 8:
                  rec->sph_fdef_flags             |= SPH_FDEF_SPACING_2;
                  exc->face->sph_found_func_flags |= SPH_FDEF_SPACING_2;
                }
                break;

               case 7:
                 rec->sph_fdef_flags             |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
                 exc->face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
                 break;

               case 8:
#if 0
                 rec->sph_fdef_flags             |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
                 exc->face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
#endif
                 break;
              }
              opcode_pointer[i] = 0;
            }
          }

          else
            opcode_pointer[i] = 0;
        }

        /* Set sph_compatibility_mode only when deltas are detected */
        exc->face->sph_compatibility_mode =
          ( ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_1 ) |
            ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_2 ) );
      }

#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

      switch ( exc->opcode )
      {
      case 0x89:    /* IDEF */
      case 0x2C:    /* FDEF */
        exc->error = FT_THROW( Nested_DEFS );
        return;

      case 0x2D:   /* ENDF */
        rec->end = exc->IP;
        return;
      }
    }
  }

Project: savannah

  Ins_FLIPOFF( TT_ExecContext  exc )
  {
    exc->GS.auto_flip = FALSE;
  }

Project: savannah

  Ins_FLIPON( TT_ExecContext  exc )
  {
    exc->GS.auto_flip = TRUE;
  }

Project: savannah

  Ins_FLIPPT( TT_ExecContext  exc )
  {
    FT_UShort  point;


#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
    /* See `ttinterp.h' for details on backward compatibility mode. */
    if ( SUBPIXEL_HINTING_MINIMAL    &&
         exc->backward_compatibility &&
         exc->iupx_called            &&
         exc->iupy_called            )
      goto Fail;
#endif

    if ( exc->top < exc->GS.loop )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Too_Few_Arguments );
      goto Fail;
    }

    while ( exc->GS.loop > 0 )
    {
      exc->args--;

      point = (FT_UShort)exc->stack[exc->args];

      if ( BOUNDS( point, exc->pts.n_points ) )
      {
        if ( exc->pedantic_hinting )
        {
          exc->error = FT_THROW( Invalid_Reference );
          return;
        }
      }
      else
        exc->pts.tags[point] ^= FT_CURVE_TAG_ON;

      exc->GS.loop--;
    }

  Fail:
    exc->GS.loop = 1;
    exc->new_top = exc->args;
  }

Project: savannah

  Ins_FLIPRGOFF( TT_ExecContext  exc,
                 FT_Long*        args )
  {
    FT_UShort  I, K, L;


#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
    /* See `ttinterp.h' for details on backward compatibility mode. */
    if ( SUBPIXEL_HINTING_MINIMAL    &&
         exc->backward_compatibility &&
         exc->iupx_called            &&
         exc->iupy_called            )
      return;
#endif

    K = (FT_UShort)args[1];
    L = (FT_UShort)args[0];

    if ( BOUNDS( K, exc->pts.n_points ) ||
         BOUNDS( L, exc->pts.n_points ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      return;
    }

    for ( I = L; I <= K; I++ )
      exc->pts.tags[I] &= ~FT_CURVE_TAG_ON;
  }

Project: savannah

  Ins_FLOOR( FT_Long*  args )
  {
    args[0] = FT_PIX_FLOOR( args[0] );
  }

Project: savannah

  Ins_GC( TT_ExecContext  exc,
          FT_Long*        args )
  {
    FT_ULong    L;
    FT_F26Dot6  R;


    L = (FT_ULong)args[0];

    if ( BOUNDSL( L, exc->zp2.n_points ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      R = 0;
    }
    else
    {
      if ( exc->opcode & 1 )
        R = FAST_DUALPROJ( &exc->zp2.org[L] );
      else
        R = FAST_PROJECT( &exc->zp2.cur[L] );
    }

    args[0] = R;
  }

Project: savannah

  Ins_GETDATA( FT_Long*  args )
  {
    args[0] = 17;
  }

Project: savannah

  Ins_GETINFO( TT_ExecContext  exc,
               FT_Long*        args )
  {
    FT_Long    K;
    TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( exc->face );


    K = 0;

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    /********************************/
    /* RASTERIZER VERSION           */
    /* Selector Bit:  0             */
    /* Return Bit(s): 0-7           */
    /*                              */
    if ( SUBPIXEL_HINTING_INFINALITY &&
         ( args[0] & 1 ) != 0        &&
         exc->subpixel_hinting       )
    {
      if ( exc->ignore_x_mode )
      {
        /* if in ClearType backward compatibility mode,         */
        /* we sometimes change the TrueType version dynamically */
        K = exc->rasterizer_version;
        FT_TRACE6(( "Setting rasterizer version %d\n",
                    exc->rasterizer_version ));
      }
      else
        K = TT_INTERPRETER_VERSION_38;
    }
    else
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
      if ( ( args[0] & 1 ) != 0 )
        K = driver->interpreter_version;

    /********************************/
    /* GLYPH ROTATED                */
    /* Selector Bit:  1             */
    /* Return Bit(s): 8             */
    /*                              */
    if ( ( args[0] & 2 ) != 0 && exc->tt_metrics.rotated )
      K |= 1 << 8;

    /********************************/
    /* GLYPH STRETCHED              */
    /* Selector Bit:  2             */
    /* Return Bit(s): 9             */
    /*                              */
    if ( ( args[0] & 4 ) != 0 && exc->tt_metrics.stretched )
      K |= 1 << 9;

#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
    /********************************/
    /* VARIATION GLYPH              */
    /* Selector Bit:  3             */
    /* Return Bit(s): 10            */
    /*                              */
    /* XXX: UNDOCUMENTED!           */
    if ( (args[0] & 8 ) != 0 && exc->face->blend )
      K |= 1 << 10;
#endif

    /********************************/
    /* BI-LEVEL HINTING AND         */
    /* GRAYSCALE RENDERING          */
    /* Selector Bit:  5             */
    /* Return Bit(s): 12            */
    /*                              */
    if ( ( args[0] & 32 ) != 0 && exc->grayscale )
      K |= 1 << 12;

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
    /* Toggle the following flags only outside of monochrome mode.      */
    /* Otherwise, instructions may behave weirdly and rendering results */
    /* may differ between v35 and v40 mode, e.g., in `Times New Roman   */
    /* Bold Italic'. */
    if ( SUBPIXEL_HINTING_MINIMAL && exc->subpixel_hinting_lean )
    {
      /********************************/
      /* HINTING FOR SUBPIXEL         */
      /* Selector Bit:  6             */
      /* Return Bit(s): 13            */
      /*                              */
      /* v40 does subpixel hinting by default. */
      if ( ( args[0] & 64 ) != 0 )
        K |= 1 << 13;

      /********************************/
      /* VERTICAL LCD SUBPIXELS?      */
      /* Selector Bit:  8             */
      /* Return Bit(s): 15            */
      /*                              */
      if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd_lean )
        K |= 1 << 15;

      /********************************/
      /* SUBPIXEL POSITIONED?         */
      /* Selector Bit:  10            */
      /* Return Bit(s): 17            */
      /*                              */
      /* XXX: FreeType supports it, dependent on what client does? */
      if ( ( args[0] & 1024 ) != 0 )
        K |= 1 << 17;

      /********************************/
      /* SYMMETRICAL SMOOTHING        */
      /* Selector Bit:  11            */
      /* Return Bit(s): 18            */
      /*                              */
      /* The only smoothing method FreeType supports unless someone sets */
      /* FT_LOAD_TARGET_MONO.                                            */
      if ( ( args[0] & 2048 ) != 0 && exc->subpixel_hinting_lean )
        K |= 1 << 18;

      /********************************/
      /* CLEARTYPE HINTING AND        */
      /* GRAYSCALE RENDERING          */
      /* Selector Bit:  12            */
      /* Return Bit(s): 19            */
      /*                              */
      /* Grayscale rendering is what FreeType does anyway unless someone */
      /* sets FT_LOAD_TARGET_MONO or FT_LOAD_TARGET_LCD(_V)              */
      if ( ( args[0] & 4096 ) != 0 && exc->grayscale_cleartype )
        K |= 1 << 19;
    }
#endif

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY

    if ( SUBPIXEL_HINTING_INFINALITY                          &&
         exc->rasterizer_version >= TT_INTERPRETER_VERSION_35 )
    {

      if ( exc->rasterizer_version >= 37 )
      {
        /********************************/
        /* HINTING FOR SUBPIXEL         */
        /* Selector Bit:  6             */
        /* Return Bit(s): 13            */
        /*                              */
        if ( ( args[0] & 64 ) != 0 && exc->subpixel_hinting )
          K |= 1 << 13;

        /********************************/
        /* COMPATIBLE WIDTHS ENABLED    */
        /* Selector Bit:  7             */
        /* Return Bit(s): 14            */
        /*                              */
        /* Functionality still needs to be added */
        if ( ( args[0] & 128 ) != 0 && exc->compatible_widths )
          K |= 1 << 14;

        /********************************/
        /* VERTICAL LCD SUBPIXELS?      */
        /* Selector Bit:  8             */
        /* Return Bit(s): 15            */
        /*                              */
        /* Functionality still needs to be added */
        if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd )
          K |= 1 << 15;

        /********************************/
        /* HINTING FOR BGR?             */
        /* Selector Bit:  9             */
        /* Return Bit(s): 16            */
        /*                              */
        /* Functionality still needs to be added */
        if ( ( args[0] & 512 ) != 0 && exc->bgr )
          K |= 1 << 16;

        if ( exc->rasterizer_version >= 38 )
        {
          /********************************/
          /* SUBPIXEL POSITIONED?         */
          /* Selector Bit:  10            */
          /* Return Bit(s): 17            */
          /*                              */
          /* Functionality still needs to be added */
          if ( ( args[0] & 1024 ) != 0 && exc->subpixel_positioned )
            K |= 1 << 17;

          /********************************/
          /* SYMMETRICAL SMOOTHING        */
          /* Selector Bit:  11            */
          /* Return Bit(s): 18            */
          /*                              */
          /* Functionality still needs to be added */
          if ( ( args[0] & 2048 ) != 0 && exc->symmetrical_smoothing )
            K |= 1 << 18;

          /********************************/
          /* GRAY CLEARTYPE               */
          /* Selector Bit:  12            */
          /* Return Bit(s): 19            */
          /*                              */
          /* Functionality still needs to be added */
          if ( ( args[0] & 4096 ) != 0 && exc->gray_cleartype )
            K |= 1 << 19;
        }
      }
    }

#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

    args[0] = K;
  }

Project: savannah

  Ins_GFV( TT_ExecContext  exc,
           FT_Long*        args )
  {
    args[0] = exc->GS.freeVector.x;
    args[1] = exc->GS.freeVector.y;
  }

Project: savannah

  Ins_GPV( TT_ExecContext  exc,
           FT_Long*        args )
  {
    args[0] = exc->GS.projVector.x;
    args[1] = exc->GS.projVector.y;
  }

Project: savannah

  Ins_GT( FT_Long*  args )
  {
    args[0] = ( args[0] > args[1] );
  }

Project: savannah

  Ins_GTEQ( FT_Long*  args )
  {
    args[0] = ( args[0] >= args[1] );
  }

Project: savannah

  Ins_IDEF( TT_ExecContext  exc,
            FT_Long*        args )
  {
    TT_DefRecord*  def;
    TT_DefRecord*  limit;


    /* we enable IDEF only in `prep' or `fpgm' */
    if ( exc->curRange == tt_coderange_glyph )
    {
      exc->error = FT_THROW( DEF_In_Glyf_Bytecode );
      return;
    }

    /*  First of all, look for the same function in our table */

    def   = exc->IDefs;
    limit = def + exc->numIDefs;

    for ( ; def < limit; def++ )
      if ( def->opc == (FT_ULong)args[0] )
        break;

    if ( def == limit )
    {
      /* check that there is enough room for a new instruction */
      if ( exc->numIDefs >= exc->maxIDefs )
      {
        exc->error = FT_THROW( Too_Many_Instruction_Defs );
        return;
      }
      exc->numIDefs++;
    }

    /* opcode must be unsigned 8-bit integer */
    if ( 0 > args[0] || args[0] > 0x00FF )
    {
      exc->error = FT_THROW( Too_Many_Instruction_Defs );
      return;
    }

    def->opc    = (FT_Byte)args[0];
    def->start  = exc->IP + 1;
    def->range  = exc->curRange;
    def->active = TRUE;

    if ( (FT_ULong)args[0] > exc->maxIns )
      exc->maxIns = (FT_Byte)args[0];

    /* Now skip the whole function definition. */
    /* We don't allow nested IDEFs & FDEFs.    */

    while ( SkipCode( exc ) == SUCCESS )
    {
      switch ( exc->opcode )
      {
      case 0x89:   /* IDEF */
      case 0x2C:   /* FDEF */
        exc->error = FT_THROW( Nested_DEFS );
        return;
      case 0x2D:   /* ENDF */
        def->end = exc->IP;
        return;
      }
    }
  }

Project: savannah

  Ins_IF( TT_ExecContext  exc,
          FT_Long*        args )
  {
    FT_Int   nIfs;
    FT_Bool  Out;


    if ( args[0] != 0 )
      return;

    nIfs = 1;
    Out = 0;

    do
    {
      if ( SkipCode( exc ) == FAILURE )
        return;

      switch ( exc->opcode )
      {
      case 0x58:      /* IF */
        nIfs++;
        break;

      case 0x1B:      /* ELSE */
        Out = FT_BOOL( nIfs == 1 );
        break;

      case 0x59:      /* EIF */
        nIfs--;
        Out = FT_BOOL( nIfs == 0 );
        break;
      }
    } while ( Out == 0 );
  }

Project: savannah

  Ins_INSTCTRL( TT_ExecContext  exc,
                FT_Long*        args )
  {
    FT_ULong  K, L, Kf;


    K = (FT_ULong)args[1];
    L = (FT_ULong)args[0];

    /* selector values cannot be `OR'ed;                 */
    /* they are indices starting with index 1, not flags */
    if ( K < 1 || K > 3 )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      return;
    }

    /* convert index to flag value */
    Kf = 1 << ( K - 1 );

    if ( L != 0 )
    {
      /* arguments to selectors look like flag values */
      if ( L != Kf )
      {
        if ( exc->pedantic_hinting )
          exc->error = FT_THROW( Invalid_Reference );
        return;
      }
    }

    exc->GS.instruct_control &= ~(FT_Byte)Kf;
    exc->GS.instruct_control |= (FT_Byte)L;

    if ( K == 3 )
    {
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
      /* INSTCTRL modifying flag 3 also has an effect */
      /* outside of the CVT program                   */
      if ( SUBPIXEL_HINTING_INFINALITY )
        exc->ignore_x_mode = FT_BOOL( L == 4 );
#endif

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
      /* Native ClearType fonts sign a waiver that turns off all backward  */
      /* compatibility hacks and lets them program points to the grid like */
      /* it's 1996.  They might sign a waiver for just one glyph, though.  */
      if ( SUBPIXEL_HINTING_MINIMAL )
        exc->backward_compatibility = !FT_BOOL( L == 4 );
#endif
    }
  }

Project: savannah

  Ins_IP( TT_ExecContext  exc )
  {
    FT_F26Dot6  old_range, cur_range;
    FT_Vector*  orus_base;
    FT_Vector*  cur_base;
    FT_Int      twilight;


    if ( exc->top < exc->GS.loop )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      goto Fail;
    }

    /*
     * We need to deal in a special way with the twilight zone.
     * Otherwise, by definition, the value of exc->twilight.orus[n] is (0,0),
     * for every n.
     */
    twilight = ( exc->GS.gep0 == 0 ||
                 exc->GS.gep1 == 0 ||
                 exc->GS.gep2 == 0 );

    if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      goto Fail;
    }

    if ( twilight )
      orus_base = &exc->zp0.org[exc->GS.rp1];
    else
      orus_base = &exc->zp0.orus[exc->GS.rp1];

    cur_base = &exc->zp0.cur[exc->GS.rp1];

    /* XXX: There are some glyphs in some braindead but popular */
    /*      fonts out there (e.g. [aeu]grave in monotype.ttf)   */
    /*      calling IP[] with bad values of rp[12].             */
    /*      Do something sane when this odd thing happens.      */
    if ( BOUNDS( exc->GS.rp1, exc->zp0.n_points ) ||
         BOUNDS( exc->GS.rp2, exc->zp1.n_points ) )
    {
      old_range = 0;
      cur_range = 0;
    }
    else
    {
      if ( twilight )
        old_range = DUALPROJ( &exc->zp1.org[exc->GS.rp2], orus_base );
      else if ( exc->metrics.x_scale == exc->metrics.y_scale )
        old_range = DUALPROJ( &exc->zp1.orus[exc->GS.rp2], orus_base );
      else
      {
        FT_Vector  vec;


        vec.x = FT_MulFix( SUB_LONG( exc->zp1.orus[exc->GS.rp2].x,
                                     orus_base->x ),
                           exc->metrics.x_scale );
        vec.y = FT_MulFix( SUB_LONG( exc->zp1.orus[exc->GS.rp2].y,
                                     orus_base->y ),
                           exc->metrics.y_scale );

        old_range = FAST_DUALPROJ( &vec );
      }

      cur_range = PROJECT( &exc->zp1.cur[exc->GS.rp2], cur_base );
    }

    for ( ; exc->GS.loop > 0; exc->GS.loop-- )
    {
      FT_UInt     point = (FT_UInt)exc->stack[--exc->args];
      FT_F26Dot6  org_dist, cur_dist, new_dist;


      /* check point bounds */
      if ( BOUNDS( point, exc->zp2.n_points ) )
      {
        if ( exc->pedantic_hinting )
        {
          exc->error = FT_THROW( Invalid_Reference );
          return;
        }
        continue;
      }

      if ( twilight )
        org_dist = DUALPROJ( &exc->zp2.org[point], orus_base );
      else if ( exc->metrics.x_scale == exc->metrics.y_scale )
        org_dist = DUALPROJ( &exc->zp2.orus[point], orus_base );
      else
      {
        FT_Vector  vec;


        vec.x = FT_MulFix( SUB_LONG( exc->zp2.orus[point].x,
                                     orus_base->x ),
                           exc->metrics.x_scale );
        vec.y = FT_MulFix( SUB_LONG( exc->zp2.orus[point].y,
                                     orus_base->y ),
                           exc->metrics.y_scale );

        org_dist = FAST_DUALPROJ( &vec );
      }

      cur_dist = PROJECT( &exc->zp2.cur[point], cur_base );

      if ( org_dist )
      {
        if ( old_range )
          new_dist = FT_MulDiv( org_dist, cur_range, old_range );
        else
        {
          /* This is the same as what MS does for the invalid case:  */
          /*                                                         */
          /*   delta = (Original_Pt - Original_RP1) -                */
          /*           (Current_Pt - Current_RP1)         ;          */
          /*                                                         */
          /* In FreeType speak:                                      */
          /*                                                         */
          /*   delta = org_dist - cur_dist          .                */
          /*                                                         */
          /* We move `point' by `new_dist - cur_dist' after leaving  */
          /* this block, thus we have                                */
          /*                                                         */
          /*   new_dist - cur_dist = delta                   ,       */
          /*   new_dist - cur_dist = org_dist - cur_dist     ,       */
          /*              new_dist = org_dist                .       */

          new_dist = org_dist;
        }
      }
      else
        new_dist = 0;

      exc->func_move( exc,
                      &exc->zp2,
                      (FT_UShort)point,
                      SUB_LONG( new_dist, cur_dist ) );
    }

  Fail:
    exc->GS.loop = 1;
    exc->new_top = exc->args;
  }

Project: savannah

  Ins_ISECT( TT_ExecContext  exc,
             FT_Long*        args )
  {
    FT_UShort   point,
                a0, a1,
                b0, b1;

    FT_F26Dot6  discriminant, dotproduct;

    FT_F26Dot6  dx,  dy,
                dax, day,
                dbx, dby;

    FT_F26Dot6  val;

    FT_Vector   R;


    point = (FT_UShort)args[0];

    a0 = (FT_UShort)args[1];
    a1 = (FT_UShort)args[2];
    b0 = (FT_UShort)args[3];
    b1 = (FT_UShort)args[4];

    if ( BOUNDS( b0,    exc->zp0.n_points ) ||
         BOUNDS( b1,    exc->zp0.n_points ) ||
         BOUNDS( a0,    exc->zp1.n_points ) ||
         BOUNDS( a1,    exc->zp1.n_points ) ||
         BOUNDS( point, exc->zp2.n_points ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      return;
    }

    /* Cramer's rule */

    dbx = SUB_LONG( exc->zp0.cur[b1].x, exc->zp0.cur[b0].x );
    dby = SUB_LONG( exc->zp0.cur[b1].y, exc->zp0.cur[b0].y );

    dax = SUB_LONG( exc->zp1.cur[a1].x, exc->zp1.cur[a0].x );
    day = SUB_LONG( exc->zp1.cur[a1].y, exc->zp1.cur[a0].y );

    dx = SUB_LONG( exc->zp0.cur[b0].x, exc->zp1.cur[a0].x );
    dy = SUB_LONG( exc->zp0.cur[b0].y, exc->zp1.cur[a0].y );

    discriminant = ADD_LONG( FT_MulDiv( dax, NEG_LONG( dby ), 0x40 ),
                             FT_MulDiv( day, dbx, 0x40 ) );
    dotproduct   = ADD_LONG( FT_MulDiv( dax, dbx, 0x40 ),
                             FT_MulDiv( day, dby, 0x40 ) );

    /* The discriminant above is actually a cross product of vectors     */
    /* da and db. Together with the dot product, they can be used as     */
    /* surrogates for sine and cosine of the angle between the vectors.  */
    /* Indeed,                                                           */
    /*       dotproduct   = |da||db|cos(angle)                           */
    /*       discriminant = |da||db|sin(angle)     .                     */
    /* We use these equations to reject grazing intersections by         */
    /* thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. */
    if ( MUL_LONG( 19, FT_ABS( discriminant ) ) > FT_ABS( dotproduct ) )
    {
      val = ADD_LONG( FT_MulDiv( dx, NEG_LONG( dby ), 0x40 ),
                      FT_MulDiv( dy, dbx, 0x40 ) );

      R.x = FT_MulDiv( val, dax, discriminant );
      R.y = FT_MulDiv( val, day, discriminant );

      /* XXX: Block in backward_compatibility and/or post-IUP? */
      exc->zp2.cur[point].x = ADD_LONG( exc->zp1.cur[a0].x, R.x );
      exc->zp2.cur[point].y = ADD_LONG( exc->zp1.cur[a0].y, R.y );
    }
    else
    {
      /* else, take the middle of the middles of A and B */

      /* XXX: Block in backward_compatibility and/or post-IUP? */
      exc->zp2.cur[point].x =
        ADD_LONG( ADD_LONG( exc->zp1.cur[a0].x, exc->zp1.cur[a1].x ),
                  ADD_LONG( exc->zp0.cur[b0].x, exc->zp0.cur[b1].x ) ) / 4;
      exc->zp2.cur[point].y =
        ADD_LONG( ADD_LONG( exc->zp1.cur[a0].y, exc->zp1.cur[a1].y ),
                  ADD_LONG( exc->zp0.cur[b0].y, exc->zp0.cur[b1].y ) ) / 4;
    }

    exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
  }

Project: savannah

  Ins_IUP( TT_ExecContext  exc )
  {
    IUP_WorkerRec  V;
    FT_Byte        mask;

    FT_UInt   first_point;   /* first point of contour        */
    FT_UInt   end_point;     /* end point (last+1) of contour */

    FT_UInt   first_touched; /* first touched point in contour   */
    FT_UInt   cur_touched;   /* current touched point in contour */

    FT_UInt   point;         /* current point   */
    FT_Short  contour;       /* current contour */


#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
    /* See `ttinterp.h' for details on backward compatibility mode.  */
    /* Allow IUP until it has been called on both axes.  Immediately */
    /* return on subsequent ones.                                    */
    if ( SUBPIXEL_HINTING_MINIMAL    &&
         exc->backward_compatibility )
    {
      if ( exc->iupx_called && exc->iupy_called )
        return;

      if ( exc->opcode & 1 )
        exc->iupx_called = TRUE;
      else
        exc->iupy_called = TRUE;
    }
#endif

    /* ignore empty outlines */
    if ( exc->pts.n_contours == 0 )
      return;

    if ( exc->opcode & 1 )
    {
      mask   = FT_CURVE_TAG_TOUCH_X;
      V.orgs = exc->pts.org;
      V.curs = exc->pts.cur;
      V.orus = exc->pts.orus;
    }
    else
    {
      mask   = FT_CURVE_TAG_TOUCH_Y;
      V.orgs = (FT_Vector*)( (FT_Pos*)exc->pts.org + 1 );
      V.curs = (FT_Vector*)( (FT_Pos*)exc->pts.cur + 1 );
      V.orus = (FT_Vector*)( (FT_Pos*)exc->pts.orus + 1 );
    }
    V.max_points = exc->pts.n_points;

    contour = 0;
    point   = 0;

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    if ( SUBPIXEL_HINTING_INFINALITY &&
         exc->ignore_x_mode          )
    {
      exc->iup_called = TRUE;
      if ( exc->sph_tweak_flags & SPH_TWEAK_SKIP_IUP )
        return;
    }
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

    do
    {
      end_point   = exc->pts.contours[contour] - exc->pts.first_point;
      first_point = point;

      if ( BOUNDS( end_point, exc->pts.n_points ) )
        end_point = exc->pts.n_points - 1;

      while ( point <= end_point && ( exc->pts.tags[point] & mask ) == 0 )
        point++;

      if ( point <= end_point )
      {
        first_touched = point;
        cur_touched   = point;

        point++;

        while ( point <= end_point )
        {
          if ( ( exc->pts.tags[point] & mask ) != 0 )
          {
            _iup_worker_interpolate( &V,
                                     cur_touched + 1,
                                     point - 1,
                                     cur_touched,
                                     point );
            cur_touched = point;
          }

          point++;
        }

        if ( cur_touched == first_touched )
          _iup_worker_shift( &V, first_point, end_point, cur_touched );
        else
        {
          _iup_worker_interpolate( &V,
                                   (FT_UShort)( cur_touched + 1 ),
                                   end_point,
                                   cur_touched,
                                   first_touched );

          if ( first_touched > 0 )
            _iup_worker_interpolate( &V,
                                     first_point,
                                     first_touched - 1,
                                     cur_touched,
                                     first_touched );
        }
      }
      contour++;
    } while ( contour < exc->pts.n_contours );
  }

Project: savannah

  Ins_JMPR( TT_ExecContext  exc,
            FT_Long*        args )
  {
    if ( args[0] == 0 && exc->args == 0 )
    {
      exc->error = FT_THROW( Bad_Argument );
      return;
    }

    exc->IP += args[0];
    if ( exc->IP < 0                                             ||
         ( exc->callTop > 0                                    &&
           exc->IP > exc->callStack[exc->callTop - 1].Def->end ) )
    {
      exc->error = FT_THROW( Bad_Argument );
      return;
    }

    exc->step_ins = FALSE;

    if ( args[0] < 0 )
    {
      if ( ++exc->neg_jump_counter > exc->neg_jump_counter_max )
        exc->error = FT_THROW( Execution_Too_Long );
    }
  }

Project: savannah

  Ins_JROF( TT_ExecContext  exc,
            FT_Long*        args )
  {
    if ( args[1] == 0 )
      Ins_JMPR( exc, args );
  }

Project: savannah

  Ins_JROT( TT_ExecContext  exc,
            FT_Long*        args )
  {
    if ( args[1] != 0 )
      Ins_JMPR( exc, args );
  }

Project: savannah

  Ins_LOOPCALL( TT_ExecContext  exc,
                FT_Long*        args )
  {
    FT_ULong       F;
    TT_CallRec*    pCrec;
    TT_DefRecord*  def;


    /* first of all, check the index */
    F = (FT_ULong)args[1];
    if ( BOUNDSL( F, exc->maxFunc + 1 ) )
      goto Fail;

    /* Except for some old Apple fonts, all functions in a TrueType */
    /* font are defined in increasing order, starting from 0.  This */
    /* means that we normally have                                  */
    /*                                                              */
    /*    exc->maxFunc+1 == exc->numFDefs                           */
    /*    exc->FDefs[n].opc == n for n in 0..exc->maxFunc           */
    /*                                                              */
    /* If this isn't true, we need to look up the function table.   */

    def = exc->FDefs + F;
    if ( exc->maxFunc + 1 != exc->numFDefs || def->opc != F )
    {
      /* look up the FDefs table */
      TT_DefRecord*  limit;


      def   = exc->FDefs;
      limit = def + exc->numFDefs;

      while ( def < limit && def->opc != F )
        def++;

      if ( def == limit )
        goto Fail;
    }

    /* check that the function is active */
    if ( !def->active )
      goto Fail;

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    if ( SUBPIXEL_HINTING_INFINALITY                         &&
         exc->ignore_x_mode                                  &&
         ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) )
      goto Fail;
    else
      exc->sph_in_func_flags = def->sph_fdef_flags;
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

    /* check stack */
    if ( exc->callTop >= exc->callSize )
    {
      exc->error = FT_THROW( Stack_Overflow );
      return;
    }

    if ( args[0] > 0 )
    {
      pCrec = exc->callStack + exc->callTop;

      pCrec->Caller_Range = exc->curRange;
      pCrec->Caller_IP    = exc->IP + 1;
      pCrec->Cur_Count    = (FT_Int)args[0];
      pCrec->Def          = def;

      exc->callTop++;

      Ins_Goto_CodeRange( exc, def->range, def->start );

      exc->step_ins = FALSE;

      exc->loopcall_counter += (FT_ULong)args[0];
      if ( exc->loopcall_counter > exc->loopcall_counter_max )
        exc->error = FT_THROW( Execution_Too_Long );
    }

    return;

  Fail:
    exc->error = FT_THROW( Invalid_Reference );
  }

Project: savannah

  Ins_LT( FT_Long*  args )
  {
    args[0] = ( args[0] < args[1] );
  }

Project: savannah

  Ins_LTEQ( FT_Long*  args )
  {
    args[0] = ( args[0] <= args[1] );
  }

Project: savannah

  Ins_MAX( FT_Long*  args )
  {
    if ( args[1] > args[0] )
      args[0] = args[1];
  }

Project: savannah

  Ins_MD( TT_ExecContext  exc,
          FT_Long*        args )
  {
    FT_UShort   K, L;
    FT_F26Dot6  D;


    K = (FT_UShort)args[1];
    L = (FT_UShort)args[0];

    if ( BOUNDS( L, exc->zp0.n_points ) ||
         BOUNDS( K, exc->zp1.n_points ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      D = 0;
    }
    else
    {
      if ( exc->opcode & 1 )
        D = PROJECT( exc->zp0.cur + L, exc->zp1.cur + K );
      else
      {
        /* XXX: UNDOCUMENTED: twilight zone special case */

        if ( exc->GS.gep0 == 0 || exc->GS.gep1 == 0 )
        {
          FT_Vector*  vec1 = exc->zp0.org + L;
          FT_Vector*  vec2 = exc->zp1.org + K;


          D = DUALPROJ( vec1, vec2 );
        }
        else
        {
          FT_Vector*  vec1 = exc->zp0.orus + L;
          FT_Vector*  vec2 = exc->zp1.orus + K;


          if ( exc->metrics.x_scale == exc->metrics.y_scale )
          {
            /* this should be faster */
            D = DUALPROJ( vec1, vec2 );
            D = FT_MulFix( D, exc->metrics.x_scale );
          }
          else
          {
            FT_Vector  vec;


            vec.x = FT_MulFix( vec1->x - vec2->x, exc->metrics.x_scale );
            vec.y = FT_MulFix( vec1->y - vec2->y, exc->metrics.y_scale );

            D = FAST_DUALPROJ( &vec );
          }
        }
      }
    }

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */
    if ( SUBPIXEL_HINTING_INFINALITY &&
         exc->ignore_x_mode          &&
         FT_ABS( D ) == 64           )
      D += 1;
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

    args[0] = D;
  }

Project: savannah

  Ins_MDAP( TT_ExecContext  exc,
            FT_Long*        args )
  {
    FT_UShort   point;
    FT_F26Dot6  cur_dist;
    FT_F26Dot6  distance;


    point = (FT_UShort)args[0];

    if ( BOUNDS( point, exc->zp0.n_points ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      return;
    }

    if ( ( exc->opcode & 1 ) != 0 )
    {
      cur_dist = FAST_PROJECT( &exc->zp0.cur[point] );
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
      if ( SUBPIXEL_HINTING_INFINALITY &&
           exc->ignore_x_mode          &&
           exc->GS.freeVector.x != 0   )
        distance = Round_None(
                     exc,
                     cur_dist,
                     exc->tt_metrics.compensations[0] ) - cur_dist;
      else
#endif
        distance = exc->func_round(
                     exc,
                     cur_dist,
                     exc->tt_metrics.compensations[0] ) - cur_dist;
    }
    else
      distance = 0;

    exc->func_move( exc, &exc->zp0, point, distance );

    exc->GS.rp0 = point;
    exc->GS.rp1 = point;
  }

Project: savannah

  Ins_MDRP( TT_ExecContext  exc,
            FT_Long*        args )
  {
    FT_UShort   point = 0;
    FT_F26Dot6  org_dist, distance, minimum_distance;


    minimum_distance = exc->GS.minimum_distance;

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    if ( SUBPIXEL_HINTING_INFINALITY                        &&
         exc->ignore_x_mode                                 &&
         exc->GS.freeVector.x != 0                          &&
         !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
      minimum_distance = 0;
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

    point = (FT_UShort)args[0];

    if ( BOUNDS( point,       exc->zp1.n_points ) ||
         BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      goto Fail;
    }

    /* XXX: Is there some undocumented feature while in the */
    /*      twilight zone?                                  */

    /* XXX: UNDOCUMENTED: twilight zone special case */

    if ( exc->GS.gep0 == 0 || exc->GS.gep1 == 0 )
    {
      FT_Vector*  vec1 = &exc->zp1.org[point];
      FT_Vector*  vec2 = &exc->zp0.org[exc->GS.rp0];


      org_dist = DUALPROJ( vec1, vec2 );
    }
    else
    {
      FT_Vector*  vec1 = &exc->zp1.orus[point];
      FT_Vector*  vec2 = &exc->zp0.orus[exc->GS.rp0];


      if ( exc->metrics.x_scale == exc->metrics.y_scale )
      {
        /* this should be faster */
        org_dist = DUALPROJ( vec1, vec2 );
        org_dist = FT_MulFix( org_dist, exc->metrics.x_scale );
      }
      else
      {
        FT_Vector  vec;


        vec.x = FT_MulFix( SUB_LONG( vec1->x, vec2->x ),
                           exc->metrics.x_scale );
        vec.y = FT_MulFix( SUB_LONG( vec1->y, vec2->y ),
                           exc->metrics.y_scale );

        org_dist = FAST_DUALPROJ( &vec );
      }
    }

    /* single width cut-in test */

    /* |org_dist - single_width_value| < single_width_cutin */
    if ( exc->GS.single_width_cutin > 0          &&
         org_dist < exc->GS.single_width_value +
                      exc->GS.single_width_cutin &&
         org_dist > exc->GS.single_width_value -
                      exc->GS.single_width_cutin )
    {
      if ( org_dist >= 0 )
        org_dist = exc->GS.single_width_value;
      else
        org_dist = -exc->GS.single_width_value;
    }

    /* round flag */

    if ( ( exc->opcode & 4 ) != 0 )
    {
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
      if ( SUBPIXEL_HINTING_INFINALITY &&
           exc->ignore_x_mode          &&
           exc->GS.freeVector.x != 0   )
        distance = Round_None(
                     exc,
                     org_dist,
                     exc->tt_metrics.compensations[exc->opcode & 3] );
      else
#endif
        distance = exc->func_round(
                     exc,
                     org_dist,
                     exc->tt_metrics.compensations[exc->opcode & 3] );
    }
    else
      distance = Round_None(
                   exc,
                   org_dist,
                   exc->tt_metrics.compensations[exc->opcode & 3] );

    /* minimum distance flag */

    if ( ( exc->opcode & 8 ) != 0 )
    {
      if ( org_dist >= 0 )
      {
        if ( distance < minimum_distance )
          distance = minimum_distance;
      }
      else
      {
        if ( distance > NEG_LONG( minimum_distance ) )
          distance = NEG_LONG( minimum_distance );
      }
    }

    /* now move the point */

    org_dist = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 );

    exc->func_move( exc, &exc->zp1, point, SUB_LONG( distance, org_dist ) );

  Fail:
    exc->GS.rp1 = exc->GS.rp0;
    exc->GS.rp2 = point;

    if ( ( exc->opcode & 16 ) != 0 )
      exc->GS.rp0 = point;
  }

Project: savannah

  Ins_MIAP( TT_ExecContext  exc,
            FT_Long*        args )
  {
    FT_ULong    cvtEntry;
    FT_UShort   point;
    FT_F26Dot6  distance;
    FT_F26Dot6  org_dist;
    FT_F26Dot6  control_value_cutin;


    control_value_cutin = exc->GS.control_value_cutin;
    cvtEntry            = (FT_ULong)args[1];
    point               = (FT_UShort)args[0];

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    if ( SUBPIXEL_HINTING_INFINALITY                        &&
         exc->ignore_x_mode                                 &&
         exc->GS.freeVector.x != 0                          &&
         exc->GS.freeVector.y == 0                          &&
         !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
      control_value_cutin = 0;
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

    if ( BOUNDS( point,     exc->zp0.n_points ) ||
         BOUNDSL( cvtEntry, exc->cvtSize )      )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      goto Fail;
    }

    /* UNDOCUMENTED!                                                      */
    /*                                                                    */
    /* The behaviour of an MIAP instruction is quite different when used  */
    /* in the twilight zone.                                              */
    /*                                                                    */
    /* First, no control value cut-in test is performed as it would fail  */
    /* anyway.  Second, the original point, i.e. (org_x,org_y) of         */
    /* zp0.point, is set to the absolute, unrounded distance found in the */
    /* CVT.                                                               */
    /*                                                                    */
    /* This is used in the CVT programs of the Microsoft fonts Arial,     */
    /* Times, etc., in order to re-adjust some key font heights.  It      */
    /* allows the use of the IP instruction in the twilight zone, which   */
    /* otherwise would be invalid according to the specification.         */
    /*                                                                    */
    /* We implement it with a special sequence for the twilight zone.     */
    /* This is a bad hack, but it seems to work.                          */
    /*                                                                    */
    /* Confirmed by Greg Hitchcock.                                       */

    distance = exc->func_read_cvt( exc, cvtEntry );

    if ( exc->GS.gep0 == 0 )   /* If in twilight zone */
    {
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
      /* Only adjust if not in sph_compatibility_mode or ignore_x_mode. */
      /* Determined via experimentation and may be incorrect...         */
      if ( !( SUBPIXEL_HINTING_INFINALITY           &&
              ( exc->ignore_x_mode                &&
                exc->face->sph_compatibility_mode ) ) )
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
        exc->zp0.org[point].x = TT_MulFix14( distance,
                                             exc->GS.freeVector.x );
      exc->zp0.org[point].y = TT_MulFix14( distance,
                                           exc->GS.freeVector.y ),
      exc->zp0.cur[point]   = exc->zp0.org[point];
    }
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    if ( SUBPIXEL_HINTING_INFINALITY                    &&
         exc->ignore_x_mode                             &&
         ( exc->sph_tweak_flags & SPH_TWEAK_MIAP_HACK ) &&
         distance > 0                                   &&
         exc->GS.freeVector.y != 0                      )
      distance = 0;
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

    org_dist = FAST_PROJECT( &exc->zp0.cur[point] );

    if ( ( exc->opcode & 1 ) != 0 )   /* rounding and control cut-in flag */
    {
      if ( FT_ABS( distance - org_dist ) > control_value_cutin )
        distance = org_dist;

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
      if ( SUBPIXEL_HINTING_INFINALITY &&
           exc->ignore_x_mode          &&
           exc->GS.freeVector.x != 0   )
        distance = Round_None( exc,
                               distance,
                               exc->tt_metrics.compensations[0] );
      else
#endif
        distance = exc->func_round( exc,
                                    distance,
                                    exc->tt_metrics.compensations[0] );
    }

    exc->func_move( exc, &exc->zp0, point, SUB_LONG( distance, org_dist ) );

  Fail:
    exc->GS.rp0 = point;
    exc->GS.rp1 = point;
  }

Project: savannah

  Ins_MIN( FT_Long*  args )
  {
    if ( args[1] < args[0] )
      args[0] = args[1];
  }

Project: savannah

  Ins_MINDEX( TT_ExecContext  exc,
              FT_Long*        args )
  {
    FT_Long  L, K;


    L = args[0];

    if ( L <= 0 || L > exc->args )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
    }
    else
    {
      K = exc->stack[exc->args - L];

      FT_ARRAY_MOVE( &exc->stack[exc->args - L    ],
                     &exc->stack[exc->args - L + 1],
                     ( L - 1 ) );

      exc->stack[exc->args - 1] = K;
    }
  }

Project: savannah

  Ins_MIRP( TT_ExecContext  exc,
            FT_Long*        args )
  {
    FT_UShort   point;
    FT_ULong    cvtEntry;

    FT_F26Dot6  cvt_dist,
                distance,
                cur_dist,
                org_dist,
                control_value_cutin,
                minimum_distance;
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    FT_Int      B1           = 0; /* pacify compiler */
    FT_Int      B2           = 0;
    FT_Bool     reverse_move = FALSE;
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */


    minimum_distance    = exc->GS.minimum_distance;
    control_value_cutin = exc->GS.control_value_cutin;
    point               = (FT_UShort)args[0];
    cvtEntry            = (FT_ULong)( args[1] + 1 );

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    if ( SUBPIXEL_HINTING_INFINALITY                        &&
         exc->ignore_x_mode                                 &&
         exc->GS.freeVector.x != 0                          &&
         !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
      control_value_cutin = minimum_distance = 0;
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

    /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */

    if ( BOUNDS( point,       exc->zp1.n_points ) ||
         BOUNDSL( cvtEntry,   exc->cvtSize + 1 )  ||
         BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      goto Fail;
    }

    if ( !cvtEntry )
      cvt_dist = 0;
    else
      cvt_dist = exc->func_read_cvt( exc, cvtEntry - 1 );

    /* single width test */

    if ( FT_ABS( cvt_dist - exc->GS.single_width_value ) <
         exc->GS.single_width_cutin )
    {
      if ( cvt_dist >= 0 )
        cvt_dist =  exc->GS.single_width_value;
      else
        cvt_dist = -exc->GS.single_width_value;
    }

    /* UNDOCUMENTED!  The MS rasterizer does that with */
    /* twilight points (confirmed by Greg Hitchcock)   */
    if ( exc->GS.gep1 == 0 )
    {
      exc->zp1.org[point].x = exc->zp0.org[exc->GS.rp0].x +
                              TT_MulFix14( cvt_dist,
                                           exc->GS.freeVector.x );
      exc->zp1.org[point].y = exc->zp0.org[exc->GS.rp0].y +
                              TT_MulFix14( cvt_dist,
                                           exc->GS.freeVector.y );
      exc->zp1.cur[point]   = exc->zp1.org[point];
    }

    org_dist = DUALPROJ( &exc->zp1.org[point], &exc->zp0.org[exc->GS.rp0] );
    cur_dist = PROJECT ( &exc->zp1.cur[point], &exc->zp0.cur[exc->GS.rp0] );

    /* auto-flip test */

    if ( exc->GS.auto_flip )
    {
      if ( ( org_dist ^ cvt_dist ) < 0 )
        cvt_dist = -cvt_dist;
    }

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    if ( SUBPIXEL_HINTING_INFINALITY                               &&
         exc->ignore_x_mode                                        &&
         exc->GS.freeVector.y != 0                                 &&
         ( exc->sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) )
    {
      if ( cur_dist < -64 )
        cvt_dist -= 16;
      else if ( cur_dist > 64 && cur_dist < 84 )
        cvt_dist += 32;
    }
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

    /* control value cut-in and round */

    if ( ( exc->opcode & 4 ) != 0 )
    {
      /* XXX: UNDOCUMENTED!  Only perform cut-in test when both points */
      /*      refer to the same zone.                                  */

      if ( exc->GS.gep0 == exc->GS.gep1 )
      {
        /* XXX: According to Greg Hitchcock, the following wording is */
        /*      the right one:                                        */
        /*                                                            */
        /*        When the absolute difference between the value in   */
        /*        the table [CVT] and the measurement directly from   */
        /*        the outline is _greater_ than the cut_in value, the */
        /*        outline measurement is used.                        */
        /*                                                            */
        /*      This is from `instgly.doc'.  The description in       */
        /*      `ttinst2.doc', version 1.66, is thus incorrect since  */
        /*      it implies `>=' instead of `>'.                       */

        if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin )
          cvt_dist = org_dist;
      }

      distance = exc->func_round(
                   exc,
                   cvt_dist,
                   exc->tt_metrics.compensations[exc->opcode & 3] );
    }
    else
    {

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
      /* do cvt cut-in always in MIRP for sph */
      if ( SUBPIXEL_HINTING_INFINALITY  &&
           exc->ignore_x_mode           &&
           exc->GS.gep0 == exc->GS.gep1 )
      {
        if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin )
          cvt_dist = org_dist;
      }
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

      distance = Round_None(
                   exc,
                   cvt_dist,
                   exc->tt_metrics.compensations[exc->opcode & 3] );
    }

    /* minimum distance test */

    if ( ( exc->opcode & 8 ) != 0 )
    {
      if ( org_dist >= 0 )
      {
        if ( distance < minimum_distance )
          distance = minimum_distance;
      }
      else
      {
        if ( distance > NEG_LONG( minimum_distance ) )
          distance = NEG_LONG( minimum_distance );
      }
    }

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    if ( SUBPIXEL_HINTING_INFINALITY )
    {
      B1 = exc->zp1.cur[point].y;

      /* Round moves if necessary */
      if ( exc->ignore_x_mode                                          &&
           exc->GS.freeVector.y != 0                                   &&
           ( exc->sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) )
        distance = FT_PIX_ROUND( B1 + distance - cur_dist ) - B1 + cur_dist;

      if ( exc->ignore_x_mode                                      &&
           exc->GS.freeVector.y != 0                               &&
           ( exc->opcode & 16 ) == 0                               &&
           ( exc->opcode & 8 ) == 0                                &&
           ( exc->sph_tweak_flags & SPH_TWEAK_COURIER_NEW_2_HACK ) )
        distance += 64;
    }
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

    exc->func_move( exc,
                    &exc->zp1,
                    point,
                    SUB_LONG( distance, cur_dist ) );

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    if ( SUBPIXEL_HINTING_INFINALITY )
    {
      B2 = exc->zp1.cur[point].y;

      /* Reverse move if necessary */
      if ( exc->ignore_x_mode )
      {
        if ( exc->face->sph_compatibility_mode &&
             exc->GS.freeVector.y != 0         &&
             ( B1 & 63 ) == 0                  &&
             ( B2 & 63 ) != 0                  )
          reverse_move = TRUE;

        if ( ( exc->sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
             exc->GS.freeVector.y != 0                                  &&
             ( B2 & 63 ) != 0                                           &&
             ( B1 & 63 ) != 0                                           )
          reverse_move = TRUE;
      }

      if ( reverse_move )
        exc->func_move( exc,
                        &exc->zp1,
                        point,
                        SUB_LONG( cur_dist, distance ) );
    }

#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

  Fail:
    exc->GS.rp1 = exc->GS.rp0;

    if ( ( exc->opcode & 16 ) != 0 )
      exc->GS.rp0 = point;

    exc->GS.rp2 = point;
  }

Project: savannah

  Ins_MPS( TT_ExecContext  exc,
           FT_Long*        args )
  {
    if ( NO_SUBPIXEL_HINTING )
    {
      /* Microsoft's GDI bytecode interpreter always returns value 12; */
      /* we return the current PPEM value instead.                     */
      args[0] = exc->func_cur_ppem( exc );
    }
    else
    {
      /* A possible practical application of the MPS instruction is to   */
      /* implement optical scaling and similar features, which should be */
      /* based on perceptual attributes, thus independent of the         */
      /* resolution.                                                     */
      args[0] = exc->pointSize;
    }
  }

Project: savannah

  Ins_MSIRP( TT_ExecContext  exc,
             FT_Long*        args )
  {
    FT_UShort   point = 0;
    FT_F26Dot6  distance;
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    FT_F26Dot6  control_value_cutin = 0;


    if ( SUBPIXEL_HINTING_INFINALITY )
    {
      control_value_cutin = exc->GS.control_value_cutin;

      if ( exc->ignore_x_mode                                 &&
           exc->GS.freeVector.x != 0                          &&
           !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
        control_value_cutin = 0;
    }
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

    point = (FT_UShort)args[0];

    if ( BOUNDS( point,       exc->zp1.n_points ) ||
         BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      return;
    }

    /* UNDOCUMENTED!  The MS rasterizer does that with */
    /* twilight points (confirmed by Greg Hitchcock)   */
    if ( exc->GS.gep1 == 0 )
    {
      exc->zp1.org[point] = exc->zp0.org[exc->GS.rp0];
      exc->func_move_orig( exc, &exc->zp1, point, args[1] );
      exc->zp1.cur[point] = exc->zp1.org[point];
    }

    distance = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 );

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    /* subpixel hinting - make MSIRP respect CVT cut-in; */
    if ( SUBPIXEL_HINTING_INFINALITY                                    &&
         exc->ignore_x_mode                                             &&
         exc->GS.freeVector.x != 0                                      &&
         FT_ABS( SUB_LONG( distance, args[1] ) ) >= control_value_cutin )
      distance = args[1];
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

    exc->func_move( exc,
                    &exc->zp1,
                    point,
                    SUB_LONG( args[1], distance ) );

    exc->GS.rp1 = exc->GS.rp0;
    exc->GS.rp2 = point;

    if ( ( exc->opcode & 1 ) != 0 )
      exc->GS.rp0 = point;
  }

Project: savannah

  Ins_MUL( FT_Long*  args )
  {
    args[0] = FT_MulDiv( args[0], args[1], 64L );
  }

Project: savannah

  Ins_NEG( FT_Long*  args )
  {
    args[0] = NEG_LONG( args[0] );
  }

Project: savannah

  Ins_NEQ( FT_Long*  args )
  {
    args[0] = ( args[0] != args[1] );
  }

Project: savannah

  Ins_NPUSHW( TT_ExecContext  exc,
              FT_Long*        args )
  {
    FT_UShort  L, K;


    L = (FT_UShort)exc->code[exc->IP + 1];

    if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
    {
      exc->error = FT_THROW( Stack_Overflow );
      return;
    }

    exc->IP += 2;

    for ( K = 0; K < L; K++ )
      args[K] = GetShortIns( exc );

    exc->step_ins = FALSE;
    exc->new_top += L;
  }

Project: savannah

  Ins_NROUND( TT_ExecContext  exc,
              FT_Long*        args )
  {
    args[0] = Round_None(
                exc,
                args[0],
                exc->tt_metrics.compensations[exc->opcode - 0x6C] );
  }

Project: savannah

  Ins_ODD( TT_ExecContext  exc,
           FT_Long*        args )
  {
    args[0] = ( ( exc->func_round( exc, args[0], 0 ) & 127 ) == 64 );
  }

Project: savannah

  Ins_POP( void )
  {
    /* nothing to do */
  }

Project: savannah

  Ins_PUSHB( TT_ExecContext  exc,
             FT_Long*        args )
  {
    FT_UShort  L, K;


    L = (FT_UShort)( exc->opcode - 0xB0 + 1 );

    if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
    {
      exc->error = FT_THROW( Stack_Overflow );
      return;
    }

    for ( K = 1; K <= L; K++ )
      args[K - 1] = exc->code[exc->IP + K];
  }

Project: savannah

  Ins_PUSHW( TT_ExecContext  exc,
             FT_Long*        args )
  {
    FT_UShort  L, K;


    L = (FT_UShort)( exc->opcode - 0xB8 + 1 );

    if ( BOUNDS( L, exc->stackSize + 1 - exc->top ) )
    {
      exc->error = FT_THROW( Stack_Overflow );
      return;
    }

    exc->IP++;

    for ( K = 0; K < L; K++ )
      args[K] = GetShortIns( exc );

    exc->step_ins = FALSE;
  }

Project: savannah

  Ins_RCVT( TT_ExecContext  exc,
            FT_Long*        args )
  {
    FT_ULong  I = (FT_ULong)args[0];


    if ( BOUNDSL( I, exc->cvtSize ) )
    {
      if ( exc->pedantic_hinting )
        ARRAY_BOUND_ERROR;
      else
        args[0] = 0;
    }
    else
      args[0] = exc->func_read_cvt( exc, I );
  }

Project: savannah

  Ins_RDTG( TT_ExecContext  exc )
  {
    exc->GS.round_state = TT_Round_Down_To_Grid;
    exc->func_round     = (TT_Round_Func)Round_Down_To_Grid;
  }

Project: savannah

  Ins_ROLL( FT_Long*  args )
  {
    FT_Long  A, B, C;


    A = args[2];
    B = args[1];
    C = args[0];

    args[2] = C;
    args[1] = A;
    args[0] = B;
  }

Project: savannah

  Ins_ROUND( TT_ExecContext  exc,
             FT_Long*        args )
  {
    args[0] = exc->func_round(
                exc,
                args[0],
                exc->tt_metrics.compensations[exc->opcode - 0x68] );
  }

Project: savannah

  Ins_RS( TT_ExecContext  exc,
          FT_Long*        args )
  {
    FT_ULong  I = (FT_ULong)args[0];


    if ( BOUNDSL( I, exc->storeSize ) )
    {
      if ( exc->pedantic_hinting )
        ARRAY_BOUND_ERROR;
      else
        args[0] = 0;
    }
    else
    {
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
      /* subpixel hinting - avoid Typeman Dstroke and */
      /* IStroke and Vacuform rounds                  */
      if ( SUBPIXEL_HINTING_INFINALITY                 &&
           exc->ignore_x_mode                          &&
           ( ( I == 24                             &&
               ( exc->face->sph_found_func_flags &
                 ( SPH_FDEF_SPACING_1 |
                   SPH_FDEF_SPACING_2 )          ) ) ||
             ( I == 22                      &&
               ( exc->sph_in_func_flags   &
                 SPH_FDEF_TYPEMAN_STROKES ) )        ||
             ( I == 8                              &&
               ( exc->face->sph_found_func_flags &
                 SPH_FDEF_VACUFORM_ROUND_1       ) &&
               exc->iup_called                     ) ) )
        args[0] = 0;
      else
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
        args[0] = exc->storage[I];
    }
  }

Project: savannah

  Ins_RTDG( TT_ExecContext  exc )
  {
    exc->GS.round_state = TT_Round_To_Double_Grid;
    exc->func_round     = (TT_Round_Func)Round_To_Double_Grid;
  }

Project: savannah

  Ins_RTG( TT_ExecContext  exc )
  {
    exc->GS.round_state = TT_Round_To_Grid;
    exc->func_round     = (TT_Round_Func)Round_To_Grid;
  }

Project: savannah

  Ins_RTHG( TT_ExecContext  exc )
  {
    exc->GS.round_state = TT_Round_To_Half_Grid;
    exc->func_round     = (TT_Round_Func)Round_To_Half_Grid;
  }

Project: savannah

  Ins_RUTG( TT_ExecContext  exc )
  {
    exc->GS.round_state = TT_Round_Up_To_Grid;
    exc->func_round     = (TT_Round_Func)Round_Up_To_Grid;
  }

Project: savannah

  Ins_S45ROUND( TT_ExecContext  exc,
                FT_Long*        args )
  {
    SetSuperRound( exc, 0x2D41, args[0] );

    exc->GS.round_state = TT_Round_Super_45;
    exc->func_round     = (TT_Round_Func)Round_Super_45;
  }

Project: savannah

  Ins_SANGW( void )
  {
    /* instruction not supported anymore */
  }

Project: savannah

  Ins_SCANCTRL( TT_ExecContext  exc,
                FT_Long*        args )
  {
    FT_Int  A;


    /* Get Threshold */
    A = (FT_Int)( args[0] & 0xFF );

    if ( A == 0xFF )
    {
      exc->GS.scan_control = TRUE;
      return;
    }
    else if ( A == 0 )
    {
      exc->GS.scan_control = FALSE;
      return;
    }

    if ( ( args[0] & 0x100 ) != 0 && exc->tt_metrics.ppem <= A )
      exc->GS.scan_control = TRUE;

    if ( ( args[0] & 0x200 ) != 0 && exc->tt_metrics.rotated )
      exc->GS.scan_control = TRUE;

    if ( ( args[0] & 0x400 ) != 0 && exc->tt_metrics.stretched )
      exc->GS.scan_control = TRUE;

    if ( ( args[0] & 0x800 ) != 0 && exc->tt_metrics.ppem > A )
      exc->GS.scan_control = FALSE;

    if ( ( args[0] & 0x1000 ) != 0 && exc->tt_metrics.rotated )
      exc->GS.scan_control = FALSE;

    if ( ( args[0] & 0x2000 ) != 0 && exc->tt_metrics.stretched )
      exc->GS.scan_control = FALSE;
  }

Project: savannah

  Ins_SCANTYPE( TT_ExecContext  exc,
                FT_Long*        args )
  {
    if ( args[0] >= 0 )
      exc->GS.scan_type = (FT_Int)args[0] & 0xFFFF;
  }

Project: savannah

  Ins_SCFS( TT_ExecContext  exc,
            FT_Long*        args )
  {
    FT_Long    K;
    FT_UShort  L;


    L = (FT_UShort)args[0];

    if ( BOUNDS( L, exc->zp2.n_points ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      return;
    }

    K = FAST_PROJECT( &exc->zp2.cur[L] );

    exc->func_move( exc, &exc->zp2, L, SUB_LONG( args[1], K ) );

    /* UNDOCUMENTED!  The MS rasterizer does that with */
    /* twilight points (confirmed by Greg Hitchcock)   */
    if ( exc->GS.gep2 == 0 )
      exc->zp2.org[L] = exc->zp2.cur[L];
  }

Project: savannah

  Ins_SCVTCI( TT_ExecContext  exc,
              FT_Long*        args )
  {
    exc->GS.control_value_cutin = (FT_F26Dot6)args[0];
  }

Project: savannah

  Ins_SDB( TT_ExecContext  exc,
           FT_Long*        args )
  {
    exc->GS.delta_base = (FT_UShort)args[0];
  }

Project: savannah

  Ins_SDPVTL( TT_ExecContext  exc,
              FT_Long*        args )
  {
    FT_Long    A, B, C;
    FT_UShort  p1, p2;            /* was FT_Int in pas type ERROR */

    FT_Byte  opcode = exc->opcode;


    p1 = (FT_UShort)args[1];
    p2 = (FT_UShort)args[0];

    if ( BOUNDS( p2, exc->zp1.n_points ) ||
         BOUNDS( p1, exc->zp2.n_points ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      return;
    }

    {
      FT_Vector*  v1 = exc->zp1.org + p2;
      FT_Vector*  v2 = exc->zp2.org + p1;


      A = SUB_LONG( v1->x, v2->x );
      B = SUB_LONG( v1->y, v2->y );

      /* If v1 == v2, SDPvTL behaves the same as */
      /* SVTCA[X], respectively.                 */
      /*                                         */
      /* Confirmed by Greg Hitchcock.            */

      if ( A == 0 && B == 0 )
      {
        A      = 0x4000;
        opcode = 0;
      }
    }

    if ( ( opcode & 1 ) != 0 )
    {
      C = B;   /* counter clockwise rotation */
      B = A;
      A = NEG_LONG( C );
    }

    Normalize( A, B, &exc->GS.dualVector );

    {
      FT_Vector*  v1 = exc->zp1.cur + p2;
      FT_Vector*  v2 = exc->zp2.cur + p1;


      A = SUB_LONG( v1->x, v2->x );
      B = SUB_LONG( v1->y, v2->y );

      if ( A == 0 && B == 0 )
      {
        A      = 0x4000;
        opcode = 0;
      }
    }

    if ( ( opcode & 1 ) != 0 )
    {
      C = B;   /* counter clockwise rotation */
      B = A;
      A = NEG_LONG( C );
    }

    Normalize( A, B, &exc->GS.projVector );
    Compute_Funcs( exc );
  }

Project: savannah

  Ins_SDS( TT_ExecContext  exc,
           FT_Long*        args )
  {
    if ( (FT_ULong)args[0] > 6UL )
      exc->error = FT_THROW( Bad_Argument );
    else
      exc->GS.delta_shift = (FT_UShort)args[0];
  }

Project: savannah

  Ins_SFVFS( TT_ExecContext  exc,
             FT_Long*        args )
  {
    FT_Short  S;
    FT_Long   X, Y;


    /* Only use low 16bits, then sign extend */
    S = (FT_Short)args[1];
    Y = (FT_Long)S;
    S = (FT_Short)args[0];
    X = S;

    Normalize( X, Y, &exc->GS.freeVector );
    Compute_Funcs( exc );
  }

Project: savannah

  Ins_SFVTL( TT_ExecContext  exc,
             FT_Long*        args )
  {
    if ( Ins_SxVTL( exc,
                    (FT_UShort)args[1],
                    (FT_UShort)args[0],
                    &exc->GS.freeVector ) == SUCCESS )
    {
      Compute_Funcs( exc );
    }
  }

Project: savannah

  Ins_SFVTPV( TT_ExecContext  exc )
  {
    exc->GS.freeVector = exc->GS.projVector;
    Compute_Funcs( exc );
  }

Project: savannah

  Ins_SHC( TT_ExecContext  exc,
           FT_Long*        args )
  {
    TT_GlyphZoneRec  zp;
    FT_UShort        refp;
    FT_F26Dot6       dx, dy;

    FT_Short         contour, bounds;
    FT_UShort        start, limit, i;


    contour = (FT_Short)args[0];
    bounds  = ( exc->GS.gep2 == 0 ) ? 1 : exc->zp2.n_contours;

    if ( BOUNDS( contour, bounds ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      return;
    }

    if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) )
      return;

    if ( contour == 0 )
      start = 0;
    else
      start = (FT_UShort)( exc->zp2.contours[contour - 1] + 1 -
                           exc->zp2.first_point );

    /* we use the number of points if in the twilight zone */
    if ( exc->GS.gep2 == 0 )
      limit = exc->zp2.n_points;
    else
      limit = (FT_UShort)( exc->zp2.contours[contour] -
                           exc->zp2.first_point + 1 );

    for ( i = start; i < limit; i++ )
    {
      if ( zp.cur != exc->zp2.cur || refp != i )
        Move_Zp2_Point( exc, i, dx, dy, TRUE );
    }
  }

Project: savannah

  Ins_SHP( TT_ExecContext  exc )
  {
    TT_GlyphZoneRec  zp;
    FT_UShort        refp;

    FT_F26Dot6       dx, dy;
    FT_UShort        point;


    if ( exc->top < exc->GS.loop )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      goto Fail;
    }

    if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) )
      return;

    while ( exc->GS.loop > 0 )
    {
      exc->args--;
      point = (FT_UShort)exc->stack[exc->args];

      if ( BOUNDS( point, exc->zp2.n_points ) )
      {
        if ( exc->pedantic_hinting )
        {
          exc->error = FT_THROW( Invalid_Reference );
          return;
        }
      }
      else
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
      /* doesn't follow Cleartype spec but produces better result */
      if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode )
        Move_Zp2_Point( exc, point, 0, dy, TRUE );
      else
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
        Move_Zp2_Point( exc, point, dx, dy, TRUE );

      exc->GS.loop--;
    }

  Fail:
    exc->GS.loop = 1;
    exc->new_top = exc->args;
  }

Project: savannah

  Ins_SHPIX( TT_ExecContext  exc,
             FT_Long*        args )
  {
    FT_F26Dot6  dx, dy;
    FT_UShort   point;
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    FT_Int      B1, B2;
#endif
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
    FT_Bool     in_twilight = FT_BOOL( exc->GS.gep0 == 0 ||
                                       exc->GS.gep1 == 0 ||
                                       exc->GS.gep2 == 0 );
#endif



    if ( exc->top < exc->GS.loop + 1 )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      goto Fail;
    }

    dx = TT_MulFix14( args[0], exc->GS.freeVector.x );
    dy = TT_MulFix14( args[0], exc->GS.freeVector.y );

    while ( exc->GS.loop > 0 )
    {
      exc->args--;

      point = (FT_UShort)exc->stack[exc->args];

      if ( BOUNDS( point, exc->zp2.n_points ) )
      {
        if ( exc->pedantic_hinting )
        {
          exc->error = FT_THROW( Invalid_Reference );
          return;
        }
      }
      else
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
      if ( SUBPIXEL_HINTING_INFINALITY )
      {
        /*  If not using ignore_x_mode rendering, allow ZP2 move.        */
        /*  If inline deltas aren't allowed, skip ZP2 move.              */
        /*  If using ignore_x_mode rendering, allow ZP2 point move if:   */
        /*   - freedom vector is y and sph_compatibility_mode is off     */
        /*   - the glyph is composite and the move is in the Y direction */
        /*   - the glyph is specifically set to allow SHPIX moves        */
        /*   - the move is on a previously Y-touched point               */

        if ( exc->ignore_x_mode )
        {
          /* save point for later comparison */
          if ( exc->GS.freeVector.y != 0 )
            B1 = exc->zp2.cur[point].y;
          else
            B1 = exc->zp2.cur[point].x;

          if ( !exc->face->sph_compatibility_mode &&
               exc->GS.freeVector.y != 0          )
          {
            Move_Zp2_Point( exc, point, dx, dy, TRUE );

            /* save new point */
            if ( exc->GS.freeVector.y != 0 )
            {
              B2 = exc->zp2.cur[point].y;

              /* reverse any disallowed moves */
              if ( ( exc->sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
                   ( B1 & 63 ) != 0                                           &&
                   ( B2 & 63 ) != 0                                           &&
                   B1 != B2                                                   )
                Move_Zp2_Point( exc,
                                point,
                                NEG_LONG( dx ),
                                NEG_LONG( dy ),
                                TRUE );
            }
          }
          else if ( exc->face->sph_compatibility_mode )
          {
            if ( exc->sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
            {
              dx = FT_PIX_ROUND( B1 + dx ) - B1;
              dy = FT_PIX_ROUND( B1 + dy ) - B1;
            }

            /* skip post-iup deltas */
            if ( exc->iup_called                                          &&
                 ( ( exc->sph_in_func_flags & SPH_FDEF_INLINE_DELTA_1 ) ||
                   ( exc->sph_in_func_flags & SPH_FDEF_INLINE_DELTA_2 ) ) )
              goto Skip;

            if ( !( exc->sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) &&
                  ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
                    ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y )    ||
                    ( exc->sph_tweak_flags & SPH_TWEAK_DO_SHPIX )      )  )
              Move_Zp2_Point( exc, point, 0, dy, TRUE );

            /* save new point */
            if ( exc->GS.freeVector.y != 0 )
            {
              B2 = exc->zp2.cur[point].y;

              /* reverse any disallowed moves */
              if ( ( B1 & 63 ) == 0 &&
                   ( B2 & 63 ) != 0 &&
                   B1 != B2         )
                Move_Zp2_Point( exc, point, 0, NEG_LONG( dy ), TRUE );
            }
          }
          else if ( exc->sph_in_func_flags & SPH_FDEF_TYPEMAN_DIAGENDCTRL )
            Move_Zp2_Point( exc, point, dx, dy, TRUE );
        }
        else
          Move_Zp2_Point( exc, point, dx, dy, TRUE );
      }
      else
#endif
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
      if ( SUBPIXEL_HINTING_MINIMAL    &&
           exc->backward_compatibility )
      {
        /* Special case: allow SHPIX to move points in the twilight zone.  */
        /* Otherwise, treat SHPIX the same as DELTAP.  Unbreaks various    */
        /* fonts such as older versions of Rokkitt and DTL Argo T Light    */
        /* that would glitch severely after calling ALIGNRP after a        */
        /* blocked SHPIX.                                                  */
        if ( in_twilight                                                ||
             ( !( exc->iupx_called && exc->iupy_called )              &&
               ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
                 ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y )    ) ) )
          Move_Zp2_Point( exc, point, 0, dy, TRUE );
      }
      else
#endif
        Move_Zp2_Point( exc, point, dx, dy, TRUE );

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    Skip:
#endif
      exc->GS.loop--;
    }

  Fail:
    exc->GS.loop = 1;
    exc->new_top = exc->args;
  }

Project: savannah

  Ins_SLOOP( TT_ExecContext  exc,
             FT_Long*        args )
  {
    if ( args[0] < 0 )
      exc->error = FT_THROW( Bad_Argument );
    else
      exc->GS.loop = args[0];
  }

Project: savannah

  Ins_SMD( TT_ExecContext  exc,
           FT_Long*        args )
  {
    exc->GS.minimum_distance = args[0];
  }

Project: savannah

  Ins_SPVFS( TT_ExecContext  exc,
             FT_Long*        args )
  {
    FT_Short  S;
    FT_Long   X, Y;


    /* Only use low 16bits, then sign extend */
    S = (FT_Short)args[1];
    Y = (FT_Long)S;
    S = (FT_Short)args[0];
    X = (FT_Long)S;

    Normalize( X, Y, &exc->GS.projVector );

    exc->GS.dualVector = exc->GS.projVector;
    Compute_Funcs( exc );
  }

Project: savannah

  Ins_SPVTL( TT_ExecContext  exc,
             FT_Long*        args )
  {
    if ( Ins_SxVTL( exc,
                    (FT_UShort)args[1],
                    (FT_UShort)args[0],
                    &exc->GS.projVector ) == SUCCESS )
    {
      exc->GS.dualVector = exc->GS.projVector;
      Compute_Funcs( exc );
    }
  }

Project: savannah

  Ins_SROUND( TT_ExecContext  exc,
              FT_Long*        args )
  {
    SetSuperRound( exc, 0x4000, args[0] );

    exc->GS.round_state = TT_Round_Super;
    exc->func_round     = (TT_Round_Func)Round_Super;
  }

Project: savannah

  Ins_SRP0( TT_ExecContext  exc,
            FT_Long*        args )
  {
    exc->GS.rp0 = (FT_UShort)args[0];
  }

Project: savannah

  Ins_SRP1( TT_ExecContext  exc,
            FT_Long*        args )
  {
    exc->GS.rp1 = (FT_UShort)args[0];
  }

Project: savannah

  Ins_SRP2( TT_ExecContext  exc,
            FT_Long*        args )
  {
    exc->GS.rp2 = (FT_UShort)args[0];
  }

Project: savannah

  Ins_SSW( TT_ExecContext  exc,
           FT_Long*        args )
  {
    exc->GS.single_width_value = FT_MulFix( args[0],
                                            exc->tt_metrics.scale );
  }

Project: savannah

  Ins_SSWCI( TT_ExecContext  exc,
             FT_Long*        args )
  {
    exc->GS.single_width_cutin = (FT_F26Dot6)args[0];
  }

Project: savannah

  Ins_SUB( FT_Long*  args )
  {
    args[0] = SUB_LONG( args[0], args[1] );
  }

Project: savannah

  Ins_SWAP( FT_Long*  args )
  {
    FT_Long  L;


    L       = args[0];
    args[0] = args[1];
    args[1] = L;
  }

Project: savannah

  Ins_SZP0( TT_ExecContext  exc,
            FT_Long*        args )
  {
    switch ( (FT_Int)args[0] )
    {
    case 0:
      exc->zp0 = exc->twilight;
      break;

    case 1:
      exc->zp0 = exc->pts;
      break;

    default:
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      return;
    }

    exc->GS.gep0 = (FT_UShort)args[0];
  }

Project: savannah

  Ins_SZP1( TT_ExecContext  exc,
            FT_Long*        args )
  {
    switch ( (FT_Int)args[0] )
    {
    case 0:
      exc->zp1 = exc->twilight;
      break;

    case 1:
      exc->zp1 = exc->pts;
      break;

    default:
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      return;
    }

    exc->GS.gep1 = (FT_UShort)args[0];
  }

Project: savannah

  Ins_SZP2( TT_ExecContext  exc,
            FT_Long*        args )
  {
    switch ( (FT_Int)args[0] )
    {
    case 0:
      exc->zp2 = exc->twilight;
      break;

    case 1:
      exc->zp2 = exc->pts;
      break;

    default:
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      return;
    }

    exc->GS.gep2 = (FT_UShort)args[0];
  }

Project: savannah

  Ins_SZPS( TT_ExecContext  exc,
            FT_Long*        args )
  {
    switch ( (FT_Int)args[0] )
    {
    case 0:
      exc->zp0 = exc->twilight;
      break;

    case 1:
      exc->zp0 = exc->pts;
      break;

    default:
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      return;
    }

    exc->zp1 = exc->zp0;
    exc->zp2 = exc->zp0;

    exc->GS.gep0 = (FT_UShort)args[0];
    exc->GS.gep1 = (FT_UShort)args[0];
    exc->GS.gep2 = (FT_UShort)args[0];
  }

Project: savannah

  Ins_SxVTL( TT_ExecContext  exc,
             FT_UShort       aIdx1,
             FT_UShort       aIdx2,
             FT_UnitVector*  Vec )
  {
    FT_Long     A, B, C;
    FT_Vector*  p1;
    FT_Vector*  p2;

    FT_Byte  opcode = exc->opcode;


    if ( BOUNDS( aIdx1, exc->zp2.n_points ) ||
         BOUNDS( aIdx2, exc->zp1.n_points ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      return FAILURE;
    }

    p1 = exc->zp1.cur + aIdx2;
    p2 = exc->zp2.cur + aIdx1;

    A = SUB_LONG( p1->x, p2->x );
    B = SUB_LONG( p1->y, p2->y );

    /* If p1 == p2, SPvTL and SFvTL behave the same as */
    /* SPvTCA[X] and SFvTCA[X], respectively.          */
    /*                                                 */
    /* Confirmed by Greg Hitchcock.                    */

    if ( A == 0 && B == 0 )
    {
      A      = 0x4000;
      opcode = 0;
    }

    if ( ( opcode & 1 ) != 0 )
    {
      C = B;   /* counter clockwise rotation */
      B = A;
      A = NEG_LONG( C );
    }

    Normalize( A, B, Vec );

    return SUCCESS;
  }

Project: savannah

  Ins_SxyTCA( TT_ExecContext  exc )
  {
    FT_Short  AA, BB;

    FT_Byte  opcode = exc->opcode;


    AA = (FT_Short)( ( opcode & 1 ) << 14 );
    BB = (FT_Short)( AA ^ 0x4000 );

    if ( opcode < 4 )
    {
      exc->GS.projVector.x = AA;
      exc->GS.projVector.y = BB;

      exc->GS.dualVector.x = AA;
      exc->GS.dualVector.y = BB;
    }

    if ( ( opcode & 2 ) == 0 )
    {
      exc->GS.freeVector.x = AA;
      exc->GS.freeVector.y = BB;
    }

    Compute_Funcs( exc );
  }

Project: savannah

  Ins_UTP( TT_ExecContext  exc,
           FT_Long*        args )
  {
    FT_UShort  point;
    FT_Byte    mask;


    point = (FT_UShort)args[0];

    if ( BOUNDS( point, exc->zp0.n_points ) )
    {
      if ( exc->pedantic_hinting )
        exc->error = FT_THROW( Invalid_Reference );
      return;
    }

    mask = 0xFF;

    if ( exc->GS.freeVector.x != 0 )
      mask &= ~FT_CURVE_TAG_TOUCH_X;

    if ( exc->GS.freeVector.y != 0 )
      mask &= ~FT_CURVE_TAG_TOUCH_Y;

    exc->zp0.tags[point] &= mask;
  }

Project: savannah

  Ins_WCVTF( TT_ExecContext  exc,
             FT_Long*        args )
  {
    FT_ULong  I = (FT_ULong)args[0];


    if ( BOUNDSL( I, exc->cvtSize ) )
    {
      if ( exc->pedantic_hinting )
        ARRAY_BOUND_ERROR;
    }
    else
      exc->cvt[I] = FT_MulFix( args[1], exc->tt_metrics.scale );
  }

Project: savannah

  Ins_WCVTP( TT_ExecContext  exc,
             FT_Long*        args )
  {
    FT_ULong  I = (FT_ULong)args[0];


    if ( BOUNDSL( I, exc->cvtSize ) )
    {
      if ( exc->pedantic_hinting )
        ARRAY_BOUND_ERROR;
    }
    else
      exc->func_write_cvt( exc, I, args[1] );
  }

Project: savannah

  Ins_WS( TT_ExecContext  exc,
          FT_Long*        args )
  {
    FT_ULong  I = (FT_ULong)args[0];


    if ( BOUNDSL( I, exc->storeSize ) )
    {
      if ( exc->pedantic_hinting )
        ARRAY_BOUND_ERROR;
    }
    else
      exc->storage[I] = args[1];
  }

Project: savannah

  Move_CVT( TT_ExecContext  exc,
            FT_ULong        idx,
            FT_F26Dot6      value )
  {
    exc->cvt[idx] += value;
  }

Project: savannah

  Move_CVT_Stretched( TT_ExecContext  exc,
                      FT_ULong        idx,
                      FT_F26Dot6      value )
  {
    exc->cvt[idx] += FT_DivFix( value, Current_Ratio( exc ) );
  }

Project: savannah

  Normalize( FT_F26Dot6      Vx,
             FT_F26Dot6      Vy,
             FT_UnitVector*  R )
  {
    FT_Vector V;


    if ( Vx == 0 && Vy == 0 )
    {
      /* XXX: UNDOCUMENTED! It seems that it is possible to try   */
      /*      to normalize the vector (0,0).  Return immediately. */
      return SUCCESS;
    }

    V.x = Vx;
    V.y = Vy;

    FT_Vector_NormLen( &V );

    R->x = (FT_F2Dot14)( V.x / 4 );
    R->y = (FT_F2Dot14)( V.y / 4 );

    return SUCCESS;
  }

Project: savannah

  Project( TT_ExecContext  exc,
           FT_Pos          dx,
           FT_Pos          dy )
  {
    return TT_DotFix14( dx, dy,
                        exc->GS.projVector.x,
                        exc->GS.projVector.y );
  }

Project: savannah

  Project_x( TT_ExecContext  exc,
             FT_Pos          dx,
             FT_Pos          dy )
  {
    FT_UNUSED( exc );
    FT_UNUSED( dy );

    return dx;
  }

Project: savannah

  Project_y( TT_ExecContext  exc,
             FT_Pos          dx,
             FT_Pos          dy )
  {
    FT_UNUSED( exc );
    FT_UNUSED( dx );

    return dy;
  }

Project: savannah

  Read_CVT( TT_ExecContext  exc,
            FT_ULong        idx )
  {
    return exc->cvt[idx];
  }

Project: savannah

  Read_CVT_Stretched( TT_ExecContext  exc,
                      FT_ULong        idx )
  {
    return FT_MulFix( exc->cvt[idx], Current_Ratio( exc ) );
  }

Project: savannah

  Round_Down_To_Grid( TT_ExecContext  exc,
                      FT_F26Dot6      distance,
                      FT_F26Dot6      compensation )
  {
    FT_F26Dot6  val;

    FT_UNUSED( exc );


    if ( distance >= 0 )
    {
      val = FT_PIX_FLOOR( ADD_LONG( distance, compensation ) );
      if ( val < 0 )
        val = 0;
    }
    else
    {
      val = NEG_LONG( FT_PIX_FLOOR( SUB_LONG( compensation, distance ) ) );
      if ( val > 0 )
        val = 0;
    }

    return val;
  }

Project: savannah

  Round_None( TT_ExecContext  exc,
              FT_F26Dot6      distance,
              FT_F26Dot6      compensation )
  {
    FT_F26Dot6  val;

    FT_UNUSED( exc );


    if ( distance >= 0 )
    {
      val = ADD_LONG( distance, compensation );
      if ( val < 0 )
        val = 0;
    }
    else
    {
      val = SUB_LONG( distance, compensation );
      if ( val > 0 )
        val = 0;
    }
    return val;
  }

Project: savannah

  Round_Super( TT_ExecContext  exc,
               FT_F26Dot6      distance,
               FT_F26Dot6      compensation )
  {
    FT_F26Dot6  val;


    if ( distance >= 0 )
    {
      val = ADD_LONG( distance,
                      exc->threshold - exc->phase + compensation ) &
              -exc->period;
      val += exc->phase;
      if ( val < 0 )
        val = exc->phase;
    }
    else
    {
      val = NEG_LONG( SUB_LONG( exc->threshold - exc->phase + compensation,
                                distance ) &
                        -exc->period );
      val -= exc->phase;
      if ( val > 0 )
        val = -exc->phase;
    }

    return val;
  }

Project: savannah

  Round_Super_45( TT_ExecContext  exc,
                  FT_F26Dot6      distance,
                  FT_F26Dot6      compensation )
  {
    FT_F26Dot6  val;


    if ( distance >= 0 )
    {
      val = ( ADD_LONG( distance,
                        exc->threshold - exc->phase + compensation ) /
                exc->period ) * exc->period;
      val += exc->phase;
      if ( val < 0 )
        val = exc->phase;
    }
    else
    {
      val = NEG_LONG( ( SUB_LONG( exc->threshold - exc->phase + compensation,
                                  distance ) /
                          exc->period ) * exc->period );
      val -= exc->phase;
      if ( val > 0 )
        val = -exc->phase;
    }

    return val;
  }

Project: savannah

  Round_To_Double_Grid( TT_ExecContext  exc,
                        FT_F26Dot6      distance,
                        FT_F26Dot6      compensation )
  {
    FT_F26Dot6  val;

    FT_UNUSED( exc );


    if ( distance >= 0 )
    {
      val = FT_PAD_ROUND_LONG( ADD_LONG( distance, compensation ), 32 );
      if ( val < 0 )
        val = 0;
    }
    else
    {
      val = NEG_LONG( FT_PAD_ROUND_LONG( SUB_LONG( compensation, distance ),
                                         32 ) );
      if ( val > 0 )
        val = 0;
    }

    return val;
  }

Project: savannah

  Round_To_Grid( TT_ExecContext  exc,
                 FT_F26Dot6      distance,
                 FT_F26Dot6      compensation )
  {
    FT_F26Dot6  val;

    FT_UNUSED( exc );


    if ( distance >= 0 )
    {
      val = FT_PIX_ROUND_LONG( ADD_LONG( distance, compensation ) );
      if ( val < 0 )
        val = 0;
    }
    else
    {
      val = NEG_LONG( FT_PIX_ROUND_LONG( SUB_LONG( compensation,
                                                   distance ) ) );
      if ( val > 0 )
        val = 0;
    }

    return val;
  }

Project: savannah

  Round_To_Half_Grid( TT_ExecContext  exc,
                      FT_F26Dot6      distance,
                      FT_F26Dot6      compensation )
  {
    FT_F26Dot6  val;

    FT_UNUSED( exc );


    if ( distance >= 0 )
    {
      val = ADD_LONG( FT_PIX_FLOOR( ADD_LONG( distance, compensation ) ),
                      32 );
      if ( val < 0 )
        val = 32;
    }
    else
    {
      val = NEG_LONG( ADD_LONG( FT_PIX_FLOOR( SUB_LONG( compensation,
                                                        distance ) ),
                                32 ) );
      if ( val > 0 )
        val = -32;
    }

    return val;
  }

Project: savannah

  Round_Up_To_Grid( TT_ExecContext  exc,
                    FT_F26Dot6      distance,
                    FT_F26Dot6      compensation )
  {
    FT_F26Dot6  val;

    FT_UNUSED( exc );


    if ( distance >= 0 )
    {
      val = FT_PIX_CEIL_LONG( ADD_LONG( distance, compensation ) );
      if ( val < 0 )
        val = 0;
    }
    else
    {
      val = NEG_LONG( FT_PIX_CEIL_LONG( SUB_LONG( compensation,
                                                  distance ) ) );
      if ( val > 0 )
        val = 0;
    }

    return val;
  }

Project: savannah

  SetSuperRound( TT_ExecContext  exc,
                 FT_F2Dot14      GridPeriod,
                 FT_Long         selector )
  {
    switch ( (FT_Int)( selector & 0xC0 ) )
    {
      case 0:
        exc->period = GridPeriod / 2;
        break;

      case 0x40:
        exc->period = GridPeriod;
        break;

      case 0x80:
        exc->period = GridPeriod * 2;
        break;

      /* This opcode is reserved, but... */
      case 0xC0:
        exc->period = GridPeriod;
        break;
    }

    switch ( (FT_Int)( selector & 0x30 ) )
    {
    case 0:
      exc->phase = 0;
      break;

    case 0x10:
      exc->phase = exc->period / 4;
      break;

    case 0x20:
      exc->phase = exc->period / 2;
      break;

    case 0x30:
      exc->phase = exc->period * 3 / 4;
      break;
    }

    if ( ( selector & 0x0F ) == 0 )
      exc->threshold = exc->period - 1;
    else
      exc->threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * exc->period / 8;

    /* convert to F26Dot6 format */
    exc->period    >>= 8;
    exc->phase     >>= 8;
    exc->threshold >>= 8;
  }

Project: savannah

  SkipCode( TT_ExecContext  exc )
  {
    exc->IP += exc->length;

    if ( exc->IP < exc->codeSize )
    {
      exc->opcode = exc->code[exc->IP];

      exc->length = opcode_length[exc->opcode];
      if ( exc->length < 0 )
      {
        if ( exc->IP + 1 >= exc->codeSize )
          goto Fail_Overflow;
        exc->length = 2 - exc->length * exc->code[exc->IP + 1];
      }

      if ( exc->IP + exc->length <= exc->codeSize )
        return SUCCESS;
    }

  Fail_Overflow:
    exc->error = FT_THROW( Code_Overflow );
    return FAILURE;
  }

Project: savannah

  TT_Clear_CodeRange( TT_ExecContext  exec,
                      FT_Int          range )
  {
    FT_ASSERT( range >= 1 && range <= 3 );

    exec->codeRangeTable[range - 1].base = NULL;
    exec->codeRangeTable[range - 1].size = 0;
  }

Project: savannah

  TT_Done_Context( TT_ExecContext  exec )
  {
    FT_Memory  memory = exec->memory;


    /* points zone */
    exec->maxPoints   = 0;
    exec->maxContours = 0;

    /* free stack */
    FT_FREE( exec->stack );
    exec->stackSize = 0;

    /* free call stack */
    FT_FREE( exec->callStack );
    exec->callSize = 0;
    exec->callTop  = 0;

    /* free glyph code range */
    FT_FREE( exec->glyphIns );
    exec->glyphSize = 0;

    exec->size = NULL;
    exec->face = NULL;

    FT_FREE( exec );
  }

Project: savannah

  TT_DotFix14( FT_Int32  ax,
               FT_Int32  ay,
               FT_Int    bx,
               FT_Int    by )
  {
    FT_Int32   m, s, hi1, hi2, hi;
    FT_UInt32  l, lo1, lo2, lo;


    /* compute ax*bx as 64-bit value */
    l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );
    m = ( ax >> 16 ) * bx;

    lo1 = l + ( (FT_UInt32)m << 16 );
    hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l );

    /* compute ay*by as 64-bit value */
    l = (FT_UInt32)( ( ay & 0xFFFFU ) * by );
    m = ( ay >> 16 ) * by;

    lo2 = l + ( (FT_UInt32)m << 16 );
    hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l );

    /* add them */
    lo = lo1 + lo2;
    hi = hi1 + hi2 + ( lo < lo1 );

    /* divide the result by 2^14 with rounding */
    s   = hi >> 31;
    l   = lo + (FT_UInt32)s;
    hi += s + ( l < lo );
    lo  = l;

    l   = lo + 0x2000U;
    hi += ( l < lo );

    return (FT_Int32)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) );
  }

Project: savannah

  TT_DotFix14_long_long( FT_Int32  ax,
                         FT_Int32  ay,
                         FT_Int    bx,
                         FT_Int    by )
  {
    /* Temporarily disable the warning that C90 doesn't support */
    /* `long long'.                                             */

    long long  temp1 = (long long)ax * bx;
    long long  temp2 = (long long)ay * by;


    temp1 += temp2;
    temp2  = temp1 >> 63;
    temp1 += 0x2000 + temp2;

    return (FT_Int32)( temp1 >> 14 );

  }

Project: savannah

  TT_Load_Context( TT_ExecContext  exec,
                   TT_Face         face,
                   TT_Size         size )
  {
    FT_Int          i;
    FT_ULong        tmp;
    TT_MaxProfile*  maxp;
    FT_Error        error;


    exec->face = face;
    maxp       = &face->max_profile;
    exec->size = size;

    if ( size )
    {
      exec->numFDefs   = size->num_function_defs;
      exec->maxFDefs   = size->max_function_defs;
      exec->numIDefs   = size->num_instruction_defs;
      exec->maxIDefs   = size->max_instruction_defs;
      exec->FDefs      = size->function_defs;
      exec->IDefs      = size->instruction_defs;
      exec->pointSize  = size->point_size;
      exec->tt_metrics = size->ttmetrics;
      exec->metrics    = *size->metrics;

      exec->maxFunc    = size->max_func;
      exec->maxIns     = size->max_ins;

      for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
        exec->codeRangeTable[i] = size->codeRangeTable[i];

      /* set graphics state */
      exec->GS = size->GS;

      exec->cvtSize = size->cvt_size;
      exec->cvt     = size->cvt;

      exec->storeSize = size->storage_size;
      exec->storage   = size->storage;

      exec->twilight  = size->twilight;

      /* In case of multi-threading it can happen that the old size object */
      /* no longer exists, thus we must clear all glyph zone references.   */
      FT_ZERO( &exec->zp0 );
      exec->zp1 = exec->zp0;
      exec->zp2 = exec->zp0;
    }

    /* XXX: We reserve a little more elements on the stack to deal safely */
    /*      with broken fonts like arialbs, courbs, timesbs, etc.         */
    tmp = (FT_ULong)exec->stackSize;
    error = Update_Max( exec->memory,
                        &tmp,
                        sizeof ( FT_F26Dot6 ),
                        (void*)&exec->stack,
                        maxp->maxStackElements + 32 );
    exec->stackSize = (FT_Long)tmp;
    if ( error )
      return error;

    tmp = exec->glyphSize;
    error = Update_Max( exec->memory,
                        &tmp,
                        sizeof ( FT_Byte ),
                        (void*)&exec->glyphIns,
                        maxp->maxSizeOfInstructions );
    exec->glyphSize = (FT_UShort)tmp;
    if ( error )
      return error;

    exec->pts.n_points   = 0;
    exec->pts.n_contours = 0;

    exec->zp1 = exec->pts;
    exec->zp2 = exec->pts;
    exec->zp0 = exec->pts;

    exec->instruction_trap = FALSE;

    return FT_Err_Ok;
  }

Project: savannah

  TT_MulFix14_arm( FT_Int32  a,
                   FT_Int    b )
  {
    FT_Int32  t, t2;


#if defined( __CC_ARM ) || defined( __ARMCC__ )

    __asm
    {
      smull t2, t,  b,  a           /* (lo=t2,hi=t) = a*b */
      mov   a,  t,  asr #31         /* a   = (hi >> 31) */
      add   a,  a,  #0x2000         /* a  += 0x2000 */
      adds  t2, t2, a               /* t2 += a */
      adc   t,  t,  #0              /* t  += carry */
      mov   a,  t2, lsr #14         /* a   = t2 >> 14 */
      orr   a,  a,  t,  lsl #18     /* a  |= t << 18 */
    }

#elif defined( __GNUC__ )

    __asm__ __volatile__ (
      "smull  %1, %2, %4, %3\n\t"       /* (lo=%1,hi=%2) = a*b */
      "mov    %0, %2, asr #31\n\t"      /* %0  = (hi >> 31) */
#if defined( __clang__ ) && defined( __thumb2__ )
      "add.w  %0, %0, #0x2000\n\t"      /* %0 += 0x2000 */
#else
      "add    %0, %0, #0x2000\n\t"      /* %0 += 0x2000 */
#endif
      "adds   %1, %1, %0\n\t"           /* %1 += %0 */
      "adc    %2, %2, #0\n\t"           /* %2 += carry */
      "mov    %0, %1, lsr #14\n\t"      /* %0  = %1 >> 16 */
      "orr    %0, %0, %2, lsl #18\n\t"  /* %0 |= %2 << 16 */
      : "=r"(a), "=&r"(t2), "=&r"(t)
      : "r"(a), "r"(b)
      : "cc" );

#endif

    return a;
  }

Project: savannah

  TT_New_Context( TT_Driver  driver )
  {
    FT_Memory  memory;
    FT_Error   error;

    TT_ExecContext  exec = NULL;


    if ( !driver )
      goto Fail;

    memory = driver->root.root.memory;

    /* allocate object */
    if ( FT_NEW( exec ) )
      goto Fail;

    /* initialize it; in case of error this deallocates `exec' too */
    error = Init_Context( exec, memory );
    if ( error )
      goto Fail;

    return exec;

  Fail:
    return NULL;
  }

Project: savannah

  TT_RunIns( TT_ExecContext  exc )
  {
    FT_ULong   ins_counter = 0;  /* executed instructions counter */
    FT_ULong   num_twilight_points;
    FT_UShort  i;

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    FT_Byte    opcode_pattern[1][2] = {
                  /* #8 TypeMan Talk Align */
                  {
                    0x06, /* SPVTL   */
                    0x7D, /* RDTG    */
                  },
                };
    FT_UShort  opcode_patterns   = 1;
    FT_UShort  opcode_pointer[1] = { 0 };
    FT_UShort  opcode_size[1]    = { 1 };
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */


#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
    exc->iup_called = FALSE;
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
    /*
     *  Toggle backward compatibility according to what font wants, except
     *  when
     *
     *  1) we have a `tricky' font that heavily relies on the interpreter to
     *     render glyphs correctly, for example DFKai-SB, or
     *  2) FT_RENDER_MODE_MONO (i.e, monochome rendering) is requested.
     *
     *  In those cases, backward compatibility needs to be turned off to get
     *  correct rendering.  The rendering is then completely up to the
     *  font's programming.
     *
     */
    if ( SUBPIXEL_HINTING_MINIMAL          &&
         exc->subpixel_hinting_lean        &&
         !FT_IS_TRICKY( &exc->face->root ) )
      exc->backward_compatibility = !( exc->GS.instruct_control & 4 );
    else
      exc->backward_compatibility = FALSE;

    exc->iupx_called = FALSE;
    exc->iupy_called = FALSE;
#endif

    /* We restrict the number of twilight points to a reasonable,     */
    /* heuristic value to avoid slow execution of malformed bytecode. */
    num_twilight_points = FT_MAX( 30,
                                  2 * ( exc->pts.n_points + exc->cvtSize ) );
    if ( exc->twilight.n_points > num_twilight_points )
    {
      if ( num_twilight_points > 0xFFFFU )
        num_twilight_points = 0xFFFFU;

      FT_TRACE5(( "TT_RunIns: Resetting number of twilight points\n"
                  "           from %d to the more reasonable value %d\n",
                  exc->twilight.n_points,
                  num_twilight_points ));
      exc->twilight.n_points = (FT_UShort)num_twilight_points;
    }

    /* Set up loop detectors.  We restrict the number of LOOPCALL loops */
    /* and the number of JMPR, JROT, and JROF calls with a negative     */
    /* argument to values that depend on various parameters like the    */
    /* size of the CVT table or the number of points in the current     */
    /* glyph (if applicable).                                           */
    /*                                                                  */
    /* The idea is that in real-world bytecode you either iterate over  */
    /* all CVT entries (in the `prep' table), or over all points (or    */
    /* contours, in the `glyf' table) of a glyph, and such iterations   */
    /* don't happen very often.                                         */
    exc->loopcall_counter = 0;
    exc->neg_jump_counter = 0;

    /* The maximum values are heuristic. */
    if ( exc->pts.n_points )
      exc->loopcall_counter_max = FT_MAX( 50,
                                          10 * exc->pts.n_points ) +
                                  FT_MAX( 50,
                                          exc->cvtSize / 10 );
    else
      exc->loopcall_counter_max = 300 + 8 * exc->cvtSize;

    /* as a protection against an unreasonable number of CVT entries  */
    /* we assume at most 100 control values per glyph for the counter */
    if ( exc->loopcall_counter_max >
         100 * (FT_ULong)exc->face->root.num_glyphs )
      exc->loopcall_counter_max = 100 * (FT_ULong)exc->face->root.num_glyphs;

    FT_TRACE5(( "TT_RunIns: Limiting total number of loops in LOOPCALL"
                " to %d\n", exc->loopcall_counter_max ));

    exc->neg_jump_counter_max = exc->loopcall_counter_max;
    FT_TRACE5(( "TT_RunIns: Limiting total number of backward jumps"
                " to %d\n", exc->neg_jump_counter_max ));

    /* set PPEM and CVT functions */
    exc->tt_metrics.ratio = 0;
    if ( exc->metrics.x_ppem != exc->metrics.y_ppem )
    {
      /* non-square pixels, use the stretched routines */
      exc->func_cur_ppem  = Current_Ppem_Stretched;
      exc->func_read_cvt  = Read_CVT_Stretched;
      exc->func_write_cvt = Write_CVT_Stretched;
      exc->func_move_cvt  = Move_CVT_Stretched;
    }
    else
    {
      /* square pixels, use normal routines */
      exc->func_cur_ppem  = Current_Ppem;
      exc->func_read_cvt  = Read_CVT;
      exc->func_write_cvt = Write_CVT;
      exc->func_move_cvt  = Move_CVT;
    }

    Compute_Funcs( exc );
    Compute_Round( exc, (FT_Byte)exc->GS.round_state );

    do
    {
      exc->opcode = exc->code[exc->IP];

#ifdef FT_DEBUG_LEVEL_TRACE
      {
        FT_Long  cnt = FT_MIN( 8, exc->top );
        FT_Long  n;


        /* if tracing level is 7, show current code position */
        /* and the first few stack elements also             */
        FT_TRACE6(( "  " ));
        FT_TRACE7(( "%06d ", exc->IP ));
        FT_TRACE6(( opcode_name[exc->opcode] + 2 ));
        FT_TRACE7(( "%*s", *opcode_name[exc->opcode] == 'A'
                              ? 2
                              : 12 - ( *opcode_name[exc->opcode] - '0' ),
                              "#" ));
        for ( n = 1; n <= cnt; n++ )
          FT_TRACE7(( " %d", exc->stack[exc->top - n] ));
        FT_TRACE6(( "\n" ));
      }
#endif /* FT_DEBUG_LEVEL_TRACE */

      if ( ( exc->length = opcode_length[exc->opcode] ) < 0 )
      {
        if ( exc->IP + 1 >= exc->codeSize )
          goto LErrorCodeOverflow_;

        exc->length = 2 - exc->length * exc->code[exc->IP + 1];
      }

      if ( exc->IP + exc->length > exc->codeSize )
        goto LErrorCodeOverflow_;

      /* First, let's check for empty stack and overflow */
      exc->args = exc->top - ( Pop_Push_Count[exc->opcode] >> 4 );

      /* `args' is the top of the stack once arguments have been popped. */
      /* One can also interpret it as the index of the last argument.    */
      if ( exc->args < 0 )
      {
        if ( exc->pedantic_hinting )
        {
          exc->error = FT_THROW( Too_Few_Arguments );
          goto LErrorLabel_;
        }

        /* push zeroes onto the stack */
        for ( i = 0; i < Pop_Push_Count[exc->opcode] >> 4; i++ )
          exc->stack[i] = 0;
        exc->args = 0;
      }

#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
      if ( exc->opcode == 0x91 )
      {
        /* this is very special: GETVARIATION returns */
        /* a variable number of arguments             */

        /* it is the job of the application to `activate' GX handling, */
        /* this is, calling any of the GX API functions on the current */
        /* font to select a variation instance                         */
        if ( exc->face->blend )
          exc->new_top = exc->args + exc->face->blend->num_axis;
      }
      else
#endif
        exc->new_top = exc->args + ( Pop_Push_Count[exc->opcode] & 15 );

      /* `new_top' is the new top of the stack, after the instruction's */
      /* execution.  `top' will be set to `new_top' after the `switch'  */
      /* statement.                                                     */
      if ( exc->new_top > exc->stackSize )
      {
        exc->error = FT_THROW( Stack_Overflow );
        goto LErrorLabel_;
      }

      exc->step_ins = TRUE;
      exc->error    = FT_Err_Ok;

#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY

      if ( SUBPIXEL_HINTING_INFINALITY )
      {
        for ( i = 0; i < opcode_patterns; i++ )
        {
          if ( opcode_pointer[i] < opcode_size[i]                  &&
               exc->opcode == opcode_pattern[i][opcode_pointer[i]] )
          {
            opcode_pointer[i] += 1;

            if ( opcode_pointer[i] == opcode_size[i] )
            {
              FT_TRACE6(( "sph: opcode ptrn: %d, %s %s\n",
                          i,
                          exc->face->root.family_name,
                          exc->face->root.style_name ));

              switch ( i )
              {
              case 0:
                break;
              }
              opcode_pointer[i] = 0;
            }
          }
          else
            opcode_pointer[i] = 0;
        }
      }

#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */

      {
        FT_Long*  args   = exc->stack + exc->args;
        FT_Byte   opcode = exc->opcode;


        switch ( opcode )
        {
        case 0x00:  /* SVTCA y  */
        case 0x01:  /* SVTCA x  */
        case 0x02:  /* SPvTCA y */
        case 0x03:  /* SPvTCA x */
        case 0x04:  /* SFvTCA y */
        case 0x05:  /* SFvTCA x */
          Ins_SxyTCA( exc );
          break;

        case 0x06:  /* SPvTL // */
        case 0x07:  /* SPvTL +  */
          Ins_SPVTL( exc, args );
          break;

        case 0x08:  /* SFvTL // */
        case 0x09:  /* SFvTL +  */
          Ins_SFVTL( exc, args );
          break;

        case 0x0A:  /* SPvFS */
          Ins_SPVFS( exc, args );
          break;

        case 0x0B:  /* SFvFS */
          Ins_SFVFS( exc, args );
          break;

        case 0x0C:  /* GPv */
          Ins_GPV( exc, args );
          break;

        case 0x0D:  /* GFv */
          Ins_GFV( exc, args );
          break;

        case 0x0E:  /* SFvTPv */
          Ins_SFVTPV( exc );
          break;

        case 0x0F:  /* ISECT  */
          Ins_ISECT( exc, args );
          break;

        case 0x10:  /* SRP0 */
          Ins_SRP0( exc, args );
          break;

        case 0x11:  /* SRP1 */
          Ins_SRP1( exc, args );
          break;

        case 0x12:  /* SRP2 */
          Ins_SRP2( exc, args );
          break;

        case 0x13:  /* SZP0 */
          Ins_SZP0( exc, args );
          break;

        case 0x14:  /* SZP1 */
          Ins_SZP1( exc, args );
          break;

        case 0x15:  /* SZP2 */
          Ins_SZP2( exc, args );
          break;

        case 0x16:  /* SZPS */
          Ins_SZPS( exc, args );
          break;

        case 0x17:  /* SLOOP */
          Ins_SLOOP( exc, args );
          break;

        case 0x18:  /* RTG */
          Ins_RTG( exc );
          break;

        case 0x19:  /* RTHG */
          Ins_RTHG( exc );
          break;

        case 0x1A:  /* SMD */
          Ins_SMD( exc, args );
          break;

        case 0x1B:  /* ELSE */
          Ins_ELSE( exc );
          break;

        case 0x1C:  /* JMPR */
          Ins_JMPR( exc, args );
          break;

        case 0x1D:  /* SCVTCI */
          Ins_SCVTCI( exc, args );
          break;

        case 0x1E:  /* SSWCI */
          Ins_SSWCI( exc, args );
          break;

        case 0x1F:  /* SSW */
          Ins_SSW( exc, args );
          break;

        case 0x20:  /* DUP */
          Ins_DUP( args );
          break;

        case 0x21:  /* POP */
          Ins_POP();
          break;

        case 0x22:  /* CLEAR */
          Ins_CLEAR( exc );
          break;

        case 0x23:  /* SWAP */
          Ins_SWAP( args );
          break;

        case 0x24:  /* DEPTH */
          Ins_DEPTH( exc, args );
          break;

        case 0x25:  /* CINDEX */
          Ins_CINDEX( exc, args );
          break;

        case 0x26:  /* MINDEX */
          Ins_MINDEX( exc, args );
          break;

        case 0x27:  /* ALIGNPTS */
          Ins_ALIGNPTS( exc, args );
          break;

        case 0x28:  /* RAW */
          Ins_UNKNOWN( exc );
          break;

        case 0x29:  /* UTP */
          Ins_UTP( exc, args );
          break;

        case 0x2A:  /* LOOPCALL */
          Ins_LOOPCALL( exc, args );
          break;

        case 0x2B:  /* CALL */
          Ins_CALL( exc, args );
          break;

        case 0x2C:  /* FDEF */
          Ins_FDEF( exc, args );
          break;

        case 0x2D:  /* ENDF */
          Ins_ENDF( exc );
          break;

        case 0x2E:  /* MDAP */
        case 0x2F:  /* MDAP */
          Ins_MDAP( exc, args );
          break;

        case 0x30:  /* IUP */
        case 0x31:  /* IUP */
          Ins_IUP( exc );
          break;

        case 0x32:  /* SHP */
        case 0x33:  /* SHP */
          Ins_SHP( exc );
          break;

        case 0x34:  /* SHC */
        case 0x35:  /* SHC */
          Ins_SHC( exc, args );
          break;

        case 0x36:  /* SHZ */
        case 0x37:  /* SHZ */
          Ins_SHZ( exc, args );
          break;

        case 0x38:  /* SHPIX */
          Ins_SHPIX( exc, args );
          break;

        case 0x39:  /* IP    */
          Ins_IP( exc );
          break;

        case 0x3A:  /* MSIRP */
        case 0x3B:  /* MSIRP */
          Ins_MSIRP( exc, args );
          break;

        case 0x3C:  /* AlignRP */
          Ins_ALIGNRP( exc );
          break;

        case 0x3D:  /* RTDG */
          Ins_RTDG( exc );
          break;

        case 0x3E:  /* MIAP */
        case 0x3F:  /* MIAP */
          Ins_MIAP( exc, args );
          break;

        case 0x40:  /* NPUSHB */
          Ins_NPUSHB( exc, args );
          break;

        case 0x41:  /* NPUSHW */
          Ins_NPUSHW( exc, args );
          break;

        case 0x42:  /* WS */
          Ins_WS( exc, args );
          break;

        case 0x43:  /* RS */
          Ins_RS( exc, args );
          break;

        case 0x44:  /* WCVTP */
          Ins_WCVTP( exc, args );
          break;

        case 0x45:  /* RCVT */
          Ins_RCVT( exc, args );
          break;

        case 0x46:  /* GC */
        case 0x47:  /* GC */
          Ins_GC( exc, args );
          break;

        case 0x48:  /* SCFS */
          Ins_SCFS( exc, args );
          break;

        case 0x49:  /* MD */
        case 0x4A:  /* MD */
          Ins_MD( exc, args );
          break;

        case 0x4B:  /* MPPEM */
          Ins_MPPEM( exc, args );
          break;

        case 0x4C:  /* MPS */
          Ins_MPS( exc, args );
          break;

        case 0x4D:  /* FLIPON */
          Ins_FLIPON( exc );
          break;

        case 0x4E:  /* FLIPOFF */
          Ins_FLIPOFF( exc );
          break;

        case 0x4F:  /* DEBUG */
          Ins_DEBUG( exc );
          break;

        case 0x50:  /* LT */
          Ins_LT( args );
          break;

        case 0x51:  /* LTEQ */
          Ins_LTEQ( args );
          break;

        case 0x52:  /* GT */
          Ins_GT( args );
          break;

        case 0x53:  /* GTEQ */
          Ins_GTEQ( args );
          break;

        case 0x54:  /* EQ */
          Ins_EQ( args );
          break;

        case 0x55:  /* NEQ */
          Ins_NEQ( args );
          break;

        case 0x56:  /* ODD */
          Ins_ODD( exc, args );
          break;

        case 0x57:  /* EVEN */
          Ins_EVEN( exc, args );
          break;

        case 0x58:  /* IF */
          Ins_IF( exc, args );
          break;

        case 0x59:  /* EIF */
          Ins_EIF();
          break;

        case 0x5A:  /* AND */
          Ins_AND( args );
          break;

        case 0x5B:  /* OR */
          Ins_OR( args );
          break;

        case 0x5C:  /* NOT */
          Ins_NOT( args );
          break;

        case 0x5D:  /* DELTAP1 */
          Ins_DELTAP( exc, args );
          break;

        case 0x5E:  /* SDB */
          Ins_SDB( exc, args );
          break;

        case 0x5F:  /* SDS */
          Ins_SDS( exc, args );
          break;

        case 0x60:  /* ADD */
          Ins_ADD( args );
          break;

        case 0x61:  /* SUB */
          Ins_SUB( args );
          break;

        case 0x62:  /* DIV */
          Ins_DIV( exc, args );
          break;

        case 0x63:  /* MUL */
          Ins_MUL( args );
          break;

        case 0x64:  /* ABS */
          Ins_ABS( args );
          break;

        case 0x65:  /* NEG */
          Ins_NEG( args );
          break;

        case 0x66:  /* FLOOR */
          Ins_FLOOR( args );
          break;

        case 0x67:  /* CEILING */
          Ins_CEILING( args );
          break;

        case 0x68:  /* ROUND */
        case 0x69:  /* ROUND */
        case 0x6A:  /* ROUND */
        case 0x6B:  /* ROUND */
          Ins_ROUND( exc, args );
          break;

        case 0x6C:  /* NROUND */
        case 0x6D:  /* NROUND */
        case 0x6E:  /* NRRUND */
        case 0x6F:  /* NROUND */
          Ins_NROUND( exc, args );
          break;

        case 0x70:  /* WCVTF */
          Ins_WCVTF( exc, args );
          break;

        case 0x71:  /* DELTAP2 */
        case 0x72:  /* DELTAP3 */
          Ins_DELTAP( exc, args );
          break;

        case 0x73:  /* DELTAC0 */
        case 0x74:  /* DELTAC1 */
        case 0x75:  /* DELTAC2 */
          Ins_DELTAC( exc, args );
          break;

        case 0x76:  /* SROUND */
          Ins_SROUND( exc, args );
          break;

        case 0x77:  /* S45Round */
          Ins_S45ROUND( exc, args );
          break;

        case 0x78:  /* JROT */
          Ins_JROT( exc, args );
          break;

        case 0x79:  /* JROF */
          Ins_JROF( exc, args );
          break;

        case 0x7A:  /* ROFF */
          Ins_ROFF( exc );
          break;

        case 0x7B:  /* ???? */
          Ins_UNKNOWN( exc );
          break;

        case 0x7C:  /* RUTG */
          Ins_RUTG( exc );
          break;

        case 0x7D:  /* RDTG */
          Ins_RDTG( exc );
          break;

        case 0x7E:  /* SANGW */
          Ins_SANGW();
          break;

        case 0x7F:  /* AA */
          Ins_AA();
          break;

        case 0x80:  /* FLIPPT */
          Ins_FLIPPT( exc );
          break;

        case 0x81:  /* FLIPRGON */
          Ins_FLIPRGON( exc, args );
          break;

        case 0x82:  /* FLIPRGOFF */
          Ins_FLIPRGOFF( exc, args );
          break;

        case 0x83:  /* UNKNOWN */
        case 0x84:  /* UNKNOWN */
          Ins_UNKNOWN( exc );
          break;

        case 0x85:  /* SCANCTRL */
          Ins_SCANCTRL( exc, args );
          break;

        case 0x86:  /* SDPvTL */
        case 0x87:  /* SDPvTL */
          Ins_SDPVTL( exc, args );
          break;

        case 0x88:  /* GETINFO */
          Ins_GETINFO( exc, args );
          break;

        case 0x89:  /* IDEF */
          Ins_IDEF( exc, args );
          break;

        case 0x8A:  /* ROLL */
          Ins_ROLL( args );
          break;

        case 0x8B:  /* MAX */
          Ins_MAX( args );
          break;

        case 0x8C:  /* MIN */
          Ins_MIN( args );
          break;

        case 0x8D:  /* SCANTYPE */
          Ins_SCANTYPE( exc, args );
          break;

        case 0x8E:  /* INSTCTRL */
          Ins_INSTCTRL( exc, args );
          break;

        case 0x8F:  /* ADJUST */
        case 0x90:  /* ADJUST */
          Ins_UNKNOWN( exc );
          break;

#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
        case 0x91:
          /* it is the job of the application to `activate' GX handling, */
          /* this is, calling any of the GX API functions on the current */
          /* font to select a variation instance                         */
          if ( exc->face->blend )
            Ins_GETVARIATION( exc, args );
          else
            Ins_UNKNOWN( exc );
          break;

        case 0x92:
          /* there is at least one MS font (LaoUI.ttf version 5.01) that */
          /* uses IDEFs for 0x91 and 0x92; for this reason we activate   */
          /* GETDATA for GX fonts only, similar to GETVARIATION          */
          if ( exc->face->blend )
            Ins_GETDATA( args );
          else
            Ins_UNKNOWN( exc );
          break;
#endif

        default:
          if ( opcode >= 0xE0 )
            Ins_MIRP( exc, args );
          else if ( opcode >= 0xC0 )
            Ins_MDRP( exc, args );
          else if ( opcode >= 0xB8 )
            Ins_PUSHW( exc, args );
          else if ( opcode >= 0xB0 )
            Ins_PUSHB( exc, args );
          else
            Ins_UNKNOWN( exc );
        }
      }

      if ( exc->error )
      {
        switch ( exc->error )
        {
          /* looking for redefined instructions */
        case FT_ERR( Invalid_Opcode ):
          {
            TT_DefRecord*  def   = exc->IDefs;
            TT_DefRecord*  limit = def + exc->numIDefs;


            for ( ; def < limit; def++ )
            {
              if ( def->active && exc->opcode == (FT_Byte)def->opc )
              {
                TT_CallRec*  callrec;


                if ( exc->callTop >= exc->callSize )
                {
                  exc->error = FT_THROW( Invalid_Reference );
                  goto LErrorLabel_;
                }

                callrec = &exc->callStack[exc->callTop];

                callrec->Caller_Range = exc->curRange;
                callrec->Caller_IP    = exc->IP + 1;
                callrec->Cur_Count    = 1;
                callrec->Def          = def;

                if ( Ins_Goto_CodeRange( exc,
                                         def->range,
                                         def->start ) == FAILURE )
                  goto LErrorLabel_;

                goto LSuiteLabel_;
              }
            }
          }

          exc->error = FT_THROW( Invalid_Opcode );
          goto LErrorLabel_;

#if 0
          break;   /* Unreachable code warning suppression.             */
                   /* Leave to remind in case a later change the editor */
                   /* to consider break;                                */
#endif

        default:
          goto LErrorLabel_;

#if 0
        break;
#endif
        }
      }

      exc->top = exc->new_top;

      if ( exc->step_ins )
        exc->IP += exc->length;

      /* increment instruction counter and check if we didn't */
      /* run this program for too long (e.g. infinite loops). */
      if ( ++ins_counter > TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES )
        return FT_THROW( Execution_Too_Long );

    LSuiteLabel_:
      if ( exc->IP >= exc->codeSize )
      {
        if ( exc->callTop > 0 )
        {
          exc->error = FT_THROW( Code_Overflow );
          goto LErrorLabel_;
        }
        else
          goto LNo_Error_;
      }
    } while ( !exc->instruction_trap );

  LNo_Error_:
    FT_TRACE4(( "  %d instruction%s executed\n",
                ins_counter == 1 ? "" : "s",
                ins_counter ));
    return FT_Err_Ok;

  LErrorCodeOverflow_:
    exc->error = FT_THROW( Code_Overflow );

  LErrorLabel_:
    if ( exc->error && !exc->instruction_trap )
      FT_TRACE1(( "  The interpreter returned error 0x%x\n", exc->error ));

    return exc->error;
  }

Project: savannah

  TT_Run_Context( TT_ExecContext  exec )
  {
    TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 );

    exec->zp0 = exec->pts;
    exec->zp1 = exec->pts;
    exec->zp2 = exec->pts;

    exec->GS.gep0 = 1;
    exec->GS.gep1 = 1;
    exec->GS.gep2 = 1;

    exec->GS.projVector.x = 0x4000;
    exec->GS.projVector.y = 0x0000;

    exec->GS.freeVector = exec->GS.projVector;
    exec->GS.dualVector = exec->GS.projVector;

    exec->GS.round_state = 1;
    exec->GS.loop        = 1;

    /* some glyphs leave something on the stack. so we clean it */
    /* before a new execution.                                  */
    exec->top     = 0;
    exec->callTop = 0;

    return exec->face->interpreter( exec );
  }

Project: savannah

  TT_Save_Context( TT_ExecContext  exec,
                   TT_Size         size )
  {
    FT_Int  i;


    /* XXX: Will probably disappear soon with all the code range */
    /*      management, which is now rather obsolete.            */
    /*                                                           */
    size->num_function_defs    = exec->numFDefs;
    size->num_instruction_defs = exec->numIDefs;

    size->max_func = exec->maxFunc;
    size->max_ins  = exec->maxIns;

    for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
      size->codeRangeTable[i] = exec->codeRangeTable[i];
  }

Project: savannah

  TT_Set_CodeRange( TT_ExecContext  exec,
                    FT_Int          range,
                    void*           base,
                    FT_Long         length )
  {
    FT_ASSERT( range >= 1 && range <= 3 );

    exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
    exec->codeRangeTable[range - 1].size = length;
  }

Project: savannah

  Update_Max( FT_Memory  memory,
              FT_ULong*  size,
              FT_ULong   multiplier,
              void*      _pbuff,
              FT_ULong   new_max )
  {
    FT_Error  error;
    void**    pbuff = (void**)_pbuff;


    if ( *size < new_max )
    {
      if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )
        return error;
      *size = new_max;
    }

    return FT_Err_Ok;
  }

Project: savannah

  Write_CVT( TT_ExecContext  exc,
             FT_ULong        idx,
             FT_F26Dot6      value )
  {
    exc->cvt[idx] = value;
  }

Project: savannah

  Write_CVT_Stretched( TT_ExecContext  exc,
                       FT_ULong        idx,
                       FT_F26Dot6      value )
  {
    exc->cvt[idx] = FT_DivFix( value, Current_Ratio( exc ) );
  }

Project: savannah

  _iup_worker_interpolate( IUP_Worker  worker,
                           FT_UInt     p1,
                           FT_UInt     p2,
                           FT_UInt     ref1,
                           FT_UInt     ref2 )
  {
    FT_UInt     i;
    FT_F26Dot6  orus1, orus2, org1, org2, cur1, cur2, delta1, delta2;


    if ( p1 > p2 )
      return;

    if ( BOUNDS( ref1, worker->max_points ) ||
         BOUNDS( ref2, worker->max_points ) )
      return;

    orus1 = worker->orus[ref1].x;
    orus2 = worker->orus[ref2].x;

    if ( orus1 > orus2 )
    {
      FT_F26Dot6  tmp_o;
      FT_UInt     tmp_r;


      tmp_o = orus1;
      orus1 = orus2;
      orus2 = tmp_o;

      tmp_r = ref1;
      ref1  = ref2;
      ref2  = tmp_r;
    }

    org1   = worker->orgs[ref1].x;
    org2   = worker->orgs[ref2].x;
    cur1   = worker->curs[ref1].x;
    cur2   = worker->curs[ref2].x;
    delta1 = SUB_LONG( cur1, org1 );
    delta2 = SUB_LONG( cur2, org2 );

    if ( cur1 == cur2 || orus1 == orus2 )
    {

      /* trivial snap or shift of untouched points */
      for ( i = p1; i <= p2; i++ )
      {
        FT_F26Dot6  x = worker->orgs[i].x;


        if ( x <= org1 )
          x = ADD_LONG( x, delta1 );

        else if ( x >= org2 )
          x = ADD_LONG( x, delta2 );

        else
          x = cur1;

        worker->curs[i].x = x;
      }
    }
    else
    {
      FT_Fixed  scale       = 0;
      FT_Bool   scale_valid = 0;


      /* interpolation */
      for ( i = p1; i <= p2; i++ )
      {
        FT_F26Dot6  x = worker->orgs[i].x;


        if ( x <= org1 )
          x = ADD_LONG( x, delta1 );

        else if ( x >= org2 )
          x = ADD_LONG( x, delta2 );

        else
        {
          if ( !scale_valid )
          {
            scale_valid = 1;
            scale       = FT_DivFix( SUB_LONG( cur2, cur1 ),
                                     SUB_LONG( orus2, orus1 ) );
          }

          x = ADD_LONG( cur1,
                        FT_MulFix( SUB_LONG( worker->orus[i].x, orus1 ),
                                   scale ) );
        }
        worker->curs[i].x = x;
      }
    }
  }

Project: savannah

  _iup_worker_shift( IUP_Worker  worker,
                     FT_UInt     p1,
                     FT_UInt     p2,
                     FT_UInt     p )
  {
    FT_UInt     i;
    FT_F26Dot6  dx;


    dx = SUB_LONG( worker->curs[p].x, worker->orgs[p].x );
    if ( dx != 0 )
    {
      for ( i = p1; i < p; i++ )
        worker->curs[i].x = ADD_LONG( worker->curs[i].x, dx );

      for ( i = p + 1; i <= p2; i++ )
        worker->curs[i].x = ADD_LONG( worker->curs[i].x, dx );
    }
  }