Commit message: None
CVE: CVE-2017-9739
CWE: CWE-125
Vulnerability description: The Ins_JMPR function in base/ttinterp.c in Artifex Ghostscript GhostXPS 9.21 allows remote attackers to cause a denial of service (heap-based buffer over-read and application crash) or possibly have unspecified other impact via a crafted document.

Project: ghostscript
File: ttinterp.c

  static Bool  Calc_Length( EXEC_OP )
  {
    CUR.opcode = CUR.code[CUR.IP];

    switch ( CUR.opcode )
    {
    case 0x40:
      if ( CUR.IP + 1 >= CUR.codeSize )
        return FAILURE;

      CUR.length = CUR.code[CUR.IP + 1] + 2;
      break;

    case 0x41:
      if ( CUR.IP + 1 >= CUR.codeSize )
        return FAILURE;

      CUR.length = CUR.code[CUR.IP + 1] * 2 + 2;
      break;

    case 0xB0:
    case 0xB1:
    case 0xB2:
    case 0xB3:
    case 0xB4:
    case 0xB5:
    case 0xB6:
    case 0xB7:
      CUR.length = CUR.opcode - 0xB0 + 2;
      break;

    case 0xB8:
    case 0xB9:
    case 0xBA:
    case 0xBB:
    case 0xBC:
    case 0xBD:
    case 0xBE:
    case 0xBF:
      CUR.length = (CUR.opcode - 0xB8) * 2 + 3;
      break;

    default:
      CUR.length = 1;
      break;
    }

    /* make sure result is in range */

    if ( CUR.IP + CUR.length > CUR.codeSize )
      return FAILURE;

    return SUCCESS;
  }

Project: ghostscript
File: ttinterp.c

  static void  Compute_Funcs( EXEC_OP )
  {
    if ( CUR.GS.freeVector.x == 0x4000 )
    {
      CUR.func_freeProj = (TProject_Function)Project_x;
      CUR.F_dot_P       = CUR.GS.projVector.x * 0x10000L;
    }
    else
    {
      if ( CUR.GS.freeVector.y == 0x4000 )
      {
        CUR.func_freeProj = (TProject_Function)Project_y;
        CUR.F_dot_P       = CUR.GS.projVector.y * 0x10000L;
      }
      else
      {
        CUR.func_move     = (TMove_Function)Direct_Move;
        CUR.func_freeProj = (TProject_Function)Free_Project;
        CUR.F_dot_P = (Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
                      (Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
      }
    }

    CUR.cached_metrics = FALSE;

    if ( CUR.GS.projVector.x == 0x4000 )
      CUR.func_project = (TProject_Function)Project_x;
    else
    {
      if ( CUR.GS.projVector.y == 0x4000 )
        CUR.func_project = (TProject_Function)Project_y;
      else
        CUR.func_project = (TProject_Function)Project;
    }

    if ( CUR.GS.dualVector.x == 0x4000 )
      CUR.func_dualproj = (TProject_Function)Project_x;
    else
    {
      if ( CUR.GS.dualVector.y == 0x4000 )
        CUR.func_dualproj = (TProject_Function)Project_y;
      else
        CUR.func_dualproj = (TProject_Function)Dual_Project;
    }

    CUR.func_move = (TMove_Function)Direct_Move;

    if ( CUR.F_dot_P == 0x40000000L )
    {
      if ( CUR.GS.freeVector.x == 0x4000 )
        CUR.func_move = (TMove_Function)Direct_Move_X;
      else
      {
        if ( CUR.GS.freeVector.y == 0x4000 )
          CUR.func_move = (TMove_Function)Direct_Move_Y;
      }
    }

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

    if ( ABS( CUR.F_dot_P ) < 0x4000000L )
      CUR.F_dot_P = 0x40000000L;

    /* Disable cached aspect ratio */
    CUR.metrics.ratio = 0;
  }

Project: ghostscript
File: ttinterp.c

  static Bool  Compute_Point_Displacement( EXEC_OPS
                                           PCoordinates  x,
                                           PCoordinates  y,
                                           PGlyph_Zone   zone,
                                           Int*          refp )
  {
    TGlyph_Zone  zp;
    Int          p;
    TT_F26Dot6   d;

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

    if ( BOUNDS( p, zp.n_points ) )
    {
      /* Don't set error code, just return. */
      /* Ported from Freetype2 */
      *refp = 0;
      return FAILURE;
    }

    *zone = zp;
    *refp = p;

    d = CUR_Func_project( zp.cur_x[p] - zp.org_x[p],
                          zp.cur_y[p] - zp.org_y[p] );

    *x = MulDiv_Round(d, (Long)CUR.GS.freeVector.x * 0x10000L, CUR.F_dot_P );
    *y = MulDiv_Round(d, (Long)CUR.GS.freeVector.y * 0x10000L, CUR.F_dot_P );

    return SUCCESS;
  }

Project: ghostscript
File: ttinterp.c

  static void  Compute_Round( EXEC_OPS Byte  round_mode )
  {
    switch ( round_mode )
    {
    case TT_Round_Off:
      CUR.func_round = (TRound_Function)Round_None;
      break;

    case TT_Round_To_Grid:
      CUR.func_round = (TRound_Function)Round_To_Grid;
      break;

    case TT_Round_Up_To_Grid:
      CUR.func_round = (TRound_Function)Round_Up_To_Grid;
      break;

    case TT_Round_Down_To_Grid:
      CUR.func_round = (TRound_Function)Round_Down_To_Grid;
      break;

    case TT_Round_To_Half_Grid:
      CUR.func_round = (TRound_Function)Round_To_Half_Grid;
      break;

    case TT_Round_To_Double_Grid:
      CUR.func_round = (TRound_Function)Round_To_Double_Grid;
      break;

    case TT_Round_Super:
      CUR.func_round = (TRound_Function)Round_Super;
      break;

    case TT_Round_Super_45:
      CUR.func_round = (TRound_Function)Round_Super_45;
      break;
    }
  }

Project: ghostscript
File: ttinterp.c

  static Long  Current_Ratio( EXEC_OP )
  {
    if ( CUR.metrics.ratio )
      return CUR.metrics.ratio;

    if ( CUR.GS.projVector.y == 0 )
      CUR.metrics.ratio = CUR.metrics.x_ratio;

    else if ( CUR.GS.projVector.x == 0 )
      CUR.metrics.ratio = CUR.metrics.y_ratio;

    else
    {
      Long  x, y;

      x = MulDiv_Round( CUR.GS.projVector.x, CUR.metrics.x_ratio, 0x4000 );
      y = MulDiv_Round( CUR.GS.projVector.y, CUR.metrics.y_ratio, 0x4000 );
      CUR.metrics.ratio = Norm( x, y );
    }

    return CUR.metrics.ratio;
  }

Project: ghostscript
File: ttinterp.c

  static void  Direct_Move( EXEC_OPS PGlyph_Zone zone,
                                     Int         point,
                                     TT_F26Dot6  distance )
  {
    TT_F26Dot6 v;

    v = CUR.GS.freeVector.x;

    if ( v != 0 )
    {
      zone->cur_x[point] += MulDiv_Round( distance,
                                          v * 0x10000L,
                                          CUR.F_dot_P );

      zone->touch[point] |= TT_Flag_Touched_X;
    }

    v = CUR.GS.freeVector.y;

    if ( v != 0 )
    {
      zone->cur_y[point] += MulDiv_Round( distance,
                                          v * 0x10000L,
                                          CUR.F_dot_P );

      zone->touch[point] |= TT_Flag_Touched_Y;
    }
  }

Project: ghostscript
File: ttinterp.c

  static void  Direct_Move_X( EXEC_OPS PGlyph_Zone  zone,
                                       Int         point,
                                       TT_F26Dot6  distance )
  { (void)exc;
    zone->cur_x[point] += distance;
    zone->touch[point] |= TT_Flag_Touched_X;
  }

Project: ghostscript
File: ttinterp.c

  static void  Direct_Move_Y( EXEC_OPS PGlyph_Zone  zone,
                                       Int         point,
                                       TT_F26Dot6  distance )
  { (void)exc;
    zone->cur_y[point] += distance;
    zone->touch[point] |= TT_Flag_Touched_Y;
  }

Project: ghostscript
File: ttinterp.c

  static TT_F26Dot6  Dual_Project( EXEC_OPS TT_F26Dot6  Vx, TT_F26Dot6  Vy )
  {
    THROW_PATENTED;
    return 0;
  }

Project: ghostscript
File: ttinterp.c

  static TT_F26Dot6  FUnits_To_Pixels( EXEC_OPS  Int  distance )
  {
    return MulDiv_Round( distance,
                         CUR.metrics.scale1,
                         CUR.metrics.scale2 );
  }

Project: ghostscript
File: ttinterp.c

  static TT_F26Dot6  Free_Project( EXEC_OPS TT_F26Dot6  Vx, TT_F26Dot6  Vy )
  {
    THROW_PATENTED;
    return 0;
  }

Project: ghostscript
File: ttinterp.c

  static Short  GetShortIns( EXEC_OP )
  {
    /* Reading a byte stream so there is no endianess (DaveP) */
    CUR.IP += 2;
    return ( CUR.code[CUR.IP-2] << 8) +
             CUR.code[CUR.IP-1];
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_AA( INS_ARG )
  { (void)exc; (void)args;
    /* Intentional - no longer supported */
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_ABS( INS_ARG )
  { (void)exc;
    args[0] = ABS( args[0] );
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_ADD( INS_ARG )
  { (void)exc;
    args[0] += args[1];
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_ALIGNPTS( INS_ARG )
  {
    Int         p1, p2;
    TT_F26Dot6  distance;

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

    if ( BOUNDS( args[0], CUR.zp1.n_points ) ||
         BOUNDS( args[1], CUR.zp0.n_points ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    distance = CUR_Func_project( CUR.zp0.cur_x[p2] -
                                   CUR.zp1.cur_x[p1],
                                 CUR.zp0.cur_y[p2] -
                                   CUR.zp1.cur_y[p1] ) / 2;

    CUR_Func_move( &CUR.zp1, p1, distance );

    CUR_Func_move( &CUR.zp0, p2, -distance );
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_ALIGNRP( INS_ARG )
  {
    Int         point;
    TT_F26Dot6  distance;
    (void)args;

    if ( CUR.top < CUR.GS.loop )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

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

      point = (Int)CUR.stack[CUR.args];

      if ( BOUNDS( point, CUR.zp1.n_points ) )
      {
        CUR.error = TT_Err_Invalid_Reference;
        return;
      }

      distance = CUR_Func_project( CUR.zp1.cur_x[point] -
                                     CUR.zp0.cur_x[CUR.GS.rp0],
                                   CUR.zp1.cur_y[point] -
                                     CUR.zp0.cur_y[CUR.GS.rp0] );

      CUR_Func_move( &CUR.zp1, point, -distance );
      CUR.GS.loop--;
    }

    CUR.GS.loop = 1;
    CUR.new_top = CUR.args;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_AND( INS_ARG )
  { (void)exc;
    if ( args[0] != 0 && args[1] != 0 )
      args[0] = 1;
    else
      args[0] = 0;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_CALL( INS_ARG )
  {
    PCallRecord  pCrec;

    if ( BOUNDS( args[0], CUR.numFDefs ) || !CUR.FDefs[args[0]].Active )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    if ( CUR.callTop >= CUR.callSize )
    {
      CUR.error = TT_Err_Stack_Overflow;
      return;
    }

    DBG_PRINT1("%d", args[0]);

    pCrec = &CUR.callStack[CUR.callTop];

    pCrec->Caller_Range = CUR.curRange;
    pCrec->Caller_IP    = CUR.IP + 1;
    pCrec->Cur_Count    = 1;
    pCrec->Cur_Restart  = CUR.FDefs[args[0]].Start;

    CUR.callTop++;

    INS_Goto_CodeRange( CUR.FDefs[args[0]].Range,
                        CUR.FDefs[args[0]].Start );

    CUR.step_ins = FALSE;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_CEILING( INS_ARG )
  { (void)exc;
    args[0] = (args[0] + 63) & (-64);
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_CINDEX( INS_ARG )
  {
    Long  L;

    L = args[0];

    if ( L<0 || L > CUR.args )
      CUR.error = TT_Err_Invalid_Reference;
    else
      args[0] = CUR.stack[CUR.args - L];
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_CLEAR( INS_ARG )
  { (void)args;
    CUR.new_top = 0;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_DEBUG( INS_ARG )
  { (void)args;
    CUR.error = TT_Err_Debug_OpCode;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_DELTAC( INS_ARG )
  {
    Long  nump, k;
    Long  A, B, C;

    nump = args[0];

    for ( k = 1; k <= nump; k++ )
    {
      if ( CUR.args < 2 )
      {
        CUR.error = TT_Err_Too_Few_Arguments;
        return;
      }

      CUR.args -= 2;

      A = CUR.stack[CUR.args + 1];
      B = CUR.stack[CUR.args];

      if ( A >= CUR.cvtSize )
      {
        CUR.error = TT_Err_Invalid_Reference;
        return;
      }

      C = ((unsigned long)(B & 0xF0)) >> 4;

      switch ( CUR.opcode )
      {
      case 0x73:
        break;

      case 0x74:
        C += 16;
        break;

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

      C += CUR.GS.delta_base;

      if ( CURRENT_Ppem() == C )
      {
        B = (B & 0xF) - 8;
        if ( B >= 0 )
          B++;
        B = B * 64 / (1L << CUR.GS.delta_shift);

        CUR_Func_move_cvt( A, B );
      }
    }

    CUR.new_top = CUR.args;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_DELTAP( INS_ARG )
  {
    Int   k;
    Long  A, B, C, nump;

    nump = args[0];

    for ( k = 1; k <= nump; k++ )
    {
      if ( CUR.args < 2 )
      {
        CUR.error = TT_Err_Too_Few_Arguments;
        return;
      }

      CUR.args -= 2;

      A = CUR.stack[CUR.args + 1];
      B = CUR.stack[CUR.args];

#if 0
      if ( BOUNDS( A, CUR.zp0.n_points ) )
#else
      /* igorm changed : allow phantom points (Altona.Page_3.2002-09-27.pdf). */
      if ( BOUNDS( A, CUR.zp0.n_points + 2 ) )
#endif
      {
/*        CUR.error = TT_Err_Invalid_Reference;*/
        return;
      }

      C = (B & 0xF0) >> 4;

      switch ( CUR.opcode )
      {
      case 0x5d:
        break;

      case 0x71:
        C += 16;
        break;

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

      C += CUR.GS.delta_base;

      if ( CURRENT_Ppem() == C )
      {
        B = (B & 0xF) - 8;
        if ( B >= 0 )
          B++;
        B = B * 64 / (1L << CUR.GS.delta_shift);

        CUR_Func_move( &CUR.zp0, (Int)A, (Int)B );
      }
    }

    CUR.new_top = CUR.args;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_DEPTH( INS_ARG )
  {
    args[0] = CUR.top;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_DIV( INS_ARG )
  {
    if ( args[1] == 0 )
    {
      CUR.error = TT_Err_Divide_By_Zero;
      return;
    }

    args[0] = MulDiv_Round( args[0], 64L, args[1] );
    DBG_PRINT1(" %d", args[0]);
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_DUP( INS_ARG )
  { (void)exc;
    args[1] = args[0];
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_EIF( INS_ARG )
  { (void)exc; (void)args;
    /* nothing to do */
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_ELSE( INS_ARG )
  {
    Int  nIfs;
    (void)args;

    nIfs = 1;

    do
    {
      if ( SKIP_Code() == FAILURE )
        return;

      switch ( CUR.opcode )
      {
      case 0x58:    /* IF */
        nIfs++;
        break;

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

Project: ghostscript
File: ttinterp.c

  static void  Ins_ENDF( INS_ARG )
  {
    PCallRecord  pRec;
     (void)args;

    if ( CUR.callTop <= 0 )     /* We encountered an ENDF without a call */
    {
      CUR.error = TT_Err_ENDF_In_Exec_Stream;
      return;
    }

    CUR.callTop--;

    pRec = &CUR.callStack[CUR.callTop];

    pRec->Cur_Count--;

    CUR.step_ins = FALSE;

    if ( pRec->Cur_Count > 0 )
    {
      CUR.callTop++;
      CUR.IP = pRec->Cur_Restart;
    }
    else
      /* Loop through the current function */
      INS_Goto_CodeRange( pRec->Caller_Range,
                          pRec->Caller_IP );

    /* Exit the current call frame.                       */

    /* NOTE: When the last intruction 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's why we do not test */
    /*       the result of Ins_Goto_CodeRange() here!     */
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_EQ( INS_ARG )
  { (void)exc;
    if ( args[0] == args[1] )
      args[0] = 1;
    else
      args[0] = 0;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_EVEN( INS_ARG )
  {
    if ( (CUR_Func_round( args[0], 0L ) & 127) == 0 )
      args[0] = 1;
    else
      args[0] = 0;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_FDEF( INS_ARG )
  {
    PDefRecord  pRec;

    if ( BOUNDS( args[0], CUR.numFDefs ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    pRec = &CUR.FDefs[args[0]];

    pRec->Range  = CUR.curRange;
    pRec->Opc    = (Byte)(args[0]);
    pRec->Start  = CUR.IP + 1;
    pRec->Active = TRUE;

    skip_FDEF(EXEC_ARG);
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_FLIPOFF( INS_ARG )
  { (void)args;
    CUR.GS.auto_flip = FALSE;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_FLIPON( INS_ARG )
  { (void)args;
    CUR.GS.auto_flip = TRUE;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_FLIPRGON( INS_ARG )
  {
    Long  I, K, L;

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

    if ( BOUNDS( K, CUR.pts.n_points ) ||
         BOUNDS( L, CUR.pts.n_points ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    for ( I = L; I <= K; I++ )
      CUR.pts.touch[I] |= TT_Flag_On_Curve;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_FLOOR( INS_ARG )
  { (void)exc;
    args[0] &= -64;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_GC( INS_ARG )
  {
    Long  L;

    L = args[0];

    if ( BOUNDS( L, CUR.zp2.n_points ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    switch ( CUR.opcode & 1 )
    {
    case 0:
      L = CUR_Func_project( CUR.zp2.cur_x[L],
                            CUR.zp2.cur_y[L] );
      break;

    case 1:
      L = CUR_Func_dualproj( CUR.zp2.org_x[L],
                             CUR.zp2.org_y[L] );
      break;
    }

    args[0] = L;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_GFV( INS_ARG )
  {
    args[0] = CUR.GS.freeVector.x;
    args[1] = CUR.GS.freeVector.y;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_GPV( INS_ARG )
  {
    args[0] = CUR.GS.projVector.x;
    args[1] = CUR.GS.projVector.y;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_GT( INS_ARG )
  { (void)exc;
    if ( args[0] > args[1] )
      args[0] = 1;
    else
      args[0] = 0;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_GTEQ( INS_ARG )
  { (void)exc;
    if ( args[0] >= args[1] )
      args[0] = 1;
    else
      args[0] = 0;
  }

Project: ghostscript
File: ttinterp.c

  static Bool  Ins_Goto_CodeRange( EXEC_OPS Int  aRange, Int  aIP )
  {
    TCodeRange*  WITH;

    if ( aRange < 1 || aRange > 3 )
    {
      CUR.error = TT_Err_Bad_Argument;
      return FAILURE;
    }

    WITH = &CUR.codeRangeTable[aRange - 1];

    if ( WITH->Base == NULL )     /* invalid coderange */
    {
      CUR.error = TT_Err_Invalid_CodeRange;
      return FAILURE;
    }

    /* NOTE: Because the last instruction of a program may be a CALL */
    /*       which will return to the first byte *after* the code    */
    /*       range, we test for AIP <= Size, instead of AIP < Size.  */

    if ( aIP > WITH->Size )
    {
      CUR.error = TT_Err_Code_Overflow;
      return FAILURE;
    }

    CUR.code     = WITH->Base;
    CUR.codeSize = WITH->Size;
    CUR.IP       = aIP;
    CUR.curRange = aRange;

    return SUCCESS;
  }

Project: ghostscript
File: ttinterp.c

  static void Ins_IDEF( INS_ARG )
  {
    if (CUR.countIDefs >= CUR.numIDefs || args[0] > 255)
        CUR.error = TT_Err_Storage_Overflow;
    else
      {
        PDefRecord  pTDR;

        CUR.IDefPtr[(Byte)(args[0])] = CUR.countIDefs;
        pTDR = &CUR.IDefs[CUR.countIDefs++];
        pTDR->Opc    = (Byte)(args[0]);
        pTDR->Start  = CUR.IP + 1;
        pTDR->Range  = CUR.curRange;
        pTDR->Active = TRUE;
        skip_FDEF(EXEC_ARG);
      }
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_IF( INS_ARG )
  {
    Int   nIfs;
    Bool  Out;

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

    nIfs = 1;
    Out = 0;

    do
    {
      if ( SKIP_Code() == FAILURE )
        return;

      switch ( CUR.opcode )
      {
      case 0x58:      /* IF */
        nIfs++;
        break;

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

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

Project: ghostscript
File: ttinterp.c

  static void  Ins_INSTCTRL( INS_ARG )
  {
    Long  K, L;

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

    if ( K < 0 || K > 3 )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    CUR.GS.instruct_control = (Int)((CUR.GS.instruct_control & (~K)) | (L & K));
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_IP( INS_ARG )
  {
    TT_F26Dot6  org_a, org_b, org_x,
                cur_a, cur_b, cur_x,
                distance;
    Int         point;
    (void)args;

    if ( CUR.top < CUR.GS.loop ||
         BOUNDS(CUR.GS.rp1, CUR.zp0.n_points) ||
         BOUNDS(CUR.GS.rp2, CUR.zp1.n_points))
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    org_a = CUR_Func_dualproj( CUR.zp0.org_x[CUR.GS.rp1],
                               CUR.zp0.org_y[CUR.GS.rp1] );

    org_b = CUR_Func_dualproj( CUR.zp1.org_x[CUR.GS.rp2],
                               CUR.zp1.org_y[CUR.GS.rp2] );

    cur_a = CUR_Func_project( CUR.zp0.cur_x[CUR.GS.rp1],
                              CUR.zp0.cur_y[CUR.GS.rp1] );

    cur_b = CUR_Func_project( CUR.zp1.cur_x[CUR.GS.rp2],
                              CUR.zp1.cur_y[CUR.GS.rp2] );

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

      point = (Int)CUR.stack[CUR.args];
      if ( BOUNDS( point, CUR.zp2.n_points ) )
      {
        CUR.error = TT_Err_Invalid_Reference;
        return;
      }

      org_x = CUR_Func_dualproj( CUR.zp2.org_x[point],
                                 CUR.zp2.org_y[point] );

      cur_x = CUR_Func_project( CUR.zp2.cur_x[point],
                                CUR.zp2.cur_y[point] );

      if ( ( org_a <= org_b && org_x <= org_a ) ||
           ( org_a >  org_b && org_x >= org_a ) )

        distance = ( cur_a - org_a ) + ( org_x - cur_x );

      else if ( ( org_a <= org_b  &&  org_x >= org_b ) ||
                ( org_a >  org_b  &&  org_x <  org_b ) )

        distance = ( cur_b - org_b ) + ( org_x - cur_x );

      else
         /* note: it seems that rounding this value isn't a good */
         /*       idea (cf. width of capital 'S' in Times)       */

         distance = MulDiv_Round( cur_b - cur_a,
                                  org_x - org_a,
                                  org_b - org_a ) + ( cur_a - cur_x );

      CUR_Func_move( &CUR.zp2, point, distance );

      CUR.GS.loop--;
    }

    CUR.GS.loop = 1;
    CUR.new_top = CUR.args;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_ISECT( INS_ARG )
  {
    Long  point,           /* are these Ints or Longs? */
          a0, a1,
          b0, b1;

    TT_F26Dot6  discriminant;

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

    TT_F26Dot6  val;

    TT_Vector   R;

    point = args[0];

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

    if ( BOUNDS( b0, CUR.zp0.n_points ) ||
         BOUNDS( b1, CUR.zp0.n_points ) ||
         BOUNDS( a0, CUR.zp1.n_points ) ||
         BOUNDS( a1, CUR.zp1.n_points ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    dbx = CUR.zp0.cur_x[b1] - CUR.zp0.cur_x[b0];
    dby = CUR.zp0.cur_y[b1] - CUR.zp0.cur_y[b0];

    dax = CUR.zp1.cur_x[a1] - CUR.zp1.cur_x[a0];
    day = CUR.zp1.cur_y[a1] - CUR.zp1.cur_y[a0];

    dx = CUR.zp0.cur_x[b0] - CUR.zp1.cur_x[a0];
    dy = CUR.zp0.cur_y[b0] - CUR.zp1.cur_y[a0];

    CUR.zp2.touch[point] |= TT_Flag_Touched_Both;

    discriminant = MulDiv_Round( dax, -dby, 0x40L ) +
                   MulDiv_Round( day, dbx, 0x40L );

    if ( ABS( discriminant ) >= 0x40 )
    {
      val = MulDiv_Round( dx, -dby, 0x40L ) + MulDiv_Round( dy, dbx, 0x40L );

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

      CUR.zp2.cur_x[point] = CUR.zp1.cur_x[a0] + R.x;
      CUR.zp2.cur_y[point] = CUR.zp1.cur_y[a0] + R.y;
    }
    else
    {
      /* else, take the middle of the middles of A and B */

      CUR.zp2.cur_x[point] = ( CUR.zp1.cur_x[a0] +
                               CUR.zp1.cur_x[a1] +
                               CUR.zp0.cur_x[b0] +
                               CUR.zp1.cur_x[b1] ) / 4;
      CUR.zp2.cur_y[point] = ( CUR.zp1.cur_y[a0] +
                               CUR.zp1.cur_y[a1] +
                               CUR.zp0.cur_y[b0] +
                               CUR.zp1.cur_y[b1] ) / 4;
    }
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_IUP( INS_ARG )
  {
    struct LOC_Ins_IUP  V;
    unsigned char       mask;

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

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

    Long point;         /* current point   */
    Long contour;       /* current contour */
    (void)args;

    if ( CUR.opcode & 1 )
    {
      mask   = TT_Flag_Touched_X;
      V.orgs = CUR.pts.org_x;
      V.curs = CUR.pts.cur_x;
    }
    else
    {
      mask   = TT_Flag_Touched_Y;
      V.orgs = CUR.pts.org_y;
      V.curs = CUR.pts.cur_y;
    }

    contour = 0;
    point   = 0;

    do
    {
      end_point   = CUR.pts.contours[contour];
      first_point = point;

      while ( point <= end_point && (CUR.pts.touch[point] & mask) == 0 )
        point++;

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

        point++;

        while ( point <= end_point )
        {
          if ( (CUR.pts.touch[point] & mask) != 0 )
          {
            Interp( (Int)(cur_touched + 1),
                    (Int)(point - 1),
                    (Int)cur_touched,
                    (Int)point,
                    &V );
            cur_touched = point;
          }

          point++;
        }

        if ( cur_touched == first_touched )
          Shift( (Int)first_point, (Int)end_point, (Int)cur_touched, &V );
        else
        {
          Interp((Int)(cur_touched + 1),
                 (Int)(end_point),
                 (Int)(cur_touched),
                 (Int)(first_touched),
                 &V );

          Interp((Int)(first_point),
                 (Int)(first_touched - 1),
                 (Int)(cur_touched),
                 (Int)(first_touched),
                 &V );
        }
      }
      contour++;
    } while ( contour < CUR.pts.n_contours );
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_JROT( INS_ARG )
  {
    if ( args[1] != 0 )
    {
      CUR.IP      += (Int)(args[0]);
      CUR.step_ins = FALSE;

      /* See JMPR below */
      if(CUR.IP > CUR.codeSize ||
         (CUR.code[CUR.IP] != 0x2D && CUR.code[CUR.IP - 1] == 0x2D))
        CUR.IP -= 1;
    }
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_LOOPCALL( INS_ARG )
  {
    PCallRecord  pTCR;

    if ( BOUNDS( args[1], CUR.numFDefs ) || !CUR.FDefs[args[1]].Active )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    if ( CUR.callTop >= CUR.callSize )
    {
      CUR.error = TT_Err_Stack_Overflow;
      return;
    }

    if ( args[0] > 0 )
    {
      pTCR = &CUR.callStack[CUR.callTop];

      pTCR->Caller_Range = CUR.curRange;
      pTCR->Caller_IP    = CUR.IP + 1;
      pTCR->Cur_Count    = (Int)(args[0]);
      pTCR->Cur_Restart  = CUR.FDefs[args[1]].Start;

      CUR.callTop++;

      INS_Goto_CodeRange( CUR.FDefs[args[1]].Range,
                          CUR.FDefs[args[1]].Start );

      CUR.step_ins = FALSE;
    }
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_LT( INS_ARG )
  { (void)exc;
    if ( args[0] < args[1] )
      args[0] = 1;
    else
      args[0] = 0;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_LTEQ( INS_ARG )
  { (void)exc;
    if ( args[0] <= args[1] )
      args[0] = 1;
    else
      args[0] = 0;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_MAX( INS_ARG )
  { (void)exc;
    if ( args[1] > args[0] )
      args[0] = args[1];
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_MD( INS_ARG )
  {
    Long       K, L;
    TT_F26Dot6 D;

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

    if( BOUNDS( args[0], CUR.zp2.n_points ) ||
        BOUNDS( args[1], CUR.zp1.n_points ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    if ( CUR.opcode & 1 )
      D = CUR_Func_project( CUR.zp2.cur_x[L] - CUR.zp1.cur_x[K],
                            CUR.zp2.cur_y[L] - CUR.zp1.cur_y[K] );
    else
      D = CUR_Func_dualproj( CUR.zp2.org_x[L] - CUR.zp1.org_x[K],
                             CUR.zp2.org_y[L] - CUR.zp1.org_y[K] );

    args[0] = D;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_MDRP( INS_ARG )
  {
    Int         point;
    TT_F26Dot6  distance,
                org_dist;

    point = (Int)args[0];

    if ( BOUNDS( args[0], CUR.zp1.n_points ) ||
         BOUNDS( CUR.GS.rp0, CUR.zp0.n_points) )
    {
        /* Current version of FreeType silently ignores this out of bounds error
         * and drops the instruction, see bug #691121
      CUR.error = TT_Err_Invalid_Reference; */
      return;
    }

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

    org_dist = CUR_Func_dualproj( CUR.zp1.org_x[point] -
                                    CUR.zp0.org_x[CUR.GS.rp0],
                                  CUR.zp1.org_y[point] -
                                    CUR.zp0.org_y[CUR.GS.rp0] );

    /* single width cutin test */

    if ( ABS(org_dist) < CUR.GS.single_width_cutin )
    {
      if ( org_dist >= 0 )
        org_dist = CUR.GS.single_width_value;
      else
        org_dist = -CUR.GS.single_width_value;
    }

    /* round flag */

    if ( (CUR.opcode & 4) != 0 )
      distance = CUR_Func_round( org_dist,
                                 CUR.metrics.compensations[CUR.opcode & 3] );
    else
      distance = Round_None( EXEC_ARGS
                             org_dist,
                             CUR.metrics.compensations[CUR.opcode & 3]  );

    /* minimum distance flag */

    if ( (CUR.opcode & 8) != 0 )
    {
      if ( org_dist >= 0 )
      {
        if ( distance < CUR.GS.minimum_distance )
          distance = CUR.GS.minimum_distance;
      }
      else
      {
        if ( distance > -CUR.GS.minimum_distance )
          distance = -CUR.GS.minimum_distance;
      }
    }

    /* now move the point */

    org_dist = CUR_Func_project( CUR.zp1.cur_x[point] -
                                   CUR.zp0.cur_x[CUR.GS.rp0],
                                 CUR.zp1.cur_y[point] -
                                   CUR.zp0.cur_y[CUR.GS.rp0] );

    CUR_Func_move( &CUR.zp1, point, distance - org_dist );

    CUR.GS.rp1 = CUR.GS.rp0;
    CUR.GS.rp2 = point;

    if ( (CUR.opcode & 16) != 0 )
      CUR.GS.rp0 = point;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_MIAP( INS_ARG )
  {
    Int         cvtEntry, point;
    TT_F26Dot6  distance,
                org_dist;

    cvtEntry = (Int)args[1];
    point    = (Int)args[0];

    if ( BOUNDS( args[0], CUR.zp0.n_points ) ||
         BOUNDS( args[1], CUR.cvtSize )      )
    {
        /* Ignore these errors, abort the instruction
         * and continue. This restores the FreeType
         * behaviour when pedantic_hinting is false. For bug
         * #689471, see also Ins_SHC above and bug #688501.
         */
      return;
    }

    /* Undocumented:                                     */
    /*                                                   */
    /* The behaviour of an MIAP instruction is quite     */
    /* different when used in the twilight zone.         */
    /*                                                   */
    /* First, no control value cutin 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 "illegal" according to the     */
    /* specs :)                                          */
    /*                                                   */
    /* We implement it with a special sequence for the   */
    /* twilight zone. This is a bad hack, but it seems   */
    /* to work.                                          */

    distance = CUR_Func_read_cvt( cvtEntry );

    DBG_PRINT3(" cvtEntry=%d point=%d distance=%d", cvtEntry, point, distance);

    if ( CUR.GS.gep0 == 0 )   /* If in twilight zone */
    {
      CUR.zp0.org_x[point] = MulDiv_Round( CUR.GS.freeVector.x,
                                           distance, 0x4000L );
      CUR.zp0.cur_x[point] = CUR.zp0.org_x[point];

      CUR.zp0.org_y[point] = MulDiv_Round( CUR.GS.freeVector.y,
                                           distance, 0x4000L );
      CUR.zp0.cur_y[point] = CUR.zp0.org_y[point];
    }

    org_dist = CUR_Func_project( CUR.zp0.cur_x[point],
                                 CUR.zp0.cur_y[point] );

    if ( (CUR.opcode & 1) != 0 )   /* rounding and control cutin flag */
    {
      if ( ABS(distance - org_dist) > CUR.GS.control_value_cutin )
        distance = org_dist;

      distance = CUR_Func_round( distance, CUR.metrics.compensations[0] );
    }

    CUR_Func_move( &CUR.zp0, point, distance - org_dist );

    CUR.GS.rp0 = point;
    CUR.GS.rp1 = point;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_MIN( INS_ARG )
  { (void)exc;
    if ( args[1] < args[0] )
      args[0] = args[1];
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_MINDEX( INS_ARG )
  {
    Long  L, K;

    L = args[0];

    if (L == 0)
        return;

    if ( L<0 || L > CUR.args )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    K = CUR.stack[CUR.args - L];

    memmove( (&CUR.stack[CUR.args - L    ]),
              (&CUR.stack[CUR.args - L + 1]),
              (L - 1) * sizeof ( Long ) );

    CUR.stack[ CUR.args-1 ] = K;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_MIRP( INS_ARG )
  {
    Int         point,
                cvtEntry;

    TT_F26Dot6  cvt_dist,
                distance,
                cur_dist,
                org_dist;

    point    = (Int)args[0];
    cvtEntry = (Int)args[1];

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

    if ( BOUNDS( args[0],   CUR.zp1.n_points ) ||
         BOUNDS( args[1]+1, CUR.cvtSize+1 )    ||
         BOUNDS(CUR.GS.rp0,  CUR.zp0.n_points) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    if ( args[1] < 0 )
      cvt_dist = 0;
    else
      cvt_dist = CUR_Func_read_cvt( cvtEntry );

    /* single width test */

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

    /* XXX : Undocumented - twilight zone */

    if ( CUR.GS.gep1 == 0 )
    {
      CUR.zp1.org_x[point] = CUR.zp0.org_x[CUR.GS.rp0] +
                             MulDiv_Round( cvt_dist,
                                           CUR.GS.freeVector.x,
                                           0x4000 );

      CUR.zp1.org_y[point] = CUR.zp0.org_y[CUR.GS.rp0] +
                             MulDiv_Round( cvt_dist,
                                           CUR.GS.freeVector.y,
                                           0x4000 );

      CUR.zp1.cur_x[point] = CUR.zp1.org_x[point];
      CUR.zp1.cur_y[point] = CUR.zp1.org_y[point];
    }

    org_dist = CUR_Func_dualproj( CUR.zp1.org_x[point] -
                                    CUR.zp0.org_x[CUR.GS.rp0],
                                  CUR.zp1.org_y[point] -
                                    CUR.zp0.org_y[CUR.GS.rp0] );

    cur_dist = CUR_Func_project( CUR.zp1.cur_x[point] -
                                   CUR.zp0.cur_x[CUR.GS.rp0],
                                 CUR.zp1.cur_y[point] -
                                   CUR.zp0.cur_y[CUR.GS.rp0] );

    /* auto-flip test */

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

    /* control value cutin and round */

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

      if ( CUR.GS.gep0 == CUR.GS.gep1 )
        if ( ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin )
          cvt_dist = org_dist;

      distance = CUR_Func_round( cvt_dist,
                                 CUR.metrics.compensations[CUR.opcode & 3] );
    }
    else
      distance = Round_None( EXEC_ARGS
                             cvt_dist,
                             CUR.metrics.compensations[CUR.opcode & 3] );

    /* minimum distance test */

    if ( (CUR.opcode & 8) != 0 )
    {
      if ( org_dist >= 0 )
      {
        if ( distance < CUR.GS.minimum_distance )
          distance = CUR.GS.minimum_distance;
      }
      else
      {
        if ( distance > -CUR.GS.minimum_distance )
          distance = -CUR.GS.minimum_distance;
      }
    }

    CUR_Func_move( &CUR.zp1, point, distance - cur_dist );

    CUR.GS.rp1 = CUR.GS.rp0;

    if ( (CUR.opcode & 16) != 0 )
      CUR.GS.rp0 = point;

    /* UNDOCUMENTED! */

    CUR.GS.rp2 = point;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_MPPEM( INS_ARG )
  {
    args[0] = CURRENT_Ppem();
    DBG_PRINT1(" %d", args[0]);
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_MPS( INS_ARG )
  {
    args[0] = CUR.metrics.pointSize;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_MSIRP( INS_ARG )
  {
    Int         point;
    TT_F26Dot6  distance;

    point = (Int)args[0];

    if ( BOUNDS( args[0], CUR.zp1.n_points ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    /* XXX: Undocumented behaviour */

    if ( CUR.GS.gep0 == 0 )   /* if in twilight zone */
    {
      CUR.zp1.org_x[point] = CUR.zp0.org_x[CUR.GS.rp0];
      CUR.zp1.org_y[point] = CUR.zp0.org_y[CUR.GS.rp0];
      CUR.zp1.cur_x[point] = CUR.zp1.org_x[point];
      CUR.zp1.cur_y[point] = CUR.zp1.org_y[point];
    }

    distance = CUR_Func_project( CUR.zp1.cur_x[point] -
                                   CUR.zp0.cur_x[CUR.GS.rp0],
                                 CUR.zp1.cur_y[point] -
                                   CUR.zp0.cur_y[CUR.GS.rp0] );

    CUR_Func_move( &CUR.zp1, point, args[1] - distance );

    CUR.GS.rp1 = CUR.GS.rp0;
    CUR.GS.rp2 = point;

    if ( (CUR.opcode & 1) != 0 )
      CUR.GS.rp0 = point;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_NEG( INS_ARG )
  { (void)exc;
    args[0] = -args[0];
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_NEQ( INS_ARG )
  { (void)exc;
    if ( args[0] != args[1] )
      args[0] = 1;
    else
      args[0] = 0;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_NOT( INS_ARG )
  { (void)exc;
    if ( args[0] != 0 )
      args[0] = 0;
    else
      args[0] = 1;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_NPUSHW( INS_ARG )
  {
    Int  L, K;

    L = (Int)CUR.code[CUR.IP + 1];

    if ( BOUNDS( L, CUR.stackSize+1-CUR.top ) )
    {
      CUR.error = TT_Err_Stack_Overflow;
      return;
    }

    CUR.IP += 2;

    for ( K = 0; K < L; K++ )
      { args[K] = GET_ShortIns();
        DBG_PRINT1(" %d", args[K]);
      }

    CUR.step_ins = FALSE;
    CUR.new_top += L;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_ODD( INS_ARG )
  {
    if ( (CUR_Func_round( args[0], 0L ) & 127) == 64 )
      args[0] = 1;
    else
      args[0] = 0;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_OR( INS_ARG )
  { (void)exc;
    if ( args[0] != 0 || args[1] != 0 )
      args[0] = 1;
    else
      args[0] = 0;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_POP( INS_ARG )
  { (void)exc; (void)args;
    /* nothing to do */
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_PUSHB( INS_ARG )
  {
    Int  L, K;

    L = ((Int)CUR.opcode - 0xB0 + 1);

    if ( BOUNDS( L, CUR.stackSize+1-CUR.top ) )
    {
      CUR.error = TT_Err_Stack_Overflow;
      return;
    }

    for ( K = 1; K <= L; K++ )
      { args[K - 1] = CUR.code[CUR.IP + K];
        DBG_PRINT1(" %d", args[K - 1]);
      }
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_PUSHW( INS_ARG )
  {
    Int  L, K;

    L = CUR.opcode - 0xB8 + 1;

    if ( BOUNDS( L, CUR.stackSize+1-CUR.top ) )
    {
      CUR.error = TT_Err_Stack_Overflow;
      return;
    }

    CUR.IP++;

    for ( K = 0; K < L; K++ )
      { args[K] = GET_ShortIns();
        DBG_PRINT1(" %d", args[K]);
      }

    CUR.step_ins = FALSE;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_RCVT( INS_ARG )
  {
    int index;
    if ( BOUNDS( args[0], CUR.cvtSize ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }
    index=args[0];
    args[0] = CUR_Func_read_cvt( index );
    DBG_PRINT3(" cvt[%d]%d:%d", index, CUR.cvt[index], args[0]);
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_RDTG( INS_ARG )
  { (void)args;
    CUR.GS.round_state = TT_Round_Down_To_Grid;

    CUR.func_round = (TRound_Function)Round_Down_To_Grid;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_ROFF( INS_ARG )
  { (void)args;
    CUR.GS.round_state = TT_Round_Off;

    CUR.func_round = (TRound_Function)Round_None;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_ROLL( INS_ARG )
  {
    Long  A, B, C;
    (void)exc;

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

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

Project: ghostscript
File: ttinterp.c

  static void  Ins_ROUND( INS_ARG )
  {
    args[0] = CUR_Func_round( args[0],
                              CUR.metrics.compensations[CUR.opcode - 0x68] );
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_RS( INS_ARG )
  {
    if ( BOUNDS( args[0], CUR.storeSize ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    args[0] = CUR.storage[args[0]];
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_RTDG( INS_ARG )
  { (void)args;
    CUR.GS.round_state = TT_Round_To_Double_Grid;

    CUR.func_round = (TRound_Function)Round_To_Double_Grid;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_RTG( INS_ARG )
  { (void)args;
    CUR.GS.round_state = TT_Round_To_Grid;

    CUR.func_round = (TRound_Function)Round_To_Grid;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_RTHG( INS_ARG )
  { (void)args;
    CUR.GS.round_state = TT_Round_To_Half_Grid;

    CUR.func_round = (TRound_Function)Round_To_Half_Grid;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_RUTG( INS_ARG )
  { (void)args;
    CUR.GS.round_state = TT_Round_Up_To_Grid;

    CUR.func_round = (TRound_Function)Round_Up_To_Grid;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_S45ROUND( INS_ARG )
  {
    SET_SuperRound( 0x2D41L, args[0] );
    CUR.GS.round_state = TT_Round_Super_45;

    CUR.func_round = (TRound_Function)Round_Super_45;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SANGW( INS_ARG )
  { (void)exc; (void)args;
    /* instruction not supported anymore */
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SCANTYPE( INS_ARG )
  {
    /* For compatibility with future enhancements, */
    /* we must ignore new modes                    */

    if ( args[0] >= 0 && args[0] <= 5 )
    {
      if ( args[0] == 3 )
        args[0] = 2;

      CUR.GS.scan_type = (Int)args[0];
    }
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SCFS( INS_ARG )
  {
    Long  K;
    Int   L;

    L = (Int)args[0];

    if ( BOUNDS( args[0], CUR.zp2.n_points ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    K = CUR_Func_project( CUR.zp2.cur_x[L],
                          CUR.zp2.cur_y[L] );

    CUR_Func_move( &CUR.zp2, L, args[1] - K );

    /* not part of the specs, but here for safety */

    if ( CUR.GS.gep2 == 0 )
    {
      CUR.zp2.org_x[L] = CUR.zp2.cur_x[L];
      CUR.zp2.org_y[L] = CUR.zp2.cur_y[L];
    }
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SCVTCI( INS_ARG )
  {
    CUR.GS.control_value_cutin = (TT_F26Dot6)args[0];
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SDB( INS_ARG )
  {
    CUR.GS.delta_base = (Int)args[0];
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SDS( INS_ARG )
  {
    CUR.GS.delta_shift = (Int)args[0];
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SFVFS( INS_ARG )
  {
    Short  S;
    Long   X, Y;

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

    if ( NORMalize( X, Y, &CUR.GS.freeVector ) == FAILURE )
      return;

    COMPUTE_Funcs();
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SFVTL( INS_ARG )
  {
    if ( INS_SxVTL( (Int)(args[1]),
                    (Int)(args[0]),
                    CUR.opcode,
                    &CUR.GS.freeVector) == FAILURE )
      return;

    COMPUTE_Funcs();
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SFVTPV( INS_ARG )
  { (void)args;
    CUR.GS.freeVector = CUR.GS.projVector;
    COMPUTE_Funcs();
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SHC( INS_ARG )
  {
    TGlyph_Zone zp;
    Int         refp;
    TT_F26Dot6  dx,
                dy;

    Long        contour, i;
    Int         first_point, last_point;

    contour = args[0];

    if ( BOUNDS( args[0], CUR.pts.n_contours ) )
    {
#if 0
      /* A workaround for the Ghostscript bug 688501.
       *  Ported from FreeType 2
       */
      CUR.error = TT_Err_Invalid_Reference;
#endif
      return;
    }

    if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
      return;

    if ( contour == 0 )
      first_point = 0;
    else
      first_point = CUR.pts.contours[contour-1] + 1;

    last_point = CUR.pts.contours[contour];

    /* undocumented: SHC doesn't touch the points */
    for ( i = first_point; i <= last_point; i++ )
    {
      if ( zp.cur_x != CUR.zp2.cur_x || refp != i )
        MOVE_Zp2_Point( i, dx, dy, FALSE );
    }
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SHP( INS_ARG )
  {
    TGlyph_Zone zp;
    Int         refp;

    TT_F26Dot6  dx,
                dy;
    Long        point;
    (void)args;

    if ( CUR.top < CUR.GS.loop )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
      return;

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

      if ( BOUNDS( point, CUR.zp2.n_points ) )
      {
        CUR.error = TT_Err_Invalid_Reference;
        return;
      }

      /* undocumented: SHP touches the points */
      MOVE_Zp2_Point( point, dx, dy, TRUE );

      CUR.GS.loop--;
    }

    CUR.GS.loop = 1;
    CUR.new_top = CUR.args;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SHZ( INS_ARG )
  {
    TGlyph_Zone zp;
    Int         refp;
    TT_F26Dot6  dx,
                dy;

    Int  last_point;
    Long i;

    if ( BOUNDS( args[0], 2 ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
      return;

    last_point = zp.n_points - 1;

    /* undocumented: SHZ doesn't touch the points */
    for ( i = 0; i <= last_point; i++ )
    {
      if ( zp.cur_x != CUR.zp2.cur_x || refp != i )
        MOVE_Zp2_Point( i, dx, dy, FALSE );
    }
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SLOOP( INS_ARG )
  {
    CUR.GS.loop = args[0];
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SMD( INS_ARG )
  {
    CUR.GS.minimum_distance = args[0];
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SPVFS( INS_ARG )
  {
    Short  S;
    Long   X, Y;

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

    if ( NORMalize( X, Y, &CUR.GS.projVector ) == FAILURE )
      return;

    CUR.GS.dualVector = CUR.GS.projVector;

    COMPUTE_Funcs();
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SPVTCA( INS_ARG )
  {
    Short  A, B;
    (void)args;
    if ( CUR.opcode & 1 )
      A = 0x4000;
    else
      A = 0;

    B = A ^ 0x4000;

    CUR.GS.projVector.x = A;
    CUR.GS.dualVector.x = A;

    CUR.GS.projVector.y = B;
    CUR.GS.dualVector.y = B;

    COMPUTE_Funcs();
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SPVTL( INS_ARG )
  {
    if ( INS_SxVTL( args[1],
                    args[0],
                    CUR.opcode,
                    &CUR.GS.projVector) == FAILURE )
      return;

    CUR.GS.dualVector = CUR.GS.projVector;
    COMPUTE_Funcs();
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SROUND( INS_ARG )
  {
    SET_SuperRound( 0x4000L, args[0] );
    CUR.GS.round_state = TT_Round_Super;

    CUR.func_round = (TRound_Function)Round_Super;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SRP0( INS_ARG )
  {
    CUR.GS.rp0 = (Int)(args[0]);
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SRP1( INS_ARG )
  {
    CUR.GS.rp1 = (Int)(args[0]);
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SSW( INS_ARG )
  {
    /* XXX : Undocumented or bug in the Windows engine ?  */
    /*                                                    */
    /* It seems that the value that is read here is       */
    /* expressed in 16.16 format, rather than in          */
    /* font units..                                       */
    /*                                                    */
    CUR.GS.single_width_value = (TT_F26Dot6)(args[0] >> 10);
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SSWCI( INS_ARG )
  {
    CUR.GS.single_width_cutin = (TT_F26Dot6)args[0];
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SUB( INS_ARG )
  { (void)exc;
    args[0] -= args[1];
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SVTCA( INS_ARG )
  {
    Short  A, B;
    (void)args;

    if ( CUR.opcode & 1 )
        A = 0x4000;
    else
        A = 0;

    B = A ^ 0x4000;

    CUR.GS.freeVector.x = A;
    CUR.GS.projVector.x = A;
    CUR.GS.dualVector.x = A;

    CUR.GS.freeVector.y = B;
    CUR.GS.projVector.y = B;
    CUR.GS.dualVector.y = B;

    COMPUTE_Funcs();
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SWAP( INS_ARG )
  {
    Long  L;
    (void)exc;

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

Project: ghostscript
File: ttinterp.c

  static void  Ins_SZP0( INS_ARG )
  {
    switch ( args[0] )
    {
    case 0:
      CUR.zp0 = CUR.twilight;
      break;

    case 1:
      CUR.zp0 = CUR.pts;
      break;

    default:
      CUR.error = TT_Err_Invalid_Reference;
      return;
      break;
    }

    CUR.GS.gep0 = (Int)(args[0]);
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SZP1( INS_ARG )
  {
    switch ( args[0] )
    {
    case 0:
      CUR.zp1 = CUR.twilight;
      break;

    case 1:
      CUR.zp1 = CUR.pts;
      break;

    default:
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    CUR.GS.gep1 = (Int)(args[0]);
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SZP2( INS_ARG )
  {
    switch ( args[0] )
    {
    case 0:
      CUR.zp2 = CUR.twilight;
      break;

    case 1:
      CUR.zp2 = CUR.pts;
      break;

    default:
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    CUR.GS.gep2 = (Int)(args[0]);
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_SZPS( INS_ARG )
  {
    switch ( args[0] )
    {
    case 0:
      CUR.zp0 = CUR.twilight;
      break;

    case 1:
      CUR.zp0 = CUR.pts;
      break;

    default:
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    CUR.zp1 = CUR.zp0;
    CUR.zp2 = CUR.zp0;

    CUR.GS.gep0 = (Int)(args[0]);
    CUR.GS.gep1 = (Int)(args[0]);
    CUR.GS.gep2 = (Int)(args[0]);
  }

Project: ghostscript
File: ttinterp.c

  static Bool  Ins_SxVTL( EXEC_OPS  Int             aIdx1,
                                    Int             aIdx2,
                                    Int             aOpc,
                                    TT_UnitVector*  Vec )
  {
    Long  A, B, C;

    if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
         BOUNDS( aIdx2, CUR.zp1.n_points ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return FAILURE;
    }

    A = CUR.zp1.cur_x[aIdx2] - CUR.zp2.cur_x[aIdx1];
    B = CUR.zp1.cur_y[aIdx2] - CUR.zp2.cur_y[aIdx1];

    if ( (aOpc & 1) != 0 )
    {
      C =  B;   /* CounterClockwise rotation */
      B =  A;
      A = -C;
    }

    if ( NORMalize( A, B, Vec ) == FAILURE )
    {
      /* When the vector is too small or zero! */

      CUR.error = TT_Err_Ok;
      Vec->x = 0x4000;
      Vec->y = 0;
    }

    return SUCCESS;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_UNKNOWN( INS_ARG )
  { /* Rewritten by igorm. */
    Byte i;
    TDefRecord*  def;
    PCallRecord  call;

#   if 0     /* The condition below appears always false
                due to limited range of data type
                - skip it to quiet a compiler warning. */
    if (CUR.opcode > sizeof(CUR.IDefPtr) / sizeof(CUR.IDefPtr[0])) {
        CUR.error = TT_Err_Invalid_Opcode;
        return;
    }
#   endif
    i = CUR.IDefPtr[(Byte)CUR.opcode];

    if (i >= CUR.numIDefs)
      {
        CUR.error = TT_Err_Invalid_Opcode;
        return;
      }
    def   = &CUR.IDefs[i];

    if ( CUR.callTop >= CUR.callSize )
    {
      CUR.error = TT_Err_Stack_Overflow;
      return;
    }

    call = CUR.callStack + CUR.callTop++;

    call->Caller_Range = CUR.curRange;
    call->Caller_IP    = CUR.IP+1;
    call->Cur_Count    = 1;
    call->Cur_Restart  = def->Start;

    INS_Goto_CodeRange( def->Range, def->Start );

    CUR.step_ins = FALSE;
    return;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_UTP( INS_ARG )
  {
    Byte  mask;

    if ( BOUNDS( args[0], CUR.zp0.n_points ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    mask = 0xFF;

    if ( CUR.GS.freeVector.x != 0 )
      mask &= ~TT_Flag_Touched_X;

    if ( CUR.GS.freeVector.y != 0 )
      mask &= ~TT_Flag_Touched_Y;

    CUR.zp0.touch[args[0]] &= mask;
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_WCVTP( INS_ARG )
  {
    if ( BOUNDS( args[0], CUR.cvtSize ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    CUR_Func_write_cvt( args[0], args[1] );
  }

Project: ghostscript
File: ttinterp.c

  static void  Ins_WS( INS_ARG )
  {
    if ( BOUNDS( args[0], CUR.storeSize ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    CUR.storage[args[0]] = args[1];
  }

Project: ghostscript
File: ttinterp.c

  static void  Interp( Int  p1, Int  p2,
                       Int  ref1, Int  ref2,
                       struct LOC_Ins_IUP*  LINK )
  {
    Long        i;
    TT_F26Dot6  x, x1, x2, d1, d2;

    if ( p1 > p2 )
      return;

    x1 = LINK->orgs[ref1];
    d1 = LINK->curs[ref1] - LINK->orgs[ref1];
    x2 = LINK->orgs[ref2];
    d2 = LINK->curs[ref2] - LINK->orgs[ref2];

    if ( x1 == x2 )
    {
      for ( i = p1; i <= p2; i++ )
      {
        x = LINK->orgs[i];

        if ( x <= x1 )
          x += d1;
        else
          x += d2;

        LINK->curs[i] = x;
      }
      return;
    }

    if ( x1 < x2 )
    {
      for ( i = p1; i <= p2; i++ )
      {
        x = LINK->orgs[i];

        if ( x <= x1 )
          x += d1;
        else
        {
          if ( x >= x2 )
            x += d2;
          else
            x = LINK->curs[ref1] +
                  MulDiv_Round( x - x1,
                                LINK->curs[ref2] - LINK->curs[ref1],
                                x2 - x1 );
        }
        LINK->curs[i] = x;
      }
      return;
    }

    /* x2 < x1 */

    for ( i = p1; i <= p2; i++ )
    {
      x = LINK->orgs[i];
      if ( x <= x2 )
        x += d2;
      else
      {
        if ( x >= x1 )
          x += d1;
        else
          x = LINK->curs[ref1] +
                MulDiv_Round( x - x1,
                              LINK->curs[ref2] - LINK->curs[ref1],
                              x2 - x1 );
      }
      LINK->curs[i] = x;
    }
  }

Project: ghostscript
File: ttinterp.c

  static void  Move_CVT( EXEC_OPS  Int index, TT_F26Dot6 value )
  {
    int ov=CUR.cvt[index];
    (void)ov; /* Quiet compiler warning in release build. */
    CUR.cvt[index] += value;
    DBG_PRINT3(" cvt[%d]%d:=%d", index, ov, CUR.cvt[index]);
  }

Project: ghostscript
File: ttinterp.c

  static void  Move_CVT_Stretched( EXEC_OPS  Int index, TT_F26Dot6  value )
  {
    int ov=CUR.cvt[index];
    (void)ov; /* Quiet compiler warning in release build. */
    CUR.cvt[index] += MulDiv_Round( value, 0x10000, CURRENT_Ratio() );
    DBG_PRINT3(" cvt[%d]%d:=%d", index, ov, CUR.cvt[index]);
  }

Project: ghostscript
File: ttinterp.c

  static void  Move_Zp2_Point( EXEC_OPS
                               Long        point,
                               TT_F26Dot6  dx,
                               TT_F26Dot6  dy,
                               Bool        touch )
  {
    if ( CUR.GS.freeVector.x != 0 )
    {
      CUR.zp2.cur_x[point] += dx;
      if ( touch )
        CUR.zp2.touch[point] |= TT_Flag_Touched_X;
    }

    if ( CUR.GS.freeVector.y != 0 )
    {
      CUR.zp2.cur_y[point] += dy;
      if ( touch )
        CUR.zp2.touch[point] |= TT_Flag_Touched_Y;
    }
  }

Project: ghostscript
File: ttinterp.c

  static TT_F26Dot6  Norm( TT_F26Dot6  X, TT_F26Dot6  Y )
  {
    Int64       T1, T2;

    MUL_64( X, X, T1 );
    MUL_64( Y, Y, T2 );

    ADD_64( T1, T2, T1 );

    return (TT_F26Dot6)SQRT_64( T1 );
  }

Project: ghostscript
File: ttinterp.c

  static Bool  Normalize( EXEC_OPS TT_F26Dot6      Vx,
                                   TT_F26Dot6      Vy,
                                   TT_UnitVector*  R )
  {
    TT_F26Dot6  W;
    Bool        S1, S2;

    if ( ABS( Vx ) < 0x10000L && ABS( Vy ) < 0x10000L )
    {
      Vx *= 0x100;
      Vy *= 0x100;

      W = Norm( Vx, Vy );

      if ( W == 0 )
      {
        /* XXX : Undocumented. It seems that it's possible to try  */
        /*       to normalize the vector (0,0). Return immediately */
        return SUCCESS;
      }

      R->x = (TT_F2Dot14)MulDiv_Round( Vx, 0x4000L, W );
      R->y = (TT_F2Dot14)MulDiv_Round( Vy, 0x4000L, W );

      return SUCCESS;
    }

    W = Norm( Vx, Vy );

    if ( W <= 0 )
    {
      CUR.error = TT_Err_Divide_By_Zero;
      return FAILURE;
    }

    Vx = MulDiv_Round( Vx, 0x4000L, W );
    Vy = MulDiv_Round( Vy, 0x4000L, W );

    W = Vx * Vx + Vy * Vy;

    /* Now, we want that Sqrt( W ) = 0x4000 */
    /* Or 0x10000000 <= W < 0x10004000      */

    if ( Vx < 0 )
    {
      Vx = -Vx;
      S1 = TRUE;
    }
    else
      S1 = FALSE;

    if ( Vy < 0 )
    {
      Vy = -Vy;
      S2 = TRUE;
    }
    else
      S2 = FALSE;

    while ( W < 0x10000000L )
    {
      /* We need to increase W, by a minimal amount */
      if ( Vx < Vy )
        Vx++;
      else
        Vy++;

      W = Vx * Vx + Vy * Vy;
    }

    while ( W >= 0x10004000L )
    {
      /* We need to decrease W, by a minimal amount */
      if ( Vx < Vy )
        Vx--;
      else
        Vy--;

      W = Vx * Vx + Vy * Vy;
    }

    /* Note that in various cases, we can only  */
    /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */

    if ( S1 )
      Vx = -Vx;

    if ( S2 )
      Vy = -Vy;

    R->x = (TT_F2Dot14)Vx;   /* Type conversion */
    R->y = (TT_F2Dot14)Vy;   /* Type conversion */

    return SUCCESS;
  }

Project: ghostscript
File: ttinterp.c

  static TT_F26Dot6  Project_x( EXEC_OPS TT_F26Dot6  Vx, TT_F26Dot6  Vy )
  { (void)exc; (void)Vy;
    return Vx;
  }

Project: ghostscript
File: ttinterp.c

  static TT_F26Dot6  Project_y( EXEC_OPS TT_F26Dot6  Vx, TT_F26Dot6  Vy )
  { (void)exc; (void)Vx;
    return Vy;
  }

Project: ghostscript
File: ttinterp.c

  static TT_F26Dot6  Read_CVT( EXEC_OPS Int  index )
  {
    return CUR.cvt[index];
  }

Project: ghostscript
File: ttinterp.c

  static TT_F26Dot6  Read_CVT_Stretched( EXEC_OPS Int  index )
  {
    return MulDiv_Round( CUR.cvt[index], CURRENT_Ratio(), 0x10000 );
  }

Project: ghostscript
File: ttinterp.c

  static TT_F26Dot6  Round_Down_To_Grid( EXEC_OPS TT_F26Dot6  distance,
                                                  TT_F26Dot6  compensation )
  {
    TT_F26Dot6  val;
    (void)exc;

    if ( distance >= 0 )
    {
      val = (distance + compensation) & (-64);
      if ( val < 0 )
        val = 0;
    }
    else
    {
      val = -( (compensation - distance) & (-64) );
      if ( val > 0 )
        val = 0;
    }

    return val;
  }

Project: ghostscript
File: ttinterp.c

  static TT_F26Dot6  Round_None( EXEC_OPS TT_F26Dot6  distance,
                                          TT_F26Dot6  compensation )
  {
    TT_F26Dot6  val;
    (void)exc;

    if ( distance >= 0 )
    {
      val = distance + compensation;
      if ( val < 0 )
        val = 0;
    }
    else {
      val = distance - compensation;
      if ( val > 0 )
        val = 0;
    }

    return val;
  }

Project: ghostscript
File: ttinterp.c

  static TT_F26Dot6  Round_Super( EXEC_OPS TT_F26Dot6  distance,
                                           TT_F26Dot6  compensation )
  {
    TT_F26Dot6  val;

    if ( distance >= 0 )
    {
      val = (distance - CUR.phase + CUR.threshold + compensation) &
              (-CUR.period);
      if ( val < 0 )
        val = 0;
      val += CUR.phase;
    }
    else
    {
      val = -( (CUR.threshold - CUR.phase - distance + compensation) &
               (-CUR.period) );
      if ( val > 0 )
        val = 0;
      val -= CUR.phase;
    }

    return val;
  }

Project: ghostscript
File: ttinterp.c

  static TT_F26Dot6  Round_Super_45( EXEC_OPS TT_F26Dot6  distance,
                                              TT_F26Dot6  compensation )
  {
    TT_F26Dot6  val;

    if ( distance >= 0 )
    {
      val = ( (distance - CUR.phase + CUR.threshold + compensation) /
                CUR.period ) * CUR.period;
      if ( val < 0 )
        val = 0;
      val += CUR.phase;
    }
    else
    {
      val = -( ( (CUR.threshold - CUR.phase - distance + compensation) /
                   CUR.period ) * CUR.period );
      if ( val > 0 )
        val = 0;
      val -= CUR.phase;
    }

    return val;
  }

Project: ghostscript
File: ttinterp.c

  static TT_F26Dot6  Round_To_Double_Grid( EXEC_OPS TT_F26Dot6  distance,
                                                    TT_F26Dot6  compensation )
  {
    TT_F26Dot6 val;
    (void)exc;

    if ( distance >= 0 )
    {
      val = (distance + compensation + 16) & (-32);
      if ( val < 0 )
        val = 0;
    }
    else
    {
      val = -( (compensation - distance + 16) & (-32) );
      if ( val > 0 )
        val = 0;
    }

    return val;
  }

Project: ghostscript
File: ttinterp.c

  static TT_F26Dot6  Round_To_Grid( EXEC_OPS TT_F26Dot6  distance,
                                             TT_F26Dot6  compensation )
  {
    TT_F26Dot6  val;
    (void)exc;

    if ( distance >= 0 )
    {
      val = (distance + compensation + 32) & (-64);
      if ( val < 0 )
        val = 0;
    }
    else
    {
      val = -( (compensation - distance + 32) & (-64) );
      if ( val > 0 )
        val = 0;
    }

    return  val;
  }

Project: ghostscript
File: ttinterp.c

  static TT_F26Dot6  Round_To_Half_Grid( EXEC_OPS TT_F26Dot6  distance,
                                                  TT_F26Dot6  compensation )
  {
    TT_F26Dot6  val;
     (void)exc;

    if ( distance >= 0 )
    {
      val = ((distance + compensation) & (-64)) + 32;
      if ( val < 0 )
        val = 0;
    }
    else
    {
      val = -( ((compensation - distance) & (-64)) + 32 );
      if ( val > 0 )
        val = 0;
    }

    return val;
  }

Project: ghostscript
File: ttinterp.c

  static TT_F26Dot6  Round_Up_To_Grid( EXEC_OPS TT_F26Dot6  distance,
                                                TT_F26Dot6  compensation )
  {
    TT_F26Dot6  val;
    (void)exc;

    if ( distance >= 0 )
    {
      val = (distance + compensation + 63) & (-64);
      if ( val < 0 )
        val = 0;
    }
    else
    {
      val = -( (compensation - distance + 63) & (-64) );
      if ( val > 0 )
        val = 0;
    }

    return val;
  }

Project: ghostscript
File: ttinterp.c

  static void  SetSuperRound( EXEC_OPS TT_F26Dot6  GridPeriod,
                                       Long        selector )
  {
    switch ( selector & 0xC0 )
    {
      case 0:
        CUR.period = GridPeriod / 2;
        break;

      case 0x40:
        CUR.period = GridPeriod;
        break;

      case 0x80:
        CUR.period = GridPeriod * 2;
        break;

      /* This opcode is reserved, but... */

      case 0xC0:
        CUR.period = GridPeriod;
        break;
    }

    switch ( selector & 0x30 )
    {
    case 0:
      CUR.phase = 0;
      break;

    case 0x10:
      CUR.phase = CUR.period / 4;
      break;

    case 0x20:
      CUR.phase = CUR.period / 2;
      break;

    case 0x30:
      CUR.phase = GridPeriod * 3 / 4;
      break;
    }

    if ( (selector & 0x0F) == 0 )
      CUR.threshold = CUR.period - 1;
    else
      CUR.threshold = ( (Int)(selector & 0x0F) - 4L ) * CUR.period / 8;

    CUR.period    /= 256;
    CUR.phase     /= 256;
    CUR.threshold /= 256;
  }

Project: ghostscript
File: ttinterp.c

  static void  Shift( Int  p1,
                      Int  p2,
                      Int  p,
                      struct LOC_Ins_IUP*  LINK )
  {
    Int         i;
    TT_F26Dot6  x;

    x = LINK->curs[p] - LINK->orgs[p];

    for ( i = p1; i < p; i++ )
      LINK->curs[i] += x;

    for ( i = p + 1; i <= p2; i++ )
      LINK->curs[i] += x;
  }

Project: ghostscript
File: ttinterp.c

  static Bool  SkipCode( EXEC_OP )
  {
    CUR.IP += CUR.length;

    if ( CUR.IP < CUR.codeSize )
      if ( CALC_Length() == SUCCESS )
        return SUCCESS;

    CUR.error = TT_Err_Code_Overflow;
    return FAILURE;
  }

Project: ghostscript
File: ttinterp.c

  static void  Write_CVT( EXEC_OPS Int  index, TT_F26Dot6  value )
  {
    int ov=CUR.cvt[index];
    (void)ov; /* Quiet compiler warning in release build. */
    CUR.cvt[index] = value;
    DBG_PRINT3(" cvt[%d]%d:=%d", index, ov, CUR.cvt[index]);
}

Project: ghostscript
File: ttinterp.c

  static void skip_FDEF( EXEC_OP )
  {
    /* We don't allow nested IDEFS & FDEFs.    */

    while ( SKIP_Code() == SUCCESS )
    {
      switch ( CUR.opcode )
      {
      case 0x89:    /* IDEF */
      case 0x2c:    /* FDEF */
        CUR.error = TT_Err_Nested_DEFS;
        return;

      case 0x2d:   /* ENDF */
        return;
      }
    }
  }