1 /***************************************************************************/
5 /* TrueType bytecode interpreter (body). */
7 /* Copyright 1996-2001 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
16 /***************************************************************************/
20 #include FT_INTERNAL_DEBUG_H
21 #include FT_INTERNAL_CALC_H
22 #include FT_TRIGONOMETRY_H
30 #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
33 #define TT_MULFIX FT_MulFix
34 #define TT_MULDIV FT_MulDiv
35 #define TT_INT64 FT_Int64
37 /*************************************************************************/
39 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
40 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
41 /* messages during execution. */
44 #define FT_COMPONENT trace_ttinterp
46 #undef NO_APPLE_PATENT
47 #define APPLE_THRESHOLD 0x4000000L
49 /*************************************************************************/
51 /* In order to detect infinite loops in the code, we set up a counter */
52 /* within the run loop. A single stroke of interpretation is now */
53 /* limitet to a maximal number of opcodes defined below. */
55 #define MAX_RUNNABLE_OPCODES 1000000L
58 /*************************************************************************/
60 /* There are two kinds of implementations: */
62 /* a. static implementation */
64 /* The current execution context is a static variable, which fields */
65 /* are accessed directly by the interpreter during execution. The */
66 /* context is named `cur'. */
68 /* This version is non-reentrant, of course. */
70 /* b. indirect implementation */
72 /* The current execution context is passed to _each_ function as its */
73 /* first argument, and each field is thus accessed indirectly. */
75 /* This version is fully re-entrant. */
77 /* The idea is that an indirect implementation may be slower to execute */
78 /* on low-end processors that are used in some systems (like 386s or */
81 /* As a consequence, the indirect implementation is now the default, as */
82 /* its performance costs can be considered negligible in our context. */
83 /* Note, however, that we kept the same source with macros because: */
85 /* - The code is kept very close in design to the Pascal code used for */
88 /* - It's much more readable that way! */
90 /* - It's still open to experimentation and tuning. */
92 /*************************************************************************/
95 #ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */
97 #define CUR (*exc) /* see ttobjs.h */
99 #else /* static implementation */
104 TT_ExecContextRec cur; /* static exec. context variable */
106 /* apparently, we have a _lot_ of direct indexing when accessing */
107 /* the static `cur', which makes the code bigger (due to all the */
108 /* four bytes addresses). */
110 #endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
113 /*************************************************************************/
115 /* The instruction argument stack. */
117 #define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */
120 /*************************************************************************/
122 /* This macro is used whenever `exec' is unused in a function, to avoid */
123 /* stupid warnings from pedantic compilers. */
125 #define FT_UNUSED_EXEC FT_UNUSED( CUR )
128 /*************************************************************************/
130 /* This macro is used whenever `args' is unused in a function, to avoid */
131 /* stupid warnings from pedantic compilers. */
133 #define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args )
136 /*************************************************************************/
138 /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */
139 /* increase readabilty of the code. */
141 /*************************************************************************/
144 #define SKIP_Code() \
147 #define GET_ShortIns() \
148 GetShortIns( EXEC_ARG )
150 #define NORMalize( x, y, v ) \
151 Normalize( EXEC_ARG_ x, y, v )
153 #define SET_SuperRound( scale, flags ) \
154 SetSuperRound( EXEC_ARG_ scale, flags )
156 #define ROUND_None( d, c ) \
157 Round_None( EXEC_ARG_ d, c )
159 #define INS_Goto_CodeRange( range, ip ) \
160 Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
162 #define CUR_Func_project( x, y ) \
163 CUR.func_project( EXEC_ARG_ x, y )
165 #define CUR_Func_move( z, p, d ) \
166 CUR.func_move( EXEC_ARG_ z, p, d )
168 #define CUR_Func_dualproj( x, y ) \
169 CUR.func_dualproj( EXEC_ARG_ x, y )
171 #define CUR_Func_freeProj( x, y ) \
172 CUR.func_freeProj( EXEC_ARG_ x, y )
174 #define CUR_Func_round( d, c ) \
175 CUR.func_round( EXEC_ARG_ d, c )
177 #define CUR_Func_read_cvt( index ) \
178 CUR.func_read_cvt( EXEC_ARG_ index )
180 #define CUR_Func_write_cvt( index, val ) \
181 CUR.func_write_cvt( EXEC_ARG_ index, val )
183 #define CUR_Func_move_cvt( index, val ) \
184 CUR.func_move_cvt( EXEC_ARG_ index, val )
186 #define CURRENT_Ratio() \
187 Current_Ratio( EXEC_ARG )
189 #define CURRENT_Ppem() \
190 Current_Ppem( EXEC_ARG )
195 #define INS_SxVTL( a, b, c, d ) \
196 Ins_SxVTL( EXEC_ARG_ a, b, c, d )
198 #define COMPUTE_Funcs() \
199 Compute_Funcs( EXEC_ARG )
201 #define COMPUTE_Round( a ) \
202 Compute_Round( EXEC_ARG_ a )
204 #define COMPUTE_Point_Displacement( a, b, c, d ) \
205 Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
207 #define MOVE_Zp2_Point( a, b, c, t ) \
208 Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
211 /*************************************************************************/
213 /* Instruction dispatch function, as used by the interpreter. */
215 typedef void (*TInstruction_Function)( INS_ARG );
218 /*************************************************************************/
220 /* A simple bounds-checking macro. */
222 #define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
232 /*************************************************************************/
234 /* CODERANGE FUNCTIONS */
236 /*************************************************************************/
239 /*************************************************************************/
242 /* TT_Goto_CodeRange */
245 /* Switches to a new code range (updates the code related elements in */
246 /* `exec', and `IP'). */
249 /* range :: The new execution code range. */
251 /* IP :: The new IP in the new code range. */
254 /* exec :: The target execution context. */
257 /* FreeType error code. 0 means success. */
259 FT_LOCAL_DEF FT_Error
260 TT_Goto_CodeRange( TT_ExecContext exec,
264 TT_CodeRange* coderange;
267 FT_Assert( range >= 1 && range <= 3 );
269 coderange = &exec->codeRangeTable[range - 1];
271 FT_Assert( coderange->base != NULL );
273 /* NOTE: Because the last instruction of a program may be a CALL */
274 /* which will return to the first byte *after* the code */
275 /* range, we test for IP <= Size instead of IP < Size. */
277 FT_Assert( (FT_ULong)IP <= coderange->size );
279 exec->code = coderange->base;
280 exec->codeSize = coderange->size;
282 exec->curRange = range;
288 /*************************************************************************/
291 /* TT_Set_CodeRange */
294 /* Sets a code range. */
297 /* range :: The code range index. */
299 /* base :: The new code base. */
301 /* length :: The range size in bytes. */
304 /* exec :: The target execution context. */
307 /* FreeType error code. 0 means success. */
309 FT_LOCAL_DEF FT_Error
310 TT_Set_CodeRange( TT_ExecContext exec,
315 FT_Assert( range >= 1 && range <= 3 );
317 exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
318 exec->codeRangeTable[range - 1].size = length;
324 /*************************************************************************/
327 /* TT_Clear_CodeRange */
330 /* Clears a code range. */
333 /* range :: The code range index. */
336 /* exec :: The target execution context. */
339 /* FreeType error code. 0 means success. */
342 /* Does not set the Error variable. */
344 FT_LOCAL_DEF FT_Error
345 TT_Clear_CodeRange( TT_ExecContext exec,
348 FT_Assert( range >= 1 && range <= 3 );
350 exec->codeRangeTable[range - 1].base = NULL;
351 exec->codeRangeTable[range - 1].size = 0;
357 /*************************************************************************/
359 /* EXECUTION CONTEXT ROUTINES */
361 /*************************************************************************/
364 /*************************************************************************/
367 /* TT_Destroy_Context */
370 /* Destroys a given context. */
373 /* exec :: A handle to the target execution context. */
375 /* memory :: A handle to the parent memory object. */
378 /* FreeType error code. 0 means success. */
381 /* Only the glyph loader and debugger should call this function. */
383 FT_LOCAL_DEF FT_Error
384 TT_Destroy_Context( TT_ExecContext exec,
387 /* free composite load stack */
388 FREE( exec->loadStack );
393 exec->maxContours = 0;
399 /* free call stack */
400 FREE( exec->callStack );
404 /* free glyph code range */
405 FREE( exec->glyphIns );
416 /*************************************************************************/
422 /* Initializes a context object. */
425 /* memory :: A handle to the parent memory object. */
427 /* face :: A handle to the source TrueType face object. */
430 /* exec :: A handle to the target execution context. */
433 /* FreeType error code. 0 means success. */
436 Init_Context( TT_ExecContext exec,
443 FT_TRACE1(( "Init_Context: new object at 0x%08p, parent = 0x%08p\n",
446 exec->memory = memory;
449 if ( ALLOC_ARRAY( exec->callStack, exec->callSize, TT_CallRec ) )
452 /* all values in the context are set to 0 already, but this is */
453 /* here as a remainder */
455 exec->maxContours = 0;
462 exec->loadStack = NULL;
463 exec->glyphIns = NULL;
471 FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n",
473 TT_Destroy_Context( exec, memory );
479 /*************************************************************************/
485 /* Checks the size of a buffer and reallocates it if necessary. */
488 /* memory :: A handle to the parent memory object. */
490 /* multiplier :: The size in bytes of each element in the buffer. */
492 /* new_max :: The new capacity (size) of the buffer. */
495 /* size :: The address of the buffer's current size expressed */
498 /* buff :: The address of the buffer base pointer. */
501 /* FreeType error code. 0 means success. */
504 Update_Max( FT_Memory memory,
513 if ( *size < new_max )
516 if ( ALLOC( *buff, new_max * multiplier ) )
525 /*************************************************************************/
528 /* TT_Load_Context */
531 /* Prepare an execution context for glyph hinting. */
534 /* face :: A handle to the source face object. */
536 /* size :: A handle to the source size object. */
539 /* exec :: A handle to the target execution context. */
542 /* FreeType error code. 0 means success. */
545 /* Only the glyph loader and debugger should call this function. */
547 FT_LOCAL_DEF FT_Error
548 TT_Load_Context( TT_ExecContext exec,
559 maxp = &face->max_profile;
564 exec->numFDefs = size->num_function_defs;
565 exec->maxFDefs = size->max_function_defs;
566 exec->numIDefs = size->num_instruction_defs;
567 exec->maxIDefs = size->max_instruction_defs;
568 exec->FDefs = size->function_defs;
569 exec->IDefs = size->instruction_defs;
570 exec->tt_metrics = size->ttmetrics;
571 exec->metrics = size->root.metrics;
573 exec->maxFunc = size->max_func;
574 exec->maxIns = size->max_ins;
576 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
577 exec->codeRangeTable[i] = size->codeRangeTable[i];
579 /* set graphics state */
582 exec->cvtSize = size->cvt_size;
583 exec->cvt = size->cvt;
585 exec->storeSize = size->storage_size;
586 exec->storage = size->storage;
588 exec->twilight = size->twilight;
591 error = Update_Max( exec->memory,
593 sizeof ( TT_SubGlyphRec ),
594 (void**)&exec->loadStack,
595 exec->face->max_components + 1 );
599 /* XXX: We reserve a little more elements on the stack to deal safely */
600 /* with broken fonts like arialbs, courbs, timesbs, etc. */
601 tmp = exec->stackSize;
602 error = Update_Max( exec->memory,
604 sizeof ( FT_F26Dot6 ),
605 (void**)&exec->stack,
606 maxp->maxStackElements + 32 );
607 exec->stackSize = (FT_UInt)tmp;
611 tmp = exec->glyphSize;
612 error = Update_Max( exec->memory,
615 (void**)&exec->glyphIns,
616 maxp->maxSizeOfInstructions );
617 exec->glyphSize = (FT_UShort)tmp;
621 exec->pts.n_points = 0;
622 exec->pts.n_contours = 0;
624 exec->instruction_trap = FALSE;
630 /*************************************************************************/
633 /* TT_Save_Context */
636 /* Saves the code ranges in a `size' object. */
639 /* exec :: A handle to the source execution context. */
642 /* size :: A handle to the target size object. */
645 /* FreeType error code. 0 means success. */
648 /* Only the glyph loader and debugger should call this function. */
650 FT_LOCAL_DEF FT_Error
651 TT_Save_Context( TT_ExecContext exec,
657 /* XXXX: Will probably disappear soon with all the code range */
658 /* management, which is now rather obsolete. */
660 size->num_function_defs = exec->numFDefs;
661 size->num_instruction_defs = exec->numIDefs;
663 size->max_func = exec->maxFunc;
664 size->max_ins = exec->maxIns;
666 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
667 size->codeRangeTable[i] = exec->codeRangeTable[i];
673 /*************************************************************************/
679 /* Executes one or more instructions in the execution context. */
682 /* debug :: A Boolean flag. If set, the function sets some internal */
683 /* variables and returns immediately, otherwise TT_RunIns() */
686 /* This is commented out currently. */
689 /* exec :: A handle to the target execution context. */
692 /* TrueTyoe error code. 0 means success. */
695 /* Only the glyph loader and debugger should call this function. */
697 FT_LOCAL_DEF FT_Error
698 TT_Run_Context( TT_ExecContext exec,
704 if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) )
708 exec->zp0 = exec->pts;
709 exec->zp1 = exec->pts;
710 exec->zp2 = exec->pts;
716 exec->GS.projVector.x = 0x4000;
717 exec->GS.projVector.y = 0x0000;
719 exec->GS.freeVector = exec->GS.projVector;
720 exec->GS.dualVector = exec->GS.projVector;
722 exec->GS.round_state = 1;
725 /* some glyphs leave something on the stack. so we clean it */
726 /* before a new execution. */
733 return exec->face->interpreter( exec );
736 return TT_RunIns( exec );
743 const TT_GraphicsState tt_default_graphics_state =
750 TRUE, 68, 0, 0, 9, 3,
755 /* documentation is in ttinterp.h */
757 FT_EXPORT_DEF( TT_ExecContext )
758 TT_New_Context( TT_Face face )
768 driver = (TT_Driver)face->root.driver;
770 memory = driver->root.root.memory;
771 exec = driver->context;
773 if ( !driver->context )
778 /* allocate object */
779 if ( ALLOC( exec, sizeof ( *exec ) ) )
783 error = Init_Context( exec, face, memory );
787 /* store it into the driver */
788 driver->context = exec;
792 return driver->context;
801 /*************************************************************************/
804 /* TT_Done_Context */
807 /* Discards an execution context. */
810 /* exec :: A handle to the target execution context. */
813 /* FreeType error code. 0 means success. */
816 /* Only the glyph loader and debugger should call this function. */
818 FT_LOCAL_DEF FT_Error
819 TT_Done_Context( TT_ExecContext exec )
821 /* Nothing at all for now */
828 /* return length of given vector */
829 #ifdef FT_CONFIG_OPTION_OLD_CALCS
841 ADD_64( T1, T2, T1 );
843 return (FT_F26Dot6)SQRT_64( T1 );
846 #else /* !FT_CONFIG_OPTION_OLD_CALCS */
856 return FT_Vector_Length( &v );
859 #endif /* FT_CONFIG_OPTION_OLD_CALCS */
862 /*************************************************************************/
864 /* Before an opcode is executed, the interpreter verifies that there are */
865 /* enough arguments on the stack, with the help of the Pop_Push_Count */
868 /* For each opcode, the first column gives the number of arguments that */
869 /* are popped from the stack; the second one gives the number of those */
870 /* that are pushed in result. */
872 /* Note that for opcodes with a varying number of parameters, either 0 */
873 /* or 1 arg is verified before execution, depending on the nature of the */
876 /* - if the number of arguments is given by the bytecode stream or the */
877 /* loop variable, 0 is chosen. */
879 /* - if the first argument is a count n that is followed by arguments */
880 /* a1 .. an, then 1 is chosen. */
882 /*************************************************************************/
886 #define PACK( x, y ) ( ( x << 4 ) | y )
890 const FT_Byte Pop_Push_Count[256] =
892 /* opcodes are gathered in groups of 16 */
893 /* please keep the spaces as they are */
895 /* SVTCA y */ PACK( 0, 0 ),
896 /* SVTCA x */ PACK( 0, 0 ),
897 /* SPvTCA y */ PACK( 0, 0 ),
898 /* SPvTCA x */ PACK( 0, 0 ),
899 /* SFvTCA y */ PACK( 0, 0 ),
900 /* SFvTCA x */ PACK( 0, 0 ),
901 /* SPvTL // */ PACK( 2, 0 ),
902 /* SPvTL + */ PACK( 2, 0 ),
903 /* SFvTL // */ PACK( 2, 0 ),
904 /* SFvTL + */ PACK( 2, 0 ),
905 /* SPvFS */ PACK( 2, 0 ),
906 /* SFvFS */ PACK( 2, 0 ),
907 /* GPV */ PACK( 0, 2 ),
908 /* GFV */ PACK( 0, 2 ),
909 /* SFvTPv */ PACK( 0, 0 ),
910 /* ISECT */ PACK( 5, 0 ),
912 /* SRP0 */ PACK( 1, 0 ),
913 /* SRP1 */ PACK( 1, 0 ),
914 /* SRP2 */ PACK( 1, 0 ),
915 /* SZP0 */ PACK( 1, 0 ),
916 /* SZP1 */ PACK( 1, 0 ),
917 /* SZP2 */ PACK( 1, 0 ),
918 /* SZPS */ PACK( 1, 0 ),
919 /* SLOOP */ PACK( 1, 0 ),
920 /* RTG */ PACK( 0, 0 ),
921 /* RTHG */ PACK( 0, 0 ),
922 /* SMD */ PACK( 1, 0 ),
923 /* ELSE */ PACK( 0, 0 ),
924 /* JMPR */ PACK( 1, 0 ),
925 /* SCvTCi */ PACK( 1, 0 ),
926 /* SSwCi */ PACK( 1, 0 ),
927 /* SSW */ PACK( 1, 0 ),
929 /* DUP */ PACK( 1, 2 ),
930 /* POP */ PACK( 1, 0 ),
931 /* CLEAR */ PACK( 0, 0 ),
932 /* SWAP */ PACK( 2, 2 ),
933 /* DEPTH */ PACK( 0, 1 ),
934 /* CINDEX */ PACK( 1, 1 ),
935 /* MINDEX */ PACK( 1, 0 ),
936 /* AlignPTS */ PACK( 2, 0 ),
937 /* INS_$28 */ PACK( 0, 0 ),
938 /* UTP */ PACK( 1, 0 ),
939 /* LOOPCALL */ PACK( 2, 0 ),
940 /* CALL */ PACK( 1, 0 ),
941 /* FDEF */ PACK( 1, 0 ),
942 /* ENDF */ PACK( 0, 0 ),
943 /* MDAP[0] */ PACK( 1, 0 ),
944 /* MDAP[1] */ PACK( 1, 0 ),
946 /* IUP[0] */ PACK( 0, 0 ),
947 /* IUP[1] */ PACK( 0, 0 ),
948 /* SHP[0] */ PACK( 0, 0 ),
949 /* SHP[1] */ PACK( 0, 0 ),
950 /* SHC[0] */ PACK( 1, 0 ),
951 /* SHC[1] */ PACK( 1, 0 ),
952 /* SHZ[0] */ PACK( 1, 0 ),
953 /* SHZ[1] */ PACK( 1, 0 ),
954 /* SHPIX */ PACK( 1, 0 ),
955 /* IP */ PACK( 0, 0 ),
956 /* MSIRP[0] */ PACK( 2, 0 ),
957 /* MSIRP[1] */ PACK( 2, 0 ),
958 /* AlignRP */ PACK( 0, 0 ),
959 /* RTDG */ PACK( 0, 0 ),
960 /* MIAP[0] */ PACK( 2, 0 ),
961 /* MIAP[1] */ PACK( 2, 0 ),
963 /* NPushB */ PACK( 0, 0 ),
964 /* NPushW */ PACK( 0, 0 ),
965 /* WS */ PACK( 2, 0 ),
966 /* RS */ PACK( 1, 1 ),
967 /* WCvtP */ PACK( 2, 0 ),
968 /* RCvt */ PACK( 1, 1 ),
969 /* GC[0] */ PACK( 1, 1 ),
970 /* GC[1] */ PACK( 1, 1 ),
971 /* SCFS */ PACK( 2, 0 ),
972 /* MD[0] */ PACK( 2, 1 ),
973 /* MD[1] */ PACK( 2, 1 ),
974 /* MPPEM */ PACK( 0, 1 ),
975 /* MPS */ PACK( 0, 1 ),
976 /* FlipON */ PACK( 0, 0 ),
977 /* FlipOFF */ PACK( 0, 0 ),
978 /* DEBUG */ PACK( 1, 0 ),
980 /* LT */ PACK( 2, 1 ),
981 /* LTEQ */ PACK( 2, 1 ),
982 /* GT */ PACK( 2, 1 ),
983 /* GTEQ */ PACK( 2, 1 ),
984 /* EQ */ PACK( 2, 1 ),
985 /* NEQ */ PACK( 2, 1 ),
986 /* ODD */ PACK( 1, 1 ),
987 /* EVEN */ PACK( 1, 1 ),
988 /* IF */ PACK( 1, 0 ),
989 /* EIF */ PACK( 0, 0 ),
990 /* AND */ PACK( 2, 1 ),
991 /* OR */ PACK( 2, 1 ),
992 /* NOT */ PACK( 1, 1 ),
993 /* DeltaP1 */ PACK( 1, 0 ),
994 /* SDB */ PACK( 1, 0 ),
995 /* SDS */ PACK( 1, 0 ),
997 /* ADD */ PACK( 2, 1 ),
998 /* SUB */ PACK( 2, 1 ),
999 /* DIV */ PACK( 2, 1 ),
1000 /* MUL */ PACK( 2, 1 ),
1001 /* ABS */ PACK( 1, 1 ),
1002 /* NEG */ PACK( 1, 1 ),
1003 /* FLOOR */ PACK( 1, 1 ),
1004 /* CEILING */ PACK( 1, 1 ),
1005 /* ROUND[0] */ PACK( 1, 1 ),
1006 /* ROUND[1] */ PACK( 1, 1 ),
1007 /* ROUND[2] */ PACK( 1, 1 ),
1008 /* ROUND[3] */ PACK( 1, 1 ),
1009 /* NROUND[0] */ PACK( 1, 1 ),
1010 /* NROUND[1] */ PACK( 1, 1 ),
1011 /* NROUND[2] */ PACK( 1, 1 ),
1012 /* NROUND[3] */ PACK( 1, 1 ),
1014 /* WCvtF */ PACK( 2, 0 ),
1015 /* DeltaP2 */ PACK( 1, 0 ),
1016 /* DeltaP3 */ PACK( 1, 0 ),
1017 /* DeltaCn[0] */ PACK( 1, 0 ),
1018 /* DeltaCn[1] */ PACK( 1, 0 ),
1019 /* DeltaCn[2] */ PACK( 1, 0 ),
1020 /* SROUND */ PACK( 1, 0 ),
1021 /* S45Round */ PACK( 1, 0 ),
1022 /* JROT */ PACK( 2, 0 ),
1023 /* JROF */ PACK( 2, 0 ),
1024 /* ROFF */ PACK( 0, 0 ),
1025 /* INS_$7B */ PACK( 0, 0 ),
1026 /* RUTG */ PACK( 0, 0 ),
1027 /* RDTG */ PACK( 0, 0 ),
1028 /* SANGW */ PACK( 1, 0 ),
1029 /* AA */ PACK( 1, 0 ),
1031 /* FlipPT */ PACK( 0, 0 ),
1032 /* FlipRgON */ PACK( 2, 0 ),
1033 /* FlipRgOFF */ PACK( 2, 0 ),
1034 /* INS_$83 */ PACK( 0, 0 ),
1035 /* INS_$84 */ PACK( 0, 0 ),
1036 /* ScanCTRL */ PACK( 1, 0 ),
1037 /* SDVPTL[0] */ PACK( 2, 0 ),
1038 /* SDVPTL[1] */ PACK( 2, 0 ),
1039 /* GetINFO */ PACK( 1, 1 ),
1040 /* IDEF */ PACK( 1, 0 ),
1041 /* ROLL */ PACK( 3, 3 ),
1042 /* MAX */ PACK( 2, 1 ),
1043 /* MIN */ PACK( 2, 1 ),
1044 /* ScanTYPE */ PACK( 1, 0 ),
1045 /* InstCTRL */ PACK( 2, 0 ),
1046 /* INS_$8F */ PACK( 0, 0 ),
1048 /* INS_$90 */ PACK( 0, 0 ),
1049 /* INS_$91 */ PACK( 0, 0 ),
1050 /* INS_$92 */ PACK( 0, 0 ),
1051 /* INS_$93 */ PACK( 0, 0 ),
1052 /* INS_$94 */ PACK( 0, 0 ),
1053 /* INS_$95 */ PACK( 0, 0 ),
1054 /* INS_$96 */ PACK( 0, 0 ),
1055 /* INS_$97 */ PACK( 0, 0 ),
1056 /* INS_$98 */ PACK( 0, 0 ),
1057 /* INS_$99 */ PACK( 0, 0 ),
1058 /* INS_$9A */ PACK( 0, 0 ),
1059 /* INS_$9B */ PACK( 0, 0 ),
1060 /* INS_$9C */ PACK( 0, 0 ),
1061 /* INS_$9D */ PACK( 0, 0 ),
1062 /* INS_$9E */ PACK( 0, 0 ),
1063 /* INS_$9F */ PACK( 0, 0 ),
1065 /* INS_$A0 */ PACK( 0, 0 ),
1066 /* INS_$A1 */ PACK( 0, 0 ),
1067 /* INS_$A2 */ PACK( 0, 0 ),
1068 /* INS_$A3 */ PACK( 0, 0 ),
1069 /* INS_$A4 */ PACK( 0, 0 ),
1070 /* INS_$A5 */ PACK( 0, 0 ),
1071 /* INS_$A6 */ PACK( 0, 0 ),
1072 /* INS_$A7 */ PACK( 0, 0 ),
1073 /* INS_$A8 */ PACK( 0, 0 ),
1074 /* INS_$A9 */ PACK( 0, 0 ),
1075 /* INS_$AA */ PACK( 0, 0 ),
1076 /* INS_$AB */ PACK( 0, 0 ),
1077 /* INS_$AC */ PACK( 0, 0 ),
1078 /* INS_$AD */ PACK( 0, 0 ),
1079 /* INS_$AE */ PACK( 0, 0 ),
1080 /* INS_$AF */ PACK( 0, 0 ),
1082 /* PushB[0] */ PACK( 0, 1 ),
1083 /* PushB[1] */ PACK( 0, 2 ),
1084 /* PushB[2] */ PACK( 0, 3 ),
1085 /* PushB[3] */ PACK( 0, 4 ),
1086 /* PushB[4] */ PACK( 0, 5 ),
1087 /* PushB[5] */ PACK( 0, 6 ),
1088 /* PushB[6] */ PACK( 0, 7 ),
1089 /* PushB[7] */ PACK( 0, 8 ),
1090 /* PushW[0] */ PACK( 0, 1 ),
1091 /* PushW[1] */ PACK( 0, 2 ),
1092 /* PushW[2] */ PACK( 0, 3 ),
1093 /* PushW[3] */ PACK( 0, 4 ),
1094 /* PushW[4] */ PACK( 0, 5 ),
1095 /* PushW[5] */ PACK( 0, 6 ),
1096 /* PushW[6] */ PACK( 0, 7 ),
1097 /* PushW[7] */ PACK( 0, 8 ),
1099 /* MDRP[00] */ PACK( 1, 0 ),
1100 /* MDRP[01] */ PACK( 1, 0 ),
1101 /* MDRP[02] */ PACK( 1, 0 ),
1102 /* MDRP[03] */ PACK( 1, 0 ),
1103 /* MDRP[04] */ PACK( 1, 0 ),
1104 /* MDRP[05] */ PACK( 1, 0 ),
1105 /* MDRP[06] */ PACK( 1, 0 ),
1106 /* MDRP[07] */ PACK( 1, 0 ),
1107 /* MDRP[08] */ PACK( 1, 0 ),
1108 /* MDRP[09] */ PACK( 1, 0 ),
1109 /* MDRP[10] */ PACK( 1, 0 ),
1110 /* MDRP[11] */ PACK( 1, 0 ),
1111 /* MDRP[12] */ PACK( 1, 0 ),
1112 /* MDRP[13] */ PACK( 1, 0 ),
1113 /* MDRP[14] */ PACK( 1, 0 ),
1114 /* MDRP[15] */ PACK( 1, 0 ),
1116 /* MDRP[16] */ PACK( 1, 0 ),
1117 /* MDRP[17] */ PACK( 1, 0 ),
1118 /* MDRP[18] */ PACK( 1, 0 ),
1119 /* MDRP[19] */ PACK( 1, 0 ),
1120 /* MDRP[20] */ PACK( 1, 0 ),
1121 /* MDRP[21] */ PACK( 1, 0 ),
1122 /* MDRP[22] */ PACK( 1, 0 ),
1123 /* MDRP[23] */ PACK( 1, 0 ),
1124 /* MDRP[24] */ PACK( 1, 0 ),
1125 /* MDRP[25] */ PACK( 1, 0 ),
1126 /* MDRP[26] */ PACK( 1, 0 ),
1127 /* MDRP[27] */ PACK( 1, 0 ),
1128 /* MDRP[28] */ PACK( 1, 0 ),
1129 /* MDRP[29] */ PACK( 1, 0 ),
1130 /* MDRP[30] */ PACK( 1, 0 ),
1131 /* MDRP[31] */ PACK( 1, 0 ),
1133 /* MIRP[00] */ PACK( 2, 0 ),
1134 /* MIRP[01] */ PACK( 2, 0 ),
1135 /* MIRP[02] */ PACK( 2, 0 ),
1136 /* MIRP[03] */ PACK( 2, 0 ),
1137 /* MIRP[04] */ PACK( 2, 0 ),
1138 /* MIRP[05] */ PACK( 2, 0 ),
1139 /* MIRP[06] */ PACK( 2, 0 ),
1140 /* MIRP[07] */ PACK( 2, 0 ),
1141 /* MIRP[08] */ PACK( 2, 0 ),
1142 /* MIRP[09] */ PACK( 2, 0 ),
1143 /* MIRP[10] */ PACK( 2, 0 ),
1144 /* MIRP[11] */ PACK( 2, 0 ),
1145 /* MIRP[12] */ PACK( 2, 0 ),
1146 /* MIRP[13] */ PACK( 2, 0 ),
1147 /* MIRP[14] */ PACK( 2, 0 ),
1148 /* MIRP[15] */ PACK( 2, 0 ),
1150 /* MIRP[16] */ PACK( 2, 0 ),
1151 /* MIRP[17] */ PACK( 2, 0 ),
1152 /* MIRP[18] */ PACK( 2, 0 ),
1153 /* MIRP[19] */ PACK( 2, 0 ),
1154 /* MIRP[20] */ PACK( 2, 0 ),
1155 /* MIRP[21] */ PACK( 2, 0 ),
1156 /* MIRP[22] */ PACK( 2, 0 ),
1157 /* MIRP[23] */ PACK( 2, 0 ),
1158 /* MIRP[24] */ PACK( 2, 0 ),
1159 /* MIRP[25] */ PACK( 2, 0 ),
1160 /* MIRP[26] */ PACK( 2, 0 ),
1161 /* MIRP[27] */ PACK( 2, 0 ),
1162 /* MIRP[28] */ PACK( 2, 0 ),
1163 /* MIRP[29] */ PACK( 2, 0 ),
1164 /* MIRP[30] */ PACK( 2, 0 ),
1165 /* MIRP[31] */ PACK( 2, 0 )
1170 const FT_Char opcode_length[256] =
1172 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1173 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1174 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1175 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1177 -1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1178 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1179 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1180 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1182 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1183 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1184 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1185 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
1187 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1188 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1189 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1190 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1194 const FT_Vector Null_Vector = {0,0};
1201 #define NULL_Vector (FT_Vector*)&Null_Vector
1204 /*************************************************************************/
1210 /* Returns the current aspect ratio scaling factor depending on the */
1211 /* projection vector's state and device resolutions. */
1214 /* The aspect ratio in 16.16 format, always <= 1.0 . */
1217 Current_Ratio( EXEC_OP )
1219 if ( CUR.tt_metrics.ratio )
1220 return CUR.tt_metrics.ratio;
1222 if ( CUR.GS.projVector.y == 0 )
1223 CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
1225 else if ( CUR.GS.projVector.x == 0 )
1226 CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
1232 x = TT_MULDIV( CUR.GS.projVector.x, CUR.tt_metrics.x_ratio, 0x4000 );
1233 y = TT_MULDIV( CUR.GS.projVector.y, CUR.tt_metrics.y_ratio, 0x4000 );
1234 CUR.tt_metrics.ratio = Norm( x, y );
1237 return CUR.tt_metrics.ratio;
1242 Current_Ppem( EXEC_OP )
1244 return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );
1248 /*************************************************************************/
1250 /* Functions related to the control value table (CVT). */
1252 /*************************************************************************/
1255 FT_CALLBACK_DEF( FT_F26Dot6 )
1256 Read_CVT( EXEC_OP_ FT_ULong index )
1258 return CUR.cvt[index];
1262 FT_CALLBACK_DEF( FT_F26Dot6 )
1263 Read_CVT_Stretched( EXEC_OP_ FT_ULong index )
1265 return TT_MULFIX( CUR.cvt[index], CURRENT_Ratio() );
1269 FT_CALLBACK_DEF( void )
1270 Write_CVT( EXEC_OP_ FT_ULong index,
1273 CUR.cvt[index] = value;
1277 FT_CALLBACK_DEF( void )
1278 Write_CVT_Stretched( EXEC_OP_ FT_ULong index,
1281 CUR.cvt[index] = FT_DivFix( value, CURRENT_Ratio() );
1285 FT_CALLBACK_DEF( void )
1286 Move_CVT( EXEC_OP_ FT_ULong index,
1289 CUR.cvt[index] += value;
1293 FT_CALLBACK_DEF( void )
1294 Move_CVT_Stretched( EXEC_OP_ FT_ULong index,
1297 CUR.cvt[index] += FT_DivFix( value, CURRENT_Ratio() );
1301 /*************************************************************************/
1307 /* Returns a short integer taken from the instruction stream at */
1311 /* Short read at code[IP]. */
1314 /* This one could become a macro. */
1317 GetShortIns( EXEC_OP )
1319 /* Reading a byte stream so there is no endianess (DaveP) */
1321 return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) +
1322 CUR.code[CUR.IP - 1] );
1326 /*************************************************************************/
1329 /* Ins_Goto_CodeRange */
1332 /* Goes to a certain code range in the instruction stream. */
1335 /* aRange :: The index of the code range. */
1337 /* aIP :: The new IP address in the code range. */
1340 /* SUCCESS or FAILURE. */
1343 Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange,
1346 TT_CodeRange* range;
1349 if ( aRange < 1 || aRange > 3 )
1351 CUR.error = TT_Err_Bad_Argument;
1355 range = &CUR.codeRangeTable[aRange - 1];
1357 if ( range->base == NULL ) /* invalid coderange */
1359 CUR.error = TT_Err_Invalid_CodeRange;
1363 /* NOTE: Because the last instruction of a program may be a CALL */
1364 /* which will return to the first byte *after* the code */
1365 /* range, we test for AIP <= Size, instead of AIP < Size. */
1367 if ( aIP > range->size )
1369 CUR.error = TT_Err_Code_Overflow;
1373 CUR.code = range->base;
1374 CUR.codeSize = range->size;
1376 CUR.curRange = aRange;
1382 /*************************************************************************/
1388 /* Moves a point by a given distance along the freedom vector. The */
1389 /* point will be `touched'. */
1392 /* point :: The index of the point to move. */
1394 /* distance :: The distance to apply. */
1397 /* zone :: The affected glyph zone. */
1400 Direct_Move( EXEC_OP_ TT_GlyphZone* zone,
1402 FT_F26Dot6 distance )
1407 v = CUR.GS.freeVector.x;
1412 #ifdef NO_APPLE_PATENT
1414 if ( ABS( CUR.F_dot_P ) > APPLE_THRESHOLD )
1415 zone->cur[point].x += distance;
1419 zone->cur[point].x += TT_MULDIV( distance,
1425 zone->tags[point] |= FT_Curve_Tag_Touch_X;
1428 v = CUR.GS.freeVector.y;
1433 #ifdef NO_APPLE_PATENT
1435 if ( ABS( CUR.F_dot_P ) > APPLE_THRESHOLD )
1436 zone->cur[point].y += distance;
1440 zone->cur[point].y += TT_MULDIV( distance,
1446 zone->tags[point] |= FT_Curve_Tag_Touch_Y;
1451 /*************************************************************************/
1453 /* Special versions of Direct_Move() */
1455 /* The following versions are used whenever both vectors are both */
1456 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1458 /*************************************************************************/
1462 Direct_Move_X( EXEC_OP_ TT_GlyphZone* zone,
1464 FT_F26Dot6 distance )
1468 zone->cur[point].x += distance;
1469 zone->tags[point] |= FT_Curve_Tag_Touch_X;
1474 Direct_Move_Y( EXEC_OP_ TT_GlyphZone* zone,
1476 FT_F26Dot6 distance )
1480 zone->cur[point].y += distance;
1481 zone->tags[point] |= FT_Curve_Tag_Touch_Y;
1485 /*************************************************************************/
1491 /* Does not round, but adds engine compensation. */
1494 /* distance :: The distance (not) to round. */
1496 /* compensation :: The engine compensation. */
1499 /* The compensated distance. */
1502 /* The TrueType specification says very few about the relationship */
1503 /* between rounding and engine compensation. However, it seems from */
1504 /* the description of super round that we should add the compensation */
1505 /* before rounding. */
1508 Round_None( EXEC_OP_ FT_F26Dot6 distance,
1509 FT_F26Dot6 compensation )
1516 if ( distance >= 0 )
1518 val = distance + compensation;
1523 val = distance - compensation;
1531 /*************************************************************************/
1537 /* Rounds value to grid after adding engine compensation. */
1540 /* distance :: The distance to round. */
1542 /* compensation :: The engine compensation. */
1545 /* Rounded distance. */
1548 Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1549 FT_F26Dot6 compensation )
1556 if ( distance >= 0 )
1558 val = distance + compensation + 32;
1566 val = -( ( compensation - distance + 32 ) & -64 );
1575 /*************************************************************************/
1578 /* Round_To_Half_Grid */
1581 /* Rounds value to half grid after adding engine compensation. */
1584 /* distance :: The distance to round. */
1586 /* compensation :: The engine compensation. */
1589 /* Rounded distance. */
1592 Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance,
1593 FT_F26Dot6 compensation )
1600 if ( distance >= 0 )
1602 val = ( ( distance + compensation ) & -64 ) + 32;
1608 val = -( ( (compensation - distance) & -64 ) + 32 );
1617 /*************************************************************************/
1620 /* Round_Down_To_Grid */
1623 /* Rounds value down to grid after adding engine compensation. */
1626 /* distance :: The distance to round. */
1628 /* compensation :: The engine compensation. */
1631 /* Rounded distance. */
1634 Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1635 FT_F26Dot6 compensation )
1642 if ( distance >= 0 )
1644 val = distance + compensation;
1652 val = -( ( compensation - distance ) & -64 );
1661 /*************************************************************************/
1664 /* Round_Up_To_Grid */
1667 /* Rounds value up to grid after adding engine compensation. */
1670 /* distance :: The distance to round. */
1672 /* compensation :: The engine compensation. */
1675 /* Rounded distance. */
1678 Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1679 FT_F26Dot6 compensation )
1686 if ( distance >= 0 )
1688 val = distance + compensation + 63;
1696 val = -( ( compensation - distance + 63 ) & -64 );
1705 /*************************************************************************/
1708 /* Round_To_Double_Grid */
1711 /* Rounds value to double grid after adding engine compensation. */
1714 /* distance :: The distance to round. */
1716 /* compensation :: The engine compensation. */
1719 /* Rounded distance. */
1722 Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance,
1723 FT_F26Dot6 compensation )
1730 if ( distance >= 0 )
1732 val = distance + compensation + 16;
1740 val = -( ( compensation - distance + 16 ) & -32 );
1749 /*************************************************************************/
1755 /* Super-rounds value to grid after adding engine compensation. */
1758 /* distance :: The distance to round. */
1760 /* compensation :: The engine compensation. */
1763 /* Rounded distance. */
1766 /* The TrueType specification says very few about the relationship */
1767 /* between rounding and engine compensation. However, it seems from */
1768 /* the description of super round that we should add the compensation */
1769 /* before rounding. */
1772 Round_Super( EXEC_OP_ FT_F26Dot6 distance,
1773 FT_F26Dot6 compensation )
1778 if ( distance >= 0 )
1780 val = ( distance - CUR.phase + CUR.threshold + compensation ) &
1788 val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &
1799 /*************************************************************************/
1802 /* Round_Super_45 */
1805 /* Super-rounds value to grid after adding engine compensation. */
1808 /* distance :: The distance to round. */
1810 /* compensation :: The engine compensation. */
1813 /* Rounded distance. */
1816 /* There is a separate function for Round_Super_45() as we may need */
1817 /* greater precision. */
1820 Round_Super_45( EXEC_OP_ FT_F26Dot6 distance,
1821 FT_F26Dot6 compensation )
1826 if ( distance >= 0 )
1828 val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
1829 CUR.period ) * CUR.period;
1836 val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /
1837 CUR.period ) * CUR.period );
1847 /*************************************************************************/
1853 /* Sets the rounding mode. */
1856 /* round_mode :: The rounding mode to be used. */
1859 Compute_Round( EXEC_OP_ FT_Byte round_mode )
1861 switch ( round_mode )
1864 CUR.func_round = (TT_Round_Func)Round_None;
1867 case TT_Round_To_Grid:
1868 CUR.func_round = (TT_Round_Func)Round_To_Grid;
1871 case TT_Round_Up_To_Grid:
1872 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
1875 case TT_Round_Down_To_Grid:
1876 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
1879 case TT_Round_To_Half_Grid:
1880 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
1883 case TT_Round_To_Double_Grid:
1884 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
1887 case TT_Round_Super:
1888 CUR.func_round = (TT_Round_Func)Round_Super;
1891 case TT_Round_Super_45:
1892 CUR.func_round = (TT_Round_Func)Round_Super_45;
1898 /*************************************************************************/
1904 /* Sets Super Round parameters. */
1907 /* GridPeriod :: Grid period */
1908 /* selector :: SROUND opcode */
1911 SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod,
1914 switch ( (FT_Int)( selector & 0xC0 ) )
1917 CUR.period = GridPeriod / 2;
1921 CUR.period = GridPeriod;
1925 CUR.period = GridPeriod * 2;
1928 /* This opcode is reserved, but... */
1931 CUR.period = GridPeriod;
1935 switch ( (FT_Int)( selector & 0x30 ) )
1942 CUR.phase = CUR.period / 4;
1946 CUR.phase = CUR.period / 2;
1950 CUR.phase = GridPeriod * 3 / 4;
1954 if ( (selector & 0x0F) == 0 )
1955 CUR.threshold = CUR.period - 1;
1957 CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8;
1961 CUR.threshold /= 256;
1965 /*************************************************************************/
1971 /* Computes the projection of vector given by (v2-v1) along the */
1972 /* current projection vector. */
1975 /* v1 :: First input vector. */
1976 /* v2 :: Second input vector. */
1979 /* The distance in F26dot6 format. */
1982 Project( EXEC_OP_ FT_Vector* v1,
1985 return TT_MULDIV( v1->x - v2->x, CUR.GS.projVector.x, 0x4000 ) +
1986 TT_MULDIV( v1->y - v2->y, CUR.GS.projVector.y, 0x4000 );
1990 /*************************************************************************/
1996 /* Computes the projection of the vector given by (v2-v1) along the */
1997 /* current dual vector. */
2000 /* v1 :: First input vector. */
2001 /* v2 :: Second input vector. */
2004 /* The distance in F26dot6 format. */
2007 Dual_Project( EXEC_OP_ FT_Vector* v1,
2010 return TT_MULDIV( v1->x - v2->x, CUR.GS.dualVector.x, 0x4000 ) +
2011 TT_MULDIV( v1->y - v2->y, CUR.GS.dualVector.y, 0x4000 );
2015 /*************************************************************************/
2021 /* Computes the projection of the vector given by (v2-v1) along the */
2022 /* current freedom vector. */
2025 /* v1 :: First input vector. */
2026 /* v2 :: Second input vector. */
2029 /* The distance in F26dot6 format. */
2032 Free_Project( EXEC_OP_ FT_Vector* v1,
2035 return TT_MULDIV( v1->x - v2->x, CUR.GS.freeVector.x, 0x4000 ) +
2036 TT_MULDIV( v1->y - v2->y, CUR.GS.freeVector.y, 0x4000 );
2040 /*************************************************************************/
2046 /* Computes the projection of the vector given by (v2-v1) along the */
2047 /* horizontal axis. */
2050 /* v1 :: First input vector. */
2051 /* v2 :: Second input vector. */
2054 /* The distance in F26dot6 format. */
2057 Project_x( EXEC_OP_ FT_Vector* v1,
2062 return ( v1->x - v2->x );
2066 /*************************************************************************/
2072 /* Computes the projection of the vector given by (v2-v1) along the */
2073 /* vertical axis. */
2076 /* v1 :: First input vector. */
2077 /* v2 :: Second input vector. */
2080 /* The distance in F26dot6 format. */
2083 Project_y( EXEC_OP_ FT_Vector* v1,
2088 return ( v1->y - v2->y );
2092 /*************************************************************************/
2098 /* Computes the projection and movement function pointers according */
2099 /* to the current graphics state. */
2102 Compute_Funcs( EXEC_OP )
2104 if ( CUR.GS.freeVector.x == 0x4000 )
2106 CUR.func_freeProj = (TT_Project_Func)Project_x;
2107 CUR.F_dot_P = CUR.GS.projVector.x * 0x10000L;
2111 if ( CUR.GS.freeVector.y == 0x4000 )
2113 CUR.func_freeProj = (TT_Project_Func)Project_y;
2114 CUR.F_dot_P = CUR.GS.projVector.y * 0x10000L;
2118 CUR.func_freeProj = (TT_Project_Func)Free_Project;
2119 CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
2120 (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
2124 if ( CUR.GS.projVector.x == 0x4000 )
2125 CUR.func_project = (TT_Project_Func)Project_x;
2128 if ( CUR.GS.projVector.y == 0x4000 )
2129 CUR.func_project = (TT_Project_Func)Project_y;
2131 CUR.func_project = (TT_Project_Func)Project;
2134 if ( CUR.GS.dualVector.x == 0x4000 )
2135 CUR.func_dualproj = (TT_Project_Func)Project_x;
2138 if ( CUR.GS.dualVector.y == 0x4000 )
2139 CUR.func_dualproj = (TT_Project_Func)Project_y;
2141 CUR.func_dualproj = (TT_Project_Func)Dual_Project;
2144 CUR.func_move = (TT_Move_Func)Direct_Move;
2146 if ( CUR.F_dot_P == 0x40000000L )
2148 if ( CUR.GS.freeVector.x == 0x4000 )
2149 CUR.func_move = (TT_Move_Func)Direct_Move_X;
2152 if ( CUR.GS.freeVector.y == 0x4000 )
2153 CUR.func_move = (TT_Move_Func)Direct_Move_Y;
2157 /* at small sizes, F_dot_P can become too small, resulting */
2158 /* in overflows and `spikes' in a number of glyphs like `w'. */
2160 if ( ABS( CUR.F_dot_P ) < 0x4000000L )
2161 CUR.F_dot_P = 0x40000000L;
2163 /* Disable cached aspect ratio */
2164 CUR.tt_metrics.ratio = 0;
2168 /*************************************************************************/
2174 /* Norms a vector. */
2177 /* Vx :: The horizontal input vector coordinate. */
2178 /* Vy :: The vertical input vector coordinate. */
2181 /* R :: The normed unit vector. */
2184 /* Returns FAILURE if a vector parameter is zero. */
2187 /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
2188 /* R is undefined. */
2191 #ifdef FT_CONFIG_OPTION_OLD_CALCS
2194 Normalize( EXEC_OP_ FT_F26Dot6 Vx,
2204 if ( ABS( Vx ) < 0x10000L && ABS( Vy ) < 0x10000L )
2213 /* XXX: UNDOCUMENTED! It seems that it is possible to try */
2214 /* to normalize the vector (0,0). Return immediately. */
2218 R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W );
2219 R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W );
2226 Vx = FT_MulDiv( Vx, 0x4000L, W );
2227 Vy = FT_MulDiv( Vy, 0x4000L, W );
2229 W = Vx * Vx + Vy * Vy;
2231 /* Now, we want that Sqrt( W ) = 0x4000 */
2232 /* Or 0x1000000 <= W < 0x1004000 */
2250 while ( W < 0x1000000L )
2252 /* We need to increase W by a minimal amount */
2258 W = Vx * Vx + Vy * Vy;
2261 while ( W >= 0x1004000L )
2263 /* We need to decrease W by a minimal amount */
2269 W = Vx * Vx + Vy * Vy;
2272 /* Note that in various cases, we can only */
2273 /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
2281 R->x = (FT_F2Dot14)Vx; /* Type conversion */
2282 R->y = (FT_F2Dot14)Vy; /* Type conversion */
2290 Normalize( EXEC_OP_ FT_F26Dot6 Vx,
2299 angle = FT_Atan2( Vx, Vy );
2301 FT_Vector_Unit( &v, angle );
2303 R->x = (short)(v.x >> 2);
2304 R->y = (short)(v.y >> 2);
2309 #endif /* FT_CONFIG_OPTION_OLD_CALCS */
2312 /*************************************************************************/
2314 /* Here we start with the implementation of the various opcodes. */
2316 /*************************************************************************/
2320 Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1,
2323 FT_UnitVector* Vec )
2330 if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
2331 BOUNDS( aIdx2, CUR.zp1.n_points ) )
2333 if ( CUR.pedantic_hinting )
2334 CUR.error = TT_Err_Invalid_Reference;
2338 p1 = CUR.zp1.cur + aIdx2;
2339 p2 = CUR.zp2.cur + aIdx1;
2344 if ( ( aOpc & 1 ) != 0 )
2346 C = B; /* counter clockwise rotation */
2351 NORMalize( A, B, Vec );
2357 /* When not using the big switch statements, the interpreter uses a */
2358 /* call table defined later below in this source. Each opcode must */
2359 /* thus have a corresponding function, even trivial ones. */
2361 /* They are all defined there. */
2368 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2369 B = A ^ (FT_Short)0x4000; \
2371 CUR.GS.freeVector.x = A; \
2372 CUR.GS.projVector.x = A; \
2373 CUR.GS.dualVector.x = A; \
2375 CUR.GS.freeVector.y = B; \
2376 CUR.GS.projVector.y = B; \
2377 CUR.GS.dualVector.y = B; \
2388 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2389 B = A ^ (FT_Short)0x4000; \
2391 CUR.GS.projVector.x = A; \
2392 CUR.GS.dualVector.x = A; \
2394 CUR.GS.projVector.y = B; \
2395 CUR.GS.dualVector.y = B; \
2406 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2407 B = A ^ (FT_Short)0x4000; \
2409 CUR.GS.freeVector.x = A; \
2410 CUR.GS.freeVector.y = B; \
2417 if ( INS_SxVTL( (FT_UShort)args[1], \
2418 (FT_UShort)args[0], \
2420 &CUR.GS.projVector ) == SUCCESS ) \
2422 CUR.GS.dualVector = CUR.GS.projVector; \
2428 if ( INS_SxVTL( (FT_UShort)args[1], \
2429 (FT_UShort)args[0], \
2431 &CUR.GS.freeVector ) == SUCCESS ) \
2436 CUR.GS.freeVector = CUR.GS.projVector; \
2446 /* Only use low 16bits, then sign extend */ \
2447 S = (FT_Short)args[1]; \
2449 S = (FT_Short)args[0]; \
2452 NORMalize( X, Y, &CUR.GS.projVector ); \
2454 CUR.GS.dualVector = CUR.GS.projVector; \
2465 /* Only use low 16bits, then sign extend */ \
2466 S = (FT_Short)args[1]; \
2468 S = (FT_Short)args[0]; \
2471 NORMalize( X, Y, &CUR.GS.freeVector ); \
2477 args[0] = CUR.GS.projVector.x; \
2478 args[1] = CUR.GS.projVector.y;
2482 args[0] = CUR.GS.freeVector.x; \
2483 args[1] = CUR.GS.freeVector.y;
2487 CUR.GS.rp0 = (FT_UShort)args[0];
2491 CUR.GS.rp1 = (FT_UShort)args[0];
2495 CUR.GS.rp2 = (FT_UShort)args[0];
2499 CUR.GS.round_state = TT_Round_To_Half_Grid; \
2500 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2504 CUR.GS.round_state = TT_Round_To_Grid; \
2505 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2509 CUR.GS.round_state = TT_Round_To_Double_Grid; \
2510 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2514 CUR.GS.round_state = TT_Round_Up_To_Grid; \
2515 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2519 CUR.GS.round_state = TT_Round_Down_To_Grid; \
2520 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2524 CUR.GS.round_state = TT_Round_Off; \
2525 CUR.func_round = (TT_Round_Func)Round_None;
2529 SET_SuperRound( 0x4000, args[0] ); \
2530 CUR.GS.round_state = TT_Round_Super; \
2531 CUR.func_round = (TT_Round_Func)Round_Super;
2534 #define DO_S45ROUND \
2535 SET_SuperRound( 0x2D41, args[0] ); \
2536 CUR.GS.round_state = TT_Round_Super_45; \
2537 CUR.func_round = (TT_Round_Func)Round_Super_45;
2541 if ( args[0] < 0 ) \
2542 CUR.error = TT_Err_Bad_Argument; \
2544 CUR.GS.loop = args[0];
2548 CUR.GS.minimum_distance = args[0];
2552 CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
2556 CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
2559 /* XXX: UNDOCUMENTED! or bug in the Windows engine? */
2561 /* It seems that the value that is read here is */
2562 /* expressed in 16.16 format rather than in font */
2566 CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
2570 CUR.GS.auto_flip = TRUE;
2573 #define DO_FLIPOFF \
2574 CUR.GS.auto_flip = FALSE;
2578 CUR.GS.delta_base = (FT_Short)args[0];
2582 CUR.GS.delta_shift = (FT_Short)args[0];
2585 #define DO_MD /* nothing */
2589 args[0] = CURRENT_Ppem();
2592 /* Note: The pointSize should be irrelevant in a given font program; */
2593 /* we thus decide to return only the ppem. */
2597 args[0] = CUR.metrics.pointSize;
2602 args[0] = CURRENT_Ppem();
2621 args[0] = args[1]; \
2637 if ( L <= 0 || L > CUR.args ) \
2638 CUR.error = TT_Err_Invalid_Reference; \
2640 args[0] = CUR.stack[CUR.args - L]; \
2645 if ( args[1] != 0 ) \
2647 CUR.IP += args[0]; \
2648 CUR.step_ins = FALSE; \
2653 CUR.IP += args[0]; \
2654 CUR.step_ins = FALSE;
2658 if ( args[1] == 0 ) \
2660 CUR.IP += args[0]; \
2661 CUR.step_ins = FALSE; \
2666 args[0] = ( args[0] < args[1] );
2670 args[0] = ( args[0] <= args[1] );
2674 args[0] = ( args[0] > args[1] );
2678 args[0] = ( args[0] >= args[1] );
2682 args[0] = ( args[0] == args[1] );
2686 args[0] = ( args[0] != args[1] );
2690 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
2694 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
2698 args[0] = ( args[0] && args[1] );
2702 args[0] = ( args[0] || args[1] );
2718 if ( args[1] == 0 ) \
2719 CUR.error = TT_Err_Divide_By_Zero; \
2721 args[0] = TT_MULDIV( args[0], 64L, args[1] );
2725 args[0] = TT_MULDIV( args[0], args[1], 64L );
2729 args[0] = ABS( args[0] );
2740 #define DO_CEILING \
2741 args[0] = ( args[0] + 63 ) & -64;
2746 FT_ULong I = (FT_ULong)args[0]; \
2749 if ( BOUNDS( I, CUR.storeSize ) ) \
2751 if ( CUR.pedantic_hinting ) \
2753 ARRAY_BOUND_ERROR; \
2759 args[0] = CUR.storage[I]; \
2765 FT_ULong I = (FT_ULong)args[0]; \
2768 if ( BOUNDS( I, CUR.storeSize ) ) \
2770 if ( CUR.pedantic_hinting ) \
2772 ARRAY_BOUND_ERROR; \
2776 CUR.storage[I] = args[1]; \
2782 FT_ULong I = (FT_ULong)args[0]; \
2785 if ( BOUNDS( I, CUR.cvtSize ) ) \
2787 if ( CUR.pedantic_hinting ) \
2789 ARRAY_BOUND_ERROR; \
2795 args[0] = CUR_Func_read_cvt( I ); \
2801 FT_ULong I = (FT_ULong)args[0]; \
2804 if ( BOUNDS( I, CUR.cvtSize ) ) \
2806 if ( CUR.pedantic_hinting ) \
2808 ARRAY_BOUND_ERROR; \
2812 CUR_Func_write_cvt( I, args[1] ); \
2818 FT_ULong I = (FT_ULong)args[0]; \
2821 if ( BOUNDS( I, CUR.cvtSize ) ) \
2823 if ( CUR.pedantic_hinting ) \
2825 ARRAY_BOUND_ERROR; \
2829 CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
2834 CUR.error = TT_Err_Debug_OpCode;
2838 args[0] = CUR_Func_round( \
2840 CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
2844 args[0] = ROUND_None( args[0], \
2845 CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
2849 if ( args[1] > args[0] ) \
2854 if ( args[1] < args[0] ) \
2858 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
2861 #undef ARRAY_BOUND_ERROR
2862 #define ARRAY_BOUND_ERROR \
2864 CUR.error = TT_Err_Invalid_Reference; \
2869 /*************************************************************************/
2871 /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
2872 /* Opcode range: 0x00-0x01 */
2876 Ins_SVTCA( INS_ARG )
2882 /*************************************************************************/
2884 /* SPVTCA[a]: Set PVector to Coordinate Axis */
2885 /* Opcode range: 0x02-0x03 */
2889 Ins_SPVTCA( INS_ARG )
2895 /*************************************************************************/
2897 /* SFVTCA[a]: Set FVector to Coordinate Axis */
2898 /* Opcode range: 0x04-0x05 */
2902 Ins_SFVTCA( INS_ARG )
2908 /*************************************************************************/
2910 /* SPVTL[a]: Set PVector To Line */
2911 /* Opcode range: 0x06-0x07 */
2912 /* Stack: uint32 uint32 --> */
2915 Ins_SPVTL( INS_ARG )
2921 /*************************************************************************/
2923 /* SFVTL[a]: Set FVector To Line */
2924 /* Opcode range: 0x08-0x09 */
2925 /* Stack: uint32 uint32 --> */
2928 Ins_SFVTL( INS_ARG )
2934 /*************************************************************************/
2936 /* SFVTPV[]: Set FVector To PVector */
2937 /* Opcode range: 0x0E */
2941 Ins_SFVTPV( INS_ARG )
2947 /*************************************************************************/
2949 /* SPVFS[]: Set PVector From Stack */
2950 /* Opcode range: 0x0A */
2951 /* Stack: f2.14 f2.14 --> */
2954 Ins_SPVFS( INS_ARG )
2960 /*************************************************************************/
2962 /* SFVFS[]: Set FVector From Stack */
2963 /* Opcode range: 0x0B */
2964 /* Stack: f2.14 f2.14 --> */
2967 Ins_SFVFS( INS_ARG )
2973 /*************************************************************************/
2975 /* GPV[]: Get Projection Vector */
2976 /* Opcode range: 0x0C */
2977 /* Stack: ef2.14 --> ef2.14 */
2986 /*************************************************************************/
2987 /* GFV[]: Get Freedom Vector */
2988 /* Opcode range: 0x0D */
2989 /* Stack: ef2.14 --> ef2.14 */
2998 /*************************************************************************/
3000 /* SRP0[]: Set Reference Point 0 */
3001 /* Opcode range: 0x10 */
3002 /* Stack: uint32 --> */
3011 /*************************************************************************/
3013 /* SRP1[]: Set Reference Point 1 */
3014 /* Opcode range: 0x11 */
3015 /* Stack: uint32 --> */
3024 /*************************************************************************/
3026 /* SRP2[]: Set Reference Point 2 */
3027 /* Opcode range: 0x12 */
3028 /* Stack: uint32 --> */
3037 /*************************************************************************/
3039 /* RTHG[]: Round To Half Grid */
3040 /* Opcode range: 0x19 */
3050 /*************************************************************************/
3052 /* RTG[]: Round To Grid */
3053 /* Opcode range: 0x18 */
3063 /*************************************************************************/
3064 /* RTDG[]: Round To Double Grid */
3065 /* Opcode range: 0x3D */
3075 /*************************************************************************/
3076 /* RUTG[]: Round Up To Grid */
3077 /* Opcode range: 0x7C */
3087 /*************************************************************************/
3089 /* RDTG[]: Round Down To Grid */
3090 /* Opcode range: 0x7D */
3100 /*************************************************************************/
3102 /* ROFF[]: Round OFF */
3103 /* Opcode range: 0x7A */
3113 /*************************************************************************/
3115 /* SROUND[]: Super ROUND */
3116 /* Opcode range: 0x76 */
3117 /* Stack: Eint8 --> */
3120 Ins_SROUND( INS_ARG )
3126 /*************************************************************************/
3128 /* S45ROUND[]: Super ROUND 45 degrees */
3129 /* Opcode range: 0x77 */
3130 /* Stack: uint32 --> */
3133 Ins_S45ROUND( INS_ARG )
3139 /*************************************************************************/
3141 /* SLOOP[]: Set LOOP variable */
3142 /* Opcode range: 0x17 */
3143 /* Stack: int32? --> */
3146 Ins_SLOOP( INS_ARG )
3152 /*************************************************************************/
3154 /* SMD[]: Set Minimum Distance */
3155 /* Opcode range: 0x1A */
3156 /* Stack: f26.6 --> */
3165 /*************************************************************************/
3167 /* SCVTCI[]: Set Control Value Table Cut In */
3168 /* Opcode range: 0x1D */
3169 /* Stack: f26.6 --> */
3172 Ins_SCVTCI( INS_ARG )
3178 /*************************************************************************/
3180 /* SSWCI[]: Set Single Width Cut In */
3181 /* Opcode range: 0x1E */
3182 /* Stack: f26.6 --> */
3185 Ins_SSWCI( INS_ARG )
3191 /*************************************************************************/
3193 /* SSW[]: Set Single Width */
3194 /* Opcode range: 0x1F */
3195 /* Stack: int32? --> */
3204 /*************************************************************************/
3206 /* FLIPON[]: Set auto-FLIP to ON */
3207 /* Opcode range: 0x4D */
3211 Ins_FLIPON( INS_ARG )
3217 /*************************************************************************/
3219 /* FLIPOFF[]: Set auto-FLIP to OFF */
3220 /* Opcode range: 0x4E */
3224 Ins_FLIPOFF( INS_ARG )
3230 /*************************************************************************/
3232 /* SANGW[]: Set ANGle Weight */
3233 /* Opcode range: 0x7E */
3234 /* Stack: uint32 --> */
3237 Ins_SANGW( INS_ARG )
3239 /* instruction not supported anymore */
3243 /*************************************************************************/
3245 /* SDB[]: Set Delta Base */
3246 /* Opcode range: 0x5E */
3247 /* Stack: uint32 --> */
3256 /*************************************************************************/
3258 /* SDS[]: Set Delta Shift */
3259 /* Opcode range: 0x5F */
3260 /* Stack: uint32 --> */
3269 /*************************************************************************/
3271 /* MPPEM[]: Measure Pixel Per EM */
3272 /* Opcode range: 0x4B */
3273 /* Stack: --> Euint16 */
3276 Ins_MPPEM( INS_ARG )
3282 /*************************************************************************/
3284 /* MPS[]: Measure Point Size */
3285 /* Opcode range: 0x4C */
3286 /* Stack: --> Euint16 */
3295 /*************************************************************************/
3297 /* DUP[]: DUPlicate the top stack's element */
3298 /* Opcode range: 0x20 */
3299 /* Stack: StkElt --> StkElt StkElt */
3308 /*************************************************************************/
3310 /* POP[]: POP the stack's top element */
3311 /* Opcode range: 0x21 */
3312 /* Stack: StkElt --> */
3321 /*************************************************************************/
3323 /* CLEAR[]: CLEAR the entire stack */
3324 /* Opcode range: 0x22 */
3325 /* Stack: StkElt... --> */
3328 Ins_CLEAR( INS_ARG )
3334 /*************************************************************************/
3336 /* SWAP[]: SWAP the stack's top two elements */
3337 /* Opcode range: 0x23 */
3338 /* Stack: 2 * StkElt --> 2 * StkElt */
3347 /*************************************************************************/
3349 /* DEPTH[]: return the stack DEPTH */
3350 /* Opcode range: 0x24 */
3351 /* Stack: --> uint32 */
3354 Ins_DEPTH( INS_ARG )
3360 /*************************************************************************/
3362 /* CINDEX[]: Copy INDEXed element */
3363 /* Opcode range: 0x25 */
3364 /* Stack: int32 --> StkElt */
3367 Ins_CINDEX( INS_ARG )
3373 /*************************************************************************/
3376 /* Opcode range: 0x59 */
3386 /*************************************************************************/
3388 /* JROT[]: Jump Relative On True */
3389 /* Opcode range: 0x78 */
3390 /* Stack: StkElt int32 --> */
3399 /*************************************************************************/
3401 /* JMPR[]: JuMP Relative */
3402 /* Opcode range: 0x1C */
3403 /* Stack: int32 --> */
3412 /*************************************************************************/
3414 /* JROF[]: Jump Relative On False */
3415 /* Opcode range: 0x79 */
3416 /* Stack: StkElt int32 --> */
3425 /*************************************************************************/
3427 /* LT[]: Less Than */
3428 /* Opcode range: 0x50 */
3429 /* Stack: int32? int32? --> bool */
3438 /*************************************************************************/
3440 /* LTEQ[]: Less Than or EQual */
3441 /* Opcode range: 0x51 */
3442 /* Stack: int32? int32? --> bool */
3451 /*************************************************************************/
3453 /* GT[]: Greater Than */
3454 /* Opcode range: 0x52 */
3455 /* Stack: int32? int32? --> bool */
3464 /*************************************************************************/
3466 /* GTEQ[]: Greater Than or EQual */
3467 /* Opcode range: 0x53 */
3468 /* Stack: int32? int32? --> bool */
3477 /*************************************************************************/
3480 /* Opcode range: 0x54 */
3481 /* Stack: StkElt StkElt --> bool */
3490 /*************************************************************************/
3492 /* NEQ[]: Not EQual */
3493 /* Opcode range: 0x55 */
3494 /* Stack: StkElt StkElt --> bool */
3503 /*************************************************************************/
3506 /* Opcode range: 0x56 */
3507 /* Stack: f26.6 --> bool */
3516 /*************************************************************************/
3518 /* EVEN[]: Is EVEN */
3519 /* Opcode range: 0x57 */
3520 /* Stack: f26.6 --> bool */
3529 /*************************************************************************/
3531 /* AND[]: logical AND */
3532 /* Opcode range: 0x5A */
3533 /* Stack: uint32 uint32 --> uint32 */
3542 /*************************************************************************/
3544 /* OR[]: logical OR */
3545 /* Opcode range: 0x5B */
3546 /* Stack: uint32 uint32 --> uint32 */
3555 /*************************************************************************/
3557 /* NOT[]: logical NOT */
3558 /* Opcode range: 0x5C */
3559 /* Stack: StkElt --> uint32 */
3568 /*************************************************************************/
3571 /* Opcode range: 0x60 */
3572 /* Stack: f26.6 f26.6 --> f26.6 */
3581 /*************************************************************************/
3583 /* SUB[]: SUBtract */
3584 /* Opcode range: 0x61 */
3585 /* Stack: f26.6 f26.6 --> f26.6 */
3594 /*************************************************************************/
3597 /* Opcode range: 0x62 */
3598 /* Stack: f26.6 f26.6 --> f26.6 */
3607 /*************************************************************************/
3609 /* MUL[]: MULtiply */
3610 /* Opcode range: 0x63 */
3611 /* Stack: f26.6 f26.6 --> f26.6 */
3620 /*************************************************************************/
3622 /* ABS[]: ABSolute value */
3623 /* Opcode range: 0x64 */
3624 /* Stack: f26.6 --> f26.6 */
3633 /*************************************************************************/
3636 /* Opcode range: 0x65 */
3637 /* Stack: f26.6 --> f26.6 */
3646 /*************************************************************************/
3648 /* FLOOR[]: FLOOR */
3649 /* Opcode range: 0x66 */
3650 /* Stack: f26.6 --> f26.6 */
3653 Ins_FLOOR( INS_ARG )
3659 /*************************************************************************/
3661 /* CEILING[]: CEILING */
3662 /* Opcode range: 0x67 */
3663 /* Stack: f26.6 --> f26.6 */
3666 Ins_CEILING( INS_ARG )
3672 /*************************************************************************/
3674 /* RS[]: Read Store */
3675 /* Opcode range: 0x43 */
3676 /* Stack: uint32 --> uint32 */
3685 /*************************************************************************/
3687 /* WS[]: Write Store */
3688 /* Opcode range: 0x42 */
3689 /* Stack: uint32 uint32 --> */
3698 /*************************************************************************/
3700 /* WCVTP[]: Write CVT in Pixel units */
3701 /* Opcode range: 0x44 */
3702 /* Stack: f26.6 uint32 --> */
3705 Ins_WCVTP( INS_ARG )
3711 /*************************************************************************/
3713 /* WCVTF[]: Write CVT in Funits */
3714 /* Opcode range: 0x70 */
3715 /* Stack: uint32 uint32 --> */
3718 Ins_WCVTF( INS_ARG )
3724 /*************************************************************************/
3726 /* RCVT[]: Read CVT */
3727 /* Opcode range: 0x45 */
3728 /* Stack: uint32 --> f26.6 */
3737 /*************************************************************************/
3739 /* AA[]: Adjust Angle */
3740 /* Opcode range: 0x7F */
3741 /* Stack: uint32 --> */
3746 /* intentionally no longer supported */
3750 /*************************************************************************/
3752 /* DEBUG[]: DEBUG. Unsupported. */
3753 /* Opcode range: 0x4F */
3754 /* Stack: uint32 --> */
3756 /* Note: The original instruction pops a value from the stack. */
3759 Ins_DEBUG( INS_ARG )
3765 /*************************************************************************/
3767 /* ROUND[ab]: ROUND value */
3768 /* Opcode range: 0x68-0x6B */
3769 /* Stack: f26.6 --> f26.6 */
3772 Ins_ROUND( INS_ARG )
3778 /*************************************************************************/
3780 /* NROUND[ab]: No ROUNDing of value */
3781 /* Opcode range: 0x6C-0x6F */
3782 /* Stack: f26.6 --> f26.6 */
3785 Ins_NROUND( INS_ARG )
3791 /*************************************************************************/
3793 /* MAX[]: MAXimum */
3794 /* Opcode range: 0x68 */
3795 /* Stack: int32? int32? --> int32 */
3804 /*************************************************************************/
3806 /* MIN[]: MINimum */
3807 /* Opcode range: 0x69 */
3808 /* Stack: int32? int32? --> int32 */
3817 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
3820 /*************************************************************************/
3822 /* The following functions are called as is within the switch statement. */
3824 /*************************************************************************/
3827 /*************************************************************************/
3829 /* MINDEX[]: Move INDEXed element */
3830 /* Opcode range: 0x26 */
3831 /* Stack: int32? --> StkElt */
3834 Ins_MINDEX( INS_ARG )
3841 if ( L <= 0 || L > CUR.args )
3843 CUR.error = TT_Err_Invalid_Reference;
3847 K = CUR.stack[CUR.args - L];
3849 MEM_Move( &CUR.stack[CUR.args - L ],
3850 &CUR.stack[CUR.args - L + 1],
3851 ( L - 1 ) * sizeof ( FT_Long ) );
3853 CUR.stack[CUR.args - 1] = K;
3857 /*************************************************************************/
3859 /* ROLL[]: ROLL top three elements */
3860 /* Opcode range: 0x8A */
3861 /* Stack: 3 * StkElt --> 3 * StkElt */
3881 /*************************************************************************/
3883 /* MANAGING THE FLOW OF CONTROL */
3885 /* Instructions appear in the specification's order. */
3887 /*************************************************************************/
3893 CUR.IP += CUR.length;
3895 if ( CUR.IP < CUR.codeSize )
3897 CUR.opcode = CUR.code[CUR.IP];
3899 CUR.length = opcode_length[CUR.opcode];
3900 if ( CUR.length < 0 )
3902 if ( CUR.IP + 1 > CUR.codeSize )
3904 CUR.length = CUR.code[CUR.IP + 1] + 2;
3907 if ( CUR.IP + CUR.length <= CUR.codeSize )
3912 CUR.error = TT_Err_Code_Overflow;
3917 /*************************************************************************/
3920 /* Opcode range: 0x58 */
3921 /* Stack: StkElt --> */
3938 if ( SKIP_Code() == FAILURE )
3941 switch ( CUR.opcode )
3947 case 0x1B: /* ELSE */
3948 Out = FT_BOOL( nIfs == 1 );
3951 case 0x59: /* EIF */
3953 Out = FT_BOOL( nIfs == 0 );
3956 } while ( Out == 0 );
3960 /*************************************************************************/
3963 /* Opcode range: 0x1B */
3978 if ( SKIP_Code() == FAILURE )
3981 switch ( CUR.opcode )
3987 case 0x59: /* EIF */
3991 } while ( nIfs != 0 );
3995 /*************************************************************************/
3997 /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
3999 /* Instructions appear in the specification's order. */
4001 /*************************************************************************/
4004 /*************************************************************************/
4006 /* FDEF[]: Function DEFinition */
4007 /* Opcode range: 0x2C */
4008 /* Stack: uint32 --> */
4015 TT_DefRecord* limit;
4018 /* some font programs are broken enough to redefine functions! */
4019 /* We will then parse the current table. */
4022 limit = rec + CUR.numFDefs;
4025 for ( ; rec < limit; rec++ )
4027 if ( rec->opc == n )
4033 /* check that there is enough room for new functions */
4034 if ( CUR.numFDefs >= CUR.maxFDefs )
4036 CUR.error = TT_Err_Too_Many_Function_Defs;
4042 rec->range = CUR.curRange;
4044 rec->start = CUR.IP + 1;
4047 if ( n > CUR.maxFunc )
4050 /* Now skip the whole function definition. */
4051 /* We don't allow nested IDEFS & FDEFs. */
4053 while ( SKIP_Code() == SUCCESS )
4055 switch ( CUR.opcode )
4057 case 0x89: /* IDEF */
4058 case 0x2C: /* FDEF */
4059 CUR.error = TT_Err_Nested_DEFS;
4062 case 0x2D: /* ENDF */
4069 /*************************************************************************/
4071 /* ENDF[]: END Function definition */
4072 /* Opcode range: 0x2D */
4083 if ( CUR.callTop <= 0 ) /* We encountered an ENDF without a call */
4085 CUR.error = TT_Err_ENDF_In_Exec_Stream;
4091 pRec = &CUR.callStack[CUR.callTop];
4095 CUR.step_ins = FALSE;
4097 if ( pRec->Cur_Count > 0 )
4100 CUR.IP = pRec->Cur_Restart;
4103 /* Loop through the current function */
4104 INS_Goto_CodeRange( pRec->Caller_Range,
4107 /* Exit the current call frame. */
4109 /* NOTE: If the last intruction of a program is a */
4110 /* CALL or LOOPCALL, the return address is */
4111 /* always out of the code range. This is a */
4112 /* valid address, and it is why we do not test */
4113 /* the result of Ins_Goto_CodeRange() here! */
4117 /*************************************************************************/
4119 /* CALL[]: CALL function */
4120 /* Opcode range: 0x2B */
4121 /* Stack: uint32? --> */
4131 /* first of all, check the index */
4134 if ( BOUNDS( F, CUR.maxFunc + 1 ) )
4137 /* Except for some old Apple fonts, all functions in a TrueType */
4138 /* font are defined in increasing order, starting from 0. This */
4139 /* means that we normally have */
4141 /* CUR.maxFunc+1 == CUR.numFDefs */
4142 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4144 /* If this isn't true, we need to look up the function table. */
4146 def = CUR.FDefs + F;
4147 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
4149 /* look up the FDefs table */
4150 TT_DefRecord* limit;
4154 limit = def + CUR.numFDefs;
4156 while ( def < limit && def->opc != F )
4163 /* check that the function is active */
4167 /* check the call stack */
4168 if ( CUR.callTop >= CUR.callSize )
4170 CUR.error = TT_Err_Stack_Overflow;
4174 pCrec = CUR.callStack + CUR.callTop;
4176 pCrec->Caller_Range = CUR.curRange;
4177 pCrec->Caller_IP = CUR.IP + 1;
4178 pCrec->Cur_Count = 1;
4179 pCrec->Cur_Restart = def->start;
4183 INS_Goto_CodeRange( def->range,
4186 CUR.step_ins = FALSE;
4190 CUR.error = TT_Err_Invalid_Reference;
4194 /*************************************************************************/
4196 /* LOOPCALL[]: LOOP and CALL function */
4197 /* Opcode range: 0x2A */
4198 /* Stack: uint32? Eint16? --> */
4201 Ins_LOOPCALL( INS_ARG )
4208 /* first of all, check the index */
4210 if ( BOUNDS( F, CUR.maxFunc + 1 ) )
4213 /* Except for some old Apple fonts, all functions in a TrueType */
4214 /* font are defined in increasing order, starting from 0. This */
4215 /* means that we normally have */
4217 /* CUR.maxFunc+1 == CUR.numFDefs */
4218 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4220 /* If this isn't true, we need to look up the function table. */
4222 def = CUR.FDefs + F;
4223 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
4225 /* look up the FDefs table */
4226 TT_DefRecord* limit;
4230 limit = def + CUR.numFDefs;
4232 while ( def < limit && def->opc != F )
4239 /* check that the function is active */
4244 if ( CUR.callTop >= CUR.callSize )
4246 CUR.error = TT_Err_Stack_Overflow;
4252 pCrec = CUR.callStack + CUR.callTop;
4254 pCrec->Caller_Range = CUR.curRange;
4255 pCrec->Caller_IP = CUR.IP + 1;
4256 pCrec->Cur_Count = (FT_Int)args[0];
4257 pCrec->Cur_Restart = def->start;
4261 INS_Goto_CodeRange( def->range, def->start );
4263 CUR.step_ins = FALSE;
4268 CUR.error = TT_Err_Invalid_Reference;
4272 /*************************************************************************/
4274 /* IDEF[]: Instruction DEFinition */
4275 /* Opcode range: 0x89 */
4276 /* Stack: Eint8 --> */
4282 TT_DefRecord* limit;
4285 /* First of all, look for the same function in our table */
4288 limit = def + CUR.numIDefs;
4290 for ( ; def < limit; def++ )
4291 if ( def->opc == (FT_ULong)args[0] )
4296 /* check that there is enough room for a new instruction */
4297 if ( CUR.numIDefs >= CUR.maxIDefs )
4299 CUR.error = TT_Err_Too_Many_Instruction_Defs;
4306 def->start = CUR.IP+1;
4307 def->range = CUR.curRange;
4310 if ( (FT_ULong)args[0] > CUR.maxIns )
4311 CUR.maxIns = args[0];
4313 /* Now skip the whole function definition. */
4314 /* We don't allow nested IDEFs & FDEFs. */
4316 while ( SKIP_Code() == SUCCESS )
4318 switch ( CUR.opcode )
4320 case 0x89: /* IDEF */
4321 case 0x2C: /* FDEF */
4322 CUR.error = TT_Err_Nested_DEFS;
4324 case 0x2D: /* ENDF */
4331 /*************************************************************************/
4333 /* PUSHING DATA ONTO THE INTERPRETER STACK */
4335 /* Instructions appear in the specification's order. */
4337 /*************************************************************************/
4340 /*************************************************************************/
4342 /* NPUSHB[]: PUSH N Bytes */
4343 /* Opcode range: 0x40 */
4344 /* Stack: --> uint32... */
4347 Ins_NPUSHB( INS_ARG )
4352 L = (FT_UShort)CUR.code[CUR.IP + 1];
4354 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4356 CUR.error = TT_Err_Stack_Overflow;
4360 for ( K = 1; K <= L; K++ )
4361 args[K - 1] = CUR.code[CUR.IP + K + 1];
4367 /*************************************************************************/
4369 /* NPUSHW[]: PUSH N Words */
4370 /* Opcode range: 0x41 */
4371 /* Stack: --> int32... */
4374 Ins_NPUSHW( INS_ARG )
4379 L = (FT_UShort)CUR.code[CUR.IP + 1];
4381 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4383 CUR.error = TT_Err_Stack_Overflow;
4389 for ( K = 0; K < L; K++ )
4390 args[K] = GET_ShortIns();
4392 CUR.step_ins = FALSE;
4397 /*************************************************************************/
4399 /* PUSHB[abc]: PUSH Bytes */
4400 /* Opcode range: 0xB0-0xB7 */
4401 /* Stack: --> uint32... */
4404 Ins_PUSHB( INS_ARG )
4409 L = (FT_UShort)(CUR.opcode - 0xB0 + 1);
4411 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4413 CUR.error = TT_Err_Stack_Overflow;
4417 for ( K = 1; K <= L; K++ )
4418 args[K - 1] = CUR.code[CUR.IP + K];
4422 /*************************************************************************/
4424 /* PUSHW[abc]: PUSH Words */
4425 /* Opcode range: 0xB8-0xBF */
4426 /* Stack: --> int32... */
4429 Ins_PUSHW( INS_ARG )
4434 L = (FT_UShort)(CUR.opcode - 0xB8 + 1);
4436 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4438 CUR.error = TT_Err_Stack_Overflow;
4444 for ( K = 0; K < L; K++ )
4445 args[K] = GET_ShortIns();
4447 CUR.step_ins = FALSE;
4451 /*************************************************************************/
4453 /* MANAGING THE GRAPHICS STATE */
4455 /* Instructions appear in the specs' order. */
4457 /*************************************************************************/
4460 /*************************************************************************/
4462 /* GC[a]: Get Coordinate projected onto */
4463 /* Opcode range: 0x46-0x47 */
4464 /* Stack: uint32 --> f26.6 */
4466 /* BULLSHIT: Measures from the original glyph must be taken along the */
4467 /* dual projection vector! */
4476 L = (FT_ULong)args[0];
4478 if ( BOUNDS( L, CUR.zp2.n_points ) )
4480 if ( CUR.pedantic_hinting )
4482 CUR.error = TT_Err_Invalid_Reference;
4490 if ( CUR.opcode & 1 )
4491 R = CUR_Func_dualproj( CUR.zp2.org + L, NULL_Vector );
4493 R = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
4500 /*************************************************************************/
4502 /* SCFS[]: Set Coordinate From Stack */
4503 /* Opcode range: 0x48 */
4504 /* Stack: f26.6 uint32 --> */
4508 /* OA := OA + ( value - OA.p )/( f.p ) * f */
4517 L = (FT_UShort)args[0];
4519 if ( BOUNDS( L, CUR.zp2.n_points ) )
4521 if ( CUR.pedantic_hinting )
4522 CUR.error = TT_Err_Invalid_Reference;
4526 K = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
4528 CUR_Func_move( &CUR.zp2, L, args[1] - K );
4530 /* not part of the specs, but here for safety */
4532 if ( CUR.GS.gep2 == 0 )
4533 CUR.zp2.org[L] = CUR.zp2.cur[L];
4537 /*************************************************************************/
4539 /* MD[a]: Measure Distance */
4540 /* Opcode range: 0x49-0x4A */
4541 /* Stack: uint32 uint32 --> f26.6 */
4543 /* BULLSHIT: Measure taken in the original glyph must be along the dual */
4544 /* projection vector. */
4546 /* Second BULLSHIT: Flag attributes are inverted! */
4547 /* 0 => measure distance in original outline */
4548 /* 1 => measure distance in grid-fitted outline */
4550 /* Third one: `zp0 - zp1', and not `zp2 - zp1! */
4559 K = (FT_UShort)args[1];
4560 L = (FT_UShort)args[0];
4562 if( BOUNDS( L, CUR.zp0.n_points ) ||
4563 BOUNDS( K, CUR.zp1.n_points ) )
4565 if ( CUR.pedantic_hinting )
4567 CUR.error = TT_Err_Invalid_Reference;
4574 if ( CUR.opcode & 1 )
4575 D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
4577 D = CUR_Func_dualproj( CUR.zp0.org + L, CUR.zp1.org + K );
4584 /*************************************************************************/
4586 /* SDPVTL[a]: Set Dual PVector to Line */
4587 /* Opcode range: 0x86-0x87 */
4588 /* Stack: uint32 uint32 --> */
4591 Ins_SDPVTL( INS_ARG )
4594 FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
4597 p1 = (FT_UShort)args[1];
4598 p2 = (FT_UShort)args[0];
4600 if ( BOUNDS( p2, CUR.zp1.n_points ) ||
4601 BOUNDS( p1, CUR.zp2.n_points ) )
4603 if ( CUR.pedantic_hinting )
4604 CUR.error = TT_Err_Invalid_Reference;
4609 FT_Vector* v1 = CUR.zp1.org + p2;
4610 FT_Vector* v2 = CUR.zp2.org + p1;
4617 if ( ( CUR.opcode & 1 ) != 0 )
4619 C = B; /* counter clockwise rotation */
4624 NORMalize( A, B, &CUR.GS.dualVector );
4627 FT_Vector* v1 = CUR.zp1.cur + p2;
4628 FT_Vector* v2 = CUR.zp2.cur + p1;
4635 if ( ( CUR.opcode & 1 ) != 0 )
4637 C = B; /* counter clockwise rotation */
4642 NORMalize( A, B, &CUR.GS.projVector );
4648 /*************************************************************************/
4650 /* SZP0[]: Set Zone Pointer 0 */
4651 /* Opcode range: 0x13 */
4652 /* Stack: uint32 --> */
4657 switch ( (FT_Int)args[0] )
4660 CUR.zp0 = CUR.twilight;
4668 if ( CUR.pedantic_hinting )
4669 CUR.error = TT_Err_Invalid_Reference;
4673 CUR.GS.gep0 = (FT_UShort)args[0];
4677 /*************************************************************************/
4679 /* SZP1[]: Set Zone Pointer 1 */
4680 /* Opcode range: 0x14 */
4681 /* Stack: uint32 --> */
4686 switch ( (FT_Int)args[0] )
4689 CUR.zp1 = CUR.twilight;
4697 if ( CUR.pedantic_hinting )
4698 CUR.error = TT_Err_Invalid_Reference;
4702 CUR.GS.gep1 = (FT_UShort)args[0];
4706 /*************************************************************************/
4708 /* SZP2[]: Set Zone Pointer 2 */
4709 /* Opcode range: 0x15 */
4710 /* Stack: uint32 --> */
4715 switch ( (FT_Int)args[0] )
4718 CUR.zp2 = CUR.twilight;
4726 if ( CUR.pedantic_hinting )
4727 CUR.error = TT_Err_Invalid_Reference;
4731 CUR.GS.gep2 = (FT_UShort)args[0];
4735 /*************************************************************************/
4737 /* SZPS[]: Set Zone PointerS */
4738 /* Opcode range: 0x16 */
4739 /* Stack: uint32 --> */
4744 switch ( (FT_Int)args[0] )
4747 CUR.zp0 = CUR.twilight;
4755 if ( CUR.pedantic_hinting )
4756 CUR.error = TT_Err_Invalid_Reference;
4763 CUR.GS.gep0 = (FT_UShort)args[0];
4764 CUR.GS.gep1 = (FT_UShort)args[0];
4765 CUR.GS.gep2 = (FT_UShort)args[0];
4769 /*************************************************************************/
4771 /* INSTCTRL[]: INSTruction ConTRoL */
4772 /* Opcode range: 0x8e */
4773 /* Stack: int32 int32 --> */
4776 Ins_INSTCTRL( INS_ARG )
4784 if ( K < 1 || K > 2 )
4786 if ( CUR.pedantic_hinting )
4787 CUR.error = TT_Err_Invalid_Reference;
4794 CUR.GS.instruct_control = FT_BOOL(
4795 ( (FT_Byte)CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L );
4799 /*************************************************************************/
4801 /* SCANCTRL[]: SCAN ConTRoL */
4802 /* Opcode range: 0x85 */
4803 /* Stack: uint32? --> */
4806 Ins_SCANCTRL( INS_ARG )
4812 A = (FT_Int)( args[0] & 0xFF );
4816 CUR.GS.scan_control = TRUE;
4821 CUR.GS.scan_control = FALSE;
4828 if ( (args[0] & 0x100) != 0 && CUR.metrics.pointSize <= A )
4829 CUR.GS.scan_control = TRUE;
4832 if ( (args[0] & 0x200) != 0 && CUR.tt_metrics.rotated )
4833 CUR.GS.scan_control = TRUE;
4835 if ( (args[0] & 0x400) != 0 && CUR.tt_metrics.stretched )
4836 CUR.GS.scan_control = TRUE;
4839 if ( (args[0] & 0x800) != 0 && CUR.metrics.pointSize > A )
4840 CUR.GS.scan_control = FALSE;
4843 if ( (args[0] & 0x1000) != 0 && CUR.tt_metrics.rotated )
4844 CUR.GS.scan_control = FALSE;
4846 if ( (args[0] & 0x2000) != 0 && CUR.tt_metrics.stretched )
4847 CUR.GS.scan_control = FALSE;
4851 /*************************************************************************/
4853 /* SCANTYPE[]: SCAN TYPE */
4854 /* Opcode range: 0x8D */
4855 /* Stack: uint32? --> */
4858 Ins_SCANTYPE( INS_ARG )
4860 /* for compatibility with future enhancements, */
4861 /* we must ignore new modes */
4863 if ( args[0] >= 0 && args[0] <= 5 )
4868 CUR.GS.scan_type = (FT_Int)args[0];
4873 /*************************************************************************/
4875 /* MANAGING OUTLINES */
4877 /* Instructions appear in the specification's order. */
4879 /*************************************************************************/
4882 /*************************************************************************/
4884 /* FLIPPT[]: FLIP PoinT */
4885 /* Opcode range: 0x80 */
4886 /* Stack: uint32... --> */
4889 Ins_FLIPPT( INS_ARG )
4896 if ( CUR.top < CUR.GS.loop )
4898 CUR.error = TT_Err_Too_Few_Arguments;
4902 while ( CUR.GS.loop > 0 )
4906 point = (FT_UShort)CUR.stack[CUR.args];
4908 if ( BOUNDS( point, CUR.pts.n_points ) )
4910 if ( CUR.pedantic_hinting )
4912 CUR.error = TT_Err_Invalid_Reference;
4917 CUR.pts.tags[point] ^= FT_Curve_Tag_On;
4923 CUR.new_top = CUR.args;
4927 /*************************************************************************/
4929 /* FLIPRGON[]: FLIP RanGe ON */
4930 /* Opcode range: 0x81 */
4931 /* Stack: uint32 uint32 --> */
4934 Ins_FLIPRGON( INS_ARG )
4939 K = (FT_UShort)args[1];
4940 L = (FT_UShort)args[0];
4942 if ( BOUNDS( K, CUR.pts.n_points ) ||
4943 BOUNDS( L, CUR.pts.n_points ) )
4945 if ( CUR.pedantic_hinting )
4946 CUR.error = TT_Err_Invalid_Reference;
4950 for ( I = L; I <= K; I++ )
4951 CUR.pts.tags[I] |= FT_Curve_Tag_On;
4955 /*************************************************************************/
4957 /* FLIPRGOFF: FLIP RanGe OFF */
4958 /* Opcode range: 0x82 */
4959 /* Stack: uint32 uint32 --> */
4962 Ins_FLIPRGOFF( INS_ARG )
4967 K = (FT_UShort)args[1];
4968 L = (FT_UShort)args[0];
4970 if ( BOUNDS( K, CUR.pts.n_points ) ||
4971 BOUNDS( L, CUR.pts.n_points ) )
4973 if ( CUR.pedantic_hinting )
4974 CUR.error = TT_Err_Invalid_Reference;
4978 for ( I = L; I <= K; I++ )
4979 CUR.pts.tags[I] &= ~FT_Curve_Tag_On;
4984 Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6* x,
4994 if ( CUR.opcode & 1 )
5005 if ( BOUNDS( p, zp.n_points ) )
5007 if ( CUR.pedantic_hinting )
5008 CUR.error = TT_Err_Invalid_Reference;
5015 d = CUR_Func_project( zp.cur + p, zp.org + p );
5017 #ifdef NO_APPLE_PATENT
5019 *x = TT_MULDIV( d, CUR.GS.freeVector.x, 0x4000 );
5020 *y = TT_MULDIV( d, CUR.GS.freeVector.y, 0x4000 );
5025 (FT_Long)CUR.GS.freeVector.x * 0x10000L,
5028 (FT_Long)CUR.GS.freeVector.y * 0x10000L,
5031 #endif /* NO_APPLE_PATENT */
5038 Move_Zp2_Point( EXEC_OP_ FT_UShort point,
5043 if ( CUR.GS.freeVector.x != 0 )
5045 CUR.zp2.cur[point].x += dx;
5047 CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_X;
5050 if ( CUR.GS.freeVector.y != 0 )
5052 CUR.zp2.cur[point].y += dy;
5054 CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_Y;
5059 /*************************************************************************/
5061 /* SHP[a]: SHift Point by the last point */
5062 /* Opcode range: 0x32-0x33 */
5063 /* Stack: uint32... --> */
5078 if ( CUR.top < CUR.GS.loop )
5080 CUR.error = TT_Err_Invalid_Reference;
5084 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5087 while ( CUR.GS.loop > 0 )
5090 point = (FT_UShort)CUR.stack[CUR.args];
5092 if ( BOUNDS( point, CUR.zp2.n_points ) )
5094 if ( CUR.pedantic_hinting )
5096 CUR.error = TT_Err_Invalid_Reference;
5101 /* XXX: UNDOCUMENTED! SHP touches the points */
5102 MOVE_Zp2_Point( point, dx, dy, TRUE );
5108 CUR.new_top = CUR.args;
5112 /*************************************************************************/
5114 /* SHC[a]: SHift Contour */
5115 /* Opcode range: 0x34-35 */
5116 /* Stack: uint32 --> */
5127 FT_UShort first_point, last_point, i;
5130 contour = (FT_UShort)args[0];
5132 if ( BOUNDS( contour, CUR.pts.n_contours ) )
5134 if ( CUR.pedantic_hinting )
5135 CUR.error = TT_Err_Invalid_Reference;
5139 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5145 first_point = (FT_UShort)(CUR.pts.contours[contour - 1] + 1);
5147 last_point = CUR.pts.contours[contour];
5149 /* XXX: this is probably wrong... at least it prevents memory */
5150 /* corruption when zp2 is the twilight zone */
5151 if ( last_point > CUR.zp2.n_points )
5153 if ( CUR.zp2.n_points > 0 )
5154 last_point = (FT_UShort)(CUR.zp2.n_points - 1);
5159 /* XXX: UNDOCUMENTED! SHC doesn't touch the points */
5160 for ( i = first_point; i <= last_point; i++ )
5162 if ( zp.cur != CUR.zp2.cur || refp != i )
5163 MOVE_Zp2_Point( i, dx, dy, FALSE );
5168 /*************************************************************************/
5170 /* SHZ[a]: SHift Zone */
5171 /* Opcode range: 0x36-37 */
5172 /* Stack: uint32 --> */
5182 FT_UShort last_point, i;
5185 if ( BOUNDS( args[0], 2 ) )
5187 if ( CUR.pedantic_hinting )
5188 CUR.error = TT_Err_Invalid_Reference;
5192 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5195 if ( CUR.zp2.n_points > 0 )
5196 last_point = (FT_UShort)(CUR.zp2.n_points - 1);
5200 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
5201 for ( i = 0; i <= last_point; i++ )
5203 if ( zp.cur != CUR.zp2.cur || refp != i )
5204 MOVE_Zp2_Point( i, dx, dy, FALSE );
5209 /*************************************************************************/
5211 /* SHPIX[]: SHift points by a PIXel amount */
5212 /* Opcode range: 0x38 */
5213 /* Stack: f26.6 uint32... --> */
5216 Ins_SHPIX( INS_ARG )
5222 if ( CUR.top < CUR.GS.loop + 1 )
5224 CUR.error = TT_Err_Invalid_Reference;
5228 dx = TT_MULDIV( args[0],
5229 (FT_Long)CUR.GS.freeVector.x,
5231 dy = TT_MULDIV( args[0],
5232 (FT_Long)CUR.GS.freeVector.y,
5235 while ( CUR.GS.loop > 0 )
5239 point = (FT_UShort)CUR.stack[CUR.args];
5241 if ( BOUNDS( point, CUR.zp2.n_points ) )
5243 if ( CUR.pedantic_hinting )
5245 CUR.error = TT_Err_Invalid_Reference;
5250 MOVE_Zp2_Point( point, dx, dy, TRUE );
5256 CUR.new_top = CUR.args;
5260 /*************************************************************************/
5262 /* MSIRP[a]: Move Stack Indirect Relative Position */
5263 /* Opcode range: 0x3A-0x3B */
5264 /* Stack: f26.6 uint32 --> */
5267 Ins_MSIRP( INS_ARG )
5270 FT_F26Dot6 distance;
5273 point = (FT_UShort)args[0];
5275 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5276 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5278 if ( CUR.pedantic_hinting )
5279 CUR.error = TT_Err_Invalid_Reference;
5283 /* XXX: UNDOCUMENTED! behaviour */
5284 if ( CUR.GS.gep0 == 0 ) /* if in twilight zone */
5286 CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
5287 CUR.zp1.cur[point] = CUR.zp1.org[point];
5290 distance = CUR_Func_project( CUR.zp1.cur + point,
5291 CUR.zp0.cur + CUR.GS.rp0 );
5293 CUR_Func_move( &CUR.zp1, point, args[1] - distance );
5295 CUR.GS.rp1 = CUR.GS.rp0;
5298 if ( (CUR.opcode & 1) != 0 )
5303 /*************************************************************************/
5305 /* MDAP[a]: Move Direct Absolute Point */
5306 /* Opcode range: 0x2E-0x2F */
5307 /* Stack: uint32 --> */
5313 FT_F26Dot6 cur_dist,
5317 point = (FT_UShort)args[0];
5319 if ( BOUNDS( point, CUR.zp0.n_points ) )
5321 if ( CUR.pedantic_hinting )
5322 CUR.error = TT_Err_Invalid_Reference;
5326 /* XXX: Is there some undocumented feature while in the */
5327 /* twilight zone? ? */
5328 if ( ( CUR.opcode & 1 ) != 0 )
5330 cur_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
5331 distance = CUR_Func_round( cur_dist,
5332 CUR.tt_metrics.compensations[0] ) - cur_dist;
5337 CUR_Func_move( &CUR.zp0, point, distance );
5344 /*************************************************************************/
5346 /* MIAP[a]: Move Indirect Absolute Point */
5347 /* Opcode range: 0x3E-0x3F */
5348 /* Stack: uint32 uint32 --> */
5355 FT_F26Dot6 distance,
5359 cvtEntry = (FT_ULong)args[1];
5360 point = (FT_UShort)args[0];
5362 if ( BOUNDS( point, CUR.zp0.n_points ) ||
5363 BOUNDS( cvtEntry, CUR.cvtSize ) )
5365 if ( CUR.pedantic_hinting )
5366 CUR.error = TT_Err_Invalid_Reference;
5372 /* The behaviour of an MIAP instruction is quite */
5373 /* different when used in the twilight zone. */
5375 /* First, no control value cutin test is performed */
5376 /* as it would fail anyway. Second, the original */
5377 /* point, i.e. (org_x,org_y) of zp0.point, is set */
5378 /* to the absolute, unrounded distance found in */
5381 /* This is used in the CVT programs of the Microsoft */
5382 /* fonts Arial, Times, etc., in order to re-adjust */
5383 /* some key font heights. It allows the use of the */
5384 /* IP instruction in the twilight zone, which */
5385 /* otherwise would be `illegal' according to the */
5386 /* specification. */
5388 /* We implement it with a special sequence for the */
5389 /* twilight zone. This is a bad hack, but it seems */
5392 distance = CUR_Func_read_cvt( cvtEntry );
5394 if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */
5396 CUR.zp0.org[point].x = TT_MULDIV( CUR.GS.freeVector.x,
5398 CUR.zp0.org[point].y = TT_MULDIV( CUR.GS.freeVector.y,
5400 CUR.zp0.cur[point] = CUR.zp0.org[point];
5403 org_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
5405 if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */
5407 if ( ABS( distance - org_dist ) > CUR.GS.control_value_cutin )
5408 distance = org_dist;
5410 distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] );
5413 CUR_Func_move( &CUR.zp0, point, distance - org_dist );
5420 /*************************************************************************/
5422 /* MDRP[abcde]: Move Direct Relative Point */
5423 /* Opcode range: 0xC0-0xDF */
5424 /* Stack: uint32 --> */
5430 FT_F26Dot6 org_dist, distance;
5433 point = (FT_UShort)args[0];
5435 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5436 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5438 if ( CUR.pedantic_hinting )
5439 CUR.error = TT_Err_Invalid_Reference;
5443 /* XXX: Is there some undocumented feature while in the */
5444 /* twilight zone? */
5446 org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
5447 CUR.zp0.org + CUR.GS.rp0 );
5449 /* single width cutin test */
5451 if ( ABS( org_dist ) < CUR.GS.single_width_cutin )
5453 if ( org_dist >= 0 )
5454 org_dist = CUR.GS.single_width_value;
5456 org_dist = -CUR.GS.single_width_value;
5461 if ( ( CUR.opcode & 4 ) != 0 )
5462 distance = CUR_Func_round(
5464 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5466 distance = ROUND_None(
5468 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5470 /* minimum distance flag */
5472 if ( ( CUR.opcode & 8 ) != 0 )
5474 if ( org_dist >= 0 )
5476 if ( distance < CUR.GS.minimum_distance )
5477 distance = CUR.GS.minimum_distance;
5481 if ( distance > -CUR.GS.minimum_distance )
5482 distance = -CUR.GS.minimum_distance;
5486 /* now move the point */
5488 org_dist = CUR_Func_project( CUR.zp1.cur + point,
5489 CUR.zp0.cur + CUR.GS.rp0 );
5491 CUR_Func_move( &CUR.zp1, point, distance - org_dist );
5493 CUR.GS.rp1 = CUR.GS.rp0;
5496 if ( ( CUR.opcode & 16 ) != 0 )
5501 /*************************************************************************/
5503 /* MIRP[abcde]: Move Indirect Relative Point */
5504 /* Opcode range: 0xE0-0xFF */
5505 /* Stack: int32? uint32 --> */
5513 FT_F26Dot6 cvt_dist,
5519 point = (FT_UShort)args[0];
5520 cvtEntry = (FT_ULong)( args[1] + 1 );
5522 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
5524 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5525 BOUNDS( cvtEntry, CUR.cvtSize + 1 ) ||
5526 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5528 if ( CUR.pedantic_hinting )
5529 CUR.error = TT_Err_Invalid_Reference;
5536 cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
5538 /* single width test */
5540 if ( ABS( cvt_dist ) < CUR.GS.single_width_cutin )
5542 if ( cvt_dist >= 0 )
5543 cvt_dist = CUR.GS.single_width_value;
5545 cvt_dist = -CUR.GS.single_width_value;
5548 /* XXX: UNDOCUMENTED! -- twilight zone */
5550 if ( CUR.GS.gep1 == 0 )
5552 CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +
5553 TT_MULDIV( cvt_dist,
5554 CUR.GS.freeVector.x,
5557 CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
5558 TT_MULDIV( cvt_dist,
5559 CUR.GS.freeVector.y,
5562 CUR.zp1.cur[point] = CUR.zp1.org[point];
5565 org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
5566 CUR.zp0.org + CUR.GS.rp0 );
5568 cur_dist = CUR_Func_project( CUR.zp1.cur + point,
5569 CUR.zp0.cur + CUR.GS.rp0 );
5571 /* auto-flip test */
5573 if ( CUR.GS.auto_flip )
5575 if ( ( org_dist ^ cvt_dist ) < 0 )
5576 cvt_dist = -cvt_dist;
5579 /* control value cutin and round */
5581 if ( ( CUR.opcode & 4 ) != 0 )
5583 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
5584 /* refer to the same zone. */
5586 if ( CUR.GS.gep0 == CUR.GS.gep1 )
5587 if ( ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin )
5588 cvt_dist = org_dist;
5590 distance = CUR_Func_round(
5592 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5595 distance = ROUND_None(
5597 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5599 /* minimum distance test */
5601 if ( ( CUR.opcode & 8 ) != 0 )
5603 if ( org_dist >= 0 )
5605 if ( distance < CUR.GS.minimum_distance )
5606 distance = CUR.GS.minimum_distance;
5610 if ( distance > -CUR.GS.minimum_distance )
5611 distance = -CUR.GS.minimum_distance;
5615 CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
5617 CUR.GS.rp1 = CUR.GS.rp0;
5619 if ( ( CUR.opcode & 16 ) != 0 )
5622 /* XXX: UNDOCUMENTED! */
5628 /*************************************************************************/
5630 /* ALIGNRP[]: ALIGN Relative Point */
5631 /* Opcode range: 0x3C */
5632 /* Stack: uint32 uint32... --> */
5635 Ins_ALIGNRP( INS_ARG )
5638 FT_F26Dot6 distance;
5643 if ( CUR.top < CUR.GS.loop ||
5644 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5646 if ( CUR.pedantic_hinting )
5647 CUR.error = TT_Err_Invalid_Reference;
5651 while ( CUR.GS.loop > 0 )
5655 point = (FT_UShort)CUR.stack[CUR.args];
5657 if ( BOUNDS( point, CUR.zp1.n_points ) )
5659 if ( CUR.pedantic_hinting )
5661 CUR.error = TT_Err_Invalid_Reference;
5667 distance = CUR_Func_project( CUR.zp1.cur + point,
5668 CUR.zp0.cur + CUR.GS.rp0 );
5670 CUR_Func_move( &CUR.zp1, point, -distance );
5677 CUR.new_top = CUR.args;
5681 /*************************************************************************/
5683 /* ISECT[]: moves point to InterSECTion */
5684 /* Opcode range: 0x0F */
5685 /* Stack: 5 * uint32 --> */
5688 Ins_ISECT( INS_ARG )
5694 FT_F26Dot6 discriminant;
5705 point = (FT_UShort)args[0];
5707 a0 = (FT_UShort)args[1];
5708 a1 = (FT_UShort)args[2];
5709 b0 = (FT_UShort)args[3];
5710 b1 = (FT_UShort)args[4];
5712 if ( BOUNDS( b0, CUR.zp0.n_points ) ||
5713 BOUNDS( b1, CUR.zp0.n_points ) ||
5714 BOUNDS( a0, CUR.zp1.n_points ) ||
5715 BOUNDS( a1, CUR.zp1.n_points ) ||
5716 BOUNDS( point, CUR.zp2.n_points ) )
5718 if ( CUR.pedantic_hinting )
5719 CUR.error = TT_Err_Invalid_Reference;
5723 dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
5724 dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
5726 dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;
5727 day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;
5729 dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;
5730 dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;
5732 CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_Both;
5734 discriminant = TT_MULDIV( dax, -dby, 0x40 ) +
5735 TT_MULDIV( day, dbx, 0x40 );
5737 if ( ABS( discriminant ) >= 0x40 )
5739 val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 );
5741 R.x = TT_MULDIV( val, dax, discriminant );
5742 R.y = TT_MULDIV( val, day, discriminant );
5744 CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
5745 CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
5749 /* else, take the middle of the middles of A and B */
5751 CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +
5754 CUR.zp0.cur[b1].x ) / 4;
5755 CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +
5758 CUR.zp0.cur[b1].y ) / 4;
5763 /*************************************************************************/
5765 /* ALIGNPTS[]: ALIGN PoinTS */
5766 /* Opcode range: 0x27 */
5767 /* Stack: uint32 uint32 --> */
5770 Ins_ALIGNPTS( INS_ARG )
5773 FT_F26Dot6 distance;
5776 p1 = (FT_UShort)args[0];
5777 p2 = (FT_UShort)args[1];
5779 if ( BOUNDS( args[0], CUR.zp1.n_points ) ||
5780 BOUNDS( args[1], CUR.zp0.n_points ) )
5782 if ( CUR.pedantic_hinting )
5783 CUR.error = TT_Err_Invalid_Reference;
5787 distance = CUR_Func_project( CUR.zp0.cur + p2,
5788 CUR.zp1.cur + p1 ) / 2;
5790 CUR_Func_move( &CUR.zp1, p1, distance );
5791 CUR_Func_move( &CUR.zp0, p2, -distance );
5795 /*************************************************************************/
5797 /* IP[]: Interpolate Point */
5798 /* Opcode range: 0x39 */
5799 /* Stack: uint32... --> */
5804 FT_F26Dot6 org_a, org_b, org_x,
5805 cur_a, cur_b, cur_x,
5812 if ( CUR.top < CUR.GS.loop )
5814 CUR.error = TT_Err_Invalid_Reference;
5818 /* XXX: There are some glyphs in some braindead but popular */
5819 /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
5820 /* calling IP[] with bad values of rp[12]. */
5821 /* Do something sane when this odd thing happens. */
5823 if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
5824 BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
5831 org_a = CUR_Func_dualproj( CUR.zp0.org + CUR.GS.rp1, NULL_Vector );
5832 org_b = CUR_Func_dualproj( CUR.zp1.org + CUR.GS.rp2, NULL_Vector );
5834 cur_a = CUR_Func_project( CUR.zp0.cur + CUR.GS.rp1, NULL_Vector );
5835 cur_b = CUR_Func_project( CUR.zp1.cur + CUR.GS.rp2, NULL_Vector );
5838 while ( CUR.GS.loop > 0 )
5842 point = (FT_UShort)CUR.stack[CUR.args];
5843 if ( BOUNDS( point, CUR.zp2.n_points ) )
5845 if ( CUR.pedantic_hinting )
5847 CUR.error = TT_Err_Invalid_Reference;
5853 org_x = CUR_Func_dualproj( CUR.zp2.org + point, NULL_Vector );
5854 cur_x = CUR_Func_project ( CUR.zp2.cur + point, NULL_Vector );
5856 if ( ( org_a <= org_b && org_x <= org_a ) ||
5857 ( org_a > org_b && org_x >= org_a ) )
5859 distance = ( cur_a - org_a ) + ( org_x - cur_x );
5861 else if ( ( org_a <= org_b && org_x >= org_b ) ||
5862 ( org_a > org_b && org_x < org_b ) )
5864 distance = ( cur_b - org_b ) + ( org_x - cur_x );
5867 /* note: it seems that rounding this value isn't a good */
5868 /* idea (cf. width of capital `S' in Times) */
5870 distance = TT_MULDIV( cur_b - cur_a,
5872 org_b - org_a ) + ( cur_a - cur_x );
5874 CUR_Func_move( &CUR.zp2, point, distance );
5881 CUR.new_top = CUR.args;
5885 /*************************************************************************/
5887 /* UTP[a]: UnTouch Point */
5888 /* Opcode range: 0x29 */
5889 /* Stack: uint32 --> */
5898 point = (FT_UShort)args[0];
5900 if ( BOUNDS( point, CUR.zp0.n_points ) )
5902 if ( CUR.pedantic_hinting )
5903 CUR.error = TT_Err_Invalid_Reference;
5909 if ( CUR.GS.freeVector.x != 0 )
5910 mask &= ~FT_Curve_Tag_Touch_X;
5912 if ( CUR.GS.freeVector.y != 0 )
5913 mask &= ~FT_Curve_Tag_Touch_Y;
5915 CUR.zp0.tags[point] &= mask;
5919 /* Local variables for Ins_IUP: */
5922 FT_Vector* orgs; /* original and current coordinate */
5923 FT_Vector* curs; /* arrays */
5931 struct LOC_Ins_IUP* LINK )
5937 x = LINK->curs[p].x - LINK->orgs[p].x;
5939 for ( i = p1; i < p; i++ )
5940 LINK->curs[i].x += x;
5942 for ( i = p + 1; i <= p2; i++ )
5943 LINK->curs[i].x += x;
5952 struct LOC_Ins_IUP* LINK )
5955 FT_F26Dot6 x, x1, x2, d1, d2;
5961 x1 = LINK->orgs[ref1].x;
5962 d1 = LINK->curs[ref1].x - LINK->orgs[ref1].x;
5963 x2 = LINK->orgs[ref2].x;
5964 d2 = LINK->curs[ref2].x - LINK->orgs[ref2].x;
5968 for ( i = p1; i <= p2; i++ )
5970 x = LINK->orgs[i].x;
5977 LINK->curs[i].x = x;
5984 for ( i = p1; i <= p2; i++ )
5986 x = LINK->orgs[i].x;
5995 x = LINK->curs[ref1].x +
5997 LINK->curs[ref2].x - LINK->curs[ref1].x,
6000 LINK->curs[i].x = x;
6007 for ( i = p1; i <= p2; i++ )
6009 x = LINK->orgs[i].x;
6017 x = LINK->curs[ref1].x +
6019 LINK->curs[ref2].x - LINK->curs[ref1].x,
6022 LINK->curs[i].x = x;
6027 /*************************************************************************/
6029 /* IUP[a]: Interpolate Untouched Points */
6030 /* Opcode range: 0x30-0x31 */
6036 struct LOC_Ins_IUP V;
6039 FT_UInt first_point; /* first point of contour */
6040 FT_UInt end_point; /* end point (last+1) of contour */
6042 FT_UInt first_touched; /* first touched point in contour */
6043 FT_UInt cur_touched; /* current touched point in contour */
6045 FT_UInt point; /* current point */
6046 FT_Short contour; /* current contour */
6051 if ( CUR.opcode & 1 )
6053 mask = FT_Curve_Tag_Touch_X;
6054 V.orgs = CUR.pts.org;
6055 V.curs = CUR.pts.cur;
6059 mask = FT_Curve_Tag_Touch_Y;
6060 V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
6061 V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
6069 end_point = CUR.pts.contours[contour];
6070 first_point = point;
6072 while ( point <= end_point && (CUR.pts.tags[point] & mask) == 0 )
6075 if ( point <= end_point )
6077 first_touched = point;
6078 cur_touched = point;
6082 while ( point <= end_point )
6084 if ( ( CUR.pts.tags[point] & mask ) != 0 )
6087 Interp( cur_touched + 1,
6092 cur_touched = point;
6098 if ( cur_touched == first_touched )
6099 Shift( first_point, end_point, cur_touched, &V );
6102 Interp( (FT_UShort)( cur_touched + 1 ),
6108 if ( first_touched > 0 )
6109 Interp( first_point,
6117 } while ( contour < CUR.pts.n_contours );
6121 /*************************************************************************/
6123 /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
6124 /* Opcode range: 0x5D,0x71,0x72 */
6125 /* Stack: uint32 (2 * uint32)... --> */
6128 Ins_DELTAP( INS_ARG )
6136 nump = (FT_ULong)args[0]; /* some points theoretically may occur more
6137 than once, thus UShort isn't enough */
6139 for ( k = 1; k <= nump; k++ )
6143 CUR.error = TT_Err_Too_Few_Arguments;
6149 A = (FT_UShort)CUR.stack[CUR.args + 1];
6150 B = CUR.stack[CUR.args];
6152 /* XXX: Because some popular fonts contain some invalid DeltaP */
6153 /* instructions, we simply ignore them when the stacked */
6154 /* point reference is off limit, rather than returning an */
6155 /* error. As a delta instruction doesn't change a glyph */
6156 /* in great ways, this shouldn't be a problem. */
6158 if ( !BOUNDS( A, CUR.zp0.n_points ) )
6160 C = ( (FT_ULong)B & 0xF0 ) >> 4;
6162 switch ( CUR.opcode )
6176 C += CUR.GS.delta_base;
6178 if ( CURRENT_Ppem() == (FT_Long)C )
6180 B = ( (FT_ULong)B & 0xF ) - 8;
6183 B = B * 64 / ( 1L << CUR.GS.delta_shift );
6185 CUR_Func_move( &CUR.zp0, A, B );
6189 if ( CUR.pedantic_hinting )
6190 CUR.error = TT_Err_Invalid_Reference;
6193 CUR.new_top = CUR.args;
6197 /*************************************************************************/
6199 /* DELTACn[]: DELTA exceptions C1, C2, C3 */
6200 /* Opcode range: 0x73,0x74,0x75 */
6201 /* Stack: uint32 (2 * uint32)... --> */
6204 Ins_DELTAC( INS_ARG )
6211 nump = (FT_ULong)args[0];
6213 for ( k = 1; k <= nump; k++ )
6217 CUR.error = TT_Err_Too_Few_Arguments;
6223 A = (FT_ULong)CUR.stack[CUR.args + 1];
6224 B = CUR.stack[CUR.args];
6226 if ( BOUNDS( A, CUR.cvtSize ) )
6228 if ( CUR.pedantic_hinting )
6230 CUR.error = TT_Err_Invalid_Reference;
6236 C = ( (FT_ULong)B & 0xF0 ) >> 4;
6238 switch ( CUR.opcode )
6252 C += CUR.GS.delta_base;
6254 if ( CURRENT_Ppem() == (FT_Long)C )
6256 B = ( (FT_ULong)B & 0xF ) - 8;
6259 B = B * 64 / ( 1L << CUR.GS.delta_shift );
6261 CUR_Func_move_cvt( A, B );
6266 CUR.new_top = CUR.args;
6270 /*************************************************************************/
6272 /* MISC. INSTRUCTIONS */
6274 /*************************************************************************/
6277 /*************************************************************************/
6279 /* GETINFO[]: GET INFOrmation */
6280 /* Opcode range: 0x88 */
6281 /* Stack: uint32 --> uint32 */
6283 /* XXX: According to Apple specs, bits 1 & 2 of the argument ought to be */
6284 /* consulted before rotated/stretched info is returned. */
6286 Ins_GETINFO( INS_ARG )
6293 /* We return then Windows 3.1 version number */
6294 /* for the font scaler */
6295 if ( ( args[0] & 1 ) != 0 )
6298 /* Has the glyph been rotated ? */
6299 if ( CUR.tt_metrics.rotated )
6302 /* Has the glyph been stretched ? */
6303 if ( CUR.tt_metrics.stretched )
6311 Ins_UNKNOWN( INS_ARG )
6313 TT_DefRecord* def = CUR.IDefs;
6314 TT_DefRecord* limit = def + CUR.numIDefs;
6319 for ( ; def < limit; def++ )
6321 if ( (FT_Byte)def->opc == CUR.opcode && def->active )
6326 if ( CUR.callTop >= CUR.callSize )
6328 CUR.error = TT_Err_Stack_Overflow;
6332 call = CUR.callStack + CUR.callTop++;
6334 call->Caller_Range = CUR.curRange;
6335 call->Caller_IP = CUR.IP+1;
6336 call->Cur_Count = 1;
6337 call->Cur_Restart = def->start;
6339 INS_Goto_CodeRange( def->range, def->start );
6341 CUR.step_ins = FALSE;
6346 CUR.error = TT_Err_Invalid_Opcode;
6350 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
6354 TInstruction_Function Instruct_Dispatch[256] =
6356 /* Opcodes are gathered in groups of 16. */
6357 /* Please keep the spaces as they are. */
6359 /* SVTCA y */ Ins_SVTCA,
6360 /* SVTCA x */ Ins_SVTCA,
6361 /* SPvTCA y */ Ins_SPVTCA,
6362 /* SPvTCA x */ Ins_SPVTCA,
6363 /* SFvTCA y */ Ins_SFVTCA,
6364 /* SFvTCA x */ Ins_SFVTCA,
6365 /* SPvTL // */ Ins_SPVTL,
6366 /* SPvTL + */ Ins_SPVTL,
6367 /* SFvTL // */ Ins_SFVTL,
6368 /* SFvTL + */ Ins_SFVTL,
6369 /* SPvFS */ Ins_SPVFS,
6370 /* SFvFS */ Ins_SFVFS,
6373 /* SFvTPv */ Ins_SFVTPV,
6374 /* ISECT */ Ins_ISECT,
6376 /* SRP0 */ Ins_SRP0,
6377 /* SRP1 */ Ins_SRP1,
6378 /* SRP2 */ Ins_SRP2,
6379 /* SZP0 */ Ins_SZP0,
6380 /* SZP1 */ Ins_SZP1,
6381 /* SZP2 */ Ins_SZP2,
6382 /* SZPS */ Ins_SZPS,
6383 /* SLOOP */ Ins_SLOOP,
6385 /* RTHG */ Ins_RTHG,
6387 /* ELSE */ Ins_ELSE,
6388 /* JMPR */ Ins_JMPR,
6389 /* SCvTCi */ Ins_SCVTCI,
6390 /* SSwCi */ Ins_SSWCI,
6395 /* CLEAR */ Ins_CLEAR,
6396 /* SWAP */ Ins_SWAP,
6397 /* DEPTH */ Ins_DEPTH,
6398 /* CINDEX */ Ins_CINDEX,
6399 /* MINDEX */ Ins_MINDEX,
6400 /* AlignPTS */ Ins_ALIGNPTS,
6401 /* INS_0x28 */ Ins_UNKNOWN,
6403 /* LOOPCALL */ Ins_LOOPCALL,
6404 /* CALL */ Ins_CALL,
6405 /* FDEF */ Ins_FDEF,
6406 /* ENDF */ Ins_ENDF,
6407 /* MDAP[0] */ Ins_MDAP,
6408 /* MDAP[1] */ Ins_MDAP,
6410 /* IUP[0] */ Ins_IUP,
6411 /* IUP[1] */ Ins_IUP,
6412 /* SHP[0] */ Ins_SHP,
6413 /* SHP[1] */ Ins_SHP,
6414 /* SHC[0] */ Ins_SHC,
6415 /* SHC[1] */ Ins_SHC,
6416 /* SHZ[0] */ Ins_SHZ,
6417 /* SHZ[1] */ Ins_SHZ,
6418 /* SHPIX */ Ins_SHPIX,
6420 /* MSIRP[0] */ Ins_MSIRP,
6421 /* MSIRP[1] */ Ins_MSIRP,
6422 /* AlignRP */ Ins_ALIGNRP,
6423 /* RTDG */ Ins_RTDG,
6424 /* MIAP[0] */ Ins_MIAP,
6425 /* MIAP[1] */ Ins_MIAP,
6427 /* NPushB */ Ins_NPUSHB,
6428 /* NPushW */ Ins_NPUSHW,
6431 /* WCvtP */ Ins_WCVTP,
6432 /* RCvt */ Ins_RCVT,
6435 /* SCFS */ Ins_SCFS,
6438 /* MPPEM */ Ins_MPPEM,
6440 /* FlipON */ Ins_FLIPON,
6441 /* FlipOFF */ Ins_FLIPOFF,
6442 /* DEBUG */ Ins_DEBUG,
6445 /* LTEQ */ Ins_LTEQ,
6447 /* GTEQ */ Ins_GTEQ,
6451 /* EVEN */ Ins_EVEN,
6457 /* DeltaP1 */ Ins_DELTAP,
6467 /* FLOOR */ Ins_FLOOR,
6468 /* CEILING */ Ins_CEILING,
6469 /* ROUND[0] */ Ins_ROUND,
6470 /* ROUND[1] */ Ins_ROUND,
6471 /* ROUND[2] */ Ins_ROUND,
6472 /* ROUND[3] */ Ins_ROUND,
6473 /* NROUND[0] */ Ins_NROUND,
6474 /* NROUND[1] */ Ins_NROUND,
6475 /* NROUND[2] */ Ins_NROUND,
6476 /* NROUND[3] */ Ins_NROUND,
6478 /* WCvtF */ Ins_WCVTF,
6479 /* DeltaP2 */ Ins_DELTAP,
6480 /* DeltaP3 */ Ins_DELTAP,
6481 /* DeltaCn[0] */ Ins_DELTAC,
6482 /* DeltaCn[1] */ Ins_DELTAC,
6483 /* DeltaCn[2] */ Ins_DELTAC,
6484 /* SROUND */ Ins_SROUND,
6485 /* S45Round */ Ins_S45ROUND,
6486 /* JROT */ Ins_JROT,
6487 /* JROF */ Ins_JROF,
6488 /* ROFF */ Ins_ROFF,
6489 /* INS_0x7B */ Ins_UNKNOWN,
6490 /* RUTG */ Ins_RUTG,
6491 /* RDTG */ Ins_RDTG,
6492 /* SANGW */ Ins_SANGW,
6495 /* FlipPT */ Ins_FLIPPT,
6496 /* FlipRgON */ Ins_FLIPRGON,
6497 /* FlipRgOFF */ Ins_FLIPRGOFF,
6498 /* INS_0x83 */ Ins_UNKNOWN,
6499 /* INS_0x84 */ Ins_UNKNOWN,
6500 /* ScanCTRL */ Ins_SCANCTRL,
6501 /* SDPVTL[0] */ Ins_SDPVTL,
6502 /* SDPVTL[1] */ Ins_SDPVTL,
6503 /* GetINFO */ Ins_GETINFO,
6504 /* IDEF */ Ins_IDEF,
6505 /* ROLL */ Ins_ROLL,
6508 /* ScanTYPE */ Ins_SCANTYPE,
6509 /* InstCTRL */ Ins_INSTCTRL,
6510 /* INS_0x8F */ Ins_UNKNOWN,
6512 /* INS_0x90 */ Ins_UNKNOWN,
6513 /* INS_0x91 */ Ins_UNKNOWN,
6514 /* INS_0x92 */ Ins_UNKNOWN,
6515 /* INS_0x93 */ Ins_UNKNOWN,
6516 /* INS_0x94 */ Ins_UNKNOWN,
6517 /* INS_0x95 */ Ins_UNKNOWN,
6518 /* INS_0x96 */ Ins_UNKNOWN,
6519 /* INS_0x97 */ Ins_UNKNOWN,
6520 /* INS_0x98 */ Ins_UNKNOWN,
6521 /* INS_0x99 */ Ins_UNKNOWN,
6522 /* INS_0x9A */ Ins_UNKNOWN,
6523 /* INS_0x9B */ Ins_UNKNOWN,
6524 /* INS_0x9C */ Ins_UNKNOWN,
6525 /* INS_0x9D */ Ins_UNKNOWN,
6526 /* INS_0x9E */ Ins_UNKNOWN,
6527 /* INS_0x9F */ Ins_UNKNOWN,
6529 /* INS_0xA0 */ Ins_UNKNOWN,
6530 /* INS_0xA1 */ Ins_UNKNOWN,
6531 /* INS_0xA2 */ Ins_UNKNOWN,
6532 /* INS_0xA3 */ Ins_UNKNOWN,
6533 /* INS_0xA4 */ Ins_UNKNOWN,
6534 /* INS_0xA5 */ Ins_UNKNOWN,
6535 /* INS_0xA6 */ Ins_UNKNOWN,
6536 /* INS_0xA7 */ Ins_UNKNOWN,
6537 /* INS_0xA8 */ Ins_UNKNOWN,
6538 /* INS_0xA9 */ Ins_UNKNOWN,
6539 /* INS_0xAA */ Ins_UNKNOWN,
6540 /* INS_0xAB */ Ins_UNKNOWN,
6541 /* INS_0xAC */ Ins_UNKNOWN,
6542 /* INS_0xAD */ Ins_UNKNOWN,
6543 /* INS_0xAE */ Ins_UNKNOWN,
6544 /* INS_0xAF */ Ins_UNKNOWN,
6546 /* PushB[0] */ Ins_PUSHB,
6547 /* PushB[1] */ Ins_PUSHB,
6548 /* PushB[2] */ Ins_PUSHB,
6549 /* PushB[3] */ Ins_PUSHB,
6550 /* PushB[4] */ Ins_PUSHB,
6551 /* PushB[5] */ Ins_PUSHB,
6552 /* PushB[6] */ Ins_PUSHB,
6553 /* PushB[7] */ Ins_PUSHB,
6554 /* PushW[0] */ Ins_PUSHW,
6555 /* PushW[1] */ Ins_PUSHW,
6556 /* PushW[2] */ Ins_PUSHW,
6557 /* PushW[3] */ Ins_PUSHW,
6558 /* PushW[4] */ Ins_PUSHW,
6559 /* PushW[5] */ Ins_PUSHW,
6560 /* PushW[6] */ Ins_PUSHW,
6561 /* PushW[7] */ Ins_PUSHW,
6563 /* MDRP[00] */ Ins_MDRP,
6564 /* MDRP[01] */ Ins_MDRP,
6565 /* MDRP[02] */ Ins_MDRP,
6566 /* MDRP[03] */ Ins_MDRP,
6567 /* MDRP[04] */ Ins_MDRP,
6568 /* MDRP[05] */ Ins_MDRP,
6569 /* MDRP[06] */ Ins_MDRP,
6570 /* MDRP[07] */ Ins_MDRP,
6571 /* MDRP[08] */ Ins_MDRP,
6572 /* MDRP[09] */ Ins_MDRP,
6573 /* MDRP[10] */ Ins_MDRP,
6574 /* MDRP[11] */ Ins_MDRP,
6575 /* MDRP[12] */ Ins_MDRP,
6576 /* MDRP[13] */ Ins_MDRP,
6577 /* MDRP[14] */ Ins_MDRP,
6578 /* MDRP[15] */ Ins_MDRP,
6580 /* MDRP[16] */ Ins_MDRP,
6581 /* MDRP[17] */ Ins_MDRP,
6582 /* MDRP[18] */ Ins_MDRP,
6583 /* MDRP[19] */ Ins_MDRP,
6584 /* MDRP[20] */ Ins_MDRP,
6585 /* MDRP[21] */ Ins_MDRP,
6586 /* MDRP[22] */ Ins_MDRP,
6587 /* MDRP[23] */ Ins_MDRP,
6588 /* MDRP[24] */ Ins_MDRP,
6589 /* MDRP[25] */ Ins_MDRP,
6590 /* MDRP[26] */ Ins_MDRP,
6591 /* MDRP[27] */ Ins_MDRP,
6592 /* MDRP[28] */ Ins_MDRP,
6593 /* MDRP[29] */ Ins_MDRP,
6594 /* MDRP[30] */ Ins_MDRP,
6595 /* MDRP[31] */ Ins_MDRP,
6597 /* MIRP[00] */ Ins_MIRP,
6598 /* MIRP[01] */ Ins_MIRP,
6599 /* MIRP[02] */ Ins_MIRP,
6600 /* MIRP[03] */ Ins_MIRP,
6601 /* MIRP[04] */ Ins_MIRP,
6602 /* MIRP[05] */ Ins_MIRP,
6603 /* MIRP[06] */ Ins_MIRP,
6604 /* MIRP[07] */ Ins_MIRP,
6605 /* MIRP[08] */ Ins_MIRP,
6606 /* MIRP[09] */ Ins_MIRP,
6607 /* MIRP[10] */ Ins_MIRP,
6608 /* MIRP[11] */ Ins_MIRP,
6609 /* MIRP[12] */ Ins_MIRP,
6610 /* MIRP[13] */ Ins_MIRP,
6611 /* MIRP[14] */ Ins_MIRP,
6612 /* MIRP[15] */ Ins_MIRP,
6614 /* MIRP[16] */ Ins_MIRP,
6615 /* MIRP[17] */ Ins_MIRP,
6616 /* MIRP[18] */ Ins_MIRP,
6617 /* MIRP[19] */ Ins_MIRP,
6618 /* MIRP[20] */ Ins_MIRP,
6619 /* MIRP[21] */ Ins_MIRP,
6620 /* MIRP[22] */ Ins_MIRP,
6621 /* MIRP[23] */ Ins_MIRP,
6622 /* MIRP[24] */ Ins_MIRP,
6623 /* MIRP[25] */ Ins_MIRP,
6624 /* MIRP[26] */ Ins_MIRP,
6625 /* MIRP[27] */ Ins_MIRP,
6626 /* MIRP[28] */ Ins_MIRP,
6627 /* MIRP[29] */ Ins_MIRP,
6628 /* MIRP[30] */ Ins_MIRP,
6629 /* MIRP[31] */ Ins_MIRP
6633 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
6636 /*************************************************************************/
6640 /* This function executes a run of opcodes. It will exit in the */
6641 /* following cases: */
6643 /* - Errors (in which case it returns FALSE). */
6645 /* - Reaching the end of the main code range (returns TRUE). */
6646 /* Reaching the end of a code range within a function call is an */
6649 /* - After executing one single opcode, if the flag `Instruction_Trap' */
6650 /* is set to TRUE (returns TRUE). */
6652 /* On exit whith TRUE, test IP < CodeSize to know wether it comes from */
6653 /* an instruction trap or a normal termination. */
6656 /* Note: The documented DEBUG opcode pops a value from the stack. This */
6657 /* behaviour is unsupported; here a DEBUG opcode is always an */
6661 /* THIS IS THE INTERPRETER'S MAIN LOOP. */
6663 /* Instructions appear in the specification's order. */
6665 /*************************************************************************/
6668 /* documentation is in ttinterp.h */
6670 FT_EXPORT_DEF( FT_Error )
6671 TT_RunIns( TT_ExecContext exc )
6673 FT_Long ins_counter = 0; /* executed instructions counter */
6676 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
6680 /* set CVT functions */
6681 CUR.tt_metrics.ratio = 0;
6682 if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
6684 /* non-square pixels, use the stretched routines */
6685 CUR.func_read_cvt = Read_CVT_Stretched;
6686 CUR.func_write_cvt = Write_CVT_Stretched;
6687 CUR.func_move_cvt = Move_CVT_Stretched;
6691 /* square pixels, use normal routines */
6692 CUR.func_read_cvt = Read_CVT;
6693 CUR.func_write_cvt = Write_CVT;
6694 CUR.func_move_cvt = Move_CVT;
6698 COMPUTE_Round( (FT_Byte)exc->GS.round_state );
6702 CUR.opcode = CUR.code[CUR.IP];
6704 if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )
6706 if ( CUR.IP + 1 > CUR.codeSize )
6707 goto LErrorCodeOverflow_;
6709 CUR.length = CUR.code[CUR.IP + 1] + 2;
6712 if ( CUR.IP + CUR.length > CUR.codeSize )
6713 goto LErrorCodeOverflow_;
6715 /* First, let's check for empty stack and overflow */
6716 CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 );
6718 /* `args' is the top of the stack once arguments have been popped. */
6719 /* One can also interpret it as the index of the last argument. */
6722 CUR.error = TT_Err_Too_Few_Arguments;
6726 CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 );
6728 /* `new_top' is the new top of the stack, after the instruction's */
6729 /* execution. `top' will be set to `new_top' after the `switch' */
6731 if ( CUR.new_top > CUR.stackSize )
6733 CUR.error = TT_Err_Stack_Overflow;
6737 CUR.step_ins = TRUE;
6738 CUR.error = TT_Err_Ok;
6740 #ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
6743 FT_Long* args = CUR.stack + CUR.args;
6744 FT_Byte opcode = CUR.opcode;
6747 #undef ARRAY_BOUND_ERROR
6748 #define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
6753 case 0x00: /* SVTCA y */
6754 case 0x01: /* SVTCA x */
6755 case 0x02: /* SPvTCA y */
6756 case 0x03: /* SPvTCA x */
6757 case 0x04: /* SFvTCA y */
6758 case 0x05: /* SFvTCA x */
6763 AA = (FT_Short)( ( opcode & 1 ) << 14 );
6764 BB = (FT_Short)( AA ^ 0x4000 );
6768 CUR.GS.projVector.x = AA;
6769 CUR.GS.projVector.y = BB;
6771 CUR.GS.dualVector.x = AA;
6772 CUR.GS.dualVector.y = BB;
6775 if ( ( opcode & 2 ) == 0 )
6777 CUR.GS.freeVector.x = AA;
6778 CUR.GS.freeVector.y = BB;
6785 case 0x06: /* SPvTL // */
6786 case 0x07: /* SPvTL + */
6790 case 0x08: /* SFvTL // */
6791 case 0x09: /* SFvTL + */
6795 case 0x0A: /* SPvFS */
6799 case 0x0B: /* SFvFS */
6803 case 0x0C: /* GPV */
6807 case 0x0D: /* GFV */
6811 case 0x0E: /* SFvTPv */
6815 case 0x0F: /* ISECT */
6816 Ins_ISECT( EXEC_ARG_ args );
6819 case 0x10: /* SRP0 */
6823 case 0x11: /* SRP1 */
6827 case 0x12: /* SRP2 */
6831 case 0x13: /* SZP0 */
6832 Ins_SZP0( EXEC_ARG_ args );
6835 case 0x14: /* SZP1 */
6836 Ins_SZP1( EXEC_ARG_ args );
6839 case 0x15: /* SZP2 */
6840 Ins_SZP2( EXEC_ARG_ args );
6843 case 0x16: /* SZPS */
6844 Ins_SZPS( EXEC_ARG_ args );
6847 case 0x17: /* SLOOP */
6851 case 0x18: /* RTG */
6855 case 0x19: /* RTHG */
6859 case 0x1A: /* SMD */
6863 case 0x1B: /* ELSE */
6864 Ins_ELSE( EXEC_ARG_ args );
6867 case 0x1C: /* JMPR */
6871 case 0x1D: /* SCVTCI */
6875 case 0x1E: /* SSWCI */
6879 case 0x1F: /* SSW */
6883 case 0x20: /* DUP */
6887 case 0x21: /* POP */
6891 case 0x22: /* CLEAR */
6895 case 0x23: /* SWAP */
6899 case 0x24: /* DEPTH */
6903 case 0x25: /* CINDEX */
6907 case 0x26: /* MINDEX */
6908 Ins_MINDEX( EXEC_ARG_ args );
6911 case 0x27: /* ALIGNPTS */
6912 Ins_ALIGNPTS( EXEC_ARG_ args );
6915 case 0x28: /* ???? */
6916 Ins_UNKNOWN( EXEC_ARG_ args );
6919 case 0x29: /* UTP */
6920 Ins_UTP( EXEC_ARG_ args );
6923 case 0x2A: /* LOOPCALL */
6924 Ins_LOOPCALL( EXEC_ARG_ args );
6927 case 0x2B: /* CALL */
6928 Ins_CALL( EXEC_ARG_ args );
6931 case 0x2C: /* FDEF */
6932 Ins_FDEF( EXEC_ARG_ args );
6935 case 0x2D: /* ENDF */
6936 Ins_ENDF( EXEC_ARG_ args );
6939 case 0x2E: /* MDAP */
6940 case 0x2F: /* MDAP */
6941 Ins_MDAP( EXEC_ARG_ args );
6945 case 0x30: /* IUP */
6946 case 0x31: /* IUP */
6947 Ins_IUP( EXEC_ARG_ args );
6950 case 0x32: /* SHP */
6951 case 0x33: /* SHP */
6952 Ins_SHP( EXEC_ARG_ args );
6955 case 0x34: /* SHC */
6956 case 0x35: /* SHC */
6957 Ins_SHC( EXEC_ARG_ args );
6960 case 0x36: /* SHZ */
6961 case 0x37: /* SHZ */
6962 Ins_SHZ( EXEC_ARG_ args );
6965 case 0x38: /* SHPIX */
6966 Ins_SHPIX( EXEC_ARG_ args );
6970 Ins_IP( EXEC_ARG_ args );
6973 case 0x3A: /* MSIRP */
6974 case 0x3B: /* MSIRP */
6975 Ins_MSIRP( EXEC_ARG_ args );
6978 case 0x3C: /* AlignRP */
6979 Ins_ALIGNRP( EXEC_ARG_ args );
6982 case 0x3D: /* RTDG */
6986 case 0x3E: /* MIAP */
6987 case 0x3F: /* MIAP */
6988 Ins_MIAP( EXEC_ARG_ args );
6991 case 0x40: /* NPUSHB */
6992 Ins_NPUSHB( EXEC_ARG_ args );
6995 case 0x41: /* NPUSHW */
6996 Ins_NPUSHW( EXEC_ARG_ args );
7004 CUR.error = TT_Err_Invalid_Reference;
7011 case 0x44: /* WCVTP */
7015 case 0x45: /* RCVT */
7021 Ins_GC( EXEC_ARG_ args );
7024 case 0x48: /* SCFS */
7025 Ins_SCFS( EXEC_ARG_ args );
7030 Ins_MD( EXEC_ARG_ args );
7033 case 0x4B: /* MPPEM */
7037 case 0x4C: /* MPS */
7041 case 0x4D: /* FLIPON */
7045 case 0x4E: /* FLIPOFF */
7049 case 0x4F: /* DEBUG */
7057 case 0x51: /* LTEQ */
7065 case 0x53: /* GTEQ */
7073 case 0x55: /* NEQ */
7077 case 0x56: /* ODD */
7081 case 0x57: /* EVEN */
7086 Ins_IF( EXEC_ARG_ args );
7089 case 0x59: /* EIF */
7093 case 0x5A: /* AND */
7101 case 0x5C: /* NOT */
7105 case 0x5D: /* DELTAP1 */
7106 Ins_DELTAP( EXEC_ARG_ args );
7109 case 0x5E: /* SDB */
7113 case 0x5F: /* SDS */
7117 case 0x60: /* ADD */
7121 case 0x61: /* SUB */
7125 case 0x62: /* DIV */
7129 case 0x63: /* MUL */
7133 case 0x64: /* ABS */
7137 case 0x65: /* NEG */
7141 case 0x66: /* FLOOR */
7145 case 0x67: /* CEILING */
7149 case 0x68: /* ROUND */
7150 case 0x69: /* ROUND */
7151 case 0x6A: /* ROUND */
7152 case 0x6B: /* ROUND */
7156 case 0x6C: /* NROUND */
7157 case 0x6D: /* NROUND */
7158 case 0x6E: /* NRRUND */
7159 case 0x6F: /* NROUND */
7163 case 0x70: /* WCVTF */
7167 case 0x71: /* DELTAP2 */
7168 case 0x72: /* DELTAP3 */
7169 Ins_DELTAP( EXEC_ARG_ args );
7172 case 0x73: /* DELTAC0 */
7173 case 0x74: /* DELTAC1 */
7174 case 0x75: /* DELTAC2 */
7175 Ins_DELTAC( EXEC_ARG_ args );
7178 case 0x76: /* SROUND */
7182 case 0x77: /* S45Round */
7186 case 0x78: /* JROT */
7190 case 0x79: /* JROF */
7194 case 0x7A: /* ROFF */
7198 case 0x7B: /* ???? */
7199 Ins_UNKNOWN( EXEC_ARG_ args );
7202 case 0x7C: /* RUTG */
7206 case 0x7D: /* RDTG */
7210 case 0x7E: /* SANGW */
7212 /* nothing - obsolete */
7215 case 0x80: /* FLIPPT */
7216 Ins_FLIPPT( EXEC_ARG_ args );
7219 case 0x81: /* FLIPRGON */
7220 Ins_FLIPRGON( EXEC_ARG_ args );
7223 case 0x82: /* FLIPRGOFF */
7224 Ins_FLIPRGOFF( EXEC_ARG_ args );
7227 case 0x83: /* UNKNOWN */
7228 case 0x84: /* UNKNOWN */
7229 Ins_UNKNOWN( EXEC_ARG_ args );
7232 case 0x85: /* SCANCTRL */
7233 Ins_SCANCTRL( EXEC_ARG_ args );
7236 case 0x86: /* SDPVTL */
7237 case 0x87: /* SDPVTL */
7238 Ins_SDPVTL( EXEC_ARG_ args );
7241 case 0x88: /* GETINFO */
7242 Ins_GETINFO( EXEC_ARG_ args );
7245 case 0x89: /* IDEF */
7246 Ins_IDEF( EXEC_ARG_ args );
7249 case 0x8A: /* ROLL */
7250 Ins_ROLL( EXEC_ARG_ args );
7253 case 0x8B: /* MAX */
7257 case 0x8C: /* MIN */
7261 case 0x8D: /* SCANTYPE */
7262 Ins_SCANTYPE( EXEC_ARG_ args );
7265 case 0x8E: /* INSTCTRL */
7266 Ins_INSTCTRL( EXEC_ARG_ args );
7270 Ins_UNKNOWN( EXEC_ARG_ args );
7274 if ( opcode >= 0xE0 )
7275 Ins_MIRP( EXEC_ARG_ args );
7276 else if ( opcode >= 0xC0 )
7277 Ins_MDRP( EXEC_ARG_ args );
7278 else if ( opcode >= 0xB8 )
7279 Ins_PUSHW( EXEC_ARG_ args );
7280 else if ( opcode >= 0xB0 )
7281 Ins_PUSHB( EXEC_ARG_ args );
7283 Ins_UNKNOWN( EXEC_ARG_ args );
7290 Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );
7292 #endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7294 if ( CUR.error != TT_Err_Ok )
7296 switch ( CUR.error )
7298 case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
7300 TT_DefRecord* def = CUR.IDefs;
7301 TT_DefRecord* limit = def + CUR.numIDefs;
7304 for ( ; def < limit; def++ )
7306 if ( def->active && CUR.opcode == (FT_Byte)def->opc )
7308 TT_CallRec* callrec;
7311 if ( CUR.callTop >= CUR.callSize )
7313 CUR.error = TT_Err_Invalid_Reference;
7317 callrec = &CUR.callStack[CUR.callTop];
7319 callrec->Caller_Range = CUR.curRange;
7320 callrec->Caller_IP = CUR.IP + 1;
7321 callrec->Cur_Count = 1;
7322 callrec->Cur_Restart = def->start;
7324 if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
7332 CUR.error = TT_Err_Invalid_Opcode;
7336 break; /* Unreachable code warning suppression. */
7337 /* Leave to remind in case a later change the editor */
7338 /* to consider break; */
7350 CUR.top = CUR.new_top;
7353 CUR.IP += CUR.length;
7355 /* increment instruction counter and check if we didn't */
7356 /* run this program for too long (e.g. infinite loops). */
7357 if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
7358 return TT_Err_Execution_Too_Long;
7361 if ( CUR.IP >= CUR.codeSize )
7363 if ( CUR.callTop > 0 )
7365 CUR.error = TT_Err_Code_Overflow;
7371 } while ( !CUR.instruction_trap );
7375 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7381 LErrorCodeOverflow_:
7382 CUR.error = TT_Err_Code_Overflow;
7386 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7394 #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */