1 /***************************************************************************/
5 /* TrueType bytecode interpreter (body). */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 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 /***************************************************************************/
20 #include FT_INTERNAL_DEBUG_H
21 #include FT_INTERNAL_CALC_H
22 #include FT_TRIGONOMETRY_H
30 #ifdef TT_USE_BYTECODE_INTERPRETER
33 #define TT_MULFIX FT_MulFix
34 #define TT_MULDIV FT_MulDiv
35 #define TT_MULDIV_NO_ROUND FT_MulDiv_No_Round
38 /*************************************************************************/
40 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
41 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
42 /* messages during execution. */
45 #define FT_COMPONENT trace_ttinterp
47 /*************************************************************************/
49 /* In order to detect infinite loops in the code, we set up a counter */
50 /* within the run loop. A single stroke of interpretation is now */
51 /* limited to a maximal number of opcodes defined below. */
53 #define MAX_RUNNABLE_OPCODES 1000000L
56 /*************************************************************************/
58 /* There are two kinds of implementations: */
60 /* a. static implementation */
62 /* The current execution context is a static variable, which fields */
63 /* are accessed directly by the interpreter during execution. The */
64 /* context is named `cur'. */
66 /* This version is non-reentrant, of course. */
68 /* b. indirect implementation */
70 /* The current execution context is passed to _each_ function as its */
71 /* first argument, and each field is thus accessed indirectly. */
73 /* This version is fully re-entrant. */
75 /* The idea is that an indirect implementation may be slower to execute */
76 /* on low-end processors that are used in some systems (like 386s or */
79 /* As a consequence, the indirect implementation is now the default, as */
80 /* its performance costs can be considered negligible in our context. */
81 /* Note, however, that we kept the same source with macros because: */
83 /* - The code is kept very close in design to the Pascal code used for */
86 /* - It's much more readable that way! */
88 /* - It's still open to experimentation and tuning. */
90 /*************************************************************************/
93 #ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */
95 #define CUR (*exc) /* see ttobjs.h */
97 /*************************************************************************/
99 /* This macro is used whenever `exec' is unused in a function, to avoid */
100 /* stupid warnings from pedantic compilers. */
102 #define FT_UNUSED_EXEC FT_UNUSED( exc )
104 #else /* static implementation */
108 #define FT_UNUSED_EXEC int __dummy = __dummy
111 TT_ExecContextRec cur
; /* static exec. context variable */
113 /* apparently, we have a _lot_ of direct indexing when accessing */
114 /* the static `cur', which makes the code bigger (due to all the */
115 /* four bytes addresses). */
117 #endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
120 /*************************************************************************/
122 /* The instruction argument stack. */
124 #define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */
127 /*************************************************************************/
129 /* This macro is used whenever `args' is unused in a function, to avoid */
130 /* stupid warnings from pedantic compilers. */
132 #define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args )
135 /*************************************************************************/
137 /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */
138 /* increase readability of the code. */
140 /*************************************************************************/
143 #define SKIP_Code() \
146 #define GET_ShortIns() \
147 GetShortIns( EXEC_ARG )
149 #define NORMalize( x, y, v ) \
150 Normalize( EXEC_ARG_ x, y, v )
152 #define SET_SuperRound( scale, flags ) \
153 SetSuperRound( EXEC_ARG_ scale, flags )
155 #define ROUND_None( d, c ) \
156 Round_None( EXEC_ARG_ d, c )
158 #define INS_Goto_CodeRange( range, ip ) \
159 Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
161 #define CUR_Func_move( z, p, d ) \
162 CUR.func_move( EXEC_ARG_ z, p, d )
164 #define CUR_Func_move_orig( z, p, d ) \
165 CUR.func_move_orig( EXEC_ARG_ z, p, d )
167 #define CUR_Func_round( d, c ) \
168 CUR.func_round( EXEC_ARG_ d, c )
170 #define CUR_Func_read_cvt( index ) \
171 CUR.func_read_cvt( EXEC_ARG_ index )
173 #define CUR_Func_write_cvt( index, val ) \
174 CUR.func_write_cvt( EXEC_ARG_ index, val )
176 #define CUR_Func_move_cvt( index, val ) \
177 CUR.func_move_cvt( EXEC_ARG_ index, val )
179 #define CURRENT_Ratio() \
180 Current_Ratio( EXEC_ARG )
182 #define CURRENT_Ppem() \
183 Current_Ppem( EXEC_ARG )
188 #define INS_SxVTL( a, b, c, d ) \
189 Ins_SxVTL( EXEC_ARG_ a, b, c, d )
191 #define COMPUTE_Funcs() \
192 Compute_Funcs( EXEC_ARG )
194 #define COMPUTE_Round( a ) \
195 Compute_Round( EXEC_ARG_ a )
197 #define COMPUTE_Point_Displacement( a, b, c, d ) \
198 Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
200 #define MOVE_Zp2_Point( a, b, c, t ) \
201 Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
204 #define CUR_Func_project( v1, v2 ) \
205 CUR.func_project( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
207 #define CUR_Func_dualproj( v1, v2 ) \
208 CUR.func_dualproj( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
210 #define CUR_fast_project( v ) \
211 CUR.func_project( EXEC_ARG_ (v)->x, (v)->y )
213 #define CUR_fast_dualproj( v ) \
214 CUR.func_dualproj( EXEC_ARG_ (v)->x, (v)->y )
217 /*************************************************************************/
219 /* Instruction dispatch function, as used by the interpreter. */
221 typedef void (*TInstruction_Function
)( INS_ARG
);
224 /*************************************************************************/
226 /* A simple bounds-checking macro. */
228 #define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
236 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
237 #define GUESS_VECTOR( V ) \
238 if ( CUR.face->unpatented_hinting ) \
240 CUR.GS.V.x = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0x4000 : 0 ); \
241 CUR.GS.V.y = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0 : 0x4000 ); \
244 #define GUESS_VECTOR( V )
247 /*************************************************************************/
249 /* CODERANGE FUNCTIONS */
251 /*************************************************************************/
254 /*************************************************************************/
257 /* TT_Goto_CodeRange */
260 /* Switches to a new code range (updates the code related elements in */
261 /* `exec', and `IP'). */
264 /* range :: The new execution code range. */
266 /* IP :: The new IP in the new code range. */
269 /* exec :: The target execution context. */
272 /* FreeType error code. 0 means success. */
274 FT_LOCAL_DEF( FT_Error
)
275 TT_Goto_CodeRange( TT_ExecContext exec
,
279 TT_CodeRange
* coderange
;
282 FT_ASSERT( range
>= 1 && range
<= 3 );
284 coderange
= &exec
->codeRangeTable
[range
- 1];
286 FT_ASSERT( coderange
->base
!= NULL
);
288 /* NOTE: Because the last instruction of a program may be a CALL */
289 /* which will return to the first byte *after* the code */
290 /* range, we test for IP <= Size instead of IP < Size. */
292 FT_ASSERT( (FT_ULong
)IP
<= coderange
->size
);
294 exec
->code
= coderange
->base
;
295 exec
->codeSize
= coderange
->size
;
297 exec
->curRange
= range
;
303 /*************************************************************************/
306 /* TT_Set_CodeRange */
309 /* Sets a code range. */
312 /* range :: The code range index. */
314 /* base :: The new code base. */
316 /* length :: The range size in bytes. */
319 /* exec :: The target execution context. */
322 /* FreeType error code. 0 means success. */
324 FT_LOCAL_DEF( FT_Error
)
325 TT_Set_CodeRange( TT_ExecContext exec
,
330 FT_ASSERT( range
>= 1 && range
<= 3 );
332 exec
->codeRangeTable
[range
- 1].base
= (FT_Byte
*)base
;
333 exec
->codeRangeTable
[range
- 1].size
= length
;
339 /*************************************************************************/
342 /* TT_Clear_CodeRange */
345 /* Clears a code range. */
348 /* range :: The code range index. */
351 /* exec :: The target execution context. */
354 /* FreeType error code. 0 means success. */
357 /* Does not set the Error variable. */
359 FT_LOCAL_DEF( FT_Error
)
360 TT_Clear_CodeRange( TT_ExecContext exec
,
363 FT_ASSERT( range
>= 1 && range
<= 3 );
365 exec
->codeRangeTable
[range
- 1].base
= NULL
;
366 exec
->codeRangeTable
[range
- 1].size
= 0;
372 /*************************************************************************/
374 /* EXECUTION CONTEXT ROUTINES */
376 /*************************************************************************/
379 /*************************************************************************/
382 /* TT_Done_Context */
385 /* Destroys a given context. */
388 /* exec :: A handle to the target execution context. */
390 /* memory :: A handle to the parent memory object. */
393 /* FreeType error code. 0 means success. */
396 /* Only the glyph loader and debugger should call this function. */
398 FT_LOCAL_DEF( FT_Error
)
399 TT_Done_Context( TT_ExecContext exec
)
401 FT_Memory memory
= exec
->memory
;
406 exec
->maxContours
= 0;
409 FT_FREE( exec
->stack
);
412 /* free call stack */
413 FT_FREE( exec
->callStack
);
417 /* free glyph code range */
418 FT_FREE( exec
->glyphIns
);
430 /*************************************************************************/
436 /* Initializes a context object. */
439 /* memory :: A handle to the parent memory object. */
442 /* exec :: A handle to the target execution context. */
445 /* FreeType error code. 0 means success. */
448 Init_Context( TT_ExecContext exec
,
454 FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec
));
456 exec
->memory
= memory
;
459 if ( FT_NEW_ARRAY( exec
->callStack
, exec
->callSize
) )
462 /* all values in the context are set to 0 already, but this is */
463 /* here as a remainder */
465 exec
->maxContours
= 0;
471 exec
->glyphIns
= NULL
;
479 FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n",
481 TT_Done_Context( exec
);
487 /*************************************************************************/
493 /* Checks the size of a buffer and reallocates it if necessary. */
496 /* memory :: A handle to the parent memory object. */
498 /* multiplier :: The size in bytes of each element in the buffer. */
500 /* new_max :: The new capacity (size) of the buffer. */
503 /* size :: The address of the buffer's current size expressed */
506 /* buff :: The address of the buffer base pointer. */
509 /* FreeType error code. 0 means success. */
512 Update_Max( FT_Memory memory
,
519 void** pbuff
= (void**)_pbuff
;
522 if ( *size
< new_max
)
524 if ( FT_REALLOC( *pbuff
, *size
* multiplier
, new_max
* multiplier
) )
533 /*************************************************************************/
536 /* TT_Load_Context */
539 /* Prepare an execution context for glyph hinting. */
542 /* face :: A handle to the source face object. */
544 /* size :: A handle to the source size object. */
547 /* exec :: A handle to the target execution context. */
550 /* FreeType error code. 0 means success. */
553 /* Only the glyph loader and debugger should call this function. */
555 FT_LOCAL_DEF( FT_Error
)
556 TT_Load_Context( TT_ExecContext exec
,
567 maxp
= &face
->max_profile
;
572 exec
->numFDefs
= size
->num_function_defs
;
573 exec
->maxFDefs
= size
->max_function_defs
;
574 exec
->numIDefs
= size
->num_instruction_defs
;
575 exec
->maxIDefs
= size
->max_instruction_defs
;
576 exec
->FDefs
= size
->function_defs
;
577 exec
->IDefs
= size
->instruction_defs
;
578 exec
->tt_metrics
= size
->ttmetrics
;
579 exec
->metrics
= size
->metrics
;
581 exec
->maxFunc
= size
->max_func
;
582 exec
->maxIns
= size
->max_ins
;
584 for ( i
= 0; i
< TT_MAX_CODE_RANGES
; i
++ )
585 exec
->codeRangeTable
[i
] = size
->codeRangeTable
[i
];
587 /* set graphics state */
590 exec
->cvtSize
= size
->cvt_size
;
591 exec
->cvt
= size
->cvt
;
593 exec
->storeSize
= size
->storage_size
;
594 exec
->storage
= size
->storage
;
596 exec
->twilight
= size
->twilight
;
599 /* XXX: We reserve a little more elements on the stack to deal safely */
600 /* with broken fonts like arialbs, courbs, timesbs, etc. */
601 tmp
= exec
->stackSize
;
602 error
= Update_Max( exec
->memory
,
604 sizeof ( FT_F26Dot6
),
606 maxp
->maxStackElements
+ 32 );
607 exec
->stackSize
= (FT_UInt
)tmp
;
611 tmp
= exec
->glyphSize
;
612 error
= Update_Max( exec
->memory
,
615 (void*)&exec
->glyphIns
,
616 maxp
->maxSizeOfInstructions
);
617 exec
->glyphSize
= (FT_UShort
)tmp
;
621 exec
->pts
.n_points
= 0;
622 exec
->pts
.n_contours
= 0;
624 exec
->zp1
= exec
->pts
;
625 exec
->zp2
= exec
->pts
;
626 exec
->zp0
= exec
->pts
;
628 exec
->instruction_trap
= FALSE
;
634 /*************************************************************************/
637 /* TT_Save_Context */
640 /* Saves the code ranges in a `size' object. */
643 /* exec :: A handle to the source execution context. */
646 /* size :: A handle to the target size object. */
649 /* FreeType error code. 0 means success. */
652 /* Only the glyph loader and debugger should call this function. */
654 FT_LOCAL_DEF( FT_Error
)
655 TT_Save_Context( TT_ExecContext exec
,
661 /* XXXX: Will probably disappear soon with all the code range */
662 /* management, which is now rather obsolete. */
664 size
->num_function_defs
= exec
->numFDefs
;
665 size
->num_instruction_defs
= exec
->numIDefs
;
667 size
->max_func
= exec
->maxFunc
;
668 size
->max_ins
= exec
->maxIns
;
670 for ( i
= 0; i
< TT_MAX_CODE_RANGES
; i
++ )
671 size
->codeRangeTable
[i
] = exec
->codeRangeTable
[i
];
677 /*************************************************************************/
683 /* Executes one or more instructions in the execution context. */
686 /* debug :: A Boolean flag. If set, the function sets some internal */
687 /* variables and returns immediately, otherwise TT_RunIns() */
690 /* This is commented out currently. */
693 /* exec :: A handle to the target execution context. */
696 /* TrueType error code. 0 means success. */
699 /* Only the glyph loader and debugger should call this function. */
701 FT_LOCAL_DEF( FT_Error
)
702 TT_Run_Context( TT_ExecContext exec
,
708 if ( ( error
= TT_Goto_CodeRange( exec
, tt_coderange_glyph
, 0 ) )
712 exec
->zp0
= exec
->pts
;
713 exec
->zp1
= exec
->pts
;
714 exec
->zp2
= exec
->pts
;
720 exec
->GS
.projVector
.x
= 0x4000;
721 exec
->GS
.projVector
.y
= 0x0000;
723 exec
->GS
.freeVector
= exec
->GS
.projVector
;
724 exec
->GS
.dualVector
= exec
->GS
.projVector
;
726 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
727 exec
->GS
.both_x_axis
= TRUE
;
730 exec
->GS
.round_state
= 1;
733 /* some glyphs leave something on the stack. so we clean it */
734 /* before a new execution. */
741 return exec
->face
->interpreter( exec
);
744 return TT_RunIns( exec
);
751 const TT_GraphicsState tt_default_graphics_state
=
758 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
763 TRUE
, 68, 0, 0, 9, 3,
768 /* documentation is in ttinterp.h */
770 FT_EXPORT_DEF( TT_ExecContext
)
771 TT_New_Context( TT_Driver driver
)
777 memory
= driver
->root
.root
.memory
;
778 exec
= driver
->context
;
780 if ( !driver
->context
)
785 /* allocate object */
786 if ( FT_NEW( exec
) )
790 error
= Init_Context( exec
, memory
);
794 /* store it into the driver */
795 driver
->context
= exec
;
799 return driver
->context
;
808 /*************************************************************************/
810 /* Before an opcode is executed, the interpreter verifies that there are */
811 /* enough arguments on the stack, with the help of the `Pop_Push_Count' */
814 /* For each opcode, the first column gives the number of arguments that */
815 /* are popped from the stack; the second one gives the number of those */
816 /* that are pushed in result. */
818 /* Opcodes which have a varying number of parameters in the data stream */
819 /* (NPUSHB, NPUSHW) are handled specially; they have a negative value in */
820 /* the `opcode_length' table, and the value in `Pop_Push_Count' is set */
823 /*************************************************************************/
827 #define PACK( x, y ) ( ( x << 4 ) | y )
831 const FT_Byte Pop_Push_Count
[256] =
833 /* opcodes are gathered in groups of 16 */
834 /* please keep the spaces as they are */
836 /* SVTCA y */ PACK( 0, 0 ),
837 /* SVTCA x */ PACK( 0, 0 ),
838 /* SPvTCA y */ PACK( 0, 0 ),
839 /* SPvTCA x */ PACK( 0, 0 ),
840 /* SFvTCA y */ PACK( 0, 0 ),
841 /* SFvTCA x */ PACK( 0, 0 ),
842 /* SPvTL // */ PACK( 2, 0 ),
843 /* SPvTL + */ PACK( 2, 0 ),
844 /* SFvTL // */ PACK( 2, 0 ),
845 /* SFvTL + */ PACK( 2, 0 ),
846 /* SPvFS */ PACK( 2, 0 ),
847 /* SFvFS */ PACK( 2, 0 ),
848 /* GPV */ PACK( 0, 2 ),
849 /* GFV */ PACK( 0, 2 ),
850 /* SFvTPv */ PACK( 0, 0 ),
851 /* ISECT */ PACK( 5, 0 ),
853 /* SRP0 */ PACK( 1, 0 ),
854 /* SRP1 */ PACK( 1, 0 ),
855 /* SRP2 */ PACK( 1, 0 ),
856 /* SZP0 */ PACK( 1, 0 ),
857 /* SZP1 */ PACK( 1, 0 ),
858 /* SZP2 */ PACK( 1, 0 ),
859 /* SZPS */ PACK( 1, 0 ),
860 /* SLOOP */ PACK( 1, 0 ),
861 /* RTG */ PACK( 0, 0 ),
862 /* RTHG */ PACK( 0, 0 ),
863 /* SMD */ PACK( 1, 0 ),
864 /* ELSE */ PACK( 0, 0 ),
865 /* JMPR */ PACK( 1, 0 ),
866 /* SCvTCi */ PACK( 1, 0 ),
867 /* SSwCi */ PACK( 1, 0 ),
868 /* SSW */ PACK( 1, 0 ),
870 /* DUP */ PACK( 1, 2 ),
871 /* POP */ PACK( 1, 0 ),
872 /* CLEAR */ PACK( 0, 0 ),
873 /* SWAP */ PACK( 2, 2 ),
874 /* DEPTH */ PACK( 0, 1 ),
875 /* CINDEX */ PACK( 1, 1 ),
876 /* MINDEX */ PACK( 1, 0 ),
877 /* AlignPTS */ PACK( 2, 0 ),
878 /* INS_$28 */ PACK( 0, 0 ),
879 /* UTP */ PACK( 1, 0 ),
880 /* LOOPCALL */ PACK( 2, 0 ),
881 /* CALL */ PACK( 1, 0 ),
882 /* FDEF */ PACK( 1, 0 ),
883 /* ENDF */ PACK( 0, 0 ),
884 /* MDAP[0] */ PACK( 1, 0 ),
885 /* MDAP[1] */ PACK( 1, 0 ),
887 /* IUP[0] */ PACK( 0, 0 ),
888 /* IUP[1] */ PACK( 0, 0 ),
889 /* SHP[0] */ PACK( 0, 0 ),
890 /* SHP[1] */ PACK( 0, 0 ),
891 /* SHC[0] */ PACK( 1, 0 ),
892 /* SHC[1] */ PACK( 1, 0 ),
893 /* SHZ[0] */ PACK( 1, 0 ),
894 /* SHZ[1] */ PACK( 1, 0 ),
895 /* SHPIX */ PACK( 1, 0 ),
896 /* IP */ PACK( 0, 0 ),
897 /* MSIRP[0] */ PACK( 2, 0 ),
898 /* MSIRP[1] */ PACK( 2, 0 ),
899 /* AlignRP */ PACK( 0, 0 ),
900 /* RTDG */ PACK( 0, 0 ),
901 /* MIAP[0] */ PACK( 2, 0 ),
902 /* MIAP[1] */ PACK( 2, 0 ),
904 /* NPushB */ PACK( 0, 0 ),
905 /* NPushW */ PACK( 0, 0 ),
906 /* WS */ PACK( 2, 0 ),
907 /* RS */ PACK( 1, 1 ),
908 /* WCvtP */ PACK( 2, 0 ),
909 /* RCvt */ PACK( 1, 1 ),
910 /* GC[0] */ PACK( 1, 1 ),
911 /* GC[1] */ PACK( 1, 1 ),
912 /* SCFS */ PACK( 2, 0 ),
913 /* MD[0] */ PACK( 2, 1 ),
914 /* MD[1] */ PACK( 2, 1 ),
915 /* MPPEM */ PACK( 0, 1 ),
916 /* MPS */ PACK( 0, 1 ),
917 /* FlipON */ PACK( 0, 0 ),
918 /* FlipOFF */ PACK( 0, 0 ),
919 /* DEBUG */ PACK( 1, 0 ),
921 /* LT */ PACK( 2, 1 ),
922 /* LTEQ */ PACK( 2, 1 ),
923 /* GT */ PACK( 2, 1 ),
924 /* GTEQ */ PACK( 2, 1 ),
925 /* EQ */ PACK( 2, 1 ),
926 /* NEQ */ PACK( 2, 1 ),
927 /* ODD */ PACK( 1, 1 ),
928 /* EVEN */ PACK( 1, 1 ),
929 /* IF */ PACK( 1, 0 ),
930 /* EIF */ PACK( 0, 0 ),
931 /* AND */ PACK( 2, 1 ),
932 /* OR */ PACK( 2, 1 ),
933 /* NOT */ PACK( 1, 1 ),
934 /* DeltaP1 */ PACK( 1, 0 ),
935 /* SDB */ PACK( 1, 0 ),
936 /* SDS */ PACK( 1, 0 ),
938 /* ADD */ PACK( 2, 1 ),
939 /* SUB */ PACK( 2, 1 ),
940 /* DIV */ PACK( 2, 1 ),
941 /* MUL */ PACK( 2, 1 ),
942 /* ABS */ PACK( 1, 1 ),
943 /* NEG */ PACK( 1, 1 ),
944 /* FLOOR */ PACK( 1, 1 ),
945 /* CEILING */ PACK( 1, 1 ),
946 /* ROUND[0] */ PACK( 1, 1 ),
947 /* ROUND[1] */ PACK( 1, 1 ),
948 /* ROUND[2] */ PACK( 1, 1 ),
949 /* ROUND[3] */ PACK( 1, 1 ),
950 /* NROUND[0] */ PACK( 1, 1 ),
951 /* NROUND[1] */ PACK( 1, 1 ),
952 /* NROUND[2] */ PACK( 1, 1 ),
953 /* NROUND[3] */ PACK( 1, 1 ),
955 /* WCvtF */ PACK( 2, 0 ),
956 /* DeltaP2 */ PACK( 1, 0 ),
957 /* DeltaP3 */ PACK( 1, 0 ),
958 /* DeltaCn[0] */ PACK( 1, 0 ),
959 /* DeltaCn[1] */ PACK( 1, 0 ),
960 /* DeltaCn[2] */ PACK( 1, 0 ),
961 /* SROUND */ PACK( 1, 0 ),
962 /* S45Round */ PACK( 1, 0 ),
963 /* JROT */ PACK( 2, 0 ),
964 /* JROF */ PACK( 2, 0 ),
965 /* ROFF */ PACK( 0, 0 ),
966 /* INS_$7B */ PACK( 0, 0 ),
967 /* RUTG */ PACK( 0, 0 ),
968 /* RDTG */ PACK( 0, 0 ),
969 /* SANGW */ PACK( 1, 0 ),
970 /* AA */ PACK( 1, 0 ),
972 /* FlipPT */ PACK( 0, 0 ),
973 /* FlipRgON */ PACK( 2, 0 ),
974 /* FlipRgOFF */ PACK( 2, 0 ),
975 /* INS_$83 */ PACK( 0, 0 ),
976 /* INS_$84 */ PACK( 0, 0 ),
977 /* ScanCTRL */ PACK( 1, 0 ),
978 /* SDVPTL[0] */ PACK( 2, 0 ),
979 /* SDVPTL[1] */ PACK( 2, 0 ),
980 /* GetINFO */ PACK( 1, 1 ),
981 /* IDEF */ PACK( 1, 0 ),
982 /* ROLL */ PACK( 3, 3 ),
983 /* MAX */ PACK( 2, 1 ),
984 /* MIN */ PACK( 2, 1 ),
985 /* ScanTYPE */ PACK( 1, 0 ),
986 /* InstCTRL */ PACK( 2, 0 ),
987 /* INS_$8F */ PACK( 0, 0 ),
989 /* INS_$90 */ PACK( 0, 0 ),
990 /* INS_$91 */ PACK( 0, 0 ),
991 /* INS_$92 */ PACK( 0, 0 ),
992 /* INS_$93 */ PACK( 0, 0 ),
993 /* INS_$94 */ PACK( 0, 0 ),
994 /* INS_$95 */ PACK( 0, 0 ),
995 /* INS_$96 */ PACK( 0, 0 ),
996 /* INS_$97 */ PACK( 0, 0 ),
997 /* INS_$98 */ PACK( 0, 0 ),
998 /* INS_$99 */ PACK( 0, 0 ),
999 /* INS_$9A */ PACK( 0, 0 ),
1000 /* INS_$9B */ PACK( 0, 0 ),
1001 /* INS_$9C */ PACK( 0, 0 ),
1002 /* INS_$9D */ PACK( 0, 0 ),
1003 /* INS_$9E */ PACK( 0, 0 ),
1004 /* INS_$9F */ PACK( 0, 0 ),
1006 /* INS_$A0 */ PACK( 0, 0 ),
1007 /* INS_$A1 */ PACK( 0, 0 ),
1008 /* INS_$A2 */ PACK( 0, 0 ),
1009 /* INS_$A3 */ PACK( 0, 0 ),
1010 /* INS_$A4 */ PACK( 0, 0 ),
1011 /* INS_$A5 */ PACK( 0, 0 ),
1012 /* INS_$A6 */ PACK( 0, 0 ),
1013 /* INS_$A7 */ PACK( 0, 0 ),
1014 /* INS_$A8 */ PACK( 0, 0 ),
1015 /* INS_$A9 */ PACK( 0, 0 ),
1016 /* INS_$AA */ PACK( 0, 0 ),
1017 /* INS_$AB */ PACK( 0, 0 ),
1018 /* INS_$AC */ PACK( 0, 0 ),
1019 /* INS_$AD */ PACK( 0, 0 ),
1020 /* INS_$AE */ PACK( 0, 0 ),
1021 /* INS_$AF */ PACK( 0, 0 ),
1023 /* PushB[0] */ PACK( 0, 1 ),
1024 /* PushB[1] */ PACK( 0, 2 ),
1025 /* PushB[2] */ PACK( 0, 3 ),
1026 /* PushB[3] */ PACK( 0, 4 ),
1027 /* PushB[4] */ PACK( 0, 5 ),
1028 /* PushB[5] */ PACK( 0, 6 ),
1029 /* PushB[6] */ PACK( 0, 7 ),
1030 /* PushB[7] */ PACK( 0, 8 ),
1031 /* PushW[0] */ PACK( 0, 1 ),
1032 /* PushW[1] */ PACK( 0, 2 ),
1033 /* PushW[2] */ PACK( 0, 3 ),
1034 /* PushW[3] */ PACK( 0, 4 ),
1035 /* PushW[4] */ PACK( 0, 5 ),
1036 /* PushW[5] */ PACK( 0, 6 ),
1037 /* PushW[6] */ PACK( 0, 7 ),
1038 /* PushW[7] */ PACK( 0, 8 ),
1040 /* MDRP[00] */ PACK( 1, 0 ),
1041 /* MDRP[01] */ PACK( 1, 0 ),
1042 /* MDRP[02] */ PACK( 1, 0 ),
1043 /* MDRP[03] */ PACK( 1, 0 ),
1044 /* MDRP[04] */ PACK( 1, 0 ),
1045 /* MDRP[05] */ PACK( 1, 0 ),
1046 /* MDRP[06] */ PACK( 1, 0 ),
1047 /* MDRP[07] */ PACK( 1, 0 ),
1048 /* MDRP[08] */ PACK( 1, 0 ),
1049 /* MDRP[09] */ PACK( 1, 0 ),
1050 /* MDRP[10] */ PACK( 1, 0 ),
1051 /* MDRP[11] */ PACK( 1, 0 ),
1052 /* MDRP[12] */ PACK( 1, 0 ),
1053 /* MDRP[13] */ PACK( 1, 0 ),
1054 /* MDRP[14] */ PACK( 1, 0 ),
1055 /* MDRP[15] */ PACK( 1, 0 ),
1057 /* MDRP[16] */ PACK( 1, 0 ),
1058 /* MDRP[17] */ PACK( 1, 0 ),
1059 /* MDRP[18] */ PACK( 1, 0 ),
1060 /* MDRP[19] */ PACK( 1, 0 ),
1061 /* MDRP[20] */ PACK( 1, 0 ),
1062 /* MDRP[21] */ PACK( 1, 0 ),
1063 /* MDRP[22] */ PACK( 1, 0 ),
1064 /* MDRP[23] */ PACK( 1, 0 ),
1065 /* MDRP[24] */ PACK( 1, 0 ),
1066 /* MDRP[25] */ PACK( 1, 0 ),
1067 /* MDRP[26] */ PACK( 1, 0 ),
1068 /* MDRP[27] */ PACK( 1, 0 ),
1069 /* MDRP[28] */ PACK( 1, 0 ),
1070 /* MDRP[29] */ PACK( 1, 0 ),
1071 /* MDRP[30] */ PACK( 1, 0 ),
1072 /* MDRP[31] */ PACK( 1, 0 ),
1074 /* MIRP[00] */ PACK( 2, 0 ),
1075 /* MIRP[01] */ PACK( 2, 0 ),
1076 /* MIRP[02] */ PACK( 2, 0 ),
1077 /* MIRP[03] */ PACK( 2, 0 ),
1078 /* MIRP[04] */ PACK( 2, 0 ),
1079 /* MIRP[05] */ PACK( 2, 0 ),
1080 /* MIRP[06] */ PACK( 2, 0 ),
1081 /* MIRP[07] */ PACK( 2, 0 ),
1082 /* MIRP[08] */ PACK( 2, 0 ),
1083 /* MIRP[09] */ PACK( 2, 0 ),
1084 /* MIRP[10] */ PACK( 2, 0 ),
1085 /* MIRP[11] */ PACK( 2, 0 ),
1086 /* MIRP[12] */ PACK( 2, 0 ),
1087 /* MIRP[13] */ PACK( 2, 0 ),
1088 /* MIRP[14] */ PACK( 2, 0 ),
1089 /* MIRP[15] */ PACK( 2, 0 ),
1091 /* MIRP[16] */ PACK( 2, 0 ),
1092 /* MIRP[17] */ PACK( 2, 0 ),
1093 /* MIRP[18] */ PACK( 2, 0 ),
1094 /* MIRP[19] */ PACK( 2, 0 ),
1095 /* MIRP[20] */ PACK( 2, 0 ),
1096 /* MIRP[21] */ PACK( 2, 0 ),
1097 /* MIRP[22] */ PACK( 2, 0 ),
1098 /* MIRP[23] */ PACK( 2, 0 ),
1099 /* MIRP[24] */ PACK( 2, 0 ),
1100 /* MIRP[25] */ PACK( 2, 0 ),
1101 /* MIRP[26] */ PACK( 2, 0 ),
1102 /* MIRP[27] */ PACK( 2, 0 ),
1103 /* MIRP[28] */ PACK( 2, 0 ),
1104 /* MIRP[29] */ PACK( 2, 0 ),
1105 /* MIRP[30] */ PACK( 2, 0 ),
1106 /* MIRP[31] */ PACK( 2, 0 )
1111 const FT_Char opcode_length
[256] =
1113 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1114 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1115 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1116 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1118 -1,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1119 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1120 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1121 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1123 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1124 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1125 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1126 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
1128 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1129 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1130 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1131 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1139 TT_MulFix14( FT_Int32 a
,
1143 FT_UInt32 ah
, al
, mid
, lo
, hi
;
1153 ah
= (FT_UInt32
)( ( a
>> 16 ) & 0xFFFFU
);
1154 al
= (FT_UInt32
)( a
& 0xFFFFU
);
1159 mid
= ( mid
<< 16 ) + ( 1 << 13 ); /* rounding */
1164 mid
= ( lo
>> 14 ) | ( hi
<< 18 );
1166 return sign
>= 0 ? (FT_Int32
)mid
: -(FT_Int32
)mid
;
1171 /* compute (a*b)/2^14 with maximal accuracy and rounding */
1173 TT_MulFix14( FT_Int32 a
,
1180 /* compute ax*bx as 64-bit value */
1181 l
= (FT_UInt32
)( ( a
& 0xFFFFU
) * b
);
1182 m
= ( a
>> 16 ) * b
;
1184 lo
= l
+ (FT_UInt32
)( m
<< 16 );
1185 hi
= ( m
>> 16 ) + ( (FT_Int32
)l
>> 31 ) + ( lo
< l
);
1187 /* divide the result by 2^14 with rounding */
1189 l
= lo
+ (FT_UInt32
)s
;
1190 hi
+= s
+ ( l
< lo
);
1196 return ( hi
<< 18 ) | ( l
>> 14 );
1201 /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */
1203 TT_DotFix14( FT_Int32 ax
,
1208 FT_Int32 m
, s
, hi1
, hi2
, hi
;
1209 FT_UInt32 l
, lo1
, lo2
, lo
;
1212 /* compute ax*bx as 64-bit value */
1213 l
= (FT_UInt32
)( ( ax
& 0xFFFFU
) * bx
);
1214 m
= ( ax
>> 16 ) * bx
;
1216 lo1
= l
+ (FT_UInt32
)( m
<< 16 );
1217 hi1
= ( m
>> 16 ) + ( (FT_Int32
)l
>> 31 ) + ( lo1
< l
);
1219 /* compute ay*by as 64-bit value */
1220 l
= (FT_UInt32
)( ( ay
& 0xFFFFU
) * by
);
1221 m
= ( ay
>> 16 ) * by
;
1223 lo2
= l
+ (FT_UInt32
)( m
<< 16 );
1224 hi2
= ( m
>> 16 ) + ( (FT_Int32
)l
>> 31 ) + ( lo2
< l
);
1228 hi
= hi1
+ hi2
+ ( lo
< lo1
);
1230 /* divide the result by 2^14 with rounding */
1232 l
= lo
+ (FT_UInt32
)s
;
1233 hi
+= s
+ ( l
< lo
);
1239 return ( hi
<< 18 ) | ( l
>> 14 );
1243 /* return length of given vector */
1248 TT_VecLen( FT_Int32 x
,
1251 FT_Int32 m
, hi1
, hi2
, hi
;
1252 FT_UInt32 l
, lo1
, lo2
, lo
;
1255 /* compute x*x as 64-bit value */
1256 lo
= (FT_UInt32
)( x
& 0xFFFFU
);
1263 lo1
= l
+ (FT_UInt32
)( m
<< 17 );
1264 hi1
= hi
+ ( m
>> 15 ) + ( lo1
< l
);
1266 /* compute y*y as 64-bit value */
1267 lo
= (FT_UInt32
)( y
& 0xFFFFU
);
1274 lo2
= l
+ (FT_UInt32
)( m
<< 17 );
1275 hi2
= hi
+ ( m
>> 15 ) + ( lo2
< l
);
1277 /* add them to get 'x*x+y*y' as 64-bit value */
1279 hi
= hi1
+ hi2
+ ( lo
< lo1
);
1281 /* compute the square root of this value */
1283 FT_UInt32 root
, rem
, test_div
;
1294 rem
= ( rem
<< 2 ) | ( (FT_UInt32
)hi
>> 30 );
1295 hi
= ( hi
<< 2 ) | ( lo
>> 30 );
1298 test_div
= ( root
<< 1 ) + 1;
1300 if ( rem
>= test_div
)
1305 } while ( --count
);
1308 return (FT_Int32
)root
;
1314 /* this version uses FT_Vector_Length which computes the same value */
1315 /* much, much faster.. */
1318 TT_VecLen( FT_F26Dot6 X
,
1327 return FT_Vector_Length( &v
);
1333 /*************************************************************************/
1339 /* Returns the current aspect ratio scaling factor depending on the */
1340 /* projection vector's state and device resolutions. */
1343 /* The aspect ratio in 16.16 format, always <= 1.0 . */
1346 Current_Ratio( EXEC_OP
)
1348 if ( !CUR
.tt_metrics
.ratio
)
1350 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1351 if ( CUR
.face
->unpatented_hinting
)
1353 if ( CUR
.GS
.both_x_axis
)
1354 CUR
.tt_metrics
.ratio
= CUR
.tt_metrics
.x_ratio
;
1356 CUR
.tt_metrics
.ratio
= CUR
.tt_metrics
.y_ratio
;
1361 if ( CUR
.GS
.projVector
.y
== 0 )
1362 CUR
.tt_metrics
.ratio
= CUR
.tt_metrics
.x_ratio
;
1364 else if ( CUR
.GS
.projVector
.x
== 0 )
1365 CUR
.tt_metrics
.ratio
= CUR
.tt_metrics
.y_ratio
;
1372 x
= TT_MULDIV( CUR
.GS
.projVector
.x
,
1373 CUR
.tt_metrics
.x_ratio
, 0x4000 );
1374 y
= TT_MULDIV( CUR
.GS
.projVector
.y
,
1375 CUR
.tt_metrics
.y_ratio
, 0x4000 );
1376 CUR
.tt_metrics
.ratio
= TT_VecLen( x
, y
);
1380 return CUR
.tt_metrics
.ratio
;
1385 Current_Ppem( EXEC_OP
)
1387 return TT_MULFIX( CUR
.tt_metrics
.ppem
, CURRENT_Ratio() );
1391 /*************************************************************************/
1393 /* Functions related to the control value table (CVT). */
1395 /*************************************************************************/
1398 FT_CALLBACK_DEF( FT_F26Dot6
)
1399 Read_CVT( EXEC_OP_ FT_ULong idx
)
1401 return CUR
.cvt
[idx
];
1405 FT_CALLBACK_DEF( FT_F26Dot6
)
1406 Read_CVT_Stretched( EXEC_OP_ FT_ULong idx
)
1408 return TT_MULFIX( CUR
.cvt
[idx
], CURRENT_Ratio() );
1412 FT_CALLBACK_DEF( void )
1413 Write_CVT( EXEC_OP_ FT_ULong idx
,
1416 CUR
.cvt
[idx
] = value
;
1420 FT_CALLBACK_DEF( void )
1421 Write_CVT_Stretched( EXEC_OP_ FT_ULong idx
,
1424 CUR
.cvt
[idx
] = FT_DivFix( value
, CURRENT_Ratio() );
1428 FT_CALLBACK_DEF( void )
1429 Move_CVT( EXEC_OP_ FT_ULong idx
,
1432 CUR
.cvt
[idx
] += value
;
1436 FT_CALLBACK_DEF( void )
1437 Move_CVT_Stretched( EXEC_OP_ FT_ULong idx
,
1440 CUR
.cvt
[idx
] += FT_DivFix( value
, CURRENT_Ratio() );
1444 /*************************************************************************/
1450 /* Returns a short integer taken from the instruction stream at */
1454 /* Short read at code[IP]. */
1457 /* This one could become a macro. */
1460 GetShortIns( EXEC_OP
)
1462 /* Reading a byte stream so there is no endianess (DaveP) */
1464 return (FT_Short
)( ( CUR
.code
[CUR
.IP
- 2] << 8 ) +
1465 CUR
.code
[CUR
.IP
- 1] );
1469 /*************************************************************************/
1472 /* Ins_Goto_CodeRange */
1475 /* Goes to a certain code range in the instruction stream. */
1478 /* aRange :: The index of the code range. */
1480 /* aIP :: The new IP address in the code range. */
1483 /* SUCCESS or FAILURE. */
1486 Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange
,
1489 TT_CodeRange
* range
;
1492 if ( aRange
< 1 || aRange
> 3 )
1494 CUR
.error
= TT_Err_Bad_Argument
;
1498 range
= &CUR
.codeRangeTable
[aRange
- 1];
1500 if ( range
->base
== NULL
) /* invalid coderange */
1502 CUR
.error
= TT_Err_Invalid_CodeRange
;
1506 /* NOTE: Because the last instruction of a program may be a CALL */
1507 /* which will return to the first byte *after* the code */
1508 /* range, we test for AIP <= Size, instead of AIP < Size. */
1510 if ( aIP
> range
->size
)
1512 CUR
.error
= TT_Err_Code_Overflow
;
1516 CUR
.code
= range
->base
;
1517 CUR
.codeSize
= range
->size
;
1519 CUR
.curRange
= aRange
;
1525 /*************************************************************************/
1531 /* Moves a point by a given distance along the freedom vector. The */
1532 /* point will be `touched'. */
1535 /* point :: The index of the point to move. */
1537 /* distance :: The distance to apply. */
1540 /* zone :: The affected glyph zone. */
1543 Direct_Move( EXEC_OP_ TT_GlyphZone zone
,
1545 FT_F26Dot6 distance
)
1550 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1551 FT_ASSERT( !CUR
.face
->unpatented_hinting
);
1554 v
= CUR
.GS
.freeVector
.x
;
1558 zone
->cur
[point
].x
+= TT_MULDIV( distance
,
1562 zone
->tags
[point
] |= FT_CURVE_TAG_TOUCH_X
;
1565 v
= CUR
.GS
.freeVector
.y
;
1569 zone
->cur
[point
].y
+= TT_MULDIV( distance
,
1573 zone
->tags
[point
] |= FT_CURVE_TAG_TOUCH_Y
;
1578 /*************************************************************************/
1581 /* Direct_Move_Orig */
1584 /* Moves the *original* position of a point by a given distance along */
1585 /* the freedom vector. Obviously, the point will not be `touched'. */
1588 /* point :: The index of the point to move. */
1590 /* distance :: The distance to apply. */
1593 /* zone :: The affected glyph zone. */
1596 Direct_Move_Orig( EXEC_OP_ TT_GlyphZone zone
,
1598 FT_F26Dot6 distance
)
1603 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1604 FT_ASSERT( !CUR
.face
->unpatented_hinting
);
1607 v
= CUR
.GS
.freeVector
.x
;
1610 zone
->org
[point
].x
+= TT_MULDIV( distance
,
1614 v
= CUR
.GS
.freeVector
.y
;
1617 zone
->org
[point
].y
+= TT_MULDIV( distance
,
1623 /*************************************************************************/
1625 /* Special versions of Direct_Move() */
1627 /* The following versions are used whenever both vectors are both */
1628 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1630 /*************************************************************************/
1634 Direct_Move_X( EXEC_OP_ TT_GlyphZone zone
,
1636 FT_F26Dot6 distance
)
1640 zone
->cur
[point
].x
+= distance
;
1641 zone
->tags
[point
] |= FT_CURVE_TAG_TOUCH_X
;
1646 Direct_Move_Y( EXEC_OP_ TT_GlyphZone zone
,
1648 FT_F26Dot6 distance
)
1652 zone
->cur
[point
].y
+= distance
;
1653 zone
->tags
[point
] |= FT_CURVE_TAG_TOUCH_Y
;
1657 /*************************************************************************/
1659 /* Special versions of Direct_Move_Orig() */
1661 /* The following versions are used whenever both vectors are both */
1662 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1664 /*************************************************************************/
1668 Direct_Move_Orig_X( EXEC_OP_ TT_GlyphZone zone
,
1670 FT_F26Dot6 distance
)
1674 zone
->org
[point
].x
+= distance
;
1679 Direct_Move_Orig_Y( EXEC_OP_ TT_GlyphZone zone
,
1681 FT_F26Dot6 distance
)
1685 zone
->org
[point
].y
+= distance
;
1689 /*************************************************************************/
1695 /* Does not round, but adds engine compensation. */
1698 /* distance :: The distance (not) to round. */
1700 /* compensation :: The engine compensation. */
1703 /* The compensated distance. */
1706 /* The TrueType specification says very few about the relationship */
1707 /* between rounding and engine compensation. However, it seems from */
1708 /* the description of super round that we should add the compensation */
1709 /* before rounding. */
1712 Round_None( EXEC_OP_ FT_F26Dot6 distance
,
1713 FT_F26Dot6 compensation
)
1720 if ( distance
>= 0 )
1722 val
= distance
+ compensation
;
1723 if ( distance
&& val
< 0 )
1727 val
= distance
- compensation
;
1735 /*************************************************************************/
1741 /* Rounds value to grid after adding engine compensation. */
1744 /* distance :: The distance to round. */
1746 /* compensation :: The engine compensation. */
1749 /* Rounded distance. */
1752 Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1753 FT_F26Dot6 compensation
)
1760 if ( distance
>= 0 )
1762 val
= distance
+ compensation
+ 32;
1763 if ( distance
&& val
> 0 )
1770 val
= -FT_PIX_ROUND( compensation
- distance
);
1779 /*************************************************************************/
1782 /* Round_To_Half_Grid */
1785 /* Rounds value to half grid after adding engine compensation. */
1788 /* distance :: The distance to round. */
1790 /* compensation :: The engine compensation. */
1793 /* Rounded distance. */
1796 Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1797 FT_F26Dot6 compensation
)
1804 if ( distance
>= 0 )
1806 val
= FT_PIX_FLOOR( distance
+ compensation
) + 32;
1807 if ( distance
&& val
< 0 )
1812 val
= -( FT_PIX_FLOOR( compensation
- distance
) + 32 );
1821 /*************************************************************************/
1824 /* Round_Down_To_Grid */
1827 /* Rounds value down to grid after adding engine compensation. */
1830 /* distance :: The distance to round. */
1832 /* compensation :: The engine compensation. */
1835 /* Rounded distance. */
1838 Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1839 FT_F26Dot6 compensation
)
1846 if ( distance
>= 0 )
1848 val
= distance
+ compensation
;
1849 if ( distance
&& val
> 0 )
1856 val
= -( ( compensation
- distance
) & -64 );
1865 /*************************************************************************/
1868 /* Round_Up_To_Grid */
1871 /* Rounds value up to grid after adding engine compensation. */
1874 /* distance :: The distance to round. */
1876 /* compensation :: The engine compensation. */
1879 /* Rounded distance. */
1882 Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1883 FT_F26Dot6 compensation
)
1890 if ( distance
>= 0 )
1892 val
= distance
+ compensation
+ 63;
1893 if ( distance
&& val
> 0 )
1900 val
= - FT_PIX_CEIL( compensation
- distance
);
1909 /*************************************************************************/
1912 /* Round_To_Double_Grid */
1915 /* Rounds value to double grid after adding engine compensation. */
1918 /* distance :: The distance to round. */
1920 /* compensation :: The engine compensation. */
1923 /* Rounded distance. */
1926 Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1927 FT_F26Dot6 compensation
)
1934 if ( distance
>= 0 )
1936 val
= distance
+ compensation
+ 16;
1937 if ( distance
&& val
> 0 )
1944 val
= -FT_PAD_ROUND( compensation
- distance
, 32 );
1953 /*************************************************************************/
1959 /* Super-rounds value to grid after adding engine compensation. */
1962 /* distance :: The distance to round. */
1964 /* compensation :: The engine compensation. */
1967 /* Rounded distance. */
1970 /* The TrueType specification says very few about the relationship */
1971 /* between rounding and engine compensation. However, it seems from */
1972 /* the description of super round that we should add the compensation */
1973 /* before rounding. */
1976 Round_Super( EXEC_OP_ FT_F26Dot6 distance
,
1977 FT_F26Dot6 compensation
)
1982 if ( distance
>= 0 )
1984 val
= ( distance
- CUR
.phase
+ CUR
.threshold
+ compensation
) &
1986 if ( distance
&& val
< 0 )
1992 val
= -( ( CUR
.threshold
- CUR
.phase
- distance
+ compensation
) &
2003 /*************************************************************************/
2006 /* Round_Super_45 */
2009 /* Super-rounds value to grid after adding engine compensation. */
2012 /* distance :: The distance to round. */
2014 /* compensation :: The engine compensation. */
2017 /* Rounded distance. */
2020 /* There is a separate function for Round_Super_45() as we may need */
2021 /* greater precision. */
2024 Round_Super_45( EXEC_OP_ FT_F26Dot6 distance
,
2025 FT_F26Dot6 compensation
)
2030 if ( distance
>= 0 )
2032 val
= ( ( distance
- CUR
.phase
+ CUR
.threshold
+ compensation
) /
2033 CUR
.period
) * CUR
.period
;
2034 if ( distance
&& val
< 0 )
2040 val
= -( ( ( CUR
.threshold
- CUR
.phase
- distance
+ compensation
) /
2041 CUR
.period
) * CUR
.period
);
2051 /*************************************************************************/
2057 /* Sets the rounding mode. */
2060 /* round_mode :: The rounding mode to be used. */
2063 Compute_Round( EXEC_OP_ FT_Byte round_mode
)
2065 switch ( round_mode
)
2068 CUR
.func_round
= (TT_Round_Func
)Round_None
;
2071 case TT_Round_To_Grid
:
2072 CUR
.func_round
= (TT_Round_Func
)Round_To_Grid
;
2075 case TT_Round_Up_To_Grid
:
2076 CUR
.func_round
= (TT_Round_Func
)Round_Up_To_Grid
;
2079 case TT_Round_Down_To_Grid
:
2080 CUR
.func_round
= (TT_Round_Func
)Round_Down_To_Grid
;
2083 case TT_Round_To_Half_Grid
:
2084 CUR
.func_round
= (TT_Round_Func
)Round_To_Half_Grid
;
2087 case TT_Round_To_Double_Grid
:
2088 CUR
.func_round
= (TT_Round_Func
)Round_To_Double_Grid
;
2091 case TT_Round_Super
:
2092 CUR
.func_round
= (TT_Round_Func
)Round_Super
;
2095 case TT_Round_Super_45
:
2096 CUR
.func_round
= (TT_Round_Func
)Round_Super_45
;
2102 /*************************************************************************/
2108 /* Sets Super Round parameters. */
2111 /* GridPeriod :: Grid period */
2112 /* selector :: SROUND opcode */
2115 SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod
,
2118 switch ( (FT_Int
)( selector
& 0xC0 ) )
2121 CUR
.period
= GridPeriod
/ 2;
2125 CUR
.period
= GridPeriod
;
2129 CUR
.period
= GridPeriod
* 2;
2132 /* This opcode is reserved, but... */
2135 CUR
.period
= GridPeriod
;
2139 switch ( (FT_Int
)( selector
& 0x30 ) )
2146 CUR
.phase
= CUR
.period
/ 4;
2150 CUR
.phase
= CUR
.period
/ 2;
2154 CUR
.phase
= CUR
.period
* 3 / 4;
2158 if ( ( selector
& 0x0F ) == 0 )
2159 CUR
.threshold
= CUR
.period
- 1;
2161 CUR
.threshold
= ( (FT_Int
)( selector
& 0x0F ) - 4 ) * CUR
.period
/ 8;
2165 CUR
.threshold
/= 256;
2169 /*************************************************************************/
2175 /* Computes the projection of vector given by (v2-v1) along the */
2176 /* current projection vector. */
2179 /* v1 :: First input vector. */
2180 /* v2 :: Second input vector. */
2183 /* The distance in F26dot6 format. */
2186 Project( EXEC_OP_ FT_Pos dx
,
2189 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2190 FT_ASSERT( !CUR
.face
->unpatented_hinting
);
2193 return TT_DotFix14( dx
, dy
,
2194 CUR
.GS
.projVector
.x
,
2195 CUR
.GS
.projVector
.y
);
2199 /*************************************************************************/
2205 /* Computes the projection of the vector given by (v2-v1) along the */
2206 /* current dual vector. */
2209 /* v1 :: First input vector. */
2210 /* v2 :: Second input vector. */
2213 /* The distance in F26dot6 format. */
2216 Dual_Project( EXEC_OP_ FT_Pos dx
,
2219 return TT_DotFix14( dx
, dy
,
2220 CUR
.GS
.dualVector
.x
,
2221 CUR
.GS
.dualVector
.y
);
2225 /*************************************************************************/
2231 /* Computes the projection of the vector given by (v2-v1) along the */
2232 /* horizontal axis. */
2235 /* v1 :: First input vector. */
2236 /* v2 :: Second input vector. */
2239 /* The distance in F26dot6 format. */
2242 Project_x( EXEC_OP_ FT_Pos dx
,
2252 /*************************************************************************/
2258 /* Computes the projection of the vector given by (v2-v1) along the */
2259 /* vertical axis. */
2262 /* v1 :: First input vector. */
2263 /* v2 :: Second input vector. */
2266 /* The distance in F26dot6 format. */
2269 Project_y( EXEC_OP_ FT_Pos dx
,
2279 /*************************************************************************/
2285 /* Computes the projection and movement function pointers according */
2286 /* to the current graphics state. */
2289 Compute_Funcs( EXEC_OP
)
2291 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2292 if ( CUR
.face
->unpatented_hinting
)
2294 /* If both vectors point rightwards along the x axis, set */
2295 /* `both-x-axis' true, otherwise set it false. The x values only */
2296 /* need be tested because the vector has been normalised to a unit */
2297 /* vector of length 0x4000 = unity. */
2298 CUR
.GS
.both_x_axis
= (FT_Bool
)( CUR
.GS
.projVector
.x
== 0x4000 &&
2299 CUR
.GS
.freeVector
.x
== 0x4000 );
2301 /* Throw away projection and freedom vector information */
2302 /* because the patents don't allow them to be stored. */
2303 /* The relevant US Patents are 5155805 and 5325479. */
2304 CUR
.GS
.projVector
.x
= 0;
2305 CUR
.GS
.projVector
.y
= 0;
2306 CUR
.GS
.freeVector
.x
= 0;
2307 CUR
.GS
.freeVector
.y
= 0;
2309 if ( CUR
.GS
.both_x_axis
)
2311 CUR
.func_project
= Project_x
;
2312 CUR
.func_move
= Direct_Move_X
;
2313 CUR
.func_move_orig
= Direct_Move_Orig_X
;
2317 CUR
.func_project
= Project_y
;
2318 CUR
.func_move
= Direct_Move_Y
;
2319 CUR
.func_move_orig
= Direct_Move_Orig_Y
;
2322 if ( CUR
.GS
.dualVector
.x
== 0x4000 )
2323 CUR
.func_dualproj
= Project_x
;
2326 if ( CUR
.GS
.dualVector
.y
== 0x4000 )
2327 CUR
.func_dualproj
= Project_y
;
2329 CUR
.func_dualproj
= Dual_Project
;
2332 /* Force recalculation of cached aspect ratio */
2333 CUR
.tt_metrics
.ratio
= 0;
2337 #endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING */
2339 if ( CUR
.GS
.freeVector
.x
== 0x4000 )
2340 CUR
.F_dot_P
= CUR
.GS
.projVector
.x
* 0x10000L
;
2343 if ( CUR
.GS
.freeVector
.y
== 0x4000 )
2344 CUR
.F_dot_P
= CUR
.GS
.projVector
.y
* 0x10000L
;
2346 CUR
.F_dot_P
= (FT_Long
)CUR
.GS
.projVector
.x
* CUR
.GS
.freeVector
.x
* 4 +
2347 (FT_Long
)CUR
.GS
.projVector
.y
* CUR
.GS
.freeVector
.y
* 4;
2350 if ( CUR
.GS
.projVector
.x
== 0x4000 )
2351 CUR
.func_project
= (TT_Project_Func
)Project_x
;
2354 if ( CUR
.GS
.projVector
.y
== 0x4000 )
2355 CUR
.func_project
= (TT_Project_Func
)Project_y
;
2357 CUR
.func_project
= (TT_Project_Func
)Project
;
2360 if ( CUR
.GS
.dualVector
.x
== 0x4000 )
2361 CUR
.func_dualproj
= (TT_Project_Func
)Project_x
;
2364 if ( CUR
.GS
.dualVector
.y
== 0x4000 )
2365 CUR
.func_dualproj
= (TT_Project_Func
)Project_y
;
2367 CUR
.func_dualproj
= (TT_Project_Func
)Dual_Project
;
2370 CUR
.func_move
= (TT_Move_Func
)Direct_Move
;
2371 CUR
.func_move_orig
= (TT_Move_Func
)Direct_Move_Orig
;
2373 if ( CUR
.F_dot_P
== 0x40000000L
)
2375 if ( CUR
.GS
.freeVector
.x
== 0x4000 )
2377 CUR
.func_move
= (TT_Move_Func
)Direct_Move_X
;
2378 CUR
.func_move_orig
= (TT_Move_Func
)Direct_Move_Orig_X
;
2382 if ( CUR
.GS
.freeVector
.y
== 0x4000 )
2384 CUR
.func_move
= (TT_Move_Func
)Direct_Move_Y
;
2385 CUR
.func_move_orig
= (TT_Move_Func
)Direct_Move_Orig_Y
;
2390 /* at small sizes, F_dot_P can become too small, resulting */
2391 /* in overflows and `spikes' in a number of glyphs like `w'. */
2393 if ( FT_ABS( CUR
.F_dot_P
) < 0x4000000L
)
2394 CUR
.F_dot_P
= 0x40000000L
;
2396 /* Disable cached aspect ratio */
2397 CUR
.tt_metrics
.ratio
= 0;
2401 /*************************************************************************/
2407 /* Norms a vector. */
2410 /* Vx :: The horizontal input vector coordinate. */
2411 /* Vy :: The vertical input vector coordinate. */
2414 /* R :: The normed unit vector. */
2417 /* Returns FAILURE if a vector parameter is zero. */
2420 /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
2421 /* R is undefined. */
2426 Normalize( EXEC_OP_ FT_F26Dot6 Vx
,
2436 if ( FT_ABS( Vx
) < 0x10000L
&& FT_ABS( Vy
) < 0x10000L
)
2441 W
= TT_VecLen( Vx
, Vy
);
2445 /* XXX: UNDOCUMENTED! It seems that it is possible to try */
2446 /* to normalize the vector (0,0). Return immediately. */
2450 R
->x
= (FT_F2Dot14
)FT_MulDiv( Vx
, 0x4000L
, W
);
2451 R
->y
= (FT_F2Dot14
)FT_MulDiv( Vy
, 0x4000L
, W
);
2456 W
= TT_VecLen( Vx
, Vy
);
2458 Vx
= FT_MulDiv( Vx
, 0x4000L
, W
);
2459 Vy
= FT_MulDiv( Vy
, 0x4000L
, W
);
2461 W
= Vx
* Vx
+ Vy
* Vy
;
2463 /* Now, we want that Sqrt( W ) = 0x4000 */
2464 /* Or 0x10000000 <= W < 0x10004000 */
2482 while ( W
< 0x10000000L
)
2484 /* We need to increase W by a minimal amount */
2490 W
= Vx
* Vx
+ Vy
* Vy
;
2493 while ( W
>= 0x10004000L
)
2495 /* We need to decrease W by a minimal amount */
2501 W
= Vx
* Vx
+ Vy
* Vy
;
2504 /* Note that in various cases, we can only */
2505 /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
2513 R
->x
= (FT_F2Dot14
)Vx
; /* Type conversion */
2514 R
->y
= (FT_F2Dot14
)Vy
; /* Type conversion */
2520 /*************************************************************************/
2522 /* Here we start with the implementation of the various opcodes. */
2524 /*************************************************************************/
2528 Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1
,
2531 FT_UnitVector
* Vec
)
2538 if ( BOUNDS( aIdx1
, CUR
.zp2
.n_points
) ||
2539 BOUNDS( aIdx2
, CUR
.zp1
.n_points
) )
2541 if ( CUR
.pedantic_hinting
)
2542 CUR
.error
= TT_Err_Invalid_Reference
;
2546 p1
= CUR
.zp1
.cur
+ aIdx2
;
2547 p2
= CUR
.zp2
.cur
+ aIdx1
;
2552 if ( ( aOpc
& 1 ) != 0 )
2554 C
= B
; /* counter clockwise rotation */
2559 NORMalize( A
, B
, Vec
);
2565 /* When not using the big switch statements, the interpreter uses a */
2566 /* call table defined later below in this source. Each opcode must */
2567 /* thus have a corresponding function, even trivial ones. */
2569 /* They are all defined there. */
2576 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2577 B = A ^ (FT_Short)0x4000; \
2579 CUR.GS.freeVector.x = A; \
2580 CUR.GS.projVector.x = A; \
2581 CUR.GS.dualVector.x = A; \
2583 CUR.GS.freeVector.y = B; \
2584 CUR.GS.projVector.y = B; \
2585 CUR.GS.dualVector.y = B; \
2596 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2597 B = A ^ (FT_Short)0x4000; \
2599 CUR.GS.projVector.x = A; \
2600 CUR.GS.dualVector.x = A; \
2602 CUR.GS.projVector.y = B; \
2603 CUR.GS.dualVector.y = B; \
2605 GUESS_VECTOR( freeVector ); \
2616 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2617 B = A ^ (FT_Short)0x4000; \
2619 CUR.GS.freeVector.x = A; \
2620 CUR.GS.freeVector.y = B; \
2622 GUESS_VECTOR( projVector ); \
2629 if ( INS_SxVTL( (FT_UShort)args[1], \
2630 (FT_UShort)args[0], \
2632 &CUR.GS.projVector ) == SUCCESS ) \
2634 CUR.GS.dualVector = CUR.GS.projVector; \
2635 GUESS_VECTOR( freeVector ); \
2641 if ( INS_SxVTL( (FT_UShort)args[1], \
2642 (FT_UShort)args[0], \
2644 &CUR.GS.freeVector ) == SUCCESS ) \
2646 GUESS_VECTOR( projVector ); \
2652 GUESS_VECTOR( projVector ); \
2653 CUR.GS.freeVector = CUR.GS.projVector; \
2663 /* Only use low 16bits, then sign extend */ \
2664 S = (FT_Short)args[1]; \
2666 S = (FT_Short)args[0]; \
2669 NORMalize( X, Y, &CUR.GS.projVector ); \
2671 CUR.GS.dualVector = CUR.GS.projVector; \
2672 GUESS_VECTOR( freeVector ); \
2683 /* Only use low 16bits, then sign extend */ \
2684 S = (FT_Short)args[1]; \
2686 S = (FT_Short)args[0]; \
2689 NORMalize( X, Y, &CUR.GS.freeVector ); \
2690 GUESS_VECTOR( projVector ); \
2695 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2697 if ( CUR.face->unpatented_hinting ) \
2699 args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
2700 args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
2704 args[0] = CUR.GS.projVector.x; \
2705 args[1] = CUR.GS.projVector.y; \
2709 args[0] = CUR.GS.projVector.x; \
2710 args[1] = CUR.GS.projVector.y;
2714 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2716 if ( CUR.face->unpatented_hinting ) \
2718 args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
2719 args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
2723 args[0] = CUR.GS.freeVector.x; \
2724 args[1] = CUR.GS.freeVector.y; \
2728 args[0] = CUR.GS.freeVector.x; \
2729 args[1] = CUR.GS.freeVector.y;
2734 CUR.GS.rp0 = (FT_UShort)args[0];
2738 CUR.GS.rp1 = (FT_UShort)args[0];
2742 CUR.GS.rp2 = (FT_UShort)args[0];
2746 CUR.GS.round_state = TT_Round_To_Half_Grid; \
2747 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2751 CUR.GS.round_state = TT_Round_To_Grid; \
2752 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2756 CUR.GS.round_state = TT_Round_To_Double_Grid; \
2757 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2761 CUR.GS.round_state = TT_Round_Up_To_Grid; \
2762 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2766 CUR.GS.round_state = TT_Round_Down_To_Grid; \
2767 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2771 CUR.GS.round_state = TT_Round_Off; \
2772 CUR.func_round = (TT_Round_Func)Round_None;
2776 SET_SuperRound( 0x4000, args[0] ); \
2777 CUR.GS.round_state = TT_Round_Super; \
2778 CUR.func_round = (TT_Round_Func)Round_Super;
2781 #define DO_S45ROUND \
2782 SET_SuperRound( 0x2D41, args[0] ); \
2783 CUR.GS.round_state = TT_Round_Super_45; \
2784 CUR.func_round = (TT_Round_Func)Round_Super_45;
2788 if ( args[0] < 0 ) \
2789 CUR.error = TT_Err_Bad_Argument; \
2791 CUR.GS.loop = args[0];
2795 CUR.GS.minimum_distance = args[0];
2799 CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
2803 CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
2806 /* XXX: UNDOCUMENTED! or bug in the Windows engine? */
2808 /* It seems that the value that is read here is */
2809 /* expressed in 16.16 format rather than in font */
2813 CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
2817 CUR.GS.auto_flip = TRUE;
2820 #define DO_FLIPOFF \
2821 CUR.GS.auto_flip = FALSE;
2825 CUR.GS.delta_base = (FT_Short)args[0];
2829 CUR.GS.delta_shift = (FT_Short)args[0];
2832 #define DO_MD /* nothing */
2836 args[0] = CURRENT_Ppem();
2839 /* Note: The pointSize should be irrelevant in a given font program; */
2840 /* we thus decide to return only the ppem. */
2844 args[0] = CUR.metrics.pointSize;
2849 args[0] = CURRENT_Ppem();
2868 args[0] = args[1]; \
2884 if ( L <= 0 || L > CUR.args ) \
2885 CUR.error = TT_Err_Invalid_Reference; \
2887 args[0] = CUR.stack[CUR.args - L]; \
2892 if ( args[1] != 0 ) \
2894 CUR.IP += args[0]; \
2895 CUR.step_ins = FALSE; \
2900 CUR.IP += args[0]; \
2901 CUR.step_ins = FALSE;
2905 if ( args[1] == 0 ) \
2907 CUR.IP += args[0]; \
2908 CUR.step_ins = FALSE; \
2913 args[0] = ( args[0] < args[1] );
2917 args[0] = ( args[0] <= args[1] );
2921 args[0] = ( args[0] > args[1] );
2925 args[0] = ( args[0] >= args[1] );
2929 args[0] = ( args[0] == args[1] );
2933 args[0] = ( args[0] != args[1] );
2937 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
2941 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
2945 args[0] = ( args[0] && args[1] );
2949 args[0] = ( args[0] || args[1] );
2965 if ( args[1] == 0 ) \
2966 CUR.error = TT_Err_Divide_By_Zero; \
2968 args[0] = TT_MULDIV_NO_ROUND( args[0], 64L, args[1] );
2972 args[0] = TT_MULDIV( args[0], args[1], 64L );
2976 args[0] = FT_ABS( args[0] );
2984 args[0] = FT_PIX_FLOOR( args[0] );
2987 #define DO_CEILING \
2988 args[0] = FT_PIX_CEIL( args[0] );
2993 FT_ULong I = (FT_ULong)args[0]; \
2996 if ( BOUNDS( I, CUR.storeSize ) ) \
2998 if ( CUR.pedantic_hinting ) \
3000 ARRAY_BOUND_ERROR; \
3006 args[0] = CUR.storage[I]; \
3012 FT_ULong I = (FT_ULong)args[0]; \
3015 if ( BOUNDS( I, CUR.storeSize ) ) \
3017 if ( CUR.pedantic_hinting ) \
3019 ARRAY_BOUND_ERROR; \
3023 CUR.storage[I] = args[1]; \
3029 FT_ULong I = (FT_ULong)args[0]; \
3032 if ( BOUNDS( I, CUR.cvtSize ) ) \
3034 if ( CUR.pedantic_hinting ) \
3036 ARRAY_BOUND_ERROR; \
3042 args[0] = CUR_Func_read_cvt( I ); \
3048 FT_ULong I = (FT_ULong)args[0]; \
3051 if ( BOUNDS( I, CUR.cvtSize ) ) \
3053 if ( CUR.pedantic_hinting ) \
3055 ARRAY_BOUND_ERROR; \
3059 CUR_Func_write_cvt( I, args[1] ); \
3065 FT_ULong I = (FT_ULong)args[0]; \
3068 if ( BOUNDS( I, CUR.cvtSize ) ) \
3070 if ( CUR.pedantic_hinting ) \
3072 ARRAY_BOUND_ERROR; \
3076 CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
3081 CUR.error = TT_Err_Debug_OpCode;
3085 args[0] = CUR_Func_round( \
3087 CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
3091 args[0] = ROUND_None( args[0], \
3092 CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
3096 if ( args[1] > args[0] ) \
3101 if ( args[1] < args[0] ) \
3105 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
3108 #undef ARRAY_BOUND_ERROR
3109 #define ARRAY_BOUND_ERROR \
3111 CUR.error = TT_Err_Invalid_Reference; \
3116 /*************************************************************************/
3118 /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
3119 /* Opcode range: 0x00-0x01 */
3123 Ins_SVTCA( INS_ARG
)
3129 /*************************************************************************/
3131 /* SPVTCA[a]: Set PVector to Coordinate Axis */
3132 /* Opcode range: 0x02-0x03 */
3136 Ins_SPVTCA( INS_ARG
)
3142 /*************************************************************************/
3144 /* SFVTCA[a]: Set FVector to Coordinate Axis */
3145 /* Opcode range: 0x04-0x05 */
3149 Ins_SFVTCA( INS_ARG
)
3155 /*************************************************************************/
3157 /* SPVTL[a]: Set PVector To Line */
3158 /* Opcode range: 0x06-0x07 */
3159 /* Stack: uint32 uint32 --> */
3162 Ins_SPVTL( INS_ARG
)
3168 /*************************************************************************/
3170 /* SFVTL[a]: Set FVector To Line */
3171 /* Opcode range: 0x08-0x09 */
3172 /* Stack: uint32 uint32 --> */
3175 Ins_SFVTL( INS_ARG
)
3181 /*************************************************************************/
3183 /* SFVTPV[]: Set FVector To PVector */
3184 /* Opcode range: 0x0E */
3188 Ins_SFVTPV( INS_ARG
)
3194 /*************************************************************************/
3196 /* SPVFS[]: Set PVector From Stack */
3197 /* Opcode range: 0x0A */
3198 /* Stack: f2.14 f2.14 --> */
3201 Ins_SPVFS( INS_ARG
)
3207 /*************************************************************************/
3209 /* SFVFS[]: Set FVector From Stack */
3210 /* Opcode range: 0x0B */
3211 /* Stack: f2.14 f2.14 --> */
3214 Ins_SFVFS( INS_ARG
)
3220 /*************************************************************************/
3222 /* GPV[]: Get Projection Vector */
3223 /* Opcode range: 0x0C */
3224 /* Stack: ef2.14 --> ef2.14 */
3233 /*************************************************************************/
3234 /* GFV[]: Get Freedom Vector */
3235 /* Opcode range: 0x0D */
3236 /* Stack: ef2.14 --> ef2.14 */
3245 /*************************************************************************/
3247 /* SRP0[]: Set Reference Point 0 */
3248 /* Opcode range: 0x10 */
3249 /* Stack: uint32 --> */
3258 /*************************************************************************/
3260 /* SRP1[]: Set Reference Point 1 */
3261 /* Opcode range: 0x11 */
3262 /* Stack: uint32 --> */
3271 /*************************************************************************/
3273 /* SRP2[]: Set Reference Point 2 */
3274 /* Opcode range: 0x12 */
3275 /* Stack: uint32 --> */
3284 /*************************************************************************/
3286 /* RTHG[]: Round To Half Grid */
3287 /* Opcode range: 0x19 */
3297 /*************************************************************************/
3299 /* RTG[]: Round To Grid */
3300 /* Opcode range: 0x18 */
3310 /*************************************************************************/
3311 /* RTDG[]: Round To Double Grid */
3312 /* Opcode range: 0x3D */
3322 /*************************************************************************/
3323 /* RUTG[]: Round Up To Grid */
3324 /* Opcode range: 0x7C */
3334 /*************************************************************************/
3336 /* RDTG[]: Round Down To Grid */
3337 /* Opcode range: 0x7D */
3347 /*************************************************************************/
3349 /* ROFF[]: Round OFF */
3350 /* Opcode range: 0x7A */
3360 /*************************************************************************/
3362 /* SROUND[]: Super ROUND */
3363 /* Opcode range: 0x76 */
3364 /* Stack: Eint8 --> */
3367 Ins_SROUND( INS_ARG
)
3373 /*************************************************************************/
3375 /* S45ROUND[]: Super ROUND 45 degrees */
3376 /* Opcode range: 0x77 */
3377 /* Stack: uint32 --> */
3380 Ins_S45ROUND( INS_ARG
)
3386 /*************************************************************************/
3388 /* SLOOP[]: Set LOOP variable */
3389 /* Opcode range: 0x17 */
3390 /* Stack: int32? --> */
3393 Ins_SLOOP( INS_ARG
)
3399 /*************************************************************************/
3401 /* SMD[]: Set Minimum Distance */
3402 /* Opcode range: 0x1A */
3403 /* Stack: f26.6 --> */
3412 /*************************************************************************/
3414 /* SCVTCI[]: Set Control Value Table Cut In */
3415 /* Opcode range: 0x1D */
3416 /* Stack: f26.6 --> */
3419 Ins_SCVTCI( INS_ARG
)
3425 /*************************************************************************/
3427 /* SSWCI[]: Set Single Width Cut In */
3428 /* Opcode range: 0x1E */
3429 /* Stack: f26.6 --> */
3432 Ins_SSWCI( INS_ARG
)
3438 /*************************************************************************/
3440 /* SSW[]: Set Single Width */
3441 /* Opcode range: 0x1F */
3442 /* Stack: int32? --> */
3451 /*************************************************************************/
3453 /* FLIPON[]: Set auto-FLIP to ON */
3454 /* Opcode range: 0x4D */
3458 Ins_FLIPON( INS_ARG
)
3464 /*************************************************************************/
3466 /* FLIPOFF[]: Set auto-FLIP to OFF */
3467 /* Opcode range: 0x4E */
3471 Ins_FLIPOFF( INS_ARG
)
3477 /*************************************************************************/
3479 /* SANGW[]: Set ANGle Weight */
3480 /* Opcode range: 0x7E */
3481 /* Stack: uint32 --> */
3484 Ins_SANGW( INS_ARG
)
3486 /* instruction not supported anymore */
3490 /*************************************************************************/
3492 /* SDB[]: Set Delta Base */
3493 /* Opcode range: 0x5E */
3494 /* Stack: uint32 --> */
3503 /*************************************************************************/
3505 /* SDS[]: Set Delta Shift */
3506 /* Opcode range: 0x5F */
3507 /* Stack: uint32 --> */
3516 /*************************************************************************/
3518 /* MPPEM[]: Measure Pixel Per EM */
3519 /* Opcode range: 0x4B */
3520 /* Stack: --> Euint16 */
3523 Ins_MPPEM( INS_ARG
)
3529 /*************************************************************************/
3531 /* MPS[]: Measure Point Size */
3532 /* Opcode range: 0x4C */
3533 /* Stack: --> Euint16 */
3542 /*************************************************************************/
3544 /* DUP[]: DUPlicate the top stack's element */
3545 /* Opcode range: 0x20 */
3546 /* Stack: StkElt --> StkElt StkElt */
3555 /*************************************************************************/
3557 /* POP[]: POP the stack's top element */
3558 /* Opcode range: 0x21 */
3559 /* Stack: StkElt --> */
3568 /*************************************************************************/
3570 /* CLEAR[]: CLEAR the entire stack */
3571 /* Opcode range: 0x22 */
3572 /* Stack: StkElt... --> */
3575 Ins_CLEAR( INS_ARG
)
3581 /*************************************************************************/
3583 /* SWAP[]: SWAP the stack's top two elements */
3584 /* Opcode range: 0x23 */
3585 /* Stack: 2 * StkElt --> 2 * StkElt */
3594 /*************************************************************************/
3596 /* DEPTH[]: return the stack DEPTH */
3597 /* Opcode range: 0x24 */
3598 /* Stack: --> uint32 */
3601 Ins_DEPTH( INS_ARG
)
3607 /*************************************************************************/
3609 /* CINDEX[]: Copy INDEXed element */
3610 /* Opcode range: 0x25 */
3611 /* Stack: int32 --> StkElt */
3614 Ins_CINDEX( INS_ARG
)
3620 /*************************************************************************/
3623 /* Opcode range: 0x59 */
3633 /*************************************************************************/
3635 /* JROT[]: Jump Relative On True */
3636 /* Opcode range: 0x78 */
3637 /* Stack: StkElt int32 --> */
3646 /*************************************************************************/
3648 /* JMPR[]: JuMP Relative */
3649 /* Opcode range: 0x1C */
3650 /* Stack: int32 --> */
3659 /*************************************************************************/
3661 /* JROF[]: Jump Relative On False */
3662 /* Opcode range: 0x79 */
3663 /* Stack: StkElt int32 --> */
3672 /*************************************************************************/
3674 /* LT[]: Less Than */
3675 /* Opcode range: 0x50 */
3676 /* Stack: int32? int32? --> bool */
3685 /*************************************************************************/
3687 /* LTEQ[]: Less Than or EQual */
3688 /* Opcode range: 0x51 */
3689 /* Stack: int32? int32? --> bool */
3698 /*************************************************************************/
3700 /* GT[]: Greater Than */
3701 /* Opcode range: 0x52 */
3702 /* Stack: int32? int32? --> bool */
3711 /*************************************************************************/
3713 /* GTEQ[]: Greater Than or EQual */
3714 /* Opcode range: 0x53 */
3715 /* Stack: int32? int32? --> bool */
3724 /*************************************************************************/
3727 /* Opcode range: 0x54 */
3728 /* Stack: StkElt StkElt --> bool */
3737 /*************************************************************************/
3739 /* NEQ[]: Not EQual */
3740 /* Opcode range: 0x55 */
3741 /* Stack: StkElt StkElt --> bool */
3750 /*************************************************************************/
3753 /* Opcode range: 0x56 */
3754 /* Stack: f26.6 --> bool */
3763 /*************************************************************************/
3765 /* EVEN[]: Is EVEN */
3766 /* Opcode range: 0x57 */
3767 /* Stack: f26.6 --> bool */
3776 /*************************************************************************/
3778 /* AND[]: logical AND */
3779 /* Opcode range: 0x5A */
3780 /* Stack: uint32 uint32 --> uint32 */
3789 /*************************************************************************/
3791 /* OR[]: logical OR */
3792 /* Opcode range: 0x5B */
3793 /* Stack: uint32 uint32 --> uint32 */
3802 /*************************************************************************/
3804 /* NOT[]: logical NOT */
3805 /* Opcode range: 0x5C */
3806 /* Stack: StkElt --> uint32 */
3815 /*************************************************************************/
3818 /* Opcode range: 0x60 */
3819 /* Stack: f26.6 f26.6 --> f26.6 */
3828 /*************************************************************************/
3830 /* SUB[]: SUBtract */
3831 /* Opcode range: 0x61 */
3832 /* Stack: f26.6 f26.6 --> f26.6 */
3841 /*************************************************************************/
3844 /* Opcode range: 0x62 */
3845 /* Stack: f26.6 f26.6 --> f26.6 */
3854 /*************************************************************************/
3856 /* MUL[]: MULtiply */
3857 /* Opcode range: 0x63 */
3858 /* Stack: f26.6 f26.6 --> f26.6 */
3867 /*************************************************************************/
3869 /* ABS[]: ABSolute value */
3870 /* Opcode range: 0x64 */
3871 /* Stack: f26.6 --> f26.6 */
3880 /*************************************************************************/
3883 /* Opcode range: 0x65 */
3884 /* Stack: f26.6 --> f26.6 */
3893 /*************************************************************************/
3895 /* FLOOR[]: FLOOR */
3896 /* Opcode range: 0x66 */
3897 /* Stack: f26.6 --> f26.6 */
3900 Ins_FLOOR( INS_ARG
)
3906 /*************************************************************************/
3908 /* CEILING[]: CEILING */
3909 /* Opcode range: 0x67 */
3910 /* Stack: f26.6 --> f26.6 */
3913 Ins_CEILING( INS_ARG
)
3919 /*************************************************************************/
3921 /* RS[]: Read Store */
3922 /* Opcode range: 0x43 */
3923 /* Stack: uint32 --> uint32 */
3932 /*************************************************************************/
3934 /* WS[]: Write Store */
3935 /* Opcode range: 0x42 */
3936 /* Stack: uint32 uint32 --> */
3945 /*************************************************************************/
3947 /* WCVTP[]: Write CVT in Pixel units */
3948 /* Opcode range: 0x44 */
3949 /* Stack: f26.6 uint32 --> */
3952 Ins_WCVTP( INS_ARG
)
3958 /*************************************************************************/
3960 /* WCVTF[]: Write CVT in Funits */
3961 /* Opcode range: 0x70 */
3962 /* Stack: uint32 uint32 --> */
3965 Ins_WCVTF( INS_ARG
)
3971 /*************************************************************************/
3973 /* RCVT[]: Read CVT */
3974 /* Opcode range: 0x45 */
3975 /* Stack: uint32 --> f26.6 */
3984 /*************************************************************************/
3986 /* AA[]: Adjust Angle */
3987 /* Opcode range: 0x7F */
3988 /* Stack: uint32 --> */
3993 /* intentionally no longer supported */
3997 /*************************************************************************/
3999 /* DEBUG[]: DEBUG. Unsupported. */
4000 /* Opcode range: 0x4F */
4001 /* Stack: uint32 --> */
4003 /* Note: The original instruction pops a value from the stack. */
4006 Ins_DEBUG( INS_ARG
)
4012 /*************************************************************************/
4014 /* ROUND[ab]: ROUND value */
4015 /* Opcode range: 0x68-0x6B */
4016 /* Stack: f26.6 --> f26.6 */
4019 Ins_ROUND( INS_ARG
)
4025 /*************************************************************************/
4027 /* NROUND[ab]: No ROUNDing of value */
4028 /* Opcode range: 0x6C-0x6F */
4029 /* Stack: f26.6 --> f26.6 */
4032 Ins_NROUND( INS_ARG
)
4038 /*************************************************************************/
4040 /* MAX[]: MAXimum */
4041 /* Opcode range: 0x68 */
4042 /* Stack: int32? int32? --> int32 */
4051 /*************************************************************************/
4053 /* MIN[]: MINimum */
4054 /* Opcode range: 0x69 */
4055 /* Stack: int32? int32? --> int32 */
4064 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
4067 /*************************************************************************/
4069 /* The following functions are called as is within the switch statement. */
4071 /*************************************************************************/
4074 /*************************************************************************/
4076 /* MINDEX[]: Move INDEXed element */
4077 /* Opcode range: 0x26 */
4078 /* Stack: int32? --> StkElt */
4081 Ins_MINDEX( INS_ARG
)
4088 if ( L
<= 0 || L
> CUR
.args
)
4090 CUR
.error
= TT_Err_Invalid_Reference
;
4094 K
= CUR
.stack
[CUR
.args
- L
];
4096 FT_ARRAY_MOVE( &CUR
.stack
[CUR
.args
- L
],
4097 &CUR
.stack
[CUR
.args
- L
+ 1],
4100 CUR
.stack
[CUR
.args
- 1] = K
;
4104 /*************************************************************************/
4106 /* ROLL[]: ROLL top three elements */
4107 /* Opcode range: 0x8A */
4108 /* Stack: 3 * StkElt --> 3 * StkElt */
4128 /*************************************************************************/
4130 /* MANAGING THE FLOW OF CONTROL */
4132 /* Instructions appear in the specification's order. */
4134 /*************************************************************************/
4140 CUR
.IP
+= CUR
.length
;
4142 if ( CUR
.IP
< CUR
.codeSize
)
4144 CUR
.opcode
= CUR
.code
[CUR
.IP
];
4146 CUR
.length
= opcode_length
[CUR
.opcode
];
4147 if ( CUR
.length
< 0 )
4149 if ( CUR
.IP
+ 1 > CUR
.codeSize
)
4151 CUR
.length
= 2 - CUR
.length
* CUR
.code
[CUR
.IP
+ 1];
4154 if ( CUR
.IP
+ CUR
.length
<= CUR
.codeSize
)
4159 CUR
.error
= TT_Err_Code_Overflow
;
4164 /*************************************************************************/
4167 /* Opcode range: 0x58 */
4168 /* Stack: StkElt --> */
4185 if ( SKIP_Code() == FAILURE
)
4188 switch ( CUR
.opcode
)
4194 case 0x1B: /* ELSE */
4195 Out
= FT_BOOL( nIfs
== 1 );
4198 case 0x59: /* EIF */
4200 Out
= FT_BOOL( nIfs
== 0 );
4203 } while ( Out
== 0 );
4207 /*************************************************************************/
4210 /* Opcode range: 0x1B */
4225 if ( SKIP_Code() == FAILURE
)
4228 switch ( CUR
.opcode
)
4234 case 0x59: /* EIF */
4238 } while ( nIfs
!= 0 );
4242 /*************************************************************************/
4244 /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
4246 /* Instructions appear in the specification's order. */
4248 /*************************************************************************/
4251 /*************************************************************************/
4253 /* FDEF[]: Function DEFinition */
4254 /* Opcode range: 0x2C */
4255 /* Stack: uint32 --> */
4262 TT_DefRecord
* limit
;
4265 /* some font programs are broken enough to redefine functions! */
4266 /* We will then parse the current table. */
4269 limit
= rec
+ CUR
.numFDefs
;
4272 for ( ; rec
< limit
; rec
++ )
4274 if ( rec
->opc
== n
)
4280 /* check that there is enough room for new functions */
4281 if ( CUR
.numFDefs
>= CUR
.maxFDefs
)
4283 CUR
.error
= TT_Err_Too_Many_Function_Defs
;
4289 rec
->range
= CUR
.curRange
;
4291 rec
->start
= CUR
.IP
+ 1;
4294 if ( n
> CUR
.maxFunc
)
4297 /* Now skip the whole function definition. */
4298 /* We don't allow nested IDEFS & FDEFs. */
4300 while ( SKIP_Code() == SUCCESS
)
4302 switch ( CUR
.opcode
)
4304 case 0x89: /* IDEF */
4305 case 0x2C: /* FDEF */
4306 CUR
.error
= TT_Err_Nested_DEFS
;
4309 case 0x2D: /* ENDF */
4316 /*************************************************************************/
4318 /* ENDF[]: END Function definition */
4319 /* Opcode range: 0x2D */
4330 if ( CUR
.callTop
<= 0 ) /* We encountered an ENDF without a call */
4332 CUR
.error
= TT_Err_ENDF_In_Exec_Stream
;
4338 pRec
= &CUR
.callStack
[CUR
.callTop
];
4342 CUR
.step_ins
= FALSE
;
4344 if ( pRec
->Cur_Count
> 0 )
4347 CUR
.IP
= pRec
->Cur_Restart
;
4350 /* Loop through the current function */
4351 INS_Goto_CodeRange( pRec
->Caller_Range
,
4354 /* Exit the current call frame. */
4356 /* NOTE: If the last instruction of a program is a */
4357 /* CALL or LOOPCALL, the return address is */
4358 /* always out of the code range. This is a */
4359 /* valid address, and it is why we do not test */
4360 /* the result of Ins_Goto_CodeRange() here! */
4364 /*************************************************************************/
4366 /* CALL[]: CALL function */
4367 /* Opcode range: 0x2B */
4368 /* Stack: uint32? --> */
4378 /* first of all, check the index */
4381 if ( BOUNDS( F
, CUR
.maxFunc
+ 1 ) )
4384 /* Except for some old Apple fonts, all functions in a TrueType */
4385 /* font are defined in increasing order, starting from 0. This */
4386 /* means that we normally have */
4388 /* CUR.maxFunc+1 == CUR.numFDefs */
4389 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4391 /* If this isn't true, we need to look up the function table. */
4393 def
= CUR
.FDefs
+ F
;
4394 if ( CUR
.maxFunc
+ 1 != CUR
.numFDefs
|| def
->opc
!= F
)
4396 /* look up the FDefs table */
4397 TT_DefRecord
* limit
;
4401 limit
= def
+ CUR
.numFDefs
;
4403 while ( def
< limit
&& def
->opc
!= F
)
4410 /* check that the function is active */
4414 /* check the call stack */
4415 if ( CUR
.callTop
>= CUR
.callSize
)
4417 CUR
.error
= TT_Err_Stack_Overflow
;
4421 pCrec
= CUR
.callStack
+ CUR
.callTop
;
4423 pCrec
->Caller_Range
= CUR
.curRange
;
4424 pCrec
->Caller_IP
= CUR
.IP
+ 1;
4425 pCrec
->Cur_Count
= 1;
4426 pCrec
->Cur_Restart
= def
->start
;
4430 INS_Goto_CodeRange( def
->range
,
4433 CUR
.step_ins
= FALSE
;
4437 CUR
.error
= TT_Err_Invalid_Reference
;
4441 /*************************************************************************/
4443 /* LOOPCALL[]: LOOP and CALL function */
4444 /* Opcode range: 0x2A */
4445 /* Stack: uint32? Eint16? --> */
4448 Ins_LOOPCALL( INS_ARG
)
4455 /* first of all, check the index */
4457 if ( BOUNDS( F
, CUR
.maxFunc
+ 1 ) )
4460 /* Except for some old Apple fonts, all functions in a TrueType */
4461 /* font are defined in increasing order, starting from 0. This */
4462 /* means that we normally have */
4464 /* CUR.maxFunc+1 == CUR.numFDefs */
4465 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4467 /* If this isn't true, we need to look up the function table. */
4469 def
= CUR
.FDefs
+ F
;
4470 if ( CUR
.maxFunc
+ 1 != CUR
.numFDefs
|| def
->opc
!= F
)
4472 /* look up the FDefs table */
4473 TT_DefRecord
* limit
;
4477 limit
= def
+ CUR
.numFDefs
;
4479 while ( def
< limit
&& def
->opc
!= F
)
4486 /* check that the function is active */
4491 if ( CUR
.callTop
>= CUR
.callSize
)
4493 CUR
.error
= TT_Err_Stack_Overflow
;
4499 pCrec
= CUR
.callStack
+ CUR
.callTop
;
4501 pCrec
->Caller_Range
= CUR
.curRange
;
4502 pCrec
->Caller_IP
= CUR
.IP
+ 1;
4503 pCrec
->Cur_Count
= (FT_Int
)args
[0];
4504 pCrec
->Cur_Restart
= def
->start
;
4508 INS_Goto_CodeRange( def
->range
, def
->start
);
4510 CUR
.step_ins
= FALSE
;
4515 CUR
.error
= TT_Err_Invalid_Reference
;
4519 /*************************************************************************/
4521 /* IDEF[]: Instruction DEFinition */
4522 /* Opcode range: 0x89 */
4523 /* Stack: Eint8 --> */
4529 TT_DefRecord
* limit
;
4532 /* First of all, look for the same function in our table */
4535 limit
= def
+ CUR
.numIDefs
;
4537 for ( ; def
< limit
; def
++ )
4538 if ( def
->opc
== (FT_ULong
)args
[0] )
4543 /* check that there is enough room for a new instruction */
4544 if ( CUR
.numIDefs
>= CUR
.maxIDefs
)
4546 CUR
.error
= TT_Err_Too_Many_Instruction_Defs
;
4553 def
->start
= CUR
.IP
+1;
4554 def
->range
= CUR
.curRange
;
4557 if ( (FT_ULong
)args
[0] > CUR
.maxIns
)
4558 CUR
.maxIns
= args
[0];
4560 /* Now skip the whole function definition. */
4561 /* We don't allow nested IDEFs & FDEFs. */
4563 while ( SKIP_Code() == SUCCESS
)
4565 switch ( CUR
.opcode
)
4567 case 0x89: /* IDEF */
4568 case 0x2C: /* FDEF */
4569 CUR
.error
= TT_Err_Nested_DEFS
;
4571 case 0x2D: /* ENDF */
4578 /*************************************************************************/
4580 /* PUSHING DATA ONTO THE INTERPRETER STACK */
4582 /* Instructions appear in the specification's order. */
4584 /*************************************************************************/
4587 /*************************************************************************/
4589 /* NPUSHB[]: PUSH N Bytes */
4590 /* Opcode range: 0x40 */
4591 /* Stack: --> uint32... */
4594 Ins_NPUSHB( INS_ARG
)
4599 L
= (FT_UShort
)CUR
.code
[CUR
.IP
+ 1];
4601 if ( BOUNDS( L
, CUR
.stackSize
+ 1 - CUR
.top
) )
4603 CUR
.error
= TT_Err_Stack_Overflow
;
4607 for ( K
= 1; K
<= L
; K
++ )
4608 args
[K
- 1] = CUR
.code
[CUR
.IP
+ K
+ 1];
4614 /*************************************************************************/
4616 /* NPUSHW[]: PUSH N Words */
4617 /* Opcode range: 0x41 */
4618 /* Stack: --> int32... */
4621 Ins_NPUSHW( INS_ARG
)
4626 L
= (FT_UShort
)CUR
.code
[CUR
.IP
+ 1];
4628 if ( BOUNDS( L
, CUR
.stackSize
+ 1 - CUR
.top
) )
4630 CUR
.error
= TT_Err_Stack_Overflow
;
4636 for ( K
= 0; K
< L
; K
++ )
4637 args
[K
] = GET_ShortIns();
4639 CUR
.step_ins
= FALSE
;
4644 /*************************************************************************/
4646 /* PUSHB[abc]: PUSH Bytes */
4647 /* Opcode range: 0xB0-0xB7 */
4648 /* Stack: --> uint32... */
4651 Ins_PUSHB( INS_ARG
)
4656 L
= (FT_UShort
)( CUR
.opcode
- 0xB0 + 1 );
4658 if ( BOUNDS( L
, CUR
.stackSize
+ 1 - CUR
.top
) )
4660 CUR
.error
= TT_Err_Stack_Overflow
;
4664 for ( K
= 1; K
<= L
; K
++ )
4665 args
[K
- 1] = CUR
.code
[CUR
.IP
+ K
];
4669 /*************************************************************************/
4671 /* PUSHW[abc]: PUSH Words */
4672 /* Opcode range: 0xB8-0xBF */
4673 /* Stack: --> int32... */
4676 Ins_PUSHW( INS_ARG
)
4681 L
= (FT_UShort
)( CUR
.opcode
- 0xB8 + 1 );
4683 if ( BOUNDS( L
, CUR
.stackSize
+ 1 - CUR
.top
) )
4685 CUR
.error
= TT_Err_Stack_Overflow
;
4691 for ( K
= 0; K
< L
; K
++ )
4692 args
[K
] = GET_ShortIns();
4694 CUR
.step_ins
= FALSE
;
4698 /*************************************************************************/
4700 /* MANAGING THE GRAPHICS STATE */
4702 /* Instructions appear in the specs' order. */
4704 /*************************************************************************/
4707 /*************************************************************************/
4709 /* GC[a]: Get Coordinate projected onto */
4710 /* Opcode range: 0x46-0x47 */
4711 /* Stack: uint32 --> f26.6 */
4713 /* BULLSHIT: Measures from the original glyph must be taken along the */
4714 /* dual projection vector! */
4723 L
= (FT_ULong
)args
[0];
4725 if ( BOUNDS( L
, CUR
.zp2
.n_points
) )
4727 if ( CUR
.pedantic_hinting
)
4729 CUR
.error
= TT_Err_Invalid_Reference
;
4737 if ( CUR
.opcode
& 1 )
4738 R
= CUR_fast_dualproj( &CUR
.zp2
.org
[L
] );
4740 R
= CUR_fast_project( &CUR
.zp2
.cur
[L
] );
4747 /*************************************************************************/
4749 /* SCFS[]: Set Coordinate From Stack */
4750 /* Opcode range: 0x48 */
4751 /* Stack: f26.6 uint32 --> */
4755 /* OA := OA + ( value - OA.p )/( f.p ) * f */
4764 L
= (FT_UShort
)args
[0];
4766 if ( BOUNDS( L
, CUR
.zp2
.n_points
) )
4768 if ( CUR
.pedantic_hinting
)
4769 CUR
.error
= TT_Err_Invalid_Reference
;
4773 K
= CUR_fast_project( &CUR
.zp2
.cur
[L
] );
4775 CUR_Func_move( &CUR
.zp2
, L
, args
[1] - K
);
4777 /* not part of the specs, but here for safety */
4779 if ( CUR
.GS
.gep2
== 0 )
4780 CUR
.zp2
.org
[L
] = CUR
.zp2
.cur
[L
];
4784 /*************************************************************************/
4786 /* MD[a]: Measure Distance */
4787 /* Opcode range: 0x49-0x4A */
4788 /* Stack: uint32 uint32 --> f26.6 */
4790 /* BULLSHIT: Measure taken in the original glyph must be along the dual */
4791 /* projection vector. */
4793 /* Second BULLSHIT: Flag attributes are inverted! */
4794 /* 0 => measure distance in original outline */
4795 /* 1 => measure distance in grid-fitted outline */
4797 /* Third one: `zp0 - zp1', and not `zp2 - zp1! */
4806 K
= (FT_UShort
)args
[1];
4807 L
= (FT_UShort
)args
[0];
4809 if( BOUNDS( L
, CUR
.zp0
.n_points
) ||
4810 BOUNDS( K
, CUR
.zp1
.n_points
) )
4812 if ( CUR
.pedantic_hinting
)
4814 CUR
.error
= TT_Err_Invalid_Reference
;
4821 if ( CUR
.opcode
& 1 )
4822 D
= CUR_Func_project( CUR
.zp0
.cur
+ L
, CUR
.zp1
.cur
+ K
);
4825 FT_Vector
* vec1
= CUR
.zp0
.orus
+ L
;
4826 FT_Vector
* vec2
= CUR
.zp1
.orus
+ K
;
4829 if ( CUR
.metrics
.x_scale
== CUR
.metrics
.y_scale
)
4831 /* this should be faster */
4832 D
= CUR_Func_dualproj( vec1
, vec2
);
4833 D
= TT_MULFIX( D
, CUR
.metrics
.x_scale
);
4840 vec
.x
= TT_MULFIX( vec1
->x
- vec2
->x
, CUR
.metrics
.x_scale
);
4841 vec
.y
= TT_MULFIX( vec1
->y
- vec2
->y
, CUR
.metrics
.y_scale
);
4843 D
= CUR_fast_dualproj( &vec
);
4852 /*************************************************************************/
4854 /* SDPVTL[a]: Set Dual PVector to Line */
4855 /* Opcode range: 0x86-0x87 */
4856 /* Stack: uint32 uint32 --> */
4859 Ins_SDPVTL( INS_ARG
)
4862 FT_UShort p1
, p2
; /* was FT_Int in pas type ERROR */
4865 p1
= (FT_UShort
)args
[1];
4866 p2
= (FT_UShort
)args
[0];
4868 if ( BOUNDS( p2
, CUR
.zp1
.n_points
) ||
4869 BOUNDS( p1
, CUR
.zp2
.n_points
) )
4871 if ( CUR
.pedantic_hinting
)
4872 CUR
.error
= TT_Err_Invalid_Reference
;
4877 FT_Vector
* v1
= CUR
.zp1
.org
+ p2
;
4878 FT_Vector
* v2
= CUR
.zp2
.org
+ p1
;
4885 if ( ( CUR
.opcode
& 1 ) != 0 )
4887 C
= B
; /* counter clockwise rotation */
4892 NORMalize( A
, B
, &CUR
.GS
.dualVector
);
4895 FT_Vector
* v1
= CUR
.zp1
.cur
+ p2
;
4896 FT_Vector
* v2
= CUR
.zp2
.cur
+ p1
;
4903 if ( ( CUR
.opcode
& 1 ) != 0 )
4905 C
= B
; /* counter clockwise rotation */
4910 NORMalize( A
, B
, &CUR
.GS
.projVector
);
4912 GUESS_VECTOR( freeVector
);
4918 /*************************************************************************/
4920 /* SZP0[]: Set Zone Pointer 0 */
4921 /* Opcode range: 0x13 */
4922 /* Stack: uint32 --> */
4927 switch ( (FT_Int
)args
[0] )
4930 CUR
.zp0
= CUR
.twilight
;
4938 if ( CUR
.pedantic_hinting
)
4939 CUR
.error
= TT_Err_Invalid_Reference
;
4943 CUR
.GS
.gep0
= (FT_UShort
)args
[0];
4947 /*************************************************************************/
4949 /* SZP1[]: Set Zone Pointer 1 */
4950 /* Opcode range: 0x14 */
4951 /* Stack: uint32 --> */
4956 switch ( (FT_Int
)args
[0] )
4959 CUR
.zp1
= CUR
.twilight
;
4967 if ( CUR
.pedantic_hinting
)
4968 CUR
.error
= TT_Err_Invalid_Reference
;
4972 CUR
.GS
.gep1
= (FT_UShort
)args
[0];
4976 /*************************************************************************/
4978 /* SZP2[]: Set Zone Pointer 2 */
4979 /* Opcode range: 0x15 */
4980 /* Stack: uint32 --> */
4985 switch ( (FT_Int
)args
[0] )
4988 CUR
.zp2
= CUR
.twilight
;
4996 if ( CUR
.pedantic_hinting
)
4997 CUR
.error
= TT_Err_Invalid_Reference
;
5001 CUR
.GS
.gep2
= (FT_UShort
)args
[0];
5005 /*************************************************************************/
5007 /* SZPS[]: Set Zone PointerS */
5008 /* Opcode range: 0x16 */
5009 /* Stack: uint32 --> */
5014 switch ( (FT_Int
)args
[0] )
5017 CUR
.zp0
= CUR
.twilight
;
5025 if ( CUR
.pedantic_hinting
)
5026 CUR
.error
= TT_Err_Invalid_Reference
;
5033 CUR
.GS
.gep0
= (FT_UShort
)args
[0];
5034 CUR
.GS
.gep1
= (FT_UShort
)args
[0];
5035 CUR
.GS
.gep2
= (FT_UShort
)args
[0];
5039 /*************************************************************************/
5041 /* INSTCTRL[]: INSTruction ConTRoL */
5042 /* Opcode range: 0x8e */
5043 /* Stack: int32 int32 --> */
5046 Ins_INSTCTRL( INS_ARG
)
5054 if ( K
< 1 || K
> 2 )
5056 if ( CUR
.pedantic_hinting
)
5057 CUR
.error
= TT_Err_Invalid_Reference
;
5064 CUR
.GS
.instruct_control
= FT_BOOL(
5065 ( (FT_Byte
)CUR
.GS
.instruct_control
& ~(FT_Byte
)K
) | (FT_Byte
)L
);
5069 /*************************************************************************/
5071 /* SCANCTRL[]: SCAN ConTRoL */
5072 /* Opcode range: 0x85 */
5073 /* Stack: uint32? --> */
5076 Ins_SCANCTRL( INS_ARG
)
5082 A
= (FT_Int
)( args
[0] & 0xFF );
5086 CUR
.GS
.scan_control
= TRUE
;
5091 CUR
.GS
.scan_control
= FALSE
;
5095 if ( ( args
[0] & 0x100 ) != 0 && CUR
.tt_metrics
.ppem
< A
)
5096 CUR
.GS
.scan_control
= TRUE
;
5098 if ( ( args
[0] & 0x200 ) != 0 && CUR
.tt_metrics
.rotated
)
5099 CUR
.GS
.scan_control
= TRUE
;
5101 if ( ( args
[0] & 0x400 ) != 0 && CUR
.tt_metrics
.stretched
)
5102 CUR
.GS
.scan_control
= TRUE
;
5104 if ( ( args
[0] & 0x800 ) != 0 && CUR
.tt_metrics
.ppem
>= A
)
5105 CUR
.GS
.scan_control
= FALSE
;
5107 if ( ( args
[0] & 0x1000 ) != 0 && CUR
.tt_metrics
.rotated
)
5108 CUR
.GS
.scan_control
= FALSE
;
5110 if ( ( args
[0] & 0x2000 ) != 0 && CUR
.tt_metrics
.stretched
)
5111 CUR
.GS
.scan_control
= FALSE
;
5115 /*************************************************************************/
5117 /* SCANTYPE[]: SCAN TYPE */
5118 /* Opcode range: 0x8D */
5119 /* Stack: uint32? --> */
5122 Ins_SCANTYPE( INS_ARG
)
5125 CUR
.GS
.scan_type
= (FT_Int
)args
[0];
5129 /*************************************************************************/
5131 /* MANAGING OUTLINES */
5133 /* Instructions appear in the specification's order. */
5135 /*************************************************************************/
5138 /*************************************************************************/
5140 /* FLIPPT[]: FLIP PoinT */
5141 /* Opcode range: 0x80 */
5142 /* Stack: uint32... --> */
5145 Ins_FLIPPT( INS_ARG
)
5152 if ( CUR
.top
< CUR
.GS
.loop
)
5154 CUR
.error
= TT_Err_Too_Few_Arguments
;
5158 while ( CUR
.GS
.loop
> 0 )
5162 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5164 if ( BOUNDS( point
, CUR
.pts
.n_points
) )
5166 if ( CUR
.pedantic_hinting
)
5168 CUR
.error
= TT_Err_Invalid_Reference
;
5173 CUR
.pts
.tags
[point
] ^= FT_CURVE_TAG_ON
;
5179 CUR
.new_top
= CUR
.args
;
5183 /*************************************************************************/
5185 /* FLIPRGON[]: FLIP RanGe ON */
5186 /* Opcode range: 0x81 */
5187 /* Stack: uint32 uint32 --> */
5190 Ins_FLIPRGON( INS_ARG
)
5195 K
= (FT_UShort
)args
[1];
5196 L
= (FT_UShort
)args
[0];
5198 if ( BOUNDS( K
, CUR
.pts
.n_points
) ||
5199 BOUNDS( L
, CUR
.pts
.n_points
) )
5201 if ( CUR
.pedantic_hinting
)
5202 CUR
.error
= TT_Err_Invalid_Reference
;
5206 for ( I
= L
; I
<= K
; I
++ )
5207 CUR
.pts
.tags
[I
] |= FT_CURVE_TAG_ON
;
5211 /*************************************************************************/
5213 /* FLIPRGOFF: FLIP RanGe OFF */
5214 /* Opcode range: 0x82 */
5215 /* Stack: uint32 uint32 --> */
5218 Ins_FLIPRGOFF( INS_ARG
)
5223 K
= (FT_UShort
)args
[1];
5224 L
= (FT_UShort
)args
[0];
5226 if ( BOUNDS( K
, CUR
.pts
.n_points
) ||
5227 BOUNDS( L
, CUR
.pts
.n_points
) )
5229 if ( CUR
.pedantic_hinting
)
5230 CUR
.error
= TT_Err_Invalid_Reference
;
5234 for ( I
= L
; I
<= K
; I
++ )
5235 CUR
.pts
.tags
[I
] &= ~FT_CURVE_TAG_ON
;
5240 Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6
* x
,
5250 if ( CUR
.opcode
& 1 )
5261 if ( BOUNDS( p
, zp
.n_points
) )
5263 if ( CUR
.pedantic_hinting
)
5264 CUR
.error
= TT_Err_Invalid_Reference
;
5272 d
= CUR_Func_project( zp
.cur
+ p
, zp
.org
+ p
);
5274 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5275 if ( CUR
.face
->unpatented_hinting
)
5277 if ( CUR
.GS
.both_x_axis
)
5292 (FT_Long
)CUR
.GS
.freeVector
.x
* 0x10000L
,
5295 (FT_Long
)CUR
.GS
.freeVector
.y
* 0x10000L
,
5304 Move_Zp2_Point( EXEC_OP_ FT_UShort point
,
5309 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5310 if ( CUR
.face
->unpatented_hinting
)
5312 if ( CUR
.GS
.both_x_axis
)
5314 CUR
.zp2
.cur
[point
].x
+= dx
;
5316 CUR
.zp2
.tags
[point
] |= FT_CURVE_TAG_TOUCH_X
;
5320 CUR
.zp2
.cur
[point
].y
+= dy
;
5322 CUR
.zp2
.tags
[point
] |= FT_CURVE_TAG_TOUCH_Y
;
5328 if ( CUR
.GS
.freeVector
.x
!= 0 )
5330 CUR
.zp2
.cur
[point
].x
+= dx
;
5332 CUR
.zp2
.tags
[point
] |= FT_CURVE_TAG_TOUCH_X
;
5335 if ( CUR
.GS
.freeVector
.y
!= 0 )
5337 CUR
.zp2
.cur
[point
].y
+= dy
;
5339 CUR
.zp2
.tags
[point
] |= FT_CURVE_TAG_TOUCH_Y
;
5344 /*************************************************************************/
5346 /* SHP[a]: SHift Point by the last point */
5347 /* Opcode range: 0x32-0x33 */
5348 /* Stack: uint32... --> */
5363 if ( CUR
.top
< CUR
.GS
.loop
)
5365 CUR
.error
= TT_Err_Invalid_Reference
;
5369 if ( COMPUTE_Point_Displacement( &dx
, &dy
, &zp
, &refp
) )
5372 while ( CUR
.GS
.loop
> 0 )
5375 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5377 if ( BOUNDS( point
, CUR
.zp2
.n_points
) )
5379 if ( CUR
.pedantic_hinting
)
5381 CUR
.error
= TT_Err_Invalid_Reference
;
5386 /* XXX: UNDOCUMENTED! SHP touches the points */
5387 MOVE_Zp2_Point( point
, dx
, dy
, TRUE
);
5393 CUR
.new_top
= CUR
.args
;
5397 /*************************************************************************/
5399 /* SHC[a]: SHift Contour */
5400 /* Opcode range: 0x34-35 */
5401 /* Stack: uint32 --> */
5412 FT_UShort first_point
, last_point
, i
;
5415 contour
= (FT_UShort
)args
[0];
5417 if ( BOUNDS( contour
, CUR
.pts
.n_contours
) )
5419 if ( CUR
.pedantic_hinting
)
5420 CUR
.error
= TT_Err_Invalid_Reference
;
5424 if ( COMPUTE_Point_Displacement( &dx
, &dy
, &zp
, &refp
) )
5430 first_point
= (FT_UShort
)( CUR
.pts
.contours
[contour
- 1] + 1 -
5431 CUR
.pts
.first_point
);
5433 last_point
= (FT_UShort
)( CUR
.pts
.contours
[contour
] -
5434 CUR
.pts
.first_point
);
5436 /* XXX: this is probably wrong... at least it prevents memory */
5437 /* corruption when zp2 is the twilight zone */
5438 if ( BOUNDS( last_point
, CUR
.zp2
.n_points
) )
5440 if ( CUR
.zp2
.n_points
> 0 )
5441 last_point
= (FT_UShort
)(CUR
.zp2
.n_points
- 1);
5446 /* XXX: UNDOCUMENTED! SHC touches the points */
5447 for ( i
= first_point
; i
<= last_point
; i
++ )
5449 if ( zp
.cur
!= CUR
.zp2
.cur
|| refp
!= i
)
5450 MOVE_Zp2_Point( i
, dx
, dy
, TRUE
);
5455 /*************************************************************************/
5457 /* SHZ[a]: SHift Zone */
5458 /* Opcode range: 0x36-37 */
5459 /* Stack: uint32 --> */
5469 FT_UShort last_point
, i
;
5472 if ( BOUNDS( args
[0], 2 ) )
5474 if ( CUR
.pedantic_hinting
)
5475 CUR
.error
= TT_Err_Invalid_Reference
;
5479 if ( COMPUTE_Point_Displacement( &dx
, &dy
, &zp
, &refp
) )
5482 /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */
5483 /* Twilight zone has no contours, so use `n_points'. */
5484 /* Normal zone's `n_points' includes phantoms, so must */
5485 /* use end of last contour. */
5486 if ( CUR
.GS
.gep2
== 0 && CUR
.zp2
.n_points
> 0 )
5487 last_point
= (FT_UShort
)( CUR
.zp2
.n_points
- 1 );
5488 else if ( CUR
.GS
.gep2
== 1 && CUR
.zp2
.n_contours
> 0 )
5489 last_point
= (FT_UShort
)( CUR
.zp2
.contours
[CUR
.zp2
.n_contours
- 1] );
5493 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
5494 for ( i
= 0; i
<= last_point
; i
++ )
5496 if ( zp
.cur
!= CUR
.zp2
.cur
|| refp
!= i
)
5497 MOVE_Zp2_Point( i
, dx
, dy
, FALSE
);
5502 /*************************************************************************/
5504 /* SHPIX[]: SHift points by a PIXel amount */
5505 /* Opcode range: 0x38 */
5506 /* Stack: f26.6 uint32... --> */
5509 Ins_SHPIX( INS_ARG
)
5515 if ( CUR
.top
< CUR
.GS
.loop
+ 1 )
5517 CUR
.error
= TT_Err_Invalid_Reference
;
5521 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5522 if ( CUR
.face
->unpatented_hinting
)
5524 if ( CUR
.GS
.both_x_axis
)
5526 dx
= TT_MulFix14( args
[0], 0x4000 );
5532 dy
= TT_MulFix14( args
[0], 0x4000 );
5538 dx
= TT_MulFix14( args
[0], CUR
.GS
.freeVector
.x
);
5539 dy
= TT_MulFix14( args
[0], CUR
.GS
.freeVector
.y
);
5542 while ( CUR
.GS
.loop
> 0 )
5546 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5548 if ( BOUNDS( point
, CUR
.zp2
.n_points
) )
5550 if ( CUR
.pedantic_hinting
)
5552 CUR
.error
= TT_Err_Invalid_Reference
;
5557 MOVE_Zp2_Point( point
, dx
, dy
, TRUE
);
5563 CUR
.new_top
= CUR
.args
;
5567 /*************************************************************************/
5569 /* MSIRP[a]: Move Stack Indirect Relative Position */
5570 /* Opcode range: 0x3A-0x3B */
5571 /* Stack: f26.6 uint32 --> */
5574 Ins_MSIRP( INS_ARG
)
5577 FT_F26Dot6 distance
;
5580 point
= (FT_UShort
)args
[0];
5582 if ( BOUNDS( point
, CUR
.zp1
.n_points
) ||
5583 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5585 if ( CUR
.pedantic_hinting
)
5586 CUR
.error
= TT_Err_Invalid_Reference
;
5590 /* XXX: UNDOCUMENTED! behaviour */
5591 if ( CUR
.GS
.gep1
== 0 ) /* if the point that is to be moved */
5592 /* is in twilight zone */
5594 CUR
.zp1
.org
[point
] = CUR
.zp0
.org
[CUR
.GS
.rp0
];
5595 CUR_Func_move_orig( &CUR
.zp1
, point
, args
[1] );
5596 CUR
.zp1
.cur
[point
] = CUR
.zp1
.org
[point
];
5599 distance
= CUR_Func_project( CUR
.zp1
.cur
+ point
,
5600 CUR
.zp0
.cur
+ CUR
.GS
.rp0
);
5602 CUR_Func_move( &CUR
.zp1
, point
, args
[1] - distance
);
5604 CUR
.GS
.rp1
= CUR
.GS
.rp0
;
5607 if ( ( CUR
.opcode
& 1 ) != 0 )
5612 /*************************************************************************/
5614 /* MDAP[a]: Move Direct Absolute Point */
5615 /* Opcode range: 0x2E-0x2F */
5616 /* Stack: uint32 --> */
5622 FT_F26Dot6 cur_dist
,
5626 point
= (FT_UShort
)args
[0];
5628 if ( BOUNDS( point
, CUR
.zp0
.n_points
) )
5630 if ( CUR
.pedantic_hinting
)
5631 CUR
.error
= TT_Err_Invalid_Reference
;
5635 /* XXX: Is there some undocumented feature while in the */
5636 /* twilight zone? ? */
5637 if ( ( CUR
.opcode
& 1 ) != 0 )
5639 cur_dist
= CUR_fast_project( &CUR
.zp0
.cur
[point
] );
5640 distance
= CUR_Func_round( cur_dist
,
5641 CUR
.tt_metrics
.compensations
[0] ) - cur_dist
;
5646 CUR_Func_move( &CUR
.zp0
, point
, distance
);
5653 /*************************************************************************/
5655 /* MIAP[a]: Move Indirect Absolute Point */
5656 /* Opcode range: 0x3E-0x3F */
5657 /* Stack: uint32 uint32 --> */
5664 FT_F26Dot6 distance
,
5668 cvtEntry
= (FT_ULong
)args
[1];
5669 point
= (FT_UShort
)args
[0];
5671 if ( BOUNDS( point
, CUR
.zp0
.n_points
) ||
5672 BOUNDS( cvtEntry
, CUR
.cvtSize
) )
5674 if ( CUR
.pedantic_hinting
)
5675 CUR
.error
= TT_Err_Invalid_Reference
;
5679 /* XXX: UNDOCUMENTED! */
5681 /* The behaviour of an MIAP instruction is quite */
5682 /* different when used in the twilight zone. */
5684 /* First, no control value cut-in test is performed */
5685 /* as it would fail anyway. Second, the original */
5686 /* point, i.e. (org_x,org_y) of zp0.point, is set */
5687 /* to the absolute, unrounded distance found in */
5690 /* This is used in the CVT programs of the Microsoft */
5691 /* fonts Arial, Times, etc., in order to re-adjust */
5692 /* some key font heights. It allows the use of the */
5693 /* IP instruction in the twilight zone, which */
5694 /* otherwise would be `illegal' according to the */
5695 /* specification. */
5697 /* We implement it with a special sequence for the */
5698 /* twilight zone. This is a bad hack, but it seems */
5701 distance
= CUR_Func_read_cvt( cvtEntry
);
5703 if ( CUR
.GS
.gep0
== 0 ) /* If in twilight zone */
5705 CUR
.zp0
.org
[point
].x
= TT_MulFix14( distance
, CUR
.GS
.freeVector
.x
);
5706 CUR
.zp0
.org
[point
].y
= TT_MulFix14( distance
, CUR
.GS
.freeVector
.y
),
5707 CUR
.zp0
.cur
[point
] = CUR
.zp0
.org
[point
];
5710 org_dist
= CUR_fast_project( &CUR
.zp0
.cur
[point
] );
5712 if ( ( CUR
.opcode
& 1 ) != 0 ) /* rounding and control cutin flag */
5714 if ( FT_ABS( distance
- org_dist
) > CUR
.GS
.control_value_cutin
)
5715 distance
= org_dist
;
5717 distance
= CUR_Func_round( distance
, CUR
.tt_metrics
.compensations
[0] );
5720 CUR_Func_move( &CUR
.zp0
, point
, distance
- org_dist
);
5727 /*************************************************************************/
5729 /* MDRP[abcde]: Move Direct Relative Point */
5730 /* Opcode range: 0xC0-0xDF */
5731 /* Stack: uint32 --> */
5737 FT_F26Dot6 org_dist
, distance
;
5740 point
= (FT_UShort
)args
[0];
5742 if ( BOUNDS( point
, CUR
.zp1
.n_points
) ||
5743 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5745 if ( CUR
.pedantic_hinting
)
5746 CUR
.error
= TT_Err_Invalid_Reference
;
5750 /* XXX: Is there some undocumented feature while in the */
5751 /* twilight zone? */
5753 /* XXX: UNDOCUMENTED: twilight zone special case */
5755 if ( CUR
.GS
.gep0
== 0 || CUR
.GS
.gep1
== 0 )
5757 FT_Vector
* vec1
= &CUR
.zp1
.org
[point
];
5758 FT_Vector
* vec2
= &CUR
.zp0
.org
[CUR
.GS
.rp0
];
5761 org_dist
= CUR_Func_dualproj( vec1
, vec2
);
5765 FT_Vector
* vec1
= &CUR
.zp1
.orus
[point
];
5766 FT_Vector
* vec2
= &CUR
.zp0
.orus
[CUR
.GS
.rp0
];
5769 if ( CUR
.metrics
.x_scale
== CUR
.metrics
.y_scale
)
5771 /* this should be faster */
5772 org_dist
= CUR_Func_dualproj( vec1
, vec2
);
5773 org_dist
= TT_MULFIX( org_dist
, CUR
.metrics
.x_scale
);
5780 vec
.x
= TT_MULFIX( vec1
->x
- vec2
->x
, CUR
.metrics
.x_scale
);
5781 vec
.y
= TT_MULFIX( vec1
->y
- vec2
->y
, CUR
.metrics
.y_scale
);
5783 org_dist
= CUR_fast_dualproj( &vec
);
5787 /* single width cut-in test */
5789 if ( FT_ABS( org_dist
- CUR
.GS
.single_width_value
) <
5790 CUR
.GS
.single_width_cutin
)
5792 if ( org_dist
>= 0 )
5793 org_dist
= CUR
.GS
.single_width_value
;
5795 org_dist
= -CUR
.GS
.single_width_value
;
5800 if ( ( CUR
.opcode
& 4 ) != 0 )
5801 distance
= CUR_Func_round(
5803 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5805 distance
= ROUND_None(
5807 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5809 /* minimum distance flag */
5811 if ( ( CUR
.opcode
& 8 ) != 0 )
5813 if ( org_dist
>= 0 )
5815 if ( distance
< CUR
.GS
.minimum_distance
)
5816 distance
= CUR
.GS
.minimum_distance
;
5820 if ( distance
> -CUR
.GS
.minimum_distance
)
5821 distance
= -CUR
.GS
.minimum_distance
;
5825 /* now move the point */
5827 org_dist
= CUR_Func_project( CUR
.zp1
.cur
+ point
,
5828 CUR
.zp0
.cur
+ CUR
.GS
.rp0
);
5830 CUR_Func_move( &CUR
.zp1
, point
, distance
- org_dist
);
5832 CUR
.GS
.rp1
= CUR
.GS
.rp0
;
5835 if ( ( CUR
.opcode
& 16 ) != 0 )
5840 /*************************************************************************/
5842 /* MIRP[abcde]: Move Indirect Relative Point */
5843 /* Opcode range: 0xE0-0xFF */
5844 /* Stack: int32? uint32 --> */
5852 FT_F26Dot6 cvt_dist
,
5858 point
= (FT_UShort
)args
[0];
5859 cvtEntry
= (FT_ULong
)( args
[1] + 1 );
5861 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
5863 if ( BOUNDS( point
, CUR
.zp1
.n_points
) ||
5864 BOUNDS( cvtEntry
, CUR
.cvtSize
+ 1 ) ||
5865 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5867 if ( CUR
.pedantic_hinting
)
5868 CUR
.error
= TT_Err_Invalid_Reference
;
5875 cvt_dist
= CUR_Func_read_cvt( cvtEntry
- 1 );
5877 /* single width test */
5879 if ( FT_ABS( cvt_dist
- CUR
.GS
.single_width_value
) <
5880 CUR
.GS
.single_width_cutin
)
5882 if ( cvt_dist
>= 0 )
5883 cvt_dist
= CUR
.GS
.single_width_value
;
5885 cvt_dist
= -CUR
.GS
.single_width_value
;
5888 /* XXX: UNDOCUMENTED! -- twilight zone */
5890 if ( CUR
.GS
.gep1
== 0 )
5892 CUR
.zp1
.org
[point
].x
= CUR
.zp0
.org
[CUR
.GS
.rp0
].x
+
5893 TT_MulFix14( cvt_dist
, CUR
.GS
.freeVector
.x
);
5895 CUR
.zp1
.org
[point
].y
= CUR
.zp0
.org
[CUR
.GS
.rp0
].y
+
5896 TT_MulFix14( cvt_dist
, CUR
.GS
.freeVector
.y
);
5898 CUR
.zp1
.cur
[point
] = CUR
.zp0
.cur
[point
];
5901 org_dist
= CUR_Func_dualproj( &CUR
.zp1
.org
[point
],
5902 &CUR
.zp0
.org
[CUR
.GS
.rp0
] );
5903 cur_dist
= CUR_Func_project ( &CUR
.zp1
.cur
[point
],
5904 &CUR
.zp0
.cur
[CUR
.GS
.rp0
] );
5906 /* auto-flip test */
5908 if ( CUR
.GS
.auto_flip
)
5910 if ( ( org_dist
^ cvt_dist
) < 0 )
5911 cvt_dist
= -cvt_dist
;
5914 /* control value cutin and round */
5916 if ( ( CUR
.opcode
& 4 ) != 0 )
5918 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
5919 /* refer to the same zone. */
5921 if ( CUR
.GS
.gep0
== CUR
.GS
.gep1
)
5922 if ( FT_ABS( cvt_dist
- org_dist
) >= CUR
.GS
.control_value_cutin
)
5923 cvt_dist
= org_dist
;
5925 distance
= CUR_Func_round(
5927 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5930 distance
= ROUND_None(
5932 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5934 /* minimum distance test */
5936 if ( ( CUR
.opcode
& 8 ) != 0 )
5938 if ( org_dist
>= 0 )
5940 if ( distance
< CUR
.GS
.minimum_distance
)
5941 distance
= CUR
.GS
.minimum_distance
;
5945 if ( distance
> -CUR
.GS
.minimum_distance
)
5946 distance
= -CUR
.GS
.minimum_distance
;
5950 CUR_Func_move( &CUR
.zp1
, point
, distance
- cur_dist
);
5952 CUR
.GS
.rp1
= CUR
.GS
.rp0
;
5954 if ( ( CUR
.opcode
& 16 ) != 0 )
5957 /* XXX: UNDOCUMENTED! */
5962 /*************************************************************************/
5964 /* ALIGNRP[]: ALIGN Relative Point */
5965 /* Opcode range: 0x3C */
5966 /* Stack: uint32 uint32... --> */
5969 Ins_ALIGNRP( INS_ARG
)
5972 FT_F26Dot6 distance
;
5977 if ( CUR
.top
< CUR
.GS
.loop
||
5978 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5980 if ( CUR
.pedantic_hinting
)
5981 CUR
.error
= TT_Err_Invalid_Reference
;
5985 while ( CUR
.GS
.loop
> 0 )
5989 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5991 if ( BOUNDS( point
, CUR
.zp1
.n_points
) )
5993 if ( CUR
.pedantic_hinting
)
5995 CUR
.error
= TT_Err_Invalid_Reference
;
6001 distance
= CUR_Func_project( CUR
.zp1
.cur
+ point
,
6002 CUR
.zp0
.cur
+ CUR
.GS
.rp0
);
6004 CUR_Func_move( &CUR
.zp1
, point
, -distance
);
6011 CUR
.new_top
= CUR
.args
;
6015 /*************************************************************************/
6017 /* ISECT[]: moves point to InterSECTion */
6018 /* Opcode range: 0x0F */
6019 /* Stack: 5 * uint32 --> */
6022 Ins_ISECT( INS_ARG
)
6028 FT_F26Dot6 discriminant
;
6039 point
= (FT_UShort
)args
[0];
6041 a0
= (FT_UShort
)args
[1];
6042 a1
= (FT_UShort
)args
[2];
6043 b0
= (FT_UShort
)args
[3];
6044 b1
= (FT_UShort
)args
[4];
6046 if ( BOUNDS( b0
, CUR
.zp0
.n_points
) ||
6047 BOUNDS( b1
, CUR
.zp0
.n_points
) ||
6048 BOUNDS( a0
, CUR
.zp1
.n_points
) ||
6049 BOUNDS( a1
, CUR
.zp1
.n_points
) ||
6050 BOUNDS( point
, CUR
.zp2
.n_points
) )
6052 if ( CUR
.pedantic_hinting
)
6053 CUR
.error
= TT_Err_Invalid_Reference
;
6057 dbx
= CUR
.zp0
.cur
[b1
].x
- CUR
.zp0
.cur
[b0
].x
;
6058 dby
= CUR
.zp0
.cur
[b1
].y
- CUR
.zp0
.cur
[b0
].y
;
6060 dax
= CUR
.zp1
.cur
[a1
].x
- CUR
.zp1
.cur
[a0
].x
;
6061 day
= CUR
.zp1
.cur
[a1
].y
- CUR
.zp1
.cur
[a0
].y
;
6063 dx
= CUR
.zp0
.cur
[b0
].x
- CUR
.zp1
.cur
[a0
].x
;
6064 dy
= CUR
.zp0
.cur
[b0
].y
- CUR
.zp1
.cur
[a0
].y
;
6066 CUR
.zp2
.tags
[point
] |= FT_CURVE_TAG_TOUCH_BOTH
;
6068 discriminant
= TT_MULDIV( dax
, -dby
, 0x40 ) +
6069 TT_MULDIV( day
, dbx
, 0x40 );
6071 if ( FT_ABS( discriminant
) >= 0x40 )
6073 val
= TT_MULDIV( dx
, -dby
, 0x40 ) + TT_MULDIV( dy
, dbx
, 0x40 );
6075 R
.x
= TT_MULDIV( val
, dax
, discriminant
);
6076 R
.y
= TT_MULDIV( val
, day
, discriminant
);
6078 CUR
.zp2
.cur
[point
].x
= CUR
.zp1
.cur
[a0
].x
+ R
.x
;
6079 CUR
.zp2
.cur
[point
].y
= CUR
.zp1
.cur
[a0
].y
+ R
.y
;
6083 /* else, take the middle of the middles of A and B */
6085 CUR
.zp2
.cur
[point
].x
= ( CUR
.zp1
.cur
[a0
].x
+
6088 CUR
.zp0
.cur
[b1
].x
) / 4;
6089 CUR
.zp2
.cur
[point
].y
= ( CUR
.zp1
.cur
[a0
].y
+
6092 CUR
.zp0
.cur
[b1
].y
) / 4;
6097 /*************************************************************************/
6099 /* ALIGNPTS[]: ALIGN PoinTS */
6100 /* Opcode range: 0x27 */
6101 /* Stack: uint32 uint32 --> */
6104 Ins_ALIGNPTS( INS_ARG
)
6107 FT_F26Dot6 distance
;
6110 p1
= (FT_UShort
)args
[0];
6111 p2
= (FT_UShort
)args
[1];
6113 if ( BOUNDS( args
[0], CUR
.zp1
.n_points
) ||
6114 BOUNDS( args
[1], CUR
.zp0
.n_points
) )
6116 if ( CUR
.pedantic_hinting
)
6117 CUR
.error
= TT_Err_Invalid_Reference
;
6121 distance
= CUR_Func_project( CUR
.zp0
.cur
+ p2
,
6122 CUR
.zp1
.cur
+ p1
) / 2;
6124 CUR_Func_move( &CUR
.zp1
, p1
, distance
);
6125 CUR_Func_move( &CUR
.zp0
, p2
, -distance
);
6129 /*************************************************************************/
6131 /* IP[]: Interpolate Point */
6132 /* Opcode range: 0x39 */
6133 /* Stack: uint32... --> */
6136 /* SOMETIMES, DUMBER CODE IS BETTER CODE */
6141 FT_F26Dot6 old_range
, cur_range
;
6142 FT_Vector
* orus_base
;
6143 FT_Vector
* cur_base
;
6149 if ( CUR
.top
< CUR
.GS
.loop
)
6151 CUR
.error
= TT_Err_Invalid_Reference
;
6156 * We need to deal in a special way with the twilight zone.
6157 * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0),
6160 twilight
= CUR
.GS
.gep0
== 0 || CUR
.GS
.gep1
== 0 || CUR
.GS
.gep2
== 0;
6162 if ( BOUNDS( CUR
.GS
.rp1
, CUR
.zp0
.n_points
) )
6164 if ( CUR
.pedantic_hinting
)
6165 CUR
.error
= TT_Err_Invalid_Reference
;
6170 orus_base
= &CUR
.zp0
.org
[CUR
.GS
.rp1
];
6172 orus_base
= &CUR
.zp0
.orus
[CUR
.GS
.rp1
];
6174 cur_base
= &CUR
.zp0
.cur
[CUR
.GS
.rp1
];
6176 /* XXX: There are some glyphs in some braindead but popular */
6177 /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
6178 /* calling IP[] with bad values of rp[12]. */
6179 /* Do something sane when this odd thing happens. */
6180 if ( BOUNDS( CUR
.GS
.rp1
, CUR
.zp0
.n_points
) ||
6181 BOUNDS( CUR
.GS
.rp2
, CUR
.zp1
.n_points
) )
6189 old_range
= CUR_Func_dualproj( &CUR
.zp1
.org
[CUR
.GS
.rp2
],
6192 old_range
= CUR_Func_dualproj( &CUR
.zp1
.orus
[CUR
.GS
.rp2
],
6195 cur_range
= CUR_Func_project ( &CUR
.zp1
.cur
[CUR
.GS
.rp2
], cur_base
);
6198 for ( ; CUR
.GS
.loop
> 0; --CUR
.GS
.loop
)
6200 FT_UInt point
= (FT_UInt
)CUR
.stack
[--CUR
.args
];
6201 FT_F26Dot6 org_dist
, cur_dist
, new_dist
;
6204 /* check point bounds */
6205 if ( BOUNDS( point
, CUR
.zp2
.n_points
) )
6207 if ( CUR
.pedantic_hinting
)
6209 CUR
.error
= TT_Err_Invalid_Reference
;
6216 org_dist
= CUR_Func_dualproj( &CUR
.zp2
.org
[point
], orus_base
);
6218 org_dist
= CUR_Func_dualproj( &CUR
.zp2
.orus
[point
], orus_base
);
6220 cur_dist
= CUR_Func_project ( &CUR
.zp2
.cur
[point
], cur_base
);
6223 new_dist
= ( old_range
!= 0 )
6224 ? TT_MULDIV( org_dist
, cur_range
, old_range
)
6229 CUR_Func_move( &CUR
.zp2
, (FT_UShort
)point
, new_dist
- cur_dist
);
6232 CUR
.new_top
= CUR
.args
;
6236 /*************************************************************************/
6238 /* UTP[a]: UnTouch Point */
6239 /* Opcode range: 0x29 */
6240 /* Stack: uint32 --> */
6249 point
= (FT_UShort
)args
[0];
6251 if ( BOUNDS( point
, CUR
.zp0
.n_points
) )
6253 if ( CUR
.pedantic_hinting
)
6254 CUR
.error
= TT_Err_Invalid_Reference
;
6260 if ( CUR
.GS
.freeVector
.x
!= 0 )
6261 mask
&= ~FT_CURVE_TAG_TOUCH_X
;
6263 if ( CUR
.GS
.freeVector
.y
!= 0 )
6264 mask
&= ~FT_CURVE_TAG_TOUCH_Y
;
6266 CUR
.zp0
.tags
[point
] &= mask
;
6270 /* Local variables for Ins_IUP: */
6271 typedef struct IUP_WorkerRec_
6273 FT_Vector
* orgs
; /* original and current coordinate */
6274 FT_Vector
* curs
; /* arrays */
6278 } IUP_WorkerRec
, *IUP_Worker
;
6282 _iup_worker_shift( IUP_Worker worker
,
6291 dx
= worker
->curs
[p
].x
- worker
->orgs
[p
].x
;
6294 for ( i
= p1
; i
< p
; i
++ )
6295 worker
->curs
[i
].x
+= dx
;
6297 for ( i
= p
+ 1; i
<= p2
; i
++ )
6298 worker
->curs
[i
].x
+= dx
;
6304 _iup_worker_interpolate( IUP_Worker worker
,
6311 FT_F26Dot6 orus1
, orus2
, org1
, org2
, delta1
, delta2
;
6317 if ( BOUNDS( ref1
, worker
->max_points
) ||
6318 BOUNDS( ref2
, worker
->max_points
) )
6321 orus1
= worker
->orus
[ref1
].x
;
6322 orus2
= worker
->orus
[ref2
].x
;
6324 if ( orus1
> orus2
)
6339 org1
= worker
->orgs
[ref1
].x
;
6340 org2
= worker
->orgs
[ref2
].x
;
6341 delta1
= worker
->curs
[ref1
].x
- org1
;
6342 delta2
= worker
->curs
[ref2
].x
- org2
;
6344 if ( orus1
== orus2
)
6346 /* simple shift of untouched points */
6347 for ( i
= p1
; i
<= p2
; i
++ )
6349 FT_F26Dot6 x
= worker
->orgs
[i
].x
;
6357 worker
->curs
[i
].x
= x
;
6363 FT_Bool scale_valid
= 0;
6367 for ( i
= p1
; i
<= p2
; i
++ )
6369 FT_F26Dot6 x
= worker
->orgs
[i
].x
;
6375 else if ( x
>= org2
)
6383 scale
= TT_MULDIV( org2
+ delta2
- ( org1
+ delta1
),
6384 0x10000, orus2
- orus1
);
6387 x
= ( org1
+ delta1
) +
6388 TT_MULFIX( worker
->orus
[i
].x
- orus1
, scale
);
6390 worker
->curs
[i
].x
= x
;
6396 /*************************************************************************/
6398 /* IUP[a]: Interpolate Untouched Points */
6399 /* Opcode range: 0x30-0x31 */
6408 FT_UInt first_point
; /* first point of contour */
6409 FT_UInt end_point
; /* end point (last+1) of contour */
6411 FT_UInt first_touched
; /* first touched point in contour */
6412 FT_UInt cur_touched
; /* current touched point in contour */
6414 FT_UInt point
; /* current point */
6415 FT_Short contour
; /* current contour */
6420 /* ignore empty outlines */
6421 if ( CUR
.pts
.n_contours
== 0 )
6424 if ( CUR
.opcode
& 1 )
6426 mask
= FT_CURVE_TAG_TOUCH_X
;
6427 V
.orgs
= CUR
.pts
.org
;
6428 V
.curs
= CUR
.pts
.cur
;
6429 V
.orus
= CUR
.pts
.orus
;
6433 mask
= FT_CURVE_TAG_TOUCH_Y
;
6434 V
.orgs
= (FT_Vector
*)( (FT_Pos
*)CUR
.pts
.org
+ 1 );
6435 V
.curs
= (FT_Vector
*)( (FT_Pos
*)CUR
.pts
.cur
+ 1 );
6436 V
.orus
= (FT_Vector
*)( (FT_Pos
*)CUR
.pts
.orus
+ 1 );
6438 V
.max_points
= CUR
.pts
.n_points
;
6445 end_point
= CUR
.pts
.contours
[contour
] - CUR
.pts
.first_point
;
6446 first_point
= point
;
6448 if ( CUR
.pts
.n_points
<= end_point
)
6449 end_point
= CUR
.pts
.n_points
;
6451 while ( point
<= end_point
&& ( CUR
.pts
.tags
[point
] & mask
) == 0 )
6454 if ( point
<= end_point
)
6456 first_touched
= point
;
6457 cur_touched
= point
;
6461 while ( point
<= end_point
)
6463 if ( ( CUR
.pts
.tags
[point
] & mask
) != 0 )
6466 _iup_worker_interpolate( &V
,
6471 cur_touched
= point
;
6477 if ( cur_touched
== first_touched
)
6478 _iup_worker_shift( &V
, first_point
, end_point
, cur_touched
);
6481 _iup_worker_interpolate( &V
,
6482 (FT_UShort
)( cur_touched
+ 1 ),
6487 if ( first_touched
> 0 )
6488 _iup_worker_interpolate( &V
,
6496 } while ( contour
< CUR
.pts
.n_contours
);
6500 /*************************************************************************/
6502 /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
6503 /* Opcode range: 0x5D,0x71,0x72 */
6504 /* Stack: uint32 (2 * uint32)... --> */
6507 Ins_DELTAP( INS_ARG
)
6515 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
6516 /* Delta hinting is covered by US Patent 5159668. */
6517 if ( CUR
.face
->unpatented_hinting
)
6519 FT_Long n
= args
[0] * 2;
6524 CUR
.error
= TT_Err_Too_Few_Arguments
;
6529 CUR
.new_top
= CUR
.args
;
6534 nump
= (FT_ULong
)args
[0]; /* some points theoretically may occur more
6535 than once, thus UShort isn't enough */
6537 for ( k
= 1; k
<= nump
; k
++ )
6541 CUR
.error
= TT_Err_Too_Few_Arguments
;
6547 A
= (FT_UShort
)CUR
.stack
[CUR
.args
+ 1];
6548 B
= CUR
.stack
[CUR
.args
];
6550 /* XXX: Because some popular fonts contain some invalid DeltaP */
6551 /* instructions, we simply ignore them when the stacked */
6552 /* point reference is off limit, rather than returning an */
6553 /* error. As a delta instruction doesn't change a glyph */
6554 /* in great ways, this shouldn't be a problem. */
6556 if ( !BOUNDS( A
, CUR
.zp0
.n_points
) )
6558 C
= ( (FT_ULong
)B
& 0xF0 ) >> 4;
6560 switch ( CUR
.opcode
)
6574 C
+= CUR
.GS
.delta_base
;
6576 if ( CURRENT_Ppem() == (FT_Long
)C
)
6578 B
= ( (FT_ULong
)B
& 0xF ) - 8;
6581 B
= B
* 64 / ( 1L << CUR
.GS
.delta_shift
);
6583 CUR_Func_move( &CUR
.zp0
, A
, B
);
6587 if ( CUR
.pedantic_hinting
)
6588 CUR
.error
= TT_Err_Invalid_Reference
;
6591 CUR
.new_top
= CUR
.args
;
6595 /*************************************************************************/
6597 /* DELTACn[]: DELTA exceptions C1, C2, C3 */
6598 /* Opcode range: 0x73,0x74,0x75 */
6599 /* Stack: uint32 (2 * uint32)... --> */
6602 Ins_DELTAC( INS_ARG
)
6609 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
6610 /* Delta hinting is covered by US Patent 5159668. */
6611 if ( CUR
.face
->unpatented_hinting
)
6613 FT_Long n
= args
[0] * 2;
6618 CUR
.error
= TT_Err_Too_Few_Arguments
;
6623 CUR
.new_top
= CUR
.args
;
6628 nump
= (FT_ULong
)args
[0];
6630 for ( k
= 1; k
<= nump
; k
++ )
6634 CUR
.error
= TT_Err_Too_Few_Arguments
;
6640 A
= (FT_ULong
)CUR
.stack
[CUR
.args
+ 1];
6641 B
= CUR
.stack
[CUR
.args
];
6643 if ( BOUNDS( A
, CUR
.cvtSize
) )
6645 if ( CUR
.pedantic_hinting
)
6647 CUR
.error
= TT_Err_Invalid_Reference
;
6653 C
= ( (FT_ULong
)B
& 0xF0 ) >> 4;
6655 switch ( CUR
.opcode
)
6669 C
+= CUR
.GS
.delta_base
;
6671 if ( CURRENT_Ppem() == (FT_Long
)C
)
6673 B
= ( (FT_ULong
)B
& 0xF ) - 8;
6676 B
= B
* 64 / ( 1L << CUR
.GS
.delta_shift
);
6678 CUR_Func_move_cvt( A
, B
);
6683 CUR
.new_top
= CUR
.args
;
6687 /*************************************************************************/
6689 /* MISC. INSTRUCTIONS */
6691 /*************************************************************************/
6694 /*************************************************************************/
6696 /* GETINFO[]: GET INFOrmation */
6697 /* Opcode range: 0x88 */
6698 /* Stack: uint32 --> uint32 */
6701 Ins_GETINFO( INS_ARG
)
6708 /* We return MS rasterizer version 1.7 for the font scaler. */
6709 if ( ( args
[0] & 1 ) != 0 )
6712 /* Has the glyph been rotated? */
6713 if ( ( args
[0] & 2 ) != 0 && CUR
.tt_metrics
.rotated
)
6716 /* Has the glyph been stretched? */
6717 if ( ( args
[0] & 4 ) != 0 && CUR
.tt_metrics
.stretched
)
6720 /* Are we hinting for grayscale? */
6721 if ( ( args
[0] & 32 ) != 0 && CUR
.grayscale
)
6729 Ins_UNKNOWN( INS_ARG
)
6731 TT_DefRecord
* def
= CUR
.IDefs
;
6732 TT_DefRecord
* limit
= def
+ CUR
.numIDefs
;
6737 for ( ; def
< limit
; def
++ )
6739 if ( (FT_Byte
)def
->opc
== CUR
.opcode
&& def
->active
)
6744 if ( CUR
.callTop
>= CUR
.callSize
)
6746 CUR
.error
= TT_Err_Stack_Overflow
;
6750 call
= CUR
.callStack
+ CUR
.callTop
++;
6752 call
->Caller_Range
= CUR
.curRange
;
6753 call
->Caller_IP
= CUR
.IP
+1;
6754 call
->Cur_Count
= 1;
6755 call
->Cur_Restart
= def
->start
;
6757 INS_Goto_CodeRange( def
->range
, def
->start
);
6759 CUR
.step_ins
= FALSE
;
6764 CUR
.error
= TT_Err_Invalid_Opcode
;
6768 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
6772 TInstruction_Function Instruct_Dispatch
[256] =
6774 /* Opcodes are gathered in groups of 16. */
6775 /* Please keep the spaces as they are. */
6777 /* SVTCA y */ Ins_SVTCA
,
6778 /* SVTCA x */ Ins_SVTCA
,
6779 /* SPvTCA y */ Ins_SPVTCA
,
6780 /* SPvTCA x */ Ins_SPVTCA
,
6781 /* SFvTCA y */ Ins_SFVTCA
,
6782 /* SFvTCA x */ Ins_SFVTCA
,
6783 /* SPvTL // */ Ins_SPVTL
,
6784 /* SPvTL + */ Ins_SPVTL
,
6785 /* SFvTL // */ Ins_SFVTL
,
6786 /* SFvTL + */ Ins_SFVTL
,
6787 /* SPvFS */ Ins_SPVFS
,
6788 /* SFvFS */ Ins_SFVFS
,
6791 /* SFvTPv */ Ins_SFVTPV
,
6792 /* ISECT */ Ins_ISECT
,
6794 /* SRP0 */ Ins_SRP0
,
6795 /* SRP1 */ Ins_SRP1
,
6796 /* SRP2 */ Ins_SRP2
,
6797 /* SZP0 */ Ins_SZP0
,
6798 /* SZP1 */ Ins_SZP1
,
6799 /* SZP2 */ Ins_SZP2
,
6800 /* SZPS */ Ins_SZPS
,
6801 /* SLOOP */ Ins_SLOOP
,
6803 /* RTHG */ Ins_RTHG
,
6805 /* ELSE */ Ins_ELSE
,
6806 /* JMPR */ Ins_JMPR
,
6807 /* SCvTCi */ Ins_SCVTCI
,
6808 /* SSwCi */ Ins_SSWCI
,
6813 /* CLEAR */ Ins_CLEAR
,
6814 /* SWAP */ Ins_SWAP
,
6815 /* DEPTH */ Ins_DEPTH
,
6816 /* CINDEX */ Ins_CINDEX
,
6817 /* MINDEX */ Ins_MINDEX
,
6818 /* AlignPTS */ Ins_ALIGNPTS
,
6819 /* INS_0x28 */ Ins_UNKNOWN
,
6821 /* LOOPCALL */ Ins_LOOPCALL
,
6822 /* CALL */ Ins_CALL
,
6823 /* FDEF */ Ins_FDEF
,
6824 /* ENDF */ Ins_ENDF
,
6825 /* MDAP[0] */ Ins_MDAP
,
6826 /* MDAP[1] */ Ins_MDAP
,
6828 /* IUP[0] */ Ins_IUP
,
6829 /* IUP[1] */ Ins_IUP
,
6830 /* SHP[0] */ Ins_SHP
,
6831 /* SHP[1] */ Ins_SHP
,
6832 /* SHC[0] */ Ins_SHC
,
6833 /* SHC[1] */ Ins_SHC
,
6834 /* SHZ[0] */ Ins_SHZ
,
6835 /* SHZ[1] */ Ins_SHZ
,
6836 /* SHPIX */ Ins_SHPIX
,
6838 /* MSIRP[0] */ Ins_MSIRP
,
6839 /* MSIRP[1] */ Ins_MSIRP
,
6840 /* AlignRP */ Ins_ALIGNRP
,
6841 /* RTDG */ Ins_RTDG
,
6842 /* MIAP[0] */ Ins_MIAP
,
6843 /* MIAP[1] */ Ins_MIAP
,
6845 /* NPushB */ Ins_NPUSHB
,
6846 /* NPushW */ Ins_NPUSHW
,
6849 /* WCvtP */ Ins_WCVTP
,
6850 /* RCvt */ Ins_RCVT
,
6853 /* SCFS */ Ins_SCFS
,
6856 /* MPPEM */ Ins_MPPEM
,
6858 /* FlipON */ Ins_FLIPON
,
6859 /* FlipOFF */ Ins_FLIPOFF
,
6860 /* DEBUG */ Ins_DEBUG
,
6863 /* LTEQ */ Ins_LTEQ
,
6865 /* GTEQ */ Ins_GTEQ
,
6869 /* EVEN */ Ins_EVEN
,
6875 /* DeltaP1 */ Ins_DELTAP
,
6885 /* FLOOR */ Ins_FLOOR
,
6886 /* CEILING */ Ins_CEILING
,
6887 /* ROUND[0] */ Ins_ROUND
,
6888 /* ROUND[1] */ Ins_ROUND
,
6889 /* ROUND[2] */ Ins_ROUND
,
6890 /* ROUND[3] */ Ins_ROUND
,
6891 /* NROUND[0] */ Ins_NROUND
,
6892 /* NROUND[1] */ Ins_NROUND
,
6893 /* NROUND[2] */ Ins_NROUND
,
6894 /* NROUND[3] */ Ins_NROUND
,
6896 /* WCvtF */ Ins_WCVTF
,
6897 /* DeltaP2 */ Ins_DELTAP
,
6898 /* DeltaP3 */ Ins_DELTAP
,
6899 /* DeltaCn[0] */ Ins_DELTAC
,
6900 /* DeltaCn[1] */ Ins_DELTAC
,
6901 /* DeltaCn[2] */ Ins_DELTAC
,
6902 /* SROUND */ Ins_SROUND
,
6903 /* S45Round */ Ins_S45ROUND
,
6904 /* JROT */ Ins_JROT
,
6905 /* JROF */ Ins_JROF
,
6906 /* ROFF */ Ins_ROFF
,
6907 /* INS_0x7B */ Ins_UNKNOWN
,
6908 /* RUTG */ Ins_RUTG
,
6909 /* RDTG */ Ins_RDTG
,
6910 /* SANGW */ Ins_SANGW
,
6913 /* FlipPT */ Ins_FLIPPT
,
6914 /* FlipRgON */ Ins_FLIPRGON
,
6915 /* FlipRgOFF */ Ins_FLIPRGOFF
,
6916 /* INS_0x83 */ Ins_UNKNOWN
,
6917 /* INS_0x84 */ Ins_UNKNOWN
,
6918 /* ScanCTRL */ Ins_SCANCTRL
,
6919 /* SDPVTL[0] */ Ins_SDPVTL
,
6920 /* SDPVTL[1] */ Ins_SDPVTL
,
6921 /* GetINFO */ Ins_GETINFO
,
6922 /* IDEF */ Ins_IDEF
,
6923 /* ROLL */ Ins_ROLL
,
6926 /* ScanTYPE */ Ins_SCANTYPE
,
6927 /* InstCTRL */ Ins_INSTCTRL
,
6928 /* INS_0x8F */ Ins_UNKNOWN
,
6930 /* INS_0x90 */ Ins_UNKNOWN
,
6931 /* INS_0x91 */ Ins_UNKNOWN
,
6932 /* INS_0x92 */ Ins_UNKNOWN
,
6933 /* INS_0x93 */ Ins_UNKNOWN
,
6934 /* INS_0x94 */ Ins_UNKNOWN
,
6935 /* INS_0x95 */ Ins_UNKNOWN
,
6936 /* INS_0x96 */ Ins_UNKNOWN
,
6937 /* INS_0x97 */ Ins_UNKNOWN
,
6938 /* INS_0x98 */ Ins_UNKNOWN
,
6939 /* INS_0x99 */ Ins_UNKNOWN
,
6940 /* INS_0x9A */ Ins_UNKNOWN
,
6941 /* INS_0x9B */ Ins_UNKNOWN
,
6942 /* INS_0x9C */ Ins_UNKNOWN
,
6943 /* INS_0x9D */ Ins_UNKNOWN
,
6944 /* INS_0x9E */ Ins_UNKNOWN
,
6945 /* INS_0x9F */ Ins_UNKNOWN
,
6947 /* INS_0xA0 */ Ins_UNKNOWN
,
6948 /* INS_0xA1 */ Ins_UNKNOWN
,
6949 /* INS_0xA2 */ Ins_UNKNOWN
,
6950 /* INS_0xA3 */ Ins_UNKNOWN
,
6951 /* INS_0xA4 */ Ins_UNKNOWN
,
6952 /* INS_0xA5 */ Ins_UNKNOWN
,
6953 /* INS_0xA6 */ Ins_UNKNOWN
,
6954 /* INS_0xA7 */ Ins_UNKNOWN
,
6955 /* INS_0xA8 */ Ins_UNKNOWN
,
6956 /* INS_0xA9 */ Ins_UNKNOWN
,
6957 /* INS_0xAA */ Ins_UNKNOWN
,
6958 /* INS_0xAB */ Ins_UNKNOWN
,
6959 /* INS_0xAC */ Ins_UNKNOWN
,
6960 /* INS_0xAD */ Ins_UNKNOWN
,
6961 /* INS_0xAE */ Ins_UNKNOWN
,
6962 /* INS_0xAF */ Ins_UNKNOWN
,
6964 /* PushB[0] */ Ins_PUSHB
,
6965 /* PushB[1] */ Ins_PUSHB
,
6966 /* PushB[2] */ Ins_PUSHB
,
6967 /* PushB[3] */ Ins_PUSHB
,
6968 /* PushB[4] */ Ins_PUSHB
,
6969 /* PushB[5] */ Ins_PUSHB
,
6970 /* PushB[6] */ Ins_PUSHB
,
6971 /* PushB[7] */ Ins_PUSHB
,
6972 /* PushW[0] */ Ins_PUSHW
,
6973 /* PushW[1] */ Ins_PUSHW
,
6974 /* PushW[2] */ Ins_PUSHW
,
6975 /* PushW[3] */ Ins_PUSHW
,
6976 /* PushW[4] */ Ins_PUSHW
,
6977 /* PushW[5] */ Ins_PUSHW
,
6978 /* PushW[6] */ Ins_PUSHW
,
6979 /* PushW[7] */ Ins_PUSHW
,
6981 /* MDRP[00] */ Ins_MDRP
,
6982 /* MDRP[01] */ Ins_MDRP
,
6983 /* MDRP[02] */ Ins_MDRP
,
6984 /* MDRP[03] */ Ins_MDRP
,
6985 /* MDRP[04] */ Ins_MDRP
,
6986 /* MDRP[05] */ Ins_MDRP
,
6987 /* MDRP[06] */ Ins_MDRP
,
6988 /* MDRP[07] */ Ins_MDRP
,
6989 /* MDRP[08] */ Ins_MDRP
,
6990 /* MDRP[09] */ Ins_MDRP
,
6991 /* MDRP[10] */ Ins_MDRP
,
6992 /* MDRP[11] */ Ins_MDRP
,
6993 /* MDRP[12] */ Ins_MDRP
,
6994 /* MDRP[13] */ Ins_MDRP
,
6995 /* MDRP[14] */ Ins_MDRP
,
6996 /* MDRP[15] */ Ins_MDRP
,
6998 /* MDRP[16] */ Ins_MDRP
,
6999 /* MDRP[17] */ Ins_MDRP
,
7000 /* MDRP[18] */ Ins_MDRP
,
7001 /* MDRP[19] */ Ins_MDRP
,
7002 /* MDRP[20] */ Ins_MDRP
,
7003 /* MDRP[21] */ Ins_MDRP
,
7004 /* MDRP[22] */ Ins_MDRP
,
7005 /* MDRP[23] */ Ins_MDRP
,
7006 /* MDRP[24] */ Ins_MDRP
,
7007 /* MDRP[25] */ Ins_MDRP
,
7008 /* MDRP[26] */ Ins_MDRP
,
7009 /* MDRP[27] */ Ins_MDRP
,
7010 /* MDRP[28] */ Ins_MDRP
,
7011 /* MDRP[29] */ Ins_MDRP
,
7012 /* MDRP[30] */ Ins_MDRP
,
7013 /* MDRP[31] */ Ins_MDRP
,
7015 /* MIRP[00] */ Ins_MIRP
,
7016 /* MIRP[01] */ Ins_MIRP
,
7017 /* MIRP[02] */ Ins_MIRP
,
7018 /* MIRP[03] */ Ins_MIRP
,
7019 /* MIRP[04] */ Ins_MIRP
,
7020 /* MIRP[05] */ Ins_MIRP
,
7021 /* MIRP[06] */ Ins_MIRP
,
7022 /* MIRP[07] */ Ins_MIRP
,
7023 /* MIRP[08] */ Ins_MIRP
,
7024 /* MIRP[09] */ Ins_MIRP
,
7025 /* MIRP[10] */ Ins_MIRP
,
7026 /* MIRP[11] */ Ins_MIRP
,
7027 /* MIRP[12] */ Ins_MIRP
,
7028 /* MIRP[13] */ Ins_MIRP
,
7029 /* MIRP[14] */ Ins_MIRP
,
7030 /* MIRP[15] */ Ins_MIRP
,
7032 /* MIRP[16] */ Ins_MIRP
,
7033 /* MIRP[17] */ Ins_MIRP
,
7034 /* MIRP[18] */ Ins_MIRP
,
7035 /* MIRP[19] */ Ins_MIRP
,
7036 /* MIRP[20] */ Ins_MIRP
,
7037 /* MIRP[21] */ Ins_MIRP
,
7038 /* MIRP[22] */ Ins_MIRP
,
7039 /* MIRP[23] */ Ins_MIRP
,
7040 /* MIRP[24] */ Ins_MIRP
,
7041 /* MIRP[25] */ Ins_MIRP
,
7042 /* MIRP[26] */ Ins_MIRP
,
7043 /* MIRP[27] */ Ins_MIRP
,
7044 /* MIRP[28] */ Ins_MIRP
,
7045 /* MIRP[29] */ Ins_MIRP
,
7046 /* MIRP[30] */ Ins_MIRP
,
7047 /* MIRP[31] */ Ins_MIRP
7051 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7054 /*************************************************************************/
7058 /* This function executes a run of opcodes. It will exit in the */
7059 /* following cases: */
7061 /* - Errors (in which case it returns FALSE). */
7063 /* - Reaching the end of the main code range (returns TRUE). */
7064 /* Reaching the end of a code range within a function call is an */
7067 /* - After executing one single opcode, if the flag `Instruction_Trap' */
7068 /* is set to TRUE (returns TRUE). */
7070 /* On exit with TRUE, test IP < CodeSize to know whether it comes from */
7071 /* an instruction trap or a normal termination. */
7074 /* Note: The documented DEBUG opcode pops a value from the stack. This */
7075 /* behaviour is unsupported; here a DEBUG opcode is always an */
7079 /* THIS IS THE INTERPRETER'S MAIN LOOP. */
7081 /* Instructions appear in the specification's order. */
7083 /*************************************************************************/
7086 /* documentation is in ttinterp.h */
7088 FT_EXPORT_DEF( FT_Error
)
7089 TT_RunIns( TT_ExecContext exc
)
7091 FT_Long ins_counter
= 0; /* executed instructions counter */
7094 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7098 /* set CVT functions */
7099 CUR
.tt_metrics
.ratio
= 0;
7100 if ( CUR
.metrics
.x_ppem
!= CUR
.metrics
.y_ppem
)
7102 /* non-square pixels, use the stretched routines */
7103 CUR
.func_read_cvt
= Read_CVT_Stretched
;
7104 CUR
.func_write_cvt
= Write_CVT_Stretched
;
7105 CUR
.func_move_cvt
= Move_CVT_Stretched
;
7109 /* square pixels, use normal routines */
7110 CUR
.func_read_cvt
= Read_CVT
;
7111 CUR
.func_write_cvt
= Write_CVT
;
7112 CUR
.func_move_cvt
= Move_CVT
;
7116 COMPUTE_Round( (FT_Byte
)exc
->GS
.round_state
);
7120 CUR
.opcode
= CUR
.code
[CUR
.IP
];
7122 if ( ( CUR
.length
= opcode_length
[CUR
.opcode
] ) < 0 )
7124 if ( CUR
.IP
+ 1 > CUR
.codeSize
)
7125 goto LErrorCodeOverflow_
;
7127 CUR
.length
= 2 - CUR
.length
* CUR
.code
[CUR
.IP
+ 1];
7130 if ( CUR
.IP
+ CUR
.length
> CUR
.codeSize
)
7131 goto LErrorCodeOverflow_
;
7133 /* First, let's check for empty stack and overflow */
7134 CUR
.args
= CUR
.top
- ( Pop_Push_Count
[CUR
.opcode
] >> 4 );
7136 /* `args' is the top of the stack once arguments have been popped. */
7137 /* One can also interpret it as the index of the last argument. */
7140 CUR
.error
= TT_Err_Too_Few_Arguments
;
7144 CUR
.new_top
= CUR
.args
+ ( Pop_Push_Count
[CUR
.opcode
] & 15 );
7146 /* `new_top' is the new top of the stack, after the instruction's */
7147 /* execution. `top' will be set to `new_top' after the `switch' */
7149 if ( CUR
.new_top
> CUR
.stackSize
)
7151 CUR
.error
= TT_Err_Stack_Overflow
;
7155 CUR
.step_ins
= TRUE
;
7156 CUR
.error
= TT_Err_Ok
;
7158 #ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
7161 FT_Long
* args
= CUR
.stack
+ CUR
.args
;
7162 FT_Byte opcode
= CUR
.opcode
;
7165 #undef ARRAY_BOUND_ERROR
7166 #define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
7171 case 0x00: /* SVTCA y */
7172 case 0x01: /* SVTCA x */
7173 case 0x02: /* SPvTCA y */
7174 case 0x03: /* SPvTCA x */
7175 case 0x04: /* SFvTCA y */
7176 case 0x05: /* SFvTCA x */
7181 AA
= (FT_Short
)( ( opcode
& 1 ) << 14 );
7182 BB
= (FT_Short
)( AA
^ 0x4000 );
7186 CUR
.GS
.projVector
.x
= AA
;
7187 CUR
.GS
.projVector
.y
= BB
;
7189 CUR
.GS
.dualVector
.x
= AA
;
7190 CUR
.GS
.dualVector
.y
= BB
;
7194 GUESS_VECTOR( projVector
);
7197 if ( ( opcode
& 2 ) == 0 )
7199 CUR
.GS
.freeVector
.x
= AA
;
7200 CUR
.GS
.freeVector
.y
= BB
;
7204 GUESS_VECTOR( freeVector
);
7211 case 0x06: /* SPvTL // */
7212 case 0x07: /* SPvTL + */
7216 case 0x08: /* SFvTL // */
7217 case 0x09: /* SFvTL + */
7221 case 0x0A: /* SPvFS */
7225 case 0x0B: /* SFvFS */
7229 case 0x0C: /* GPV */
7233 case 0x0D: /* GFV */
7237 case 0x0E: /* SFvTPv */
7241 case 0x0F: /* ISECT */
7242 Ins_ISECT( EXEC_ARG_ args
);
7245 case 0x10: /* SRP0 */
7249 case 0x11: /* SRP1 */
7253 case 0x12: /* SRP2 */
7257 case 0x13: /* SZP0 */
7258 Ins_SZP0( EXEC_ARG_ args
);
7261 case 0x14: /* SZP1 */
7262 Ins_SZP1( EXEC_ARG_ args
);
7265 case 0x15: /* SZP2 */
7266 Ins_SZP2( EXEC_ARG_ args
);
7269 case 0x16: /* SZPS */
7270 Ins_SZPS( EXEC_ARG_ args
);
7273 case 0x17: /* SLOOP */
7277 case 0x18: /* RTG */
7281 case 0x19: /* RTHG */
7285 case 0x1A: /* SMD */
7289 case 0x1B: /* ELSE */
7290 Ins_ELSE( EXEC_ARG_ args
);
7293 case 0x1C: /* JMPR */
7297 case 0x1D: /* SCVTCI */
7301 case 0x1E: /* SSWCI */
7305 case 0x1F: /* SSW */
7309 case 0x20: /* DUP */
7313 case 0x21: /* POP */
7317 case 0x22: /* CLEAR */
7321 case 0x23: /* SWAP */
7325 case 0x24: /* DEPTH */
7329 case 0x25: /* CINDEX */
7333 case 0x26: /* MINDEX */
7334 Ins_MINDEX( EXEC_ARG_ args
);
7337 case 0x27: /* ALIGNPTS */
7338 Ins_ALIGNPTS( EXEC_ARG_ args
);
7341 case 0x28: /* ???? */
7342 Ins_UNKNOWN( EXEC_ARG_ args
);
7345 case 0x29: /* UTP */
7346 Ins_UTP( EXEC_ARG_ args
);
7349 case 0x2A: /* LOOPCALL */
7350 Ins_LOOPCALL( EXEC_ARG_ args
);
7353 case 0x2B: /* CALL */
7354 Ins_CALL( EXEC_ARG_ args
);
7357 case 0x2C: /* FDEF */
7358 Ins_FDEF( EXEC_ARG_ args
);
7361 case 0x2D: /* ENDF */
7362 Ins_ENDF( EXEC_ARG_ args
);
7365 case 0x2E: /* MDAP */
7366 case 0x2F: /* MDAP */
7367 Ins_MDAP( EXEC_ARG_ args
);
7371 case 0x30: /* IUP */
7372 case 0x31: /* IUP */
7373 Ins_IUP( EXEC_ARG_ args
);
7376 case 0x32: /* SHP */
7377 case 0x33: /* SHP */
7378 Ins_SHP( EXEC_ARG_ args
);
7381 case 0x34: /* SHC */
7382 case 0x35: /* SHC */
7383 Ins_SHC( EXEC_ARG_ args
);
7386 case 0x36: /* SHZ */
7387 case 0x37: /* SHZ */
7388 Ins_SHZ( EXEC_ARG_ args
);
7391 case 0x38: /* SHPIX */
7392 Ins_SHPIX( EXEC_ARG_ args
);
7396 Ins_IP( EXEC_ARG_ args
);
7399 case 0x3A: /* MSIRP */
7400 case 0x3B: /* MSIRP */
7401 Ins_MSIRP( EXEC_ARG_ args
);
7404 case 0x3C: /* AlignRP */
7405 Ins_ALIGNRP( EXEC_ARG_ args
);
7408 case 0x3D: /* RTDG */
7412 case 0x3E: /* MIAP */
7413 case 0x3F: /* MIAP */
7414 Ins_MIAP( EXEC_ARG_ args
);
7417 case 0x40: /* NPUSHB */
7418 Ins_NPUSHB( EXEC_ARG_ args
);
7421 case 0x41: /* NPUSHW */
7422 Ins_NPUSHW( EXEC_ARG_ args
);
7430 CUR
.error
= TT_Err_Invalid_Reference
;
7437 case 0x44: /* WCVTP */
7441 case 0x45: /* RCVT */
7447 Ins_GC( EXEC_ARG_ args
);
7450 case 0x48: /* SCFS */
7451 Ins_SCFS( EXEC_ARG_ args
);
7456 Ins_MD( EXEC_ARG_ args
);
7459 case 0x4B: /* MPPEM */
7463 case 0x4C: /* MPS */
7467 case 0x4D: /* FLIPON */
7471 case 0x4E: /* FLIPOFF */
7475 case 0x4F: /* DEBUG */
7483 case 0x51: /* LTEQ */
7491 case 0x53: /* GTEQ */
7499 case 0x55: /* NEQ */
7503 case 0x56: /* ODD */
7507 case 0x57: /* EVEN */
7512 Ins_IF( EXEC_ARG_ args
);
7515 case 0x59: /* EIF */
7519 case 0x5A: /* AND */
7527 case 0x5C: /* NOT */
7531 case 0x5D: /* DELTAP1 */
7532 Ins_DELTAP( EXEC_ARG_ args
);
7535 case 0x5E: /* SDB */
7539 case 0x5F: /* SDS */
7543 case 0x60: /* ADD */
7547 case 0x61: /* SUB */
7551 case 0x62: /* DIV */
7555 case 0x63: /* MUL */
7559 case 0x64: /* ABS */
7563 case 0x65: /* NEG */
7567 case 0x66: /* FLOOR */
7571 case 0x67: /* CEILING */
7575 case 0x68: /* ROUND */
7576 case 0x69: /* ROUND */
7577 case 0x6A: /* ROUND */
7578 case 0x6B: /* ROUND */
7582 case 0x6C: /* NROUND */
7583 case 0x6D: /* NROUND */
7584 case 0x6E: /* NRRUND */
7585 case 0x6F: /* NROUND */
7589 case 0x70: /* WCVTF */
7593 case 0x71: /* DELTAP2 */
7594 case 0x72: /* DELTAP3 */
7595 Ins_DELTAP( EXEC_ARG_ args
);
7598 case 0x73: /* DELTAC0 */
7599 case 0x74: /* DELTAC1 */
7600 case 0x75: /* DELTAC2 */
7601 Ins_DELTAC( EXEC_ARG_ args
);
7604 case 0x76: /* SROUND */
7608 case 0x77: /* S45Round */
7612 case 0x78: /* JROT */
7616 case 0x79: /* JROF */
7620 case 0x7A: /* ROFF */
7624 case 0x7B: /* ???? */
7625 Ins_UNKNOWN( EXEC_ARG_ args
);
7628 case 0x7C: /* RUTG */
7632 case 0x7D: /* RDTG */
7636 case 0x7E: /* SANGW */
7638 /* nothing - obsolete */
7641 case 0x80: /* FLIPPT */
7642 Ins_FLIPPT( EXEC_ARG_ args
);
7645 case 0x81: /* FLIPRGON */
7646 Ins_FLIPRGON( EXEC_ARG_ args
);
7649 case 0x82: /* FLIPRGOFF */
7650 Ins_FLIPRGOFF( EXEC_ARG_ args
);
7653 case 0x83: /* UNKNOWN */
7654 case 0x84: /* UNKNOWN */
7655 Ins_UNKNOWN( EXEC_ARG_ args
);
7658 case 0x85: /* SCANCTRL */
7659 Ins_SCANCTRL( EXEC_ARG_ args
);
7662 case 0x86: /* SDPVTL */
7663 case 0x87: /* SDPVTL */
7664 Ins_SDPVTL( EXEC_ARG_ args
);
7667 case 0x88: /* GETINFO */
7668 Ins_GETINFO( EXEC_ARG_ args
);
7671 case 0x89: /* IDEF */
7672 Ins_IDEF( EXEC_ARG_ args
);
7675 case 0x8A: /* ROLL */
7676 Ins_ROLL( EXEC_ARG_ args
);
7679 case 0x8B: /* MAX */
7683 case 0x8C: /* MIN */
7687 case 0x8D: /* SCANTYPE */
7688 Ins_SCANTYPE( EXEC_ARG_ args
);
7691 case 0x8E: /* INSTCTRL */
7692 Ins_INSTCTRL( EXEC_ARG_ args
);
7696 Ins_UNKNOWN( EXEC_ARG_ args
);
7700 if ( opcode
>= 0xE0 )
7701 Ins_MIRP( EXEC_ARG_ args
);
7702 else if ( opcode
>= 0xC0 )
7703 Ins_MDRP( EXEC_ARG_ args
);
7704 else if ( opcode
>= 0xB8 )
7705 Ins_PUSHW( EXEC_ARG_ args
);
7706 else if ( opcode
>= 0xB0 )
7707 Ins_PUSHB( EXEC_ARG_ args
);
7709 Ins_UNKNOWN( EXEC_ARG_ args
);
7716 Instruct_Dispatch
[CUR
.opcode
]( EXEC_ARG_
&CUR
.stack
[CUR
.args
] );
7718 #endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7720 if ( CUR
.error
!= TT_Err_Ok
)
7722 switch ( CUR
.error
)
7724 case TT_Err_Invalid_Opcode
: /* looking for redefined instructions */
7726 TT_DefRecord
* def
= CUR
.IDefs
;
7727 TT_DefRecord
* limit
= def
+ CUR
.numIDefs
;
7730 for ( ; def
< limit
; def
++ )
7732 if ( def
->active
&& CUR
.opcode
== (FT_Byte
)def
->opc
)
7734 TT_CallRec
* callrec
;
7737 if ( CUR
.callTop
>= CUR
.callSize
)
7739 CUR
.error
= TT_Err_Invalid_Reference
;
7743 callrec
= &CUR
.callStack
[CUR
.callTop
];
7745 callrec
->Caller_Range
= CUR
.curRange
;
7746 callrec
->Caller_IP
= CUR
.IP
+ 1;
7747 callrec
->Cur_Count
= 1;
7748 callrec
->Cur_Restart
= def
->start
;
7750 if ( INS_Goto_CodeRange( def
->range
, def
->start
) == FAILURE
)
7758 CUR
.error
= TT_Err_Invalid_Opcode
;
7762 break; /* Unreachable code warning suppression. */
7763 /* Leave to remind in case a later change the editor */
7764 /* to consider break; */
7776 CUR
.top
= CUR
.new_top
;
7779 CUR
.IP
+= CUR
.length
;
7781 /* increment instruction counter and check if we didn't */
7782 /* run this program for too long (e.g. infinite loops). */
7783 if ( ++ins_counter
> MAX_RUNNABLE_OPCODES
)
7784 return TT_Err_Execution_Too_Long
;
7787 if ( CUR
.IP
>= CUR
.codeSize
)
7789 if ( CUR
.callTop
> 0 )
7791 CUR
.error
= TT_Err_Code_Overflow
;
7797 } while ( !CUR
.instruction_trap
);
7801 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7807 LErrorCodeOverflow_
:
7808 CUR
.error
= TT_Err_Code_Overflow
;
7812 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7820 #endif /* TT_USE_BYTECODE_INTERPRETER */