1 (*******************************************************************
5 * TrueType bytecode intepreter.
7 * Copyright 1996 David Turner, Robert Wilhelm and Werner Lemberg
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.
16 * Changes between 2.0 and 1.2 :
18 * - Lots, lots, of changes : This version is not re-entrant,
22 ******************************************************************)
32 function Run_Ins( exec
: PExec_Context
) : Boolean;
33 (* Run the interpreter with the current code range and IP *)
42 TInstruction_Function
= procedure( args
: PStorage
);
45 Null_Vector
: TT_Vector
= (x
:0;y
:0);
48 exc
: TExec_Context
; (* static variable *)
52 (*********************************************************************)
54 (* Before an opcode is executed, the interpreter verifies that *)
55 (* there are enough arguments on the stack, with the help of *)
56 (* the Pop_Push_Count table. *)
58 (* Note that for opcodes with a varying numbre of parameters, *)
59 (* either 0 or 1 arg is verified before execution, depending *)
60 (* on the nature of the instruction : *)
62 (* - if the number of arguments is given by the bytecode *)
63 (* stream or the loop variable, 0 is chosen. *)
65 (* - if the first argument is a count n that is followed *)
66 (* by arguments a1..an, then 1 is chosen. *)
68 (*********************************************************************)
70 Pop_Push_Count
: array[0..511] of byte
112 (* MINDEX *) 1, 0, (* first arg *)
125 (* SHP[0] *) 0, 0, (* no args *)
126 (* SHP[1] *) 0, 0, (* no args *)
131 (* SHPIX *) 1, 0, (* first arg *)
132 (* IP *) 0, 0, (* no args *)
135 (* AlignRP *) 0, 0, (* no args *)
170 (* DeltaP1 *) 1, 0, (* first arg *)
192 (* DeltaP2 *) 1, 0, (* first arg *)
193 (* DeltaP3 *) 1, 0, (* first arg *)
194 (* DeltaCn[0]*) 1, 0, (* first arg *)
195 (* DeltaCn[1]*) 1, 0, (* first arg *)
196 (* DeltaCn[2]*) 1, 0, (* first arg *)
208 (* FlipPT *) 0, 0, (* no args *)
218 (* ROLL *) 3, 3, (* pops 3 args/push 3 args *)
346 (*******************************************************************
350 * Description : returns the norm (length) of a vector
352 * Input : X, Y vector
354 * Output : returns length in F26dot6
356 *****************************************************************)
358 function Norm( X
, Y
: TT_F26dot6
): TT_F26dot6
;
367 if ( (T1
.lo
or T1
.Hi
) = 0 ) then Norm
:= 0
368 else Norm
:= Sqrt64( T1
);
371 (*******************************************************************
373 * Function : Scale_Pixels
375 * Description : Converts from FUnits to Fractional pixels
378 *****************************************************************)
380 function Scale_Pixels( value
: long
) : TT_F26Dot6
;
381 {$IFDEF INLINE} inline; {$ENDIF}
383 Scale_Pixels
:= MulDiv_Round( value
,
385 exc
.metrics
.scale2
);
388 function Get_Current_Ratio
: Long
;
392 if exc
.metrics
.ratio
<> 0 then
393 Get_Current_Ratio
:= exc
.metrics
.ratio
396 if exc
.GS
.projVector
.y
= 0 then
397 exc
.metrics
.ratio
:= exc
.metrics
.x_ratio
399 else if exc
.GS
.projVector
.x
= 0 then
400 exc
.metrics
.ratio
:= exc
.metrics
.y_ratio
404 x
:= MulDiv_Round( exc
.GS
.projVector
.x
,
408 y
:= MulDiv_Round( exc
.GS
.projVector
.y
,
412 exc
.metrics
.ratio
:= Norm( x
, y
);
415 Get_Current_Ratio
:= exc
.metrics
.ratio
;
419 function Get_Ppem
: Long
;
420 {$IFDEF INLINE} inline; {$ENDIF}
422 Get_Ppem
:= MulDiv_Round( exc
.metrics
.ppem
, Get_Current_Ratio
, $10000 );
426 function Read_CVT( index
: Int
) : TT_F26Dot6
;
427 {$IFNDEF FPK} far; {$ENDIF}
429 Read_CVT
:= exc
.cvt
^[index
];
432 function Read_CVT_Stretched( index
: Int
) : TT_F26Dot6
; far;
434 Read_CVT_Stretched
:= MulDiv_Round( exc
.cvt
^[index
],
440 procedure Write_CVT( index
: Int
; value
: TT_F26Dot6
); far;
442 exc
.cvt
^[index
] := value
;
445 procedure Write_CVT_Stretched( index
: Int
; value
: TT_F26Dot6
); far;
447 exc
.cvt
^[index
] := MulDiv_Round( value
,
453 procedure Move_CVT( index
: Int
; value
: TT_F26Dot6
); far;
455 inc( exc
.cvt
^[index
], value
);
458 procedure Move_CVT_Stretched( index
: Int
; value
: TT_F26dot6
); far;
460 inc( exc
.cvt
^[index
], MulDiv_Round( value
,
462 Get_Current_Ratio
));
465 (*******************************************************************
467 * Function : Calc_Length
469 * Description : Computes the length in bytes of current opcode
471 *****************************************************************)
473 function Calc_Length
: boolean;
475 Calc_Length
:= false;
477 exc
.opcode
:= exc
.Code
^[exc
.IP
];
481 $40 : if exc
.IP
+1 >= exc
.codeSize
484 exc
.length
:= exc
.code
^[exc
.IP
+1] + 2;
486 $41 : if exc
.IP
+1 >= exc
.codeSize
489 exc
.length
:= exc
.code
^[exc
.IP
+1]*2 + 2;
491 $B0..$B7 : exc
.length
:= exc
.opcode
-$B0 + 2;
492 $B8..$BF : exc
.length
:= (exc
.opcode
-$B8)*2 + 3;
497 Calc_Length
:= exc
.IP
+exc
.length
<= exc
.codeSize
;
500 (*******************************************************************
502 * Function : Get_Short
504 * Description : Return a short integer taken from the instruction
505 * stream at address IP.
509 * Output : Short read at Code^[IP..IP+1]
511 * Notes : This one could become a Macro in the C version
513 *****************************************************************)
515 function GetShort
: Short
;
517 L
: Array[0..1] of Byte;
518 resultat
: Short
absolute L
; (* XXX : un-portable *)
520 (* This is little-endian code *)
522 L
[1] := exc
.code
^[exc
.IP
]; inc(exc
.IP
);
523 L
[0] := exc
.code
^[exc
.IP
]; inc(exc
.IP
);
524 GetShort
:= resultat
;
528 function Goto_CodeRange( aRange
,
529 aIP
: Int
): boolean;
532 Goto_CodeRange
:= False;
536 if (aRange
<1) or (aRange
>3) then
538 exc
.error
:= TT_Err_Bad_Argument
;
542 with CodeRangeTable
[ARange
] do
545 if Base
= nil then (* invalid coderange *)
547 error
:= TT_Err_Invalid_Coderange
;
551 (* NOTE : Because the last instruction of a program may be a CALL *)
552 (* which will return to the first byte *after* the code *)
553 (* range, we test for AIP <= Size, instead of AIP < Size *)
557 error
:= TT_Err_Code_Overflow
;
558 Goto_CodeRange
:= False;
570 Goto_CodeRange
:= True;
574 (*******************************************************************
576 * Function : Direct_Move
578 * Description : Moves a point by a given distance along the
581 * Input : Vx, Vy point coordinates to move
582 * touch touch flag to modify
587 *****************************************************************)
590 procedure Direct_Move( zone
: PGlyph_Zone
;
592 distance
: TT_F26dot6
);
596 v
:= exc
.GS
.freeVector
.x
;
599 inc( zone
^.cur
^[point
].x
, MulDiv_Round( distance
,
603 zone
^.flags
^[point
] := zone
^.flags
^[point
] or TT_Flag_Touched_X
;
606 v
:= exc
.GS
.freeVector
.y
;
609 inc( zone
^.cur
^[point
].y
, MulDiv_Round( distance
,
613 zone
^.flags
^[point
] := zone
^.flags
^[point
] or TT_Flag_Touched_Y
;
617 (* The following versions are used whenever both vectors are both *)
618 (* along one of the coordinate unit vectors, i.e. in 90% cases *)
620 procedure Direct_Move_X( zone
: PGlyph_Zone
;
622 distance
: TT_F26dot6
);
624 inc( zone
^.cur
^[point
].x
, distance
);
625 zone
^.flags
^[point
] := zone
^.flags
^[point
] or TT_Flag_Touched_X
;
628 procedure Direct_Move_Y( zone
: PGlyph_Zone
;
630 distance
: TT_F26dot6
);
632 inc( zone
^.cur
^[point
].y
, distance
);
633 zone
^.flags
^[point
] := zone
^.flags
^[point
] or TT_Flag_Touched_Y
;
636 (*******************************************************************
638 * Function : Round_None
640 * Description : Do not round, but add engine compensation
642 * Input : distance : distance to round
643 * compensation : engine compensation
645 * Output : rounded distance
647 * NOTE : The spec says very few about the relationship between
648 * rounding and engine compensation. However, it seems
649 * from the description of super round that we should
650 * should add the compensation before rounding
652 *****************************************************************)
654 function Round_None( distance
: TT_F26dot6
;
655 compensation
: TT_F26dot6
) : TT_F26dot6
;
659 if distance
>= 0 then
661 val
:= distance
+ compensation
;
662 if val
< 0 then val
:= 0;
666 val
:= distance
- compensation
;
667 if val
> 0 then val
:= 0;
673 (*******************************************************************
675 * Function : Round_To_Grid
677 * Description : round value to grid after adding engine
680 * Input : distance : distance to round
681 * compensation : engine compensation
683 * Output : rounded distance
685 *****************************************************************)
687 function Round_To_Grid( distance
: TT_F26dot6
;
688 compensation
: TT_F26dot6
) : TT_F26dot6
;
692 if distance
>= 0 then
694 val
:= (distance
+ 32 + compensation
) and -64;
695 if val
< 0 then val
:= 0;
699 val
:= - ((compensation
- distance
+ 32) and -64);
700 if val
> 0 then val
:= 0;
703 Round_To_Grid
:= val
;
706 (*******************************************************************
708 * Function : Round_To_Half_Grid
710 * Description : round value to half grid after adding engine
713 * Input : distance : distance to round
714 * compensation : engine compensation
716 * Output : rounded distance
718 *****************************************************************)
720 function Round_To_Half_Grid( distance
: TT_F26dot6
;
721 compensation
: TT_F26dot6
) : TT_F26dot6
;
725 if distance
>= 0 then
727 val
:= (distance
+ compensation
) and -64 + 32;
728 if val
< 0 then val
:= 0;
732 val
:= - ((-distance
+ compensation
) and -64 + 32);
733 if val
> 0 then val
:= 0;
736 Round_To_Half_Grid
:= val
;
740 (*******************************************************************
742 * Function : Round_Down_To_Grid
744 * Description : round value down to grid after adding engine
747 * Input : distance : distance to round
748 * compensation : engine compensation
750 * Output : rounded distance
752 *****************************************************************)
754 function Round_Down_To_Grid( distance
: TT_F26dot6
;
755 compensation
: TT_F26dot6
) : TT_F26dot6
;
759 if distance
>= 0 then
761 val
:= (distance
+ compensation
) and -64;
762 if val
< 0 then val
:= 0;
766 val
:= - ((-distance
+ compensation
) and -64);
767 if val
> 0 then val
:= 0;
770 Round_Down_To_Grid
:= val
;
773 (*******************************************************************
775 * Function : Round_Up_To_Grid
777 * Description : round value up to grid after adding engine
780 * Input : distance : distance to round
781 * compensation : engine compensation
783 * Output : rounded distance
785 *****************************************************************)
787 function Round_Up_To_Grid( distance
: TT_F26dot6
;
788 compensation
: TT_F26dot6
) : TT_F26dot6
;
792 if distance
>= 0 then
794 val
:= (distance
+ 63 + compensation
) and -64;
795 if val
< 0 then val
:= 0;
799 val
:= - ((-distance
+ 63 + compensation
) and -64);
800 if val
> 0 then val
:= 0;
803 Round_Up_To_Grid
:= val
;
806 (*******************************************************************
808 * Function : Round_To_Double_Grid
810 * Description : round value to double grid after adding engine
813 * Input : distance : distance to round
814 * compensation : engine compensation
816 * Output : rounded distance
818 *****************************************************************)
820 function Round_To_Double_Grid( distance
: TT_F26dot6
;
821 compensation
: TT_F26dot6
) : TT_F26dot6
;
825 if distance
>= 0 then
827 val
:= (distance
+ 16 + compensation
) and -32;
828 if val
< 0 then val
:= 0;
832 val
:= - ((-distance
+ 16 + compensation
) and -32);
833 if val
> 0 then val
:= 0;
836 Round_To_Double_Grid
:= val
;
839 (*******************************************************************
841 * Function : Round_Super
843 * Description : super round value to grid after adding engine
846 * Input : distance : distance to round
847 * compensation : engine compensation
849 * Output : rounded distance
851 * NOTE : The spec says very few about the relationship between
852 * rounding and engine compensation. However, it seems
853 * from the description of super round that we should
854 * should add the compensation before rounding
856 *****************************************************************)
858 function Round_Super( distance
: TT_F26dot6
;
859 compensation
: TT_F26dot6
) : TT_F26dot6
;
865 if distance
>= 0 then
867 val
:= (distance
- phase
+ threshold
+ compensation
) and -period
;
868 if val
< 0 then val
:= 0;
873 val
:= -((-distance
- phase
+ threshold
+ compensation
) and -period
);
874 if val
> 0 then val
:= 0;
881 (*******************************************************************
883 * Function : Round_Super_45
885 * Description : super round value to grid after adding engine
888 * Input : distance : distance to round
889 * compensation : engine compensation
891 * Output : rounded distance
893 * NOTE : There is a separate function for Round_Super_45 as we
894 * may need a greater precision.
896 *****************************************************************)
898 function Round_Super_45( distance
: TT_F26dot6
;
899 compensation
: TT_F26dot6
) : TT_F26dot6
;
905 if distance
>= 0 then
907 val
:= ((distance
- phase
+ threshold
+ compensation
) div period
)
909 if val
< 0 then val
:= 0;
914 val
:= -((-distance
- phase
+ threshold
+ compensation
) div period
916 if val
> 0 then val
:= 0;
920 Round_Super_45
:= val
;
924 procedure Compute_Round( round_mode
: Byte );
929 TT_Round_Off
: exc
.func_round
:= @Round_None
;
930 TT_Round_To_Grid
: exc
.func_round
:= @Round_To_Grid
;
931 TT_Round_Up_To_Grid
: exc
.func_round
:= @Round_Up_To_Grid
;
932 TT_Round_Down_To_Grid
: exc
.func_round
:= @Round_Down_To_Grid
;
933 TT_Round_To_Half_Grid
: exc
.func_round
:= @Round_To_Half_Grid
;
934 TT_Round_To_Double_Grid
: exc
.func_round
:= @Round_To_Double_Grid
;
935 TT_Round_Super
: exc
.func_round
:= @Round_Super
;
936 TT_Round_Super_45
: exc
.func_round
:= @Round_Super_45
;
938 TT_Round_Off
: exc
.func_round
:= Round_None
;
939 TT_Round_To_Grid
: exc
.func_round
:= Round_To_Grid
;
940 TT_Round_Up_To_Grid
: exc
.func_round
:= Round_Up_To_Grid
;
941 TT_Round_Down_To_Grid
: exc
.func_round
:= Round_Down_To_Grid
;
942 TT_Round_To_Half_Grid
: exc
.func_round
:= Round_To_Half_Grid
;
943 TT_Round_To_Double_Grid
: exc
.func_round
:= Round_To_Double_Grid
;
944 TT_Round_Super
: exc
.func_round
:= Round_Super
;
945 TT_Round_Super_45
: exc
.func_round
:= Round_Super_45
;
951 (*******************************************************************
953 * Function : SetSuperRound
955 * Description : Set Super Round parameters
957 * Input : GridPeriod Grid period
958 * OpCode SROUND opcode
964 *****************************************************************)
966 procedure SetSuperRound( GridPeriod
: TT_F26dot6
; selector
: Long
);
972 Case selector
and $C0 of
974 $00 : period
:= GridPeriod
div 2;
975 $40 : period
:= GridPeriod
;
976 $80 : period
:= GridPeriod
* 2;
978 (* This opcode is reserved, but ... *)
980 $C0 : period
:= GridPeriod
;
983 Case selector
and $30 of
986 $10 : phase
:= period
div 4;
987 $20 : phase
:= period
div 2;
988 $30 : phase
:= gridPeriod
*3 div 4;
991 if selector
and $F = 0 then
993 Threshold
:= Period
-1
995 Threshold
:= (Integer( selector
and $F )-4)*period
div 8;
997 period
:= period
div 256;
998 phase
:= phase
div 256;
999 threshold
:= threshold
div 256;
1004 (*******************************************************************
1006 * Function : Project
1008 * Description : Computes the projection of (Vx,Vy) along the
1009 * current projection vector
1011 * Input : Vx, Vy input vector
1013 * Output : return distance in F26dot6
1015 *****************************************************************)
1018 function Project( var P1
, P2
: TT_Vector
) : TT_F26dot6
;
1022 with exc
.GS
.projVector
do
1024 MulTo64( P1
.x
- P2
.x
, x
, T1
);
1025 MulTo64( P1
.y
- P2
.y
, y
, T2
);
1028 Add64( T1
, T2
, T1
);
1030 Project
:= Div64by32( T1
, $4000 );
1034 function Dual_Project( var P1
, P2
: TT_Vector
) : TT_F26dot6
;
1038 with exc
.GS
.dualVector
do
1040 MulTo64( P1
.x
- P2
.x
, x
, T1
);
1041 MulTo64( P1
.y
- P2
.y
, y
, T2
);
1044 Add64( T1
, T2
, T1
);
1046 Dual_Project
:= Div64by32( T1
, $4000 );
1050 function Free_Project( var P1
, P2
: TT_Vector
) : TT_F26dot6
;
1054 with exc
.GS
.freeVector
do
1056 MulTo64( P1
.x
- P2
.x
, x
, T1
);
1057 MulTo64( P1
.y
- P2
.y
, y
, T2
);
1060 Add64( T1
, T2
, T1
);
1062 Free_Project
:= Div64by32( T1
, $4000 );
1066 function Project_x( var P1
, P2
: TT_Vector
) : TT_F26dot6
;
1068 Project_x
:= P1
.x
- P2
.x
;
1071 function Project_y( var P1
, P2
: TT_Vector
) : TT_F26dot6
;
1073 Project_y
:= P1
.y
- P2
.y
;
1077 (*******************************************************************
1079 * Function : Compute_Funcs
1081 * Description : Computes the projections and movement function
1082 * pointers according to the current graphics state
1086 *****************************************************************)
1088 procedure Compute_Funcs
;
1093 if (freeVector
.x
= $4000) then
1096 func_freeProj
:= @Project_x
;
1098 func_freeProj
:= Project_x
;
1100 F_dot_P
:= Long(projVector
.x
) * $10000;
1103 if (freeVector
.y
= $4000) then
1106 func_freeProj
:= @Project_y
;
1108 func_freeProj
:= Project_y
;
1110 F_dot_P
:= Long(projVector
.y
) * $10000;
1115 func_move
:= @Direct_Move
;
1116 func_freeProj
:= @Free_Project
;
1118 func_move
:= Direct_Move
;
1119 func_freeProj
:= Free_Project
;
1121 F_dot_P
:= Long(projVector
.x
) * freeVector
.x
* 4 +
1122 Long(projVector
.y
) * freeVector
.y
* 4;
1126 if (projVector
.x
= $4000) then func_Project
:= @Project_x
1128 if (projVector
.y
= $4000) then func_Project
:= @Project_y
1130 func_Project
:= @Project
;
1132 if (dualVector
.x
= $4000) then func_dualproj
:= @Project_x
1134 if (dualVector
.y
= $4000) then func_dualproj
:= @Project_y
1136 func_dualproj
:= @Dual_Project
;
1138 func_move
:= @Direct_Move
;
1140 if F_dot_P
= $40000000 then
1142 if freeVector
.x
= $4000 then func_move
:= @Direct_Move_x
1144 if freeVector
.y
= $4000 then func_move
:= @Direct_Move_y
;
1146 if (projVector
.x
= $4000) then func_Project
:= Project_x
1148 if (projVector
.y
= $4000) then func_Project
:= Project_y
1150 func_Project
:= Project
;
1152 if (dualVector
.x
= $4000) then func_dualproj
:= Project_x
1154 if (dualVector
.y
= $4000) then func_dualproj
:= Project_y
1156 func_dualproj
:= Dual_Project
;
1158 func_move
:= Direct_Move
;
1160 if F_dot_P
= $40000000 then
1162 if freeVector
.x
= $4000 then func_move
:= Direct_Move_x
1164 if freeVector
.y
= $4000 then func_move
:= Direct_Move_y
;
1167 (* at small sizes, F_dot_P can become too small, resulting *)
1168 (* in overflows and 'spikes' in a number of glyfs like 'w' *)
1170 if abs( F_dot_P
) < $4000000 then F_dot_P
:= $40000000;
1172 (* set aspect ratio to 0 to force recomputation by Get_Current_Ratio *)
1178 (**************************************************)
1180 (* Normalize : Normer un vecteur ( U, V ) *)
1181 (* r‚sultat dans ( X, Y ) *)
1182 (* False si vecteur paramÅ tre nul *)
1184 (**************************************************)
1186 function Normalize( U
, V
: TT_F26dot6
; var R
: TT_UnitVector
): boolean;
1194 if (Abs(U
) < $10000) and (Abs(V
) < $10000) then
1202 (* XXX : Undocumented. Apparently, it is possible to try *)
1203 (* to normalize the vector (0,0). Return success *)
1205 Normalize
:= SUCCESS
;
1209 R
.x
:= MulDiv( U
, $4000, W
);
1210 R
.y
:= MulDiv( V
, $4000, W
);
1220 U
:= MulDiv( U
, $4000, W
);
1221 V
:= MulDiv( V
, $4000, W
);
1225 (* Now, we want that Sqrt( W ) = $4000 *)
1226 (* Or $1000000 <= W < $1004000 *)
1228 if U
< 0 then begin U
:= -U
; S1
:= True; end else S1
:= False;
1229 if V
< 0 then begin V
:= -V
; S2
:= True; end else S2
:= False;
1231 while W
< $1000000 do
1233 (* We need to increase W, by a minimal amount *)
1234 if U
< V
then inc( U
)
1239 while W
>= $1004000 do
1241 (* We need to decrease W, by a minimal amount *)
1242 if U
< V
then dec( U
)
1247 (* Note that in various cases, we can only *)
1248 (* compute a Sqrt(W) of $3FFF, eg. U=V *)
1253 R
.x
:= U
; (* Type conversion *)
1254 R
.y
:= V
; (* Type conversion *)
1260 exc
.error
:= TT_Err_Divide_By_Zero
;
1269 (****************************************************************)
1271 (* MANAGING THE STACK *)
1273 (* Instructions appear in the specs' order *)
1275 (****************************************************************)
1277 (*******************************************)
1278 (* DUP[] : Duplicate top stack element *)
1279 (* CodeRange : $20 *)
1281 procedure Ins_DUP( args
: PStorage
);
1283 args
^[1] := args
^[0];
1286 (*******************************************)
1287 (* POP[] : POPs the stack's top elt. *)
1288 (* CodeRange : $21 *)
1290 procedure Ins_POP( args
: PStorage
);
1295 (*******************************************)
1296 (* CLEAR[] : Clear the entire stack *)
1297 (* CodeRange : $22 *)
1299 procedure Ins_CLEAR( args
: PStorage
);
1304 (*******************************************)
1305 (* SWAP[] : Swap the top two elements *)
1306 (* CodeRange : $23 *)
1308 procedure Ins_SWAP( args
: PStorage
);
1312 args
^[0] := args
^[1];
1316 (*******************************************)
1317 (* DEPTH[] : return the stack depth *)
1318 (* CodeRange : $24 *)
1320 procedure Ins_DEPTH( args
: PStorage
);
1322 args
^[0] := exc
.top
;
1325 (*******************************************)
1326 (* CINDEX[] : copy indexed element *)
1327 (* CodeRange : $25 *)
1329 procedure Ins_CINDEX( args
: PStorage
);
1334 if (L
<= 0) or (L
> exc
.args
) then
1335 exc
.error
:= TT_Err_Invalid_Reference
1337 args
^[0] := exc
.stack
^[exc
.args
-l
];
1340 (*******************************************)
1341 (* MINDEX[] : move indexed element *)
1342 (* CodeRange : $26 *)
1344 procedure Ins_MINDEX( args
: PStorage
);
1349 if (L
<= 0) or (L
> exc
.args
) then
1350 exc
.Error
:= TT_Err_Invalid_Reference
1353 K
:= exc
.stack
^[exc
.args
-L
];
1355 move( exc
.stack
^[exc
.args
-L
+1],
1356 exc
.stack
^[exc
.args
-L
],
1357 (L
-1)*sizeof(Long
) );
1359 exc
.stack
^[exc
.args
-1] := K
;
1363 (*******************************************)
1364 (* ROLL[] : roll top three elements *)
1365 (* CodeRange : $8A *)
1367 procedure Ins_ROLL( args
: PStorage
);
1380 (****************************************************************)
1382 (* MANAGING THE FLOW OF CONTROL *)
1384 (* Instructions appear in the specs' order *)
1386 (****************************************************************)
1388 function SkipCode
: boolean;
1394 inc( exc
.IP
, exc
.length
);
1396 b
:= exc
.IP
< exc
.codeSize
;
1398 if b
then b
:= Calc_Length
;
1401 exc
.error
:= TT_Err_Code_Overflow
;
1407 (*******************************************)
1408 (* IF[] : IF test *)
1409 (* CodeRange : $58 *)
1411 procedure Ins_IF( args
: PStorage
);
1416 if args
^[0] <> 0 then exit
;
1423 if not SkipCode
then exit
;
1444 (*******************************************)
1446 (* CodeRange : $1B *)
1448 procedure Ins_ELSE( args
: PStorage
);
1456 if not SkipCode
then exit
;
1470 (*******************************************)
1471 (* EIF[] : End IF *)
1472 (* CodeRange : $59 *)
1474 procedure Ins_EIF( args
: PStorage
);
1479 (*******************************************)
1480 (* JROT[] : Jump Relative On True *)
1481 (* CodeRange : $78 *)
1483 procedure Ins_JROT( args
: PStorage
);
1485 if args
^[1] <> 0 then
1487 inc( exc
.IP
, args
^[0] );
1488 exc
.step_ins
:= false;
1492 (*******************************************)
1493 (* JMPR[] : JuMP Relative *)
1494 (* CodeRange : $1C *)
1496 procedure Ins_JMPR( args
: PStorage
);
1498 inc( exc
.IP
, args
^[0] );
1499 exc
.step_ins
:= false;
1502 (*******************************************)
1503 (* JROF[] : Jump Relative On False *)
1504 (* CodeRange : $79 *)
1506 procedure Ins_JROF( args
: PStorage
);
1508 if args
^[1] = 0 then
1510 inc( exc
.IP
, args
^[0] );
1511 exc
.step_ins
:= false;
1515 (****************************************************************)
1517 (* LOGICAL FUNCTIONS *)
1519 (* Instructions appear in the specs' order *)
1521 (****************************************************************)
1523 (*******************************************)
1524 (* LT[] : Less Than *)
1525 (* CodeRange : $50 *)
1527 procedure Ins_LT( args
: PStorage
);
1529 if args
^[0] < args
^[1] then args
^[0] := 1
1533 (*******************************************)
1534 (* LTEQ[] : Less Than or EQual *)
1535 (* CodeRange : $51 *)
1537 procedure Ins_LTEQ( args
: PStorage
);
1539 if args
^[0] <= args
^[1] then args
^[0] := 1
1543 (*******************************************)
1544 (* GT[] : Greater Than *)
1545 (* CodeRange : $52 *)
1547 procedure Ins_GT( args
: PStorage
);
1549 if args
^[0] > args
^[1] then args
^[0] := 1
1553 (*******************************************)
1554 (* GTEQ[] : Greater Than or EQual *)
1555 (* CodeRange : $53 *)
1557 procedure Ins_GTEQ( args
: PStorage
);
1559 if args
^[0] >= args
^[1] then args
^[0] := 1
1563 (*******************************************)
1565 (* CodeRange : $54 *)
1567 procedure Ins_EQ( args
: PStorage
);
1569 if args
^[0] = args
^[1] then args
^[0] := 1
1573 (*******************************************)
1574 (* NEQ[] : Not EQual *)
1575 (* CodeRange : $55 *)
1577 procedure Ins_NEQ( args
: PStorage
);
1579 if args
^[0] <> args
^[1] then args
^[0] := 1
1583 (*******************************************)
1585 (* CodeRange : $56 *)
1587 procedure Ins_ODD( args
: PStorage
);
1589 if exc
.func_round( args
^[0], 0 ) and 127 = 64 then args
^[0] := 1
1593 (*******************************************)
1595 (* CodeRange : $57 *)
1597 procedure Ins_EVEN( args
: PStorage
);
1599 if exc
.func_round( args
^[0], 0 ) and 127 = 0 then args
^[0] := 1
1603 (*******************************************)
1604 (* AND[] : logical AND *)
1605 (* CodeRange : $5A *)
1607 procedure Ins_AND( args
: PStorage
);
1609 if ( args
^[0] <> 0 ) and
1610 ( args
^[1] <> 0 ) then args
^[0] := 1
1614 (*******************************************)
1615 (* OR[] : logical OR *)
1616 (* CodeRange : $5B *)
1618 procedure Ins_OR( args
: PStorage
);
1620 if ( args
^[0] <> 0 ) or
1621 ( args
^[1] <> 0 ) then args
^[0] := 1
1625 (*******************************************)
1626 (* NOT[] : logical NOT *)
1627 (* CodeRange : $5C *)
1629 procedure Ins_NOT( args
: PStorage
);
1631 if args
^[0] <> 0 then args
^[0] := 0
1635 (****************************************************************)
1637 (* ARITHMETIC AND MATH INSTRUCTIONS *)
1639 (* Instructions appear in the specs' order *)
1641 (****************************************************************)
1643 (*******************************************)
1645 (* CodeRange : $60 *)
1647 procedure Ins_ADD( args
: PStorage
);
1649 inc( args
^[0], args
^[1] );
1652 (*******************************************)
1653 (* SUB[] : SUBstract *)
1654 (* CodeRange : $61 *)
1656 procedure Ins_SUB( args
: PStorage
);
1658 dec( args
^[0], args
^[1] );
1661 (*******************************************)
1662 (* DIV[] : DIVide *)
1663 (* CodeRange : $62 *)
1665 procedure Ins_DIV( args
: PStorage
);
1667 if args
^[1] = 0 then
1669 exc
.error
:= TT_Err_Divide_By_Zero
;
1673 args
^[0] := MulDiv_Round( args
^[0], 64, args
^[1] );
1676 (*******************************************)
1677 (* MUL[] : MULtiply *)
1678 (* CodeRange : $63 *)
1680 procedure Ins_MUL( args
: PStorage
);
1682 args
^[0] := MulDiv_Round( args
^[0], args
^[1], 64 );
1685 (*******************************************)
1686 (* ABS[] : ABSolute value *)
1687 (* CodeRange : $64 *)
1689 procedure Ins_ABS( args
: PStorage
);
1691 args
^[0] := abs( args
^[0] );
1694 (*******************************************)
1695 (* NEG[] : NEGate *)
1696 (* CodeRange : $65 *)
1698 procedure Ins_NEG( args
: PStorage
);
1700 args
^[0] := -args
^[0];
1703 (*******************************************)
1704 (* FLOOR[] : FLOOR *)
1705 (* CodeRange : $66 *)
1707 procedure Ins_FLOOR( args
: PStorage
);
1709 args
^[0] := args
^[0] and -64;
1712 (*******************************************)
1713 (* CEILING[] : CEILING *)
1714 (* CodeRange : $67 *)
1716 procedure Ins_CEILING( args
: PStorage
);
1718 args
^[0] := ( args
^[0]+63 ) and -64;
1721 (*******************************************)
1722 (* MAX[] : MAXimum *)
1723 (* CodeRange : $68 *)
1725 procedure Ins_MAX( args
: PStorage
);
1727 if args
^[1] > args
^[0] then args
^[0] := args
^[1];
1730 (*******************************************)
1731 (* MIN[] : MINimum *)
1732 (* CodeRange : $69 *)
1734 procedure Ins_MIN( args
: PStorage
);
1736 if args
^[1] < args
^[0] then args
^[0] := args
^[1];
1739 (****************************************************************)
1741 (* COMPENSATING FOR THE ENGINE CHARACTERISTICS *)
1743 (* Instructions appear in the specs' order *)
1745 (****************************************************************)
1747 (*******************************************)
1748 (* ROUND[ab] : ROUND value *)
1749 (* CodeRange : $68-$6B *)
1751 procedure Ins_ROUND( args
: PStorage
);
1753 args
^[0] := exc
.func_round( args
^[0],
1754 exc
.metrics
.compensations
[ exc
.opcode
-$68 ] );
1757 (*******************************************)
1758 (* NROUND[ab]: No ROUNDing of value *)
1759 (* CodeRange : $6C-$6F *)
1761 procedure Ins_NROUND( args
: PStorage
);
1763 args
^[0] := Round_None( args
^[0],
1764 exc
.metrics
.compensations
[ exc
.opcode
-$6C ] );
1767 (****************************************************************)
1769 (* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS *)
1771 (* Instructions appear in the specs' order *)
1773 (****************************************************************)
1775 (*******************************************)
1776 (* FDEF[] : Function DEFinition *)
1777 (* CodeRange : $2C *)
1779 procedure Ins_FDEF( args
: PStorage
);
1787 if exc
.numFDefs
>= exc
.maxFDefs
then begin
1788 exc
.error
:= TT_Err_Too_Many_FuncDefs
;
1792 func
:= Int(args
^[0]);
1793 with exc
.FDefs
^[exc
.numFDefs
] do
1795 Range
:= exc
.curRange
;
1801 if func
> exc
.maxFunc
then
1802 exc
.maxFunc
:= func
;
1806 (* now skip the whole function definition *)
1807 (* we don't allow nested IDEFS & FDEFs *)
1816 exc
.error
:= TT_Err_Nested_Defs
;
1825 (*******************************************)
1826 (* ENDF[] : END Function definition *)
1827 (* CodeRange : $2D *)
1829 procedure Ins_ENDF( args
: PStorage
);
1832 if exc
.callTop
<= 0 then (* We encountered an ENDF without a call *)
1834 exc
.error
:= TT_Err_ENDF_in_Exec_Stream
;
1840 with exc
.Callstack
^[exc
.CallTop
] do
1844 exc
.step_ins
:= false;
1846 if Cur_Count
> 0 then
1849 (* Loop the current function *)
1851 exc
.IP
:= Cur_Restart
;
1855 (* exit the current call frame *)
1856 (* NOTE : When the last intruction of a program *)
1857 (* is a CALL or LOOPCALL, the return address *)
1858 (* is always out of the code range. This is *)
1859 (* valid address, and is why we do not test *)
1860 (* the result of Goto_CodeRange here !! *)
1862 Goto_CodeRange( Caller_Range
, Caller_IP
)
1867 (*******************************************)
1868 (* CALL[] : CALL function *)
1869 (* CodeRange : $2B *)
1871 procedure Ins_CALL( args
: PStorage
);
1879 (* First of all, check index *)
1880 if (args
^[0] < 0) or (args
^[0] > exc
.maxFunc
) then
1883 (* Except for some old Apple fonts, all functions in a TrueType *)
1884 (* fonts are defined in increasing order, starting from 0. *)
1886 (* This mean that, normally, we have : *)
1888 (* exc.maxFunc+1 = exc.numFDefs *)
1889 (* exc.FDefs[n].opc = n for n in 0..exc.maxFunc *)
1892 nn
:= Int(args
^[0]);
1893 def
:= @exc
.FDefs
^[nn
];
1895 if ( exc
.maxFunc
+1 <> exc
.numFDefs
) or ( def
^.opc
<> nn
) then begin
1896 (* lookup the FDefs table *)
1898 def
:= @exc
.FDefs
^[0];
1899 while (ii
< exc
.numFDefs
) and (def
^.opc
<> nn
) do begin
1904 (* Fail if the function isn't listed *)
1905 if ii
>= exc
.numFDefs
then
1909 (* check that the function is active *)
1910 if not def
^.active
then
1913 (* check call stack *)
1914 if exc
.callTop
>= exc
.callSize
then
1916 exc
.error
:= TT_Err_Stack_Overflow
;
1920 with exc
.callstack
^[exc
.callTop
] do
1922 Caller_Range
:= exc
.curRange
;
1923 Caller_IP
:= exc
.IP
+1;
1925 Cur_Restart
:= def
^.Start
;
1930 with def
^ do Goto_CodeRange( Range
, Start
);
1932 exc
.step_ins
:= false;
1936 exc
.error
:= TT_Err_Invalid_Reference
;
1940 (*******************************************)
1941 (* LOOPCALL[]: LOOP and CALL function *)
1942 (* CodeRange : $2A *)
1944 procedure Ins_LOOPCALL( args
: PStorage
);
1947 if ( args
^[1] < 0 ) or ( args
^[1] >= exc
.numFDefs
) or
1948 ( not exc
.FDefs
^[args
^[1]].Active
) then
1950 exc
.error
:= TT_Err_Invalid_Reference
;
1954 if exc
.callTop
>= exc
.callSize
then
1956 exc
.error
:= TT_Err_Stack_Overflow
;
1960 if args
^[0] > 0 then
1962 with exc
.callstack
^[exc
.callTop
] do
1964 Caller_Range
:= exc
.curRange
;
1965 Caller_IP
:= exc
.IP
+1;
1966 Cur_Count
:= args
^[0];
1967 Cur_Restart
:= exc
.FDefs
^[args
^[1]].Start
;
1972 with exc
.FDefs
^[args
^[1]] do Goto_CodeRange( Range
, Start
);
1974 exc
.step_ins
:= false;
1979 (*******************************************)
1980 (* IDEF[] : Instruction DEFinition *)
1981 (* CodeRange : $89 *)
1983 procedure Ins_IDEF( args
: PStorage
);
1990 while ( A
< exc
.numIDefs
) do
1991 with exc
.IDefs
^[A
] do
1998 Range
:= exc
.curRange
;
2003 (* now skip the whole function definition *)
2004 (* we don't allow nested IDEFS & FDEFs *)
2012 exc
.error
:= TT_Err_Nested_Defs
;
2025 (****************************************************************)
2027 (* PUSHING DATA ONTO THE INTERPRETER STACK *)
2029 (* Instructions appear in the specs' order *)
2031 (****************************************************************)
2033 (*******************************************)
2034 (* NPUSHB[] : PUSH N Bytes *)
2035 (* CodeRange : $40 *)
2037 procedure Ins_NPUSHB( args
: PStorage
);
2041 L
:= exc
.code
^[exc
.IP
+1];
2043 if exc
.top
+ L
> exc
.stackSize
then
2045 exc
.error
:= TT_Err_Stack_Overflow
;
2050 args
^[k
-1] := exc
.code
^[exc
.IP
+1+k
];
2052 inc( exc
.new_top
, L
);
2055 (*******************************************)
2056 (* NPUSHW[] : PUSH N Words *)
2057 (* CodeRange : $41 *)
2059 procedure Ins_NPUSHW( args
: PStorage
);
2063 L
:= exc
.code
^[exc
.IP
+1];
2065 if exc
.top
+ L
> exc
.stackSize
then
2067 exc
.error
:= TT_Err_Stack_Overflow
;
2074 args
^[k
-1] := GetShort
;
2076 exc
.step_ins
:= false;
2078 inc( exc
.new_top
, L
);
2081 (*******************************************)
2082 (* PUSHB[abc]: PUSH Bytes *)
2083 (* CodeRange : $B0-$B7 *)
2085 procedure Ins_PUSHB( args
: PStorage
);
2089 L
:= exc
.opcode
- $B0+1;
2091 if exc
.top
+ L
>= exc
.stackSize
then
2093 exc
.error
:= TT_Err_Stack_Overflow
;
2098 args
^[k
-1] := exc
.code
^[exc
.ip
+k
];
2102 (*******************************************)
2103 (* PUSHW[abc]: PUSH Words *)
2104 (* CodeRange : $B8-$BF *)
2106 procedure Ins_PUSHW( args
: PStorage
);
2110 L
:= exc
.opcode
- $B8+1;
2112 if exc
.top
+ L
>= exc
.stackSize
then
2114 exc
.error
:= TT_Err_Stack_Overflow
;
2121 args
^[k
-1] := GetShort
;
2123 exc
.step_ins
:= false;
2127 (****************************************************************)
2129 (* MANAGING THE STORAGE AREA *)
2131 (* Instructions appear in the specs' order *)
2133 (****************************************************************)
2135 (*******************************************)
2136 (* RS[] : Read Store *)
2137 (* CodeRange : $43 *)
2139 procedure Ins_RS( args
: PStorage
);
2141 if (args
^[0] < 0) or (args
^[0] >= exc
.storeSize
) then
2143 exc
.error
:= TT_Err_Invalid_Reference
;
2147 args
^[0] := exc
.storage
^[args
^[0]];
2150 (*******************************************)
2151 (* WS[] : Write Store *)
2152 (* CodeRange : $42 *)
2154 procedure Ins_WS( args
: PStorage
);
2156 if (args
^[0] < 0) or (args
^[0] >= exc
.storeSize
) then
2158 exc
.error
:= TT_Err_Invalid_Reference
;
2162 exc
.storage
^[args
^[0]] := args
^[1];
2165 (*******************************************)
2166 (* WCVTP[] : Write CVT in Pixel units *)
2167 (* CodeRange : $44 *)
2169 procedure Ins_WCVTP( args
: PStorage
);
2171 if (args
^[0] < 0) or (args
^[0] >= exc
.cvtSize
) then
2173 exc
.error
:= TT_Err_Invalid_Reference
;
2177 exc
.func_write_cvt( args
^[0], args
^[1] );
2180 (*******************************************)
2181 (* WCVTF[] : Write CVT in FUnits *)
2182 (* CodeRange : $70 *)
2184 procedure Ins_WCVTF( args
: PStorage
);
2186 if (args
^[0] < 0) or (args
^[0] >= exc
.cvtSize
) then
2188 exc
.error
:= TT_Err_Invalid_Reference
;
2192 exc
.cvt
^[args
^[0]] := Scale_Pixels(args
^[1]);
2195 (*******************************************)
2196 (* RCVT[] : Read CVT *)
2197 (* CodeRange : $45 *)
2199 procedure Ins_RCVT( args
: PStorage
);
2201 if (args
^[0] < 0) or (args
^[0] >= exc
.cvtSize
) then
2203 exc
.error
:= TT_Err_Invalid_Reference
;
2207 args
^[0] := exc
.func_read_cvt(args
^[0]);
2210 (****************************************************************)
2212 (* MANAGING THE GRAPHICS STATE *)
2214 (* Instructions appear in the specs' order *)
2216 (****************************************************************)
2218 (*******************************************)
2219 (* SVTCA[a] : Set F and P vectors to axis *)
2220 (* CodeRange : $00-$01 *)
2222 procedure Ins_SVTCA( args
: PStorage
);
2225 case (exc
.opcode
and 1) of
2231 exc
.GS
.freeVector
.x
:= A
;
2232 exc
.GS
.projVector
.x
:= A
;
2233 exc
.GS
.dualVector
.x
:= A
;
2235 exc
.GS
.freeVector
.y
:= B
;
2236 exc
.GS
.projVector
.y
:= B
;
2237 exc
.GS
.dualVector
.y
:= B
;
2242 (*******************************************)
2243 (* SPVTCA[a] : Set PVector to Axis *)
2244 (* CodeRange : $02-$03 *)
2246 procedure Ins_SPVTCA( args
: PStorage
);
2249 case (exc
.opcode
and 1) of
2255 exc
.GS
.projVector
.x
:= A
;
2256 exc
.GS
.dualVector
.x
:= A
;
2258 exc
.GS
.projVector
.y
:= B
;
2259 exc
.GS
.dualVector
.y
:= B
;
2264 (*******************************************)
2265 (* SFVTCA[a] : Set FVector to Axis *)
2266 (* CodeRange : $04-$05 *)
2268 procedure Ins_SFVTCA( args
: PStorage
);
2271 case (exc
.opcode
and 1) of
2277 exc
.GS
.freeVector
.x
:= A
;
2278 exc
.GS
.freeVector
.y
:= B
;
2285 function Ins_SxVTL( aIdx1
: Int
;
2288 var Vec
: TT_UnitVector
) : boolean;
2297 if (aIdx2
>= zp1
.n_points
) or (aIdx1
>= zp2
.n_points
) then
2299 Error
:= TT_Err_Invalid_Reference
;
2303 with zp1
.Cur
^[aIdx2
] do
2309 with zp2
.Cur
^[aIdx1
] do
2315 if aOpc
and 1 <> 0 then
2317 C
:= B
; (* CounterClockwise rotation *)
2322 if not Normalize( A
, B
, Vec
) then
2324 exc
.error
:= TT_Err_Ok
;
2334 (*******************************************)
2335 (* SPVTL[a] : Set PVector to Line *)
2336 (* CodeRange : $06-$07 *)
2338 procedure Ins_SPVTL( args
: PStorage
);
2340 if not INS_SxVTL( args
^[1],
2343 exc
.GS
.projVector
) then exit
;
2345 exc
.GS
.dualVector
:= exc
.GS
.projVector
;
2349 (*******************************************)
2350 (* SFVTL[a] : Set FVector to Line *)
2351 (* CodeRange : $08-$09 *)
2353 procedure Ins_SFVTL( args
: PStorage
);
2355 if not INS_SxVTL( args
^[1],
2358 exc
.GS
.freeVector
) then exit
;
2363 (*******************************************)
2364 (* SFVTPV[] : Set FVector to PVector *)
2365 (* CodeRange : $0E *)
2367 procedure Ins_SFVTPV( args
: PStorage
);
2369 exc
.GS
.freeVector
:= exc
.GS
.projVector
;
2373 (*******************************************)
2374 (* SDPVTL[a] : Set Dual PVector to Line *)
2375 (* CodeRange : $86-$87 *)
2377 procedure Ins_SDPVTL( args
: PStorage
);
2386 if (args
^[0] < 0) or (args
^[0] >= exc
.zp1
.n_points
) or
2387 (args
^[1] < 0) or (args
^[1] >= exc
.zp2
.n_points
) then
2389 exc
.error
:= TT_Err_Invalid_Reference
;
2393 A
:= exc
.zp1
.org
^[p2
].x
- exc
.zp2
.org
^[p1
].x
;
2394 B
:= exc
.zp1
.org
^[p2
].y
- exc
.zp2
.org
^[p1
].y
;
2396 if exc
.opcode
and 1 <> 0 then
2398 C
:= B
; (* CounterClockwise rotation *)
2403 Normalize( A
, B
, exc
.GS
.dualVector
);
2405 A
:= exc
.zp1
.cur
^[p2
].x
- exc
.zp2
.cur
^[p1
].x
;
2406 B
:= exc
.zp1
.cur
^[p2
].y
- exc
.zp2
.cur
^[p1
].y
;
2408 if exc
.opcode
and 1 <> 0 then
2410 C
:= B
; (* CounterClockwise rotation *)
2415 Normalize( A
, B
, exc
.GS
.projVector
);
2418 exc
.error
:= TT_Err_Ok
;
2421 (*******************************************)
2422 (* SPVFS[] : Set PVector From Stack *)
2423 (* CodeRange : $0A *)
2425 procedure Ins_SPVFS( args
: PStorage
);
2430 S
:= args
^[1]; Y
:= S
; (* type conversion; extends sign *)
2431 S
:= args
^[0]; X
:= S
; (* type conversion; extends sign *)
2433 if not Normalize( X
, Y
, exc
.GS
.projVector
) then exit
;
2435 exc
.GS
.dualVector
:= exc
.GS
.projVector
;
2440 (*******************************************)
2441 (* SFVFS[] : Set FVector From Stack *)
2442 (* CodeRange : $0B *)
2444 procedure Ins_SFVFS( args
: PStorage
);
2449 S
:= args
^[1]; Y
:= S
; (* type conversion; extends sign *)
2450 S
:= args
^[0]; X
:= S
; (* type conversion; extends sign *)
2452 if not Normalize( X
, Y
, exc
.GS
.freeVector
) then exit
;
2457 (*******************************************)
2458 (* GPV[] : Get Projection Vector *)
2459 (* CodeRange : $0C *)
2461 procedure Ins_GPV( args
: PStorage
);
2463 args
^[0] := exc
.GS
.projVector
.x
;
2464 args
^[1] := exc
.GS
.projVector
.y
;
2467 (*******************************************)
2468 (* GFV[] : Get Freedom Vector *)
2469 (* CodeRange : $0D *)
2471 procedure Ins_GFV( args
: PStorage
);
2473 args
^[0] := exc
.GS
.freeVector
.x
;
2474 args
^[1] := exc
.GS
.freeVector
.y
;
2477 (*******************************************)
2478 (* SRP0[] : Set Reference Point 0 *)
2479 (* CodeRange : $10 *)
2481 procedure Ins_SRP0( args
: PStorage
);
2483 exc
.GS
.rp0
:= args
^[0];
2486 (*******************************************)
2487 (* SRP1[] : Set Reference Point 1 *)
2488 (* CodeRange : $11 *)
2490 procedure Ins_SRP1( args
: PStorage
);
2492 exc
.GS
.rp1
:= args
^[0];
2495 (*******************************************)
2496 (* SRP2[] : Set Reference Point 2 *)
2497 (* CodeRange : $12 *)
2499 procedure Ins_SRP2( args
: PStorage
);
2501 exc
.GS
.rp2
:= args
^[0];
2504 (*******************************************)
2505 (* SZP0[] : Set Zone Pointer 0 *)
2506 (* CodeRange : $13 *)
2508 procedure Ins_SZP0( args
: PStorage
);
2512 0 : exc
.zp0
:= exc
.Twilight
;
2513 1 : exc
.zp0
:= exc
.Pts
;
2515 exc
.error
:= TT_Err_Invalid_Reference
;
2519 exc
.GS
.gep0
:= args
^[0];
2522 (*******************************************)
2523 (* SZP1[] : Set Zone Pointer 1 *)
2524 (* CodeRange : $14 *)
2526 procedure Ins_SZP1( args
: PStorage
);
2530 0 : exc
.zp1
:= exc
.Twilight
;
2531 1 : exc
.zp1
:= exc
.Pts
;
2533 exc
.error
:= TT_Err_Invalid_Reference
;
2537 exc
.GS
.gep1
:= args
^[0];
2540 (*******************************************)
2541 (* SZP2[] : Set Zone Pointer 2 *)
2542 (* CodeRange : $15 *)
2544 procedure Ins_SZP2( args
: PStorage
);
2548 0 : exc
.zp2
:= exc
.Twilight
;
2549 1 : exc
.zp2
:= exc
.Pts
;
2551 exc
.error
:= TT_Err_Invalid_Reference
;
2555 exc
.GS
.gep2
:= args
^[0];
2558 (*******************************************)
2559 (* SZPS[] : Set Zone Pointers *)
2560 (* CodeRange : $16 *)
2562 procedure Ins_SZPS( args
: PStorage
);
2566 0 : exc
.zp0
:= exc
.Twilight
;
2567 1 : exc
.zp0
:= exc
.Pts
;
2569 exc
.error
:= TT_Err_Invalid_Reference
;
2576 exc
.GS
.gep0
:= args
^[0];
2577 exc
.GS
.gep1
:= args
^[0];
2578 exc
.GS
.gep2
:= args
^[0];
2581 (*******************************************)
2582 (* RTHG[] : Round To Half Grid *)
2583 (* CodeRange : $19 *)
2585 procedure Ins_RTHG( args
: PStorage
);
2587 exc
.GS
.round_state
:= TT_Round_To_Half_Grid
;
2590 exc
.func_round
:= @Round_To_Half_Grid
;
2592 exc
.func_round
:= Round_To_Half_Grid
;
2596 (*******************************************)
2597 (* RTG[] : Round To Grid *)
2598 (* CodeRange : $18 *)
2600 procedure Ins_RTG( args
: PStorage
);
2602 exc
.GS
.round_state
:= TT_Round_To_Grid
;
2605 exc
.func_round
:= @Round_To_Grid
;
2607 exc
.func_round
:= Round_To_Grid
;
2611 (*******************************************)
2612 (* RTDG[] : Round To Double Grid *)
2613 (* CodeRange : $3D *)
2615 procedure Ins_RTDG( args
: PStorage
);
2617 exc
.GS
.round_state
:= TT_Round_To_Double_Grid
;
2620 exc
.func_round
:= @Round_To_Double_Grid
;
2622 exc
.func_round
:= Round_To_Double_Grid
;
2626 (*******************************************)
2627 (* RUTG[] : Round Up To Grid *)
2628 (* CodeRange : $7C *)
2630 procedure Ins_RUTG( args
: PStorage
);
2632 exc
.GS
.round_state
:= TT_Round_Up_To_Grid
;
2635 exc
.func_round
:= @Round_Up_To_Grid
;
2637 exc
.func_round
:= Round_Up_To_Grid
;
2641 (*******************************************)
2642 (* RDTG[] : Round Down To Grid *)
2643 (* CodeRange : $7D *)
2645 procedure Ins_RDTG( args
: PStorage
);
2647 exc
.GS
.round_state
:= TT_Round_Down_To_Grid
;
2650 exc
.func_round
:= @Round_Down_To_Grid
;
2652 exc
.func_round
:= Round_Down_To_Grid
;
2656 (*******************************************)
2657 (* ROFF[] : Round OFF *)
2658 (* CodeRange : $7A *)
2660 procedure Ins_ROFF( args
: PStorage
);
2662 exc
.GS
.round_state
:= TT_Round_Off
;
2665 exc
.func_round
:= @Round_None
;
2667 exc
.func_round
:= Round_None
;
2671 (*******************************************)
2672 (* SROUND[] : Super ROUND *)
2673 (* CodeRange : $76 *)
2675 procedure Ins_SROUND( args
: PStorage
);
2677 SetSuperRound( $4000, args
^[0] );
2678 exc
.GS
.round_state
:= TT_Round_Super
;
2681 exc
.func_round
:= @Round_Super
;
2683 exc
.func_round
:= Round_Super
;
2687 (*******************************************)
2688 (* S45ROUND[]: Super ROUND 45 degrees *)
2689 (* CodeRange : $77 *)
2691 procedure Ins_S45ROUND( args
: PStorage
);
2693 SetSuperRound( $2D41, args
^[0] );
2694 exc
.GS
.round_state
:= TT_Round_Super_45
;
2697 exc
.func_round
:= @Round_Super_45
;
2699 exc
.func_round
:= Round_Super_45
;
2704 (*******************************************)
2705 (* SLOOP[] : Set LOOP variable *)
2706 (* CodeRange : $17 *)
2708 procedure Ins_SLOOP( args
: PStorage
);
2710 exc
.GS
.Loop
:= args
^[0];
2713 (*******************************************)
2714 (* SMD[] : Set Minimum Distance *)
2715 (* CodeRange : $1A *)
2717 procedure Ins_SMD( args
: PStorage
);
2719 exc
.GS
.minimum_distance
:= args
^[0];
2722 (*******************************************)
2723 (* INSTCTRL[]: INSTruction ConTRol *)
2724 (* CodeRange : $8e *)
2726 procedure Ins_INSTCTRL( args
: PStorage
);
2733 if ( K
< 1 ) or ( K
> 2 ) then
2735 exc
.error
:= TT_Err_Invalid_Reference
;
2739 if L
<> 0 then L
:= K
;
2741 exc
.GS
.instruct_control
:= ( exc
.GS
.instruct_control
and not K
) or L
;
2744 (*******************************************)
2745 (* SCANCTRL[]: SCAN ConTRol *)
2746 (* CodeRange : $85 *)
2748 procedure Ins_SCANCTRL( args
: PStorage
);
2754 A
:= args
^[0] and $FF;
2757 exc
.GS
.scan_Control
:= True
2760 exc
.GS
.scan_Control
:= False
2766 (* XXX TODO : Add rotation and stretch cases *)
2768 if ( args
^[0] and $100 <> 0 ) and
2769 ( exc
.metrics
.pointSize
<= A
) then exc
.GS
.scan_Control
:= True;
2771 if ( args
^[0] and $200 <> 0 ) and
2772 ( false ) then exc
.GS
.scan_Control
:= True;
2774 if ( args
^[0] and $400 <> 0 ) and
2775 ( false ) then exc
.GS
.scan_Control
:= True;
2777 if ( args
^[0] and $800 <> 0 ) and
2778 ( exc
.metrics
.pointSize
> A
) then exc
.GS
.scan_Control
:= False;
2780 if ( args
^[0] and $1000 <> 0 ) and
2781 ( not False ) then exc
.GS
.scan_Control
:= False;
2783 if ( args
^[0] and $2000 <> 0 ) and
2784 ( not False ) then exc
.GS
.scan_Control
:= False;
2788 (*******************************************)
2789 (* SCANTYPE[]: SCAN TYPE *)
2790 (* CodeRange : $8D *)
2792 procedure Ins_SCANTYPE( args
: PStorage
);
2794 (* For compatibility with future enhancements, *)
2795 (* we must ignore new modes *)
2797 if (args
^[0] >= 0 ) and (args
^[0] <= 5) then
2799 if args
^[0] = 3 then args
^[0] := 2;
2801 exc
.GS
.scan_type
:= args
^[0];
2805 (**********************************************)
2806 (* SCVTCI[] : Set Control Value Table Cut In *)
2807 (* CodeRange : $1D *)
2809 procedure Ins_SCVTCI( args
: PStorage
);
2811 exc
.GS
.control_value_cutin
:= args
^[0];
2814 (**********************************************)
2815 (* SSWCI[] : Set Single Width Cut In *)
2816 (* CodeRange : $1E *)
2818 procedure Ins_SSWCI( args
: PStorage
);
2820 exc
.GS
.single_width_cutin
:= args
^[0];
2823 (**********************************************)
2824 (* SSW[] : Set Single Width *)
2825 (* CodeRange : $1F *)
2827 procedure Ins_SSW( args
: PStorage
);
2829 exc
.GS
.single_width_value
:= args
^[0] div $400;
2832 (**********************************************)
2833 (* FLIPON[] : Set Auto_flip to On *)
2834 (* CodeRange : $4D *)
2836 procedure Ins_FLIPON( args
: PStorage
);
2838 exc
.GS
.auto_flip
:= True;
2841 (**********************************************)
2842 (* FLIPOFF[] : Set Auto_flip to Off *)
2843 (* CodeRange : $4E *)
2845 procedure Ins_FLIPOFF( args
: PStorage
);
2847 exc
.GS
.auto_flip
:= False;
2850 (**********************************************)
2851 (* SANGW[] : Set Angle Weigth *)
2852 (* CodeRange : $7E *)
2854 procedure Ins_SANGW( args
: PStorage
);
2856 (* instruction not supported anymore *)
2859 (**********************************************)
2860 (* SDB[] : Set Delta Base *)
2861 (* CodeRange : $5E *)
2863 procedure Ins_SDB( args
: PStorage
);
2865 exc
.GS
.delta_base
:= args
^[0]
2868 (**********************************************)
2869 (* SDS[] : Set Delta Shift *)
2870 (* CodeRange : $5F *)
2872 procedure Ins_SDS( args
: PStorage
);
2874 exc
.GS
.delta_shift
:= args
^[0]
2877 (**********************************************)
2878 (* GC[a] : Get Coordinate projected onto *)
2879 (* CodeRange : $46-$47 *)
2881 (* BULLSHIT : Measures from the original glyph must to be taken *)
2882 (* along the dual projection vector !! *)
2884 procedure Ins_GC( args
: PStorage
);
2890 if (L
< 0) or (L
>= exc
.zp2
.n_points
) then
2892 exc
.error
:= TT_Err_Invalid_Reference
;
2896 case exc
.opcode
and 1 of
2898 0 : L
:= exc
.func_project ( exc
.zp2
.cur
^[L
], Null_Vector
);
2899 1 : L
:= exc
.func_dualProj( exc
.zp2
.org
^[L
], Null_Vector
);
2905 (**********************************************)
2906 (* SCFS[] : Set Coordinate From Stack *)
2907 (* CodeRange : $48 *)
2911 (* OA := OA + ( value - OA.p )/( f.p ) x f *)
2914 procedure Ins_SCFS( args
: PStorage
);
2920 if (args
^[0] < 0) or (args
^[0] >= exc
.zp2
.n_points
) then
2922 exc
.error
:= TT_Err_Invalid_Reference
;
2926 K
:= exc
.func_project( exc
.zp2
.cur
^[L
], Null_Vector
);
2928 exc
.func_move( @exc
.zp2
, L
, args
^[1] - K
);
2930 (* not part of the specs, but here for safety *)
2932 if exc
.GS
.gep2
= 0 then
2933 exc
.zp2
.org
^[L
] := exc
.zp2
.cur
^[L
];
2937 (**********************************************)
2938 (* MD[a] : Measure Distance *)
2939 (* CodeRange : $49-$4A *)
2941 (* BULLSHIT : Measure taken in the original glyph must be along *)
2942 (* the dual projection vector *)
2944 (* Second BULLSHIT : Flag attributions are inverted !! *)
2945 (* 0 => measure distance in original outline *)
2946 (* 1 => measure distance in grid-fitted outline *)
2948 procedure Ins_MD( args
: PStorage
);
2958 if (args
^[0] < 0) or (args
^[0] >= exc
.zp0
.n_points
) or
2959 (args
^[1] < 0) or (args
^[1] >= exc
.zp1
.n_points
) then
2961 exc
.error
:= TT_Err_Invalid_Reference
;
2965 case exc
.opcode
and 1 of
2967 0 : D
:= exc
.func_dualProj( exc
.zp0
.org
^[L
], exc
.zp1
.org
^[K
] );
2968 1 : D
:= exc
.func_project ( exc
.zp0
.cur
^[L
], exc
.zp1
.cur
^[K
] );
2974 (**********************************************)
2975 (* MPPEM[] : Measure Pixel Per EM *)
2976 (* CodeRange : $4B *)
2978 procedure Ins_MPPEM( args
: PStorage
);
2980 args
^[0] := Get_Ppem
;
2983 (**********************************************)
2984 (* MPS[] : Measure PointSize *)
2985 (* CodeRange : $4C *)
2987 procedure Ins_MPS( args
: PStorage
);
2989 args
^[0] := exc
.metrics
.pointSize
;
2992 (****************************************************************)
2994 (* MANAGING OUTLINES *)
2996 (* Instructions appear in the specs' order *)
2998 (****************************************************************)
3001 (**********************************************)
3002 (* FLIPPT[] : FLIP PoinT *)
3003 (* CodeRange : $80 *)
3005 procedure Ins_FLIPPT( args
: PStorage
);
3009 if exc
.top
< exc
.GS
.loop
then
3011 exc
.error
:= TT_Err_Too_Few_Arguments
;
3015 while exc
.GS
.loop
> 0 do
3019 point
:= exc
.stack
^[ exc
.args
];
3021 if (point
< 0) or (point
>= exc
.pts
.n_points
) then
3023 exc
.error
:= TT_Err_Invalid_Reference
;
3027 exc
.pts
.flags
^[point
] := exc
.pts
.flags
^[point
] xor TT_Flag_On_Curve
;
3033 exc
.new_top
:= exc
.args
;
3036 (**********************************************)
3037 (* FLIPRGON[]: FLIP RanGe ON *)
3038 (* CodeRange : $81 *)
3040 procedure Ins_FLIPRGON( args
: PStorage
);
3047 if (K
< 0) or (K
>= exc
.pts
.n_points
) or
3048 (L
< 0) or (L
>= exc
.pts
.n_points
) then
3050 exc
.error
:= TT_Err_Invalid_Reference
;
3055 exc
.pts
.flags
^[I
] := exc
.pts
.flags
^[I
] or TT_Flag_On_Curve
;
3058 (**********************************************)
3059 (* FLIPRGOFF : FLIP RanGe OFF *)
3060 (* CodeRange : $82 *)
3062 procedure Ins_FLIPRGOFF( args
: PStorage
);
3069 if (K
< 0) or (K
>= exc
.pts
.n_points
) or
3070 (L
< 0) or (L
>= exc
.pts
.n_points
) then
3072 exc
.error
:= TT_Err_Invalid_Reference
;
3077 exc
.pts
.flags
^[I
] := exc
.pts
.flags
^[I
] and not TT_Flag_On_Curve
;
3082 function Compute_Point_Displacement( var x
: TT_F26dot6
;
3084 var zone
: PGlyph_Zone
;
3085 var refp
: Int
) : TError
;
3094 Compute_Point_Displacement
:= Success
;
3096 case exc
.opcode
and 1 of
3097 0 : begin zp
:= @exc
.zp1
; p
:= exc
.GS
.rp2
; end;
3098 1 : begin zp
:= @exc
.zp0
; p
:= exc
.GS
.rp1
; end;
3101 if (p
< 0) or (p
>= zp
^.n_points
) then
3103 exc
.error
:= TT_Err_Invalid_Displacement
;
3104 Compute_Point_Displacement
:= Failure
;
3111 d
:= exc
.func_project( zp
^.cur
^[p
], zp
^.org
^[p
] );
3113 x
:= MulDiv_Round( d
, Long(exc
.GS
.freeVector
.x
)*$10000, exc
.F_dot_P
);
3114 y
:= MulDiv_Round( d
, Long(exc
.GS
.freeVector
.y
)*$10000, exc
.F_dot_P
);
3119 procedure Move_Zp2_Point( point
: Int
;
3123 if exc
.GS
.freeVector
.x
<> 0 then
3125 inc( exc
.zp2
.cur
^[point
].x
, dx
);
3126 exc
.zp2
.flags
^[point
] := exc
.zp2
.flags
^[point
] or TT_Flag_Touched_X
;
3129 if exc
.GS
.freeVector
.y
<> 0 then
3131 inc( exc
.zp2
.cur
^[point
].y
, dy
);
3132 exc
.zp2
.flags
^[point
] := exc
.zp2
.flags
^[point
] or TT_Flag_Touched_Y
;
3136 (**********************************************)
3137 (* SHP[a] : SHift Point by the last point *)
3138 (* CodeRange : $32-33 *)
3140 procedure Ins_SHP( args
: PStorage
);
3150 if Compute_Point_Displacement( dx
, dy
, zp
, refp
) then
3153 if exc
.top
< exc
.GS
.loop
then
3155 exc
.error
:= TT_Err_Invalid_Reference
;
3159 while exc
.GS
.loop
> 0 do
3164 point
:= exc
.stack
^[ exc
.args
];
3166 if (point
< 0) or (point
>= exc
.zp2
.n_points
) then
3168 exc
.error
:= TT_Err_Invalid_Reference
;
3172 Move_Zp2_Point( point
, dx
, dy
);
3179 exc
.new_top
:= exc
.args
;
3182 (**********************************************)
3183 (* SHC[a] : SHift Contour *)
3184 (* CodeRange : $34-35 *)
3186 procedure Ins_SHC( args
: PStorage
);
3195 first_point
, last_point
: Int
;
3198 contour
:= args
^[0];
3200 if (args
^[0] < 0) or (args
^[0] >= exc
.pts
.n_contours
) then
3202 exc
.error
:= TT_Err_Invalid_Reference
;
3206 if Compute_Point_Displacement( dx
, dy
, zp
, refp
) then
3209 if contour
= 0 then first_point
:= 0 else
3210 first_point
:= exc
.pts
.conEnds
^[contour
-1]+1;
3212 last_point
:= exc
.pts
.conEnds
^[contour
];
3214 for i
:= first_point
to last_point
do
3216 if (zp
^.cur
<> exc
.zp2
.cur
) or
3219 Move_Zp2_Point( i
, dx
, dy
);
3224 (**********************************************)
3225 (* SHZ[a] : SHift Zone *)
3226 (* CodeRange : $36-37 *)
3228 procedure Ins_SHZ( args
: PStorage
);
3242 if (args
^[0] < 0) or (args
^[0] > 1) then
3244 exc
.error
:= TT_Err_Invalid_Reference
;
3248 if Compute_Point_Displacement( dx
, dy
, zp
, refp
) then
3251 last_point
:= zp
^.n_points
-1;
3253 for i
:= 0 to last_point
do
3255 if (zp
^.cur
<> exc
.zp2
.cur
) or
3258 Move_Zp2_Point( i
, dx
, dy
);
3263 (**********************************************)
3264 (* SHPIX[] : SHift points by a PIXel amount *)
3265 (* CodeRange : $38 *)
3267 procedure Ins_SHPIX( args
: PStorage
);
3274 if exc
.top
< exc
.GS
.loop
then
3276 exc
.error
:= TT_Err_Invalid_Reference
;
3280 dx
:= MulDiv_Round( args
^[0],
3281 exc
.GS
.freeVector
.x
,
3284 dy
:= MulDiv_Round( args
^[0],
3285 exc
.GS
.freeVector
.y
,
3288 while exc
.GS
.loop
> 0 do
3293 point
:= exc
.stack
^[ exc
.args
];
3295 if (point
< 0) or (point
>= exc
.zp2
.n_points
) then
3297 exc
.error
:= TT_Err_Invalid_Reference
;
3301 Move_Zp2_Point( point
, dx
, dy
);
3308 exc
.new_top
:= exc
.args
;
3311 (**********************************************)
3312 (* MSIRP[a] : Move Stack Indirect Relative *)
3313 (* CodeRange : $3A-$3B *)
3315 procedure Ins_MSIRP( args
: PStorage
);
3318 distance
: TT_F26dot6
;
3325 if (args
^[0] < 0) or (args
^[0] >= exc
.zp1
.n_points
) then
3327 exc
.error
:= TT_Err_Invalid_Reference
;
3331 (* XXX : UNDOCUMENTED - Twilight Zone *)
3333 (* Again, one stupid undocumented feature found in the *)
3334 (* twilight zone. What did these guys had in mind when *)
3335 (* they wrote the spec ? There _must_ be another *)
3336 (* specification than the published one !! #@%$& !! *)
3338 if exc
.GS
.gep0
= 0 then (* if in twilight zone *)
3340 exc
.zp1
.org
^[point
] := exc
.zp0
.org
^[exc
.GS
.rp0
];
3341 exc
.zp1
.cur
^[point
] := exc
.zp1
.org
^[point
];
3344 distance
:= exc
.func_project( exc
.zp1
.cur
^[point
],
3345 exc
.zp0
.cur
^[exc
.GS
.rp0
] );
3347 exc
.func_move( @exc
.zp1
, point
, args
^[1] - distance
);
3349 exc
.GS
.rp1
:= exc
.GS
.rp0
;
3350 exc
.GS
.rp2
:= point
;
3352 if exc
.opcode
and 1 <> 0 then exc
.GS
.rp0
:= point
;
3355 (**********************************************)
3356 (* MDAP[a] : Move Direct Absolute Point *)
3357 (* CodeRange : $2E-$2F *)
3359 procedure Ins_MDAP( args
: PStorage
);
3362 cur_dist
: TT_F26dot6
;
3363 distance
: TT_F26dot6
;
3367 if (args
^[0] < 0) or (args
^[0] >= exc
.zp0
.n_points
) then
3369 exc
.error
:= TT_Err_Invalid_Reference
;
3373 (* XXXX Is there some undocumented feature while in the *)
3374 (* twilight zone ?? *)
3376 if exc
.opcode
and 1 <> 0 then
3379 cur_dist
:= exc
.func_project( exc
.zp0
.cur
^[point
], Null_Vector
);
3381 distance
:= exc
.func_round( cur_dist
,
3382 exc
.metrics
.compensations
[0] ) -
3388 exc
.func_move( @exc
.zp0
, point
, distance
);
3390 exc
.GS
.rp0
:= point
;
3391 exc
.GS
.rp1
:= point
;
3394 (**********************************************)
3395 (* MIAP[a] : Move Indirect Absolute Point *)
3396 (* CodeRange : $3E-$3F *)
3398 procedure Ins_MIAP( args
: PStorage
);
3402 distance
: TT_F26dot6
;
3403 org_dist
: TT_F26dot6
;
3405 cvtEntry
:= args
^[1];
3408 if (args
^[0] < 0) or (args
^[0] >= exc
.zp0
.n_points
) or
3409 (args
^[1] < 0) or (args
^[1] >= exc
.cvtSize
) then
3411 exc
.error
:= TT_Err_Invalid_Reference
;
3415 (* Undocumented : *)
3417 (* The behaviour of an MIAP instruction is quite *)
3418 (* different when used in the twilight zone^. *)
3420 (* First, no control value cutin test is performed *)
3421 (* as it would fail anyway. Second, the original *)
3422 (* point, i.e. (org_x,org_y) of zp0.point, is set *)
3423 (* to the absolute, unrounded, distance found in *)
3426 (* This is used in the CVT programs of the Microsoft *)
3427 (* fonts Arial, Times, etc.., in order to re-adjust *)
3428 (* some key font heights. It allows the use of the *)
3429 (* IP instruction in the twilight zone, which *)
3430 (* otherwise would be "illegal" per se the specs :) *)
3432 (* We implement it with a special sequence for the *)
3433 (* twilight zone. This is a bad hack, but it seems *)
3437 distance
:= exc
.func_read_cvt(cvtEntry
);
3439 if exc
.GS
.gep0
= 0 then (* If in twilight zone *)
3441 exc
.zp0
.org
^[point
].y
:= MulDiv_Round( exc
.GS
.freeVector
.x
,
3445 exc
.zp0
.org
^[point
].y
:= MulDiv_Round( exc
.GS
.freeVector
.y
,
3449 exc
.zp0
.cur
^[point
] := exc
.zp0
.org
^[point
];
3452 org_dist
:= exc
.func_project( exc
.zp0
.cur
^[point
], Null_Vector
);
3454 if exc
.opcode
and 1 <> 0 then (* rounding and control cutin flag *)
3457 if abs( distance
-org_dist
) > exc
.GS
.control_value_cutin
then
3458 distance
:= org_dist
;
3460 distance
:= exc
.func_round( distance
,
3461 exc
.metrics
.compensations
[0] );
3464 exc
.func_move( @exc
.zp0
, point
, distance
- org_dist
);
3466 exc
.GS
.rp0
:= point
;
3467 exc
.GS
.rp1
:= point
;
3471 (**********************************************)
3472 (* MDRP[abcde] : Move Direct Relative Point *)
3473 (* CodeRange : $C0-$DF *)
3475 procedure Ins_MDRP( args
: PStorage
);
3478 distance
: TT_F26dot6
;
3479 org_dist
: TT_F26dot6
;
3483 if (args
^[0] < 0) or (args
^[0] >= exc
.zp1
.n_points
) then
3485 exc
.error
:= TT_Err_Invalid_Reference
;
3489 (* XXXX Is there some undocumented feature while in the *)
3490 (* twilight zone ?? *)
3492 org_dist
:= exc
.func_dualProj( exc
.zp1
.org
^[point
],
3493 exc
.zp0
.org
^[exc
.GS
.rp0
] );
3494 (* single width cutin test *)
3496 if abs(org_dist
) < exc
.GS
.single_width_cutin
then
3498 if org_dist
>= 0 then org_dist
:= exc
.GS
.single_width_value
3499 else org_dist
:= -exc
.GS
.single_width_value
;
3503 if exc
.opcode
and 4 <> 0 then
3505 distance
:= exc
.func_round( org_dist
,
3506 exc
.metrics
.compensations
[ exc
.opcode
and 3 ] )
3508 distance
:= Round_None( org_dist
,
3509 exc
.metrics
.compensations
[ exc
.opcode
and 3 ] );
3511 (* minimum distance flag *)
3513 if exc
.opcode
and 8 <> 0 then
3516 if org_dist
>= 0 then
3518 if distance
< exc
.GS
.minimum_distance
then
3519 distance
:= exc
.GS
.minimum_distance
3522 if distance
> -exc
.GS
.minimum_distance
then
3523 distance
:= -exc
.GS
.minimum_distance
;
3526 (* now move the point *)
3528 org_dist
:= exc
.func_project( exc
.zp1
.cur
^[point
],
3529 exc
.zp0
.cur
^[exc
.GS
.rp0
] );
3531 exc
.func_move( @exc
.zp1
, point
, distance
- org_dist
);
3533 exc
.GS
.rp1
:= exc
.GS
.rp0
;
3534 exc
.GS
.rp2
:= point
;
3536 if exc
.opcode
and 16 <> 0 then exc
.GS
.rp0
:= point
;
3539 (**********************************************)
3540 (* MIRP[abcde] : Move Indirect Relative Point *)
3541 (* CodeRange : $E0-$FF *)
3543 procedure Ins_MIRP( args
: PStorage
);
3547 cvt_dist
: TT_F26dot6
;
3548 distance
: TT_F26dot6
;
3549 cur_dist
: TT_F26dot6
;
3550 org_dist
: TT_F26dot6
;
3554 cvtEntry
:= args
^[1];
3556 (* XXX : UNDOCUMENTED => cvt[-1] = 0 ???? *)
3558 if (args
^[0] < 0 ) or (args
^[0] >= exc
.zp1
.n_points
) or
3559 (args
^[1] < -1) or (args
^[1] >= exc
.cvtSize
) then
3561 exc
.error
:= TT_Err_Invalid_Reference
;
3565 if cvtEntry
< 0 then
3568 cvt_dist
:= exc
.func_read_cvt(cvtEntry
);
3570 (* single width test *)
3572 if abs(cvt_dist
) < exc
.GS
.single_width_cutin
then
3574 if cvt_dist
>= 0 then cvt_dist
:= exc
.GS
.single_width_value
3575 else cvt_dist
:= -exc
.GS
.single_width_value
;
3577 (* XXX : Undocumented - twilight zone *)
3579 if exc
.GS
.gep1
= 0 then (* if in twilight zone *)
3581 exc
.zp1
.org
^[point
].x
:= exc
.zp0
.org
^[exc
.GS
.rp0
].x
+
3582 MulDiv_Round( cvt_dist
,
3583 exc
.GS
.freeVector
.x
,
3586 exc
.zp1
.org
^[point
].x
:= exc
.zp0
.org
^[exc
.GS
.rp0
].y
+
3587 MulDiv_Round( cvt_dist
,
3588 exc
.GS
.freeVector
.y
,
3591 exc
.zp1
.cur
^[point
] := exc
.zp1
.org
^[point
];
3595 org_dist
:= exc
.func_dualProj( exc
.zp1
.org
^[point
],
3596 exc
.zp0
.org
^[exc
.GS
.rp0
] );
3598 cur_dist
:= exc
.func_Project( exc
.zp1
.cur
^[point
],
3599 exc
.zp0
.cur
^[exc
.GS
.rp0
] );
3601 (* auto-flip test *)
3603 if exc
.GS
.auto_flip
then
3604 if (org_dist
xor cvt_dist
< 0) then
3605 cvt_dist
:= -cvt_dist
;
3607 (* control value cutin and round *)
3609 if exc
.opcode
and 4 <> 0 then
3611 (* XXX : UNDOCUMENTED : only perform cut-in test when both *)
3612 (* zone pointers refer to the points zone *)
3614 if exc
.GS
.gep0
= exc
.GS
.gep1
then
3615 if abs( cvt_dist
- org_dist
) >= exc
.GS
.control_value_cutin
then
3616 cvt_dist
:= org_dist
;
3618 distance
:= exc
.func_round( cvt_dist
,
3619 exc
.metrics
.compensations
[ exc
.opcode
and 3 ] );
3622 distance
:= Round_None( cvt_dist
,
3623 exc
.metrics
.compensations
[ exc
.opcode
and 3 ] );
3625 (* minimum distance test *)
3627 if exc
.opcode
and 8 <> 0 then
3629 if org_dist
>= 0 then
3631 if distance
< exc
.GS
.minimum_distance
then
3632 distance
:= exc
.GS
.minimum_distance
3635 if distance
> -exc
.GS
.minimum_distance
then
3636 distance
:= -exc
.GS
.minimum_distance
;
3639 exc
.func_move( @exc
.zp1
, point
, distance
- cur_dist
);
3641 exc
.GS
.rp1
:= exc
.GS
.rp0
;
3643 if exc
.opcode
and 16 <> 0 then exc
.GS
.rp0
:= point
;
3645 (* UNDOCUMENTED !! *)
3647 exc
.GS
.rp2
:= point
;
3650 (**********************************************)
3651 (* ALIGNRP[] : ALIGN Relative Point *)
3652 (* CodeRange : $3C *)
3654 procedure Ins_ALIGNRP( args
: PStorage
);
3657 distance
: TT_F26dot6
;
3659 if exc
.top
< exc
.GS
.loop
then
3661 exc
.error
:= TT_Err_Invalid_Reference
;
3665 while exc
.GS
.loop
> 0 do
3670 point
:= exc
.stack
^[ exc
.args
];
3672 if (point
< 0) or (point
>= exc
.zp1
.n_points
) then
3674 exc
.error
:= TT_Err_Invalid_Reference
;
3678 distance
:= exc
.func_project( exc
.zp1
.cur
^[point
],
3679 exc
.zp0
.cur
^[exc
.GS
.rp0
] );
3681 exc
.func_move( @exc
.zp1
, point
, -distance
);
3687 exc
.new_top
:= exc
.args
;
3690 (**********************************************)
3691 (* AA[] : Adjust Angle *)
3692 (* CodeRange : $7F *)
3694 procedure Ins_AA( args
: PStorage
);
3696 (* Intentional - no longer supported *)
3699 (**********************************************)
3700 (* ISECT[] : moves point to InterSECTion *)
3701 (* CodeRange : $0F *)
3703 procedure Ins_ISECT( args
: PStorage
);
3709 discriminant
: TT_F26dot6
;
3712 dbx
, dby
: TT_F26dot6
;
3718 U
, V
: TT_UnitVector
;
3728 if (b0
>= exc
.zp0
.n_points
) or (b1
>= exc
.zp0
.n_points
) or
3729 (a0
>= exc
.zp1
.n_points
) or (a1
>= exc
.zp1
.n_points
) or
3730 (point
>= exc
.zp0
.n_points
) then
3732 exc
.error
:= TT_Err_Invalid_Reference
;
3736 if Normalize( exc.zp1.cur_x^[a1] - exc.zp1.cur_x^[a0],
3737 exc.zp1.cur_y^[a1] - exc.zp1.cur_y^[a0],
3740 Normalize( - exc.zp0.cur_x^[b1] - exc.zp0.cur_x^[b0],
3741 exc.zp0.cur_y^[b1] - exc.zp0.cur_y^[b0],
3746 dx := MulDiv_Round( exc.zp0.cur_x^[b0] -
3751 MulDiv_Round( exc.zp0.cur_y^[b0] -
3756 dy := MulDiv_Round( U.x, V.x, $4000 ) +
3757 MulDiv_Round( U.y, V.y, $4000 );
3761 dx := MulDiv_Round( dx, $4000, dy );
3763 exc.zp2.flags^[point] := exc.zp2.flags^[point] or
3764 TT_Flag_Touched_Both;
3766 exc.zp2.cur_x^[point] := exc.zp1.cur_x^[a0] +
3768 MulDiv_Round( dx, U.x, $4000 );
3770 exc.zp2.cur_y^[point] := exc.zp1.cur_y^[a0] +
3772 MulDiv_Round( dx, U.y, $4000 );
3778 dbx
:= exc
.zp0
.cur
^[b1
].x
- exc
.zp0
.cur
^[b0
].x
;
3779 dby
:= exc
.zp0
.cur
^[b1
].y
- exc
.zp0
.cur
^[b0
].y
;
3781 dax
:= exc
.zp1
.cur
^[a1
].x
- exc
.zp1
.cur
^[a0
].x
;
3782 day
:= exc
.zp1
.cur
^[a1
].y
- exc
.zp1
.cur
^[a0
].y
;
3784 dx
:= exc
.zp0
.cur
^[b0
].x
- exc
.zp1
.cur
^[a0
].x
;
3785 dy
:= exc
.zp0
.cur
^[b0
].y
- exc
.zp1
.cur
^[a0
].y
;
3787 exc
.zp2
.flags
^[point
] := exc
.zp2
.flags
^[point
] or
3788 TT_Flag_Touched_Both
;
3790 discriminant
:= MulDiv( dax
, -dby
, $40 ) +
3791 MulDiv( day
, dbx
, $40 );
3793 if abs(discriminant
) >= $40 then
3796 val
:= MulDiv( dx
, -dby
, $40 ) +
3797 MulDiv( dy
, dbx
, $40 );
3799 R
.x
:= MulDiv( val
, dax
, discriminant
);
3800 R
.y
:= MulDiv( val
, day
, discriminant
);
3802 exc
.zp2
.cur
^[point
].x
:= exc
.zp1
.cur
^[a0
].x
+ R
.x
;
3803 exc
.zp2
.cur
^[point
].y
:= exc
.zp1
.cur
^[a0
].y
+ R
.y
;
3808 (* else, take the middle of the middles of A and B *)
3810 exc
.zp2
.cur
^[point
].x
:= ( exc
.zp1
.cur
^[a0
].x
+
3811 exc
.zp1
.cur
^[a1
].x
+
3812 exc
.zp0
.cur
^[b0
].x
+
3813 exc
.zp0
.cur
^[b1
].x
) div 4;
3815 exc
.zp2
.cur
^[point
].y
:= ( exc
.zp1
.cur
^[a0
].y
+
3816 exc
.zp1
.cur
^[a1
].y
+
3817 exc
.zp0
.cur
^[b0
].y
+
3818 exc
.zp0
.cur
^[b1
].y
) div 4;
3822 (**********************************************)
3823 (* ALIGNPTS[] : ALIGN PoinTS *)
3824 (* CodeRange : $27 *)
3826 procedure Ins_ALIGNPTS( args
: PStorage
);
3829 distance
: TT_F26dot6
;
3834 if (args
^[0] < 0) or (args
^[0] >= exc
.zp1
.n_points
) or
3835 (args
^[1] < 0) or (args
^[1] >= exc
.zp0
.n_points
) then
3837 exc
.error
:= TT_Err_Invalid_Reference
;
3841 distance
:= exc
.func_project( exc
.zp0
.cur
^[p2
],
3842 exc
.zp1
.cur
^[p1
] ) div 2;
3844 exc
.func_move( @exc
.zp1
, p1
, distance
);
3845 exc
.func_move( @exc
.zp0
, p2
, -distance
);
3848 (**********************************************)
3849 (* IP[] : Interpolate Point *)
3850 (* CodeRange : $39 *)
3852 procedure Ins_IP( args
: PStorage
);
3861 distance
: TT_F26dot6
;
3866 if exc
.top
< exc
.GS
.loop
then
3868 exc
.error
:= TT_Err_Invalid_Reference
;
3872 org_a
:= exc
.func_dualProj( exc
.zp0
.org
^[exc
.GS
.rp1
], Null_Vector
);
3874 org_b
:= exc
.func_dualProj( exc
.zp1
.org
^[exc
.GS
.rp2
], Null_Vector
);
3876 cur_a
:= exc
.func_project( exc
.zp0
.cur
^[exc
.GS
.rp1
], Null_Vector
);
3878 cur_b
:= exc
.func_project( exc
.zp1
.cur
^[exc
.GS
.rp2
], Null_Vector
);
3880 while exc
.GS
.loop
> 0 do
3885 point
:= exc
.stack
^[ exc
.args
];
3887 org_x
:= exc
.func_dualProj( exc
.zp2
.org
^[point
], Null_Vector
);
3889 cur_x
:= exc
.func_project( exc
.zp2
.cur
^[point
], Null_Vector
);
3891 if (( org_a
<= org_b
) and ( org_x
<= org_a
)) or
3892 (( org_a
> org_b
) and ( org_x
>= org_a
)) then
3894 distance
:= ( cur_a
- org_a
) + ( org_x
- cur_x
);
3897 if (( org_a
<= org_b
) and ( org_x
>= org_b
)) or
3898 (( org_a
> org_b
) and ( org_x
< org_b
)) then
3900 distance
:= ( cur_b
- org_b
) + ( org_x
- cur_x
);
3904 (* note : it seems that rounding this value isn't a good *)
3905 (* idea ( width of capital 'S' in Times *)
3907 distance
:= MulDiv( cur_b
- cur_a
,
3909 org_b
- org_a
) + ( cur_a
- cur_x
);
3912 exc
.func_move( @exc
.zp2
, point
, distance
);
3918 exc
.new_top
:= exc
.args
;
3921 (**********************************************)
3922 (* UTP[a] : UnTouch Point *)
3923 (* CodeRange : $29 *)
3925 procedure Ins_UTP( args
: PStorage
);
3929 if (args
^[0] < 0) or (args
^[0] >= exc
.zp0
.n_points
) then
3931 exc
.error
:= TT_Err_Invalid_Reference
;
3937 if exc
.GS
.freeVector
.x
<> 0 then mask
:= mask
and not TT_Flag_Touched_X
;
3938 if exc
.GS
.freeVector
.y
<> 0 then mask
:= mask
and not TT_Flag_Touched_Y
;
3940 exc
.zp0
.flags
^[args
^[0]] := exc
.zp0
.flags
^[args
^[0]] and mask
;
3943 (**********************************************)
3944 (* IUP[a] : Interpolate Untouched Points *)
3945 (* CodeRange : $30-$31 *)
3947 procedure Ins_IUP( args
: PStorage
);
3951 first_point
, (* first point of contour *)
3952 end_point
, (* end point (last+1) of contour *)
3954 first_touched
, (* first touched point in contour *)
3955 cur_touched
, (* current touched point in contour *)
3957 point
, (* current point *)
3958 contour
: Int
; (* current contour *)
3960 orgs
, (* original and current coordinate *)
3961 curs
: TT_Points
; (* arrays *)
3963 procedure Shift_X( p1
, p2
, p
: Int
);
3968 x
:= curs
^[p
].x
- orgs
^[p
].x
;
3970 for i
:= p1
to p
-1 do inc( curs
^[i
].x
, x
);
3971 for i
:= p
+1 to p2
do inc( curs
^[i
].x
, x
);
3974 procedure Shift_Y( p1
, p2
, p
: Int
);
3979 y
:= curs
^[p
].y
- orgs
^[p
].y
;
3981 for i
:= p1
to p
-1 do inc( curs
^[i
].y
, y
);
3982 for i
:= p
+1 to p2
do inc( curs
^[i
].y
, y
);
3986 procedure Interp_X( p1
, p2
, ref1
, ref2
: Int
);
3989 x
, x1
, x2
, d1
, d2
: TT_F26dot6
;
3992 if p1
> p2
then exit
;
3994 x1
:= orgs
^[ref1
].x
; d1
:= curs
^[ref1
].x
- orgs
^[ref1
].x
;
3995 x2
:= orgs
^[ref2
].x
; d2
:= curs
^[ref2
].x
- orgs
^[ref2
].x
;
3998 for i
:= p1
to p2
do
4001 if x
<= x1
then x
:= x
+ d1
4010 for i
:= p1
to p2
do
4014 if (x
<= x1
) then x
:= x
+ d1
4016 if (x
>= x2
) then x
:= x
+ d2
4018 x
:= curs
^[ref1
].x
+
4019 MulDiv( x
-x1
, curs
^[ref2
].x
-curs
^[ref1
].x
, x2
-x1
);
4027 for i
:= p1
to p2
do
4031 if ( x
<= x2
) then x
:= x
+ d2
4033 if ( x
>= x1
) then x
:= x
+ d1
4035 x
:= curs
^[ref1
].x
+
4036 MulDiv( x
-x1
, curs
^[ref2
].x
-curs
^[ref1
].x
, x2
-x1
);
4042 procedure Interp_Y( p1
, p2
, ref1
, ref2
: Int
);
4045 y
, y1
, y2
, d1
, d2
: TT_F26dot6
;
4048 if p1
> p2
then exit
;
4050 y1
:= orgs
^[ref1
].y
; d1
:= curs
^[ref1
].y
- orgs
^[ref1
].y
;
4051 y2
:= orgs
^[ref2
].y
; d2
:= curs
^[ref2
].y
- orgs
^[ref2
].y
;
4054 for i
:= p1
to p2
do
4057 if y
<= y1
then y
:= y
+ d1
4066 for i
:= p1
to p2
do
4070 if (y
<= y1
) then y
:= y
+ d1
4072 if (y
>= y2
) then y
:= y
+ d2
4074 y
:= curs
^[ref1
].y
+
4075 MulDiv( y
-y1
, curs
^[ref2
].y
-curs
^[ref1
].y
, y2
-y1
);
4083 for i
:= p1
to p2
do
4087 if ( y
<= y2
) then y
:= y
+ d2
4089 if ( y
>= y1
) then y
:= y
+ d1
4091 y
:= curs
^[ref1
].y
+
4092 MulDiv( y
-y1
, curs
^[ref2
].y
-curs
^[ref1
].y
, y2
-y1
);
4099 orgs
:= exc
.pts
.org
;
4100 curs
:= exc
.pts
.cur
;
4102 case exc
.opcode
and 1 of
4103 0 : mask
:= TT_Flag_Touched_Y
;
4104 1 : mask
:= TT_Flag_Touched_X
;
4115 end_point
:= pts
.conEnds
^[contour
];
4116 first_point
:= point
;
4118 while ( point
<= end_point
) and
4119 ( pts
.flags
^[point
] and mask
= 0 ) do inc(point
);
4121 if point
<= end_point
then
4124 first_touched
:= point
;
4125 cur_touched
:= point
;
4129 while ( point
<= end_point
) do
4131 if pts
.flags
^[point
] and mask
<> 0 then
4133 if opcode
and 1 <> 0 then
4134 Interp_X( cur_touched
+1, point
-1, cur_touched
, point
)
4136 Interp_Y( cur_touched
+1, point
-1, cur_touched
, point
);
4138 cur_touched
:= point
;
4144 if cur_touched
= first_touched
then
4145 if opcode
and 1 <> 0 then
4146 Shift_X( first_point
, end_point
, cur_touched
)
4148 Shift_Y( first_point
, end_point
, cur_touched
)
4151 if opcode
and 1 <> 0 then
4153 interp_x( cur_touched
+1, end_point
, cur_touched
, first_touched
);
4154 interp_x( first_point
, first_touched
-1, cur_touched
, first_touched
);
4158 interp_y( cur_touched
+1, end_point
, cur_touched
, first_touched
);
4159 interp_y( first_point
, first_touched
-1, cur_touched
, first_touched
);
4167 until contour
>= pts
.n_contours
;
4173 (**********************************************)
4174 (* DELTAPn[] : DELTA Exceptions P1, P2, P3 *)
4175 (* CodeRange : $5D,$71,$72 *)
4177 procedure Ins_DELTAP( args
: PStorage
);
4186 for K
:= 1 to nump
do
4188 if exc
.args
< 2 then
4190 exc
.error
:= TT_Err_Too_Few_Arguments
;
4196 A
:= exc
.stack
^[exc
.args
+1];
4197 B
:= exc
.stack
^[ exc
.args
];
4200 (* some commonly fonts have broke programs where the *)
4201 (* the point reference has an invalid value. Here, we *)
4202 (* simply ignore them, because a DeltaP won't change *)
4203 (* a glyph shape dramatically.. *)
4206 if A
< exc
.zp0
.n_points
then
4208 C
:= ( B
and $F0 ) shr 4;
4216 C
:= C
+ exc
.GS
.delta_Base
;
4218 if GET_Ppem
= C
then
4220 B
:= (B
and $F) - 8;
4221 if B
>= 0 then B
:= B
+1;
4222 B
:= ( B
*64 ) div ( 1 shl exc
.GS
.delta_Shift
);
4224 exc
.func_move( @exc
.zp0
, A
, B
);
4230 exc
.new_top
:= exc
.args
;
4234 (**********************************************)
4235 (* DELTACn[] : DELTA Exceptions C1, C2, C3 *)
4236 (* CodeRange : $73,$74,$75 *)
4238 procedure Ins_DELTAC( args
: PStorage
);
4247 for K
:= 1 to nump
do
4249 if exc
.args
< 2 then
4251 exc
.error
:= TT_Err_Too_Few_Arguments
;
4257 A
:= exc
.stack
^[exc
.args
+1];
4258 B
:= exc
.stack
^[ exc
.args
];
4260 if A
>= exc
.cvtSize
then
4262 exc
.error
:= TT_Err_Invalid_Reference
;
4266 C
:= ( B
and $F0 ) shr 4;
4274 C
:= C
+ exc
.GS
.delta_Base
;
4276 if GET_Ppem
= C
then
4278 B
:= (B
and $F) - 8;
4279 if B
>= 0 then B
:= B
+1;
4280 B
:= ( B
*64 ) div ( 1 shl exc
.GS
.delta_Shift
);
4282 exc
.func_move_cvt( A
, B
);
4286 exc
.new_top
:= exc
.args
;
4289 (****************************************************************)
4291 (* MISC. INSTRUCTIONS *)
4293 (****************************************************************)
4295 (***********************************************************)
4296 (* DEBUG[] : DEBUG. Unsupported *)
4297 (* CodeRange : $4F *)
4299 (* NOTE : The original instruction pops a value from the stack *)
4301 procedure Ins_DEBUG( args
: PStorage
);
4303 exc
.error
:= TT_Err_Debug_Opcode
;
4306 (**********************************************)
4307 (* GETINFO[] : GET INFOrmation *)
4308 (* CodeRange : $88 *)
4310 procedure Ins_GETINFO( args
: PStorage
);
4316 if args
^[0] and 1 <> 0 then K
:= 3;
4317 (* We return then Windows 3.1 version number *)
4318 (* for the font scaler *)
4320 if false then K
:= K
or $80;
4321 (* Has the glyph been rotated ? *)
4324 if false then K
:= K
or $100;
4325 (* Has the glyph been stretched ? *)
4332 procedure Ins_UNKNOWN( args
: PStorage
);
4334 exc
.error
:= TT_Err_Invalid_Opcode
;
4341 Instruct_Dispatch
: array[0..255] of TInstruction_Function
4343 (* SVTCA y *) Ins_SVTCA
,
4344 (* SVTCA x *) Ins_SVTCA
,
4345 (* SPvTCA y *) Ins_SPVTCA
,
4346 (* SPvTCA x *) Ins_SPVTCA
,
4347 (* SFvTCA y *) Ins_SFVTCA
,
4348 (* SFvTCA x *) Ins_SFVTCA
,
4349 (* SPvTL // *) Ins_SPVTL
,
4350 (* SPvTL + *) Ins_SPVTL
,
4351 (* SFvTL // *) Ins_SFVTL
,
4352 (* SFvTL + *) Ins_SFVTL
,
4353 (* SPvFS *) Ins_SPVFS
,
4354 (* SFvFS *) Ins_SFVFS
,
4357 (* SFvTPv *) Ins_SFVTPV
,
4358 (* ISECT *) Ins_ISECT
,
4360 (* SRP0 *) Ins_SRP0
,
4361 (* SRP1 *) Ins_SRP1
,
4362 (* SRP2 *) Ins_SRP2
,
4363 (* SZP0 *) Ins_SZP0
,
4364 (* SZP1 *) Ins_SZP1
,
4365 (* SZP2 *) Ins_SZP2
,
4366 (* SZPS *) Ins_SZPS
,
4367 (* SLOOP *) Ins_SLOOP
,
4369 (* RTHG *) Ins_RTHG
,
4371 (* ELSE *) Ins_ELSE
,
4372 (* JMPR *) Ins_JMPR
,
4373 (* SCvTCi *) Ins_SCVTCI
,
4374 (* SSwCi *) Ins_SSWCI
,
4379 (* CLEAR *) Ins_CLEAR
,
4380 (* SWAP *) Ins_SWAP
,
4381 (* DEPTH *) Ins_DEPTH
,
4382 (* CINDEX *) Ins_CINDEX
,
4383 (* MINDEX *) Ins_MINDEX
,
4384 (* AlignPTS *) Ins_ALIGNPTS
,
4385 (* INS_$28 *) Ins_UNKNOWN
,
4387 (* LOOPCALL *) Ins_LOOPCALL
,
4388 (* CALL *) Ins_CALL
,
4389 (* FDEF *) Ins_FDEF
,
4390 (* ENDF *) Ins_ENDF
,
4391 (* MDAP[0] *) Ins_MDAP
,
4392 (* MDAP[1] *) Ins_MDAP
,
4394 (* IUP[0] *) Ins_IUP
,
4395 (* IUP[1] *) Ins_IUP
,
4396 (* SHP[0] *) Ins_SHP
,
4397 (* SHP[1] *) Ins_SHP
,
4398 (* SHC[0] *) Ins_SHC
,
4399 (* SHC[1] *) Ins_SHC
,
4400 (* SHZ[0] *) Ins_SHZ
,
4401 (* SHZ[1] *) Ins_SHZ
,
4402 (* SHPIX *) Ins_SHPIX
,
4404 (* MSIRP[0] *) Ins_MSIRP
,
4405 (* MSIRP[1] *) Ins_MSIRP
,
4406 (* AlignRP *) Ins_ALIGNRP
,
4407 (* RTDG *) Ins_RTDG
,
4408 (* MIAP[0] *) Ins_MIAP
,
4409 (* MIAP[1] *) Ins_MIAP
,
4411 (* NPushB *) Ins_NPUSHB
,
4412 (* NPushW *) Ins_NPUSHW
,
4415 (* WCvtP *) Ins_WCVTP
,
4416 (* RCvt *) Ins_RCVT
,
4419 (* SCFS *) Ins_SCFS
,
4422 (* MPPEM *) Ins_MPPEM
,
4424 (* FlipON *) Ins_FLIPON
,
4425 (* FlipOFF *) Ins_FLIPOFF
,
4426 (* DEBUG *) Ins_DEBUG
,
4429 (* LTEQ *) Ins_LTEQ
,
4431 (* GTEQ *) Ins_GTEQ
,
4435 (* EVEN *) Ins_EVEN
,
4441 (* DeltaP1 *) Ins_DELTAP
,
4451 (* FLOOR *) Ins_FLOOR
,
4452 (* CEILING *) Ins_CEILING
,
4453 (* ROUND[0] *) Ins_ROUND
,
4454 (* ROUND[1] *) Ins_ROUND
,
4455 (* ROUND[2] *) Ins_ROUND
,
4456 (* ROUND[3] *) Ins_ROUND
,
4457 (* NROUND[0]*) Ins_ROUND
,
4458 (* NROUND[1]*) Ins_ROUND
,
4459 (* NROUND[2]*) Ins_ROUND
,
4460 (* NROUND[3]*) Ins_ROUND
,
4462 (* WCvtF *) Ins_WCVTF
,
4463 (* DeltaP2 *) Ins_DELTAP
,
4464 (* DeltaP3 *) Ins_DELTAP
,
4465 (* DeltaCn[0]*) Ins_DELTAC
,
4466 (* DeltaCn[1]*) Ins_DELTAC
,
4467 (* DeltaCn[2]*) Ins_DELTAC
,
4468 (* SROUND *) Ins_SROUND
,
4469 (* S45Round *) Ins_S45ROUND
,
4470 (* JROT *) Ins_JROT
,
4471 (* JROF *) Ins_JROF
,
4472 (* ROFF *) Ins_ROFF
,
4473 (* INS_$7B *) Ins_UNKNOWN
,
4474 (* RUTG *) Ins_RUTG
,
4475 (* RDTG *) Ins_RDTG
,
4476 (* SANGW *) Ins_SANGW
,
4479 (* FlipPT *) Ins_FLIPPT
,
4480 (* FlipRgON *) Ins_FLIPRGON
,
4481 (* FlipRgOFF*) Ins_FLIPRGOFF
,
4482 (* INS_$83 *) Ins_UNKNOWN
,
4483 (* INS_$84 *) Ins_UNKNOWN
,
4484 (* ScanCTRL *) Ins_SCANCTRL
,
4485 (* SDPVTL[0]*) Ins_SDPVTL
,
4486 (* SDPVTL[1]*) Ins_SDPVTL
,
4487 (* GetINFO *) Ins_GETINFO
,
4488 (* IDEF *) Ins_IDEF
,
4489 (* ROLL *) Ins_ROLL
,
4492 (* ScanTYPE *) Ins_SCANTYPE
,
4493 (* InstCTRL *) Ins_INSTCTRL
,
4494 (* INS_$8F *) Ins_UNKNOWN
,
4496 (* INS_$90 *) Ins_UNKNOWN
,
4497 (* INS_$91 *) Ins_UNKNOWN
,
4498 (* INS_$92 *) Ins_UNKNOWN
,
4499 (* INS_$93 *) Ins_UNKNOWN
,
4500 (* INS_$94 *) Ins_UNKNOWN
,
4501 (* INS_$95 *) Ins_UNKNOWN
,
4502 (* INS_$96 *) Ins_UNKNOWN
,
4503 (* INS_$97 *) Ins_UNKNOWN
,
4504 (* INS_$98 *) Ins_UNKNOWN
,
4505 (* INS_$99 *) Ins_UNKNOWN
,
4506 (* INS_$9A *) Ins_UNKNOWN
,
4507 (* INS_$9B *) Ins_UNKNOWN
,
4508 (* INS_$9C *) Ins_UNKNOWN
,
4509 (* INS_$9D *) Ins_UNKNOWN
,
4510 (* INS_$9E *) Ins_UNKNOWN
,
4511 (* INS_$9F *) Ins_UNKNOWN
,
4513 (* INS_$A0 *) Ins_UNKNOWN
,
4514 (* INS_$A1 *) Ins_UNKNOWN
,
4515 (* INS_$A2 *) Ins_UNKNOWN
,
4516 (* INS_$A3 *) Ins_UNKNOWN
,
4517 (* INS_$A4 *) Ins_UNKNOWN
,
4518 (* INS_$A5 *) Ins_UNKNOWN
,
4519 (* INS_$A6 *) Ins_UNKNOWN
,
4520 (* INS_$A7 *) Ins_UNKNOWN
,
4521 (* INS_$A8 *) Ins_UNKNOWN
,
4522 (* INS_$A9 *) Ins_UNKNOWN
,
4523 (* INS_$AA *) Ins_UNKNOWN
,
4524 (* INS_$AB *) Ins_UNKNOWN
,
4525 (* INS_$AC *) Ins_UNKNOWN
,
4526 (* INS_$AD *) Ins_UNKNOWN
,
4527 (* INS_$AE *) Ins_UNKNOWN
,
4528 (* INS_$AF *) Ins_UNKNOWN
,
4530 (* PushB[0] *) Ins_PUSHB
,
4531 (* PushB[1] *) Ins_PUSHB
,
4532 (* PushB[2] *) Ins_PUSHB
,
4533 (* PushB[3] *) Ins_PUSHB
,
4534 (* PushB[4] *) Ins_PUSHB
,
4535 (* PushB[5] *) Ins_PUSHB
,
4536 (* PushB[6] *) Ins_PUSHB
,
4537 (* PushB[7] *) Ins_PUSHB
,
4538 (* PushW[0] *) Ins_PUSHW
,
4539 (* PushW[1] *) Ins_PUSHW
,
4540 (* PushW[2] *) Ins_PUSHW
,
4541 (* PushW[3] *) Ins_PUSHW
,
4542 (* PushW[4] *) Ins_PUSHW
,
4543 (* PushW[5] *) Ins_PUSHW
,
4544 (* PushW[6] *) Ins_PUSHW
,
4545 (* PushW[7] *) Ins_PUSHW
,
4547 (* MDRP[00] *) Ins_MDRP
,
4548 (* MDRP[01] *) Ins_MDRP
,
4549 (* MDRP[02] *) Ins_MDRP
,
4550 (* MDRP[03] *) Ins_MDRP
,
4551 (* MDRP[04] *) Ins_MDRP
,
4552 (* MDRP[05] *) Ins_MDRP
,
4553 (* MDRP[06] *) Ins_MDRP
,
4554 (* MDRP[07] *) Ins_MDRP
,
4555 (* MDRP[08] *) Ins_MDRP
,
4556 (* MDRP[09] *) Ins_MDRP
,
4557 (* MDRP[10] *) Ins_MDRP
,
4558 (* MDRP[11] *) Ins_MDRP
,
4559 (* MDRP[12] *) Ins_MDRP
,
4560 (* MDRP[13] *) Ins_MDRP
,
4561 (* MDRP[14] *) Ins_MDRP
,
4562 (* MDRP[15] *) Ins_MDRP
,
4563 (* MDRP[16] *) Ins_MDRP
,
4564 (* MDRP[17] *) Ins_MDRP
,
4566 (* MDRP[18] *) Ins_MDRP
,
4567 (* MDRP[19] *) Ins_MDRP
,
4568 (* MDRP[20] *) Ins_MDRP
,
4569 (* MDRP[21] *) Ins_MDRP
,
4570 (* MDRP[22] *) Ins_MDRP
,
4571 (* MDRP[23] *) Ins_MDRP
,
4572 (* MDRP[24] *) Ins_MDRP
,
4573 (* MDRP[25] *) Ins_MDRP
,
4574 (* MDRP[26] *) Ins_MDRP
,
4575 (* MDRP[27] *) Ins_MDRP
,
4576 (* MDRP[28] *) Ins_MDRP
,
4577 (* MDRP[29] *) Ins_MDRP
,
4578 (* MDRP[30] *) Ins_MDRP
,
4579 (* MDRP[31] *) Ins_MDRP
,
4581 (* MIRP[00] *) Ins_MIRP
,
4582 (* MIRP[01] *) Ins_MIRP
,
4583 (* MIRP[02] *) Ins_MIRP
,
4584 (* MIRP[03] *) Ins_MIRP
,
4585 (* MIRP[04] *) Ins_MIRP
,
4586 (* MIRP[05] *) Ins_MIRP
,
4587 (* MIRP[06] *) Ins_MIRP
,
4588 (* MIRP[07] *) Ins_MIRP
,
4589 (* MIRP[08] *) Ins_MIRP
,
4590 (* MIRP[09] *) Ins_MIRP
,
4591 (* MIRP[10] *) Ins_MIRP
,
4592 (* MIRP[11] *) Ins_MIRP
,
4593 (* MIRP[12] *) Ins_MIRP
,
4594 (* MIRP[13] *) Ins_MIRP
,
4595 (* MIRP[14] *) Ins_MIRP
,
4596 (* MIRP[15] *) Ins_MIRP
,
4598 (* MIRP[16] *) Ins_MIRP
,
4599 (* MIRP[17] *) Ins_MIRP
,
4600 (* MIRP[18] *) Ins_MIRP
,
4601 (* MIRP[19] *) Ins_MIRP
,
4602 (* MIRP[20] *) Ins_MIRP
,
4603 (* MIRP[21] *) Ins_MIRP
,
4604 (* MIRP[22] *) Ins_MIRP
,
4605 (* MIRP[23] *) Ins_MIRP
,
4606 (* MIRP[24] *) Ins_MIRP
,
4607 (* MIRP[25] *) Ins_MIRP
,
4608 (* MIRP[26] *) Ins_MIRP
,
4609 (* MIRP[27] *) Ins_MIRP
,
4610 (* MIRP[28] *) Ins_MIRP
,
4611 (* MIRP[29] *) Ins_MIRP
,
4612 (* MIRP[30] *) Ins_MIRP
,
4613 (* MIRP[31] *) Ins_MIRP
4617 (****************************************************************)
4621 (* This function executes a run of opcodes. It will exit *)
4622 (* in the following cases : *)
4624 (* - Errors ( in which case it returns FALSE ) *)
4626 (* - Reaching the end of the main code range (returns TRUE) *)
4627 (* reaching the end of a code range within a function *)
4628 (* call is an error. *)
4630 (* - After executing one single opcode, if the flag *)
4631 (* 'Instruction_Trap' is set to TRUE. (returns TRUE) *)
4633 (* On exit whith TRUE, test IP < CodeSize to know wether it *)
4634 (* comes from a instruction trap or a normal termination *)
4637 (* Note : The documented DEBUG opcode pops a value from *)
4638 (* the stack. This behaviour is unsupported, here *)
4639 (* a DEBUG opcode is always an error. *)
4642 (* THIS IS THE INTERPRETER'S MAIN LOOP *)
4644 (* Instructions appear in the specs' order *)
4646 (****************************************************************)
4648 function Run_Ins( exec
: PExec_Context
) : Boolean;
4650 SuiteLabel
, ErrorLabel
, No_Error
;
4657 (* set cvt functions *)
4659 exc
.metrics
.ratio
:= 0;
4660 if exc
.instance
^.metrics
.x_ppem
<> exc
.instance
^.metrics
.y_ppem
then
4663 exc
.func_read_cvt
:= @Read_CVT_Stretched
;
4664 exc
.func_write_cvt
:= @Write_CVT_Stretched
;
4665 exc
.func_move_cvt
:= @Move_CVT_Stretched
;
4669 exc
.func_read_cvt
:= @Read_CVT
;
4670 exc
.func_write_cvt
:= @Write_CVT
;
4671 exc
.func_move_cvt
:= @Move_CVT
;
4675 exc
.func_read_cvt
:= Read_CVT_Stretched
;
4676 exc
.func_write_cvt
:= Write_CVT_Stretched
;
4677 exc
.func_move_cvt
:= Move_CVT_Stretched
;
4681 exc
.func_read_cvt
:= Read_CVT
;
4682 exc
.func_write_cvt
:= Write_CVT
;
4683 exc
.func_move_cvt
:= Move_CVT
;
4687 Compute_Round( exc
.GS
.round_state
);
4692 (* First, let's check for empty stack and overflow *)
4694 exc
.args
:= exc
.top
- Pop_Push_Count
[ exc
.opcode
*2 ];
4696 (* args is the top of the stack once arguments have been popped *)
4697 (* one can also see it as the index of the last argument *)
4699 if exc
.args
< 0 then
4701 exc
.error
:= TT_Err_Too_Few_Arguments
;
4705 exc
.new_top
:= exc
.args
+ Pop_Push_Count
[ exc
.opcode
*2+1 ];
4707 (* new_top is the new top of the stack, after the instruction's *)
4708 (* execution. top will be set to new_top after the 'case' *)
4710 if exc
.new_top
> exc
.stackSize
then
4712 exc
.error
:= TT_Err_Stack_Overflow
;
4716 exc
.step_ins
:= true;
4717 exc
.error
:= TT_Err_Ok
;
4719 Instruct_Dispatch
[ exc
.opcode
]( PStorage(@exc
.stack
^[exc
.args
]) );
4721 if exc
.error
<> TT_Err_Ok
then
4726 TT_Err_Invalid_Opcode
: (* looking for redefined instructions *)
4730 while ( A
< exc
.numIDefs
) do
4731 with exc
.IDefs
^[A
] do
4733 if Active
and ( exc
.opcode
= Opc
) then
4735 if exc
.callTop
>= exc
.callSize
then
4737 exc
.error
:= TT_Err_Invalid_Reference
;
4741 with exc
.callstack
^[exc
.callTop
] do
4743 Caller_Range
:= exc
.curRange
;
4744 Caller_IP
:= exc
.IP
+1;
4746 Cur_Restart
:= Start
;
4749 if not Goto_CodeRange( Range
, Start
) then
4757 exc
.error
:= TT_Err_Invalid_Opcode
;
4762 exc
.error
:= exc
.error
;
4768 exc
.top
:= exc
.new_top
;
4770 if exc
.step_ins
then inc( exc
.IP
, exc
.length
);
4774 if (exc
.IP
>= exc
.codeSize
) then
4776 if exc
.callTop
> 0 then
4778 exc
.error
:= TT_Err_Code_Overflow
;
4784 until exc
.instruction_trap
;