1 /***************************************************************************/
5 /* TrueType bytecode interpreter (body). */
7 /* Copyright 1996-2012 */
8 /* by David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
16 /***************************************************************************/
19 /* Greg Hitchcock from Microsoft has helped a lot in resolving unclear */
20 /* issues; many thanks! */
24 #include FT_INTERNAL_DEBUG_H
25 #include FT_INTERNAL_CALC_H
26 #include FT_TRIGONOMETRY_H
34 #ifdef TT_USE_BYTECODE_INTERPRETER
38 #define xxxSPH_DEBUG_MORE_VERBOSE
41 /*************************************************************************/
43 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
44 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
45 /* messages during execution. */
48 #define FT_COMPONENT trace_ttinterp
50 /*************************************************************************/
52 /* In order to detect infinite loops in the code, we set up a counter */
53 /* within the run loop. A single stroke of interpretation is now */
54 /* limited to a maximum number of opcodes defined below. */
56 #define MAX_RUNNABLE_OPCODES 1000000L
59 /*************************************************************************/
61 /* There are two kinds of implementations: */
63 /* a. static implementation */
65 /* The current execution context is a static variable, which fields */
66 /* are accessed directly by the interpreter during execution. The */
67 /* context is named `cur'. */
69 /* This version is non-reentrant, of course. */
71 /* b. indirect implementation */
73 /* The current execution context is passed to _each_ function as its */
74 /* first argument, and each field is thus accessed indirectly. */
76 /* This version is fully re-entrant. */
78 /* The idea is that an indirect implementation may be slower to execute */
79 /* on low-end processors that are used in some systems (like 386s or */
82 /* As a consequence, the indirect implementation is now the default, as */
83 /* its performance costs can be considered negligible in our context. */
84 /* Note, however, that we kept the same source with macros because: */
86 /* - The code is kept very close in design to the Pascal code used for */
89 /* - It's much more readable that way! */
91 /* - It's still open to experimentation and tuning. */
93 /*************************************************************************/
96 #ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */
98 #define CUR (*exc) /* see ttobjs.h */
100 /*************************************************************************/
102 /* This macro is used whenever `exec' is unused in a function, to avoid */
103 /* stupid warnings from pedantic compilers. */
105 #define FT_UNUSED_EXEC FT_UNUSED( exc )
107 #else /* static implementation */
111 #define FT_UNUSED_EXEC int __dummy = __dummy
114 TT_ExecContextRec cur; /* static exec. context variable */
116 /* apparently, we have a _lot_ of direct indexing when accessing */
117 /* the static `cur', which makes the code bigger (due to all the */
118 /* four bytes addresses). */
120 #endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
123 /*************************************************************************/
125 /* The instruction argument stack. */
127 #define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */
130 /*************************************************************************/
132 /* This macro is used whenever `args' is unused in a function, to avoid */
133 /* stupid warnings from pedantic compilers. */
135 #define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args )
138 /*************************************************************************/
140 /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */
141 /* increase readability of the code. */
143 /*************************************************************************/
146 #define SKIP_Code() \
149 #define GET_ShortIns() \
150 GetShortIns( EXEC_ARG )
152 #define NORMalize( x, y, v ) \
153 Normalize( EXEC_ARG_ x, y, v )
155 #define SET_SuperRound( scale, flags ) \
156 SetSuperRound( EXEC_ARG_ scale, flags )
158 #define ROUND_None( d, c ) \
159 Round_None( EXEC_ARG_ d, c )
161 #define INS_Goto_CodeRange( range, ip ) \
162 Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
164 #define CUR_Func_move( z, p, d ) \
165 CUR.func_move( EXEC_ARG_ z, p, d )
167 #define CUR_Func_move_orig( z, p, d ) \
168 CUR.func_move_orig( EXEC_ARG_ z, p, d )
170 #define CUR_Func_round( d, c ) \
171 CUR.func_round( EXEC_ARG_ d, c )
173 #define CUR_Func_read_cvt( index ) \
174 CUR.func_read_cvt( EXEC_ARG_ index )
176 #define CUR_Func_write_cvt( index, val ) \
177 CUR.func_write_cvt( EXEC_ARG_ index, val )
179 #define CUR_Func_move_cvt( index, val ) \
180 CUR.func_move_cvt( EXEC_ARG_ index, val )
182 #define CURRENT_Ratio() \
183 Current_Ratio( EXEC_ARG )
185 #define CURRENT_Ppem() \
186 Current_Ppem( EXEC_ARG )
191 #define INS_SxVTL( a, b, c, d ) \
192 Ins_SxVTL( EXEC_ARG_ a, b, c, d )
194 #define COMPUTE_Funcs() \
195 Compute_Funcs( EXEC_ARG )
197 #define COMPUTE_Round( a ) \
198 Compute_Round( EXEC_ARG_ a )
200 #define COMPUTE_Point_Displacement( a, b, c, d ) \
201 Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
203 #define MOVE_Zp2_Point( a, b, c, t ) \
204 Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
207 #define CUR_Func_project( v1, v2 ) \
208 CUR.func_project( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
210 #define CUR_Func_dualproj( v1, v2 ) \
211 CUR.func_dualproj( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
213 #define CUR_fast_project( v ) \
214 CUR.func_project( EXEC_ARG_ (v)->x, (v)->y )
216 #define CUR_fast_dualproj( v ) \
217 CUR.func_dualproj( EXEC_ARG_ (v)->x, (v)->y )
220 /*************************************************************************/
222 /* Instruction dispatch function, as used by the interpreter. */
224 typedef void (*TInstruction_Function)( INS_ARG );
227 /*************************************************************************/
229 /* Two simple bounds-checking macros. */
231 #define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
232 #define BOUNDSL( x, n ) ( (FT_ULong)(x) >= (FT_ULong)(n) )
234 /*************************************************************************/
236 /* This macro computes (a*2^14)/b and complements TT_MulFix14. */
238 #define TT_DivFix14( a, b ) \
239 FT_DivFix( a, (b) << 2 )
248 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
249 #define GUESS_VECTOR( V ) \
250 if ( CUR.face->unpatented_hinting ) \
252 CUR.GS.V.x = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0x4000 : 0 ); \
253 CUR.GS.V.y = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0 : 0x4000 ); \
256 #define GUESS_VECTOR( V )
259 /*************************************************************************/
261 /* CODERANGE FUNCTIONS */
263 /*************************************************************************/
266 /*************************************************************************/
269 /* TT_Goto_CodeRange */
272 /* Switches to a new code range (updates the code related elements in */
273 /* `exec', and `IP'). */
276 /* range :: The new execution code range. */
278 /* IP :: The new IP in the new code range. */
281 /* exec :: The target execution context. */
284 /* FreeType error code. 0 means success. */
286 FT_LOCAL_DEF( FT_Error )
287 TT_Goto_CodeRange( TT_ExecContext exec,
291 TT_CodeRange* coderange;
294 FT_ASSERT( range >= 1 && range <= 3 );
296 coderange = &exec->codeRangeTable[range - 1];
298 FT_ASSERT( coderange->base != NULL );
300 /* NOTE: Because the last instruction of a program may be a CALL */
301 /* which will return to the first byte *after* the code */
302 /* range, we test for IP <= Size instead of IP < Size. */
304 FT_ASSERT( (FT_ULong)IP <= coderange->size );
306 exec->code = coderange->base;
307 exec->codeSize = coderange->size;
309 exec->curRange = range;
315 /*************************************************************************/
318 /* TT_Set_CodeRange */
321 /* Sets a code range. */
324 /* range :: The code range index. */
326 /* base :: The new code base. */
328 /* length :: The range size in bytes. */
331 /* exec :: The target execution context. */
334 /* FreeType error code. 0 means success. */
336 FT_LOCAL_DEF( FT_Error )
337 TT_Set_CodeRange( TT_ExecContext exec,
342 FT_ASSERT( range >= 1 && range <= 3 );
344 exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
345 exec->codeRangeTable[range - 1].size = length;
351 /*************************************************************************/
354 /* TT_Clear_CodeRange */
357 /* Clears a code range. */
360 /* range :: The code range index. */
363 /* exec :: The target execution context. */
366 /* FreeType error code. 0 means success. */
369 /* Does not set the Error variable. */
371 FT_LOCAL_DEF( FT_Error )
372 TT_Clear_CodeRange( TT_ExecContext exec,
375 FT_ASSERT( range >= 1 && range <= 3 );
377 exec->codeRangeTable[range - 1].base = NULL;
378 exec->codeRangeTable[range - 1].size = 0;
384 /*************************************************************************/
386 /* EXECUTION CONTEXT ROUTINES */
388 /*************************************************************************/
391 /*************************************************************************/
394 /* TT_Done_Context */
397 /* Destroys a given context. */
400 /* exec :: A handle to the target execution context. */
402 /* memory :: A handle to the parent memory object. */
405 /* FreeType error code. 0 means success. */
408 /* Only the glyph loader and debugger should call this function. */
410 FT_LOCAL_DEF( FT_Error )
411 TT_Done_Context( TT_ExecContext exec )
413 FT_Memory memory = exec->memory;
418 exec->maxContours = 0;
421 FT_FREE( exec->stack );
424 /* free call stack */
425 FT_FREE( exec->callStack );
429 /* free glyph code range */
430 FT_FREE( exec->glyphIns );
442 /*************************************************************************/
448 /* Initializes a context object. */
451 /* memory :: A handle to the parent memory object. */
454 /* exec :: A handle to the target execution context. */
457 /* FreeType error code. 0 means success. */
460 Init_Context( TT_ExecContext exec,
466 FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec ));
468 exec->memory = memory;
471 if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )
474 /* all values in the context are set to 0 already, but this is */
475 /* here as a remainder */
477 exec->maxContours = 0;
483 exec->glyphIns = NULL;
491 FT_ERROR(( "Init_Context: not enough memory for %p\n", exec ));
492 TT_Done_Context( exec );
498 /*************************************************************************/
504 /* Checks the size of a buffer and reallocates it if necessary. */
507 /* memory :: A handle to the parent memory object. */
509 /* multiplier :: The size in bytes of each element in the buffer. */
511 /* new_max :: The new capacity (size) of the buffer. */
514 /* size :: The address of the buffer's current size expressed */
517 /* buff :: The address of the buffer base pointer. */
520 /* FreeType error code. 0 means success. */
522 FT_LOCAL_DEF( FT_Error )
523 Update_Max( FT_Memory memory,
530 void** pbuff = (void**)_pbuff;
533 if ( *size < new_max )
535 if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )
544 /*************************************************************************/
547 /* TT_Load_Context */
550 /* Prepare an execution context for glyph hinting. */
553 /* face :: A handle to the source face object. */
555 /* size :: A handle to the source size object. */
558 /* exec :: A handle to the target execution context. */
561 /* FreeType error code. 0 means success. */
564 /* Only the glyph loader and debugger should call this function. */
566 FT_LOCAL_DEF( FT_Error )
567 TT_Load_Context( TT_ExecContext exec,
578 maxp = &face->max_profile;
583 exec->numFDefs = size->num_function_defs;
584 exec->maxFDefs = size->max_function_defs;
585 exec->numIDefs = size->num_instruction_defs;
586 exec->maxIDefs = size->max_instruction_defs;
587 exec->FDefs = size->function_defs;
588 exec->IDefs = size->instruction_defs;
589 exec->tt_metrics = size->ttmetrics;
590 exec->metrics = size->metrics;
592 exec->maxFunc = size->max_func;
593 exec->maxIns = size->max_ins;
595 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
596 exec->codeRangeTable[i] = size->codeRangeTable[i];
598 /* set graphics state */
601 exec->cvtSize = size->cvt_size;
602 exec->cvt = size->cvt;
604 exec->storeSize = size->storage_size;
605 exec->storage = size->storage;
607 exec->twilight = size->twilight;
609 /* In case of multi-threading it can happen that the old size object */
610 /* no longer exists, thus we must clear all glyph zone references. */
611 ft_memset( &exec->zp0, 0, sizeof ( exec->zp0 ) );
612 exec->zp1 = exec->zp0;
613 exec->zp2 = exec->zp0;
616 /* XXX: We reserve a little more elements on the stack to deal safely */
617 /* with broken fonts like arialbs, courbs, timesbs, etc. */
618 tmp = exec->stackSize;
619 error = Update_Max( exec->memory,
621 sizeof ( FT_F26Dot6 ),
623 maxp->maxStackElements + 32 );
624 exec->stackSize = (FT_UInt)tmp;
628 tmp = exec->glyphSize;
629 error = Update_Max( exec->memory,
632 (void*)&exec->glyphIns,
633 maxp->maxSizeOfInstructions );
634 exec->glyphSize = (FT_UShort)tmp;
638 exec->pts.n_points = 0;
639 exec->pts.n_contours = 0;
641 exec->zp1 = exec->pts;
642 exec->zp2 = exec->pts;
643 exec->zp0 = exec->pts;
645 exec->instruction_trap = FALSE;
651 /*************************************************************************/
654 /* TT_Save_Context */
657 /* Saves the code ranges in a `size' object. */
660 /* exec :: A handle to the source execution context. */
663 /* size :: A handle to the target size object. */
666 /* FreeType error code. 0 means success. */
669 /* Only the glyph loader and debugger should call this function. */
671 FT_LOCAL_DEF( FT_Error )
672 TT_Save_Context( TT_ExecContext exec,
678 /* XXX: Will probably disappear soon with all the code range */
679 /* management, which is now rather obsolete. */
681 size->num_function_defs = exec->numFDefs;
682 size->num_instruction_defs = exec->numIDefs;
684 size->max_func = exec->maxFunc;
685 size->max_ins = exec->maxIns;
687 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
688 size->codeRangeTable[i] = exec->codeRangeTable[i];
694 /*************************************************************************/
700 /* Executes one or more instructions in the execution context. */
703 /* debug :: A Boolean flag. If set, the function sets some internal */
704 /* variables and returns immediately, otherwise TT_RunIns() */
707 /* This is commented out currently. */
710 /* exec :: A handle to the target execution context. */
713 /* TrueType error code. 0 means success. */
716 /* Only the glyph loader and debugger should call this function. */
718 FT_LOCAL_DEF( FT_Error )
719 TT_Run_Context( TT_ExecContext exec,
725 if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) )
729 exec->zp0 = exec->pts;
730 exec->zp1 = exec->pts;
731 exec->zp2 = exec->pts;
737 exec->GS.projVector.x = 0x4000;
738 exec->GS.projVector.y = 0x0000;
740 exec->GS.freeVector = exec->GS.projVector;
741 exec->GS.dualVector = exec->GS.projVector;
743 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
744 exec->GS.both_x_axis = TRUE;
747 exec->GS.round_state = 1;
750 /* some glyphs leave something on the stack. so we clean it */
751 /* before a new execution. */
758 return exec->face->interpreter( exec );
761 return TT_RunIns( exec );
768 /* The default value for `scan_control' is documented as FALSE in the */
769 /* TrueType specification. This is confusing since it implies a */
770 /* Boolean value. However, this is not the case, thus both the */
771 /* default values of our `scan_type' and `scan_control' fields (which */
772 /* the documentation's `scan_control' variable is split into) are */
775 const TT_GraphicsState tt_default_graphics_state =
782 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
787 TRUE, 68, 0, 0, 9, 3,
792 /* documentation is in ttinterp.h */
794 FT_EXPORT_DEF( TT_ExecContext )
795 TT_New_Context( TT_Driver driver )
801 memory = driver->root.root.memory;
802 exec = driver->context;
804 if ( !driver->context )
809 /* allocate object */
810 if ( FT_NEW( exec ) )
813 /* initialize it; in case of error this deallocates `exec' too */
814 error = Init_Context( exec, memory );
818 /* store it into the driver */
819 driver->context = exec;
822 return driver->context;
829 /*************************************************************************/
831 /* Before an opcode is executed, the interpreter verifies that there are */
832 /* enough arguments on the stack, with the help of the `Pop_Push_Count' */
835 /* For each opcode, the first column gives the number of arguments that */
836 /* are popped from the stack; the second one gives the number of those */
837 /* that are pushed in result. */
839 /* Opcodes which have a varying number of parameters in the data stream */
840 /* (NPUSHB, NPUSHW) are handled specially; they have a negative value in */
841 /* the `opcode_length' table, and the value in `Pop_Push_Count' is set */
844 /*************************************************************************/
848 #define PACK( x, y ) ( ( x << 4 ) | y )
852 const FT_Byte Pop_Push_Count[256] =
854 /* opcodes are gathered in groups of 16 */
855 /* please keep the spaces as they are */
857 /* SVTCA y */ PACK( 0, 0 ),
858 /* SVTCA x */ PACK( 0, 0 ),
859 /* SPvTCA y */ PACK( 0, 0 ),
860 /* SPvTCA x */ PACK( 0, 0 ),
861 /* SFvTCA y */ PACK( 0, 0 ),
862 /* SFvTCA x */ PACK( 0, 0 ),
863 /* SPvTL // */ PACK( 2, 0 ),
864 /* SPvTL + */ PACK( 2, 0 ),
865 /* SFvTL // */ PACK( 2, 0 ),
866 /* SFvTL + */ PACK( 2, 0 ),
867 /* SPvFS */ PACK( 2, 0 ),
868 /* SFvFS */ PACK( 2, 0 ),
869 /* GPV */ PACK( 0, 2 ),
870 /* GFV */ PACK( 0, 2 ),
871 /* SFvTPv */ PACK( 0, 0 ),
872 /* ISECT */ PACK( 5, 0 ),
874 /* SRP0 */ PACK( 1, 0 ),
875 /* SRP1 */ PACK( 1, 0 ),
876 /* SRP2 */ PACK( 1, 0 ),
877 /* SZP0 */ PACK( 1, 0 ),
878 /* SZP1 */ PACK( 1, 0 ),
879 /* SZP2 */ PACK( 1, 0 ),
880 /* SZPS */ PACK( 1, 0 ),
881 /* SLOOP */ PACK( 1, 0 ),
882 /* RTG */ PACK( 0, 0 ),
883 /* RTHG */ PACK( 0, 0 ),
884 /* SMD */ PACK( 1, 0 ),
885 /* ELSE */ PACK( 0, 0 ),
886 /* JMPR */ PACK( 1, 0 ),
887 /* SCvTCi */ PACK( 1, 0 ),
888 /* SSwCi */ PACK( 1, 0 ),
889 /* SSW */ PACK( 1, 0 ),
891 /* DUP */ PACK( 1, 2 ),
892 /* POP */ PACK( 1, 0 ),
893 /* CLEAR */ PACK( 0, 0 ),
894 /* SWAP */ PACK( 2, 2 ),
895 /* DEPTH */ PACK( 0, 1 ),
896 /* CINDEX */ PACK( 1, 1 ),
897 /* MINDEX */ PACK( 1, 0 ),
898 /* AlignPTS */ PACK( 2, 0 ),
899 /* INS_$28 */ PACK( 0, 0 ),
900 /* UTP */ PACK( 1, 0 ),
901 /* LOOPCALL */ PACK( 2, 0 ),
902 /* CALL */ PACK( 1, 0 ),
903 /* FDEF */ PACK( 1, 0 ),
904 /* ENDF */ PACK( 0, 0 ),
905 /* MDAP[0] */ PACK( 1, 0 ),
906 /* MDAP[1] */ PACK( 1, 0 ),
908 /* IUP[0] */ PACK( 0, 0 ),
909 /* IUP[1] */ PACK( 0, 0 ),
910 /* SHP[0] */ PACK( 0, 0 ),
911 /* SHP[1] */ PACK( 0, 0 ),
912 /* SHC[0] */ PACK( 1, 0 ),
913 /* SHC[1] */ PACK( 1, 0 ),
914 /* SHZ[0] */ PACK( 1, 0 ),
915 /* SHZ[1] */ PACK( 1, 0 ),
916 /* SHPIX */ PACK( 1, 0 ),
917 /* IP */ PACK( 0, 0 ),
918 /* MSIRP[0] */ PACK( 2, 0 ),
919 /* MSIRP[1] */ PACK( 2, 0 ),
920 /* AlignRP */ PACK( 0, 0 ),
921 /* RTDG */ PACK( 0, 0 ),
922 /* MIAP[0] */ PACK( 2, 0 ),
923 /* MIAP[1] */ PACK( 2, 0 ),
925 /* NPushB */ PACK( 0, 0 ),
926 /* NPushW */ PACK( 0, 0 ),
927 /* WS */ PACK( 2, 0 ),
928 /* RS */ PACK( 1, 1 ),
929 /* WCvtP */ PACK( 2, 0 ),
930 /* RCvt */ PACK( 1, 1 ),
931 /* GC[0] */ PACK( 1, 1 ),
932 /* GC[1] */ PACK( 1, 1 ),
933 /* SCFS */ PACK( 2, 0 ),
934 /* MD[0] */ PACK( 2, 1 ),
935 /* MD[1] */ PACK( 2, 1 ),
936 /* MPPEM */ PACK( 0, 1 ),
937 /* MPS */ PACK( 0, 1 ),
938 /* FlipON */ PACK( 0, 0 ),
939 /* FlipOFF */ PACK( 0, 0 ),
940 /* DEBUG */ PACK( 1, 0 ),
942 /* LT */ PACK( 2, 1 ),
943 /* LTEQ */ PACK( 2, 1 ),
944 /* GT */ PACK( 2, 1 ),
945 /* GTEQ */ PACK( 2, 1 ),
946 /* EQ */ PACK( 2, 1 ),
947 /* NEQ */ PACK( 2, 1 ),
948 /* ODD */ PACK( 1, 1 ),
949 /* EVEN */ PACK( 1, 1 ),
950 /* IF */ PACK( 1, 0 ),
951 /* EIF */ PACK( 0, 0 ),
952 /* AND */ PACK( 2, 1 ),
953 /* OR */ PACK( 2, 1 ),
954 /* NOT */ PACK( 1, 1 ),
955 /* DeltaP1 */ PACK( 1, 0 ),
956 /* SDB */ PACK( 1, 0 ),
957 /* SDS */ PACK( 1, 0 ),
959 /* ADD */ PACK( 2, 1 ),
960 /* SUB */ PACK( 2, 1 ),
961 /* DIV */ PACK( 2, 1 ),
962 /* MUL */ PACK( 2, 1 ),
963 /* ABS */ PACK( 1, 1 ),
964 /* NEG */ PACK( 1, 1 ),
965 /* FLOOR */ PACK( 1, 1 ),
966 /* CEILING */ PACK( 1, 1 ),
967 /* ROUND[0] */ PACK( 1, 1 ),
968 /* ROUND[1] */ PACK( 1, 1 ),
969 /* ROUND[2] */ PACK( 1, 1 ),
970 /* ROUND[3] */ PACK( 1, 1 ),
971 /* NROUND[0] */ PACK( 1, 1 ),
972 /* NROUND[1] */ PACK( 1, 1 ),
973 /* NROUND[2] */ PACK( 1, 1 ),
974 /* NROUND[3] */ PACK( 1, 1 ),
976 /* WCvtF */ PACK( 2, 0 ),
977 /* DeltaP2 */ PACK( 1, 0 ),
978 /* DeltaP3 */ PACK( 1, 0 ),
979 /* DeltaCn[0] */ PACK( 1, 0 ),
980 /* DeltaCn[1] */ PACK( 1, 0 ),
981 /* DeltaCn[2] */ PACK( 1, 0 ),
982 /* SROUND */ PACK( 1, 0 ),
983 /* S45Round */ PACK( 1, 0 ),
984 /* JROT */ PACK( 2, 0 ),
985 /* JROF */ PACK( 2, 0 ),
986 /* ROFF */ PACK( 0, 0 ),
987 /* INS_$7B */ PACK( 0, 0 ),
988 /* RUTG */ PACK( 0, 0 ),
989 /* RDTG */ PACK( 0, 0 ),
990 /* SANGW */ PACK( 1, 0 ),
991 /* AA */ PACK( 1, 0 ),
993 /* FlipPT */ PACK( 0, 0 ),
994 /* FlipRgON */ PACK( 2, 0 ),
995 /* FlipRgOFF */ PACK( 2, 0 ),
996 /* INS_$83 */ PACK( 0, 0 ),
997 /* INS_$84 */ PACK( 0, 0 ),
998 /* ScanCTRL */ PACK( 1, 0 ),
999 /* SDPVTL[0] */ PACK( 2, 0 ),
1000 /* SDPVTL[1] */ PACK( 2, 0 ),
1001 /* GetINFO */ PACK( 1, 1 ),
1002 /* IDEF */ PACK( 1, 0 ),
1003 /* ROLL */ PACK( 3, 3 ),
1004 /* MAX */ PACK( 2, 1 ),
1005 /* MIN */ PACK( 2, 1 ),
1006 /* ScanTYPE */ PACK( 1, 0 ),
1007 /* InstCTRL */ PACK( 2, 0 ),
1008 /* INS_$8F */ PACK( 0, 0 ),
1010 /* INS_$90 */ PACK( 0, 0 ),
1011 /* INS_$91 */ PACK( 0, 0 ),
1012 /* INS_$92 */ PACK( 0, 0 ),
1013 /* INS_$93 */ PACK( 0, 0 ),
1014 /* INS_$94 */ PACK( 0, 0 ),
1015 /* INS_$95 */ PACK( 0, 0 ),
1016 /* INS_$96 */ PACK( 0, 0 ),
1017 /* INS_$97 */ PACK( 0, 0 ),
1018 /* INS_$98 */ PACK( 0, 0 ),
1019 /* INS_$99 */ PACK( 0, 0 ),
1020 /* INS_$9A */ PACK( 0, 0 ),
1021 /* INS_$9B */ PACK( 0, 0 ),
1022 /* INS_$9C */ PACK( 0, 0 ),
1023 /* INS_$9D */ PACK( 0, 0 ),
1024 /* INS_$9E */ PACK( 0, 0 ),
1025 /* INS_$9F */ PACK( 0, 0 ),
1027 /* INS_$A0 */ PACK( 0, 0 ),
1028 /* INS_$A1 */ PACK( 0, 0 ),
1029 /* INS_$A2 */ PACK( 0, 0 ),
1030 /* INS_$A3 */ PACK( 0, 0 ),
1031 /* INS_$A4 */ PACK( 0, 0 ),
1032 /* INS_$A5 */ PACK( 0, 0 ),
1033 /* INS_$A6 */ PACK( 0, 0 ),
1034 /* INS_$A7 */ PACK( 0, 0 ),
1035 /* INS_$A8 */ PACK( 0, 0 ),
1036 /* INS_$A9 */ PACK( 0, 0 ),
1037 /* INS_$AA */ PACK( 0, 0 ),
1038 /* INS_$AB */ PACK( 0, 0 ),
1039 /* INS_$AC */ PACK( 0, 0 ),
1040 /* INS_$AD */ PACK( 0, 0 ),
1041 /* INS_$AE */ PACK( 0, 0 ),
1042 /* INS_$AF */ PACK( 0, 0 ),
1044 /* PushB[0] */ PACK( 0, 1 ),
1045 /* PushB[1] */ PACK( 0, 2 ),
1046 /* PushB[2] */ PACK( 0, 3 ),
1047 /* PushB[3] */ PACK( 0, 4 ),
1048 /* PushB[4] */ PACK( 0, 5 ),
1049 /* PushB[5] */ PACK( 0, 6 ),
1050 /* PushB[6] */ PACK( 0, 7 ),
1051 /* PushB[7] */ PACK( 0, 8 ),
1052 /* PushW[0] */ PACK( 0, 1 ),
1053 /* PushW[1] */ PACK( 0, 2 ),
1054 /* PushW[2] */ PACK( 0, 3 ),
1055 /* PushW[3] */ PACK( 0, 4 ),
1056 /* PushW[4] */ PACK( 0, 5 ),
1057 /* PushW[5] */ PACK( 0, 6 ),
1058 /* PushW[6] */ PACK( 0, 7 ),
1059 /* PushW[7] */ PACK( 0, 8 ),
1061 /* MDRP[00] */ PACK( 1, 0 ),
1062 /* MDRP[01] */ PACK( 1, 0 ),
1063 /* MDRP[02] */ PACK( 1, 0 ),
1064 /* MDRP[03] */ PACK( 1, 0 ),
1065 /* MDRP[04] */ PACK( 1, 0 ),
1066 /* MDRP[05] */ PACK( 1, 0 ),
1067 /* MDRP[06] */ PACK( 1, 0 ),
1068 /* MDRP[07] */ PACK( 1, 0 ),
1069 /* MDRP[08] */ PACK( 1, 0 ),
1070 /* MDRP[09] */ PACK( 1, 0 ),
1071 /* MDRP[10] */ PACK( 1, 0 ),
1072 /* MDRP[11] */ PACK( 1, 0 ),
1073 /* MDRP[12] */ PACK( 1, 0 ),
1074 /* MDRP[13] */ PACK( 1, 0 ),
1075 /* MDRP[14] */ PACK( 1, 0 ),
1076 /* MDRP[15] */ PACK( 1, 0 ),
1078 /* MDRP[16] */ PACK( 1, 0 ),
1079 /* MDRP[17] */ PACK( 1, 0 ),
1080 /* MDRP[18] */ PACK( 1, 0 ),
1081 /* MDRP[19] */ PACK( 1, 0 ),
1082 /* MDRP[20] */ PACK( 1, 0 ),
1083 /* MDRP[21] */ PACK( 1, 0 ),
1084 /* MDRP[22] */ PACK( 1, 0 ),
1085 /* MDRP[23] */ PACK( 1, 0 ),
1086 /* MDRP[24] */ PACK( 1, 0 ),
1087 /* MDRP[25] */ PACK( 1, 0 ),
1088 /* MDRP[26] */ PACK( 1, 0 ),
1089 /* MDRP[27] */ PACK( 1, 0 ),
1090 /* MDRP[28] */ PACK( 1, 0 ),
1091 /* MDRP[29] */ PACK( 1, 0 ),
1092 /* MDRP[30] */ PACK( 1, 0 ),
1093 /* MDRP[31] */ PACK( 1, 0 ),
1095 /* MIRP[00] */ PACK( 2, 0 ),
1096 /* MIRP[01] */ PACK( 2, 0 ),
1097 /* MIRP[02] */ PACK( 2, 0 ),
1098 /* MIRP[03] */ PACK( 2, 0 ),
1099 /* MIRP[04] */ PACK( 2, 0 ),
1100 /* MIRP[05] */ PACK( 2, 0 ),
1101 /* MIRP[06] */ PACK( 2, 0 ),
1102 /* MIRP[07] */ PACK( 2, 0 ),
1103 /* MIRP[08] */ PACK( 2, 0 ),
1104 /* MIRP[09] */ PACK( 2, 0 ),
1105 /* MIRP[10] */ PACK( 2, 0 ),
1106 /* MIRP[11] */ PACK( 2, 0 ),
1107 /* MIRP[12] */ PACK( 2, 0 ),
1108 /* MIRP[13] */ PACK( 2, 0 ),
1109 /* MIRP[14] */ PACK( 2, 0 ),
1110 /* MIRP[15] */ PACK( 2, 0 ),
1112 /* MIRP[16] */ PACK( 2, 0 ),
1113 /* MIRP[17] */ PACK( 2, 0 ),
1114 /* MIRP[18] */ PACK( 2, 0 ),
1115 /* MIRP[19] */ PACK( 2, 0 ),
1116 /* MIRP[20] */ PACK( 2, 0 ),
1117 /* MIRP[21] */ PACK( 2, 0 ),
1118 /* MIRP[22] */ PACK( 2, 0 ),
1119 /* MIRP[23] */ PACK( 2, 0 ),
1120 /* MIRP[24] */ PACK( 2, 0 ),
1121 /* MIRP[25] */ PACK( 2, 0 ),
1122 /* MIRP[26] */ PACK( 2, 0 ),
1123 /* MIRP[27] */ PACK( 2, 0 ),
1124 /* MIRP[28] */ PACK( 2, 0 ),
1125 /* MIRP[29] */ PACK( 2, 0 ),
1126 /* MIRP[30] */ PACK( 2, 0 ),
1127 /* MIRP[31] */ PACK( 2, 0 )
1131 #ifdef FT_DEBUG_LEVEL_TRACE
1134 const char* const opcode_name[256] =
1409 #endif /* FT_DEBUG_LEVEL_TRACE */
1413 const FT_Char opcode_length[256] =
1415 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1416 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1417 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1418 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1420 -1,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1421 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1422 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1423 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1425 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1426 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1427 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1428 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
1430 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1431 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1432 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1433 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1441 TT_MulFix14( FT_Int32 a,
1445 FT_UInt32 ah, al, mid, lo, hi;
1455 ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU );
1456 al = (FT_UInt32)( a & 0xFFFFU );
1461 mid = ( mid << 16 ) + ( 1 << 13 ); /* rounding */
1466 mid = ( lo >> 14 ) | ( hi << 18 );
1468 return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid;
1473 /* compute (a*b)/2^14 with maximum accuracy and rounding */
1475 TT_MulFix14( FT_Int32 a,
1482 /* compute ax*bx as 64-bit value */
1483 l = (FT_UInt32)( ( a & 0xFFFFU ) * b );
1484 m = ( a >> 16 ) * b;
1486 lo = l + (FT_UInt32)( m << 16 );
1487 hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l );
1489 /* divide the result by 2^14 with rounding */
1491 l = lo + (FT_UInt32)s;
1492 hi += s + ( l < lo );
1498 return ( hi << 18 ) | ( l >> 14 );
1503 /* compute (ax*bx+ay*by)/2^14 with maximum accuracy and rounding */
1505 TT_DotFix14( FT_Int32 ax,
1510 FT_Int32 m, s, hi1, hi2, hi;
1511 FT_UInt32 l, lo1, lo2, lo;
1514 /* compute ax*bx as 64-bit value */
1515 l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );
1516 m = ( ax >> 16 ) * bx;
1518 lo1 = l + (FT_UInt32)( m << 16 );
1519 hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l );
1521 /* compute ay*by as 64-bit value */
1522 l = (FT_UInt32)( ( ay & 0xFFFFU ) * by );
1523 m = ( ay >> 16 ) * by;
1525 lo2 = l + (FT_UInt32)( m << 16 );
1526 hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l );
1530 hi = hi1 + hi2 + ( lo < lo1 );
1532 /* divide the result by 2^14 with rounding */
1534 l = lo + (FT_UInt32)s;
1535 hi += s + ( l < lo );
1541 return ( hi << 18 ) | ( l >> 14 );
1545 /* return length of given vector */
1550 TT_VecLen( FT_Int32 x,
1553 FT_Int32 m, hi1, hi2, hi;
1554 FT_UInt32 l, lo1, lo2, lo;
1557 /* compute x*x as 64-bit value */
1558 lo = (FT_UInt32)( x & 0xFFFFU );
1565 lo1 = l + (FT_UInt32)( m << 17 );
1566 hi1 = hi + ( m >> 15 ) + ( lo1 < l );
1568 /* compute y*y as 64-bit value */
1569 lo = (FT_UInt32)( y & 0xFFFFU );
1576 lo2 = l + (FT_UInt32)( m << 17 );
1577 hi2 = hi + ( m >> 15 ) + ( lo2 < l );
1579 /* add them to get 'x*x+y*y' as 64-bit value */
1581 hi = hi1 + hi2 + ( lo < lo1 );
1583 /* compute the square root of this value */
1585 FT_UInt32 root, rem, test_div;
1596 rem = ( rem << 2 ) | ( (FT_UInt32)hi >> 30 );
1597 hi = ( hi << 2 ) | ( lo >> 30 );
1600 test_div = ( root << 1 ) + 1;
1602 if ( rem >= test_div )
1607 } while ( --count );
1610 return (FT_Int32)root;
1616 /* this version uses FT_Vector_Length which computes the same value */
1617 /* much, much faster.. */
1620 TT_VecLen( FT_F26Dot6 X,
1629 return FT_Vector_Length( &v );
1635 /*************************************************************************/
1641 /* Returns the current aspect ratio scaling factor depending on the */
1642 /* projection vector's state and device resolutions. */
1645 /* The aspect ratio in 16.16 format, always <= 1.0 . */
1648 Current_Ratio( EXEC_OP )
1650 if ( !CUR.tt_metrics.ratio )
1652 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1653 if ( CUR.face->unpatented_hinting )
1655 if ( CUR.GS.both_x_axis )
1656 CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
1658 CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
1663 if ( CUR.GS.projVector.y == 0 )
1664 CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
1666 else if ( CUR.GS.projVector.x == 0 )
1667 CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
1674 x = TT_MulFix14( CUR.tt_metrics.x_ratio,
1675 CUR.GS.projVector.x );
1676 y = TT_MulFix14( CUR.tt_metrics.y_ratio,
1677 CUR.GS.projVector.y );
1678 CUR.tt_metrics.ratio = TT_VecLen( x, y );
1682 return CUR.tt_metrics.ratio;
1687 Current_Ppem( EXEC_OP )
1689 return FT_MulFix( CUR.tt_metrics.ppem, CURRENT_Ratio() );
1693 /*************************************************************************/
1695 /* Functions related to the control value table (CVT). */
1697 /*************************************************************************/
1700 FT_CALLBACK_DEF( FT_F26Dot6 )
1701 Read_CVT( EXEC_OP_ FT_ULong idx )
1703 return CUR.cvt[idx];
1707 FT_CALLBACK_DEF( FT_F26Dot6 )
1708 Read_CVT_Stretched( EXEC_OP_ FT_ULong idx )
1710 return FT_MulFix( CUR.cvt[idx], CURRENT_Ratio() );
1714 FT_CALLBACK_DEF( void )
1715 Write_CVT( EXEC_OP_ FT_ULong idx,
1718 CUR.cvt[idx] = value;
1722 FT_CALLBACK_DEF( void )
1723 Write_CVT_Stretched( EXEC_OP_ FT_ULong idx,
1726 CUR.cvt[idx] = FT_DivFix( value, CURRENT_Ratio() );
1730 FT_CALLBACK_DEF( void )
1731 Move_CVT( EXEC_OP_ FT_ULong idx,
1734 CUR.cvt[idx] += value;
1738 FT_CALLBACK_DEF( void )
1739 Move_CVT_Stretched( EXEC_OP_ FT_ULong idx,
1742 CUR.cvt[idx] += FT_DivFix( value, CURRENT_Ratio() );
1746 /*************************************************************************/
1752 /* Returns a short integer taken from the instruction stream at */
1756 /* Short read at code[IP]. */
1759 /* This one could become a macro. */
1762 GetShortIns( EXEC_OP )
1764 /* Reading a byte stream so there is no endianess (DaveP) */
1766 return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) +
1767 CUR.code[CUR.IP - 1] );
1771 /*************************************************************************/
1774 /* Ins_Goto_CodeRange */
1777 /* Goes to a certain code range in the instruction stream. */
1780 /* aRange :: The index of the code range. */
1782 /* aIP :: The new IP address in the code range. */
1785 /* SUCCESS or FAILURE. */
1788 Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange,
1791 TT_CodeRange* range;
1794 if ( aRange < 1 || aRange > 3 )
1796 CUR.error = TT_Err_Bad_Argument;
1800 range = &CUR.codeRangeTable[aRange - 1];
1802 if ( range->base == NULL ) /* invalid coderange */
1804 CUR.error = TT_Err_Invalid_CodeRange;
1808 /* NOTE: Because the last instruction of a program may be a CALL */
1809 /* which will return to the first byte *after* the code */
1810 /* range, we test for aIP <= Size, instead of aIP < Size. */
1812 if ( aIP > range->size )
1814 CUR.error = TT_Err_Code_Overflow;
1818 CUR.code = range->base;
1819 CUR.codeSize = range->size;
1821 CUR.curRange = aRange;
1827 /*************************************************************************/
1833 /* Moves a point by a given distance along the freedom vector. The */
1834 /* point will be `touched'. */
1837 /* point :: The index of the point to move. */
1839 /* distance :: The distance to apply. */
1842 /* zone :: The affected glyph zone. */
1845 Direct_Move( EXEC_OP_ TT_GlyphZone zone,
1847 FT_F26Dot6 distance )
1852 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1853 FT_ASSERT( !CUR.face->unpatented_hinting );
1856 v = CUR.GS.freeVector.x;
1860 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
1861 if ( !CUR.ignore_x_mode ||
1862 ( CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) )
1863 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
1864 zone->cur[point].x += FT_MulDiv( distance, v, CUR.F_dot_P );
1866 zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
1869 v = CUR.GS.freeVector.y;
1873 zone->cur[point].y += FT_MulDiv( distance, v, CUR.F_dot_P );
1875 zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1880 /*************************************************************************/
1883 /* Direct_Move_Orig */
1886 /* Moves the *original* position of a point by a given distance along */
1887 /* the freedom vector. Obviously, the point will not be `touched'. */
1890 /* point :: The index of the point to move. */
1892 /* distance :: The distance to apply. */
1895 /* zone :: The affected glyph zone. */
1898 Direct_Move_Orig( EXEC_OP_ TT_GlyphZone zone,
1900 FT_F26Dot6 distance )
1905 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1906 FT_ASSERT( !CUR.face->unpatented_hinting );
1909 v = CUR.GS.freeVector.x;
1912 zone->org[point].x += FT_MulDiv( distance, v, CUR.F_dot_P );
1914 v = CUR.GS.freeVector.y;
1917 zone->org[point].y += FT_MulDiv( distance, v, CUR.F_dot_P );
1921 /*************************************************************************/
1923 /* Special versions of Direct_Move() */
1925 /* The following versions are used whenever both vectors are both */
1926 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1928 /*************************************************************************/
1932 Direct_Move_X( EXEC_OP_ TT_GlyphZone zone,
1934 FT_F26Dot6 distance )
1938 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
1939 if ( !CUR.ignore_x_mode ||
1940 ( CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVEX ) )
1941 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
1942 zone->cur[point].x += distance;
1943 zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
1948 Direct_Move_Y( EXEC_OP_ TT_GlyphZone zone,
1950 FT_F26Dot6 distance )
1954 zone->cur[point].y += distance;
1955 zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1959 /*************************************************************************/
1961 /* Special versions of Direct_Move_Orig() */
1963 /* The following versions are used whenever both vectors are both */
1964 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1966 /*************************************************************************/
1970 Direct_Move_Orig_X( EXEC_OP_ TT_GlyphZone zone,
1972 FT_F26Dot6 distance )
1976 zone->org[point].x += distance;
1981 Direct_Move_Orig_Y( EXEC_OP_ TT_GlyphZone zone,
1983 FT_F26Dot6 distance )
1987 zone->org[point].y += distance;
1991 /*************************************************************************/
1997 /* Does not round, but adds engine compensation. */
2000 /* distance :: The distance (not) to round. */
2002 /* compensation :: The engine compensation. */
2005 /* The compensated distance. */
2008 /* The TrueType specification says very few about the relationship */
2009 /* between rounding and engine compensation. However, it seems from */
2010 /* the description of super round that we should add the compensation */
2011 /* before rounding. */
2014 Round_None( EXEC_OP_ FT_F26Dot6 distance,
2015 FT_F26Dot6 compensation )
2022 if ( distance >= 0 )
2024 val = distance + compensation;
2025 if ( distance && val < 0 )
2030 val = distance - compensation;
2038 /*************************************************************************/
2044 /* Rounds value to grid after adding engine compensation. */
2047 /* distance :: The distance to round. */
2049 /* compensation :: The engine compensation. */
2052 /* Rounded distance. */
2055 Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
2056 FT_F26Dot6 compensation )
2063 if ( distance >= 0 )
2065 val = distance + compensation + 32;
2066 if ( distance && val > 0 )
2073 val = -FT_PIX_ROUND( compensation - distance );
2082 /*************************************************************************/
2085 /* Round_To_Half_Grid */
2088 /* Rounds value to half grid after adding engine compensation. */
2091 /* distance :: The distance to round. */
2093 /* compensation :: The engine compensation. */
2096 /* Rounded distance. */
2099 Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance,
2100 FT_F26Dot6 compensation )
2107 if ( distance >= 0 )
2109 val = FT_PIX_FLOOR( distance + compensation ) + 32;
2110 if ( distance && val < 0 )
2115 val = -( FT_PIX_FLOOR( compensation - distance ) + 32 );
2124 /*************************************************************************/
2127 /* Round_Down_To_Grid */
2130 /* Rounds value down to grid after adding engine compensation. */
2133 /* distance :: The distance to round. */
2135 /* compensation :: The engine compensation. */
2138 /* Rounded distance. */
2141 Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
2142 FT_F26Dot6 compensation )
2149 if ( distance >= 0 )
2151 val = distance + compensation;
2152 if ( distance && val > 0 )
2159 val = -( ( compensation - distance ) & -64 );
2168 /*************************************************************************/
2171 /* Round_Up_To_Grid */
2174 /* Rounds value up to grid after adding engine compensation. */
2177 /* distance :: The distance to round. */
2179 /* compensation :: The engine compensation. */
2182 /* Rounded distance. */
2185 Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
2186 FT_F26Dot6 compensation )
2193 if ( distance >= 0 )
2195 val = distance + compensation + 63;
2196 if ( distance && val > 0 )
2203 val = -FT_PIX_CEIL( compensation - distance );
2212 /*************************************************************************/
2215 /* Round_To_Double_Grid */
2218 /* Rounds value to double grid after adding engine compensation. */
2221 /* distance :: The distance to round. */
2223 /* compensation :: The engine compensation. */
2226 /* Rounded distance. */
2229 Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance,
2230 FT_F26Dot6 compensation )
2237 if ( distance >= 0 )
2239 val = distance + compensation + 16;
2240 if ( distance && val > 0 )
2247 val = -FT_PAD_ROUND( compensation - distance, 32 );
2256 /*************************************************************************/
2262 /* Super-rounds value to grid after adding engine compensation. */
2265 /* distance :: The distance to round. */
2267 /* compensation :: The engine compensation. */
2270 /* Rounded distance. */
2273 /* The TrueType specification says very few about the relationship */
2274 /* between rounding and engine compensation. However, it seems from */
2275 /* the description of super round that we should add the compensation */
2276 /* before rounding. */
2279 Round_Super( EXEC_OP_ FT_F26Dot6 distance,
2280 FT_F26Dot6 compensation )
2285 if ( distance >= 0 )
2287 val = ( distance - CUR.phase + CUR.threshold + compensation ) &
2289 if ( distance && val < 0 )
2295 val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &
2306 /*************************************************************************/
2309 /* Round_Super_45 */
2312 /* Super-rounds value to grid after adding engine compensation. */
2315 /* distance :: The distance to round. */
2317 /* compensation :: The engine compensation. */
2320 /* Rounded distance. */
2323 /* There is a separate function for Round_Super_45() as we may need */
2324 /* greater precision. */
2327 Round_Super_45( EXEC_OP_ FT_F26Dot6 distance,
2328 FT_F26Dot6 compensation )
2333 if ( distance >= 0 )
2335 val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
2336 CUR.period ) * CUR.period;
2337 if ( distance && val < 0 )
2343 val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /
2344 CUR.period ) * CUR.period );
2354 /*************************************************************************/
2360 /* Sets the rounding mode. */
2363 /* round_mode :: The rounding mode to be used. */
2366 Compute_Round( EXEC_OP_ FT_Byte round_mode )
2368 switch ( round_mode )
2371 CUR.func_round = (TT_Round_Func)Round_None;
2374 case TT_Round_To_Grid:
2375 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2378 case TT_Round_Up_To_Grid:
2379 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2382 case TT_Round_Down_To_Grid:
2383 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2386 case TT_Round_To_Half_Grid:
2387 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2390 case TT_Round_To_Double_Grid:
2391 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2394 case TT_Round_Super:
2395 CUR.func_round = (TT_Round_Func)Round_Super;
2398 case TT_Round_Super_45:
2399 CUR.func_round = (TT_Round_Func)Round_Super_45;
2405 /*************************************************************************/
2411 /* Sets Super Round parameters. */
2414 /* GridPeriod :: The grid period. */
2416 /* selector :: The SROUND opcode. */
2419 SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod,
2422 switch ( (FT_Int)( selector & 0xC0 ) )
2425 CUR.period = GridPeriod / 2;
2429 CUR.period = GridPeriod;
2433 CUR.period = GridPeriod * 2;
2436 /* This opcode is reserved, but... */
2439 CUR.period = GridPeriod;
2443 switch ( (FT_Int)( selector & 0x30 ) )
2450 CUR.phase = CUR.period / 4;
2454 CUR.phase = CUR.period / 2;
2458 CUR.phase = CUR.period * 3 / 4;
2462 if ( ( selector & 0x0F ) == 0 )
2463 CUR.threshold = CUR.period - 1;
2465 CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8;
2469 CUR.threshold /= 256;
2473 /*************************************************************************/
2479 /* Computes the projection of vector given by (v2-v1) along the */
2480 /* current projection vector. */
2483 /* v1 :: First input vector. */
2484 /* v2 :: Second input vector. */
2487 /* The distance in F26dot6 format. */
2490 Project( EXEC_OP_ FT_Pos dx,
2493 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2494 FT_ASSERT( !CUR.face->unpatented_hinting );
2497 return TT_DotFix14( (FT_UInt32)dx, (FT_UInt32)dy,
2498 CUR.GS.projVector.x,
2499 CUR.GS.projVector.y );
2503 /*************************************************************************/
2509 /* Computes the projection of the vector given by (v2-v1) along the */
2510 /* current dual vector. */
2513 /* v1 :: First input vector. */
2514 /* v2 :: Second input vector. */
2517 /* The distance in F26dot6 format. */
2520 Dual_Project( EXEC_OP_ FT_Pos dx,
2523 return TT_DotFix14( (FT_UInt32)dx, (FT_UInt32)dy,
2524 CUR.GS.dualVector.x,
2525 CUR.GS.dualVector.y );
2529 /*************************************************************************/
2535 /* Computes the projection of the vector given by (v2-v1) along the */
2536 /* horizontal axis. */
2539 /* v1 :: First input vector. */
2540 /* v2 :: Second input vector. */
2543 /* The distance in F26dot6 format. */
2546 Project_x( EXEC_OP_ FT_Pos dx,
2556 /*************************************************************************/
2562 /* Computes the projection of the vector given by (v2-v1) along the */
2563 /* vertical axis. */
2566 /* v1 :: First input vector. */
2567 /* v2 :: Second input vector. */
2570 /* The distance in F26dot6 format. */
2573 Project_y( EXEC_OP_ FT_Pos dx,
2583 /*************************************************************************/
2589 /* Computes the projection and movement function pointers according */
2590 /* to the current graphics state. */
2593 Compute_Funcs( EXEC_OP )
2595 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2596 if ( CUR.face->unpatented_hinting )
2598 /* If both vectors point rightwards along the x axis, set */
2599 /* `both-x-axis' true, otherwise set it false. The x values only */
2600 /* need be tested because the vector has been normalised to a unit */
2601 /* vector of length 0x4000 = unity. */
2602 CUR.GS.both_x_axis = (FT_Bool)( CUR.GS.projVector.x == 0x4000 &&
2603 CUR.GS.freeVector.x == 0x4000 );
2605 /* Throw away projection and freedom vector information */
2606 /* because the patents don't allow them to be stored. */
2607 /* The relevant US Patents are 5155805 and 5325479. */
2608 CUR.GS.projVector.x = 0;
2609 CUR.GS.projVector.y = 0;
2610 CUR.GS.freeVector.x = 0;
2611 CUR.GS.freeVector.y = 0;
2613 if ( CUR.GS.both_x_axis )
2615 CUR.func_project = Project_x;
2616 CUR.func_move = Direct_Move_X;
2617 CUR.func_move_orig = Direct_Move_Orig_X;
2621 CUR.func_project = Project_y;
2622 CUR.func_move = Direct_Move_Y;
2623 CUR.func_move_orig = Direct_Move_Orig_Y;
2626 if ( CUR.GS.dualVector.x == 0x4000 )
2627 CUR.func_dualproj = Project_x;
2628 else if ( CUR.GS.dualVector.y == 0x4000 )
2629 CUR.func_dualproj = Project_y;
2631 CUR.func_dualproj = Dual_Project;
2633 /* Force recalculation of cached aspect ratio */
2634 CUR.tt_metrics.ratio = 0;
2638 #endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING */
2640 if ( CUR.GS.freeVector.x == 0x4000 )
2641 CUR.F_dot_P = CUR.GS.projVector.x;
2642 else if ( CUR.GS.freeVector.y == 0x4000 )
2643 CUR.F_dot_P = CUR.GS.projVector.y;
2645 CUR.F_dot_P = ( (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x +
2646 (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y ) >>
2649 if ( CUR.GS.projVector.x == 0x4000 )
2650 CUR.func_project = (TT_Project_Func)Project_x;
2651 else if ( CUR.GS.projVector.y == 0x4000 )
2652 CUR.func_project = (TT_Project_Func)Project_y;
2654 CUR.func_project = (TT_Project_Func)Project;
2656 if ( CUR.GS.dualVector.x == 0x4000 )
2657 CUR.func_dualproj = (TT_Project_Func)Project_x;
2658 else if ( CUR.GS.dualVector.y == 0x4000 )
2659 CUR.func_dualproj = (TT_Project_Func)Project_y;
2661 CUR.func_dualproj = (TT_Project_Func)Dual_Project;
2663 CUR.func_move = (TT_Move_Func)Direct_Move;
2664 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig;
2666 if ( CUR.F_dot_P == 0x4000L )
2668 if ( CUR.GS.freeVector.x == 0x4000 )
2670 CUR.func_move = (TT_Move_Func)Direct_Move_X;
2671 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;
2673 else if ( CUR.GS.freeVector.y == 0x4000 )
2675 CUR.func_move = (TT_Move_Func)Direct_Move_Y;
2676 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
2680 /* at small sizes, F_dot_P can become too small, resulting */
2681 /* in overflows and `spikes' in a number of glyphs like `w'. */
2683 if ( FT_ABS( CUR.F_dot_P ) < 0x400L )
2684 CUR.F_dot_P = 0x4000L;
2686 /* Disable cached aspect ratio */
2687 CUR.tt_metrics.ratio = 0;
2691 /*************************************************************************/
2697 /* Norms a vector. */
2700 /* Vx :: The horizontal input vector coordinate. */
2701 /* Vy :: The vertical input vector coordinate. */
2704 /* R :: The normed unit vector. */
2707 /* Returns FAILURE if a vector parameter is zero. */
2710 /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
2711 /* R is undefined. */
2716 Normalize( EXEC_OP_ FT_F26Dot6 Vx,
2726 if ( FT_ABS( Vx ) < 0x10000L && FT_ABS( Vy ) < 0x10000L )
2731 W = TT_VecLen( Vx, Vy );
2735 /* XXX: UNDOCUMENTED! It seems that it is possible to try */
2736 /* to normalize the vector (0,0). Return immediately. */
2740 R->x = (FT_F2Dot14)TT_DivFix14( Vx, W );
2741 R->y = (FT_F2Dot14)TT_DivFix14( Vy, W );
2746 W = TT_VecLen( Vx, Vy );
2748 Vx = TT_DivFix14( Vx, W );
2749 Vy = TT_DivFix14( Vy, W );
2751 W = Vx * Vx + Vy * Vy;
2753 /* Now, we want that Sqrt( W ) = 0x4000 */
2754 /* Or 0x10000000 <= W < 0x10004000 */
2772 while ( W < 0x10000000L )
2774 /* We need to increase W by a minimal amount */
2780 W = Vx * Vx + Vy * Vy;
2783 while ( W >= 0x10004000L )
2785 /* We need to decrease W by a minimal amount */
2791 W = Vx * Vx + Vy * Vy;
2794 /* Note that in various cases, we can only */
2795 /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
2803 R->x = (FT_F2Dot14)Vx; /* Type conversion */
2804 R->y = (FT_F2Dot14)Vy; /* Type conversion */
2810 /*************************************************************************/
2812 /* Here we start with the implementation of the various opcodes. */
2814 /*************************************************************************/
2818 Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1,
2821 FT_UnitVector* Vec )
2828 if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
2829 BOUNDS( aIdx2, CUR.zp1.n_points ) )
2831 if ( CUR.pedantic_hinting )
2832 CUR.error = TT_Err_Invalid_Reference;
2836 p1 = CUR.zp1.cur + aIdx2;
2837 p2 = CUR.zp2.cur + aIdx1;
2842 /* If p1 == p2, SPVTL and SFVTL behave the same as */
2843 /* SPVTCA[X] and SFVTCA[X], respectively. */
2845 /* Confirmed by Greg Hitchcock. */
2847 if ( A == 0 && B == 0 )
2853 if ( ( aOpc & 1 ) != 0 )
2855 C = B; /* counter clockwise rotation */
2860 NORMalize( A, B, Vec );
2866 /* When not using the big switch statements, the interpreter uses a */
2867 /* call table defined later below in this source. Each opcode must */
2868 /* thus have a corresponding function, even trivial ones. */
2870 /* They are all defined there. */
2877 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2878 B = A ^ (FT_Short)0x4000; \
2880 CUR.GS.freeVector.x = A; \
2881 CUR.GS.projVector.x = A; \
2882 CUR.GS.dualVector.x = A; \
2884 CUR.GS.freeVector.y = B; \
2885 CUR.GS.projVector.y = B; \
2886 CUR.GS.dualVector.y = B; \
2897 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2898 B = A ^ (FT_Short)0x4000; \
2900 CUR.GS.projVector.x = A; \
2901 CUR.GS.dualVector.x = A; \
2903 CUR.GS.projVector.y = B; \
2904 CUR.GS.dualVector.y = B; \
2906 GUESS_VECTOR( freeVector ); \
2917 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2918 B = A ^ (FT_Short)0x4000; \
2920 CUR.GS.freeVector.x = A; \
2921 CUR.GS.freeVector.y = B; \
2923 GUESS_VECTOR( projVector ); \
2930 if ( INS_SxVTL( (FT_UShort)args[1], \
2931 (FT_UShort)args[0], \
2933 &CUR.GS.projVector ) == SUCCESS ) \
2935 CUR.GS.dualVector = CUR.GS.projVector; \
2936 GUESS_VECTOR( freeVector ); \
2942 if ( INS_SxVTL( (FT_UShort)args[1], \
2943 (FT_UShort)args[0], \
2945 &CUR.GS.freeVector ) == SUCCESS ) \
2947 GUESS_VECTOR( projVector ); \
2953 GUESS_VECTOR( projVector ); \
2954 CUR.GS.freeVector = CUR.GS.projVector; \
2964 /* Only use low 16bits, then sign extend */ \
2965 S = (FT_Short)args[1]; \
2967 S = (FT_Short)args[0]; \
2970 NORMalize( X, Y, &CUR.GS.projVector ); \
2972 CUR.GS.dualVector = CUR.GS.projVector; \
2973 GUESS_VECTOR( freeVector ); \
2984 /* Only use low 16bits, then sign extend */ \
2985 S = (FT_Short)args[1]; \
2987 S = (FT_Short)args[0]; \
2990 NORMalize( X, Y, &CUR.GS.freeVector ); \
2991 GUESS_VECTOR( projVector ); \
2996 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2998 if ( CUR.face->unpatented_hinting ) \
3000 args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
3001 args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
3005 args[0] = CUR.GS.projVector.x; \
3006 args[1] = CUR.GS.projVector.y; \
3010 args[0] = CUR.GS.projVector.x; \
3011 args[1] = CUR.GS.projVector.y;
3015 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
3017 if ( CUR.face->unpatented_hinting ) \
3019 args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
3020 args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
3024 args[0] = CUR.GS.freeVector.x; \
3025 args[1] = CUR.GS.freeVector.y; \
3029 args[0] = CUR.GS.freeVector.x; \
3030 args[1] = CUR.GS.freeVector.y;
3035 CUR.GS.rp0 = (FT_UShort)args[0];
3039 CUR.GS.rp1 = (FT_UShort)args[0];
3043 CUR.GS.rp2 = (FT_UShort)args[0];
3047 CUR.GS.round_state = TT_Round_To_Half_Grid; \
3048 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
3052 CUR.GS.round_state = TT_Round_To_Grid; \
3053 CUR.func_round = (TT_Round_Func)Round_To_Grid;
3057 CUR.GS.round_state = TT_Round_To_Double_Grid; \
3058 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
3062 CUR.GS.round_state = TT_Round_Up_To_Grid; \
3063 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
3067 CUR.GS.round_state = TT_Round_Down_To_Grid; \
3068 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
3072 CUR.GS.round_state = TT_Round_Off; \
3073 CUR.func_round = (TT_Round_Func)Round_None;
3077 SET_SuperRound( 0x4000, args[0] ); \
3078 CUR.GS.round_state = TT_Round_Super; \
3079 CUR.func_round = (TT_Round_Func)Round_Super;
3082 #define DO_S45ROUND \
3083 SET_SuperRound( 0x2D41, args[0] ); \
3084 CUR.GS.round_state = TT_Round_Super_45; \
3085 CUR.func_round = (TT_Round_Func)Round_Super_45;
3089 if ( args[0] < 0 ) \
3090 CUR.error = TT_Err_Bad_Argument; \
3092 CUR.GS.loop = args[0];
3096 CUR.GS.minimum_distance = args[0];
3100 CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
3104 CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
3108 CUR.GS.single_width_value = FT_MulFix( args[0], \
3109 CUR.tt_metrics.scale );
3113 CUR.GS.auto_flip = TRUE;
3116 #define DO_FLIPOFF \
3117 CUR.GS.auto_flip = FALSE;
3121 CUR.GS.delta_base = (FT_Short)args[0];
3125 CUR.GS.delta_shift = (FT_Short)args[0];
3128 #define DO_MD /* nothing */
3132 args[0] = CURRENT_Ppem();
3135 /* Note: The pointSize should be irrelevant in a given font program; */
3136 /* we thus decide to return only the ppem. */
3140 args[0] = CUR.metrics.pointSize;
3145 args[0] = CURRENT_Ppem();
3164 args[0] = args[1]; \
3180 if ( L <= 0 || L > CUR.args ) \
3182 if ( CUR.pedantic_hinting ) \
3183 CUR.error = TT_Err_Invalid_Reference; \
3187 args[0] = CUR.stack[CUR.args - L]; \
3192 if ( args[1] != 0 ) \
3194 if ( args[0] == 0 && CUR.args == 0 ) \
3195 CUR.error = TT_Err_Bad_Argument; \
3196 CUR.IP += args[0]; \
3197 if ( CUR.IP < 0 || \
3198 ( CUR.callTop > 0 && \
3199 CUR.IP > CUR.callStack[CUR.callTop - 1].Cur_End ) ) \
3200 CUR.error = TT_Err_Bad_Argument; \
3201 CUR.step_ins = FALSE; \
3206 if ( args[0] == 0 && CUR.args == 0 ) \
3207 CUR.error = TT_Err_Bad_Argument; \
3208 CUR.IP += args[0]; \
3209 if ( CUR.IP < 0 || \
3210 ( CUR.callTop > 0 && \
3211 CUR.IP > CUR.callStack[CUR.callTop - 1].Cur_End ) ) \
3212 CUR.error = TT_Err_Bad_Argument; \
3213 CUR.step_ins = FALSE;
3217 if ( args[1] == 0 ) \
3219 if ( args[0] == 0 && CUR.args == 0 ) \
3220 CUR.error = TT_Err_Bad_Argument; \
3221 CUR.IP += args[0]; \
3222 if ( CUR.IP < 0 || \
3223 ( CUR.callTop > 0 && \
3224 CUR.IP > CUR.callStack[CUR.callTop - 1].Cur_End ) ) \
3225 CUR.error = TT_Err_Bad_Argument; \
3226 CUR.step_ins = FALSE; \
3231 args[0] = ( args[0] < args[1] );
3235 args[0] = ( args[0] <= args[1] );
3239 args[0] = ( args[0] > args[1] );
3243 args[0] = ( args[0] >= args[1] );
3247 args[0] = ( args[0] == args[1] );
3251 args[0] = ( args[0] != args[1] );
3255 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
3259 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
3263 args[0] = ( args[0] && args[1] );
3267 args[0] = ( args[0] || args[1] );
3283 if ( args[1] == 0 ) \
3284 CUR.error = TT_Err_Divide_By_Zero; \
3286 args[0] = FT_MulDiv_No_Round( args[0], 64L, args[1] );
3290 args[0] = FT_MulDiv( args[0], args[1], 64L );
3294 args[0] = FT_ABS( args[0] );
3302 args[0] = FT_PIX_FLOOR( args[0] );
3305 #define DO_CEILING \
3306 args[0] = FT_PIX_CEIL( args[0] );
3308 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
3312 FT_ULong I = (FT_ULong)args[0]; \
3315 if ( BOUNDSL( I, CUR.storeSize ) ) \
3317 if ( CUR.pedantic_hinting ) \
3318 ARRAY_BOUND_ERROR; \
3324 /* subpixel hinting - avoid Typeman Dstroke and */ \
3325 /* IStroke and Vacuform rounds */ \
3327 if ( CUR.compatibility_mode && \
3328 ( I == 24 || I == 22 || I == 8 ) ) \
3331 args[0] = CUR.storage[I]; \
3335 #else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
3339 FT_ULong I = (FT_ULong)args[0]; \
3342 if ( BOUNDSL( I, CUR.storeSize ) ) \
3344 if ( CUR.pedantic_hinting ) \
3346 ARRAY_BOUND_ERROR; \
3352 args[0] = CUR.storage[I]; \
3355 #endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
3360 FT_ULong I = (FT_ULong)args[0]; \
3363 if ( BOUNDSL( I, CUR.storeSize ) ) \
3365 if ( CUR.pedantic_hinting ) \
3367 ARRAY_BOUND_ERROR; \
3371 CUR.storage[I] = args[1]; \
3377 FT_ULong I = (FT_ULong)args[0]; \
3380 if ( BOUNDSL( I, CUR.cvtSize ) ) \
3382 if ( CUR.pedantic_hinting ) \
3384 ARRAY_BOUND_ERROR; \
3390 args[0] = CUR_Func_read_cvt( I ); \
3396 FT_ULong I = (FT_ULong)args[0]; \
3399 if ( BOUNDSL( I, CUR.cvtSize ) ) \
3401 if ( CUR.pedantic_hinting ) \
3403 ARRAY_BOUND_ERROR; \
3407 CUR_Func_write_cvt( I, args[1] ); \
3413 FT_ULong I = (FT_ULong)args[0]; \
3416 if ( BOUNDSL( I, CUR.cvtSize ) ) \
3418 if ( CUR.pedantic_hinting ) \
3420 ARRAY_BOUND_ERROR; \
3424 CUR.cvt[I] = FT_MulFix( args[1], CUR.tt_metrics.scale ); \
3429 CUR.error = TT_Err_Debug_OpCode;
3433 args[0] = CUR_Func_round( \
3435 CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
3439 args[0] = ROUND_None( args[0], \
3440 CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
3444 if ( args[1] > args[0] ) \
3449 if ( args[1] < args[0] ) \
3453 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
3456 #undef ARRAY_BOUND_ERROR
3457 #define ARRAY_BOUND_ERROR \
3459 CUR.error = TT_Err_Invalid_Reference; \
3464 /*************************************************************************/
3466 /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
3467 /* Opcode range: 0x00-0x01 */
3471 Ins_SVTCA( INS_ARG )
3477 /*************************************************************************/
3479 /* SPVTCA[a]: Set PVector to Coordinate Axis */
3480 /* Opcode range: 0x02-0x03 */
3484 Ins_SPVTCA( INS_ARG )
3490 /*************************************************************************/
3492 /* SFVTCA[a]: Set FVector to Coordinate Axis */
3493 /* Opcode range: 0x04-0x05 */
3497 Ins_SFVTCA( INS_ARG )
3503 /*************************************************************************/
3505 /* SPVTL[a]: Set PVector To Line */
3506 /* Opcode range: 0x06-0x07 */
3507 /* Stack: uint32 uint32 --> */
3510 Ins_SPVTL( INS_ARG )
3516 /*************************************************************************/
3518 /* SFVTL[a]: Set FVector To Line */
3519 /* Opcode range: 0x08-0x09 */
3520 /* Stack: uint32 uint32 --> */
3523 Ins_SFVTL( INS_ARG )
3529 /*************************************************************************/
3531 /* SFVTPV[]: Set FVector To PVector */
3532 /* Opcode range: 0x0E */
3536 Ins_SFVTPV( INS_ARG )
3542 /*************************************************************************/
3544 /* SPVFS[]: Set PVector From Stack */
3545 /* Opcode range: 0x0A */
3546 /* Stack: f2.14 f2.14 --> */
3549 Ins_SPVFS( INS_ARG )
3555 /*************************************************************************/
3557 /* SFVFS[]: Set FVector From Stack */
3558 /* Opcode range: 0x0B */
3559 /* Stack: f2.14 f2.14 --> */
3562 Ins_SFVFS( INS_ARG )
3568 /*************************************************************************/
3570 /* GPV[]: Get Projection Vector */
3571 /* Opcode range: 0x0C */
3572 /* Stack: ef2.14 --> ef2.14 */
3581 /*************************************************************************/
3582 /* GFV[]: Get Freedom Vector */
3583 /* Opcode range: 0x0D */
3584 /* Stack: ef2.14 --> ef2.14 */
3593 /*************************************************************************/
3595 /* SRP0[]: Set Reference Point 0 */
3596 /* Opcode range: 0x10 */
3597 /* Stack: uint32 --> */
3606 /*************************************************************************/
3608 /* SRP1[]: Set Reference Point 1 */
3609 /* Opcode range: 0x11 */
3610 /* Stack: uint32 --> */
3619 /*************************************************************************/
3621 /* SRP2[]: Set Reference Point 2 */
3622 /* Opcode range: 0x12 */
3623 /* Stack: uint32 --> */
3632 /*************************************************************************/
3634 /* RTHG[]: Round To Half Grid */
3635 /* Opcode range: 0x19 */
3645 /*************************************************************************/
3647 /* RTG[]: Round To Grid */
3648 /* Opcode range: 0x18 */
3658 /*************************************************************************/
3659 /* RTDG[]: Round To Double Grid */
3660 /* Opcode range: 0x3D */
3670 /*************************************************************************/
3671 /* RUTG[]: Round Up To Grid */
3672 /* Opcode range: 0x7C */
3682 /*************************************************************************/
3684 /* RDTG[]: Round Down To Grid */
3685 /* Opcode range: 0x7D */
3695 /*************************************************************************/
3697 /* ROFF[]: Round OFF */
3698 /* Opcode range: 0x7A */
3708 /*************************************************************************/
3710 /* SROUND[]: Super ROUND */
3711 /* Opcode range: 0x76 */
3712 /* Stack: Eint8 --> */
3715 Ins_SROUND( INS_ARG )
3721 /*************************************************************************/
3723 /* S45ROUND[]: Super ROUND 45 degrees */
3724 /* Opcode range: 0x77 */
3725 /* Stack: uint32 --> */
3728 Ins_S45ROUND( INS_ARG )
3734 /*************************************************************************/
3736 /* SLOOP[]: Set LOOP variable */
3737 /* Opcode range: 0x17 */
3738 /* Stack: int32? --> */
3741 Ins_SLOOP( INS_ARG )
3747 /*************************************************************************/
3749 /* SMD[]: Set Minimum Distance */
3750 /* Opcode range: 0x1A */
3751 /* Stack: f26.6 --> */
3760 /*************************************************************************/
3762 /* SCVTCI[]: Set Control Value Table Cut In */
3763 /* Opcode range: 0x1D */
3764 /* Stack: f26.6 --> */
3767 Ins_SCVTCI( INS_ARG )
3773 /*************************************************************************/
3775 /* SSWCI[]: Set Single Width Cut In */
3776 /* Opcode range: 0x1E */
3777 /* Stack: f26.6 --> */
3780 Ins_SSWCI( INS_ARG )
3786 /*************************************************************************/
3788 /* SSW[]: Set Single Width */
3789 /* Opcode range: 0x1F */
3790 /* Stack: int32? --> */
3799 /*************************************************************************/
3801 /* FLIPON[]: Set auto-FLIP to ON */
3802 /* Opcode range: 0x4D */
3806 Ins_FLIPON( INS_ARG )
3812 /*************************************************************************/
3814 /* FLIPOFF[]: Set auto-FLIP to OFF */
3815 /* Opcode range: 0x4E */
3819 Ins_FLIPOFF( INS_ARG )
3825 /*************************************************************************/
3827 /* SANGW[]: Set ANGle Weight */
3828 /* Opcode range: 0x7E */
3829 /* Stack: uint32 --> */
3832 Ins_SANGW( INS_ARG )
3834 /* instruction not supported anymore */
3838 /*************************************************************************/
3840 /* SDB[]: Set Delta Base */
3841 /* Opcode range: 0x5E */
3842 /* Stack: uint32 --> */
3851 /*************************************************************************/
3853 /* SDS[]: Set Delta Shift */
3854 /* Opcode range: 0x5F */
3855 /* Stack: uint32 --> */
3864 /*************************************************************************/
3866 /* MPPEM[]: Measure Pixel Per EM */
3867 /* Opcode range: 0x4B */
3868 /* Stack: --> Euint16 */
3871 Ins_MPPEM( INS_ARG )
3877 /*************************************************************************/
3879 /* MPS[]: Measure Point Size */
3880 /* Opcode range: 0x4C */
3881 /* Stack: --> Euint16 */
3890 /*************************************************************************/
3892 /* DUP[]: DUPlicate the top stack's element */
3893 /* Opcode range: 0x20 */
3894 /* Stack: StkElt --> StkElt StkElt */
3903 /*************************************************************************/
3905 /* POP[]: POP the stack's top element */
3906 /* Opcode range: 0x21 */
3907 /* Stack: StkElt --> */
3916 /*************************************************************************/
3918 /* CLEAR[]: CLEAR the entire stack */
3919 /* Opcode range: 0x22 */
3920 /* Stack: StkElt... --> */
3923 Ins_CLEAR( INS_ARG )
3929 /*************************************************************************/
3931 /* SWAP[]: SWAP the stack's top two elements */
3932 /* Opcode range: 0x23 */
3933 /* Stack: 2 * StkElt --> 2 * StkElt */
3942 /*************************************************************************/
3944 /* DEPTH[]: return the stack DEPTH */
3945 /* Opcode range: 0x24 */
3946 /* Stack: --> uint32 */
3949 Ins_DEPTH( INS_ARG )
3955 /*************************************************************************/
3957 /* CINDEX[]: Copy INDEXed element */
3958 /* Opcode range: 0x25 */
3959 /* Stack: int32 --> StkElt */
3962 Ins_CINDEX( INS_ARG )
3968 /*************************************************************************/
3971 /* Opcode range: 0x59 */
3981 /*************************************************************************/
3983 /* JROT[]: Jump Relative On True */
3984 /* Opcode range: 0x78 */
3985 /* Stack: StkElt int32 --> */
3994 /*************************************************************************/
3996 /* JMPR[]: JuMP Relative */
3997 /* Opcode range: 0x1C */
3998 /* Stack: int32 --> */
4007 /*************************************************************************/
4009 /* JROF[]: Jump Relative On False */
4010 /* Opcode range: 0x79 */
4011 /* Stack: StkElt int32 --> */
4020 /*************************************************************************/
4022 /* LT[]: Less Than */
4023 /* Opcode range: 0x50 */
4024 /* Stack: int32? int32? --> bool */
4033 /*************************************************************************/
4035 /* LTEQ[]: Less Than or EQual */
4036 /* Opcode range: 0x51 */
4037 /* Stack: int32? int32? --> bool */
4046 /*************************************************************************/
4048 /* GT[]: Greater Than */
4049 /* Opcode range: 0x52 */
4050 /* Stack: int32? int32? --> bool */
4059 /*************************************************************************/
4061 /* GTEQ[]: Greater Than or EQual */
4062 /* Opcode range: 0x53 */
4063 /* Stack: int32? int32? --> bool */
4072 /*************************************************************************/
4075 /* Opcode range: 0x54 */
4076 /* Stack: StkElt StkElt --> bool */
4085 /*************************************************************************/
4087 /* NEQ[]: Not EQual */
4088 /* Opcode range: 0x55 */
4089 /* Stack: StkElt StkElt --> bool */
4098 /*************************************************************************/
4101 /* Opcode range: 0x56 */
4102 /* Stack: f26.6 --> bool */
4111 /*************************************************************************/
4113 /* EVEN[]: Is EVEN */
4114 /* Opcode range: 0x57 */
4115 /* Stack: f26.6 --> bool */
4124 /*************************************************************************/
4126 /* AND[]: logical AND */
4127 /* Opcode range: 0x5A */
4128 /* Stack: uint32 uint32 --> uint32 */
4137 /*************************************************************************/
4139 /* OR[]: logical OR */
4140 /* Opcode range: 0x5B */
4141 /* Stack: uint32 uint32 --> uint32 */
4150 /*************************************************************************/
4152 /* NOT[]: logical NOT */
4153 /* Opcode range: 0x5C */
4154 /* Stack: StkElt --> uint32 */
4163 /*************************************************************************/
4166 /* Opcode range: 0x60 */
4167 /* Stack: f26.6 f26.6 --> f26.6 */
4176 /*************************************************************************/
4178 /* SUB[]: SUBtract */
4179 /* Opcode range: 0x61 */
4180 /* Stack: f26.6 f26.6 --> f26.6 */
4189 /*************************************************************************/
4192 /* Opcode range: 0x62 */
4193 /* Stack: f26.6 f26.6 --> f26.6 */
4202 /*************************************************************************/
4204 /* MUL[]: MULtiply */
4205 /* Opcode range: 0x63 */
4206 /* Stack: f26.6 f26.6 --> f26.6 */
4215 /*************************************************************************/
4217 /* ABS[]: ABSolute value */
4218 /* Opcode range: 0x64 */
4219 /* Stack: f26.6 --> f26.6 */
4228 /*************************************************************************/
4231 /* Opcode range: 0x65 */
4232 /* Stack: f26.6 --> f26.6 */
4241 /*************************************************************************/
4243 /* FLOOR[]: FLOOR */
4244 /* Opcode range: 0x66 */
4245 /* Stack: f26.6 --> f26.6 */
4248 Ins_FLOOR( INS_ARG )
4254 /*************************************************************************/
4256 /* CEILING[]: CEILING */
4257 /* Opcode range: 0x67 */
4258 /* Stack: f26.6 --> f26.6 */
4261 Ins_CEILING( INS_ARG )
4267 /*************************************************************************/
4269 /* RS[]: Read Store */
4270 /* Opcode range: 0x43 */
4271 /* Stack: uint32 --> uint32 */
4280 /*************************************************************************/
4282 /* WS[]: Write Store */
4283 /* Opcode range: 0x42 */
4284 /* Stack: uint32 uint32 --> */
4293 /*************************************************************************/
4295 /* WCVTP[]: Write CVT in Pixel units */
4296 /* Opcode range: 0x44 */
4297 /* Stack: f26.6 uint32 --> */
4300 Ins_WCVTP( INS_ARG )
4306 /*************************************************************************/
4308 /* WCVTF[]: Write CVT in Funits */
4309 /* Opcode range: 0x70 */
4310 /* Stack: uint32 uint32 --> */
4313 Ins_WCVTF( INS_ARG )
4319 /*************************************************************************/
4321 /* RCVT[]: Read CVT */
4322 /* Opcode range: 0x45 */
4323 /* Stack: uint32 --> f26.6 */
4332 /*************************************************************************/
4334 /* AA[]: Adjust Angle */
4335 /* Opcode range: 0x7F */
4336 /* Stack: uint32 --> */
4341 /* intentionally no longer supported */
4345 /*************************************************************************/
4347 /* DEBUG[]: DEBUG. Unsupported. */
4348 /* Opcode range: 0x4F */
4349 /* Stack: uint32 --> */
4351 /* Note: The original instruction pops a value from the stack. */
4354 Ins_DEBUG( INS_ARG )
4360 /*************************************************************************/
4362 /* ROUND[ab]: ROUND value */
4363 /* Opcode range: 0x68-0x6B */
4364 /* Stack: f26.6 --> f26.6 */
4367 Ins_ROUND( INS_ARG )
4373 /*************************************************************************/
4375 /* NROUND[ab]: No ROUNDing of value */
4376 /* Opcode range: 0x6C-0x6F */
4377 /* Stack: f26.6 --> f26.6 */
4380 Ins_NROUND( INS_ARG )
4386 /*************************************************************************/
4388 /* MAX[]: MAXimum */
4389 /* Opcode range: 0x68 */
4390 /* Stack: int32? int32? --> int32 */
4399 /*************************************************************************/
4401 /* MIN[]: MINimum */
4402 /* Opcode range: 0x69 */
4403 /* Stack: int32? int32? --> int32 */
4412 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
4415 /*************************************************************************/
4417 /* The following functions are called as is within the switch statement. */
4419 /*************************************************************************/
4422 /*************************************************************************/
4424 /* MINDEX[]: Move INDEXed element */
4425 /* Opcode range: 0x26 */
4426 /* Stack: int32? --> StkElt */
4429 Ins_MINDEX( INS_ARG )
4436 if ( L <= 0 || L > CUR.args )
4438 if ( CUR.pedantic_hinting )
4439 CUR.error = TT_Err_Invalid_Reference;
4443 K = CUR.stack[CUR.args - L];
4445 FT_ARRAY_MOVE( &CUR.stack[CUR.args - L ],
4446 &CUR.stack[CUR.args - L + 1],
4449 CUR.stack[CUR.args - 1] = K;
4454 /*************************************************************************/
4456 /* ROLL[]: ROLL top three elements */
4457 /* Opcode range: 0x8A */
4458 /* Stack: 3 * StkElt --> 3 * StkElt */
4478 /*************************************************************************/
4480 /* MANAGING THE FLOW OF CONTROL */
4482 /* Instructions appear in the specification's order. */
4484 /*************************************************************************/
4490 CUR.IP += CUR.length;
4492 if ( CUR.IP < CUR.codeSize )
4494 CUR.opcode = CUR.code[CUR.IP];
4496 CUR.length = opcode_length[CUR.opcode];
4497 if ( CUR.length < 0 )
4499 if ( CUR.IP + 1 >= CUR.codeSize )
4501 CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
4504 if ( CUR.IP + CUR.length <= CUR.codeSize )
4509 CUR.error = TT_Err_Code_Overflow;
4514 /*************************************************************************/
4517 /* Opcode range: 0x58 */
4518 /* Stack: StkElt --> */
4535 if ( SKIP_Code() == FAILURE )
4538 switch ( CUR.opcode )
4544 case 0x1B: /* ELSE */
4545 Out = FT_BOOL( nIfs == 1 );
4548 case 0x59: /* EIF */
4550 Out = FT_BOOL( nIfs == 0 );
4553 } while ( Out == 0 );
4557 /*************************************************************************/
4560 /* Opcode range: 0x1B */
4575 if ( SKIP_Code() == FAILURE )
4578 switch ( CUR.opcode )
4584 case 0x59: /* EIF */
4588 } while ( nIfs != 0 );
4592 /*************************************************************************/
4594 /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
4596 /* Instructions appear in the specification's order. */
4598 /*************************************************************************/
4601 /*************************************************************************/
4603 /* FDEF[]: Function DEFinition */
4604 /* Opcode range: 0x2C */
4605 /* Stack: uint32 --> */
4612 TT_DefRecord* limit;
4614 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
4615 /* arguments to opcodes are skipped by `SKIP_Code' */
4616 FT_Byte opcode_pattern[1][12] = {
4617 /* #0 TTFautohint bytecode (old) */
4629 FT_UShort opcode_patterns = 1;
4630 FT_UShort opcode_pointer[1] = { 0, };
4631 FT_UShort opcode_size[1] = { 7, };
4633 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
4636 /* some font programs are broken enough to redefine functions! */
4637 /* We will then parse the current table. */
4640 limit = rec + CUR.numFDefs;
4643 for ( ; rec < limit; rec++ )
4645 if ( rec->opc == n )
4651 /* check that there is enough room for new functions */
4652 if ( CUR.numFDefs >= CUR.maxFDefs )
4654 CUR.error = TT_Err_Too_Many_Function_Defs;
4660 /* Although FDEF takes unsigned 32-bit integer, */
4661 /* func # must be within unsigned 16-bit integer */
4664 CUR.error = TT_Err_Too_Many_Function_Defs;
4668 rec->range = CUR.curRange;
4669 rec->opc = (FT_UInt16)n;
4670 rec->start = CUR.IP + 1;
4672 rec->inline_delta = FALSE;
4674 if ( n > CUR.maxFunc )
4675 CUR.maxFunc = (FT_UInt16)n;
4677 /* Now skip the whole function definition. */
4678 /* We don't allow nested IDEFS & FDEFs. */
4680 while ( SKIP_Code() == SUCCESS )
4682 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
4684 #ifdef SPH_DEBUG_MORE_VERBOSE
4685 printf ( "Opcode: %d ", CUR.opcode );
4688 for ( i = 0; i < opcode_patterns; i++ )
4690 if ( opcode_pointer[i] < opcode_size[i] &&
4691 CUR.opcode == opcode_pattern[i][opcode_pointer[i]] )
4693 #ifdef SPH_DEBUG_MORE_VERBOSE
4694 printf( "function %d, opcode ptrn: %d"
4695 " op# %d: %d FOUND \n",
4696 n, i, opcode_pointer[i], CUR.opcode );
4698 opcode_pointer[i] += 1;
4700 if ( opcode_pointer[i] == opcode_size[i] )
4703 printf( "Function signature %d detected in FDEF %d\n", i, n);
4709 CUR.size->ttfautohinted = TRUE;
4712 opcode_pointer[i] = 0;
4717 opcode_pointer[i] = 0;
4720 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
4722 switch ( CUR.opcode )
4724 case 0x89: /* IDEF */
4725 case 0x2C: /* FDEF */
4726 CUR.error = TT_Err_Nested_DEFS;
4729 case 0x2D: /* ENDF */
4737 /*************************************************************************/
4739 /* ENDF[]: END Function definition */
4740 /* Opcode range: 0x2D */
4751 if ( CUR.callTop <= 0 ) /* We encountered an ENDF without a call */
4753 CUR.error = TT_Err_ENDF_In_Exec_Stream;
4759 pRec = &CUR.callStack[CUR.callTop];
4763 CUR.step_ins = FALSE;
4765 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
4767 * CUR.ignore_x_mode may be turned off prior to function calls. This
4768 * ensures it is turned back on.
4770 CUR.ignore_x_mode = ( CUR.subpixel_hinting || CUR.grayscale_hinting ) &&
4771 !( CUR.sph_tweak_flags & SPH_TWEAK_PIXEL_HINTING );
4772 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
4774 if ( pRec->Cur_Count > 0 )
4777 CUR.IP = pRec->Cur_Restart;
4780 /* Loop through the current function */
4781 INS_Goto_CodeRange( pRec->Caller_Range,
4784 /* Exit the current call frame. */
4786 /* NOTE: If the last instruction of a program is a */
4787 /* CALL or LOOPCALL, the return address is */
4788 /* always out of the code range. This is a */
4789 /* valid address, and it is why we do not test */
4790 /* the result of Ins_Goto_CodeRange() here! */
4794 /*************************************************************************/
4796 /* CALL[]: CALL function */
4797 /* Opcode range: 0x2B */
4798 /* Stack: uint32? --> */
4808 /* first of all, check the index */
4811 if ( BOUNDSL( F, CUR.maxFunc + 1 ) )
4814 /* Except for some old Apple fonts, all functions in a TrueType */
4815 /* font are defined in increasing order, starting from 0. This */
4816 /* means that we normally have */
4818 /* CUR.maxFunc+1 == CUR.numFDefs */
4819 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4821 /* If this isn't true, we need to look up the function table. */
4823 def = CUR.FDefs + F;
4824 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
4826 /* look up the FDefs table */
4827 TT_DefRecord* limit;
4831 limit = def + CUR.numFDefs;
4833 while ( def < limit && def->opc != F )
4840 /* check that the function is active */
4845 /* check the call stack */
4846 if ( CUR.callTop >= CUR.callSize )
4848 CUR.error = TT_Err_Stack_Overflow;
4852 pCrec = CUR.callStack + CUR.callTop;
4854 pCrec->Caller_Range = CUR.curRange;
4855 pCrec->Caller_IP = CUR.IP + 1;
4856 pCrec->Cur_Count = 1;
4857 pCrec->Cur_Restart = def->start;
4858 pCrec->Cur_End = def->end;
4862 INS_Goto_CodeRange( def->range,
4865 CUR.step_ins = FALSE;
4869 CUR.error = TT_Err_Invalid_Reference;
4873 /*************************************************************************/
4875 /* LOOPCALL[]: LOOP and CALL function */
4876 /* Opcode range: 0x2A */
4877 /* Stack: uint32? Eint16? --> */
4880 Ins_LOOPCALL( INS_ARG )
4887 /* first of all, check the index */
4889 if ( BOUNDSL( F, CUR.maxFunc + 1 ) )
4892 /* Except for some old Apple fonts, all functions in a TrueType */
4893 /* font are defined in increasing order, starting from 0. This */
4894 /* means that we normally have */
4896 /* CUR.maxFunc+1 == CUR.numFDefs */
4897 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4899 /* If this isn't true, we need to look up the function table. */
4901 def = CUR.FDefs + F;
4902 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
4904 /* look up the FDefs table */
4905 TT_DefRecord* limit;
4909 limit = def + CUR.numFDefs;
4911 while ( def < limit && def->opc != F )
4918 /* check that the function is active */
4923 if ( CUR.callTop >= CUR.callSize )
4925 CUR.error = TT_Err_Stack_Overflow;
4931 pCrec = CUR.callStack + CUR.callTop;
4933 pCrec->Caller_Range = CUR.curRange;
4934 pCrec->Caller_IP = CUR.IP + 1;
4935 pCrec->Cur_Count = (FT_Int)args[0];
4936 pCrec->Cur_Restart = def->start;
4937 pCrec->Cur_End = def->end;
4941 INS_Goto_CodeRange( def->range, def->start );
4943 CUR.step_ins = FALSE;
4949 CUR.error = TT_Err_Invalid_Reference;
4953 /*************************************************************************/
4955 /* IDEF[]: Instruction DEFinition */
4956 /* Opcode range: 0x89 */
4957 /* Stack: Eint8 --> */
4963 TT_DefRecord* limit;
4966 /* First of all, look for the same function in our table */
4969 limit = def + CUR.numIDefs;
4971 for ( ; def < limit; def++ )
4972 if ( def->opc == (FT_ULong)args[0] )
4977 /* check that there is enough room for a new instruction */
4978 if ( CUR.numIDefs >= CUR.maxIDefs )
4980 CUR.error = TT_Err_Too_Many_Instruction_Defs;
4986 /* opcode must be unsigned 8-bit integer */
4987 if ( 0 > args[0] || args[0] > 0x00FF )
4989 CUR.error = TT_Err_Too_Many_Instruction_Defs;
4993 def->opc = (FT_Byte)args[0];
4994 def->start = CUR.IP + 1;
4995 def->range = CUR.curRange;
4998 if ( (FT_ULong)args[0] > CUR.maxIns )
4999 CUR.maxIns = (FT_Byte)args[0];
5001 /* Now skip the whole function definition. */
5002 /* We don't allow nested IDEFs & FDEFs. */
5004 while ( SKIP_Code() == SUCCESS )
5006 switch ( CUR.opcode )
5008 case 0x89: /* IDEF */
5009 case 0x2C: /* FDEF */
5010 CUR.error = TT_Err_Nested_DEFS;
5012 case 0x2D: /* ENDF */
5019 /*************************************************************************/
5021 /* PUSHING DATA ONTO THE INTERPRETER STACK */
5023 /* Instructions appear in the specification's order. */
5025 /*************************************************************************/
5028 /*************************************************************************/
5030 /* NPUSHB[]: PUSH N Bytes */
5031 /* Opcode range: 0x40 */
5032 /* Stack: --> uint32... */
5035 Ins_NPUSHB( INS_ARG )
5040 L = (FT_UShort)CUR.code[CUR.IP + 1];
5042 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
5044 CUR.error = TT_Err_Stack_Overflow;
5048 for ( K = 1; K <= L; K++ )
5049 args[K - 1] = CUR.code[CUR.IP + K + 1];
5055 /*************************************************************************/
5057 /* NPUSHW[]: PUSH N Words */
5058 /* Opcode range: 0x41 */
5059 /* Stack: --> int32... */
5062 Ins_NPUSHW( INS_ARG )
5067 L = (FT_UShort)CUR.code[CUR.IP + 1];
5069 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
5071 CUR.error = TT_Err_Stack_Overflow;
5077 for ( K = 0; K < L; K++ )
5078 args[K] = GET_ShortIns();
5080 CUR.step_ins = FALSE;
5085 /*************************************************************************/
5087 /* PUSHB[abc]: PUSH Bytes */
5088 /* Opcode range: 0xB0-0xB7 */
5089 /* Stack: --> uint32... */
5092 Ins_PUSHB( INS_ARG )
5097 L = (FT_UShort)( CUR.opcode - 0xB0 + 1 );
5099 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
5101 CUR.error = TT_Err_Stack_Overflow;
5105 for ( K = 1; K <= L; K++ )
5106 args[K - 1] = CUR.code[CUR.IP + K];
5110 /*************************************************************************/
5112 /* PUSHW[abc]: PUSH Words */
5113 /* Opcode range: 0xB8-0xBF */
5114 /* Stack: --> int32... */
5117 Ins_PUSHW( INS_ARG )
5122 L = (FT_UShort)( CUR.opcode - 0xB8 + 1 );
5124 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
5126 CUR.error = TT_Err_Stack_Overflow;
5132 for ( K = 0; K < L; K++ )
5133 args[K] = GET_ShortIns();
5135 CUR.step_ins = FALSE;
5139 /*************************************************************************/
5141 /* MANAGING THE GRAPHICS STATE */
5143 /* Instructions appear in the specs' order. */
5145 /*************************************************************************/
5148 /*************************************************************************/
5150 /* GC[a]: Get Coordinate projected onto */
5151 /* Opcode range: 0x46-0x47 */
5152 /* Stack: uint32 --> f26.6 */
5154 /* XXX: UNDOCUMENTED: Measures from the original glyph must be taken */
5155 /* along the dual projection vector! */
5164 L = (FT_ULong)args[0];
5166 if ( BOUNDSL( L, CUR.zp2.n_points ) )
5168 if ( CUR.pedantic_hinting )
5169 CUR.error = TT_Err_Invalid_Reference;
5174 if ( CUR.opcode & 1 )
5175 R = CUR_fast_dualproj( &CUR.zp2.org[L] );
5177 R = CUR_fast_project( &CUR.zp2.cur[L] );
5184 /*************************************************************************/
5186 /* SCFS[]: Set Coordinate From Stack */
5187 /* Opcode range: 0x48 */
5188 /* Stack: f26.6 uint32 --> */
5192 /* OA := OA + ( value - OA.p )/( f.p ) * f */
5201 L = (FT_UShort)args[0];
5203 if ( BOUNDS( L, CUR.zp2.n_points ) )
5205 if ( CUR.pedantic_hinting )
5206 CUR.error = TT_Err_Invalid_Reference;
5210 K = CUR_fast_project( &CUR.zp2.cur[L] );
5212 CUR_Func_move( &CUR.zp2, L, args[1] - K );
5214 /* UNDOCUMENTED! The MS rasterizer does that with */
5215 /* twilight points (confirmed by Greg Hitchcock) */
5216 if ( CUR.GS.gep2 == 0 )
5217 CUR.zp2.org[L] = CUR.zp2.cur[L];
5221 /*************************************************************************/
5223 /* MD[a]: Measure Distance */
5224 /* Opcode range: 0x49-0x4A */
5225 /* Stack: uint32 uint32 --> f26.6 */
5227 /* XXX: UNDOCUMENTED: Measure taken in the original glyph must be along */
5228 /* the dual projection vector. */
5230 /* XXX: UNDOCUMENTED: Flag attributes are inverted! */
5231 /* 0 => measure distance in original outline */
5232 /* 1 => measure distance in grid-fitted outline */
5234 /* XXX: UNDOCUMENTED: `zp0 - zp1', and not `zp2 - zp1! */
5243 K = (FT_UShort)args[1];
5244 L = (FT_UShort)args[0];
5246 if ( BOUNDS( L, CUR.zp0.n_points ) ||
5247 BOUNDS( K, CUR.zp1.n_points ) )
5249 if ( CUR.pedantic_hinting )
5250 CUR.error = TT_Err_Invalid_Reference;
5255 if ( CUR.opcode & 1 )
5256 D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
5259 /* XXX: UNDOCUMENTED: twilight zone special case */
5261 if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
5263 FT_Vector* vec1 = CUR.zp0.org + L;
5264 FT_Vector* vec2 = CUR.zp1.org + K;
5267 D = CUR_Func_dualproj( vec1, vec2 );
5271 FT_Vector* vec1 = CUR.zp0.orus + L;
5272 FT_Vector* vec2 = CUR.zp1.orus + K;
5275 if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
5277 /* this should be faster */
5278 D = CUR_Func_dualproj( vec1, vec2 );
5279 D = FT_MulFix( D, CUR.metrics.x_scale );
5286 vec.x = FT_MulFix( vec1->x - vec2->x, CUR.metrics.x_scale );
5287 vec.y = FT_MulFix( vec1->y - vec2->y, CUR.metrics.y_scale );
5289 D = CUR_fast_dualproj( &vec );
5295 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
5296 /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */
5297 if ( CUR.ignore_x_mode && FT_ABS( D ) == 64 )
5299 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
5305 /*************************************************************************/
5307 /* SDPVTL[a]: Set Dual PVector to Line */
5308 /* Opcode range: 0x86-0x87 */
5309 /* Stack: uint32 uint32 --> */
5312 Ins_SDPVTL( INS_ARG )
5315 FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
5316 FT_Int aOpc = CUR.opcode;
5319 p1 = (FT_UShort)args[1];
5320 p2 = (FT_UShort)args[0];
5322 if ( BOUNDS( p2, CUR.zp1.n_points ) ||
5323 BOUNDS( p1, CUR.zp2.n_points ) )
5325 if ( CUR.pedantic_hinting )
5326 CUR.error = TT_Err_Invalid_Reference;
5331 FT_Vector* v1 = CUR.zp1.org + p2;
5332 FT_Vector* v2 = CUR.zp2.org + p1;
5338 /* If v1 == v2, SDPVTL behaves the same as */
5339 /* SVTCA[X], respectively. */
5341 /* Confirmed by Greg Hitchcock. */
5343 if ( A == 0 && B == 0 )
5350 if ( ( aOpc & 1 ) != 0 )
5352 C = B; /* counter clockwise rotation */
5357 NORMalize( A, B, &CUR.GS.dualVector );
5360 FT_Vector* v1 = CUR.zp1.cur + p2;
5361 FT_Vector* v2 = CUR.zp2.cur + p1;
5368 if ( ( aOpc & 1 ) != 0 )
5370 C = B; /* counter clockwise rotation */
5375 NORMalize( A, B, &CUR.GS.projVector );
5377 GUESS_VECTOR( freeVector );
5383 /*************************************************************************/
5385 /* SZP0[]: Set Zone Pointer 0 */
5386 /* Opcode range: 0x13 */
5387 /* Stack: uint32 --> */
5392 switch ( (FT_Int)args[0] )
5395 CUR.zp0 = CUR.twilight;
5403 if ( CUR.pedantic_hinting )
5404 CUR.error = TT_Err_Invalid_Reference;
5408 CUR.GS.gep0 = (FT_UShort)args[0];
5412 /*************************************************************************/
5414 /* SZP1[]: Set Zone Pointer 1 */
5415 /* Opcode range: 0x14 */
5416 /* Stack: uint32 --> */
5421 switch ( (FT_Int)args[0] )
5424 CUR.zp1 = CUR.twilight;
5432 if ( CUR.pedantic_hinting )
5433 CUR.error = TT_Err_Invalid_Reference;
5437 CUR.GS.gep1 = (FT_UShort)args[0];
5441 /*************************************************************************/
5443 /* SZP2[]: Set Zone Pointer 2 */
5444 /* Opcode range: 0x15 */
5445 /* Stack: uint32 --> */
5450 switch ( (FT_Int)args[0] )
5453 CUR.zp2 = CUR.twilight;
5461 if ( CUR.pedantic_hinting )
5462 CUR.error = TT_Err_Invalid_Reference;
5466 CUR.GS.gep2 = (FT_UShort)args[0];
5470 /*************************************************************************/
5472 /* SZPS[]: Set Zone PointerS */
5473 /* Opcode range: 0x16 */
5474 /* Stack: uint32 --> */
5479 switch ( (FT_Int)args[0] )
5482 CUR.zp0 = CUR.twilight;
5490 if ( CUR.pedantic_hinting )
5491 CUR.error = TT_Err_Invalid_Reference;
5498 CUR.GS.gep0 = (FT_UShort)args[0];
5499 CUR.GS.gep1 = (FT_UShort)args[0];
5500 CUR.GS.gep2 = (FT_UShort)args[0];
5504 /*************************************************************************/
5506 /* INSTCTRL[]: INSTruction ConTRoL */
5507 /* Opcode range: 0x8e */
5508 /* Stack: int32 int32 --> */
5511 Ins_INSTCTRL( INS_ARG )
5519 if ( K < 1 || K > 2 )
5521 if ( CUR.pedantic_hinting )
5522 CUR.error = TT_Err_Invalid_Reference;
5529 CUR.GS.instruct_control = FT_BOOL(
5530 ( (FT_Byte)CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L );
5534 /*************************************************************************/
5536 /* SCANCTRL[]: SCAN ConTRoL */
5537 /* Opcode range: 0x85 */
5538 /* Stack: uint32? --> */
5541 Ins_SCANCTRL( INS_ARG )
5547 A = (FT_Int)( args[0] & 0xFF );
5551 CUR.GS.scan_control = TRUE;
5556 CUR.GS.scan_control = FALSE;
5560 if ( ( args[0] & 0x100 ) != 0 && CUR.tt_metrics.ppem <= A )
5561 CUR.GS.scan_control = TRUE;
5563 if ( ( args[0] & 0x200 ) != 0 && CUR.tt_metrics.rotated )
5564 CUR.GS.scan_control = TRUE;
5566 if ( ( args[0] & 0x400 ) != 0 && CUR.tt_metrics.stretched )
5567 CUR.GS.scan_control = TRUE;
5569 if ( ( args[0] & 0x800 ) != 0 && CUR.tt_metrics.ppem > A )
5570 CUR.GS.scan_control = FALSE;
5572 if ( ( args[0] & 0x1000 ) != 0 && CUR.tt_metrics.rotated )
5573 CUR.GS.scan_control = FALSE;
5575 if ( ( args[0] & 0x2000 ) != 0 && CUR.tt_metrics.stretched )
5576 CUR.GS.scan_control = FALSE;
5580 /*************************************************************************/
5582 /* SCANTYPE[]: SCAN TYPE */
5583 /* Opcode range: 0x8D */
5584 /* Stack: uint32? --> */
5587 Ins_SCANTYPE( INS_ARG )
5590 CUR.GS.scan_type = (FT_Int)args[0];
5594 /*************************************************************************/
5596 /* MANAGING OUTLINES */
5598 /* Instructions appear in the specification's order. */
5600 /*************************************************************************/
5603 /*************************************************************************/
5605 /* FLIPPT[]: FLIP PoinT */
5606 /* Opcode range: 0x80 */
5607 /* Stack: uint32... --> */
5610 Ins_FLIPPT( INS_ARG )
5617 if ( CUR.top < CUR.GS.loop )
5619 if ( CUR.pedantic_hinting )
5620 CUR.error = TT_Err_Too_Few_Arguments;
5624 while ( CUR.GS.loop > 0 )
5628 point = (FT_UShort)CUR.stack[CUR.args];
5630 if ( BOUNDS( point, CUR.pts.n_points ) )
5632 if ( CUR.pedantic_hinting )
5634 CUR.error = TT_Err_Invalid_Reference;
5639 CUR.pts.tags[point] ^= FT_CURVE_TAG_ON;
5646 CUR.new_top = CUR.args;
5650 /*************************************************************************/
5652 /* FLIPRGON[]: FLIP RanGe ON */
5653 /* Opcode range: 0x81 */
5654 /* Stack: uint32 uint32 --> */
5657 Ins_FLIPRGON( INS_ARG )
5662 K = (FT_UShort)args[1];
5663 L = (FT_UShort)args[0];
5665 if ( BOUNDS( K, CUR.pts.n_points ) ||
5666 BOUNDS( L, CUR.pts.n_points ) )
5668 if ( CUR.pedantic_hinting )
5669 CUR.error = TT_Err_Invalid_Reference;
5673 for ( I = L; I <= K; I++ )
5674 CUR.pts.tags[I] |= FT_CURVE_TAG_ON;
5678 /*************************************************************************/
5680 /* FLIPRGOFF: FLIP RanGe OFF */
5681 /* Opcode range: 0x82 */
5682 /* Stack: uint32 uint32 --> */
5685 Ins_FLIPRGOFF( INS_ARG )
5690 K = (FT_UShort)args[1];
5691 L = (FT_UShort)args[0];
5693 if ( BOUNDS( K, CUR.pts.n_points ) ||
5694 BOUNDS( L, CUR.pts.n_points ) )
5696 if ( CUR.pedantic_hinting )
5697 CUR.error = TT_Err_Invalid_Reference;
5701 for ( I = L; I <= K; I++ )
5702 CUR.pts.tags[I] &= ~FT_CURVE_TAG_ON;
5707 Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6* x,
5717 if ( CUR.opcode & 1 )
5728 if ( BOUNDS( p, zp.n_points ) )
5730 if ( CUR.pedantic_hinting )
5731 CUR.error = TT_Err_Invalid_Reference;
5739 d = CUR_Func_project( zp.cur + p, zp.org + p );
5741 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5742 if ( CUR.face->unpatented_hinting )
5744 if ( CUR.GS.both_x_axis )
5758 *x = FT_MulDiv( d, (FT_Long)CUR.GS.freeVector.x, CUR.F_dot_P );
5759 *y = FT_MulDiv( d, (FT_Long)CUR.GS.freeVector.y, CUR.F_dot_P );
5767 Move_Zp2_Point( EXEC_OP_ FT_UShort point,
5772 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5773 if ( CUR.face->unpatented_hinting )
5775 if ( CUR.GS.both_x_axis )
5777 CUR.zp2.cur[point].x += dx;
5779 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
5783 CUR.zp2.cur[point].y += dy;
5785 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
5791 if ( CUR.GS.freeVector.x != 0 )
5793 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
5794 if ( !CUR.ignore_x_mode ||
5795 ( CUR.ignore_x_mode &&
5796 ( CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_X_MOVE_ZP2 ) ) )
5797 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
5798 CUR.zp2.cur[point].x += dx;
5800 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
5803 if ( CUR.GS.freeVector.y != 0 )
5805 CUR.zp2.cur[point].y += dy;
5807 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
5812 /*************************************************************************/
5814 /* SHP[a]: SHift Point by the last point */
5815 /* Opcode range: 0x32-0x33 */
5816 /* Stack: uint32... --> */
5831 if ( CUR.top < CUR.GS.loop )
5833 if ( CUR.pedantic_hinting )
5834 CUR.error = TT_Err_Invalid_Reference;
5838 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5841 while ( CUR.GS.loop > 0 )
5844 point = (FT_UShort)CUR.stack[CUR.args];
5846 if ( BOUNDS( point, CUR.zp2.n_points ) )
5848 if ( CUR.pedantic_hinting )
5850 CUR.error = TT_Err_Invalid_Reference;
5855 MOVE_Zp2_Point( point, dx, dy, TRUE );
5862 CUR.new_top = CUR.args;
5866 /*************************************************************************/
5868 /* SHC[a]: SHift Contour */
5869 /* Opcode range: 0x34-35 */
5870 /* Stack: uint32 --> */
5872 /* UNDOCUMENTED: According to Greg Hitchcock, there is one (virtual) */
5873 /* contour in the twilight zone, namely contour number */
5874 /* zero which includes all points of it. */
5883 FT_Short contour, bounds;
5884 FT_UShort start, limit, i;
5887 contour = (FT_UShort)args[0];
5888 bounds = ( CUR.GS.gep2 == 0 ) ? 1 : CUR.zp2.n_contours;
5890 if ( BOUNDS( contour, bounds ) )
5892 if ( CUR.pedantic_hinting )
5893 CUR.error = TT_Err_Invalid_Reference;
5897 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5903 start = (FT_UShort)( CUR.zp2.contours[contour - 1] + 1 -
5904 CUR.zp2.first_point );
5906 /* we use the number of points if in the twilight zone */
5907 if ( CUR.GS.gep2 == 0 )
5908 limit = CUR.zp2.n_points;
5910 limit = (FT_UShort)( CUR.zp2.contours[contour] -
5911 CUR.zp2.first_point + 1 );
5913 for ( i = start; i < limit; i++ )
5915 if ( zp.cur != CUR.zp2.cur || refp != i )
5916 MOVE_Zp2_Point( i, dx, dy, TRUE );
5921 /*************************************************************************/
5923 /* SHZ[a]: SHift Zone */
5924 /* Opcode range: 0x36-37 */
5925 /* Stack: uint32 --> */
5938 if ( BOUNDS( args[0], 2 ) )
5940 if ( CUR.pedantic_hinting )
5941 CUR.error = TT_Err_Invalid_Reference;
5945 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5948 /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */
5949 /* Twilight zone has no real contours, so use `n_points'. */
5950 /* Normal zone's `n_points' includes phantoms, so must */
5951 /* use end of last contour. */
5952 if ( CUR.GS.gep2 == 0 )
5953 limit = (FT_UShort)CUR.zp2.n_points;
5954 else if ( CUR.GS.gep2 == 1 && CUR.zp2.n_contours > 0 )
5955 limit = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] + 1 );
5959 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
5960 for ( i = 0; i < limit; i++ )
5962 if ( zp.cur != CUR.zp2.cur || refp != i )
5963 MOVE_Zp2_Point( i, dx, dy, FALSE );
5968 /*************************************************************************/
5970 /* SHPIX[]: SHift points by a PIXel amount */
5971 /* Opcode range: 0x38 */
5972 /* Stack: f26.6 uint32... --> */
5975 Ins_SHPIX( INS_ARG )
5979 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
5984 if ( CUR.top < CUR.GS.loop + 1 )
5986 if ( CUR.pedantic_hinting )
5987 CUR.error = TT_Err_Invalid_Reference;
5991 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5992 if ( CUR.face->unpatented_hinting )
5994 if ( CUR.GS.both_x_axis )
5996 dx = (FT_UInt32)args[0];
6002 dy = (FT_UInt32)args[0];
6008 dx = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.x );
6009 dy = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.y );
6012 while ( CUR.GS.loop > 0 )
6016 point = (FT_UShort)CUR.stack[CUR.args];
6018 if ( BOUNDS( point, CUR.zp2.n_points ) )
6020 if ( CUR.pedantic_hinting )
6022 CUR.error = TT_Err_Invalid_Reference;
6027 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6029 /* If not using ignore_x_mode rendering, allow ZP2 move. */
6030 /* If inline deltas aren't allowed, skip ZP2 move. */
6031 /* If using ignore_x_mode rendering, allow ZP2 point move if: */
6032 /* - freedom vector is y and compatibility_mode is off */
6033 /* - the glyph is composite and the move is in the Y direction */
6034 /* - the glyph is specifically set to allow SHPIX moves */
6035 /* - the move is on a previously Y-touched point */
6037 if ( CUR.ignore_x_mode )
6039 /* save point for later comparison */
6040 if ( CUR.GS.freeVector.y != 0 )
6041 B1 = CUR.zp2.cur[point].y;
6043 B1 = CUR.zp2.cur[point].x;
6045 if ( CUR.GS.freeVector.y != 0 &&
6046 ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_INLINE_DELTAS ) )
6049 if ( CUR.ignore_x_mode &&
6050 !CUR.compatibility_mode && CUR.GS.freeVector.y != 0 )
6051 MOVE_Zp2_Point( point, dx, dy, TRUE );
6053 else if ( CUR.ignore_x_mode && CUR.compatibility_mode )
6055 if ( CUR.ignore_x_mode &&
6056 ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) )
6058 dx = FT_PIX_ROUND( B1 + dx ) - B1;
6059 dy = FT_PIX_ROUND( B1 + dy ) - B1;
6062 if ( !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) &&
6063 ( ( CUR.is_composite && CUR.GS.freeVector.y != 0 ) ||
6064 ( CUR.zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) ||
6065 ( CUR.sph_tweak_flags & SPH_TWEAK_DO_SHPIX ) ) )
6066 MOVE_Zp2_Point( point, dx, dy, TRUE );
6069 /* save new point */
6070 if ( CUR.GS.freeVector.y != 0 )
6071 B2 = CUR.zp2.cur[point].y;
6073 B2 = CUR.zp2.cur[point].x;
6075 /* reverse any disallowed moves */
6076 if ( ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
6077 CUR.GS.freeVector.y != 0 &&
6081 ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES ) &&
6082 CUR.GS.freeVector.y != 0 &&
6086 !CUR.size->ttfautohinted ) )
6089 printf( "Reversing ZP2 move\n" );
6091 MOVE_Zp2_Point( point, -dx, -dy, TRUE );
6095 MOVE_Zp2_Point( point, dx, dy, TRUE );
6099 MOVE_Zp2_Point( point, dx, dy, TRUE );
6100 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6107 CUR.new_top = CUR.args;
6111 /*************************************************************************/
6113 /* MSIRP[a]: Move Stack Indirect Relative Position */
6114 /* Opcode range: 0x3A-0x3B */
6115 /* Stack: f26.6 uint32 --> */
6118 Ins_MSIRP( INS_ARG )
6121 FT_F26Dot6 distance;
6122 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6123 FT_F26Dot6 control_value_cutin;
6126 control_value_cutin = CUR.GS.control_value_cutin;
6128 if ( CUR.ignore_x_mode &&
6129 CUR.GS.freeVector.x != 0 &&
6130 !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6131 control_value_cutin = 0;
6132 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6134 point = (FT_UShort)args[0];
6136 if ( BOUNDS( point, CUR.zp1.n_points ) ||
6137 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
6139 if ( CUR.pedantic_hinting )
6140 CUR.error = TT_Err_Invalid_Reference;
6144 /* UNDOCUMENTED! The MS rasterizer does that with */
6145 /* twilight points (confirmed by Greg Hitchcock) */
6146 if ( CUR.GS.gep1 == 0 )
6148 CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
6149 CUR_Func_move_orig( &CUR.zp1, point, args[1] );
6150 CUR.zp1.cur[point] = CUR.zp1.org[point];
6153 distance = CUR_Func_project( CUR.zp1.cur + point,
6154 CUR.zp0.cur + CUR.GS.rp0 );
6156 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6157 /* subpixel hinting - make MSIRP respect CVT cut-in; */
6158 if ( CUR.ignore_x_mode &&
6159 CUR.GS.freeVector.x != 0 &&
6160 FT_ABS( distance - args[1] ) >= control_value_cutin )
6162 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6164 CUR_Func_move( &CUR.zp1, point, args[1] - distance );
6166 CUR.GS.rp1 = CUR.GS.rp0;
6169 if ( ( CUR.opcode & 1 ) != 0 )
6174 /*************************************************************************/
6176 /* MDAP[a]: Move Direct Absolute Point */
6177 /* Opcode range: 0x2E-0x2F */
6178 /* Stack: uint32 --> */
6184 FT_F26Dot6 cur_dist;
6185 FT_F26Dot6 distance;
6188 point = (FT_UShort)args[0];
6190 if ( BOUNDS( point, CUR.zp0.n_points ) )
6192 if ( CUR.pedantic_hinting )
6193 CUR.error = TT_Err_Invalid_Reference;
6197 if ( ( CUR.opcode & 1 ) != 0 )
6199 cur_dist = CUR_fast_project( &CUR.zp0.cur[point] );
6200 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6201 if ( CUR.ignore_x_mode &&
6202 CUR.GS.freeVector.x != 0 )
6203 distance = ROUND_None(
6205 CUR.tt_metrics.compensations[0] ) - cur_dist;
6208 distance = CUR_Func_round(
6210 CUR.tt_metrics.compensations[0] ) - cur_dist;
6215 CUR_Func_move( &CUR.zp0, point, distance );
6222 /*************************************************************************/
6224 /* MIAP[a]: Move Indirect Absolute Point */
6225 /* Opcode range: 0x3E-0x3F */
6226 /* Stack: uint32 uint32 --> */
6233 FT_F26Dot6 distance;
6234 FT_F26Dot6 org_dist;
6235 FT_F26Dot6 control_value_cutin;
6238 control_value_cutin = CUR.GS.control_value_cutin;
6239 cvtEntry = (FT_ULong)args[1];
6240 point = (FT_UShort)args[0];
6242 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6243 if ( CUR.ignore_x_mode &&
6244 CUR.GS.freeVector.x != 0 &&
6245 !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6246 control_value_cutin = 0;
6247 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6249 if ( BOUNDS( point, CUR.zp0.n_points ) ||
6250 BOUNDSL( cvtEntry, CUR.cvtSize ) )
6252 if ( CUR.pedantic_hinting )
6253 CUR.error = TT_Err_Invalid_Reference;
6259 /* The behaviour of an MIAP instruction is quite different when used */
6260 /* in the twilight zone. */
6262 /* First, no control value cut-in test is performed as it would fail */
6263 /* anyway. Second, the original point, i.e. (org_x,org_y) of */
6264 /* zp0.point, is set to the absolute, unrounded distance found in the */
6267 /* This is used in the CVT programs of the Microsoft fonts Arial, */
6268 /* Times, etc., in order to re-adjust some key font heights. It */
6269 /* allows the use of the IP instruction in the twilight zone, which */
6270 /* otherwise would be invalid according to the specification. */
6272 /* We implement it with a special sequence for the twilight zone. */
6273 /* This is a bad hack, but it seems to work. */
6275 /* Confirmed by Greg Hitchcock. */
6277 distance = CUR_Func_read_cvt( cvtEntry );
6279 if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */
6281 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6282 /* only adjust legacy fonts x otherwise breaks Calibri italic */
6283 if ( CUR.compatibility_mode )
6284 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6285 CUR.zp0.org[point].x = TT_MulFix14( (FT_UInt32)distance,
6286 CUR.GS.freeVector.x );
6287 CUR.zp0.org[point].y = TT_MulFix14( (FT_UInt32)distance,
6288 CUR.GS.freeVector.y ),
6289 CUR.zp0.cur[point] = CUR.zp0.org[point];
6291 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6292 if ( ( CUR.sph_tweak_flags & SPH_TWEAK_MIAP_HACK ) &&
6294 CUR.GS.freeVector.y != 0 )
6296 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6298 org_dist = CUR_fast_project( &CUR.zp0.cur[point] );
6300 if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cut-in flag */
6302 if ( FT_ABS( distance - org_dist ) > control_value_cutin )
6303 distance = org_dist;
6305 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6306 if ( CUR.ignore_x_mode &&
6307 CUR.GS.freeVector.x != 0 )
6308 distance = ROUND_None( distance,
6309 CUR.tt_metrics.compensations[0] );
6312 distance = CUR_Func_round( distance,
6313 CUR.tt_metrics.compensations[0] );
6316 CUR_Func_move( &CUR.zp0, point, distance - org_dist );
6324 /*************************************************************************/
6326 /* MDRP[abcde]: Move Direct Relative Point */
6327 /* Opcode range: 0xC0-0xDF */
6328 /* Stack: uint32 --> */
6334 FT_F26Dot6 org_dist, distance, minimum_distance;
6337 minimum_distance = CUR.GS.minimum_distance;
6339 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6340 if ( CUR.ignore_x_mode &&
6341 CUR.GS.freeVector.x != 0 &&
6342 !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6343 minimum_distance = 0;
6344 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6347 point = (FT_UShort)args[0];
6349 if ( BOUNDS( point, CUR.zp1.n_points ) ||
6350 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
6352 if ( CUR.pedantic_hinting )
6353 CUR.error = TT_Err_Invalid_Reference;
6357 /* XXX: Is there some undocumented feature while in the */
6358 /* twilight zone? */
6360 /* XXX: UNDOCUMENTED: twilight zone special case */
6362 if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
6364 FT_Vector* vec1 = &CUR.zp1.org[point];
6365 FT_Vector* vec2 = &CUR.zp0.org[CUR.GS.rp0];
6368 org_dist = CUR_Func_dualproj( vec1, vec2 );
6372 FT_Vector* vec1 = &CUR.zp1.orus[point];
6373 FT_Vector* vec2 = &CUR.zp0.orus[CUR.GS.rp0];
6376 if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
6378 /* this should be faster */
6379 org_dist = CUR_Func_dualproj( vec1, vec2 );
6380 org_dist = FT_MulFix( org_dist, CUR.metrics.x_scale );
6387 vec.x = FT_MulFix( vec1->x - vec2->x, CUR.metrics.x_scale );
6388 vec.y = FT_MulFix( vec1->y - vec2->y, CUR.metrics.y_scale );
6390 org_dist = CUR_fast_dualproj( &vec );
6394 /* single width cut-in test */
6396 if ( FT_ABS( org_dist - CUR.GS.single_width_value ) <
6397 CUR.GS.single_width_cutin )
6399 if ( org_dist >= 0 )
6400 org_dist = CUR.GS.single_width_value;
6402 org_dist = -CUR.GS.single_width_value;
6407 if ( ( CUR.opcode & 4 ) != 0 )
6409 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6410 if ( CUR.ignore_x_mode && CUR.GS.freeVector.x != 0 )
6411 distance = ROUND_None(
6413 CUR.tt_metrics.compensations[CUR.opcode & 3] );
6416 distance = CUR_Func_round(
6418 CUR.tt_metrics.compensations[CUR.opcode & 3] );
6421 distance = ROUND_None(
6423 CUR.tt_metrics.compensations[CUR.opcode & 3] );
6425 /* minimum distance flag */
6427 if ( ( CUR.opcode & 8 ) != 0 )
6429 if ( org_dist >= 0 )
6431 if ( distance < minimum_distance )
6432 distance = minimum_distance;
6436 if ( distance > -minimum_distance )
6437 distance = -minimum_distance;
6441 /* now move the point */
6443 org_dist = CUR_Func_project( CUR.zp1.cur + point,
6444 CUR.zp0.cur + CUR.GS.rp0 );
6446 CUR_Func_move( &CUR.zp1, point, distance - org_dist );
6449 CUR.GS.rp1 = CUR.GS.rp0;
6452 if ( ( CUR.opcode & 16 ) != 0 )
6457 /*************************************************************************/
6459 /* MIRP[abcde]: Move Indirect Relative Point */
6460 /* Opcode range: 0xE0-0xFF */
6461 /* Stack: int32? uint32 --> */
6469 FT_F26Dot6 cvt_dist,
6473 control_value_cutin,
6475 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6478 FT_Bool reverse_move = FALSE;
6479 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6482 minimum_distance = CUR.GS.minimum_distance;
6483 control_value_cutin = CUR.GS.control_value_cutin;
6484 point = (FT_UShort)args[0];
6485 cvtEntry = (FT_ULong)( args[1] + 1 );
6487 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6488 if ( CUR.ignore_x_mode &&
6489 CUR.GS.freeVector.x != 0 &&
6490 !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6491 control_value_cutin = minimum_distance = 0;
6492 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6494 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
6496 if ( BOUNDS( point, CUR.zp1.n_points ) ||
6497 BOUNDSL( cvtEntry, CUR.cvtSize + 1 ) ||
6498 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
6500 if ( CUR.pedantic_hinting )
6501 CUR.error = TT_Err_Invalid_Reference;
6508 cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
6509 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6510 if ( CUR.sph_tweak_flags & SPH_TWEAK_MIRP_CVT_ZERO )
6514 /* single width test */
6516 if ( FT_ABS( cvt_dist - CUR.GS.single_width_value ) <
6517 CUR.GS.single_width_cutin )
6519 if ( cvt_dist >= 0 )
6520 cvt_dist = CUR.GS.single_width_value;
6522 cvt_dist = -CUR.GS.single_width_value;
6525 /* UNDOCUMENTED! The MS rasterizer does that with */
6526 /* twilight points (confirmed by Greg Hitchcock) */
6527 if ( CUR.GS.gep1 == 0 )
6529 CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +
6530 TT_MulFix14( (FT_UInt32)cvt_dist,
6531 CUR.GS.freeVector.x );
6532 CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
6533 TT_MulFix14( (FT_UInt32)cvt_dist,
6534 CUR.GS.freeVector.y );
6535 CUR.zp1.cur[point] = CUR.zp1.org[point];
6538 org_dist = CUR_Func_dualproj( &CUR.zp1.org[point],
6539 &CUR.zp0.org[CUR.GS.rp0] );
6540 cur_dist = CUR_Func_project ( &CUR.zp1.cur[point],
6541 &CUR.zp0.cur[CUR.GS.rp0] );
6543 /* auto-flip test */
6545 if ( CUR.GS.auto_flip )
6547 if ( ( org_dist ^ cvt_dist ) < 0 )
6548 cvt_dist = -cvt_dist;
6550 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6551 if ( CUR.GS.freeVector.y != 0 &&
6552 ( CUR.sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) )
6554 if ( cur_dist < -64 )
6556 else if ( cur_dist > 64 && cur_dist < 84 )
6559 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6560 /* control value cut-in and round */
6562 if ( ( CUR.opcode & 4 ) != 0 )
6564 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
6565 /* refer to the same zone. */
6567 if ( CUR.GS.gep0 == CUR.GS.gep1 )
6569 /* XXX: According to Greg Hitchcock, the following wording is */
6570 /* the right one: */
6572 /* When the absolute difference between the value in */
6573 /* the table [CVT] and the measurement directly from */
6574 /* the outline is _greater_ than the cut_in value, the */
6575 /* outline measurement is used. */
6577 /* This is from `instgly.doc'. The description in */
6578 /* `ttinst2.doc', version 1.66, is thus incorrect since */
6579 /* it implies `>=' instead of `>'. */
6581 if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin )
6582 cvt_dist = org_dist;
6585 distance = CUR_Func_round(
6587 CUR.tt_metrics.compensations[CUR.opcode & 3] );
6590 distance = ROUND_None(
6592 CUR.tt_metrics.compensations[CUR.opcode & 3] );
6594 /* minimum distance test */
6596 if ( ( CUR.opcode & 8 ) != 0 )
6598 if ( org_dist >= 0 )
6600 if ( distance < minimum_distance )
6601 distance = minimum_distance;
6605 if ( distance > -minimum_distance )
6606 distance = -minimum_distance;
6610 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6611 B1 = CUR.zp1.cur[point].y;
6613 /* Round moves if necessary */
6614 if ( CUR.ignore_x_mode &&
6615 CUR.GS.freeVector.y != 0 &&
6616 ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) )
6617 distance = FT_PIX_ROUND( B1 + distance - cur_dist ) - B1 + cur_dist;
6619 if ( CUR.GS.freeVector.y != 0 &&
6620 ( CUR.opcode & 16 ) == 0 &&
6621 ( CUR.opcode & 8 ) == 0 &&
6622 ( CUR.sph_tweak_flags & SPH_TWEAK_COURIER_NEW_2_HACK ) )
6624 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6626 CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
6628 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6629 B2 = CUR.zp1.cur[point].y;
6631 /* Reverse move if necessary */
6632 if ( CUR.ignore_x_mode )
6634 if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES ) &&
6635 CUR.GS.freeVector.y != 0 &&
6638 !CUR.size->ttfautohinted )
6639 reverse_move = TRUE;
6641 if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
6642 CUR.GS.freeVector.y != 0 &&
6645 reverse_move = TRUE;
6647 if ( ( CUR.sph_tweak_flags &
6648 SPH_TWEAK_DELTAP_SKIP_EXAGGERATED_VALUES ) &&
6650 FT_ABS( B1 - B2 ) >= 64 )
6651 reverse_move = TRUE;
6655 CUR_Func_move( &CUR.zp1, point, -( distance - cur_dist ) );
6657 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6660 CUR.GS.rp1 = CUR.GS.rp0;
6662 if ( ( CUR.opcode & 16 ) != 0 )
6669 /*************************************************************************/
6671 /* ALIGNRP[]: ALIGN Relative Point */
6672 /* Opcode range: 0x3C */
6673 /* Stack: uint32 uint32... --> */
6676 Ins_ALIGNRP( INS_ARG )
6679 FT_F26Dot6 distance;
6684 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6685 if ( CUR.ignore_x_mode &&
6687 ( CUR.sph_tweak_flags & SPH_TWEAK_NO_ALIGNRP_AFTER_IUP ) )
6689 CUR.error = TT_Err_Invalid_Reference;
6692 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6694 if ( CUR.top < CUR.GS.loop ||
6695 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
6697 if ( CUR.pedantic_hinting )
6698 CUR.error = TT_Err_Invalid_Reference;
6702 while ( CUR.GS.loop > 0 )
6706 point = (FT_UShort)CUR.stack[CUR.args];
6708 if ( BOUNDS( point, CUR.zp1.n_points ) )
6710 if ( CUR.pedantic_hinting )
6712 CUR.error = TT_Err_Invalid_Reference;
6718 distance = CUR_Func_project( CUR.zp1.cur + point,
6719 CUR.zp0.cur + CUR.GS.rp0 );
6721 CUR_Func_move( &CUR.zp1, point, -distance );
6729 CUR.new_top = CUR.args;
6733 /*************************************************************************/
6735 /* ISECT[]: moves point to InterSECTion */
6736 /* Opcode range: 0x0F */
6737 /* Stack: 5 * uint32 --> */
6740 Ins_ISECT( INS_ARG )
6746 FT_F26Dot6 discriminant, dotproduct;
6757 point = (FT_UShort)args[0];
6759 a0 = (FT_UShort)args[1];
6760 a1 = (FT_UShort)args[2];
6761 b0 = (FT_UShort)args[3];
6762 b1 = (FT_UShort)args[4];
6764 if ( BOUNDS( b0, CUR.zp0.n_points ) ||
6765 BOUNDS( b1, CUR.zp0.n_points ) ||
6766 BOUNDS( a0, CUR.zp1.n_points ) ||
6767 BOUNDS( a1, CUR.zp1.n_points ) ||
6768 BOUNDS( point, CUR.zp2.n_points ) )
6770 if ( CUR.pedantic_hinting )
6771 CUR.error = TT_Err_Invalid_Reference;
6777 dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
6778 dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
6780 dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;
6781 day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;
6783 dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;
6784 dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;
6786 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
6788 discriminant = FT_MulDiv( dax, -dby, 0x40 ) +
6789 FT_MulDiv( day, dbx, 0x40 );
6790 dotproduct = FT_MulDiv( dax, dbx, 0x40 ) +
6791 FT_MulDiv( day, dby, 0x40 );
6793 /* The discriminant above is actually a cross product of vectors */
6794 /* da and db. Together with the dot product, they can be used as */
6795 /* surrogates for sine and cosine of the angle between the vectors. */
6797 /* dotproduct = |da||db|cos(angle) */
6798 /* discriminant = |da||db|sin(angle) . */
6799 /* We use these equations to reject grazing intersections by */
6800 /* thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. */
6801 if ( 19 * FT_ABS( discriminant ) > FT_ABS( dotproduct ) )
6803 val = FT_MulDiv( dx, -dby, 0x40 ) + FT_MulDiv( dy, dbx, 0x40 );
6805 R.x = FT_MulDiv( val, dax, discriminant );
6806 R.y = FT_MulDiv( val, day, discriminant );
6808 CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
6809 CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
6813 /* else, take the middle of the middles of A and B */
6815 CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +
6818 CUR.zp0.cur[b1].x ) / 4;
6819 CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +
6822 CUR.zp0.cur[b1].y ) / 4;
6827 /*************************************************************************/
6829 /* ALIGNPTS[]: ALIGN PoinTS */
6830 /* Opcode range: 0x27 */
6831 /* Stack: uint32 uint32 --> */
6834 Ins_ALIGNPTS( INS_ARG )
6837 FT_F26Dot6 distance;
6840 p1 = (FT_UShort)args[0];
6841 p2 = (FT_UShort)args[1];
6843 if ( BOUNDS( p1, CUR.zp1.n_points ) ||
6844 BOUNDS( p2, CUR.zp0.n_points ) )
6846 if ( CUR.pedantic_hinting )
6847 CUR.error = TT_Err_Invalid_Reference;
6851 distance = CUR_Func_project( CUR.zp0.cur + p2,
6852 CUR.zp1.cur + p1 ) / 2;
6854 CUR_Func_move( &CUR.zp1, p1, distance );
6855 CUR_Func_move( &CUR.zp0, p2, -distance );
6859 /*************************************************************************/
6861 /* IP[]: Interpolate Point */
6862 /* Opcode range: 0x39 */
6863 /* Stack: uint32... --> */
6866 /* SOMETIMES, DUMBER CODE IS BETTER CODE */
6871 FT_F26Dot6 old_range, cur_range;
6872 FT_Vector* orus_base;
6873 FT_Vector* cur_base;
6879 if ( CUR.top < CUR.GS.loop )
6881 if ( CUR.pedantic_hinting )
6882 CUR.error = TT_Err_Invalid_Reference;
6887 * We need to deal in a special way with the twilight zone.
6888 * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0),
6891 twilight = CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 || CUR.GS.gep2 == 0;
6893 if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) )
6895 if ( CUR.pedantic_hinting )
6896 CUR.error = TT_Err_Invalid_Reference;
6901 orus_base = &CUR.zp0.org[CUR.GS.rp1];
6903 orus_base = &CUR.zp0.orus[CUR.GS.rp1];
6905 cur_base = &CUR.zp0.cur[CUR.GS.rp1];
6907 /* XXX: There are some glyphs in some braindead but popular */
6908 /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
6909 /* calling IP[] with bad values of rp[12]. */
6910 /* Do something sane when this odd thing happens. */
6911 if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
6912 BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
6920 old_range = CUR_Func_dualproj( &CUR.zp1.org[CUR.GS.rp2],
6922 else if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
6923 old_range = CUR_Func_dualproj( &CUR.zp1.orus[CUR.GS.rp2],
6930 vec.x = FT_MulFix( CUR.zp1.orus[CUR.GS.rp2].x - orus_base->x,
6931 CUR.metrics.x_scale );
6932 vec.y = FT_MulFix( CUR.zp1.orus[CUR.GS.rp2].y - orus_base->y,
6933 CUR.metrics.y_scale );
6935 old_range = CUR_fast_dualproj( &vec );
6938 cur_range = CUR_Func_project ( &CUR.zp1.cur[CUR.GS.rp2], cur_base );
6941 for ( ; CUR.GS.loop > 0; --CUR.GS.loop )
6943 FT_UInt point = (FT_UInt)CUR.stack[--CUR.args];
6944 FT_F26Dot6 org_dist, cur_dist, new_dist;
6947 /* check point bounds */
6948 if ( BOUNDS( point, CUR.zp2.n_points ) )
6950 if ( CUR.pedantic_hinting )
6952 CUR.error = TT_Err_Invalid_Reference;
6959 org_dist = CUR_Func_dualproj( &CUR.zp2.org[point], orus_base );
6960 else if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
6961 org_dist = CUR_Func_dualproj( &CUR.zp2.orus[point], orus_base );
6967 vec.x = FT_MulFix( CUR.zp2.orus[point].x - orus_base->x,
6968 CUR.metrics.x_scale );
6969 vec.y = FT_MulFix( CUR.zp2.orus[point].y - orus_base->y,
6970 CUR.metrics.y_scale );
6972 org_dist = CUR_fast_dualproj( &vec );
6975 cur_dist = CUR_Func_project ( &CUR.zp2.cur[point], cur_base );
6978 new_dist = ( old_range != 0 )
6979 ? FT_MulDiv( org_dist, cur_range, old_range )
6984 CUR_Func_move( &CUR.zp2, (FT_UShort)point, new_dist - cur_dist );
6989 CUR.new_top = CUR.args;
6993 /*************************************************************************/
6995 /* UTP[a]: UnTouch Point */
6996 /* Opcode range: 0x29 */
6997 /* Stack: uint32 --> */
7006 point = (FT_UShort)args[0];
7008 if ( BOUNDS( point, CUR.zp0.n_points ) )
7010 if ( CUR.pedantic_hinting )
7011 CUR.error = TT_Err_Invalid_Reference;
7017 if ( CUR.GS.freeVector.x != 0 )
7018 mask &= ~FT_CURVE_TAG_TOUCH_X;
7020 if ( CUR.GS.freeVector.y != 0 )
7021 mask &= ~FT_CURVE_TAG_TOUCH_Y;
7023 CUR.zp0.tags[point] &= mask;
7027 /* Local variables for Ins_IUP: */
7028 typedef struct IUP_WorkerRec_
7030 FT_Vector* orgs; /* original and current coordinate */
7031 FT_Vector* curs; /* arrays */
7035 } IUP_WorkerRec, *IUP_Worker;
7039 _iup_worker_shift( IUP_Worker worker,
7048 dx = worker->curs[p].x - worker->orgs[p].x;
7051 for ( i = p1; i < p; i++ )
7052 worker->curs[i].x += dx;
7054 for ( i = p + 1; i <= p2; i++ )
7055 worker->curs[i].x += dx;
7061 _iup_worker_interpolate( IUP_Worker worker,
7068 FT_F26Dot6 orus1, orus2, org1, org2, delta1, delta2;
7074 if ( BOUNDS( ref1, worker->max_points ) ||
7075 BOUNDS( ref2, worker->max_points ) )
7078 orus1 = worker->orus[ref1].x;
7079 orus2 = worker->orus[ref2].x;
7081 if ( orus1 > orus2 )
7096 org1 = worker->orgs[ref1].x;
7097 org2 = worker->orgs[ref2].x;
7098 delta1 = worker->curs[ref1].x - org1;
7099 delta2 = worker->curs[ref2].x - org2;
7101 if ( orus1 == orus2 )
7103 /* simple shift of untouched points */
7104 for ( i = p1; i <= p2; i++ )
7106 FT_F26Dot6 x = worker->orgs[i].x;
7114 worker->curs[i].x = x;
7120 FT_Bool scale_valid = 0;
7124 for ( i = p1; i <= p2; i++ )
7126 FT_F26Dot6 x = worker->orgs[i].x;
7132 else if ( x >= org2 )
7140 scale = FT_DivFix( org2 + delta2 - ( org1 + delta1 ),
7144 x = ( org1 + delta1 ) +
7145 FT_MulFix( worker->orus[i].x - orus1, scale );
7147 worker->curs[i].x = x;
7153 /*************************************************************************/
7155 /* IUP[a]: Interpolate Untouched Points */
7156 /* Opcode range: 0x30-0x31 */
7165 FT_UInt first_point; /* first point of contour */
7166 FT_UInt end_point; /* end point (last+1) of contour */
7168 FT_UInt first_touched; /* first touched point in contour */
7169 FT_UInt cur_touched; /* current touched point in contour */
7171 FT_UInt point; /* current point */
7172 FT_Short contour; /* current contour */
7177 /* ignore empty outlines */
7178 if ( CUR.pts.n_contours == 0 )
7181 if ( CUR.opcode & 1 )
7183 mask = FT_CURVE_TAG_TOUCH_X;
7184 V.orgs = CUR.pts.org;
7185 V.curs = CUR.pts.cur;
7186 V.orus = CUR.pts.orus;
7190 mask = FT_CURVE_TAG_TOUCH_Y;
7191 V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
7192 V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
7193 V.orus = (FT_Vector*)( (FT_Pos*)CUR.pts.orus + 1 );
7195 V.max_points = CUR.pts.n_points;
7200 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
7201 if ( CUR.ignore_x_mode )
7204 if ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_IUP )
7207 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
7211 end_point = CUR.pts.contours[contour] - CUR.pts.first_point;
7212 first_point = point;
7214 if ( BOUNDS ( end_point, CUR.pts.n_points ) )
7215 end_point = CUR.pts.n_points - 1;
7217 while ( point <= end_point && ( CUR.pts.tags[point] & mask ) == 0 )
7220 if ( point <= end_point )
7222 first_touched = point;
7223 cur_touched = point;
7227 while ( point <= end_point )
7229 if ( ( CUR.pts.tags[point] & mask ) != 0 )
7231 _iup_worker_interpolate( &V,
7236 cur_touched = point;
7242 if ( cur_touched == first_touched )
7243 _iup_worker_shift( &V, first_point, end_point, cur_touched );
7246 _iup_worker_interpolate( &V,
7247 (FT_UShort)( cur_touched + 1 ),
7252 if ( first_touched > 0 )
7253 _iup_worker_interpolate( &V,
7261 } while ( contour < CUR.pts.n_contours );
7265 /*************************************************************************/
7267 /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
7268 /* Opcode range: 0x5D,0x71,0x72 */
7269 /* Stack: uint32 (2 * uint32)... --> */
7272 Ins_DELTAP( INS_ARG )
7278 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
7283 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
7284 /* Delta hinting is covered by US Patent 5159668. */
7285 if ( CUR.face->unpatented_hinting )
7287 FT_Long n = args[0] * 2;
7292 if ( CUR.pedantic_hinting )
7293 CUR.error = TT_Err_Too_Few_Arguments;
7298 CUR.new_top = CUR.args;
7303 nump = (FT_ULong)args[0]; /* some points theoretically may occur more
7304 than once, thus UShort isn't enough */
7306 for ( k = 1; k <= nump; k++ )
7310 if ( CUR.pedantic_hinting )
7311 CUR.error = TT_Err_Too_Few_Arguments;
7318 A = (FT_UShort)CUR.stack[CUR.args + 1];
7319 B = CUR.stack[CUR.args];
7321 /* XXX: Because some popular fonts contain some invalid DeltaP */
7322 /* instructions, we simply ignore them when the stacked */
7323 /* point reference is off limit, rather than returning an */
7324 /* error. As a delta instruction doesn't change a glyph */
7325 /* in great ways, this shouldn't be a problem. */
7327 if ( !BOUNDS( A, CUR.zp0.n_points ) )
7329 C = ( (FT_ULong)B & 0xF0 ) >> 4;
7331 switch ( CUR.opcode )
7345 C += CUR.GS.delta_base;
7347 if ( CURRENT_Ppem() == (FT_Long)C )
7349 B = ( (FT_ULong)B & 0xF ) - 8;
7352 B = B * 64 / ( 1L << CUR.GS.delta_shift );
7354 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
7356 * Allow delta move if
7358 * - not using ignore_x_mode rendering
7359 * - glyph is specifically set to allow it
7360 * - glyph is composite and freedom vector is not subpixel vector
7362 if ( !CUR.ignore_x_mode ||
7363 ( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_DO_DELTAP ) ||
7364 ( CUR.is_composite && CUR.GS.freeVector.y != 0 ) )
7365 CUR_Func_move( &CUR.zp0, A, B );
7367 /* Otherwise apply subpixel hinting and compatibility mode rules */
7368 else if ( CUR.ignore_x_mode )
7370 if ( CUR.GS.freeVector.y != 0 )
7371 B1 = CUR.zp0.cur[A].y;
7373 B1 = CUR.zp0.cur[A].x;
7375 /* Standard Subpixel Hinting: Allow y move */
7376 if ( !CUR.compatibility_mode && CUR.GS.freeVector.y != 0 )
7377 CUR_Func_move( &CUR.zp0, A, B );
7379 /* Compatibility Mode: Allow x or y move if point touched in
7381 else if ( CUR.compatibility_mode &&
7382 !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) )
7384 /* save the y value of the point now; compare after move */
7385 B1 = CUR.zp0.cur[A].y;
7387 if ( ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) )
7388 B = FT_PIX_ROUND( B1 + B ) - B1;
7391 * Allow delta move if using compatibility_mode, IUP has not
7392 * been called, and point is touched on Y.
7394 if ( !CUR.iup_called &&
7395 ( CUR.zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) )
7396 CUR_Func_move( &CUR.zp0, A, B );
7399 B2 = CUR.zp0.cur[A].y;
7401 /* Reverse this move if it results in a disallowed move */
7402 if ( CUR.GS.freeVector.y != 0 &&
7403 ( ( ( CUR.sph_tweak_flags &
7404 SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES ) &&
7407 !CUR.size->ttfautohinted ) ||
7408 ( ( CUR.sph_tweak_flags &
7409 SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
7412 CUR_Func_move( &CUR.zp0, A, -B );
7415 CUR_Func_move( &CUR.zp0, A, B );
7416 #endif /* *TT_CONFIG_OPTION_SUBPIXEL_HINTING */
7420 if ( CUR.pedantic_hinting )
7421 CUR.error = TT_Err_Invalid_Reference;
7425 CUR.new_top = CUR.args;
7429 /*************************************************************************/
7431 /* DELTACn[]: DELTA exceptions C1, C2, C3 */
7432 /* Opcode range: 0x73,0x74,0x75 */
7433 /* Stack: uint32 (2 * uint32)... --> */
7436 Ins_DELTAC( INS_ARG )
7443 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
7444 /* Delta hinting is covered by US Patent 5159668. */
7445 if ( CUR.face->unpatented_hinting )
7447 FT_Long n = args[0] * 2;
7452 if ( CUR.pedantic_hinting )
7453 CUR.error = TT_Err_Too_Few_Arguments;
7458 CUR.new_top = CUR.args;
7463 nump = (FT_ULong)args[0];
7465 for ( k = 1; k <= nump; k++ )
7469 if ( CUR.pedantic_hinting )
7470 CUR.error = TT_Err_Too_Few_Arguments;
7477 A = (FT_ULong)CUR.stack[CUR.args + 1];
7478 B = CUR.stack[CUR.args];
7480 if ( BOUNDSL( A, CUR.cvtSize ) )
7482 if ( CUR.pedantic_hinting )
7484 CUR.error = TT_Err_Invalid_Reference;
7490 C = ( (FT_ULong)B & 0xF0 ) >> 4;
7492 switch ( CUR.opcode )
7506 C += CUR.GS.delta_base;
7508 if ( CURRENT_Ppem() == (FT_Long)C )
7510 B = ( (FT_ULong)B & 0xF ) - 8;
7513 B = B * 64 / ( 1L << CUR.GS.delta_shift );
7515 CUR_Func_move_cvt( A, B );
7521 CUR.new_top = CUR.args;
7525 /*************************************************************************/
7527 /* MISC. INSTRUCTIONS */
7529 /*************************************************************************/
7532 /*************************************************************************/
7534 /* GETINFO[]: GET INFOrmation */
7535 /* Opcode range: 0x88 */
7536 /* Stack: uint32 --> uint32 */
7539 Ins_GETINFO( INS_ARG )
7546 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
7547 /********************************/
7548 /* RASTERIZER VERSION */
7549 /* Selector Bit: 0 */
7550 /* Return Bit(s): 0-7 */
7552 if ( ( args[0] & 1 ) != 0 && CUR.ignore_x_mode )
7554 K = CUR.rasterizer_version;
7555 #ifdef SPH_DEBUG_MORE_VERBOSE
7556 printf(" SETTING AS %d\n", CUR.rasterizer_version );
7560 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
7561 if ( ( args[0] & 1 ) != 0 )
7564 /********************************/
7566 /* Selector Bit: 1 */
7567 /* Return Bit(s): 8 */
7569 if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated )
7572 /********************************/
7573 /* GLYPH STRETCHED */
7574 /* Selector Bit: 2 */
7575 /* Return Bit(s): 9 */
7577 if ( ( args[0] & 4 ) != 0 && CUR.tt_metrics.stretched )
7580 /********************************/
7581 /* HINTING FOR GRAYSCALE */
7582 /* Selector Bit: 5 */
7583 /* Return Bit(s): 12 */
7585 if ( ( args[0] & 32 ) != 0 && CUR.grayscale )
7588 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
7589 if ( CUR.ignore_x_mode && CUR.rasterizer_version >= 35 )
7591 /********************************/
7592 /* HINTING FOR GRAYSCALE */
7593 /* Selector Bit: 5 */
7594 /* Return Bit(s): 12 */
7596 if ( ( args[0] & 32 ) != 0 && CUR.grayscale_hinting )
7599 /********************************/
7600 /* HINTING FOR SUBPIXEL */
7601 /* Selector Bit: 6 */
7602 /* Return Bit(s): 13 */
7604 if ( ( args[0] & 64 ) != 0 &&
7605 CUR.subpixel_hinting &&
7606 CUR.rasterizer_version >= 37 )
7610 /* the stuff below is irrelevant if subpixel_hinting is not set */
7612 /********************************/
7613 /* COMPATIBLE WIDTHS ENABLED */
7614 /* Selector Bit: 7 */
7615 /* Return Bit(s): 14 */
7617 /* Functionality still needs to be added */
7618 if ( ( args[0] & 128 ) != 0 && CUR.compatible_widths )
7621 /********************************/
7622 /* SYMMETRICAL SMOOTHING */
7623 /* Selector Bit: 8 */
7624 /* Return Bit(s): 15 */
7626 /* Functionality still needs to be added */
7627 if ( ( args[0] & 256 ) != 0 && CUR.symmetrical_smoothing )
7630 /********************************/
7631 /* HINTING FOR BGR? */
7632 /* Selector Bit: 9 */
7633 /* Return Bit(s): 16 */
7635 /* Functionality still needs to be added */
7636 if ( ( args[0] & 512 ) != 0 && CUR.bgr )
7639 if ( CUR.rasterizer_version >= 38 )
7641 /********************************/
7642 /* SUBPIXEL POSITIONED? */
7643 /* Selector Bit: 10 */
7644 /* Return Bit(s): 17 */
7646 /* Functionality still needs to be added */
7647 if ( ( args[0] & 1024 ) != 0 && CUR.subpixel_positioned )
7652 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
7658 Ins_UNKNOWN( INS_ARG )
7660 TT_DefRecord* def = CUR.IDefs;
7661 TT_DefRecord* limit = def + CUR.numIDefs;
7666 for ( ; def < limit; def++ )
7668 if ( (FT_Byte)def->opc == CUR.opcode && def->active )
7673 if ( CUR.callTop >= CUR.callSize )
7675 CUR.error = TT_Err_Stack_Overflow;
7679 call = CUR.callStack + CUR.callTop++;
7681 call->Caller_Range = CUR.curRange;
7682 call->Caller_IP = CUR.IP + 1;
7683 call->Cur_Count = 1;
7684 call->Cur_Restart = def->start;
7685 call->Cur_End = def->end;
7687 INS_Goto_CodeRange( def->range, def->start );
7689 CUR.step_ins = FALSE;
7694 CUR.error = TT_Err_Invalid_Opcode;
7698 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
7702 TInstruction_Function Instruct_Dispatch[256] =
7704 /* Opcodes are gathered in groups of 16. */
7705 /* Please keep the spaces as they are. */
7707 /* SVTCA y */ Ins_SVTCA,
7708 /* SVTCA x */ Ins_SVTCA,
7709 /* SPvTCA y */ Ins_SPVTCA,
7710 /* SPvTCA x */ Ins_SPVTCA,
7711 /* SFvTCA y */ Ins_SFVTCA,
7712 /* SFvTCA x */ Ins_SFVTCA,
7713 /* SPvTL // */ Ins_SPVTL,
7714 /* SPvTL + */ Ins_SPVTL,
7715 /* SFvTL // */ Ins_SFVTL,
7716 /* SFvTL + */ Ins_SFVTL,
7717 /* SPvFS */ Ins_SPVFS,
7718 /* SFvFS */ Ins_SFVFS,
7721 /* SFvTPv */ Ins_SFVTPV,
7722 /* ISECT */ Ins_ISECT,
7724 /* SRP0 */ Ins_SRP0,
7725 /* SRP1 */ Ins_SRP1,
7726 /* SRP2 */ Ins_SRP2,
7727 /* SZP0 */ Ins_SZP0,
7728 /* SZP1 */ Ins_SZP1,
7729 /* SZP2 */ Ins_SZP2,
7730 /* SZPS */ Ins_SZPS,
7731 /* SLOOP */ Ins_SLOOP,
7733 /* RTHG */ Ins_RTHG,
7735 /* ELSE */ Ins_ELSE,
7736 /* JMPR */ Ins_JMPR,
7737 /* SCvTCi */ Ins_SCVTCI,
7738 /* SSwCi */ Ins_SSWCI,
7743 /* CLEAR */ Ins_CLEAR,
7744 /* SWAP */ Ins_SWAP,
7745 /* DEPTH */ Ins_DEPTH,
7746 /* CINDEX */ Ins_CINDEX,
7747 /* MINDEX */ Ins_MINDEX,
7748 /* AlignPTS */ Ins_ALIGNPTS,
7749 /* INS_0x28 */ Ins_UNKNOWN,
7751 /* LOOPCALL */ Ins_LOOPCALL,
7752 /* CALL */ Ins_CALL,
7753 /* FDEF */ Ins_FDEF,
7754 /* ENDF */ Ins_ENDF,
7755 /* MDAP[0] */ Ins_MDAP,
7756 /* MDAP[1] */ Ins_MDAP,
7758 /* IUP[0] */ Ins_IUP,
7759 /* IUP[1] */ Ins_IUP,
7760 /* SHP[0] */ Ins_SHP,
7761 /* SHP[1] */ Ins_SHP,
7762 /* SHC[0] */ Ins_SHC,
7763 /* SHC[1] */ Ins_SHC,
7764 /* SHZ[0] */ Ins_SHZ,
7765 /* SHZ[1] */ Ins_SHZ,
7766 /* SHPIX */ Ins_SHPIX,
7768 /* MSIRP[0] */ Ins_MSIRP,
7769 /* MSIRP[1] */ Ins_MSIRP,
7770 /* AlignRP */ Ins_ALIGNRP,
7771 /* RTDG */ Ins_RTDG,
7772 /* MIAP[0] */ Ins_MIAP,
7773 /* MIAP[1] */ Ins_MIAP,
7775 /* NPushB */ Ins_NPUSHB,
7776 /* NPushW */ Ins_NPUSHW,
7779 /* WCvtP */ Ins_WCVTP,
7780 /* RCvt */ Ins_RCVT,
7783 /* SCFS */ Ins_SCFS,
7786 /* MPPEM */ Ins_MPPEM,
7788 /* FlipON */ Ins_FLIPON,
7789 /* FlipOFF */ Ins_FLIPOFF,
7790 /* DEBUG */ Ins_DEBUG,
7793 /* LTEQ */ Ins_LTEQ,
7795 /* GTEQ */ Ins_GTEQ,
7799 /* EVEN */ Ins_EVEN,
7805 /* DeltaP1 */ Ins_DELTAP,
7815 /* FLOOR */ Ins_FLOOR,
7816 /* CEILING */ Ins_CEILING,
7817 /* ROUND[0] */ Ins_ROUND,
7818 /* ROUND[1] */ Ins_ROUND,
7819 /* ROUND[2] */ Ins_ROUND,
7820 /* ROUND[3] */ Ins_ROUND,
7821 /* NROUND[0] */ Ins_NROUND,
7822 /* NROUND[1] */ Ins_NROUND,
7823 /* NROUND[2] */ Ins_NROUND,
7824 /* NROUND[3] */ Ins_NROUND,
7826 /* WCvtF */ Ins_WCVTF,
7827 /* DeltaP2 */ Ins_DELTAP,
7828 /* DeltaP3 */ Ins_DELTAP,
7829 /* DeltaCn[0] */ Ins_DELTAC,
7830 /* DeltaCn[1] */ Ins_DELTAC,
7831 /* DeltaCn[2] */ Ins_DELTAC,
7832 /* SROUND */ Ins_SROUND,
7833 /* S45Round */ Ins_S45ROUND,
7834 /* JROT */ Ins_JROT,
7835 /* JROF */ Ins_JROF,
7836 /* ROFF */ Ins_ROFF,
7837 /* INS_0x7B */ Ins_UNKNOWN,
7838 /* RUTG */ Ins_RUTG,
7839 /* RDTG */ Ins_RDTG,
7840 /* SANGW */ Ins_SANGW,
7843 /* FlipPT */ Ins_FLIPPT,
7844 /* FlipRgON */ Ins_FLIPRGON,
7845 /* FlipRgOFF */ Ins_FLIPRGOFF,
7846 /* INS_0x83 */ Ins_UNKNOWN,
7847 /* INS_0x84 */ Ins_UNKNOWN,
7848 /* ScanCTRL */ Ins_SCANCTRL,
7849 /* SDPVTL[0] */ Ins_SDPVTL,
7850 /* SDPVTL[1] */ Ins_SDPVTL,
7851 /* GetINFO */ Ins_GETINFO,
7852 /* IDEF */ Ins_IDEF,
7853 /* ROLL */ Ins_ROLL,
7856 /* ScanTYPE */ Ins_SCANTYPE,
7857 /* InstCTRL */ Ins_INSTCTRL,
7858 /* INS_0x8F */ Ins_UNKNOWN,
7860 /* INS_0x90 */ Ins_UNKNOWN,
7861 /* INS_0x91 */ Ins_UNKNOWN,
7862 /* INS_0x92 */ Ins_UNKNOWN,
7863 /* INS_0x93 */ Ins_UNKNOWN,
7864 /* INS_0x94 */ Ins_UNKNOWN,
7865 /* INS_0x95 */ Ins_UNKNOWN,
7866 /* INS_0x96 */ Ins_UNKNOWN,
7867 /* INS_0x97 */ Ins_UNKNOWN,
7868 /* INS_0x98 */ Ins_UNKNOWN,
7869 /* INS_0x99 */ Ins_UNKNOWN,
7870 /* INS_0x9A */ Ins_UNKNOWN,
7871 /* INS_0x9B */ Ins_UNKNOWN,
7872 /* INS_0x9C */ Ins_UNKNOWN,
7873 /* INS_0x9D */ Ins_UNKNOWN,
7874 /* INS_0x9E */ Ins_UNKNOWN,
7875 /* INS_0x9F */ Ins_UNKNOWN,
7877 /* INS_0xA0 */ Ins_UNKNOWN,
7878 /* INS_0xA1 */ Ins_UNKNOWN,
7879 /* INS_0xA2 */ Ins_UNKNOWN,
7880 /* INS_0xA3 */ Ins_UNKNOWN,
7881 /* INS_0xA4 */ Ins_UNKNOWN,
7882 /* INS_0xA5 */ Ins_UNKNOWN,
7883 /* INS_0xA6 */ Ins_UNKNOWN,
7884 /* INS_0xA7 */ Ins_UNKNOWN,
7885 /* INS_0xA8 */ Ins_UNKNOWN,
7886 /* INS_0xA9 */ Ins_UNKNOWN,
7887 /* INS_0xAA */ Ins_UNKNOWN,
7888 /* INS_0xAB */ Ins_UNKNOWN,
7889 /* INS_0xAC */ Ins_UNKNOWN,
7890 /* INS_0xAD */ Ins_UNKNOWN,
7891 /* INS_0xAE */ Ins_UNKNOWN,
7892 /* INS_0xAF */ Ins_UNKNOWN,
7894 /* PushB[0] */ Ins_PUSHB,
7895 /* PushB[1] */ Ins_PUSHB,
7896 /* PushB[2] */ Ins_PUSHB,
7897 /* PushB[3] */ Ins_PUSHB,
7898 /* PushB[4] */ Ins_PUSHB,
7899 /* PushB[5] */ Ins_PUSHB,
7900 /* PushB[6] */ Ins_PUSHB,
7901 /* PushB[7] */ Ins_PUSHB,
7902 /* PushW[0] */ Ins_PUSHW,
7903 /* PushW[1] */ Ins_PUSHW,
7904 /* PushW[2] */ Ins_PUSHW,
7905 /* PushW[3] */ Ins_PUSHW,
7906 /* PushW[4] */ Ins_PUSHW,
7907 /* PushW[5] */ Ins_PUSHW,
7908 /* PushW[6] */ Ins_PUSHW,
7909 /* PushW[7] */ Ins_PUSHW,
7911 /* MDRP[00] */ Ins_MDRP,
7912 /* MDRP[01] */ Ins_MDRP,
7913 /* MDRP[02] */ Ins_MDRP,
7914 /* MDRP[03] */ Ins_MDRP,
7915 /* MDRP[04] */ Ins_MDRP,
7916 /* MDRP[05] */ Ins_MDRP,
7917 /* MDRP[06] */ Ins_MDRP,
7918 /* MDRP[07] */ Ins_MDRP,
7919 /* MDRP[08] */ Ins_MDRP,
7920 /* MDRP[09] */ Ins_MDRP,
7921 /* MDRP[10] */ Ins_MDRP,
7922 /* MDRP[11] */ Ins_MDRP,
7923 /* MDRP[12] */ Ins_MDRP,
7924 /* MDRP[13] */ Ins_MDRP,
7925 /* MDRP[14] */ Ins_MDRP,
7926 /* MDRP[15] */ Ins_MDRP,
7928 /* MDRP[16] */ Ins_MDRP,
7929 /* MDRP[17] */ Ins_MDRP,
7930 /* MDRP[18] */ Ins_MDRP,
7931 /* MDRP[19] */ Ins_MDRP,
7932 /* MDRP[20] */ Ins_MDRP,
7933 /* MDRP[21] */ Ins_MDRP,
7934 /* MDRP[22] */ Ins_MDRP,
7935 /* MDRP[23] */ Ins_MDRP,
7936 /* MDRP[24] */ Ins_MDRP,
7937 /* MDRP[25] */ Ins_MDRP,
7938 /* MDRP[26] */ Ins_MDRP,
7939 /* MDRP[27] */ Ins_MDRP,
7940 /* MDRP[28] */ Ins_MDRP,
7941 /* MDRP[29] */ Ins_MDRP,
7942 /* MDRP[30] */ Ins_MDRP,
7943 /* MDRP[31] */ Ins_MDRP,
7945 /* MIRP[00] */ Ins_MIRP,
7946 /* MIRP[01] */ Ins_MIRP,
7947 /* MIRP[02] */ Ins_MIRP,
7948 /* MIRP[03] */ Ins_MIRP,
7949 /* MIRP[04] */ Ins_MIRP,
7950 /* MIRP[05] */ Ins_MIRP,
7951 /* MIRP[06] */ Ins_MIRP,
7952 /* MIRP[07] */ Ins_MIRP,
7953 /* MIRP[08] */ Ins_MIRP,
7954 /* MIRP[09] */ Ins_MIRP,
7955 /* MIRP[10] */ Ins_MIRP,
7956 /* MIRP[11] */ Ins_MIRP,
7957 /* MIRP[12] */ Ins_MIRP,
7958 /* MIRP[13] */ Ins_MIRP,
7959 /* MIRP[14] */ Ins_MIRP,
7960 /* MIRP[15] */ Ins_MIRP,
7962 /* MIRP[16] */ Ins_MIRP,
7963 /* MIRP[17] */ Ins_MIRP,
7964 /* MIRP[18] */ Ins_MIRP,
7965 /* MIRP[19] */ Ins_MIRP,
7966 /* MIRP[20] */ Ins_MIRP,
7967 /* MIRP[21] */ Ins_MIRP,
7968 /* MIRP[22] */ Ins_MIRP,
7969 /* MIRP[23] */ Ins_MIRP,
7970 /* MIRP[24] */ Ins_MIRP,
7971 /* MIRP[25] */ Ins_MIRP,
7972 /* MIRP[26] */ Ins_MIRP,
7973 /* MIRP[27] */ Ins_MIRP,
7974 /* MIRP[28] */ Ins_MIRP,
7975 /* MIRP[29] */ Ins_MIRP,
7976 /* MIRP[30] */ Ins_MIRP,
7977 /* MIRP[31] */ Ins_MIRP
7981 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7984 /*************************************************************************/
7988 /* This function executes a run of opcodes. It will exit in the */
7989 /* following cases: */
7991 /* - Errors (in which case it returns FALSE). */
7993 /* - Reaching the end of the main code range (returns TRUE). */
7994 /* Reaching the end of a code range within a function call is an */
7997 /* - After executing one single opcode, if the flag `Instruction_Trap' */
7998 /* is set to TRUE (returns TRUE). */
8000 /* On exit with TRUE, test IP < CodeSize to know whether it comes from */
8001 /* an instruction trap or a normal termination. */
8004 /* Note: The documented DEBUG opcode pops a value from the stack. This */
8005 /* behaviour is unsupported; here a DEBUG opcode is always an */
8009 /* THIS IS THE INTERPRETER'S MAIN LOOP. */
8011 /* Instructions appear in the specification's order. */
8013 /*************************************************************************/
8016 /* documentation is in ttinterp.h */
8018 FT_EXPORT_DEF( FT_Error )
8019 TT_RunIns( TT_ExecContext exc )
8021 FT_Long ins_counter = 0; /* executed instructions counter */
8024 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
8028 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
8029 if ( CUR.ignore_x_mode )
8030 CUR.iup_called = FALSE;
8031 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
8033 /* set CVT functions */
8034 CUR.tt_metrics.ratio = 0;
8035 if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
8037 /* non-square pixels, use the stretched routines */
8038 CUR.func_read_cvt = Read_CVT_Stretched;
8039 CUR.func_write_cvt = Write_CVT_Stretched;
8040 CUR.func_move_cvt = Move_CVT_Stretched;
8044 /* square pixels, use normal routines */
8045 CUR.func_read_cvt = Read_CVT;
8046 CUR.func_write_cvt = Write_CVT;
8047 CUR.func_move_cvt = Move_CVT;
8051 COMPUTE_Round( (FT_Byte)exc->GS.round_state );
8055 CUR.opcode = CUR.code[CUR.IP];
8058 FT_TRACE7(( opcode_name[CUR.opcode] ));
8059 FT_TRACE7(( "\n" ));
8061 if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )
8063 if ( CUR.IP + 1 >= CUR.codeSize )
8064 goto LErrorCodeOverflow_;
8066 CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
8069 if ( CUR.IP + CUR.length > CUR.codeSize )
8070 goto LErrorCodeOverflow_;
8072 /* First, let's check for empty stack and overflow */
8073 CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 );
8075 /* `args' is the top of the stack once arguments have been popped. */
8076 /* One can also interpret it as the index of the last argument. */
8082 if ( CUR.pedantic_hinting )
8084 CUR.error = TT_Err_Too_Few_Arguments;
8088 /* push zeroes onto the stack */
8089 for ( i = 0; i < Pop_Push_Count[CUR.opcode] >> 4; i++ )
8094 CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 );
8096 /* `new_top' is the new top of the stack, after the instruction's */
8097 /* execution. `top' will be set to `new_top' after the `switch' */
8099 if ( CUR.new_top > CUR.stackSize )
8101 CUR.error = TT_Err_Stack_Overflow;
8105 CUR.step_ins = TRUE;
8106 CUR.error = TT_Err_Ok;
8108 #ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
8111 FT_Long* args = CUR.stack + CUR.args;
8112 FT_Byte opcode = CUR.opcode;
8115 #undef ARRAY_BOUND_ERROR
8116 #define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
8121 case 0x00: /* SVTCA y */
8122 case 0x01: /* SVTCA x */
8123 case 0x02: /* SPvTCA y */
8124 case 0x03: /* SPvTCA x */
8125 case 0x04: /* SFvTCA y */
8126 case 0x05: /* SFvTCA x */
8131 AA = (FT_Short)( ( opcode & 1 ) << 14 );
8132 BB = (FT_Short)( AA ^ 0x4000 );
8136 CUR.GS.projVector.x = AA;
8137 CUR.GS.projVector.y = BB;
8139 CUR.GS.dualVector.x = AA;
8140 CUR.GS.dualVector.y = BB;
8144 GUESS_VECTOR( projVector );
8147 if ( ( opcode & 2 ) == 0 )
8149 CUR.GS.freeVector.x = AA;
8150 CUR.GS.freeVector.y = BB;
8154 GUESS_VECTOR( freeVector );
8161 case 0x06: /* SPvTL // */
8162 case 0x07: /* SPvTL + */
8166 case 0x08: /* SFvTL // */
8167 case 0x09: /* SFvTL + */
8171 case 0x0A: /* SPvFS */
8175 case 0x0B: /* SFvFS */
8179 case 0x0C: /* GPV */
8183 case 0x0D: /* GFV */
8187 case 0x0E: /* SFvTPv */
8191 case 0x0F: /* ISECT */
8192 Ins_ISECT( EXEC_ARG_ args );
8195 case 0x10: /* SRP0 */
8199 case 0x11: /* SRP1 */
8203 case 0x12: /* SRP2 */
8207 case 0x13: /* SZP0 */
8208 Ins_SZP0( EXEC_ARG_ args );
8211 case 0x14: /* SZP1 */
8212 Ins_SZP1( EXEC_ARG_ args );
8215 case 0x15: /* SZP2 */
8216 Ins_SZP2( EXEC_ARG_ args );
8219 case 0x16: /* SZPS */
8220 Ins_SZPS( EXEC_ARG_ args );
8223 case 0x17: /* SLOOP */
8227 case 0x18: /* RTG */
8231 case 0x19: /* RTHG */
8235 case 0x1A: /* SMD */
8239 case 0x1B: /* ELSE */
8240 Ins_ELSE( EXEC_ARG_ args );
8243 case 0x1C: /* JMPR */
8247 case 0x1D: /* SCVTCI */
8251 case 0x1E: /* SSWCI */
8255 case 0x1F: /* SSW */
8259 case 0x20: /* DUP */
8263 case 0x21: /* POP */
8267 case 0x22: /* CLEAR */
8271 case 0x23: /* SWAP */
8275 case 0x24: /* DEPTH */
8279 case 0x25: /* CINDEX */
8283 case 0x26: /* MINDEX */
8284 Ins_MINDEX( EXEC_ARG_ args );
8287 case 0x27: /* ALIGNPTS */
8288 Ins_ALIGNPTS( EXEC_ARG_ args );
8291 case 0x28: /* ???? */
8292 Ins_UNKNOWN( EXEC_ARG_ args );
8295 case 0x29: /* UTP */
8296 Ins_UTP( EXEC_ARG_ args );
8299 case 0x2A: /* LOOPCALL */
8300 Ins_LOOPCALL( EXEC_ARG_ args );
8303 case 0x2B: /* CALL */
8304 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
8305 if ( !CUR.ignore_x_mode ||
8308 !( CUR.sph_tweak_flags & SPH_TWEAK_NO_CALL_AFTER_IUP ) ) )
8309 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
8310 Ins_CALL( EXEC_ARG_ args );
8313 case 0x2C: /* FDEF */
8314 Ins_FDEF( EXEC_ARG_ args );
8317 case 0x2D: /* ENDF */
8318 Ins_ENDF( EXEC_ARG_ args );
8321 case 0x2E: /* MDAP */
8322 case 0x2F: /* MDAP */
8323 Ins_MDAP( EXEC_ARG_ args );
8326 case 0x30: /* IUP */
8327 case 0x31: /* IUP */
8328 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
8329 if ( CUR.ignore_x_mode )
8330 CUR.iup_called = TRUE;
8331 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
8332 Ins_IUP( EXEC_ARG_ args );
8335 case 0x32: /* SHP */
8336 case 0x33: /* SHP */
8337 Ins_SHP( EXEC_ARG_ args );
8340 case 0x34: /* SHC */
8341 case 0x35: /* SHC */
8342 Ins_SHC( EXEC_ARG_ args );
8345 case 0x36: /* SHZ */
8346 case 0x37: /* SHZ */
8347 Ins_SHZ( EXEC_ARG_ args );
8350 case 0x38: /* SHPIX */
8351 Ins_SHPIX( EXEC_ARG_ args );
8355 Ins_IP( EXEC_ARG_ args );
8358 case 0x3A: /* MSIRP */
8359 case 0x3B: /* MSIRP */
8360 Ins_MSIRP( EXEC_ARG_ args );
8363 case 0x3C: /* AlignRP */
8364 Ins_ALIGNRP( EXEC_ARG_ args );
8367 case 0x3D: /* RTDG */
8371 case 0x3E: /* MIAP */
8372 case 0x3F: /* MIAP */
8373 Ins_MIAP( EXEC_ARG_ args );
8376 case 0x40: /* NPUSHB */
8377 Ins_NPUSHB( EXEC_ARG_ args );
8380 case 0x41: /* NPUSHW */
8381 Ins_NPUSHW( EXEC_ARG_ args );
8389 CUR.error = TT_Err_Invalid_Reference;
8396 case 0x44: /* WCVTP */
8400 case 0x45: /* RCVT */
8406 Ins_GC( EXEC_ARG_ args );
8409 case 0x48: /* SCFS */
8410 Ins_SCFS( EXEC_ARG_ args );
8415 Ins_MD( EXEC_ARG_ args );
8418 case 0x4B: /* MPPEM */
8422 case 0x4C: /* MPS */
8426 case 0x4D: /* FLIPON */
8430 case 0x4E: /* FLIPOFF */
8434 case 0x4F: /* DEBUG */
8442 case 0x51: /* LTEQ */
8450 case 0x53: /* GTEQ */
8458 case 0x55: /* NEQ */
8462 case 0x56: /* ODD */
8466 case 0x57: /* EVEN */
8471 Ins_IF( EXEC_ARG_ args );
8474 case 0x59: /* EIF */
8478 case 0x5A: /* AND */
8486 case 0x5C: /* NOT */
8490 case 0x5D: /* DELTAP1 */
8491 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
8492 if ( !CUR.ignore_x_mode ||
8495 !( CUR.sph_tweak_flags & SPH_TWEAK_NO_DELTAP_AFTER_IUP ) ) )
8496 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
8497 Ins_DELTAP( EXEC_ARG_ args );
8500 case 0x5E: /* SDB */
8504 case 0x5F: /* SDS */
8508 case 0x60: /* ADD */
8512 case 0x61: /* SUB */
8516 case 0x62: /* DIV */
8520 case 0x63: /* MUL */
8524 case 0x64: /* ABS */
8528 case 0x65: /* NEG */
8532 case 0x66: /* FLOOR */
8536 case 0x67: /* CEILING */
8540 case 0x68: /* ROUND */
8541 case 0x69: /* ROUND */
8542 case 0x6A: /* ROUND */
8543 case 0x6B: /* ROUND */
8547 case 0x6C: /* NROUND */
8548 case 0x6D: /* NROUND */
8549 case 0x6E: /* NRRUND */
8550 case 0x6F: /* NROUND */
8554 case 0x70: /* WCVTF */
8558 case 0x71: /* DELTAP2 */
8559 case 0x72: /* DELTAP3 */
8560 Ins_DELTAP( EXEC_ARG_ args );
8563 case 0x73: /* DELTAC0 */
8564 case 0x74: /* DELTAC1 */
8565 case 0x75: /* DELTAC2 */
8566 Ins_DELTAC( EXEC_ARG_ args );
8569 case 0x76: /* SROUND */
8573 case 0x77: /* S45Round */
8577 case 0x78: /* JROT */
8581 case 0x79: /* JROF */
8585 case 0x7A: /* ROFF */
8589 case 0x7B: /* ???? */
8590 Ins_UNKNOWN( EXEC_ARG_ args );
8593 case 0x7C: /* RUTG */
8597 case 0x7D: /* RDTG */
8601 case 0x7E: /* SANGW */
8603 /* nothing - obsolete */
8606 case 0x80: /* FLIPPT */
8607 Ins_FLIPPT( EXEC_ARG_ args );
8610 case 0x81: /* FLIPRGON */
8611 Ins_FLIPRGON( EXEC_ARG_ args );
8614 case 0x82: /* FLIPRGOFF */
8615 Ins_FLIPRGOFF( EXEC_ARG_ args );
8618 case 0x83: /* UNKNOWN */
8619 case 0x84: /* UNKNOWN */
8620 Ins_UNKNOWN( EXEC_ARG_ args );
8623 case 0x85: /* SCANCTRL */
8624 Ins_SCANCTRL( EXEC_ARG_ args );
8627 case 0x86: /* SDPVTL */
8628 case 0x87: /* SDPVTL */
8629 Ins_SDPVTL( EXEC_ARG_ args );
8632 case 0x88: /* GETINFO */
8633 Ins_GETINFO( EXEC_ARG_ args );
8636 case 0x89: /* IDEF */
8637 Ins_IDEF( EXEC_ARG_ args );
8640 case 0x8A: /* ROLL */
8641 Ins_ROLL( EXEC_ARG_ args );
8644 case 0x8B: /* MAX */
8648 case 0x8C: /* MIN */
8652 case 0x8D: /* SCANTYPE */
8653 Ins_SCANTYPE( EXEC_ARG_ args );
8656 case 0x8E: /* INSTCTRL */
8657 Ins_INSTCTRL( EXEC_ARG_ args );
8661 Ins_UNKNOWN( EXEC_ARG_ args );
8665 if ( opcode >= 0xE0 )
8666 Ins_MIRP( EXEC_ARG_ args );
8667 else if ( opcode >= 0xC0 )
8668 Ins_MDRP( EXEC_ARG_ args );
8669 else if ( opcode >= 0xB8 )
8670 Ins_PUSHW( EXEC_ARG_ args );
8671 else if ( opcode >= 0xB0 )
8672 Ins_PUSHB( EXEC_ARG_ args );
8674 Ins_UNKNOWN( EXEC_ARG_ args );
8681 Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );
8683 #endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
8685 if ( CUR.error != TT_Err_Ok )
8687 switch ( CUR.error )
8689 case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
8691 TT_DefRecord* def = CUR.IDefs;
8692 TT_DefRecord* limit = def + CUR.numIDefs;
8695 for ( ; def < limit; def++ )
8697 if ( def->active && CUR.opcode == (FT_Byte)def->opc )
8699 TT_CallRec* callrec;
8702 if ( CUR.callTop >= CUR.callSize )
8704 CUR.error = TT_Err_Invalid_Reference;
8708 callrec = &CUR.callStack[CUR.callTop];
8710 callrec->Caller_Range = CUR.curRange;
8711 callrec->Caller_IP = CUR.IP + 1;
8712 callrec->Cur_Count = 1;
8713 callrec->Cur_Restart = def->start;
8714 callrec->Cur_End = def->end;
8716 if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
8724 CUR.error = TT_Err_Invalid_Opcode;
8728 break; /* Unreachable code warning suppression. */
8729 /* Leave to remind in case a later change the editor */
8730 /* to consider break; */
8742 CUR.top = CUR.new_top;
8745 CUR.IP += CUR.length;
8747 /* increment instruction counter and check if we didn't */
8748 /* run this program for too long (e.g. infinite loops). */
8749 if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
8750 return TT_Err_Execution_Too_Long;
8753 if ( CUR.IP >= CUR.codeSize )
8755 if ( CUR.callTop > 0 )
8757 CUR.error = TT_Err_Code_Overflow;
8763 } while ( !CUR.instruction_trap );
8767 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
8773 LErrorCodeOverflow_:
8774 CUR.error = TT_Err_Code_Overflow;
8778 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
8782 /* If any errors have occurred, function tables may be broken. */
8783 /* Force a re-execution of `prep' and `fpgm' tables if no */
8784 /* bytecode debugger is run. */
8785 if ( CUR.error && !CUR.instruction_trap )
8787 FT_TRACE1(( " The interpreter returned error 0x%x\n", CUR.error ));
8788 exc->size->cvt_ready = FALSE;
8795 #endif /* TT_USE_BYTECODE_INTERPRETER */