home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: SysTools / SysTools.zip / ft-beta.zip / freetype / lib / ttinterp.c < prev    next >
C/C++ Source or Header  |  1997-10-06  |  137KB  |  5,248 lines

  1. /*******************************************************************
  2.  *
  3.  *  ttinterp.c                                              2.3
  4.  *
  5.  *  TrueType bytecode intepreter.
  6.  *
  7.  *  Copyright 1996 David Turner, Robert Wilhelm and Werner Lemberg
  8.  *
  9.  *  This file is part of the FreeType project, and may only be used
  10.  *  modified and distributed under the terms of the FreeType project
  11.  *  license, LICENSE.TXT. By continuing to use, modify or distribute
  12.  *  this file you indicate that you have read the license and
  13.  *  understand and accept it fully.
  14.  *
  15.  *
  16.  *  TODO :
  17.  *
  18.  *  - Fix the non-square pixel case (or how to manage the CVT to
  19.  *    detect horizontal and vertical scaled FUnits ?)
  20.  *
  21.  *
  22.  *  Changes between 2.3 and 2.2 :
  23.  *
  24.  *  - added support for rotation, stretching, instruction control
  25.  *
  26.  *  - added support for non-square pixels. However, this doesn't
  27.  *    work perfectly yet..
  28.  *
  29.  *  Changes between 2.2 and 2.1 :
  30.  *
  31.  *  - a small bugfix in the Push opcodes
  32.  *
  33.  *  Changes between 2.1 and 2.0 :
  34.  *
  35.  *  - created the TTExec component to take care of all execution
  36.  *    context management. The interpreter has now one single
  37.  *    function.
  38.  *
  39.  *  - made some changes to support re-entrancy. The re-entrant
  40.  *    interpreter is smaller !
  41.  *
  42.  ******************************************************************/
  43.  
  44. #include "freetype.h"
  45. #include "tttypes.h"
  46. #include "tterror.h"
  47. #include "ttcalc.h"
  48. #include "ttmemory.h"
  49. #include "ttinterp.h"
  50.  
  51. #ifdef DEBUG
  52. #include "ttdebug.h"
  53.  
  54. #ifdef HAVE_CONIO_H
  55. #include "conio.h"
  56. #endif
  57.  
  58. #endif /* DEBUG */
  59.  
  60. /* There are two kinds of implementations there :             */
  61. /*                                                            */
  62. /* a. static implementation :                                 */
  63. /*                                                            */
  64. /*    the current execution context is a static variable,     */
  65. /*    which fields are accessed directly by the interpreter   */
  66. /*    during execution. the context is named 'cur'.           */
  67. /*                                                            */
  68. /*    this version is non-reentrant, of course..              */
  69. /*                                                            */
  70. /*                                                            */
  71. /* b. indirect implementation :                               */
  72. /*                                                            */
  73. /*    the current execution context is passed to _each_       */
  74. /*    function as its first argument, and each field is       */
  75. /*    thus accessed indirectly.                               */
  76. /*                                                            */
  77. /*    this version is however fully re-entrant..              */
  78. /*                                                            */
  79. /*                                                            */
  80. /*  The idea is that an indirect implementation may be        */
  81. /*  slower to execute on the low-end processors that are      */
  82. /*  used in some systems (like 386s or even 486s).            */
  83. /*                                                            */
  84. /*  When the interpreter started, we had no idea of the       */
  85. /*  time that glyph hinting (i.e. executing instructions)     */
  86. /*  could take in the whole process of rendering a glyph,     */
  87. /*  and a 10 to 30% performance penalty on low-end systems    */
  88. /*  didn't seem much of a good idea. This question led us     */
  89. /*  to provide two distinct builds of the C version from      */
  90. /*  a single source, with the use of macros (again !)         */
  91. /*                                                            */
  92. /*  Now that the engine is working (and working really        */
  93. /*  well !), it seems that the greatest time-consuming        */
  94. /*  factors are : file i/o, glyph loading, rasterizing and    */
  95. /*  _then_ glyph hinting !                                    */
  96. /*                                                            */
  97. /*  Tests performed with two versions of the 'timer' program  */
  98. /*  seem to indicate that hinting takes less than 5% of the   */
  99. /*  rendering process, which is dominated by glyph loading    */
  100. /*  and scan-line conversion by an high order of magnitude.   */
  101. /*                                                            */
  102. /*  As a consequence, the indirect implementation is now the  */
  103. /*  default, as its performance costs can be considered       */
  104. /*  negligible  in our context.. Note however that we         */
  105. /*  kept  the same source with macros because :               */
  106. /*                                                            */
  107. /*    - the code is kept very close in design to the          */
  108. /*      Pascal one used for development.                      */
  109. /*                                                            */
  110. /*    - it's much more readable that way !                    */
  111. /*                                                            */
  112. /*    - it's still open to later experimentation and tuning   */
  113.  
  114.  
  115. #ifndef TT_STATIC_INTERPRETER      /* indirect implementation */
  116.  
  117.   #define CUR (*exc)   /* see ttobjs.h */
  118.  
  119. #else                              /* static implementation */
  120.  
  121.   #define CUR cur
  122.   static TExecution_Context cur;   /* static exec. context variable */
  123.  
  124.   /* apparently, we have a _lot_ of direct indexing when accessing  */
  125.   /* the static 'cur', which makes the code bigger ( due to all the */
  126.   /* four bytes addresses ).                                        */
  127.  
  128. #endif
  129.  
  130.  #define INS_ARG         EXEC_OPS PStorage args  /* see ttexec.h */
  131.  
  132.  #define SKIP_Code()     SkipCode( EXEC_ARG )
  133.  
  134.  #define GET_ShortIns()  GetShortIns( EXEC_ARG )
  135.  
  136.  #define COMPUTE_Funcs() Compute_Funcs( EXEC_ARG )
  137.  
  138.  #define NORMalize(x,y,v)  Normalize( EXEC_ARGS x, y, v )
  139.  
  140.  #define SET_SuperRound(scale,flags)  SetSuperRound( EXEC_ARGS scale, flags )
  141.  
  142.  #define INS_Goto_CodeRange(range,ip) Ins_Goto_CodeRange( EXEC_ARGS range, ip )
  143.  
  144.  #define CUR_Func_project(x,y)  CUR.func_project( EXEC_ARGS x, y )
  145.  #define CUR_Func_move(z,p,d)   CUR.func_move( EXEC_ARGS z, p, d )
  146.  #define CUR_Func_dualproj(x,y) CUR.func_dualproj( EXEC_ARGS x, y )
  147.  #define CUR_Func_freeProj(x,y) CUR.func_freeProj( EXEC_ARGS x, y )
  148.  #define CUR_Func_round(d,c)    CUR.func_round( EXEC_ARGS d, c )
  149.  
  150.  #define CALC_Length()  Calc_Length( EXEC_ARG )
  151.  
  152.  #define INS_SxVTL(a,b,c,d) Ins_SxVTL( EXEC_ARGS a, b, c, d )
  153.  
  154.  #define COMPUTE_Point_Displacement(a,b,c,d) \
  155.            Compute_Point_Displacement( EXEC_ARGS a, b, c, d )
  156.  
  157.  #define MOVE_Zp2_Point(a,b,c)  Move_Zp2_Point( EXEC_ARGS a, b, c )
  158.  
  159.  #define CUR_Ppem()  Cur_PPEM( EXEC_ARG )
  160.  
  161.  typedef  void (*TInstruction_Function)( INS_ARG );
  162.  /* Instruction dispatch function, as used by the interpreter */
  163.  
  164.  
  165. /* end local struct definitions */
  166.  
  167. #ifndef ABS
  168. #define ABS(x)  ( (x) < 0 ? -(x) : (x) )
  169. #endif
  170.  
  171.  
  172. /*********************************************************************/
  173. /*                                                                   */
  174. /*  Before an opcode is executed, the interpreter verifies that      */
  175. /*  there are enough arguments on the stack, with the help of        */
  176. /*  the Pop_Push_Count table.                                        */
  177. /*                                                                   */
  178. /*  For each opcode, the first column gives the number of arguments  */
  179. /*  that are popped from the stack; the second one gives the number  */
  180. /*  of those that are pushed in result.                              */
  181. /*                                                                   */
  182. /*  Note that for opcodes with a varying number of parameters,       */
  183. /*  either 0 or 1 arg is verified before execution, depending        */
  184. /*  on the nature of the instruction :                               */
  185. /*                                                                   */
  186. /*   - if the number of arguments is given by the bytecode           */
  187. /*     stream or the loop variable, 0 is chosen.                     */
  188. /*                                                                   */
  189. /*   - if the first argument is a count n that is followed           */
  190. /*     by arguments a1..an, then 1 is chosen.                        */
  191. /*                                                                   */
  192. /*********************************************************************/
  193.  
  194. static unsigned char Pop_Push_Count[512] =
  195.              /* opcodes are gathered in groups of 16 */
  196.              /* please keep the spaces as they are   */
  197.           {
  198.              /*  SVTCA  y  */  0, 0,
  199.              /*  SVTCA  x  */  0, 0,
  200.              /*  SPvTCA y  */  0, 0,
  201.              /*  SPvTCA x  */  0, 0,
  202.              /*  SFvTCA y  */  0, 0,
  203.              /*  SFvTCA x  */  0, 0,
  204.              /*  SPvTL //  */  2, 0,
  205.              /*  SPvTL +   */  2, 0,
  206.              /*  SFvTL //  */  2, 0,
  207.              /*  SFvTL +   */  2, 0,
  208.              /*  SPvFS     */  2, 0,
  209.              /*  SFvFS     */  2, 0,
  210.              /*  GPV       */  0, 2,
  211.              /*  GFV       */  0, 2,
  212.              /*  SFvTPv    */  0, 0,
  213.              /*  ISECT     */  5, 0,
  214.  
  215.              /*  SRP0      */  1, 0,
  216.              /*  SRP1      */  1, 0,
  217.              /*  SRP2      */  1, 0,
  218.              /*  SZP0      */  1, 0,
  219.              /*  SZP1      */  1, 0,
  220.              /*  SZP2      */  1, 0,
  221.              /*  SZPS      */  1, 0,
  222.              /*  SLOOP     */  1, 0,
  223.              /*  RTG       */  0, 0,
  224.              /*  RTHG      */  0, 0,
  225.              /*  SMD       */  1, 0,
  226.              /*  ELSE      */  0, 0,
  227.              /*  JMPR      */  1, 0,
  228.              /*  SCvTCi    */  1, 0,
  229.              /*  SSwCi     */  1, 0,
  230.              /*  SSW       */  1, 0,
  231.              
  232.              /*  DUP       */  1, 2,
  233.              /*  POP       */  1, 0,
  234.              /*  CLEAR     */  0, 0,
  235.              /*  SWAP      */  2, 2,
  236.              /*  DEPTH     */  0, 1,
  237.              /*  CINDEX    */  1, 1,
  238.              /*  MINDEX    */  1, 0,
  239.              /*  AlignPTS  */  2, 0,
  240.              /*  INS_$28   */  0, 0,
  241.              /*  UTP       */  1, 0,
  242.              /*  LOOPCALL  */  2, 0,
  243.              /*  CALL      */  1, 0,
  244.              /*  FDEF      */  1, 0,
  245.              /*  ENDF      */  0, 0,
  246.              /*  MDAP[0]   */  1, 0,
  247.              /*  MDAP[1]   */  1, 0,
  248.              
  249.              /*  IUP[0]    */  0, 0,
  250.              /*  IUP[1]    */  0, 0,
  251.              /*  SHP[0]    */  0, 0,
  252.              /*  SHP[1]    */  0, 0,
  253.              /*  SHC[0]    */  1, 0,
  254.              /*  SHC[1]    */  1, 0,
  255.              /*  SHZ[0]    */  1, 0,
  256.              /*  SHZ[1]    */  1, 0,
  257.              /*  SHPIX     */  1, 0,
  258.              /*  IP        */  0, 0,
  259.              /*  MSIRP[0]  */  2, 0,
  260.              /*  MSIRP[1]  */  2, 0,
  261.              /*  AlignRP   */  0, 0,
  262.              /*  RTDG      */  0, 0,
  263.              /*  MIAP[0]   */  2, 0,
  264.              /*  MIAP[1]   */  2, 0,
  265.              
  266.              /*  NPushB    */  0, 0,
  267.              /*  NPushW    */  0, 0,
  268.              /*  WS        */  2, 0,
  269.              /*  RS        */  1, 1,
  270.              /*  WCvtP     */  2, 0,
  271.              /*  RCvt      */  1, 1,
  272.              /*  GC[0]     */  1, 1,
  273.              /*  GC[1]     */  1, 1,
  274.              /*  SCFS      */  2, 0,
  275.              /*  MD[0]     */  2, 1,
  276.              /*  MD[1]     */  2, 1,
  277.              /*  MPPEM     */  0, 1,
  278.              /*  MPS       */  0, 1,
  279.              /*  FlipON    */  0, 0,
  280.              /*  FlipOFF   */  0, 0,
  281.              /*  DEBUG     */  1, 0,
  282.              
  283.              /*  LT        */  2, 1,
  284.              /*  LTEQ      */  2, 1,
  285.              /*  GT        */  2, 1,
  286.              /*  GTEQ      */  2, 1,
  287.              /*  EQ        */  2, 1,
  288.              /*  NEQ       */  2, 1,
  289.              /*  ODD       */  1, 1,
  290.              /*  EVEN      */  1, 1,
  291.              /*  IF        */  1, 0,
  292.              /*  EIF       */  0, 0,
  293.              /*  AND       */  2, 1,
  294.              /*  OR        */  2, 1,
  295.              /*  NOT       */  1, 1,
  296.              /*  DeltaP1   */  1, 0,
  297.              /*  SDB       */  1, 0,
  298.              /*  SDS       */  1, 0,
  299.              
  300.              /*  ADD       */  2, 1,
  301.              /*  SUB       */  2, 1,
  302.              /*  DIV       */  2, 1,
  303.              /*  MUL       */  2, 1,
  304.              /*  ABS       */  1, 1,
  305.              /*  NEG       */  1, 1,
  306.              /*  FLOOR     */  1, 1,
  307.              /*  CEILING   */  1, 1,
  308.              /*  ROUND[0]  */  1, 1,
  309.              /*  ROUND[1]  */  1, 1,
  310.              /*  ROUND[2]  */  1, 1,
  311.              /*  ROUND[3]  */  1, 1,
  312.              /*  NROUND[0] */  1, 1,
  313.              /*  NROUND[1] */  1, 1,
  314.              /*  NROUND[2] */  1, 1,
  315.              /*  NROUND[3] */  1, 1,
  316.              
  317.              /*  WCvtF     */  2, 0,
  318.              /*  DeltaP2   */  1, 0,
  319.              /*  DeltaP3   */  1, 0,
  320.              /*  DeltaCn[0] */ 1, 0,
  321.              /*  DeltaCn[1] */ 1, 0,
  322.              /*  DeltaCn[2] */ 1, 0,
  323.              /*  SROUND    */  1, 0,
  324.              /*  S45Round  */  1, 0,
  325.              /*  JROT      */  2, 0,
  326.              /*  JROF      */  2, 0,
  327.              /*  ROFF      */  0, 0,
  328.              /*  INS_$7B   */  0, 0,
  329.              /*  RUTG      */  0, 0,
  330.              /*  RDTG      */  0, 0,
  331.              /*  SANGW     */  1, 0,
  332.              /*  AA        */  1, 0,
  333.              
  334.              /*  FlipPT    */  0, 0,
  335.              /*  FlipRgON  */  2, 0,
  336.              /*  FlipRgOFF */  2, 0,
  337.              /*  INS_$83   */  0, 0,
  338.              /*  INS_$84   */  0, 0,
  339.              /*  ScanCTRL  */  1, 0,
  340.              /*  SDVPTL[0] */  2, 0,
  341.              /*  SDVPTL[1] */  2, 0,
  342.              /*  GetINFO   */  1, 1,
  343.              /*  IDEF      */  1, 0,
  344.              /*  ROLL      */  3, 3,
  345.              /*  MAX       */  2, 1,
  346.              /*  MIN       */  2, 1,
  347.              /*  ScanTYPE  */  1, 0,
  348.              /*  InstCTRL  */  2, 0,
  349.              /*  INS_$8F   */  0, 0,
  350.              
  351.              /*  INS_$90  */   0, 0,
  352.              /*  INS_$91  */   0, 0,
  353.              /*  INS_$92  */   0, 0,
  354.              /*  INS_$93  */   0, 0,
  355.              /*  INS_$94  */   0, 0,
  356.              /*  INS_$95  */   0, 0,
  357.              /*  INS_$96  */   0, 0,
  358.              /*  INS_$97  */   0, 0,
  359.              /*  INS_$98  */   0, 0,
  360.              /*  INS_$99  */   0, 0,
  361.              /*  INS_$9A  */   0, 0,
  362.              /*  INS_$9B  */   0, 0,
  363.              /*  INS_$9C  */   0, 0,
  364.              /*  INS_$9D  */   0, 0,
  365.              /*  INS_$9E  */   0, 0,
  366.              /*  INS_$9F  */   0, 0,
  367.              
  368.              /*  INS_$A0  */   0, 0,
  369.              /*  INS_$A1  */   0, 0,
  370.              /*  INS_$A2  */   0, 0,
  371.              /*  INS_$A3  */   0, 0,
  372.              /*  INS_$A4  */   0, 0,
  373.              /*  INS_$A5  */   0, 0,
  374.              /*  INS_$A6  */   0, 0,
  375.              /*  INS_$A7  */   0, 0,
  376.              /*  INS_$A8  */   0, 0,
  377.              /*  INS_$A9  */   0, 0,
  378.              /*  INS_$AA  */   0, 0,
  379.              /*  INS_$AB  */   0, 0,
  380.              /*  INS_$AC  */   0, 0,
  381.              /*  INS_$AD  */   0, 0,
  382.              /*  INS_$AE  */   0, 0,
  383.              /*  INS_$AF  */   0, 0,
  384.              
  385.              /*  PushB[0]  */  0, 1,
  386.              /*  PushB[1]  */  0, 2,
  387.              /*  PushB[2]  */  0, 3,
  388.              /*  PushB[3]  */  0, 4,
  389.              /*  PushB[4]  */  0, 5,
  390.              /*  PushB[5]  */  0, 6,
  391.              /*  PushB[6]  */  0, 7,
  392.              /*  PushB[7]  */  0, 8,
  393.              /*  PushW[0]  */  0, 1,
  394.              /*  PushW[1]  */  0, 2,
  395.              /*  PushW[2]  */  0, 3,
  396.              /*  PushW[3]  */  0, 4,
  397.              /*  PushW[4]  */  0, 5,
  398.              /*  PushW[5]  */  0, 6,
  399.              /*  PushW[6]  */  0, 7,
  400.              /*  PushW[7]  */  0, 8,
  401.              
  402.              /*  MDRP[00]  */  1, 0,
  403.              /*  MDRP[01]  */  1, 0,
  404.              /*  MDRP[02]  */  1, 0,
  405.              /*  MDRP[03]  */  1, 0,
  406.              /*  MDRP[04]  */  1, 0,
  407.              /*  MDRP[05]  */  1, 0,
  408.              /*  MDRP[06]  */  1, 0,
  409.              /*  MDRP[07]  */  1, 0,
  410.              /*  MDRP[08]  */  1, 0,
  411.              /*  MDRP[09]  */  1, 0,
  412.              /*  MDRP[10]  */  1, 0,
  413.              /*  MDRP[11]  */  1, 0,
  414.              /*  MDRP[12]  */  1, 0,
  415.              /*  MDRP[13]  */  1, 0,
  416.              /*  MDRP[14]  */  1, 0,
  417.              /*  MDRP[15]  */  1, 0,
  418.              
  419.              /*  MDRP[16]  */  1, 0,
  420.              /*  MDRP[17]  */  1, 0,
  421.              /*  MDRP[18]  */  1, 0,
  422.              /*  MDRP[19]  */  1, 0,
  423.              /*  MDRP[20]  */  1, 0,
  424.              /*  MDRP[21]  */  1, 0,
  425.              /*  MDRP[22]  */  1, 0,
  426.              /*  MDRP[23]  */  1, 0,
  427.              /*  MDRP[24]  */  1, 0,
  428.              /*  MDRP[25]  */  1, 0,
  429.              /*  MDRP[26]  */  1, 0,
  430.              /*  MDRP[27]  */  1, 0,
  431.              /*  MDRP[28]  */  1, 0,
  432.              /*  MDRP[29]  */  1, 0,
  433.              /*  MDRP[30]  */  1, 0,
  434.              /*  MDRP[31]  */  1, 0,
  435.              
  436.              /*  MIRP[00]  */  2, 0,
  437.              /*  MIRP[01]  */  2, 0,
  438.              /*  MIRP[02]  */  2, 0,
  439.              /*  MIRP[03]  */  2, 0,
  440.              /*  MIRP[04]  */  2, 0,
  441.              /*  MIRP[05]  */  2, 0,
  442.              /*  MIRP[06]  */  2, 0,
  443.              /*  MIRP[07]  */  2, 0,
  444.              /*  MIRP[08]  */  2, 0,
  445.              /*  MIRP[09]  */  2, 0,
  446.              /*  MIRP[10]  */  2, 0,
  447.              /*  MIRP[11]  */  2, 0,
  448.              /*  MIRP[12]  */  2, 0,
  449.              /*  MIRP[13]  */  2, 0,
  450.              /*  MIRP[14]  */  2, 0,
  451.              /*  MIRP[15]  */  2, 0,
  452.              
  453.              /*  MIRP[16]  */  2, 0,
  454.              /*  MIRP[17]  */  2, 0,
  455.              /*  MIRP[18]  */  2, 0,
  456.              /*  MIRP[19]  */  2, 0,
  457.              /*  MIRP[20]  */  2, 0,
  458.              /*  MIRP[21]  */  2, 0,
  459.              /*  MIRP[22]  */  2, 0,
  460.              /*  MIRP[23]  */  2, 0,
  461.              /*  MIRP[24]  */  2, 0,
  462.              /*  MIRP[25]  */  2, 0,
  463.              /*  MIRP[26]  */  2, 0,
  464.              /*  MIRP[27]  */  2, 0,
  465.              /*  MIRP[28]  */  2, 0,
  466.              /*  MIRP[29]  */  2, 0,
  467.              /*  MIRP[30]  */  2, 0,
  468.              /*  MIRP[31]  */  2, 0
  469.   };
  470.  
  471.  
  472.  
  473. /******************************************************************
  474.  *
  475.  *  Function    :  Cur_PPEM
  476.  *
  477.  *  Description :  Returns the current ppem along the projection
  478.  *                 vector.
  479.  *
  480.  *****************************************************************/
  481.  
  482. static TT_F26Dot6  Cur_PPEM( EXEC_OP )
  483. {
  484.   Int64 Tx, Ty;
  485.   Int32 x,  y;
  486.  
  487.   if (CUR.cached_metrics)
  488.     return CUR.cur_ppem;
  489.  
  490.   if (!CUR.GS.projVector.y)
  491.   {
  492.     CUR.cur_ppem = CUR.metrics.x_ppem;
  493.     CUR.scale1   = CUR.metrics.x_scale1;
  494.     CUR.scale2   = CUR.metrics.x_scale2;
  495.   }
  496.   else if ( !CUR.GS.projVector.x )
  497.   {
  498.     CUR.cur_ppem = CUR.metrics.y_ppem;
  499.     CUR.scale1   = CUR.metrics.y_scale1;
  500.     CUR.scale2   = CUR.metrics.y_scale2;
  501.   }
  502.   else
  503.   {
  504.     /* Rotation */
  505.  
  506.     x = MulDiv_Round( CUR.metrics.x_ppem, CUR.GS.projVector.x, 0x40 );
  507.     /* x = x_ppem.proj_x * 256 */
  508.  
  509.     y = MulDiv_Round( CUR.metrics.y_ppem, CUR.GS.projVector.y, 0x40 );
  510.     /* y = y_ppem.proj_y * 256 */
  511.  
  512.     MUL_64( x, x, Tx );
  513.     MUL_64( y, y, Ty );
  514.     ADD_64( Tx, Ty, Tx );
  515.  
  516.     CUR.cur_ppem = SQRT_64( Tx ) / 256;
  517.  
  518.     /* XXX: Fix this.. for now we simply don't care */
  519.     CUR.scale1 = CUR.metrics.x_scale1;
  520.     CUR.scale2 = CUR.metrics.x_scale2;
  521.   }
  522.  
  523.   CUR.cached_metrics = TRUE;
  524.   return CUR.cur_ppem;
  525. }
  526.  
  527. /******************************************************************
  528.  *
  529.  *  Function    :  Calc_Length
  530.  *
  531.  *  Description :  Computes the length in bytes of current opcode
  532.  *
  533.  *****************************************************************/
  534.  
  535. static Bool Calc_Length( EXEC_OP )
  536. {
  537.  
  538.   CUR.opcode = CUR.code[CUR.IP];
  539.  
  540.   switch (CUR.opcode) 
  541.   {
  542.  
  543.   case 0x40:
  544.     if (CUR.IP + 1 >= CUR.codeSize)
  545.       return FAILURE;
  546.  
  547.     CUR.length = CUR.code[CUR.IP + 1] + 2;
  548.     break;
  549.  
  550.   case 0x41:
  551.     if (CUR.IP + 1 >= CUR.codeSize)
  552.       return FAILURE;
  553.  
  554.     CUR.length = CUR.code[CUR.IP + 1] * 2 + 2;
  555.     break;
  556.  
  557.   case 0xB0:
  558.   case 0xB1:
  559.   case 0xB2:
  560.   case 0xB3:
  561.   case 0xB4:
  562.   case 0xB5:
  563.   case 0xB6:
  564.   case 0xB7:
  565.     CUR.length = CUR.opcode - 0xB0 + 2;
  566.     break;
  567.  
  568.   case 0xB8:
  569.   case 0xB9:
  570.   case 0xBA:
  571.   case 0xBB:
  572.   case 0xBC:
  573.   case 0xBD:
  574.   case 0xBE:
  575.   case 0xBF:
  576.     CUR.length = (CUR.opcode - 0xB8) * 2 + 3;
  577.     break;
  578.  
  579.   default:
  580.     CUR.length = 1;
  581.     break;
  582.   }
  583.  
  584.   /* make sure result is in range */
  585.  
  586.   if ( CUR.IP + CUR.length > CUR.codeSize )
  587.     return FAILURE;
  588.  
  589.   return SUCCESS;
  590. }
  591.  
  592.  
  593. /*******************************************************************
  594.  *
  595.  *  Function    :  GetShortIns
  596.  *
  597.  *  Description :  Return a short integer taken from the instruction
  598.  *                 stream at address IP.
  599.  *
  600.  *  Input  :  None
  601.  *
  602.  *  Output :  Short read at Code^[IP..IP+1]
  603.  *
  604.  *  Notes  :  This one could become a Macro in the C version
  605.  *
  606.  *****************************************************************/
  607.  
  608. static Short GetShortIns( EXEC_OP )
  609. {
  610.      /* Reading a byte stream so there is no endianess DaveP */
  611.      CUR.IP += 2;
  612.      return ( CUR.code[CUR.IP-2] << 8) +
  613.               CUR.code[CUR.IP-1];
  614. }
  615.  
  616.  
  617. /*******************************************************************
  618.  *
  619.  *  Function    :  Ins_Goto_CodeRange
  620.  *
  621.  *  Description :  
  622.  *                
  623.  *
  624.  *  Input  : 
  625.  *
  626.  *  Output :  
  627.  *
  628.  *  Notes  :  
  629.  *
  630.  *****************************************************************/
  631.  
  632. static Bool Ins_Goto_CodeRange( EXEC_OPS Int aRange, Int aIP)
  633. {
  634.   TCodeRange *WITH;
  635.  
  636.   if (aRange < 1 || aRange > 3) 
  637.   {
  638.     CUR.error = TT_Err_Bad_Argument;
  639.     return FAILURE;
  640.   }
  641.  
  642.   WITH = &CUR.codeRangeTable[ aRange-1 ];
  643.  
  644.   if (WITH->Base == NULL)     /* invalid coderange */
  645.   {
  646.     CUR.error = TT_Err_Invalid_Coderange;
  647.     return FAILURE;
  648.   }
  649.  
  650.   /* NOTE : Because the last instruction of a program may be a CALL */
  651.   /*        which will return to the first byte *after* the code    */
  652.   /*        range, we test for AIP <= Size, instead of AIP < Size   */
  653.  
  654.   if (aIP > WITH->Size) 
  655.   {
  656.     CUR.error = TT_Err_Code_Overflow;
  657.     return FAILURE;
  658.   }
  659.  
  660.   CUR.code     = WITH->Base;
  661.   CUR.codeSize = WITH->Size;
  662.   CUR.IP       = aIP;
  663.   CUR.curRange = aRange;
  664.  
  665.   return SUCCESS;
  666. }
  667.  
  668.  
  669. /*******************************************************************
  670.  *
  671.  *  Function    :  Direct_Move
  672.  *
  673.  *  Description :  Moves a point by a given distance along the
  674.  *                 freedom vector.
  675.  *
  676.  *  Input  : Vx, Vy      point coordinates to move
  677.  *           touch       touch flag to modify
  678.  *           distance
  679.  *
  680.  *  Output :  None
  681.  *
  682.  *****************************************************************/
  683.  
  684. static void Direct_Move( EXEC_OPS PVecRecord  zone,
  685.                                   Int         point,
  686.                                   TT_F26Dot6  distance)
  687. {
  688.   TT_F26Dot6 v;
  689.  
  690.   v = CUR.GS.freeVector.x;
  691.   if (v != 0)
  692.   {
  693.     zone->cur_x[point] += MulDiv_Round( distance,
  694.                                         v * 0x10000L,
  695.                                         CUR.F_dot_P);
  696.  
  697.     zone->touch[point] |= TT_Flag_Touched_X;
  698.   }
  699.  
  700.   v = CUR.GS.freeVector.y;
  701.   if (v != 0) 
  702.   {
  703.     zone->cur_y[point] += MulDiv_Round( distance,
  704.                                         v * 0x10000L,
  705.                                         CUR.F_dot_P);
  706.  
  707.     zone->touch[point] |= TT_Flag_Touched_Y;
  708.   }
  709. }
  710.  
  711.  
  712. /* The following versions are used whenever both vectors are both */
  713. /* along one of the coordinate unit vectors, i.e. in 90% cases    */
  714.  
  715. /*******************************************************************
  716.  * Direct_Move_X
  717.  *
  718.  * 
  719.  *******************************************************************/
  720.  
  721. static void Direct_Move_X( EXEC_OPS PVecRecord  zone,
  722.                                     Int         point,
  723.                                     TT_F26Dot6  distance)
  724. {
  725.   zone->cur_x[point] += distance;
  726.   zone->touch[point] |= TT_Flag_Touched_X;
  727. }
  728.  
  729.  
  730. /*******************************************************************
  731.  * Direct_Move_Y
  732.  *
  733.  * 
  734.  *******************************************************************/
  735.  
  736. static void Direct_Move_Y( EXEC_OPS PVecRecord  zone,
  737.                                     Int         point,
  738.                                     TT_F26Dot6  distance)
  739. {
  740.   zone->cur_y[point] += distance;
  741.   zone->touch[point] |= TT_Flag_Touched_Y;
  742. }
  743.  
  744.  
  745. /*******************************************************************
  746.  *
  747.  *  Function    :  Round_None
  748.  *
  749.  *  Description :  Do not round, but add engine compensation
  750.  *
  751.  *  Input  :  distance      : distance to round
  752.  *            compensation  : engine compensation
  753.  *
  754.  *  Output :  rounded distance
  755.  *
  756.  *  NOTE : The spec says very few about the relationship between
  757.  *         rounding and engine compensation. However, it seems
  758.  *         from the description of super round that we should
  759.  *         should add the compensation before rounding
  760.  *
  761.  ******************************************************************/
  762.  
  763. static TT_F26Dot6 Round_None( EXEC_OPS TT_F26Dot6 distance,
  764.                                        TT_F26Dot6 compensation)
  765. {
  766.   TT_F26Dot6 val;
  767.  
  768.   if (distance >= 0) 
  769.   {
  770.     val = distance + compensation;
  771.     if (val < 0)
  772.       val = 0;
  773.   }
  774.   else {
  775.     val = distance - compensation;
  776.     if (val > 0)
  777.       val = 0;
  778.   }
  779.   return val;
  780. }
  781.  
  782.  
  783. /*******************************************************************
  784.  *
  785.  *  Function    :  Round_To_Grid
  786.  *
  787.  *  Description :  round value to grid after adding engine
  788.  *                 compensation
  789.  *
  790.  *  Input  :  distance      : distance to round
  791.  *            compensation  : engine compensation
  792.  *
  793.  *  Output :  rounded distance
  794.  *
  795.  *****************************************************************/
  796.  
  797. static TT_F26Dot6 Round_To_Grid( EXEC_OPS TT_F26Dot6 distance,
  798.                                           TT_F26Dot6 compensation)
  799. {
  800.   TT_F26Dot6 val;
  801.  
  802.   if (distance >= 0) 
  803.   {
  804.     val = (distance + compensation + 32) & (-64);
  805.     if (val < 0)
  806.       val = 0;
  807.   }
  808.   else 
  809.   {
  810.     val = -((compensation - distance + 32) & (-64));
  811.     if (val > 0)
  812.       val = 0;
  813.   }
  814.   return val;
  815. }
  816.  
  817. /*******************************************************************
  818.  *
  819.  *  Function    :  Round_To_Half_Grid
  820.  *
  821.  *  Description :  round value to half grid after adding engine
  822.  *                 compensation
  823.  *
  824.  *  Input  :  distance      : distance to round
  825.  *            compensation  : engine compensation
  826.  *
  827.  *  Output :  rounded distance
  828.  *
  829.  *****************************************************************/
  830.  
  831. static TT_F26Dot6 Round_To_Half_Grid( EXEC_OPS TT_F26Dot6 distance,
  832.                                                TT_F26Dot6 compensation )
  833. {
  834.   TT_F26Dot6 val;
  835.  
  836.   if (distance >= 0) 
  837.   {
  838.     val = ((distance + compensation) & (-64)) + 32;
  839.     if (val < 0)
  840.       val = 0;
  841.   }
  842.   else 
  843.   {
  844.     val = -(((compensation - distance) & (-64)) + 32);
  845.     if (val > 0)
  846.       val = 0;
  847.   }
  848.   return val;
  849. }
  850.  
  851.  
  852. /*******************************************************************
  853.  *
  854.  *  Function    :  Round_Down_To_Grid
  855.  *
  856.  *  Description :  round value down to grid after adding engine
  857.  *                 compensation
  858.  *
  859.  *  Input  :  distance      : distance to round
  860.  *            compensation  : engine compensation
  861.  *
  862.  *  Output :  rounded distance
  863.  *
  864.  *****************************************************************/
  865.  
  866. static TT_F26Dot6 Round_Down_To_Grid( EXEC_OPS TT_F26Dot6 distance,
  867.                                                TT_F26Dot6 compensation )
  868. {
  869.   TT_F26Dot6 val;
  870.  
  871.   if (distance >= 0) 
  872.   {
  873.     val = (distance + compensation) & (-64);
  874.     if (val < 0)
  875.       val = 0;
  876.   }
  877.   else 
  878.   {
  879.     val = -((compensation - distance) & (-64));
  880.     if (val > 0)
  881.       val = 0;
  882.   }
  883.   return val;
  884. }
  885.  
  886.  
  887. /*******************************************************************
  888.  *
  889.  *  Function    :  Round_Up_To_Grid
  890.  *
  891.  *  Description :  round value up to grid after adding engine
  892.  *                 compensation
  893.  *
  894.  *  Input  :  distance      : distance to round
  895.  *            compensation  : engine compensation
  896.  *
  897.  *  Output :  rounded distance
  898.  *
  899.  *****************************************************************/
  900.  
  901. static TT_F26Dot6 Round_Up_To_Grid( EXEC_OPS TT_F26Dot6 distance,
  902.                                              TT_F26Dot6 compensation )
  903. {
  904.   TT_F26Dot6 val;
  905.  
  906.   if (distance >= 0)
  907.   {
  908.     val = (distance + compensation + 63) & (-64);
  909.     if (val < 0)
  910.       val = 0;
  911.   }
  912.   else 
  913.   {
  914.     val = -((compensation - distance + 63) & (-64));
  915.     if (val > 0)
  916.       val = 0;
  917.   }
  918.   return val;
  919. }
  920.  
  921.  
  922. /*******************************************************************
  923.  *
  924.  *  Function    :  Round_To_Double_Grid
  925.  *
  926.  *  Description :  round value to double grid after adding engine
  927.  *                 compensation
  928.  *
  929.  *  Input  :  distance      : distance to round
  930.  *            compensation  : engine compensation
  931.  *
  932.  *  Output :  rounded distance
  933.  *
  934.  *****************************************************************/
  935.  
  936. static TT_F26Dot6 Round_To_Double_Grid( EXEC_OPS TT_F26Dot6 distance,
  937.                                                  TT_F26Dot6 compensation )
  938. {
  939.   TT_F26Dot6 val;
  940.  
  941.   if (distance >= 0) 
  942.   {
  943.     val = (distance + compensation + 16) & (-32);
  944.     if (val < 0)
  945.       val = 0;
  946.   }
  947.   else 
  948.   {
  949.     val = -((compensation - distance + 16) & (-32));
  950.     if (val > 0)
  951.       val = 0;
  952.   }
  953.   return val;
  954. }
  955.  
  956.  
  957. /*******************************************************************
  958.  *
  959.  *  Function    :  Round_Super
  960.  *
  961.  *  Description :  super round value to grid after adding engine
  962.  *                 compensation
  963.  *
  964.  *  Input  :  distance      : distance to round
  965.  *            compensation  : engine compensation
  966.  *
  967.  *  Output :  rounded distance
  968.  *
  969.  *  NOTE : The spec says very few about the relationship between
  970.  *         rounding and engine compensation. However, it seems
  971.  *         from the description of super round that we should
  972.  *         should add the compensation before rounding
  973.  *
  974.  *****************************************************************/
  975.  
  976. static TT_F26Dot6 Round_Super( EXEC_OPS TT_F26Dot6 distance,
  977.                                         TT_F26Dot6 compensation )
  978. {
  979.   TT_F26Dot6 val;
  980.  
  981.   if (distance >= 0)
  982.   {
  983.     val = (distance - CUR.phase + CUR.threshold + compensation) & (-CUR.period);
  984.     if (val < 0)
  985.       val = 0;
  986.     val += CUR.phase;
  987.   }
  988.   else
  989.   {
  990.     val = -((CUR.threshold - CUR.phase - distance + compensation) & (-CUR.period));
  991.     if (val > 0)
  992.       val = 0;
  993.     val -= CUR.phase;
  994.    }
  995.   return val;
  996. }
  997.  
  998.  
  999. /*******************************************************************
  1000.  *
  1001.  *  Function    :  Round_Super_45
  1002.  *
  1003.  *  Description :  super round value to grid after adding engine
  1004.  *                 compensation
  1005.  *
  1006.  *  Input  :  distance      : distance to round
  1007.  *            compensation  : engine compensation
  1008.  *
  1009.  *  Output :  rounded distance
  1010.  *
  1011.  *  NOTE : There is a separate function for Round_Super_45 as we
  1012.  *         may need a greater precision.
  1013.  *
  1014.  *****************************************************************/
  1015.  
  1016. static TT_F26Dot6 Round_Super_45( EXEC_OPS TT_F26Dot6 distance,
  1017.                                            TT_F26Dot6 compensation)
  1018. {
  1019.   TT_F26Dot6 val;
  1020.  
  1021.   if (distance >= 0)
  1022.   {
  1023.     val = ((distance - CUR.phase + CUR.threshold + compensation) / 
  1024.             CUR.period) * CUR.period;
  1025.     if (val < 0)
  1026.       val = 0;
  1027.     val += CUR.phase;
  1028.   }
  1029.   else 
  1030.   {
  1031.     val = -(((CUR.threshold - CUR.phase - distance + compensation) / 
  1032.               CUR.period) * CUR.period);
  1033.     if (val > 0)
  1034.       val = 0;
  1035.     val -= CUR.phase;
  1036.   }
  1037.   return val;
  1038. }
  1039.  
  1040.  
  1041. /******************************************************************************
  1042.  * Compute_Round
  1043.  *
  1044.  * 
  1045.  ******************************************************************************/
  1046.  
  1047. static void Compute_Round( EXEC_OPS Byte round_mode )
  1048. {
  1049.   switch (round_mode) {
  1050.  
  1051.   case TT_Round_Off:
  1052.     CUR.func_round = (TRound_Function)Round_None;
  1053.     break;
  1054.  
  1055.   case TT_Round_To_Grid:
  1056.     CUR.func_round = (TRound_Function)Round_To_Grid;
  1057.     break;
  1058.  
  1059.   case TT_Round_Up_To_Grid:
  1060.     CUR.func_round = (TRound_Function)Round_Up_To_Grid;
  1061.     break;
  1062.  
  1063.   case TT_Round_Down_To_Grid:
  1064.     CUR.func_round = (TRound_Function)Round_Down_To_Grid;
  1065.     break;
  1066.  
  1067.   case TT_Round_To_Half_Grid:
  1068.     CUR.func_round = (TRound_Function)Round_To_Half_Grid;
  1069.     break;
  1070.  
  1071.   case TT_Round_To_Double_Grid:
  1072.     CUR.func_round = (TRound_Function)Round_To_Double_Grid;
  1073.     break;
  1074.  
  1075.   case TT_Round_Super:
  1076.     CUR.func_round = (TRound_Function)Round_Super;
  1077.     break;
  1078.  
  1079.   case TT_Round_Super_45:
  1080.     CUR.func_round = (TRound_Function)Round_Super_45;
  1081.     break;
  1082.  
  1083.   }
  1084. }
  1085.  
  1086.  
  1087. /*******************************************************************
  1088.  *
  1089.  *  Function    :  SetSuperRound
  1090.  *
  1091.  *  Description :  Set Super Round parameters
  1092.  *
  1093.  *  Input  :  GridPeriod   Grid period
  1094.  *            OpCode       SROUND opcode
  1095.  *
  1096.  *  Output :  None
  1097.  *
  1098.  *  Notes  :
  1099.  *
  1100.  *****************************************************************/
  1101.  
  1102. static void SetSuperRound( EXEC_OPS TT_F26Dot6 GridPeriod, Long selector)
  1103. {
  1104.   switch (selector & 0xC0)
  1105.    {
  1106.     case 0:
  1107.       CUR.period = GridPeriod / 2;
  1108.       break;
  1109.   
  1110.     case 0x40:
  1111.       CUR.period = GridPeriod;
  1112.       break;
  1113.   
  1114.     case 0x80:
  1115.       CUR.period = GridPeriod * 2;
  1116.       break;
  1117.   
  1118.     /* This opcode is reserved, but ... */
  1119.   
  1120.     case 0xC0:
  1121.       CUR.period = GridPeriod;
  1122.       break;
  1123.   }
  1124.  
  1125.   switch (selector & 0x30)
  1126.     {
  1127.     case 0:
  1128.       CUR.phase = 0;
  1129.       break;
  1130.   
  1131.     case 0x10:
  1132.       CUR.phase = CUR.period / 4;
  1133.       break;
  1134.   
  1135.     case 0x20:
  1136.       CUR.phase = CUR.period / 2;
  1137.       break;
  1138.   
  1139.     case 0x30:
  1140.       CUR.phase = GridPeriod * 3 / 4;
  1141.       break;
  1142.     }
  1143.  
  1144.   if ((selector & 0x0F) == 0)
  1145.     CUR.threshold = CUR.period - 1;
  1146.   else
  1147.     CUR.threshold = ((Int)(selector & 0x0F) - 4L) * CUR.period / 8;
  1148.  
  1149.   CUR.period    /= 256;
  1150.   CUR.phase     /= 256;
  1151.   CUR.threshold /= 256;
  1152.  
  1153. }
  1154.  
  1155. /*******************************************************************
  1156.  *
  1157.  *  Function    :  Norm
  1158.  *
  1159.  *  Description :  returns the norm (length) of a vector
  1160.  *
  1161.  *  Input  :  X, Y   vector
  1162.  *
  1163.  *  Output :  returns length in F26dot6
  1164.  *
  1165.  *****************************************************************/
  1166.  
  1167. static TT_F26Dot6 Norm( TT_F26Dot6 X, TT_F26Dot6 Y )
  1168. {
  1169.   Int64 T1, T2;
  1170.  
  1171.   MUL_64(X, X, T1);
  1172.   MUL_64(Y, Y, T2);
  1173.  
  1174.   ADD_64(T1, T2, T1);
  1175.  
  1176.   return (TT_F26Dot6)SQRT_64(T1);
  1177. }
  1178.  
  1179.  
  1180. /*******************************************************************
  1181.  *
  1182.  *  Function    :  Project
  1183.  *
  1184.  *  Description :  Computes the projection of (Vx,Vy) along the
  1185.  *                 current projection vector
  1186.  *
  1187.  *  Input  :  Vx, Vy    input vector
  1188.  *
  1189.  *  Output :  return distance in F26dot6
  1190.  *
  1191.  *****************************************************************/
  1192.  
  1193. static TT_F26Dot6 Project( EXEC_OPS TT_F26Dot6 Vx, TT_F26Dot6 Vy)
  1194. {
  1195.   Int64 T1, T2;
  1196.  
  1197.   MUL_64( Vx, CUR.GS.projVector.x, T1);
  1198.   MUL_64( Vy, CUR.GS.projVector.y, T2);
  1199.  
  1200.   ADD_64( T1, T2, T1);
  1201.  
  1202.   return (DIV_64( T1, 0x4000L));
  1203. }
  1204.  
  1205.  
  1206. /******************************************************************************
  1207.  * #function#
  1208.  *
  1209.  * 
  1210.  ******************************************************************************/
  1211.  
  1212. static TT_F26Dot6 Dual_Project( EXEC_OPS TT_F26Dot6 Vx, TT_F26Dot6 Vy)
  1213. {
  1214.   Int64 T1, T2;
  1215.  
  1216.   MUL_64( Vx, CUR.GS.dualVector.x, T1);
  1217.   MUL_64( Vy, CUR.GS.dualVector.y, T2);
  1218.  
  1219.   ADD_64( T1, T2, T1);
  1220.  
  1221.   return ((TT_F26Dot6)DIV_64( T1, 0x4000L));
  1222. }
  1223.  
  1224.  
  1225. /******************************************************************************
  1226.  * #function#
  1227.  *
  1228.  * 
  1229.  ******************************************************************************/
  1230.  
  1231. static TT_F26Dot6 Free_Project( EXEC_OPS TT_F26Dot6 Vx, TT_F26Dot6 Vy)
  1232. {
  1233.   Int64 T1, T2;
  1234.  
  1235.   MUL_64( Vx, CUR.GS.freeVector.x, T1);
  1236.   MUL_64( Vy, CUR.GS.freeVector.y, T2);
  1237.  
  1238.   ADD_64( T1, T2, T1);
  1239.  
  1240.   return ((TT_F26Dot6)DIV_64( T1, 0x4000L ));
  1241. }
  1242.  
  1243.  
  1244. /******************************************************************************
  1245.  * #function#
  1246.  *
  1247.  * 
  1248.  ******************************************************************************/
  1249.  
  1250. static TT_F26Dot6 Project_x( EXEC_OPS TT_F26Dot6 Vx, TT_F26Dot6 Vy)
  1251. {
  1252.   return Vx;
  1253. }
  1254.  
  1255. /******************************************************************************
  1256.  * #function#
  1257.  *
  1258.  * 
  1259.  ******************************************************************************/
  1260.  
  1261. static TT_F26Dot6 Project_y( EXEC_OPS TT_F26Dot6 Vx, TT_F26Dot6 Vy)
  1262. {
  1263.   return Vy;
  1264. }
  1265.  
  1266.  
  1267. /*******************************************************************
  1268.  *
  1269.  *  Function    :  Compute_Funcs
  1270.  *
  1271.  *  Description :  Computes the projections and movement function
  1272.  *                 pointers according to the current graphics state
  1273.  *
  1274.  *  Input  :  None
  1275.  *
  1276.  *****************************************************************/
  1277.  
  1278. static void Compute_Funcs( EXEC_OP )
  1279. {
  1280.   if (CUR.GS.freeVector.x == 0x4000)
  1281.   {
  1282.     CUR.func_freeProj = (TProject_Function)Project_x;
  1283.     CUR.F_dot_P       = CUR.GS.projVector.x * 0x10000L;
  1284.   }
  1285.   else
  1286.   {
  1287.     if (CUR.GS.freeVector.y == 0x4000)
  1288.     {
  1289.       CUR.func_freeProj = (TProject_Function)Project_y;
  1290.       CUR.F_dot_P       = CUR.GS.projVector.y * 0x10000L;
  1291.     }
  1292.     else
  1293.     {
  1294.       CUR.func_move = (TMove_Function)Direct_Move;
  1295.       CUR.func_freeProj = (TProject_Function)Free_Project;
  1296.       CUR.F_dot_P = (Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
  1297.                     (Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
  1298.     }
  1299.   }
  1300.  
  1301.   CUR.cached_metrics = FALSE;
  1302.   CUR_Ppem();  /* Force computation */
  1303.  
  1304.   if (CUR.GS.projVector.x == 0x4000)
  1305.   {
  1306.     CUR.func_project = (TProject_Function)Project_x;
  1307.   }
  1308.   else
  1309.   {
  1310.     if (CUR.GS.projVector.y == 0x4000)
  1311.     {
  1312.       CUR.func_project = (TProject_Function)Project_y;
  1313.     } 
  1314.     else
  1315.     {
  1316.       CUR.func_project = (TProject_Function)Project;
  1317.     }
  1318.   }
  1319.  
  1320.   if (CUR.GS.dualVector.x == 0x4000)
  1321.   {
  1322.     CUR.func_dualproj = (TProject_Function)Project_x;
  1323.   }
  1324.   else
  1325.   {
  1326.     if (CUR.GS.dualVector.y == 0x4000)
  1327.     {
  1328.       CUR.func_dualproj = (TProject_Function)Project_y;
  1329.     }
  1330.     else
  1331.     {
  1332.       CUR.func_dualproj = (TProject_Function)Dual_Project;
  1333.     }
  1334.   }
  1335.  
  1336.   CUR.func_move = (TMove_Function)Direct_Move;
  1337.  
  1338.   if (CUR.F_dot_P == 0x40000000L)
  1339.   {
  1340.     if (CUR.GS.freeVector.x == 0x4000)
  1341.     {
  1342.       CUR.func_move = (TMove_Function)Direct_Move_X;
  1343.     } 
  1344.     else
  1345.     {
  1346.       if (CUR.GS.freeVector.y == 0x4000)
  1347.       {
  1348.         CUR.func_move = (TMove_Function)Direct_Move_Y;
  1349.       }
  1350.     }
  1351.   }
  1352.  
  1353.   /* at small sizes, F_dot_P can become too small, resulting */
  1354.   /* in overflows and 'spikes' in a number of glyfs like 'w' */
  1355.  
  1356.   if (ABS(CUR.F_dot_P) < 0x4000000L)
  1357.     CUR.F_dot_P = 0x40000000L;
  1358.  
  1359. }
  1360.  
  1361.  
  1362. /**************************************************/
  1363. /*                                                */
  1364. /* Normalize :  Normer un vecteur ( U, V )        */
  1365. /*              rsultat dans     ( X, Y )        */
  1366. /*              False si vecteur paramtre nul    */
  1367. /*                                                */
  1368. /**************************************************/
  1369.  
  1370. static Bool Normalize( EXEC_OPS TT_F26Dot6 U, TT_F26Dot6 V, TT_UnitVector *R)
  1371. {
  1372.   TT_F26Dot6 W;
  1373.   Bool S1, S2;
  1374.  
  1375.   if (ABS(U) < 0x10000L && ABS(V) < 0x10000L)
  1376.   {
  1377.     U *= 0x100;    /* from DavidT 05n2.diff */
  1378.     V *= 0x100;
  1379.  
  1380.     W = Norm(U, V);
  1381.     if (W == 0) 
  1382.     {
  1383.       CUR.error = TT_Err_Divide_By_Zero;
  1384.       return FAILURE;
  1385.     }
  1386.  
  1387.     R->x = (TT_F2Dot14)MulDiv(U, 0x4000L, W);
  1388.     R->y = (TT_F2Dot14)MulDiv(V, 0x4000L, W);
  1389.  
  1390.     return SUCCESS;
  1391.   }
  1392.  
  1393.   W = Norm(U, V);
  1394.  
  1395.   if (W <= 0)
  1396.   {
  1397.     CUR.error = TT_Err_Divide_By_Zero;
  1398.     return FAILURE;
  1399.   }
  1400.     
  1401.   U = MulDiv(U, 0x4000L, W);
  1402.   V = MulDiv(V, 0x4000L, W);
  1403.  
  1404.   W = U * U + V * V;
  1405.  
  1406.   /* Now, we want that Sqrt( W ) = $4000 */
  1407.   /* Or $1000000 <= W < $1004000         */
  1408.  
  1409.   if (U < 0)
  1410.   {
  1411.     U = -U;
  1412.     S1 = TRUE;
  1413.   }
  1414.   else
  1415.     S1 = FALSE;
  1416.  
  1417.   if (V < 0)
  1418.   {
  1419.     V = -V;
  1420.     S2 = TRUE;
  1421.   }
  1422.   else
  1423.     S2 = FALSE;
  1424.  
  1425.   while (W < 0x1000000L)
  1426.   {
  1427.     /* We need to increase W, by a minimal amount */
  1428.     if (U < V)
  1429.       U++;
  1430.     else
  1431.       V++;
  1432.     W = U * U + V * V;
  1433.   }
  1434.  
  1435.   while (W >= 0x1004000L)
  1436.   {
  1437.     /* We need to decrease W, by a minimal amount */
  1438.     if (U < V)
  1439.       U--;
  1440.     else
  1441.       V--;
  1442.     W = U * U + V * V;
  1443.   }
  1444.  
  1445.   /* Note that in various cases, we can only */
  1446.   /* compute a Sqrt(W) of $3FFF, eg. U=V     */
  1447.  
  1448.   if (S1)
  1449.     U = -U;
  1450.  
  1451.   if (S2)
  1452.     V = -V;
  1453.  
  1454.   R->x = (TT_F2Dot14)U;   /* Type conversion */
  1455.   R->y = (TT_F2Dot14)V;   /* Type conversion */
  1456.  
  1457.   return SUCCESS;
  1458. }
  1459.  
  1460.  
  1461. /****************************************************************/
  1462. /*                                                              */
  1463. /* MANAGING THE STACK                                           */
  1464. /*                                                              */
  1465. /*  Instructions appear in the specs' order                     */
  1466. /*                                                              */
  1467. /****************************************************************/
  1468.  
  1469. /*******************************************/
  1470. /* DUP[]     : Duplicate top stack element */
  1471. /* CodeRange : $20                         */
  1472.  
  1473. static void Ins_DUP( INS_ARG )
  1474. {
  1475.   args[1] = args[0];
  1476. }
  1477.  
  1478. /*******************************************/
  1479. /* POP[]     : POPs the stack's top elt.   */
  1480. /* CodeRange : $21                         */
  1481.  
  1482. static void Ins_POP( INS_ARG )
  1483. {
  1484.   /* nothing to do */
  1485. }
  1486.  
  1487. /*******************************************/
  1488. /* CLEAR[]   : Clear the entire stack      */
  1489. /* CodeRange : $22                         */
  1490.  
  1491. static void Ins_CLEAR( INS_ARG )
  1492. {
  1493.   CUR.new_top = 0;
  1494. }
  1495.  
  1496. /*******************************************/
  1497. /* SWAP[]    : Swap the top two elements   */
  1498. /* CodeRange : $23                         */
  1499.  
  1500. static void Ins_SWAP( INS_ARG )
  1501. {
  1502.   Long L;
  1503.  
  1504.   L       = args[0];
  1505.   args[0] = args[1];
  1506.   args[1] = L;
  1507. }
  1508.  
  1509. /*******************************************/
  1510. /* DEPTH[]   : return the stack depth      */
  1511. /* CodeRange : $24                         */
  1512.  
  1513. static void Ins_DEPTH( INS_ARG )
  1514. {
  1515.   args[0] = CUR.top;
  1516. }
  1517.  
  1518. /*******************************************/
  1519. /* CINDEX[]  : copy indexed element        */
  1520. /* CodeRange : $25                         */
  1521.  
  1522. static void Ins_CINDEX( INS_ARG )
  1523. {
  1524.   Long L;
  1525.  
  1526.   L = args[0];
  1527.  
  1528.   if ( (unsigned)L > CUR.args )
  1529.     CUR.error = TT_Err_Invalid_Reference;
  1530.   else
  1531.     args[0] = CUR.stack[CUR.args - L];
  1532. }
  1533.  
  1534.  
  1535. /*******************************************/
  1536. /* MINDEX[]  : move indexed element        */
  1537. /* CodeRange : $26                         */
  1538.  
  1539. static void Ins_MINDEX( INS_ARG )
  1540. {
  1541.   Long L, K;
  1542.  
  1543.   L = args[0];
  1544.   if ( (unsigned)L > CUR.args)
  1545.   {
  1546.     CUR.error = TT_Err_Invalid_Reference;
  1547.     return;
  1548.   }
  1549.     
  1550.   K = CUR.stack[CUR.args - L];
  1551.  
  1552.   MEM_Copy( (&CUR.stack[ CUR.args-L   ]),
  1553.             (&CUR.stack[ CUR.args-L+1 ]),
  1554.             ( L-1 ) * sizeof(Long));
  1555.  
  1556.   CUR.stack[ CUR.args-1 ] = K;
  1557. }
  1558.  
  1559.  
  1560. /*******************************************/
  1561. /* ROLL[]    : roll top three elements     */
  1562. /* CodeRange : $8A                         */
  1563.  
  1564. static void Ins_ROLL( INS_ARG )
  1565. {
  1566.   Long A, B, C;
  1567.  
  1568.   A = args[2];
  1569.   B = args[1];
  1570.   C = args[0];
  1571.  
  1572.   args[2] = C;
  1573.   args[1] = A;
  1574.   args[0] = B;
  1575. }
  1576.  
  1577.  
  1578. /****************************************************************/
  1579. /*                                                              */
  1580. /* MANAGING THE FLOW OF CONTROL                                 */
  1581. /*                                                              */
  1582. /*  Instructions appear in the specs' order                     */
  1583. /*                                                              */
  1584. /****************************************************************/
  1585.  
  1586. static Bool SkipCode( EXEC_OP )
  1587. {
  1588.   CUR.IP += CUR.length;
  1589.  
  1590.   if ( CUR.IP < CUR.codeSize )
  1591.     if ( CALC_Length() == SUCCESS )
  1592.       return SUCCESS;
  1593.  
  1594.   CUR.error = TT_Err_Code_Overflow;
  1595.   return FAILURE;
  1596. }
  1597.  
  1598.  
  1599. /*******************************************/
  1600. /* IF[]      : IF test                     */
  1601. /* CodeRange : $58                         */
  1602.  
  1603. static void Ins_IF( INS_ARG )
  1604. {
  1605.   Int nIfs;
  1606.   Bool Out;
  1607.  
  1608.   if (args[0] != 0)
  1609.     return;
  1610.  
  1611.   nIfs = 1;
  1612.   Out = 0;
  1613.  
  1614.   do 
  1615.   {
  1616.     if ( SKIP_Code() == FAILURE )
  1617.       return;
  1618.  
  1619.     switch (CUR.opcode)
  1620.     {
  1621.       case 0x58:      /* IF */
  1622.         nIfs++;
  1623.         break;
  1624.   
  1625.       case 0x1b:      /* ELSE */
  1626.         Out = (nIfs == 1);
  1627.         break;
  1628.   
  1629.       case 0x59:      /* EIF */
  1630.         nIfs--;
  1631.         Out = (nIfs == 0);
  1632.         break;
  1633.     }
  1634.  
  1635.   } while ( Out == 0 );
  1636.  
  1637. }
  1638.  
  1639.  
  1640. /*******************************************/
  1641. /* ELSE[]    : ELSE                        */
  1642. /* CodeRange : $1B                         */
  1643.  
  1644. static void Ins_ELSE( INS_ARG )
  1645. {
  1646.   Int nIfs;
  1647.  
  1648.   nIfs = 1;
  1649.  
  1650.   do 
  1651.   {
  1652.     if ( SKIP_Code() == FAILURE )
  1653.       return;
  1654.  
  1655.     switch (CUR.opcode) 
  1656.     {
  1657.       case 0x58:    /* IF */
  1658.         nIfs++;
  1659.         break;
  1660.   
  1661.       case 0x59:    /* EIF */
  1662.         nIfs--;
  1663.         break;
  1664.     }
  1665.  
  1666.   } while ( nIfs != 0 );
  1667.  
  1668. }
  1669.  
  1670.  
  1671. /*******************************************/
  1672. /* EIF[]     : End IF                      */
  1673. /* CodeRange : $59                         */
  1674.  
  1675. static void Ins_EIF( INS_ARG )
  1676. {
  1677.   /* nothing to do */
  1678. }
  1679.  
  1680.  
  1681. /*******************************************/
  1682. /* JROT[]    : Jump Relative On True       */
  1683. /* CodeRange : $78                         */
  1684.  
  1685. static void Ins_JROT( INS_ARG )
  1686. {
  1687.   if (args[1] != 0)
  1688.   {
  1689.     CUR.IP      += (Int)(args[0]);
  1690.     CUR.step_ins = FALSE;
  1691.   }
  1692. }
  1693.  
  1694.  
  1695. /*******************************************/
  1696. /* JMPR[]    : JuMP Relative               */
  1697. /* CodeRange : $1C                         */
  1698.  
  1699. static void Ins_JMPR( INS_ARG )
  1700. {
  1701.   CUR.IP      += (Int)(args[0]);
  1702.   CUR.step_ins = FALSE;
  1703. }
  1704.  
  1705.  
  1706. /*******************************************/
  1707. /* JROF[]    : Jump Relative On False      */
  1708. /* CodeRange : $79                         */
  1709.  
  1710. static void Ins_JROF( INS_ARG )
  1711. {
  1712.   if (args[1] == 0)
  1713.     {
  1714.     CUR.IP      += (Int)(args[0]);
  1715.     CUR.step_ins = FALSE;
  1716.     }
  1717. }
  1718.  
  1719.  
  1720. /****************************************************************/
  1721. /*                                                              */
  1722. /* LOGICAL FUNCTIONS                                            */
  1723. /*                                                              */
  1724. /*  Instructions appear in the specs' order                     */
  1725. /*                                                              */
  1726. /****************************************************************/
  1727.  
  1728. /*******************************************/
  1729. /* LT[]      : Less Than                   */
  1730. /* CodeRange : $50                         */
  1731.  
  1732. static void Ins_LT( INS_ARG )
  1733. {
  1734.   if (args[0] < args[1])
  1735.     args[0] = 1;
  1736.   else
  1737.     args[0] = 0;
  1738. }
  1739.  
  1740. /*******************************************/
  1741. /* LTEQ[]    : Less Than or EQual          */
  1742. /* CodeRange : $51                         */
  1743.  
  1744. static void Ins_LTEQ( INS_ARG )
  1745. {
  1746.   if (args[0] <= args[1])
  1747.     args[0] = 1;
  1748.   else
  1749.     args[0] = 0;
  1750. }
  1751.  
  1752. /*******************************************/
  1753. /* GT[]      : Greater Than                */
  1754. /* CodeRange : $52                         */
  1755.  
  1756. static void Ins_GT( INS_ARG )
  1757. {
  1758.   if (args[0] > args[1])
  1759.     args[0] = 1;
  1760.   else
  1761.     args[0] = 0;
  1762. }
  1763.  
  1764. /*******************************************/
  1765. /* GTEQ[]    : Greater Than or EQual       */
  1766. /* CodeRange : $53                         */
  1767.  
  1768. static void Ins_GTEQ( INS_ARG )
  1769. {
  1770.   if (args[0] >= args[1])
  1771.     args[0] = 1;
  1772.   else
  1773.     args[0] = 0;
  1774. }
  1775.  
  1776. /*******************************************/
  1777. /* EQ[]      : EQual                       */
  1778. /* CodeRange : $54                         */
  1779.  
  1780. static void Ins_EQ( INS_ARG )
  1781. {
  1782.   if (args[0] == args[1])
  1783.     args[0] = 1;
  1784.   else
  1785.     args[0] = 0;
  1786. }
  1787.  
  1788. /*******************************************/
  1789. /* NEQ[]     : Not EQual                   */
  1790. /* CodeRange : $55                         */
  1791.  
  1792. static void Ins_NEQ( INS_ARG )
  1793. {
  1794.   if (args[0] != args[1])
  1795.     args[0] = 1;
  1796.   else
  1797.     args[0] = 0;
  1798. }
  1799.  
  1800. /*******************************************/
  1801. /* ODD[]     : Odd                         */
  1802. /* CodeRange : $56                         */
  1803. static void Ins_ODD( INS_ARG )
  1804. {
  1805.    if((CUR_Func_round( args[0], 0L) & 127) == 64)
  1806.      args[0] = 1;
  1807.    else
  1808.      args[0] = 0;
  1809. }
  1810.  
  1811. /*******************************************/
  1812. /* EVEN[]    : Even                        */
  1813. /* CodeRange : $57                         */
  1814. static void Ins_EVEN( INS_ARG )
  1815. {
  1816.   if((CUR_Func_round( args[0], 0L) & 127) == 0)
  1817.     args[0] = 1;
  1818.   else
  1819.     args[0] = 0;
  1820. }
  1821.  
  1822. /*******************************************/
  1823. /* AND[]     : logical AND                 */
  1824. /* CodeRange : $5A                         */
  1825.  
  1826. static void Ins_AND( INS_ARG )
  1827. {
  1828.   if (args[0] != 0 && args[1] != 0)
  1829.     args[0] = 1;
  1830.   else
  1831.     args[0] = 0;
  1832. }
  1833.  
  1834. /*******************************************/
  1835. /* OR[]      : logical OR                  */
  1836. /* CodeRange : $5B                         */
  1837.  
  1838. static void Ins_OR( INS_ARG )
  1839. {
  1840.   if (args[0] != 0 || args[1] != 0)
  1841.     args[0] = 1;
  1842.   else
  1843.     args[0] = 0;
  1844. }
  1845.  
  1846. /*******************************************/
  1847. /* NOT[]     : logical NOT                 */
  1848. /* CodeRange : $5C                         */
  1849.  
  1850. static void Ins_NOT( INS_ARG )
  1851. {
  1852.   if (args[0] != 0)
  1853.     args[0] = 0;
  1854.   else
  1855.     args[0] = 1;
  1856. }
  1857.  
  1858. /****************************************************************/
  1859. /*                                                              */
  1860. /* ARITHMETIC AND MATH INSTRUCTIONS                             */
  1861. /*                                                              */
  1862. /*  Instructions appear in the specs' order                     */
  1863. /*                                                              */
  1864. /****************************************************************/
  1865.  
  1866. /*******************************************/
  1867. /* ADD[]     : ADD                         */
  1868. /* CodeRange : $60                         */
  1869.  
  1870. static void Ins_ADD( INS_ARG )
  1871. {
  1872.   args[0] += args[1];
  1873. }
  1874.  
  1875. /*******************************************/
  1876. /* SUB[]     : SUBstract                   */
  1877. /* CodeRange : $61                         */
  1878.  
  1879. static void Ins_SUB( INS_ARG )
  1880. {
  1881.   args[0] -= args[1];
  1882. }
  1883.  
  1884. /*******************************************/
  1885. /* DIV[]     : DIVide                      */
  1886. /* CodeRange : $62                         */
  1887.  
  1888. static void Ins_DIV( INS_ARG )
  1889. {
  1890.   if (args[1] == 0) 
  1891.   {
  1892.     CUR.error = TT_Err_Divide_By_Zero;
  1893.     return;
  1894.   }
  1895.  
  1896.   args[0] = MulDiv_Round(args[0], 64L, args[1]);
  1897. }
  1898.  
  1899. /*******************************************/
  1900. /* MUL[]     : MULtiply                    */
  1901. /* CodeRange : $63                         */
  1902.  
  1903. static void Ins_MUL( INS_ARG )
  1904. {
  1905.   args[0] = MulDiv_Round(args[0], args[1], 64L);
  1906. }
  1907.  
  1908. /*******************************************/
  1909. /* ABS[]     : ABSolute value              */
  1910. /* CodeRange : $64                         */
  1911.  
  1912. static void Ins_ABS( INS_ARG )
  1913. {
  1914.   args[0] = ABS(args[0]);
  1915. }
  1916.  
  1917. /*******************************************/
  1918. /* NEG[]     : NEGate                      */
  1919. /* CodeRange : $65                         */
  1920.  
  1921. static void Ins_NEG( INS_ARG )
  1922. {
  1923.   args[0] = -args[0];
  1924. }
  1925.  
  1926. /*******************************************/
  1927. /* FLOOR[]   : FLOOR                       */
  1928. /* CodeRange : $66                         */
  1929.  
  1930. static void Ins_FLOOR( INS_ARG )
  1931. {
  1932.   args[0] &= -64;
  1933. }
  1934.  
  1935. /*******************************************/
  1936. /* CEILING[] : CEILING                     */
  1937. /* CodeRange : $67                         */
  1938.  
  1939. static void Ins_CEILING( INS_ARG )
  1940. {
  1941.   args[0] = (args[0] + 63) & (-64);
  1942. }
  1943.  
  1944. /*******************************************/
  1945. /* MAX[]     : MAXimum                     */
  1946. /* CodeRange : $68                         */
  1947.  
  1948. static void Ins_MAX( INS_ARG )
  1949. {
  1950.   if (args[1] > args[0])
  1951.     args[0] = args[1];
  1952. }
  1953.  
  1954. /*******************************************/
  1955. /* MIN[]     : MINimum                     */
  1956. /* CodeRange : $69                         */
  1957.  
  1958. static void Ins_MIN( INS_ARG )
  1959. {
  1960.   if (args[1] < args[0])
  1961.     args[0] = args[1];
  1962. }
  1963.  
  1964. /****************************************************************/
  1965. /*                                                              */
  1966. /* COMPENSATING FOR THE ENGINE CHARACTERISTICS                  */
  1967. /*                                                              */
  1968. /*  Instructions appear in the specs' order                     */
  1969. /*                                                              */
  1970. /****************************************************************/
  1971.  
  1972. /*******************************************/
  1973. /* ROUND[ab] : ROUND value                 */
  1974. /* CodeRange : $68-$6B                     */
  1975.  
  1976. static void Ins_ROUND( INS_ARG )
  1977. {
  1978.     args[0] = CUR_Func_round( args[0],
  1979.                               CUR.metrics.compensations[ CUR.opcode-0x68 ]);
  1980. }
  1981.  
  1982.  
  1983. /*******************************************/
  1984. /* NROUND[ab]: No ROUNDing of value        */
  1985. /* CodeRange : $6C-$6F                     */
  1986.  
  1987. static void Ins_NROUND( INS_ARG )
  1988. {
  1989.   args[0] = Round_None( EXEC_ARGS
  1990.                         args[0],
  1991.                         CUR.metrics.compensations[ CUR.opcode-0x6C ]);
  1992. }
  1993.  
  1994. /****************************************************************/
  1995. /*                                                              */
  1996. /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS                */
  1997. /*                                                              */
  1998. /*  Instructions appear in the specs' order                     */
  1999. /*                                                              */
  2000. /****************************************************************/
  2001.  
  2002. /*******************************************/
  2003. /* FDEF[]    : Function DEFinition         */
  2004. /* CodeRange : $2C                         */
  2005.  
  2006. static void Ins_FDEF( INS_ARG )
  2007. {
  2008.   TDefRecord *pRec;
  2009.  
  2010.   if ( args[0] < 0 || args[0] >= CUR.numFDefs) 
  2011.   {
  2012.     CUR.error = TT_Err_Invalid_Reference;
  2013.     return;
  2014.   }
  2015.  
  2016.   pRec = &CUR.FDefs[args[0]];
  2017.  
  2018.   pRec->Range  = CUR.curRange;
  2019.   pRec->Opc    = (Byte)(args[0]);
  2020.   pRec->Start  = CUR.IP + 1;
  2021.   pRec->Active = TRUE;
  2022.   
  2023.   /* now skip the whole function definition */
  2024.   /* we don't allow nested IDEFS & FDEFs    */
  2025.  
  2026.   while ( SKIP_Code() == SUCCESS ) 
  2027.   {
  2028.     switch (CUR.opcode)
  2029.     {
  2030.       case 0x89:    /* IDEF */
  2031.       case 0x2c:    /* FDEF */
  2032.         CUR.error = TT_Err_Nested_DEFS;
  2033.         return;
  2034.   
  2035.       case 0x2d:   /* ENDF */
  2036.         return;
  2037.     }
  2038.   }
  2039.  
  2040. }
  2041.  
  2042. /*******************************************/
  2043. /* ENDF[]    : END Function definition     */
  2044. /* CodeRange : $2D                         */
  2045.  
  2046. static void Ins_ENDF( INS_ARG )
  2047. {
  2048.   TCallRecord *pRec;
  2049.  
  2050.   if (CUR.callTop <= 0) {   /* We encountered an ENDF without a call */
  2051.     CUR.error = TT_Err_ENDF_In_Exec_Stream;
  2052.     return;
  2053.   }
  2054.  
  2055.   CUR.callTop--;
  2056.  
  2057.   pRec = &CUR.callStack[CUR.callTop];
  2058.  
  2059.   pRec->Cur_Count--;
  2060.  
  2061.   CUR.step_ins = FALSE;
  2062.  
  2063.   if (pRec->Cur_Count > 0)
  2064.   {
  2065.     CUR.callTop++;
  2066.     CUR.IP = pRec->Cur_Restart;
  2067.   }
  2068.   else
  2069.     INS_Goto_CodeRange( pRec->Caller_Range, 
  2070.                         pRec->Caller_IP );
  2071.  
  2072.   /* Loop the current function */
  2073.  
  2074.  
  2075.   /* exit the current call frame                      */
  2076.   /* NOTE : When the last intruction of a program     */
  2077.   /*        is a CALL or LOOPCALL, the return address */
  2078.   /*        is always out of the code range. This is  */
  2079.   /*        valid address, and  is why we do not test */
  2080.   /*        the result of Ins_Goto_CodeRange here !!      */
  2081.  
  2082. }
  2083.  
  2084.  
  2085. /*******************************************/
  2086. /* CALL[]    : CALL function               */
  2087. /* CodeRange : $2B                         */
  2088.  
  2089. static void Ins_CALL( INS_ARG )
  2090. {
  2091.   TCallRecord *pCrec;
  2092.  
  2093.   if ( args[0] < 0 || args[0] >= CUR.numFDefs ||
  2094.        !CUR.FDefs[args[0]].Active) 
  2095.   {
  2096.     CUR.error = TT_Err_Invalid_Reference;
  2097.     return;
  2098.   }
  2099.  
  2100.   if (CUR.callTop >= CUR.callSize) 
  2101.   {
  2102.     CUR.error = TT_Err_Stack_Overflow;
  2103.     return;
  2104.   }
  2105.  
  2106.   pCrec = &CUR.callStack[CUR.callTop];
  2107.  
  2108.   pCrec->Caller_Range = CUR.curRange;
  2109.   pCrec->Caller_IP    = CUR.IP + 1;
  2110.   pCrec->Cur_Count    = 1;
  2111.   pCrec->Cur_Restart  = CUR.FDefs[args[0]].Start;
  2112.  
  2113.   CUR.callTop++;
  2114.  
  2115.   INS_Goto_CodeRange( CUR.FDefs[args[0]].Range,
  2116.                       CUR.FDefs[args[0]].Start);
  2117.  
  2118.   CUR.step_ins = FALSE;
  2119. }
  2120.  
  2121.  
  2122. /*******************************************/
  2123. /* LOOPCALL[]: LOOP and CALL function      */
  2124. /* CodeRange : $2A                         */
  2125.  
  2126. static void Ins_LOOPCALL( INS_ARG )
  2127. {
  2128.   TCallRecord *pTCR;
  2129.  
  2130.   if ( args[1] < 0 || args[1] >= CUR.numFDefs ||
  2131.        !CUR.FDefs[args[1]].Active)
  2132.   {
  2133.     CUR.error = TT_Err_Invalid_Reference;
  2134.     return;
  2135.   }
  2136.  
  2137.   if (CUR.callTop >= CUR.callSize) 
  2138.   {
  2139.     CUR.error = TT_Err_Stack_Overflow;
  2140.     return;
  2141.   }
  2142.  
  2143.   if (args[0] > 0) 
  2144.   {
  2145.     pTCR = &CUR.callStack[CUR.callTop];
  2146.   
  2147.     pTCR->Caller_Range = CUR.curRange;
  2148.     pTCR->Caller_IP    = CUR.IP + 1;
  2149.     pTCR->Cur_Count    = (Int)(args[0]);
  2150.     pTCR->Cur_Restart  = CUR.FDefs[args[1]].Start;
  2151.   
  2152.     CUR.callTop++;
  2153.   
  2154.     INS_Goto_CodeRange( CUR.FDefs[args[1]].Range, 
  2155.                         CUR.FDefs[args[1]].Start );
  2156.   
  2157.     CUR.step_ins = FALSE;
  2158.   }
  2159. }
  2160.  
  2161.  
  2162. /*******************************************/
  2163. /* IDEF[]    : Instruction DEFinition      */
  2164. /* CodeRange : $89                         */
  2165.  
  2166. static void Ins_IDEF( INS_ARG )
  2167. {
  2168.   Int A;
  2169.   TDefRecord *pTDR;
  2170.  
  2171.   A = 0;
  2172.  
  2173.   while (A < CUR.numIDefs) 
  2174.   {
  2175.     pTDR = &CUR.IDefs[A];
  2176.  
  2177.     if ( pTDR->Active == 0 ) 
  2178.     {
  2179.       pTDR->Opc    = (Byte)(args[0]);
  2180.       pTDR->Start  = CUR.IP + 1;
  2181.       pTDR->Range  = CUR.curRange;
  2182.       pTDR->Active = TRUE;
  2183.   
  2184.       A = CUR.numIDefs;
  2185.   
  2186.       /* now skip the whole function definition */
  2187.       /* we don't allow nested IDEFS & FDEFs    */
  2188.   
  2189.       while ( SKIP_Code() == SUCCESS ) 
  2190.       {
  2191.         switch (CUR.opcode)
  2192.         {
  2193.           case 0x89:   /* IDEF */
  2194.           case 0x2c:   /* FDEF */
  2195.             CUR.error = TT_Err_Nested_DEFS;
  2196.             return;
  2197.           case 0x2d:   /* ENDF */
  2198.             return;
  2199.         }
  2200.       }
  2201.     }
  2202.     else
  2203.         A++;
  2204.   }
  2205. }
  2206.  
  2207. /****************************************************************/
  2208. /*                                                              */
  2209. /* PUSHING DATA ONTO THE INTERPRETER STACK                      */
  2210. /*                                                              */
  2211. /*  Instructions appear in the specs' order                     */
  2212. /*                                                              */
  2213. /****************************************************************/
  2214.  
  2215. /*******************************************/
  2216. /* NPUSHB[]  : PUSH N Bytes                */
  2217. /* CodeRange : $40                         */
  2218.  
  2219. static void Ins_NPUSHB( INS_ARG )
  2220. {
  2221.   Int L, K;
  2222.  
  2223.   L = (Int)CUR.code[ CUR.IP+1 ];
  2224.  
  2225.   if (CUR.top + L > CUR.stackSize) 
  2226.   {
  2227.     CUR.error = TT_Err_Stack_Overflow;
  2228.     return;
  2229.   }
  2230.  
  2231.   for (K = 1; K <= L; K++)
  2232.     args[ K-1 ] = CUR.code[ CUR.IP+K+1 ];
  2233.  
  2234.   CUR.new_top += L;
  2235. }
  2236.  
  2237.  
  2238. /*******************************************/
  2239. /* NPUSHW[]  : PUSH N Words                */
  2240. /* CodeRange : $41                         */
  2241.  
  2242. static void Ins_NPUSHW( INS_ARG )
  2243. {
  2244.   Int L, K;
  2245.  
  2246.   L = (Int)CUR.code[ CUR.IP+1 ];
  2247.  
  2248.   if ( CUR.top+L > CUR.stackSize )
  2249.   {
  2250.      CUR.error = TT_Err_Stack_Overflow;
  2251.      return;
  2252.   }
  2253.  
  2254.   CUR.IP += 2;
  2255.  
  2256.   for (K = 0; K < L; K++)
  2257.     args[K] = GET_ShortIns();
  2258.  
  2259.   CUR.step_ins = FALSE;
  2260.  
  2261.   CUR.new_top += L;
  2262. }
  2263.  
  2264.  
  2265. /*******************************************/
  2266. /* PUSHB[abc]: PUSH Bytes                  */
  2267. /* CodeRange : $B0-$B7                     */
  2268.  
  2269. static void Ins_PUSHB( INS_ARG )
  2270. {
  2271.   Int L, K;
  2272.  
  2273.   L = ((Int)CUR.opcode - 0xB0 + 1);
  2274.  
  2275.   if ( CUR.top+L > CUR.stackSize ) 
  2276.   {
  2277.     CUR.error = TT_Err_Stack_Overflow;
  2278.     return;
  2279.   }
  2280.  
  2281.   for (K = 1; K <= L; K++)
  2282.     args[ K-1 ] = CUR.code[ CUR.IP+K ];
  2283.  
  2284. }
  2285.  
  2286.  
  2287. /*******************************************/
  2288. /* PUSHW[abc]: PUSH Words                  */
  2289. /* CodeRange : $B8-$BF                     */
  2290.  
  2291. static void Ins_PUSHW( INS_ARG )
  2292. {
  2293.   Int L, K;
  2294.  
  2295.   L = CUR.opcode - 0xB8 + 1;
  2296.  
  2297.   if ( CUR.top+L > CUR.stackSize ) 
  2298.   {
  2299.     CUR.error = TT_Err_Stack_Overflow;
  2300.     return;
  2301.   }
  2302.  
  2303.   CUR.IP++;
  2304.  
  2305.   for (K = 0; K < L; K++)
  2306.     args[K] = GET_ShortIns();
  2307.  
  2308.   CUR.step_ins = FALSE;
  2309.  
  2310. }
  2311.  
  2312.  
  2313. /****************************************************************/
  2314. /*                                                              */
  2315. /* MANAGING THE STORAGE AREA                                    */
  2316. /*                                                              */
  2317. /*  Instructions appear in the specs' order                     */
  2318. /*                                                              */
  2319. /****************************************************************/
  2320.  
  2321. /*******************************************/
  2322. /* RS[]      : Read Store                  */
  2323. /* CodeRange : $43                         */
  2324.  
  2325. static void Ins_RS( INS_ARG )
  2326. {
  2327.   if ((unsigned)args[0] >= CUR.storeSize) 
  2328.   {
  2329.     CUR.error = TT_Err_Invalid_Reference;
  2330.     return;
  2331.   }
  2332.  
  2333.   args[0] = CUR.storage[args[0]];
  2334. }
  2335.  
  2336.  
  2337. /*******************************************/
  2338. /* WS[]      : Write Store                 */
  2339. /* CodeRange : $42                         */
  2340.  
  2341. static void Ins_WS( INS_ARG )
  2342. {
  2343.   if ( (unsigned)args[0] >= CUR.storeSize ) 
  2344.   {
  2345.     CUR.error = TT_Err_Invalid_Reference;
  2346.     return;
  2347.   }
  2348.   CUR.storage[args[0]] = args[1];
  2349. }
  2350.  
  2351.  
  2352. /*******************************************/
  2353. /* WCVTP[]   : Write CVT in Pixel units    */
  2354. /* CodeRange : $44                         */
  2355.  
  2356. static void Ins_WCVTP( INS_ARG )
  2357. {
  2358.   if ( (unsigned)args[0] >= CUR.cvtSize ) 
  2359.   {
  2360.     CUR.error = TT_Err_Invalid_Reference;
  2361.     return;
  2362.   }
  2363.  
  2364.   CUR.cvt[args[0]] = args[1];
  2365. }
  2366.  
  2367.  
  2368. /*******************************************/
  2369. /* WCVTF[]   : Write CVT in FUnits         */
  2370. /* CodeRange : $70                         */
  2371.  
  2372. static void Ins_WCVTF( INS_ARG )
  2373. {
  2374.   if ( (unsigned)args[0] >= CUR.cvtSize )
  2375.   {
  2376.     CUR.error = TT_Err_Invalid_Reference;
  2377.     return;
  2378.   }
  2379.  
  2380.   CUR.cvt[args[0]] = MulDiv_Round(args[1], CUR.scale1, CUR.scale2);
  2381. }
  2382.  
  2383.  
  2384. /*******************************************/
  2385. /* RCVT[]    : Read CVT                    */
  2386. /* CodeRange : $45                         */
  2387.  
  2388. static void Ins_RCVT( INS_ARG )
  2389. {
  2390.   if ( (unsigned)args[0] >= CUR.cvtSize)
  2391.   {
  2392.     CUR.error = TT_Err_Invalid_Reference;
  2393.     return;
  2394.   }
  2395.  
  2396.   args[0] = CUR.cvt[args[0]];
  2397. }
  2398.  
  2399.  
  2400. /****************************************************************/
  2401. /*                                                              */
  2402. /* MANAGING THE GRAPHICS STATE                                  */
  2403. /*                                                              */
  2404. /*  Instructions appear in the specs' order                     */
  2405. /*                                                              */
  2406. /****************************************************************/
  2407.  
  2408. /*******************************************/
  2409. /* SVTCA[a]  : Set F and P vectors to axis */
  2410. /* CodeRange : $00-$01                     */
  2411.  
  2412. static void Ins_SVTCA( INS_ARG )
  2413. {
  2414.   Short A, B;
  2415.  
  2416.   if (CUR.opcode & 1)
  2417.       A = 0x4000;
  2418.   else
  2419.       A = 0;
  2420.  
  2421.   B = A ^ 0x4000;
  2422.  
  2423.   CUR.GS.freeVector.x = A;
  2424.   CUR.GS.projVector.x = A;
  2425.   CUR.GS.dualVector.x = A;
  2426.  
  2427.   CUR.GS.freeVector.y = B;
  2428.   CUR.GS.projVector.y = B;
  2429.   CUR.GS.dualVector.y = B;
  2430.  
  2431.   COMPUTE_Funcs();
  2432. }
  2433.  
  2434.  
  2435. /*******************************************/
  2436. /* SPVTCA[a] : Set PVector to Axis         */
  2437. /* CodeRange : $02-$03                     */
  2438.  
  2439. static void Ins_SPVTCA( INS_ARG )
  2440. {
  2441.   Short A, B;
  2442.  
  2443.   if (CUR.opcode & 1)
  2444.     A = 0x4000;
  2445.   else
  2446.     A = 0;
  2447.  
  2448.   B = A ^ 0x4000;
  2449.  
  2450.   CUR.GS.projVector.x = A;
  2451.   CUR.GS.dualVector.x = A;
  2452.  
  2453.   CUR.GS.projVector.y = B;
  2454.   CUR.GS.dualVector.y = B;
  2455.  
  2456.   COMPUTE_Funcs();
  2457. }
  2458.  
  2459.  
  2460. /*******************************************/
  2461. /* SFVTCA[a] : Set FVector to Axis         */
  2462. /* CodeRange : $04-$05                     */
  2463. static void Ins_SFVTCA( INS_ARG )
  2464. {
  2465.   Short A, B;
  2466.   if (CUR.opcode & 1)
  2467.     A = 0x4000;
  2468.   else
  2469.     A = 0;
  2470.  
  2471.   B = A ^ 0x4000;
  2472.  
  2473.   CUR.GS.freeVector.x = A;
  2474.   CUR.GS.freeVector.y = B;
  2475.  
  2476.   COMPUTE_Funcs();
  2477. }
  2478.  
  2479.  
  2480.  
  2481. static Bool Ins_SxVTL( EXEC_OPS  Int            aIdx1, 
  2482.                                  Int            aIdx2, 
  2483.                                  Int            aOpc,
  2484.                                  TT_UnitVector *Vec)
  2485. {
  2486.   Long A, B, C;
  2487.  
  2488.   if ( (unsigned)aIdx2 >= CUR.zp1.n || 
  2489.        (unsigned)aIdx1 >= CUR.zp2.n )
  2490.   {
  2491.     CUR.error = TT_Err_Invalid_Reference;
  2492.     return FAILURE;
  2493.   }
  2494.  
  2495.   A = CUR.zp1.cur_x[aIdx2] - CUR.zp2.cur_x[aIdx1];
  2496.   B = CUR.zp1.cur_y[aIdx2] - CUR.zp2.cur_y[aIdx1];
  2497.  
  2498.   if ((aOpc & 1) != 0)
  2499.   {
  2500.     C =  B;   /* CounterClockwise rotation */
  2501.     B =  A;
  2502.     A = -C;
  2503.   }
  2504.  
  2505.   if ( NORMalize(A, B, Vec) == FAILURE )
  2506.   {
  2507.     /* When the vector is too small, or zero ! */
  2508.  
  2509.     CUR.error = TT_Err_Ok;
  2510.     Vec->x = 0x4000;
  2511.     Vec->y = 0;
  2512.   }
  2513.  
  2514.   return SUCCESS;
  2515.  
  2516. }
  2517.  
  2518.  
  2519. /*******************************************/
  2520. /* SPVTL[a]  : Set PVector to Line         */
  2521. /* CodeRange : $06-$07                     */
  2522.  
  2523. static void Ins_SPVTL( INS_ARG )
  2524. {
  2525.   if ( INS_SxVTL( args[1],
  2526.                   args[0],
  2527.                   CUR.opcode,
  2528.                   &CUR.GS.projVector) == FAILURE )
  2529.     return;
  2530.  
  2531.   CUR.GS.dualVector = CUR.GS.projVector;
  2532.   COMPUTE_Funcs();
  2533. }
  2534.  
  2535.  
  2536. /*******************************************/
  2537. /* SFVTL[a]  : Set FVector to Line         */
  2538. /* CodeRange : $08-$09                     */
  2539.  
  2540. static void Ins_SFVTL( INS_ARG )
  2541. {
  2542.   if ( INS_SxVTL( (Int)(args[1]),
  2543.                   (Int)(args[0]),
  2544.                   CUR.opcode,
  2545.                   &CUR.GS.freeVector) == FAILURE )
  2546.     return;
  2547.  
  2548.   COMPUTE_Funcs();
  2549. }
  2550.  
  2551.  
  2552. /*******************************************/
  2553. /* SFVTPV[]  : Set FVector to PVector      */
  2554. /* CodeRange : $0E                         */
  2555.  
  2556. static void Ins_SFVTPV( INS_ARG )
  2557. {
  2558.   CUR.GS.freeVector = CUR.GS.projVector;
  2559.   COMPUTE_Funcs();
  2560. }
  2561.  
  2562.  
  2563. /*******************************************/
  2564. /* SDPVTL[a] : Set Dual PVector to Line    */
  2565. /* CodeRange : $86-$87                     */
  2566.  
  2567. static void Ins_SDPVTL( INS_ARG )
  2568. {
  2569.   Long A, B, C;
  2570.   Long  p1, p2;    /* was Int in pas type ERROR */
  2571.  
  2572.   p1 = args[1];
  2573.   p2 = args[0];
  2574.  
  2575.   if ( (unsigned)p2 >= CUR.zp1.n ||
  2576.        (unsigned)p1 >= CUR.zp2.n )
  2577.   {
  2578.     CUR.error = TT_Err_Invalid_Reference;
  2579.     return;
  2580.   }
  2581.  
  2582.   A = CUR.zp1.org_x[p2] - CUR.zp2.org_x[p1];
  2583.   B = CUR.zp1.org_y[p2] - CUR.zp2.org_y[p1];
  2584.  
  2585.   if ((CUR.opcode & 1) != 0)
  2586.   {
  2587.     C =  B;   /* CounterClockwise rotation */
  2588.     B =  A;
  2589.     A = -C;
  2590.   }
  2591.  
  2592.   if ( NORMalize( A, B, &CUR.GS.dualVector ) == FAILURE )
  2593.     return;
  2594.  
  2595.   A = CUR.zp1.cur_x[p2] - CUR.zp2.cur_x[p1];
  2596.   B = CUR.zp1.cur_y[p2] - CUR.zp2.cur_y[p1];
  2597.  
  2598.   if ( (CUR.opcode & 1) != 0 )
  2599.   {
  2600.     C =  B;   /* CounterClockwise rotation */
  2601.     B =  A;
  2602.     A = -C;
  2603.   }
  2604.  
  2605.   if ( NORMalize(A, B, &CUR.GS.projVector) == FAILURE )
  2606.     return;
  2607.  
  2608.   COMPUTE_Funcs();
  2609. }
  2610.  
  2611.  
  2612. /*******************************************/
  2613. /* SPVFS[]   : Set PVector From Stack      */
  2614. /* CodeRange : $0A                         */
  2615.  
  2616. static void Ins_SPVFS( INS_ARG )
  2617. {
  2618.   Short S;
  2619.   Long  X, Y;
  2620.     /* Only use low 16bits, then sign extend */
  2621.   S = (Short)args[1];
  2622.   Y = (Long)S;
  2623.   S = (Short)args[0];
  2624.   X = (Long)S;
  2625.   if ( NORMalize(X, Y, &CUR.GS.projVector) == FAILURE )
  2626.     return;
  2627.  
  2628.   CUR.GS.dualVector = CUR.GS.projVector;
  2629.  
  2630.   COMPUTE_Funcs();
  2631. }
  2632.  
  2633.  
  2634. /*******************************************/
  2635. /* SFVFS[]   : Set FVector From Stack      */
  2636. /* CodeRange : $0B                         */
  2637.  
  2638. static void Ins_SFVFS( INS_ARG )
  2639. {
  2640.   Short S;
  2641.   Long X, Y;
  2642.  
  2643.     /* Only use low 16bits, then sign extend */
  2644.   S = (Short)args[1];
  2645.   Y = (Long)S;
  2646.   S = (Short)args[0];
  2647.   X = S;
  2648.  
  2649.   if ( NORMalize(X, Y, &CUR.GS.freeVector) == FAILURE )
  2650.     return;
  2651.  
  2652.   COMPUTE_Funcs();
  2653. }
  2654.  
  2655.  
  2656. /*******************************************/
  2657. /* GPV[]     : Get Projection Vector       */
  2658. /* CodeRange : $0C                         */
  2659.  
  2660. static void Ins_GPV( INS_ARG )
  2661. {
  2662.   args[0] = CUR.GS.projVector.x;
  2663.   args[1] = CUR.GS.projVector.y;
  2664. }
  2665.  
  2666.  
  2667. /*******************************************/
  2668. /* GFV[]     : Get Freedom Vector          */
  2669. /* CodeRange : $0D                         */
  2670.  
  2671. static void Ins_GFV( INS_ARG )
  2672. {
  2673.   args[0] = CUR.GS.freeVector.x;
  2674.   args[1] = CUR.GS.freeVector.y;
  2675. }
  2676.  
  2677.  
  2678. /*******************************************/
  2679. /* SRP0[]    : Set Reference Point 0       */
  2680. /* CodeRange : $10                         */
  2681.  
  2682. static void Ins_SRP0( INS_ARG )
  2683. {
  2684.   CUR.GS.rp0 = (Int)(args[0]);
  2685. }
  2686.  
  2687.  
  2688. /*******************************************/
  2689. /* SRP1[]    : Set Reference Point 1       */
  2690. /* CodeRange : $11                         */
  2691.  
  2692. static void Ins_SRP1( INS_ARG )
  2693. {
  2694.   CUR.GS.rp1 = (Int)(args[0]);
  2695. }
  2696.  
  2697.  
  2698. /*******************************************/
  2699. /* SRP2[]    : Set Reference Point 2       */
  2700. /* CodeRange : $12                         */
  2701.  
  2702. static void Ins_SRP2( INS_ARG )
  2703. {
  2704.   CUR.GS.rp2 = (Int)(args[0]);
  2705. }
  2706.  
  2707.  
  2708. /*******************************************/
  2709. /* SZP0[]    : Set Zone Pointer 0          */
  2710. /* CodeRange : $13                         */
  2711.  
  2712. static void Ins_SZP0( INS_ARG )
  2713. {
  2714.   switch (args[0]) 
  2715.   {
  2716.     case 0:
  2717.       CUR.zp0 = CUR.twilight;
  2718.       break;
  2719.   
  2720.     case 1:
  2721.       CUR.zp0 = CUR.pts;
  2722.       break;
  2723.   
  2724.     default:
  2725.       CUR.error = TT_Err_Invalid_Reference;
  2726.       return;
  2727.       break;
  2728.   }
  2729.  
  2730.   CUR.GS.gep0 = (Int)(args[0]);
  2731. }
  2732.  
  2733.  
  2734. /*******************************************/
  2735. /* SZP1[]    : Set Zone Pointer 1          */
  2736. /* CodeRange : $14                         */
  2737.  
  2738. static void Ins_SZP1( INS_ARG )
  2739. {
  2740.   switch (args[0])
  2741.   {
  2742.     case 0:
  2743.       CUR.zp1 = CUR.twilight;
  2744.       break;
  2745.   
  2746.     case 1:
  2747.       CUR.zp1 = CUR.pts;
  2748.       break;
  2749.   
  2750.     default:
  2751.       CUR.error = TT_Err_Invalid_Reference;
  2752.       return;
  2753.   }
  2754.  
  2755.   CUR.GS.gep1 = (Int)(args[0]);
  2756. }
  2757.  
  2758.  
  2759. /*******************************************/
  2760. /* SZP2[]    : Set Zone Pointer 2          */
  2761. /* CodeRange : $15                         */
  2762.  
  2763. static void Ins_SZP2( INS_ARG )
  2764. {
  2765.   switch (args[0])
  2766.   {
  2767.     case 0:
  2768.       CUR.zp2 = CUR.twilight;
  2769.       break;
  2770.   
  2771.     case 1:
  2772.       CUR.zp2 = CUR.pts;
  2773.       break;
  2774.   
  2775.     default:
  2776.       CUR.error = TT_Err_Invalid_Reference;
  2777.       return;
  2778.   }
  2779.  
  2780.   CUR.GS.gep2 = (Int)(args[0]);
  2781. }
  2782.  
  2783.  
  2784. /*******************************************/
  2785. /* SZPS[]    : Set Zone Pointers           */
  2786. /* CodeRange : $16                         */
  2787.  
  2788. static void Ins_SZPS( INS_ARG )
  2789. {
  2790.   switch (args[0])
  2791.   {
  2792.     case 0:
  2793.       CUR.zp0 = CUR.twilight;
  2794.       break;
  2795.   
  2796.     case 1:
  2797.       CUR.zp0 = CUR.pts;
  2798.       break;
  2799.   
  2800.     default:
  2801.       CUR.error = TT_Err_Invalid_Reference;
  2802.       return;
  2803.   }
  2804.  
  2805.   CUR.zp1 = CUR.zp0;
  2806.   CUR.zp2 = CUR.zp0;
  2807.  
  2808.   CUR.GS.gep0 = (Int)(args[0]);
  2809.   CUR.GS.gep1 = (Int)(args[0]);
  2810.   CUR.GS.gep2 = (Int)(args[0]);
  2811. }
  2812.  
  2813.  
  2814. /*******************************************/
  2815. /* RTHG[]    : Round To Half Grid          */
  2816. /* CodeRange : $19                         */
  2817.  
  2818. static void Ins_RTHG( INS_ARG )
  2819. {
  2820.   CUR.GS.round_state = TT_Round_To_Half_Grid;
  2821.  
  2822.   CUR.func_round = (TRound_Function)Round_To_Half_Grid;
  2823. }
  2824.  
  2825.  
  2826. /*******************************************/
  2827. /* RTG[]     : Round To Grid               */
  2828. /* CodeRange : $18                         */
  2829.  
  2830. static void Ins_RTG( INS_ARG )
  2831. {
  2832.   CUR.GS.round_state = TT_Round_To_Grid;
  2833.  
  2834.   CUR.func_round = (TRound_Function)Round_To_Grid;
  2835. }
  2836.  
  2837.  
  2838. /*******************************************/
  2839. /* RTDG[]    : Round To Double Grid        */
  2840. /* CodeRange : $3D                         */
  2841.  
  2842. static void Ins_RTDG( INS_ARG )
  2843. {
  2844.   CUR.GS.round_state = TT_Round_To_Double_Grid;
  2845.  
  2846.   CUR.func_round = (TRound_Function)Round_To_Double_Grid;
  2847. }
  2848.  
  2849.  
  2850. /*******************************************/
  2851. /* RUTG[]    : Round Up To Grid            */
  2852. /* CodeRange : $7C                         */
  2853.  
  2854. static void Ins_RUTG( INS_ARG )
  2855. {
  2856.   CUR.GS.round_state = TT_Round_Up_To_Grid;
  2857.  
  2858.   CUR.func_round = (TRound_Function)Round_Up_To_Grid;
  2859. }
  2860.  
  2861.  
  2862. /*******************************************/
  2863. /* RDTG[]    : Round Down To Grid          */
  2864. /* CodeRange : $7D                         */
  2865.  
  2866. static void Ins_RDTG( INS_ARG )
  2867. {
  2868.   CUR.GS.round_state = TT_Round_Down_To_Grid;
  2869.  
  2870.   CUR.func_round = (TRound_Function)Round_Down_To_Grid;
  2871. }
  2872.  
  2873.  
  2874. /*******************************************/
  2875. /* ROFF[]    : Round OFF                   */
  2876. /* CodeRange : $7A                         */
  2877.  
  2878. static void Ins_ROFF( INS_ARG )
  2879. {
  2880.   CUR.GS.round_state = TT_Round_Off;
  2881.  
  2882.   CUR.func_round = (TRound_Function)Round_None;
  2883. }
  2884.  
  2885.  
  2886. /*******************************************/
  2887. /* SROUND[]  : Super ROUND                 */
  2888. /* CodeRange : $76                         */
  2889.  
  2890. static void Ins_SROUND( INS_ARG )
  2891. {
  2892.   SET_SuperRound( 0x4000L, args[0] );
  2893.   CUR.GS.round_state = TT_Round_Super;
  2894.  
  2895.   CUR.func_round = (TRound_Function)Round_Super;
  2896. }
  2897.  
  2898.  
  2899. /*******************************************/
  2900. /* S45ROUND[]: Super ROUND 45 degrees      */
  2901. /* CodeRange : $77                         */
  2902.  
  2903. static void Ins_S45ROUND( INS_ARG )
  2904. {
  2905.   SET_SuperRound( 0x00002D41, args[0] );
  2906.   CUR.GS.round_state = TT_Round_Super_45;
  2907.  
  2908.   CUR.func_round = (TRound_Function)Round_Super_45;
  2909. }
  2910.  
  2911.  
  2912. /*******************************************/
  2913. /* SLOOP[]   : Set LOOP variable           */
  2914. /* CodeRange : $17                         */
  2915.  
  2916. static void Ins_SLOOP( INS_ARG )
  2917. {
  2918.   CUR.GS.loop = args[0];
  2919. }
  2920.  
  2921.  
  2922. /*******************************************/
  2923. /* SMD[]     : Set Minimum Distance        */
  2924. /* CodeRange : $1A                         */
  2925.  
  2926. static void Ins_SMD( INS_ARG )
  2927. {
  2928.   CUR.GS.minimum_distance = args[0];
  2929. }
  2930.  
  2931.  
  2932. /*******************************************/
  2933. /* INSTCTRL[]: INSTruction ConTRol         */
  2934. /* CodeRange : $8e                         */
  2935.  
  2936. static void Ins_INSTCTRL( INS_ARG )
  2937. {
  2938.   Long K, L;
  2939.  
  2940.   K = args[1];
  2941.   L = args[0];
  2942.  
  2943.   if (K < 1 || K > 2)
  2944.   {
  2945.     CUR.error = TT_Err_Invalid_Reference;
  2946.     return;
  2947.   }
  2948.  
  2949.   if( L != 0 )
  2950.       L = K;
  2951.  
  2952.   CUR.GS.instruct_control = 
  2953.          (Int)((CUR.GS.instruct_control & (~K)) | L);
  2954. }
  2955.  
  2956.  
  2957. /*******************************************/
  2958. /* SCANCTRL[]: SCAN ConTRol                */
  2959. /* CodeRange : $85                         */
  2960.  
  2961. static void Ins_SCANCTRL( INS_ARG )
  2962. {
  2963.   Int A;
  2964.  
  2965.   /* Get Threshold */
  2966.   A = (Int)(args[0] & 0xFF);
  2967.  
  2968.   if (A == 0xFF)
  2969.   {
  2970.     CUR.GS.scan_control = TRUE;
  2971.     return;
  2972.   }
  2973.   if (A == 0)
  2974.   {
  2975.     CUR.GS.scan_control = FALSE;
  2976.     return;
  2977.   }
  2978.     
  2979.   A *= 64;
  2980.  
  2981.   if ( (args[0] & 0x100) != 0 && CUR.metrics.pointSize <= A)
  2982.     CUR.GS.scan_control = TRUE;
  2983.  
  2984.   if (( (args[0] & 0x200) != 0) && CUR.metrics.rotated )
  2985.     CUR.GS.scan_control = TRUE;
  2986.  
  2987.   if (( (args[0]  & 0x400) != 0) && CUR.metrics.stretched )
  2988.     CUR.GS.scan_control = TRUE;
  2989.  
  2990.   if ( (args[0] & 0x800) != 0 && CUR.metrics.pointSize > A)
  2991.     CUR.GS.scan_control = FALSE;
  2992.  
  2993.   if (( (args[0] & 0x1000) != 0) && CUR.metrics.rotated )
  2994.     CUR.GS.scan_control = FALSE;
  2995.  
  2996.   if (((args[0] & 0x2000) != 0) && CUR.metrics.stretched )
  2997.     CUR.GS.scan_control = FALSE;
  2998.  
  2999. }
  3000.  
  3001.  
  3002. /*******************************************/
  3003. /* SCANTYPE[]: SCAN TYPE                   */
  3004. /* CodeRange : $8D                         */
  3005.  
  3006. static void Ins_SCANTYPE( INS_ARG )
  3007. {
  3008.   /* For compatibility with future enhancements, */
  3009.   /* we must ignore new modes                    */
  3010.  
  3011.   if (args[0] >= 0 && args[0] <= 5)
  3012.   {
  3013.     if (args[0] == 3)
  3014.       args[0] = 2;
  3015.     CUR.GS.scan_type = (Int)args[0];
  3016.   }
  3017. }
  3018.  
  3019.  
  3020. /**********************************************/
  3021. /* SCVTCI[]  : Set Control Value Table Cut In */
  3022. /* CodeRange : $1D                            */
  3023.  
  3024. static void Ins_SCVTCI( INS_ARG )
  3025. {
  3026.   CUR.GS.control_value_cutin = (TT_F26Dot6)args[0];
  3027. }
  3028.  
  3029.  
  3030. /**********************************************/
  3031. /* SSWCI[]   : Set Single Width Cut In        */
  3032. /* CodeRange : $1E                            */
  3033.  
  3034. static void Ins_SSWCI( INS_ARG )
  3035. {
  3036.   CUR.GS.single_width_cutin = (TT_F26Dot6)args[0];
  3037. }
  3038.  
  3039.  
  3040. /**********************************************/
  3041. /* SSW[]     : Set Single Width               */
  3042. /* CodeRange : $1F                            */
  3043.  
  3044. static void Ins_SSW( INS_ARG )
  3045. {
  3046.   CUR.GS.single_width_value = (TT_F26Dot6)args[0];
  3047. }
  3048.  
  3049.  
  3050. /**********************************************/
  3051. /* FLIPON[]  : Set Auto_flip to On            */
  3052. /* CodeRange : $4D                            */
  3053.  
  3054. static void Ins_FLIPON( INS_ARG )
  3055. {
  3056.   CUR.GS.auto_flip = TRUE;
  3057. }
  3058.  
  3059.  
  3060. /**********************************************/
  3061. /* FLIPOFF[] : Set Auto_flip to Off           */
  3062. /* CodeRange : $4E                            */
  3063.  
  3064. static void Ins_FLIPOFF( INS_ARG )
  3065. {
  3066.   CUR.GS.auto_flip = FALSE;
  3067. }
  3068.  
  3069.  
  3070. /**********************************************/
  3071. /* SANGW[]   : Set Angle Weigth               */
  3072. /* CodeRange : $7E                            */
  3073.  
  3074. static void Ins_SANGW( INS_ARG )
  3075. {
  3076.   /* instruction not supported anymore */
  3077. }
  3078.  
  3079.  
  3080. /**********************************************/
  3081. /* SDB[]     : Set Delta Base                 */
  3082. /* CodeRange : $5E                            */
  3083.  
  3084. static void Ins_SDB( INS_ARG )
  3085. {
  3086.   CUR.GS.delta_base = (Int)args[0];
  3087. }
  3088.  
  3089.  
  3090. /**********************************************/
  3091. /* SDS[]     : Set Delta Shift                */
  3092. /* CodeRange : $5F                            */
  3093.  
  3094. static void Ins_SDS( INS_ARG )
  3095. {
  3096.   CUR.GS.delta_shift = (Int)args[0];
  3097. }
  3098.  
  3099.  
  3100. /**********************************************/
  3101. /* GC[a]     : Get Coordinate projected onto  */
  3102. /* CodeRange : $46-$47                        */
  3103.  
  3104. /* BULLSHIT : Measures from the original glyph must to be taken */
  3105. /*            along the dual projection vector !!               */
  3106.  
  3107. static void Ins_GC( INS_ARG )
  3108. {
  3109.   Long L;
  3110.  
  3111.   L = args[0];
  3112.  
  3113.   if ( (unsigned)L >= CUR.zp2.n)
  3114.   {
  3115.     CUR.error = TT_Err_Invalid_Reference;
  3116.     return;
  3117.   }
  3118.  
  3119.   switch (CUR.opcode & 1) 
  3120.   {
  3121.     case 0:
  3122.       L = CUR_Func_project( CUR.zp2.cur_x[L],
  3123.                             CUR.zp2.cur_y[L]);
  3124.       break;
  3125.   
  3126.     case 1:
  3127.       L = CUR_Func_dualproj( CUR.zp2.org_x[L],
  3128.                              CUR.zp2.org_y[L]);
  3129.       break;
  3130.   }
  3131.  
  3132.   args[0] = L;
  3133. }
  3134.  
  3135.  
  3136. /**********************************************/
  3137. /* SCFS[]    : Set Coordinate From Stack      */
  3138. /* CodeRange : $48                            */
  3139. /*                                            */
  3140. /* Formule :                                  */
  3141. /*                                            */
  3142. /*   OA := OA + ( value - OA.p )/( f.p ) x f  */
  3143. /*                                            */
  3144.  
  3145. static void Ins_SCFS( INS_ARG )
  3146. {
  3147.   Long K;
  3148.   Int L;
  3149.  
  3150.   L = (Int)args[0];
  3151.  
  3152.   if ( args[0] < 0 || args[0] >= CUR.zp2.n)
  3153.   {
  3154.     CUR.error = TT_Err_Invalid_Reference;
  3155.     return;
  3156.   }
  3157.  
  3158.   K = CUR_Func_project( CUR.zp2.cur_x[L],
  3159.                         CUR.zp2.cur_y[L]);
  3160.  
  3161.   CUR_Func_move(&CUR.zp2, L, args[1] - K);
  3162.  
  3163.   /* not part of the specs, but here for safety */
  3164.  
  3165.   if (CUR.GS.gep2 == 0)
  3166.   {
  3167.     CUR.zp2.org_x[L] = CUR.zp2.cur_x[L];
  3168.     CUR.zp2.org_y[L] = CUR.zp2.cur_y[L];
  3169.   }
  3170. }
  3171.  
  3172.  
  3173. /**********************************************/
  3174. /* MD[a]     : Measure Distance               */
  3175. /* CodeRange : $49-$4A                        */
  3176.  
  3177. /* BULLSHIT : Measure taken in the original glyph must be along */
  3178. /*            the dual projection vector                        */
  3179.  
  3180. /* Second BULLSHIT : Flag attributions are inverted !!            */
  3181. /*                   0 => measure distance in original outline    */
  3182. /*                   1 => measure distance in grid-fitted outline */
  3183.  
  3184. static void Ins_MD( INS_ARG )
  3185. {
  3186.   Long K, L;
  3187.   TT_F26Dot6 D;
  3188.  
  3189.   K = args[1];
  3190.   L = args[0];
  3191.  
  3192.   if( (unsigned)args[0] >= CUR.zp2.n ||
  3193.       (unsigned)args[1] >= CUR.zp1.n )
  3194.   {
  3195.     CUR.error = TT_Err_Invalid_Reference;
  3196.     return;
  3197.   }
  3198.  
  3199.   if (CUR.opcode & 1)
  3200.     D = CUR_Func_project( CUR.zp2.cur_x[L] - CUR.zp1.cur_x[K],
  3201.                           CUR.zp2.cur_y[L] - CUR.zp1.cur_y[K]);
  3202.   else
  3203.     D = CUR_Func_dualproj( CUR.zp2.org_x[L] - CUR.zp1.org_x[K],
  3204.                            CUR.zp2.org_y[L] - CUR.zp1.org_y[K]);
  3205.  
  3206.   args[0] = D;
  3207. }
  3208.  
  3209.  
  3210. /**********************************************/
  3211. /* MPPEM[]   : Measure Pixel Per EM           */
  3212. /* CodeRange : $4B                            */
  3213.  
  3214. static void Ins_MPPEM( INS_ARG )
  3215. {
  3216.   args[0] = CUR_Ppem();
  3217. }
  3218.  
  3219.  
  3220. /**********************************************/
  3221. /* MPS[]     : Measure PointSize              */
  3222. /* CodeRange : $4C                            */
  3223.  
  3224. static void Ins_MPS( INS_ARG )
  3225. {
  3226.   args[0] = CUR.metrics.pointSize;
  3227. }
  3228.  
  3229.  
  3230. /****************************************************************/
  3231. /*                                                              */
  3232. /* MANAGING OUTLINES                                            */
  3233. /*                                                              */
  3234. /*  Instructions appear in the specs' order                     */
  3235. /*                                                              */
  3236. /****************************************************************/
  3237.  
  3238.  
  3239. /**********************************************/
  3240. /* FLIPPT[]  : FLIP PoinT                     */
  3241. /* CodeRange : $80                            */
  3242.  
  3243. static void Ins_FLIPPT( INS_ARG )
  3244. {
  3245.   Long point;
  3246.  
  3247.   if (CUR.top < CUR.GS.loop)
  3248.   {
  3249.     CUR.error = TT_Err_Too_Few_Arguments;
  3250.     return;
  3251.   }
  3252.  
  3253.   while (CUR.GS.loop > 0)
  3254.   {
  3255.     CUR.args--;
  3256.  
  3257.     point = CUR.stack[CUR.args];
  3258.  
  3259.     if (point < 0 || point >= CUR.pts.n)
  3260.     {
  3261.       CUR.error = TT_Err_Invalid_Reference;
  3262.       return;
  3263.     }
  3264.  
  3265.     CUR.pts.touch[point] ^= TT_Flag_On_Curve;
  3266.  
  3267.     CUR.GS.loop--;
  3268.   }
  3269.  
  3270.   CUR.GS.loop = 1;
  3271.   CUR.new_top = CUR.args;
  3272. }
  3273.  
  3274.  
  3275. /**********************************************/
  3276. /* FLIPRGON[]: FLIP RanGe ON                  */
  3277. /* CodeRange : $81                            */
  3278.  
  3279. static void Ins_FLIPRGON( INS_ARG )
  3280. {
  3281.   Long I, K, L;
  3282.  
  3283.   K = args[1];
  3284.   L = args[0];
  3285.  
  3286.   if ( (unsigned)K >= CUR.pts.n ||
  3287.        (unsigned)L >= CUR.pts.n )
  3288.   {
  3289.     CUR.error = TT_Err_Invalid_Reference;
  3290.     return;
  3291.   }
  3292.  
  3293.   for (I = L; I <= K; I++)
  3294.     CUR.pts.touch[I] |= TT_Flag_On_Curve;
  3295. }
  3296.  
  3297.  
  3298. /**********************************************/
  3299. /* FLIPRGOFF : FLIP RanGe OFF                 */
  3300. /* CodeRange : $82                            */
  3301.  
  3302. static void Ins_FLIPRGOFF( INS_ARG )
  3303. {
  3304.   Long I, K, L;
  3305.  
  3306.   K = args[1];
  3307.   L = args[0];
  3308.  
  3309.   if ( (unsigned)K >= CUR.pts.n ||
  3310.        (unsigned)L >= CUR.pts.n )
  3311.   {
  3312.     CUR.error = TT_Err_Invalid_Reference;
  3313.     return;
  3314.   }
  3315.  
  3316.   for (I = L; I <= K; I++)
  3317.     CUR.pts.touch[I] &= ~TT_Flag_On_Curve;
  3318. }
  3319.  
  3320.  
  3321.  
  3322. static void Compute_Point_Displacement( EXEC_OPS
  3323.                                         PCoordinates  x,
  3324.                                         PCoordinates  y,
  3325.                                         PVecRecord    zone,
  3326.                                         Int*          refp)
  3327. {
  3328.   TVecRecord  zp;
  3329.   Int         p;
  3330.   TT_F26Dot6  d;
  3331.  
  3332.   if (CUR.opcode & 1)
  3333.   {
  3334.     zp = CUR.zp0;
  3335.     p = CUR.GS.rp1;
  3336.   }
  3337.   else 
  3338.   {
  3339.     zp = CUR.zp1;
  3340.     p = CUR.GS.rp2;
  3341.   }
  3342.  
  3343.   *zone = zp;
  3344.   *refp = p;
  3345.  
  3346.   d = CUR_Func_project( zp.cur_x[p] - zp.org_x[p],
  3347.                         zp.cur_y[p] - zp.org_y[p]);
  3348.  
  3349.   *x = MulDiv_Round(d, (Long)CUR.GS.freeVector.x * 0x10000L, CUR.F_dot_P);
  3350.   *y = MulDiv_Round(d, (Long)CUR.GS.freeVector.y * 0x10000L, CUR.F_dot_P);
  3351.  
  3352. }
  3353.  
  3354. /****************************************************
  3355.  * Move_Zp2_Point
  3356.  *
  3357.  * 
  3358.  ****************************************************/
  3359.  
  3360. static void Move_Zp2_Point( EXEC_OPS
  3361.                             Long point,
  3362.                             TT_F26Dot6 dx,
  3363.                             TT_F26Dot6 dy)
  3364. {
  3365.   if (CUR.GS.freeVector.x != 0)
  3366.   {
  3367.     CUR.zp2.cur_x[point] += dx;
  3368.     CUR.zp2.touch[point] |= TT_Flag_Touched_X;
  3369.   }
  3370.  
  3371.   if (CUR.GS.freeVector.y != 0)
  3372.   {
  3373.     CUR.zp2.cur_y[point] += dy;
  3374.     CUR.zp2.touch[point] |= TT_Flag_Touched_Y;
  3375.   }
  3376. }
  3377.  
  3378.  
  3379. /**********************************************/
  3380. /* SHP[a]    : SHift Point by the last point  */
  3381. /* CodeRange : $32-33                         */
  3382.  
  3383. static void Ins_SHP( INS_ARG )
  3384. {
  3385.   TVecRecord  zp;
  3386.   Int         refp;
  3387.  
  3388.   TT_F26Dot6 dx,
  3389.              dy;
  3390.   Long       point;
  3391.  
  3392.   if (CUR.top < CUR.GS.loop)
  3393.   {
  3394.     CUR.error = TT_Err_Invalid_Reference;
  3395.     return;
  3396.   } 
  3397.  
  3398.   COMPUTE_Point_Displacement(&dx, &dy, &zp, &refp);
  3399.  
  3400.   while (CUR.GS.loop > 0)
  3401.   {
  3402.     CUR.args--;
  3403.     point = CUR.stack[CUR.args];
  3404.  
  3405.     if ( (unsigned)point >= CUR.zp2.n)
  3406.     {
  3407.       CUR.error = TT_Err_Invalid_Reference;
  3408.       return;
  3409.     }
  3410.  
  3411.     MOVE_Zp2_Point(point, dx, dy);
  3412.  
  3413.     CUR.GS.loop--;
  3414.   }
  3415.  
  3416.   CUR.GS.loop = 1;
  3417.   CUR.new_top = CUR.args;
  3418. }
  3419.  
  3420.  
  3421. /**********************************************/
  3422. /* SHC[a]    : SHift Contour                  */
  3423. /* CodeRange : $34-35                         */
  3424.  
  3425. static void Ins_SHC( INS_ARG )
  3426. {
  3427.   TVecRecord  zp;
  3428.   Int         refp;
  3429.   TT_F26Dot6  dx,
  3430.               dy;
  3431.  
  3432.   Long contour, i;
  3433.  
  3434.   Int first_point, last_point;
  3435.  
  3436.   contour = args[0];
  3437.  
  3438.   if ( (unsigned)args[0] >= CUR.numContours)
  3439.   {
  3440.     CUR.error = TT_Err_Invalid_Reference;
  3441.     return;
  3442.   }
  3443.  
  3444.   COMPUTE_Point_Displacement(&dx, &dy, &zp, &refp);
  3445.  
  3446.   if (contour == 0)
  3447.     first_point = 0;
  3448.   else
  3449.     first_point = CUR.endContours[contour - 1] + 1;
  3450.  
  3451.   last_point = CUR.endContours[contour];
  3452.  
  3453.   for (i = first_point; i <= last_point; i++)
  3454.   {
  3455.     if (zp.cur_x != CUR.zp2.cur_x || refp != i)
  3456.       MOVE_Zp2_Point(i, dx, dy);
  3457.   }
  3458.  
  3459. }
  3460.  
  3461.  
  3462. /**********************************************/
  3463. /* SHZ[a]    : SHift Zone                     */
  3464. /* CodeRange : $36-37                         */
  3465.  
  3466. static void Ins_SHZ( INS_ARG )
  3467. {
  3468.   TVecRecord  zp;
  3469.   Int         refp;
  3470.   TT_F26Dot6  dx,
  3471.               dy;
  3472.  
  3473.   Int  last_point;
  3474.   Long i;
  3475.  
  3476.   if ( (unsigned)args[0] > 1)
  3477.   {
  3478.     CUR.error = TT_Err_Invalid_Reference;
  3479.     return;
  3480.   }
  3481.  
  3482.   COMPUTE_Point_Displacement(&dx, &dy, &zp, &refp);
  3483.  
  3484.   last_point = zp.n - 1;
  3485.  
  3486.   for (i = 0; i <= last_point; i++)
  3487.   {
  3488.     if (zp.cur_x != CUR.zp2.cur_x || refp != i)
  3489.       MOVE_Zp2_Point(i, dx, dy);
  3490.   }
  3491.  
  3492. }
  3493.  
  3494.  
  3495. /**********************************************/
  3496. /* SHPIX[]   : SHift points by a PIXel amount */
  3497. /* CodeRange : $38                            */
  3498.  
  3499. static void Ins_SHPIX( INS_ARG )
  3500. {
  3501.   TT_F26Dot6 dx, dy;
  3502.   Long       point;
  3503.  
  3504.   if (CUR.top < CUR.GS.loop)
  3505.   {
  3506.     CUR.error = TT_Err_Invalid_Reference;
  3507.     return;
  3508.   }
  3509.  
  3510.   dx = MulDiv_Round( args[0],
  3511.                      (Long)CUR.GS.freeVector.x * 0x10000L,
  3512.                      CUR.F_dot_P);
  3513.  
  3514.   dy = MulDiv_Round( args[0],
  3515.                      (Long)CUR.GS.freeVector.y * 0x10000L,
  3516.                      CUR.F_dot_P);
  3517.  
  3518.   while (CUR.GS.loop > 0)
  3519.   {
  3520.     CUR.args--;
  3521.  
  3522.     point = CUR.stack[CUR.args];
  3523.  
  3524.     if ( (unsigned)point >= CUR.zp2.n)
  3525.     {
  3526.       CUR.error = TT_Err_Invalid_Reference;
  3527.       return;
  3528.     }
  3529.  
  3530.     MOVE_Zp2_Point(point, dx, dy);
  3531.  
  3532.     CUR.GS.loop--;
  3533.   }
  3534.  
  3535.   CUR.GS.loop = 1;
  3536.   CUR.new_top = CUR.args;
  3537. }
  3538.  
  3539.  
  3540. /**********************************************/
  3541. /* MSIRP[a]  : Move Stack Indirect Relative   */
  3542. /* CodeRange : $3A-$3B                        */
  3543.  
  3544. static void Ins_MSIRP( INS_ARG )
  3545. {
  3546.   Int        point;
  3547.   TT_F26Dot6 distance;
  3548.  
  3549.   point = (Int)args[0];
  3550.  
  3551.   if ( (unsigned)args[0] >= CUR.zp1.n)
  3552.   {
  3553.     CUR.error = TT_Err_Invalid_Reference;
  3554.     return;
  3555.     /* XXXX Is there some undocumented feature while in the */
  3556.     /*      twilight zone ??                                */
  3557.   }
  3558.  
  3559.   distance = CUR_Func_project( CUR.zp1.cur_x[point] -
  3560.                                CUR.zp0.cur_x[CUR.GS.rp0],
  3561.                                      
  3562.                                 CUR.zp1.cur_y[point] - 
  3563.                                 CUR.zp0.cur_y[CUR.GS.rp0]);
  3564.  
  3565.   /* Davep is point int or long in func call was set from PStorage */
  3566.  
  3567.   CUR_Func_move(&CUR.zp1, point, args[1] - distance);
  3568.  
  3569.   CUR.GS.rp1 = CUR.GS.rp0;
  3570.   CUR.GS.rp2 = point;
  3571.  
  3572.   if ((CUR.opcode & 1) != 0)
  3573.     CUR.GS.rp0 = point;
  3574. }
  3575.  
  3576.  
  3577. /**********************************************/
  3578. /* MDAP[a]   : Move Direct Absolute Point     */
  3579. /* CodeRange : $2E-$2F                        */
  3580.  
  3581. static void Ins_MDAP( INS_ARG )
  3582. {
  3583.   Int       point;
  3584.   TT_F26Dot6 cur_dist,
  3585.              distance;
  3586.  
  3587.   point = (Int)args[0];
  3588.  
  3589.   if ( (unsigned)args[0] >= CUR.zp0.n)
  3590.   {
  3591.     CUR.error = TT_Err_Invalid_Reference;
  3592.     return;
  3593.   }
  3594.  
  3595.   /* XXXX Is there some undocumented feature while in the */
  3596.   /*      twilight zone ??                                */
  3597.  
  3598.   if ((CUR.opcode & 1) != 0) 
  3599.   {
  3600.     cur_dist = CUR_Func_project( CUR.zp0.cur_x[point],
  3601.                                  CUR.zp0.cur_y[point]);
  3602.  
  3603.     distance = CUR_Func_round( cur_dist,
  3604.                                CUR.metrics.compensations[0] ) - cur_dist;
  3605.   }
  3606.   else
  3607.     distance = 0;
  3608.  
  3609.  
  3610.   CUR_Func_move(&CUR.zp0, point, distance);
  3611.  
  3612.   CUR.GS.rp0 = point;
  3613.   CUR.GS.rp1 = point;
  3614. }
  3615.  
  3616.  
  3617. /**********************************************/
  3618. /* MIAP[a]   : Move Indirect Absolute Point   */
  3619. /* CodeRange : $3E-$3F                        */
  3620.  
  3621. static void Ins_MIAP( INS_ARG )
  3622. {
  3623.   Int        cvtEntry, point;
  3624.   TT_F26Dot6 distance,
  3625.              org_dist;
  3626.  
  3627.   cvtEntry = (Int)args[1];
  3628.   point    = (Int)args[0];
  3629.  
  3630.   if ( (unsigned)args[0] >= CUR.zp0.n ||
  3631.        (unsigned)args[1] >= CUR.cvtSize )
  3632.   {
  3633.     CUR.error = TT_Err_Invalid_Reference;
  3634.     return;
  3635.   }
  3636.  
  3637.   /* Undocumented :                                    */
  3638.   /*                                                   */
  3639.   /* The behaviour of an MIAP instruction is quite     */
  3640.   /* different when used in the twilight zone.         */
  3641.   /*                                                   */
  3642.   /* First, no control value cutin test is performed   */
  3643.   /* as it would fail anyway. Second, the original     */
  3644.   /* point, i.e. (org_x,org_y) of zp0.point, is set    */
  3645.   /* to the absolute, unrounded, distance found in     */
  3646.   /* the CVT.                                          */
  3647.   /*                                                   */
  3648.   /* This is used in the CVT programs of the Microsoft */
  3649.   /* fonts Arial, Times, etc.., in order to re-adjust  */
  3650.   /* some key font heights. It allows the use of the   */
  3651.   /* IP instruction in the twilight zone, which        */
  3652.   /* otherwise would be "illegal" per se the specs :)  */
  3653.   /*                                                   */
  3654.   /* We implement it with a special sequence for the   */
  3655.   /* twilight zone. This is a bad hack, but it seems   */
  3656.   /* to work..                                         */
  3657.   /*                                         - David   */
  3658.  
  3659.   distance = CUR.cvt[cvtEntry];
  3660.  
  3661.   if (CUR.GS.gep0 == 0)   /* If in twilight zone */
  3662.   {
  3663.     CUR.zp0.org_x[point] = MulDiv_Round( CUR.GS.freeVector.x,
  3664.                                          distance, 0x4000L);
  3665.  
  3666.     CUR.zp0.cur_x[point] = CUR.zp0.org_x[point];
  3667.  
  3668.     CUR.zp0.org_y[point] = MulDiv_Round( CUR.GS.freeVector.y,
  3669.                                          distance,
  3670.                                          0x4000L);
  3671.  
  3672.     CUR.zp0.cur_y[point] = CUR.zp0.org_y[point];
  3673.   }
  3674.  
  3675.   org_dist = CUR_Func_project( CUR.zp0.cur_x[point],
  3676.                                CUR.zp0.cur_y[point]);
  3677.  
  3678.   if ((CUR.opcode & 1) != 0)   /* rounding and control cutin flag */
  3679.   {
  3680.    if (ABS(distance - org_dist) > CUR.GS.control_value_cutin)
  3681.        distance = org_dist;
  3682.  
  3683.     distance = CUR_Func_round(distance, CUR.metrics.compensations[0]);
  3684.   }
  3685.  
  3686.   CUR_Func_move(&CUR.zp0, point, distance - org_dist);
  3687.  
  3688.   CUR.GS.rp0 = point;
  3689.   CUR.GS.rp1 = point;
  3690. }
  3691.  
  3692.  
  3693. /**********************************************/
  3694. /* MDRP[abcde] : Move Direct Relative Point   */
  3695. /* CodeRange   : $C0-$DF                      */
  3696.  
  3697. static void Ins_MDRP( INS_ARG )
  3698. {
  3699.   Int       point;
  3700.   TT_F26Dot6 distance,
  3701.              org_dist;
  3702.  
  3703.   point = (Int)args[0];
  3704.  
  3705.   if ( (unsigned)args[0] >= CUR.zp1.n)
  3706.   {
  3707.     CUR.error = TT_Err_Invalid_Reference;
  3708.     return;
  3709.   }
  3710.  
  3711.   /* XXXX Is there some undocumented feature while in the */
  3712.   /*      twilight zone ??                                */
  3713.  
  3714.   org_dist = CUR_Func_dualproj( CUR.zp1.org_x[point] -
  3715.                                 CUR.zp0.org_x[CUR.GS.rp0],
  3716.                                      
  3717.                                 CUR.zp1.org_y[point] -
  3718.                                 CUR.zp0.org_y[CUR.GS.rp0] );
  3719.  
  3720.   /* single width cutin test */
  3721.  
  3722.   if (ABS(org_dist) < CUR.GS.single_width_cutin)
  3723.   {
  3724.     if (org_dist >= 0)
  3725.       org_dist = CUR.GS.single_width_value;
  3726.     else
  3727.       org_dist = -CUR.GS.single_width_value;
  3728.   }
  3729.  
  3730.   /* round flag */
  3731.  
  3732.   if ((CUR.opcode & 4) != 0)
  3733.     distance = CUR_Func_round( org_dist,
  3734.                                CUR.metrics.compensations[CUR.opcode & 3]);
  3735.   else
  3736.     distance = Round_None( EXEC_ARGS
  3737.                            org_dist,
  3738.                            CUR.metrics.compensations[CUR.opcode & 3]);
  3739.  
  3740.   /* minimum distance flag */
  3741.  
  3742.   if ((CUR.opcode & 8) != 0) 
  3743.   {
  3744.     if (org_dist >= 0) 
  3745.     {
  3746.       if (distance < CUR.GS.minimum_distance)
  3747.         distance = CUR.GS.minimum_distance;
  3748.     }
  3749.     else 
  3750.     {
  3751.       if (distance > -CUR.GS.minimum_distance)
  3752.       {
  3753.          distance = -CUR.GS.minimum_distance;
  3754.       }
  3755.     }
  3756.   }
  3757.  
  3758.   /* now move the point */
  3759.  
  3760.   org_dist = CUR_Func_project( CUR.zp1.cur_x[point] - 
  3761.                                CUR.zp0.cur_x[CUR.GS.rp0],
  3762.                                      
  3763.                                CUR.zp1.cur_y[point] - 
  3764.                                CUR.zp0.cur_y[CUR.GS.rp0]);
  3765.  
  3766.   CUR_Func_move(&CUR.zp1, point, distance - org_dist);
  3767.  
  3768.   CUR.GS.rp1 = CUR.GS.rp0;
  3769.   CUR.GS.rp2 = point;
  3770.  
  3771.   if ((CUR.opcode & 16) != 0)
  3772.     CUR.GS.rp0 = point;
  3773. }
  3774.  
  3775.  
  3776. /**********************************************/
  3777. /* MIRP[abcde] : Move Indirect Relative Point */
  3778. /* CodeRange   : $E0-$FF                      */
  3779.  
  3780. static void Ins_MIRP( INS_ARG )
  3781. {
  3782.   Int       point,
  3783.             cvtEntry;
  3784.  
  3785.   TT_F26Dot6 cvt_dist,
  3786.              distance,
  3787.              cur_dist,
  3788.              org_dist;
  3789.  
  3790.   point    = (Int)args[0];
  3791.   cvtEntry = (Int)args[1];
  3792.  
  3793.   if ( (unsigned)args[0] >= CUR.zp1.n ||
  3794.        (unsigned)args[1] >= CUR.cvtSize )
  3795.   {
  3796.     CUR.error = TT_Err_Invalid_Reference;
  3797.     return;
  3798.   }
  3799.  
  3800.   cvt_dist = CUR.cvt[cvtEntry];
  3801.  
  3802.   /* single width test */
  3803.  
  3804.   if ( ABS(cvt_dist) < CUR.GS.single_width_cutin )
  3805.   {
  3806.     if (cvt_dist >= 0)
  3807.       cvt_dist =  CUR.GS.single_width_value;
  3808.     else
  3809.       cvt_dist = -CUR.GS.single_width_value;
  3810.   }
  3811.  
  3812.   /* XXXX Is there some undocumented feature while in the */
  3813.   /*      twilight zone ??                                */
  3814.  
  3815.   org_dist = CUR_Func_dualproj( CUR.zp1.org_x[point] - 
  3816.                                 CUR.zp0.org_x[CUR.GS.rp0],
  3817.                                       
  3818.                                 CUR.zp1.org_y[point] - 
  3819.                                 CUR.zp0.org_y[CUR.GS.rp0]);
  3820.   
  3821.   cur_dist = CUR_Func_project( CUR.zp1.cur_x[point] -
  3822.                                CUR.zp0.cur_x[CUR.GS.rp0],
  3823.                                      
  3824.                                CUR.zp1.cur_y[point] - 
  3825.                                CUR.zp0.cur_y[CUR.GS.rp0]);
  3826.  
  3827.   /* auto-flip test */
  3828.  
  3829.   if (CUR.GS.auto_flip)
  3830.   {
  3831.     if ((org_dist ^ cvt_dist) < 0)
  3832.       cvt_dist = -cvt_dist;
  3833.   }
  3834.  
  3835.   /* control value cutin and round */
  3836.  
  3837.   if ((CUR.opcode & 4) != 0) 
  3838.   {
  3839.     if (ABS(cvt_dist - org_dist) >= CUR.GS.control_value_cutin)
  3840.       cvt_dist = org_dist;
  3841.  
  3842.     distance = CUR_Func_round( cvt_dist,
  3843.                                CUR.metrics.compensations[CUR.opcode & 3]);
  3844.   }
  3845.   else
  3846.     distance = Round_None( EXEC_ARGS
  3847.                            cvt_dist,
  3848.                            CUR.metrics.compensations[CUR.opcode & 3]);
  3849.  
  3850.   /* minimum distance test */
  3851.  
  3852.   if ((CUR.opcode & 8) != 0)
  3853.    {
  3854.     if (org_dist >= 0)
  3855.      {
  3856.       if (distance < CUR.GS.minimum_distance)
  3857.         distance = CUR.GS.minimum_distance;
  3858.       }
  3859.     else
  3860.       {
  3861.       if (distance > -CUR.GS.minimum_distance)
  3862.         distance = -CUR.GS.minimum_distance;
  3863.       }
  3864.     }
  3865.  
  3866.   CUR_Func_move(&CUR.zp1, point, distance - cur_dist);
  3867.  
  3868.   CUR.GS.rp1 = CUR.GS.rp0;
  3869.  
  3870.   if ((CUR.opcode & 16) != 0)
  3871.     CUR.GS.rp0 = point;
  3872.  
  3873.   /* UNDOCUMENTED !! */
  3874.  
  3875.   CUR.GS.rp2 = point;
  3876. }
  3877.  
  3878.  
  3879. /**********************************************/
  3880. /* ALIGNRP[]   : ALIGN Relative Point         */
  3881. /* CodeRange   : $3C                          */
  3882.  
  3883. static void Ins_ALIGNRP( INS_ARG )
  3884. {
  3885.   Int        point;
  3886.   TT_F26Dot6 distance;
  3887.  
  3888.   if (CUR.top < CUR.GS.loop)
  3889.   {
  3890.     CUR.error = TT_Err_Invalid_Reference;
  3891.     return;
  3892.   }
  3893.  
  3894.   while (CUR.GS.loop > 0) 
  3895.   {
  3896.     CUR.args--;
  3897.  
  3898.     point = (Int)CUR.stack[CUR.args];
  3899.  
  3900.     if ( (unsigned)point >= CUR.zp1.n)
  3901.     {
  3902.       CUR.error = TT_Err_Invalid_Reference;
  3903.       return;
  3904.     }
  3905.  
  3906.     distance = CUR_Func_project( CUR.zp1.cur_x[point] - 
  3907.                                  CUR.zp0.cur_x[CUR.GS.rp0],
  3908.                                        
  3909.                                  CUR.zp1.cur_y[point] - 
  3910.                                  CUR.zp0.cur_y[CUR.GS.rp0]);
  3911.     
  3912.     CUR_Func_move(&CUR.zp1, point, -distance);
  3913.     CUR.GS.loop--;
  3914.   }
  3915.  
  3916.   CUR.GS.loop = 1;
  3917.   CUR.new_top = CUR.args;
  3918. }
  3919.  
  3920.  
  3921. /**********************************************/
  3922. /* AA[]        : Adjust Angle                 */
  3923. /* CodeRange   : $7F                          */
  3924.  
  3925. static void Ins_AA( INS_ARG )
  3926. {
  3927.   /* Intentional - no longer supported */
  3928. }
  3929.  
  3930.  
  3931. /**********************************************/
  3932. /* ISECT[]     : moves point to InterSECTion  */
  3933. /* CodeRange   : $0F                          */
  3934.  
  3935. static void Ins_ISECT( INS_ARG )
  3936. {
  3937.   Long point,        /* are these Ints or Longs */
  3938.        a0, a1, 
  3939.        b0, b1;
  3940.  
  3941.   TT_F26Dot6 discriminant;
  3942.    
  3943.   TT_F26Dot6 dx,  dy, 
  3944.              dax, day, 
  3945.              dbx, dby;
  3946.  
  3947.   TT_F26Dot6 val;
  3948.  
  3949.   TT_Vector R;
  3950.  
  3951.   point = args[0];
  3952.  
  3953.   a0 = args[1];
  3954.   a1 = args[2];
  3955.   b0 = args[3];
  3956.   b1 = args[4];
  3957.  
  3958.   if ( (unsigned)b0 >= CUR.zp0.n ||
  3959.        (unsigned)b1 >= CUR.zp0.n ||
  3960.        (unsigned)a0 >= CUR.zp1.n ||
  3961.        (unsigned)a1 >= CUR.zp1.n || 
  3962.        (unsigned)point >= CUR.zp0.n)
  3963.   {
  3964.     CUR.error = TT_Err_Invalid_Reference;
  3965.     return;
  3966.   }
  3967.   dbx = CUR.zp0.cur_x[b1] - CUR.zp0.cur_x[b0];
  3968.   dby = CUR.zp0.cur_y[b1] - CUR.zp0.cur_y[b0];
  3969.  
  3970.   dax = CUR.zp1.cur_x[a1] - CUR.zp1.cur_x[a0];
  3971.   day = CUR.zp1.cur_y[a1] - CUR.zp1.cur_y[a0];
  3972.  
  3973.   dx = CUR.zp0.cur_x[b0] - CUR.zp1.cur_x[a0];
  3974.   dy = CUR.zp0.cur_y[b0] - CUR.zp1.cur_y[a0];
  3975.  
  3976.   CUR.zp2.touch[point] |= TT_Flag_Touched_Both;
  3977.  
  3978.   discriminant = MulDiv( dax, -dby, 0x40L) +
  3979.                  MulDiv( day, dbx, 0x40L);
  3980.  
  3981.   if (ABS(discriminant) >= 0x40)
  3982.   {
  3983.     val = MulDiv(dx, -dby, 0x40L) + MulDiv(dy, dbx, 0x40L);
  3984.   
  3985.     R.x = MulDiv(val, dax, discriminant);
  3986.     R.y = MulDiv(val, day, discriminant);
  3987.   
  3988.     CUR.zp2.cur_x[point] = CUR.zp1.cur_x[a0] + R.x;
  3989.     CUR.zp2.cur_y[point] = CUR.zp1.cur_y[a0] + R.y;
  3990.   
  3991.   }
  3992.   else
  3993.   {
  3994.     /* else, take the middle of the middles of A and B */
  3995.  
  3996.     CUR.zp2.cur_x[point] = ( CUR.zp1.cur_x[a0] +
  3997.                              CUR.zp1.cur_x[a1] +
  3998.                              CUR.zp0.cur_x[b0] + 
  3999.                              CUR.zp1.cur_x[b1]) / 4;
  4000.  
  4001.     CUR.zp2.cur_y[point] = ( CUR.zp1.cur_y[a0] + 
  4002.                              CUR.zp1.cur_y[a1] +
  4003.                              CUR.zp0.cur_y[b0] + 
  4004.                              CUR.zp1.cur_y[b1]) / 4;
  4005.   }
  4006. }
  4007.  
  4008.  
  4009. /**********************************************/
  4010. /* ALIGNPTS[]  : ALIGN PoinTS                 */
  4011. /* CodeRange   : $27                          */
  4012.  
  4013. static void Ins_ALIGNPTS( INS_ARG )
  4014. {
  4015.   Int       p1, p2;
  4016.   TT_F26Dot6 distance;
  4017.  
  4018.   p1 = (Int)args[0];
  4019.   p2 = (Int)args[1];
  4020.  
  4021.   if ( (unsigned)args[0] >= CUR.zp1.n ||
  4022.        (unsigned)args[1] >= CUR.zp0.n )
  4023.   {
  4024.     CUR.error = TT_Err_Invalid_Reference;
  4025.     return;
  4026.   }
  4027.  
  4028.   distance = CUR_Func_project( CUR.zp0.cur_x[p2] - 
  4029.                                CUR.zp1.cur_x[p1],
  4030.                                      
  4031.                                CUR.zp0.cur_y[p2] - 
  4032.                                CUR.zp1.cur_x[p1]) / 2;
  4033.  
  4034.   CUR_Func_move(&CUR.zp1, p1, distance);
  4035.   
  4036.   CUR_Func_move(&CUR.zp0, p2, -distance);
  4037. }
  4038.  
  4039.  
  4040. /**********************************************/
  4041. /* IP[]        : Interpolate Point            */
  4042. /* CodeRange   : $39                          */
  4043.  
  4044. static void Ins_IP( INS_ARG )
  4045. {
  4046.   TT_F26Dot6 org_a,
  4047.              org_b, 
  4048.              org_x, 
  4049.              cur_a, 
  4050.              cur_b, 
  4051.              cur_x, 
  4052.              distance;
  4053.   Int       point;
  4054.  
  4055.   if (CUR.top < CUR.GS.loop)
  4056.   {
  4057.     CUR.error = TT_Err_Invalid_Reference;
  4058.     return;
  4059.   }
  4060.  
  4061.   org_a = CUR_Func_dualproj( CUR.zp0.org_x[CUR.GS.rp1],
  4062.                              CUR.zp0.org_y[CUR.GS.rp1] );
  4063.                                       
  4064.   org_b = CUR_Func_dualproj( CUR.zp1.org_x[CUR.GS.rp2],
  4065.                              CUR.zp1.org_y[CUR.GS.rp2] );
  4066.  
  4067.   cur_a = CUR_Func_project( CUR.zp0.cur_x[CUR.GS.rp1],
  4068.                             CUR.zp0.cur_y[CUR.GS.rp1] );
  4069.  
  4070.   cur_b = CUR_Func_project( CUR.zp1.cur_x[CUR.GS.rp2],
  4071.                             CUR.zp1.cur_y[CUR.GS.rp2] );
  4072.  
  4073.   while (CUR.GS.loop > 0) 
  4074.   {
  4075.     CUR.args--;
  4076.  
  4077.     point = (Int)CUR.stack[CUR.args];
  4078.  
  4079.     org_x = CUR_Func_dualproj( CUR.zp2.org_x[point],
  4080.                                CUR.zp2.org_y[point] );
  4081.     
  4082.     cur_x = CUR_Func_project( CUR.zp2.cur_x[point],
  4083.                               CUR.zp2.cur_y[point] );
  4084.  
  4085.        if ( ( org_a <= org_b && org_x <= org_a ) ||
  4086.             ( org_a >  org_b && org_x >= org_a ) )
  4087.          {
  4088.            distance = ( cur_a - org_a ) + ( org_x - cur_x );
  4089.          }
  4090.        else if ( ( org_a <= org_b  &&  org_x >= org_b ) ||
  4091.                  ( org_a >  org_b  &&  org_x <  org_b ) )
  4092.           {
  4093.             distance = ( cur_b - org_b ) + ( org_x - cur_x );
  4094.           }
  4095.        else
  4096.        {
  4097.          /* note : it seems that rounding this value isn't a good */
  4098.          /*        idea ( width of capital 'S' in Times )         */
  4099.  
  4100.          distance = MulDiv( cur_b - cur_a,
  4101.                             org_x - org_a,
  4102.                             org_b - org_a ) + ( cur_a - cur_x );
  4103.        }
  4104.  
  4105.     CUR_Func_move(&CUR.zp2, point, distance);
  4106.  
  4107.     CUR.GS.loop--;
  4108.   }
  4109.  
  4110.   CUR.GS.loop = 1;
  4111.   CUR.new_top = CUR.args;
  4112. }
  4113.  
  4114.  
  4115. /**********************************************/
  4116. /* UTP[a]      : UnTouch Point                */
  4117. /* CodeRange   : $29                          */
  4118.  
  4119. static void Ins_UTP( INS_ARG )
  4120. {
  4121.   Byte mask;
  4122.  
  4123.   if ( (unsigned)args[0] >= CUR.zp0.n)
  4124.   {
  4125.     CUR.error = TT_Err_Invalid_Reference;
  4126.     return;
  4127.   }
  4128.  
  4129.   mask = 0xFF;
  4130.  
  4131.   if (CUR.GS.freeVector.x != 0)
  4132.     mask &= ~TT_Flag_Touched_X;
  4133.  
  4134.   if (CUR.GS.freeVector.y != 0)
  4135.     mask &= ~TT_Flag_Touched_Y;
  4136.  
  4137.   CUR.zp0.touch[args[0]] &= mask;
  4138. }
  4139.  
  4140.  
  4141.  
  4142. /* Local variables for Ins_IUP: */
  4143. struct LOC_Ins_IUP
  4144. {
  4145.   PCoordinates orgs;   /* original and current coordinate */
  4146.   PCoordinates curs;   /* arrays                          */
  4147. };
  4148.  
  4149. /******************************************************************************
  4150.  * Local Procedure for Ins_IUP
  4151.  *
  4152.  * 
  4153.  ******************************************************************************/
  4154. static void Shift( Int p1,
  4155.                    Int p2,
  4156.                    Int p,
  4157.                    struct LOC_Ins_IUP *LINK)
  4158. {
  4159.   Int        i;
  4160.   TT_F26Dot6 x;
  4161.  
  4162.   x = LINK->curs[p] - LINK->orgs[p];
  4163.  
  4164.   for (i = p1; i < p; i++)
  4165.     LINK->curs[i] += x;
  4166.  
  4167.   for (i = p + 1; i <= p2; i++)
  4168.     LINK->curs[i] += x;
  4169. }
  4170.  
  4171. /******************************************************************************
  4172.  * Local Procedure for Ins_INP
  4173.  *
  4174.  * 
  4175.  ******************************************************************************/
  4176.  
  4177. static void Interp(Int p1, Int p2, Int ref1, Int ref2,
  4178.                   struct LOC_Ins_IUP *LINK)
  4179. {
  4180.   Long       i;
  4181.   TT_F26Dot6 x, x1, x2, d1, d2;
  4182.  
  4183.   if (p1 > p2)
  4184.     return;
  4185.  
  4186.   x1 = LINK->orgs[ref1];
  4187.   d1 = LINK->curs[ref1] - LINK->orgs[ref1];
  4188.   x2 = LINK->orgs[ref2];
  4189.   d2 = LINK->curs[ref2] - LINK->orgs[ref2];
  4190.  
  4191.   if (x1 == x2)
  4192.   {
  4193.     for (i = p1; i <= p2; i++) 
  4194.     {
  4195.       x = LINK->orgs[i];
  4196.  
  4197.       if (x <= x1) x += d1;
  4198.               else x += d2;
  4199.  
  4200.       LINK->curs[i] = x;
  4201.     }
  4202.     return;
  4203.   }
  4204.  
  4205.   if (x1 < x2)
  4206.   {
  4207.     for (i = p1; i <= p2; i++)
  4208.     {
  4209.       x = LINK->orgs[i];
  4210.  
  4211.       if (x <= x1) 
  4212.         x += d1;
  4213.       else   
  4214.       {
  4215.         if (x >= x2)
  4216.           x += d2;
  4217.         else
  4218.           x = LINK->curs[ref1] + MulDiv( x - x1,
  4219.                                          LINK->curs[ref2] - LINK->curs[ref1],
  4220.                                          x2 - x1);
  4221.       }
  4222.       LINK->curs[i] = x;
  4223.     }
  4224.     return;
  4225.   }
  4226.  
  4227.   /* x2 < x1 */
  4228.  
  4229.   for (i = p1; i <= p2; i++)
  4230.   {
  4231.     x = LINK->orgs[i];
  4232.     if (x <= x2)
  4233.       x += d2;
  4234.     else
  4235.     {
  4236.       if (x >= x1)
  4237.         x += d1;
  4238.       else
  4239.         x = LINK->curs[ref1] + MulDiv( x - x1,
  4240.                                        LINK->curs[ref2] - LINK->curs[ref1],
  4241.                                        x2 - x1);
  4242.     }
  4243.     LINK->curs[i] = x;
  4244.   }
  4245. }
  4246.  
  4247.  
  4248. /**********************************************/
  4249. /* IUP[a]      : Interpolate Untouched Points */
  4250. /* CodeRange   : $30-$31                      */
  4251.  
  4252. static void Ins_IUP( INS_ARG )
  4253. {
  4254.   struct LOC_Ins_IUP V;
  4255.   unsigned char mask;
  4256.  
  4257.   Long first_point;   /* first point of contour        */
  4258.   Long end_point;   /* end point (last+1) of contour */
  4259.  
  4260.   Long first_touched;   /* first touched point in contour   */
  4261.   Long cur_touched;   /* current touched point in contour */
  4262.  
  4263.   Long point;   /* current point   */
  4264.   Long contour;   /* current contour */
  4265.  
  4266.   if (CUR.opcode & 1)
  4267.   {
  4268.     mask   = TT_Flag_Touched_X;
  4269.     V.orgs = CUR.pts.org_x;
  4270.     V.curs = CUR.pts.cur_x;
  4271.   }
  4272.   else
  4273.   {
  4274.     mask   = TT_Flag_Touched_Y;
  4275.     V.orgs = CUR.pts.org_y;
  4276.     V.curs = CUR.pts.cur_y;
  4277.   }
  4278.  
  4279.   contour = 0;
  4280.   point   = 0;
  4281.  
  4282.   do 
  4283.   {
  4284.     end_point   = CUR.endContours[contour];
  4285.     first_point = point;
  4286.  
  4287.     while (point <= end_point && (CUR.pts.touch[point] & mask) == 0)
  4288.       point++;
  4289.  
  4290.     if (point <= end_point) 
  4291.     {
  4292.       first_touched = point;
  4293.       cur_touched   = point;
  4294.  
  4295.       point++;
  4296.  
  4297.       while (point <= end_point)
  4298.       {
  4299.         if ((CUR.pts.touch[point] & mask) != 0) 
  4300.         {
  4301.           Interp( (Int)(cur_touched + 1),
  4302.                   (Int)(point - 1),
  4303.                   (Int)cur_touched,
  4304.                   (Int)point,
  4305.                   &V);
  4306.           cur_touched = point;
  4307.         }
  4308.  
  4309.         point++;
  4310.       }
  4311.  
  4312.       if (cur_touched == first_touched)
  4313.         Shift((Int)first_point, (Int)end_point, (Int)cur_touched, &V);
  4314.       else
  4315.       {
  4316.         Interp((Int)(cur_touched + 1),
  4317.                (Int)(end_point),
  4318.                (Int)(cur_touched),
  4319.                (Int)(first_touched),
  4320.                &V);
  4321.  
  4322.         Interp((Int)(first_point),
  4323.                (Int)(first_touched - 1),
  4324.                (Int)(cur_touched),
  4325.                (Int)(first_touched),
  4326.                &V);
  4327.       }
  4328.     }
  4329.     contour++;
  4330.   } while (contour < CUR.numContours);
  4331. }
  4332.  
  4333.  
  4334. /**********************************************/
  4335. /* DELTAPn[]   : DELTA Exceptions P1, P2, P3  */
  4336. /* CodeRange   : $5D,$71,$72                  */
  4337.  
  4338. static void Ins_DELTAP( INS_ARG )
  4339. {
  4340.   Int k;
  4341.   Long A, B, C, nump;
  4342.  
  4343.   nump = args[0];
  4344.  
  4345.   for (k = 1; k <= nump; k++) 
  4346.   {
  4347.     if (CUR.args < 2) 
  4348.     {
  4349.       CUR.error = TT_Err_Too_Few_Arguments;
  4350.       return;
  4351.     }
  4352.  
  4353.     CUR.args -= 2;
  4354.  
  4355.     A = CUR.stack[CUR.args + 1];
  4356.     B = CUR.stack[CUR.args];
  4357.  
  4358.     if (A >= CUR.zp0.n) 
  4359.     {
  4360.       CUR.error = TT_Err_Invalid_Reference;
  4361.       return;
  4362.     }
  4363.  
  4364.     C = (B & 0xF0) >> 4;
  4365.  
  4366.     switch (CUR.opcode) 
  4367.     {
  4368.       case 0x5d:
  4369.         break;
  4370.   
  4371.       case 0x71:
  4372.         C += 16;
  4373.         break;
  4374.   
  4375.       case 0x72:
  4376.         C += 32;
  4377.         break;
  4378.     }
  4379.  
  4380.     C += CUR.GS.delta_base;
  4381.  
  4382.     if (CUR_Ppem() == C) 
  4383.     {
  4384.       B = (B & 0xF) - 8;
  4385.       if (B >= 0)
  4386.         B++;
  4387.       B = B * 64 / (1L << CUR.GS.delta_shift);
  4388.  
  4389.       CUR_Func_move(&CUR.zp0, (Int)A, (Int)B);
  4390.     }
  4391.   }
  4392.   CUR.new_top = CUR.args;
  4393. }
  4394.  
  4395.  
  4396. /**********************************************/
  4397. /* DELTACn[]   : DELTA Exceptions C1, C2, C3  */
  4398. /* CodeRange   : $73,$74,$75                  */
  4399.  
  4400. static void Ins_DELTAC( INS_ARG )
  4401. {
  4402.   Long nump, k;
  4403.   Long A, B, C;
  4404.  
  4405.   nump = args[0];
  4406.  
  4407.   for (k = 1; k <= nump; k++) 
  4408.   {
  4409.     if (CUR.args < 2)
  4410.     {
  4411.       CUR.error = TT_Err_Too_Few_Arguments;
  4412.       return;
  4413.     }
  4414.  
  4415.     CUR.args -= 2;
  4416.  
  4417.     A = CUR.stack[CUR.args + 1];
  4418.     B = CUR.stack[CUR.args];
  4419.  
  4420.     if (A >= CUR.cvtSize)
  4421.     {
  4422.       CUR.error = TT_Err_Invalid_Reference;
  4423.       return;
  4424.     }
  4425.  
  4426.     C = ((unsigned long)(B & 0xF0)) >> 4;
  4427.  
  4428.     switch (CUR.opcode)
  4429.     {
  4430.       case 0x73:
  4431.         break;
  4432.   
  4433.       case 0x74:
  4434.         C += 16;
  4435.         break;
  4436.   
  4437.       case 0x75:
  4438.         C += 32;
  4439.         break;
  4440.     }
  4441.  
  4442.     C += CUR.GS.delta_base;
  4443.  
  4444.     if (CUR_Ppem() == C)
  4445.     {
  4446.       B = (B & 0xF) - 8;
  4447.       if (B >= 0)
  4448.         B++;
  4449.       B = B * 64 / (1L << CUR.GS.delta_shift);
  4450.  
  4451.       CUR.cvt[A] += (Int)B;
  4452.     }
  4453.   }
  4454.  
  4455.   CUR.new_top = CUR.args;
  4456. }
  4457.  
  4458.  
  4459. /****************************************************************/
  4460. /*                                                              */
  4461. /* MISC. INSTRUCTIONS                                           */
  4462. /*                                                              */
  4463. /****************************************************************/
  4464.  
  4465. /***********************************************************/
  4466. /* DEBUG[]     : DEBUG. Unsupported                        */
  4467. /* CodeRange   : $4F                                       */
  4468.  
  4469. /* NOTE : The original instruction pops a value from the stack */
  4470.  
  4471. static void Ins_DEBUG( INS_ARG )
  4472. {
  4473.   CUR.error = TT_Err_Debug_OpCode;
  4474. }
  4475.  
  4476.  
  4477. /**********************************************/
  4478. /* GETINFO[]   : GET INFOrmation              */
  4479. /* CodeRange   : $88                          */
  4480.  
  4481. static void Ins_GETINFO( INS_ARG )
  4482. {
  4483.   Long K;
  4484.  
  4485.   K = 0;
  4486.  
  4487.   if ((args[0] & 1) != 0)
  4488.     K = 3;
  4489.   /* We return then Windows 3.1 version number */
  4490.   /* for the font scaler                       */
  4491.  
  4492.   if (CUR.metrics.rotated)
  4493.     K |= 0x80;
  4494.   /* Has the glyph been rotated ? */
  4495.  
  4496.   if (CUR.metrics.stretched)
  4497.     K |= 0x100;
  4498.   /* Has the glyph been stretched ? */
  4499.  
  4500.   args[0] = K;
  4501. }
  4502.  
  4503.  
  4504. static void Ins_UNKNOWN( INS_ARG )
  4505. {
  4506.   CUR.error = TT_Err_Invalid_Opcode;
  4507. }
  4508.  
  4509.  
  4510. static TInstruction_Function Instruct_Dispatch[256] = {
  4511.  
  4512.              /* opcodes are gathered in groups of 16 */
  4513.              /* please keep the spaces as they are   */
  4514.  
  4515.              /*  SVTCA  y  */  Ins_SVTCA,
  4516.              /*  SVTCA  x  */  Ins_SVTCA,
  4517.              /*  SPvTCA y  */  Ins_SPVTCA,
  4518.              /*  SPvTCA x  */  Ins_SPVTCA,
  4519.              /*  SFvTCA y  */  Ins_SFVTCA,
  4520.              /*  SFvTCA x  */  Ins_SFVTCA,
  4521.              /*  SPvTL //  */  Ins_SPVTL,
  4522.              /*  SPvTL +   */  Ins_SPVTL,
  4523.              /*  SFvTL //  */  Ins_SFVTL,
  4524.              /*  SFvTL +   */  Ins_SFVTL,
  4525.              /*  SPvFS     */  Ins_SPVFS,
  4526.              /*  SFvFS     */  Ins_SFVFS,
  4527.              /*  GPV       */  Ins_GPV,
  4528.              /*  GFV       */  Ins_GFV,
  4529.              /*  SFvTPv    */  Ins_SFVTPV,
  4530.              /*  ISECT     */  Ins_ISECT,
  4531.              
  4532.              /*  SRP0      */  Ins_SRP0,
  4533.              /*  SRP1      */  Ins_SRP1,
  4534.              /*  SRP2      */  Ins_SRP2,
  4535.              /*  SZP0      */  Ins_SZP0,
  4536.              /*  SZP1      */  Ins_SZP1,
  4537.              /*  SZP2      */  Ins_SZP2,
  4538.              /*  SZPS      */  Ins_SZPS,
  4539.              /*  SLOOP     */  Ins_SLOOP,
  4540.              /*  RTG       */  Ins_RTG,
  4541.              /*  RTHG      */  Ins_RTHG,
  4542.              /*  SMD       */  Ins_SMD,
  4543.              /*  ELSE      */  Ins_ELSE,
  4544.              /*  JMPR      */  Ins_JMPR,
  4545.              /*  SCvTCi    */  Ins_SCVTCI,
  4546.              /*  SSwCi     */  Ins_SSWCI,
  4547.              /*  SSW       */  Ins_SSW,
  4548.              
  4549.              /*  DUP       */  Ins_DUP,
  4550.              /*  POP       */  Ins_POP,
  4551.              /*  CLEAR     */  Ins_CLEAR,
  4552.              /*  SWAP      */  Ins_SWAP,
  4553.              /*  DEPTH     */  Ins_DEPTH,
  4554.              /*  CINDEX    */  Ins_CINDEX,
  4555.              /*  MINDEX    */  Ins_MINDEX,
  4556.              /*  AlignPTS  */  Ins_ALIGNPTS,
  4557.              /*  INS_$28   */  Ins_UNKNOWN,
  4558.              /*  UTP       */  Ins_UTP,
  4559.              /*  LOOPCALL  */  Ins_LOOPCALL,
  4560.              /*  CALL      */  Ins_CALL,
  4561.              /*  FDEF      */  Ins_FDEF,
  4562.              /*  ENDF      */  Ins_ENDF,
  4563.              /*  MDAP[0]   */  Ins_MDAP,
  4564.              /*  MDAP[1]   */  Ins_MDAP,
  4565.              
  4566.              /*  IUP[0]    */  Ins_IUP,
  4567.              /*  IUP[1]    */  Ins_IUP,
  4568.              /*  SHP[0]    */  Ins_SHP,
  4569.              /*  SHP[1]    */  Ins_SHP,
  4570.              /*  SHC[0]    */  Ins_SHC,
  4571.              /*  SHC[1]    */  Ins_SHC,
  4572.              /*  SHZ[0]    */  Ins_SHZ,
  4573.              /*  SHZ[1]    */  Ins_SHZ,
  4574.              /*  SHPIX     */  Ins_SHPIX,
  4575.              /*  IP        */  Ins_IP,
  4576.              /*  MSIRP[0]  */  Ins_MSIRP,
  4577.              /*  MSIRP[1]  */  Ins_MSIRP,
  4578.              /*  AlignRP   */  Ins_ALIGNRP,
  4579.              /*  RTDG      */  Ins_RTDG,
  4580.              /*  MIAP[0]   */  Ins_MIAP,
  4581.              /*  MIAP[1]   */  Ins_MIAP,
  4582.              
  4583.              /*  NPushB    */  Ins_NPUSHB,
  4584.              /*  NPushW    */  Ins_NPUSHW,
  4585.              /*  WS        */  Ins_WS,
  4586.              /*  RS        */  Ins_RS,
  4587.              /*  WCvtP     */  Ins_WCVTP,
  4588.              /*  RCvt      */  Ins_RCVT,
  4589.              /*  GC[0]     */  Ins_GC,
  4590.              /*  GC[1]     */  Ins_GC,
  4591.              /*  SCFS      */  Ins_SCFS,
  4592.              /*  MD[0]     */  Ins_MD,
  4593.              /*  MD[1]     */  Ins_MD,
  4594.              /*  MPPEM     */  Ins_MPPEM,
  4595.              /*  MPS       */  Ins_MPS,
  4596.              /*  FlipON    */  Ins_FLIPON,
  4597.              /*  FlipOFF   */  Ins_FLIPOFF,
  4598.              /*  DEBUG     */  Ins_DEBUG,
  4599.              
  4600.              /*  LT        */  Ins_LT,
  4601.              /*  LTEQ      */  Ins_LTEQ,
  4602.              /*  GT        */  Ins_GT,
  4603.              /*  GTEQ      */  Ins_GTEQ,
  4604.              /*  EQ        */  Ins_EQ,
  4605.              /*  NEQ       */  Ins_NEQ,
  4606.              /*  ODD       */  Ins_ODD,
  4607.              /*  EVEN      */  Ins_EVEN,
  4608.              /*  IF        */  Ins_IF,
  4609.              /*  EIF       */  Ins_EIF,
  4610.              /*  AND       */  Ins_AND,
  4611.              /*  OR        */  Ins_OR,
  4612.              /*  NOT       */  Ins_NOT,
  4613.              /*  DeltaP1   */  Ins_DELTAP,
  4614.              /*  SDB       */  Ins_SDB,
  4615.              /*  SDS       */  Ins_SDS,
  4616.              
  4617.              /*  ADD       */  Ins_ADD,
  4618.              /*  SUB       */  Ins_SUB,
  4619.              /*  DIV       */  Ins_DIV,
  4620.              /*  MUL       */  Ins_MUL,
  4621.              /*  ABS       */  Ins_ABS,
  4622.              /*  NEG       */  Ins_NEG,
  4623.              /*  FLOOR     */  Ins_FLOOR,
  4624.              /*  CEILING   */  Ins_CEILING,
  4625.              /*  ROUND[0]  */  Ins_ROUND,
  4626.              /*  ROUND[1]  */  Ins_ROUND,
  4627.              /*  ROUND[2]  */  Ins_ROUND,
  4628.              /*  ROUND[3]  */  Ins_ROUND,
  4629.              /*  NROUND[0] */  Ins_NROUND,
  4630.              /*  NROUND[1] */  Ins_NROUND,
  4631.              /*  NROUND[2] */  Ins_NROUND,
  4632.              /*  NROUND[3] */  Ins_NROUND,
  4633.              
  4634.              /*  WCvtF     */  Ins_WCVTF,
  4635.              /*  DeltaP2   */  Ins_DELTAP,
  4636.              /*  DeltaP3   */  Ins_DELTAP,
  4637.              /*  DeltaCn[0] */ Ins_DELTAC,
  4638.              /*  DeltaCn[1] */ Ins_DELTAC,
  4639.              /*  DeltaCn[2] */ Ins_DELTAC,
  4640.              /*  SROUND    */  Ins_SROUND,
  4641.              /*  S45Round  */  Ins_S45ROUND,
  4642.              /*  JROT      */  Ins_JROT,
  4643.              /*  JROF      */  Ins_JROF,
  4644.              /*  ROFF      */  Ins_ROFF,
  4645.              /*  INS_$7B   */  Ins_UNKNOWN,
  4646.              /*  RUTG      */  Ins_RUTG,
  4647.              /*  RDTG      */  Ins_RDTG,
  4648.              /*  SANGW     */  Ins_SANGW,
  4649.              /*  AA        */  Ins_AA,
  4650.              
  4651.              /*  FlipPT    */  Ins_FLIPPT,
  4652.              /*  FlipRgON  */  Ins_FLIPRGON,
  4653.              /*  FlipRgOFF */  Ins_FLIPRGOFF,
  4654.              /*  INS_$83   */  Ins_UNKNOWN,
  4655.              /*  INS_$84   */  Ins_UNKNOWN,
  4656.              /*  ScanCTRL  */  Ins_SCANCTRL,
  4657.              /*  SDPVTL[0] */  Ins_SDPVTL,
  4658.              /*  SDPVTL[1] */  Ins_SDPVTL,
  4659.              /*  GetINFO   */  Ins_GETINFO,
  4660.              /*  IDEF      */  Ins_IDEF,
  4661.              /*  ROLL      */  Ins_ROLL,
  4662.              /*  MAX       */  Ins_MAX,
  4663.              /*  MIN       */  Ins_MIN,
  4664.              /*  ScanTYPE  */  Ins_SCANTYPE,
  4665.              /*  InstCTRL  */  Ins_INSTCTRL,
  4666.              /*  INS_$8F   */  Ins_UNKNOWN,
  4667.              
  4668.              /*  INS_$90  */   Ins_UNKNOWN,
  4669.              /*  INS_$91  */   Ins_UNKNOWN,
  4670.              /*  INS_$92  */   Ins_UNKNOWN,
  4671.              /*  INS_$93  */   Ins_UNKNOWN,
  4672.              /*  INS_$94  */   Ins_UNKNOWN,
  4673.              /*  INS_$95  */   Ins_UNKNOWN,
  4674.              /*  INS_$96  */   Ins_UNKNOWN,
  4675.              /*  INS_$97  */   Ins_UNKNOWN,
  4676.              /*  INS_$98  */   Ins_UNKNOWN,
  4677.              /*  INS_$99  */   Ins_UNKNOWN,
  4678.              /*  INS_$9A  */   Ins_UNKNOWN,
  4679.              /*  INS_$9B  */   Ins_UNKNOWN,
  4680.              /*  INS_$9C  */   Ins_UNKNOWN,
  4681.              /*  INS_$9D  */   Ins_UNKNOWN,
  4682.              /*  INS_$9E  */   Ins_UNKNOWN,
  4683.              /*  INS_$9F  */   Ins_UNKNOWN,
  4684.              
  4685.              /*  INS_$A0  */   Ins_UNKNOWN,
  4686.              /*  INS_$A1  */   Ins_UNKNOWN,
  4687.              /*  INS_$A2  */   Ins_UNKNOWN,
  4688.              /*  INS_$A3  */   Ins_UNKNOWN,
  4689.              /*  INS_$A4  */   Ins_UNKNOWN,
  4690.              /*  INS_$A5  */   Ins_UNKNOWN,
  4691.              /*  INS_$A6  */   Ins_UNKNOWN,
  4692.              /*  INS_$A7  */   Ins_UNKNOWN,
  4693.              /*  INS_$A8  */   Ins_UNKNOWN,
  4694.              /*  INS_$A9  */   Ins_UNKNOWN,
  4695.              /*  INS_$AA  */   Ins_UNKNOWN,
  4696.              /*  INS_$AB  */   Ins_UNKNOWN,
  4697.              /*  INS_$AC  */   Ins_UNKNOWN,
  4698.              /*  INS_$AD  */   Ins_UNKNOWN,
  4699.              /*  INS_$AE  */   Ins_UNKNOWN,
  4700.              /*  INS_$AF  */   Ins_UNKNOWN,
  4701.              
  4702.              /*  PushB[0]  */  Ins_PUSHB,
  4703.              /*  PushB[1]  */  Ins_PUSHB,
  4704.              /*  PushB[2]  */  Ins_PUSHB,
  4705.              /*  PushB[3]  */  Ins_PUSHB,
  4706.              /*  PushB[4]  */  Ins_PUSHB,
  4707.              /*  PushB[5]  */  Ins_PUSHB,
  4708.              /*  PushB[6]  */  Ins_PUSHB,
  4709.              /*  PushB[7]  */  Ins_PUSHB,
  4710.              /*  PushW[0]  */  Ins_PUSHW,
  4711.              /*  PushW[1]  */  Ins_PUSHW,
  4712.              /*  PushW[2]  */  Ins_PUSHW,
  4713.              /*  PushW[3]  */  Ins_PUSHW,
  4714.              /*  PushW[4]  */  Ins_PUSHW,
  4715.              /*  PushW[5]  */  Ins_PUSHW,
  4716.              /*  PushW[6]  */  Ins_PUSHW,
  4717.              /*  PushW[7]  */  Ins_PUSHW,
  4718.              
  4719.              /*  MDRP[00]  */  Ins_MDRP,
  4720.              /*  MDRP[01]  */  Ins_MDRP,
  4721.              /*  MDRP[02]  */  Ins_MDRP,
  4722.              /*  MDRP[03]  */  Ins_MDRP,
  4723.              /*  MDRP[04]  */  Ins_MDRP,
  4724.              /*  MDRP[05]  */  Ins_MDRP,
  4725.              /*  MDRP[06]  */  Ins_MDRP,
  4726.              /*  MDRP[07]  */  Ins_MDRP,
  4727.              /*  MDRP[08]  */  Ins_MDRP,
  4728.              /*  MDRP[09]  */  Ins_MDRP,
  4729.              /*  MDRP[10]  */  Ins_MDRP,
  4730.              /*  MDRP[11]  */  Ins_MDRP,
  4731.              /*  MDRP[12]  */  Ins_MDRP,
  4732.              /*  MDRP[13]  */  Ins_MDRP,
  4733.              /*  MDRP[14]  */  Ins_MDRP,
  4734.              /*  MDRP[15]  */  Ins_MDRP,
  4735.              
  4736.              /*  MDRP[16]  */  Ins_MDRP,
  4737.              /*  MDRP[17]  */  Ins_MDRP,
  4738.              /*  MDRP[18]  */  Ins_MDRP,
  4739.              /*  MDRP[19]  */  Ins_MDRP,
  4740.              /*  MDRP[20]  */  Ins_MDRP,
  4741.              /*  MDRP[21]  */  Ins_MDRP,
  4742.              /*  MDRP[22]  */  Ins_MDRP,
  4743.              /*  MDRP[23]  */  Ins_MDRP,
  4744.              /*  MDRP[24]  */  Ins_MDRP,
  4745.              /*  MDRP[25]  */  Ins_MDRP,
  4746.              /*  MDRP[26]  */  Ins_MDRP,
  4747.              /*  MDRP[27]  */  Ins_MDRP,
  4748.              /*  MDRP[28]  */  Ins_MDRP,
  4749.              /*  MDRP[29]  */  Ins_MDRP,
  4750.              /*  MDRP[30]  */  Ins_MDRP,
  4751.              /*  MDRP[31]  */  Ins_MDRP,
  4752.              
  4753.              /*  MIRP[00]  */  Ins_MIRP,
  4754.              /*  MIRP[01]  */  Ins_MIRP,
  4755.              /*  MIRP[02]  */  Ins_MIRP,
  4756.              /*  MIRP[03]  */  Ins_MIRP,
  4757.              /*  MIRP[04]  */  Ins_MIRP,
  4758.              /*  MIRP[05]  */  Ins_MIRP,
  4759.              /*  MIRP[06]  */  Ins_MIRP,
  4760.              /*  MIRP[07]  */  Ins_MIRP,
  4761.              /*  MIRP[08]  */  Ins_MIRP,
  4762.              /*  MIRP[09]  */  Ins_MIRP,
  4763.              /*  MIRP[10]  */  Ins_MIRP,
  4764.              /*  MIRP[11]  */  Ins_MIRP,
  4765.              /*  MIRP[12]  */  Ins_MIRP,
  4766.              /*  MIRP[13]  */  Ins_MIRP,
  4767.              /*  MIRP[14]  */  Ins_MIRP,
  4768.              /*  MIRP[15]  */  Ins_MIRP,
  4769.              
  4770.              /*  MIRP[16]  */  Ins_MIRP,
  4771.              /*  MIRP[17]  */  Ins_MIRP,
  4772.              /*  MIRP[18]  */  Ins_MIRP,
  4773.              /*  MIRP[19]  */  Ins_MIRP,
  4774.              /*  MIRP[20]  */  Ins_MIRP,
  4775.              /*  MIRP[21]  */  Ins_MIRP,
  4776.              /*  MIRP[22]  */  Ins_MIRP,
  4777.              /*  MIRP[23]  */  Ins_MIRP,
  4778.              /*  MIRP[24]  */  Ins_MIRP,
  4779.              /*  MIRP[25]  */  Ins_MIRP,
  4780.              /*  MIRP[26]  */  Ins_MIRP,
  4781.              /*  MIRP[27]  */  Ins_MIRP,
  4782.              /*  MIRP[28]  */  Ins_MIRP,
  4783.              /*  MIRP[29]  */  Ins_MIRP,
  4784.              /*  MIRP[30]  */  Ins_MIRP,
  4785.              /*  MIRP[31]  */  Ins_MIRP
  4786.            };
  4787.  
  4788.  
  4789. /****************************************************************/
  4790. /*                                                              */
  4791. /*                    RUN                                       */
  4792. /*                                                              */
  4793. /*  This function executes a run of opcodes. It will exit       */
  4794. /*  in the following cases :                                    */
  4795. /*                                                              */
  4796. /*   - Errors ( in which case it returns FALSE )                */
  4797. /*                                                              */
  4798. /*   - Reaching the end of the main code range  (returns TRUE)  */
  4799. /*      reaching the end of a code range within a function      */
  4800. /*      call is an error.                                       */
  4801. /*                                                              */
  4802. /*   - After executing one single opcode, if the flag           */
  4803. /*     'Instruction_Trap' is set to TRUE. (returns TRUE)        */
  4804. /*                                                              */
  4805. /*  On exit whith TRUE, test IP < CodeSize to know wether it    */
  4806. /*  comes from a instruction trap or a normal termination       */
  4807. /*                                                              */
  4808. /*                                                              */
  4809. /*     Note : The documented DEBUG opcode pops a value from     */
  4810. /*            the stack. This behaviour is unsupported, here    */
  4811. /*            a DEBUG opcode is always an error.                */
  4812. /*                                                              */
  4813. /*                                                              */
  4814. /* THIS IS THE INTERPRETER'S MAIN LOOP                          */
  4815. /*                                                              */
  4816. /*  Instructions appear in the specs' order                     */
  4817. /*                                                              */
  4818. /****************************************************************/
  4819.  
  4820. #ifndef DEBUG
  4821. TT_Error  RunIns( PExecution_Context exc ) 
  4822. #else
  4823. TT_Error  RunIns2( PExecution_Context exc )
  4824. #endif
  4825. {
  4826.   Bool Result;
  4827.   Int A;
  4828.   TDefRecord *WITH;
  4829.   TCallRecord *WITH1;
  4830.  
  4831.   COMPUTE_Funcs();
  4832.   Compute_Round( EXEC_ARGS exc->GS.round_state);
  4833.  
  4834.   do 
  4835.   {
  4836.     CALC_Length();
  4837.  
  4838.     /* First, let's check for empty stack and overflow */
  4839.  
  4840.     CUR.args = CUR.top - Pop_Push_Count[ CUR.opcode*2 ];
  4841.  
  4842.     /* args is the top of the stack once arguments have been popped */
  4843.     /* one can also see it as the index of the last argument        */
  4844.  
  4845.     if (CUR.args < 0)
  4846.     {
  4847.       CUR.error = TT_Err_Too_Few_Arguments;
  4848.       goto _LErrorLabel;
  4849.     }
  4850.  
  4851.     CUR.new_top = CUR.args + Pop_Push_Count[ CUR.opcode*2+1 ];
  4852.  
  4853.     /* new_top  is the new top of the stack, after the instruction's */
  4854.     /* execution. top will be set to new_top after the 'case'        */
  4855.  
  4856.     if (CUR.new_top > CUR.stackSize)
  4857.     {
  4858.       CUR.error = TT_Err_Stack_Overflow;
  4859.       goto _LErrorLabel;
  4860.     }
  4861.  
  4862.     CUR.step_ins = TRUE;
  4863.     CUR.error    = TT_Err_Ok;
  4864.  
  4865.     Instruct_Dispatch[CUR.opcode]( EXEC_ARGS &CUR.stack[CUR.args] );
  4866.  
  4867.     if (CUR.error != TT_Err_Ok) 
  4868.     {
  4869.       switch (CUR.error)
  4870.       {
  4871.         case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
  4872.           A = 0;
  4873.           while (A < CUR.numIDefs) 
  4874.           {
  4875.             WITH = &CUR.IDefs[A];
  4876.             if (WITH->Active && CUR.opcode == WITH->Opc)
  4877.             {
  4878.               if (CUR.callTop >= CUR.callSize)
  4879.               {
  4880.                 CUR.error = TT_Err_Invalid_Reference;
  4881.                 goto _LErrorLabel;
  4882.               }
  4883.         
  4884.               WITH1 = &CUR.callStack[CUR.callTop];
  4885.         
  4886.               WITH1->Caller_Range = CUR.curRange;
  4887.               WITH1->Caller_IP    = CUR.IP + 1;
  4888.               WITH1->Cur_Count    = 1;
  4889.               WITH1->Cur_Restart  = WITH->Start;
  4890.  
  4891.               if ( INS_Goto_CodeRange( WITH->Range, WITH->Start ) == FAILURE )
  4892.                 goto _LErrorLabel;
  4893.         
  4894.               goto _LSuiteLabel;
  4895.             }
  4896.             else 
  4897.             {
  4898.               A++;
  4899.               continue;
  4900.             }
  4901.           }
  4902.           CUR.error = TT_Err_Invalid_Opcode;
  4903.           goto _LErrorLabel;
  4904.           break;
  4905.  
  4906.         default:
  4907.           CUR.error = CUR.error;
  4908.           goto _LErrorLabel;
  4909.           break;
  4910.       }
  4911.     }
  4912.  
  4913.     CUR.top = CUR.new_top;
  4914.  
  4915.     if (CUR.step_ins)
  4916.       CUR.IP += CUR.length;
  4917.  
  4918. _LSuiteLabel:
  4919.  
  4920.     if (CUR.IP >= CUR.codeSize) 
  4921.     {
  4922.       if (CUR.callTop > 0) 
  4923.       {
  4924.         CUR.error = TT_Err_Code_Overflow;
  4925.         goto _LErrorLabel;
  4926.       } 
  4927.       else
  4928.         goto _LNo_Error;
  4929.     }
  4930.  
  4931.  
  4932.   } while ( !CUR.instruction_trap );
  4933.  
  4934. _LNo_Error:
  4935.   Result = SUCCESS;
  4936.   /* Load_Instance_Context(aIns); */
  4937.   return TT_Err_Ok;
  4938.  
  4939. _LErrorLabel:
  4940.   Result = FAILURE;
  4941.  
  4942.   /* Load_Instance_Context(aIns); */
  4943.  
  4944.   return CUR.error;
  4945. }
  4946.  
  4947.  
  4948.  
  4949. #ifdef DEBUG
  4950.  
  4951. TT_Error  RunIns( PExecution_Context exc ) 
  4952. {
  4953.   Bool Result;
  4954.   Int  A, next_IP, diff;
  4955.   char ch, *temp;
  4956.  
  4957.   TT_Error  error;
  4958.  
  4959.   TVecRecord  save;
  4960.   TVecRecord  pts;
  4961.  
  4962. #define TT_Round_Off             5
  4963. #define TT_Round_To_Half_Grid    0
  4964. #define TT_Round_To_Grid         1
  4965. #define TT_Round_To_Double_Grid  2
  4966. #define TT_Round_Up_To_Grid      4
  4967. #define TT_Round_Down_To_Grid    3
  4968. #define TT_Round_Super           6
  4969. #define TT_Round_Super_45        7
  4970.  
  4971.   const char* round_str[8] =
  4972.          {
  4973.            "to half-grid",
  4974.            "to grid",
  4975.            "to double grid",
  4976.            "down to grid",
  4977.            "up to grid",
  4978.            "off",
  4979.            "super",
  4980.            "super 45"
  4981.          };
  4982.  
  4983. /*
  4984.   if ( !Goto_CodeRange( exc, TT_CodeRange_Glyph, 0 ) )
  4985.     return FAILURE;
  4986.  
  4987.   exc->pts = ((PInstance)exc->owner)->pts;
  4988.   exc->numContours = ((PInstance)exc)->numContours;
  4989.  
  4990.   exc->zp0 = exc->pts;
  4991.   exc->zp1 = exc->pts;
  4992.   exc->zp2 = exc->pts;
  4993.  
  4994.   exc->GS  = exc->default_GS;
  4995.  
  4996.   exc->GS.gep0 = 1;
  4997.   exc->GS.gep1 = 1;
  4998.   exc->GS.gep2 = 1;
  4999.  
  5000.   exc->GS.projVector.x = 0x4000;
  5001.   exc->GS.projVector.y = 0x0000;
  5002.   exc->GS.freeVector.x = 0x4000;
  5003.   exc->GS.freeVector.y = 0x0000;
  5004.   exc->GS.dualVector.x = 0x4000;
  5005.   exc->GS.dualVector.y = 0x0000;
  5006.  
  5007.   exc->GS.round_state = 1;
  5008.  
  5009.   exc->top = 0;
  5010.   / * some glyphs leave something on the stack !! * /
  5011.   / * we must empty it                            * /
  5012. */
  5013.  
  5014.   if ( exc->curRange != TT_CodeRange_Cvt )
  5015.     return RunIns2( exc );
  5016.  
  5017.   pts = exc->pts;
  5018.  
  5019.   save.n = pts.n;
  5020.  
  5021.   save.org_x = (PCoordinates)malloc( sizeof(TT_F26Dot6)*save.n );
  5022.   save.org_y = (PCoordinates)malloc( sizeof(TT_F26Dot6)*save.n );
  5023.   save.cur_x = (PCoordinates)malloc( sizeof(TT_F26Dot6)*save.n );
  5024.   save.cur_y = (PCoordinates)malloc( sizeof(TT_F26Dot6)*save.n );
  5025.   save.touch = (PByte)malloc( save.n );
  5026.  
  5027.   exc->instruction_trap = 1;
  5028.  
  5029.   do 
  5030.   {
  5031.     if ( CUR.IP < CUR.codeSize )
  5032.     {
  5033.       CALC_Length();
  5034.   
  5035.       CUR.args = CUR.top - Pop_Push_Count[ CUR.opcode*2 ];
  5036.   
  5037.       /* args is the top of the stack once arguments have been popped */
  5038.       /* one can also see it as the index of the last argument        */
  5039.   
  5040.       /* First print the current stack */
  5041.   
  5042.       A = CUR.args-4;
  5043.       if ( A < 0 ) A = 0;
  5044.   
  5045.       while ( A < CUR.top )
  5046.       {
  5047.         DebugTrace(( "%04lx ", CUR.stack[A] ));
  5048.         A++;
  5049.         if ( A == CUR.args ) DebugTrace(( "* " ));
  5050.       }
  5051.       DebugTrace(( "\n" ));
  5052.   
  5053.       /* Now print the current line */
  5054.  
  5055. #if 1
  5056.       DebugTrace(( "%s\n", (char*)Cur_U_Line( &CUR ) ));
  5057. #endif
  5058.   
  5059.       /* First, check for empty stack and overflow */
  5060.   
  5061.       if (CUR.args < 0)
  5062.       {
  5063.         DebugTrace(( "ERROR : Too Few Arguments\n" ));
  5064.         CUR.error = TT_Err_Too_Few_Arguments;
  5065.         goto _LErrorLabel;
  5066.       }
  5067.   
  5068.       CUR.new_top = CUR.args + Pop_Push_Count[ CUR.opcode*2+1 ];
  5069.   
  5070.       /* new_top  is the new top of the stack, after the instruction's */
  5071.       /* execution. top will be set to new_top after the 'case'        */
  5072.   
  5073.       if (CUR.new_top > CUR.stackSize)
  5074.       {
  5075.         DebugTrace(( "ERROR : Stack overflow\n" ));
  5076.         CUR.error = TT_Err_Stack_Overflow;
  5077.         goto _LErrorLabel;
  5078.       }
  5079.     }
  5080.     else
  5081.       DebugTrace(( "End of program reached.\n" ));
  5082.   
  5083.     do
  5084.     {
  5085. #ifdef OS2
  5086.       ch = getch();
  5087.       if ( ch > ' ' ) DebugTrace(( "%c\n", ch ));
  5088. #else
  5089.       ch = getchar();
  5090. #endif
  5091.       switch (ch)
  5092.       {
  5093.         case '\n':
  5094.       ch = '\0';
  5095.       break;
  5096.  
  5097.         case '?' :
  5098.           DebugTrace(( "Help\n\n" ));
  5099.           DebugTrace(( "?   Show this page\n" ));
  5100.           DebugTrace(( "q   Quit debugger\n" ));
  5101.           DebugTrace(( "n   Next instruction\n" ));
  5102.           DebugTrace(( "s   Step into\n" ));
  5103.           DebugTrace(( "v   Show vector info\n" ));
  5104.           DebugTrace(( "p   Show points zone\n\n" ));
  5105.           ch = '\0';
  5106.           break;
  5107.  
  5108.         case 'v' :
  5109.           DebugTrace(( "freedom    (%04hx,%04hx)\n", 
  5110.                        exc->GS.freeVector.x,
  5111.                        exc->GS.freeVector.y ));
  5112.           DebugTrace(( "projection (%04hx,%04hx)\n", 
  5113.                        exc->GS.projVector.x,
  5114.                        exc->GS.projVector.y ));
  5115.           DebugTrace(( "dual       (%04hx,%04hx)\n\n", 
  5116.                        exc->GS.dualVector.x,
  5117.                        exc->GS.dualVector.y ));
  5118.           ch = '\0';
  5119.           break;
  5120.  
  5121.         case 'g' :
  5122.           DebugTrace(( "rounding   %s\n", round_str[exc->GS.round_state] ));
  5123.           DebugTrace(( "min dist   %04lx\n", exc->GS.minimum_distance ));
  5124.           DebugTrace(( "cvt_cutin  %04lx\n", exc->GS.control_value_cutin ));
  5125.           ch = '\0';
  5126.           break;
  5127.  
  5128.         case 'p' :
  5129.           for ( A = 0; A < exc->pts.n; A++ )
  5130.           {
  5131.             DebugTrace(( "%02hx  ", A ));
  5132.  
  5133.             DebugTrace(( "%08lx,%08lx - ", 
  5134.                          pts.org_x[A],
  5135.                          pts.org_y[A] ));
  5136.  
  5137.             DebugTrace(( "%08lx,%08lx\n", 
  5138.                          pts.cur_x[A],
  5139.                          pts.cur_y[A] ));
  5140.           }
  5141.           DebugTrace(( "\n" ));
  5142.           ch = '\0';
  5143.           break;
  5144.       }
  5145.     }
  5146.     while ( ch == '\0' );
  5147.  
  5148.     MEM_Copy( save.org_x, pts.org_x, pts.n * sizeof(TT_F26Dot6) );
  5149.     MEM_Copy( save.org_y, pts.org_y, pts.n * sizeof(TT_F26Dot6) );
  5150.     MEM_Copy( save.cur_x, pts.cur_x, pts.n * sizeof(TT_F26Dot6) );
  5151.     MEM_Copy( save.cur_y, pts.cur_y, pts.n * sizeof(TT_F26Dot6) );
  5152.     MEM_Copy( save.touch, pts.touch, pts.n );
  5153.  
  5154.     switch (ch)
  5155.     {
  5156.       case 'q':
  5157.         goto _LErrorLabel;
  5158.  
  5159.       case 's' :
  5160.         if ( CUR.IP < CUR.codeSize )
  5161.           if ( (error = RunIns2( exc )) )
  5162.             goto _LErrorLabel;
  5163.         break;
  5164.  
  5165.       case 'n' :
  5166.         if ( CUR.IP < CUR.codeSize )
  5167.         {
  5168.           next_IP = CUR.IP + CUR.length;
  5169.           while ( CUR.IP != next_IP )
  5170.           {
  5171.             if ( (error = RunIns2( exc )) )
  5172.               goto _LErrorLabel;
  5173.           }
  5174.         }
  5175.         break;
  5176.  
  5177.       default:
  5178.         DebugTrace(( "unknown command. Press ? for help\n" ));
  5179.     }
  5180.  
  5181.     for ( A = 0; A < pts.n; A++ )
  5182.     {
  5183.       diff = 0;
  5184.       if ( save.org_x[A] != pts.org_x[A] ) diff |= 1;
  5185.       if ( save.org_y[A] != pts.org_y[A] ) diff |= 2;
  5186.       if ( save.cur_x[A] != pts.cur_x[A] ) diff |= 4;
  5187.       if ( save.cur_y[A] != pts.cur_y[A] ) diff |= 8;
  5188.       if ( save.touch[A] != pts.touch[A] ) diff |= 16;
  5189.  
  5190.       if ( diff )
  5191.       {
  5192.         DebugTrace(( "%02hx  ", A ));
  5193.  
  5194.         if ( diff & 16 ) temp = "(%01hx)"; else temp = " %01hx ";
  5195.         DebugTrace(( temp, save.touch[A] & 7 ));
  5196.  
  5197.         if ( diff & 1 ) temp = "(%08lx)"; else temp = " %08lx ";
  5198.         DebugTrace(( temp, save.org_x[A] ));
  5199.  
  5200.         if ( diff & 2 ) temp = "(%08lx)"; else temp = " %08lx ";
  5201.         DebugTrace(( temp, save.org_y[A] ));
  5202.  
  5203.         if ( diff & 4 ) temp = "(%08lx)"; else temp = " %08lx ";
  5204.         DebugTrace(( temp, save.cur_x[A] ));
  5205.  
  5206.         if ( diff & 8 ) temp = "(%08lx)"; else temp = " %08lx ";
  5207.         DebugTrace(( temp, save.cur_y[A] ));
  5208.  
  5209.         DebugTrace(( "\n" ));
  5210.  
  5211.         DebugTrace(( "%02hx  ", A ));
  5212.  
  5213.         if ( diff & 16 ) temp = "[%01hx]"; else temp = " %01hx ";
  5214.         DebugTrace(( temp, pts.touch[A] & 7 ));
  5215.  
  5216.         if ( diff & 1 ) temp = "[%08lx]"; else temp = " %08lx ";
  5217.         DebugTrace(( temp, pts.org_x[A] ));
  5218.  
  5219.         if ( diff & 2 ) temp = "[%08lx]"; else temp = " %08lx ";
  5220.         DebugTrace(( temp, pts.org_y[A] ));
  5221.  
  5222.         if ( diff & 4 ) temp = "[%08lx]"; else temp = " %08lx ";
  5223.         DebugTrace(( temp, pts.cur_x[A] ));
  5224.  
  5225.         if ( diff & 8 ) temp = "[%08lx]"; else temp = " %08lx ";
  5226.         DebugTrace(( temp, pts.cur_y[A] ));
  5227.  
  5228.         DebugTrace(( "\n\n" ));
  5229.       }
  5230.     }
  5231.  
  5232.   } while ( TRUE );
  5233.  
  5234. _LErrorLabel:
  5235.   Result = FAILURE;
  5236.  
  5237.   /* Load_Instance_Context(aIns); */
  5238.  
  5239.   return error;
  5240. }
  5241.  
  5242. #endif /* DEBUG */
  5243.  
  5244.  
  5245.  
  5246. /* End. */
  5247.  
  5248.