1 /***************************************************************************/
5 /* TrueType bytecode interpreter (body). */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 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 /* TrueTyoe 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
);
4824 D
= CUR_Func_dualproj( CUR
.zp0
.org
+ L
, CUR
.zp1
.org
+ K
);
4831 /*************************************************************************/
4833 /* SDPVTL[a]: Set Dual PVector to Line */
4834 /* Opcode range: 0x86-0x87 */
4835 /* Stack: uint32 uint32 --> */
4838 Ins_SDPVTL( INS_ARG
)
4841 FT_UShort p1
, p2
; /* was FT_Int in pas type ERROR */
4844 p1
= (FT_UShort
)args
[1];
4845 p2
= (FT_UShort
)args
[0];
4847 if ( BOUNDS( p2
, CUR
.zp1
.n_points
) ||
4848 BOUNDS( p1
, CUR
.zp2
.n_points
) )
4850 if ( CUR
.pedantic_hinting
)
4851 CUR
.error
= TT_Err_Invalid_Reference
;
4856 FT_Vector
* v1
= CUR
.zp1
.org
+ p2
;
4857 FT_Vector
* v2
= CUR
.zp2
.org
+ p1
;
4864 if ( ( CUR
.opcode
& 1 ) != 0 )
4866 C
= B
; /* counter clockwise rotation */
4871 NORMalize( A
, B
, &CUR
.GS
.dualVector
);
4874 FT_Vector
* v1
= CUR
.zp1
.cur
+ p2
;
4875 FT_Vector
* v2
= CUR
.zp2
.cur
+ p1
;
4882 if ( ( CUR
.opcode
& 1 ) != 0 )
4884 C
= B
; /* counter clockwise rotation */
4889 NORMalize( A
, B
, &CUR
.GS
.projVector
);
4891 GUESS_VECTOR( freeVector
);
4897 /*************************************************************************/
4899 /* SZP0[]: Set Zone Pointer 0 */
4900 /* Opcode range: 0x13 */
4901 /* Stack: uint32 --> */
4906 switch ( (FT_Int
)args
[0] )
4909 CUR
.zp0
= CUR
.twilight
;
4917 if ( CUR
.pedantic_hinting
)
4918 CUR
.error
= TT_Err_Invalid_Reference
;
4922 CUR
.GS
.gep0
= (FT_UShort
)args
[0];
4926 /*************************************************************************/
4928 /* SZP1[]: Set Zone Pointer 1 */
4929 /* Opcode range: 0x14 */
4930 /* Stack: uint32 --> */
4935 switch ( (FT_Int
)args
[0] )
4938 CUR
.zp1
= CUR
.twilight
;
4946 if ( CUR
.pedantic_hinting
)
4947 CUR
.error
= TT_Err_Invalid_Reference
;
4951 CUR
.GS
.gep1
= (FT_UShort
)args
[0];
4955 /*************************************************************************/
4957 /* SZP2[]: Set Zone Pointer 2 */
4958 /* Opcode range: 0x15 */
4959 /* Stack: uint32 --> */
4964 switch ( (FT_Int
)args
[0] )
4967 CUR
.zp2
= CUR
.twilight
;
4975 if ( CUR
.pedantic_hinting
)
4976 CUR
.error
= TT_Err_Invalid_Reference
;
4980 CUR
.GS
.gep2
= (FT_UShort
)args
[0];
4984 /*************************************************************************/
4986 /* SZPS[]: Set Zone PointerS */
4987 /* Opcode range: 0x16 */
4988 /* Stack: uint32 --> */
4993 switch ( (FT_Int
)args
[0] )
4996 CUR
.zp0
= CUR
.twilight
;
5004 if ( CUR
.pedantic_hinting
)
5005 CUR
.error
= TT_Err_Invalid_Reference
;
5012 CUR
.GS
.gep0
= (FT_UShort
)args
[0];
5013 CUR
.GS
.gep1
= (FT_UShort
)args
[0];
5014 CUR
.GS
.gep2
= (FT_UShort
)args
[0];
5018 /*************************************************************************/
5020 /* INSTCTRL[]: INSTruction ConTRoL */
5021 /* Opcode range: 0x8e */
5022 /* Stack: int32 int32 --> */
5025 Ins_INSTCTRL( INS_ARG
)
5033 if ( K
< 1 || K
> 2 )
5035 if ( CUR
.pedantic_hinting
)
5036 CUR
.error
= TT_Err_Invalid_Reference
;
5043 CUR
.GS
.instruct_control
= FT_BOOL(
5044 ( (FT_Byte
)CUR
.GS
.instruct_control
& ~(FT_Byte
)K
) | (FT_Byte
)L
);
5048 /*************************************************************************/
5050 /* SCANCTRL[]: SCAN ConTRoL */
5051 /* Opcode range: 0x85 */
5052 /* Stack: uint32? --> */
5055 Ins_SCANCTRL( INS_ARG
)
5061 A
= (FT_Int
)( args
[0] & 0xFF );
5065 CUR
.GS
.scan_control
= TRUE
;
5070 CUR
.GS
.scan_control
= FALSE
;
5077 if ( ( args
[0] & 0x100 ) != 0 && CUR
.metrics
.pointSize
<= A
)
5078 CUR
.GS
.scan_control
= TRUE
;
5081 if ( ( args
[0] & 0x200 ) != 0 && CUR
.tt_metrics
.rotated
)
5082 CUR
.GS
.scan_control
= TRUE
;
5084 if ( ( args
[0] & 0x400 ) != 0 && CUR
.tt_metrics
.stretched
)
5085 CUR
.GS
.scan_control
= TRUE
;
5088 if ( ( args
[0] & 0x800 ) != 0 && CUR
.metrics
.pointSize
> A
)
5089 CUR
.GS
.scan_control
= FALSE
;
5092 if ( ( args
[0] & 0x1000 ) != 0 && CUR
.tt_metrics
.rotated
)
5093 CUR
.GS
.scan_control
= FALSE
;
5095 if ( ( args
[0] & 0x2000 ) != 0 && CUR
.tt_metrics
.stretched
)
5096 CUR
.GS
.scan_control
= FALSE
;
5100 /*************************************************************************/
5102 /* SCANTYPE[]: SCAN TYPE */
5103 /* Opcode range: 0x8D */
5104 /* Stack: uint32? --> */
5107 Ins_SCANTYPE( INS_ARG
)
5109 /* for compatibility with future enhancements, */
5110 /* we must ignore new modes */
5112 if ( args
[0] >= 0 && args
[0] <= 5 )
5117 CUR
.GS
.scan_type
= (FT_Int
)args
[0];
5122 /*************************************************************************/
5124 /* MANAGING OUTLINES */
5126 /* Instructions appear in the specification's order. */
5128 /*************************************************************************/
5131 /*************************************************************************/
5133 /* FLIPPT[]: FLIP PoinT */
5134 /* Opcode range: 0x80 */
5135 /* Stack: uint32... --> */
5138 Ins_FLIPPT( INS_ARG
)
5145 if ( CUR
.top
< CUR
.GS
.loop
)
5147 CUR
.error
= TT_Err_Too_Few_Arguments
;
5151 while ( CUR
.GS
.loop
> 0 )
5155 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5157 if ( BOUNDS( point
, CUR
.pts
.n_points
) )
5159 if ( CUR
.pedantic_hinting
)
5161 CUR
.error
= TT_Err_Invalid_Reference
;
5166 CUR
.pts
.tags
[point
] ^= FT_CURVE_TAG_ON
;
5172 CUR
.new_top
= CUR
.args
;
5176 /*************************************************************************/
5178 /* FLIPRGON[]: FLIP RanGe ON */
5179 /* Opcode range: 0x81 */
5180 /* Stack: uint32 uint32 --> */
5183 Ins_FLIPRGON( INS_ARG
)
5188 K
= (FT_UShort
)args
[1];
5189 L
= (FT_UShort
)args
[0];
5191 if ( BOUNDS( K
, CUR
.pts
.n_points
) ||
5192 BOUNDS( L
, CUR
.pts
.n_points
) )
5194 if ( CUR
.pedantic_hinting
)
5195 CUR
.error
= TT_Err_Invalid_Reference
;
5199 for ( I
= L
; I
<= K
; I
++ )
5200 CUR
.pts
.tags
[I
] |= FT_CURVE_TAG_ON
;
5204 /*************************************************************************/
5206 /* FLIPRGOFF: FLIP RanGe OFF */
5207 /* Opcode range: 0x82 */
5208 /* Stack: uint32 uint32 --> */
5211 Ins_FLIPRGOFF( INS_ARG
)
5216 K
= (FT_UShort
)args
[1];
5217 L
= (FT_UShort
)args
[0];
5219 if ( BOUNDS( K
, CUR
.pts
.n_points
) ||
5220 BOUNDS( L
, CUR
.pts
.n_points
) )
5222 if ( CUR
.pedantic_hinting
)
5223 CUR
.error
= TT_Err_Invalid_Reference
;
5227 for ( I
= L
; I
<= K
; I
++ )
5228 CUR
.pts
.tags
[I
] &= ~FT_CURVE_TAG_ON
;
5233 Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6
* x
,
5243 if ( CUR
.opcode
& 1 )
5254 if ( BOUNDS( p
, zp
.n_points
) )
5256 if ( CUR
.pedantic_hinting
)
5257 CUR
.error
= TT_Err_Invalid_Reference
;
5265 d
= CUR_Func_project( zp
.cur
+ p
, zp
.org
+ p
);
5267 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5268 if ( CUR
.face
->unpatented_hinting
)
5270 if ( CUR
.GS
.both_x_axis
)
5285 (FT_Long
)CUR
.GS
.freeVector
.x
* 0x10000L
,
5288 (FT_Long
)CUR
.GS
.freeVector
.y
* 0x10000L
,
5297 Move_Zp2_Point( EXEC_OP_ FT_UShort point
,
5302 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5303 if ( CUR
.face
->unpatented_hinting
)
5305 if ( CUR
.GS
.both_x_axis
)
5307 CUR
.zp2
.cur
[point
].x
+= dx
;
5309 CUR
.zp2
.tags
[point
] |= FT_CURVE_TAG_TOUCH_X
;
5313 CUR
.zp2
.cur
[point
].y
+= dy
;
5315 CUR
.zp2
.tags
[point
] |= FT_CURVE_TAG_TOUCH_Y
;
5321 if ( CUR
.GS
.freeVector
.x
!= 0 )
5323 CUR
.zp2
.cur
[point
].x
+= dx
;
5325 CUR
.zp2
.tags
[point
] |= FT_CURVE_TAG_TOUCH_X
;
5328 if ( CUR
.GS
.freeVector
.y
!= 0 )
5330 CUR
.zp2
.cur
[point
].y
+= dy
;
5332 CUR
.zp2
.tags
[point
] |= FT_CURVE_TAG_TOUCH_Y
;
5337 /*************************************************************************/
5339 /* SHP[a]: SHift Point by the last point */
5340 /* Opcode range: 0x32-0x33 */
5341 /* Stack: uint32... --> */
5356 if ( CUR
.top
< CUR
.GS
.loop
)
5358 CUR
.error
= TT_Err_Invalid_Reference
;
5362 if ( COMPUTE_Point_Displacement( &dx
, &dy
, &zp
, &refp
) )
5365 while ( CUR
.GS
.loop
> 0 )
5368 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5370 if ( BOUNDS( point
, CUR
.zp2
.n_points
) )
5372 if ( CUR
.pedantic_hinting
)
5374 CUR
.error
= TT_Err_Invalid_Reference
;
5379 /* XXX: UNDOCUMENTED! SHP touches the points */
5380 MOVE_Zp2_Point( point
, dx
, dy
, TRUE
);
5386 CUR
.new_top
= CUR
.args
;
5390 /*************************************************************************/
5392 /* SHC[a]: SHift Contour */
5393 /* Opcode range: 0x34-35 */
5394 /* Stack: uint32 --> */
5405 FT_UShort first_point
, last_point
, i
;
5408 contour
= (FT_UShort
)args
[0];
5410 if ( BOUNDS( contour
, CUR
.pts
.n_contours
) )
5412 if ( CUR
.pedantic_hinting
)
5413 CUR
.error
= TT_Err_Invalid_Reference
;
5417 if ( COMPUTE_Point_Displacement( &dx
, &dy
, &zp
, &refp
) )
5423 first_point
= (FT_UShort
)( CUR
.pts
.contours
[contour
- 1] + 1 -
5424 CUR
.pts
.first_point
);
5426 last_point
= (FT_UShort
)( CUR
.pts
.contours
[contour
] -
5427 CUR
.pts
.first_point
);
5429 /* XXX: this is probably wrong... at least it prevents memory */
5430 /* corruption when zp2 is the twilight zone */
5431 if ( last_point
> CUR
.zp2
.n_points
)
5433 if ( CUR
.zp2
.n_points
> 0 )
5434 last_point
= (FT_UShort
)(CUR
.zp2
.n_points
- 1);
5439 /* XXX: UNDOCUMENTED! SHC touches the points */
5440 for ( i
= first_point
; i
<= last_point
; i
++ )
5442 if ( zp
.cur
!= CUR
.zp2
.cur
|| refp
!= i
)
5443 MOVE_Zp2_Point( i
, dx
, dy
, TRUE
);
5448 /*************************************************************************/
5450 /* SHZ[a]: SHift Zone */
5451 /* Opcode range: 0x36-37 */
5452 /* Stack: uint32 --> */
5462 FT_UShort last_point
, i
;
5465 if ( BOUNDS( args
[0], 2 ) )
5467 if ( CUR
.pedantic_hinting
)
5468 CUR
.error
= TT_Err_Invalid_Reference
;
5472 if ( COMPUTE_Point_Displacement( &dx
, &dy
, &zp
, &refp
) )
5475 /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */
5476 /* Twilight zone has no contours, so use `n_points'. */
5477 /* Normal zone's `n_points' includes phantoms, so must */
5478 /* use end of last contour. */
5479 if ( CUR
.GS
.gep2
== 0 && CUR
.zp2
.n_points
> 0 )
5480 last_point
= (FT_UShort
)( CUR
.zp2
.n_points
- 1 );
5481 else if ( CUR
.GS
.gep2
== 1 && CUR
.zp2
.n_contours
> 0 )
5482 last_point
= (FT_UShort
)( CUR
.zp2
.contours
[CUR
.zp2
.n_contours
- 1] );
5486 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
5487 for ( i
= 0; i
<= last_point
; i
++ )
5489 if ( zp
.cur
!= CUR
.zp2
.cur
|| refp
!= i
)
5490 MOVE_Zp2_Point( i
, dx
, dy
, FALSE
);
5495 /*************************************************************************/
5497 /* SHPIX[]: SHift points by a PIXel amount */
5498 /* Opcode range: 0x38 */
5499 /* Stack: f26.6 uint32... --> */
5502 Ins_SHPIX( INS_ARG
)
5508 if ( CUR
.top
< CUR
.GS
.loop
+ 1 )
5510 CUR
.error
= TT_Err_Invalid_Reference
;
5514 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5515 if ( CUR
.face
->unpatented_hinting
)
5517 if ( CUR
.GS
.both_x_axis
)
5519 dx
= TT_MulFix14( args
[0], 0x4000 );
5525 dy
= TT_MulFix14( args
[0], 0x4000 );
5531 dx
= TT_MulFix14( args
[0], CUR
.GS
.freeVector
.x
);
5532 dy
= TT_MulFix14( args
[0], CUR
.GS
.freeVector
.y
);
5535 while ( CUR
.GS
.loop
> 0 )
5539 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5541 if ( BOUNDS( point
, CUR
.zp2
.n_points
) )
5543 if ( CUR
.pedantic_hinting
)
5545 CUR
.error
= TT_Err_Invalid_Reference
;
5550 MOVE_Zp2_Point( point
, dx
, dy
, TRUE
);
5556 CUR
.new_top
= CUR
.args
;
5560 /*************************************************************************/
5562 /* MSIRP[a]: Move Stack Indirect Relative Position */
5563 /* Opcode range: 0x3A-0x3B */
5564 /* Stack: f26.6 uint32 --> */
5567 Ins_MSIRP( INS_ARG
)
5570 FT_F26Dot6 distance
;
5573 point
= (FT_UShort
)args
[0];
5575 if ( BOUNDS( point
, CUR
.zp1
.n_points
) ||
5576 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5578 if ( CUR
.pedantic_hinting
)
5579 CUR
.error
= TT_Err_Invalid_Reference
;
5583 /* XXX: UNDOCUMENTED! behaviour */
5584 if ( CUR
.GS
.gep1
== 0 ) /* if the point that is to be moved */
5585 /* is in twilight zone */
5587 CUR
.zp1
.org
[point
] = CUR
.zp0
.org
[CUR
.GS
.rp0
];
5588 CUR_Func_move_orig( &CUR
.zp1
, point
, args
[1] );
5589 CUR
.zp1
.cur
[point
] = CUR
.zp1
.org
[point
];
5592 distance
= CUR_Func_project( CUR
.zp1
.cur
+ point
,
5593 CUR
.zp0
.cur
+ CUR
.GS
.rp0
);
5595 CUR_Func_move( &CUR
.zp1
, point
, args
[1] - distance
);
5597 CUR
.GS
.rp1
= CUR
.GS
.rp0
;
5600 if ( ( CUR
.opcode
& 1 ) != 0 )
5605 /*************************************************************************/
5607 /* MDAP[a]: Move Direct Absolute Point */
5608 /* Opcode range: 0x2E-0x2F */
5609 /* Stack: uint32 --> */
5615 FT_F26Dot6 cur_dist
,
5619 point
= (FT_UShort
)args
[0];
5621 if ( BOUNDS( point
, CUR
.zp0
.n_points
) )
5623 if ( CUR
.pedantic_hinting
)
5624 CUR
.error
= TT_Err_Invalid_Reference
;
5628 /* XXX: Is there some undocumented feature while in the */
5629 /* twilight zone? ? */
5630 if ( ( CUR
.opcode
& 1 ) != 0 )
5632 cur_dist
= CUR_fast_project( &CUR
.zp0
.cur
[point
] );
5633 distance
= CUR_Func_round( cur_dist
,
5634 CUR
.tt_metrics
.compensations
[0] ) - cur_dist
;
5639 CUR_Func_move( &CUR
.zp0
, point
, distance
);
5646 /*************************************************************************/
5648 /* MIAP[a]: Move Indirect Absolute Point */
5649 /* Opcode range: 0x3E-0x3F */
5650 /* Stack: uint32 uint32 --> */
5657 FT_F26Dot6 distance
,
5661 cvtEntry
= (FT_ULong
)args
[1];
5662 point
= (FT_UShort
)args
[0];
5664 if ( BOUNDS( point
, CUR
.zp0
.n_points
) ||
5665 BOUNDS( cvtEntry
, CUR
.cvtSize
) )
5667 if ( CUR
.pedantic_hinting
)
5668 CUR
.error
= TT_Err_Invalid_Reference
;
5672 /* XXX: UNDOCUMENTED! */
5674 /* The behaviour of an MIAP instruction is quite */
5675 /* different when used in the twilight zone. */
5677 /* First, no control value cut-in test is performed */
5678 /* as it would fail anyway. Second, the original */
5679 /* point, i.e. (org_x,org_y) of zp0.point, is set */
5680 /* to the absolute, unrounded distance found in */
5683 /* This is used in the CVT programs of the Microsoft */
5684 /* fonts Arial, Times, etc., in order to re-adjust */
5685 /* some key font heights. It allows the use of the */
5686 /* IP instruction in the twilight zone, which */
5687 /* otherwise would be `illegal' according to the */
5688 /* specification. */
5690 /* We implement it with a special sequence for the */
5691 /* twilight zone. This is a bad hack, but it seems */
5694 distance
= CUR_Func_read_cvt( cvtEntry
);
5696 if ( CUR
.GS
.gep0
== 0 ) /* If in twilight zone */
5698 CUR
.zp0
.org
[point
].x
= TT_MulFix14( distance
, CUR
.GS
.freeVector
.x
);
5699 CUR
.zp0
.org
[point
].y
= TT_MulFix14( distance
, CUR
.GS
.freeVector
.y
),
5700 CUR
.zp0
.cur
[point
] = CUR
.zp0
.org
[point
];
5703 org_dist
= CUR_fast_project( &CUR
.zp0
.cur
[point
] );
5705 if ( ( CUR
.opcode
& 1 ) != 0 ) /* rounding and control cutin flag */
5707 if ( FT_ABS( distance
- org_dist
) > CUR
.GS
.control_value_cutin
)
5708 distance
= org_dist
;
5710 distance
= CUR_Func_round( distance
, CUR
.tt_metrics
.compensations
[0] );
5713 CUR_Func_move( &CUR
.zp0
, point
, distance
- org_dist
);
5720 /*************************************************************************/
5722 /* MDRP[abcde]: Move Direct Relative Point */
5723 /* Opcode range: 0xC0-0xDF */
5724 /* Stack: uint32 --> */
5730 FT_F26Dot6 org_dist
, distance
;
5733 point
= (FT_UShort
)args
[0];
5735 if ( BOUNDS( point
, CUR
.zp1
.n_points
) ||
5736 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5738 if ( CUR
.pedantic_hinting
)
5739 CUR
.error
= TT_Err_Invalid_Reference
;
5743 /* XXX: Is there some undocumented feature while in the */
5744 /* twilight zone? */
5746 /* XXX: UNDOCUMENTED: twilight zone special case */
5748 if ( CUR
.GS
.gep0
== 0 || CUR
.GS
.gep1
== 0 )
5750 FT_Vector
* vec1
= &CUR
.zp1
.org
[point
];
5751 FT_Vector
* vec2
= &CUR
.zp0
.org
[CUR
.GS
.rp0
];
5754 org_dist
= CUR_Func_dualproj( vec1
, vec2
);
5758 FT_Vector
* vec1
= &CUR
.zp1
.orus
[point
];
5759 FT_Vector
* vec2
= &CUR
.zp0
.orus
[CUR
.GS
.rp0
];
5762 if ( CUR
.metrics
.x_scale
== CUR
.metrics
.y_scale
)
5764 /* this should be faster */
5765 org_dist
= CUR_Func_dualproj( vec1
, vec2
);
5766 org_dist
= TT_MULFIX( org_dist
, CUR
.metrics
.x_scale
);
5773 vec
.x
= TT_MULFIX( vec1
->x
- vec2
->x
, CUR
.metrics
.x_scale
);
5774 vec
.y
= TT_MULFIX( vec1
->y
- vec2
->y
, CUR
.metrics
.y_scale
);
5776 org_dist
= CUR_fast_dualproj( &vec
);
5780 /* single width cut-in test */
5782 if ( FT_ABS( org_dist
- CUR
.GS
.single_width_value
) <
5783 CUR
.GS
.single_width_cutin
)
5785 if ( org_dist
>= 0 )
5786 org_dist
= CUR
.GS
.single_width_value
;
5788 org_dist
= -CUR
.GS
.single_width_value
;
5793 if ( ( CUR
.opcode
& 4 ) != 0 )
5794 distance
= CUR_Func_round(
5796 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5798 distance
= ROUND_None(
5800 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5802 /* minimum distance flag */
5804 if ( ( CUR
.opcode
& 8 ) != 0 )
5806 if ( org_dist
>= 0 )
5808 if ( distance
< CUR
.GS
.minimum_distance
)
5809 distance
= CUR
.GS
.minimum_distance
;
5813 if ( distance
> -CUR
.GS
.minimum_distance
)
5814 distance
= -CUR
.GS
.minimum_distance
;
5818 /* now move the point */
5820 org_dist
= CUR_Func_project( CUR
.zp1
.cur
+ point
,
5821 CUR
.zp0
.cur
+ CUR
.GS
.rp0
);
5823 CUR_Func_move( &CUR
.zp1
, point
, distance
- org_dist
);
5825 CUR
.GS
.rp1
= CUR
.GS
.rp0
;
5828 if ( ( CUR
.opcode
& 16 ) != 0 )
5833 /*************************************************************************/
5835 /* MIRP[abcde]: Move Indirect Relative Point */
5836 /* Opcode range: 0xE0-0xFF */
5837 /* Stack: int32? uint32 --> */
5845 FT_F26Dot6 cvt_dist
,
5851 point
= (FT_UShort
)args
[0];
5852 cvtEntry
= (FT_ULong
)( args
[1] + 1 );
5854 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
5856 if ( BOUNDS( point
, CUR
.zp1
.n_points
) ||
5857 BOUNDS( cvtEntry
, CUR
.cvtSize
+ 1 ) ||
5858 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5860 if ( CUR
.pedantic_hinting
)
5861 CUR
.error
= TT_Err_Invalid_Reference
;
5868 cvt_dist
= CUR_Func_read_cvt( cvtEntry
- 1 );
5870 /* single width test */
5872 if ( FT_ABS( cvt_dist
- CUR
.GS
.single_width_value
) <
5873 CUR
.GS
.single_width_cutin
)
5875 if ( cvt_dist
>= 0 )
5876 cvt_dist
= CUR
.GS
.single_width_value
;
5878 cvt_dist
= -CUR
.GS
.single_width_value
;
5881 /* XXX: UNDOCUMENTED! -- twilight zone */
5883 if ( CUR
.GS
.gep1
== 0 )
5885 CUR
.zp1
.org
[point
].x
= CUR
.zp0
.org
[CUR
.GS
.rp0
].x
+
5886 TT_MulFix14( cvt_dist
, CUR
.GS
.freeVector
.x
);
5888 CUR
.zp1
.org
[point
].y
= CUR
.zp0
.org
[CUR
.GS
.rp0
].y
+
5889 TT_MulFix14( cvt_dist
, CUR
.GS
.freeVector
.y
);
5891 CUR
.zp1
.cur
[point
] = CUR
.zp0
.cur
[point
];
5894 org_dist
= CUR_Func_dualproj( &CUR
.zp1
.org
[point
],
5895 &CUR
.zp0
.org
[CUR
.GS
.rp0
] );
5896 cur_dist
= CUR_Func_project ( &CUR
.zp1
.cur
[point
],
5897 &CUR
.zp0
.cur
[CUR
.GS
.rp0
] );
5899 /* auto-flip test */
5901 if ( CUR
.GS
.auto_flip
)
5903 if ( ( org_dist
^ cvt_dist
) < 0 )
5904 cvt_dist
= -cvt_dist
;
5907 /* control value cutin and round */
5909 if ( ( CUR
.opcode
& 4 ) != 0 )
5911 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
5912 /* refer to the same zone. */
5914 if ( CUR
.GS
.gep0
== CUR
.GS
.gep1
)
5915 if ( FT_ABS( cvt_dist
- org_dist
) >= CUR
.GS
.control_value_cutin
)
5916 cvt_dist
= org_dist
;
5918 distance
= CUR_Func_round(
5920 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5923 distance
= ROUND_None(
5925 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5927 /* minimum distance test */
5929 if ( ( CUR
.opcode
& 8 ) != 0 )
5931 if ( org_dist
>= 0 )
5933 if ( distance
< CUR
.GS
.minimum_distance
)
5934 distance
= CUR
.GS
.minimum_distance
;
5938 if ( distance
> -CUR
.GS
.minimum_distance
)
5939 distance
= -CUR
.GS
.minimum_distance
;
5943 CUR_Func_move( &CUR
.zp1
, point
, distance
- cur_dist
);
5945 CUR
.GS
.rp1
= CUR
.GS
.rp0
;
5947 if ( ( CUR
.opcode
& 16 ) != 0 )
5950 /* XXX: UNDOCUMENTED! */
5955 /*************************************************************************/
5957 /* ALIGNRP[]: ALIGN Relative Point */
5958 /* Opcode range: 0x3C */
5959 /* Stack: uint32 uint32... --> */
5962 Ins_ALIGNRP( INS_ARG
)
5965 FT_F26Dot6 distance
;
5970 if ( CUR
.top
< CUR
.GS
.loop
||
5971 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5973 if ( CUR
.pedantic_hinting
)
5974 CUR
.error
= TT_Err_Invalid_Reference
;
5978 while ( CUR
.GS
.loop
> 0 )
5982 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5984 if ( BOUNDS( point
, CUR
.zp1
.n_points
) )
5986 if ( CUR
.pedantic_hinting
)
5988 CUR
.error
= TT_Err_Invalid_Reference
;
5994 distance
= CUR_Func_project( CUR
.zp1
.cur
+ point
,
5995 CUR
.zp0
.cur
+ CUR
.GS
.rp0
);
5997 CUR_Func_move( &CUR
.zp1
, point
, -distance
);
6004 CUR
.new_top
= CUR
.args
;
6008 /*************************************************************************/
6010 /* ISECT[]: moves point to InterSECTion */
6011 /* Opcode range: 0x0F */
6012 /* Stack: 5 * uint32 --> */
6015 Ins_ISECT( INS_ARG
)
6021 FT_F26Dot6 discriminant
;
6032 point
= (FT_UShort
)args
[0];
6034 a0
= (FT_UShort
)args
[1];
6035 a1
= (FT_UShort
)args
[2];
6036 b0
= (FT_UShort
)args
[3];
6037 b1
= (FT_UShort
)args
[4];
6039 if ( BOUNDS( b0
, CUR
.zp0
.n_points
) ||
6040 BOUNDS( b1
, CUR
.zp0
.n_points
) ||
6041 BOUNDS( a0
, CUR
.zp1
.n_points
) ||
6042 BOUNDS( a1
, CUR
.zp1
.n_points
) ||
6043 BOUNDS( point
, CUR
.zp2
.n_points
) )
6045 if ( CUR
.pedantic_hinting
)
6046 CUR
.error
= TT_Err_Invalid_Reference
;
6050 dbx
= CUR
.zp0
.cur
[b1
].x
- CUR
.zp0
.cur
[b0
].x
;
6051 dby
= CUR
.zp0
.cur
[b1
].y
- CUR
.zp0
.cur
[b0
].y
;
6053 dax
= CUR
.zp1
.cur
[a1
].x
- CUR
.zp1
.cur
[a0
].x
;
6054 day
= CUR
.zp1
.cur
[a1
].y
- CUR
.zp1
.cur
[a0
].y
;
6056 dx
= CUR
.zp0
.cur
[b0
].x
- CUR
.zp1
.cur
[a0
].x
;
6057 dy
= CUR
.zp0
.cur
[b0
].y
- CUR
.zp1
.cur
[a0
].y
;
6059 CUR
.zp2
.tags
[point
] |= FT_CURVE_TAG_TOUCH_BOTH
;
6061 discriminant
= TT_MULDIV( dax
, -dby
, 0x40 ) +
6062 TT_MULDIV( day
, dbx
, 0x40 );
6064 if ( FT_ABS( discriminant
) >= 0x40 )
6066 val
= TT_MULDIV( dx
, -dby
, 0x40 ) + TT_MULDIV( dy
, dbx
, 0x40 );
6068 R
.x
= TT_MULDIV( val
, dax
, discriminant
);
6069 R
.y
= TT_MULDIV( val
, day
, discriminant
);
6071 CUR
.zp2
.cur
[point
].x
= CUR
.zp1
.cur
[a0
].x
+ R
.x
;
6072 CUR
.zp2
.cur
[point
].y
= CUR
.zp1
.cur
[a0
].y
+ R
.y
;
6076 /* else, take the middle of the middles of A and B */
6078 CUR
.zp2
.cur
[point
].x
= ( CUR
.zp1
.cur
[a0
].x
+
6081 CUR
.zp0
.cur
[b1
].x
) / 4;
6082 CUR
.zp2
.cur
[point
].y
= ( CUR
.zp1
.cur
[a0
].y
+
6085 CUR
.zp0
.cur
[b1
].y
) / 4;
6090 /*************************************************************************/
6092 /* ALIGNPTS[]: ALIGN PoinTS */
6093 /* Opcode range: 0x27 */
6094 /* Stack: uint32 uint32 --> */
6097 Ins_ALIGNPTS( INS_ARG
)
6100 FT_F26Dot6 distance
;
6103 p1
= (FT_UShort
)args
[0];
6104 p2
= (FT_UShort
)args
[1];
6106 if ( BOUNDS( args
[0], CUR
.zp1
.n_points
) ||
6107 BOUNDS( args
[1], CUR
.zp0
.n_points
) )
6109 if ( CUR
.pedantic_hinting
)
6110 CUR
.error
= TT_Err_Invalid_Reference
;
6114 distance
= CUR_Func_project( CUR
.zp0
.cur
+ p2
,
6115 CUR
.zp1
.cur
+ p1
) / 2;
6117 CUR_Func_move( &CUR
.zp1
, p1
, distance
);
6118 CUR_Func_move( &CUR
.zp0
, p2
, -distance
);
6122 /*************************************************************************/
6124 /* IP[]: Interpolate Point */
6125 /* Opcode range: 0x39 */
6126 /* Stack: uint32... --> */
6129 /* SOMETIMES, DUMBER CODE IS BETTER CODE */
6134 FT_F26Dot6 old_range
, cur_range
;
6135 FT_Vector
* orus_base
;
6136 FT_Vector
* cur_base
;
6142 if ( CUR
.top
< CUR
.GS
.loop
)
6144 CUR
.error
= TT_Err_Invalid_Reference
;
6149 * We need to deal in a special way with the twilight zone.
6150 * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0),
6153 twilight
= CUR
.GS
.gep0
== 0 || CUR
.GS
.gep1
== 0 || CUR
.GS
.gep2
== 0;
6155 if ( BOUNDS( CUR
.GS
.rp1
, CUR
.zp0
.n_points
) )
6157 if ( CUR
.pedantic_hinting
)
6158 CUR
.error
= TT_Err_Invalid_Reference
;
6163 orus_base
= &CUR
.zp0
.org
[CUR
.GS
.rp1
];
6165 orus_base
= &CUR
.zp0
.orus
[CUR
.GS
.rp1
];
6167 cur_base
= &CUR
.zp0
.cur
[CUR
.GS
.rp1
];
6169 /* XXX: There are some glyphs in some braindead but popular */
6170 /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
6171 /* calling IP[] with bad values of rp[12]. */
6172 /* Do something sane when this odd thing happens. */
6173 if ( BOUNDS( CUR
.GS
.rp1
, CUR
.zp0
.n_points
) ||
6174 BOUNDS( CUR
.GS
.rp2
, CUR
.zp1
.n_points
) )
6182 old_range
= CUR_Func_dualproj( &CUR
.zp1
.org
[CUR
.GS
.rp2
],
6185 old_range
= CUR_Func_dualproj( &CUR
.zp1
.orus
[CUR
.GS
.rp2
],
6188 cur_range
= CUR_Func_project ( &CUR
.zp1
.cur
[CUR
.GS
.rp2
], cur_base
);
6191 for ( ; CUR
.GS
.loop
> 0; --CUR
.GS
.loop
)
6193 FT_UInt point
= (FT_UInt
)CUR
.stack
[--CUR
.args
];
6194 FT_F26Dot6 org_dist
, cur_dist
, new_dist
;
6197 /* check point bounds */
6198 if ( BOUNDS( point
, CUR
.zp2
.n_points
) )
6200 if ( CUR
.pedantic_hinting
)
6202 CUR
.error
= TT_Err_Invalid_Reference
;
6209 org_dist
= CUR_Func_dualproj( &CUR
.zp2
.org
[point
], orus_base
);
6211 org_dist
= CUR_Func_dualproj( &CUR
.zp2
.orus
[point
], orus_base
);
6213 cur_dist
= CUR_Func_project ( &CUR
.zp2
.cur
[point
], cur_base
);
6214 new_dist
= ( old_range
!= 0 )
6215 ? TT_MULDIV( org_dist
, cur_range
, old_range
)
6218 CUR_Func_move( &CUR
.zp2
, (FT_UShort
)point
, new_dist
- cur_dist
);
6221 CUR
.new_top
= CUR
.args
;
6225 /*************************************************************************/
6227 /* UTP[a]: UnTouch Point */
6228 /* Opcode range: 0x29 */
6229 /* Stack: uint32 --> */
6238 point
= (FT_UShort
)args
[0];
6240 if ( BOUNDS( point
, CUR
.zp0
.n_points
) )
6242 if ( CUR
.pedantic_hinting
)
6243 CUR
.error
= TT_Err_Invalid_Reference
;
6249 if ( CUR
.GS
.freeVector
.x
!= 0 )
6250 mask
&= ~FT_CURVE_TAG_TOUCH_X
;
6252 if ( CUR
.GS
.freeVector
.y
!= 0 )
6253 mask
&= ~FT_CURVE_TAG_TOUCH_Y
;
6255 CUR
.zp0
.tags
[point
] &= mask
;
6259 /* Local variables for Ins_IUP: */
6262 FT_Vector
* orgs
; /* original and current coordinate */
6263 FT_Vector
* curs
; /* arrays */
6267 } IUP_WorkerRec
, *IUP_Worker
;
6271 _iup_worker_shift( IUP_Worker worker
,
6280 dx
= worker
->curs
[p
].x
- worker
->orgs
[p
].x
;
6283 for ( i
= p1
; i
< p
; i
++ )
6284 worker
->curs
[i
].x
+= dx
;
6286 for ( i
= p
+ 1; i
<= p2
; i
++ )
6287 worker
->curs
[i
].x
+= dx
;
6293 _iup_worker_interpolate( IUP_Worker worker
,
6300 FT_F26Dot6 orus1
, orus2
, org1
, org2
, delta1
, delta2
;
6306 if ( BOUNDS( ref1
, worker
->max_points
) ||
6307 BOUNDS( ref2
, worker
->max_points
) )
6310 orus1
= worker
->orus
[ref1
].x
;
6311 orus2
= worker
->orus
[ref2
].x
;
6313 if ( orus1
> orus2
)
6328 org1
= worker
->orgs
[ref1
].x
;
6329 org2
= worker
->orgs
[ref2
].x
;
6330 delta1
= worker
->curs
[ref1
].x
- org1
;
6331 delta2
= worker
->curs
[ref2
].x
- org2
;
6333 if ( orus1
== orus2
)
6335 /* simple shift of untouched points */
6336 for ( i
= p1
; i
<= p2
; i
++ )
6338 FT_F26Dot6 x
= worker
->orgs
[i
].x
;
6346 worker
->curs
[i
].x
= x
;
6352 FT_Bool scale_valid
= 0;
6356 for ( i
= p1
; i
<= p2
; i
++ )
6358 FT_F26Dot6 x
= worker
->orgs
[i
].x
;
6364 else if ( x
>= org2
)
6372 scale
= TT_MULDIV( org2
+ delta2
- ( org1
+ delta1
),
6373 0x10000, orus2
- orus1
);
6376 x
= ( org1
+ delta1
) +
6377 TT_MULFIX( worker
->orus
[i
].x
- orus1
, scale
);
6379 worker
->curs
[i
].x
= x
;
6385 /*************************************************************************/
6387 /* IUP[a]: Interpolate Untouched Points */
6388 /* Opcode range: 0x30-0x31 */
6397 FT_UInt first_point
; /* first point of contour */
6398 FT_UInt end_point
; /* end point (last+1) of contour */
6400 FT_UInt first_touched
; /* first touched point in contour */
6401 FT_UInt cur_touched
; /* current touched point in contour */
6403 FT_UInt point
; /* current point */
6404 FT_Short contour
; /* current contour */
6409 /* ignore empty outlines */
6410 if ( CUR
.pts
.n_contours
== 0 )
6413 if ( CUR
.opcode
& 1 )
6415 mask
= FT_CURVE_TAG_TOUCH_X
;
6416 V
.orgs
= CUR
.pts
.org
;
6417 V
.curs
= CUR
.pts
.cur
;
6418 V
.orus
= CUR
.pts
.orus
;
6422 mask
= FT_CURVE_TAG_TOUCH_Y
;
6423 V
.orgs
= (FT_Vector
*)( (FT_Pos
*)CUR
.pts
.org
+ 1 );
6424 V
.curs
= (FT_Vector
*)( (FT_Pos
*)CUR
.pts
.cur
+ 1 );
6425 V
.orus
= (FT_Vector
*)( (FT_Pos
*)CUR
.pts
.orus
+ 1 );
6427 V
.max_points
= CUR
.pts
.n_points
;
6434 end_point
= CUR
.pts
.contours
[contour
] - CUR
.pts
.first_point
;
6435 first_point
= point
;
6437 while ( point
<= end_point
&& ( CUR
.pts
.tags
[point
] & mask
) == 0 )
6440 if ( point
<= end_point
)
6442 first_touched
= point
;
6443 cur_touched
= point
;
6447 while ( point
<= end_point
)
6449 if ( ( CUR
.pts
.tags
[point
] & mask
) != 0 )
6452 _iup_worker_interpolate( &V
,
6457 cur_touched
= point
;
6463 if ( cur_touched
== first_touched
)
6464 _iup_worker_shift( &V
, first_point
, end_point
, cur_touched
);
6467 _iup_worker_interpolate( &V
,
6468 (FT_UShort
)( cur_touched
+ 1 ),
6473 if ( first_touched
> 0 )
6474 _iup_worker_interpolate( &V
,
6482 } while ( contour
< CUR
.pts
.n_contours
);
6486 /*************************************************************************/
6488 /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
6489 /* Opcode range: 0x5D,0x71,0x72 */
6490 /* Stack: uint32 (2 * uint32)... --> */
6493 Ins_DELTAP( INS_ARG
)
6501 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
6502 /* Delta hinting is covered by US Patent 5159668. */
6503 if ( CUR
.face
->unpatented_hinting
)
6505 FT_Long n
= args
[0] * 2;
6510 CUR
.error
= TT_Err_Too_Few_Arguments
;
6515 CUR
.new_top
= CUR
.args
;
6520 nump
= (FT_ULong
)args
[0]; /* some points theoretically may occur more
6521 than once, thus UShort isn't enough */
6523 for ( k
= 1; k
<= nump
; k
++ )
6527 CUR
.error
= TT_Err_Too_Few_Arguments
;
6533 A
= (FT_UShort
)CUR
.stack
[CUR
.args
+ 1];
6534 B
= CUR
.stack
[CUR
.args
];
6536 /* XXX: Because some popular fonts contain some invalid DeltaP */
6537 /* instructions, we simply ignore them when the stacked */
6538 /* point reference is off limit, rather than returning an */
6539 /* error. As a delta instruction doesn't change a glyph */
6540 /* in great ways, this shouldn't be a problem. */
6542 if ( !BOUNDS( A
, CUR
.zp0
.n_points
) )
6544 C
= ( (FT_ULong
)B
& 0xF0 ) >> 4;
6546 switch ( CUR
.opcode
)
6560 C
+= CUR
.GS
.delta_base
;
6562 if ( CURRENT_Ppem() == (FT_Long
)C
)
6564 B
= ( (FT_ULong
)B
& 0xF ) - 8;
6567 B
= B
* 64 / ( 1L << CUR
.GS
.delta_shift
);
6569 CUR_Func_move( &CUR
.zp0
, A
, B
);
6573 if ( CUR
.pedantic_hinting
)
6574 CUR
.error
= TT_Err_Invalid_Reference
;
6577 CUR
.new_top
= CUR
.args
;
6581 /*************************************************************************/
6583 /* DELTACn[]: DELTA exceptions C1, C2, C3 */
6584 /* Opcode range: 0x73,0x74,0x75 */
6585 /* Stack: uint32 (2 * uint32)... --> */
6588 Ins_DELTAC( INS_ARG
)
6595 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
6596 /* Delta hinting is covered by US Patent 5159668. */
6597 if ( CUR
.face
->unpatented_hinting
)
6599 FT_Long n
= args
[0] * 2;
6604 CUR
.error
= TT_Err_Too_Few_Arguments
;
6609 CUR
.new_top
= CUR
.args
;
6614 nump
= (FT_ULong
)args
[0];
6616 for ( k
= 1; k
<= nump
; k
++ )
6620 CUR
.error
= TT_Err_Too_Few_Arguments
;
6626 A
= (FT_ULong
)CUR
.stack
[CUR
.args
+ 1];
6627 B
= CUR
.stack
[CUR
.args
];
6629 if ( BOUNDS( A
, CUR
.cvtSize
) )
6631 if ( CUR
.pedantic_hinting
)
6633 CUR
.error
= TT_Err_Invalid_Reference
;
6639 C
= ( (FT_ULong
)B
& 0xF0 ) >> 4;
6641 switch ( CUR
.opcode
)
6655 C
+= CUR
.GS
.delta_base
;
6657 if ( CURRENT_Ppem() == (FT_Long
)C
)
6659 B
= ( (FT_ULong
)B
& 0xF ) - 8;
6662 B
= B
* 64 / ( 1L << CUR
.GS
.delta_shift
);
6664 CUR_Func_move_cvt( A
, B
);
6669 CUR
.new_top
= CUR
.args
;
6673 /*************************************************************************/
6675 /* MISC. INSTRUCTIONS */
6677 /*************************************************************************/
6680 /*************************************************************************/
6682 /* GETINFO[]: GET INFOrmation */
6683 /* Opcode range: 0x88 */
6684 /* Stack: uint32 --> uint32 */
6687 Ins_GETINFO( INS_ARG
)
6694 /* We return MS rasterizer version 1.7 for the font scaler. */
6695 if ( ( args
[0] & 1 ) != 0 )
6698 /* Has the glyph been rotated? */
6699 if ( ( args
[0] & 2 ) != 0 && CUR
.tt_metrics
.rotated
)
6702 /* Has the glyph been stretched? */
6703 if ( ( args
[0] & 4 ) != 0 && CUR
.tt_metrics
.stretched
)
6706 /* Are we hinting for grayscale? */
6707 if ( ( args
[0] & 32 ) != 0 && CUR
.grayscale
)
6715 Ins_UNKNOWN( INS_ARG
)
6717 TT_DefRecord
* def
= CUR
.IDefs
;
6718 TT_DefRecord
* limit
= def
+ CUR
.numIDefs
;
6723 for ( ; def
< limit
; def
++ )
6725 if ( (FT_Byte
)def
->opc
== CUR
.opcode
&& def
->active
)
6730 if ( CUR
.callTop
>= CUR
.callSize
)
6732 CUR
.error
= TT_Err_Stack_Overflow
;
6736 call
= CUR
.callStack
+ CUR
.callTop
++;
6738 call
->Caller_Range
= CUR
.curRange
;
6739 call
->Caller_IP
= CUR
.IP
+1;
6740 call
->Cur_Count
= 1;
6741 call
->Cur_Restart
= def
->start
;
6743 INS_Goto_CodeRange( def
->range
, def
->start
);
6745 CUR
.step_ins
= FALSE
;
6750 CUR
.error
= TT_Err_Invalid_Opcode
;
6754 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
6758 TInstruction_Function Instruct_Dispatch
[256] =
6760 /* Opcodes are gathered in groups of 16. */
6761 /* Please keep the spaces as they are. */
6763 /* SVTCA y */ Ins_SVTCA
,
6764 /* SVTCA x */ Ins_SVTCA
,
6765 /* SPvTCA y */ Ins_SPVTCA
,
6766 /* SPvTCA x */ Ins_SPVTCA
,
6767 /* SFvTCA y */ Ins_SFVTCA
,
6768 /* SFvTCA x */ Ins_SFVTCA
,
6769 /* SPvTL // */ Ins_SPVTL
,
6770 /* SPvTL + */ Ins_SPVTL
,
6771 /* SFvTL // */ Ins_SFVTL
,
6772 /* SFvTL + */ Ins_SFVTL
,
6773 /* SPvFS */ Ins_SPVFS
,
6774 /* SFvFS */ Ins_SFVFS
,
6777 /* SFvTPv */ Ins_SFVTPV
,
6778 /* ISECT */ Ins_ISECT
,
6780 /* SRP0 */ Ins_SRP0
,
6781 /* SRP1 */ Ins_SRP1
,
6782 /* SRP2 */ Ins_SRP2
,
6783 /* SZP0 */ Ins_SZP0
,
6784 /* SZP1 */ Ins_SZP1
,
6785 /* SZP2 */ Ins_SZP2
,
6786 /* SZPS */ Ins_SZPS
,
6787 /* SLOOP */ Ins_SLOOP
,
6789 /* RTHG */ Ins_RTHG
,
6791 /* ELSE */ Ins_ELSE
,
6792 /* JMPR */ Ins_JMPR
,
6793 /* SCvTCi */ Ins_SCVTCI
,
6794 /* SSwCi */ Ins_SSWCI
,
6799 /* CLEAR */ Ins_CLEAR
,
6800 /* SWAP */ Ins_SWAP
,
6801 /* DEPTH */ Ins_DEPTH
,
6802 /* CINDEX */ Ins_CINDEX
,
6803 /* MINDEX */ Ins_MINDEX
,
6804 /* AlignPTS */ Ins_ALIGNPTS
,
6805 /* INS_0x28 */ Ins_UNKNOWN
,
6807 /* LOOPCALL */ Ins_LOOPCALL
,
6808 /* CALL */ Ins_CALL
,
6809 /* FDEF */ Ins_FDEF
,
6810 /* ENDF */ Ins_ENDF
,
6811 /* MDAP[0] */ Ins_MDAP
,
6812 /* MDAP[1] */ Ins_MDAP
,
6814 /* IUP[0] */ Ins_IUP
,
6815 /* IUP[1] */ Ins_IUP
,
6816 /* SHP[0] */ Ins_SHP
,
6817 /* SHP[1] */ Ins_SHP
,
6818 /* SHC[0] */ Ins_SHC
,
6819 /* SHC[1] */ Ins_SHC
,
6820 /* SHZ[0] */ Ins_SHZ
,
6821 /* SHZ[1] */ Ins_SHZ
,
6822 /* SHPIX */ Ins_SHPIX
,
6824 /* MSIRP[0] */ Ins_MSIRP
,
6825 /* MSIRP[1] */ Ins_MSIRP
,
6826 /* AlignRP */ Ins_ALIGNRP
,
6827 /* RTDG */ Ins_RTDG
,
6828 /* MIAP[0] */ Ins_MIAP
,
6829 /* MIAP[1] */ Ins_MIAP
,
6831 /* NPushB */ Ins_NPUSHB
,
6832 /* NPushW */ Ins_NPUSHW
,
6835 /* WCvtP */ Ins_WCVTP
,
6836 /* RCvt */ Ins_RCVT
,
6839 /* SCFS */ Ins_SCFS
,
6842 /* MPPEM */ Ins_MPPEM
,
6844 /* FlipON */ Ins_FLIPON
,
6845 /* FlipOFF */ Ins_FLIPOFF
,
6846 /* DEBUG */ Ins_DEBUG
,
6849 /* LTEQ */ Ins_LTEQ
,
6851 /* GTEQ */ Ins_GTEQ
,
6855 /* EVEN */ Ins_EVEN
,
6861 /* DeltaP1 */ Ins_DELTAP
,
6871 /* FLOOR */ Ins_FLOOR
,
6872 /* CEILING */ Ins_CEILING
,
6873 /* ROUND[0] */ Ins_ROUND
,
6874 /* ROUND[1] */ Ins_ROUND
,
6875 /* ROUND[2] */ Ins_ROUND
,
6876 /* ROUND[3] */ Ins_ROUND
,
6877 /* NROUND[0] */ Ins_NROUND
,
6878 /* NROUND[1] */ Ins_NROUND
,
6879 /* NROUND[2] */ Ins_NROUND
,
6880 /* NROUND[3] */ Ins_NROUND
,
6882 /* WCvtF */ Ins_WCVTF
,
6883 /* DeltaP2 */ Ins_DELTAP
,
6884 /* DeltaP3 */ Ins_DELTAP
,
6885 /* DeltaCn[0] */ Ins_DELTAC
,
6886 /* DeltaCn[1] */ Ins_DELTAC
,
6887 /* DeltaCn[2] */ Ins_DELTAC
,
6888 /* SROUND */ Ins_SROUND
,
6889 /* S45Round */ Ins_S45ROUND
,
6890 /* JROT */ Ins_JROT
,
6891 /* JROF */ Ins_JROF
,
6892 /* ROFF */ Ins_ROFF
,
6893 /* INS_0x7B */ Ins_UNKNOWN
,
6894 /* RUTG */ Ins_RUTG
,
6895 /* RDTG */ Ins_RDTG
,
6896 /* SANGW */ Ins_SANGW
,
6899 /* FlipPT */ Ins_FLIPPT
,
6900 /* FlipRgON */ Ins_FLIPRGON
,
6901 /* FlipRgOFF */ Ins_FLIPRGOFF
,
6902 /* INS_0x83 */ Ins_UNKNOWN
,
6903 /* INS_0x84 */ Ins_UNKNOWN
,
6904 /* ScanCTRL */ Ins_SCANCTRL
,
6905 /* SDPVTL[0] */ Ins_SDPVTL
,
6906 /* SDPVTL[1] */ Ins_SDPVTL
,
6907 /* GetINFO */ Ins_GETINFO
,
6908 /* IDEF */ Ins_IDEF
,
6909 /* ROLL */ Ins_ROLL
,
6912 /* ScanTYPE */ Ins_SCANTYPE
,
6913 /* InstCTRL */ Ins_INSTCTRL
,
6914 /* INS_0x8F */ Ins_UNKNOWN
,
6916 /* INS_0x90 */ Ins_UNKNOWN
,
6917 /* INS_0x91 */ Ins_UNKNOWN
,
6918 /* INS_0x92 */ Ins_UNKNOWN
,
6919 /* INS_0x93 */ Ins_UNKNOWN
,
6920 /* INS_0x94 */ Ins_UNKNOWN
,
6921 /* INS_0x95 */ Ins_UNKNOWN
,
6922 /* INS_0x96 */ Ins_UNKNOWN
,
6923 /* INS_0x97 */ Ins_UNKNOWN
,
6924 /* INS_0x98 */ Ins_UNKNOWN
,
6925 /* INS_0x99 */ Ins_UNKNOWN
,
6926 /* INS_0x9A */ Ins_UNKNOWN
,
6927 /* INS_0x9B */ Ins_UNKNOWN
,
6928 /* INS_0x9C */ Ins_UNKNOWN
,
6929 /* INS_0x9D */ Ins_UNKNOWN
,
6930 /* INS_0x9E */ Ins_UNKNOWN
,
6931 /* INS_0x9F */ Ins_UNKNOWN
,
6933 /* INS_0xA0 */ Ins_UNKNOWN
,
6934 /* INS_0xA1 */ Ins_UNKNOWN
,
6935 /* INS_0xA2 */ Ins_UNKNOWN
,
6936 /* INS_0xA3 */ Ins_UNKNOWN
,
6937 /* INS_0xA4 */ Ins_UNKNOWN
,
6938 /* INS_0xA5 */ Ins_UNKNOWN
,
6939 /* INS_0xA6 */ Ins_UNKNOWN
,
6940 /* INS_0xA7 */ Ins_UNKNOWN
,
6941 /* INS_0xA8 */ Ins_UNKNOWN
,
6942 /* INS_0xA9 */ Ins_UNKNOWN
,
6943 /* INS_0xAA */ Ins_UNKNOWN
,
6944 /* INS_0xAB */ Ins_UNKNOWN
,
6945 /* INS_0xAC */ Ins_UNKNOWN
,
6946 /* INS_0xAD */ Ins_UNKNOWN
,
6947 /* INS_0xAE */ Ins_UNKNOWN
,
6948 /* INS_0xAF */ Ins_UNKNOWN
,
6950 /* PushB[0] */ Ins_PUSHB
,
6951 /* PushB[1] */ Ins_PUSHB
,
6952 /* PushB[2] */ Ins_PUSHB
,
6953 /* PushB[3] */ Ins_PUSHB
,
6954 /* PushB[4] */ Ins_PUSHB
,
6955 /* PushB[5] */ Ins_PUSHB
,
6956 /* PushB[6] */ Ins_PUSHB
,
6957 /* PushB[7] */ Ins_PUSHB
,
6958 /* PushW[0] */ Ins_PUSHW
,
6959 /* PushW[1] */ Ins_PUSHW
,
6960 /* PushW[2] */ Ins_PUSHW
,
6961 /* PushW[3] */ Ins_PUSHW
,
6962 /* PushW[4] */ Ins_PUSHW
,
6963 /* PushW[5] */ Ins_PUSHW
,
6964 /* PushW[6] */ Ins_PUSHW
,
6965 /* PushW[7] */ Ins_PUSHW
,
6967 /* MDRP[00] */ Ins_MDRP
,
6968 /* MDRP[01] */ Ins_MDRP
,
6969 /* MDRP[02] */ Ins_MDRP
,
6970 /* MDRP[03] */ Ins_MDRP
,
6971 /* MDRP[04] */ Ins_MDRP
,
6972 /* MDRP[05] */ Ins_MDRP
,
6973 /* MDRP[06] */ Ins_MDRP
,
6974 /* MDRP[07] */ Ins_MDRP
,
6975 /* MDRP[08] */ Ins_MDRP
,
6976 /* MDRP[09] */ Ins_MDRP
,
6977 /* MDRP[10] */ Ins_MDRP
,
6978 /* MDRP[11] */ Ins_MDRP
,
6979 /* MDRP[12] */ Ins_MDRP
,
6980 /* MDRP[13] */ Ins_MDRP
,
6981 /* MDRP[14] */ Ins_MDRP
,
6982 /* MDRP[15] */ Ins_MDRP
,
6984 /* MDRP[16] */ Ins_MDRP
,
6985 /* MDRP[17] */ Ins_MDRP
,
6986 /* MDRP[18] */ Ins_MDRP
,
6987 /* MDRP[19] */ Ins_MDRP
,
6988 /* MDRP[20] */ Ins_MDRP
,
6989 /* MDRP[21] */ Ins_MDRP
,
6990 /* MDRP[22] */ Ins_MDRP
,
6991 /* MDRP[23] */ Ins_MDRP
,
6992 /* MDRP[24] */ Ins_MDRP
,
6993 /* MDRP[25] */ Ins_MDRP
,
6994 /* MDRP[26] */ Ins_MDRP
,
6995 /* MDRP[27] */ Ins_MDRP
,
6996 /* MDRP[28] */ Ins_MDRP
,
6997 /* MDRP[29] */ Ins_MDRP
,
6998 /* MDRP[30] */ Ins_MDRP
,
6999 /* MDRP[31] */ Ins_MDRP
,
7001 /* MIRP[00] */ Ins_MIRP
,
7002 /* MIRP[01] */ Ins_MIRP
,
7003 /* MIRP[02] */ Ins_MIRP
,
7004 /* MIRP[03] */ Ins_MIRP
,
7005 /* MIRP[04] */ Ins_MIRP
,
7006 /* MIRP[05] */ Ins_MIRP
,
7007 /* MIRP[06] */ Ins_MIRP
,
7008 /* MIRP[07] */ Ins_MIRP
,
7009 /* MIRP[08] */ Ins_MIRP
,
7010 /* MIRP[09] */ Ins_MIRP
,
7011 /* MIRP[10] */ Ins_MIRP
,
7012 /* MIRP[11] */ Ins_MIRP
,
7013 /* MIRP[12] */ Ins_MIRP
,
7014 /* MIRP[13] */ Ins_MIRP
,
7015 /* MIRP[14] */ Ins_MIRP
,
7016 /* MIRP[15] */ Ins_MIRP
,
7018 /* MIRP[16] */ Ins_MIRP
,
7019 /* MIRP[17] */ Ins_MIRP
,
7020 /* MIRP[18] */ Ins_MIRP
,
7021 /* MIRP[19] */ Ins_MIRP
,
7022 /* MIRP[20] */ Ins_MIRP
,
7023 /* MIRP[21] */ Ins_MIRP
,
7024 /* MIRP[22] */ Ins_MIRP
,
7025 /* MIRP[23] */ Ins_MIRP
,
7026 /* MIRP[24] */ Ins_MIRP
,
7027 /* MIRP[25] */ Ins_MIRP
,
7028 /* MIRP[26] */ Ins_MIRP
,
7029 /* MIRP[27] */ Ins_MIRP
,
7030 /* MIRP[28] */ Ins_MIRP
,
7031 /* MIRP[29] */ Ins_MIRP
,
7032 /* MIRP[30] */ Ins_MIRP
,
7033 /* MIRP[31] */ Ins_MIRP
7037 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7040 /*************************************************************************/
7044 /* This function executes a run of opcodes. It will exit in the */
7045 /* following cases: */
7047 /* - Errors (in which case it returns FALSE). */
7049 /* - Reaching the end of the main code range (returns TRUE). */
7050 /* Reaching the end of a code range within a function call is an */
7053 /* - After executing one single opcode, if the flag `Instruction_Trap' */
7054 /* is set to TRUE (returns TRUE). */
7056 /* On exit with TRUE, test IP < CodeSize to know whether it comes from */
7057 /* an instruction trap or a normal termination. */
7060 /* Note: The documented DEBUG opcode pops a value from the stack. This */
7061 /* behaviour is unsupported; here a DEBUG opcode is always an */
7065 /* THIS IS THE INTERPRETER'S MAIN LOOP. */
7067 /* Instructions appear in the specification's order. */
7069 /*************************************************************************/
7072 /* documentation is in ttinterp.h */
7074 FT_EXPORT_DEF( FT_Error
)
7075 TT_RunIns( TT_ExecContext exc
)
7077 FT_Long ins_counter
= 0; /* executed instructions counter */
7080 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7084 /* set CVT functions */
7085 CUR
.tt_metrics
.ratio
= 0;
7086 if ( CUR
.metrics
.x_ppem
!= CUR
.metrics
.y_ppem
)
7088 /* non-square pixels, use the stretched routines */
7089 CUR
.func_read_cvt
= Read_CVT_Stretched
;
7090 CUR
.func_write_cvt
= Write_CVT_Stretched
;
7091 CUR
.func_move_cvt
= Move_CVT_Stretched
;
7095 /* square pixels, use normal routines */
7096 CUR
.func_read_cvt
= Read_CVT
;
7097 CUR
.func_write_cvt
= Write_CVT
;
7098 CUR
.func_move_cvt
= Move_CVT
;
7102 COMPUTE_Round( (FT_Byte
)exc
->GS
.round_state
);
7106 CUR
.opcode
= CUR
.code
[CUR
.IP
];
7108 if ( ( CUR
.length
= opcode_length
[CUR
.opcode
] ) < 0 )
7110 if ( CUR
.IP
+ 1 > CUR
.codeSize
)
7111 goto LErrorCodeOverflow_
;
7113 CUR
.length
= 2 - CUR
.length
* CUR
.code
[CUR
.IP
+ 1];
7116 if ( CUR
.IP
+ CUR
.length
> CUR
.codeSize
)
7117 goto LErrorCodeOverflow_
;
7119 /* First, let's check for empty stack and overflow */
7120 CUR
.args
= CUR
.top
- ( Pop_Push_Count
[CUR
.opcode
] >> 4 );
7122 /* `args' is the top of the stack once arguments have been popped. */
7123 /* One can also interpret it as the index of the last argument. */
7126 CUR
.error
= TT_Err_Too_Few_Arguments
;
7130 CUR
.new_top
= CUR
.args
+ ( Pop_Push_Count
[CUR
.opcode
] & 15 );
7132 /* `new_top' is the new top of the stack, after the instruction's */
7133 /* execution. `top' will be set to `new_top' after the `switch' */
7135 if ( CUR
.new_top
> CUR
.stackSize
)
7137 CUR
.error
= TT_Err_Stack_Overflow
;
7141 CUR
.step_ins
= TRUE
;
7142 CUR
.error
= TT_Err_Ok
;
7144 #ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
7147 FT_Long
* args
= CUR
.stack
+ CUR
.args
;
7148 FT_Byte opcode
= CUR
.opcode
;
7151 #undef ARRAY_BOUND_ERROR
7152 #define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
7157 case 0x00: /* SVTCA y */
7158 case 0x01: /* SVTCA x */
7159 case 0x02: /* SPvTCA y */
7160 case 0x03: /* SPvTCA x */
7161 case 0x04: /* SFvTCA y */
7162 case 0x05: /* SFvTCA x */
7167 AA
= (FT_Short
)( ( opcode
& 1 ) << 14 );
7168 BB
= (FT_Short
)( AA
^ 0x4000 );
7172 CUR
.GS
.projVector
.x
= AA
;
7173 CUR
.GS
.projVector
.y
= BB
;
7175 CUR
.GS
.dualVector
.x
= AA
;
7176 CUR
.GS
.dualVector
.y
= BB
;
7180 GUESS_VECTOR( projVector
);
7183 if ( ( opcode
& 2 ) == 0 )
7185 CUR
.GS
.freeVector
.x
= AA
;
7186 CUR
.GS
.freeVector
.y
= BB
;
7190 GUESS_VECTOR( freeVector
);
7197 case 0x06: /* SPvTL // */
7198 case 0x07: /* SPvTL + */
7202 case 0x08: /* SFvTL // */
7203 case 0x09: /* SFvTL + */
7207 case 0x0A: /* SPvFS */
7211 case 0x0B: /* SFvFS */
7215 case 0x0C: /* GPV */
7219 case 0x0D: /* GFV */
7223 case 0x0E: /* SFvTPv */
7227 case 0x0F: /* ISECT */
7228 Ins_ISECT( EXEC_ARG_ args
);
7231 case 0x10: /* SRP0 */
7235 case 0x11: /* SRP1 */
7239 case 0x12: /* SRP2 */
7243 case 0x13: /* SZP0 */
7244 Ins_SZP0( EXEC_ARG_ args
);
7247 case 0x14: /* SZP1 */
7248 Ins_SZP1( EXEC_ARG_ args
);
7251 case 0x15: /* SZP2 */
7252 Ins_SZP2( EXEC_ARG_ args
);
7255 case 0x16: /* SZPS */
7256 Ins_SZPS( EXEC_ARG_ args
);
7259 case 0x17: /* SLOOP */
7263 case 0x18: /* RTG */
7267 case 0x19: /* RTHG */
7271 case 0x1A: /* SMD */
7275 case 0x1B: /* ELSE */
7276 Ins_ELSE( EXEC_ARG_ args
);
7279 case 0x1C: /* JMPR */
7283 case 0x1D: /* SCVTCI */
7287 case 0x1E: /* SSWCI */
7291 case 0x1F: /* SSW */
7295 case 0x20: /* DUP */
7299 case 0x21: /* POP */
7303 case 0x22: /* CLEAR */
7307 case 0x23: /* SWAP */
7311 case 0x24: /* DEPTH */
7315 case 0x25: /* CINDEX */
7319 case 0x26: /* MINDEX */
7320 Ins_MINDEX( EXEC_ARG_ args
);
7323 case 0x27: /* ALIGNPTS */
7324 Ins_ALIGNPTS( EXEC_ARG_ args
);
7327 case 0x28: /* ???? */
7328 Ins_UNKNOWN( EXEC_ARG_ args
);
7331 case 0x29: /* UTP */
7332 Ins_UTP( EXEC_ARG_ args
);
7335 case 0x2A: /* LOOPCALL */
7336 Ins_LOOPCALL( EXEC_ARG_ args
);
7339 case 0x2B: /* CALL */
7340 Ins_CALL( EXEC_ARG_ args
);
7343 case 0x2C: /* FDEF */
7344 Ins_FDEF( EXEC_ARG_ args
);
7347 case 0x2D: /* ENDF */
7348 Ins_ENDF( EXEC_ARG_ args
);
7351 case 0x2E: /* MDAP */
7352 case 0x2F: /* MDAP */
7353 Ins_MDAP( EXEC_ARG_ args
);
7357 case 0x30: /* IUP */
7358 case 0x31: /* IUP */
7359 Ins_IUP( EXEC_ARG_ args
);
7362 case 0x32: /* SHP */
7363 case 0x33: /* SHP */
7364 Ins_SHP( EXEC_ARG_ args
);
7367 case 0x34: /* SHC */
7368 case 0x35: /* SHC */
7369 Ins_SHC( EXEC_ARG_ args
);
7372 case 0x36: /* SHZ */
7373 case 0x37: /* SHZ */
7374 Ins_SHZ( EXEC_ARG_ args
);
7377 case 0x38: /* SHPIX */
7378 Ins_SHPIX( EXEC_ARG_ args
);
7382 Ins_IP( EXEC_ARG_ args
);
7385 case 0x3A: /* MSIRP */
7386 case 0x3B: /* MSIRP */
7387 Ins_MSIRP( EXEC_ARG_ args
);
7390 case 0x3C: /* AlignRP */
7391 Ins_ALIGNRP( EXEC_ARG_ args
);
7394 case 0x3D: /* RTDG */
7398 case 0x3E: /* MIAP */
7399 case 0x3F: /* MIAP */
7400 Ins_MIAP( EXEC_ARG_ args
);
7403 case 0x40: /* NPUSHB */
7404 Ins_NPUSHB( EXEC_ARG_ args
);
7407 case 0x41: /* NPUSHW */
7408 Ins_NPUSHW( EXEC_ARG_ args
);
7416 CUR
.error
= TT_Err_Invalid_Reference
;
7423 case 0x44: /* WCVTP */
7427 case 0x45: /* RCVT */
7433 Ins_GC( EXEC_ARG_ args
);
7436 case 0x48: /* SCFS */
7437 Ins_SCFS( EXEC_ARG_ args
);
7442 Ins_MD( EXEC_ARG_ args
);
7445 case 0x4B: /* MPPEM */
7449 case 0x4C: /* MPS */
7453 case 0x4D: /* FLIPON */
7457 case 0x4E: /* FLIPOFF */
7461 case 0x4F: /* DEBUG */
7469 case 0x51: /* LTEQ */
7477 case 0x53: /* GTEQ */
7485 case 0x55: /* NEQ */
7489 case 0x56: /* ODD */
7493 case 0x57: /* EVEN */
7498 Ins_IF( EXEC_ARG_ args
);
7501 case 0x59: /* EIF */
7505 case 0x5A: /* AND */
7513 case 0x5C: /* NOT */
7517 case 0x5D: /* DELTAP1 */
7518 Ins_DELTAP( EXEC_ARG_ args
);
7521 case 0x5E: /* SDB */
7525 case 0x5F: /* SDS */
7529 case 0x60: /* ADD */
7533 case 0x61: /* SUB */
7537 case 0x62: /* DIV */
7541 case 0x63: /* MUL */
7545 case 0x64: /* ABS */
7549 case 0x65: /* NEG */
7553 case 0x66: /* FLOOR */
7557 case 0x67: /* CEILING */
7561 case 0x68: /* ROUND */
7562 case 0x69: /* ROUND */
7563 case 0x6A: /* ROUND */
7564 case 0x6B: /* ROUND */
7568 case 0x6C: /* NROUND */
7569 case 0x6D: /* NROUND */
7570 case 0x6E: /* NRRUND */
7571 case 0x6F: /* NROUND */
7575 case 0x70: /* WCVTF */
7579 case 0x71: /* DELTAP2 */
7580 case 0x72: /* DELTAP3 */
7581 Ins_DELTAP( EXEC_ARG_ args
);
7584 case 0x73: /* DELTAC0 */
7585 case 0x74: /* DELTAC1 */
7586 case 0x75: /* DELTAC2 */
7587 Ins_DELTAC( EXEC_ARG_ args
);
7590 case 0x76: /* SROUND */
7594 case 0x77: /* S45Round */
7598 case 0x78: /* JROT */
7602 case 0x79: /* JROF */
7606 case 0x7A: /* ROFF */
7610 case 0x7B: /* ???? */
7611 Ins_UNKNOWN( EXEC_ARG_ args
);
7614 case 0x7C: /* RUTG */
7618 case 0x7D: /* RDTG */
7622 case 0x7E: /* SANGW */
7624 /* nothing - obsolete */
7627 case 0x80: /* FLIPPT */
7628 Ins_FLIPPT( EXEC_ARG_ args
);
7631 case 0x81: /* FLIPRGON */
7632 Ins_FLIPRGON( EXEC_ARG_ args
);
7635 case 0x82: /* FLIPRGOFF */
7636 Ins_FLIPRGOFF( EXEC_ARG_ args
);
7639 case 0x83: /* UNKNOWN */
7640 case 0x84: /* UNKNOWN */
7641 Ins_UNKNOWN( EXEC_ARG_ args
);
7644 case 0x85: /* SCANCTRL */
7645 Ins_SCANCTRL( EXEC_ARG_ args
);
7648 case 0x86: /* SDPVTL */
7649 case 0x87: /* SDPVTL */
7650 Ins_SDPVTL( EXEC_ARG_ args
);
7653 case 0x88: /* GETINFO */
7654 Ins_GETINFO( EXEC_ARG_ args
);
7657 case 0x89: /* IDEF */
7658 Ins_IDEF( EXEC_ARG_ args
);
7661 case 0x8A: /* ROLL */
7662 Ins_ROLL( EXEC_ARG_ args
);
7665 case 0x8B: /* MAX */
7669 case 0x8C: /* MIN */
7673 case 0x8D: /* SCANTYPE */
7674 Ins_SCANTYPE( EXEC_ARG_ args
);
7677 case 0x8E: /* INSTCTRL */
7678 Ins_INSTCTRL( EXEC_ARG_ args
);
7682 Ins_UNKNOWN( EXEC_ARG_ args
);
7686 if ( opcode
>= 0xE0 )
7687 Ins_MIRP( EXEC_ARG_ args
);
7688 else if ( opcode
>= 0xC0 )
7689 Ins_MDRP( EXEC_ARG_ args
);
7690 else if ( opcode
>= 0xB8 )
7691 Ins_PUSHW( EXEC_ARG_ args
);
7692 else if ( opcode
>= 0xB0 )
7693 Ins_PUSHB( EXEC_ARG_ args
);
7695 Ins_UNKNOWN( EXEC_ARG_ args
);
7702 Instruct_Dispatch
[CUR
.opcode
]( EXEC_ARG_
&CUR
.stack
[CUR
.args
] );
7704 #endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7706 if ( CUR
.error
!= TT_Err_Ok
)
7708 switch ( CUR
.error
)
7710 case TT_Err_Invalid_Opcode
: /* looking for redefined instructions */
7712 TT_DefRecord
* def
= CUR
.IDefs
;
7713 TT_DefRecord
* limit
= def
+ CUR
.numIDefs
;
7716 for ( ; def
< limit
; def
++ )
7718 if ( def
->active
&& CUR
.opcode
== (FT_Byte
)def
->opc
)
7720 TT_CallRec
* callrec
;
7723 if ( CUR
.callTop
>= CUR
.callSize
)
7725 CUR
.error
= TT_Err_Invalid_Reference
;
7729 callrec
= &CUR
.callStack
[CUR
.callTop
];
7731 callrec
->Caller_Range
= CUR
.curRange
;
7732 callrec
->Caller_IP
= CUR
.IP
+ 1;
7733 callrec
->Cur_Count
= 1;
7734 callrec
->Cur_Restart
= def
->start
;
7736 if ( INS_Goto_CodeRange( def
->range
, def
->start
) == FAILURE
)
7744 CUR
.error
= TT_Err_Invalid_Opcode
;
7748 break; /* Unreachable code warning suppression. */
7749 /* Leave to remind in case a later change the editor */
7750 /* to consider break; */
7762 CUR
.top
= CUR
.new_top
;
7765 CUR
.IP
+= CUR
.length
;
7767 /* increment instruction counter and check if we didn't */
7768 /* run this program for too long (e.g. infinite loops). */
7769 if ( ++ins_counter
> MAX_RUNNABLE_OPCODES
)
7770 return TT_Err_Execution_Too_Long
;
7773 if ( CUR
.IP
>= CUR
.codeSize
)
7775 if ( CUR
.callTop
> 0 )
7777 CUR
.error
= TT_Err_Code_Overflow
;
7783 } while ( !CUR
.instruction_trap
);
7787 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7793 LErrorCodeOverflow_
:
7794 CUR
.error
= TT_Err_Code_Overflow
;
7798 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7806 #endif /* TT_USE_BYTECODE_INTERPRETER */