1 /***************************************************************************/
5 /* TrueType bytecode interpreter (body). */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
16 /***************************************************************************/
20 #include FT_INTERNAL_DEBUG_H
21 #include FT_INTERNAL_CALC_H
22 #include FT_TRIGONOMETRY_H
30 #ifdef TT_USE_BYTECODE_INTERPRETER
33 #define TT_MULFIX FT_MulFix
34 #define TT_MULDIV FT_MulDiv
35 #define TT_MULDIV_NO_ROUND FT_MulDiv_No_Round
38 /*************************************************************************/
40 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
41 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
42 /* messages during execution. */
45 #define FT_COMPONENT trace_ttinterp
47 /*************************************************************************/
49 /* In order to detect infinite loops in the code, we set up a counter */
50 /* within the run loop. A single stroke of interpretation is now */
51 /* limited to a maximal number of opcodes defined below. */
53 #define MAX_RUNNABLE_OPCODES 1000000L
56 /*************************************************************************/
58 /* There are two kinds of implementations: */
60 /* a. static implementation */
62 /* The current execution context is a static variable, which fields */
63 /* are accessed directly by the interpreter during execution. The */
64 /* context is named `cur'. */
66 /* This version is non-reentrant, of course. */
68 /* b. indirect implementation */
70 /* The current execution context is passed to _each_ function as its */
71 /* first argument, and each field is thus accessed indirectly. */
73 /* This version is fully re-entrant. */
75 /* The idea is that an indirect implementation may be slower to execute */
76 /* on low-end processors that are used in some systems (like 386s or */
79 /* As a consequence, the indirect implementation is now the default, as */
80 /* its performance costs can be considered negligible in our context. */
81 /* Note, however, that we kept the same source with macros because: */
83 /* - The code is kept very close in design to the Pascal code used for */
86 /* - It's much more readable that way! */
88 /* - It's still open to experimentation and tuning. */
90 /*************************************************************************/
93 #ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */
95 #define CUR (*exc) /* see ttobjs.h */
97 /*************************************************************************/
99 /* This macro is used whenever `exec' is unused in a function, to avoid */
100 /* stupid warnings from pedantic compilers. */
102 #define FT_UNUSED_EXEC FT_UNUSED( exc )
104 #else /* static implementation */
108 #define FT_UNUSED_EXEC int __dummy = __dummy
111 TT_ExecContextRec cur
; /* static exec. context variable */
113 /* apparently, we have a _lot_ of direct indexing when accessing */
114 /* the static `cur', which makes the code bigger (due to all the */
115 /* four bytes addresses). */
117 #endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
120 /*************************************************************************/
122 /* The instruction argument stack. */
124 #define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */
127 /*************************************************************************/
129 /* This macro is used whenever `args' is unused in a function, to avoid */
130 /* stupid warnings from pedantic compilers. */
132 #define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args )
135 /*************************************************************************/
137 /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */
138 /* increase readability of the code. */
140 /*************************************************************************/
143 #define SKIP_Code() \
146 #define GET_ShortIns() \
147 GetShortIns( EXEC_ARG )
149 #define NORMalize( x, y, v ) \
150 Normalize( EXEC_ARG_ x, y, v )
152 #define SET_SuperRound( scale, flags ) \
153 SetSuperRound( EXEC_ARG_ scale, flags )
155 #define ROUND_None( d, c ) \
156 Round_None( EXEC_ARG_ d, c )
158 #define INS_Goto_CodeRange( range, ip ) \
159 Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
161 #define CUR_Func_move( z, p, d ) \
162 CUR.func_move( EXEC_ARG_ z, p, d )
164 #define CUR_Func_move_orig( z, p, d ) \
165 CUR.func_move_orig( EXEC_ARG_ z, p, d )
167 #define CUR_Func_round( d, c ) \
168 CUR.func_round( EXEC_ARG_ d, c )
170 #define CUR_Func_read_cvt( index ) \
171 CUR.func_read_cvt( EXEC_ARG_ index )
173 #define CUR_Func_write_cvt( index, val ) \
174 CUR.func_write_cvt( EXEC_ARG_ index, val )
176 #define CUR_Func_move_cvt( index, val ) \
177 CUR.func_move_cvt( EXEC_ARG_ index, val )
179 #define CURRENT_Ratio() \
180 Current_Ratio( EXEC_ARG )
182 #define CURRENT_Ppem() \
183 Current_Ppem( EXEC_ARG )
188 #define INS_SxVTL( a, b, c, d ) \
189 Ins_SxVTL( EXEC_ARG_ a, b, c, d )
191 #define COMPUTE_Funcs() \
192 Compute_Funcs( EXEC_ARG )
194 #define COMPUTE_Round( a ) \
195 Compute_Round( EXEC_ARG_ a )
197 #define COMPUTE_Point_Displacement( a, b, c, d ) \
198 Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
200 #define MOVE_Zp2_Point( a, b, c, t ) \
201 Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
204 #define CUR_Func_project( v1, v2 ) \
205 CUR.func_project( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
207 #define CUR_Func_dualproj( v1, v2 ) \
208 CUR.func_dualproj( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
210 #define CUR_fast_project( v ) \
211 CUR.func_project( EXEC_ARG_ (v)->x, (v)->y )
213 #define CUR_fast_dualproj( v ) \
214 CUR.func_dualproj( EXEC_ARG_ (v)->x, (v)->y )
217 /*************************************************************************/
219 /* Instruction dispatch function, as used by the interpreter. */
221 typedef void (*TInstruction_Function
)( INS_ARG
);
224 /*************************************************************************/
226 /* A simple bounds-checking macro. */
228 #define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
236 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
237 #define GUESS_VECTOR( V ) \
238 if ( CUR.face->unpatented_hinting ) \
240 CUR.GS.V.x = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0x4000 : 0 ); \
241 CUR.GS.V.y = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0 : 0x4000 ); \
244 #define GUESS_VECTOR( V )
247 /*************************************************************************/
249 /* CODERANGE FUNCTIONS */
251 /*************************************************************************/
254 /*************************************************************************/
257 /* TT_Goto_CodeRange */
260 /* Switches to a new code range (updates the code related elements in */
261 /* `exec', and `IP'). */
264 /* range :: The new execution code range. */
266 /* IP :: The new IP in the new code range. */
269 /* exec :: The target execution context. */
272 /* FreeType error code. 0 means success. */
274 FT_LOCAL_DEF( FT_Error
)
275 TT_Goto_CodeRange( TT_ExecContext exec
,
279 TT_CodeRange
* coderange
;
282 FT_ASSERT( range
>= 1 && range
<= 3 );
284 coderange
= &exec
->codeRangeTable
[range
- 1];
286 FT_ASSERT( coderange
->base
!= NULL
);
288 /* NOTE: Because the last instruction of a program may be a CALL */
289 /* which will return to the first byte *after* the code */
290 /* range, we test for IP <= Size instead of IP < Size. */
292 FT_ASSERT( (FT_ULong
)IP
<= coderange
->size
);
294 exec
->code
= coderange
->base
;
295 exec
->codeSize
= coderange
->size
;
297 exec
->curRange
= range
;
303 /*************************************************************************/
306 /* TT_Set_CodeRange */
309 /* Sets a code range. */
312 /* range :: The code range index. */
314 /* base :: The new code base. */
316 /* length :: The range size in bytes. */
319 /* exec :: The target execution context. */
322 /* FreeType error code. 0 means success. */
324 FT_LOCAL_DEF( FT_Error
)
325 TT_Set_CodeRange( TT_ExecContext exec
,
330 FT_ASSERT( range
>= 1 && range
<= 3 );
332 exec
->codeRangeTable
[range
- 1].base
= (FT_Byte
*)base
;
333 exec
->codeRangeTable
[range
- 1].size
= length
;
339 /*************************************************************************/
342 /* TT_Clear_CodeRange */
345 /* Clears a code range. */
348 /* range :: The code range index. */
351 /* exec :: The target execution context. */
354 /* FreeType error code. 0 means success. */
357 /* Does not set the Error variable. */
359 FT_LOCAL_DEF( FT_Error
)
360 TT_Clear_CodeRange( TT_ExecContext exec
,
363 FT_ASSERT( range
>= 1 && range
<= 3 );
365 exec
->codeRangeTable
[range
- 1].base
= NULL
;
366 exec
->codeRangeTable
[range
- 1].size
= 0;
372 /*************************************************************************/
374 /* EXECUTION CONTEXT ROUTINES */
376 /*************************************************************************/
379 /*************************************************************************/
382 /* TT_Done_Context */
385 /* Destroys a given context. */
388 /* exec :: A handle to the target execution context. */
390 /* memory :: A handle to the parent memory object. */
393 /* FreeType error code. 0 means success. */
396 /* Only the glyph loader and debugger should call this function. */
398 FT_LOCAL_DEF( FT_Error
)
399 TT_Done_Context( TT_ExecContext exec
)
401 FT_Memory memory
= exec
->memory
;
406 exec
->maxContours
= 0;
409 FT_FREE( exec
->stack
);
412 /* free call stack */
413 FT_FREE( exec
->callStack
);
417 /* free glyph code range */
418 FT_FREE( exec
->glyphIns
);
430 /*************************************************************************/
436 /* Initializes a context object. */
439 /* memory :: A handle to the parent memory object. */
442 /* exec :: A handle to the target execution context. */
445 /* FreeType error code. 0 means success. */
448 Init_Context( TT_ExecContext exec
,
454 FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec
));
456 exec
->memory
= memory
;
459 if ( FT_NEW_ARRAY( exec
->callStack
, exec
->callSize
) )
462 /* all values in the context are set to 0 already, but this is */
463 /* here as a remainder */
465 exec
->maxContours
= 0;
471 exec
->glyphIns
= NULL
;
479 FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n",
481 TT_Done_Context( exec
);
487 /*************************************************************************/
493 /* Checks the size of a buffer and reallocates it if necessary. */
496 /* memory :: A handle to the parent memory object. */
498 /* multiplier :: The size in bytes of each element in the buffer. */
500 /* new_max :: The new capacity (size) of the buffer. */
503 /* size :: The address of the buffer's current size expressed */
506 /* buff :: The address of the buffer base pointer. */
509 /* FreeType error code. 0 means success. */
512 Update_Max( FT_Memory memory
,
519 void** pbuff
= (void**)_pbuff
;
522 if ( *size
< new_max
)
524 if ( FT_REALLOC( *pbuff
, *size
* multiplier
, new_max
* multiplier
) )
533 /*************************************************************************/
536 /* TT_Load_Context */
539 /* Prepare an execution context for glyph hinting. */
542 /* face :: A handle to the source face object. */
544 /* size :: A handle to the source size object. */
547 /* exec :: A handle to the target execution context. */
550 /* FreeType error code. 0 means success. */
553 /* Only the glyph loader and debugger should call this function. */
555 FT_LOCAL_DEF( FT_Error
)
556 TT_Load_Context( TT_ExecContext exec
,
567 maxp
= &face
->max_profile
;
572 exec
->numFDefs
= size
->num_function_defs
;
573 exec
->maxFDefs
= size
->max_function_defs
;
574 exec
->numIDefs
= size
->num_instruction_defs
;
575 exec
->maxIDefs
= size
->max_instruction_defs
;
576 exec
->FDefs
= size
->function_defs
;
577 exec
->IDefs
= size
->instruction_defs
;
578 exec
->tt_metrics
= size
->ttmetrics
;
579 exec
->metrics
= size
->metrics
;
581 exec
->maxFunc
= size
->max_func
;
582 exec
->maxIns
= size
->max_ins
;
584 for ( i
= 0; i
< TT_MAX_CODE_RANGES
; i
++ )
585 exec
->codeRangeTable
[i
] = size
->codeRangeTable
[i
];
587 /* set graphics state */
590 exec
->cvtSize
= size
->cvt_size
;
591 exec
->cvt
= size
->cvt
;
593 exec
->storeSize
= size
->storage_size
;
594 exec
->storage
= size
->storage
;
596 exec
->twilight
= size
->twilight
;
599 /* XXX: We reserve a little more elements on the stack to deal safely */
600 /* with broken fonts like arialbs, courbs, timesbs, etc. */
601 tmp
= exec
->stackSize
;
602 error
= Update_Max( exec
->memory
,
604 sizeof ( FT_F26Dot6
),
606 maxp
->maxStackElements
+ 32 );
607 exec
->stackSize
= (FT_UInt
)tmp
;
611 tmp
= exec
->glyphSize
;
612 error
= Update_Max( exec
->memory
,
615 (void*)&exec
->glyphIns
,
616 maxp
->maxSizeOfInstructions
);
617 exec
->glyphSize
= (FT_UShort
)tmp
;
621 exec
->pts
.n_points
= 0;
622 exec
->pts
.n_contours
= 0;
624 exec
->zp1
= exec
->pts
;
625 exec
->zp2
= exec
->pts
;
626 exec
->zp0
= exec
->pts
;
628 exec
->instruction_trap
= FALSE
;
634 /*************************************************************************/
637 /* TT_Save_Context */
640 /* Saves the code ranges in a `size' object. */
643 /* exec :: A handle to the source execution context. */
646 /* size :: A handle to the target size object. */
649 /* FreeType error code. 0 means success. */
652 /* Only the glyph loader and debugger should call this function. */
654 FT_LOCAL_DEF( FT_Error
)
655 TT_Save_Context( TT_ExecContext exec
,
661 /* XXXX: Will probably disappear soon with all the code range */
662 /* management, which is now rather obsolete. */
664 size
->num_function_defs
= exec
->numFDefs
;
665 size
->num_instruction_defs
= exec
->numIDefs
;
667 size
->max_func
= exec
->maxFunc
;
668 size
->max_ins
= exec
->maxIns
;
670 for ( i
= 0; i
< TT_MAX_CODE_RANGES
; i
++ )
671 size
->codeRangeTable
[i
] = exec
->codeRangeTable
[i
];
677 /*************************************************************************/
683 /* Executes one or more instructions in the execution context. */
686 /* debug :: A Boolean flag. If set, the function sets some internal */
687 /* variables and returns immediately, otherwise TT_RunIns() */
690 /* This is commented out currently. */
693 /* exec :: A handle to the target execution context. */
696 /* TrueType error code. 0 means success. */
699 /* Only the glyph loader and debugger should call this function. */
701 FT_LOCAL_DEF( FT_Error
)
702 TT_Run_Context( TT_ExecContext exec
,
708 if ( ( error
= TT_Goto_CodeRange( exec
, tt_coderange_glyph
, 0 ) )
712 exec
->zp0
= exec
->pts
;
713 exec
->zp1
= exec
->pts
;
714 exec
->zp2
= exec
->pts
;
720 exec
->GS
.projVector
.x
= 0x4000;
721 exec
->GS
.projVector
.y
= 0x0000;
723 exec
->GS
.freeVector
= exec
->GS
.projVector
;
724 exec
->GS
.dualVector
= exec
->GS
.projVector
;
726 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
727 exec
->GS
.both_x_axis
= TRUE
;
730 exec
->GS
.round_state
= 1;
733 /* some glyphs leave something on the stack. so we clean it */
734 /* before a new execution. */
741 return exec
->face
->interpreter( exec
);
744 return TT_RunIns( exec
);
751 /* The default value for `scan_control' is documented as FALSE in the */
752 /* TrueType specification. This is confusing since it implies a */
753 /* Boolean value. However, this is not the case, thus both the */
754 /* default values of our `scan_type' and `scan_control' fields (which */
755 /* the documentation's `scan_control' variable is split into) are */
758 const TT_GraphicsState tt_default_graphics_state
=
765 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
770 TRUE
, 68, 0, 0, 9, 3,
775 /* documentation is in ttinterp.h */
777 FT_EXPORT_DEF( TT_ExecContext
)
778 TT_New_Context( TT_Driver driver
)
784 memory
= driver
->root
.root
.memory
;
785 exec
= driver
->context
;
787 if ( !driver
->context
)
792 /* allocate object */
793 if ( FT_NEW( exec
) )
796 /* initialize it; in case of error this deallocates `exec' too */
797 error
= Init_Context( exec
, memory
);
801 /* store it into the driver */
802 driver
->context
= exec
;
805 return driver
->context
;
812 /*************************************************************************/
814 /* Before an opcode is executed, the interpreter verifies that there are */
815 /* enough arguments on the stack, with the help of the `Pop_Push_Count' */
818 /* For each opcode, the first column gives the number of arguments that */
819 /* are popped from the stack; the second one gives the number of those */
820 /* that are pushed in result. */
822 /* Opcodes which have a varying number of parameters in the data stream */
823 /* (NPUSHB, NPUSHW) are handled specially; they have a negative value in */
824 /* the `opcode_length' table, and the value in `Pop_Push_Count' is set */
827 /*************************************************************************/
831 #define PACK( x, y ) ( ( x << 4 ) | y )
835 const FT_Byte Pop_Push_Count
[256] =
837 /* opcodes are gathered in groups of 16 */
838 /* please keep the spaces as they are */
840 /* SVTCA y */ PACK( 0, 0 ),
841 /* SVTCA x */ PACK( 0, 0 ),
842 /* SPvTCA y */ PACK( 0, 0 ),
843 /* SPvTCA x */ PACK( 0, 0 ),
844 /* SFvTCA y */ PACK( 0, 0 ),
845 /* SFvTCA x */ PACK( 0, 0 ),
846 /* SPvTL // */ PACK( 2, 0 ),
847 /* SPvTL + */ PACK( 2, 0 ),
848 /* SFvTL // */ PACK( 2, 0 ),
849 /* SFvTL + */ PACK( 2, 0 ),
850 /* SPvFS */ PACK( 2, 0 ),
851 /* SFvFS */ PACK( 2, 0 ),
852 /* GPV */ PACK( 0, 2 ),
853 /* GFV */ PACK( 0, 2 ),
854 /* SFvTPv */ PACK( 0, 0 ),
855 /* ISECT */ PACK( 5, 0 ),
857 /* SRP0 */ PACK( 1, 0 ),
858 /* SRP1 */ PACK( 1, 0 ),
859 /* SRP2 */ PACK( 1, 0 ),
860 /* SZP0 */ PACK( 1, 0 ),
861 /* SZP1 */ PACK( 1, 0 ),
862 /* SZP2 */ PACK( 1, 0 ),
863 /* SZPS */ PACK( 1, 0 ),
864 /* SLOOP */ PACK( 1, 0 ),
865 /* RTG */ PACK( 0, 0 ),
866 /* RTHG */ PACK( 0, 0 ),
867 /* SMD */ PACK( 1, 0 ),
868 /* ELSE */ PACK( 0, 0 ),
869 /* JMPR */ PACK( 1, 0 ),
870 /* SCvTCi */ PACK( 1, 0 ),
871 /* SSwCi */ PACK( 1, 0 ),
872 /* SSW */ PACK( 1, 0 ),
874 /* DUP */ PACK( 1, 2 ),
875 /* POP */ PACK( 1, 0 ),
876 /* CLEAR */ PACK( 0, 0 ),
877 /* SWAP */ PACK( 2, 2 ),
878 /* DEPTH */ PACK( 0, 1 ),
879 /* CINDEX */ PACK( 1, 1 ),
880 /* MINDEX */ PACK( 1, 0 ),
881 /* AlignPTS */ PACK( 2, 0 ),
882 /* INS_$28 */ PACK( 0, 0 ),
883 /* UTP */ PACK( 1, 0 ),
884 /* LOOPCALL */ PACK( 2, 0 ),
885 /* CALL */ PACK( 1, 0 ),
886 /* FDEF */ PACK( 1, 0 ),
887 /* ENDF */ PACK( 0, 0 ),
888 /* MDAP[0] */ PACK( 1, 0 ),
889 /* MDAP[1] */ PACK( 1, 0 ),
891 /* IUP[0] */ PACK( 0, 0 ),
892 /* IUP[1] */ PACK( 0, 0 ),
893 /* SHP[0] */ PACK( 0, 0 ),
894 /* SHP[1] */ PACK( 0, 0 ),
895 /* SHC[0] */ PACK( 1, 0 ),
896 /* SHC[1] */ PACK( 1, 0 ),
897 /* SHZ[0] */ PACK( 1, 0 ),
898 /* SHZ[1] */ PACK( 1, 0 ),
899 /* SHPIX */ PACK( 1, 0 ),
900 /* IP */ PACK( 0, 0 ),
901 /* MSIRP[0] */ PACK( 2, 0 ),
902 /* MSIRP[1] */ PACK( 2, 0 ),
903 /* AlignRP */ PACK( 0, 0 ),
904 /* RTDG */ PACK( 0, 0 ),
905 /* MIAP[0] */ PACK( 2, 0 ),
906 /* MIAP[1] */ PACK( 2, 0 ),
908 /* NPushB */ PACK( 0, 0 ),
909 /* NPushW */ PACK( 0, 0 ),
910 /* WS */ PACK( 2, 0 ),
911 /* RS */ PACK( 1, 1 ),
912 /* WCvtP */ PACK( 2, 0 ),
913 /* RCvt */ PACK( 1, 1 ),
914 /* GC[0] */ PACK( 1, 1 ),
915 /* GC[1] */ PACK( 1, 1 ),
916 /* SCFS */ PACK( 2, 0 ),
917 /* MD[0] */ PACK( 2, 1 ),
918 /* MD[1] */ PACK( 2, 1 ),
919 /* MPPEM */ PACK( 0, 1 ),
920 /* MPS */ PACK( 0, 1 ),
921 /* FlipON */ PACK( 0, 0 ),
922 /* FlipOFF */ PACK( 0, 0 ),
923 /* DEBUG */ PACK( 1, 0 ),
925 /* LT */ PACK( 2, 1 ),
926 /* LTEQ */ PACK( 2, 1 ),
927 /* GT */ PACK( 2, 1 ),
928 /* GTEQ */ PACK( 2, 1 ),
929 /* EQ */ PACK( 2, 1 ),
930 /* NEQ */ PACK( 2, 1 ),
931 /* ODD */ PACK( 1, 1 ),
932 /* EVEN */ PACK( 1, 1 ),
933 /* IF */ PACK( 1, 0 ),
934 /* EIF */ PACK( 0, 0 ),
935 /* AND */ PACK( 2, 1 ),
936 /* OR */ PACK( 2, 1 ),
937 /* NOT */ PACK( 1, 1 ),
938 /* DeltaP1 */ PACK( 1, 0 ),
939 /* SDB */ PACK( 1, 0 ),
940 /* SDS */ PACK( 1, 0 ),
942 /* ADD */ PACK( 2, 1 ),
943 /* SUB */ PACK( 2, 1 ),
944 /* DIV */ PACK( 2, 1 ),
945 /* MUL */ PACK( 2, 1 ),
946 /* ABS */ PACK( 1, 1 ),
947 /* NEG */ PACK( 1, 1 ),
948 /* FLOOR */ PACK( 1, 1 ),
949 /* CEILING */ PACK( 1, 1 ),
950 /* ROUND[0] */ PACK( 1, 1 ),
951 /* ROUND[1] */ PACK( 1, 1 ),
952 /* ROUND[2] */ PACK( 1, 1 ),
953 /* ROUND[3] */ PACK( 1, 1 ),
954 /* NROUND[0] */ PACK( 1, 1 ),
955 /* NROUND[1] */ PACK( 1, 1 ),
956 /* NROUND[2] */ PACK( 1, 1 ),
957 /* NROUND[3] */ PACK( 1, 1 ),
959 /* WCvtF */ PACK( 2, 0 ),
960 /* DeltaP2 */ PACK( 1, 0 ),
961 /* DeltaP3 */ PACK( 1, 0 ),
962 /* DeltaCn[0] */ PACK( 1, 0 ),
963 /* DeltaCn[1] */ PACK( 1, 0 ),
964 /* DeltaCn[2] */ PACK( 1, 0 ),
965 /* SROUND */ PACK( 1, 0 ),
966 /* S45Round */ PACK( 1, 0 ),
967 /* JROT */ PACK( 2, 0 ),
968 /* JROF */ PACK( 2, 0 ),
969 /* ROFF */ PACK( 0, 0 ),
970 /* INS_$7B */ PACK( 0, 0 ),
971 /* RUTG */ PACK( 0, 0 ),
972 /* RDTG */ PACK( 0, 0 ),
973 /* SANGW */ PACK( 1, 0 ),
974 /* AA */ PACK( 1, 0 ),
976 /* FlipPT */ PACK( 0, 0 ),
977 /* FlipRgON */ PACK( 2, 0 ),
978 /* FlipRgOFF */ PACK( 2, 0 ),
979 /* INS_$83 */ PACK( 0, 0 ),
980 /* INS_$84 */ PACK( 0, 0 ),
981 /* ScanCTRL */ PACK( 1, 0 ),
982 /* SDVPTL[0] */ PACK( 2, 0 ),
983 /* SDVPTL[1] */ PACK( 2, 0 ),
984 /* GetINFO */ PACK( 1, 1 ),
985 /* IDEF */ PACK( 1, 0 ),
986 /* ROLL */ PACK( 3, 3 ),
987 /* MAX */ PACK( 2, 1 ),
988 /* MIN */ PACK( 2, 1 ),
989 /* ScanTYPE */ PACK( 1, 0 ),
990 /* InstCTRL */ PACK( 2, 0 ),
991 /* INS_$8F */ PACK( 0, 0 ),
993 /* INS_$90 */ PACK( 0, 0 ),
994 /* INS_$91 */ PACK( 0, 0 ),
995 /* INS_$92 */ PACK( 0, 0 ),
996 /* INS_$93 */ PACK( 0, 0 ),
997 /* INS_$94 */ PACK( 0, 0 ),
998 /* INS_$95 */ PACK( 0, 0 ),
999 /* INS_$96 */ PACK( 0, 0 ),
1000 /* INS_$97 */ PACK( 0, 0 ),
1001 /* INS_$98 */ PACK( 0, 0 ),
1002 /* INS_$99 */ PACK( 0, 0 ),
1003 /* INS_$9A */ PACK( 0, 0 ),
1004 /* INS_$9B */ PACK( 0, 0 ),
1005 /* INS_$9C */ PACK( 0, 0 ),
1006 /* INS_$9D */ PACK( 0, 0 ),
1007 /* INS_$9E */ PACK( 0, 0 ),
1008 /* INS_$9F */ PACK( 0, 0 ),
1010 /* INS_$A0 */ PACK( 0, 0 ),
1011 /* INS_$A1 */ PACK( 0, 0 ),
1012 /* INS_$A2 */ PACK( 0, 0 ),
1013 /* INS_$A3 */ PACK( 0, 0 ),
1014 /* INS_$A4 */ PACK( 0, 0 ),
1015 /* INS_$A5 */ PACK( 0, 0 ),
1016 /* INS_$A6 */ PACK( 0, 0 ),
1017 /* INS_$A7 */ PACK( 0, 0 ),
1018 /* INS_$A8 */ PACK( 0, 0 ),
1019 /* INS_$A9 */ PACK( 0, 0 ),
1020 /* INS_$AA */ PACK( 0, 0 ),
1021 /* INS_$AB */ PACK( 0, 0 ),
1022 /* INS_$AC */ PACK( 0, 0 ),
1023 /* INS_$AD */ PACK( 0, 0 ),
1024 /* INS_$AE */ PACK( 0, 0 ),
1025 /* INS_$AF */ PACK( 0, 0 ),
1027 /* PushB[0] */ PACK( 0, 1 ),
1028 /* PushB[1] */ PACK( 0, 2 ),
1029 /* PushB[2] */ PACK( 0, 3 ),
1030 /* PushB[3] */ PACK( 0, 4 ),
1031 /* PushB[4] */ PACK( 0, 5 ),
1032 /* PushB[5] */ PACK( 0, 6 ),
1033 /* PushB[6] */ PACK( 0, 7 ),
1034 /* PushB[7] */ PACK( 0, 8 ),
1035 /* PushW[0] */ PACK( 0, 1 ),
1036 /* PushW[1] */ PACK( 0, 2 ),
1037 /* PushW[2] */ PACK( 0, 3 ),
1038 /* PushW[3] */ PACK( 0, 4 ),
1039 /* PushW[4] */ PACK( 0, 5 ),
1040 /* PushW[5] */ PACK( 0, 6 ),
1041 /* PushW[6] */ PACK( 0, 7 ),
1042 /* PushW[7] */ PACK( 0, 8 ),
1044 /* MDRP[00] */ PACK( 1, 0 ),
1045 /* MDRP[01] */ PACK( 1, 0 ),
1046 /* MDRP[02] */ PACK( 1, 0 ),
1047 /* MDRP[03] */ PACK( 1, 0 ),
1048 /* MDRP[04] */ PACK( 1, 0 ),
1049 /* MDRP[05] */ PACK( 1, 0 ),
1050 /* MDRP[06] */ PACK( 1, 0 ),
1051 /* MDRP[07] */ PACK( 1, 0 ),
1052 /* MDRP[08] */ PACK( 1, 0 ),
1053 /* MDRP[09] */ PACK( 1, 0 ),
1054 /* MDRP[10] */ PACK( 1, 0 ),
1055 /* MDRP[11] */ PACK( 1, 0 ),
1056 /* MDRP[12] */ PACK( 1, 0 ),
1057 /* MDRP[13] */ PACK( 1, 0 ),
1058 /* MDRP[14] */ PACK( 1, 0 ),
1059 /* MDRP[15] */ PACK( 1, 0 ),
1061 /* MDRP[16] */ PACK( 1, 0 ),
1062 /* MDRP[17] */ PACK( 1, 0 ),
1063 /* MDRP[18] */ PACK( 1, 0 ),
1064 /* MDRP[19] */ PACK( 1, 0 ),
1065 /* MDRP[20] */ PACK( 1, 0 ),
1066 /* MDRP[21] */ PACK( 1, 0 ),
1067 /* MDRP[22] */ PACK( 1, 0 ),
1068 /* MDRP[23] */ PACK( 1, 0 ),
1069 /* MDRP[24] */ PACK( 1, 0 ),
1070 /* MDRP[25] */ PACK( 1, 0 ),
1071 /* MDRP[26] */ PACK( 1, 0 ),
1072 /* MDRP[27] */ PACK( 1, 0 ),
1073 /* MDRP[28] */ PACK( 1, 0 ),
1074 /* MDRP[29] */ PACK( 1, 0 ),
1075 /* MDRP[30] */ PACK( 1, 0 ),
1076 /* MDRP[31] */ PACK( 1, 0 ),
1078 /* MIRP[00] */ PACK( 2, 0 ),
1079 /* MIRP[01] */ PACK( 2, 0 ),
1080 /* MIRP[02] */ PACK( 2, 0 ),
1081 /* MIRP[03] */ PACK( 2, 0 ),
1082 /* MIRP[04] */ PACK( 2, 0 ),
1083 /* MIRP[05] */ PACK( 2, 0 ),
1084 /* MIRP[06] */ PACK( 2, 0 ),
1085 /* MIRP[07] */ PACK( 2, 0 ),
1086 /* MIRP[08] */ PACK( 2, 0 ),
1087 /* MIRP[09] */ PACK( 2, 0 ),
1088 /* MIRP[10] */ PACK( 2, 0 ),
1089 /* MIRP[11] */ PACK( 2, 0 ),
1090 /* MIRP[12] */ PACK( 2, 0 ),
1091 /* MIRP[13] */ PACK( 2, 0 ),
1092 /* MIRP[14] */ PACK( 2, 0 ),
1093 /* MIRP[15] */ PACK( 2, 0 ),
1095 /* MIRP[16] */ PACK( 2, 0 ),
1096 /* MIRP[17] */ PACK( 2, 0 ),
1097 /* MIRP[18] */ PACK( 2, 0 ),
1098 /* MIRP[19] */ PACK( 2, 0 ),
1099 /* MIRP[20] */ PACK( 2, 0 ),
1100 /* MIRP[21] */ PACK( 2, 0 ),
1101 /* MIRP[22] */ PACK( 2, 0 ),
1102 /* MIRP[23] */ PACK( 2, 0 ),
1103 /* MIRP[24] */ PACK( 2, 0 ),
1104 /* MIRP[25] */ PACK( 2, 0 ),
1105 /* MIRP[26] */ PACK( 2, 0 ),
1106 /* MIRP[27] */ PACK( 2, 0 ),
1107 /* MIRP[28] */ PACK( 2, 0 ),
1108 /* MIRP[29] */ PACK( 2, 0 ),
1109 /* MIRP[30] */ PACK( 2, 0 ),
1110 /* MIRP[31] */ PACK( 2, 0 )
1115 const FT_Char opcode_length
[256] =
1117 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1118 1, 1, 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,
1122 -1,-2, 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,
1127 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
1132 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1133 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1134 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1135 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1143 TT_MulFix14( FT_Int32 a
,
1147 FT_UInt32 ah
, al
, mid
, lo
, hi
;
1157 ah
= (FT_UInt32
)( ( a
>> 16 ) & 0xFFFFU
);
1158 al
= (FT_UInt32
)( a
& 0xFFFFU
);
1163 mid
= ( mid
<< 16 ) + ( 1 << 13 ); /* rounding */
1168 mid
= ( lo
>> 14 ) | ( hi
<< 18 );
1170 return sign
>= 0 ? (FT_Int32
)mid
: -(FT_Int32
)mid
;
1175 /* compute (a*b)/2^14 with maximal accuracy and rounding */
1177 TT_MulFix14( FT_Int32 a
,
1184 /* compute ax*bx as 64-bit value */
1185 l
= (FT_UInt32
)( ( a
& 0xFFFFU
) * b
);
1186 m
= ( a
>> 16 ) * b
;
1188 lo
= l
+ (FT_UInt32
)( m
<< 16 );
1189 hi
= ( m
>> 16 ) + ( (FT_Int32
)l
>> 31 ) + ( lo
< l
);
1191 /* divide the result by 2^14 with rounding */
1193 l
= lo
+ (FT_UInt32
)s
;
1194 hi
+= s
+ ( l
< lo
);
1200 return ( hi
<< 18 ) | ( l
>> 14 );
1205 /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */
1207 TT_DotFix14( FT_Int32 ax
,
1212 FT_Int32 m
, s
, hi1
, hi2
, hi
;
1213 FT_UInt32 l
, lo1
, lo2
, lo
;
1216 /* compute ax*bx as 64-bit value */
1217 l
= (FT_UInt32
)( ( ax
& 0xFFFFU
) * bx
);
1218 m
= ( ax
>> 16 ) * bx
;
1220 lo1
= l
+ (FT_UInt32
)( m
<< 16 );
1221 hi1
= ( m
>> 16 ) + ( (FT_Int32
)l
>> 31 ) + ( lo1
< l
);
1223 /* compute ay*by as 64-bit value */
1224 l
= (FT_UInt32
)( ( ay
& 0xFFFFU
) * by
);
1225 m
= ( ay
>> 16 ) * by
;
1227 lo2
= l
+ (FT_UInt32
)( m
<< 16 );
1228 hi2
= ( m
>> 16 ) + ( (FT_Int32
)l
>> 31 ) + ( lo2
< l
);
1232 hi
= hi1
+ hi2
+ ( lo
< lo1
);
1234 /* divide the result by 2^14 with rounding */
1236 l
= lo
+ (FT_UInt32
)s
;
1237 hi
+= s
+ ( l
< lo
);
1243 return ( hi
<< 18 ) | ( l
>> 14 );
1247 /* return length of given vector */
1252 TT_VecLen( FT_Int32 x
,
1255 FT_Int32 m
, hi1
, hi2
, hi
;
1256 FT_UInt32 l
, lo1
, lo2
, lo
;
1259 /* compute x*x as 64-bit value */
1260 lo
= (FT_UInt32
)( x
& 0xFFFFU
);
1267 lo1
= l
+ (FT_UInt32
)( m
<< 17 );
1268 hi1
= hi
+ ( m
>> 15 ) + ( lo1
< l
);
1270 /* compute y*y as 64-bit value */
1271 lo
= (FT_UInt32
)( y
& 0xFFFFU
);
1278 lo2
= l
+ (FT_UInt32
)( m
<< 17 );
1279 hi2
= hi
+ ( m
>> 15 ) + ( lo2
< l
);
1281 /* add them to get 'x*x+y*y' as 64-bit value */
1283 hi
= hi1
+ hi2
+ ( lo
< lo1
);
1285 /* compute the square root of this value */
1287 FT_UInt32 root
, rem
, test_div
;
1298 rem
= ( rem
<< 2 ) | ( (FT_UInt32
)hi
>> 30 );
1299 hi
= ( hi
<< 2 ) | ( lo
>> 30 );
1302 test_div
= ( root
<< 1 ) + 1;
1304 if ( rem
>= test_div
)
1309 } while ( --count
);
1312 return (FT_Int32
)root
;
1318 /* this version uses FT_Vector_Length which computes the same value */
1319 /* much, much faster.. */
1322 TT_VecLen( FT_F26Dot6 X
,
1331 return FT_Vector_Length( &v
);
1337 /*************************************************************************/
1343 /* Returns the current aspect ratio scaling factor depending on the */
1344 /* projection vector's state and device resolutions. */
1347 /* The aspect ratio in 16.16 format, always <= 1.0 . */
1350 Current_Ratio( EXEC_OP
)
1352 if ( !CUR
.tt_metrics
.ratio
)
1354 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1355 if ( CUR
.face
->unpatented_hinting
)
1357 if ( CUR
.GS
.both_x_axis
)
1358 CUR
.tt_metrics
.ratio
= CUR
.tt_metrics
.x_ratio
;
1360 CUR
.tt_metrics
.ratio
= CUR
.tt_metrics
.y_ratio
;
1365 if ( CUR
.GS
.projVector
.y
== 0 )
1366 CUR
.tt_metrics
.ratio
= CUR
.tt_metrics
.x_ratio
;
1368 else if ( CUR
.GS
.projVector
.x
== 0 )
1369 CUR
.tt_metrics
.ratio
= CUR
.tt_metrics
.y_ratio
;
1376 x
= TT_MULDIV( CUR
.GS
.projVector
.x
,
1377 CUR
.tt_metrics
.x_ratio
, 0x4000 );
1378 y
= TT_MULDIV( CUR
.GS
.projVector
.y
,
1379 CUR
.tt_metrics
.y_ratio
, 0x4000 );
1380 CUR
.tt_metrics
.ratio
= TT_VecLen( x
, y
);
1384 return CUR
.tt_metrics
.ratio
;
1389 Current_Ppem( EXEC_OP
)
1391 return TT_MULFIX( CUR
.tt_metrics
.ppem
, CURRENT_Ratio() );
1395 /*************************************************************************/
1397 /* Functions related to the control value table (CVT). */
1399 /*************************************************************************/
1402 FT_CALLBACK_DEF( FT_F26Dot6
)
1403 Read_CVT( EXEC_OP_ FT_ULong idx
)
1405 return CUR
.cvt
[idx
];
1409 FT_CALLBACK_DEF( FT_F26Dot6
)
1410 Read_CVT_Stretched( EXEC_OP_ FT_ULong idx
)
1412 return TT_MULFIX( CUR
.cvt
[idx
], CURRENT_Ratio() );
1416 FT_CALLBACK_DEF( void )
1417 Write_CVT( EXEC_OP_ FT_ULong idx
,
1420 CUR
.cvt
[idx
] = value
;
1424 FT_CALLBACK_DEF( void )
1425 Write_CVT_Stretched( EXEC_OP_ FT_ULong idx
,
1428 CUR
.cvt
[idx
] = FT_DivFix( value
, CURRENT_Ratio() );
1432 FT_CALLBACK_DEF( void )
1433 Move_CVT( EXEC_OP_ FT_ULong idx
,
1436 CUR
.cvt
[idx
] += value
;
1440 FT_CALLBACK_DEF( void )
1441 Move_CVT_Stretched( EXEC_OP_ FT_ULong idx
,
1444 CUR
.cvt
[idx
] += FT_DivFix( value
, CURRENT_Ratio() );
1448 /*************************************************************************/
1454 /* Returns a short integer taken from the instruction stream at */
1458 /* Short read at code[IP]. */
1461 /* This one could become a macro. */
1464 GetShortIns( EXEC_OP
)
1466 /* Reading a byte stream so there is no endianess (DaveP) */
1468 return (FT_Short
)( ( CUR
.code
[CUR
.IP
- 2] << 8 ) +
1469 CUR
.code
[CUR
.IP
- 1] );
1473 /*************************************************************************/
1476 /* Ins_Goto_CodeRange */
1479 /* Goes to a certain code range in the instruction stream. */
1482 /* aRange :: The index of the code range. */
1484 /* aIP :: The new IP address in the code range. */
1487 /* SUCCESS or FAILURE. */
1490 Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange
,
1493 TT_CodeRange
* range
;
1496 if ( aRange
< 1 || aRange
> 3 )
1498 CUR
.error
= TT_Err_Bad_Argument
;
1502 range
= &CUR
.codeRangeTable
[aRange
- 1];
1504 if ( range
->base
== NULL
) /* invalid coderange */
1506 CUR
.error
= TT_Err_Invalid_CodeRange
;
1510 /* NOTE: Because the last instruction of a program may be a CALL */
1511 /* which will return to the first byte *after* the code */
1512 /* range, we test for AIP <= Size, instead of AIP < Size. */
1514 if ( aIP
> range
->size
)
1516 CUR
.error
= TT_Err_Code_Overflow
;
1520 CUR
.code
= range
->base
;
1521 CUR
.codeSize
= range
->size
;
1523 CUR
.curRange
= aRange
;
1529 /*************************************************************************/
1535 /* Moves a point by a given distance along the freedom vector. The */
1536 /* point will be `touched'. */
1539 /* point :: The index of the point to move. */
1541 /* distance :: The distance to apply. */
1544 /* zone :: The affected glyph zone. */
1547 Direct_Move( EXEC_OP_ TT_GlyphZone zone
,
1549 FT_F26Dot6 distance
)
1554 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1555 FT_ASSERT( !CUR
.face
->unpatented_hinting
);
1558 v
= CUR
.GS
.freeVector
.x
;
1562 zone
->cur
[point
].x
+= TT_MULDIV( distance
,
1566 zone
->tags
[point
] |= FT_CURVE_TAG_TOUCH_X
;
1569 v
= CUR
.GS
.freeVector
.y
;
1573 zone
->cur
[point
].y
+= TT_MULDIV( distance
,
1577 zone
->tags
[point
] |= FT_CURVE_TAG_TOUCH_Y
;
1582 /*************************************************************************/
1585 /* Direct_Move_Orig */
1588 /* Moves the *original* position of a point by a given distance along */
1589 /* the freedom vector. Obviously, the point will not be `touched'. */
1592 /* point :: The index of the point to move. */
1594 /* distance :: The distance to apply. */
1597 /* zone :: The affected glyph zone. */
1600 Direct_Move_Orig( EXEC_OP_ TT_GlyphZone zone
,
1602 FT_F26Dot6 distance
)
1607 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1608 FT_ASSERT( !CUR
.face
->unpatented_hinting
);
1611 v
= CUR
.GS
.freeVector
.x
;
1614 zone
->org
[point
].x
+= TT_MULDIV( distance
,
1618 v
= CUR
.GS
.freeVector
.y
;
1621 zone
->org
[point
].y
+= TT_MULDIV( distance
,
1627 /*************************************************************************/
1629 /* Special versions of Direct_Move() */
1631 /* The following versions are used whenever both vectors are both */
1632 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1634 /*************************************************************************/
1638 Direct_Move_X( EXEC_OP_ TT_GlyphZone zone
,
1640 FT_F26Dot6 distance
)
1644 zone
->cur
[point
].x
+= distance
;
1645 zone
->tags
[point
] |= FT_CURVE_TAG_TOUCH_X
;
1650 Direct_Move_Y( EXEC_OP_ TT_GlyphZone zone
,
1652 FT_F26Dot6 distance
)
1656 zone
->cur
[point
].y
+= distance
;
1657 zone
->tags
[point
] |= FT_CURVE_TAG_TOUCH_Y
;
1661 /*************************************************************************/
1663 /* Special versions of Direct_Move_Orig() */
1665 /* The following versions are used whenever both vectors are both */
1666 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1668 /*************************************************************************/
1672 Direct_Move_Orig_X( EXEC_OP_ TT_GlyphZone zone
,
1674 FT_F26Dot6 distance
)
1678 zone
->org
[point
].x
+= distance
;
1683 Direct_Move_Orig_Y( EXEC_OP_ TT_GlyphZone zone
,
1685 FT_F26Dot6 distance
)
1689 zone
->org
[point
].y
+= distance
;
1693 /*************************************************************************/
1699 /* Does not round, but adds engine compensation. */
1702 /* distance :: The distance (not) to round. */
1704 /* compensation :: The engine compensation. */
1707 /* The compensated distance. */
1710 /* The TrueType specification says very few about the relationship */
1711 /* between rounding and engine compensation. However, it seems from */
1712 /* the description of super round that we should add the compensation */
1713 /* before rounding. */
1716 Round_None( EXEC_OP_ FT_F26Dot6 distance
,
1717 FT_F26Dot6 compensation
)
1724 if ( distance
>= 0 )
1726 val
= distance
+ compensation
;
1727 if ( distance
&& val
< 0 )
1731 val
= distance
- compensation
;
1739 /*************************************************************************/
1745 /* Rounds value to grid after adding engine compensation. */
1748 /* distance :: The distance to round. */
1750 /* compensation :: The engine compensation. */
1753 /* Rounded distance. */
1756 Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1757 FT_F26Dot6 compensation
)
1764 if ( distance
>= 0 )
1766 val
= distance
+ compensation
+ 32;
1767 if ( distance
&& val
> 0 )
1774 val
= -FT_PIX_ROUND( compensation
- distance
);
1783 /*************************************************************************/
1786 /* Round_To_Half_Grid */
1789 /* Rounds value to half grid after adding engine compensation. */
1792 /* distance :: The distance to round. */
1794 /* compensation :: The engine compensation. */
1797 /* Rounded distance. */
1800 Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1801 FT_F26Dot6 compensation
)
1808 if ( distance
>= 0 )
1810 val
= FT_PIX_FLOOR( distance
+ compensation
) + 32;
1811 if ( distance
&& val
< 0 )
1816 val
= -( FT_PIX_FLOOR( compensation
- distance
) + 32 );
1825 /*************************************************************************/
1828 /* Round_Down_To_Grid */
1831 /* Rounds value down to grid after adding engine compensation. */
1834 /* distance :: The distance to round. */
1836 /* compensation :: The engine compensation. */
1839 /* Rounded distance. */
1842 Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1843 FT_F26Dot6 compensation
)
1850 if ( distance
>= 0 )
1852 val
= distance
+ compensation
;
1853 if ( distance
&& val
> 0 )
1860 val
= -( ( compensation
- distance
) & -64 );
1869 /*************************************************************************/
1872 /* Round_Up_To_Grid */
1875 /* Rounds value up to grid after adding engine compensation. */
1878 /* distance :: The distance to round. */
1880 /* compensation :: The engine compensation. */
1883 /* Rounded distance. */
1886 Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1887 FT_F26Dot6 compensation
)
1894 if ( distance
>= 0 )
1896 val
= distance
+ compensation
+ 63;
1897 if ( distance
&& val
> 0 )
1904 val
= - FT_PIX_CEIL( compensation
- distance
);
1913 /*************************************************************************/
1916 /* Round_To_Double_Grid */
1919 /* Rounds value to double grid after adding engine compensation. */
1922 /* distance :: The distance to round. */
1924 /* compensation :: The engine compensation. */
1927 /* Rounded distance. */
1930 Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1931 FT_F26Dot6 compensation
)
1938 if ( distance
>= 0 )
1940 val
= distance
+ compensation
+ 16;
1941 if ( distance
&& val
> 0 )
1948 val
= -FT_PAD_ROUND( compensation
- distance
, 32 );
1957 /*************************************************************************/
1963 /* Super-rounds value to grid after adding engine compensation. */
1966 /* distance :: The distance to round. */
1968 /* compensation :: The engine compensation. */
1971 /* Rounded distance. */
1974 /* The TrueType specification says very few about the relationship */
1975 /* between rounding and engine compensation. However, it seems from */
1976 /* the description of super round that we should add the compensation */
1977 /* before rounding. */
1980 Round_Super( EXEC_OP_ FT_F26Dot6 distance
,
1981 FT_F26Dot6 compensation
)
1986 if ( distance
>= 0 )
1988 val
= ( distance
- CUR
.phase
+ CUR
.threshold
+ compensation
) &
1990 if ( distance
&& val
< 0 )
1996 val
= -( ( CUR
.threshold
- CUR
.phase
- distance
+ compensation
) &
2007 /*************************************************************************/
2010 /* Round_Super_45 */
2013 /* Super-rounds value to grid after adding engine compensation. */
2016 /* distance :: The distance to round. */
2018 /* compensation :: The engine compensation. */
2021 /* Rounded distance. */
2024 /* There is a separate function for Round_Super_45() as we may need */
2025 /* greater precision. */
2028 Round_Super_45( EXEC_OP_ FT_F26Dot6 distance
,
2029 FT_F26Dot6 compensation
)
2034 if ( distance
>= 0 )
2036 val
= ( ( distance
- CUR
.phase
+ CUR
.threshold
+ compensation
) /
2037 CUR
.period
) * CUR
.period
;
2038 if ( distance
&& val
< 0 )
2044 val
= -( ( ( CUR
.threshold
- CUR
.phase
- distance
+ compensation
) /
2045 CUR
.period
) * CUR
.period
);
2055 /*************************************************************************/
2061 /* Sets the rounding mode. */
2064 /* round_mode :: The rounding mode to be used. */
2067 Compute_Round( EXEC_OP_ FT_Byte round_mode
)
2069 switch ( round_mode
)
2072 CUR
.func_round
= (TT_Round_Func
)Round_None
;
2075 case TT_Round_To_Grid
:
2076 CUR
.func_round
= (TT_Round_Func
)Round_To_Grid
;
2079 case TT_Round_Up_To_Grid
:
2080 CUR
.func_round
= (TT_Round_Func
)Round_Up_To_Grid
;
2083 case TT_Round_Down_To_Grid
:
2084 CUR
.func_round
= (TT_Round_Func
)Round_Down_To_Grid
;
2087 case TT_Round_To_Half_Grid
:
2088 CUR
.func_round
= (TT_Round_Func
)Round_To_Half_Grid
;
2091 case TT_Round_To_Double_Grid
:
2092 CUR
.func_round
= (TT_Round_Func
)Round_To_Double_Grid
;
2095 case TT_Round_Super
:
2096 CUR
.func_round
= (TT_Round_Func
)Round_Super
;
2099 case TT_Round_Super_45
:
2100 CUR
.func_round
= (TT_Round_Func
)Round_Super_45
;
2106 /*************************************************************************/
2112 /* Sets Super Round parameters. */
2115 /* GridPeriod :: Grid period */
2116 /* selector :: SROUND opcode */
2119 SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod
,
2122 switch ( (FT_Int
)( selector
& 0xC0 ) )
2125 CUR
.period
= GridPeriod
/ 2;
2129 CUR
.period
= GridPeriod
;
2133 CUR
.period
= GridPeriod
* 2;
2136 /* This opcode is reserved, but... */
2139 CUR
.period
= GridPeriod
;
2143 switch ( (FT_Int
)( selector
& 0x30 ) )
2150 CUR
.phase
= CUR
.period
/ 4;
2154 CUR
.phase
= CUR
.period
/ 2;
2158 CUR
.phase
= CUR
.period
* 3 / 4;
2162 if ( ( selector
& 0x0F ) == 0 )
2163 CUR
.threshold
= CUR
.period
- 1;
2165 CUR
.threshold
= ( (FT_Int
)( selector
& 0x0F ) - 4 ) * CUR
.period
/ 8;
2169 CUR
.threshold
/= 256;
2173 /*************************************************************************/
2179 /* Computes the projection of vector given by (v2-v1) along the */
2180 /* current projection vector. */
2183 /* v1 :: First input vector. */
2184 /* v2 :: Second input vector. */
2187 /* The distance in F26dot6 format. */
2190 Project( EXEC_OP_ FT_Pos dx
,
2193 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2194 FT_ASSERT( !CUR
.face
->unpatented_hinting
);
2197 return TT_DotFix14( (FT_UInt32
)dx
, (FT_UInt32
)dy
,
2198 CUR
.GS
.projVector
.x
,
2199 CUR
.GS
.projVector
.y
);
2203 /*************************************************************************/
2209 /* Computes the projection of the vector given by (v2-v1) along the */
2210 /* current dual vector. */
2213 /* v1 :: First input vector. */
2214 /* v2 :: Second input vector. */
2217 /* The distance in F26dot6 format. */
2220 Dual_Project( EXEC_OP_ FT_Pos dx
,
2223 return TT_DotFix14( (FT_UInt32
)dx
, (FT_UInt32
)dy
,
2224 CUR
.GS
.dualVector
.x
,
2225 CUR
.GS
.dualVector
.y
);
2229 /*************************************************************************/
2235 /* Computes the projection of the vector given by (v2-v1) along the */
2236 /* horizontal axis. */
2239 /* v1 :: First input vector. */
2240 /* v2 :: Second input vector. */
2243 /* The distance in F26dot6 format. */
2246 Project_x( EXEC_OP_ FT_Pos dx
,
2256 /*************************************************************************/
2262 /* Computes the projection of the vector given by (v2-v1) along the */
2263 /* vertical axis. */
2266 /* v1 :: First input vector. */
2267 /* v2 :: Second input vector. */
2270 /* The distance in F26dot6 format. */
2273 Project_y( EXEC_OP_ FT_Pos dx
,
2283 /*************************************************************************/
2289 /* Computes the projection and movement function pointers according */
2290 /* to the current graphics state. */
2293 Compute_Funcs( EXEC_OP
)
2295 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2296 if ( CUR
.face
->unpatented_hinting
)
2298 /* If both vectors point rightwards along the x axis, set */
2299 /* `both-x-axis' true, otherwise set it false. The x values only */
2300 /* need be tested because the vector has been normalised to a unit */
2301 /* vector of length 0x4000 = unity. */
2302 CUR
.GS
.both_x_axis
= (FT_Bool
)( CUR
.GS
.projVector
.x
== 0x4000 &&
2303 CUR
.GS
.freeVector
.x
== 0x4000 );
2305 /* Throw away projection and freedom vector information */
2306 /* because the patents don't allow them to be stored. */
2307 /* The relevant US Patents are 5155805 and 5325479. */
2308 CUR
.GS
.projVector
.x
= 0;
2309 CUR
.GS
.projVector
.y
= 0;
2310 CUR
.GS
.freeVector
.x
= 0;
2311 CUR
.GS
.freeVector
.y
= 0;
2313 if ( CUR
.GS
.both_x_axis
)
2315 CUR
.func_project
= Project_x
;
2316 CUR
.func_move
= Direct_Move_X
;
2317 CUR
.func_move_orig
= Direct_Move_Orig_X
;
2321 CUR
.func_project
= Project_y
;
2322 CUR
.func_move
= Direct_Move_Y
;
2323 CUR
.func_move_orig
= Direct_Move_Orig_Y
;
2326 if ( CUR
.GS
.dualVector
.x
== 0x4000 )
2327 CUR
.func_dualproj
= Project_x
;
2330 if ( CUR
.GS
.dualVector
.y
== 0x4000 )
2331 CUR
.func_dualproj
= Project_y
;
2333 CUR
.func_dualproj
= Dual_Project
;
2336 /* Force recalculation of cached aspect ratio */
2337 CUR
.tt_metrics
.ratio
= 0;
2341 #endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING */
2343 if ( CUR
.GS
.freeVector
.x
== 0x4000 )
2344 CUR
.F_dot_P
= CUR
.GS
.projVector
.x
* 0x10000L
;
2347 if ( CUR
.GS
.freeVector
.y
== 0x4000 )
2348 CUR
.F_dot_P
= CUR
.GS
.projVector
.y
* 0x10000L
;
2350 CUR
.F_dot_P
= (FT_Long
)CUR
.GS
.projVector
.x
* CUR
.GS
.freeVector
.x
* 4 +
2351 (FT_Long
)CUR
.GS
.projVector
.y
* CUR
.GS
.freeVector
.y
* 4;
2354 if ( CUR
.GS
.projVector
.x
== 0x4000 )
2355 CUR
.func_project
= (TT_Project_Func
)Project_x
;
2358 if ( CUR
.GS
.projVector
.y
== 0x4000 )
2359 CUR
.func_project
= (TT_Project_Func
)Project_y
;
2361 CUR
.func_project
= (TT_Project_Func
)Project
;
2364 if ( CUR
.GS
.dualVector
.x
== 0x4000 )
2365 CUR
.func_dualproj
= (TT_Project_Func
)Project_x
;
2368 if ( CUR
.GS
.dualVector
.y
== 0x4000 )
2369 CUR
.func_dualproj
= (TT_Project_Func
)Project_y
;
2371 CUR
.func_dualproj
= (TT_Project_Func
)Dual_Project
;
2374 CUR
.func_move
= (TT_Move_Func
)Direct_Move
;
2375 CUR
.func_move_orig
= (TT_Move_Func
)Direct_Move_Orig
;
2377 if ( CUR
.F_dot_P
== 0x40000000L
)
2379 if ( CUR
.GS
.freeVector
.x
== 0x4000 )
2381 CUR
.func_move
= (TT_Move_Func
)Direct_Move_X
;
2382 CUR
.func_move_orig
= (TT_Move_Func
)Direct_Move_Orig_X
;
2386 if ( CUR
.GS
.freeVector
.y
== 0x4000 )
2388 CUR
.func_move
= (TT_Move_Func
)Direct_Move_Y
;
2389 CUR
.func_move_orig
= (TT_Move_Func
)Direct_Move_Orig_Y
;
2394 /* at small sizes, F_dot_P can become too small, resulting */
2395 /* in overflows and `spikes' in a number of glyphs like `w'. */
2397 if ( FT_ABS( CUR
.F_dot_P
) < 0x4000000L
)
2398 CUR
.F_dot_P
= 0x40000000L
;
2400 /* Disable cached aspect ratio */
2401 CUR
.tt_metrics
.ratio
= 0;
2405 /*************************************************************************/
2411 /* Norms a vector. */
2414 /* Vx :: The horizontal input vector coordinate. */
2415 /* Vy :: The vertical input vector coordinate. */
2418 /* R :: The normed unit vector. */
2421 /* Returns FAILURE if a vector parameter is zero. */
2424 /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
2425 /* R is undefined. */
2430 Normalize( EXEC_OP_ FT_F26Dot6 Vx
,
2440 if ( FT_ABS( Vx
) < 0x10000L
&& FT_ABS( Vy
) < 0x10000L
)
2445 W
= TT_VecLen( Vx
, Vy
);
2449 /* XXX: UNDOCUMENTED! It seems that it is possible to try */
2450 /* to normalize the vector (0,0). Return immediately. */
2454 R
->x
= (FT_F2Dot14
)FT_MulDiv( Vx
, 0x4000L
, W
);
2455 R
->y
= (FT_F2Dot14
)FT_MulDiv( Vy
, 0x4000L
, W
);
2460 W
= TT_VecLen( Vx
, Vy
);
2462 Vx
= FT_MulDiv( Vx
, 0x4000L
, W
);
2463 Vy
= FT_MulDiv( Vy
, 0x4000L
, W
);
2465 W
= Vx
* Vx
+ Vy
* Vy
;
2467 /* Now, we want that Sqrt( W ) = 0x4000 */
2468 /* Or 0x10000000 <= W < 0x10004000 */
2486 while ( W
< 0x10000000L
)
2488 /* We need to increase W by a minimal amount */
2494 W
= Vx
* Vx
+ Vy
* Vy
;
2497 while ( W
>= 0x10004000L
)
2499 /* We need to decrease W by a minimal amount */
2505 W
= Vx
* Vx
+ Vy
* Vy
;
2508 /* Note that in various cases, we can only */
2509 /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
2517 R
->x
= (FT_F2Dot14
)Vx
; /* Type conversion */
2518 R
->y
= (FT_F2Dot14
)Vy
; /* Type conversion */
2524 /*************************************************************************/
2526 /* Here we start with the implementation of the various opcodes. */
2528 /*************************************************************************/
2532 Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1
,
2535 FT_UnitVector
* Vec
)
2542 if ( BOUNDS( aIdx1
, CUR
.zp2
.n_points
) ||
2543 BOUNDS( aIdx2
, CUR
.zp1
.n_points
) )
2545 if ( CUR
.pedantic_hinting
)
2546 CUR
.error
= TT_Err_Invalid_Reference
;
2550 p1
= CUR
.zp1
.cur
+ aIdx2
;
2551 p2
= CUR
.zp2
.cur
+ aIdx1
;
2556 if ( ( aOpc
& 1 ) != 0 )
2558 C
= B
; /* counter clockwise rotation */
2563 NORMalize( A
, B
, Vec
);
2569 /* When not using the big switch statements, the interpreter uses a */
2570 /* call table defined later below in this source. Each opcode must */
2571 /* thus have a corresponding function, even trivial ones. */
2573 /* They are all defined there. */
2580 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2581 B = A ^ (FT_Short)0x4000; \
2583 CUR.GS.freeVector.x = A; \
2584 CUR.GS.projVector.x = A; \
2585 CUR.GS.dualVector.x = A; \
2587 CUR.GS.freeVector.y = B; \
2588 CUR.GS.projVector.y = B; \
2589 CUR.GS.dualVector.y = B; \
2600 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2601 B = A ^ (FT_Short)0x4000; \
2603 CUR.GS.projVector.x = A; \
2604 CUR.GS.dualVector.x = A; \
2606 CUR.GS.projVector.y = B; \
2607 CUR.GS.dualVector.y = B; \
2609 GUESS_VECTOR( freeVector ); \
2620 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2621 B = A ^ (FT_Short)0x4000; \
2623 CUR.GS.freeVector.x = A; \
2624 CUR.GS.freeVector.y = B; \
2626 GUESS_VECTOR( projVector ); \
2633 if ( INS_SxVTL( (FT_UShort)args[1], \
2634 (FT_UShort)args[0], \
2636 &CUR.GS.projVector ) == SUCCESS ) \
2638 CUR.GS.dualVector = CUR.GS.projVector; \
2639 GUESS_VECTOR( freeVector ); \
2645 if ( INS_SxVTL( (FT_UShort)args[1], \
2646 (FT_UShort)args[0], \
2648 &CUR.GS.freeVector ) == SUCCESS ) \
2650 GUESS_VECTOR( projVector ); \
2656 GUESS_VECTOR( projVector ); \
2657 CUR.GS.freeVector = CUR.GS.projVector; \
2667 /* Only use low 16bits, then sign extend */ \
2668 S = (FT_Short)args[1]; \
2670 S = (FT_Short)args[0]; \
2673 NORMalize( X, Y, &CUR.GS.projVector ); \
2675 CUR.GS.dualVector = CUR.GS.projVector; \
2676 GUESS_VECTOR( freeVector ); \
2687 /* Only use low 16bits, then sign extend */ \
2688 S = (FT_Short)args[1]; \
2690 S = (FT_Short)args[0]; \
2693 NORMalize( X, Y, &CUR.GS.freeVector ); \
2694 GUESS_VECTOR( projVector ); \
2699 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2701 if ( CUR.face->unpatented_hinting ) \
2703 args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
2704 args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
2708 args[0] = CUR.GS.projVector.x; \
2709 args[1] = CUR.GS.projVector.y; \
2713 args[0] = CUR.GS.projVector.x; \
2714 args[1] = CUR.GS.projVector.y;
2718 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2720 if ( CUR.face->unpatented_hinting ) \
2722 args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
2723 args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
2727 args[0] = CUR.GS.freeVector.x; \
2728 args[1] = CUR.GS.freeVector.y; \
2732 args[0] = CUR.GS.freeVector.x; \
2733 args[1] = CUR.GS.freeVector.y;
2738 CUR.GS.rp0 = (FT_UShort)args[0];
2742 CUR.GS.rp1 = (FT_UShort)args[0];
2746 CUR.GS.rp2 = (FT_UShort)args[0];
2750 CUR.GS.round_state = TT_Round_To_Half_Grid; \
2751 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2755 CUR.GS.round_state = TT_Round_To_Grid; \
2756 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2760 CUR.GS.round_state = TT_Round_To_Double_Grid; \
2761 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2765 CUR.GS.round_state = TT_Round_Up_To_Grid; \
2766 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2770 CUR.GS.round_state = TT_Round_Down_To_Grid; \
2771 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2775 CUR.GS.round_state = TT_Round_Off; \
2776 CUR.func_round = (TT_Round_Func)Round_None;
2780 SET_SuperRound( 0x4000, args[0] ); \
2781 CUR.GS.round_state = TT_Round_Super; \
2782 CUR.func_round = (TT_Round_Func)Round_Super;
2785 #define DO_S45ROUND \
2786 SET_SuperRound( 0x2D41, args[0] ); \
2787 CUR.GS.round_state = TT_Round_Super_45; \
2788 CUR.func_round = (TT_Round_Func)Round_Super_45;
2792 if ( args[0] < 0 ) \
2793 CUR.error = TT_Err_Bad_Argument; \
2795 CUR.GS.loop = args[0];
2799 CUR.GS.minimum_distance = args[0];
2803 CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
2807 CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
2810 /* XXX: UNDOCUMENTED! or bug in the Windows engine? */
2812 /* It seems that the value that is read here is */
2813 /* expressed in 16.16 format rather than in font */
2817 CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
2821 CUR.GS.auto_flip = TRUE;
2824 #define DO_FLIPOFF \
2825 CUR.GS.auto_flip = FALSE;
2829 CUR.GS.delta_base = (FT_Short)args[0];
2833 CUR.GS.delta_shift = (FT_Short)args[0];
2836 #define DO_MD /* nothing */
2840 args[0] = CURRENT_Ppem();
2843 /* Note: The pointSize should be irrelevant in a given font program; */
2844 /* we thus decide to return only the ppem. */
2848 args[0] = CUR.metrics.pointSize;
2853 args[0] = CURRENT_Ppem();
2872 args[0] = args[1]; \
2888 if ( L <= 0 || L > CUR.args ) \
2889 CUR.error = TT_Err_Invalid_Reference; \
2891 args[0] = CUR.stack[CUR.args - L]; \
2896 if ( args[1] != 0 ) \
2898 CUR.IP += args[0]; \
2899 CUR.step_ins = FALSE; \
2904 CUR.IP += args[0]; \
2905 CUR.step_ins = FALSE;
2909 if ( args[1] == 0 ) \
2911 CUR.IP += args[0]; \
2912 CUR.step_ins = FALSE; \
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] = ( args[0] != args[1] );
2941 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
2945 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
2949 args[0] = ( args[0] && args[1] );
2953 args[0] = ( args[0] || args[1] );
2969 if ( args[1] == 0 ) \
2970 CUR.error = TT_Err_Divide_By_Zero; \
2972 args[0] = TT_MULDIV_NO_ROUND( args[0], 64L, args[1] );
2976 args[0] = TT_MULDIV( args[0], args[1], 64L );
2980 args[0] = FT_ABS( args[0] );
2988 args[0] = FT_PIX_FLOOR( args[0] );
2991 #define DO_CEILING \
2992 args[0] = FT_PIX_CEIL( args[0] );
2997 FT_ULong I = (FT_ULong)args[0]; \
3000 if ( BOUNDS( I, CUR.storeSize ) ) \
3002 if ( CUR.pedantic_hinting ) \
3004 ARRAY_BOUND_ERROR; \
3010 args[0] = CUR.storage[I]; \
3016 FT_ULong I = (FT_ULong)args[0]; \
3019 if ( BOUNDS( I, CUR.storeSize ) ) \
3021 if ( CUR.pedantic_hinting ) \
3023 ARRAY_BOUND_ERROR; \
3027 CUR.storage[I] = args[1]; \
3033 FT_ULong I = (FT_ULong)args[0]; \
3036 if ( BOUNDS( I, CUR.cvtSize ) ) \
3038 if ( CUR.pedantic_hinting ) \
3040 ARRAY_BOUND_ERROR; \
3046 args[0] = CUR_Func_read_cvt( I ); \
3052 FT_ULong I = (FT_ULong)args[0]; \
3055 if ( BOUNDS( I, CUR.cvtSize ) ) \
3057 if ( CUR.pedantic_hinting ) \
3059 ARRAY_BOUND_ERROR; \
3063 CUR_Func_write_cvt( I, args[1] ); \
3069 FT_ULong I = (FT_ULong)args[0]; \
3072 if ( BOUNDS( I, CUR.cvtSize ) ) \
3074 if ( CUR.pedantic_hinting ) \
3076 ARRAY_BOUND_ERROR; \
3080 CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
3085 CUR.error = TT_Err_Debug_OpCode;
3089 args[0] = CUR_Func_round( \
3091 CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
3095 args[0] = ROUND_None( args[0], \
3096 CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
3100 if ( args[1] > args[0] ) \
3105 if ( args[1] < args[0] ) \
3109 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
3112 #undef ARRAY_BOUND_ERROR
3113 #define ARRAY_BOUND_ERROR \
3115 CUR.error = TT_Err_Invalid_Reference; \
3120 /*************************************************************************/
3122 /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
3123 /* Opcode range: 0x00-0x01 */
3127 Ins_SVTCA( INS_ARG
)
3133 /*************************************************************************/
3135 /* SPVTCA[a]: Set PVector to Coordinate Axis */
3136 /* Opcode range: 0x02-0x03 */
3140 Ins_SPVTCA( INS_ARG
)
3146 /*************************************************************************/
3148 /* SFVTCA[a]: Set FVector to Coordinate Axis */
3149 /* Opcode range: 0x04-0x05 */
3153 Ins_SFVTCA( INS_ARG
)
3159 /*************************************************************************/
3161 /* SPVTL[a]: Set PVector To Line */
3162 /* Opcode range: 0x06-0x07 */
3163 /* Stack: uint32 uint32 --> */
3166 Ins_SPVTL( INS_ARG
)
3172 /*************************************************************************/
3174 /* SFVTL[a]: Set FVector To Line */
3175 /* Opcode range: 0x08-0x09 */
3176 /* Stack: uint32 uint32 --> */
3179 Ins_SFVTL( INS_ARG
)
3185 /*************************************************************************/
3187 /* SFVTPV[]: Set FVector To PVector */
3188 /* Opcode range: 0x0E */
3192 Ins_SFVTPV( INS_ARG
)
3198 /*************************************************************************/
3200 /* SPVFS[]: Set PVector From Stack */
3201 /* Opcode range: 0x0A */
3202 /* Stack: f2.14 f2.14 --> */
3205 Ins_SPVFS( INS_ARG
)
3211 /*************************************************************************/
3213 /* SFVFS[]: Set FVector From Stack */
3214 /* Opcode range: 0x0B */
3215 /* Stack: f2.14 f2.14 --> */
3218 Ins_SFVFS( INS_ARG
)
3224 /*************************************************************************/
3226 /* GPV[]: Get Projection Vector */
3227 /* Opcode range: 0x0C */
3228 /* Stack: ef2.14 --> ef2.14 */
3237 /*************************************************************************/
3238 /* GFV[]: Get Freedom Vector */
3239 /* Opcode range: 0x0D */
3240 /* Stack: ef2.14 --> ef2.14 */
3249 /*************************************************************************/
3251 /* SRP0[]: Set Reference Point 0 */
3252 /* Opcode range: 0x10 */
3253 /* Stack: uint32 --> */
3262 /*************************************************************************/
3264 /* SRP1[]: Set Reference Point 1 */
3265 /* Opcode range: 0x11 */
3266 /* Stack: uint32 --> */
3275 /*************************************************************************/
3277 /* SRP2[]: Set Reference Point 2 */
3278 /* Opcode range: 0x12 */
3279 /* Stack: uint32 --> */
3288 /*************************************************************************/
3290 /* RTHG[]: Round To Half Grid */
3291 /* Opcode range: 0x19 */
3301 /*************************************************************************/
3303 /* RTG[]: Round To Grid */
3304 /* Opcode range: 0x18 */
3314 /*************************************************************************/
3315 /* RTDG[]: Round To Double Grid */
3316 /* Opcode range: 0x3D */
3326 /*************************************************************************/
3327 /* RUTG[]: Round Up To Grid */
3328 /* Opcode range: 0x7C */
3338 /*************************************************************************/
3340 /* RDTG[]: Round Down To Grid */
3341 /* Opcode range: 0x7D */
3351 /*************************************************************************/
3353 /* ROFF[]: Round OFF */
3354 /* Opcode range: 0x7A */
3364 /*************************************************************************/
3366 /* SROUND[]: Super ROUND */
3367 /* Opcode range: 0x76 */
3368 /* Stack: Eint8 --> */
3371 Ins_SROUND( INS_ARG
)
3377 /*************************************************************************/
3379 /* S45ROUND[]: Super ROUND 45 degrees */
3380 /* Opcode range: 0x77 */
3381 /* Stack: uint32 --> */
3384 Ins_S45ROUND( INS_ARG
)
3390 /*************************************************************************/
3392 /* SLOOP[]: Set LOOP variable */
3393 /* Opcode range: 0x17 */
3394 /* Stack: int32? --> */
3397 Ins_SLOOP( INS_ARG
)
3403 /*************************************************************************/
3405 /* SMD[]: Set Minimum Distance */
3406 /* Opcode range: 0x1A */
3407 /* Stack: f26.6 --> */
3416 /*************************************************************************/
3418 /* SCVTCI[]: Set Control Value Table Cut In */
3419 /* Opcode range: 0x1D */
3420 /* Stack: f26.6 --> */
3423 Ins_SCVTCI( INS_ARG
)
3429 /*************************************************************************/
3431 /* SSWCI[]: Set Single Width Cut In */
3432 /* Opcode range: 0x1E */
3433 /* Stack: f26.6 --> */
3436 Ins_SSWCI( INS_ARG
)
3442 /*************************************************************************/
3444 /* SSW[]: Set Single Width */
3445 /* Opcode range: 0x1F */
3446 /* Stack: int32? --> */
3455 /*************************************************************************/
3457 /* FLIPON[]: Set auto-FLIP to ON */
3458 /* Opcode range: 0x4D */
3462 Ins_FLIPON( INS_ARG
)
3468 /*************************************************************************/
3470 /* FLIPOFF[]: Set auto-FLIP to OFF */
3471 /* Opcode range: 0x4E */
3475 Ins_FLIPOFF( INS_ARG
)
3481 /*************************************************************************/
3483 /* SANGW[]: Set ANGle Weight */
3484 /* Opcode range: 0x7E */
3485 /* Stack: uint32 --> */
3488 Ins_SANGW( INS_ARG
)
3490 /* instruction not supported anymore */
3494 /*************************************************************************/
3496 /* SDB[]: Set Delta Base */
3497 /* Opcode range: 0x5E */
3498 /* Stack: uint32 --> */
3507 /*************************************************************************/
3509 /* SDS[]: Set Delta Shift */
3510 /* Opcode range: 0x5F */
3511 /* Stack: uint32 --> */
3520 /*************************************************************************/
3522 /* MPPEM[]: Measure Pixel Per EM */
3523 /* Opcode range: 0x4B */
3524 /* Stack: --> Euint16 */
3527 Ins_MPPEM( INS_ARG
)
3533 /*************************************************************************/
3535 /* MPS[]: Measure Point Size */
3536 /* Opcode range: 0x4C */
3537 /* Stack: --> Euint16 */
3546 /*************************************************************************/
3548 /* DUP[]: DUPlicate the top stack's element */
3549 /* Opcode range: 0x20 */
3550 /* Stack: StkElt --> StkElt StkElt */
3559 /*************************************************************************/
3561 /* POP[]: POP the stack's top element */
3562 /* Opcode range: 0x21 */
3563 /* Stack: StkElt --> */
3572 /*************************************************************************/
3574 /* CLEAR[]: CLEAR the entire stack */
3575 /* Opcode range: 0x22 */
3576 /* Stack: StkElt... --> */
3579 Ins_CLEAR( INS_ARG
)
3585 /*************************************************************************/
3587 /* SWAP[]: SWAP the stack's top two elements */
3588 /* Opcode range: 0x23 */
3589 /* Stack: 2 * StkElt --> 2 * StkElt */
3598 /*************************************************************************/
3600 /* DEPTH[]: return the stack DEPTH */
3601 /* Opcode range: 0x24 */
3602 /* Stack: --> uint32 */
3605 Ins_DEPTH( INS_ARG
)
3611 /*************************************************************************/
3613 /* CINDEX[]: Copy INDEXed element */
3614 /* Opcode range: 0x25 */
3615 /* Stack: int32 --> StkElt */
3618 Ins_CINDEX( INS_ARG
)
3624 /*************************************************************************/
3627 /* Opcode range: 0x59 */
3637 /*************************************************************************/
3639 /* JROT[]: Jump Relative On True */
3640 /* Opcode range: 0x78 */
3641 /* Stack: StkElt int32 --> */
3650 /*************************************************************************/
3652 /* JMPR[]: JuMP Relative */
3653 /* Opcode range: 0x1C */
3654 /* Stack: int32 --> */
3663 /*************************************************************************/
3665 /* JROF[]: Jump Relative On False */
3666 /* Opcode range: 0x79 */
3667 /* Stack: StkElt int32 --> */
3676 /*************************************************************************/
3678 /* LT[]: Less Than */
3679 /* Opcode range: 0x50 */
3680 /* Stack: int32? int32? --> bool */
3689 /*************************************************************************/
3691 /* LTEQ[]: Less Than or EQual */
3692 /* Opcode range: 0x51 */
3693 /* Stack: int32? int32? --> bool */
3702 /*************************************************************************/
3704 /* GT[]: Greater Than */
3705 /* Opcode range: 0x52 */
3706 /* Stack: int32? int32? --> bool */
3715 /*************************************************************************/
3717 /* GTEQ[]: Greater Than or EQual */
3718 /* Opcode range: 0x53 */
3719 /* Stack: int32? int32? --> bool */
3728 /*************************************************************************/
3731 /* Opcode range: 0x54 */
3732 /* Stack: StkElt StkElt --> bool */
3741 /*************************************************************************/
3743 /* NEQ[]: Not EQual */
3744 /* Opcode range: 0x55 */
3745 /* Stack: StkElt StkElt --> bool */
3754 /*************************************************************************/
3757 /* Opcode range: 0x56 */
3758 /* Stack: f26.6 --> bool */
3767 /*************************************************************************/
3769 /* EVEN[]: Is EVEN */
3770 /* Opcode range: 0x57 */
3771 /* Stack: f26.6 --> bool */
3780 /*************************************************************************/
3782 /* AND[]: logical AND */
3783 /* Opcode range: 0x5A */
3784 /* Stack: uint32 uint32 --> uint32 */
3793 /*************************************************************************/
3795 /* OR[]: logical OR */
3796 /* Opcode range: 0x5B */
3797 /* Stack: uint32 uint32 --> uint32 */
3806 /*************************************************************************/
3808 /* NOT[]: logical NOT */
3809 /* Opcode range: 0x5C */
3810 /* Stack: StkElt --> uint32 */
3819 /*************************************************************************/
3822 /* Opcode range: 0x60 */
3823 /* Stack: f26.6 f26.6 --> f26.6 */
3832 /*************************************************************************/
3834 /* SUB[]: SUBtract */
3835 /* Opcode range: 0x61 */
3836 /* Stack: f26.6 f26.6 --> f26.6 */
3845 /*************************************************************************/
3848 /* Opcode range: 0x62 */
3849 /* Stack: f26.6 f26.6 --> f26.6 */
3858 /*************************************************************************/
3860 /* MUL[]: MULtiply */
3861 /* Opcode range: 0x63 */
3862 /* Stack: f26.6 f26.6 --> f26.6 */
3871 /*************************************************************************/
3873 /* ABS[]: ABSolute value */
3874 /* Opcode range: 0x64 */
3875 /* Stack: f26.6 --> f26.6 */
3884 /*************************************************************************/
3887 /* Opcode range: 0x65 */
3888 /* Stack: f26.6 --> f26.6 */
3897 /*************************************************************************/
3899 /* FLOOR[]: FLOOR */
3900 /* Opcode range: 0x66 */
3901 /* Stack: f26.6 --> f26.6 */
3904 Ins_FLOOR( INS_ARG
)
3910 /*************************************************************************/
3912 /* CEILING[]: CEILING */
3913 /* Opcode range: 0x67 */
3914 /* Stack: f26.6 --> f26.6 */
3917 Ins_CEILING( INS_ARG
)
3923 /*************************************************************************/
3925 /* RS[]: Read Store */
3926 /* Opcode range: 0x43 */
3927 /* Stack: uint32 --> uint32 */
3936 /*************************************************************************/
3938 /* WS[]: Write Store */
3939 /* Opcode range: 0x42 */
3940 /* Stack: uint32 uint32 --> */
3949 /*************************************************************************/
3951 /* WCVTP[]: Write CVT in Pixel units */
3952 /* Opcode range: 0x44 */
3953 /* Stack: f26.6 uint32 --> */
3956 Ins_WCVTP( INS_ARG
)
3962 /*************************************************************************/
3964 /* WCVTF[]: Write CVT in Funits */
3965 /* Opcode range: 0x70 */
3966 /* Stack: uint32 uint32 --> */
3969 Ins_WCVTF( INS_ARG
)
3975 /*************************************************************************/
3977 /* RCVT[]: Read CVT */
3978 /* Opcode range: 0x45 */
3979 /* Stack: uint32 --> f26.6 */
3988 /*************************************************************************/
3990 /* AA[]: Adjust Angle */
3991 /* Opcode range: 0x7F */
3992 /* Stack: uint32 --> */
3997 /* intentionally no longer supported */
4001 /*************************************************************************/
4003 /* DEBUG[]: DEBUG. Unsupported. */
4004 /* Opcode range: 0x4F */
4005 /* Stack: uint32 --> */
4007 /* Note: The original instruction pops a value from the stack. */
4010 Ins_DEBUG( INS_ARG
)
4016 /*************************************************************************/
4018 /* ROUND[ab]: ROUND value */
4019 /* Opcode range: 0x68-0x6B */
4020 /* Stack: f26.6 --> f26.6 */
4023 Ins_ROUND( INS_ARG
)
4029 /*************************************************************************/
4031 /* NROUND[ab]: No ROUNDing of value */
4032 /* Opcode range: 0x6C-0x6F */
4033 /* Stack: f26.6 --> f26.6 */
4036 Ins_NROUND( INS_ARG
)
4042 /*************************************************************************/
4044 /* MAX[]: MAXimum */
4045 /* Opcode range: 0x68 */
4046 /* Stack: int32? int32? --> int32 */
4055 /*************************************************************************/
4057 /* MIN[]: MINimum */
4058 /* Opcode range: 0x69 */
4059 /* Stack: int32? int32? --> int32 */
4068 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
4071 /*************************************************************************/
4073 /* The following functions are called as is within the switch statement. */
4075 /*************************************************************************/
4078 /*************************************************************************/
4080 /* MINDEX[]: Move INDEXed element */
4081 /* Opcode range: 0x26 */
4082 /* Stack: int32? --> StkElt */
4085 Ins_MINDEX( INS_ARG
)
4092 if ( L
<= 0 || L
> CUR
.args
)
4094 CUR
.error
= TT_Err_Invalid_Reference
;
4098 K
= CUR
.stack
[CUR
.args
- L
];
4100 FT_ARRAY_MOVE( &CUR
.stack
[CUR
.args
- L
],
4101 &CUR
.stack
[CUR
.args
- L
+ 1],
4104 CUR
.stack
[CUR
.args
- 1] = K
;
4108 /*************************************************************************/
4110 /* ROLL[]: ROLL top three elements */
4111 /* Opcode range: 0x8A */
4112 /* Stack: 3 * StkElt --> 3 * StkElt */
4132 /*************************************************************************/
4134 /* MANAGING THE FLOW OF CONTROL */
4136 /* Instructions appear in the specification's order. */
4138 /*************************************************************************/
4144 CUR
.IP
+= CUR
.length
;
4146 if ( CUR
.IP
< CUR
.codeSize
)
4148 CUR
.opcode
= CUR
.code
[CUR
.IP
];
4150 CUR
.length
= opcode_length
[CUR
.opcode
];
4151 if ( CUR
.length
< 0 )
4153 if ( CUR
.IP
+ 1 > CUR
.codeSize
)
4155 CUR
.length
= 2 - CUR
.length
* CUR
.code
[CUR
.IP
+ 1];
4158 if ( CUR
.IP
+ CUR
.length
<= CUR
.codeSize
)
4163 CUR
.error
= TT_Err_Code_Overflow
;
4168 /*************************************************************************/
4171 /* Opcode range: 0x58 */
4172 /* Stack: StkElt --> */
4189 if ( SKIP_Code() == FAILURE
)
4192 switch ( CUR
.opcode
)
4198 case 0x1B: /* ELSE */
4199 Out
= FT_BOOL( nIfs
== 1 );
4202 case 0x59: /* EIF */
4204 Out
= FT_BOOL( nIfs
== 0 );
4207 } while ( Out
== 0 );
4211 /*************************************************************************/
4214 /* Opcode range: 0x1B */
4229 if ( SKIP_Code() == FAILURE
)
4232 switch ( CUR
.opcode
)
4238 case 0x59: /* EIF */
4242 } while ( nIfs
!= 0 );
4246 /*************************************************************************/
4248 /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
4250 /* Instructions appear in the specification's order. */
4252 /*************************************************************************/
4255 /*************************************************************************/
4257 /* FDEF[]: Function DEFinition */
4258 /* Opcode range: 0x2C */
4259 /* Stack: uint32 --> */
4266 TT_DefRecord
* limit
;
4269 /* some font programs are broken enough to redefine functions! */
4270 /* We will then parse the current table. */
4273 limit
= rec
+ CUR
.numFDefs
;
4276 for ( ; rec
< limit
; rec
++ )
4278 if ( rec
->opc
== n
)
4284 /* check that there is enough room for new functions */
4285 if ( CUR
.numFDefs
>= CUR
.maxFDefs
)
4287 CUR
.error
= TT_Err_Too_Many_Function_Defs
;
4293 /* Although FDEF takes unsigned 32-bit integer, */
4294 /* func # must be within unsigned 16-bit integer */
4297 CUR
.error
= TT_Err_Too_Many_Function_Defs
;
4301 rec
->range
= CUR
.curRange
;
4302 rec
->opc
= (FT_UInt16
)n
;
4303 rec
->start
= CUR
.IP
+ 1;
4306 if ( n
> CUR
.maxFunc
)
4307 CUR
.maxFunc
= (FT_UInt16
)n
;
4309 /* Now skip the whole function definition. */
4310 /* We don't allow nested IDEFS & FDEFs. */
4312 while ( SKIP_Code() == SUCCESS
)
4314 switch ( CUR
.opcode
)
4316 case 0x89: /* IDEF */
4317 case 0x2C: /* FDEF */
4318 CUR
.error
= TT_Err_Nested_DEFS
;
4321 case 0x2D: /* ENDF */
4328 /*************************************************************************/
4330 /* ENDF[]: END Function definition */
4331 /* Opcode range: 0x2D */
4342 if ( CUR
.callTop
<= 0 ) /* We encountered an ENDF without a call */
4344 CUR
.error
= TT_Err_ENDF_In_Exec_Stream
;
4350 pRec
= &CUR
.callStack
[CUR
.callTop
];
4354 CUR
.step_ins
= FALSE
;
4356 if ( pRec
->Cur_Count
> 0 )
4359 CUR
.IP
= pRec
->Cur_Restart
;
4362 /* Loop through the current function */
4363 INS_Goto_CodeRange( pRec
->Caller_Range
,
4366 /* Exit the current call frame. */
4368 /* NOTE: If the last instruction of a program is a */
4369 /* CALL or LOOPCALL, the return address is */
4370 /* always out of the code range. This is a */
4371 /* valid address, and it is why we do not test */
4372 /* the result of Ins_Goto_CodeRange() here! */
4376 /*************************************************************************/
4378 /* CALL[]: CALL function */
4379 /* Opcode range: 0x2B */
4380 /* Stack: uint32? --> */
4390 /* first of all, check the index */
4393 if ( BOUNDS( F
, CUR
.maxFunc
+ 1 ) )
4396 /* Except for some old Apple fonts, all functions in a TrueType */
4397 /* font are defined in increasing order, starting from 0. This */
4398 /* means that we normally have */
4400 /* CUR.maxFunc+1 == CUR.numFDefs */
4401 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4403 /* If this isn't true, we need to look up the function table. */
4405 def
= CUR
.FDefs
+ F
;
4406 if ( CUR
.maxFunc
+ 1 != CUR
.numFDefs
|| def
->opc
!= F
)
4408 /* look up the FDefs table */
4409 TT_DefRecord
* limit
;
4413 limit
= def
+ CUR
.numFDefs
;
4415 while ( def
< limit
&& def
->opc
!= F
)
4422 /* check that the function is active */
4426 /* check the call stack */
4427 if ( CUR
.callTop
>= CUR
.callSize
)
4429 CUR
.error
= TT_Err_Stack_Overflow
;
4433 pCrec
= CUR
.callStack
+ CUR
.callTop
;
4435 pCrec
->Caller_Range
= CUR
.curRange
;
4436 pCrec
->Caller_IP
= CUR
.IP
+ 1;
4437 pCrec
->Cur_Count
= 1;
4438 pCrec
->Cur_Restart
= def
->start
;
4442 INS_Goto_CodeRange( def
->range
,
4445 CUR
.step_ins
= FALSE
;
4449 CUR
.error
= TT_Err_Invalid_Reference
;
4453 /*************************************************************************/
4455 /* LOOPCALL[]: LOOP and CALL function */
4456 /* Opcode range: 0x2A */
4457 /* Stack: uint32? Eint16? --> */
4460 Ins_LOOPCALL( INS_ARG
)
4467 /* first of all, check the index */
4469 if ( BOUNDS( F
, CUR
.maxFunc
+ 1 ) )
4472 /* Except for some old Apple fonts, all functions in a TrueType */
4473 /* font are defined in increasing order, starting from 0. This */
4474 /* means that we normally have */
4476 /* CUR.maxFunc+1 == CUR.numFDefs */
4477 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4479 /* If this isn't true, we need to look up the function table. */
4481 def
= CUR
.FDefs
+ F
;
4482 if ( CUR
.maxFunc
+ 1 != CUR
.numFDefs
|| def
->opc
!= F
)
4484 /* look up the FDefs table */
4485 TT_DefRecord
* limit
;
4489 limit
= def
+ CUR
.numFDefs
;
4491 while ( def
< limit
&& def
->opc
!= F
)
4498 /* check that the function is active */
4503 if ( CUR
.callTop
>= CUR
.callSize
)
4505 CUR
.error
= TT_Err_Stack_Overflow
;
4511 pCrec
= CUR
.callStack
+ CUR
.callTop
;
4513 pCrec
->Caller_Range
= CUR
.curRange
;
4514 pCrec
->Caller_IP
= CUR
.IP
+ 1;
4515 pCrec
->Cur_Count
= (FT_Int
)args
[0];
4516 pCrec
->Cur_Restart
= def
->start
;
4520 INS_Goto_CodeRange( def
->range
, def
->start
);
4522 CUR
.step_ins
= FALSE
;
4527 CUR
.error
= TT_Err_Invalid_Reference
;
4531 /*************************************************************************/
4533 /* IDEF[]: Instruction DEFinition */
4534 /* Opcode range: 0x89 */
4535 /* Stack: Eint8 --> */
4541 TT_DefRecord
* limit
;
4544 /* First of all, look for the same function in our table */
4547 limit
= def
+ CUR
.numIDefs
;
4549 for ( ; def
< limit
; def
++ )
4550 if ( def
->opc
== (FT_ULong
)args
[0] )
4555 /* check that there is enough room for a new instruction */
4556 if ( CUR
.numIDefs
>= CUR
.maxIDefs
)
4558 CUR
.error
= TT_Err_Too_Many_Instruction_Defs
;
4564 /* opcode must be unsigned 8-bit integer */
4565 if ( 0 > args
[0] || args
[0] > 0x00FF )
4567 CUR
.error
= TT_Err_Too_Many_Instruction_Defs
;
4571 def
->opc
= (FT_Byte
)args
[0];
4572 def
->start
= CUR
.IP
+1;
4573 def
->range
= CUR
.curRange
;
4576 if ( (FT_ULong
)args
[0] > CUR
.maxIns
)
4577 CUR
.maxIns
= (FT_Byte
)args
[0];
4579 /* Now skip the whole function definition. */
4580 /* We don't allow nested IDEFs & FDEFs. */
4582 while ( SKIP_Code() == SUCCESS
)
4584 switch ( CUR
.opcode
)
4586 case 0x89: /* IDEF */
4587 case 0x2C: /* FDEF */
4588 CUR
.error
= TT_Err_Nested_DEFS
;
4590 case 0x2D: /* ENDF */
4597 /*************************************************************************/
4599 /* PUSHING DATA ONTO THE INTERPRETER STACK */
4601 /* Instructions appear in the specification's order. */
4603 /*************************************************************************/
4606 /*************************************************************************/
4608 /* NPUSHB[]: PUSH N Bytes */
4609 /* Opcode range: 0x40 */
4610 /* Stack: --> uint32... */
4613 Ins_NPUSHB( INS_ARG
)
4618 L
= (FT_UShort
)CUR
.code
[CUR
.IP
+ 1];
4620 if ( BOUNDS( L
, CUR
.stackSize
+ 1 - CUR
.top
) )
4622 CUR
.error
= TT_Err_Stack_Overflow
;
4626 for ( K
= 1; K
<= L
; K
++ )
4627 args
[K
- 1] = CUR
.code
[CUR
.IP
+ K
+ 1];
4633 /*************************************************************************/
4635 /* NPUSHW[]: PUSH N Words */
4636 /* Opcode range: 0x41 */
4637 /* Stack: --> int32... */
4640 Ins_NPUSHW( INS_ARG
)
4645 L
= (FT_UShort
)CUR
.code
[CUR
.IP
+ 1];
4647 if ( BOUNDS( L
, CUR
.stackSize
+ 1 - CUR
.top
) )
4649 CUR
.error
= TT_Err_Stack_Overflow
;
4655 for ( K
= 0; K
< L
; K
++ )
4656 args
[K
] = GET_ShortIns();
4658 CUR
.step_ins
= FALSE
;
4663 /*************************************************************************/
4665 /* PUSHB[abc]: PUSH Bytes */
4666 /* Opcode range: 0xB0-0xB7 */
4667 /* Stack: --> uint32... */
4670 Ins_PUSHB( INS_ARG
)
4675 L
= (FT_UShort
)( CUR
.opcode
- 0xB0 + 1 );
4677 if ( BOUNDS( L
, CUR
.stackSize
+ 1 - CUR
.top
) )
4679 CUR
.error
= TT_Err_Stack_Overflow
;
4683 for ( K
= 1; K
<= L
; K
++ )
4684 args
[K
- 1] = CUR
.code
[CUR
.IP
+ K
];
4688 /*************************************************************************/
4690 /* PUSHW[abc]: PUSH Words */
4691 /* Opcode range: 0xB8-0xBF */
4692 /* Stack: --> int32... */
4695 Ins_PUSHW( INS_ARG
)
4700 L
= (FT_UShort
)( CUR
.opcode
- 0xB8 + 1 );
4702 if ( BOUNDS( L
, CUR
.stackSize
+ 1 - CUR
.top
) )
4704 CUR
.error
= TT_Err_Stack_Overflow
;
4710 for ( K
= 0; K
< L
; K
++ )
4711 args
[K
] = GET_ShortIns();
4713 CUR
.step_ins
= FALSE
;
4717 /*************************************************************************/
4719 /* MANAGING THE GRAPHICS STATE */
4721 /* Instructions appear in the specs' order. */
4723 /*************************************************************************/
4726 /*************************************************************************/
4728 /* GC[a]: Get Coordinate projected onto */
4729 /* Opcode range: 0x46-0x47 */
4730 /* Stack: uint32 --> f26.6 */
4732 /* BULLSHIT: Measures from the original glyph must be taken along the */
4733 /* dual projection vector! */
4742 L
= (FT_ULong
)args
[0];
4744 if ( BOUNDS( L
, CUR
.zp2
.n_points
) )
4746 if ( CUR
.pedantic_hinting
)
4748 CUR
.error
= TT_Err_Invalid_Reference
;
4756 if ( CUR
.opcode
& 1 )
4757 R
= CUR_fast_dualproj( &CUR
.zp2
.org
[L
] );
4759 R
= CUR_fast_project( &CUR
.zp2
.cur
[L
] );
4766 /*************************************************************************/
4768 /* SCFS[]: Set Coordinate From Stack */
4769 /* Opcode range: 0x48 */
4770 /* Stack: f26.6 uint32 --> */
4774 /* OA := OA + ( value - OA.p )/( f.p ) * f */
4783 L
= (FT_UShort
)args
[0];
4785 if ( BOUNDS( L
, CUR
.zp2
.n_points
) )
4787 if ( CUR
.pedantic_hinting
)
4788 CUR
.error
= TT_Err_Invalid_Reference
;
4792 K
= CUR_fast_project( &CUR
.zp2
.cur
[L
] );
4794 CUR_Func_move( &CUR
.zp2
, L
, args
[1] - K
);
4796 /* not part of the specs, but here for safety */
4798 if ( CUR
.GS
.gep2
== 0 )
4799 CUR
.zp2
.org
[L
] = CUR
.zp2
.cur
[L
];
4803 /*************************************************************************/
4805 /* MD[a]: Measure Distance */
4806 /* Opcode range: 0x49-0x4A */
4807 /* Stack: uint32 uint32 --> f26.6 */
4809 /* BULLSHIT: Measure taken in the original glyph must be along the dual */
4810 /* projection vector. */
4812 /* Second BULLSHIT: Flag attributes are inverted! */
4813 /* 0 => measure distance in original outline */
4814 /* 1 => measure distance in grid-fitted outline */
4816 /* Third one: `zp0 - zp1', and not `zp2 - zp1! */
4825 K
= (FT_UShort
)args
[1];
4826 L
= (FT_UShort
)args
[0];
4828 if( BOUNDS( L
, CUR
.zp0
.n_points
) ||
4829 BOUNDS( K
, CUR
.zp1
.n_points
) )
4831 if ( CUR
.pedantic_hinting
)
4833 CUR
.error
= TT_Err_Invalid_Reference
;
4840 if ( CUR
.opcode
& 1 )
4841 D
= CUR_Func_project( CUR
.zp0
.cur
+ L
, CUR
.zp1
.cur
+ K
);
4844 FT_Vector
* vec1
= CUR
.zp0
.orus
+ L
;
4845 FT_Vector
* vec2
= CUR
.zp1
.orus
+ K
;
4848 if ( CUR
.metrics
.x_scale
== CUR
.metrics
.y_scale
)
4850 /* this should be faster */
4851 D
= CUR_Func_dualproj( vec1
, vec2
);
4852 D
= TT_MULFIX( D
, CUR
.metrics
.x_scale
);
4859 vec
.x
= TT_MULFIX( vec1
->x
- vec2
->x
, CUR
.metrics
.x_scale
);
4860 vec
.y
= TT_MULFIX( vec1
->y
- vec2
->y
, CUR
.metrics
.y_scale
);
4862 D
= CUR_fast_dualproj( &vec
);
4871 /*************************************************************************/
4873 /* SDPVTL[a]: Set Dual PVector to Line */
4874 /* Opcode range: 0x86-0x87 */
4875 /* Stack: uint32 uint32 --> */
4878 Ins_SDPVTL( INS_ARG
)
4881 FT_UShort p1
, p2
; /* was FT_Int in pas type ERROR */
4884 p1
= (FT_UShort
)args
[1];
4885 p2
= (FT_UShort
)args
[0];
4887 if ( BOUNDS( p2
, CUR
.zp1
.n_points
) ||
4888 BOUNDS( p1
, CUR
.zp2
.n_points
) )
4890 if ( CUR
.pedantic_hinting
)
4891 CUR
.error
= TT_Err_Invalid_Reference
;
4896 FT_Vector
* v1
= CUR
.zp1
.org
+ p2
;
4897 FT_Vector
* v2
= CUR
.zp2
.org
+ p1
;
4904 if ( ( CUR
.opcode
& 1 ) != 0 )
4906 C
= B
; /* counter clockwise rotation */
4911 NORMalize( A
, B
, &CUR
.GS
.dualVector
);
4914 FT_Vector
* v1
= CUR
.zp1
.cur
+ p2
;
4915 FT_Vector
* v2
= CUR
.zp2
.cur
+ p1
;
4922 if ( ( CUR
.opcode
& 1 ) != 0 )
4924 C
= B
; /* counter clockwise rotation */
4929 NORMalize( A
, B
, &CUR
.GS
.projVector
);
4931 GUESS_VECTOR( freeVector
);
4937 /*************************************************************************/
4939 /* SZP0[]: Set Zone Pointer 0 */
4940 /* Opcode range: 0x13 */
4941 /* Stack: uint32 --> */
4946 switch ( (FT_Int
)args
[0] )
4949 CUR
.zp0
= CUR
.twilight
;
4957 if ( CUR
.pedantic_hinting
)
4958 CUR
.error
= TT_Err_Invalid_Reference
;
4962 CUR
.GS
.gep0
= (FT_UShort
)args
[0];
4966 /*************************************************************************/
4968 /* SZP1[]: Set Zone Pointer 1 */
4969 /* Opcode range: 0x14 */
4970 /* Stack: uint32 --> */
4975 switch ( (FT_Int
)args
[0] )
4978 CUR
.zp1
= CUR
.twilight
;
4986 if ( CUR
.pedantic_hinting
)
4987 CUR
.error
= TT_Err_Invalid_Reference
;
4991 CUR
.GS
.gep1
= (FT_UShort
)args
[0];
4995 /*************************************************************************/
4997 /* SZP2[]: Set Zone Pointer 2 */
4998 /* Opcode range: 0x15 */
4999 /* Stack: uint32 --> */
5004 switch ( (FT_Int
)args
[0] )
5007 CUR
.zp2
= CUR
.twilight
;
5015 if ( CUR
.pedantic_hinting
)
5016 CUR
.error
= TT_Err_Invalid_Reference
;
5020 CUR
.GS
.gep2
= (FT_UShort
)args
[0];
5024 /*************************************************************************/
5026 /* SZPS[]: Set Zone PointerS */
5027 /* Opcode range: 0x16 */
5028 /* Stack: uint32 --> */
5033 switch ( (FT_Int
)args
[0] )
5036 CUR
.zp0
= CUR
.twilight
;
5044 if ( CUR
.pedantic_hinting
)
5045 CUR
.error
= TT_Err_Invalid_Reference
;
5052 CUR
.GS
.gep0
= (FT_UShort
)args
[0];
5053 CUR
.GS
.gep1
= (FT_UShort
)args
[0];
5054 CUR
.GS
.gep2
= (FT_UShort
)args
[0];
5058 /*************************************************************************/
5060 /* INSTCTRL[]: INSTruction ConTRoL */
5061 /* Opcode range: 0x8e */
5062 /* Stack: int32 int32 --> */
5065 Ins_INSTCTRL( INS_ARG
)
5073 if ( K
< 1 || K
> 2 )
5075 if ( CUR
.pedantic_hinting
)
5076 CUR
.error
= TT_Err_Invalid_Reference
;
5083 CUR
.GS
.instruct_control
= FT_BOOL(
5084 ( (FT_Byte
)CUR
.GS
.instruct_control
& ~(FT_Byte
)K
) | (FT_Byte
)L
);
5088 /*************************************************************************/
5090 /* SCANCTRL[]: SCAN ConTRoL */
5091 /* Opcode range: 0x85 */
5092 /* Stack: uint32? --> */
5095 Ins_SCANCTRL( INS_ARG
)
5101 A
= (FT_Int
)( args
[0] & 0xFF );
5105 CUR
.GS
.scan_control
= TRUE
;
5110 CUR
.GS
.scan_control
= FALSE
;
5114 if ( ( args
[0] & 0x100 ) != 0 && CUR
.tt_metrics
.ppem
<= A
)
5115 CUR
.GS
.scan_control
= TRUE
;
5117 if ( ( args
[0] & 0x200 ) != 0 && CUR
.tt_metrics
.rotated
)
5118 CUR
.GS
.scan_control
= TRUE
;
5120 if ( ( args
[0] & 0x400 ) != 0 && CUR
.tt_metrics
.stretched
)
5121 CUR
.GS
.scan_control
= TRUE
;
5123 if ( ( args
[0] & 0x800 ) != 0 && CUR
.tt_metrics
.ppem
> A
)
5124 CUR
.GS
.scan_control
= FALSE
;
5126 if ( ( args
[0] & 0x1000 ) != 0 && CUR
.tt_metrics
.rotated
)
5127 CUR
.GS
.scan_control
= FALSE
;
5129 if ( ( args
[0] & 0x2000 ) != 0 && CUR
.tt_metrics
.stretched
)
5130 CUR
.GS
.scan_control
= FALSE
;
5134 /*************************************************************************/
5136 /* SCANTYPE[]: SCAN TYPE */
5137 /* Opcode range: 0x8D */
5138 /* Stack: uint32? --> */
5141 Ins_SCANTYPE( INS_ARG
)
5144 CUR
.GS
.scan_type
= (FT_Int
)args
[0];
5148 /*************************************************************************/
5150 /* MANAGING OUTLINES */
5152 /* Instructions appear in the specification's order. */
5154 /*************************************************************************/
5157 /*************************************************************************/
5159 /* FLIPPT[]: FLIP PoinT */
5160 /* Opcode range: 0x80 */
5161 /* Stack: uint32... --> */
5164 Ins_FLIPPT( INS_ARG
)
5171 if ( CUR
.top
< CUR
.GS
.loop
)
5173 CUR
.error
= TT_Err_Too_Few_Arguments
;
5177 while ( CUR
.GS
.loop
> 0 )
5181 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5183 if ( BOUNDS( point
, CUR
.pts
.n_points
) )
5185 if ( CUR
.pedantic_hinting
)
5187 CUR
.error
= TT_Err_Invalid_Reference
;
5192 CUR
.pts
.tags
[point
] ^= FT_CURVE_TAG_ON
;
5198 CUR
.new_top
= CUR
.args
;
5202 /*************************************************************************/
5204 /* FLIPRGON[]: FLIP RanGe ON */
5205 /* Opcode range: 0x81 */
5206 /* Stack: uint32 uint32 --> */
5209 Ins_FLIPRGON( INS_ARG
)
5214 K
= (FT_UShort
)args
[1];
5215 L
= (FT_UShort
)args
[0];
5217 if ( BOUNDS( K
, CUR
.pts
.n_points
) ||
5218 BOUNDS( L
, CUR
.pts
.n_points
) )
5220 if ( CUR
.pedantic_hinting
)
5221 CUR
.error
= TT_Err_Invalid_Reference
;
5225 for ( I
= L
; I
<= K
; I
++ )
5226 CUR
.pts
.tags
[I
] |= FT_CURVE_TAG_ON
;
5230 /*************************************************************************/
5232 /* FLIPRGOFF: FLIP RanGe OFF */
5233 /* Opcode range: 0x82 */
5234 /* Stack: uint32 uint32 --> */
5237 Ins_FLIPRGOFF( INS_ARG
)
5242 K
= (FT_UShort
)args
[1];
5243 L
= (FT_UShort
)args
[0];
5245 if ( BOUNDS( K
, CUR
.pts
.n_points
) ||
5246 BOUNDS( L
, CUR
.pts
.n_points
) )
5248 if ( CUR
.pedantic_hinting
)
5249 CUR
.error
= TT_Err_Invalid_Reference
;
5253 for ( I
= L
; I
<= K
; I
++ )
5254 CUR
.pts
.tags
[I
] &= ~FT_CURVE_TAG_ON
;
5259 Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6
* x
,
5269 if ( CUR
.opcode
& 1 )
5280 if ( BOUNDS( p
, zp
.n_points
) )
5282 if ( CUR
.pedantic_hinting
)
5283 CUR
.error
= TT_Err_Invalid_Reference
;
5291 d
= CUR_Func_project( zp
.cur
+ p
, zp
.org
+ p
);
5293 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5294 if ( CUR
.face
->unpatented_hinting
)
5296 if ( CUR
.GS
.both_x_axis
)
5311 (FT_Long
)CUR
.GS
.freeVector
.x
* 0x10000L
,
5314 (FT_Long
)CUR
.GS
.freeVector
.y
* 0x10000L
,
5323 Move_Zp2_Point( EXEC_OP_ FT_UShort point
,
5328 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5329 if ( CUR
.face
->unpatented_hinting
)
5331 if ( CUR
.GS
.both_x_axis
)
5333 CUR
.zp2
.cur
[point
].x
+= dx
;
5335 CUR
.zp2
.tags
[point
] |= FT_CURVE_TAG_TOUCH_X
;
5339 CUR
.zp2
.cur
[point
].y
+= dy
;
5341 CUR
.zp2
.tags
[point
] |= FT_CURVE_TAG_TOUCH_Y
;
5347 if ( CUR
.GS
.freeVector
.x
!= 0 )
5349 CUR
.zp2
.cur
[point
].x
+= dx
;
5351 CUR
.zp2
.tags
[point
] |= FT_CURVE_TAG_TOUCH_X
;
5354 if ( CUR
.GS
.freeVector
.y
!= 0 )
5356 CUR
.zp2
.cur
[point
].y
+= dy
;
5358 CUR
.zp2
.tags
[point
] |= FT_CURVE_TAG_TOUCH_Y
;
5363 /*************************************************************************/
5365 /* SHP[a]: SHift Point by the last point */
5366 /* Opcode range: 0x32-0x33 */
5367 /* Stack: uint32... --> */
5382 if ( CUR
.top
< CUR
.GS
.loop
)
5384 CUR
.error
= TT_Err_Invalid_Reference
;
5388 if ( COMPUTE_Point_Displacement( &dx
, &dy
, &zp
, &refp
) )
5391 while ( CUR
.GS
.loop
> 0 )
5394 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5396 if ( BOUNDS( point
, CUR
.zp2
.n_points
) )
5398 if ( CUR
.pedantic_hinting
)
5400 CUR
.error
= TT_Err_Invalid_Reference
;
5405 /* XXX: UNDOCUMENTED! SHP touches the points */
5406 MOVE_Zp2_Point( point
, dx
, dy
, TRUE
);
5412 CUR
.new_top
= CUR
.args
;
5416 /*************************************************************************/
5418 /* SHC[a]: SHift Contour */
5419 /* Opcode range: 0x34-35 */
5420 /* Stack: uint32 --> */
5431 FT_UShort first_point
, last_point
, i
;
5434 contour
= (FT_UShort
)args
[0];
5436 if ( BOUNDS( contour
, CUR
.pts
.n_contours
) )
5438 if ( CUR
.pedantic_hinting
)
5439 CUR
.error
= TT_Err_Invalid_Reference
;
5443 if ( COMPUTE_Point_Displacement( &dx
, &dy
, &zp
, &refp
) )
5449 first_point
= (FT_UShort
)( CUR
.pts
.contours
[contour
- 1] + 1 -
5450 CUR
.pts
.first_point
);
5452 last_point
= (FT_UShort
)( CUR
.pts
.contours
[contour
] -
5453 CUR
.pts
.first_point
);
5455 /* XXX: this is probably wrong... at least it prevents memory */
5456 /* corruption when zp2 is the twilight zone */
5457 if ( BOUNDS( last_point
, CUR
.zp2
.n_points
) )
5459 if ( CUR
.zp2
.n_points
> 0 )
5460 last_point
= (FT_UShort
)(CUR
.zp2
.n_points
- 1);
5465 /* XXX: UNDOCUMENTED! SHC touches the points */
5466 for ( i
= first_point
; i
<= last_point
; i
++ )
5468 if ( zp
.cur
!= CUR
.zp2
.cur
|| refp
!= i
)
5469 MOVE_Zp2_Point( i
, dx
, dy
, TRUE
);
5474 /*************************************************************************/
5476 /* SHZ[a]: SHift Zone */
5477 /* Opcode range: 0x36-37 */
5478 /* Stack: uint32 --> */
5488 FT_UShort last_point
, i
;
5491 if ( BOUNDS( args
[0], 2 ) )
5493 if ( CUR
.pedantic_hinting
)
5494 CUR
.error
= TT_Err_Invalid_Reference
;
5498 if ( COMPUTE_Point_Displacement( &dx
, &dy
, &zp
, &refp
) )
5501 /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */
5502 /* Twilight zone has no contours, so use `n_points'. */
5503 /* Normal zone's `n_points' includes phantoms, so must */
5504 /* use end of last contour. */
5505 if ( CUR
.GS
.gep2
== 0 && CUR
.zp2
.n_points
> 0 )
5506 last_point
= (FT_UShort
)( CUR
.zp2
.n_points
- 1 );
5507 else if ( CUR
.GS
.gep2
== 1 && CUR
.zp2
.n_contours
> 0 )
5508 last_point
= (FT_UShort
)( CUR
.zp2
.contours
[CUR
.zp2
.n_contours
- 1] );
5512 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
5513 for ( i
= 0; i
<= last_point
; i
++ )
5515 if ( zp
.cur
!= CUR
.zp2
.cur
|| refp
!= i
)
5516 MOVE_Zp2_Point( i
, dx
, dy
, FALSE
);
5521 /*************************************************************************/
5523 /* SHPIX[]: SHift points by a PIXel amount */
5524 /* Opcode range: 0x38 */
5525 /* Stack: f26.6 uint32... --> */
5528 Ins_SHPIX( INS_ARG
)
5534 if ( CUR
.top
< CUR
.GS
.loop
+ 1 )
5536 CUR
.error
= TT_Err_Invalid_Reference
;
5540 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5541 if ( CUR
.face
->unpatented_hinting
)
5543 if ( CUR
.GS
.both_x_axis
)
5545 dx
= TT_MulFix14( (FT_UInt32
)args
[0], 0x4000 );
5551 dy
= TT_MulFix14( (FT_UInt32
)args
[0], 0x4000 );
5557 dx
= TT_MulFix14( (FT_UInt32
)args
[0], CUR
.GS
.freeVector
.x
);
5558 dy
= TT_MulFix14( (FT_UInt32
)args
[0], CUR
.GS
.freeVector
.y
);
5561 while ( CUR
.GS
.loop
> 0 )
5565 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5567 if ( BOUNDS( point
, CUR
.zp2
.n_points
) )
5569 if ( CUR
.pedantic_hinting
)
5571 CUR
.error
= TT_Err_Invalid_Reference
;
5576 MOVE_Zp2_Point( point
, dx
, dy
, TRUE
);
5582 CUR
.new_top
= CUR
.args
;
5586 /*************************************************************************/
5588 /* MSIRP[a]: Move Stack Indirect Relative Position */
5589 /* Opcode range: 0x3A-0x3B */
5590 /* Stack: f26.6 uint32 --> */
5593 Ins_MSIRP( INS_ARG
)
5596 FT_F26Dot6 distance
;
5599 point
= (FT_UShort
)args
[0];
5601 if ( BOUNDS( point
, CUR
.zp1
.n_points
) ||
5602 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5604 if ( CUR
.pedantic_hinting
)
5605 CUR
.error
= TT_Err_Invalid_Reference
;
5609 /* XXX: UNDOCUMENTED! behaviour */
5610 if ( CUR
.GS
.gep1
== 0 ) /* if the point that is to be moved */
5611 /* is in twilight zone */
5613 CUR
.zp1
.org
[point
] = CUR
.zp0
.org
[CUR
.GS
.rp0
];
5614 CUR_Func_move_orig( &CUR
.zp1
, point
, args
[1] );
5615 CUR
.zp1
.cur
[point
] = CUR
.zp1
.org
[point
];
5618 distance
= CUR_Func_project( CUR
.zp1
.cur
+ point
,
5619 CUR
.zp0
.cur
+ CUR
.GS
.rp0
);
5621 CUR_Func_move( &CUR
.zp1
, point
, args
[1] - distance
);
5623 CUR
.GS
.rp1
= CUR
.GS
.rp0
;
5626 if ( ( CUR
.opcode
& 1 ) != 0 )
5631 /*************************************************************************/
5633 /* MDAP[a]: Move Direct Absolute Point */
5634 /* Opcode range: 0x2E-0x2F */
5635 /* Stack: uint32 --> */
5641 FT_F26Dot6 cur_dist
,
5645 point
= (FT_UShort
)args
[0];
5647 if ( BOUNDS( point
, CUR
.zp0
.n_points
) )
5649 if ( CUR
.pedantic_hinting
)
5650 CUR
.error
= TT_Err_Invalid_Reference
;
5654 /* XXX: Is there some undocumented feature while in the */
5655 /* twilight zone? ? */
5656 if ( ( CUR
.opcode
& 1 ) != 0 )
5658 cur_dist
= CUR_fast_project( &CUR
.zp0
.cur
[point
] );
5659 distance
= CUR_Func_round( cur_dist
,
5660 CUR
.tt_metrics
.compensations
[0] ) - cur_dist
;
5665 CUR_Func_move( &CUR
.zp0
, point
, distance
);
5672 /*************************************************************************/
5674 /* MIAP[a]: Move Indirect Absolute Point */
5675 /* Opcode range: 0x3E-0x3F */
5676 /* Stack: uint32 uint32 --> */
5683 FT_F26Dot6 distance
,
5687 cvtEntry
= (FT_ULong
)args
[1];
5688 point
= (FT_UShort
)args
[0];
5690 if ( BOUNDS( point
, CUR
.zp0
.n_points
) ||
5691 BOUNDS( cvtEntry
, CUR
.cvtSize
) )
5693 if ( CUR
.pedantic_hinting
)
5694 CUR
.error
= TT_Err_Invalid_Reference
;
5698 /* XXX: UNDOCUMENTED! */
5700 /* The behaviour of an MIAP instruction is quite */
5701 /* different when used in the twilight zone. */
5703 /* First, no control value cut-in test is performed */
5704 /* as it would fail anyway. Second, the original */
5705 /* point, i.e. (org_x,org_y) of zp0.point, is set */
5706 /* to the absolute, unrounded distance found in */
5709 /* This is used in the CVT programs of the Microsoft */
5710 /* fonts Arial, Times, etc., in order to re-adjust */
5711 /* some key font heights. It allows the use of the */
5712 /* IP instruction in the twilight zone, which */
5713 /* otherwise would be `illegal' according to the */
5714 /* specification. */
5716 /* We implement it with a special sequence for the */
5717 /* twilight zone. This is a bad hack, but it seems */
5720 distance
= CUR_Func_read_cvt( cvtEntry
);
5722 if ( CUR
.GS
.gep0
== 0 ) /* If in twilight zone */
5724 CUR
.zp0
.org
[point
].x
= TT_MulFix14( (FT_UInt32
)distance
, CUR
.GS
.freeVector
.x
);
5725 CUR
.zp0
.org
[point
].y
= TT_MulFix14( (FT_UInt32
)distance
, CUR
.GS
.freeVector
.y
),
5726 CUR
.zp0
.cur
[point
] = CUR
.zp0
.org
[point
];
5729 org_dist
= CUR_fast_project( &CUR
.zp0
.cur
[point
] );
5731 if ( ( CUR
.opcode
& 1 ) != 0 ) /* rounding and control cutin flag */
5733 if ( FT_ABS( distance
- org_dist
) > CUR
.GS
.control_value_cutin
)
5734 distance
= org_dist
;
5736 distance
= CUR_Func_round( distance
, CUR
.tt_metrics
.compensations
[0] );
5739 CUR_Func_move( &CUR
.zp0
, point
, distance
- org_dist
);
5746 /*************************************************************************/
5748 /* MDRP[abcde]: Move Direct Relative Point */
5749 /* Opcode range: 0xC0-0xDF */
5750 /* Stack: uint32 --> */
5756 FT_F26Dot6 org_dist
, distance
;
5759 point
= (FT_UShort
)args
[0];
5761 if ( BOUNDS( point
, CUR
.zp1
.n_points
) ||
5762 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5764 if ( CUR
.pedantic_hinting
)
5765 CUR
.error
= TT_Err_Invalid_Reference
;
5769 /* XXX: Is there some undocumented feature while in the */
5770 /* twilight zone? */
5772 /* XXX: UNDOCUMENTED: twilight zone special case */
5774 if ( CUR
.GS
.gep0
== 0 || CUR
.GS
.gep1
== 0 )
5776 FT_Vector
* vec1
= &CUR
.zp1
.org
[point
];
5777 FT_Vector
* vec2
= &CUR
.zp0
.org
[CUR
.GS
.rp0
];
5780 org_dist
= CUR_Func_dualproj( vec1
, vec2
);
5784 FT_Vector
* vec1
= &CUR
.zp1
.orus
[point
];
5785 FT_Vector
* vec2
= &CUR
.zp0
.orus
[CUR
.GS
.rp0
];
5788 if ( CUR
.metrics
.x_scale
== CUR
.metrics
.y_scale
)
5790 /* this should be faster */
5791 org_dist
= CUR_Func_dualproj( vec1
, vec2
);
5792 org_dist
= TT_MULFIX( org_dist
, CUR
.metrics
.x_scale
);
5799 vec
.x
= TT_MULFIX( vec1
->x
- vec2
->x
, CUR
.metrics
.x_scale
);
5800 vec
.y
= TT_MULFIX( vec1
->y
- vec2
->y
, CUR
.metrics
.y_scale
);
5802 org_dist
= CUR_fast_dualproj( &vec
);
5806 /* single width cut-in test */
5808 if ( FT_ABS( org_dist
- CUR
.GS
.single_width_value
) <
5809 CUR
.GS
.single_width_cutin
)
5811 if ( org_dist
>= 0 )
5812 org_dist
= CUR
.GS
.single_width_value
;
5814 org_dist
= -CUR
.GS
.single_width_value
;
5819 if ( ( CUR
.opcode
& 4 ) != 0 )
5820 distance
= CUR_Func_round(
5822 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5824 distance
= ROUND_None(
5826 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5828 /* minimum distance flag */
5830 if ( ( CUR
.opcode
& 8 ) != 0 )
5832 if ( org_dist
>= 0 )
5834 if ( distance
< CUR
.GS
.minimum_distance
)
5835 distance
= CUR
.GS
.minimum_distance
;
5839 if ( distance
> -CUR
.GS
.minimum_distance
)
5840 distance
= -CUR
.GS
.minimum_distance
;
5844 /* now move the point */
5846 org_dist
= CUR_Func_project( CUR
.zp1
.cur
+ point
,
5847 CUR
.zp0
.cur
+ CUR
.GS
.rp0
);
5849 CUR_Func_move( &CUR
.zp1
, point
, distance
- org_dist
);
5851 CUR
.GS
.rp1
= CUR
.GS
.rp0
;
5854 if ( ( CUR
.opcode
& 16 ) != 0 )
5859 /*************************************************************************/
5861 /* MIRP[abcde]: Move Indirect Relative Point */
5862 /* Opcode range: 0xE0-0xFF */
5863 /* Stack: int32? uint32 --> */
5871 FT_F26Dot6 cvt_dist
,
5877 point
= (FT_UShort
)args
[0];
5878 cvtEntry
= (FT_ULong
)( args
[1] + 1 );
5880 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
5882 if ( BOUNDS( point
, CUR
.zp1
.n_points
) ||
5883 BOUNDS( cvtEntry
, CUR
.cvtSize
+ 1 ) ||
5884 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5886 if ( CUR
.pedantic_hinting
)
5887 CUR
.error
= TT_Err_Invalid_Reference
;
5894 cvt_dist
= CUR_Func_read_cvt( cvtEntry
- 1 );
5896 /* single width test */
5898 if ( FT_ABS( cvt_dist
- CUR
.GS
.single_width_value
) <
5899 CUR
.GS
.single_width_cutin
)
5901 if ( cvt_dist
>= 0 )
5902 cvt_dist
= CUR
.GS
.single_width_value
;
5904 cvt_dist
= -CUR
.GS
.single_width_value
;
5907 /* XXX: UNDOCUMENTED! -- twilight zone */
5909 if ( CUR
.GS
.gep1
== 0 )
5911 CUR
.zp1
.org
[point
].x
= CUR
.zp0
.org
[CUR
.GS
.rp0
].x
+
5912 TT_MulFix14( (FT_UInt32
)cvt_dist
,
5913 CUR
.GS
.freeVector
.x
);
5915 CUR
.zp1
.org
[point
].y
= CUR
.zp0
.org
[CUR
.GS
.rp0
].y
+
5916 TT_MulFix14( (FT_UInt32
)cvt_dist
,
5917 CUR
.GS
.freeVector
.y
);
5919 CUR
.zp1
.cur
[point
] = CUR
.zp0
.cur
[point
];
5922 org_dist
= CUR_Func_dualproj( &CUR
.zp1
.org
[point
],
5923 &CUR
.zp0
.org
[CUR
.GS
.rp0
] );
5924 cur_dist
= CUR_Func_project ( &CUR
.zp1
.cur
[point
],
5925 &CUR
.zp0
.cur
[CUR
.GS
.rp0
] );
5927 /* auto-flip test */
5929 if ( CUR
.GS
.auto_flip
)
5931 if ( ( org_dist
^ cvt_dist
) < 0 )
5932 cvt_dist
= -cvt_dist
;
5935 /* control value cutin and round */
5937 if ( ( CUR
.opcode
& 4 ) != 0 )
5939 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
5940 /* refer to the same zone. */
5942 if ( CUR
.GS
.gep0
== CUR
.GS
.gep1
)
5943 if ( FT_ABS( cvt_dist
- org_dist
) >= CUR
.GS
.control_value_cutin
)
5944 cvt_dist
= org_dist
;
5946 distance
= CUR_Func_round(
5948 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5951 distance
= ROUND_None(
5953 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5955 /* minimum distance test */
5957 if ( ( CUR
.opcode
& 8 ) != 0 )
5959 if ( org_dist
>= 0 )
5961 if ( distance
< CUR
.GS
.minimum_distance
)
5962 distance
= CUR
.GS
.minimum_distance
;
5966 if ( distance
> -CUR
.GS
.minimum_distance
)
5967 distance
= -CUR
.GS
.minimum_distance
;
5971 CUR_Func_move( &CUR
.zp1
, point
, distance
- cur_dist
);
5973 CUR
.GS
.rp1
= CUR
.GS
.rp0
;
5975 if ( ( CUR
.opcode
& 16 ) != 0 )
5978 /* XXX: UNDOCUMENTED! */
5983 /*************************************************************************/
5985 /* ALIGNRP[]: ALIGN Relative Point */
5986 /* Opcode range: 0x3C */
5987 /* Stack: uint32 uint32... --> */
5990 Ins_ALIGNRP( INS_ARG
)
5993 FT_F26Dot6 distance
;
5998 if ( CUR
.top
< CUR
.GS
.loop
||
5999 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
6001 if ( CUR
.pedantic_hinting
)
6002 CUR
.error
= TT_Err_Invalid_Reference
;
6006 while ( CUR
.GS
.loop
> 0 )
6010 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
6012 if ( BOUNDS( point
, CUR
.zp1
.n_points
) )
6014 if ( CUR
.pedantic_hinting
)
6016 CUR
.error
= TT_Err_Invalid_Reference
;
6022 distance
= CUR_Func_project( CUR
.zp1
.cur
+ point
,
6023 CUR
.zp0
.cur
+ CUR
.GS
.rp0
);
6025 CUR_Func_move( &CUR
.zp1
, point
, -distance
);
6032 CUR
.new_top
= CUR
.args
;
6036 /*************************************************************************/
6038 /* ISECT[]: moves point to InterSECTion */
6039 /* Opcode range: 0x0F */
6040 /* Stack: 5 * uint32 --> */
6043 Ins_ISECT( INS_ARG
)
6049 FT_F26Dot6 discriminant
;
6060 point
= (FT_UShort
)args
[0];
6062 a0
= (FT_UShort
)args
[1];
6063 a1
= (FT_UShort
)args
[2];
6064 b0
= (FT_UShort
)args
[3];
6065 b1
= (FT_UShort
)args
[4];
6067 if ( BOUNDS( b0
, CUR
.zp0
.n_points
) ||
6068 BOUNDS( b1
, CUR
.zp0
.n_points
) ||
6069 BOUNDS( a0
, CUR
.zp1
.n_points
) ||
6070 BOUNDS( a1
, CUR
.zp1
.n_points
) ||
6071 BOUNDS( point
, CUR
.zp2
.n_points
) )
6073 if ( CUR
.pedantic_hinting
)
6074 CUR
.error
= TT_Err_Invalid_Reference
;
6078 dbx
= CUR
.zp0
.cur
[b1
].x
- CUR
.zp0
.cur
[b0
].x
;
6079 dby
= CUR
.zp0
.cur
[b1
].y
- CUR
.zp0
.cur
[b0
].y
;
6081 dax
= CUR
.zp1
.cur
[a1
].x
- CUR
.zp1
.cur
[a0
].x
;
6082 day
= CUR
.zp1
.cur
[a1
].y
- CUR
.zp1
.cur
[a0
].y
;
6084 dx
= CUR
.zp0
.cur
[b0
].x
- CUR
.zp1
.cur
[a0
].x
;
6085 dy
= CUR
.zp0
.cur
[b0
].y
- CUR
.zp1
.cur
[a0
].y
;
6087 CUR
.zp2
.tags
[point
] |= FT_CURVE_TAG_TOUCH_BOTH
;
6089 discriminant
= TT_MULDIV( dax
, -dby
, 0x40 ) +
6090 TT_MULDIV( day
, dbx
, 0x40 );
6092 if ( FT_ABS( discriminant
) >= 0x40 )
6094 val
= TT_MULDIV( dx
, -dby
, 0x40 ) + TT_MULDIV( dy
, dbx
, 0x40 );
6096 R
.x
= TT_MULDIV( val
, dax
, discriminant
);
6097 R
.y
= TT_MULDIV( val
, day
, discriminant
);
6099 CUR
.zp2
.cur
[point
].x
= CUR
.zp1
.cur
[a0
].x
+ R
.x
;
6100 CUR
.zp2
.cur
[point
].y
= CUR
.zp1
.cur
[a0
].y
+ R
.y
;
6104 /* else, take the middle of the middles of A and B */
6106 CUR
.zp2
.cur
[point
].x
= ( CUR
.zp1
.cur
[a0
].x
+
6109 CUR
.zp0
.cur
[b1
].x
) / 4;
6110 CUR
.zp2
.cur
[point
].y
= ( CUR
.zp1
.cur
[a0
].y
+
6113 CUR
.zp0
.cur
[b1
].y
) / 4;
6118 /*************************************************************************/
6120 /* ALIGNPTS[]: ALIGN PoinTS */
6121 /* Opcode range: 0x27 */
6122 /* Stack: uint32 uint32 --> */
6125 Ins_ALIGNPTS( INS_ARG
)
6128 FT_F26Dot6 distance
;
6131 p1
= (FT_UShort
)args
[0];
6132 p2
= (FT_UShort
)args
[1];
6134 if ( BOUNDS( args
[0], CUR
.zp1
.n_points
) ||
6135 BOUNDS( args
[1], CUR
.zp0
.n_points
) )
6137 if ( CUR
.pedantic_hinting
)
6138 CUR
.error
= TT_Err_Invalid_Reference
;
6142 distance
= CUR_Func_project( CUR
.zp0
.cur
+ p2
,
6143 CUR
.zp1
.cur
+ p1
) / 2;
6145 CUR_Func_move( &CUR
.zp1
, p1
, distance
);
6146 CUR_Func_move( &CUR
.zp0
, p2
, -distance
);
6150 /*************************************************************************/
6152 /* IP[]: Interpolate Point */
6153 /* Opcode range: 0x39 */
6154 /* Stack: uint32... --> */
6157 /* SOMETIMES, DUMBER CODE IS BETTER CODE */
6162 FT_F26Dot6 old_range
, cur_range
;
6163 FT_Vector
* orus_base
;
6164 FT_Vector
* cur_base
;
6170 if ( CUR
.top
< CUR
.GS
.loop
)
6172 CUR
.error
= TT_Err_Invalid_Reference
;
6177 * We need to deal in a special way with the twilight zone.
6178 * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0),
6181 twilight
= CUR
.GS
.gep0
== 0 || CUR
.GS
.gep1
== 0 || CUR
.GS
.gep2
== 0;
6183 if ( BOUNDS( CUR
.GS
.rp1
, CUR
.zp0
.n_points
) )
6185 if ( CUR
.pedantic_hinting
)
6186 CUR
.error
= TT_Err_Invalid_Reference
;
6191 orus_base
= &CUR
.zp0
.org
[CUR
.GS
.rp1
];
6193 orus_base
= &CUR
.zp0
.orus
[CUR
.GS
.rp1
];
6195 cur_base
= &CUR
.zp0
.cur
[CUR
.GS
.rp1
];
6197 /* XXX: There are some glyphs in some braindead but popular */
6198 /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
6199 /* calling IP[] with bad values of rp[12]. */
6200 /* Do something sane when this odd thing happens. */
6201 if ( BOUNDS( CUR
.GS
.rp1
, CUR
.zp0
.n_points
) ||
6202 BOUNDS( CUR
.GS
.rp2
, CUR
.zp1
.n_points
) )
6210 old_range
= CUR_Func_dualproj( &CUR
.zp1
.org
[CUR
.GS
.rp2
],
6213 old_range
= CUR_Func_dualproj( &CUR
.zp1
.orus
[CUR
.GS
.rp2
],
6216 cur_range
= CUR_Func_project ( &CUR
.zp1
.cur
[CUR
.GS
.rp2
], cur_base
);
6219 for ( ; CUR
.GS
.loop
> 0; --CUR
.GS
.loop
)
6221 FT_UInt point
= (FT_UInt
)CUR
.stack
[--CUR
.args
];
6222 FT_F26Dot6 org_dist
, cur_dist
, new_dist
;
6225 /* check point bounds */
6226 if ( BOUNDS( point
, CUR
.zp2
.n_points
) )
6228 if ( CUR
.pedantic_hinting
)
6230 CUR
.error
= TT_Err_Invalid_Reference
;
6237 org_dist
= CUR_Func_dualproj( &CUR
.zp2
.org
[point
], orus_base
);
6239 org_dist
= CUR_Func_dualproj( &CUR
.zp2
.orus
[point
], orus_base
);
6241 cur_dist
= CUR_Func_project ( &CUR
.zp2
.cur
[point
], cur_base
);
6244 new_dist
= ( old_range
!= 0 )
6245 ? TT_MULDIV( org_dist
, cur_range
, old_range
)
6250 CUR_Func_move( &CUR
.zp2
, (FT_UShort
)point
, new_dist
- cur_dist
);
6253 CUR
.new_top
= CUR
.args
;
6257 /*************************************************************************/
6259 /* UTP[a]: UnTouch Point */
6260 /* Opcode range: 0x29 */
6261 /* Stack: uint32 --> */
6270 point
= (FT_UShort
)args
[0];
6272 if ( BOUNDS( point
, CUR
.zp0
.n_points
) )
6274 if ( CUR
.pedantic_hinting
)
6275 CUR
.error
= TT_Err_Invalid_Reference
;
6281 if ( CUR
.GS
.freeVector
.x
!= 0 )
6282 mask
&= ~FT_CURVE_TAG_TOUCH_X
;
6284 if ( CUR
.GS
.freeVector
.y
!= 0 )
6285 mask
&= ~FT_CURVE_TAG_TOUCH_Y
;
6287 CUR
.zp0
.tags
[point
] &= mask
;
6291 /* Local variables for Ins_IUP: */
6292 typedef struct IUP_WorkerRec_
6294 FT_Vector
* orgs
; /* original and current coordinate */
6295 FT_Vector
* curs
; /* arrays */
6299 } IUP_WorkerRec
, *IUP_Worker
;
6303 _iup_worker_shift( IUP_Worker worker
,
6312 dx
= worker
->curs
[p
].x
- worker
->orgs
[p
].x
;
6315 for ( i
= p1
; i
< p
; i
++ )
6316 worker
->curs
[i
].x
+= dx
;
6318 for ( i
= p
+ 1; i
<= p2
; i
++ )
6319 worker
->curs
[i
].x
+= dx
;
6325 _iup_worker_interpolate( IUP_Worker worker
,
6332 FT_F26Dot6 orus1
, orus2
, org1
, org2
, delta1
, delta2
;
6338 if ( BOUNDS( ref1
, worker
->max_points
) ||
6339 BOUNDS( ref2
, worker
->max_points
) )
6342 orus1
= worker
->orus
[ref1
].x
;
6343 orus2
= worker
->orus
[ref2
].x
;
6345 if ( orus1
> orus2
)
6360 org1
= worker
->orgs
[ref1
].x
;
6361 org2
= worker
->orgs
[ref2
].x
;
6362 delta1
= worker
->curs
[ref1
].x
- org1
;
6363 delta2
= worker
->curs
[ref2
].x
- org2
;
6365 if ( orus1
== orus2
)
6367 /* simple shift of untouched points */
6368 for ( i
= p1
; i
<= p2
; i
++ )
6370 FT_F26Dot6 x
= worker
->orgs
[i
].x
;
6378 worker
->curs
[i
].x
= x
;
6384 FT_Bool scale_valid
= 0;
6388 for ( i
= p1
; i
<= p2
; i
++ )
6390 FT_F26Dot6 x
= worker
->orgs
[i
].x
;
6396 else if ( x
>= org2
)
6404 scale
= TT_MULDIV( org2
+ delta2
- ( org1
+ delta1
),
6405 0x10000L
, orus2
- orus1
);
6408 x
= ( org1
+ delta1
) +
6409 TT_MULFIX( worker
->orus
[i
].x
- orus1
, scale
);
6411 worker
->curs
[i
].x
= x
;
6417 /*************************************************************************/
6419 /* IUP[a]: Interpolate Untouched Points */
6420 /* Opcode range: 0x30-0x31 */
6429 FT_UInt first_point
; /* first point of contour */
6430 FT_UInt end_point
; /* end point (last+1) of contour */
6432 FT_UInt first_touched
; /* first touched point in contour */
6433 FT_UInt cur_touched
; /* current touched point in contour */
6435 FT_UInt point
; /* current point */
6436 FT_Short contour
; /* current contour */
6441 /* ignore empty outlines */
6442 if ( CUR
.pts
.n_contours
== 0 )
6445 if ( CUR
.opcode
& 1 )
6447 mask
= FT_CURVE_TAG_TOUCH_X
;
6448 V
.orgs
= CUR
.pts
.org
;
6449 V
.curs
= CUR
.pts
.cur
;
6450 V
.orus
= CUR
.pts
.orus
;
6454 mask
= FT_CURVE_TAG_TOUCH_Y
;
6455 V
.orgs
= (FT_Vector
*)( (FT_Pos
*)CUR
.pts
.org
+ 1 );
6456 V
.curs
= (FT_Vector
*)( (FT_Pos
*)CUR
.pts
.cur
+ 1 );
6457 V
.orus
= (FT_Vector
*)( (FT_Pos
*)CUR
.pts
.orus
+ 1 );
6459 V
.max_points
= CUR
.pts
.n_points
;
6466 end_point
= CUR
.pts
.contours
[contour
] - CUR
.pts
.first_point
;
6467 first_point
= point
;
6469 if ( CUR
.pts
.n_points
<= end_point
)
6470 end_point
= CUR
.pts
.n_points
;
6472 while ( point
<= end_point
&& ( CUR
.pts
.tags
[point
] & mask
) == 0 )
6475 if ( point
<= end_point
)
6477 first_touched
= point
;
6478 cur_touched
= point
;
6482 while ( point
<= end_point
)
6484 if ( ( CUR
.pts
.tags
[point
] & mask
) != 0 )
6487 _iup_worker_interpolate( &V
,
6492 cur_touched
= point
;
6498 if ( cur_touched
== first_touched
)
6499 _iup_worker_shift( &V
, first_point
, end_point
, cur_touched
);
6502 _iup_worker_interpolate( &V
,
6503 (FT_UShort
)( cur_touched
+ 1 ),
6508 if ( first_touched
> 0 )
6509 _iup_worker_interpolate( &V
,
6517 } while ( contour
< CUR
.pts
.n_contours
);
6521 /*************************************************************************/
6523 /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
6524 /* Opcode range: 0x5D,0x71,0x72 */
6525 /* Stack: uint32 (2 * uint32)... --> */
6528 Ins_DELTAP( INS_ARG
)
6536 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
6537 /* Delta hinting is covered by US Patent 5159668. */
6538 if ( CUR
.face
->unpatented_hinting
)
6540 FT_Long n
= args
[0] * 2;
6545 CUR
.error
= TT_Err_Too_Few_Arguments
;
6550 CUR
.new_top
= CUR
.args
;
6555 nump
= (FT_ULong
)args
[0]; /* some points theoretically may occur more
6556 than once, thus UShort isn't enough */
6558 for ( k
= 1; k
<= nump
; k
++ )
6562 CUR
.error
= TT_Err_Too_Few_Arguments
;
6568 A
= (FT_UShort
)CUR
.stack
[CUR
.args
+ 1];
6569 B
= CUR
.stack
[CUR
.args
];
6571 /* XXX: Because some popular fonts contain some invalid DeltaP */
6572 /* instructions, we simply ignore them when the stacked */
6573 /* point reference is off limit, rather than returning an */
6574 /* error. As a delta instruction doesn't change a glyph */
6575 /* in great ways, this shouldn't be a problem. */
6577 if ( !BOUNDS( A
, CUR
.zp0
.n_points
) )
6579 C
= ( (FT_ULong
)B
& 0xF0 ) >> 4;
6581 switch ( CUR
.opcode
)
6595 C
+= CUR
.GS
.delta_base
;
6597 if ( CURRENT_Ppem() == (FT_Long
)C
)
6599 B
= ( (FT_ULong
)B
& 0xF ) - 8;
6602 B
= B
* 64 / ( 1L << CUR
.GS
.delta_shift
);
6604 CUR_Func_move( &CUR
.zp0
, A
, B
);
6608 if ( CUR
.pedantic_hinting
)
6609 CUR
.error
= TT_Err_Invalid_Reference
;
6612 CUR
.new_top
= CUR
.args
;
6616 /*************************************************************************/
6618 /* DELTACn[]: DELTA exceptions C1, C2, C3 */
6619 /* Opcode range: 0x73,0x74,0x75 */
6620 /* Stack: uint32 (2 * uint32)... --> */
6623 Ins_DELTAC( INS_ARG
)
6630 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
6631 /* Delta hinting is covered by US Patent 5159668. */
6632 if ( CUR
.face
->unpatented_hinting
)
6634 FT_Long n
= args
[0] * 2;
6639 CUR
.error
= TT_Err_Too_Few_Arguments
;
6644 CUR
.new_top
= CUR
.args
;
6649 nump
= (FT_ULong
)args
[0];
6651 for ( k
= 1; k
<= nump
; k
++ )
6655 CUR
.error
= TT_Err_Too_Few_Arguments
;
6661 A
= (FT_ULong
)CUR
.stack
[CUR
.args
+ 1];
6662 B
= CUR
.stack
[CUR
.args
];
6664 if ( BOUNDS( A
, CUR
.cvtSize
) )
6666 if ( CUR
.pedantic_hinting
)
6668 CUR
.error
= TT_Err_Invalid_Reference
;
6674 C
= ( (FT_ULong
)B
& 0xF0 ) >> 4;
6676 switch ( CUR
.opcode
)
6690 C
+= CUR
.GS
.delta_base
;
6692 if ( CURRENT_Ppem() == (FT_Long
)C
)
6694 B
= ( (FT_ULong
)B
& 0xF ) - 8;
6697 B
= B
* 64 / ( 1L << CUR
.GS
.delta_shift
);
6699 CUR_Func_move_cvt( A
, B
);
6704 CUR
.new_top
= CUR
.args
;
6708 /*************************************************************************/
6710 /* MISC. INSTRUCTIONS */
6712 /*************************************************************************/
6715 /*************************************************************************/
6717 /* GETINFO[]: GET INFOrmation */
6718 /* Opcode range: 0x88 */
6719 /* Stack: uint32 --> uint32 */
6722 Ins_GETINFO( INS_ARG
)
6729 /* We return MS rasterizer version 1.7 for the font scaler. */
6730 if ( ( args
[0] & 1 ) != 0 )
6733 /* Has the glyph been rotated? */
6734 if ( ( args
[0] & 2 ) != 0 && CUR
.tt_metrics
.rotated
)
6737 /* Has the glyph been stretched? */
6738 if ( ( args
[0] & 4 ) != 0 && CUR
.tt_metrics
.stretched
)
6741 /* Are we hinting for grayscale? */
6742 if ( ( args
[0] & 32 ) != 0 && CUR
.grayscale
)
6750 Ins_UNKNOWN( INS_ARG
)
6752 TT_DefRecord
* def
= CUR
.IDefs
;
6753 TT_DefRecord
* limit
= def
+ CUR
.numIDefs
;
6758 for ( ; def
< limit
; def
++ )
6760 if ( (FT_Byte
)def
->opc
== CUR
.opcode
&& def
->active
)
6765 if ( CUR
.callTop
>= CUR
.callSize
)
6767 CUR
.error
= TT_Err_Stack_Overflow
;
6771 call
= CUR
.callStack
+ CUR
.callTop
++;
6773 call
->Caller_Range
= CUR
.curRange
;
6774 call
->Caller_IP
= CUR
.IP
+1;
6775 call
->Cur_Count
= 1;
6776 call
->Cur_Restart
= def
->start
;
6778 INS_Goto_CodeRange( def
->range
, def
->start
);
6780 CUR
.step_ins
= FALSE
;
6785 CUR
.error
= TT_Err_Invalid_Opcode
;
6789 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
6793 TInstruction_Function Instruct_Dispatch
[256] =
6795 /* Opcodes are gathered in groups of 16. */
6796 /* Please keep the spaces as they are. */
6798 /* SVTCA y */ Ins_SVTCA
,
6799 /* SVTCA x */ Ins_SVTCA
,
6800 /* SPvTCA y */ Ins_SPVTCA
,
6801 /* SPvTCA x */ Ins_SPVTCA
,
6802 /* SFvTCA y */ Ins_SFVTCA
,
6803 /* SFvTCA x */ Ins_SFVTCA
,
6804 /* SPvTL // */ Ins_SPVTL
,
6805 /* SPvTL + */ Ins_SPVTL
,
6806 /* SFvTL // */ Ins_SFVTL
,
6807 /* SFvTL + */ Ins_SFVTL
,
6808 /* SPvFS */ Ins_SPVFS
,
6809 /* SFvFS */ Ins_SFVFS
,
6812 /* SFvTPv */ Ins_SFVTPV
,
6813 /* ISECT */ Ins_ISECT
,
6815 /* SRP0 */ Ins_SRP0
,
6816 /* SRP1 */ Ins_SRP1
,
6817 /* SRP2 */ Ins_SRP2
,
6818 /* SZP0 */ Ins_SZP0
,
6819 /* SZP1 */ Ins_SZP1
,
6820 /* SZP2 */ Ins_SZP2
,
6821 /* SZPS */ Ins_SZPS
,
6822 /* SLOOP */ Ins_SLOOP
,
6824 /* RTHG */ Ins_RTHG
,
6826 /* ELSE */ Ins_ELSE
,
6827 /* JMPR */ Ins_JMPR
,
6828 /* SCvTCi */ Ins_SCVTCI
,
6829 /* SSwCi */ Ins_SSWCI
,
6834 /* CLEAR */ Ins_CLEAR
,
6835 /* SWAP */ Ins_SWAP
,
6836 /* DEPTH */ Ins_DEPTH
,
6837 /* CINDEX */ Ins_CINDEX
,
6838 /* MINDEX */ Ins_MINDEX
,
6839 /* AlignPTS */ Ins_ALIGNPTS
,
6840 /* INS_0x28 */ Ins_UNKNOWN
,
6842 /* LOOPCALL */ Ins_LOOPCALL
,
6843 /* CALL */ Ins_CALL
,
6844 /* FDEF */ Ins_FDEF
,
6845 /* ENDF */ Ins_ENDF
,
6846 /* MDAP[0] */ Ins_MDAP
,
6847 /* MDAP[1] */ Ins_MDAP
,
6849 /* IUP[0] */ Ins_IUP
,
6850 /* IUP[1] */ Ins_IUP
,
6851 /* SHP[0] */ Ins_SHP
,
6852 /* SHP[1] */ Ins_SHP
,
6853 /* SHC[0] */ Ins_SHC
,
6854 /* SHC[1] */ Ins_SHC
,
6855 /* SHZ[0] */ Ins_SHZ
,
6856 /* SHZ[1] */ Ins_SHZ
,
6857 /* SHPIX */ Ins_SHPIX
,
6859 /* MSIRP[0] */ Ins_MSIRP
,
6860 /* MSIRP[1] */ Ins_MSIRP
,
6861 /* AlignRP */ Ins_ALIGNRP
,
6862 /* RTDG */ Ins_RTDG
,
6863 /* MIAP[0] */ Ins_MIAP
,
6864 /* MIAP[1] */ Ins_MIAP
,
6866 /* NPushB */ Ins_NPUSHB
,
6867 /* NPushW */ Ins_NPUSHW
,
6870 /* WCvtP */ Ins_WCVTP
,
6871 /* RCvt */ Ins_RCVT
,
6874 /* SCFS */ Ins_SCFS
,
6877 /* MPPEM */ Ins_MPPEM
,
6879 /* FlipON */ Ins_FLIPON
,
6880 /* FlipOFF */ Ins_FLIPOFF
,
6881 /* DEBUG */ Ins_DEBUG
,
6884 /* LTEQ */ Ins_LTEQ
,
6886 /* GTEQ */ Ins_GTEQ
,
6890 /* EVEN */ Ins_EVEN
,
6896 /* DeltaP1 */ Ins_DELTAP
,
6906 /* FLOOR */ Ins_FLOOR
,
6907 /* CEILING */ Ins_CEILING
,
6908 /* ROUND[0] */ Ins_ROUND
,
6909 /* ROUND[1] */ Ins_ROUND
,
6910 /* ROUND[2] */ Ins_ROUND
,
6911 /* ROUND[3] */ Ins_ROUND
,
6912 /* NROUND[0] */ Ins_NROUND
,
6913 /* NROUND[1] */ Ins_NROUND
,
6914 /* NROUND[2] */ Ins_NROUND
,
6915 /* NROUND[3] */ Ins_NROUND
,
6917 /* WCvtF */ Ins_WCVTF
,
6918 /* DeltaP2 */ Ins_DELTAP
,
6919 /* DeltaP3 */ Ins_DELTAP
,
6920 /* DeltaCn[0] */ Ins_DELTAC
,
6921 /* DeltaCn[1] */ Ins_DELTAC
,
6922 /* DeltaCn[2] */ Ins_DELTAC
,
6923 /* SROUND */ Ins_SROUND
,
6924 /* S45Round */ Ins_S45ROUND
,
6925 /* JROT */ Ins_JROT
,
6926 /* JROF */ Ins_JROF
,
6927 /* ROFF */ Ins_ROFF
,
6928 /* INS_0x7B */ Ins_UNKNOWN
,
6929 /* RUTG */ Ins_RUTG
,
6930 /* RDTG */ Ins_RDTG
,
6931 /* SANGW */ Ins_SANGW
,
6934 /* FlipPT */ Ins_FLIPPT
,
6935 /* FlipRgON */ Ins_FLIPRGON
,
6936 /* FlipRgOFF */ Ins_FLIPRGOFF
,
6937 /* INS_0x83 */ Ins_UNKNOWN
,
6938 /* INS_0x84 */ Ins_UNKNOWN
,
6939 /* ScanCTRL */ Ins_SCANCTRL
,
6940 /* SDPVTL[0] */ Ins_SDPVTL
,
6941 /* SDPVTL[1] */ Ins_SDPVTL
,
6942 /* GetINFO */ Ins_GETINFO
,
6943 /* IDEF */ Ins_IDEF
,
6944 /* ROLL */ Ins_ROLL
,
6947 /* ScanTYPE */ Ins_SCANTYPE
,
6948 /* InstCTRL */ Ins_INSTCTRL
,
6949 /* INS_0x8F */ Ins_UNKNOWN
,
6951 /* INS_0x90 */ Ins_UNKNOWN
,
6952 /* INS_0x91 */ Ins_UNKNOWN
,
6953 /* INS_0x92 */ Ins_UNKNOWN
,
6954 /* INS_0x93 */ Ins_UNKNOWN
,
6955 /* INS_0x94 */ Ins_UNKNOWN
,
6956 /* INS_0x95 */ Ins_UNKNOWN
,
6957 /* INS_0x96 */ Ins_UNKNOWN
,
6958 /* INS_0x97 */ Ins_UNKNOWN
,
6959 /* INS_0x98 */ Ins_UNKNOWN
,
6960 /* INS_0x99 */ Ins_UNKNOWN
,
6961 /* INS_0x9A */ Ins_UNKNOWN
,
6962 /* INS_0x9B */ Ins_UNKNOWN
,
6963 /* INS_0x9C */ Ins_UNKNOWN
,
6964 /* INS_0x9D */ Ins_UNKNOWN
,
6965 /* INS_0x9E */ Ins_UNKNOWN
,
6966 /* INS_0x9F */ Ins_UNKNOWN
,
6968 /* INS_0xA0 */ Ins_UNKNOWN
,
6969 /* INS_0xA1 */ Ins_UNKNOWN
,
6970 /* INS_0xA2 */ Ins_UNKNOWN
,
6971 /* INS_0xA3 */ Ins_UNKNOWN
,
6972 /* INS_0xA4 */ Ins_UNKNOWN
,
6973 /* INS_0xA5 */ Ins_UNKNOWN
,
6974 /* INS_0xA6 */ Ins_UNKNOWN
,
6975 /* INS_0xA7 */ Ins_UNKNOWN
,
6976 /* INS_0xA8 */ Ins_UNKNOWN
,
6977 /* INS_0xA9 */ Ins_UNKNOWN
,
6978 /* INS_0xAA */ Ins_UNKNOWN
,
6979 /* INS_0xAB */ Ins_UNKNOWN
,
6980 /* INS_0xAC */ Ins_UNKNOWN
,
6981 /* INS_0xAD */ Ins_UNKNOWN
,
6982 /* INS_0xAE */ Ins_UNKNOWN
,
6983 /* INS_0xAF */ Ins_UNKNOWN
,
6985 /* PushB[0] */ Ins_PUSHB
,
6986 /* PushB[1] */ Ins_PUSHB
,
6987 /* PushB[2] */ Ins_PUSHB
,
6988 /* PushB[3] */ Ins_PUSHB
,
6989 /* PushB[4] */ Ins_PUSHB
,
6990 /* PushB[5] */ Ins_PUSHB
,
6991 /* PushB[6] */ Ins_PUSHB
,
6992 /* PushB[7] */ Ins_PUSHB
,
6993 /* PushW[0] */ Ins_PUSHW
,
6994 /* PushW[1] */ Ins_PUSHW
,
6995 /* PushW[2] */ Ins_PUSHW
,
6996 /* PushW[3] */ Ins_PUSHW
,
6997 /* PushW[4] */ Ins_PUSHW
,
6998 /* PushW[5] */ Ins_PUSHW
,
6999 /* PushW[6] */ Ins_PUSHW
,
7000 /* PushW[7] */ Ins_PUSHW
,
7002 /* MDRP[00] */ Ins_MDRP
,
7003 /* MDRP[01] */ Ins_MDRP
,
7004 /* MDRP[02] */ Ins_MDRP
,
7005 /* MDRP[03] */ Ins_MDRP
,
7006 /* MDRP[04] */ Ins_MDRP
,
7007 /* MDRP[05] */ Ins_MDRP
,
7008 /* MDRP[06] */ Ins_MDRP
,
7009 /* MDRP[07] */ Ins_MDRP
,
7010 /* MDRP[08] */ Ins_MDRP
,
7011 /* MDRP[09] */ Ins_MDRP
,
7012 /* MDRP[10] */ Ins_MDRP
,
7013 /* MDRP[11] */ Ins_MDRP
,
7014 /* MDRP[12] */ Ins_MDRP
,
7015 /* MDRP[13] */ Ins_MDRP
,
7016 /* MDRP[14] */ Ins_MDRP
,
7017 /* MDRP[15] */ Ins_MDRP
,
7019 /* MDRP[16] */ Ins_MDRP
,
7020 /* MDRP[17] */ Ins_MDRP
,
7021 /* MDRP[18] */ Ins_MDRP
,
7022 /* MDRP[19] */ Ins_MDRP
,
7023 /* MDRP[20] */ Ins_MDRP
,
7024 /* MDRP[21] */ Ins_MDRP
,
7025 /* MDRP[22] */ Ins_MDRP
,
7026 /* MDRP[23] */ Ins_MDRP
,
7027 /* MDRP[24] */ Ins_MDRP
,
7028 /* MDRP[25] */ Ins_MDRP
,
7029 /* MDRP[26] */ Ins_MDRP
,
7030 /* MDRP[27] */ Ins_MDRP
,
7031 /* MDRP[28] */ Ins_MDRP
,
7032 /* MDRP[29] */ Ins_MDRP
,
7033 /* MDRP[30] */ Ins_MDRP
,
7034 /* MDRP[31] */ Ins_MDRP
,
7036 /* MIRP[00] */ Ins_MIRP
,
7037 /* MIRP[01] */ Ins_MIRP
,
7038 /* MIRP[02] */ Ins_MIRP
,
7039 /* MIRP[03] */ Ins_MIRP
,
7040 /* MIRP[04] */ Ins_MIRP
,
7041 /* MIRP[05] */ Ins_MIRP
,
7042 /* MIRP[06] */ Ins_MIRP
,
7043 /* MIRP[07] */ Ins_MIRP
,
7044 /* MIRP[08] */ Ins_MIRP
,
7045 /* MIRP[09] */ Ins_MIRP
,
7046 /* MIRP[10] */ Ins_MIRP
,
7047 /* MIRP[11] */ Ins_MIRP
,
7048 /* MIRP[12] */ Ins_MIRP
,
7049 /* MIRP[13] */ Ins_MIRP
,
7050 /* MIRP[14] */ Ins_MIRP
,
7051 /* MIRP[15] */ Ins_MIRP
,
7053 /* MIRP[16] */ Ins_MIRP
,
7054 /* MIRP[17] */ Ins_MIRP
,
7055 /* MIRP[18] */ Ins_MIRP
,
7056 /* MIRP[19] */ Ins_MIRP
,
7057 /* MIRP[20] */ Ins_MIRP
,
7058 /* MIRP[21] */ Ins_MIRP
,
7059 /* MIRP[22] */ Ins_MIRP
,
7060 /* MIRP[23] */ Ins_MIRP
,
7061 /* MIRP[24] */ Ins_MIRP
,
7062 /* MIRP[25] */ Ins_MIRP
,
7063 /* MIRP[26] */ Ins_MIRP
,
7064 /* MIRP[27] */ Ins_MIRP
,
7065 /* MIRP[28] */ Ins_MIRP
,
7066 /* MIRP[29] */ Ins_MIRP
,
7067 /* MIRP[30] */ Ins_MIRP
,
7068 /* MIRP[31] */ Ins_MIRP
7072 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7075 /*************************************************************************/
7079 /* This function executes a run of opcodes. It will exit in the */
7080 /* following cases: */
7082 /* - Errors (in which case it returns FALSE). */
7084 /* - Reaching the end of the main code range (returns TRUE). */
7085 /* Reaching the end of a code range within a function call is an */
7088 /* - After executing one single opcode, if the flag `Instruction_Trap' */
7089 /* is set to TRUE (returns TRUE). */
7091 /* On exit with TRUE, test IP < CodeSize to know whether it comes from */
7092 /* an instruction trap or a normal termination. */
7095 /* Note: The documented DEBUG opcode pops a value from the stack. This */
7096 /* behaviour is unsupported; here a DEBUG opcode is always an */
7100 /* THIS IS THE INTERPRETER'S MAIN LOOP. */
7102 /* Instructions appear in the specification's order. */
7104 /*************************************************************************/
7107 /* documentation is in ttinterp.h */
7109 FT_EXPORT_DEF( FT_Error
)
7110 TT_RunIns( TT_ExecContext exc
)
7112 FT_Long ins_counter
= 0; /* executed instructions counter */
7115 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7119 /* set CVT functions */
7120 CUR
.tt_metrics
.ratio
= 0;
7121 if ( CUR
.metrics
.x_ppem
!= CUR
.metrics
.y_ppem
)
7123 /* non-square pixels, use the stretched routines */
7124 CUR
.func_read_cvt
= Read_CVT_Stretched
;
7125 CUR
.func_write_cvt
= Write_CVT_Stretched
;
7126 CUR
.func_move_cvt
= Move_CVT_Stretched
;
7130 /* square pixels, use normal routines */
7131 CUR
.func_read_cvt
= Read_CVT
;
7132 CUR
.func_write_cvt
= Write_CVT
;
7133 CUR
.func_move_cvt
= Move_CVT
;
7137 COMPUTE_Round( (FT_Byte
)exc
->GS
.round_state
);
7141 CUR
.opcode
= CUR
.code
[CUR
.IP
];
7143 if ( ( CUR
.length
= opcode_length
[CUR
.opcode
] ) < 0 )
7145 if ( CUR
.IP
+ 1 > CUR
.codeSize
)
7146 goto LErrorCodeOverflow_
;
7148 CUR
.length
= 2 - CUR
.length
* CUR
.code
[CUR
.IP
+ 1];
7151 if ( CUR
.IP
+ CUR
.length
> CUR
.codeSize
)
7152 goto LErrorCodeOverflow_
;
7154 /* First, let's check for empty stack and overflow */
7155 CUR
.args
= CUR
.top
- ( Pop_Push_Count
[CUR
.opcode
] >> 4 );
7157 /* `args' is the top of the stack once arguments have been popped. */
7158 /* One can also interpret it as the index of the last argument. */
7161 CUR
.error
= TT_Err_Too_Few_Arguments
;
7165 CUR
.new_top
= CUR
.args
+ ( Pop_Push_Count
[CUR
.opcode
] & 15 );
7167 /* `new_top' is the new top of the stack, after the instruction's */
7168 /* execution. `top' will be set to `new_top' after the `switch' */
7170 if ( CUR
.new_top
> CUR
.stackSize
)
7172 CUR
.error
= TT_Err_Stack_Overflow
;
7176 CUR
.step_ins
= TRUE
;
7177 CUR
.error
= TT_Err_Ok
;
7179 #ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
7182 FT_Long
* args
= CUR
.stack
+ CUR
.args
;
7183 FT_Byte opcode
= CUR
.opcode
;
7186 #undef ARRAY_BOUND_ERROR
7187 #define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
7192 case 0x00: /* SVTCA y */
7193 case 0x01: /* SVTCA x */
7194 case 0x02: /* SPvTCA y */
7195 case 0x03: /* SPvTCA x */
7196 case 0x04: /* SFvTCA y */
7197 case 0x05: /* SFvTCA x */
7202 AA
= (FT_Short
)( ( opcode
& 1 ) << 14 );
7203 BB
= (FT_Short
)( AA
^ 0x4000 );
7207 CUR
.GS
.projVector
.x
= AA
;
7208 CUR
.GS
.projVector
.y
= BB
;
7210 CUR
.GS
.dualVector
.x
= AA
;
7211 CUR
.GS
.dualVector
.y
= BB
;
7215 GUESS_VECTOR( projVector
);
7218 if ( ( opcode
& 2 ) == 0 )
7220 CUR
.GS
.freeVector
.x
= AA
;
7221 CUR
.GS
.freeVector
.y
= BB
;
7225 GUESS_VECTOR( freeVector
);
7232 case 0x06: /* SPvTL // */
7233 case 0x07: /* SPvTL + */
7237 case 0x08: /* SFvTL // */
7238 case 0x09: /* SFvTL + */
7242 case 0x0A: /* SPvFS */
7246 case 0x0B: /* SFvFS */
7250 case 0x0C: /* GPV */
7254 case 0x0D: /* GFV */
7258 case 0x0E: /* SFvTPv */
7262 case 0x0F: /* ISECT */
7263 Ins_ISECT( EXEC_ARG_ args
);
7266 case 0x10: /* SRP0 */
7270 case 0x11: /* SRP1 */
7274 case 0x12: /* SRP2 */
7278 case 0x13: /* SZP0 */
7279 Ins_SZP0( EXEC_ARG_ args
);
7282 case 0x14: /* SZP1 */
7283 Ins_SZP1( EXEC_ARG_ args
);
7286 case 0x15: /* SZP2 */
7287 Ins_SZP2( EXEC_ARG_ args
);
7290 case 0x16: /* SZPS */
7291 Ins_SZPS( EXEC_ARG_ args
);
7294 case 0x17: /* SLOOP */
7298 case 0x18: /* RTG */
7302 case 0x19: /* RTHG */
7306 case 0x1A: /* SMD */
7310 case 0x1B: /* ELSE */
7311 Ins_ELSE( EXEC_ARG_ args
);
7314 case 0x1C: /* JMPR */
7318 case 0x1D: /* SCVTCI */
7322 case 0x1E: /* SSWCI */
7326 case 0x1F: /* SSW */
7330 case 0x20: /* DUP */
7334 case 0x21: /* POP */
7338 case 0x22: /* CLEAR */
7342 case 0x23: /* SWAP */
7346 case 0x24: /* DEPTH */
7350 case 0x25: /* CINDEX */
7354 case 0x26: /* MINDEX */
7355 Ins_MINDEX( EXEC_ARG_ args
);
7358 case 0x27: /* ALIGNPTS */
7359 Ins_ALIGNPTS( EXEC_ARG_ args
);
7362 case 0x28: /* ???? */
7363 Ins_UNKNOWN( EXEC_ARG_ args
);
7366 case 0x29: /* UTP */
7367 Ins_UTP( EXEC_ARG_ args
);
7370 case 0x2A: /* LOOPCALL */
7371 Ins_LOOPCALL( EXEC_ARG_ args
);
7374 case 0x2B: /* CALL */
7375 Ins_CALL( EXEC_ARG_ args
);
7378 case 0x2C: /* FDEF */
7379 Ins_FDEF( EXEC_ARG_ args
);
7382 case 0x2D: /* ENDF */
7383 Ins_ENDF( EXEC_ARG_ args
);
7386 case 0x2E: /* MDAP */
7387 case 0x2F: /* MDAP */
7388 Ins_MDAP( EXEC_ARG_ args
);
7392 case 0x30: /* IUP */
7393 case 0x31: /* IUP */
7394 Ins_IUP( EXEC_ARG_ args
);
7397 case 0x32: /* SHP */
7398 case 0x33: /* SHP */
7399 Ins_SHP( EXEC_ARG_ args
);
7402 case 0x34: /* SHC */
7403 case 0x35: /* SHC */
7404 Ins_SHC( EXEC_ARG_ args
);
7407 case 0x36: /* SHZ */
7408 case 0x37: /* SHZ */
7409 Ins_SHZ( EXEC_ARG_ args
);
7412 case 0x38: /* SHPIX */
7413 Ins_SHPIX( EXEC_ARG_ args
);
7417 Ins_IP( EXEC_ARG_ args
);
7420 case 0x3A: /* MSIRP */
7421 case 0x3B: /* MSIRP */
7422 Ins_MSIRP( EXEC_ARG_ args
);
7425 case 0x3C: /* AlignRP */
7426 Ins_ALIGNRP( EXEC_ARG_ args
);
7429 case 0x3D: /* RTDG */
7433 case 0x3E: /* MIAP */
7434 case 0x3F: /* MIAP */
7435 Ins_MIAP( EXEC_ARG_ args
);
7438 case 0x40: /* NPUSHB */
7439 Ins_NPUSHB( EXEC_ARG_ args
);
7442 case 0x41: /* NPUSHW */
7443 Ins_NPUSHW( EXEC_ARG_ args
);
7451 CUR
.error
= TT_Err_Invalid_Reference
;
7458 case 0x44: /* WCVTP */
7462 case 0x45: /* RCVT */
7468 Ins_GC( EXEC_ARG_ args
);
7471 case 0x48: /* SCFS */
7472 Ins_SCFS( EXEC_ARG_ args
);
7477 Ins_MD( EXEC_ARG_ args
);
7480 case 0x4B: /* MPPEM */
7484 case 0x4C: /* MPS */
7488 case 0x4D: /* FLIPON */
7492 case 0x4E: /* FLIPOFF */
7496 case 0x4F: /* DEBUG */
7504 case 0x51: /* LTEQ */
7512 case 0x53: /* GTEQ */
7520 case 0x55: /* NEQ */
7524 case 0x56: /* ODD */
7528 case 0x57: /* EVEN */
7533 Ins_IF( EXEC_ARG_ args
);
7536 case 0x59: /* EIF */
7540 case 0x5A: /* AND */
7548 case 0x5C: /* NOT */
7552 case 0x5D: /* DELTAP1 */
7553 Ins_DELTAP( EXEC_ARG_ args
);
7556 case 0x5E: /* SDB */
7560 case 0x5F: /* SDS */
7564 case 0x60: /* ADD */
7568 case 0x61: /* SUB */
7572 case 0x62: /* DIV */
7576 case 0x63: /* MUL */
7580 case 0x64: /* ABS */
7584 case 0x65: /* NEG */
7588 case 0x66: /* FLOOR */
7592 case 0x67: /* CEILING */
7596 case 0x68: /* ROUND */
7597 case 0x69: /* ROUND */
7598 case 0x6A: /* ROUND */
7599 case 0x6B: /* ROUND */
7603 case 0x6C: /* NROUND */
7604 case 0x6D: /* NROUND */
7605 case 0x6E: /* NRRUND */
7606 case 0x6F: /* NROUND */
7610 case 0x70: /* WCVTF */
7614 case 0x71: /* DELTAP2 */
7615 case 0x72: /* DELTAP3 */
7616 Ins_DELTAP( EXEC_ARG_ args
);
7619 case 0x73: /* DELTAC0 */
7620 case 0x74: /* DELTAC1 */
7621 case 0x75: /* DELTAC2 */
7622 Ins_DELTAC( EXEC_ARG_ args
);
7625 case 0x76: /* SROUND */
7629 case 0x77: /* S45Round */
7633 case 0x78: /* JROT */
7637 case 0x79: /* JROF */
7641 case 0x7A: /* ROFF */
7645 case 0x7B: /* ???? */
7646 Ins_UNKNOWN( EXEC_ARG_ args
);
7649 case 0x7C: /* RUTG */
7653 case 0x7D: /* RDTG */
7657 case 0x7E: /* SANGW */
7659 /* nothing - obsolete */
7662 case 0x80: /* FLIPPT */
7663 Ins_FLIPPT( EXEC_ARG_ args
);
7666 case 0x81: /* FLIPRGON */
7667 Ins_FLIPRGON( EXEC_ARG_ args
);
7670 case 0x82: /* FLIPRGOFF */
7671 Ins_FLIPRGOFF( EXEC_ARG_ args
);
7674 case 0x83: /* UNKNOWN */
7675 case 0x84: /* UNKNOWN */
7676 Ins_UNKNOWN( EXEC_ARG_ args
);
7679 case 0x85: /* SCANCTRL */
7680 Ins_SCANCTRL( EXEC_ARG_ args
);
7683 case 0x86: /* SDPVTL */
7684 case 0x87: /* SDPVTL */
7685 Ins_SDPVTL( EXEC_ARG_ args
);
7688 case 0x88: /* GETINFO */
7689 Ins_GETINFO( EXEC_ARG_ args
);
7692 case 0x89: /* IDEF */
7693 Ins_IDEF( EXEC_ARG_ args
);
7696 case 0x8A: /* ROLL */
7697 Ins_ROLL( EXEC_ARG_ args
);
7700 case 0x8B: /* MAX */
7704 case 0x8C: /* MIN */
7708 case 0x8D: /* SCANTYPE */
7709 Ins_SCANTYPE( EXEC_ARG_ args
);
7712 case 0x8E: /* INSTCTRL */
7713 Ins_INSTCTRL( EXEC_ARG_ args
);
7717 Ins_UNKNOWN( EXEC_ARG_ args
);
7721 if ( opcode
>= 0xE0 )
7722 Ins_MIRP( EXEC_ARG_ args
);
7723 else if ( opcode
>= 0xC0 )
7724 Ins_MDRP( EXEC_ARG_ args
);
7725 else if ( opcode
>= 0xB8 )
7726 Ins_PUSHW( EXEC_ARG_ args
);
7727 else if ( opcode
>= 0xB0 )
7728 Ins_PUSHB( EXEC_ARG_ args
);
7730 Ins_UNKNOWN( EXEC_ARG_ args
);
7737 Instruct_Dispatch
[CUR
.opcode
]( EXEC_ARG_
&CUR
.stack
[CUR
.args
] );
7739 #endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7741 if ( CUR
.error
!= TT_Err_Ok
)
7743 switch ( CUR
.error
)
7745 case TT_Err_Invalid_Opcode
: /* looking for redefined instructions */
7747 TT_DefRecord
* def
= CUR
.IDefs
;
7748 TT_DefRecord
* limit
= def
+ CUR
.numIDefs
;
7751 for ( ; def
< limit
; def
++ )
7753 if ( def
->active
&& CUR
.opcode
== (FT_Byte
)def
->opc
)
7755 TT_CallRec
* callrec
;
7758 if ( CUR
.callTop
>= CUR
.callSize
)
7760 CUR
.error
= TT_Err_Invalid_Reference
;
7764 callrec
= &CUR
.callStack
[CUR
.callTop
];
7766 callrec
->Caller_Range
= CUR
.curRange
;
7767 callrec
->Caller_IP
= CUR
.IP
+ 1;
7768 callrec
->Cur_Count
= 1;
7769 callrec
->Cur_Restart
= def
->start
;
7771 if ( INS_Goto_CodeRange( def
->range
, def
->start
) == FAILURE
)
7779 CUR
.error
= TT_Err_Invalid_Opcode
;
7783 break; /* Unreachable code warning suppression. */
7784 /* Leave to remind in case a later change the editor */
7785 /* to consider break; */
7797 CUR
.top
= CUR
.new_top
;
7800 CUR
.IP
+= CUR
.length
;
7802 /* increment instruction counter and check if we didn't */
7803 /* run this program for too long (e.g. infinite loops). */
7804 if ( ++ins_counter
> MAX_RUNNABLE_OPCODES
)
7805 return TT_Err_Execution_Too_Long
;
7808 if ( CUR
.IP
>= CUR
.codeSize
)
7810 if ( CUR
.callTop
> 0 )
7812 CUR
.error
= TT_Err_Code_Overflow
;
7818 } while ( !CUR
.instruction_trap
);
7822 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7828 LErrorCodeOverflow_
:
7829 CUR
.error
= TT_Err_Code_Overflow
;
7833 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7841 #endif /* TT_USE_BYTECODE_INTERPRETER */