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
37 #define TT_MULFIX FT_MulFix
38 #define TT_MULDIV FT_MulDiv
39 #define TT_MULDIV_NO_ROUND FT_MulDiv_No_Round
42 /*************************************************************************/
44 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
45 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
46 /* messages during execution. */
49 #define FT_COMPONENT trace_ttinterp
51 /*************************************************************************/
53 /* In order to detect infinite loops in the code, we set up a counter */
54 /* within the run loop. A single stroke of interpretation is now */
55 /* limited to a maximal number of opcodes defined below. */
57 #define MAX_RUNNABLE_OPCODES 1000000L
60 /*************************************************************************/
62 /* There are two kinds of implementations: */
64 /* a. static implementation */
66 /* The current execution context is a static variable, which fields */
67 /* are accessed directly by the interpreter during execution. The */
68 /* context is named `cur'. */
70 /* This version is non-reentrant, of course. */
72 /* b. indirect implementation */
74 /* The current execution context is passed to _each_ function as its */
75 /* first argument, and each field is thus accessed indirectly. */
77 /* This version is fully re-entrant. */
79 /* The idea is that an indirect implementation may be slower to execute */
80 /* on low-end processors that are used in some systems (like 386s or */
83 /* As a consequence, the indirect implementation is now the default, as */
84 /* its performance costs can be considered negligible in our context. */
85 /* Note, however, that we kept the same source with macros because: */
87 /* - The code is kept very close in design to the Pascal code used for */
90 /* - It's much more readable that way! */
92 /* - It's still open to experimentation and tuning. */
94 /*************************************************************************/
97 #ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */
99 #define CUR (*exc) /* see ttobjs.h */
101 /*************************************************************************/
103 /* This macro is used whenever `exec' is unused in a function, to avoid */
104 /* stupid warnings from pedantic compilers. */
106 #define FT_UNUSED_EXEC FT_UNUSED( exc )
108 #else /* static implementation */
112 #define FT_UNUSED_EXEC int __dummy = __dummy
115 TT_ExecContextRec cur; /* static exec. context variable */
117 /* apparently, we have a _lot_ of direct indexing when accessing */
118 /* the static `cur', which makes the code bigger (due to all the */
119 /* four bytes addresses). */
121 #endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
124 /*************************************************************************/
126 /* The instruction argument stack. */
128 #define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */
131 /*************************************************************************/
133 /* This macro is used whenever `args' is unused in a function, to avoid */
134 /* stupid warnings from pedantic compilers. */
136 #define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args )
139 /*************************************************************************/
141 /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */
142 /* increase readability of the code. */
144 /*************************************************************************/
147 #define SKIP_Code() \
150 #define GET_ShortIns() \
151 GetShortIns( EXEC_ARG )
153 #define NORMalize( x, y, v ) \
154 Normalize( EXEC_ARG_ x, y, v )
156 #define SET_SuperRound( scale, flags ) \
157 SetSuperRound( EXEC_ARG_ scale, flags )
159 #define ROUND_None( d, c ) \
160 Round_None( EXEC_ARG_ d, c )
162 #define INS_Goto_CodeRange( range, ip ) \
163 Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
165 #define CUR_Func_move( z, p, d ) \
166 CUR.func_move( EXEC_ARG_ z, p, d )
168 #define CUR_Func_move_orig( z, p, d ) \
169 CUR.func_move_orig( EXEC_ARG_ z, p, d )
171 #define CUR_Func_round( d, c ) \
172 CUR.func_round( EXEC_ARG_ d, c )
174 #define CUR_Func_read_cvt( index ) \
175 CUR.func_read_cvt( EXEC_ARG_ index )
177 #define CUR_Func_write_cvt( index, val ) \
178 CUR.func_write_cvt( EXEC_ARG_ index, val )
180 #define CUR_Func_move_cvt( index, val ) \
181 CUR.func_move_cvt( EXEC_ARG_ index, val )
183 #define CURRENT_Ratio() \
184 Current_Ratio( EXEC_ARG )
186 #define CURRENT_Ppem() \
187 Current_Ppem( EXEC_ARG )
192 #define INS_SxVTL( a, b, c, d ) \
193 Ins_SxVTL( EXEC_ARG_ a, b, c, d )
195 #define COMPUTE_Funcs() \
196 Compute_Funcs( EXEC_ARG )
198 #define COMPUTE_Round( a ) \
199 Compute_Round( EXEC_ARG_ a )
201 #define COMPUTE_Point_Displacement( a, b, c, d ) \
202 Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
204 #define MOVE_Zp2_Point( a, b, c, t ) \
205 Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
208 #define CUR_Func_project( v1, v2 ) \
209 CUR.func_project( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
211 #define CUR_Func_dualproj( v1, v2 ) \
212 CUR.func_dualproj( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
214 #define CUR_fast_project( v ) \
215 CUR.func_project( EXEC_ARG_ (v)->x, (v)->y )
217 #define CUR_fast_dualproj( v ) \
218 CUR.func_dualproj( EXEC_ARG_ (v)->x, (v)->y )
221 /*************************************************************************/
223 /* Instruction dispatch function, as used by the interpreter. */
225 typedef void (*TInstruction_Function)( INS_ARG );
228 /*************************************************************************/
230 /* Two simple bounds-checking macros. */
232 #define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
233 #define BOUNDSL( x, n ) ( (FT_ULong)(x) >= (FT_ULong)(n) )
241 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
242 #define GUESS_VECTOR( V ) \
243 if ( CUR.face->unpatented_hinting ) \
245 CUR.GS.V.x = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0x4000 : 0 ); \
246 CUR.GS.V.y = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0 : 0x4000 ); \
249 #define GUESS_VECTOR( V )
252 /*************************************************************************/
254 /* CODERANGE FUNCTIONS */
256 /*************************************************************************/
259 /*************************************************************************/
262 /* TT_Goto_CodeRange */
265 /* Switches to a new code range (updates the code related elements in */
266 /* `exec', and `IP'). */
269 /* range :: The new execution code range. */
271 /* IP :: The new IP in the new code range. */
274 /* exec :: The target execution context. */
277 /* FreeType error code. 0 means success. */
279 FT_LOCAL_DEF( FT_Error )
280 TT_Goto_CodeRange( TT_ExecContext exec,
284 TT_CodeRange* coderange;
287 FT_ASSERT( range >= 1 && range <= 3 );
289 coderange = &exec->codeRangeTable[range - 1];
291 FT_ASSERT( coderange->base != NULL );
293 /* NOTE: Because the last instruction of a program may be a CALL */
294 /* which will return to the first byte *after* the code */
295 /* range, we test for IP <= Size instead of IP < Size. */
297 FT_ASSERT( (FT_ULong)IP <= coderange->size );
299 exec->code = coderange->base;
300 exec->codeSize = coderange->size;
302 exec->curRange = range;
308 /*************************************************************************/
311 /* TT_Set_CodeRange */
314 /* Sets a code range. */
317 /* range :: The code range index. */
319 /* base :: The new code base. */
321 /* length :: The range size in bytes. */
324 /* exec :: The target execution context. */
327 /* FreeType error code. 0 means success. */
329 FT_LOCAL_DEF( FT_Error )
330 TT_Set_CodeRange( TT_ExecContext exec,
335 FT_ASSERT( range >= 1 && range <= 3 );
337 exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
338 exec->codeRangeTable[range - 1].size = length;
344 /*************************************************************************/
347 /* TT_Clear_CodeRange */
350 /* Clears a code range. */
353 /* range :: The code range index. */
356 /* exec :: The target execution context. */
359 /* FreeType error code. 0 means success. */
362 /* Does not set the Error variable. */
364 FT_LOCAL_DEF( FT_Error )
365 TT_Clear_CodeRange( TT_ExecContext exec,
368 FT_ASSERT( range >= 1 && range <= 3 );
370 exec->codeRangeTable[range - 1].base = NULL;
371 exec->codeRangeTable[range - 1].size = 0;
377 /*************************************************************************/
379 /* EXECUTION CONTEXT ROUTINES */
381 /*************************************************************************/
384 /*************************************************************************/
387 /* TT_Done_Context */
390 /* Destroys a given context. */
393 /* exec :: A handle to the target execution context. */
395 /* memory :: A handle to the parent memory object. */
398 /* FreeType error code. 0 means success. */
401 /* Only the glyph loader and debugger should call this function. */
403 FT_LOCAL_DEF( FT_Error )
404 TT_Done_Context( TT_ExecContext exec )
406 FT_Memory memory = exec->memory;
411 exec->maxContours = 0;
414 FT_FREE( exec->stack );
417 /* free call stack */
418 FT_FREE( exec->callStack );
422 /* free glyph code range */
423 FT_FREE( exec->glyphIns );
435 /*************************************************************************/
441 /* Initializes a context object. */
444 /* memory :: A handle to the parent memory object. */
447 /* exec :: A handle to the target execution context. */
450 /* FreeType error code. 0 means success. */
453 Init_Context( TT_ExecContext exec,
459 FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec ));
461 exec->memory = memory;
464 if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )
467 /* all values in the context are set to 0 already, but this is */
468 /* here as a remainder */
470 exec->maxContours = 0;
476 exec->glyphIns = NULL;
484 FT_ERROR(( "Init_Context: not enough memory for %p\n", exec ));
485 TT_Done_Context( exec );
491 /*************************************************************************/
497 /* Checks the size of a buffer and reallocates it if necessary. */
500 /* memory :: A handle to the parent memory object. */
502 /* multiplier :: The size in bytes of each element in the buffer. */
504 /* new_max :: The new capacity (size) of the buffer. */
507 /* size :: The address of the buffer's current size expressed */
510 /* buff :: The address of the buffer base pointer. */
513 /* FreeType error code. 0 means success. */
515 FT_LOCAL_DEF( FT_Error )
516 Update_Max( FT_Memory memory,
523 void** pbuff = (void**)_pbuff;
526 if ( *size < new_max )
528 if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )
537 /*************************************************************************/
540 /* TT_Load_Context */
543 /* Prepare an execution context for glyph hinting. */
546 /* face :: A handle to the source face object. */
548 /* size :: A handle to the source size object. */
551 /* exec :: A handle to the target execution context. */
554 /* FreeType error code. 0 means success. */
557 /* Only the glyph loader and debugger should call this function. */
559 FT_LOCAL_DEF( FT_Error )
560 TT_Load_Context( TT_ExecContext exec,
571 maxp = &face->max_profile;
576 exec->numFDefs = size->num_function_defs;
577 exec->maxFDefs = size->max_function_defs;
578 exec->numIDefs = size->num_instruction_defs;
579 exec->maxIDefs = size->max_instruction_defs;
580 exec->FDefs = size->function_defs;
581 exec->IDefs = size->instruction_defs;
582 exec->tt_metrics = size->ttmetrics;
583 exec->metrics = size->metrics;
585 exec->maxFunc = size->max_func;
586 exec->maxIns = size->max_ins;
588 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
589 exec->codeRangeTable[i] = size->codeRangeTable[i];
591 /* set graphics state */
594 exec->cvtSize = size->cvt_size;
595 exec->cvt = size->cvt;
597 exec->storeSize = size->storage_size;
598 exec->storage = size->storage;
600 exec->twilight = size->twilight;
602 /* In case of multi-threading it can happen that the old size object */
603 /* no longer exists, thus we must clear all glyph zone references. */
604 ft_memset( &exec->zp0, 0, sizeof ( exec->zp0 ) );
605 exec->zp1 = exec->zp0;
606 exec->zp2 = exec->zp0;
609 /* XXX: We reserve a little more elements on the stack to deal safely */
610 /* with broken fonts like arialbs, courbs, timesbs, etc. */
611 tmp = exec->stackSize;
612 error = Update_Max( exec->memory,
614 sizeof ( FT_F26Dot6 ),
616 maxp->maxStackElements + 32 );
617 exec->stackSize = (FT_UInt)tmp;
621 tmp = exec->glyphSize;
622 error = Update_Max( exec->memory,
625 (void*)&exec->glyphIns,
626 maxp->maxSizeOfInstructions );
627 exec->glyphSize = (FT_UShort)tmp;
631 exec->pts.n_points = 0;
632 exec->pts.n_contours = 0;
634 exec->zp1 = exec->pts;
635 exec->zp2 = exec->pts;
636 exec->zp0 = exec->pts;
638 exec->instruction_trap = FALSE;
644 /*************************************************************************/
647 /* TT_Save_Context */
650 /* Saves the code ranges in a `size' object. */
653 /* exec :: A handle to the source execution context. */
656 /* size :: A handle to the target size object. */
659 /* FreeType error code. 0 means success. */
662 /* Only the glyph loader and debugger should call this function. */
664 FT_LOCAL_DEF( FT_Error )
665 TT_Save_Context( TT_ExecContext exec,
671 /* XXX: Will probably disappear soon with all the code range */
672 /* management, which is now rather obsolete. */
674 size->num_function_defs = exec->numFDefs;
675 size->num_instruction_defs = exec->numIDefs;
677 size->max_func = exec->maxFunc;
678 size->max_ins = exec->maxIns;
680 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
681 size->codeRangeTable[i] = exec->codeRangeTable[i];
687 /*************************************************************************/
693 /* Executes one or more instructions in the execution context. */
696 /* debug :: A Boolean flag. If set, the function sets some internal */
697 /* variables and returns immediately, otherwise TT_RunIns() */
700 /* This is commented out currently. */
703 /* exec :: A handle to the target execution context. */
706 /* TrueType error code. 0 means success. */
709 /* Only the glyph loader and debugger should call this function. */
711 FT_LOCAL_DEF( FT_Error )
712 TT_Run_Context( TT_ExecContext exec,
718 if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) )
722 exec->zp0 = exec->pts;
723 exec->zp1 = exec->pts;
724 exec->zp2 = exec->pts;
730 exec->GS.projVector.x = 0x4000;
731 exec->GS.projVector.y = 0x0000;
733 exec->GS.freeVector = exec->GS.projVector;
734 exec->GS.dualVector = exec->GS.projVector;
736 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
737 exec->GS.both_x_axis = TRUE;
740 exec->GS.round_state = 1;
743 /* some glyphs leave something on the stack. so we clean it */
744 /* before a new execution. */
751 return exec->face->interpreter( exec );
754 return TT_RunIns( exec );
761 /* The default value for `scan_control' is documented as FALSE in the */
762 /* TrueType specification. This is confusing since it implies a */
763 /* Boolean value. However, this is not the case, thus both the */
764 /* default values of our `scan_type' and `scan_control' fields (which */
765 /* the documentation's `scan_control' variable is split into) are */
768 const TT_GraphicsState tt_default_graphics_state =
775 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
780 TRUE, 68, 0, 0, 9, 3,
785 /* documentation is in ttinterp.h */
787 FT_EXPORT_DEF( TT_ExecContext )
788 TT_New_Context( TT_Driver driver )
794 memory = driver->root.root.memory;
795 exec = driver->context;
797 if ( !driver->context )
802 /* allocate object */
803 if ( FT_NEW( exec ) )
806 /* initialize it; in case of error this deallocates `exec' too */
807 error = Init_Context( exec, memory );
811 /* store it into the driver */
812 driver->context = exec;
815 return driver->context;
822 /*************************************************************************/
824 /* Before an opcode is executed, the interpreter verifies that there are */
825 /* enough arguments on the stack, with the help of the `Pop_Push_Count' */
828 /* For each opcode, the first column gives the number of arguments that */
829 /* are popped from the stack; the second one gives the number of those */
830 /* that are pushed in result. */
832 /* Opcodes which have a varying number of parameters in the data stream */
833 /* (NPUSHB, NPUSHW) are handled specially; they have a negative value in */
834 /* the `opcode_length' table, and the value in `Pop_Push_Count' is set */
837 /*************************************************************************/
841 #define PACK( x, y ) ( ( x << 4 ) | y )
845 const FT_Byte Pop_Push_Count[256] =
847 /* opcodes are gathered in groups of 16 */
848 /* please keep the spaces as they are */
850 /* SVTCA y */ PACK( 0, 0 ),
851 /* SVTCA x */ PACK( 0, 0 ),
852 /* SPvTCA y */ PACK( 0, 0 ),
853 /* SPvTCA x */ PACK( 0, 0 ),
854 /* SFvTCA y */ PACK( 0, 0 ),
855 /* SFvTCA x */ PACK( 0, 0 ),
856 /* SPvTL // */ PACK( 2, 0 ),
857 /* SPvTL + */ PACK( 2, 0 ),
858 /* SFvTL // */ PACK( 2, 0 ),
859 /* SFvTL + */ PACK( 2, 0 ),
860 /* SPvFS */ PACK( 2, 0 ),
861 /* SFvFS */ PACK( 2, 0 ),
862 /* GPV */ PACK( 0, 2 ),
863 /* GFV */ PACK( 0, 2 ),
864 /* SFvTPv */ PACK( 0, 0 ),
865 /* ISECT */ PACK( 5, 0 ),
867 /* SRP0 */ PACK( 1, 0 ),
868 /* SRP1 */ PACK( 1, 0 ),
869 /* SRP2 */ PACK( 1, 0 ),
870 /* SZP0 */ PACK( 1, 0 ),
871 /* SZP1 */ PACK( 1, 0 ),
872 /* SZP2 */ PACK( 1, 0 ),
873 /* SZPS */ PACK( 1, 0 ),
874 /* SLOOP */ PACK( 1, 0 ),
875 /* RTG */ PACK( 0, 0 ),
876 /* RTHG */ PACK( 0, 0 ),
877 /* SMD */ PACK( 1, 0 ),
878 /* ELSE */ PACK( 0, 0 ),
879 /* JMPR */ PACK( 1, 0 ),
880 /* SCvTCi */ PACK( 1, 0 ),
881 /* SSwCi */ PACK( 1, 0 ),
882 /* SSW */ PACK( 1, 0 ),
884 /* DUP */ PACK( 1, 2 ),
885 /* POP */ PACK( 1, 0 ),
886 /* CLEAR */ PACK( 0, 0 ),
887 /* SWAP */ PACK( 2, 2 ),
888 /* DEPTH */ PACK( 0, 1 ),
889 /* CINDEX */ PACK( 1, 1 ),
890 /* MINDEX */ PACK( 1, 0 ),
891 /* AlignPTS */ PACK( 2, 0 ),
892 /* INS_$28 */ PACK( 0, 0 ),
893 /* UTP */ PACK( 1, 0 ),
894 /* LOOPCALL */ PACK( 2, 0 ),
895 /* CALL */ PACK( 1, 0 ),
896 /* FDEF */ PACK( 1, 0 ),
897 /* ENDF */ PACK( 0, 0 ),
898 /* MDAP[0] */ PACK( 1, 0 ),
899 /* MDAP[1] */ PACK( 1, 0 ),
901 /* IUP[0] */ PACK( 0, 0 ),
902 /* IUP[1] */ PACK( 0, 0 ),
903 /* SHP[0] */ PACK( 0, 0 ),
904 /* SHP[1] */ PACK( 0, 0 ),
905 /* SHC[0] */ PACK( 1, 0 ),
906 /* SHC[1] */ PACK( 1, 0 ),
907 /* SHZ[0] */ PACK( 1, 0 ),
908 /* SHZ[1] */ PACK( 1, 0 ),
909 /* SHPIX */ PACK( 1, 0 ),
910 /* IP */ PACK( 0, 0 ),
911 /* MSIRP[0] */ PACK( 2, 0 ),
912 /* MSIRP[1] */ PACK( 2, 0 ),
913 /* AlignRP */ PACK( 0, 0 ),
914 /* RTDG */ PACK( 0, 0 ),
915 /* MIAP[0] */ PACK( 2, 0 ),
916 /* MIAP[1] */ PACK( 2, 0 ),
918 /* NPushB */ PACK( 0, 0 ),
919 /* NPushW */ PACK( 0, 0 ),
920 /* WS */ PACK( 2, 0 ),
921 /* RS */ PACK( 1, 1 ),
922 /* WCvtP */ PACK( 2, 0 ),
923 /* RCvt */ PACK( 1, 1 ),
924 /* GC[0] */ PACK( 1, 1 ),
925 /* GC[1] */ PACK( 1, 1 ),
926 /* SCFS */ PACK( 2, 0 ),
927 /* MD[0] */ PACK( 2, 1 ),
928 /* MD[1] */ PACK( 2, 1 ),
929 /* MPPEM */ PACK( 0, 1 ),
930 /* MPS */ PACK( 0, 1 ),
931 /* FlipON */ PACK( 0, 0 ),
932 /* FlipOFF */ PACK( 0, 0 ),
933 /* DEBUG */ PACK( 1, 0 ),
935 /* LT */ PACK( 2, 1 ),
936 /* LTEQ */ PACK( 2, 1 ),
937 /* GT */ PACK( 2, 1 ),
938 /* GTEQ */ PACK( 2, 1 ),
939 /* EQ */ PACK( 2, 1 ),
940 /* NEQ */ PACK( 2, 1 ),
941 /* ODD */ PACK( 1, 1 ),
942 /* EVEN */ PACK( 1, 1 ),
943 /* IF */ PACK( 1, 0 ),
944 /* EIF */ PACK( 0, 0 ),
945 /* AND */ PACK( 2, 1 ),
946 /* OR */ PACK( 2, 1 ),
947 /* NOT */ PACK( 1, 1 ),
948 /* DeltaP1 */ PACK( 1, 0 ),
949 /* SDB */ PACK( 1, 0 ),
950 /* SDS */ PACK( 1, 0 ),
952 /* ADD */ PACK( 2, 1 ),
953 /* SUB */ PACK( 2, 1 ),
954 /* DIV */ PACK( 2, 1 ),
955 /* MUL */ PACK( 2, 1 ),
956 /* ABS */ PACK( 1, 1 ),
957 /* NEG */ PACK( 1, 1 ),
958 /* FLOOR */ PACK( 1, 1 ),
959 /* CEILING */ PACK( 1, 1 ),
960 /* ROUND[0] */ PACK( 1, 1 ),
961 /* ROUND[1] */ PACK( 1, 1 ),
962 /* ROUND[2] */ PACK( 1, 1 ),
963 /* ROUND[3] */ PACK( 1, 1 ),
964 /* NROUND[0] */ PACK( 1, 1 ),
965 /* NROUND[1] */ PACK( 1, 1 ),
966 /* NROUND[2] */ PACK( 1, 1 ),
967 /* NROUND[3] */ PACK( 1, 1 ),
969 /* WCvtF */ PACK( 2, 0 ),
970 /* DeltaP2 */ PACK( 1, 0 ),
971 /* DeltaP3 */ PACK( 1, 0 ),
972 /* DeltaCn[0] */ PACK( 1, 0 ),
973 /* DeltaCn[1] */ PACK( 1, 0 ),
974 /* DeltaCn[2] */ PACK( 1, 0 ),
975 /* SROUND */ PACK( 1, 0 ),
976 /* S45Round */ PACK( 1, 0 ),
977 /* JROT */ PACK( 2, 0 ),
978 /* JROF */ PACK( 2, 0 ),
979 /* ROFF */ PACK( 0, 0 ),
980 /* INS_$7B */ PACK( 0, 0 ),
981 /* RUTG */ PACK( 0, 0 ),
982 /* RDTG */ PACK( 0, 0 ),
983 /* SANGW */ PACK( 1, 0 ),
984 /* AA */ PACK( 1, 0 ),
986 /* FlipPT */ PACK( 0, 0 ),
987 /* FlipRgON */ PACK( 2, 0 ),
988 /* FlipRgOFF */ PACK( 2, 0 ),
989 /* INS_$83 */ PACK( 0, 0 ),
990 /* INS_$84 */ PACK( 0, 0 ),
991 /* ScanCTRL */ PACK( 1, 0 ),
992 /* SDPVTL[0] */ PACK( 2, 0 ),
993 /* SDPVTL[1] */ PACK( 2, 0 ),
994 /* GetINFO */ PACK( 1, 1 ),
995 /* IDEF */ PACK( 1, 0 ),
996 /* ROLL */ PACK( 3, 3 ),
997 /* MAX */ PACK( 2, 1 ),
998 /* MIN */ PACK( 2, 1 ),
999 /* ScanTYPE */ PACK( 1, 0 ),
1000 /* InstCTRL */ PACK( 2, 0 ),
1001 /* INS_$8F */ PACK( 0, 0 ),
1003 /* INS_$90 */ PACK( 0, 0 ),
1004 /* INS_$91 */ PACK( 0, 0 ),
1005 /* INS_$92 */ PACK( 0, 0 ),
1006 /* INS_$93 */ PACK( 0, 0 ),
1007 /* INS_$94 */ PACK( 0, 0 ),
1008 /* INS_$95 */ PACK( 0, 0 ),
1009 /* INS_$96 */ PACK( 0, 0 ),
1010 /* INS_$97 */ PACK( 0, 0 ),
1011 /* INS_$98 */ PACK( 0, 0 ),
1012 /* INS_$99 */ PACK( 0, 0 ),
1013 /* INS_$9A */ PACK( 0, 0 ),
1014 /* INS_$9B */ PACK( 0, 0 ),
1015 /* INS_$9C */ PACK( 0, 0 ),
1016 /* INS_$9D */ PACK( 0, 0 ),
1017 /* INS_$9E */ PACK( 0, 0 ),
1018 /* INS_$9F */ PACK( 0, 0 ),
1020 /* INS_$A0 */ PACK( 0, 0 ),
1021 /* INS_$A1 */ PACK( 0, 0 ),
1022 /* INS_$A2 */ PACK( 0, 0 ),
1023 /* INS_$A3 */ PACK( 0, 0 ),
1024 /* INS_$A4 */ PACK( 0, 0 ),
1025 /* INS_$A5 */ PACK( 0, 0 ),
1026 /* INS_$A6 */ PACK( 0, 0 ),
1027 /* INS_$A7 */ PACK( 0, 0 ),
1028 /* INS_$A8 */ PACK( 0, 0 ),
1029 /* INS_$A9 */ PACK( 0, 0 ),
1030 /* INS_$AA */ PACK( 0, 0 ),
1031 /* INS_$AB */ PACK( 0, 0 ),
1032 /* INS_$AC */ PACK( 0, 0 ),
1033 /* INS_$AD */ PACK( 0, 0 ),
1034 /* INS_$AE */ PACK( 0, 0 ),
1035 /* INS_$AF */ PACK( 0, 0 ),
1037 /* PushB[0] */ PACK( 0, 1 ),
1038 /* PushB[1] */ PACK( 0, 2 ),
1039 /* PushB[2] */ PACK( 0, 3 ),
1040 /* PushB[3] */ PACK( 0, 4 ),
1041 /* PushB[4] */ PACK( 0, 5 ),
1042 /* PushB[5] */ PACK( 0, 6 ),
1043 /* PushB[6] */ PACK( 0, 7 ),
1044 /* PushB[7] */ PACK( 0, 8 ),
1045 /* PushW[0] */ PACK( 0, 1 ),
1046 /* PushW[1] */ PACK( 0, 2 ),
1047 /* PushW[2] */ PACK( 0, 3 ),
1048 /* PushW[3] */ PACK( 0, 4 ),
1049 /* PushW[4] */ PACK( 0, 5 ),
1050 /* PushW[5] */ PACK( 0, 6 ),
1051 /* PushW[6] */ PACK( 0, 7 ),
1052 /* PushW[7] */ PACK( 0, 8 ),
1054 /* MDRP[00] */ PACK( 1, 0 ),
1055 /* MDRP[01] */ PACK( 1, 0 ),
1056 /* MDRP[02] */ PACK( 1, 0 ),
1057 /* MDRP[03] */ PACK( 1, 0 ),
1058 /* MDRP[04] */ PACK( 1, 0 ),
1059 /* MDRP[05] */ PACK( 1, 0 ),
1060 /* MDRP[06] */ PACK( 1, 0 ),
1061 /* MDRP[07] */ PACK( 1, 0 ),
1062 /* MDRP[08] */ PACK( 1, 0 ),
1063 /* MDRP[09] */ PACK( 1, 0 ),
1064 /* MDRP[10] */ PACK( 1, 0 ),
1065 /* MDRP[11] */ PACK( 1, 0 ),
1066 /* MDRP[12] */ PACK( 1, 0 ),
1067 /* MDRP[13] */ PACK( 1, 0 ),
1068 /* MDRP[14] */ PACK( 1, 0 ),
1069 /* MDRP[15] */ PACK( 1, 0 ),
1071 /* MDRP[16] */ PACK( 1, 0 ),
1072 /* MDRP[17] */ PACK( 1, 0 ),
1073 /* MDRP[18] */ PACK( 1, 0 ),
1074 /* MDRP[19] */ PACK( 1, 0 ),
1075 /* MDRP[20] */ PACK( 1, 0 ),
1076 /* MDRP[21] */ PACK( 1, 0 ),
1077 /* MDRP[22] */ PACK( 1, 0 ),
1078 /* MDRP[23] */ PACK( 1, 0 ),
1079 /* MDRP[24] */ PACK( 1, 0 ),
1080 /* MDRP[25] */ PACK( 1, 0 ),
1081 /* MDRP[26] */ PACK( 1, 0 ),
1082 /* MDRP[27] */ PACK( 1, 0 ),
1083 /* MDRP[28] */ PACK( 1, 0 ),
1084 /* MDRP[29] */ PACK( 1, 0 ),
1085 /* MDRP[30] */ PACK( 1, 0 ),
1086 /* MDRP[31] */ PACK( 1, 0 ),
1088 /* MIRP[00] */ PACK( 2, 0 ),
1089 /* MIRP[01] */ PACK( 2, 0 ),
1090 /* MIRP[02] */ PACK( 2, 0 ),
1091 /* MIRP[03] */ PACK( 2, 0 ),
1092 /* MIRP[04] */ PACK( 2, 0 ),
1093 /* MIRP[05] */ PACK( 2, 0 ),
1094 /* MIRP[06] */ PACK( 2, 0 ),
1095 /* MIRP[07] */ PACK( 2, 0 ),
1096 /* MIRP[08] */ PACK( 2, 0 ),
1097 /* MIRP[09] */ PACK( 2, 0 ),
1098 /* MIRP[10] */ PACK( 2, 0 ),
1099 /* MIRP[11] */ PACK( 2, 0 ),
1100 /* MIRP[12] */ PACK( 2, 0 ),
1101 /* MIRP[13] */ PACK( 2, 0 ),
1102 /* MIRP[14] */ PACK( 2, 0 ),
1103 /* MIRP[15] */ PACK( 2, 0 ),
1105 /* MIRP[16] */ PACK( 2, 0 ),
1106 /* MIRP[17] */ PACK( 2, 0 ),
1107 /* MIRP[18] */ PACK( 2, 0 ),
1108 /* MIRP[19] */ PACK( 2, 0 ),
1109 /* MIRP[20] */ PACK( 2, 0 ),
1110 /* MIRP[21] */ PACK( 2, 0 ),
1111 /* MIRP[22] */ PACK( 2, 0 ),
1112 /* MIRP[23] */ PACK( 2, 0 ),
1113 /* MIRP[24] */ PACK( 2, 0 ),
1114 /* MIRP[25] */ PACK( 2, 0 ),
1115 /* MIRP[26] */ PACK( 2, 0 ),
1116 /* MIRP[27] */ PACK( 2, 0 ),
1117 /* MIRP[28] */ PACK( 2, 0 ),
1118 /* MIRP[29] */ PACK( 2, 0 ),
1119 /* MIRP[30] */ PACK( 2, 0 ),
1120 /* MIRP[31] */ PACK( 2, 0 )
1124 #ifdef FT_DEBUG_LEVEL_TRACE
1127 const char* const opcode_name[256] =
1402 #endif /* FT_DEBUG_LEVEL_TRACE */
1406 const FT_Char opcode_length[256] =
1408 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1409 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1410 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1411 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1413 -1,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1414 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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,
1418 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1419 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1420 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1421 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
1423 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1424 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
1434 TT_MulFix14( FT_Int32 a,
1438 FT_UInt32 ah, al, mid, lo, hi;
1448 ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU );
1449 al = (FT_UInt32)( a & 0xFFFFU );
1454 mid = ( mid << 16 ) + ( 1 << 13 ); /* rounding */
1459 mid = ( lo >> 14 ) | ( hi << 18 );
1461 return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid;
1466 /* compute (a*b)/2^14 with maximal accuracy and rounding */
1468 TT_MulFix14( FT_Int32 a,
1475 /* compute ax*bx as 64-bit value */
1476 l = (FT_UInt32)( ( a & 0xFFFFU ) * b );
1477 m = ( a >> 16 ) * b;
1479 lo = l + (FT_UInt32)( m << 16 );
1480 hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l );
1482 /* divide the result by 2^14 with rounding */
1484 l = lo + (FT_UInt32)s;
1485 hi += s + ( l < lo );
1491 return ( hi << 18 ) | ( l >> 14 );
1496 /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */
1498 TT_DotFix14( FT_Int32 ax,
1503 FT_Int32 m, s, hi1, hi2, hi;
1504 FT_UInt32 l, lo1, lo2, lo;
1507 /* compute ax*bx as 64-bit value */
1508 l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );
1509 m = ( ax >> 16 ) * bx;
1511 lo1 = l + (FT_UInt32)( m << 16 );
1512 hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l );
1514 /* compute ay*by as 64-bit value */
1515 l = (FT_UInt32)( ( ay & 0xFFFFU ) * by );
1516 m = ( ay >> 16 ) * by;
1518 lo2 = l + (FT_UInt32)( m << 16 );
1519 hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l );
1523 hi = hi1 + hi2 + ( lo < lo1 );
1525 /* divide the result by 2^14 with rounding */
1527 l = lo + (FT_UInt32)s;
1528 hi += s + ( l < lo );
1534 return ( hi << 18 ) | ( l >> 14 );
1538 /* return length of given vector */
1543 TT_VecLen( FT_Int32 x,
1546 FT_Int32 m, hi1, hi2, hi;
1547 FT_UInt32 l, lo1, lo2, lo;
1550 /* compute x*x as 64-bit value */
1551 lo = (FT_UInt32)( x & 0xFFFFU );
1558 lo1 = l + (FT_UInt32)( m << 17 );
1559 hi1 = hi + ( m >> 15 ) + ( lo1 < l );
1561 /* compute y*y as 64-bit value */
1562 lo = (FT_UInt32)( y & 0xFFFFU );
1569 lo2 = l + (FT_UInt32)( m << 17 );
1570 hi2 = hi + ( m >> 15 ) + ( lo2 < l );
1572 /* add them to get 'x*x+y*y' as 64-bit value */
1574 hi = hi1 + hi2 + ( lo < lo1 );
1576 /* compute the square root of this value */
1578 FT_UInt32 root, rem, test_div;
1589 rem = ( rem << 2 ) | ( (FT_UInt32)hi >> 30 );
1590 hi = ( hi << 2 ) | ( lo >> 30 );
1593 test_div = ( root << 1 ) + 1;
1595 if ( rem >= test_div )
1600 } while ( --count );
1603 return (FT_Int32)root;
1609 /* this version uses FT_Vector_Length which computes the same value */
1610 /* much, much faster.. */
1613 TT_VecLen( FT_F26Dot6 X,
1622 return FT_Vector_Length( &v );
1628 /*************************************************************************/
1634 /* Returns the current aspect ratio scaling factor depending on the */
1635 /* projection vector's state and device resolutions. */
1638 /* The aspect ratio in 16.16 format, always <= 1.0 . */
1641 Current_Ratio( EXEC_OP )
1643 if ( !CUR.tt_metrics.ratio )
1645 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1646 if ( CUR.face->unpatented_hinting )
1648 if ( CUR.GS.both_x_axis )
1649 CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
1651 CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
1656 if ( CUR.GS.projVector.y == 0 )
1657 CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
1659 else if ( CUR.GS.projVector.x == 0 )
1660 CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
1667 x = TT_MULDIV( CUR.GS.projVector.x,
1668 CUR.tt_metrics.x_ratio, 0x4000 );
1669 y = TT_MULDIV( CUR.GS.projVector.y,
1670 CUR.tt_metrics.y_ratio, 0x4000 );
1671 CUR.tt_metrics.ratio = TT_VecLen( x, y );
1675 return CUR.tt_metrics.ratio;
1680 Current_Ppem( EXEC_OP )
1682 return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );
1686 /*************************************************************************/
1688 /* Functions related to the control value table (CVT). */
1690 /*************************************************************************/
1693 FT_CALLBACK_DEF( FT_F26Dot6 )
1694 Read_CVT( EXEC_OP_ FT_ULong idx )
1696 return CUR.cvt[idx];
1700 FT_CALLBACK_DEF( FT_F26Dot6 )
1701 Read_CVT_Stretched( EXEC_OP_ FT_ULong idx )
1703 return TT_MULFIX( CUR.cvt[idx], CURRENT_Ratio() );
1707 FT_CALLBACK_DEF( void )
1708 Write_CVT( EXEC_OP_ FT_ULong idx,
1711 CUR.cvt[idx] = value;
1715 FT_CALLBACK_DEF( void )
1716 Write_CVT_Stretched( EXEC_OP_ FT_ULong idx,
1719 CUR.cvt[idx] = FT_DivFix( value, CURRENT_Ratio() );
1723 FT_CALLBACK_DEF( void )
1724 Move_CVT( EXEC_OP_ FT_ULong idx,
1727 CUR.cvt[idx] += value;
1731 FT_CALLBACK_DEF( void )
1732 Move_CVT_Stretched( EXEC_OP_ FT_ULong idx,
1735 CUR.cvt[idx] += FT_DivFix( value, CURRENT_Ratio() );
1739 /*************************************************************************/
1745 /* Returns a short integer taken from the instruction stream at */
1749 /* Short read at code[IP]. */
1752 /* This one could become a macro. */
1755 GetShortIns( EXEC_OP )
1757 /* Reading a byte stream so there is no endianess (DaveP) */
1759 return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) +
1760 CUR.code[CUR.IP - 1] );
1764 /*************************************************************************/
1767 /* Ins_Goto_CodeRange */
1770 /* Goes to a certain code range in the instruction stream. */
1773 /* aRange :: The index of the code range. */
1775 /* aIP :: The new IP address in the code range. */
1778 /* SUCCESS or FAILURE. */
1781 Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange,
1784 TT_CodeRange* range;
1787 if ( aRange < 1 || aRange > 3 )
1789 CUR.error = TT_Err_Bad_Argument;
1793 range = &CUR.codeRangeTable[aRange - 1];
1795 if ( range->base == NULL ) /* invalid coderange */
1797 CUR.error = TT_Err_Invalid_CodeRange;
1801 /* NOTE: Because the last instruction of a program may be a CALL */
1802 /* which will return to the first byte *after* the code */
1803 /* range, we test for aIP <= Size, instead of aIP < Size. */
1805 if ( aIP > range->size )
1807 CUR.error = TT_Err_Code_Overflow;
1811 CUR.code = range->base;
1812 CUR.codeSize = range->size;
1814 CUR.curRange = aRange;
1820 /*************************************************************************/
1826 /* Moves a point by a given distance along the freedom vector. The */
1827 /* point will be `touched'. */
1830 /* point :: The index of the point to move. */
1832 /* distance :: The distance to apply. */
1835 /* zone :: The affected glyph zone. */
1838 Direct_Move( EXEC_OP_ TT_GlyphZone zone,
1840 FT_F26Dot6 distance )
1845 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1846 FT_ASSERT( !CUR.face->unpatented_hinting );
1849 v = CUR.GS.freeVector.x;
1853 zone->cur[point].x += TT_MULDIV( distance,
1857 zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
1860 v = CUR.GS.freeVector.y;
1864 zone->cur[point].y += TT_MULDIV( distance,
1868 zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1873 /*************************************************************************/
1876 /* Direct_Move_Orig */
1879 /* Moves the *original* position of a point by a given distance along */
1880 /* the freedom vector. Obviously, the point will not be `touched'. */
1883 /* point :: The index of the point to move. */
1885 /* distance :: The distance to apply. */
1888 /* zone :: The affected glyph zone. */
1891 Direct_Move_Orig( EXEC_OP_ TT_GlyphZone zone,
1893 FT_F26Dot6 distance )
1898 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1899 FT_ASSERT( !CUR.face->unpatented_hinting );
1902 v = CUR.GS.freeVector.x;
1905 zone->org[point].x += TT_MULDIV( distance,
1909 v = CUR.GS.freeVector.y;
1912 zone->org[point].y += TT_MULDIV( distance,
1918 /*************************************************************************/
1920 /* Special versions of Direct_Move() */
1922 /* The following versions are used whenever both vectors are both */
1923 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1925 /*************************************************************************/
1929 Direct_Move_X( EXEC_OP_ TT_GlyphZone zone,
1931 FT_F26Dot6 distance )
1935 zone->cur[point].x += distance;
1936 zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
1941 Direct_Move_Y( EXEC_OP_ TT_GlyphZone zone,
1943 FT_F26Dot6 distance )
1947 zone->cur[point].y += distance;
1948 zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1952 /*************************************************************************/
1954 /* Special versions of Direct_Move_Orig() */
1956 /* The following versions are used whenever both vectors are both */
1957 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1959 /*************************************************************************/
1963 Direct_Move_Orig_X( EXEC_OP_ TT_GlyphZone zone,
1965 FT_F26Dot6 distance )
1969 zone->org[point].x += distance;
1974 Direct_Move_Orig_Y( EXEC_OP_ TT_GlyphZone zone,
1976 FT_F26Dot6 distance )
1980 zone->org[point].y += distance;
1984 /*************************************************************************/
1990 /* Does not round, but adds engine compensation. */
1993 /* distance :: The distance (not) to round. */
1995 /* compensation :: The engine compensation. */
1998 /* The compensated distance. */
2001 /* The TrueType specification says very few about the relationship */
2002 /* between rounding and engine compensation. However, it seems from */
2003 /* the description of super round that we should add the compensation */
2004 /* before rounding. */
2007 Round_None( EXEC_OP_ FT_F26Dot6 distance,
2008 FT_F26Dot6 compensation )
2015 if ( distance >= 0 )
2017 val = distance + compensation;
2018 if ( distance && val < 0 )
2023 val = distance - compensation;
2031 /*************************************************************************/
2037 /* Rounds value to grid after adding engine compensation. */
2040 /* distance :: The distance to round. */
2042 /* compensation :: The engine compensation. */
2045 /* Rounded distance. */
2048 Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
2049 FT_F26Dot6 compensation )
2056 if ( distance >= 0 )
2058 val = distance + compensation + 32;
2059 if ( distance && val > 0 )
2066 val = -FT_PIX_ROUND( compensation - distance );
2075 /*************************************************************************/
2078 /* Round_To_Half_Grid */
2081 /* Rounds value to half grid after adding engine compensation. */
2084 /* distance :: The distance to round. */
2086 /* compensation :: The engine compensation. */
2089 /* Rounded distance. */
2092 Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance,
2093 FT_F26Dot6 compensation )
2100 if ( distance >= 0 )
2102 val = FT_PIX_FLOOR( distance + compensation ) + 32;
2103 if ( distance && val < 0 )
2108 val = -( FT_PIX_FLOOR( compensation - distance ) + 32 );
2117 /*************************************************************************/
2120 /* Round_Down_To_Grid */
2123 /* Rounds value down to grid after adding engine compensation. */
2126 /* distance :: The distance to round. */
2128 /* compensation :: The engine compensation. */
2131 /* Rounded distance. */
2134 Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
2135 FT_F26Dot6 compensation )
2142 if ( distance >= 0 )
2144 val = distance + compensation;
2145 if ( distance && val > 0 )
2152 val = -( ( compensation - distance ) & -64 );
2161 /*************************************************************************/
2164 /* Round_Up_To_Grid */
2167 /* Rounds value up to grid after adding engine compensation. */
2170 /* distance :: The distance to round. */
2172 /* compensation :: The engine compensation. */
2175 /* Rounded distance. */
2178 Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
2179 FT_F26Dot6 compensation )
2186 if ( distance >= 0 )
2188 val = distance + compensation + 63;
2189 if ( distance && val > 0 )
2196 val = - FT_PIX_CEIL( compensation - distance );
2205 /*************************************************************************/
2208 /* Round_To_Double_Grid */
2211 /* Rounds value to double grid after adding engine compensation. */
2214 /* distance :: The distance to round. */
2216 /* compensation :: The engine compensation. */
2219 /* Rounded distance. */
2222 Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance,
2223 FT_F26Dot6 compensation )
2230 if ( distance >= 0 )
2232 val = distance + compensation + 16;
2233 if ( distance && val > 0 )
2240 val = -FT_PAD_ROUND( compensation - distance, 32 );
2249 /*************************************************************************/
2255 /* Super-rounds value to grid after adding engine compensation. */
2258 /* distance :: The distance to round. */
2260 /* compensation :: The engine compensation. */
2263 /* Rounded distance. */
2266 /* The TrueType specification says very few about the relationship */
2267 /* between rounding and engine compensation. However, it seems from */
2268 /* the description of super round that we should add the compensation */
2269 /* before rounding. */
2272 Round_Super( EXEC_OP_ FT_F26Dot6 distance,
2273 FT_F26Dot6 compensation )
2278 if ( distance >= 0 )
2280 val = ( distance - CUR.phase + CUR.threshold + compensation ) &
2282 if ( distance && val < 0 )
2288 val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &
2299 /*************************************************************************/
2302 /* Round_Super_45 */
2305 /* Super-rounds value to grid after adding engine compensation. */
2308 /* distance :: The distance to round. */
2310 /* compensation :: The engine compensation. */
2313 /* Rounded distance. */
2316 /* There is a separate function for Round_Super_45() as we may need */
2317 /* greater precision. */
2320 Round_Super_45( EXEC_OP_ FT_F26Dot6 distance,
2321 FT_F26Dot6 compensation )
2326 if ( distance >= 0 )
2328 val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
2329 CUR.period ) * CUR.period;
2330 if ( distance && val < 0 )
2336 val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /
2337 CUR.period ) * CUR.period );
2347 /*************************************************************************/
2353 /* Sets the rounding mode. */
2356 /* round_mode :: The rounding mode to be used. */
2359 Compute_Round( EXEC_OP_ FT_Byte round_mode )
2361 switch ( round_mode )
2364 CUR.func_round = (TT_Round_Func)Round_None;
2367 case TT_Round_To_Grid:
2368 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2371 case TT_Round_Up_To_Grid:
2372 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2375 case TT_Round_Down_To_Grid:
2376 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2379 case TT_Round_To_Half_Grid:
2380 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2383 case TT_Round_To_Double_Grid:
2384 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2387 case TT_Round_Super:
2388 CUR.func_round = (TT_Round_Func)Round_Super;
2391 case TT_Round_Super_45:
2392 CUR.func_round = (TT_Round_Func)Round_Super_45;
2398 /*************************************************************************/
2404 /* Sets Super Round parameters. */
2407 /* GridPeriod :: Grid period */
2408 /* selector :: SROUND opcode */
2411 SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod,
2414 switch ( (FT_Int)( selector & 0xC0 ) )
2417 CUR.period = GridPeriod / 2;
2421 CUR.period = GridPeriod;
2425 CUR.period = GridPeriod * 2;
2428 /* This opcode is reserved, but... */
2431 CUR.period = GridPeriod;
2435 switch ( (FT_Int)( selector & 0x30 ) )
2442 CUR.phase = CUR.period / 4;
2446 CUR.phase = CUR.period / 2;
2450 CUR.phase = CUR.period * 3 / 4;
2454 if ( ( selector & 0x0F ) == 0 )
2455 CUR.threshold = CUR.period - 1;
2457 CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8;
2461 CUR.threshold /= 256;
2465 /*************************************************************************/
2471 /* Computes the projection of vector given by (v2-v1) along the */
2472 /* current projection vector. */
2475 /* v1 :: First input vector. */
2476 /* v2 :: Second input vector. */
2479 /* The distance in F26dot6 format. */
2482 Project( EXEC_OP_ FT_Pos dx,
2485 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2486 FT_ASSERT( !CUR.face->unpatented_hinting );
2489 return TT_DotFix14( (FT_UInt32)dx, (FT_UInt32)dy,
2490 CUR.GS.projVector.x,
2491 CUR.GS.projVector.y );
2495 /*************************************************************************/
2501 /* Computes the projection of the vector given by (v2-v1) along the */
2502 /* current dual vector. */
2505 /* v1 :: First input vector. */
2506 /* v2 :: Second input vector. */
2509 /* The distance in F26dot6 format. */
2512 Dual_Project( EXEC_OP_ FT_Pos dx,
2515 return TT_DotFix14( (FT_UInt32)dx, (FT_UInt32)dy,
2516 CUR.GS.dualVector.x,
2517 CUR.GS.dualVector.y );
2521 /*************************************************************************/
2527 /* Computes the projection of the vector given by (v2-v1) along the */
2528 /* horizontal axis. */
2531 /* v1 :: First input vector. */
2532 /* v2 :: Second input vector. */
2535 /* The distance in F26dot6 format. */
2538 Project_x( EXEC_OP_ FT_Pos dx,
2548 /*************************************************************************/
2554 /* Computes the projection of the vector given by (v2-v1) along the */
2555 /* vertical axis. */
2558 /* v1 :: First input vector. */
2559 /* v2 :: Second input vector. */
2562 /* The distance in F26dot6 format. */
2565 Project_y( EXEC_OP_ FT_Pos dx,
2575 /*************************************************************************/
2581 /* Computes the projection and movement function pointers according */
2582 /* to the current graphics state. */
2585 Compute_Funcs( EXEC_OP )
2587 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2588 if ( CUR.face->unpatented_hinting )
2590 /* If both vectors point rightwards along the x axis, set */
2591 /* `both-x-axis' true, otherwise set it false. The x values only */
2592 /* need be tested because the vector has been normalised to a unit */
2593 /* vector of length 0x4000 = unity. */
2594 CUR.GS.both_x_axis = (FT_Bool)( CUR.GS.projVector.x == 0x4000 &&
2595 CUR.GS.freeVector.x == 0x4000 );
2597 /* Throw away projection and freedom vector information */
2598 /* because the patents don't allow them to be stored. */
2599 /* The relevant US Patents are 5155805 and 5325479. */
2600 CUR.GS.projVector.x = 0;
2601 CUR.GS.projVector.y = 0;
2602 CUR.GS.freeVector.x = 0;
2603 CUR.GS.freeVector.y = 0;
2605 if ( CUR.GS.both_x_axis )
2607 CUR.func_project = Project_x;
2608 CUR.func_move = Direct_Move_X;
2609 CUR.func_move_orig = Direct_Move_Orig_X;
2613 CUR.func_project = Project_y;
2614 CUR.func_move = Direct_Move_Y;
2615 CUR.func_move_orig = Direct_Move_Orig_Y;
2618 if ( CUR.GS.dualVector.x == 0x4000 )
2619 CUR.func_dualproj = Project_x;
2622 if ( CUR.GS.dualVector.y == 0x4000 )
2623 CUR.func_dualproj = Project_y;
2625 CUR.func_dualproj = Dual_Project;
2628 /* Force recalculation of cached aspect ratio */
2629 CUR.tt_metrics.ratio = 0;
2633 #endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING */
2635 if ( CUR.GS.freeVector.x == 0x4000 )
2636 CUR.F_dot_P = CUR.GS.projVector.x * 0x10000L;
2639 if ( CUR.GS.freeVector.y == 0x4000 )
2640 CUR.F_dot_P = CUR.GS.projVector.y * 0x10000L;
2642 CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
2643 (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
2646 if ( CUR.GS.projVector.x == 0x4000 )
2647 CUR.func_project = (TT_Project_Func)Project_x;
2650 if ( CUR.GS.projVector.y == 0x4000 )
2651 CUR.func_project = (TT_Project_Func)Project_y;
2653 CUR.func_project = (TT_Project_Func)Project;
2656 if ( CUR.GS.dualVector.x == 0x4000 )
2657 CUR.func_dualproj = (TT_Project_Func)Project_x;
2660 if ( CUR.GS.dualVector.y == 0x4000 )
2661 CUR.func_dualproj = (TT_Project_Func)Project_y;
2663 CUR.func_dualproj = (TT_Project_Func)Dual_Project;
2666 CUR.func_move = (TT_Move_Func)Direct_Move;
2667 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig;
2669 if ( CUR.F_dot_P == 0x40000000L )
2671 if ( CUR.GS.freeVector.x == 0x4000 )
2673 CUR.func_move = (TT_Move_Func)Direct_Move_X;
2674 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;
2678 if ( CUR.GS.freeVector.y == 0x4000 )
2680 CUR.func_move = (TT_Move_Func)Direct_Move_Y;
2681 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
2686 /* at small sizes, F_dot_P can become too small, resulting */
2687 /* in overflows and `spikes' in a number of glyphs like `w'. */
2689 if ( FT_ABS( CUR.F_dot_P ) < 0x4000000L )
2690 CUR.F_dot_P = 0x40000000L;
2692 /* Disable cached aspect ratio */
2693 CUR.tt_metrics.ratio = 0;
2697 /*************************************************************************/
2703 /* Norms a vector. */
2706 /* Vx :: The horizontal input vector coordinate. */
2707 /* Vy :: The vertical input vector coordinate. */
2710 /* R :: The normed unit vector. */
2713 /* Returns FAILURE if a vector parameter is zero. */
2716 /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
2717 /* R is undefined. */
2722 Normalize( EXEC_OP_ FT_F26Dot6 Vx,
2732 if ( FT_ABS( Vx ) < 0x10000L && FT_ABS( Vy ) < 0x10000L )
2737 W = TT_VecLen( Vx, Vy );
2741 /* XXX: UNDOCUMENTED! It seems that it is possible to try */
2742 /* to normalize the vector (0,0). Return immediately. */
2746 R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W );
2747 R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W );
2752 W = TT_VecLen( Vx, Vy );
2754 Vx = FT_MulDiv( Vx, 0x4000L, W );
2755 Vy = FT_MulDiv( Vy, 0x4000L, W );
2757 W = Vx * Vx + Vy * Vy;
2759 /* Now, we want that Sqrt( W ) = 0x4000 */
2760 /* Or 0x10000000 <= W < 0x10004000 */
2778 while ( W < 0x10000000L )
2780 /* We need to increase W by a minimal amount */
2786 W = Vx * Vx + Vy * Vy;
2789 while ( W >= 0x10004000L )
2791 /* We need to decrease W by a minimal amount */
2797 W = Vx * Vx + Vy * Vy;
2800 /* Note that in various cases, we can only */
2801 /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
2809 R->x = (FT_F2Dot14)Vx; /* Type conversion */
2810 R->y = (FT_F2Dot14)Vy; /* Type conversion */
2816 /*************************************************************************/
2818 /* Here we start with the implementation of the various opcodes. */
2820 /*************************************************************************/
2824 Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1,
2827 FT_UnitVector* Vec )
2834 if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
2835 BOUNDS( aIdx2, CUR.zp1.n_points ) )
2837 if ( CUR.pedantic_hinting )
2838 CUR.error = TT_Err_Invalid_Reference;
2842 p1 = CUR.zp1.cur + aIdx2;
2843 p2 = CUR.zp2.cur + aIdx1;
2848 /* If p1 == p2, SPVTL and SFVTL behave the same as */
2849 /* SPVTCA[X] and SFVTCA[X], respectively. */
2851 /* Confirmed by Greg Hitchcock. */
2853 if ( A == 0 && B == 0 )
2859 if ( ( aOpc & 1 ) != 0 )
2861 C = B; /* counter clockwise rotation */
2866 NORMalize( A, B, Vec );
2872 /* When not using the big switch statements, the interpreter uses a */
2873 /* call table defined later below in this source. Each opcode must */
2874 /* thus have a corresponding function, even trivial ones. */
2876 /* They are all defined there. */
2883 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2884 B = A ^ (FT_Short)0x4000; \
2886 CUR.GS.freeVector.x = A; \
2887 CUR.GS.projVector.x = A; \
2888 CUR.GS.dualVector.x = A; \
2890 CUR.GS.freeVector.y = B; \
2891 CUR.GS.projVector.y = B; \
2892 CUR.GS.dualVector.y = B; \
2903 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2904 B = A ^ (FT_Short)0x4000; \
2906 CUR.GS.projVector.x = A; \
2907 CUR.GS.dualVector.x = A; \
2909 CUR.GS.projVector.y = B; \
2910 CUR.GS.dualVector.y = B; \
2912 GUESS_VECTOR( freeVector ); \
2923 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2924 B = A ^ (FT_Short)0x4000; \
2926 CUR.GS.freeVector.x = A; \
2927 CUR.GS.freeVector.y = B; \
2929 GUESS_VECTOR( projVector ); \
2936 if ( INS_SxVTL( (FT_UShort)args[1], \
2937 (FT_UShort)args[0], \
2939 &CUR.GS.projVector ) == SUCCESS ) \
2941 CUR.GS.dualVector = CUR.GS.projVector; \
2942 GUESS_VECTOR( freeVector ); \
2948 if ( INS_SxVTL( (FT_UShort)args[1], \
2949 (FT_UShort)args[0], \
2951 &CUR.GS.freeVector ) == SUCCESS ) \
2953 GUESS_VECTOR( projVector ); \
2959 GUESS_VECTOR( projVector ); \
2960 CUR.GS.freeVector = CUR.GS.projVector; \
2970 /* Only use low 16bits, then sign extend */ \
2971 S = (FT_Short)args[1]; \
2973 S = (FT_Short)args[0]; \
2976 NORMalize( X, Y, &CUR.GS.projVector ); \
2978 CUR.GS.dualVector = CUR.GS.projVector; \
2979 GUESS_VECTOR( freeVector ); \
2990 /* Only use low 16bits, then sign extend */ \
2991 S = (FT_Short)args[1]; \
2993 S = (FT_Short)args[0]; \
2996 NORMalize( X, Y, &CUR.GS.freeVector ); \
2997 GUESS_VECTOR( projVector ); \
3002 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
3004 if ( CUR.face->unpatented_hinting ) \
3006 args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
3007 args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
3011 args[0] = CUR.GS.projVector.x; \
3012 args[1] = CUR.GS.projVector.y; \
3016 args[0] = CUR.GS.projVector.x; \
3017 args[1] = CUR.GS.projVector.y;
3021 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
3023 if ( CUR.face->unpatented_hinting ) \
3025 args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
3026 args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
3030 args[0] = CUR.GS.freeVector.x; \
3031 args[1] = CUR.GS.freeVector.y; \
3035 args[0] = CUR.GS.freeVector.x; \
3036 args[1] = CUR.GS.freeVector.y;
3041 CUR.GS.rp0 = (FT_UShort)args[0];
3045 CUR.GS.rp1 = (FT_UShort)args[0];
3049 CUR.GS.rp2 = (FT_UShort)args[0];
3053 CUR.GS.round_state = TT_Round_To_Half_Grid; \
3054 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
3058 CUR.GS.round_state = TT_Round_To_Grid; \
3059 CUR.func_round = (TT_Round_Func)Round_To_Grid;
3063 CUR.GS.round_state = TT_Round_To_Double_Grid; \
3064 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
3068 CUR.GS.round_state = TT_Round_Up_To_Grid; \
3069 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
3073 CUR.GS.round_state = TT_Round_Down_To_Grid; \
3074 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
3078 CUR.GS.round_state = TT_Round_Off; \
3079 CUR.func_round = (TT_Round_Func)Round_None;
3083 SET_SuperRound( 0x4000, args[0] ); \
3084 CUR.GS.round_state = TT_Round_Super; \
3085 CUR.func_round = (TT_Round_Func)Round_Super;
3088 #define DO_S45ROUND \
3089 SET_SuperRound( 0x2D41, args[0] ); \
3090 CUR.GS.round_state = TT_Round_Super_45; \
3091 CUR.func_round = (TT_Round_Func)Round_Super_45;
3095 if ( args[0] < 0 ) \
3096 CUR.error = TT_Err_Bad_Argument; \
3098 CUR.GS.loop = args[0];
3102 CUR.GS.minimum_distance = args[0];
3106 CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
3110 CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
3113 /* XXX: UNDOCUMENTED! or bug in the Windows engine? */
3115 /* It seems that the value that is read here is */
3116 /* expressed in 16.16 format rather than in font */
3120 CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
3124 CUR.GS.auto_flip = TRUE;
3127 #define DO_FLIPOFF \
3128 CUR.GS.auto_flip = FALSE;
3132 CUR.GS.delta_base = (FT_Short)args[0];
3136 CUR.GS.delta_shift = (FT_Short)args[0];
3139 #define DO_MD /* nothing */
3143 args[0] = CURRENT_Ppem();
3146 /* Note: The pointSize should be irrelevant in a given font program; */
3147 /* we thus decide to return only the ppem. */
3151 args[0] = CUR.metrics.pointSize;
3156 args[0] = CURRENT_Ppem();
3175 args[0] = args[1]; \
3191 if ( L <= 0 || L > CUR.args ) \
3193 if ( CUR.pedantic_hinting ) \
3194 CUR.error = TT_Err_Invalid_Reference; \
3198 args[0] = CUR.stack[CUR.args - L]; \
3203 if ( args[1] != 0 ) \
3205 if ( args[0] == 0 && CUR.args == 0 ) \
3206 CUR.error = TT_Err_Bad_Argument; \
3207 CUR.IP += args[0]; \
3208 if ( CUR.IP < 0 || \
3209 ( CUR.callTop > 0 && \
3210 CUR.IP > CUR.callStack[CUR.callTop - 1].Cur_End ) ) \
3211 CUR.error = TT_Err_Bad_Argument; \
3212 CUR.step_ins = FALSE; \
3217 if ( args[0] == 0 && CUR.args == 0 ) \
3218 CUR.error = TT_Err_Bad_Argument; \
3219 CUR.IP += args[0]; \
3220 if ( CUR.IP < 0 || \
3221 ( CUR.callTop > 0 && \
3222 CUR.IP > CUR.callStack[CUR.callTop - 1].Cur_End ) ) \
3223 CUR.error = TT_Err_Bad_Argument; \
3224 CUR.step_ins = FALSE;
3228 if ( args[1] == 0 ) \
3230 if ( args[0] == 0 && CUR.args == 0 ) \
3231 CUR.error = TT_Err_Bad_Argument; \
3232 CUR.IP += args[0]; \
3233 if ( CUR.IP < 0 || \
3234 ( CUR.callTop > 0 && \
3235 CUR.IP > CUR.callStack[CUR.callTop - 1].Cur_End ) ) \
3236 CUR.error = TT_Err_Bad_Argument; \
3237 CUR.step_ins = FALSE; \
3242 args[0] = ( args[0] < args[1] );
3246 args[0] = ( args[0] <= args[1] );
3250 args[0] = ( args[0] > args[1] );
3254 args[0] = ( args[0] >= args[1] );
3258 args[0] = ( args[0] == args[1] );
3262 args[0] = ( args[0] != args[1] );
3266 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
3270 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
3274 args[0] = ( args[0] && args[1] );
3278 args[0] = ( args[0] || args[1] );
3294 if ( args[1] == 0 ) \
3295 CUR.error = TT_Err_Divide_By_Zero; \
3297 args[0] = TT_MULDIV_NO_ROUND( args[0], 64L, args[1] );
3301 args[0] = TT_MULDIV( args[0], args[1], 64L );
3305 args[0] = FT_ABS( args[0] );
3313 args[0] = FT_PIX_FLOOR( args[0] );
3316 #define DO_CEILING \
3317 args[0] = FT_PIX_CEIL( args[0] );
3322 FT_ULong I = (FT_ULong)args[0]; \
3325 if ( BOUNDSL( I, CUR.storeSize ) ) \
3327 if ( CUR.pedantic_hinting ) \
3329 ARRAY_BOUND_ERROR; \
3335 args[0] = CUR.storage[I]; \
3341 FT_ULong I = (FT_ULong)args[0]; \
3344 if ( BOUNDSL( I, CUR.storeSize ) ) \
3346 if ( CUR.pedantic_hinting ) \
3348 ARRAY_BOUND_ERROR; \
3352 CUR.storage[I] = args[1]; \
3358 FT_ULong I = (FT_ULong)args[0]; \
3361 if ( BOUNDSL( I, CUR.cvtSize ) ) \
3363 if ( CUR.pedantic_hinting ) \
3365 ARRAY_BOUND_ERROR; \
3371 args[0] = CUR_Func_read_cvt( I ); \
3377 FT_ULong I = (FT_ULong)args[0]; \
3380 if ( BOUNDSL( I, CUR.cvtSize ) ) \
3382 if ( CUR.pedantic_hinting ) \
3384 ARRAY_BOUND_ERROR; \
3388 CUR_Func_write_cvt( I, args[1] ); \
3394 FT_ULong I = (FT_ULong)args[0]; \
3397 if ( BOUNDSL( I, CUR.cvtSize ) ) \
3399 if ( CUR.pedantic_hinting ) \
3401 ARRAY_BOUND_ERROR; \
3405 CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
3410 CUR.error = TT_Err_Debug_OpCode;
3414 args[0] = CUR_Func_round( \
3416 CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
3420 args[0] = ROUND_None( args[0], \
3421 CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
3425 if ( args[1] > args[0] ) \
3430 if ( args[1] < args[0] ) \
3434 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
3437 #undef ARRAY_BOUND_ERROR
3438 #define ARRAY_BOUND_ERROR \
3440 CUR.error = TT_Err_Invalid_Reference; \
3445 /*************************************************************************/
3447 /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
3448 /* Opcode range: 0x00-0x01 */
3452 Ins_SVTCA( INS_ARG )
3458 /*************************************************************************/
3460 /* SPVTCA[a]: Set PVector to Coordinate Axis */
3461 /* Opcode range: 0x02-0x03 */
3465 Ins_SPVTCA( INS_ARG )
3471 /*************************************************************************/
3473 /* SFVTCA[a]: Set FVector to Coordinate Axis */
3474 /* Opcode range: 0x04-0x05 */
3478 Ins_SFVTCA( INS_ARG )
3484 /*************************************************************************/
3486 /* SPVTL[a]: Set PVector To Line */
3487 /* Opcode range: 0x06-0x07 */
3488 /* Stack: uint32 uint32 --> */
3491 Ins_SPVTL( INS_ARG )
3497 /*************************************************************************/
3499 /* SFVTL[a]: Set FVector To Line */
3500 /* Opcode range: 0x08-0x09 */
3501 /* Stack: uint32 uint32 --> */
3504 Ins_SFVTL( INS_ARG )
3510 /*************************************************************************/
3512 /* SFVTPV[]: Set FVector To PVector */
3513 /* Opcode range: 0x0E */
3517 Ins_SFVTPV( INS_ARG )
3523 /*************************************************************************/
3525 /* SPVFS[]: Set PVector From Stack */
3526 /* Opcode range: 0x0A */
3527 /* Stack: f2.14 f2.14 --> */
3530 Ins_SPVFS( INS_ARG )
3536 /*************************************************************************/
3538 /* SFVFS[]: Set FVector From Stack */
3539 /* Opcode range: 0x0B */
3540 /* Stack: f2.14 f2.14 --> */
3543 Ins_SFVFS( INS_ARG )
3549 /*************************************************************************/
3551 /* GPV[]: Get Projection Vector */
3552 /* Opcode range: 0x0C */
3553 /* Stack: ef2.14 --> ef2.14 */
3562 /*************************************************************************/
3563 /* GFV[]: Get Freedom Vector */
3564 /* Opcode range: 0x0D */
3565 /* Stack: ef2.14 --> ef2.14 */
3574 /*************************************************************************/
3576 /* SRP0[]: Set Reference Point 0 */
3577 /* Opcode range: 0x10 */
3578 /* Stack: uint32 --> */
3587 /*************************************************************************/
3589 /* SRP1[]: Set Reference Point 1 */
3590 /* Opcode range: 0x11 */
3591 /* Stack: uint32 --> */
3600 /*************************************************************************/
3602 /* SRP2[]: Set Reference Point 2 */
3603 /* Opcode range: 0x12 */
3604 /* Stack: uint32 --> */
3613 /*************************************************************************/
3615 /* RTHG[]: Round To Half Grid */
3616 /* Opcode range: 0x19 */
3626 /*************************************************************************/
3628 /* RTG[]: Round To Grid */
3629 /* Opcode range: 0x18 */
3639 /*************************************************************************/
3640 /* RTDG[]: Round To Double Grid */
3641 /* Opcode range: 0x3D */
3651 /*************************************************************************/
3652 /* RUTG[]: Round Up To Grid */
3653 /* Opcode range: 0x7C */
3663 /*************************************************************************/
3665 /* RDTG[]: Round Down To Grid */
3666 /* Opcode range: 0x7D */
3676 /*************************************************************************/
3678 /* ROFF[]: Round OFF */
3679 /* Opcode range: 0x7A */
3689 /*************************************************************************/
3691 /* SROUND[]: Super ROUND */
3692 /* Opcode range: 0x76 */
3693 /* Stack: Eint8 --> */
3696 Ins_SROUND( INS_ARG )
3702 /*************************************************************************/
3704 /* S45ROUND[]: Super ROUND 45 degrees */
3705 /* Opcode range: 0x77 */
3706 /* Stack: uint32 --> */
3709 Ins_S45ROUND( INS_ARG )
3715 /*************************************************************************/
3717 /* SLOOP[]: Set LOOP variable */
3718 /* Opcode range: 0x17 */
3719 /* Stack: int32? --> */
3722 Ins_SLOOP( INS_ARG )
3728 /*************************************************************************/
3730 /* SMD[]: Set Minimum Distance */
3731 /* Opcode range: 0x1A */
3732 /* Stack: f26.6 --> */
3741 /*************************************************************************/
3743 /* SCVTCI[]: Set Control Value Table Cut In */
3744 /* Opcode range: 0x1D */
3745 /* Stack: f26.6 --> */
3748 Ins_SCVTCI( INS_ARG )
3754 /*************************************************************************/
3756 /* SSWCI[]: Set Single Width Cut In */
3757 /* Opcode range: 0x1E */
3758 /* Stack: f26.6 --> */
3761 Ins_SSWCI( INS_ARG )
3767 /*************************************************************************/
3769 /* SSW[]: Set Single Width */
3770 /* Opcode range: 0x1F */
3771 /* Stack: int32? --> */
3780 /*************************************************************************/
3782 /* FLIPON[]: Set auto-FLIP to ON */
3783 /* Opcode range: 0x4D */
3787 Ins_FLIPON( INS_ARG )
3793 /*************************************************************************/
3795 /* FLIPOFF[]: Set auto-FLIP to OFF */
3796 /* Opcode range: 0x4E */
3800 Ins_FLIPOFF( INS_ARG )
3806 /*************************************************************************/
3808 /* SANGW[]: Set ANGle Weight */
3809 /* Opcode range: 0x7E */
3810 /* Stack: uint32 --> */
3813 Ins_SANGW( INS_ARG )
3815 /* instruction not supported anymore */
3819 /*************************************************************************/
3821 /* SDB[]: Set Delta Base */
3822 /* Opcode range: 0x5E */
3823 /* Stack: uint32 --> */
3832 /*************************************************************************/
3834 /* SDS[]: Set Delta Shift */
3835 /* Opcode range: 0x5F */
3836 /* Stack: uint32 --> */
3845 /*************************************************************************/
3847 /* MPPEM[]: Measure Pixel Per EM */
3848 /* Opcode range: 0x4B */
3849 /* Stack: --> Euint16 */
3852 Ins_MPPEM( INS_ARG )
3858 /*************************************************************************/
3860 /* MPS[]: Measure Point Size */
3861 /* Opcode range: 0x4C */
3862 /* Stack: --> Euint16 */
3871 /*************************************************************************/
3873 /* DUP[]: DUPlicate the top stack's element */
3874 /* Opcode range: 0x20 */
3875 /* Stack: StkElt --> StkElt StkElt */
3884 /*************************************************************************/
3886 /* POP[]: POP the stack's top element */
3887 /* Opcode range: 0x21 */
3888 /* Stack: StkElt --> */
3897 /*************************************************************************/
3899 /* CLEAR[]: CLEAR the entire stack */
3900 /* Opcode range: 0x22 */
3901 /* Stack: StkElt... --> */
3904 Ins_CLEAR( INS_ARG )
3910 /*************************************************************************/
3912 /* SWAP[]: SWAP the stack's top two elements */
3913 /* Opcode range: 0x23 */
3914 /* Stack: 2 * StkElt --> 2 * StkElt */
3923 /*************************************************************************/
3925 /* DEPTH[]: return the stack DEPTH */
3926 /* Opcode range: 0x24 */
3927 /* Stack: --> uint32 */
3930 Ins_DEPTH( INS_ARG )
3936 /*************************************************************************/
3938 /* CINDEX[]: Copy INDEXed element */
3939 /* Opcode range: 0x25 */
3940 /* Stack: int32 --> StkElt */
3943 Ins_CINDEX( INS_ARG )
3949 /*************************************************************************/
3952 /* Opcode range: 0x59 */
3962 /*************************************************************************/
3964 /* JROT[]: Jump Relative On True */
3965 /* Opcode range: 0x78 */
3966 /* Stack: StkElt int32 --> */
3975 /*************************************************************************/
3977 /* JMPR[]: JuMP Relative */
3978 /* Opcode range: 0x1C */
3979 /* Stack: int32 --> */
3988 /*************************************************************************/
3990 /* JROF[]: Jump Relative On False */
3991 /* Opcode range: 0x79 */
3992 /* Stack: StkElt int32 --> */
4001 /*************************************************************************/
4003 /* LT[]: Less Than */
4004 /* Opcode range: 0x50 */
4005 /* Stack: int32? int32? --> bool */
4014 /*************************************************************************/
4016 /* LTEQ[]: Less Than or EQual */
4017 /* Opcode range: 0x51 */
4018 /* Stack: int32? int32? --> bool */
4027 /*************************************************************************/
4029 /* GT[]: Greater Than */
4030 /* Opcode range: 0x52 */
4031 /* Stack: int32? int32? --> bool */
4040 /*************************************************************************/
4042 /* GTEQ[]: Greater Than or EQual */
4043 /* Opcode range: 0x53 */
4044 /* Stack: int32? int32? --> bool */
4053 /*************************************************************************/
4056 /* Opcode range: 0x54 */
4057 /* Stack: StkElt StkElt --> bool */
4066 /*************************************************************************/
4068 /* NEQ[]: Not EQual */
4069 /* Opcode range: 0x55 */
4070 /* Stack: StkElt StkElt --> bool */
4079 /*************************************************************************/
4082 /* Opcode range: 0x56 */
4083 /* Stack: f26.6 --> bool */
4092 /*************************************************************************/
4094 /* EVEN[]: Is EVEN */
4095 /* Opcode range: 0x57 */
4096 /* Stack: f26.6 --> bool */
4105 /*************************************************************************/
4107 /* AND[]: logical AND */
4108 /* Opcode range: 0x5A */
4109 /* Stack: uint32 uint32 --> uint32 */
4118 /*************************************************************************/
4120 /* OR[]: logical OR */
4121 /* Opcode range: 0x5B */
4122 /* Stack: uint32 uint32 --> uint32 */
4131 /*************************************************************************/
4133 /* NOT[]: logical NOT */
4134 /* Opcode range: 0x5C */
4135 /* Stack: StkElt --> uint32 */
4144 /*************************************************************************/
4147 /* Opcode range: 0x60 */
4148 /* Stack: f26.6 f26.6 --> f26.6 */
4157 /*************************************************************************/
4159 /* SUB[]: SUBtract */
4160 /* Opcode range: 0x61 */
4161 /* Stack: f26.6 f26.6 --> f26.6 */
4170 /*************************************************************************/
4173 /* Opcode range: 0x62 */
4174 /* Stack: f26.6 f26.6 --> f26.6 */
4183 /*************************************************************************/
4185 /* MUL[]: MULtiply */
4186 /* Opcode range: 0x63 */
4187 /* Stack: f26.6 f26.6 --> f26.6 */
4196 /*************************************************************************/
4198 /* ABS[]: ABSolute value */
4199 /* Opcode range: 0x64 */
4200 /* Stack: f26.6 --> f26.6 */
4209 /*************************************************************************/
4212 /* Opcode range: 0x65 */
4213 /* Stack: f26.6 --> f26.6 */
4222 /*************************************************************************/
4224 /* FLOOR[]: FLOOR */
4225 /* Opcode range: 0x66 */
4226 /* Stack: f26.6 --> f26.6 */
4229 Ins_FLOOR( INS_ARG )
4235 /*************************************************************************/
4237 /* CEILING[]: CEILING */
4238 /* Opcode range: 0x67 */
4239 /* Stack: f26.6 --> f26.6 */
4242 Ins_CEILING( INS_ARG )
4248 /*************************************************************************/
4250 /* RS[]: Read Store */
4251 /* Opcode range: 0x43 */
4252 /* Stack: uint32 --> uint32 */
4261 /*************************************************************************/
4263 /* WS[]: Write Store */
4264 /* Opcode range: 0x42 */
4265 /* Stack: uint32 uint32 --> */
4274 /*************************************************************************/
4276 /* WCVTP[]: Write CVT in Pixel units */
4277 /* Opcode range: 0x44 */
4278 /* Stack: f26.6 uint32 --> */
4281 Ins_WCVTP( INS_ARG )
4287 /*************************************************************************/
4289 /* WCVTF[]: Write CVT in Funits */
4290 /* Opcode range: 0x70 */
4291 /* Stack: uint32 uint32 --> */
4294 Ins_WCVTF( INS_ARG )
4300 /*************************************************************************/
4302 /* RCVT[]: Read CVT */
4303 /* Opcode range: 0x45 */
4304 /* Stack: uint32 --> f26.6 */
4313 /*************************************************************************/
4315 /* AA[]: Adjust Angle */
4316 /* Opcode range: 0x7F */
4317 /* Stack: uint32 --> */
4322 /* intentionally no longer supported */
4326 /*************************************************************************/
4328 /* DEBUG[]: DEBUG. Unsupported. */
4329 /* Opcode range: 0x4F */
4330 /* Stack: uint32 --> */
4332 /* Note: The original instruction pops a value from the stack. */
4335 Ins_DEBUG( INS_ARG )
4341 /*************************************************************************/
4343 /* ROUND[ab]: ROUND value */
4344 /* Opcode range: 0x68-0x6B */
4345 /* Stack: f26.6 --> f26.6 */
4348 Ins_ROUND( INS_ARG )
4354 /*************************************************************************/
4356 /* NROUND[ab]: No ROUNDing of value */
4357 /* Opcode range: 0x6C-0x6F */
4358 /* Stack: f26.6 --> f26.6 */
4361 Ins_NROUND( INS_ARG )
4367 /*************************************************************************/
4369 /* MAX[]: MAXimum */
4370 /* Opcode range: 0x68 */
4371 /* Stack: int32? int32? --> int32 */
4380 /*************************************************************************/
4382 /* MIN[]: MINimum */
4383 /* Opcode range: 0x69 */
4384 /* Stack: int32? int32? --> int32 */
4393 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
4396 /*************************************************************************/
4398 /* The following functions are called as is within the switch statement. */
4400 /*************************************************************************/
4403 /*************************************************************************/
4405 /* MINDEX[]: Move INDEXed element */
4406 /* Opcode range: 0x26 */
4407 /* Stack: int32? --> StkElt */
4410 Ins_MINDEX( INS_ARG )
4417 if ( L <= 0 || L > CUR.args )
4419 if ( CUR.pedantic_hinting )
4420 CUR.error = TT_Err_Invalid_Reference;
4424 K = CUR.stack[CUR.args - L];
4426 FT_ARRAY_MOVE( &CUR.stack[CUR.args - L ],
4427 &CUR.stack[CUR.args - L + 1],
4430 CUR.stack[CUR.args - 1] = K;
4435 /*************************************************************************/
4437 /* ROLL[]: ROLL top three elements */
4438 /* Opcode range: 0x8A */
4439 /* Stack: 3 * StkElt --> 3 * StkElt */
4459 /*************************************************************************/
4461 /* MANAGING THE FLOW OF CONTROL */
4463 /* Instructions appear in the specification's order. */
4465 /*************************************************************************/
4471 CUR.IP += CUR.length;
4473 if ( CUR.IP < CUR.codeSize )
4475 CUR.opcode = CUR.code[CUR.IP];
4477 CUR.length = opcode_length[CUR.opcode];
4478 if ( CUR.length < 0 )
4480 if ( CUR.IP + 1 >= CUR.codeSize )
4482 CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
4485 if ( CUR.IP + CUR.length <= CUR.codeSize )
4490 CUR.error = TT_Err_Code_Overflow;
4495 /*************************************************************************/
4498 /* Opcode range: 0x58 */
4499 /* Stack: StkElt --> */
4516 if ( SKIP_Code() == FAILURE )
4519 switch ( CUR.opcode )
4525 case 0x1B: /* ELSE */
4526 Out = FT_BOOL( nIfs == 1 );
4529 case 0x59: /* EIF */
4531 Out = FT_BOOL( nIfs == 0 );
4534 } while ( Out == 0 );
4538 /*************************************************************************/
4541 /* Opcode range: 0x1B */
4556 if ( SKIP_Code() == FAILURE )
4559 switch ( CUR.opcode )
4565 case 0x59: /* EIF */
4569 } while ( nIfs != 0 );
4573 /*************************************************************************/
4575 /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
4577 /* Instructions appear in the specification's order. */
4579 /*************************************************************************/
4582 /*************************************************************************/
4584 /* FDEF[]: Function DEFinition */
4585 /* Opcode range: 0x2C */
4586 /* Stack: uint32 --> */
4593 TT_DefRecord* limit;
4596 /* some font programs are broken enough to redefine functions! */
4597 /* We will then parse the current table. */
4600 limit = rec + CUR.numFDefs;
4603 for ( ; rec < limit; rec++ )
4605 if ( rec->opc == n )
4611 /* check that there is enough room for new functions */
4612 if ( CUR.numFDefs >= CUR.maxFDefs )
4614 CUR.error = TT_Err_Too_Many_Function_Defs;
4620 /* Although FDEF takes unsigned 32-bit integer, */
4621 /* func # must be within unsigned 16-bit integer */
4624 CUR.error = TT_Err_Too_Many_Function_Defs;
4628 rec->range = CUR.curRange;
4629 rec->opc = (FT_UInt16)n;
4630 rec->start = CUR.IP + 1;
4633 if ( n > CUR.maxFunc )
4634 CUR.maxFunc = (FT_UInt16)n;
4636 /* Now skip the whole function definition. */
4637 /* We don't allow nested IDEFS & FDEFs. */
4639 while ( SKIP_Code() == SUCCESS )
4641 switch ( CUR.opcode )
4643 case 0x89: /* IDEF */
4644 case 0x2C: /* FDEF */
4645 CUR.error = TT_Err_Nested_DEFS;
4648 case 0x2D: /* ENDF */
4656 /*************************************************************************/
4658 /* ENDF[]: END Function definition */
4659 /* Opcode range: 0x2D */
4670 if ( CUR.callTop <= 0 ) /* We encountered an ENDF without a call */
4672 CUR.error = TT_Err_ENDF_In_Exec_Stream;
4678 pRec = &CUR.callStack[CUR.callTop];
4682 CUR.step_ins = FALSE;
4684 if ( pRec->Cur_Count > 0 )
4687 CUR.IP = pRec->Cur_Restart;
4690 /* Loop through the current function */
4691 INS_Goto_CodeRange( pRec->Caller_Range,
4694 /* Exit the current call frame. */
4696 /* NOTE: If the last instruction of a program is a */
4697 /* CALL or LOOPCALL, the return address is */
4698 /* always out of the code range. This is a */
4699 /* valid address, and it is why we do not test */
4700 /* the result of Ins_Goto_CodeRange() here! */
4704 /*************************************************************************/
4706 /* CALL[]: CALL function */
4707 /* Opcode range: 0x2B */
4708 /* Stack: uint32? --> */
4718 /* first of all, check the index */
4721 if ( BOUNDSL( F, CUR.maxFunc + 1 ) )
4724 /* Except for some old Apple fonts, all functions in a TrueType */
4725 /* font are defined in increasing order, starting from 0. This */
4726 /* means that we normally have */
4728 /* CUR.maxFunc+1 == CUR.numFDefs */
4729 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4731 /* If this isn't true, we need to look up the function table. */
4733 def = CUR.FDefs + F;
4734 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
4736 /* look up the FDefs table */
4737 TT_DefRecord* limit;
4741 limit = def + CUR.numFDefs;
4743 while ( def < limit && def->opc != F )
4750 /* check that the function is active */
4754 /* check the call stack */
4755 if ( CUR.callTop >= CUR.callSize )
4757 CUR.error = TT_Err_Stack_Overflow;
4761 pCrec = CUR.callStack + CUR.callTop;
4763 pCrec->Caller_Range = CUR.curRange;
4764 pCrec->Caller_IP = CUR.IP + 1;
4765 pCrec->Cur_Count = 1;
4766 pCrec->Cur_Restart = def->start;
4767 pCrec->Cur_End = def->end;
4771 INS_Goto_CodeRange( def->range,
4774 CUR.step_ins = FALSE;
4778 CUR.error = TT_Err_Invalid_Reference;
4782 /*************************************************************************/
4784 /* LOOPCALL[]: LOOP and CALL function */
4785 /* Opcode range: 0x2A */
4786 /* Stack: uint32? Eint16? --> */
4789 Ins_LOOPCALL( INS_ARG )
4796 /* first of all, check the index */
4798 if ( BOUNDSL( F, CUR.maxFunc + 1 ) )
4801 /* Except for some old Apple fonts, all functions in a TrueType */
4802 /* font are defined in increasing order, starting from 0. This */
4803 /* means that we normally have */
4805 /* CUR.maxFunc+1 == CUR.numFDefs */
4806 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4808 /* If this isn't true, we need to look up the function table. */
4810 def = CUR.FDefs + F;
4811 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
4813 /* look up the FDefs table */
4814 TT_DefRecord* limit;
4818 limit = def + CUR.numFDefs;
4820 while ( def < limit && def->opc != F )
4827 /* check that the function is active */
4832 if ( CUR.callTop >= CUR.callSize )
4834 CUR.error = TT_Err_Stack_Overflow;
4840 pCrec = CUR.callStack + CUR.callTop;
4842 pCrec->Caller_Range = CUR.curRange;
4843 pCrec->Caller_IP = CUR.IP + 1;
4844 pCrec->Cur_Count = (FT_Int)args[0];
4845 pCrec->Cur_Restart = def->start;
4846 pCrec->Cur_End = def->end;
4850 INS_Goto_CodeRange( def->range, def->start );
4852 CUR.step_ins = FALSE;
4857 CUR.error = TT_Err_Invalid_Reference;
4861 /*************************************************************************/
4863 /* IDEF[]: Instruction DEFinition */
4864 /* Opcode range: 0x89 */
4865 /* Stack: Eint8 --> */
4871 TT_DefRecord* limit;
4874 /* First of all, look for the same function in our table */
4877 limit = def + CUR.numIDefs;
4879 for ( ; def < limit; def++ )
4880 if ( def->opc == (FT_ULong)args[0] )
4885 /* check that there is enough room for a new instruction */
4886 if ( CUR.numIDefs >= CUR.maxIDefs )
4888 CUR.error = TT_Err_Too_Many_Instruction_Defs;
4894 /* opcode must be unsigned 8-bit integer */
4895 if ( 0 > args[0] || args[0] > 0x00FF )
4897 CUR.error = TT_Err_Too_Many_Instruction_Defs;
4901 def->opc = (FT_Byte)args[0];
4902 def->start = CUR.IP + 1;
4903 def->range = CUR.curRange;
4906 if ( (FT_ULong)args[0] > CUR.maxIns )
4907 CUR.maxIns = (FT_Byte)args[0];
4909 /* Now skip the whole function definition. */
4910 /* We don't allow nested IDEFs & FDEFs. */
4912 while ( SKIP_Code() == SUCCESS )
4914 switch ( CUR.opcode )
4916 case 0x89: /* IDEF */
4917 case 0x2C: /* FDEF */
4918 CUR.error = TT_Err_Nested_DEFS;
4920 case 0x2D: /* ENDF */
4927 /*************************************************************************/
4929 /* PUSHING DATA ONTO THE INTERPRETER STACK */
4931 /* Instructions appear in the specification's order. */
4933 /*************************************************************************/
4936 /*************************************************************************/
4938 /* NPUSHB[]: PUSH N Bytes */
4939 /* Opcode range: 0x40 */
4940 /* Stack: --> uint32... */
4943 Ins_NPUSHB( INS_ARG )
4948 L = (FT_UShort)CUR.code[CUR.IP + 1];
4950 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4952 CUR.error = TT_Err_Stack_Overflow;
4956 for ( K = 1; K <= L; K++ )
4957 args[K - 1] = CUR.code[CUR.IP + K + 1];
4963 /*************************************************************************/
4965 /* NPUSHW[]: PUSH N Words */
4966 /* Opcode range: 0x41 */
4967 /* Stack: --> int32... */
4970 Ins_NPUSHW( INS_ARG )
4975 L = (FT_UShort)CUR.code[CUR.IP + 1];
4977 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4979 CUR.error = TT_Err_Stack_Overflow;
4985 for ( K = 0; K < L; K++ )
4986 args[K] = GET_ShortIns();
4988 CUR.step_ins = FALSE;
4993 /*************************************************************************/
4995 /* PUSHB[abc]: PUSH Bytes */
4996 /* Opcode range: 0xB0-0xB7 */
4997 /* Stack: --> uint32... */
5000 Ins_PUSHB( INS_ARG )
5005 L = (FT_UShort)( CUR.opcode - 0xB0 + 1 );
5007 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
5009 CUR.error = TT_Err_Stack_Overflow;
5013 for ( K = 1; K <= L; K++ )
5014 args[K - 1] = CUR.code[CUR.IP + K];
5018 /*************************************************************************/
5020 /* PUSHW[abc]: PUSH Words */
5021 /* Opcode range: 0xB8-0xBF */
5022 /* Stack: --> int32... */
5025 Ins_PUSHW( INS_ARG )
5030 L = (FT_UShort)( CUR.opcode - 0xB8 + 1 );
5032 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
5034 CUR.error = TT_Err_Stack_Overflow;
5040 for ( K = 0; K < L; K++ )
5041 args[K] = GET_ShortIns();
5043 CUR.step_ins = FALSE;
5047 /*************************************************************************/
5049 /* MANAGING THE GRAPHICS STATE */
5051 /* Instructions appear in the specs' order. */
5053 /*************************************************************************/
5056 /*************************************************************************/
5058 /* GC[a]: Get Coordinate projected onto */
5059 /* Opcode range: 0x46-0x47 */
5060 /* Stack: uint32 --> f26.6 */
5062 /* XXX: UNDOCUMENTED: Measures from the original glyph must be taken */
5063 /* along the dual projection vector! */
5072 L = (FT_ULong)args[0];
5074 if ( BOUNDSL( L, CUR.zp2.n_points ) )
5076 if ( CUR.pedantic_hinting )
5077 CUR.error = TT_Err_Invalid_Reference;
5082 if ( CUR.opcode & 1 )
5083 R = CUR_fast_dualproj( &CUR.zp2.org[L] );
5085 R = CUR_fast_project( &CUR.zp2.cur[L] );
5092 /*************************************************************************/
5094 /* SCFS[]: Set Coordinate From Stack */
5095 /* Opcode range: 0x48 */
5096 /* Stack: f26.6 uint32 --> */
5100 /* OA := OA + ( value - OA.p )/( f.p ) * f */
5109 L = (FT_UShort)args[0];
5111 if ( BOUNDS( L, CUR.zp2.n_points ) )
5113 if ( CUR.pedantic_hinting )
5114 CUR.error = TT_Err_Invalid_Reference;
5118 K = CUR_fast_project( &CUR.zp2.cur[L] );
5120 CUR_Func_move( &CUR.zp2, L, args[1] - K );
5122 /* UNDOCUMENTED! The MS rasterizer does that with */
5123 /* twilight points (confirmed by Greg Hitchcock) */
5124 if ( CUR.GS.gep2 == 0 )
5125 CUR.zp2.org[L] = CUR.zp2.cur[L];
5129 /*************************************************************************/
5131 /* MD[a]: Measure Distance */
5132 /* Opcode range: 0x49-0x4A */
5133 /* Stack: uint32 uint32 --> f26.6 */
5135 /* XXX: UNDOCUMENTED: Measure taken in the original glyph must be along */
5136 /* the dual projection vector. */
5138 /* XXX: UNDOCUMENTED: Flag attributes are inverted! */
5139 /* 0 => measure distance in original outline */
5140 /* 1 => measure distance in grid-fitted outline */
5142 /* XXX: UNDOCUMENTED: `zp0 - zp1', and not `zp2 - zp1! */
5151 K = (FT_UShort)args[1];
5152 L = (FT_UShort)args[0];
5154 if ( BOUNDS( L, CUR.zp0.n_points ) ||
5155 BOUNDS( K, CUR.zp1.n_points ) )
5157 if ( CUR.pedantic_hinting )
5158 CUR.error = TT_Err_Invalid_Reference;
5163 if ( CUR.opcode & 1 )
5164 D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
5167 /* XXX: UNDOCUMENTED: twilight zone special case */
5169 if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
5171 FT_Vector* vec1 = CUR.zp0.org + L;
5172 FT_Vector* vec2 = CUR.zp1.org + K;
5175 D = CUR_Func_dualproj( vec1, vec2 );
5179 FT_Vector* vec1 = CUR.zp0.orus + L;
5180 FT_Vector* vec2 = CUR.zp1.orus + K;
5183 if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
5185 /* this should be faster */
5186 D = CUR_Func_dualproj( vec1, vec2 );
5187 D = TT_MULFIX( D, CUR.metrics.x_scale );
5194 vec.x = TT_MULFIX( vec1->x - vec2->x, CUR.metrics.x_scale );
5195 vec.y = TT_MULFIX( vec1->y - vec2->y, CUR.metrics.y_scale );
5197 D = CUR_fast_dualproj( &vec );
5207 /*************************************************************************/
5209 /* SDPVTL[a]: Set Dual PVector to Line */
5210 /* Opcode range: 0x86-0x87 */
5211 /* Stack: uint32 uint32 --> */
5214 Ins_SDPVTL( INS_ARG )
5217 FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
5218 FT_Int aOpc = CUR.opcode;
5221 p1 = (FT_UShort)args[1];
5222 p2 = (FT_UShort)args[0];
5224 if ( BOUNDS( p2, CUR.zp1.n_points ) ||
5225 BOUNDS( p1, CUR.zp2.n_points ) )
5227 if ( CUR.pedantic_hinting )
5228 CUR.error = TT_Err_Invalid_Reference;
5233 FT_Vector* v1 = CUR.zp1.org + p2;
5234 FT_Vector* v2 = CUR.zp2.org + p1;
5240 /* If v1 == v2, SDPVTL behaves the same as */
5241 /* SVTCA[X], respectively. */
5243 /* Confirmed by Greg Hitchcock. */
5245 if ( A == 0 && B == 0 )
5252 if ( ( aOpc & 1 ) != 0 )
5254 C = B; /* counter clockwise rotation */
5259 NORMalize( A, B, &CUR.GS.dualVector );
5262 FT_Vector* v1 = CUR.zp1.cur + p2;
5263 FT_Vector* v2 = CUR.zp2.cur + p1;
5270 if ( ( aOpc & 1 ) != 0 )
5272 C = B; /* counter clockwise rotation */
5277 NORMalize( A, B, &CUR.GS.projVector );
5279 GUESS_VECTOR( freeVector );
5285 /*************************************************************************/
5287 /* SZP0[]: Set Zone Pointer 0 */
5288 /* Opcode range: 0x13 */
5289 /* Stack: uint32 --> */
5294 switch ( (FT_Int)args[0] )
5297 CUR.zp0 = CUR.twilight;
5305 if ( CUR.pedantic_hinting )
5306 CUR.error = TT_Err_Invalid_Reference;
5310 CUR.GS.gep0 = (FT_UShort)args[0];
5314 /*************************************************************************/
5316 /* SZP1[]: Set Zone Pointer 1 */
5317 /* Opcode range: 0x14 */
5318 /* Stack: uint32 --> */
5323 switch ( (FT_Int)args[0] )
5326 CUR.zp1 = CUR.twilight;
5334 if ( CUR.pedantic_hinting )
5335 CUR.error = TT_Err_Invalid_Reference;
5339 CUR.GS.gep1 = (FT_UShort)args[0];
5343 /*************************************************************************/
5345 /* SZP2[]: Set Zone Pointer 2 */
5346 /* Opcode range: 0x15 */
5347 /* Stack: uint32 --> */
5352 switch ( (FT_Int)args[0] )
5355 CUR.zp2 = CUR.twilight;
5363 if ( CUR.pedantic_hinting )
5364 CUR.error = TT_Err_Invalid_Reference;
5368 CUR.GS.gep2 = (FT_UShort)args[0];
5372 /*************************************************************************/
5374 /* SZPS[]: Set Zone PointerS */
5375 /* Opcode range: 0x16 */
5376 /* Stack: uint32 --> */
5381 switch ( (FT_Int)args[0] )
5384 CUR.zp0 = CUR.twilight;
5392 if ( CUR.pedantic_hinting )
5393 CUR.error = TT_Err_Invalid_Reference;
5400 CUR.GS.gep0 = (FT_UShort)args[0];
5401 CUR.GS.gep1 = (FT_UShort)args[0];
5402 CUR.GS.gep2 = (FT_UShort)args[0];
5406 /*************************************************************************/
5408 /* INSTCTRL[]: INSTruction ConTRoL */
5409 /* Opcode range: 0x8e */
5410 /* Stack: int32 int32 --> */
5413 Ins_INSTCTRL( INS_ARG )
5421 if ( K < 1 || K > 2 )
5423 if ( CUR.pedantic_hinting )
5424 CUR.error = TT_Err_Invalid_Reference;
5431 CUR.GS.instruct_control = FT_BOOL(
5432 ( (FT_Byte)CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L );
5436 /*************************************************************************/
5438 /* SCANCTRL[]: SCAN ConTRoL */
5439 /* Opcode range: 0x85 */
5440 /* Stack: uint32? --> */
5443 Ins_SCANCTRL( INS_ARG )
5449 A = (FT_Int)( args[0] & 0xFF );
5453 CUR.GS.scan_control = TRUE;
5458 CUR.GS.scan_control = FALSE;
5462 if ( ( args[0] & 0x100 ) != 0 && CUR.tt_metrics.ppem <= A )
5463 CUR.GS.scan_control = TRUE;
5465 if ( ( args[0] & 0x200 ) != 0 && CUR.tt_metrics.rotated )
5466 CUR.GS.scan_control = TRUE;
5468 if ( ( args[0] & 0x400 ) != 0 && CUR.tt_metrics.stretched )
5469 CUR.GS.scan_control = TRUE;
5471 if ( ( args[0] & 0x800 ) != 0 && CUR.tt_metrics.ppem > A )
5472 CUR.GS.scan_control = FALSE;
5474 if ( ( args[0] & 0x1000 ) != 0 && CUR.tt_metrics.rotated )
5475 CUR.GS.scan_control = FALSE;
5477 if ( ( args[0] & 0x2000 ) != 0 && CUR.tt_metrics.stretched )
5478 CUR.GS.scan_control = FALSE;
5482 /*************************************************************************/
5484 /* SCANTYPE[]: SCAN TYPE */
5485 /* Opcode range: 0x8D */
5486 /* Stack: uint32? --> */
5489 Ins_SCANTYPE( INS_ARG )
5492 CUR.GS.scan_type = (FT_Int)args[0];
5496 /*************************************************************************/
5498 /* MANAGING OUTLINES */
5500 /* Instructions appear in the specification's order. */
5502 /*************************************************************************/
5505 /*************************************************************************/
5507 /* FLIPPT[]: FLIP PoinT */
5508 /* Opcode range: 0x80 */
5509 /* Stack: uint32... --> */
5512 Ins_FLIPPT( INS_ARG )
5519 if ( CUR.top < CUR.GS.loop )
5521 if ( CUR.pedantic_hinting )
5522 CUR.error = TT_Err_Too_Few_Arguments;
5526 while ( CUR.GS.loop > 0 )
5530 point = (FT_UShort)CUR.stack[CUR.args];
5532 if ( BOUNDS( point, CUR.pts.n_points ) )
5534 if ( CUR.pedantic_hinting )
5536 CUR.error = TT_Err_Invalid_Reference;
5541 CUR.pts.tags[point] ^= FT_CURVE_TAG_ON;
5548 CUR.new_top = CUR.args;
5552 /*************************************************************************/
5554 /* FLIPRGON[]: FLIP RanGe ON */
5555 /* Opcode range: 0x81 */
5556 /* Stack: uint32 uint32 --> */
5559 Ins_FLIPRGON( INS_ARG )
5564 K = (FT_UShort)args[1];
5565 L = (FT_UShort)args[0];
5567 if ( BOUNDS( K, CUR.pts.n_points ) ||
5568 BOUNDS( L, CUR.pts.n_points ) )
5570 if ( CUR.pedantic_hinting )
5571 CUR.error = TT_Err_Invalid_Reference;
5575 for ( I = L; I <= K; I++ )
5576 CUR.pts.tags[I] |= FT_CURVE_TAG_ON;
5580 /*************************************************************************/
5582 /* FLIPRGOFF: FLIP RanGe OFF */
5583 /* Opcode range: 0x82 */
5584 /* Stack: uint32 uint32 --> */
5587 Ins_FLIPRGOFF( INS_ARG )
5592 K = (FT_UShort)args[1];
5593 L = (FT_UShort)args[0];
5595 if ( BOUNDS( K, CUR.pts.n_points ) ||
5596 BOUNDS( L, CUR.pts.n_points ) )
5598 if ( CUR.pedantic_hinting )
5599 CUR.error = TT_Err_Invalid_Reference;
5603 for ( I = L; I <= K; I++ )
5604 CUR.pts.tags[I] &= ~FT_CURVE_TAG_ON;
5609 Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6* x,
5619 if ( CUR.opcode & 1 )
5630 if ( BOUNDS( p, zp.n_points ) )
5632 if ( CUR.pedantic_hinting )
5633 CUR.error = TT_Err_Invalid_Reference;
5641 d = CUR_Func_project( zp.cur + p, zp.org + p );
5643 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5644 if ( CUR.face->unpatented_hinting )
5646 if ( CUR.GS.both_x_axis )
5661 (FT_Long)CUR.GS.freeVector.x * 0x10000L,
5664 (FT_Long)CUR.GS.freeVector.y * 0x10000L,
5673 Move_Zp2_Point( EXEC_OP_ FT_UShort point,
5678 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5679 if ( CUR.face->unpatented_hinting )
5681 if ( CUR.GS.both_x_axis )
5683 CUR.zp2.cur[point].x += dx;
5685 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
5689 CUR.zp2.cur[point].y += dy;
5691 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
5697 if ( CUR.GS.freeVector.x != 0 )
5699 CUR.zp2.cur[point].x += dx;
5701 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
5704 if ( CUR.GS.freeVector.y != 0 )
5706 CUR.zp2.cur[point].y += dy;
5708 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
5713 /*************************************************************************/
5715 /* SHP[a]: SHift Point by the last point */
5716 /* Opcode range: 0x32-0x33 */
5717 /* Stack: uint32... --> */
5732 if ( CUR.top < CUR.GS.loop )
5734 if ( CUR.pedantic_hinting )
5735 CUR.error = TT_Err_Invalid_Reference;
5739 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5742 while ( CUR.GS.loop > 0 )
5745 point = (FT_UShort)CUR.stack[CUR.args];
5747 if ( BOUNDS( point, CUR.zp2.n_points ) )
5749 if ( CUR.pedantic_hinting )
5751 CUR.error = TT_Err_Invalid_Reference;
5756 MOVE_Zp2_Point( point, dx, dy, TRUE );
5763 CUR.new_top = CUR.args;
5767 /*************************************************************************/
5769 /* SHC[a]: SHift Contour */
5770 /* Opcode range: 0x34-35 */
5771 /* Stack: uint32 --> */
5773 /* UNDOCUMENTED: According to Greg Hitchcock, there is one (virtual) */
5774 /* contour in the twilight zone, namely contour number */
5784 FT_Short contour, bounds;
5785 FT_UShort start, limit, i;
5788 contour = (FT_UShort)args[0];
5789 bounds = ( CUR.GS.gep2 == 0 ) ? 1 : CUR.zp2.n_contours;
5791 if ( BOUNDS( contour, bounds ) )
5793 if ( CUR.pedantic_hinting )
5794 CUR.error = TT_Err_Invalid_Reference;
5798 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5804 start = (FT_UShort)( CUR.zp2.contours[contour - 1] + 1 -
5805 CUR.zp2.first_point );
5807 /* we use the number of points if in the twilight zone */
5808 if ( CUR.GS.gep2 == 0 )
5809 limit = CUR.zp2.n_points;
5811 limit = (FT_UShort)( CUR.zp2.contours[contour] -
5812 CUR.zp2.first_point + 1 );
5814 for ( i = start; i < limit; i++ )
5816 if ( zp.cur != CUR.zp2.cur || refp != i )
5817 MOVE_Zp2_Point( i, dx, dy, TRUE );
5822 /*************************************************************************/
5824 /* SHZ[a]: SHift Zone */
5825 /* Opcode range: 0x36-37 */
5826 /* Stack: uint32 --> */
5839 if ( BOUNDS( args[0], 2 ) )
5841 if ( CUR.pedantic_hinting )
5842 CUR.error = TT_Err_Invalid_Reference;
5846 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5849 /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */
5850 /* Twilight zone has no real contours, so use `n_points'. */
5851 /* Normal zone's `n_points' includes phantoms, so must */
5852 /* use end of last contour. */
5853 if ( CUR.GS.gep2 == 0 )
5854 limit = (FT_UShort)CUR.zp2.n_points;
5855 else if ( CUR.GS.gep2 == 1 && CUR.zp2.n_contours > 0 )
5856 limit = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] + 1 );
5860 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
5861 for ( i = 0; i < limit; i++ )
5863 if ( zp.cur != CUR.zp2.cur || refp != i )
5864 MOVE_Zp2_Point( i, dx, dy, FALSE );
5869 /*************************************************************************/
5871 /* SHPIX[]: SHift points by a PIXel amount */
5872 /* Opcode range: 0x38 */
5873 /* Stack: f26.6 uint32... --> */
5876 Ins_SHPIX( INS_ARG )
5882 if ( CUR.top < CUR.GS.loop + 1 )
5884 if ( CUR.pedantic_hinting )
5885 CUR.error = TT_Err_Invalid_Reference;
5889 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5890 if ( CUR.face->unpatented_hinting )
5892 if ( CUR.GS.both_x_axis )
5894 dx = TT_MulFix14( (FT_UInt32)args[0], 0x4000 );
5900 dy = TT_MulFix14( (FT_UInt32)args[0], 0x4000 );
5906 dx = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.x );
5907 dy = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.y );
5910 while ( CUR.GS.loop > 0 )
5914 point = (FT_UShort)CUR.stack[CUR.args];
5916 if ( BOUNDS( point, CUR.zp2.n_points ) )
5918 if ( CUR.pedantic_hinting )
5920 CUR.error = TT_Err_Invalid_Reference;
5925 MOVE_Zp2_Point( point, dx, dy, TRUE );
5932 CUR.new_top = CUR.args;
5936 /*************************************************************************/
5938 /* MSIRP[a]: Move Stack Indirect Relative Position */
5939 /* Opcode range: 0x3A-0x3B */
5940 /* Stack: f26.6 uint32 --> */
5943 Ins_MSIRP( INS_ARG )
5946 FT_F26Dot6 distance;
5949 point = (FT_UShort)args[0];
5951 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5952 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5954 if ( CUR.pedantic_hinting )
5955 CUR.error = TT_Err_Invalid_Reference;
5959 /* UNDOCUMENTED! The MS rasterizer does that with */
5960 /* twilight points (confirmed by Greg Hitchcock) */
5961 if ( CUR.GS.gep1 == 0 )
5963 CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
5964 CUR_Func_move_orig( &CUR.zp1, point, args[1] );
5965 CUR.zp1.cur[point] = CUR.zp1.org[point];
5968 distance = CUR_Func_project( CUR.zp1.cur + point,
5969 CUR.zp0.cur + CUR.GS.rp0 );
5971 CUR_Func_move( &CUR.zp1, point, args[1] - distance );
5973 CUR.GS.rp1 = CUR.GS.rp0;
5976 if ( ( CUR.opcode & 1 ) != 0 )
5981 /*************************************************************************/
5983 /* MDAP[a]: Move Direct Absolute Point */
5984 /* Opcode range: 0x2E-0x2F */
5985 /* Stack: uint32 --> */
5991 FT_F26Dot6 cur_dist,
5995 point = (FT_UShort)args[0];
5997 if ( BOUNDS( point, CUR.zp0.n_points ) )
5999 if ( CUR.pedantic_hinting )
6000 CUR.error = TT_Err_Invalid_Reference;
6004 if ( ( CUR.opcode & 1 ) != 0 )
6006 cur_dist = CUR_fast_project( &CUR.zp0.cur[point] );
6007 distance = CUR_Func_round( cur_dist,
6008 CUR.tt_metrics.compensations[0] ) - cur_dist;
6013 CUR_Func_move( &CUR.zp0, point, distance );
6020 /*************************************************************************/
6022 /* MIAP[a]: Move Indirect Absolute Point */
6023 /* Opcode range: 0x3E-0x3F */
6024 /* Stack: uint32 uint32 --> */
6031 FT_F26Dot6 distance,
6035 cvtEntry = (FT_ULong)args[1];
6036 point = (FT_UShort)args[0];
6038 if ( BOUNDS( point, CUR.zp0.n_points ) ||
6039 BOUNDSL( cvtEntry, CUR.cvtSize ) )
6041 if ( CUR.pedantic_hinting )
6042 CUR.error = TT_Err_Invalid_Reference;
6048 /* The behaviour of an MIAP instruction is quite different when used */
6049 /* in the twilight zone. */
6051 /* First, no control value cut-in test is performed as it would fail */
6052 /* anyway. Second, the original point, i.e. (org_x,org_y) of */
6053 /* zp0.point, is set to the absolute, unrounded distance found in the */
6056 /* This is used in the CVT programs of the Microsoft fonts Arial, */
6057 /* Times, etc., in order to re-adjust some key font heights. It */
6058 /* allows the use of the IP instruction in the twilight zone, which */
6059 /* otherwise would be invalid according to the specification. */
6061 /* We implement it with a special sequence for the twilight zone. */
6062 /* This is a bad hack, but it seems to work. */
6064 /* Confirmed by Greg Hitchcock. */
6066 distance = CUR_Func_read_cvt( cvtEntry );
6068 if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */
6070 CUR.zp0.org[point].x = TT_MulFix14( (FT_UInt32)distance,
6071 CUR.GS.freeVector.x );
6072 CUR.zp0.org[point].y = TT_MulFix14( (FT_UInt32)distance,
6073 CUR.GS.freeVector.y ),
6074 CUR.zp0.cur[point] = CUR.zp0.org[point];
6077 org_dist = CUR_fast_project( &CUR.zp0.cur[point] );
6079 if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */
6081 if ( FT_ABS( distance - org_dist ) > CUR.GS.control_value_cutin )
6082 distance = org_dist;
6084 distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] );
6087 CUR_Func_move( &CUR.zp0, point, distance - org_dist );
6095 /*************************************************************************/
6097 /* MDRP[abcde]: Move Direct Relative Point */
6098 /* Opcode range: 0xC0-0xDF */
6099 /* Stack: uint32 --> */
6105 FT_F26Dot6 org_dist, distance;
6108 point = (FT_UShort)args[0];
6110 if ( BOUNDS( point, CUR.zp1.n_points ) ||
6111 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
6113 if ( CUR.pedantic_hinting )
6114 CUR.error = TT_Err_Invalid_Reference;
6118 /* XXX: Is there some undocumented feature while in the */
6119 /* twilight zone? */
6121 /* XXX: UNDOCUMENTED: twilight zone special case */
6123 if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
6125 FT_Vector* vec1 = &CUR.zp1.org[point];
6126 FT_Vector* vec2 = &CUR.zp0.org[CUR.GS.rp0];
6129 org_dist = CUR_Func_dualproj( vec1, vec2 );
6133 FT_Vector* vec1 = &CUR.zp1.orus[point];
6134 FT_Vector* vec2 = &CUR.zp0.orus[CUR.GS.rp0];
6137 if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
6139 /* this should be faster */
6140 org_dist = CUR_Func_dualproj( vec1, vec2 );
6141 org_dist = TT_MULFIX( org_dist, CUR.metrics.x_scale );
6148 vec.x = TT_MULFIX( vec1->x - vec2->x, CUR.metrics.x_scale );
6149 vec.y = TT_MULFIX( vec1->y - vec2->y, CUR.metrics.y_scale );
6151 org_dist = CUR_fast_dualproj( &vec );
6155 /* single width cut-in test */
6157 if ( FT_ABS( org_dist - CUR.GS.single_width_value ) <
6158 CUR.GS.single_width_cutin )
6160 if ( org_dist >= 0 )
6161 org_dist = CUR.GS.single_width_value;
6163 org_dist = -CUR.GS.single_width_value;
6168 if ( ( CUR.opcode & 4 ) != 0 )
6169 distance = CUR_Func_round(
6171 CUR.tt_metrics.compensations[CUR.opcode & 3] );
6173 distance = ROUND_None(
6175 CUR.tt_metrics.compensations[CUR.opcode & 3] );
6177 /* minimum distance flag */
6179 if ( ( CUR.opcode & 8 ) != 0 )
6181 if ( org_dist >= 0 )
6183 if ( distance < CUR.GS.minimum_distance )
6184 distance = CUR.GS.minimum_distance;
6188 if ( distance > -CUR.GS.minimum_distance )
6189 distance = -CUR.GS.minimum_distance;
6193 /* now move the point */
6195 org_dist = CUR_Func_project( CUR.zp1.cur + point,
6196 CUR.zp0.cur + CUR.GS.rp0 );
6198 CUR_Func_move( &CUR.zp1, point, distance - org_dist );
6201 CUR.GS.rp1 = CUR.GS.rp0;
6204 if ( ( CUR.opcode & 16 ) != 0 )
6209 /*************************************************************************/
6211 /* MIRP[abcde]: Move Indirect Relative Point */
6212 /* Opcode range: 0xE0-0xFF */
6213 /* Stack: int32? uint32 --> */
6221 FT_F26Dot6 cvt_dist,
6227 point = (FT_UShort)args[0];
6228 cvtEntry = (FT_ULong)( args[1] + 1 );
6230 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
6232 if ( BOUNDS( point, CUR.zp1.n_points ) ||
6233 BOUNDSL( cvtEntry, CUR.cvtSize + 1 ) ||
6234 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
6236 if ( CUR.pedantic_hinting )
6237 CUR.error = TT_Err_Invalid_Reference;
6244 cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
6246 /* single width test */
6248 if ( FT_ABS( cvt_dist - CUR.GS.single_width_value ) <
6249 CUR.GS.single_width_cutin )
6251 if ( cvt_dist >= 0 )
6252 cvt_dist = CUR.GS.single_width_value;
6254 cvt_dist = -CUR.GS.single_width_value;
6257 /* UNDOCUMENTED! The MS rasterizer does that with */
6258 /* twilight points (confirmed by Greg Hitchcock) */
6259 if ( CUR.GS.gep1 == 0 )
6261 CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +
6262 TT_MulFix14( (FT_UInt32)cvt_dist,
6263 CUR.GS.freeVector.x );
6264 CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
6265 TT_MulFix14( (FT_UInt32)cvt_dist,
6266 CUR.GS.freeVector.y );
6267 CUR.zp1.cur[point] = CUR.zp1.org[point];
6270 org_dist = CUR_Func_dualproj( &CUR.zp1.org[point],
6271 &CUR.zp0.org[CUR.GS.rp0] );
6272 cur_dist = CUR_Func_project ( &CUR.zp1.cur[point],
6273 &CUR.zp0.cur[CUR.GS.rp0] );
6275 /* auto-flip test */
6277 if ( CUR.GS.auto_flip )
6279 if ( ( org_dist ^ cvt_dist ) < 0 )
6280 cvt_dist = -cvt_dist;
6283 /* control value cutin and round */
6285 if ( ( CUR.opcode & 4 ) != 0 )
6287 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
6288 /* refer to the same zone. */
6290 if ( CUR.GS.gep0 == CUR.GS.gep1 )
6292 /* XXX: According to Greg Hitchcock, the following wording is */
6293 /* the right one: */
6295 /* When the absolute difference between the value in */
6296 /* the table [CVT] and the measurement directly from */
6297 /* the outline is _greater_ than the cut_in value, the */
6298 /* outline measurement is used. */
6300 /* This is from `instgly.doc'. The description in */
6301 /* `ttinst2.doc', version 1.66, is thus incorrect since */
6302 /* it implies `>=' instead of `>'. */
6304 if ( FT_ABS( cvt_dist - org_dist ) > CUR.GS.control_value_cutin )
6305 cvt_dist = org_dist;
6308 distance = CUR_Func_round(
6310 CUR.tt_metrics.compensations[CUR.opcode & 3] );
6313 distance = ROUND_None(
6315 CUR.tt_metrics.compensations[CUR.opcode & 3] );
6317 /* minimum distance test */
6319 if ( ( CUR.opcode & 8 ) != 0 )
6321 if ( org_dist >= 0 )
6323 if ( distance < CUR.GS.minimum_distance )
6324 distance = CUR.GS.minimum_distance;
6328 if ( distance > -CUR.GS.minimum_distance )
6329 distance = -CUR.GS.minimum_distance;
6333 CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
6336 CUR.GS.rp1 = CUR.GS.rp0;
6338 if ( ( CUR.opcode & 16 ) != 0 )
6345 /*************************************************************************/
6347 /* ALIGNRP[]: ALIGN Relative Point */
6348 /* Opcode range: 0x3C */
6349 /* Stack: uint32 uint32... --> */
6352 Ins_ALIGNRP( INS_ARG )
6355 FT_F26Dot6 distance;
6360 if ( CUR.top < CUR.GS.loop ||
6361 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
6363 if ( CUR.pedantic_hinting )
6364 CUR.error = TT_Err_Invalid_Reference;
6368 while ( CUR.GS.loop > 0 )
6372 point = (FT_UShort)CUR.stack[CUR.args];
6374 if ( BOUNDS( point, CUR.zp1.n_points ) )
6376 if ( CUR.pedantic_hinting )
6378 CUR.error = TT_Err_Invalid_Reference;
6384 distance = CUR_Func_project( CUR.zp1.cur + point,
6385 CUR.zp0.cur + CUR.GS.rp0 );
6387 CUR_Func_move( &CUR.zp1, point, -distance );
6395 CUR.new_top = CUR.args;
6399 /*************************************************************************/
6401 /* ISECT[]: moves point to InterSECTion */
6402 /* Opcode range: 0x0F */
6403 /* Stack: 5 * uint32 --> */
6406 Ins_ISECT( INS_ARG )
6412 FT_F26Dot6 discriminant;
6423 point = (FT_UShort)args[0];
6425 a0 = (FT_UShort)args[1];
6426 a1 = (FT_UShort)args[2];
6427 b0 = (FT_UShort)args[3];
6428 b1 = (FT_UShort)args[4];
6430 if ( BOUNDS( b0, CUR.zp0.n_points ) ||
6431 BOUNDS( b1, CUR.zp0.n_points ) ||
6432 BOUNDS( a0, CUR.zp1.n_points ) ||
6433 BOUNDS( a1, CUR.zp1.n_points ) ||
6434 BOUNDS( point, CUR.zp2.n_points ) )
6436 if ( CUR.pedantic_hinting )
6437 CUR.error = TT_Err_Invalid_Reference;
6441 dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
6442 dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
6444 dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;
6445 day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;
6447 dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;
6448 dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;
6450 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
6452 discriminant = TT_MULDIV( dax, -dby, 0x40 ) +
6453 TT_MULDIV( day, dbx, 0x40 );
6455 if ( FT_ABS( discriminant ) >= 0x40 )
6457 val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 );
6459 R.x = TT_MULDIV( val, dax, discriminant );
6460 R.y = TT_MULDIV( val, day, discriminant );
6462 CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
6463 CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
6467 /* else, take the middle of the middles of A and B */
6469 CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +
6472 CUR.zp0.cur[b1].x ) / 4;
6473 CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +
6476 CUR.zp0.cur[b1].y ) / 4;
6481 /*************************************************************************/
6483 /* ALIGNPTS[]: ALIGN PoinTS */
6484 /* Opcode range: 0x27 */
6485 /* Stack: uint32 uint32 --> */
6488 Ins_ALIGNPTS( INS_ARG )
6491 FT_F26Dot6 distance;
6494 p1 = (FT_UShort)args[0];
6495 p2 = (FT_UShort)args[1];
6497 if ( BOUNDS( p1, CUR.zp1.n_points ) ||
6498 BOUNDS( p2, CUR.zp0.n_points ) )
6500 if ( CUR.pedantic_hinting )
6501 CUR.error = TT_Err_Invalid_Reference;
6505 distance = CUR_Func_project( CUR.zp0.cur + p2,
6506 CUR.zp1.cur + p1 ) / 2;
6508 CUR_Func_move( &CUR.zp1, p1, distance );
6509 CUR_Func_move( &CUR.zp0, p2, -distance );
6513 /*************************************************************************/
6515 /* IP[]: Interpolate Point */
6516 /* Opcode range: 0x39 */
6517 /* Stack: uint32... --> */
6520 /* SOMETIMES, DUMBER CODE IS BETTER CODE */
6525 FT_F26Dot6 old_range, cur_range;
6526 FT_Vector* orus_base;
6527 FT_Vector* cur_base;
6533 if ( CUR.top < CUR.GS.loop )
6535 if ( CUR.pedantic_hinting )
6536 CUR.error = TT_Err_Invalid_Reference;
6541 * We need to deal in a special way with the twilight zone.
6542 * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0),
6545 twilight = CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 || CUR.GS.gep2 == 0;
6547 if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) )
6549 if ( CUR.pedantic_hinting )
6550 CUR.error = TT_Err_Invalid_Reference;
6555 orus_base = &CUR.zp0.org[CUR.GS.rp1];
6557 orus_base = &CUR.zp0.orus[CUR.GS.rp1];
6559 cur_base = &CUR.zp0.cur[CUR.GS.rp1];
6561 /* XXX: There are some glyphs in some braindead but popular */
6562 /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
6563 /* calling IP[] with bad values of rp[12]. */
6564 /* Do something sane when this odd thing happens. */
6565 if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
6566 BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
6574 old_range = CUR_Func_dualproj( &CUR.zp1.org[CUR.GS.rp2],
6576 else if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
6577 old_range = CUR_Func_dualproj( &CUR.zp1.orus[CUR.GS.rp2],
6584 vec.x = TT_MULFIX( CUR.zp1.orus[CUR.GS.rp2].x - orus_base->x,
6585 CUR.metrics.x_scale );
6586 vec.y = TT_MULFIX( CUR.zp1.orus[CUR.GS.rp2].y - orus_base->y,
6587 CUR.metrics.y_scale );
6589 old_range = CUR_fast_dualproj( &vec );
6592 cur_range = CUR_Func_project ( &CUR.zp1.cur[CUR.GS.rp2], cur_base );
6595 for ( ; CUR.GS.loop > 0; --CUR.GS.loop )
6597 FT_UInt point = (FT_UInt)CUR.stack[--CUR.args];
6598 FT_F26Dot6 org_dist, cur_dist, new_dist;
6601 /* check point bounds */
6602 if ( BOUNDS( point, CUR.zp2.n_points ) )
6604 if ( CUR.pedantic_hinting )
6606 CUR.error = TT_Err_Invalid_Reference;
6613 org_dist = CUR_Func_dualproj( &CUR.zp2.org[point], orus_base );
6614 else if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
6615 org_dist = CUR_Func_dualproj( &CUR.zp2.orus[point], orus_base );
6621 vec.x = TT_MULFIX( CUR.zp2.orus[point].x - orus_base->x,
6622 CUR.metrics.x_scale );
6623 vec.y = TT_MULFIX( CUR.zp2.orus[point].y - orus_base->y,
6624 CUR.metrics.y_scale );
6626 org_dist = CUR_fast_dualproj( &vec );
6629 cur_dist = CUR_Func_project ( &CUR.zp2.cur[point], cur_base );
6632 new_dist = ( old_range != 0 )
6633 ? TT_MULDIV( org_dist, cur_range, old_range )
6638 CUR_Func_move( &CUR.zp2, (FT_UShort)point, new_dist - cur_dist );
6643 CUR.new_top = CUR.args;
6647 /*************************************************************************/
6649 /* UTP[a]: UnTouch Point */
6650 /* Opcode range: 0x29 */
6651 /* Stack: uint32 --> */
6660 point = (FT_UShort)args[0];
6662 if ( BOUNDS( point, CUR.zp0.n_points ) )
6664 if ( CUR.pedantic_hinting )
6665 CUR.error = TT_Err_Invalid_Reference;
6671 if ( CUR.GS.freeVector.x != 0 )
6672 mask &= ~FT_CURVE_TAG_TOUCH_X;
6674 if ( CUR.GS.freeVector.y != 0 )
6675 mask &= ~FT_CURVE_TAG_TOUCH_Y;
6677 CUR.zp0.tags[point] &= mask;
6681 /* Local variables for Ins_IUP: */
6682 typedef struct IUP_WorkerRec_
6684 FT_Vector* orgs; /* original and current coordinate */
6685 FT_Vector* curs; /* arrays */
6689 } IUP_WorkerRec, *IUP_Worker;
6693 _iup_worker_shift( IUP_Worker worker,
6702 dx = worker->curs[p].x - worker->orgs[p].x;
6705 for ( i = p1; i < p; i++ )
6706 worker->curs[i].x += dx;
6708 for ( i = p + 1; i <= p2; i++ )
6709 worker->curs[i].x += dx;
6715 _iup_worker_interpolate( IUP_Worker worker,
6722 FT_F26Dot6 orus1, orus2, org1, org2, delta1, delta2;
6728 if ( BOUNDS( ref1, worker->max_points ) ||
6729 BOUNDS( ref2, worker->max_points ) )
6732 orus1 = worker->orus[ref1].x;
6733 orus2 = worker->orus[ref2].x;
6735 if ( orus1 > orus2 )
6750 org1 = worker->orgs[ref1].x;
6751 org2 = worker->orgs[ref2].x;
6752 delta1 = worker->curs[ref1].x - org1;
6753 delta2 = worker->curs[ref2].x - org2;
6755 if ( orus1 == orus2 )
6757 /* simple shift of untouched points */
6758 for ( i = p1; i <= p2; i++ )
6760 FT_F26Dot6 x = worker->orgs[i].x;
6768 worker->curs[i].x = x;
6774 FT_Bool scale_valid = 0;
6778 for ( i = p1; i <= p2; i++ )
6780 FT_F26Dot6 x = worker->orgs[i].x;
6786 else if ( x >= org2 )
6794 scale = TT_MULDIV( org2 + delta2 - ( org1 + delta1 ),
6795 0x10000L, orus2 - orus1 );
6798 x = ( org1 + delta1 ) +
6799 TT_MULFIX( worker->orus[i].x - orus1, scale );
6801 worker->curs[i].x = x;
6807 /*************************************************************************/
6809 /* IUP[a]: Interpolate Untouched Points */
6810 /* Opcode range: 0x30-0x31 */
6819 FT_UInt first_point; /* first point of contour */
6820 FT_UInt end_point; /* end point (last+1) of contour */
6822 FT_UInt first_touched; /* first touched point in contour */
6823 FT_UInt cur_touched; /* current touched point in contour */
6825 FT_UInt point; /* current point */
6826 FT_Short contour; /* current contour */
6831 /* ignore empty outlines */
6832 if ( CUR.pts.n_contours == 0 )
6835 if ( CUR.opcode & 1 )
6837 mask = FT_CURVE_TAG_TOUCH_X;
6838 V.orgs = CUR.pts.org;
6839 V.curs = CUR.pts.cur;
6840 V.orus = CUR.pts.orus;
6844 mask = FT_CURVE_TAG_TOUCH_Y;
6845 V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
6846 V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
6847 V.orus = (FT_Vector*)( (FT_Pos*)CUR.pts.orus + 1 );
6849 V.max_points = CUR.pts.n_points;
6856 end_point = CUR.pts.contours[contour] - CUR.pts.first_point;
6857 first_point = point;
6859 if ( BOUNDS ( end_point, CUR.pts.n_points ) )
6860 end_point = CUR.pts.n_points - 1;
6862 while ( point <= end_point && ( CUR.pts.tags[point] & mask ) == 0 )
6865 if ( point <= end_point )
6867 first_touched = point;
6868 cur_touched = point;
6872 while ( point <= end_point )
6874 if ( ( CUR.pts.tags[point] & mask ) != 0 )
6876 _iup_worker_interpolate( &V,
6881 cur_touched = point;
6887 if ( cur_touched == first_touched )
6888 _iup_worker_shift( &V, first_point, end_point, cur_touched );
6891 _iup_worker_interpolate( &V,
6892 (FT_UShort)( cur_touched + 1 ),
6897 if ( first_touched > 0 )
6898 _iup_worker_interpolate( &V,
6906 } while ( contour < CUR.pts.n_contours );
6910 /*************************************************************************/
6912 /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
6913 /* Opcode range: 0x5D,0x71,0x72 */
6914 /* Stack: uint32 (2 * uint32)... --> */
6917 Ins_DELTAP( INS_ARG )
6925 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
6926 /* Delta hinting is covered by US Patent 5159668. */
6927 if ( CUR.face->unpatented_hinting )
6929 FT_Long n = args[0] * 2;
6934 if ( CUR.pedantic_hinting )
6935 CUR.error = TT_Err_Too_Few_Arguments;
6940 CUR.new_top = CUR.args;
6945 nump = (FT_ULong)args[0]; /* some points theoretically may occur more
6946 than once, thus UShort isn't enough */
6948 for ( k = 1; k <= nump; k++ )
6952 if ( CUR.pedantic_hinting )
6953 CUR.error = TT_Err_Too_Few_Arguments;
6960 A = (FT_UShort)CUR.stack[CUR.args + 1];
6961 B = CUR.stack[CUR.args];
6963 /* XXX: Because some popular fonts contain some invalid DeltaP */
6964 /* instructions, we simply ignore them when the stacked */
6965 /* point reference is off limit, rather than returning an */
6966 /* error. As a delta instruction doesn't change a glyph */
6967 /* in great ways, this shouldn't be a problem. */
6969 if ( !BOUNDS( A, CUR.zp0.n_points ) )
6971 C = ( (FT_ULong)B & 0xF0 ) >> 4;
6973 switch ( CUR.opcode )
6987 C += CUR.GS.delta_base;
6989 if ( CURRENT_Ppem() == (FT_Long)C )
6991 B = ( (FT_ULong)B & 0xF ) - 8;
6994 B = B * 64 / ( 1L << CUR.GS.delta_shift );
6996 CUR_Func_move( &CUR.zp0, A, B );
7000 if ( CUR.pedantic_hinting )
7001 CUR.error = TT_Err_Invalid_Reference;
7005 CUR.new_top = CUR.args;
7009 /*************************************************************************/
7011 /* DELTACn[]: DELTA exceptions C1, C2, C3 */
7012 /* Opcode range: 0x73,0x74,0x75 */
7013 /* Stack: uint32 (2 * uint32)... --> */
7016 Ins_DELTAC( INS_ARG )
7023 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
7024 /* Delta hinting is covered by US Patent 5159668. */
7025 if ( CUR.face->unpatented_hinting )
7027 FT_Long n = args[0] * 2;
7032 if ( CUR.pedantic_hinting )
7033 CUR.error = TT_Err_Too_Few_Arguments;
7038 CUR.new_top = CUR.args;
7043 nump = (FT_ULong)args[0];
7045 for ( k = 1; k <= nump; k++ )
7049 if ( CUR.pedantic_hinting )
7050 CUR.error = TT_Err_Too_Few_Arguments;
7057 A = (FT_ULong)CUR.stack[CUR.args + 1];
7058 B = CUR.stack[CUR.args];
7060 if ( BOUNDSL( A, CUR.cvtSize ) )
7062 if ( CUR.pedantic_hinting )
7064 CUR.error = TT_Err_Invalid_Reference;
7070 C = ( (FT_ULong)B & 0xF0 ) >> 4;
7072 switch ( CUR.opcode )
7086 C += CUR.GS.delta_base;
7088 if ( CURRENT_Ppem() == (FT_Long)C )
7090 B = ( (FT_ULong)B & 0xF ) - 8;
7093 B = B * 64 / ( 1L << CUR.GS.delta_shift );
7095 CUR_Func_move_cvt( A, B );
7101 CUR.new_top = CUR.args;
7105 /*************************************************************************/
7107 /* MISC. INSTRUCTIONS */
7109 /*************************************************************************/
7112 /*************************************************************************/
7114 /* GETINFO[]: GET INFOrmation */
7115 /* Opcode range: 0x88 */
7116 /* Stack: uint32 --> uint32 */
7119 Ins_GETINFO( INS_ARG )
7126 /* We return MS rasterizer version 1.7 for the font scaler. */
7127 if ( ( args[0] & 1 ) != 0 )
7130 /* Has the glyph been rotated? */
7131 if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated )
7134 /* Has the glyph been stretched? */
7135 if ( ( args[0] & 4 ) != 0 && CUR.tt_metrics.stretched )
7138 /* Are we hinting for grayscale? */
7139 if ( ( args[0] & 32 ) != 0 && CUR.grayscale )
7147 Ins_UNKNOWN( INS_ARG )
7149 TT_DefRecord* def = CUR.IDefs;
7150 TT_DefRecord* limit = def + CUR.numIDefs;
7155 for ( ; def < limit; def++ )
7157 if ( (FT_Byte)def->opc == CUR.opcode && def->active )
7162 if ( CUR.callTop >= CUR.callSize )
7164 CUR.error = TT_Err_Stack_Overflow;
7168 call = CUR.callStack + CUR.callTop++;
7170 call->Caller_Range = CUR.curRange;
7171 call->Caller_IP = CUR.IP + 1;
7172 call->Cur_Count = 1;
7173 call->Cur_Restart = def->start;
7174 call->Cur_End = def->end;
7176 INS_Goto_CodeRange( def->range, def->start );
7178 CUR.step_ins = FALSE;
7183 CUR.error = TT_Err_Invalid_Opcode;
7187 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
7191 TInstruction_Function Instruct_Dispatch[256] =
7193 /* Opcodes are gathered in groups of 16. */
7194 /* Please keep the spaces as they are. */
7196 /* SVTCA y */ Ins_SVTCA,
7197 /* SVTCA x */ Ins_SVTCA,
7198 /* SPvTCA y */ Ins_SPVTCA,
7199 /* SPvTCA x */ Ins_SPVTCA,
7200 /* SFvTCA y */ Ins_SFVTCA,
7201 /* SFvTCA x */ Ins_SFVTCA,
7202 /* SPvTL // */ Ins_SPVTL,
7203 /* SPvTL + */ Ins_SPVTL,
7204 /* SFvTL // */ Ins_SFVTL,
7205 /* SFvTL + */ Ins_SFVTL,
7206 /* SPvFS */ Ins_SPVFS,
7207 /* SFvFS */ Ins_SFVFS,
7210 /* SFvTPv */ Ins_SFVTPV,
7211 /* ISECT */ Ins_ISECT,
7213 /* SRP0 */ Ins_SRP0,
7214 /* SRP1 */ Ins_SRP1,
7215 /* SRP2 */ Ins_SRP2,
7216 /* SZP0 */ Ins_SZP0,
7217 /* SZP1 */ Ins_SZP1,
7218 /* SZP2 */ Ins_SZP2,
7219 /* SZPS */ Ins_SZPS,
7220 /* SLOOP */ Ins_SLOOP,
7222 /* RTHG */ Ins_RTHG,
7224 /* ELSE */ Ins_ELSE,
7225 /* JMPR */ Ins_JMPR,
7226 /* SCvTCi */ Ins_SCVTCI,
7227 /* SSwCi */ Ins_SSWCI,
7232 /* CLEAR */ Ins_CLEAR,
7233 /* SWAP */ Ins_SWAP,
7234 /* DEPTH */ Ins_DEPTH,
7235 /* CINDEX */ Ins_CINDEX,
7236 /* MINDEX */ Ins_MINDEX,
7237 /* AlignPTS */ Ins_ALIGNPTS,
7238 /* INS_0x28 */ Ins_UNKNOWN,
7240 /* LOOPCALL */ Ins_LOOPCALL,
7241 /* CALL */ Ins_CALL,
7242 /* FDEF */ Ins_FDEF,
7243 /* ENDF */ Ins_ENDF,
7244 /* MDAP[0] */ Ins_MDAP,
7245 /* MDAP[1] */ Ins_MDAP,
7247 /* IUP[0] */ Ins_IUP,
7248 /* IUP[1] */ Ins_IUP,
7249 /* SHP[0] */ Ins_SHP,
7250 /* SHP[1] */ Ins_SHP,
7251 /* SHC[0] */ Ins_SHC,
7252 /* SHC[1] */ Ins_SHC,
7253 /* SHZ[0] */ Ins_SHZ,
7254 /* SHZ[1] */ Ins_SHZ,
7255 /* SHPIX */ Ins_SHPIX,
7257 /* MSIRP[0] */ Ins_MSIRP,
7258 /* MSIRP[1] */ Ins_MSIRP,
7259 /* AlignRP */ Ins_ALIGNRP,
7260 /* RTDG */ Ins_RTDG,
7261 /* MIAP[0] */ Ins_MIAP,
7262 /* MIAP[1] */ Ins_MIAP,
7264 /* NPushB */ Ins_NPUSHB,
7265 /* NPushW */ Ins_NPUSHW,
7268 /* WCvtP */ Ins_WCVTP,
7269 /* RCvt */ Ins_RCVT,
7272 /* SCFS */ Ins_SCFS,
7275 /* MPPEM */ Ins_MPPEM,
7277 /* FlipON */ Ins_FLIPON,
7278 /* FlipOFF */ Ins_FLIPOFF,
7279 /* DEBUG */ Ins_DEBUG,
7282 /* LTEQ */ Ins_LTEQ,
7284 /* GTEQ */ Ins_GTEQ,
7288 /* EVEN */ Ins_EVEN,
7294 /* DeltaP1 */ Ins_DELTAP,
7304 /* FLOOR */ Ins_FLOOR,
7305 /* CEILING */ Ins_CEILING,
7306 /* ROUND[0] */ Ins_ROUND,
7307 /* ROUND[1] */ Ins_ROUND,
7308 /* ROUND[2] */ Ins_ROUND,
7309 /* ROUND[3] */ Ins_ROUND,
7310 /* NROUND[0] */ Ins_NROUND,
7311 /* NROUND[1] */ Ins_NROUND,
7312 /* NROUND[2] */ Ins_NROUND,
7313 /* NROUND[3] */ Ins_NROUND,
7315 /* WCvtF */ Ins_WCVTF,
7316 /* DeltaP2 */ Ins_DELTAP,
7317 /* DeltaP3 */ Ins_DELTAP,
7318 /* DeltaCn[0] */ Ins_DELTAC,
7319 /* DeltaCn[1] */ Ins_DELTAC,
7320 /* DeltaCn[2] */ Ins_DELTAC,
7321 /* SROUND */ Ins_SROUND,
7322 /* S45Round */ Ins_S45ROUND,
7323 /* JROT */ Ins_JROT,
7324 /* JROF */ Ins_JROF,
7325 /* ROFF */ Ins_ROFF,
7326 /* INS_0x7B */ Ins_UNKNOWN,
7327 /* RUTG */ Ins_RUTG,
7328 /* RDTG */ Ins_RDTG,
7329 /* SANGW */ Ins_SANGW,
7332 /* FlipPT */ Ins_FLIPPT,
7333 /* FlipRgON */ Ins_FLIPRGON,
7334 /* FlipRgOFF */ Ins_FLIPRGOFF,
7335 /* INS_0x83 */ Ins_UNKNOWN,
7336 /* INS_0x84 */ Ins_UNKNOWN,
7337 /* ScanCTRL */ Ins_SCANCTRL,
7338 /* SDPVTL[0] */ Ins_SDPVTL,
7339 /* SDPVTL[1] */ Ins_SDPVTL,
7340 /* GetINFO */ Ins_GETINFO,
7341 /* IDEF */ Ins_IDEF,
7342 /* ROLL */ Ins_ROLL,
7345 /* ScanTYPE */ Ins_SCANTYPE,
7346 /* InstCTRL */ Ins_INSTCTRL,
7347 /* INS_0x8F */ Ins_UNKNOWN,
7349 /* INS_0x90 */ Ins_UNKNOWN,
7350 /* INS_0x91 */ Ins_UNKNOWN,
7351 /* INS_0x92 */ Ins_UNKNOWN,
7352 /* INS_0x93 */ Ins_UNKNOWN,
7353 /* INS_0x94 */ Ins_UNKNOWN,
7354 /* INS_0x95 */ Ins_UNKNOWN,
7355 /* INS_0x96 */ Ins_UNKNOWN,
7356 /* INS_0x97 */ Ins_UNKNOWN,
7357 /* INS_0x98 */ Ins_UNKNOWN,
7358 /* INS_0x99 */ Ins_UNKNOWN,
7359 /* INS_0x9A */ Ins_UNKNOWN,
7360 /* INS_0x9B */ Ins_UNKNOWN,
7361 /* INS_0x9C */ Ins_UNKNOWN,
7362 /* INS_0x9D */ Ins_UNKNOWN,
7363 /* INS_0x9E */ Ins_UNKNOWN,
7364 /* INS_0x9F */ Ins_UNKNOWN,
7366 /* INS_0xA0 */ Ins_UNKNOWN,
7367 /* INS_0xA1 */ Ins_UNKNOWN,
7368 /* INS_0xA2 */ Ins_UNKNOWN,
7369 /* INS_0xA3 */ Ins_UNKNOWN,
7370 /* INS_0xA4 */ Ins_UNKNOWN,
7371 /* INS_0xA5 */ Ins_UNKNOWN,
7372 /* INS_0xA6 */ Ins_UNKNOWN,
7373 /* INS_0xA7 */ Ins_UNKNOWN,
7374 /* INS_0xA8 */ Ins_UNKNOWN,
7375 /* INS_0xA9 */ Ins_UNKNOWN,
7376 /* INS_0xAA */ Ins_UNKNOWN,
7377 /* INS_0xAB */ Ins_UNKNOWN,
7378 /* INS_0xAC */ Ins_UNKNOWN,
7379 /* INS_0xAD */ Ins_UNKNOWN,
7380 /* INS_0xAE */ Ins_UNKNOWN,
7381 /* INS_0xAF */ Ins_UNKNOWN,
7383 /* PushB[0] */ Ins_PUSHB,
7384 /* PushB[1] */ Ins_PUSHB,
7385 /* PushB[2] */ Ins_PUSHB,
7386 /* PushB[3] */ Ins_PUSHB,
7387 /* PushB[4] */ Ins_PUSHB,
7388 /* PushB[5] */ Ins_PUSHB,
7389 /* PushB[6] */ Ins_PUSHB,
7390 /* PushB[7] */ Ins_PUSHB,
7391 /* PushW[0] */ Ins_PUSHW,
7392 /* PushW[1] */ Ins_PUSHW,
7393 /* PushW[2] */ Ins_PUSHW,
7394 /* PushW[3] */ Ins_PUSHW,
7395 /* PushW[4] */ Ins_PUSHW,
7396 /* PushW[5] */ Ins_PUSHW,
7397 /* PushW[6] */ Ins_PUSHW,
7398 /* PushW[7] */ Ins_PUSHW,
7400 /* MDRP[00] */ Ins_MDRP,
7401 /* MDRP[01] */ Ins_MDRP,
7402 /* MDRP[02] */ Ins_MDRP,
7403 /* MDRP[03] */ Ins_MDRP,
7404 /* MDRP[04] */ Ins_MDRP,
7405 /* MDRP[05] */ Ins_MDRP,
7406 /* MDRP[06] */ Ins_MDRP,
7407 /* MDRP[07] */ Ins_MDRP,
7408 /* MDRP[08] */ Ins_MDRP,
7409 /* MDRP[09] */ Ins_MDRP,
7410 /* MDRP[10] */ Ins_MDRP,
7411 /* MDRP[11] */ Ins_MDRP,
7412 /* MDRP[12] */ Ins_MDRP,
7413 /* MDRP[13] */ Ins_MDRP,
7414 /* MDRP[14] */ Ins_MDRP,
7415 /* MDRP[15] */ Ins_MDRP,
7417 /* MDRP[16] */ Ins_MDRP,
7418 /* MDRP[17] */ Ins_MDRP,
7419 /* MDRP[18] */ Ins_MDRP,
7420 /* MDRP[19] */ Ins_MDRP,
7421 /* MDRP[20] */ Ins_MDRP,
7422 /* MDRP[21] */ Ins_MDRP,
7423 /* MDRP[22] */ Ins_MDRP,
7424 /* MDRP[23] */ Ins_MDRP,
7425 /* MDRP[24] */ Ins_MDRP,
7426 /* MDRP[25] */ Ins_MDRP,
7427 /* MDRP[26] */ Ins_MDRP,
7428 /* MDRP[27] */ Ins_MDRP,
7429 /* MDRP[28] */ Ins_MDRP,
7430 /* MDRP[29] */ Ins_MDRP,
7431 /* MDRP[30] */ Ins_MDRP,
7432 /* MDRP[31] */ Ins_MDRP,
7434 /* MIRP[00] */ Ins_MIRP,
7435 /* MIRP[01] */ Ins_MIRP,
7436 /* MIRP[02] */ Ins_MIRP,
7437 /* MIRP[03] */ Ins_MIRP,
7438 /* MIRP[04] */ Ins_MIRP,
7439 /* MIRP[05] */ Ins_MIRP,
7440 /* MIRP[06] */ Ins_MIRP,
7441 /* MIRP[07] */ Ins_MIRP,
7442 /* MIRP[08] */ Ins_MIRP,
7443 /* MIRP[09] */ Ins_MIRP,
7444 /* MIRP[10] */ Ins_MIRP,
7445 /* MIRP[11] */ Ins_MIRP,
7446 /* MIRP[12] */ Ins_MIRP,
7447 /* MIRP[13] */ Ins_MIRP,
7448 /* MIRP[14] */ Ins_MIRP,
7449 /* MIRP[15] */ Ins_MIRP,
7451 /* MIRP[16] */ Ins_MIRP,
7452 /* MIRP[17] */ Ins_MIRP,
7453 /* MIRP[18] */ Ins_MIRP,
7454 /* MIRP[19] */ Ins_MIRP,
7455 /* MIRP[20] */ Ins_MIRP,
7456 /* MIRP[21] */ Ins_MIRP,
7457 /* MIRP[22] */ Ins_MIRP,
7458 /* MIRP[23] */ Ins_MIRP,
7459 /* MIRP[24] */ Ins_MIRP,
7460 /* MIRP[25] */ Ins_MIRP,
7461 /* MIRP[26] */ Ins_MIRP,
7462 /* MIRP[27] */ Ins_MIRP,
7463 /* MIRP[28] */ Ins_MIRP,
7464 /* MIRP[29] */ Ins_MIRP,
7465 /* MIRP[30] */ Ins_MIRP,
7466 /* MIRP[31] */ Ins_MIRP
7470 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7473 /*************************************************************************/
7477 /* This function executes a run of opcodes. It will exit in the */
7478 /* following cases: */
7480 /* - Errors (in which case it returns FALSE). */
7482 /* - Reaching the end of the main code range (returns TRUE). */
7483 /* Reaching the end of a code range within a function call is an */
7486 /* - After executing one single opcode, if the flag `Instruction_Trap' */
7487 /* is set to TRUE (returns TRUE). */
7489 /* On exit with TRUE, test IP < CodeSize to know whether it comes from */
7490 /* an instruction trap or a normal termination. */
7493 /* Note: The documented DEBUG opcode pops a value from the stack. This */
7494 /* behaviour is unsupported; here a DEBUG opcode is always an */
7498 /* THIS IS THE INTERPRETER'S MAIN LOOP. */
7500 /* Instructions appear in the specification's order. */
7502 /*************************************************************************/
7505 /* documentation is in ttinterp.h */
7507 FT_EXPORT_DEF( FT_Error )
7508 TT_RunIns( TT_ExecContext exc )
7510 FT_Long ins_counter = 0; /* executed instructions counter */
7513 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7517 /* set CVT functions */
7518 CUR.tt_metrics.ratio = 0;
7519 if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
7521 /* non-square pixels, use the stretched routines */
7522 CUR.func_read_cvt = Read_CVT_Stretched;
7523 CUR.func_write_cvt = Write_CVT_Stretched;
7524 CUR.func_move_cvt = Move_CVT_Stretched;
7528 /* square pixels, use normal routines */
7529 CUR.func_read_cvt = Read_CVT;
7530 CUR.func_write_cvt = Write_CVT;
7531 CUR.func_move_cvt = Move_CVT;
7535 COMPUTE_Round( (FT_Byte)exc->GS.round_state );
7539 CUR.opcode = CUR.code[CUR.IP];
7542 FT_TRACE7(( opcode_name[CUR.opcode] ));
7543 FT_TRACE7(( "\n" ));
7545 if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )
7547 if ( CUR.IP + 1 >= CUR.codeSize )
7548 goto LErrorCodeOverflow_;
7550 CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
7553 if ( CUR.IP + CUR.length > CUR.codeSize )
7554 goto LErrorCodeOverflow_;
7556 /* First, let's check for empty stack and overflow */
7557 CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 );
7559 /* `args' is the top of the stack once arguments have been popped. */
7560 /* One can also interpret it as the index of the last argument. */
7566 if ( CUR.pedantic_hinting )
7568 CUR.error = TT_Err_Too_Few_Arguments;
7572 /* push zeroes onto the stack */
7573 for ( i = 0; i < Pop_Push_Count[CUR.opcode] >> 4; i++ )
7578 CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 );
7580 /* `new_top' is the new top of the stack, after the instruction's */
7581 /* execution. `top' will be set to `new_top' after the `switch' */
7583 if ( CUR.new_top > CUR.stackSize )
7585 CUR.error = TT_Err_Stack_Overflow;
7589 CUR.step_ins = TRUE;
7590 CUR.error = TT_Err_Ok;
7592 #ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
7595 FT_Long* args = CUR.stack + CUR.args;
7596 FT_Byte opcode = CUR.opcode;
7599 #undef ARRAY_BOUND_ERROR
7600 #define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
7605 case 0x00: /* SVTCA y */
7606 case 0x01: /* SVTCA x */
7607 case 0x02: /* SPvTCA y */
7608 case 0x03: /* SPvTCA x */
7609 case 0x04: /* SFvTCA y */
7610 case 0x05: /* SFvTCA x */
7615 AA = (FT_Short)( ( opcode & 1 ) << 14 );
7616 BB = (FT_Short)( AA ^ 0x4000 );
7620 CUR.GS.projVector.x = AA;
7621 CUR.GS.projVector.y = BB;
7623 CUR.GS.dualVector.x = AA;
7624 CUR.GS.dualVector.y = BB;
7628 GUESS_VECTOR( projVector );
7631 if ( ( opcode & 2 ) == 0 )
7633 CUR.GS.freeVector.x = AA;
7634 CUR.GS.freeVector.y = BB;
7638 GUESS_VECTOR( freeVector );
7645 case 0x06: /* SPvTL // */
7646 case 0x07: /* SPvTL + */
7650 case 0x08: /* SFvTL // */
7651 case 0x09: /* SFvTL + */
7655 case 0x0A: /* SPvFS */
7659 case 0x0B: /* SFvFS */
7663 case 0x0C: /* GPV */
7667 case 0x0D: /* GFV */
7671 case 0x0E: /* SFvTPv */
7675 case 0x0F: /* ISECT */
7676 Ins_ISECT( EXEC_ARG_ args );
7679 case 0x10: /* SRP0 */
7683 case 0x11: /* SRP1 */
7687 case 0x12: /* SRP2 */
7691 case 0x13: /* SZP0 */
7692 Ins_SZP0( EXEC_ARG_ args );
7695 case 0x14: /* SZP1 */
7696 Ins_SZP1( EXEC_ARG_ args );
7699 case 0x15: /* SZP2 */
7700 Ins_SZP2( EXEC_ARG_ args );
7703 case 0x16: /* SZPS */
7704 Ins_SZPS( EXEC_ARG_ args );
7707 case 0x17: /* SLOOP */
7711 case 0x18: /* RTG */
7715 case 0x19: /* RTHG */
7719 case 0x1A: /* SMD */
7723 case 0x1B: /* ELSE */
7724 Ins_ELSE( EXEC_ARG_ args );
7727 case 0x1C: /* JMPR */
7731 case 0x1D: /* SCVTCI */
7735 case 0x1E: /* SSWCI */
7739 case 0x1F: /* SSW */
7743 case 0x20: /* DUP */
7747 case 0x21: /* POP */
7751 case 0x22: /* CLEAR */
7755 case 0x23: /* SWAP */
7759 case 0x24: /* DEPTH */
7763 case 0x25: /* CINDEX */
7767 case 0x26: /* MINDEX */
7768 Ins_MINDEX( EXEC_ARG_ args );
7771 case 0x27: /* ALIGNPTS */
7772 Ins_ALIGNPTS( EXEC_ARG_ args );
7775 case 0x28: /* ???? */
7776 Ins_UNKNOWN( EXEC_ARG_ args );
7779 case 0x29: /* UTP */
7780 Ins_UTP( EXEC_ARG_ args );
7783 case 0x2A: /* LOOPCALL */
7784 Ins_LOOPCALL( EXEC_ARG_ args );
7787 case 0x2B: /* CALL */
7788 Ins_CALL( EXEC_ARG_ args );
7791 case 0x2C: /* FDEF */
7792 Ins_FDEF( EXEC_ARG_ args );
7795 case 0x2D: /* ENDF */
7796 Ins_ENDF( EXEC_ARG_ args );
7799 case 0x2E: /* MDAP */
7800 case 0x2F: /* MDAP */
7801 Ins_MDAP( EXEC_ARG_ args );
7805 case 0x30: /* IUP */
7806 case 0x31: /* IUP */
7807 Ins_IUP( EXEC_ARG_ args );
7810 case 0x32: /* SHP */
7811 case 0x33: /* SHP */
7812 Ins_SHP( EXEC_ARG_ args );
7815 case 0x34: /* SHC */
7816 case 0x35: /* SHC */
7817 Ins_SHC( EXEC_ARG_ args );
7820 case 0x36: /* SHZ */
7821 case 0x37: /* SHZ */
7822 Ins_SHZ( EXEC_ARG_ args );
7825 case 0x38: /* SHPIX */
7826 Ins_SHPIX( EXEC_ARG_ args );
7830 Ins_IP( EXEC_ARG_ args );
7833 case 0x3A: /* MSIRP */
7834 case 0x3B: /* MSIRP */
7835 Ins_MSIRP( EXEC_ARG_ args );
7838 case 0x3C: /* AlignRP */
7839 Ins_ALIGNRP( EXEC_ARG_ args );
7842 case 0x3D: /* RTDG */
7846 case 0x3E: /* MIAP */
7847 case 0x3F: /* MIAP */
7848 Ins_MIAP( EXEC_ARG_ args );
7851 case 0x40: /* NPUSHB */
7852 Ins_NPUSHB( EXEC_ARG_ args );
7855 case 0x41: /* NPUSHW */
7856 Ins_NPUSHW( EXEC_ARG_ args );
7864 CUR.error = TT_Err_Invalid_Reference;
7871 case 0x44: /* WCVTP */
7875 case 0x45: /* RCVT */
7881 Ins_GC( EXEC_ARG_ args );
7884 case 0x48: /* SCFS */
7885 Ins_SCFS( EXEC_ARG_ args );
7890 Ins_MD( EXEC_ARG_ args );
7893 case 0x4B: /* MPPEM */
7897 case 0x4C: /* MPS */
7901 case 0x4D: /* FLIPON */
7905 case 0x4E: /* FLIPOFF */
7909 case 0x4F: /* DEBUG */
7917 case 0x51: /* LTEQ */
7925 case 0x53: /* GTEQ */
7933 case 0x55: /* NEQ */
7937 case 0x56: /* ODD */
7941 case 0x57: /* EVEN */
7946 Ins_IF( EXEC_ARG_ args );
7949 case 0x59: /* EIF */
7953 case 0x5A: /* AND */
7961 case 0x5C: /* NOT */
7965 case 0x5D: /* DELTAP1 */
7966 Ins_DELTAP( EXEC_ARG_ args );
7969 case 0x5E: /* SDB */
7973 case 0x5F: /* SDS */
7977 case 0x60: /* ADD */
7981 case 0x61: /* SUB */
7985 case 0x62: /* DIV */
7989 case 0x63: /* MUL */
7993 case 0x64: /* ABS */
7997 case 0x65: /* NEG */
8001 case 0x66: /* FLOOR */
8005 case 0x67: /* CEILING */
8009 case 0x68: /* ROUND */
8010 case 0x69: /* ROUND */
8011 case 0x6A: /* ROUND */
8012 case 0x6B: /* ROUND */
8016 case 0x6C: /* NROUND */
8017 case 0x6D: /* NROUND */
8018 case 0x6E: /* NRRUND */
8019 case 0x6F: /* NROUND */
8023 case 0x70: /* WCVTF */
8027 case 0x71: /* DELTAP2 */
8028 case 0x72: /* DELTAP3 */
8029 Ins_DELTAP( EXEC_ARG_ args );
8032 case 0x73: /* DELTAC0 */
8033 case 0x74: /* DELTAC1 */
8034 case 0x75: /* DELTAC2 */
8035 Ins_DELTAC( EXEC_ARG_ args );
8038 case 0x76: /* SROUND */
8042 case 0x77: /* S45Round */
8046 case 0x78: /* JROT */
8050 case 0x79: /* JROF */
8054 case 0x7A: /* ROFF */
8058 case 0x7B: /* ???? */
8059 Ins_UNKNOWN( EXEC_ARG_ args );
8062 case 0x7C: /* RUTG */
8066 case 0x7D: /* RDTG */
8070 case 0x7E: /* SANGW */
8072 /* nothing - obsolete */
8075 case 0x80: /* FLIPPT */
8076 Ins_FLIPPT( EXEC_ARG_ args );
8079 case 0x81: /* FLIPRGON */
8080 Ins_FLIPRGON( EXEC_ARG_ args );
8083 case 0x82: /* FLIPRGOFF */
8084 Ins_FLIPRGOFF( EXEC_ARG_ args );
8087 case 0x83: /* UNKNOWN */
8088 case 0x84: /* UNKNOWN */
8089 Ins_UNKNOWN( EXEC_ARG_ args );
8092 case 0x85: /* SCANCTRL */
8093 Ins_SCANCTRL( EXEC_ARG_ args );
8096 case 0x86: /* SDPVTL */
8097 case 0x87: /* SDPVTL */
8098 Ins_SDPVTL( EXEC_ARG_ args );
8101 case 0x88: /* GETINFO */
8102 Ins_GETINFO( EXEC_ARG_ args );
8105 case 0x89: /* IDEF */
8106 Ins_IDEF( EXEC_ARG_ args );
8109 case 0x8A: /* ROLL */
8110 Ins_ROLL( EXEC_ARG_ args );
8113 case 0x8B: /* MAX */
8117 case 0x8C: /* MIN */
8121 case 0x8D: /* SCANTYPE */
8122 Ins_SCANTYPE( EXEC_ARG_ args );
8125 case 0x8E: /* INSTCTRL */
8126 Ins_INSTCTRL( EXEC_ARG_ args );
8130 Ins_UNKNOWN( EXEC_ARG_ args );
8134 if ( opcode >= 0xE0 )
8135 Ins_MIRP( EXEC_ARG_ args );
8136 else if ( opcode >= 0xC0 )
8137 Ins_MDRP( EXEC_ARG_ args );
8138 else if ( opcode >= 0xB8 )
8139 Ins_PUSHW( EXEC_ARG_ args );
8140 else if ( opcode >= 0xB0 )
8141 Ins_PUSHB( EXEC_ARG_ args );
8143 Ins_UNKNOWN( EXEC_ARG_ args );
8150 Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );
8152 #endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
8154 if ( CUR.error != TT_Err_Ok )
8156 switch ( CUR.error )
8158 case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
8160 TT_DefRecord* def = CUR.IDefs;
8161 TT_DefRecord* limit = def + CUR.numIDefs;
8164 for ( ; def < limit; def++ )
8166 if ( def->active && CUR.opcode == (FT_Byte)def->opc )
8168 TT_CallRec* callrec;
8171 if ( CUR.callTop >= CUR.callSize )
8173 CUR.error = TT_Err_Invalid_Reference;
8177 callrec = &CUR.callStack[CUR.callTop];
8179 callrec->Caller_Range = CUR.curRange;
8180 callrec->Caller_IP = CUR.IP + 1;
8181 callrec->Cur_Count = 1;
8182 callrec->Cur_Restart = def->start;
8183 callrec->Cur_End = def->end;
8185 if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
8193 CUR.error = TT_Err_Invalid_Opcode;
8197 break; /* Unreachable code warning suppression. */
8198 /* Leave to remind in case a later change the editor */
8199 /* to consider break; */
8211 CUR.top = CUR.new_top;
8214 CUR.IP += CUR.length;
8216 /* increment instruction counter and check if we didn't */
8217 /* run this program for too long (e.g. infinite loops). */
8218 if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
8219 return TT_Err_Execution_Too_Long;
8222 if ( CUR.IP >= CUR.codeSize )
8224 if ( CUR.callTop > 0 )
8226 CUR.error = TT_Err_Code_Overflow;
8232 } while ( !CUR.instruction_trap );
8236 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
8242 LErrorCodeOverflow_:
8243 CUR.error = TT_Err_Code_Overflow;
8247 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
8251 /* If any errors have occurred, function tables may be broken. */
8252 /* Force a re-execution of `prep' and `fpgm' tables if no */
8253 /* bytecode debugger is run. */
8254 if ( CUR.error && !CUR.instruction_trap )
8256 FT_TRACE1(( " The interpreter returned error 0x%x\n", CUR.error ));
8257 exc->size->cvt_ready = FALSE;
8264 #endif /* TT_USE_BYTECODE_INTERPRETER */