1 /***************************************************************************/
5 /* TrueType bytecode interpreter (body). */
7 /* Copyright 1996-2000 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
16 /***************************************************************************/
19 #include <freetype/internal/ftdebug.h>
20 #include <freetype/internal/ftcalc.h>
21 #include <freetype/ftsystem.h>
24 #ifdef FT_FLAT_COMPILE
30 #include <truetype/ttinterp.h>
35 #include <freetype/internal/tterrors.h>
38 #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
41 #define TT_MULFIX FT_MulFix
42 #define TT_MULDIV FT_MulDiv
44 #define TT_INT64 FT_Int64
47 /*************************************************************************/
49 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
50 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
51 /* messages during execution. */
54 #define FT_COMPONENT trace_ttinterp
56 #undef NO_APPLE_PATENT
57 #define APPLE_THRESHOLD 0x4000000L
59 /*************************************************************************/
61 /* In order to detect infinite loops in the code, we set up a counter */
62 /* within the run loop. A single stroke of interpretation is now */
63 /* limitet to a maximal number of opcodes defined below. */
65 #define MAX_RUNNABLE_OPCODES 1000000L
68 /*************************************************************************/
70 /* There are two kinds of implementations: */
72 /* a. static implementation */
74 /* The current execution context is a static variable, which fields */
75 /* are accessed directly by the interpreter during execution. The */
76 /* context is named `cur'. */
78 /* This version is non-reentrant, of course. */
80 /* b. indirect implementation */
82 /* The current execution context is passed to _each_ function as its */
83 /* first argument, and each field is thus accessed indirectly. */
85 /* This version is fully re-entrant. */
87 /* The idea is that an indirect implementation may be slower to execute */
88 /* on low-end processors that are used in some systems (like 386s or */
91 /* As a consequence, the indirect implementation is now the default, as */
92 /* its performance costs can be considered negligible in our context. */
93 /* Note, however, that we kept the same source with macros because: */
95 /* - The code is kept very close in design to the Pascal code used for */
98 /* - It's much more readable that way! */
100 /* - It's still open to experimentation and tuning. */
102 /*************************************************************************/
105 #ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */
107 #define CUR (*exc) /* see ttobjs.h */
109 #else /* static implementation */
114 TT_ExecContextRec cur
; /* static exec. context variable */
116 /* apparently, we have a _lot_ of direct indexing when accessing */
117 /* the static `cur', which makes the code bigger (due to all the */
118 /* four bytes addresses). */
120 #endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
123 /*************************************************************************/
125 /* The instruction argument stack. */
127 #define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */
130 /*************************************************************************/
132 /* This macro is used whenever `exec' is unused in a function, to avoid */
133 /* stupid warnings from pedantic compilers. */
135 #define FT_UNUSED_EXEC FT_UNUSED( CUR )
138 /*************************************************************************/
140 /* This macro is used whenever `args' is unused in a function, to avoid */
141 /* stupid warnings from pedantic compilers. */
143 #define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args )
146 /*************************************************************************/
148 /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */
149 /* increase readabilty of the code. */
151 /*************************************************************************/
154 #define SKIP_Code() \
157 #define GET_ShortIns() \
158 GetShortIns( EXEC_ARG )
160 #define NORMalize( x, y, v ) \
161 Normalize( EXEC_ARG_ x, y, v )
163 #define SET_SuperRound( scale, flags ) \
164 SetSuperRound( EXEC_ARG_ scale, flags )
166 #define ROUND_None( d, c ) \
167 Round_None( EXEC_ARG_ d, c )
169 #define INS_Goto_CodeRange( range, ip ) \
170 Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
172 #define CUR_Func_project( x, y ) \
173 CUR.func_project( EXEC_ARG_ x, y )
175 #define CUR_Func_move( z, p, d ) \
176 CUR.func_move( EXEC_ARG_ z, p, d )
178 #define CUR_Func_dualproj( x, y ) \
179 CUR.func_dualproj( EXEC_ARG_ x, y )
181 #define CUR_Func_freeProj( x, y ) \
182 CUR.func_freeProj( EXEC_ARG_ x, y )
184 #define CUR_Func_round( d, c ) \
185 CUR.func_round( EXEC_ARG_ d, c )
187 #define CUR_Func_read_cvt( index ) \
188 CUR.func_read_cvt( EXEC_ARG_ index )
190 #define CUR_Func_write_cvt( index, val ) \
191 CUR.func_write_cvt( EXEC_ARG_ index, val )
193 #define CUR_Func_move_cvt( index, val ) \
194 CUR.func_move_cvt( EXEC_ARG_ index, val )
196 #define CURRENT_Ratio() \
197 Current_Ratio( EXEC_ARG )
199 #define CURRENT_Ppem() \
200 Current_Ppem( EXEC_ARG )
205 #define CALC_Length() \
206 Calc_Length( EXEC_ARG )
208 #define INS_SxVTL( a, b, c, d ) \
209 Ins_SxVTL( EXEC_ARG_ a, b, c, d )
211 #define COMPUTE_Funcs() \
212 Compute_Funcs( EXEC_ARG )
214 #define COMPUTE_Round( a ) \
215 Compute_Round( EXEC_ARG_ a )
217 #define COMPUTE_Point_Displacement( a, b, c, d ) \
218 Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
220 #define MOVE_Zp2_Point( a, b, c, t ) \
221 Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
224 /*************************************************************************/
226 /* Instruction dispatch function, as used by the interpreter. */
228 typedef void (*TInstruction_Function
)( INS_ARG
);
231 /*************************************************************************/
233 /* A simple bounds-checking macro. */
235 #define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
245 /*************************************************************************/
247 /* CODERANGE FUNCTIONS */
249 /*************************************************************************/
252 /*************************************************************************/
255 /* TT_Goto_CodeRange */
258 /* Switches to a new code range (updates the code related elements in */
259 /* `exec', and `IP'). */
262 /* range :: The new execution code range. */
264 /* IP :: The new IP in the new code range. */
267 /* exec :: The target execution context. */
270 /* FreeType error code. 0 means success. */
273 FT_Error
TT_Goto_CodeRange( TT_ExecContext exec
,
277 TT_CodeRange
* coderange
;
280 FT_Assert( range
>= 1 && range
<= 3 );
282 coderange
= &exec
->codeRangeTable
[range
- 1];
284 FT_Assert( coderange
->base
!= NULL
);
286 /* NOTE: Because the last instruction of a program may be a CALL */
287 /* which will return to the first byte *after* the code */
288 /* range, we test for IP <= Size instead of IP < Size. */
290 FT_Assert( (FT_ULong
)IP
<= coderange
->size
);
292 exec
->code
= coderange
->base
;
293 exec
->codeSize
= coderange
->size
;
295 exec
->curRange
= range
;
301 /*************************************************************************/
304 /* TT_Set_CodeRange */
307 /* Sets a code range. */
310 /* range :: The code range index. */
312 /* base :: The new code base. */
314 /* length :: The range size in bytes. */
317 /* exec :: The target execution context. */
320 /* FreeType error code. 0 means success. */
323 FT_Error
TT_Set_CodeRange( TT_ExecContext exec
,
328 FT_Assert( range
>= 1 && range
<= 3 );
330 exec
->codeRangeTable
[range
- 1].base
= (FT_Byte
*)base
;
331 exec
->codeRangeTable
[range
- 1].size
= length
;
337 /*************************************************************************/
340 /* TT_Clear_CodeRange */
343 /* Clears a code range. */
346 /* range :: The code range index. */
349 /* exec :: The target execution context. */
352 /* FreeType error code. 0 means success. */
355 /* Does not set the Error variable. */
358 FT_Error
TT_Clear_CodeRange( TT_ExecContext exec
,
361 FT_Assert( range
>= 1 && range
<= 3 );
363 exec
->codeRangeTable
[range
- 1].base
= NULL
;
364 exec
->codeRangeTable
[range
- 1].size
= 0;
370 /*************************************************************************/
372 /* EXECUTION CONTEXT ROUTINES */
374 /*************************************************************************/
377 /*************************************************************************/
380 /* TT_Destroy_Context */
383 /* Destroys a given context. */
386 /* exec :: A handle to the target execution context. */
388 /* memory :: A handle to the parent memory object. */
391 /* FreeType error code. 0 means success. */
394 /* Only the glyph loader and debugger should call this function. */
397 FT_Error
TT_Destroy_Context( TT_ExecContext exec
,
400 /* free composite load stack */
401 FREE( exec
->loadStack
);
406 exec
->maxContours
= 0;
412 /* free call stack */
413 FREE( exec
->callStack
);
417 /* free glyph code range */
418 FREE( exec
->glyphIns
);
429 /*************************************************************************/
435 /* Initializes a context object. */
438 /* memory :: A handle to the parent memory object. */
440 /* face :: A handle to the source TrueType face object. */
443 /* exec :: A handle to the target execution context. */
446 /* FreeType error code. 0 means success. */
449 FT_Error
Init_Context( TT_ExecContext exec
,
456 FT_TRACE1(( "Init_Context: new object at 0x%08p, parent = 0x%08p\n",
459 exec
->memory
= memory
;
462 if ( ALLOC_ARRAY( exec
->callStack
, exec
->callSize
, TT_CallRec
) )
465 /* all values in the context are set to 0 already, but this is */
466 /* here as a remainder */
468 exec
->maxContours
= 0;
475 exec
->loadStack
= NULL
;
476 exec
->glyphIns
= NULL
;
484 FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n",
486 TT_Destroy_Context( exec
, memory
);
492 /*************************************************************************/
498 /* Checks the size of a buffer and reallocates it if necessary. */
501 /* memory :: A handle to the parent memory object. */
503 /* multiplier :: The size in bytes of each element in the buffer. */
505 /* new_max :: The new capacity (size) of the buffer. */
508 /* size :: The address of the buffer's current size expressed */
511 /* buff :: The address of the buffer base pointer. */
514 /* FreeType error code. 0 means success. */
517 FT_Error
Update_Max( FT_Memory memory
,
526 if ( *size
< new_max
)
529 if ( ALLOC( *buff
, new_max
* multiplier
) )
538 /*************************************************************************/
541 /* TT_Load_Context */
544 /* Prepare an execution context for glyph hinting. */
547 /* face :: A handle to the source face object. */
549 /* size :: A handle to the source size object. */
552 /* exec :: A handle to the target execution context. */
555 /* FreeType error code. 0 means success. */
558 /* Only the glyph loader and debugger should call this function. */
561 FT_Error
TT_Load_Context( TT_ExecContext exec
,
572 maxp
= &face
->max_profile
;
577 exec
->numFDefs
= size
->num_function_defs
;
578 exec
->maxFDefs
= size
->max_function_defs
;
579 exec
->numIDefs
= size
->num_instruction_defs
;
580 exec
->maxIDefs
= size
->max_instruction_defs
;
581 exec
->FDefs
= size
->function_defs
;
582 exec
->IDefs
= size
->instruction_defs
;
583 exec
->tt_metrics
= size
->ttmetrics
;
584 exec
->metrics
= size
->root
.metrics
;
586 exec
->maxFunc
= size
->max_func
;
587 exec
->maxIns
= size
->max_ins
;
589 for ( i
= 0; i
< TT_MAX_CODE_RANGES
; i
++ )
590 exec
->codeRangeTable
[i
] = size
->codeRangeTable
[i
];
592 /* set graphics state */
595 exec
->cvtSize
= size
->cvt_size
;
596 exec
->cvt
= size
->cvt
;
598 exec
->storeSize
= size
->storage_size
;
599 exec
->storage
= size
->storage
;
601 exec
->twilight
= size
->twilight
;
604 error
= Update_Max( exec
->memory
,
606 sizeof ( TT_SubGlyphRec
),
607 (void**)&exec
->loadStack
,
608 exec
->face
->max_components
+ 1 );
612 /* XXX: We reserve a little more elements on the stack to deal safely */
613 /* with broken fonts like arialbs, courbs, timesbs, etc. */
614 tmp
= exec
->stackSize
;
615 error
= Update_Max( exec
->memory
,
617 sizeof ( FT_F26Dot6
),
618 (void**)&exec
->stack
,
619 maxp
->maxStackElements
+ 32 );
620 exec
->stackSize
= (FT_UInt
)tmp
;
624 tmp
= exec
->glyphSize
;
625 error
= Update_Max( exec
->memory
,
628 (void**)&exec
->glyphIns
,
629 maxp
->maxSizeOfInstructions
);
630 exec
->glyphSize
= (FT_UShort
)tmp
;
634 exec
->pts
.n_points
= 0;
635 exec
->pts
.n_contours
= 0;
637 exec
->instruction_trap
= FALSE
;
643 /*************************************************************************/
646 /* TT_Save_Context */
649 /* Saves the code ranges in a `size' object. */
652 /* exec :: A handle to the source execution context. */
655 /* size :: A handle to the target size object. */
658 /* FreeType error code. 0 means success. */
661 /* Only the glyph loader and debugger should call this function. */
664 FT_Error
TT_Save_Context( TT_ExecContext exec
,
670 /* XXXX: Will probably disappear soon with all the code range */
671 /* management, which is now rather obsolete. */
673 size
->num_function_defs
= exec
->numFDefs
;
674 size
->num_instruction_defs
= exec
->numIDefs
;
676 size
->max_func
= exec
->maxFunc
;
677 size
->max_ins
= exec
->maxIns
;
679 for ( i
= 0; i
< TT_MAX_CODE_RANGES
; i
++ )
680 size
->codeRangeTable
[i
] = exec
->codeRangeTable
[i
];
686 /*************************************************************************/
692 /* Executes one or more instructions in the execution context. */
695 /* debug :: A Boolean flag. If set, the function sets some internal */
696 /* variables and returns immediately, otherwise TT_RunIns() */
699 /* This is commented out currently. */
702 /* exec :: A handle to the target execution context. */
705 /* TrueTyoe error code. 0 means success. */
708 /* Only the glyph loader and debugger should call this function. */
711 FT_Error
TT_Run_Context( TT_ExecContext exec
,
717 if ( ( error
= TT_Goto_CodeRange( exec
, tt_coderange_glyph
, 0 ) )
721 exec
->zp0
= exec
->pts
;
722 exec
->zp1
= exec
->pts
;
723 exec
->zp2
= exec
->pts
;
729 exec
->GS
.projVector
.x
= 0x4000;
730 exec
->GS
.projVector
.y
= 0x0000;
732 exec
->GS
.freeVector
= exec
->GS
.projVector
;
733 exec
->GS
.dualVector
= exec
->GS
.projVector
;
735 exec
->GS
.round_state
= 1;
738 /* some glyphs leave something on the stack. so we clean it */
739 /* before a new execution. */
746 return exec
->face
->interpreter( exec
);
749 return TT_RunIns( exec
);
756 const TT_GraphicsState tt_default_graphics_state
=
763 TRUE
, 68, 0, 0, 9, 3,
768 /*************************************************************************/
774 /* Queries the face context for a given font. Note that there is */
775 /* now a _single_ execution context in the TrueType driver which is */
776 /* shared among faces. */
779 /* face :: A handle to the source face object. */
782 /* A handle to the execution context. Initialized for `face'. */
785 /* Only the glyph loader and debugger should call this function. */
787 FT_EXPORT_FUNC( TT_ExecContext
) TT_New_Context( TT_Face face
)
797 driver
= (TT_Driver
)face
->root
.driver
;
799 memory
= driver
->root
.root
.memory
;
800 exec
= driver
->context
;
802 if ( !driver
->context
)
807 /* allocate object */
808 if ( ALLOC( exec
, sizeof ( *exec
) ) )
812 error
= Init_Context( exec
, face
, memory
);
816 /* store it into the driver */
817 driver
->context
= exec
;
821 return driver
->context
;
830 /*************************************************************************/
833 /* TT_Done_Context */
836 /* Discards an execution context. */
839 /* exec :: A handle to the target execution context. */
842 /* FreeType error code. 0 means success. */
845 /* Only the glyph loader and debugger should call this function. */
848 FT_Error
TT_Done_Context( TT_ExecContext exec
)
850 /* Nothing at all for now */
857 #ifdef FT_CONFIG_OPTION_OLD_CALCS
859 static FT_F26Dot6
Norm( FT_F26Dot6 X
,
868 ADD_64( T1
, T2
, T1
);
870 return (FT_F26Dot6
)SQRT_64( T1
);
873 #endif /* FT_CONFIG_OPTION_OLD_CALCS */
876 /*************************************************************************/
878 /* Before an opcode is executed, the interpreter verifies that there are */
879 /* enough arguments on the stack, with the help of the Pop_Push_Count */
882 /* For each opcode, the first column gives the number of arguments that */
883 /* are popped from the stack; the second one gives the number of those */
884 /* that are pushed in result. */
886 /* Note that for opcodes with a varying number of parameters, either 0 */
887 /* or 1 arg is verified before execution, depending on the nature of the */
890 /* - if the number of arguments is given by the bytecode stream or the */
891 /* loop variable, 0 is chosen. */
893 /* - if the first argument is a count n that is followed by arguments */
894 /* a1 .. an, then 1 is chosen. */
896 /*************************************************************************/
900 #define PACK( x, y ) ( ( x << 4 ) | y )
904 const FT_Byte Pop_Push_Count
[256] =
906 /* opcodes are gathered in groups of 16 */
907 /* please keep the spaces as they are */
909 /* SVTCA y */ PACK( 0, 0 ),
910 /* SVTCA x */ PACK( 0, 0 ),
911 /* SPvTCA y */ PACK( 0, 0 ),
912 /* SPvTCA x */ PACK( 0, 0 ),
913 /* SFvTCA y */ PACK( 0, 0 ),
914 /* SFvTCA x */ PACK( 0, 0 ),
915 /* SPvTL // */ PACK( 2, 0 ),
916 /* SPvTL + */ PACK( 2, 0 ),
917 /* SFvTL // */ PACK( 2, 0 ),
918 /* SFvTL + */ PACK( 2, 0 ),
919 /* SPvFS */ PACK( 2, 0 ),
920 /* SFvFS */ PACK( 2, 0 ),
921 /* GPV */ PACK( 0, 2 ),
922 /* GFV */ PACK( 0, 2 ),
923 /* SFvTPv */ PACK( 0, 0 ),
924 /* ISECT */ PACK( 5, 0 ),
926 /* SRP0 */ PACK( 1, 0 ),
927 /* SRP1 */ PACK( 1, 0 ),
928 /* SRP2 */ PACK( 1, 0 ),
929 /* SZP0 */ PACK( 1, 0 ),
930 /* SZP1 */ PACK( 1, 0 ),
931 /* SZP2 */ PACK( 1, 0 ),
932 /* SZPS */ PACK( 1, 0 ),
933 /* SLOOP */ PACK( 1, 0 ),
934 /* RTG */ PACK( 0, 0 ),
935 /* RTHG */ PACK( 0, 0 ),
936 /* SMD */ PACK( 1, 0 ),
937 /* ELSE */ PACK( 0, 0 ),
938 /* JMPR */ PACK( 1, 0 ),
939 /* SCvTCi */ PACK( 1, 0 ),
940 /* SSwCi */ PACK( 1, 0 ),
941 /* SSW */ PACK( 1, 0 ),
943 /* DUP */ PACK( 1, 2 ),
944 /* POP */ PACK( 1, 0 ),
945 /* CLEAR */ PACK( 0, 0 ),
946 /* SWAP */ PACK( 2, 2 ),
947 /* DEPTH */ PACK( 0, 1 ),
948 /* CINDEX */ PACK( 1, 1 ),
949 /* MINDEX */ PACK( 1, 0 ),
950 /* AlignPTS */ PACK( 2, 0 ),
951 /* INS_$28 */ PACK( 0, 0 ),
952 /* UTP */ PACK( 1, 0 ),
953 /* LOOPCALL */ PACK( 2, 0 ),
954 /* CALL */ PACK( 1, 0 ),
955 /* FDEF */ PACK( 1, 0 ),
956 /* ENDF */ PACK( 0, 0 ),
957 /* MDAP[0] */ PACK( 1, 0 ),
958 /* MDAP[1] */ PACK( 1, 0 ),
960 /* IUP[0] */ PACK( 0, 0 ),
961 /* IUP[1] */ PACK( 0, 0 ),
962 /* SHP[0] */ PACK( 0, 0 ),
963 /* SHP[1] */ PACK( 0, 0 ),
964 /* SHC[0] */ PACK( 1, 0 ),
965 /* SHC[1] */ PACK( 1, 0 ),
966 /* SHZ[0] */ PACK( 1, 0 ),
967 /* SHZ[1] */ PACK( 1, 0 ),
968 /* SHPIX */ PACK( 1, 0 ),
969 /* IP */ PACK( 0, 0 ),
970 /* MSIRP[0] */ PACK( 2, 0 ),
971 /* MSIRP[1] */ PACK( 2, 0 ),
972 /* AlignRP */ PACK( 0, 0 ),
973 /* RTDG */ PACK( 0, 0 ),
974 /* MIAP[0] */ PACK( 2, 0 ),
975 /* MIAP[1] */ PACK( 2, 0 ),
977 /* NPushB */ PACK( 0, 0 ),
978 /* NPushW */ PACK( 0, 0 ),
979 /* WS */ PACK( 2, 0 ),
980 /* RS */ PACK( 1, 1 ),
981 /* WCvtP */ PACK( 2, 0 ),
982 /* RCvt */ PACK( 1, 1 ),
983 /* GC[0] */ PACK( 1, 1 ),
984 /* GC[1] */ PACK( 1, 1 ),
985 /* SCFS */ PACK( 2, 0 ),
986 /* MD[0] */ PACK( 2, 1 ),
987 /* MD[1] */ PACK( 2, 1 ),
988 /* MPPEM */ PACK( 0, 1 ),
989 /* MPS */ PACK( 0, 1 ),
990 /* FlipON */ PACK( 0, 0 ),
991 /* FlipOFF */ PACK( 0, 0 ),
992 /* DEBUG */ PACK( 1, 0 ),
994 /* LT */ PACK( 2, 1 ),
995 /* LTEQ */ PACK( 2, 1 ),
996 /* GT */ PACK( 2, 1 ),
997 /* GTEQ */ PACK( 2, 1 ),
998 /* EQ */ PACK( 2, 1 ),
999 /* NEQ */ PACK( 2, 1 ),
1000 /* ODD */ PACK( 1, 1 ),
1001 /* EVEN */ PACK( 1, 1 ),
1002 /* IF */ PACK( 1, 0 ),
1003 /* EIF */ PACK( 0, 0 ),
1004 /* AND */ PACK( 2, 1 ),
1005 /* OR */ PACK( 2, 1 ),
1006 /* NOT */ PACK( 1, 1 ),
1007 /* DeltaP1 */ PACK( 1, 0 ),
1008 /* SDB */ PACK( 1, 0 ),
1009 /* SDS */ PACK( 1, 0 ),
1011 /* ADD */ PACK( 2, 1 ),
1012 /* SUB */ PACK( 2, 1 ),
1013 /* DIV */ PACK( 2, 1 ),
1014 /* MUL */ PACK( 2, 1 ),
1015 /* ABS */ PACK( 1, 1 ),
1016 /* NEG */ PACK( 1, 1 ),
1017 /* FLOOR */ PACK( 1, 1 ),
1018 /* CEILING */ PACK( 1, 1 ),
1019 /* ROUND[0] */ PACK( 1, 1 ),
1020 /* ROUND[1] */ PACK( 1, 1 ),
1021 /* ROUND[2] */ PACK( 1, 1 ),
1022 /* ROUND[3] */ PACK( 1, 1 ),
1023 /* NROUND[0] */ PACK( 1, 1 ),
1024 /* NROUND[1] */ PACK( 1, 1 ),
1025 /* NROUND[2] */ PACK( 1, 1 ),
1026 /* NROUND[3] */ PACK( 1, 1 ),
1028 /* WCvtF */ PACK( 2, 0 ),
1029 /* DeltaP2 */ PACK( 1, 0 ),
1030 /* DeltaP3 */ PACK( 1, 0 ),
1031 /* DeltaCn[0] */ PACK( 1, 0 ),
1032 /* DeltaCn[1] */ PACK( 1, 0 ),
1033 /* DeltaCn[2] */ PACK( 1, 0 ),
1034 /* SROUND */ PACK( 1, 0 ),
1035 /* S45Round */ PACK( 1, 0 ),
1036 /* JROT */ PACK( 2, 0 ),
1037 /* JROF */ PACK( 2, 0 ),
1038 /* ROFF */ PACK( 0, 0 ),
1039 /* INS_$7B */ PACK( 0, 0 ),
1040 /* RUTG */ PACK( 0, 0 ),
1041 /* RDTG */ PACK( 0, 0 ),
1042 /* SANGW */ PACK( 1, 0 ),
1043 /* AA */ PACK( 1, 0 ),
1045 /* FlipPT */ PACK( 0, 0 ),
1046 /* FlipRgON */ PACK( 2, 0 ),
1047 /* FlipRgOFF */ PACK( 2, 0 ),
1048 /* INS_$83 */ PACK( 0, 0 ),
1049 /* INS_$84 */ PACK( 0, 0 ),
1050 /* ScanCTRL */ PACK( 1, 0 ),
1051 /* SDVPTL[0] */ PACK( 2, 0 ),
1052 /* SDVPTL[1] */ PACK( 2, 0 ),
1053 /* GetINFO */ PACK( 1, 1 ),
1054 /* IDEF */ PACK( 1, 0 ),
1055 /* ROLL */ PACK( 3, 3 ),
1056 /* MAX */ PACK( 2, 1 ),
1057 /* MIN */ PACK( 2, 1 ),
1058 /* ScanTYPE */ PACK( 1, 0 ),
1059 /* InstCTRL */ PACK( 2, 0 ),
1060 /* INS_$8F */ PACK( 0, 0 ),
1062 /* INS_$90 */ PACK( 0, 0 ),
1063 /* INS_$91 */ PACK( 0, 0 ),
1064 /* INS_$92 */ PACK( 0, 0 ),
1065 /* INS_$93 */ PACK( 0, 0 ),
1066 /* INS_$94 */ PACK( 0, 0 ),
1067 /* INS_$95 */ PACK( 0, 0 ),
1068 /* INS_$96 */ PACK( 0, 0 ),
1069 /* INS_$97 */ PACK( 0, 0 ),
1070 /* INS_$98 */ PACK( 0, 0 ),
1071 /* INS_$99 */ PACK( 0, 0 ),
1072 /* INS_$9A */ PACK( 0, 0 ),
1073 /* INS_$9B */ PACK( 0, 0 ),
1074 /* INS_$9C */ PACK( 0, 0 ),
1075 /* INS_$9D */ PACK( 0, 0 ),
1076 /* INS_$9E */ PACK( 0, 0 ),
1077 /* INS_$9F */ PACK( 0, 0 ),
1079 /* INS_$A0 */ PACK( 0, 0 ),
1080 /* INS_$A1 */ PACK( 0, 0 ),
1081 /* INS_$A2 */ PACK( 0, 0 ),
1082 /* INS_$A3 */ PACK( 0, 0 ),
1083 /* INS_$A4 */ PACK( 0, 0 ),
1084 /* INS_$A5 */ PACK( 0, 0 ),
1085 /* INS_$A6 */ PACK( 0, 0 ),
1086 /* INS_$A7 */ PACK( 0, 0 ),
1087 /* INS_$A8 */ PACK( 0, 0 ),
1088 /* INS_$A9 */ PACK( 0, 0 ),
1089 /* INS_$AA */ PACK( 0, 0 ),
1090 /* INS_$AB */ PACK( 0, 0 ),
1091 /* INS_$AC */ PACK( 0, 0 ),
1092 /* INS_$AD */ PACK( 0, 0 ),
1093 /* INS_$AE */ PACK( 0, 0 ),
1094 /* INS_$AF */ PACK( 0, 0 ),
1096 /* PushB[0] */ PACK( 0, 1 ),
1097 /* PushB[1] */ PACK( 0, 2 ),
1098 /* PushB[2] */ PACK( 0, 3 ),
1099 /* PushB[3] */ PACK( 0, 4 ),
1100 /* PushB[4] */ PACK( 0, 5 ),
1101 /* PushB[5] */ PACK( 0, 6 ),
1102 /* PushB[6] */ PACK( 0, 7 ),
1103 /* PushB[7] */ PACK( 0, 8 ),
1104 /* PushW[0] */ PACK( 0, 1 ),
1105 /* PushW[1] */ PACK( 0, 2 ),
1106 /* PushW[2] */ PACK( 0, 3 ),
1107 /* PushW[3] */ PACK( 0, 4 ),
1108 /* PushW[4] */ PACK( 0, 5 ),
1109 /* PushW[5] */ PACK( 0, 6 ),
1110 /* PushW[6] */ PACK( 0, 7 ),
1111 /* PushW[7] */ PACK( 0, 8 ),
1113 /* MDRP[00] */ PACK( 1, 0 ),
1114 /* MDRP[01] */ PACK( 1, 0 ),
1115 /* MDRP[02] */ PACK( 1, 0 ),
1116 /* MDRP[03] */ PACK( 1, 0 ),
1117 /* MDRP[04] */ PACK( 1, 0 ),
1118 /* MDRP[05] */ PACK( 1, 0 ),
1119 /* MDRP[06] */ PACK( 1, 0 ),
1120 /* MDRP[07] */ PACK( 1, 0 ),
1121 /* MDRP[08] */ PACK( 1, 0 ),
1122 /* MDRP[09] */ PACK( 1, 0 ),
1123 /* MDRP[10] */ PACK( 1, 0 ),
1124 /* MDRP[11] */ PACK( 1, 0 ),
1125 /* MDRP[12] */ PACK( 1, 0 ),
1126 /* MDRP[13] */ PACK( 1, 0 ),
1127 /* MDRP[14] */ PACK( 1, 0 ),
1128 /* MDRP[15] */ PACK( 1, 0 ),
1130 /* MDRP[16] */ PACK( 1, 0 ),
1131 /* MDRP[17] */ PACK( 1, 0 ),
1132 /* MDRP[18] */ PACK( 1, 0 ),
1133 /* MDRP[19] */ PACK( 1, 0 ),
1134 /* MDRP[20] */ PACK( 1, 0 ),
1135 /* MDRP[21] */ PACK( 1, 0 ),
1136 /* MDRP[22] */ PACK( 1, 0 ),
1137 /* MDRP[23] */ PACK( 1, 0 ),
1138 /* MDRP[24] */ PACK( 1, 0 ),
1139 /* MDRP[25] */ PACK( 1, 0 ),
1140 /* MDRP[26] */ PACK( 1, 0 ),
1141 /* MDRP[27] */ PACK( 1, 0 ),
1142 /* MDRP[28] */ PACK( 1, 0 ),
1143 /* MDRP[29] */ PACK( 1, 0 ),
1144 /* MDRP[30] */ PACK( 1, 0 ),
1145 /* MDRP[31] */ PACK( 1, 0 ),
1147 /* MIRP[00] */ PACK( 2, 0 ),
1148 /* MIRP[01] */ PACK( 2, 0 ),
1149 /* MIRP[02] */ PACK( 2, 0 ),
1150 /* MIRP[03] */ PACK( 2, 0 ),
1151 /* MIRP[04] */ PACK( 2, 0 ),
1152 /* MIRP[05] */ PACK( 2, 0 ),
1153 /* MIRP[06] */ PACK( 2, 0 ),
1154 /* MIRP[07] */ PACK( 2, 0 ),
1155 /* MIRP[08] */ PACK( 2, 0 ),
1156 /* MIRP[09] */ PACK( 2, 0 ),
1157 /* MIRP[10] */ PACK( 2, 0 ),
1158 /* MIRP[11] */ PACK( 2, 0 ),
1159 /* MIRP[12] */ PACK( 2, 0 ),
1160 /* MIRP[13] */ PACK( 2, 0 ),
1161 /* MIRP[14] */ PACK( 2, 0 ),
1162 /* MIRP[15] */ PACK( 2, 0 ),
1164 /* MIRP[16] */ PACK( 2, 0 ),
1165 /* MIRP[17] */ PACK( 2, 0 ),
1166 /* MIRP[18] */ PACK( 2, 0 ),
1167 /* MIRP[19] */ PACK( 2, 0 ),
1168 /* MIRP[20] */ PACK( 2, 0 ),
1169 /* MIRP[21] */ PACK( 2, 0 ),
1170 /* MIRP[22] */ PACK( 2, 0 ),
1171 /* MIRP[23] */ PACK( 2, 0 ),
1172 /* MIRP[24] */ PACK( 2, 0 ),
1173 /* MIRP[25] */ PACK( 2, 0 ),
1174 /* MIRP[26] */ PACK( 2, 0 ),
1175 /* MIRP[27] */ PACK( 2, 0 ),
1176 /* MIRP[28] */ PACK( 2, 0 ),
1177 /* MIRP[29] */ PACK( 2, 0 ),
1178 /* MIRP[30] */ PACK( 2, 0 ),
1179 /* MIRP[31] */ PACK( 2, 0 )
1184 const FT_Char opcode_length
[256] =
1186 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1187 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1188 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1189 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1191 -1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1192 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1193 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1194 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1196 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1197 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1198 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1199 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
1201 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1202 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1203 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1204 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1208 const FT_Vector Null_Vector
= {0,0};
1215 #define NULL_Vector (FT_Vector*)&Null_Vector
1218 /*************************************************************************/
1224 /* Returns the current aspect ratio scaling factor depending on the */
1225 /* projection vector's state and device resolutions. */
1228 /* The aspect ratio in 16.16 format, always <= 1.0 . */
1231 FT_Long
Current_Ratio( EXEC_OP
)
1233 if ( CUR
.tt_metrics
.ratio
)
1234 return CUR
.tt_metrics
.ratio
;
1236 if ( CUR
.GS
.projVector
.y
== 0 )
1237 CUR
.tt_metrics
.ratio
= CUR
.tt_metrics
.x_ratio
;
1239 else if ( CUR
.GS
.projVector
.x
== 0 )
1240 CUR
.tt_metrics
.ratio
= CUR
.tt_metrics
.y_ratio
;
1247 #ifdef FT_CONFIG_OPTION_OLD_CALCS
1249 x
= TT_MULDIV( CUR
.GS
.projVector
.x
, CUR
.tt_metrics
.x_ratio
, 0x4000 );
1250 y
= TT_MULDIV( CUR
.GS
.projVector
.y
, CUR
.tt_metrics
.y_ratio
, 0x4000 );
1251 CUR
.tt_metrics
.ratio
= Norm( x
, y
);
1255 x
= TT_MULDIV( CUR
.GS
.projVector
.x
, CUR
.tt_metrics
.x_ratio
, 0x8000 );
1256 y
= TT_MULDIV( CUR
.GS
.projVector
.y
, CUR
.tt_metrics
.y_ratio
, 0x8000 );
1257 CUR
.tt_metrics
.ratio
= FT_Sqrt32( x
* x
+ y
* y
) << 1;
1259 #endif /* FT_CONFIG_OPTION_OLD_CALCS */
1263 return CUR
.tt_metrics
.ratio
;
1268 FT_Long
Current_Ppem( EXEC_OP
)
1270 return TT_MULFIX( CUR
.tt_metrics
.ppem
, CURRENT_Ratio() );
1274 /*************************************************************************/
1276 /* Functions related to the control value table (CVT). */
1278 /*************************************************************************/
1282 FT_F26Dot6
Read_CVT( EXEC_OP_ FT_ULong index
)
1284 return CUR
.cvt
[index
];
1289 FT_F26Dot6
Read_CVT_Stretched( EXEC_OP_ FT_ULong index
)
1291 return TT_MULFIX( CUR
.cvt
[index
], CURRENT_Ratio() );
1296 void Write_CVT( EXEC_OP_ FT_ULong index
,
1299 CUR
.cvt
[index
] = value
;
1304 void Write_CVT_Stretched( EXEC_OP_ FT_ULong index
,
1307 CUR
.cvt
[index
] = FT_DivFix( value
, CURRENT_Ratio() );
1312 void Move_CVT( EXEC_OP_ FT_ULong index
,
1315 CUR
.cvt
[index
] += value
;
1320 void Move_CVT_Stretched( EXEC_OP_ FT_ULong index
,
1323 CUR
.cvt
[index
] += FT_DivFix( value
, CURRENT_Ratio() );
1327 /*************************************************************************/
1333 /* Returns a short integer taken from the instruction stream at */
1337 /* Short read at code[IP]. */
1340 /* This one could become a macro. */
1342 static FT_Short
GetShortIns( EXEC_OP
)
1344 /* Reading a byte stream so there is no endianess (DaveP) */
1346 return (FT_Short
)( ( CUR
.code
[CUR
.IP
- 2] << 8 ) +
1347 CUR
.code
[CUR
.IP
- 1] );
1351 /*************************************************************************/
1354 /* Ins_Goto_CodeRange */
1357 /* Goes to a certain code range in the instruction stream. */
1360 /* aRange :: The index of the code range. */
1362 /* aIP :: The new IP address in the code range. */
1365 /* SUCCESS or FAILURE. */
1368 FT_Bool
Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange
,
1371 TT_CodeRange
* range
;
1374 if ( aRange
< 1 || aRange
> 3 )
1376 CUR
.error
= TT_Err_Bad_Argument
;
1380 range
= &CUR
.codeRangeTable
[aRange
- 1];
1382 if ( range
->base
== NULL
) /* invalid coderange */
1384 CUR
.error
= TT_Err_Invalid_CodeRange
;
1388 /* NOTE: Because the last instruction of a program may be a CALL */
1389 /* which will return to the first byte *after* the code */
1390 /* range, we test for AIP <= Size, instead of AIP < Size. */
1392 if ( aIP
> range
->size
)
1394 CUR
.error
= TT_Err_Code_Overflow
;
1398 CUR
.code
= range
->base
;
1399 CUR
.codeSize
= range
->size
;
1401 CUR
.curRange
= aRange
;
1407 /*************************************************************************/
1413 /* Moves a point by a given distance along the freedom vector. The */
1414 /* point will be `touched'. */
1417 /* point :: The index of the point to move. */
1419 /* distance :: The distance to apply. */
1422 /* zone :: The affected glyph zone. */
1425 void Direct_Move( EXEC_OP_ TT_GlyphZone
* zone
,
1427 FT_F26Dot6 distance
)
1432 v
= CUR
.GS
.freeVector
.x
;
1437 #ifdef NO_APPLE_PATENT
1439 if ( ABS( CUR
.F_dot_P
) > APPLE_THRESHOLD
)
1440 zone
->cur
[point
].x
+= distance
;
1444 zone
->cur
[point
].x
+= TT_MULDIV( distance
,
1450 zone
->tags
[point
] |= FT_Curve_Tag_Touch_X
;
1453 v
= CUR
.GS
.freeVector
.y
;
1458 #ifdef NO_APPLE_PATENT
1460 if ( ABS( CUR
.F_dot_P
) > APPLE_THRESHOLD
)
1461 zone
->cur
[point
].y
+= distance
;
1465 zone
->cur
[point
].y
+= TT_MULDIV( distance
,
1471 zone
->tags
[point
] |= FT_Curve_Tag_Touch_Y
;
1476 /*************************************************************************/
1478 /* Special versions of Direct_Move() */
1480 /* The following versions are used whenever both vectors are both */
1481 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1483 /*************************************************************************/
1487 void Direct_Move_X( EXEC_OP_ TT_GlyphZone
* zone
,
1489 FT_F26Dot6 distance
)
1493 zone
->cur
[point
].x
+= distance
;
1494 zone
->tags
[point
] |= FT_Curve_Tag_Touch_X
;
1499 void Direct_Move_Y( EXEC_OP_ TT_GlyphZone
* zone
,
1501 FT_F26Dot6 distance
)
1505 zone
->cur
[point
].y
+= distance
;
1506 zone
->tags
[point
] |= FT_Curve_Tag_Touch_Y
;
1510 /*************************************************************************/
1516 /* Does not round, but adds engine compensation. */
1519 /* distance :: The distance (not) to round. */
1521 /* compensation :: The engine compensation. */
1524 /* The compensated distance. */
1527 /* The TrueType specification says very few about the relationship */
1528 /* between rounding and engine compensation. However, it seems from */
1529 /* the description of super round that we should add the compensation */
1530 /* before rounding. */
1533 FT_F26Dot6
Round_None( EXEC_OP_ FT_F26Dot6 distance
,
1534 FT_F26Dot6 compensation
)
1541 if ( distance
>= 0 )
1543 val
= distance
+ compensation
;
1548 val
= distance
- compensation
;
1556 /*************************************************************************/
1562 /* Rounds value to grid after adding engine compensation. */
1565 /* distance :: The distance to round. */
1567 /* compensation :: The engine compensation. */
1570 /* Rounded distance. */
1573 FT_F26Dot6
Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1574 FT_F26Dot6 compensation
)
1581 if ( distance
>= 0 )
1583 val
= distance
+ compensation
+ 32;
1591 val
= -( ( compensation
- distance
+ 32 ) & -64 );
1600 /*************************************************************************/
1603 /* Round_To_Half_Grid */
1606 /* Rounds value to half grid after adding engine compensation. */
1609 /* distance :: The distance to round. */
1611 /* compensation :: The engine compensation. */
1614 /* Rounded distance. */
1617 FT_F26Dot6
Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1618 FT_F26Dot6 compensation
)
1625 if ( distance
>= 0 )
1627 val
= ( ( distance
+ compensation
) & -64 ) + 32;
1633 val
= -( ( (compensation
- distance
) & -64 ) + 32 );
1642 /*************************************************************************/
1645 /* Round_Down_To_Grid */
1648 /* Rounds value down to grid after adding engine compensation. */
1651 /* distance :: The distance to round. */
1653 /* compensation :: The engine compensation. */
1656 /* Rounded distance. */
1659 FT_F26Dot6
Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1660 FT_F26Dot6 compensation
)
1667 if ( distance
>= 0 )
1669 val
= distance
+ compensation
;
1677 val
= -( ( compensation
- distance
) & -64 );
1686 /*************************************************************************/
1689 /* Round_Up_To_Grid */
1692 /* Rounds value up to grid after adding engine compensation. */
1695 /* distance :: The distance to round. */
1697 /* compensation :: The engine compensation. */
1700 /* Rounded distance. */
1703 FT_F26Dot6
Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1704 FT_F26Dot6 compensation
)
1711 if ( distance
>= 0 )
1713 val
= distance
+ compensation
+ 63;
1721 val
= -( ( compensation
- distance
+ 63 ) & -64 );
1730 /*************************************************************************/
1733 /* Round_To_Double_Grid */
1736 /* Rounds value to double grid after adding engine compensation. */
1739 /* distance :: The distance to round. */
1741 /* compensation :: The engine compensation. */
1744 /* Rounded distance. */
1747 FT_F26Dot6
Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1748 FT_F26Dot6 compensation
)
1755 if ( distance
>= 0 )
1757 val
= distance
+ compensation
+ 16;
1765 val
= -( ( compensation
- distance
+ 16 ) & -32 );
1774 /*************************************************************************/
1780 /* Super-rounds value to grid after adding engine compensation. */
1783 /* distance :: The distance to round. */
1785 /* compensation :: The engine compensation. */
1788 /* Rounded distance. */
1791 /* The TrueType specification says very few about the relationship */
1792 /* between rounding and engine compensation. However, it seems from */
1793 /* the description of super round that we should add the compensation */
1794 /* before rounding. */
1797 FT_F26Dot6
Round_Super( EXEC_OP_ FT_F26Dot6 distance
,
1798 FT_F26Dot6 compensation
)
1803 if ( distance
>= 0 )
1805 val
= ( distance
- CUR
.phase
+ CUR
.threshold
+ compensation
) &
1813 val
= -( ( CUR
.threshold
- CUR
.phase
- distance
+ compensation
) &
1824 /*************************************************************************/
1827 /* Round_Super_45 */
1830 /* Super-rounds value to grid after adding engine compensation. */
1833 /* distance :: The distance to round. */
1835 /* compensation :: The engine compensation. */
1838 /* Rounded distance. */
1841 /* There is a separate function for Round_Super_45() as we may need */
1842 /* greater precision. */
1845 FT_F26Dot6
Round_Super_45( EXEC_OP_ FT_F26Dot6 distance
,
1846 FT_F26Dot6 compensation
)
1851 if ( distance
>= 0 )
1853 val
= ( ( distance
- CUR
.phase
+ CUR
.threshold
+ compensation
) /
1854 CUR
.period
) * CUR
.period
;
1861 val
= -( ( ( CUR
.threshold
- CUR
.phase
- distance
+ compensation
) /
1862 CUR
.period
) * CUR
.period
);
1872 /*************************************************************************/
1878 /* Sets the rounding mode. */
1881 /* round_mode :: The rounding mode to be used. */
1884 void Compute_Round( EXEC_OP_ FT_Byte round_mode
)
1886 switch ( round_mode
)
1889 CUR
.func_round
= (TT_Round_Func
)Round_None
;
1892 case TT_Round_To_Grid
:
1893 CUR
.func_round
= (TT_Round_Func
)Round_To_Grid
;
1896 case TT_Round_Up_To_Grid
:
1897 CUR
.func_round
= (TT_Round_Func
)Round_Up_To_Grid
;
1900 case TT_Round_Down_To_Grid
:
1901 CUR
.func_round
= (TT_Round_Func
)Round_Down_To_Grid
;
1904 case TT_Round_To_Half_Grid
:
1905 CUR
.func_round
= (TT_Round_Func
)Round_To_Half_Grid
;
1908 case TT_Round_To_Double_Grid
:
1909 CUR
.func_round
= (TT_Round_Func
)Round_To_Double_Grid
;
1912 case TT_Round_Super
:
1913 CUR
.func_round
= (TT_Round_Func
)Round_Super
;
1916 case TT_Round_Super_45
:
1917 CUR
.func_round
= (TT_Round_Func
)Round_Super_45
;
1923 /*************************************************************************/
1929 /* Sets Super Round parameters. */
1932 /* GridPeriod :: Grid period */
1933 /* selector :: SROUND opcode */
1936 void SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod
,
1939 switch ( (FT_Int
)( selector
& 0xC0 ) )
1942 CUR
.period
= GridPeriod
/ 2;
1946 CUR
.period
= GridPeriod
;
1950 CUR
.period
= GridPeriod
* 2;
1953 /* This opcode is reserved, but... */
1956 CUR
.period
= GridPeriod
;
1960 switch ( (FT_Int
)( selector
& 0x30 ) )
1967 CUR
.phase
= CUR
.period
/ 4;
1971 CUR
.phase
= CUR
.period
/ 2;
1975 CUR
.phase
= GridPeriod
* 3 / 4;
1979 if ( (selector
& 0x0F) == 0 )
1980 CUR
.threshold
= CUR
.period
- 1;
1982 CUR
.threshold
= ( (FT_Int
)( selector
& 0x0F ) - 4 ) * CUR
.period
/ 8;
1986 CUR
.threshold
/= 256;
1990 /*************************************************************************/
1996 /* Computes the projection of vector given by (v2-v1) along the */
1997 /* current projection vector. */
2000 /* v1 :: First input vector. */
2001 /* v2 :: Second input vector. */
2004 /* The distance in F26dot6 format. */
2007 FT_F26Dot6
Project( EXEC_OP_ FT_Vector
* v1
,
2010 return TT_MULDIV( v1
->x
- v2
->x
, CUR
.GS
.projVector
.x
, 0x4000 ) +
2011 TT_MULDIV( v1
->y
- v2
->y
, CUR
.GS
.projVector
.y
, 0x4000 );
2015 /*************************************************************************/
2021 /* Computes the projection of the vector given by (v2-v1) along the */
2022 /* current dual vector. */
2025 /* v1 :: First input vector. */
2026 /* v2 :: Second input vector. */
2029 /* The distance in F26dot6 format. */
2032 FT_F26Dot6
Dual_Project( EXEC_OP_ FT_Vector
* v1
,
2035 return TT_MULDIV( v1
->x
- v2
->x
, CUR
.GS
.dualVector
.x
, 0x4000 ) +
2036 TT_MULDIV( v1
->y
- v2
->y
, CUR
.GS
.dualVector
.y
, 0x4000 );
2040 /*************************************************************************/
2046 /* Computes the projection of the vector given by (v2-v1) along the */
2047 /* current freedom vector. */
2050 /* v1 :: First input vector. */
2051 /* v2 :: Second input vector. */
2054 /* The distance in F26dot6 format. */
2057 FT_F26Dot6
Free_Project( EXEC_OP_ FT_Vector
* v1
,
2060 return TT_MULDIV( v1
->x
- v2
->x
, CUR
.GS
.freeVector
.x
, 0x4000 ) +
2061 TT_MULDIV( v1
->y
- v2
->y
, CUR
.GS
.freeVector
.y
, 0x4000 );
2065 /*************************************************************************/
2071 /* Computes the projection of the vector given by (v2-v1) along the */
2072 /* horizontal axis. */
2075 /* v1 :: First input vector. */
2076 /* v2 :: Second input vector. */
2079 /* The distance in F26dot6 format. */
2082 FT_F26Dot6
Project_x( EXEC_OP_ FT_Vector
* v1
,
2087 return ( v1
->x
- v2
->x
);
2091 /*************************************************************************/
2097 /* Computes the projection of the vector given by (v2-v1) along the */
2098 /* vertical axis. */
2101 /* v1 :: First input vector. */
2102 /* v2 :: Second input vector. */
2105 /* The distance in F26dot6 format. */
2108 FT_F26Dot6
Project_y( EXEC_OP_ FT_Vector
* v1
,
2113 return ( v1
->y
- v2
->y
);
2117 /*************************************************************************/
2123 /* Computes the projection and movement function pointers according */
2124 /* to the current graphics state. */
2127 void Compute_Funcs( EXEC_OP
)
2129 if ( CUR
.GS
.freeVector
.x
== 0x4000 )
2131 CUR
.func_freeProj
= (TT_Project_Func
)Project_x
;
2132 CUR
.F_dot_P
= CUR
.GS
.projVector
.x
* 0x10000L
;
2136 if ( CUR
.GS
.freeVector
.y
== 0x4000 )
2138 CUR
.func_freeProj
= (TT_Project_Func
)Project_y
;
2139 CUR
.F_dot_P
= CUR
.GS
.projVector
.y
* 0x10000L
;
2143 CUR
.func_freeProj
= (TT_Project_Func
)Free_Project
;
2144 CUR
.F_dot_P
= (FT_Long
)CUR
.GS
.projVector
.x
* CUR
.GS
.freeVector
.x
* 4 +
2145 (FT_Long
)CUR
.GS
.projVector
.y
* CUR
.GS
.freeVector
.y
* 4;
2149 if ( CUR
.GS
.projVector
.x
== 0x4000 )
2150 CUR
.func_project
= (TT_Project_Func
)Project_x
;
2153 if ( CUR
.GS
.projVector
.y
== 0x4000 )
2154 CUR
.func_project
= (TT_Project_Func
)Project_y
;
2156 CUR
.func_project
= (TT_Project_Func
)Project
;
2159 if ( CUR
.GS
.dualVector
.x
== 0x4000 )
2160 CUR
.func_dualproj
= (TT_Project_Func
)Project_x
;
2163 if ( CUR
.GS
.dualVector
.y
== 0x4000 )
2164 CUR
.func_dualproj
= (TT_Project_Func
)Project_y
;
2166 CUR
.func_dualproj
= (TT_Project_Func
)Dual_Project
;
2169 CUR
.func_move
= (TT_Move_Func
)Direct_Move
;
2171 if ( CUR
.F_dot_P
== 0x40000000L
)
2173 if ( CUR
.GS
.freeVector
.x
== 0x4000 )
2174 CUR
.func_move
= (TT_Move_Func
)Direct_Move_X
;
2177 if ( CUR
.GS
.freeVector
.y
== 0x4000 )
2178 CUR
.func_move
= (TT_Move_Func
)Direct_Move_Y
;
2182 /* at small sizes, F_dot_P can become too small, resulting */
2183 /* in overflows and `spikes' in a number of glyphs like `w'. */
2185 if ( ABS( CUR
.F_dot_P
) < 0x4000000L
)
2186 CUR
.F_dot_P
= 0x40000000L
;
2188 /* Disable cached aspect ratio */
2189 CUR
.tt_metrics
.ratio
= 0;
2193 /*************************************************************************/
2199 /* Norms a vector. */
2202 /* Vx :: The horizontal input vector coordinate. */
2203 /* Vy :: The vertical input vector coordinate. */
2206 /* R :: The normed unit vector. */
2209 /* Returns FAILURE if a vector parameter is zero. */
2212 /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
2213 /* R is undefined. */
2216 #ifdef FT_CONFIG_OPTION_OLD_CALCS
2219 FT_Bool
Normalize( EXEC_OP_ FT_F26Dot6 Vx
,
2229 if ( ABS( Vx
) < 0x10000L
&& ABS( Vy
) < 0x10000L
)
2238 /* XXX: UNDOCUMENTED! It seems that it is possible to try */
2239 /* to normalize the vector (0,0). Return immediately. */
2243 R
->x
= (FT_F2Dot14
)FT_MulDiv( Vx
, 0x4000L
, W
);
2244 R
->y
= (FT_F2Dot14
)FT_MulDiv( Vy
, 0x4000L
, W
);
2251 Vx
= FT_MulDiv( Vx
, 0x4000L
, W
);
2252 Vy
= FT_MulDiv( Vy
, 0x4000L
, W
);
2254 W
= Vx
* Vx
+ Vy
* Vy
;
2256 /* Now, we want that Sqrt( W ) = 0x4000 */
2257 /* Or 0x1000000 <= W < 0x1004000 */
2275 while ( W
< 0x1000000L
)
2277 /* We need to increase W by a minimal amount */
2283 W
= Vx
* Vx
+ Vy
* Vy
;
2286 while ( W
>= 0x1004000L
)
2288 /* We need to decrease W by a minimal amount */
2294 W
= Vx
* Vx
+ Vy
* Vy
;
2297 /* Note that in various cases, we can only */
2298 /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
2306 R
->x
= (FT_F2Dot14
)Vx
; /* Type conversion */
2307 R
->y
= (FT_F2Dot14
)Vy
; /* Type conversion */
2315 FT_Bool
Normalize( EXEC_OP_ FT_F26Dot6 Vx
,
2321 FT_ULong H
, L
, L2
, hi
, lo
, med
;
2337 /* check that we are not trying to normalise zero! */
2341 /* compute (u*u + v*v) on 64 bits with two 32-bit registers [H:L] */
2342 hi
= (FT_ULong
)u
>> 16;
2343 lo
= (FT_ULong
)u
& 0xFFFF;
2346 H
= hi
* hi
+ ( med
>> 15 );
2352 hi
= (FT_ULong
)v
>> 16;
2353 lo
= (FT_ULong
)v
& 0xFFFF;
2356 H
+= hi
* hi
+ ( med
>> 15 );
2366 /* if the value is smaller than 32-bits */
2370 while ( ( L
& 0xC0000000L
) == 0 )
2377 R
->x
= (FT_F2Dot14
)TT_MULDIV( Vx
<< shift
, 0x4000, d
);
2378 R
->y
= (FT_F2Dot14
)TT_MULDIV( Vy
<< shift
, 0x4000, d
);
2380 /* if the value is greater than 64-bits */
2386 L
= ( L
>> 2 ) | ( H
<< 30 );
2392 R
->x
= (FT_F2Dot14
)TT_MULDIV( Vx
>> shift
, 0x4000, d
);
2393 R
->y
= (FT_F2Dot14
)TT_MULDIV( Vy
>> shift
, 0x4000, d
);
2401 sx
= R
->x
>= 0 ? 1 : -1;
2402 sy
= R
->y
>= 0 ? 1 : -1;
2403 x
= (FT_ULong
)sx
* R
->x
;
2404 y
= (FT_ULong
)sy
* R
->y
;
2408 /* we now want to adjust (x,y) in order to have sqrt(w) == 0x4000 */
2409 /* which means 0x1000000 <= w < 0x1004000 */
2410 while ( w
<= 0x10000000L
)
2412 /* increment the smallest coordinate */
2421 while ( w
>= 0x10040000L
)
2423 /* decrement the smallest coordinate */
2439 #endif /* FT_CONFIG_OPTION_OLD_CALCS */
2442 /*************************************************************************/
2444 /* Here we start with the implementation of the various opcodes. */
2446 /*************************************************************************/
2450 FT_Bool
Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1
,
2453 FT_UnitVector
* Vec
)
2460 if ( BOUNDS( aIdx1
, CUR
.zp2
.n_points
) ||
2461 BOUNDS( aIdx2
, CUR
.zp1
.n_points
) )
2463 if ( CUR
.pedantic_hinting
)
2464 CUR
.error
= TT_Err_Invalid_Reference
;
2468 p1
= CUR
.zp1
.cur
+ aIdx2
;
2469 p2
= CUR
.zp2
.cur
+ aIdx1
;
2474 if ( ( aOpc
& 1 ) != 0 )
2476 C
= B
; /* counter clockwise rotation */
2481 NORMalize( A
, B
, Vec
);
2487 /* When not using the big switch statements, the interpreter uses a */
2488 /* call table defined later below in this source. Each opcode must */
2489 /* thus have a corresponding function, even trivial ones. */
2491 /* They are all defined there. */
2498 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2499 B = A ^ (FT_Short)0x4000; \
2501 CUR.GS.freeVector.x = A; \
2502 CUR.GS.projVector.x = A; \
2503 CUR.GS.dualVector.x = A; \
2505 CUR.GS.freeVector.y = B; \
2506 CUR.GS.projVector.y = B; \
2507 CUR.GS.dualVector.y = B; \
2518 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2519 B = A ^ (FT_Short)0x4000; \
2521 CUR.GS.projVector.x = A; \
2522 CUR.GS.dualVector.x = A; \
2524 CUR.GS.projVector.y = B; \
2525 CUR.GS.dualVector.y = B; \
2536 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2537 B = A ^ (FT_Short)0x4000; \
2539 CUR.GS.freeVector.x = A; \
2540 CUR.GS.freeVector.y = B; \
2547 if ( INS_SxVTL( (FT_UShort)args[1], \
2548 (FT_UShort)args[0], \
2550 &CUR.GS.projVector ) == SUCCESS ) \
2552 CUR.GS.dualVector = CUR.GS.projVector; \
2558 if ( INS_SxVTL( (FT_UShort)args[1], \
2559 (FT_UShort)args[0], \
2561 &CUR.GS.freeVector ) == SUCCESS ) \
2566 CUR.GS.freeVector = CUR.GS.projVector; \
2576 /* Only use low 16bits, then sign extend */ \
2577 S = (FT_Short)args[1]; \
2579 S = (FT_Short)args[0]; \
2582 NORMalize( X, Y, &CUR.GS.projVector ); \
2584 CUR.GS.dualVector = CUR.GS.projVector; \
2595 /* Only use low 16bits, then sign extend */ \
2596 S = (FT_Short)args[1]; \
2598 S = (FT_Short)args[0]; \
2601 NORMalize( X, Y, &CUR.GS.freeVector ); \
2607 args[0] = CUR.GS.projVector.x; \
2608 args[1] = CUR.GS.projVector.y;
2612 args[0] = CUR.GS.freeVector.x; \
2613 args[1] = CUR.GS.freeVector.y;
2617 CUR.GS.rp0 = (FT_UShort)args[0];
2621 CUR.GS.rp1 = (FT_UShort)args[0];
2625 CUR.GS.rp2 = (FT_UShort)args[0];
2629 CUR.GS.round_state = TT_Round_To_Half_Grid; \
2630 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2634 CUR.GS.round_state = TT_Round_To_Grid; \
2635 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2639 CUR.GS.round_state = TT_Round_To_Double_Grid; \
2640 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2644 CUR.GS.round_state = TT_Round_Up_To_Grid; \
2645 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2649 CUR.GS.round_state = TT_Round_Down_To_Grid; \
2650 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2654 CUR.GS.round_state = TT_Round_Off; \
2655 CUR.func_round = (TT_Round_Func)Round_None;
2659 SET_SuperRound( 0x4000, args[0] ); \
2660 CUR.GS.round_state = TT_Round_Super; \
2661 CUR.func_round = (TT_Round_Func)Round_Super;
2664 #define DO_S45ROUND \
2665 SET_SuperRound( 0x2D41, args[0] ); \
2666 CUR.GS.round_state = TT_Round_Super_45; \
2667 CUR.func_round = (TT_Round_Func)Round_Super_45;
2671 if ( args[0] < 0 ) \
2672 CUR.error = TT_Err_Bad_Argument; \
2674 CUR.GS.loop = args[0];
2678 CUR.GS.minimum_distance = args[0];
2682 CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
2686 CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
2689 /* XXX: UNDOCUMENTED! or bug in the Windows engine? */
2691 /* It seems that the value that is read here is */
2692 /* expressed in 16.16 format rather than in font */
2696 CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
2700 CUR.GS.auto_flip = TRUE;
2703 #define DO_FLIPOFF \
2704 CUR.GS.auto_flip = FALSE;
2708 CUR.GS.delta_base = (FT_Short)args[0];
2712 CUR.GS.delta_shift = (FT_Short)args[0];
2715 #define DO_MD /* nothing */
2719 args[0] = CURRENT_Ppem();
2722 /* Note: The pointSize should be irrelevant in a given font program; */
2723 /* we thus decide to return only the ppem. */
2727 args[0] = CUR.metrics.pointSize;
2732 args[0] = CURRENT_Ppem();
2751 args[0] = args[1]; \
2767 if ( L <= 0 || L > CUR.args ) \
2768 CUR.error = TT_Err_Invalid_Reference; \
2770 args[0] = CUR.stack[CUR.args - L]; \
2775 if ( args[1] != 0 ) \
2777 CUR.IP += args[0]; \
2778 CUR.step_ins = FALSE; \
2783 CUR.IP += args[0]; \
2784 CUR.step_ins = FALSE;
2788 if ( args[1] == 0 ) \
2790 CUR.IP += args[0]; \
2791 CUR.step_ins = FALSE; \
2796 args[0] = ( args[0] < args[1] );
2800 args[0] = ( args[0] <= args[1] );
2804 args[0] = ( args[0] > args[1] );
2808 args[0] = ( args[0] >= args[1] );
2812 args[0] = ( args[0] == args[1] );
2816 args[0] = ( args[0] != args[1] );
2820 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
2824 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
2828 args[0] = ( args[0] && args[1] );
2832 args[0] = ( args[0] || args[1] );
2848 if ( args[1] == 0 ) \
2849 CUR.error = TT_Err_Divide_By_Zero; \
2851 args[0] = TT_MULDIV( args[0], 64L, args[1] );
2855 args[0] = TT_MULDIV( args[0], args[1], 64L );
2859 args[0] = ABS( args[0] );
2870 #define DO_CEILING \
2871 args[0] = ( args[0] + 63 ) & -64;
2876 FT_ULong I = (FT_ULong)args[0]; \
2879 if ( BOUNDS( I, CUR.storeSize ) ) \
2881 if ( CUR.pedantic_hinting ) \
2883 ARRAY_BOUND_ERROR; \
2889 args[0] = CUR.storage[I]; \
2895 FT_ULong I = (FT_ULong)args[0]; \
2898 if ( BOUNDS( I, CUR.storeSize ) ) \
2900 if ( CUR.pedantic_hinting ) \
2902 ARRAY_BOUND_ERROR; \
2906 CUR.storage[I] = args[1]; \
2912 FT_ULong I = (FT_ULong)args[0]; \
2915 if ( BOUNDS( I, CUR.cvtSize ) ) \
2917 if ( CUR.pedantic_hinting ) \
2919 ARRAY_BOUND_ERROR; \
2925 args[0] = CUR_Func_read_cvt( I ); \
2931 FT_ULong I = (FT_ULong)args[0]; \
2934 if ( BOUNDS( I, CUR.cvtSize ) ) \
2936 if ( CUR.pedantic_hinting ) \
2938 ARRAY_BOUND_ERROR; \
2942 CUR_Func_write_cvt( I, args[1] ); \
2948 FT_ULong I = (FT_ULong)args[0]; \
2951 if ( BOUNDS( I, CUR.cvtSize ) ) \
2953 if ( CUR.pedantic_hinting ) \
2955 ARRAY_BOUND_ERROR; \
2959 CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
2964 CUR.error = TT_Err_Debug_OpCode;
2968 args[0] = CUR_Func_round( \
2970 CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
2974 args[0] = ROUND_None( args[0], \
2975 CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
2979 if ( args[1] > args[0] ) \
2984 if ( args[1] < args[0] ) \
2988 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
2991 #undef ARRAY_BOUND_ERROR
2992 #define ARRAY_BOUND_ERROR \
2994 CUR.error = TT_Err_Invalid_Reference; \
2999 /*************************************************************************/
3001 /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
3002 /* Opcode range: 0x00-0x01 */
3006 void Ins_SVTCA( INS_ARG
)
3012 /*************************************************************************/
3014 /* SPVTCA[a]: Set PVector to Coordinate Axis */
3015 /* Opcode range: 0x02-0x03 */
3019 void Ins_SPVTCA( INS_ARG
)
3025 /*************************************************************************/
3027 /* SFVTCA[a]: Set FVector to Coordinate Axis */
3028 /* Opcode range: 0x04-0x05 */
3032 void Ins_SFVTCA( INS_ARG
)
3038 /*************************************************************************/
3040 /* SPVTL[a]: Set PVector To Line */
3041 /* Opcode range: 0x06-0x07 */
3042 /* Stack: uint32 uint32 --> */
3045 void Ins_SPVTL( INS_ARG
)
3051 /*************************************************************************/
3053 /* SFVTL[a]: Set FVector To Line */
3054 /* Opcode range: 0x08-0x09 */
3055 /* Stack: uint32 uint32 --> */
3058 void Ins_SFVTL( INS_ARG
)
3064 /*************************************************************************/
3066 /* SFVTPV[]: Set FVector To PVector */
3067 /* Opcode range: 0x0E */
3071 void Ins_SFVTPV( INS_ARG
)
3077 /*************************************************************************/
3079 /* SPVFS[]: Set PVector From Stack */
3080 /* Opcode range: 0x0A */
3081 /* Stack: f2.14 f2.14 --> */
3084 void Ins_SPVFS( INS_ARG
)
3090 /*************************************************************************/
3092 /* SFVFS[]: Set FVector From Stack */
3093 /* Opcode range: 0x0B */
3094 /* Stack: f2.14 f2.14 --> */
3097 void Ins_SFVFS( INS_ARG
)
3103 /*************************************************************************/
3105 /* GPV[]: Get Projection Vector */
3106 /* Opcode range: 0x0C */
3107 /* Stack: ef2.14 --> ef2.14 */
3110 void Ins_GPV( INS_ARG
)
3116 /*************************************************************************/
3117 /* GFV[]: Get Freedom Vector */
3118 /* Opcode range: 0x0D */
3119 /* Stack: ef2.14 --> ef2.14 */
3122 void Ins_GFV( INS_ARG
)
3128 /*************************************************************************/
3130 /* SRP0[]: Set Reference Point 0 */
3131 /* Opcode range: 0x10 */
3132 /* Stack: uint32 --> */
3135 void Ins_SRP0( INS_ARG
)
3141 /*************************************************************************/
3143 /* SRP1[]: Set Reference Point 1 */
3144 /* Opcode range: 0x11 */
3145 /* Stack: uint32 --> */
3148 void Ins_SRP1( INS_ARG
)
3154 /*************************************************************************/
3156 /* SRP2[]: Set Reference Point 2 */
3157 /* Opcode range: 0x12 */
3158 /* Stack: uint32 --> */
3161 void Ins_SRP2( INS_ARG
)
3167 /*************************************************************************/
3169 /* RTHG[]: Round To Half Grid */
3170 /* Opcode range: 0x19 */
3174 void Ins_RTHG( INS_ARG
)
3180 /*************************************************************************/
3182 /* RTG[]: Round To Grid */
3183 /* Opcode range: 0x18 */
3187 void Ins_RTG( INS_ARG
)
3193 /*************************************************************************/
3194 /* RTDG[]: Round To Double Grid */
3195 /* Opcode range: 0x3D */
3199 void Ins_RTDG( INS_ARG
)
3205 /*************************************************************************/
3206 /* RUTG[]: Round Up To Grid */
3207 /* Opcode range: 0x7C */
3211 void Ins_RUTG( INS_ARG
)
3217 /*************************************************************************/
3219 /* RDTG[]: Round Down To Grid */
3220 /* Opcode range: 0x7D */
3224 void Ins_RDTG( INS_ARG
)
3230 /*************************************************************************/
3232 /* ROFF[]: Round OFF */
3233 /* Opcode range: 0x7A */
3237 void Ins_ROFF( INS_ARG
)
3243 /*************************************************************************/
3245 /* SROUND[]: Super ROUND */
3246 /* Opcode range: 0x76 */
3247 /* Stack: Eint8 --> */
3250 void Ins_SROUND( INS_ARG
)
3256 /*************************************************************************/
3258 /* S45ROUND[]: Super ROUND 45 degrees */
3259 /* Opcode range: 0x77 */
3260 /* Stack: uint32 --> */
3263 void Ins_S45ROUND( INS_ARG
)
3269 /*************************************************************************/
3271 /* SLOOP[]: Set LOOP variable */
3272 /* Opcode range: 0x17 */
3273 /* Stack: int32? --> */
3276 void Ins_SLOOP( INS_ARG
)
3282 /*************************************************************************/
3284 /* SMD[]: Set Minimum Distance */
3285 /* Opcode range: 0x1A */
3286 /* Stack: f26.6 --> */
3289 void Ins_SMD( INS_ARG
)
3295 /*************************************************************************/
3297 /* SCVTCI[]: Set Control Value Table Cut In */
3298 /* Opcode range: 0x1D */
3299 /* Stack: f26.6 --> */
3302 void Ins_SCVTCI( INS_ARG
)
3308 /*************************************************************************/
3310 /* SSWCI[]: Set Single Width Cut In */
3311 /* Opcode range: 0x1E */
3312 /* Stack: f26.6 --> */
3315 void Ins_SSWCI( INS_ARG
)
3321 /*************************************************************************/
3323 /* SSW[]: Set Single Width */
3324 /* Opcode range: 0x1F */
3325 /* Stack: int32? --> */
3328 void Ins_SSW( INS_ARG
)
3334 /*************************************************************************/
3336 /* FLIPON[]: Set auto-FLIP to ON */
3337 /* Opcode range: 0x4D */
3341 void Ins_FLIPON( INS_ARG
)
3347 /*************************************************************************/
3349 /* FLIPOFF[]: Set auto-FLIP to OFF */
3350 /* Opcode range: 0x4E */
3354 void Ins_FLIPOFF( INS_ARG
)
3360 /*************************************************************************/
3362 /* SANGW[]: Set ANGle Weight */
3363 /* Opcode range: 0x7E */
3364 /* Stack: uint32 --> */
3367 void Ins_SANGW( INS_ARG
)
3369 /* instruction not supported anymore */
3373 /*************************************************************************/
3375 /* SDB[]: Set Delta Base */
3376 /* Opcode range: 0x5E */
3377 /* Stack: uint32 --> */
3380 void Ins_SDB( INS_ARG
)
3386 /*************************************************************************/
3388 /* SDS[]: Set Delta Shift */
3389 /* Opcode range: 0x5F */
3390 /* Stack: uint32 --> */
3393 void Ins_SDS( INS_ARG
)
3399 /*************************************************************************/
3401 /* MPPEM[]: Measure Pixel Per EM */
3402 /* Opcode range: 0x4B */
3403 /* Stack: --> Euint16 */
3406 void Ins_MPPEM( INS_ARG
)
3412 /*************************************************************************/
3414 /* MPS[]: Measure Point Size */
3415 /* Opcode range: 0x4C */
3416 /* Stack: --> Euint16 */
3419 void Ins_MPS( INS_ARG
)
3425 /*************************************************************************/
3427 /* DUP[]: DUPlicate the top stack's element */
3428 /* Opcode range: 0x20 */
3429 /* Stack: StkElt --> StkElt StkElt */
3432 void Ins_DUP( INS_ARG
)
3438 /*************************************************************************/
3440 /* POP[]: POP the stack's top element */
3441 /* Opcode range: 0x21 */
3442 /* Stack: StkElt --> */
3445 void Ins_POP( INS_ARG
)
3451 /*************************************************************************/
3453 /* CLEAR[]: CLEAR the entire stack */
3454 /* Opcode range: 0x22 */
3455 /* Stack: StkElt... --> */
3458 void Ins_CLEAR( INS_ARG
)
3464 /*************************************************************************/
3466 /* SWAP[]: SWAP the stack's top two elements */
3467 /* Opcode range: 0x23 */
3468 /* Stack: 2 * StkElt --> 2 * StkElt */
3471 void Ins_SWAP( INS_ARG
)
3477 /*************************************************************************/
3479 /* DEPTH[]: return the stack DEPTH */
3480 /* Opcode range: 0x24 */
3481 /* Stack: --> uint32 */
3484 void Ins_DEPTH( INS_ARG
)
3490 /*************************************************************************/
3492 /* CINDEX[]: Copy INDEXed element */
3493 /* Opcode range: 0x25 */
3494 /* Stack: int32 --> StkElt */
3497 void Ins_CINDEX( INS_ARG
)
3503 /*************************************************************************/
3506 /* Opcode range: 0x59 */
3510 void Ins_EIF( INS_ARG
)
3516 /*************************************************************************/
3518 /* JROT[]: Jump Relative On True */
3519 /* Opcode range: 0x78 */
3520 /* Stack: StkElt int32 --> */
3523 void Ins_JROT( INS_ARG
)
3529 /*************************************************************************/
3531 /* JMPR[]: JuMP Relative */
3532 /* Opcode range: 0x1C */
3533 /* Stack: int32 --> */
3536 void Ins_JMPR( INS_ARG
)
3542 /*************************************************************************/
3544 /* JROF[]: Jump Relative On False */
3545 /* Opcode range: 0x79 */
3546 /* Stack: StkElt int32 --> */
3549 void Ins_JROF( INS_ARG
)
3555 /*************************************************************************/
3557 /* LT[]: Less Than */
3558 /* Opcode range: 0x50 */
3559 /* Stack: int32? int32? --> bool */
3562 void Ins_LT( INS_ARG
)
3568 /*************************************************************************/
3570 /* LTEQ[]: Less Than or EQual */
3571 /* Opcode range: 0x51 */
3572 /* Stack: int32? int32? --> bool */
3575 void Ins_LTEQ( INS_ARG
)
3581 /*************************************************************************/
3583 /* GT[]: Greater Than */
3584 /* Opcode range: 0x52 */
3585 /* Stack: int32? int32? --> bool */
3588 void Ins_GT( INS_ARG
)
3594 /*************************************************************************/
3596 /* GTEQ[]: Greater Than or EQual */
3597 /* Opcode range: 0x53 */
3598 /* Stack: int32? int32? --> bool */
3601 void Ins_GTEQ( INS_ARG
)
3607 /*************************************************************************/
3610 /* Opcode range: 0x54 */
3611 /* Stack: StkElt StkElt --> bool */
3614 void Ins_EQ( INS_ARG
)
3620 /*************************************************************************/
3622 /* NEQ[]: Not EQual */
3623 /* Opcode range: 0x55 */
3624 /* Stack: StkElt StkElt --> bool */
3627 void Ins_NEQ( INS_ARG
)
3633 /*************************************************************************/
3636 /* Opcode range: 0x56 */
3637 /* Stack: f26.6 --> bool */
3640 void Ins_ODD( INS_ARG
)
3646 /*************************************************************************/
3648 /* EVEN[]: Is EVEN */
3649 /* Opcode range: 0x57 */
3650 /* Stack: f26.6 --> bool */
3653 void Ins_EVEN( INS_ARG
)
3659 /*************************************************************************/
3661 /* AND[]: logical AND */
3662 /* Opcode range: 0x5A */
3663 /* Stack: uint32 uint32 --> uint32 */
3666 void Ins_AND( INS_ARG
)
3672 /*************************************************************************/
3674 /* OR[]: logical OR */
3675 /* Opcode range: 0x5B */
3676 /* Stack: uint32 uint32 --> uint32 */
3679 void Ins_OR( INS_ARG
)
3685 /*************************************************************************/
3687 /* NOT[]: logical NOT */
3688 /* Opcode range: 0x5C */
3689 /* Stack: StkElt --> uint32 */
3692 void Ins_NOT( INS_ARG
)
3698 /*************************************************************************/
3701 /* Opcode range: 0x60 */
3702 /* Stack: f26.6 f26.6 --> f26.6 */
3705 void Ins_ADD( INS_ARG
)
3711 /*************************************************************************/
3713 /* SUB[]: SUBtract */
3714 /* Opcode range: 0x61 */
3715 /* Stack: f26.6 f26.6 --> f26.6 */
3718 void Ins_SUB( INS_ARG
)
3724 /*************************************************************************/
3727 /* Opcode range: 0x62 */
3728 /* Stack: f26.6 f26.6 --> f26.6 */
3731 void Ins_DIV( INS_ARG
)
3737 /*************************************************************************/
3739 /* MUL[]: MULtiply */
3740 /* Opcode range: 0x63 */
3741 /* Stack: f26.6 f26.6 --> f26.6 */
3744 void Ins_MUL( INS_ARG
)
3750 /*************************************************************************/
3752 /* ABS[]: ABSolute value */
3753 /* Opcode range: 0x64 */
3754 /* Stack: f26.6 --> f26.6 */
3757 void Ins_ABS( INS_ARG
)
3763 /*************************************************************************/
3766 /* Opcode range: 0x65 */
3767 /* Stack: f26.6 --> f26.6 */
3770 void Ins_NEG( INS_ARG
)
3776 /*************************************************************************/
3778 /* FLOOR[]: FLOOR */
3779 /* Opcode range: 0x66 */
3780 /* Stack: f26.6 --> f26.6 */
3783 void Ins_FLOOR( INS_ARG
)
3789 /*************************************************************************/
3791 /* CEILING[]: CEILING */
3792 /* Opcode range: 0x67 */
3793 /* Stack: f26.6 --> f26.6 */
3796 void Ins_CEILING( INS_ARG
)
3802 /*************************************************************************/
3804 /* RS[]: Read Store */
3805 /* Opcode range: 0x43 */
3806 /* Stack: uint32 --> uint32 */
3809 void Ins_RS( INS_ARG
)
3815 /*************************************************************************/
3817 /* WS[]: Write Store */
3818 /* Opcode range: 0x42 */
3819 /* Stack: uint32 uint32 --> */
3822 void Ins_WS( INS_ARG
)
3828 /*************************************************************************/
3830 /* WCVTP[]: Write CVT in Pixel units */
3831 /* Opcode range: 0x44 */
3832 /* Stack: f26.6 uint32 --> */
3835 void Ins_WCVTP( INS_ARG
)
3841 /*************************************************************************/
3843 /* WCVTF[]: Write CVT in Funits */
3844 /* Opcode range: 0x70 */
3845 /* Stack: uint32 uint32 --> */
3848 void Ins_WCVTF( INS_ARG
)
3854 /*************************************************************************/
3856 /* RCVT[]: Read CVT */
3857 /* Opcode range: 0x45 */
3858 /* Stack: uint32 --> f26.6 */
3861 void Ins_RCVT( INS_ARG
)
3867 /*************************************************************************/
3869 /* AA[]: Adjust Angle */
3870 /* Opcode range: 0x7F */
3871 /* Stack: uint32 --> */
3874 void Ins_AA( INS_ARG
)
3876 /* intentionally no longer supported */
3880 /*************************************************************************/
3882 /* DEBUG[]: DEBUG. Unsupported. */
3883 /* Opcode range: 0x4F */
3884 /* Stack: uint32 --> */
3886 /* Note: The original instruction pops a value from the stack. */
3889 void Ins_DEBUG( INS_ARG
)
3895 /*************************************************************************/
3897 /* ROUND[ab]: ROUND value */
3898 /* Opcode range: 0x68-0x6B */
3899 /* Stack: f26.6 --> f26.6 */
3902 void Ins_ROUND( INS_ARG
)
3908 /*************************************************************************/
3910 /* NROUND[ab]: No ROUNDing of value */
3911 /* Opcode range: 0x6C-0x6F */
3912 /* Stack: f26.6 --> f26.6 */
3915 void Ins_NROUND( INS_ARG
)
3921 /*************************************************************************/
3923 /* MAX[]: MAXimum */
3924 /* Opcode range: 0x68 */
3925 /* Stack: int32? int32? --> int32 */
3928 void Ins_MAX( INS_ARG
)
3934 /*************************************************************************/
3936 /* MIN[]: MINimum */
3937 /* Opcode range: 0x69 */
3938 /* Stack: int32? int32? --> int32 */
3941 void Ins_MIN( INS_ARG
)
3947 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
3950 /*************************************************************************/
3952 /* The following functions are called as is within the switch statement. */
3954 /*************************************************************************/
3957 /*************************************************************************/
3959 /* MINDEX[]: Move INDEXed element */
3960 /* Opcode range: 0x26 */
3961 /* Stack: int32? --> StkElt */
3964 void Ins_MINDEX( INS_ARG
)
3971 if ( L
<= 0 || L
> CUR
.args
)
3973 CUR
.error
= TT_Err_Invalid_Reference
;
3977 K
= CUR
.stack
[CUR
.args
- L
];
3979 MEM_Move( &CUR
.stack
[CUR
.args
- L
],
3980 &CUR
.stack
[CUR
.args
- L
+ 1],
3981 ( L
- 1 ) * sizeof ( FT_Long
) );
3983 CUR
.stack
[CUR
.args
- 1] = K
;
3987 /*************************************************************************/
3989 /* ROLL[]: ROLL top three elements */
3990 /* Opcode range: 0x8A */
3991 /* Stack: 3 * StkElt --> 3 * StkElt */
3994 void Ins_ROLL( INS_ARG
)
4011 /*************************************************************************/
4013 /* MANAGING THE FLOW OF CONTROL */
4015 /* Instructions appear in the specification's order. */
4017 /*************************************************************************/
4021 FT_Bool
SkipCode( EXEC_OP
)
4023 CUR
.IP
+= CUR
.length
;
4025 if ( CUR
.IP
< CUR
.codeSize
)
4027 CUR
.opcode
= CUR
.code
[CUR
.IP
];
4029 CUR
.length
= opcode_length
[CUR
.opcode
];
4030 if ( CUR
.length
< 0 )
4032 if ( CUR
.IP
+ 1 > CUR
.codeSize
)
4034 CUR
.length
= CUR
.code
[CUR
.IP
+ 1] + 2;
4037 if ( CUR
.IP
+ CUR
.length
<= CUR
.codeSize
)
4042 CUR
.error
= TT_Err_Code_Overflow
;
4047 /*************************************************************************/
4050 /* Opcode range: 0x58 */
4051 /* Stack: StkElt --> */
4054 void Ins_IF( INS_ARG
)
4068 if ( SKIP_Code() == FAILURE
)
4071 switch ( CUR
.opcode
)
4077 case 0x1B: /* ELSE */
4078 Out
= ( nIfs
== 1 );
4081 case 0x59: /* EIF */
4083 Out
= ( nIfs
== 0 );
4086 } while ( Out
== 0 );
4090 /*************************************************************************/
4093 /* Opcode range: 0x1B */
4097 void Ins_ELSE( INS_ARG
)
4108 if ( SKIP_Code() == FAILURE
)
4111 switch ( CUR
.opcode
)
4117 case 0x59: /* EIF */
4121 } while ( nIfs
!= 0 );
4125 /*************************************************************************/
4127 /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
4129 /* Instructions appear in the specification's order. */
4131 /*************************************************************************/
4134 /*************************************************************************/
4136 /* FDEF[]: Function DEFinition */
4137 /* Opcode range: 0x2C */
4138 /* Stack: uint32 --> */
4141 void Ins_FDEF( INS_ARG
)
4145 TT_DefRecord
* limit
;
4148 /* some font programs are broken enough to redefine functions! */
4149 /* We will then parse the current table. */
4152 limit
= rec
+ CUR
.numFDefs
;
4155 for ( ; rec
< limit
; rec
++ )
4157 if ( rec
->opc
== n
)
4163 /* check that there is enough room for new functions */
4164 if ( CUR
.numFDefs
>= CUR
.maxFDefs
)
4166 CUR
.error
= TT_Err_Too_Many_Function_Defs
;
4172 rec
->range
= CUR
.curRange
;
4174 rec
->start
= CUR
.IP
+ 1;
4177 if ( n
> CUR
.maxFunc
)
4180 /* Now skip the whole function definition. */
4181 /* We don't allow nested IDEFS & FDEFs. */
4183 while ( SKIP_Code() == SUCCESS
)
4185 switch ( CUR
.opcode
)
4187 case 0x89: /* IDEF */
4188 case 0x2C: /* FDEF */
4189 CUR
.error
= TT_Err_Nested_DEFS
;
4192 case 0x2D: /* ENDF */
4199 /*************************************************************************/
4201 /* ENDF[]: END Function definition */
4202 /* Opcode range: 0x2D */
4206 void Ins_ENDF( INS_ARG
)
4213 if ( CUR
.callTop
<= 0 ) /* We encountered an ENDF without a call */
4215 CUR
.error
= TT_Err_ENDF_In_Exec_Stream
;
4221 pRec
= &CUR
.callStack
[CUR
.callTop
];
4225 CUR
.step_ins
= FALSE
;
4227 if ( pRec
->Cur_Count
> 0 )
4230 CUR
.IP
= pRec
->Cur_Restart
;
4233 /* Loop through the current function */
4234 INS_Goto_CodeRange( pRec
->Caller_Range
,
4237 /* Exit the current call frame. */
4239 /* NOTE: If the last intruction of a program is a */
4240 /* CALL or LOOPCALL, the return address is */
4241 /* always out of the code range. This is a */
4242 /* valid address, and it is why we do not test */
4243 /* the result of Ins_Goto_CodeRange() here! */
4247 /*************************************************************************/
4249 /* CALL[]: CALL function */
4250 /* Opcode range: 0x2B */
4251 /* Stack: uint32? --> */
4254 void Ins_CALL( INS_ARG
)
4261 /* first of all, check the index */
4264 if ( BOUNDS( F
, CUR
.maxFunc
+ 1 ) )
4267 /* Except for some old Apple fonts, all functions in a TrueType */
4268 /* font are defined in increasing order, starting from 0. This */
4269 /* means that we normally have */
4271 /* CUR.maxFunc+1 == CUR.numFDefs */
4272 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4274 /* If this isn't true, we need to look up the function table. */
4276 def
= CUR
.FDefs
+ F
;
4277 if ( CUR
.maxFunc
+ 1 != CUR
.numFDefs
|| def
->opc
!= F
)
4279 /* look up the FDefs table */
4280 TT_DefRecord
* limit
;
4284 limit
= def
+ CUR
.numFDefs
;
4286 while ( def
< limit
&& def
->opc
!= F
)
4293 /* check that the function is active */
4297 /* check the call stack */
4298 if ( CUR
.callTop
>= CUR
.callSize
)
4300 CUR
.error
= TT_Err_Stack_Overflow
;
4304 pCrec
= CUR
.callStack
+ CUR
.callTop
;
4306 pCrec
->Caller_Range
= CUR
.curRange
;
4307 pCrec
->Caller_IP
= CUR
.IP
+ 1;
4308 pCrec
->Cur_Count
= 1;
4309 pCrec
->Cur_Restart
= def
->start
;
4313 INS_Goto_CodeRange( def
->range
,
4316 CUR
.step_ins
= FALSE
;
4320 CUR
.error
= TT_Err_Invalid_Reference
;
4324 /*************************************************************************/
4326 /* LOOPCALL[]: LOOP and CALL function */
4327 /* Opcode range: 0x2A */
4328 /* Stack: uint32? Eint16? --> */
4331 void Ins_LOOPCALL( INS_ARG
)
4338 /* first of all, check the index */
4340 if ( BOUNDS( F
, CUR
.maxFunc
+ 1 ) )
4343 /* Except for some old Apple fonts, all functions in a TrueType */
4344 /* font are defined in increasing order, starting from 0. This */
4345 /* means that we normally have */
4347 /* CUR.maxFunc+1 == CUR.numFDefs */
4348 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4350 /* If this isn't true, we need to look up the function table. */
4352 def
= CUR
.FDefs
+ F
;
4353 if ( CUR
.maxFunc
+ 1 != CUR
.numFDefs
|| def
->opc
!= F
)
4355 /* look up the FDefs table */
4356 TT_DefRecord
* limit
;
4360 limit
= def
+ CUR
.numFDefs
;
4362 while ( def
< limit
&& def
->opc
!= F
)
4369 /* check that the function is active */
4374 if ( CUR
.callTop
>= CUR
.callSize
)
4376 CUR
.error
= TT_Err_Stack_Overflow
;
4382 pCrec
= CUR
.callStack
+ CUR
.callTop
;
4384 pCrec
->Caller_Range
= CUR
.curRange
;
4385 pCrec
->Caller_IP
= CUR
.IP
+ 1;
4386 pCrec
->Cur_Count
= (FT_Int
)args
[0];
4387 pCrec
->Cur_Restart
= def
->start
;
4391 INS_Goto_CodeRange( def
->range
, def
->start
);
4393 CUR
.step_ins
= FALSE
;
4398 CUR
.error
= TT_Err_Invalid_Reference
;
4402 /*************************************************************************/
4404 /* IDEF[]: Instruction DEFinition */
4405 /* Opcode range: 0x89 */
4406 /* Stack: Eint8 --> */
4409 void Ins_IDEF( INS_ARG
)
4412 TT_DefRecord
* limit
;
4415 /* First of all, look for the same function in our table */
4418 limit
= def
+ CUR
.numIDefs
;
4420 for ( ; def
< limit
; def
++ )
4421 if ( def
->opc
== (FT_ULong
)args
[0] )
4426 /* check that there is enough room for a new instruction */
4427 if ( CUR
.numIDefs
>= CUR
.maxIDefs
)
4429 CUR
.error
= TT_Err_Too_Many_Instruction_Defs
;
4436 def
->start
= CUR
.IP
+1;
4437 def
->range
= CUR
.curRange
;
4440 if ( (FT_ULong
)args
[0] > CUR
.maxIns
)
4441 CUR
.maxIns
= args
[0];
4443 /* Now skip the whole function definition. */
4444 /* We don't allow nested IDEFs & FDEFs. */
4446 while ( SKIP_Code() == SUCCESS
)
4448 switch ( CUR
.opcode
)
4450 case 0x89: /* IDEF */
4451 case 0x2C: /* FDEF */
4452 CUR
.error
= TT_Err_Nested_DEFS
;
4454 case 0x2D: /* ENDF */
4461 /*************************************************************************/
4463 /* PUSHING DATA ONTO THE INTERPRETER STACK */
4465 /* Instructions appear in the specification's order. */
4467 /*************************************************************************/
4470 /*************************************************************************/
4472 /* NPUSHB[]: PUSH N Bytes */
4473 /* Opcode range: 0x40 */
4474 /* Stack: --> uint32... */
4477 void Ins_NPUSHB( INS_ARG
)
4482 L
= (FT_UShort
)CUR
.code
[CUR
.IP
+ 1];
4484 if ( BOUNDS( L
, CUR
.stackSize
+ 1 - CUR
.top
) )
4486 CUR
.error
= TT_Err_Stack_Overflow
;
4490 for ( K
= 1; K
<= L
; K
++ )
4491 args
[K
- 1] = CUR
.code
[CUR
.IP
+ K
+ 1];
4497 /*************************************************************************/
4499 /* NPUSHW[]: PUSH N Words */
4500 /* Opcode range: 0x41 */
4501 /* Stack: --> int32... */
4504 void Ins_NPUSHW( INS_ARG
)
4509 L
= (FT_UShort
)CUR
.code
[CUR
.IP
+ 1];
4511 if ( BOUNDS( L
, CUR
.stackSize
+ 1 - CUR
.top
) )
4513 CUR
.error
= TT_Err_Stack_Overflow
;
4519 for ( K
= 0; K
< L
; K
++ )
4520 args
[K
] = GET_ShortIns();
4522 CUR
.step_ins
= FALSE
;
4527 /*************************************************************************/
4529 /* PUSHB[abc]: PUSH Bytes */
4530 /* Opcode range: 0xB0-0xB7 */
4531 /* Stack: --> uint32... */
4534 void Ins_PUSHB( INS_ARG
)
4539 L
= (FT_UShort
)CUR
.opcode
- 0xB0 + 1;
4541 if ( BOUNDS( L
, CUR
.stackSize
+ 1 - CUR
.top
) )
4543 CUR
.error
= TT_Err_Stack_Overflow
;
4547 for ( K
= 1; K
<= L
; K
++ )
4548 args
[K
- 1] = CUR
.code
[CUR
.IP
+ K
];
4552 /*************************************************************************/
4554 /* PUSHW[abc]: PUSH Words */
4555 /* Opcode range: 0xB8-0xBF */
4556 /* Stack: --> int32... */
4559 void Ins_PUSHW( INS_ARG
)
4564 L
= (FT_UShort
)CUR
.opcode
- 0xB8 + 1;
4566 if ( BOUNDS( L
, CUR
.stackSize
+ 1 - CUR
.top
) )
4568 CUR
.error
= TT_Err_Stack_Overflow
;
4574 for ( K
= 0; K
< L
; K
++ )
4575 args
[K
] = GET_ShortIns();
4577 CUR
.step_ins
= FALSE
;
4581 /*************************************************************************/
4583 /* MANAGING THE GRAPHICS STATE */
4585 /* Instructions appear in the specs' order. */
4587 /*************************************************************************/
4590 /*************************************************************************/
4592 /* GC[a]: Get Coordinate projected onto */
4593 /* Opcode range: 0x46-0x47 */
4594 /* Stack: uint32 --> f26.6 */
4596 /* BULLSHIT: Measures from the original glyph must be taken along the */
4597 /* dual projection vector! */
4599 static void Ins_GC( INS_ARG
)
4605 L
= (FT_ULong
)args
[0];
4607 if ( BOUNDS( L
, CUR
.zp2
.n_points
) )
4609 if ( CUR
.pedantic_hinting
)
4611 CUR
.error
= TT_Err_Invalid_Reference
;
4619 if ( CUR
.opcode
& 1 )
4620 R
= CUR_Func_dualproj( CUR
.zp2
.org
+ L
, NULL_Vector
);
4622 R
= CUR_Func_project( CUR
.zp2
.cur
+ L
, NULL_Vector
);
4629 /*************************************************************************/
4631 /* SCFS[]: Set Coordinate From Stack */
4632 /* Opcode range: 0x48 */
4633 /* Stack: f26.6 uint32 --> */
4637 /* OA := OA + ( value - OA.p )/( f.p ) * f */
4640 void Ins_SCFS( INS_ARG
)
4646 L
= (FT_UShort
)args
[0];
4648 if ( BOUNDS( L
, CUR
.zp2
.n_points
) )
4650 if ( CUR
.pedantic_hinting
)
4651 CUR
.error
= TT_Err_Invalid_Reference
;
4655 K
= CUR_Func_project( CUR
.zp2
.cur
+ L
, NULL_Vector
);
4657 CUR_Func_move( &CUR
.zp2
, L
, args
[1] - K
);
4659 /* not part of the specs, but here for safety */
4661 if ( CUR
.GS
.gep2
== 0 )
4662 CUR
.zp2
.org
[L
] = CUR
.zp2
.cur
[L
];
4666 /*************************************************************************/
4668 /* MD[a]: Measure Distance */
4669 /* Opcode range: 0x49-0x4A */
4670 /* Stack: uint32 uint32 --> f26.6 */
4672 /* BULLSHIT: Measure taken in the original glyph must be along the dual */
4673 /* projection vector. */
4675 /* Second BULLSHIT: Flag attributes are inverted! */
4676 /* 0 => measure distance in original outline */
4677 /* 1 => measure distance in grid-fitted outline */
4679 /* Third one: `zp0 - zp1', and not `zp2 - zp1! */
4682 void Ins_MD( INS_ARG
)
4688 K
= (FT_UShort
)args
[1];
4689 L
= (FT_UShort
)args
[0];
4691 if( BOUNDS( L
, CUR
.zp0
.n_points
) ||
4692 BOUNDS( K
, CUR
.zp1
.n_points
) )
4694 if ( CUR
.pedantic_hinting
)
4696 CUR
.error
= TT_Err_Invalid_Reference
;
4703 if ( CUR
.opcode
& 1 )
4704 D
= CUR_Func_project( CUR
.zp0
.cur
+ L
, CUR
.zp1
.cur
+ K
);
4706 D
= CUR_Func_dualproj( CUR
.zp0
.org
+ L
, CUR
.zp1
.org
+ K
);
4713 /*************************************************************************/
4715 /* SDPVTL[a]: Set Dual PVector to Line */
4716 /* Opcode range: 0x86-0x87 */
4717 /* Stack: uint32 uint32 --> */
4720 void Ins_SDPVTL( INS_ARG
)
4723 FT_UShort p1
, p2
; /* was FT_Int in pas type ERROR */
4726 p1
= (FT_UShort
)args
[1];
4727 p2
= (FT_UShort
)args
[0];
4729 if ( BOUNDS( p2
, CUR
.zp1
.n_points
) ||
4730 BOUNDS( p1
, CUR
.zp2
.n_points
) )
4732 if ( CUR
.pedantic_hinting
)
4733 CUR
.error
= TT_Err_Invalid_Reference
;
4738 FT_Vector
* v1
= CUR
.zp1
.org
+ p2
;
4739 FT_Vector
* v2
= CUR
.zp2
.org
+ p1
;
4746 if ( ( CUR
.opcode
& 1 ) != 0 )
4748 C
= B
; /* counter clockwise rotation */
4753 NORMalize( A
, B
, &CUR
.GS
.dualVector
);
4756 FT_Vector
* v1
= CUR
.zp1
.cur
+ p2
;
4757 FT_Vector
* v2
= CUR
.zp2
.cur
+ p1
;
4764 if ( ( CUR
.opcode
& 1 ) != 0 )
4766 C
= B
; /* counter clockwise rotation */
4771 NORMalize( A
, B
, &CUR
.GS
.projVector
);
4777 /*************************************************************************/
4779 /* SZP0[]: Set Zone Pointer 0 */
4780 /* Opcode range: 0x13 */
4781 /* Stack: uint32 --> */
4784 void Ins_SZP0( INS_ARG
)
4786 switch ( (FT_Int
)args
[0] )
4789 CUR
.zp0
= CUR
.twilight
;
4797 if ( CUR
.pedantic_hinting
)
4798 CUR
.error
= TT_Err_Invalid_Reference
;
4802 CUR
.GS
.gep0
= (FT_UShort
)args
[0];
4806 /*************************************************************************/
4808 /* SZP1[]: Set Zone Pointer 1 */
4809 /* Opcode range: 0x14 */
4810 /* Stack: uint32 --> */
4813 void Ins_SZP1( INS_ARG
)
4815 switch ( (FT_Int
)args
[0] )
4818 CUR
.zp1
= CUR
.twilight
;
4826 if ( CUR
.pedantic_hinting
)
4827 CUR
.error
= TT_Err_Invalid_Reference
;
4831 CUR
.GS
.gep1
= (FT_UShort
)args
[0];
4835 /*************************************************************************/
4837 /* SZP2[]: Set Zone Pointer 2 */
4838 /* Opcode range: 0x15 */
4839 /* Stack: uint32 --> */
4842 void Ins_SZP2( INS_ARG
)
4844 switch ( (FT_Int
)args
[0] )
4847 CUR
.zp2
= CUR
.twilight
;
4855 if ( CUR
.pedantic_hinting
)
4856 CUR
.error
= TT_Err_Invalid_Reference
;
4860 CUR
.GS
.gep2
= (FT_UShort
)args
[0];
4864 /*************************************************************************/
4866 /* SZPS[]: Set Zone PointerS */
4867 /* Opcode range: 0x16 */
4868 /* Stack: uint32 --> */
4871 void Ins_SZPS( INS_ARG
)
4873 switch ( (FT_Int
)args
[0] )
4876 CUR
.zp0
= CUR
.twilight
;
4884 if ( CUR
.pedantic_hinting
)
4885 CUR
.error
= TT_Err_Invalid_Reference
;
4892 CUR
.GS
.gep0
= (FT_UShort
)args
[0];
4893 CUR
.GS
.gep1
= (FT_UShort
)args
[0];
4894 CUR
.GS
.gep2
= (FT_UShort
)args
[0];
4898 /*************************************************************************/
4900 /* INSTCTRL[]: INSTruction ConTRoL */
4901 /* Opcode range: 0x8e */
4902 /* Stack: int32 int32 --> */
4905 void Ins_INSTCTRL( INS_ARG
)
4913 if ( K
< 1 || K
> 2 )
4915 if ( CUR
.pedantic_hinting
)
4916 CUR
.error
= TT_Err_Invalid_Reference
;
4923 CUR
.GS
.instruct_control
=
4924 (FT_Byte
)( CUR
.GS
.instruct_control
& ~(FT_Byte
)K
) | (FT_Byte
)L
;
4928 /*************************************************************************/
4930 /* SCANCTRL[]: SCAN ConTRoL */
4931 /* Opcode range: 0x85 */
4932 /* Stack: uint32? --> */
4935 void Ins_SCANCTRL( INS_ARG
)
4941 A
= (FT_Int
)( args
[0] & 0xFF );
4945 CUR
.GS
.scan_control
= TRUE
;
4950 CUR
.GS
.scan_control
= FALSE
;
4957 if ( (args
[0] & 0x100) != 0 && CUR
.metrics
.pointSize
<= A
)
4958 CUR
.GS
.scan_control
= TRUE
;
4961 if ( (args
[0] & 0x200) != 0 && CUR
.tt_metrics
.rotated
)
4962 CUR
.GS
.scan_control
= TRUE
;
4964 if ( (args
[0] & 0x400) != 0 && CUR
.tt_metrics
.stretched
)
4965 CUR
.GS
.scan_control
= TRUE
;
4968 if ( (args
[0] & 0x800) != 0 && CUR
.metrics
.pointSize
> A
)
4969 CUR
.GS
.scan_control
= FALSE
;
4972 if ( (args
[0] & 0x1000) != 0 && CUR
.tt_metrics
.rotated
)
4973 CUR
.GS
.scan_control
= FALSE
;
4975 if ( (args
[0] & 0x2000) != 0 && CUR
.tt_metrics
.stretched
)
4976 CUR
.GS
.scan_control
= FALSE
;
4980 /*************************************************************************/
4982 /* SCANTYPE[]: SCAN TYPE */
4983 /* Opcode range: 0x8D */
4984 /* Stack: uint32? --> */
4987 void Ins_SCANTYPE( INS_ARG
)
4989 /* for compatibility with future enhancements, */
4990 /* we must ignore new modes */
4992 if ( args
[0] >= 0 && args
[0] <= 5 )
4997 CUR
.GS
.scan_type
= (FT_Int
)args
[0];
5002 /*************************************************************************/
5004 /* MANAGING OUTLINES */
5006 /* Instructions appear in the specification's order. */
5008 /*************************************************************************/
5011 /*************************************************************************/
5013 /* FLIPPT[]: FLIP PoinT */
5014 /* Opcode range: 0x80 */
5015 /* Stack: uint32... --> */
5018 void Ins_FLIPPT( INS_ARG
)
5025 if ( CUR
.top
< CUR
.GS
.loop
)
5027 CUR
.error
= TT_Err_Too_Few_Arguments
;
5031 while ( CUR
.GS
.loop
> 0 )
5035 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5037 if ( BOUNDS( point
, CUR
.pts
.n_points
) )
5039 if ( CUR
.pedantic_hinting
)
5041 CUR
.error
= TT_Err_Invalid_Reference
;
5046 CUR
.pts
.tags
[point
] ^= FT_Curve_Tag_On
;
5052 CUR
.new_top
= CUR
.args
;
5056 /*************************************************************************/
5058 /* FLIPRGON[]: FLIP RanGe ON */
5059 /* Opcode range: 0x81 */
5060 /* Stack: uint32 uint32 --> */
5063 void Ins_FLIPRGON( INS_ARG
)
5068 K
= (FT_UShort
)args
[1];
5069 L
= (FT_UShort
)args
[0];
5071 if ( BOUNDS( K
, CUR
.pts
.n_points
) ||
5072 BOUNDS( L
, CUR
.pts
.n_points
) )
5074 if ( CUR
.pedantic_hinting
)
5075 CUR
.error
= TT_Err_Invalid_Reference
;
5079 for ( I
= L
; I
<= K
; I
++ )
5080 CUR
.pts
.tags
[I
] |= FT_Curve_Tag_On
;
5084 /*************************************************************************/
5086 /* FLIPRGOFF: FLIP RanGe OFF */
5087 /* Opcode range: 0x82 */
5088 /* Stack: uint32 uint32 --> */
5091 void Ins_FLIPRGOFF( INS_ARG
)
5096 K
= (FT_UShort
)args
[1];
5097 L
= (FT_UShort
)args
[0];
5099 if ( BOUNDS( K
, CUR
.pts
.n_points
) ||
5100 BOUNDS( L
, CUR
.pts
.n_points
) )
5102 if ( CUR
.pedantic_hinting
)
5103 CUR
.error
= TT_Err_Invalid_Reference
;
5107 for ( I
= L
; I
<= K
; I
++ )
5108 CUR
.pts
.tags
[I
] &= ~FT_Curve_Tag_On
;
5113 FT_Bool
Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6
* x
,
5123 if ( CUR
.opcode
& 1 )
5134 if ( BOUNDS( p
, zp
.n_points
) )
5136 if ( CUR
.pedantic_hinting
)
5137 CUR
.error
= TT_Err_Invalid_Reference
;
5144 d
= CUR_Func_project( zp
.cur
+ p
, zp
.org
+ p
);
5146 #ifdef NO_APPLE_PATENT
5148 *x
= TT_MULDIV( d
, CUR
.GS
.freeVector
.x
, 0x4000 );
5149 *y
= TT_MULDIV( d
, CUR
.GS
.freeVector
.y
, 0x4000 );
5154 (FT_Long
)CUR
.GS
.freeVector
.x
* 0x10000L
,
5157 (FT_Long
)CUR
.GS
.freeVector
.y
* 0x10000L
,
5160 #endif /* NO_APPLE_PATENT */
5167 void Move_Zp2_Point( EXEC_OP_ FT_UShort point
,
5172 if ( CUR
.GS
.freeVector
.x
!= 0 )
5174 CUR
.zp2
.cur
[point
].x
+= dx
;
5176 CUR
.zp2
.tags
[point
] |= FT_Curve_Tag_Touch_X
;
5179 if ( CUR
.GS
.freeVector
.y
!= 0 )
5181 CUR
.zp2
.cur
[point
].y
+= dy
;
5183 CUR
.zp2
.tags
[point
] |= FT_Curve_Tag_Touch_Y
;
5188 /*************************************************************************/
5190 /* SHP[a]: SHift Point by the last point */
5191 /* Opcode range: 0x32-0x33 */
5192 /* Stack: uint32... --> */
5195 void Ins_SHP( INS_ARG
)
5207 if ( CUR
.top
< CUR
.GS
.loop
)
5209 CUR
.error
= TT_Err_Invalid_Reference
;
5213 if ( COMPUTE_Point_Displacement( &dx
, &dy
, &zp
, &refp
) )
5216 while ( CUR
.GS
.loop
> 0 )
5219 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5221 if ( BOUNDS( point
, CUR
.zp2
.n_points
) )
5223 if ( CUR
.pedantic_hinting
)
5225 CUR
.error
= TT_Err_Invalid_Reference
;
5230 /* XXX: UNDOCUMENTED! SHP touches the points */
5231 MOVE_Zp2_Point( point
, dx
, dy
, TRUE
);
5237 CUR
.new_top
= CUR
.args
;
5241 /*************************************************************************/
5243 /* SHC[a]: SHift Contour */
5244 /* Opcode range: 0x34-35 */
5245 /* Stack: uint32 --> */
5248 void Ins_SHC( INS_ARG
)
5256 FT_UShort first_point
, last_point
, i
;
5259 contour
= (FT_UShort
)args
[0];
5261 if ( BOUNDS( contour
, CUR
.pts
.n_contours
) )
5263 if ( CUR
.pedantic_hinting
)
5264 CUR
.error
= TT_Err_Invalid_Reference
;
5268 if ( COMPUTE_Point_Displacement( &dx
, &dy
, &zp
, &refp
) )
5274 first_point
= CUR
.pts
.contours
[contour
- 1] + 1;
5276 last_point
= CUR
.pts
.contours
[contour
];
5278 /* XXX: this is probably wrong... at least it prevents memory */
5279 /* corruption when zp2 is the twilight zone */
5280 if ( last_point
> CUR
.zp2
.n_points
)
5282 if ( CUR
.zp2
.n_points
> 0 )
5283 last_point
= CUR
.zp2
.n_points
- 1;
5288 /* XXX: UNDOCUMENTED! SHC doesn't touch the points */
5289 for ( i
= first_point
; i
<= last_point
; i
++ )
5291 if ( zp
.cur
!= CUR
.zp2
.cur
|| refp
!= i
)
5292 MOVE_Zp2_Point( i
, dx
, dy
, FALSE
);
5297 /*************************************************************************/
5299 /* SHZ[a]: SHift Zone */
5300 /* Opcode range: 0x36-37 */
5301 /* Stack: uint32 --> */
5304 void Ins_SHZ( INS_ARG
)
5311 FT_UShort last_point
, i
;
5314 if ( BOUNDS( args
[0], 2 ) )
5316 if ( CUR
.pedantic_hinting
)
5317 CUR
.error
= TT_Err_Invalid_Reference
;
5321 if ( COMPUTE_Point_Displacement( &dx
, &dy
, &zp
, &refp
) )
5324 if ( CUR
.zp2
.n_points
> 0 )
5325 last_point
= CUR
.zp2
.n_points
- 1;
5329 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
5330 for ( i
= 0; i
<= last_point
; i
++ )
5332 if ( zp
.cur
!= CUR
.zp2
.cur
|| refp
!= i
)
5333 MOVE_Zp2_Point( i
, dx
, dy
, FALSE
);
5338 /*************************************************************************/
5340 /* SHPIX[]: SHift points by a PIXel amount */
5341 /* Opcode range: 0x38 */
5342 /* Stack: f26.6 uint32... --> */
5345 void Ins_SHPIX( INS_ARG
)
5351 if ( CUR
.top
< CUR
.GS
.loop
+ 1 )
5353 CUR
.error
= TT_Err_Invalid_Reference
;
5357 dx
= TT_MULDIV( args
[0],
5358 (FT_Long
)CUR
.GS
.freeVector
.x
,
5360 dy
= TT_MULDIV( args
[0],
5361 (FT_Long
)CUR
.GS
.freeVector
.y
,
5364 while ( CUR
.GS
.loop
> 0 )
5368 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5370 if ( BOUNDS( point
, CUR
.zp2
.n_points
) )
5372 if ( CUR
.pedantic_hinting
)
5374 CUR
.error
= TT_Err_Invalid_Reference
;
5379 MOVE_Zp2_Point( point
, dx
, dy
, TRUE
);
5385 CUR
.new_top
= CUR
.args
;
5389 /*************************************************************************/
5391 /* MSIRP[a]: Move Stack Indirect Relative Position */
5392 /* Opcode range: 0x3A-0x3B */
5393 /* Stack: f26.6 uint32 --> */
5396 void Ins_MSIRP( INS_ARG
)
5399 FT_F26Dot6 distance
;
5402 point
= (FT_UShort
)args
[0];
5404 if ( BOUNDS( point
, CUR
.zp1
.n_points
) ||
5405 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5407 if ( CUR
.pedantic_hinting
)
5408 CUR
.error
= TT_Err_Invalid_Reference
;
5412 /* XXX: UNDOCUMENTED! behaviour */
5413 if ( CUR
.GS
.gep0
== 0 ) /* if in twilight zone */
5415 CUR
.zp1
.org
[point
] = CUR
.zp0
.org
[CUR
.GS
.rp0
];
5416 CUR
.zp1
.cur
[point
] = CUR
.zp1
.org
[point
];
5419 distance
= CUR_Func_project( CUR
.zp1
.cur
+ point
,
5420 CUR
.zp0
.cur
+ CUR
.GS
.rp0
);
5422 CUR_Func_move( &CUR
.zp1
, point
, args
[1] - distance
);
5424 CUR
.GS
.rp1
= CUR
.GS
.rp0
;
5427 if ( (CUR
.opcode
& 1) != 0 )
5432 /*************************************************************************/
5434 /* MDAP[a]: Move Direct Absolute Point */
5435 /* Opcode range: 0x2E-0x2F */
5436 /* Stack: uint32 --> */
5439 void Ins_MDAP( INS_ARG
)
5442 FT_F26Dot6 cur_dist
,
5446 point
= (FT_UShort
)args
[0];
5448 if ( BOUNDS( point
, CUR
.zp0
.n_points
) )
5450 if ( CUR
.pedantic_hinting
)
5451 CUR
.error
= TT_Err_Invalid_Reference
;
5455 /* XXX: Is there some undocumented feature while in the */
5456 /* twilight zone? ? */
5457 if ( ( CUR
.opcode
& 1 ) != 0 )
5459 cur_dist
= CUR_Func_project( CUR
.zp0
.cur
+ point
, NULL_Vector
);
5460 distance
= CUR_Func_round( cur_dist
,
5461 CUR
.tt_metrics
.compensations
[0] ) - cur_dist
;
5466 CUR_Func_move( &CUR
.zp0
, point
, distance
);
5473 /*************************************************************************/
5475 /* MIAP[a]: Move Indirect Absolute Point */
5476 /* Opcode range: 0x3E-0x3F */
5477 /* Stack: uint32 uint32 --> */
5480 void Ins_MIAP( INS_ARG
)
5484 FT_F26Dot6 distance
,
5488 cvtEntry
= (FT_ULong
)args
[1];
5489 point
= (FT_UShort
)args
[0];
5491 if ( BOUNDS( point
, CUR
.zp0
.n_points
) ||
5492 BOUNDS( cvtEntry
, CUR
.cvtSize
) )
5494 if ( CUR
.pedantic_hinting
)
5495 CUR
.error
= TT_Err_Invalid_Reference
;
5501 /* The behaviour of an MIAP instruction is quite */
5502 /* different when used in the twilight zone. */
5504 /* First, no control value cutin test is performed */
5505 /* as it would fail anyway. Second, the original */
5506 /* point, i.e. (org_x,org_y) of zp0.point, is set */
5507 /* to the absolute, unrounded distance found in */
5510 /* This is used in the CVT programs of the Microsoft */
5511 /* fonts Arial, Times, etc., in order to re-adjust */
5512 /* some key font heights. It allows the use of the */
5513 /* IP instruction in the twilight zone, which */
5514 /* otherwise would be `illegal' according to the */
5515 /* specification. */
5517 /* We implement it with a special sequence for the */
5518 /* twilight zone. This is a bad hack, but it seems */
5521 distance
= CUR_Func_read_cvt( cvtEntry
);
5523 if ( CUR
.GS
.gep0
== 0 ) /* If in twilight zone */
5525 CUR
.zp0
.org
[point
].x
= TT_MULDIV( CUR
.GS
.freeVector
.x
,
5527 CUR
.zp0
.org
[point
].y
= TT_MULDIV( CUR
.GS
.freeVector
.y
,
5529 CUR
.zp0
.cur
[point
] = CUR
.zp0
.org
[point
];
5532 org_dist
= CUR_Func_project( CUR
.zp0
.cur
+ point
, NULL_Vector
);
5534 if ( ( CUR
.opcode
& 1 ) != 0 ) /* rounding and control cutin flag */
5536 if ( ABS( distance
- org_dist
) > CUR
.GS
.control_value_cutin
)
5537 distance
= org_dist
;
5539 distance
= CUR_Func_round( distance
, CUR
.tt_metrics
.compensations
[0] );
5542 CUR_Func_move( &CUR
.zp0
, point
, distance
- org_dist
);
5549 /*************************************************************************/
5551 /* MDRP[abcde]: Move Direct Relative Point */
5552 /* Opcode range: 0xC0-0xDF */
5553 /* Stack: uint32 --> */
5556 void Ins_MDRP( INS_ARG
)
5559 FT_F26Dot6 org_dist
, distance
;
5562 point
= (FT_UShort
)args
[0];
5564 if ( BOUNDS( point
, CUR
.zp1
.n_points
) ||
5565 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5567 if ( CUR
.pedantic_hinting
)
5568 CUR
.error
= TT_Err_Invalid_Reference
;
5572 /* XXX: Is there some undocumented feature while in the */
5573 /* twilight zone? */
5575 org_dist
= CUR_Func_dualproj( CUR
.zp1
.org
+ point
,
5576 CUR
.zp0
.org
+ CUR
.GS
.rp0
);
5578 /* single width cutin test */
5580 if ( ABS( org_dist
) < CUR
.GS
.single_width_cutin
)
5582 if ( org_dist
>= 0 )
5583 org_dist
= CUR
.GS
.single_width_value
;
5585 org_dist
= -CUR
.GS
.single_width_value
;
5590 if ( ( CUR
.opcode
& 4 ) != 0 )
5591 distance
= CUR_Func_round(
5593 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5595 distance
= ROUND_None(
5597 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5599 /* minimum distance flag */
5601 if ( ( CUR
.opcode
& 8 ) != 0 )
5603 if ( org_dist
>= 0 )
5605 if ( distance
< CUR
.GS
.minimum_distance
)
5606 distance
= CUR
.GS
.minimum_distance
;
5610 if ( distance
> -CUR
.GS
.minimum_distance
)
5611 distance
= -CUR
.GS
.minimum_distance
;
5615 /* now move the point */
5617 org_dist
= CUR_Func_project( CUR
.zp1
.cur
+ point
,
5618 CUR
.zp0
.cur
+ CUR
.GS
.rp0
);
5620 CUR_Func_move( &CUR
.zp1
, point
, distance
- org_dist
);
5622 CUR
.GS
.rp1
= CUR
.GS
.rp0
;
5625 if ( ( CUR
.opcode
& 16 ) != 0 )
5630 /*************************************************************************/
5632 /* MIRP[abcde]: Move Indirect Relative Point */
5633 /* Opcode range: 0xE0-0xFF */
5634 /* Stack: int32? uint32 --> */
5637 void Ins_MIRP( INS_ARG
)
5642 FT_F26Dot6 cvt_dist
,
5648 point
= (FT_UShort
)args
[0];
5649 cvtEntry
= (FT_ULong
)( args
[1] + 1 );
5651 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
5653 if ( BOUNDS( point
, CUR
.zp1
.n_points
) ||
5654 BOUNDS( cvtEntry
, CUR
.cvtSize
+ 1 ) ||
5655 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5657 if ( CUR
.pedantic_hinting
)
5658 CUR
.error
= TT_Err_Invalid_Reference
;
5665 cvt_dist
= CUR_Func_read_cvt( cvtEntry
- 1 );
5667 /* single width test */
5669 if ( ABS( cvt_dist
) < CUR
.GS
.single_width_cutin
)
5671 if ( cvt_dist
>= 0 )
5672 cvt_dist
= CUR
.GS
.single_width_value
;
5674 cvt_dist
= -CUR
.GS
.single_width_value
;
5677 /* XXX: UNDOCUMENTED! -- twilight zone */
5679 if ( CUR
.GS
.gep1
== 0 )
5681 CUR
.zp1
.org
[point
].x
= CUR
.zp0
.org
[CUR
.GS
.rp0
].x
+
5682 TT_MULDIV( cvt_dist
,
5683 CUR
.GS
.freeVector
.x
,
5686 CUR
.zp1
.org
[point
].y
= CUR
.zp0
.org
[CUR
.GS
.rp0
].y
+
5687 TT_MULDIV( cvt_dist
,
5688 CUR
.GS
.freeVector
.y
,
5691 CUR
.zp1
.cur
[point
] = CUR
.zp1
.org
[point
];
5694 org_dist
= CUR_Func_dualproj( CUR
.zp1
.org
+ point
,
5695 CUR
.zp0
.org
+ CUR
.GS
.rp0
);
5697 cur_dist
= CUR_Func_project( CUR
.zp1
.cur
+ point
,
5698 CUR
.zp0
.cur
+ CUR
.GS
.rp0
);
5700 /* auto-flip test */
5702 if ( CUR
.GS
.auto_flip
)
5704 if ( ( org_dist
^ cvt_dist
) < 0 )
5705 cvt_dist
= -cvt_dist
;
5708 /* control value cutin and round */
5710 if ( ( CUR
.opcode
& 4 ) != 0 )
5712 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
5713 /* refer to the same zone. */
5715 if ( CUR
.GS
.gep0
== CUR
.GS
.gep1
)
5716 if ( ABS( cvt_dist
- org_dist
) >= CUR
.GS
.control_value_cutin
)
5717 cvt_dist
= org_dist
;
5719 distance
= CUR_Func_round(
5721 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5724 distance
= ROUND_None(
5726 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5728 /* minimum distance test */
5730 if ( ( CUR
.opcode
& 8 ) != 0 )
5732 if ( org_dist
>= 0 )
5734 if ( distance
< CUR
.GS
.minimum_distance
)
5735 distance
= CUR
.GS
.minimum_distance
;
5739 if ( distance
> -CUR
.GS
.minimum_distance
)
5740 distance
= -CUR
.GS
.minimum_distance
;
5744 CUR_Func_move( &CUR
.zp1
, point
, distance
- cur_dist
);
5746 CUR
.GS
.rp1
= CUR
.GS
.rp0
;
5748 if ( ( CUR
.opcode
& 16 ) != 0 )
5751 /* XXX: UNDOCUMENTED! */
5757 /*************************************************************************/
5759 /* ALIGNRP[]: ALIGN Relative Point */
5760 /* Opcode range: 0x3C */
5761 /* Stack: uint32 uint32... --> */
5764 void Ins_ALIGNRP( INS_ARG
)
5767 FT_F26Dot6 distance
;
5772 if ( CUR
.top
< CUR
.GS
.loop
||
5773 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5775 if ( CUR
.pedantic_hinting
)
5776 CUR
.error
= TT_Err_Invalid_Reference
;
5780 while ( CUR
.GS
.loop
> 0 )
5784 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5786 if ( BOUNDS( point
, CUR
.zp1
.n_points
) )
5788 if ( CUR
.pedantic_hinting
)
5790 CUR
.error
= TT_Err_Invalid_Reference
;
5796 distance
= CUR_Func_project( CUR
.zp1
.cur
+ point
,
5797 CUR
.zp0
.cur
+ CUR
.GS
.rp0
);
5799 CUR_Func_move( &CUR
.zp1
, point
, -distance
);
5806 CUR
.new_top
= CUR
.args
;
5810 /*************************************************************************/
5812 /* ISECT[]: moves point to InterSECTion */
5813 /* Opcode range: 0x0F */
5814 /* Stack: 5 * uint32 --> */
5817 void Ins_ISECT( INS_ARG
)
5823 FT_F26Dot6 discriminant
;
5834 point
= (FT_UShort
)args
[0];
5836 a0
= (FT_UShort
)args
[1];
5837 a1
= (FT_UShort
)args
[2];
5838 b0
= (FT_UShort
)args
[3];
5839 b1
= (FT_UShort
)args
[4];
5841 if ( BOUNDS( b0
, CUR
.zp0
.n_points
) ||
5842 BOUNDS( b1
, CUR
.zp0
.n_points
) ||
5843 BOUNDS( a0
, CUR
.zp1
.n_points
) ||
5844 BOUNDS( a1
, CUR
.zp1
.n_points
) ||
5845 BOUNDS( point
, CUR
.zp2
.n_points
) )
5847 if ( CUR
.pedantic_hinting
)
5848 CUR
.error
= TT_Err_Invalid_Reference
;
5852 dbx
= CUR
.zp0
.cur
[b1
].x
- CUR
.zp0
.cur
[b0
].x
;
5853 dby
= CUR
.zp0
.cur
[b1
].y
- CUR
.zp0
.cur
[b0
].y
;
5855 dax
= CUR
.zp1
.cur
[a1
].x
- CUR
.zp1
.cur
[a0
].x
;
5856 day
= CUR
.zp1
.cur
[a1
].y
- CUR
.zp1
.cur
[a0
].y
;
5858 dx
= CUR
.zp0
.cur
[b0
].x
- CUR
.zp1
.cur
[a0
].x
;
5859 dy
= CUR
.zp0
.cur
[b0
].y
- CUR
.zp1
.cur
[a0
].y
;
5861 CUR
.zp2
.tags
[point
] |= FT_Curve_Tag_Touch_Both
;
5863 discriminant
= TT_MULDIV( dax
, -dby
, 0x40 ) +
5864 TT_MULDIV( day
, dbx
, 0x40 );
5866 if ( ABS( discriminant
) >= 0x40 )
5868 val
= TT_MULDIV( dx
, -dby
, 0x40 ) + TT_MULDIV( dy
, dbx
, 0x40 );
5870 R
.x
= TT_MULDIV( val
, dax
, discriminant
);
5871 R
.y
= TT_MULDIV( val
, day
, discriminant
);
5873 CUR
.zp2
.cur
[point
].x
= CUR
.zp1
.cur
[a0
].x
+ R
.x
;
5874 CUR
.zp2
.cur
[point
].y
= CUR
.zp1
.cur
[a0
].y
+ R
.y
;
5878 /* else, take the middle of the middles of A and B */
5880 CUR
.zp2
.cur
[point
].x
= ( CUR
.zp1
.cur
[a0
].x
+
5883 CUR
.zp0
.cur
[b1
].x
) / 4;
5884 CUR
.zp2
.cur
[point
].y
= ( CUR
.zp1
.cur
[a0
].y
+
5887 CUR
.zp0
.cur
[b1
].y
) / 4;
5892 /*************************************************************************/
5894 /* ALIGNPTS[]: ALIGN PoinTS */
5895 /* Opcode range: 0x27 */
5896 /* Stack: uint32 uint32 --> */
5899 void Ins_ALIGNPTS( INS_ARG
)
5902 FT_F26Dot6 distance
;
5905 p1
= (FT_UShort
)args
[0];
5906 p2
= (FT_UShort
)args
[1];
5908 if ( BOUNDS( args
[0], CUR
.zp1
.n_points
) ||
5909 BOUNDS( args
[1], CUR
.zp0
.n_points
) )
5911 if ( CUR
.pedantic_hinting
)
5912 CUR
.error
= TT_Err_Invalid_Reference
;
5916 distance
= CUR_Func_project( CUR
.zp0
.cur
+ p2
,
5917 CUR
.zp1
.cur
+ p1
) / 2;
5919 CUR_Func_move( &CUR
.zp1
, p1
, distance
);
5920 CUR_Func_move( &CUR
.zp0
, p2
, -distance
);
5924 /*************************************************************************/
5926 /* IP[]: Interpolate Point */
5927 /* Opcode range: 0x39 */
5928 /* Stack: uint32... --> */
5931 void Ins_IP( INS_ARG
)
5933 FT_F26Dot6 org_a
, org_b
, org_x
,
5934 cur_a
, cur_b
, cur_x
,
5941 if ( CUR
.top
< CUR
.GS
.loop
)
5943 CUR
.error
= TT_Err_Invalid_Reference
;
5947 /* XXX: There are some glyphs in some braindead but popular */
5948 /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
5949 /* calling IP[] with bad values of rp[12]. */
5950 /* Do something sane when this odd thing happens. */
5952 if ( BOUNDS( CUR
.GS
.rp1
, CUR
.zp0
.n_points
) ||
5953 BOUNDS( CUR
.GS
.rp2
, CUR
.zp1
.n_points
) )
5960 org_a
= CUR_Func_dualproj( CUR
.zp0
.org
+ CUR
.GS
.rp1
, NULL_Vector
);
5961 org_b
= CUR_Func_dualproj( CUR
.zp1
.org
+ CUR
.GS
.rp2
, NULL_Vector
);
5963 cur_a
= CUR_Func_project( CUR
.zp0
.cur
+ CUR
.GS
.rp1
, NULL_Vector
);
5964 cur_b
= CUR_Func_project( CUR
.zp1
.cur
+ CUR
.GS
.rp2
, NULL_Vector
);
5967 while ( CUR
.GS
.loop
> 0 )
5971 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5972 if ( BOUNDS( point
, CUR
.zp2
.n_points
) )
5974 if ( CUR
.pedantic_hinting
)
5976 CUR
.error
= TT_Err_Invalid_Reference
;
5982 org_x
= CUR_Func_dualproj( CUR
.zp2
.org
+ point
, NULL_Vector
);
5983 cur_x
= CUR_Func_project ( CUR
.zp2
.cur
+ point
, NULL_Vector
);
5985 if ( ( org_a
<= org_b
&& org_x
<= org_a
) ||
5986 ( org_a
> org_b
&& org_x
>= org_a
) )
5988 distance
= ( cur_a
- org_a
) + ( org_x
- cur_x
);
5990 else if ( ( org_a
<= org_b
&& org_x
>= org_b
) ||
5991 ( org_a
> org_b
&& org_x
< org_b
) )
5993 distance
= ( cur_b
- org_b
) + ( org_x
- cur_x
);
5996 /* note: it seems that rounding this value isn't a good */
5997 /* idea (cf. width of capital `S' in Times) */
5999 distance
= TT_MULDIV( cur_b
- cur_a
,
6001 org_b
- org_a
) + ( cur_a
- cur_x
);
6003 CUR_Func_move( &CUR
.zp2
, point
, distance
);
6010 CUR
.new_top
= CUR
.args
;
6014 /*************************************************************************/
6016 /* UTP[a]: UnTouch Point */
6017 /* Opcode range: 0x29 */
6018 /* Stack: uint32 --> */
6021 void Ins_UTP( INS_ARG
)
6027 point
= (FT_UShort
)args
[0];
6029 if ( BOUNDS( point
, CUR
.zp0
.n_points
) )
6031 if ( CUR
.pedantic_hinting
)
6032 CUR
.error
= TT_Err_Invalid_Reference
;
6038 if ( CUR
.GS
.freeVector
.x
!= 0 )
6039 mask
&= ~FT_Curve_Tag_Touch_X
;
6041 if ( CUR
.GS
.freeVector
.y
!= 0 )
6042 mask
&= ~FT_Curve_Tag_Touch_Y
;
6044 CUR
.zp0
.tags
[point
] &= mask
;
6048 /* Local variables for Ins_IUP: */
6051 FT_Vector
* orgs
; /* original and current coordinate */
6052 FT_Vector
* curs
; /* arrays */
6057 void Shift( FT_UInt p1
,
6060 struct LOC_Ins_IUP
* LINK
)
6066 x
= LINK
->curs
[p
].x
- LINK
->orgs
[p
].x
;
6068 for ( i
= p1
; i
< p
; i
++ )
6069 LINK
->curs
[i
].x
+= x
;
6071 for ( i
= p
+ 1; i
<= p2
; i
++ )
6072 LINK
->curs
[i
].x
+= x
;
6077 void Interp( FT_UInt p1
,
6081 struct LOC_Ins_IUP
* LINK
)
6084 FT_F26Dot6 x
, x1
, x2
, d1
, d2
;
6090 x1
= LINK
->orgs
[ref1
].x
;
6091 d1
= LINK
->curs
[ref1
].x
- LINK
->orgs
[ref1
].x
;
6092 x2
= LINK
->orgs
[ref2
].x
;
6093 d2
= LINK
->curs
[ref2
].x
- LINK
->orgs
[ref2
].x
;
6097 for ( i
= p1
; i
<= p2
; i
++ )
6099 x
= LINK
->orgs
[i
].x
;
6106 LINK
->curs
[i
].x
= x
;
6113 for ( i
= p1
; i
<= p2
; i
++ )
6115 x
= LINK
->orgs
[i
].x
;
6124 x
= LINK
->curs
[ref1
].x
+
6126 LINK
->curs
[ref2
].x
- LINK
->curs
[ref1
].x
,
6129 LINK
->curs
[i
].x
= x
;
6136 for ( i
= p1
; i
<= p2
; i
++ )
6138 x
= LINK
->orgs
[i
].x
;
6146 x
= LINK
->curs
[ref1
].x
+
6148 LINK
->curs
[ref2
].x
- LINK
->curs
[ref1
].x
,
6151 LINK
->curs
[i
].x
= x
;
6156 /*************************************************************************/
6158 /* IUP[a]: Interpolate Untouched Points */
6159 /* Opcode range: 0x30-0x31 */
6163 void Ins_IUP( INS_ARG
)
6165 struct LOC_Ins_IUP V
;
6168 FT_UInt first_point
; /* first point of contour */
6169 FT_UInt end_point
; /* end point (last+1) of contour */
6171 FT_UInt first_touched
; /* first touched point in contour */
6172 FT_UInt cur_touched
; /* current touched point in contour */
6174 FT_UInt point
; /* current point */
6175 FT_Short contour
; /* current contour */
6180 if ( CUR
.opcode
& 1 )
6182 mask
= FT_Curve_Tag_Touch_X
;
6183 V
.orgs
= CUR
.pts
.org
;
6184 V
.curs
= CUR
.pts
.cur
;
6188 mask
= FT_Curve_Tag_Touch_Y
;
6189 V
.orgs
= (FT_Vector
*)( (FT_Pos
*)CUR
.pts
.org
+ 1 );
6190 V
.curs
= (FT_Vector
*)( (FT_Pos
*)CUR
.pts
.cur
+ 1 );
6198 end_point
= CUR
.pts
.contours
[contour
];
6199 first_point
= point
;
6201 while ( point
<= end_point
&& (CUR
.pts
.tags
[point
] & mask
) == 0 )
6204 if ( point
<= end_point
)
6206 first_touched
= point
;
6207 cur_touched
= point
;
6211 while ( point
<= end_point
)
6213 if ( ( CUR
.pts
.tags
[point
] & mask
) != 0 )
6216 Interp( cur_touched
+ 1,
6221 cur_touched
= point
;
6227 if ( cur_touched
== first_touched
)
6228 Shift( first_point
, end_point
, cur_touched
, &V
);
6231 Interp( (FT_UShort
)( cur_touched
+ 1 ),
6237 if ( first_touched
> 0 )
6238 Interp( first_point
,
6246 } while ( contour
< CUR
.pts
.n_contours
);
6250 /*************************************************************************/
6252 /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
6253 /* Opcode range: 0x5D,0x71,0x72 */
6254 /* Stack: uint32 (2 * uint32)... --> */
6257 void Ins_DELTAP( INS_ARG
)
6265 nump
= (FT_ULong
)args
[0]; /* some points theoretically may occur more
6266 than once, thus UShort isn't enough */
6268 for ( k
= 1; k
<= nump
; k
++ )
6272 CUR
.error
= TT_Err_Too_Few_Arguments
;
6278 A
= (FT_UShort
)CUR
.stack
[CUR
.args
+ 1];
6279 B
= CUR
.stack
[CUR
.args
];
6281 /* XXX: Because some popular fonts contain some invalid DeltaP */
6282 /* instructions, we simply ignore them when the stacked */
6283 /* point reference is off limit, rather than returning an */
6284 /* error. As a delta instruction doesn't change a glyph */
6285 /* in great ways, this shouldn't be a problem. */
6287 if ( !BOUNDS( A
, CUR
.zp0
.n_points
) )
6289 C
= ( (FT_ULong
)B
& 0xF0 ) >> 4;
6291 switch ( CUR
.opcode
)
6305 C
+= CUR
.GS
.delta_base
;
6307 if ( CURRENT_Ppem() == (FT_Long
)C
)
6309 B
= ( (FT_ULong
)B
& 0xF ) - 8;
6312 B
= B
* 64 / ( 1L << CUR
.GS
.delta_shift
);
6314 CUR_Func_move( &CUR
.zp0
, A
, B
);
6318 if ( CUR
.pedantic_hinting
)
6319 CUR
.error
= TT_Err_Invalid_Reference
;
6322 CUR
.new_top
= CUR
.args
;
6326 /*************************************************************************/
6328 /* DELTACn[]: DELTA exceptions C1, C2, C3 */
6329 /* Opcode range: 0x73,0x74,0x75 */
6330 /* Stack: uint32 (2 * uint32)... --> */
6333 void Ins_DELTAC( INS_ARG
)
6340 nump
= (FT_ULong
)args
[0];
6342 for ( k
= 1; k
<= nump
; k
++ )
6346 CUR
.error
= TT_Err_Too_Few_Arguments
;
6352 A
= (FT_ULong
)CUR
.stack
[CUR
.args
+ 1];
6353 B
= CUR
.stack
[CUR
.args
];
6355 if ( BOUNDS( A
, CUR
.cvtSize
) )
6357 if ( CUR
.pedantic_hinting
)
6359 CUR
.error
= TT_Err_Invalid_Reference
;
6365 C
= ( (FT_ULong
)B
& 0xF0 ) >> 4;
6367 switch ( CUR
.opcode
)
6381 C
+= CUR
.GS
.delta_base
;
6383 if ( CURRENT_Ppem() == (FT_Long
)C
)
6385 B
= ( (FT_ULong
)B
& 0xF ) - 8;
6388 B
= B
* 64 / ( 1L << CUR
.GS
.delta_shift
);
6390 CUR_Func_move_cvt( A
, B
);
6395 CUR
.new_top
= CUR
.args
;
6399 /*************************************************************************/
6401 /* MISC. INSTRUCTIONS */
6403 /*************************************************************************/
6406 /*************************************************************************/
6408 /* GETINFO[]: GET INFOrmation */
6409 /* Opcode range: 0x88 */
6410 /* Stack: uint32 --> uint32 */
6412 /* XXX: According to Apple specs, bits 1 & 2 of the argument ought to be */
6413 /* consulted before rotated/stretched info is returned. */
6415 void Ins_GETINFO( INS_ARG
)
6422 /* We return then Windows 3.1 version number */
6423 /* for the font scaler */
6424 if ( ( args
[0] & 1 ) != 0 )
6427 /* Has the glyph been rotated ? */
6428 if ( CUR
.tt_metrics
.rotated
)
6431 /* Has the glyph been stretched ? */
6432 if ( CUR
.tt_metrics
.stretched
)
6440 void Ins_UNKNOWN( INS_ARG
)
6442 TT_DefRecord
* def
= CUR
.IDefs
;
6443 TT_DefRecord
* limit
= def
+ CUR
.numIDefs
;
6448 for ( ; def
< limit
; def
++ )
6450 if ( def
->opc
== CUR
.opcode
&& def
->active
)
6455 if ( CUR
.callTop
>= CUR
.callSize
)
6457 CUR
.error
= TT_Err_Stack_Overflow
;
6461 call
= CUR
.callStack
+ CUR
.callTop
++;
6463 call
->Caller_Range
= CUR
.curRange
;
6464 call
->Caller_IP
= CUR
.IP
+1;
6465 call
->Cur_Count
= 1;
6466 call
->Cur_Restart
= def
->start
;
6468 INS_Goto_CodeRange( def
->range
, def
->start
);
6470 CUR
.step_ins
= FALSE
;
6475 CUR
.error
= TT_Err_Invalid_Opcode
;
6479 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
6483 TInstruction_Function Instruct_Dispatch
[256] =
6485 /* Opcodes are gathered in groups of 16. */
6486 /* Please keep the spaces as they are. */
6488 /* SVTCA y */ Ins_SVTCA
,
6489 /* SVTCA x */ Ins_SVTCA
,
6490 /* SPvTCA y */ Ins_SPVTCA
,
6491 /* SPvTCA x */ Ins_SPVTCA
,
6492 /* SFvTCA y */ Ins_SFVTCA
,
6493 /* SFvTCA x */ Ins_SFVTCA
,
6494 /* SPvTL // */ Ins_SPVTL
,
6495 /* SPvTL + */ Ins_SPVTL
,
6496 /* SFvTL // */ Ins_SFVTL
,
6497 /* SFvTL + */ Ins_SFVTL
,
6498 /* SPvFS */ Ins_SPVFS
,
6499 /* SFvFS */ Ins_SFVFS
,
6502 /* SFvTPv */ Ins_SFVTPV
,
6503 /* ISECT */ Ins_ISECT
,
6505 /* SRP0 */ Ins_SRP0
,
6506 /* SRP1 */ Ins_SRP1
,
6507 /* SRP2 */ Ins_SRP2
,
6508 /* SZP0 */ Ins_SZP0
,
6509 /* SZP1 */ Ins_SZP1
,
6510 /* SZP2 */ Ins_SZP2
,
6511 /* SZPS */ Ins_SZPS
,
6512 /* SLOOP */ Ins_SLOOP
,
6514 /* RTHG */ Ins_RTHG
,
6516 /* ELSE */ Ins_ELSE
,
6517 /* JMPR */ Ins_JMPR
,
6518 /* SCvTCi */ Ins_SCVTCI
,
6519 /* SSwCi */ Ins_SSWCI
,
6524 /* CLEAR */ Ins_CLEAR
,
6525 /* SWAP */ Ins_SWAP
,
6526 /* DEPTH */ Ins_DEPTH
,
6527 /* CINDEX */ Ins_CINDEX
,
6528 /* MINDEX */ Ins_MINDEX
,
6529 /* AlignPTS */ Ins_ALIGNPTS
,
6530 /* INS_0x28 */ Ins_UNKNOWN
,
6532 /* LOOPCALL */ Ins_LOOPCALL
,
6533 /* CALL */ Ins_CALL
,
6534 /* FDEF */ Ins_FDEF
,
6535 /* ENDF */ Ins_ENDF
,
6536 /* MDAP[0] */ Ins_MDAP
,
6537 /* MDAP[1] */ Ins_MDAP
,
6539 /* IUP[0] */ Ins_IUP
,
6540 /* IUP[1] */ Ins_IUP
,
6541 /* SHP[0] */ Ins_SHP
,
6542 /* SHP[1] */ Ins_SHP
,
6543 /* SHC[0] */ Ins_SHC
,
6544 /* SHC[1] */ Ins_SHC
,
6545 /* SHZ[0] */ Ins_SHZ
,
6546 /* SHZ[1] */ Ins_SHZ
,
6547 /* SHPIX */ Ins_SHPIX
,
6549 /* MSIRP[0] */ Ins_MSIRP
,
6550 /* MSIRP[1] */ Ins_MSIRP
,
6551 /* AlignRP */ Ins_ALIGNRP
,
6552 /* RTDG */ Ins_RTDG
,
6553 /* MIAP[0] */ Ins_MIAP
,
6554 /* MIAP[1] */ Ins_MIAP
,
6556 /* NPushB */ Ins_NPUSHB
,
6557 /* NPushW */ Ins_NPUSHW
,
6560 /* WCvtP */ Ins_WCVTP
,
6561 /* RCvt */ Ins_RCVT
,
6564 /* SCFS */ Ins_SCFS
,
6567 /* MPPEM */ Ins_MPPEM
,
6569 /* FlipON */ Ins_FLIPON
,
6570 /* FlipOFF */ Ins_FLIPOFF
,
6571 /* DEBUG */ Ins_DEBUG
,
6574 /* LTEQ */ Ins_LTEQ
,
6576 /* GTEQ */ Ins_GTEQ
,
6580 /* EVEN */ Ins_EVEN
,
6586 /* DeltaP1 */ Ins_DELTAP
,
6596 /* FLOOR */ Ins_FLOOR
,
6597 /* CEILING */ Ins_CEILING
,
6598 /* ROUND[0] */ Ins_ROUND
,
6599 /* ROUND[1] */ Ins_ROUND
,
6600 /* ROUND[2] */ Ins_ROUND
,
6601 /* ROUND[3] */ Ins_ROUND
,
6602 /* NROUND[0] */ Ins_NROUND
,
6603 /* NROUND[1] */ Ins_NROUND
,
6604 /* NROUND[2] */ Ins_NROUND
,
6605 /* NROUND[3] */ Ins_NROUND
,
6607 /* WCvtF */ Ins_WCVTF
,
6608 /* DeltaP2 */ Ins_DELTAP
,
6609 /* DeltaP3 */ Ins_DELTAP
,
6610 /* DeltaCn[0] */ Ins_DELTAC
,
6611 /* DeltaCn[1] */ Ins_DELTAC
,
6612 /* DeltaCn[2] */ Ins_DELTAC
,
6613 /* SROUND */ Ins_SROUND
,
6614 /* S45Round */ Ins_S45ROUND
,
6615 /* JROT */ Ins_JROT
,
6616 /* JROF */ Ins_JROF
,
6617 /* ROFF */ Ins_ROFF
,
6618 /* INS_0x7B */ Ins_UNKNOWN
,
6619 /* RUTG */ Ins_RUTG
,
6620 /* RDTG */ Ins_RDTG
,
6621 /* SANGW */ Ins_SANGW
,
6624 /* FlipPT */ Ins_FLIPPT
,
6625 /* FlipRgON */ Ins_FLIPRGON
,
6626 /* FlipRgOFF */ Ins_FLIPRGOFF
,
6627 /* INS_0x83 */ Ins_UNKNOWN
,
6628 /* INS_0x84 */ Ins_UNKNOWN
,
6629 /* ScanCTRL */ Ins_SCANCTRL
,
6630 /* SDPVTL[0] */ Ins_SDPVTL
,
6631 /* SDPVTL[1] */ Ins_SDPVTL
,
6632 /* GetINFO */ Ins_GETINFO
,
6633 /* IDEF */ Ins_IDEF
,
6634 /* ROLL */ Ins_ROLL
,
6637 /* ScanTYPE */ Ins_SCANTYPE
,
6638 /* InstCTRL */ Ins_INSTCTRL
,
6639 /* INS_0x8F */ Ins_UNKNOWN
,
6641 /* INS_0x90 */ Ins_UNKNOWN
,
6642 /* INS_0x91 */ Ins_UNKNOWN
,
6643 /* INS_0x92 */ Ins_UNKNOWN
,
6644 /* INS_0x93 */ Ins_UNKNOWN
,
6645 /* INS_0x94 */ Ins_UNKNOWN
,
6646 /* INS_0x95 */ Ins_UNKNOWN
,
6647 /* INS_0x96 */ Ins_UNKNOWN
,
6648 /* INS_0x97 */ Ins_UNKNOWN
,
6649 /* INS_0x98 */ Ins_UNKNOWN
,
6650 /* INS_0x99 */ Ins_UNKNOWN
,
6651 /* INS_0x9A */ Ins_UNKNOWN
,
6652 /* INS_0x9B */ Ins_UNKNOWN
,
6653 /* INS_0x9C */ Ins_UNKNOWN
,
6654 /* INS_0x9D */ Ins_UNKNOWN
,
6655 /* INS_0x9E */ Ins_UNKNOWN
,
6656 /* INS_0x9F */ Ins_UNKNOWN
,
6658 /* INS_0xA0 */ Ins_UNKNOWN
,
6659 /* INS_0xA1 */ Ins_UNKNOWN
,
6660 /* INS_0xA2 */ Ins_UNKNOWN
,
6661 /* INS_0xA3 */ Ins_UNKNOWN
,
6662 /* INS_0xA4 */ Ins_UNKNOWN
,
6663 /* INS_0xA5 */ Ins_UNKNOWN
,
6664 /* INS_0xA6 */ Ins_UNKNOWN
,
6665 /* INS_0xA7 */ Ins_UNKNOWN
,
6666 /* INS_0xA8 */ Ins_UNKNOWN
,
6667 /* INS_0xA9 */ Ins_UNKNOWN
,
6668 /* INS_0xAA */ Ins_UNKNOWN
,
6669 /* INS_0xAB */ Ins_UNKNOWN
,
6670 /* INS_0xAC */ Ins_UNKNOWN
,
6671 /* INS_0xAD */ Ins_UNKNOWN
,
6672 /* INS_0xAE */ Ins_UNKNOWN
,
6673 /* INS_0xAF */ Ins_UNKNOWN
,
6675 /* PushB[0] */ Ins_PUSHB
,
6676 /* PushB[1] */ Ins_PUSHB
,
6677 /* PushB[2] */ Ins_PUSHB
,
6678 /* PushB[3] */ Ins_PUSHB
,
6679 /* PushB[4] */ Ins_PUSHB
,
6680 /* PushB[5] */ Ins_PUSHB
,
6681 /* PushB[6] */ Ins_PUSHB
,
6682 /* PushB[7] */ Ins_PUSHB
,
6683 /* PushW[0] */ Ins_PUSHW
,
6684 /* PushW[1] */ Ins_PUSHW
,
6685 /* PushW[2] */ Ins_PUSHW
,
6686 /* PushW[3] */ Ins_PUSHW
,
6687 /* PushW[4] */ Ins_PUSHW
,
6688 /* PushW[5] */ Ins_PUSHW
,
6689 /* PushW[6] */ Ins_PUSHW
,
6690 /* PushW[7] */ Ins_PUSHW
,
6692 /* MDRP[00] */ Ins_MDRP
,
6693 /* MDRP[01] */ Ins_MDRP
,
6694 /* MDRP[02] */ Ins_MDRP
,
6695 /* MDRP[03] */ Ins_MDRP
,
6696 /* MDRP[04] */ Ins_MDRP
,
6697 /* MDRP[05] */ Ins_MDRP
,
6698 /* MDRP[06] */ Ins_MDRP
,
6699 /* MDRP[07] */ Ins_MDRP
,
6700 /* MDRP[08] */ Ins_MDRP
,
6701 /* MDRP[09] */ Ins_MDRP
,
6702 /* MDRP[10] */ Ins_MDRP
,
6703 /* MDRP[11] */ Ins_MDRP
,
6704 /* MDRP[12] */ Ins_MDRP
,
6705 /* MDRP[13] */ Ins_MDRP
,
6706 /* MDRP[14] */ Ins_MDRP
,
6707 /* MDRP[15] */ Ins_MDRP
,
6709 /* MDRP[16] */ Ins_MDRP
,
6710 /* MDRP[17] */ Ins_MDRP
,
6711 /* MDRP[18] */ Ins_MDRP
,
6712 /* MDRP[19] */ Ins_MDRP
,
6713 /* MDRP[20] */ Ins_MDRP
,
6714 /* MDRP[21] */ Ins_MDRP
,
6715 /* MDRP[22] */ Ins_MDRP
,
6716 /* MDRP[23] */ Ins_MDRP
,
6717 /* MDRP[24] */ Ins_MDRP
,
6718 /* MDRP[25] */ Ins_MDRP
,
6719 /* MDRP[26] */ Ins_MDRP
,
6720 /* MDRP[27] */ Ins_MDRP
,
6721 /* MDRP[28] */ Ins_MDRP
,
6722 /* MDRP[29] */ Ins_MDRP
,
6723 /* MDRP[30] */ Ins_MDRP
,
6724 /* MDRP[31] */ Ins_MDRP
,
6726 /* MIRP[00] */ Ins_MIRP
,
6727 /* MIRP[01] */ Ins_MIRP
,
6728 /* MIRP[02] */ Ins_MIRP
,
6729 /* MIRP[03] */ Ins_MIRP
,
6730 /* MIRP[04] */ Ins_MIRP
,
6731 /* MIRP[05] */ Ins_MIRP
,
6732 /* MIRP[06] */ Ins_MIRP
,
6733 /* MIRP[07] */ Ins_MIRP
,
6734 /* MIRP[08] */ Ins_MIRP
,
6735 /* MIRP[09] */ Ins_MIRP
,
6736 /* MIRP[10] */ Ins_MIRP
,
6737 /* MIRP[11] */ Ins_MIRP
,
6738 /* MIRP[12] */ Ins_MIRP
,
6739 /* MIRP[13] */ Ins_MIRP
,
6740 /* MIRP[14] */ Ins_MIRP
,
6741 /* MIRP[15] */ Ins_MIRP
,
6743 /* MIRP[16] */ Ins_MIRP
,
6744 /* MIRP[17] */ Ins_MIRP
,
6745 /* MIRP[18] */ Ins_MIRP
,
6746 /* MIRP[19] */ Ins_MIRP
,
6747 /* MIRP[20] */ Ins_MIRP
,
6748 /* MIRP[21] */ Ins_MIRP
,
6749 /* MIRP[22] */ Ins_MIRP
,
6750 /* MIRP[23] */ Ins_MIRP
,
6751 /* MIRP[24] */ Ins_MIRP
,
6752 /* MIRP[25] */ Ins_MIRP
,
6753 /* MIRP[26] */ Ins_MIRP
,
6754 /* MIRP[27] */ Ins_MIRP
,
6755 /* MIRP[28] */ Ins_MIRP
,
6756 /* MIRP[29] */ Ins_MIRP
,
6757 /* MIRP[30] */ Ins_MIRP
,
6758 /* MIRP[31] */ Ins_MIRP
6762 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
6765 /*************************************************************************/
6769 /* This function executes a run of opcodes. It will exit in the */
6770 /* following cases: */
6772 /* - Errors (in which case it returns FALSE). */
6774 /* - Reaching the end of the main code range (returns TRUE). */
6775 /* Reaching the end of a code range within a function call is an */
6778 /* - After executing one single opcode, if the flag `Instruction_Trap' */
6779 /* is set to TRUE (returns TRUE). */
6781 /* On exit whith TRUE, test IP < CodeSize to know wether it comes from */
6782 /* an instruction trap or a normal termination. */
6785 /* Note: The documented DEBUG opcode pops a value from the stack. This */
6786 /* behaviour is unsupported; here a DEBUG opcode is always an */
6790 /* THIS IS THE INTERPRETER'S MAIN LOOP. */
6792 /* Instructions appear in the specification's order. */
6794 /*************************************************************************/
6797 /*************************************************************************/
6803 /* Executes one or more instruction in the execution context. This */
6804 /* is the main function of the TrueType opcode interpreter. */
6807 /* exec :: A handle to the target execution context. */
6810 /* FreeType error code. 0 means success. */
6813 /* Only the object manager and debugger should call this function. */
6815 /* This function is publicly exported because it is directly */
6816 /* invoked by the TrueType debugger. */
6818 FT_EXPORT_FUNC( FT_Error
) TT_RunIns( TT_ExecContext exc
)
6820 FT_Long ins_counter
= 0; /* executed instructions counter */
6823 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
6827 /* set CVT functions */
6828 CUR
.tt_metrics
.ratio
= 0;
6829 if ( CUR
.metrics
.x_ppem
!= CUR
.metrics
.y_ppem
)
6831 /* non-square pixels, use the stretched routines */
6832 CUR
.func_read_cvt
= Read_CVT_Stretched
;
6833 CUR
.func_write_cvt
= Write_CVT_Stretched
;
6834 CUR
.func_move_cvt
= Move_CVT_Stretched
;
6838 /* square pixels, use normal routines */
6839 CUR
.func_read_cvt
= Read_CVT
;
6840 CUR
.func_write_cvt
= Write_CVT
;
6841 CUR
.func_move_cvt
= Move_CVT
;
6845 COMPUTE_Round( (FT_Byte
)exc
->GS
.round_state
);
6849 CUR
.opcode
= CUR
.code
[CUR
.IP
];
6851 if ( ( CUR
.length
= opcode_length
[CUR
.opcode
] ) < 0 )
6853 if ( CUR
.IP
+ 1 > CUR
.codeSize
)
6854 goto LErrorCodeOverflow_
;
6856 CUR
.length
= CUR
.code
[CUR
.IP
+ 1] + 2;
6859 if ( CUR
.IP
+ CUR
.length
> CUR
.codeSize
)
6860 goto LErrorCodeOverflow_
;
6862 /* First, let's check for empty stack and overflow */
6863 CUR
.args
= CUR
.top
- ( Pop_Push_Count
[CUR
.opcode
] >> 4 );
6865 /* `args' is the top of the stack once arguments have been popped. */
6866 /* One can also interpret it as the index of the last argument. */
6869 CUR
.error
= TT_Err_Too_Few_Arguments
;
6873 CUR
.new_top
= CUR
.args
+ ( Pop_Push_Count
[CUR
.opcode
] & 15 );
6875 /* `new_top' is the new top of the stack, after the instruction's */
6876 /* execution. `top' will be set to `new_top' after the `switch' */
6878 if ( CUR
.new_top
> CUR
.stackSize
)
6880 CUR
.error
= TT_Err_Stack_Overflow
;
6884 CUR
.step_ins
= TRUE
;
6885 CUR
.error
= TT_Err_Ok
;
6887 #ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
6890 FT_Long
* args
= CUR
.stack
+ CUR
.args
;
6891 FT_Byte opcode
= CUR
.opcode
;
6894 #undef ARRAY_BOUND_ERROR
6895 #define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
6900 case 0x00: /* SVTCA y */
6901 case 0x01: /* SVTCA x */
6902 case 0x02: /* SPvTCA y */
6903 case 0x03: /* SPvTCA x */
6904 case 0x04: /* SFvTCA y */
6905 case 0x05: /* SFvTCA x */
6910 AA
= (FT_Short
)( opcode
& 1 ) << 14;
6911 BB
= AA
^ (FT_Short
)0x4000;
6915 CUR
.GS
.projVector
.x
= AA
;
6916 CUR
.GS
.projVector
.y
= BB
;
6918 CUR
.GS
.dualVector
.x
= AA
;
6919 CUR
.GS
.dualVector
.y
= BB
;
6922 if ( ( opcode
& 2 ) == 0 )
6924 CUR
.GS
.freeVector
.x
= AA
;
6925 CUR
.GS
.freeVector
.y
= BB
;
6932 case 0x06: /* SPvTL // */
6933 case 0x07: /* SPvTL + */
6937 case 0x08: /* SFvTL // */
6938 case 0x09: /* SFvTL + */
6942 case 0x0A: /* SPvFS */
6946 case 0x0B: /* SFvFS */
6950 case 0x0C: /* GPV */
6954 case 0x0D: /* GFV */
6958 case 0x0E: /* SFvTPv */
6962 case 0x0F: /* ISECT */
6963 Ins_ISECT( EXEC_ARG_ args
);
6966 case 0x10: /* SRP0 */
6970 case 0x11: /* SRP1 */
6974 case 0x12: /* SRP2 */
6978 case 0x13: /* SZP0 */
6979 Ins_SZP0( EXEC_ARG_ args
);
6982 case 0x14: /* SZP1 */
6983 Ins_SZP1( EXEC_ARG_ args
);
6986 case 0x15: /* SZP2 */
6987 Ins_SZP2( EXEC_ARG_ args
);
6990 case 0x16: /* SZPS */
6991 Ins_SZPS( EXEC_ARG_ args
);
6994 case 0x17: /* SLOOP */
6998 case 0x18: /* RTG */
7002 case 0x19: /* RTHG */
7006 case 0x1A: /* SMD */
7010 case 0x1B: /* ELSE */
7011 Ins_ELSE( EXEC_ARG_ args
);
7014 case 0x1C: /* JMPR */
7018 case 0x1D: /* SCVTCI */
7022 case 0x1E: /* SSWCI */
7026 case 0x1F: /* SSW */
7030 case 0x20: /* DUP */
7034 case 0x21: /* POP */
7038 case 0x22: /* CLEAR */
7042 case 0x23: /* SWAP */
7046 case 0x24: /* DEPTH */
7050 case 0x25: /* CINDEX */
7054 case 0x26: /* MINDEX */
7055 Ins_MINDEX( EXEC_ARG_ args
);
7058 case 0x27: /* ALIGNPTS */
7059 Ins_ALIGNPTS( EXEC_ARG_ args
);
7062 case 0x28: /* ???? */
7063 Ins_UNKNOWN( EXEC_ARG_ args
);
7066 case 0x29: /* UTP */
7067 Ins_UTP( EXEC_ARG_ args
);
7070 case 0x2A: /* LOOPCALL */
7071 Ins_LOOPCALL( EXEC_ARG_ args
);
7074 case 0x2B: /* CALL */
7075 Ins_CALL( EXEC_ARG_ args
);
7078 case 0x2C: /* FDEF */
7079 Ins_FDEF( EXEC_ARG_ args
);
7082 case 0x2D: /* ENDF */
7083 Ins_ENDF( EXEC_ARG_ args
);
7086 case 0x2E: /* MDAP */
7087 case 0x2F: /* MDAP */
7088 Ins_MDAP( EXEC_ARG_ args
);
7092 case 0x30: /* IUP */
7093 case 0x31: /* IUP */
7094 Ins_IUP( EXEC_ARG_ args
);
7097 case 0x32: /* SHP */
7098 case 0x33: /* SHP */
7099 Ins_SHP( EXEC_ARG_ args
);
7102 case 0x34: /* SHC */
7103 case 0x35: /* SHC */
7104 Ins_SHC( EXEC_ARG_ args
);
7107 case 0x36: /* SHZ */
7108 case 0x37: /* SHZ */
7109 Ins_SHZ( EXEC_ARG_ args
);
7112 case 0x38: /* SHPIX */
7113 Ins_SHPIX( EXEC_ARG_ args
);
7117 Ins_IP( EXEC_ARG_ args
);
7120 case 0x3A: /* MSIRP */
7121 case 0x3B: /* MSIRP */
7122 Ins_MSIRP( EXEC_ARG_ args
);
7125 case 0x3C: /* AlignRP */
7126 Ins_ALIGNRP( EXEC_ARG_ args
);
7129 case 0x3D: /* RTDG */
7133 case 0x3E: /* MIAP */
7134 case 0x3F: /* MIAP */
7135 Ins_MIAP( EXEC_ARG_ args
);
7138 case 0x40: /* NPUSHB */
7139 Ins_NPUSHB( EXEC_ARG_ args
);
7142 case 0x41: /* NPUSHW */
7143 Ins_NPUSHW( EXEC_ARG_ args
);
7151 CUR
.error
= TT_Err_Invalid_Reference
;
7158 case 0x44: /* WCVTP */
7162 case 0x45: /* RCVT */
7168 Ins_GC( EXEC_ARG_ args
);
7171 case 0x48: /* SCFS */
7172 Ins_SCFS( EXEC_ARG_ args
);
7177 Ins_MD( EXEC_ARG_ args
);
7180 case 0x4B: /* MPPEM */
7184 case 0x4C: /* MPS */
7188 case 0x4D: /* FLIPON */
7192 case 0x4E: /* FLIPOFF */
7196 case 0x4F: /* DEBUG */
7204 case 0x51: /* LTEQ */
7212 case 0x53: /* GTEQ */
7220 case 0x55: /* NEQ */
7224 case 0x56: /* ODD */
7228 case 0x57: /* EVEN */
7233 Ins_IF( EXEC_ARG_ args
);
7236 case 0x59: /* EIF */
7240 case 0x5A: /* AND */
7248 case 0x5C: /* NOT */
7252 case 0x5D: /* DELTAP1 */
7253 Ins_DELTAP( EXEC_ARG_ args
);
7256 case 0x5E: /* SDB */
7260 case 0x5F: /* SDS */
7264 case 0x60: /* ADD */
7268 case 0x61: /* SUB */
7272 case 0x62: /* DIV */
7276 case 0x63: /* MUL */
7280 case 0x64: /* ABS */
7284 case 0x65: /* NEG */
7288 case 0x66: /* FLOOR */
7292 case 0x67: /* CEILING */
7296 case 0x68: /* ROUND */
7297 case 0x69: /* ROUND */
7298 case 0x6A: /* ROUND */
7299 case 0x6B: /* ROUND */
7303 case 0x6C: /* NROUND */
7304 case 0x6D: /* NROUND */
7305 case 0x6E: /* NRRUND */
7306 case 0x6F: /* NROUND */
7310 case 0x70: /* WCVTF */
7314 case 0x71: /* DELTAP2 */
7315 case 0x72: /* DELTAP3 */
7316 Ins_DELTAP( EXEC_ARG_ args
);
7319 case 0x73: /* DELTAC0 */
7320 case 0x74: /* DELTAC1 */
7321 case 0x75: /* DELTAC2 */
7322 Ins_DELTAC( EXEC_ARG_ args
);
7325 case 0x76: /* SROUND */
7329 case 0x77: /* S45Round */
7333 case 0x78: /* JROT */
7337 case 0x79: /* JROF */
7341 case 0x7A: /* ROFF */
7345 case 0x7B: /* ???? */
7346 Ins_UNKNOWN( EXEC_ARG_ args
);
7349 case 0x7C: /* RUTG */
7353 case 0x7D: /* RDTG */
7357 case 0x7E: /* SANGW */
7359 /* nothing - obsolete */
7362 case 0x80: /* FLIPPT */
7363 Ins_FLIPPT( EXEC_ARG_ args
);
7366 case 0x81: /* FLIPRGON */
7367 Ins_FLIPRGON( EXEC_ARG_ args
);
7370 case 0x82: /* FLIPRGOFF */
7371 Ins_FLIPRGOFF( EXEC_ARG_ args
);
7374 case 0x83: /* UNKNOWN */
7375 case 0x84: /* UNKNOWN */
7376 Ins_UNKNOWN( EXEC_ARG_ args
);
7379 case 0x85: /* SCANCTRL */
7380 Ins_SCANCTRL( EXEC_ARG_ args
);
7383 case 0x86: /* SDPVTL */
7384 case 0x87: /* SDPVTL */
7385 Ins_SDPVTL( EXEC_ARG_ args
);
7388 case 0x88: /* GETINFO */
7389 Ins_GETINFO( EXEC_ARG_ args
);
7392 case 0x89: /* IDEF */
7393 Ins_IDEF( EXEC_ARG_ args
);
7396 case 0x8A: /* ROLL */
7397 Ins_ROLL( EXEC_ARG_ args
);
7400 case 0x8B: /* MAX */
7404 case 0x8C: /* MIN */
7408 case 0x8D: /* SCANTYPE */
7409 Ins_SCANTYPE( EXEC_ARG_ args
);
7412 case 0x8E: /* INSTCTRL */
7413 Ins_INSTCTRL( EXEC_ARG_ args
);
7417 Ins_UNKNOWN( EXEC_ARG_ args
);
7421 if ( opcode
>= 0xE0 )
7422 Ins_MIRP( EXEC_ARG_ args
);
7423 else if ( opcode
>= 0xC0 )
7424 Ins_MDRP( EXEC_ARG_ args
);
7425 else if ( opcode
>= 0xB8 )
7426 Ins_PUSHW( EXEC_ARG_ args
);
7427 else if ( opcode
>= 0xB0 )
7428 Ins_PUSHB( EXEC_ARG_ args
);
7430 Ins_UNKNOWN( EXEC_ARG_ args
);
7437 Instruct_Dispatch
[CUR
.opcode
]( EXEC_ARG_
&CUR
.stack
[CUR
.args
] );
7439 #endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7441 if ( CUR
.error
!= TT_Err_Ok
)
7443 switch ( CUR
.error
)
7445 case TT_Err_Invalid_Opcode
: /* looking for redefined instructions */
7447 TT_DefRecord
* def
= CUR
.IDefs
;
7448 TT_DefRecord
* limit
= def
+ CUR
.numIDefs
;
7451 for ( ; def
< limit
; def
++ )
7453 if ( def
->active
&& CUR
.opcode
== def
->opc
)
7455 TT_CallRec
* callrec
;
7458 if ( CUR
.callTop
>= CUR
.callSize
)
7460 CUR
.error
= TT_Err_Invalid_Reference
;
7464 callrec
= &CUR
.callStack
[CUR
.callTop
];
7466 callrec
->Caller_Range
= CUR
.curRange
;
7467 callrec
->Caller_IP
= CUR
.IP
+ 1;
7468 callrec
->Cur_Count
= 1;
7469 callrec
->Cur_Restart
= def
->start
;
7471 if ( INS_Goto_CodeRange( def
->range
, def
->start
) == FAILURE
)
7479 CUR
.error
= TT_Err_Invalid_Opcode
;
7483 break; /* Unreachable code warning suppression. */
7484 /* Leave to remind in case a later change the editor */
7485 /* to consider break; */
7497 CUR
.top
= CUR
.new_top
;
7500 CUR
.IP
+= CUR
.length
;
7502 /* increment instruction counter and check if we didn't */
7503 /* run this program for too long (e.g. infinite loops). */
7504 if ( ++ins_counter
> MAX_RUNNABLE_OPCODES
)
7505 return TT_Err_Execution_Too_Long
;
7508 if ( CUR
.IP
>= CUR
.codeSize
)
7510 if ( CUR
.callTop
> 0 )
7512 CUR
.error
= TT_Err_Code_Overflow
;
7518 } while ( !CUR
.instruction_trap
);
7522 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7528 LErrorCodeOverflow_
:
7529 CUR
.error
= TT_Err_Code_Overflow
;
7533 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7541 #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */