1 /***************************************************************************/
5 /* TrueType bytecode interpreter (body). */
7 /* Copyright 1996-2014 */
8 /* by David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
16 /***************************************************************************/
19 /* Greg Hitchcock from Microsoft has helped a lot in resolving unclear */
20 /* issues; many thanks! */
24 #include FT_INTERNAL_DEBUG_H
25 #include FT_INTERNAL_CALC_H
26 #include FT_TRIGONOMETRY_H
28 #include FT_TRUETYPE_DRIVER_H
35 #ifdef TT_USE_BYTECODE_INTERPRETER
38 /*************************************************************************/
40 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
41 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
42 /* messages during execution. */
45 #define FT_COMPONENT trace_ttinterp
47 /*************************************************************************/
49 /* In order to detect infinite loops in the code, we set up a counter */
50 /* within the run loop. A single stroke of interpretation is now */
51 /* limited to a maximum number of opcodes defined below. */
53 #define MAX_RUNNABLE_OPCODES 1000000L
56 /*************************************************************************/
58 /* There are two kinds of implementations: */
60 /* a. static implementation */
62 /* The current execution context is a static variable, which fields */
63 /* are accessed directly by the interpreter during execution. The */
64 /* context is named `cur'. */
66 /* This version is non-reentrant, of course. */
68 /* b. indirect implementation */
70 /* The current execution context is passed to _each_ function as its */
71 /* first argument, and each field is thus accessed indirectly. */
73 /* This version is fully re-entrant. */
75 /* The idea is that an indirect implementation may be slower to execute */
76 /* on low-end processors that are used in some systems (like 386s or */
79 /* As a consequence, the indirect implementation is now the default, as */
80 /* its performance costs can be considered negligible in our context. */
81 /* Note, however, that we kept the same source with macros because: */
83 /* - The code is kept very close in design to the Pascal code used for */
86 /* - It's much more readable that way! */
88 /* - It's still open to experimentation and tuning. */
90 /*************************************************************************/
93 #ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */
95 #define CUR (*exc) /* see ttobjs.h */
97 /*************************************************************************/
99 /* This macro is used whenever `exec' is unused in a function, to avoid */
100 /* stupid warnings from pedantic compilers. */
102 #define FT_UNUSED_EXEC FT_UNUSED( exc )
104 #else /* static implementation */
108 #define FT_UNUSED_EXEC int __dummy = __dummy
111 TT_ExecContextRec cur; /* static exec. context variable */
113 /* apparently, we have a _lot_ of direct indexing when accessing */
114 /* the static `cur', which makes the code bigger (due to all the */
115 /* four bytes addresses). */
117 #endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
120 /*************************************************************************/
122 /* The instruction argument stack. */
124 #define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */
127 /*************************************************************************/
129 /* This macro is used whenever `args' is unused in a function, to avoid */
130 /* stupid warnings from pedantic compilers. */
132 #define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args )
135 #define SUBPIXEL_HINTING \
136 ( ((TT_Driver)FT_FACE_DRIVER( CUR.face ))->interpreter_version == \
137 TT_INTERPRETER_VERSION_38 )
140 /*************************************************************************/
142 /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */
143 /* increase readability of the code. */
145 /*************************************************************************/
148 #define SKIP_Code() \
151 #define GET_ShortIns() \
152 GetShortIns( EXEC_ARG )
154 #define NORMalize( x, y, v ) \
155 Normalize( EXEC_ARG_ x, y, v )
157 #define SET_SuperRound( scale, flags ) \
158 SetSuperRound( EXEC_ARG_ scale, flags )
160 #define ROUND_None( d, c ) \
161 Round_None( EXEC_ARG_ d, c )
163 #define INS_Goto_CodeRange( range, ip ) \
164 Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
166 #define CUR_Func_move( z, p, d ) \
167 CUR.func_move( EXEC_ARG_ z, p, d )
169 #define CUR_Func_move_orig( z, p, d ) \
170 CUR.func_move_orig( EXEC_ARG_ z, p, d )
172 #define CUR_Func_round( d, c ) \
173 CUR.func_round( EXEC_ARG_ d, c )
175 #define CUR_Func_cur_ppem() \
176 CUR.func_cur_ppem( EXEC_ARG )
178 #define CUR_Func_read_cvt( index ) \
179 CUR.func_read_cvt( EXEC_ARG_ index )
181 #define CUR_Func_write_cvt( index, val ) \
182 CUR.func_write_cvt( EXEC_ARG_ index, val )
184 #define CUR_Func_move_cvt( index, val ) \
185 CUR.func_move_cvt( EXEC_ARG_ index, val )
187 #define CURRENT_Ratio() \
188 Current_Ratio( EXEC_ARG )
190 #define INS_SxVTL( a, b, c, d ) \
191 Ins_SxVTL( EXEC_ARG_ a, b, c, d )
193 #define COMPUTE_Funcs() \
194 Compute_Funcs( EXEC_ARG )
196 #define COMPUTE_Round( a ) \
197 Compute_Round( EXEC_ARG_ a )
199 #define COMPUTE_Point_Displacement( a, b, c, d ) \
200 Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
202 #define MOVE_Zp2_Point( a, b, c, t ) \
203 Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
206 #define CUR_Func_project( v1, v2 ) \
207 CUR.func_project( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
209 #define CUR_Func_dualproj( v1, v2 ) \
210 CUR.func_dualproj( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
212 #define CUR_fast_project( v ) \
213 CUR.func_project( EXEC_ARG_ (v)->x, (v)->y )
215 #define CUR_fast_dualproj( v ) \
216 CUR.func_dualproj( EXEC_ARG_ (v)->x, (v)->y )
219 /*************************************************************************/
221 /* Instruction dispatch function, as used by the interpreter. */
223 typedef void (*TInstruction_Function)( INS_ARG );
226 /*************************************************************************/
228 /* Two simple bounds-checking macros. */
230 #define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
231 #define BOUNDSL( x, n ) ( (FT_ULong)(x) >= (FT_ULong)(n) )
233 /*************************************************************************/
235 /* This macro computes (a*2^14)/b and complements TT_MulFix14. */
237 #define TT_DivFix14( a, b ) \
238 FT_DivFix( a, (b) << 2 )
247 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
248 #define GUESS_VECTOR( V ) \
249 if ( CUR.face->unpatented_hinting ) \
251 CUR.GS.V.x = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0x4000 : 0 ); \
252 CUR.GS.V.y = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0 : 0x4000 ); \
255 #define GUESS_VECTOR( V )
258 /*************************************************************************/
260 /* CODERANGE FUNCTIONS */
262 /*************************************************************************/
265 /*************************************************************************/
268 /* TT_Goto_CodeRange */
271 /* Switches to a new code range (updates the code related elements in */
272 /* `exec', and `IP'). */
275 /* range :: The new execution code range. */
277 /* IP :: The new IP in the new code range. */
280 /* exec :: The target execution context. */
283 TT_Goto_CodeRange( TT_ExecContext exec,
287 TT_CodeRange* coderange;
290 FT_ASSERT( range >= 1 && range <= 3 );
292 coderange = &exec->codeRangeTable[range - 1];
294 FT_ASSERT( coderange->base != NULL );
296 /* NOTE: Because the last instruction of a program may be a CALL */
297 /* which will return to the first byte *after* the code */
298 /* range, we test for IP <= Size instead of IP < Size. */
300 FT_ASSERT( (FT_ULong)IP <= coderange->size );
302 exec->code = coderange->base;
303 exec->codeSize = coderange->size;
305 exec->curRange = range;
309 /*************************************************************************/
312 /* TT_Set_CodeRange */
315 /* Sets a code range. */
318 /* range :: The code range index. */
320 /* base :: The new code base. */
322 /* length :: The range size in bytes. */
325 /* exec :: The target execution context. */
328 TT_Set_CodeRange( TT_ExecContext exec,
333 FT_ASSERT( range >= 1 && range <= 3 );
335 exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
336 exec->codeRangeTable[range - 1].size = length;
340 /*************************************************************************/
343 /* TT_Clear_CodeRange */
346 /* Clears a code range. */
349 /* range :: The code range index. */
352 /* exec :: The target execution context. */
355 TT_Clear_CodeRange( TT_ExecContext exec,
358 FT_ASSERT( range >= 1 && range <= 3 );
360 exec->codeRangeTable[range - 1].base = NULL;
361 exec->codeRangeTable[range - 1].size = 0;
365 /*************************************************************************/
367 /* EXECUTION CONTEXT ROUTINES */
369 /*************************************************************************/
372 /*************************************************************************/
375 /* TT_Done_Context */
378 /* Destroys a given context. */
381 /* exec :: A handle to the target execution context. */
383 /* memory :: A handle to the parent memory object. */
386 /* Only the glyph loader and debugger should call this function. */
389 TT_Done_Context( TT_ExecContext exec )
391 FT_Memory memory = exec->memory;
396 exec->maxContours = 0;
399 FT_FREE( exec->stack );
402 /* free call stack */
403 FT_FREE( exec->callStack );
407 /* free glyph code range */
408 FT_FREE( exec->glyphIns );
418 /*************************************************************************/
424 /* Initializes a context object. */
427 /* memory :: A handle to the parent memory object. */
430 /* exec :: A handle to the target execution context. */
433 /* FreeType error code. 0 means success. */
436 Init_Context( TT_ExecContext exec,
442 FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec ));
444 exec->memory = memory;
447 if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )
450 /* all values in the context are set to 0 already, but this is */
451 /* here as a remainder */
453 exec->maxContours = 0;
459 exec->glyphIns = NULL;
467 FT_ERROR(( "Init_Context: not enough memory for %p\n", exec ));
468 TT_Done_Context( exec );
474 /*************************************************************************/
480 /* Checks the size of a buffer and reallocates it if necessary. */
483 /* memory :: A handle to the parent memory object. */
485 /* multiplier :: The size in bytes of each element in the buffer. */
487 /* new_max :: The new capacity (size) of the buffer. */
490 /* size :: The address of the buffer's current size expressed */
493 /* buff :: The address of the buffer base pointer. */
496 /* FreeType error code. 0 means success. */
498 FT_LOCAL_DEF( FT_Error )
499 Update_Max( FT_Memory memory,
506 void** pbuff = (void**)_pbuff;
509 if ( *size < new_max )
511 if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )
520 /*************************************************************************/
523 /* TT_Load_Context */
526 /* Prepare an execution context for glyph hinting. */
529 /* face :: A handle to the source face object. */
531 /* size :: A handle to the source size object. */
534 /* exec :: A handle to the target execution context. */
537 /* FreeType error code. 0 means success. */
540 /* Only the glyph loader and debugger should call this function. */
542 FT_LOCAL_DEF( FT_Error )
543 TT_Load_Context( TT_ExecContext exec,
554 maxp = &face->max_profile;
559 exec->numFDefs = size->num_function_defs;
560 exec->maxFDefs = size->max_function_defs;
561 exec->numIDefs = size->num_instruction_defs;
562 exec->maxIDefs = size->max_instruction_defs;
563 exec->FDefs = size->function_defs;
564 exec->IDefs = size->instruction_defs;
565 exec->tt_metrics = size->ttmetrics;
566 exec->metrics = size->metrics;
568 exec->maxFunc = size->max_func;
569 exec->maxIns = size->max_ins;
571 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
572 exec->codeRangeTable[i] = size->codeRangeTable[i];
574 /* set graphics state */
577 exec->cvtSize = size->cvt_size;
578 exec->cvt = size->cvt;
580 exec->storeSize = size->storage_size;
581 exec->storage = size->storage;
583 exec->twilight = size->twilight;
585 /* In case of multi-threading it can happen that the old size object */
586 /* no longer exists, thus we must clear all glyph zone references. */
587 ft_memset( &exec->zp0, 0, sizeof ( exec->zp0 ) );
588 exec->zp1 = exec->zp0;
589 exec->zp2 = exec->zp0;
592 /* XXX: We reserve a little more elements on the stack to deal safely */
593 /* with broken fonts like arialbs, courbs, timesbs, etc. */
594 tmp = exec->stackSize;
595 error = Update_Max( exec->memory,
597 sizeof ( FT_F26Dot6 ),
599 maxp->maxStackElements + 32 );
600 exec->stackSize = (FT_UInt)tmp;
604 tmp = exec->glyphSize;
605 error = Update_Max( exec->memory,
608 (void*)&exec->glyphIns,
609 maxp->maxSizeOfInstructions );
610 exec->glyphSize = (FT_UShort)tmp;
614 exec->pts.n_points = 0;
615 exec->pts.n_contours = 0;
617 exec->zp1 = exec->pts;
618 exec->zp2 = exec->pts;
619 exec->zp0 = exec->pts;
621 exec->instruction_trap = FALSE;
627 /*************************************************************************/
630 /* TT_Save_Context */
633 /* Saves the code ranges in a `size' object. */
636 /* exec :: A handle to the source execution context. */
639 /* size :: A handle to the target size object. */
642 /* Only the glyph loader and debugger should call this function. */
645 TT_Save_Context( TT_ExecContext exec,
651 /* XXX: Will probably disappear soon with all the code range */
652 /* management, which is now rather obsolete. */
654 size->num_function_defs = exec->numFDefs;
655 size->num_instruction_defs = exec->numIDefs;
657 size->max_func = exec->maxFunc;
658 size->max_ins = exec->maxIns;
660 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
661 size->codeRangeTable[i] = exec->codeRangeTable[i];
665 /*************************************************************************/
671 /* Executes one or more instructions in the execution context. */
674 /* debug :: A Boolean flag. If set, the function sets some internal */
675 /* variables and returns immediately, otherwise TT_RunIns() */
678 /* This is commented out currently. */
681 /* exec :: A handle to the target execution context. */
684 /* TrueType error code. 0 means success. */
687 /* Only the glyph loader and debugger should call this function. */
689 FT_LOCAL_DEF( FT_Error )
690 TT_Run_Context( TT_ExecContext exec,
693 TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 );
695 exec->zp0 = exec->pts;
696 exec->zp1 = exec->pts;
697 exec->zp2 = exec->pts;
703 exec->GS.projVector.x = 0x4000;
704 exec->GS.projVector.y = 0x0000;
706 exec->GS.freeVector = exec->GS.projVector;
707 exec->GS.dualVector = exec->GS.projVector;
709 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
710 exec->GS.both_x_axis = TRUE;
713 exec->GS.round_state = 1;
716 /* some glyphs leave something on the stack. so we clean it */
717 /* before a new execution. */
724 return exec->face->interpreter( exec );
727 return TT_RunIns( exec );
734 /* The default value for `scan_control' is documented as FALSE in the */
735 /* TrueType specification. This is confusing since it implies a */
736 /* Boolean value. However, this is not the case, thus both the */
737 /* default values of our `scan_type' and `scan_control' fields (which */
738 /* the documentation's `scan_control' variable is split into) are */
741 const TT_GraphicsState tt_default_graphics_state =
748 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
753 TRUE, 68, 0, 0, 9, 3,
758 /* documentation is in ttinterp.h */
760 FT_EXPORT_DEF( TT_ExecContext )
761 TT_New_Context( TT_Driver driver )
769 memory = driver->root.root.memory;
771 if ( !driver->context )
777 /* allocate object */
778 if ( FT_NEW( exec ) )
781 /* initialize it; in case of error this deallocates `exec' too */
782 error = Init_Context( exec, memory );
786 /* store it into the driver */
787 driver->context = exec;
790 return driver->context;
797 /*************************************************************************/
799 /* Before an opcode is executed, the interpreter verifies that there are */
800 /* enough arguments on the stack, with the help of the `Pop_Push_Count' */
803 /* For each opcode, the first column gives the number of arguments that */
804 /* are popped from the stack; the second one gives the number of those */
805 /* that are pushed in result. */
807 /* Opcodes which have a varying number of parameters in the data stream */
808 /* (NPUSHB, NPUSHW) are handled specially; they have a negative value in */
809 /* the `opcode_length' table, and the value in `Pop_Push_Count' is set */
812 /*************************************************************************/
816 #define PACK( x, y ) ( ( x << 4 ) | y )
820 const FT_Byte Pop_Push_Count[256] =
822 /* opcodes are gathered in groups of 16 */
823 /* please keep the spaces as they are */
825 /* SVTCA y */ PACK( 0, 0 ),
826 /* SVTCA x */ PACK( 0, 0 ),
827 /* SPvTCA y */ PACK( 0, 0 ),
828 /* SPvTCA x */ PACK( 0, 0 ),
829 /* SFvTCA y */ PACK( 0, 0 ),
830 /* SFvTCA x */ PACK( 0, 0 ),
831 /* SPvTL // */ PACK( 2, 0 ),
832 /* SPvTL + */ PACK( 2, 0 ),
833 /* SFvTL // */ PACK( 2, 0 ),
834 /* SFvTL + */ PACK( 2, 0 ),
835 /* SPvFS */ PACK( 2, 0 ),
836 /* SFvFS */ PACK( 2, 0 ),
837 /* GPV */ PACK( 0, 2 ),
838 /* GFV */ PACK( 0, 2 ),
839 /* SFvTPv */ PACK( 0, 0 ),
840 /* ISECT */ PACK( 5, 0 ),
842 /* SRP0 */ PACK( 1, 0 ),
843 /* SRP1 */ PACK( 1, 0 ),
844 /* SRP2 */ PACK( 1, 0 ),
845 /* SZP0 */ PACK( 1, 0 ),
846 /* SZP1 */ PACK( 1, 0 ),
847 /* SZP2 */ PACK( 1, 0 ),
848 /* SZPS */ PACK( 1, 0 ),
849 /* SLOOP */ PACK( 1, 0 ),
850 /* RTG */ PACK( 0, 0 ),
851 /* RTHG */ PACK( 0, 0 ),
852 /* SMD */ PACK( 1, 0 ),
853 /* ELSE */ PACK( 0, 0 ),
854 /* JMPR */ PACK( 1, 0 ),
855 /* SCvTCi */ PACK( 1, 0 ),
856 /* SSwCi */ PACK( 1, 0 ),
857 /* SSW */ PACK( 1, 0 ),
859 /* DUP */ PACK( 1, 2 ),
860 /* POP */ PACK( 1, 0 ),
861 /* CLEAR */ PACK( 0, 0 ),
862 /* SWAP */ PACK( 2, 2 ),
863 /* DEPTH */ PACK( 0, 1 ),
864 /* CINDEX */ PACK( 1, 1 ),
865 /* MINDEX */ PACK( 1, 0 ),
866 /* AlignPTS */ PACK( 2, 0 ),
867 /* INS_$28 */ PACK( 0, 0 ),
868 /* UTP */ PACK( 1, 0 ),
869 /* LOOPCALL */ PACK( 2, 0 ),
870 /* CALL */ PACK( 1, 0 ),
871 /* FDEF */ PACK( 1, 0 ),
872 /* ENDF */ PACK( 0, 0 ),
873 /* MDAP[0] */ PACK( 1, 0 ),
874 /* MDAP[1] */ PACK( 1, 0 ),
876 /* IUP[0] */ PACK( 0, 0 ),
877 /* IUP[1] */ PACK( 0, 0 ),
878 /* SHP[0] */ PACK( 0, 0 ),
879 /* SHP[1] */ PACK( 0, 0 ),
880 /* SHC[0] */ PACK( 1, 0 ),
881 /* SHC[1] */ PACK( 1, 0 ),
882 /* SHZ[0] */ PACK( 1, 0 ),
883 /* SHZ[1] */ PACK( 1, 0 ),
884 /* SHPIX */ PACK( 1, 0 ),
885 /* IP */ PACK( 0, 0 ),
886 /* MSIRP[0] */ PACK( 2, 0 ),
887 /* MSIRP[1] */ PACK( 2, 0 ),
888 /* AlignRP */ PACK( 0, 0 ),
889 /* RTDG */ PACK( 0, 0 ),
890 /* MIAP[0] */ PACK( 2, 0 ),
891 /* MIAP[1] */ PACK( 2, 0 ),
893 /* NPushB */ PACK( 0, 0 ),
894 /* NPushW */ PACK( 0, 0 ),
895 /* WS */ PACK( 2, 0 ),
896 /* RS */ PACK( 1, 1 ),
897 /* WCvtP */ PACK( 2, 0 ),
898 /* RCvt */ PACK( 1, 1 ),
899 /* GC[0] */ PACK( 1, 1 ),
900 /* GC[1] */ PACK( 1, 1 ),
901 /* SCFS */ PACK( 2, 0 ),
902 /* MD[0] */ PACK( 2, 1 ),
903 /* MD[1] */ PACK( 2, 1 ),
904 /* MPPEM */ PACK( 0, 1 ),
905 /* MPS */ PACK( 0, 1 ),
906 /* FlipON */ PACK( 0, 0 ),
907 /* FlipOFF */ PACK( 0, 0 ),
908 /* DEBUG */ PACK( 1, 0 ),
910 /* LT */ PACK( 2, 1 ),
911 /* LTEQ */ PACK( 2, 1 ),
912 /* GT */ PACK( 2, 1 ),
913 /* GTEQ */ PACK( 2, 1 ),
914 /* EQ */ PACK( 2, 1 ),
915 /* NEQ */ PACK( 2, 1 ),
916 /* ODD */ PACK( 1, 1 ),
917 /* EVEN */ PACK( 1, 1 ),
918 /* IF */ PACK( 1, 0 ),
919 /* EIF */ PACK( 0, 0 ),
920 /* AND */ PACK( 2, 1 ),
921 /* OR */ PACK( 2, 1 ),
922 /* NOT */ PACK( 1, 1 ),
923 /* DeltaP1 */ PACK( 1, 0 ),
924 /* SDB */ PACK( 1, 0 ),
925 /* SDS */ PACK( 1, 0 ),
927 /* ADD */ PACK( 2, 1 ),
928 /* SUB */ PACK( 2, 1 ),
929 /* DIV */ PACK( 2, 1 ),
930 /* MUL */ PACK( 2, 1 ),
931 /* ABS */ PACK( 1, 1 ),
932 /* NEG */ PACK( 1, 1 ),
933 /* FLOOR */ PACK( 1, 1 ),
934 /* CEILING */ PACK( 1, 1 ),
935 /* ROUND[0] */ PACK( 1, 1 ),
936 /* ROUND[1] */ PACK( 1, 1 ),
937 /* ROUND[2] */ PACK( 1, 1 ),
938 /* ROUND[3] */ PACK( 1, 1 ),
939 /* NROUND[0] */ PACK( 1, 1 ),
940 /* NROUND[1] */ PACK( 1, 1 ),
941 /* NROUND[2] */ PACK( 1, 1 ),
942 /* NROUND[3] */ PACK( 1, 1 ),
944 /* WCvtF */ PACK( 2, 0 ),
945 /* DeltaP2 */ PACK( 1, 0 ),
946 /* DeltaP3 */ PACK( 1, 0 ),
947 /* DeltaCn[0] */ PACK( 1, 0 ),
948 /* DeltaCn[1] */ PACK( 1, 0 ),
949 /* DeltaCn[2] */ PACK( 1, 0 ),
950 /* SROUND */ PACK( 1, 0 ),
951 /* S45Round */ PACK( 1, 0 ),
952 /* JROT */ PACK( 2, 0 ),
953 /* JROF */ PACK( 2, 0 ),
954 /* ROFF */ PACK( 0, 0 ),
955 /* INS_$7B */ PACK( 0, 0 ),
956 /* RUTG */ PACK( 0, 0 ),
957 /* RDTG */ PACK( 0, 0 ),
958 /* SANGW */ PACK( 1, 0 ),
959 /* AA */ PACK( 1, 0 ),
961 /* FlipPT */ PACK( 0, 0 ),
962 /* FlipRgON */ PACK( 2, 0 ),
963 /* FlipRgOFF */ PACK( 2, 0 ),
964 /* INS_$83 */ PACK( 0, 0 ),
965 /* INS_$84 */ PACK( 0, 0 ),
966 /* ScanCTRL */ PACK( 1, 0 ),
967 /* SDPVTL[0] */ PACK( 2, 0 ),
968 /* SDPVTL[1] */ PACK( 2, 0 ),
969 /* GetINFO */ PACK( 1, 1 ),
970 /* IDEF */ PACK( 1, 0 ),
971 /* ROLL */ PACK( 3, 3 ),
972 /* MAX */ PACK( 2, 1 ),
973 /* MIN */ PACK( 2, 1 ),
974 /* ScanTYPE */ PACK( 1, 0 ),
975 /* InstCTRL */ PACK( 2, 0 ),
976 /* INS_$8F */ PACK( 0, 0 ),
978 /* INS_$90 */ PACK( 0, 0 ),
979 /* INS_$91 */ PACK( 0, 0 ),
980 /* INS_$92 */ PACK( 0, 0 ),
981 /* INS_$93 */ PACK( 0, 0 ),
982 /* INS_$94 */ PACK( 0, 0 ),
983 /* INS_$95 */ PACK( 0, 0 ),
984 /* INS_$96 */ PACK( 0, 0 ),
985 /* INS_$97 */ PACK( 0, 0 ),
986 /* INS_$98 */ PACK( 0, 0 ),
987 /* INS_$99 */ PACK( 0, 0 ),
988 /* INS_$9A */ PACK( 0, 0 ),
989 /* INS_$9B */ PACK( 0, 0 ),
990 /* INS_$9C */ PACK( 0, 0 ),
991 /* INS_$9D */ PACK( 0, 0 ),
992 /* INS_$9E */ PACK( 0, 0 ),
993 /* INS_$9F */ PACK( 0, 0 ),
995 /* INS_$A0 */ PACK( 0, 0 ),
996 /* INS_$A1 */ PACK( 0, 0 ),
997 /* INS_$A2 */ PACK( 0, 0 ),
998 /* INS_$A3 */ PACK( 0, 0 ),
999 /* INS_$A4 */ PACK( 0, 0 ),
1000 /* INS_$A5 */ PACK( 0, 0 ),
1001 /* INS_$A6 */ PACK( 0, 0 ),
1002 /* INS_$A7 */ PACK( 0, 0 ),
1003 /* INS_$A8 */ PACK( 0, 0 ),
1004 /* INS_$A9 */ PACK( 0, 0 ),
1005 /* INS_$AA */ PACK( 0, 0 ),
1006 /* INS_$AB */ PACK( 0, 0 ),
1007 /* INS_$AC */ PACK( 0, 0 ),
1008 /* INS_$AD */ PACK( 0, 0 ),
1009 /* INS_$AE */ PACK( 0, 0 ),
1010 /* INS_$AF */ PACK( 0, 0 ),
1012 /* PushB[0] */ PACK( 0, 1 ),
1013 /* PushB[1] */ PACK( 0, 2 ),
1014 /* PushB[2] */ PACK( 0, 3 ),
1015 /* PushB[3] */ PACK( 0, 4 ),
1016 /* PushB[4] */ PACK( 0, 5 ),
1017 /* PushB[5] */ PACK( 0, 6 ),
1018 /* PushB[6] */ PACK( 0, 7 ),
1019 /* PushB[7] */ PACK( 0, 8 ),
1020 /* PushW[0] */ PACK( 0, 1 ),
1021 /* PushW[1] */ PACK( 0, 2 ),
1022 /* PushW[2] */ PACK( 0, 3 ),
1023 /* PushW[3] */ PACK( 0, 4 ),
1024 /* PushW[4] */ PACK( 0, 5 ),
1025 /* PushW[5] */ PACK( 0, 6 ),
1026 /* PushW[6] */ PACK( 0, 7 ),
1027 /* PushW[7] */ PACK( 0, 8 ),
1029 /* MDRP[00] */ PACK( 1, 0 ),
1030 /* MDRP[01] */ PACK( 1, 0 ),
1031 /* MDRP[02] */ PACK( 1, 0 ),
1032 /* MDRP[03] */ PACK( 1, 0 ),
1033 /* MDRP[04] */ PACK( 1, 0 ),
1034 /* MDRP[05] */ PACK( 1, 0 ),
1035 /* MDRP[06] */ PACK( 1, 0 ),
1036 /* MDRP[07] */ PACK( 1, 0 ),
1037 /* MDRP[08] */ PACK( 1, 0 ),
1038 /* MDRP[09] */ PACK( 1, 0 ),
1039 /* MDRP[10] */ PACK( 1, 0 ),
1040 /* MDRP[11] */ PACK( 1, 0 ),
1041 /* MDRP[12] */ PACK( 1, 0 ),
1042 /* MDRP[13] */ PACK( 1, 0 ),
1043 /* MDRP[14] */ PACK( 1, 0 ),
1044 /* MDRP[15] */ PACK( 1, 0 ),
1046 /* MDRP[16] */ PACK( 1, 0 ),
1047 /* MDRP[17] */ PACK( 1, 0 ),
1048 /* MDRP[18] */ PACK( 1, 0 ),
1049 /* MDRP[19] */ PACK( 1, 0 ),
1050 /* MDRP[20] */ PACK( 1, 0 ),
1051 /* MDRP[21] */ PACK( 1, 0 ),
1052 /* MDRP[22] */ PACK( 1, 0 ),
1053 /* MDRP[23] */ PACK( 1, 0 ),
1054 /* MDRP[24] */ PACK( 1, 0 ),
1055 /* MDRP[25] */ PACK( 1, 0 ),
1056 /* MDRP[26] */ PACK( 1, 0 ),
1057 /* MDRP[27] */ PACK( 1, 0 ),
1058 /* MDRP[28] */ PACK( 1, 0 ),
1059 /* MDRP[29] */ PACK( 1, 0 ),
1060 /* MDRP[30] */ PACK( 1, 0 ),
1061 /* MDRP[31] */ PACK( 1, 0 ),
1063 /* MIRP[00] */ PACK( 2, 0 ),
1064 /* MIRP[01] */ PACK( 2, 0 ),
1065 /* MIRP[02] */ PACK( 2, 0 ),
1066 /* MIRP[03] */ PACK( 2, 0 ),
1067 /* MIRP[04] */ PACK( 2, 0 ),
1068 /* MIRP[05] */ PACK( 2, 0 ),
1069 /* MIRP[06] */ PACK( 2, 0 ),
1070 /* MIRP[07] */ PACK( 2, 0 ),
1071 /* MIRP[08] */ PACK( 2, 0 ),
1072 /* MIRP[09] */ PACK( 2, 0 ),
1073 /* MIRP[10] */ PACK( 2, 0 ),
1074 /* MIRP[11] */ PACK( 2, 0 ),
1075 /* MIRP[12] */ PACK( 2, 0 ),
1076 /* MIRP[13] */ PACK( 2, 0 ),
1077 /* MIRP[14] */ PACK( 2, 0 ),
1078 /* MIRP[15] */ PACK( 2, 0 ),
1080 /* MIRP[16] */ PACK( 2, 0 ),
1081 /* MIRP[17] */ PACK( 2, 0 ),
1082 /* MIRP[18] */ PACK( 2, 0 ),
1083 /* MIRP[19] */ PACK( 2, 0 ),
1084 /* MIRP[20] */ PACK( 2, 0 ),
1085 /* MIRP[21] */ PACK( 2, 0 ),
1086 /* MIRP[22] */ PACK( 2, 0 ),
1087 /* MIRP[23] */ PACK( 2, 0 ),
1088 /* MIRP[24] */ PACK( 2, 0 ),
1089 /* MIRP[25] */ PACK( 2, 0 ),
1090 /* MIRP[26] */ PACK( 2, 0 ),
1091 /* MIRP[27] */ PACK( 2, 0 ),
1092 /* MIRP[28] */ PACK( 2, 0 ),
1093 /* MIRP[29] */ PACK( 2, 0 ),
1094 /* MIRP[30] */ PACK( 2, 0 ),
1095 /* MIRP[31] */ PACK( 2, 0 )
1099 #ifdef FT_DEBUG_LEVEL_TRACE
1102 const char* const opcode_name[256] =
1377 #endif /* FT_DEBUG_LEVEL_TRACE */
1381 const FT_Char opcode_length[256] =
1383 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1384 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1385 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1386 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1388 -1,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1389 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1390 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1391 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1393 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1394 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1395 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1396 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
1398 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1399 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1400 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1401 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1407 #ifndef FT_CONFIG_OPTION_NO_ASSEMBLER
1409 #if defined( __arm__ ) && \
1410 ( defined( __thumb2__ ) || !defined( __thumb__ ) )
1412 #define TT_MulFix14 TT_MulFix14_arm
1415 TT_MulFix14_arm( FT_Int32 a,
1421 #if defined( __CC_ARM ) || defined( __ARMCC__ )
1425 smull t2, t, b, a /* (lo=t2,hi=t) = a*b */
1426 mov a, t, asr #31 /* a = (hi >> 31) */
1427 add a, a, #0x2000 /* a += 0x2000 */
1428 adds t2, t2, a /* t2 += a */
1429 adc t, t, #0 /* t += carry */
1430 mov a, t2, lsr #14 /* a = t2 >> 14 */
1431 orr a, a, t, lsl #18 /* a |= t << 18 */
1434 #elif defined( __GNUC__ )
1436 __asm__ __volatile__ (
1437 "smull %1, %2, %4, %3\n\t" /* (lo=%1,hi=%2) = a*b */
1438 "mov %0, %2, asr #31\n\t" /* %0 = (hi >> 31) */
1439 #if defined( __clang__ ) && defined( __thumb2__ )
1440 "add.w %0, %0, #0x2000\n\t" /* %0 += 0x2000 */
1442 "add %0, %0, #0x2000\n\t" /* %0 += 0x2000 */
1444 "adds %1, %1, %0\n\t" /* %1 += %0 */
1445 "adc %2, %2, #0\n\t" /* %2 += carry */
1446 "mov %0, %1, lsr #14\n\t" /* %0 = %1 >> 16 */
1447 "orr %0, %0, %2, lsl #18\n\t" /* %0 |= %2 << 16 */
1448 : "=r"(a), "=&r"(t2), "=&r"(t)
1457 #endif /* __arm__ && ( __thumb2__ || !__thumb__ ) */
1459 #endif /* !FT_CONFIG_OPTION_NO_ASSEMBLER */
1462 #if defined( __GNUC__ ) && \
1463 ( defined( __i386__ ) || defined( __x86_64__ ) )
1465 #define TT_MulFix14 TT_MulFix14_long_long
1467 /* Temporarily disable the warning that C90 doesn't support `long long'. */
1468 #if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406
1469 #pragma GCC diagnostic push
1471 #pragma GCC diagnostic ignored "-Wlong-long"
1473 /* This is declared `noinline' because inlining the function results */
1474 /* in slower code. The `pure' attribute indicates that the result */
1475 /* only depends on the parameters. */
1476 static __attribute__(( noinline ))
1477 __attribute__(( pure )) FT_Int32
1478 TT_MulFix14_long_long( FT_Int32 a,
1482 long long ret = (long long)a * b;
1484 /* The following line assumes that right shifting of signed values */
1485 /* will actually preserve the sign bit. The exact behaviour is */
1486 /* undefined, but this is true on x86 and x86_64. */
1487 long long tmp = ret >> 63;
1490 ret += 0x2000 + tmp;
1492 return (FT_Int32)( ret >> 14 );
1495 #if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406
1496 #pragma GCC diagnostic pop
1499 #endif /* __GNUC__ && ( __i386__ || __x86_64__ ) */
1504 /* Compute (a*b)/2^14 with maximum accuracy and rounding. */
1505 /* This is optimized to be faster than calling FT_MulFix() */
1506 /* for platforms where sizeof(int) == 2. */
1508 TT_MulFix14( FT_Int32 a,
1512 FT_UInt32 ah, al, mid, lo, hi;
1522 ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU );
1523 al = (FT_UInt32)( a & 0xFFFFU );
1528 mid = ( mid << 16 ) + ( 1 << 13 ); /* rounding */
1533 mid = ( lo >> 14 ) | ( hi << 18 );
1535 return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid;
1538 #endif /* !TT_MulFix14 */
1541 #if defined( __GNUC__ ) && \
1542 ( defined( __i386__ ) || \
1543 defined( __x86_64__ ) || \
1544 defined( __arm__ ) )
1546 #define TT_DotFix14 TT_DotFix14_long_long
1548 #if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406
1549 #pragma GCC diagnostic push
1551 #pragma GCC diagnostic ignored "-Wlong-long"
1553 static __attribute__(( pure )) FT_Int32
1554 TT_DotFix14_long_long( FT_Int32 ax,
1559 /* Temporarily disable the warning that C90 doesn't support */
1562 long long temp1 = (long long)ax * bx;
1563 long long temp2 = (long long)ay * by;
1567 temp2 = temp1 >> 63;
1568 temp1 += 0x2000 + temp2;
1570 return (FT_Int32)( temp1 >> 14 );
1574 #if ( __GNUC__ * 100 + __GNUC_MINOR__ ) >= 406
1575 #pragma GCC diagnostic pop
1578 #endif /* __GNUC__ && (__arm__ || __i386__ || __x86_64__) */
1583 /* compute (ax*bx+ay*by)/2^14 with maximum accuracy and rounding */
1585 TT_DotFix14( FT_Int32 ax,
1590 FT_Int32 m, s, hi1, hi2, hi;
1591 FT_UInt32 l, lo1, lo2, lo;
1594 /* compute ax*bx as 64-bit value */
1595 l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );
1596 m = ( ax >> 16 ) * bx;
1598 lo1 = l + ( (FT_UInt32)m << 16 );
1599 hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l );
1601 /* compute ay*by as 64-bit value */
1602 l = (FT_UInt32)( ( ay & 0xFFFFU ) * by );
1603 m = ( ay >> 16 ) * by;
1605 lo2 = l + ( (FT_UInt32)m << 16 );
1606 hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l );
1610 hi = hi1 + hi2 + ( lo < lo1 );
1612 /* divide the result by 2^14 with rounding */
1614 l = lo + (FT_UInt32)s;
1615 hi += s + ( l < lo );
1621 return (FT_Int32)( ( (FT_UInt32)hi << 18 ) | ( l >> 14 ) );
1624 #endif /* TT_DotFix14 */
1627 /*************************************************************************/
1633 /* Returns the current aspect ratio scaling factor depending on the */
1634 /* projection vector's state and device resolutions. */
1637 /* The aspect ratio in 16.16 format, always <= 1.0 . */
1640 Current_Ratio( EXEC_OP )
1642 if ( !CUR.tt_metrics.ratio )
1644 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1645 if ( CUR.face->unpatented_hinting )
1647 if ( CUR.GS.both_x_axis )
1648 CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
1650 CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
1655 if ( CUR.GS.projVector.y == 0 )
1656 CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
1658 else if ( CUR.GS.projVector.x == 0 )
1659 CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
1666 x = TT_MulFix14( CUR.tt_metrics.x_ratio,
1667 CUR.GS.projVector.x );
1668 y = TT_MulFix14( CUR.tt_metrics.y_ratio,
1669 CUR.GS.projVector.y );
1670 CUR.tt_metrics.ratio = FT_Hypot( x, y );
1674 return CUR.tt_metrics.ratio;
1678 FT_CALLBACK_DEF( FT_Long )
1679 Current_Ppem( EXEC_OP )
1681 return CUR.tt_metrics.ppem;
1685 FT_CALLBACK_DEF( FT_Long )
1686 Current_Ppem_Stretched( EXEC_OP )
1688 return FT_MulFix( CUR.tt_metrics.ppem, CURRENT_Ratio() );
1692 /*************************************************************************/
1694 /* Functions related to the control value table (CVT). */
1696 /*************************************************************************/
1699 FT_CALLBACK_DEF( FT_F26Dot6 )
1700 Read_CVT( EXEC_OP_ FT_ULong idx )
1702 return CUR.cvt[idx];
1706 FT_CALLBACK_DEF( FT_F26Dot6 )
1707 Read_CVT_Stretched( EXEC_OP_ FT_ULong idx )
1709 return FT_MulFix( CUR.cvt[idx], CURRENT_Ratio() );
1713 FT_CALLBACK_DEF( void )
1714 Write_CVT( EXEC_OP_ FT_ULong idx,
1717 CUR.cvt[idx] = value;
1721 FT_CALLBACK_DEF( void )
1722 Write_CVT_Stretched( EXEC_OP_ FT_ULong idx,
1725 CUR.cvt[idx] = FT_DivFix( value, CURRENT_Ratio() );
1729 FT_CALLBACK_DEF( void )
1730 Move_CVT( EXEC_OP_ FT_ULong idx,
1733 CUR.cvt[idx] += value;
1737 FT_CALLBACK_DEF( void )
1738 Move_CVT_Stretched( EXEC_OP_ FT_ULong idx,
1741 CUR.cvt[idx] += FT_DivFix( value, CURRENT_Ratio() );
1745 /*************************************************************************/
1751 /* Returns a short integer taken from the instruction stream at */
1755 /* Short read at code[IP]. */
1758 /* This one could become a macro. */
1761 GetShortIns( EXEC_OP )
1763 /* Reading a byte stream so there is no endianess (DaveP) */
1765 return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) +
1766 CUR.code[CUR.IP - 1] );
1770 /*************************************************************************/
1773 /* Ins_Goto_CodeRange */
1776 /* Goes to a certain code range in the instruction stream. */
1779 /* aRange :: The index of the code range. */
1781 /* aIP :: The new IP address in the code range. */
1784 /* SUCCESS or FAILURE. */
1787 Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange,
1790 TT_CodeRange* range;
1793 if ( aRange < 1 || aRange > 3 )
1795 CUR.error = FT_THROW( Bad_Argument );
1799 range = &CUR.codeRangeTable[aRange - 1];
1801 if ( range->base == NULL ) /* invalid coderange */
1803 CUR.error = FT_THROW( Invalid_CodeRange );
1807 /* NOTE: Because the last instruction of a program may be a CALL */
1808 /* which will return to the first byte *after* the code */
1809 /* range, we test for aIP <= Size, instead of aIP < Size. */
1811 if ( aIP > range->size )
1813 CUR.error = FT_THROW( Code_Overflow );
1817 CUR.code = range->base;
1818 CUR.codeSize = range->size;
1820 CUR.curRange = aRange;
1826 /*************************************************************************/
1832 /* Moves a point by a given distance along the freedom vector. The */
1833 /* point will be `touched'. */
1836 /* point :: The index of the point to move. */
1838 /* distance :: The distance to apply. */
1841 /* zone :: The affected glyph zone. */
1844 Direct_Move( EXEC_OP_ TT_GlyphZone zone,
1846 FT_F26Dot6 distance )
1851 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1852 FT_ASSERT( !CUR.face->unpatented_hinting );
1855 v = CUR.GS.freeVector.x;
1859 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
1860 if ( !SUBPIXEL_HINTING ||
1861 ( !CUR.ignore_x_mode ||
1862 ( CUR.sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) ) )
1863 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
1864 zone->cur[point].x += FT_MulDiv( distance, v, CUR.F_dot_P );
1866 zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
1869 v = CUR.GS.freeVector.y;
1873 zone->cur[point].y += FT_MulDiv( distance, v, CUR.F_dot_P );
1875 zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1880 /*************************************************************************/
1883 /* Direct_Move_Orig */
1886 /* Moves the *original* position of a point by a given distance along */
1887 /* the freedom vector. Obviously, the point will not be `touched'. */
1890 /* point :: The index of the point to move. */
1892 /* distance :: The distance to apply. */
1895 /* zone :: The affected glyph zone. */
1898 Direct_Move_Orig( EXEC_OP_ TT_GlyphZone zone,
1900 FT_F26Dot6 distance )
1905 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1906 FT_ASSERT( !CUR.face->unpatented_hinting );
1909 v = CUR.GS.freeVector.x;
1912 zone->org[point].x += FT_MulDiv( distance, v, CUR.F_dot_P );
1914 v = CUR.GS.freeVector.y;
1917 zone->org[point].y += FT_MulDiv( distance, v, CUR.F_dot_P );
1921 /*************************************************************************/
1923 /* Special versions of Direct_Move() */
1925 /* The following versions are used whenever both vectors are both */
1926 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1928 /*************************************************************************/
1932 Direct_Move_X( EXEC_OP_ TT_GlyphZone zone,
1934 FT_F26Dot6 distance )
1938 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
1939 if ( !SUBPIXEL_HINTING ||
1940 !CUR.ignore_x_mode )
1941 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
1942 zone->cur[point].x += distance;
1944 zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
1949 Direct_Move_Y( EXEC_OP_ TT_GlyphZone zone,
1951 FT_F26Dot6 distance )
1955 zone->cur[point].y += distance;
1956 zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1960 /*************************************************************************/
1962 /* Special versions of Direct_Move_Orig() */
1964 /* The following versions are used whenever both vectors are both */
1965 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1967 /*************************************************************************/
1971 Direct_Move_Orig_X( EXEC_OP_ TT_GlyphZone zone,
1973 FT_F26Dot6 distance )
1977 zone->org[point].x += distance;
1982 Direct_Move_Orig_Y( EXEC_OP_ TT_GlyphZone zone,
1984 FT_F26Dot6 distance )
1988 zone->org[point].y += distance;
1992 /*************************************************************************/
1998 /* Does not round, but adds engine compensation. */
2001 /* distance :: The distance (not) to round. */
2003 /* compensation :: The engine compensation. */
2006 /* The compensated distance. */
2009 /* The TrueType specification says very few about the relationship */
2010 /* between rounding and engine compensation. However, it seems from */
2011 /* the description of super round that we should add the compensation */
2012 /* before rounding. */
2015 Round_None( EXEC_OP_ FT_F26Dot6 distance,
2016 FT_F26Dot6 compensation )
2023 if ( distance >= 0 )
2025 val = distance + compensation;
2031 val = distance - compensation;
2039 /*************************************************************************/
2045 /* Rounds value to grid after adding engine compensation. */
2048 /* distance :: The distance to round. */
2050 /* compensation :: The engine compensation. */
2053 /* Rounded distance. */
2056 Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
2057 FT_F26Dot6 compensation )
2064 if ( distance >= 0 )
2066 val = FT_PIX_ROUND( distance + compensation );
2072 val = -FT_PIX_ROUND( compensation - distance );
2081 /*************************************************************************/
2084 /* Round_To_Half_Grid */
2087 /* Rounds value to half grid after adding engine compensation. */
2090 /* distance :: The distance to round. */
2092 /* compensation :: The engine compensation. */
2095 /* Rounded distance. */
2098 Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance,
2099 FT_F26Dot6 compensation )
2106 if ( distance >= 0 )
2108 val = FT_PIX_FLOOR( distance + compensation ) + 32;
2114 val = -( FT_PIX_FLOOR( compensation - distance ) + 32 );
2123 /*************************************************************************/
2126 /* Round_Down_To_Grid */
2129 /* Rounds value down to grid after adding engine compensation. */
2132 /* distance :: The distance to round. */
2134 /* compensation :: The engine compensation. */
2137 /* Rounded distance. */
2140 Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
2141 FT_F26Dot6 compensation )
2148 if ( distance >= 0 )
2150 val = FT_PIX_FLOOR( distance + compensation );
2156 val = -FT_PIX_FLOOR( compensation - distance );
2165 /*************************************************************************/
2168 /* Round_Up_To_Grid */
2171 /* Rounds value up to grid after adding engine compensation. */
2174 /* distance :: The distance to round. */
2176 /* compensation :: The engine compensation. */
2179 /* Rounded distance. */
2182 Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
2183 FT_F26Dot6 compensation )
2190 if ( distance >= 0 )
2192 val = FT_PIX_CEIL( distance + compensation );
2198 val = -FT_PIX_CEIL( compensation - distance );
2207 /*************************************************************************/
2210 /* Round_To_Double_Grid */
2213 /* Rounds value to double grid after adding engine compensation. */
2216 /* distance :: The distance to round. */
2218 /* compensation :: The engine compensation. */
2221 /* Rounded distance. */
2224 Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance,
2225 FT_F26Dot6 compensation )
2232 if ( distance >= 0 )
2234 val = FT_PAD_ROUND( distance + compensation, 32 );
2240 val = -FT_PAD_ROUND( compensation - distance, 32 );
2249 /*************************************************************************/
2255 /* Super-rounds value to grid after adding engine compensation. */
2258 /* distance :: The distance to round. */
2260 /* compensation :: The engine compensation. */
2263 /* Rounded distance. */
2266 /* The TrueType specification says very few about the relationship */
2267 /* between rounding and engine compensation. However, it seems from */
2268 /* the description of super round that we should add the compensation */
2269 /* before rounding. */
2272 Round_Super( EXEC_OP_ FT_F26Dot6 distance,
2273 FT_F26Dot6 compensation )
2278 if ( distance >= 0 )
2280 val = ( distance - CUR.phase + CUR.threshold + compensation ) &
2288 val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &
2299 /*************************************************************************/
2302 /* Round_Super_45 */
2305 /* Super-rounds value to grid after adding engine compensation. */
2308 /* distance :: The distance to round. */
2310 /* compensation :: The engine compensation. */
2313 /* Rounded distance. */
2316 /* There is a separate function for Round_Super_45() as we may need */
2317 /* greater precision. */
2320 Round_Super_45( EXEC_OP_ FT_F26Dot6 distance,
2321 FT_F26Dot6 compensation )
2326 if ( distance >= 0 )
2328 val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
2329 CUR.period ) * CUR.period;
2336 val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /
2337 CUR.period ) * CUR.period );
2347 /*************************************************************************/
2353 /* Sets the rounding mode. */
2356 /* round_mode :: The rounding mode to be used. */
2359 Compute_Round( EXEC_OP_ FT_Byte round_mode )
2361 switch ( round_mode )
2364 CUR.func_round = (TT_Round_Func)Round_None;
2367 case TT_Round_To_Grid:
2368 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2371 case TT_Round_Up_To_Grid:
2372 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2375 case TT_Round_Down_To_Grid:
2376 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2379 case TT_Round_To_Half_Grid:
2380 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2383 case TT_Round_To_Double_Grid:
2384 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2387 case TT_Round_Super:
2388 CUR.func_round = (TT_Round_Func)Round_Super;
2391 case TT_Round_Super_45:
2392 CUR.func_round = (TT_Round_Func)Round_Super_45;
2398 /*************************************************************************/
2404 /* Sets Super Round parameters. */
2407 /* GridPeriod :: The grid period. */
2409 /* selector :: The SROUND opcode. */
2412 SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod,
2415 switch ( (FT_Int)( selector & 0xC0 ) )
2418 CUR.period = GridPeriod / 2;
2422 CUR.period = GridPeriod;
2426 CUR.period = GridPeriod * 2;
2429 /* This opcode is reserved, but... */
2432 CUR.period = GridPeriod;
2436 switch ( (FT_Int)( selector & 0x30 ) )
2443 CUR.phase = CUR.period / 4;
2447 CUR.phase = CUR.period / 2;
2451 CUR.phase = CUR.period * 3 / 4;
2455 if ( ( selector & 0x0F ) == 0 )
2456 CUR.threshold = CUR.period - 1;
2458 CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8;
2462 CUR.threshold /= 256;
2466 /*************************************************************************/
2472 /* Computes the projection of vector given by (v2-v1) along the */
2473 /* current projection vector. */
2476 /* v1 :: First input vector. */
2477 /* v2 :: Second input vector. */
2480 /* The distance in F26dot6 format. */
2483 Project( EXEC_OP_ FT_Pos dx,
2486 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2487 FT_ASSERT( !CUR.face->unpatented_hinting );
2490 return TT_DotFix14( (FT_UInt32)dx, (FT_UInt32)dy,
2491 CUR.GS.projVector.x,
2492 CUR.GS.projVector.y );
2496 /*************************************************************************/
2502 /* Computes the projection of the vector given by (v2-v1) along the */
2503 /* current dual vector. */
2506 /* v1 :: First input vector. */
2507 /* v2 :: Second input vector. */
2510 /* The distance in F26dot6 format. */
2513 Dual_Project( EXEC_OP_ FT_Pos dx,
2516 return TT_DotFix14( (FT_UInt32)dx, (FT_UInt32)dy,
2517 CUR.GS.dualVector.x,
2518 CUR.GS.dualVector.y );
2522 /*************************************************************************/
2528 /* Computes the projection of the vector given by (v2-v1) along the */
2529 /* horizontal axis. */
2532 /* v1 :: First input vector. */
2533 /* v2 :: Second input vector. */
2536 /* The distance in F26dot6 format. */
2539 Project_x( EXEC_OP_ FT_Pos dx,
2549 /*************************************************************************/
2555 /* Computes the projection of the vector given by (v2-v1) along the */
2556 /* vertical axis. */
2559 /* v1 :: First input vector. */
2560 /* v2 :: Second input vector. */
2563 /* The distance in F26dot6 format. */
2566 Project_y( EXEC_OP_ FT_Pos dx,
2576 /*************************************************************************/
2582 /* Computes the projection and movement function pointers according */
2583 /* to the current graphics state. */
2586 Compute_Funcs( EXEC_OP )
2588 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2589 if ( CUR.face->unpatented_hinting )
2591 /* If both vectors point rightwards along the x axis, set */
2592 /* `both-x-axis' true, otherwise set it false. The x values only */
2593 /* need be tested because the vector has been normalised to a unit */
2594 /* vector of length 0x4000 = unity. */
2595 CUR.GS.both_x_axis = (FT_Bool)( CUR.GS.projVector.x == 0x4000 &&
2596 CUR.GS.freeVector.x == 0x4000 );
2598 /* Throw away projection and freedom vector information */
2599 /* because the patents don't allow them to be stored. */
2600 /* The relevant US Patents are 5155805 and 5325479. */
2601 CUR.GS.projVector.x = 0;
2602 CUR.GS.projVector.y = 0;
2603 CUR.GS.freeVector.x = 0;
2604 CUR.GS.freeVector.y = 0;
2606 if ( CUR.GS.both_x_axis )
2608 CUR.func_project = Project_x;
2609 CUR.func_move = Direct_Move_X;
2610 CUR.func_move_orig = Direct_Move_Orig_X;
2614 CUR.func_project = Project_y;
2615 CUR.func_move = Direct_Move_Y;
2616 CUR.func_move_orig = Direct_Move_Orig_Y;
2619 if ( CUR.GS.dualVector.x == 0x4000 )
2620 CUR.func_dualproj = Project_x;
2621 else if ( CUR.GS.dualVector.y == 0x4000 )
2622 CUR.func_dualproj = Project_y;
2624 CUR.func_dualproj = Dual_Project;
2626 /* Force recalculation of cached aspect ratio */
2627 CUR.tt_metrics.ratio = 0;
2631 #endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING */
2633 if ( CUR.GS.freeVector.x == 0x4000 )
2634 CUR.F_dot_P = CUR.GS.projVector.x;
2635 else if ( CUR.GS.freeVector.y == 0x4000 )
2636 CUR.F_dot_P = CUR.GS.projVector.y;
2638 CUR.F_dot_P = ( (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x +
2639 (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y ) >>
2642 if ( CUR.GS.projVector.x == 0x4000 )
2643 CUR.func_project = (TT_Project_Func)Project_x;
2644 else if ( CUR.GS.projVector.y == 0x4000 )
2645 CUR.func_project = (TT_Project_Func)Project_y;
2647 CUR.func_project = (TT_Project_Func)Project;
2649 if ( CUR.GS.dualVector.x == 0x4000 )
2650 CUR.func_dualproj = (TT_Project_Func)Project_x;
2651 else if ( CUR.GS.dualVector.y == 0x4000 )
2652 CUR.func_dualproj = (TT_Project_Func)Project_y;
2654 CUR.func_dualproj = (TT_Project_Func)Dual_Project;
2656 CUR.func_move = (TT_Move_Func)Direct_Move;
2657 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig;
2659 if ( CUR.F_dot_P == 0x4000L )
2661 if ( CUR.GS.freeVector.x == 0x4000 )
2663 CUR.func_move = (TT_Move_Func)Direct_Move_X;
2664 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;
2666 else if ( CUR.GS.freeVector.y == 0x4000 )
2668 CUR.func_move = (TT_Move_Func)Direct_Move_Y;
2669 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
2673 /* at small sizes, F_dot_P can become too small, resulting */
2674 /* in overflows and `spikes' in a number of glyphs like `w'. */
2676 if ( FT_ABS( CUR.F_dot_P ) < 0x400L )
2677 CUR.F_dot_P = 0x4000L;
2679 /* Disable cached aspect ratio */
2680 CUR.tt_metrics.ratio = 0;
2684 /*************************************************************************/
2690 /* Norms a vector. */
2693 /* Vx :: The horizontal input vector coordinate. */
2694 /* Vy :: The vertical input vector coordinate. */
2697 /* R :: The normed unit vector. */
2700 /* Returns FAILURE if a vector parameter is zero. */
2703 /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
2704 /* R is undefined. */
2707 Normalize( EXEC_OP_ FT_F26Dot6 Vx,
2716 if ( FT_ABS( Vx ) < 0x4000L && FT_ABS( Vy ) < 0x4000L )
2718 if ( Vx == 0 && Vy == 0 )
2720 /* XXX: UNDOCUMENTED! It seems that it is possible to try */
2721 /* to normalize the vector (0,0). Return immediately. */
2729 W = FT_Hypot( Vx, Vy );
2731 R->x = (FT_F2Dot14)TT_DivFix14( Vx, W );
2732 R->y = (FT_F2Dot14)TT_DivFix14( Vy, W );
2738 /*************************************************************************/
2740 /* Here we start with the implementation of the various opcodes. */
2742 /*************************************************************************/
2746 Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1,
2749 FT_UnitVector* Vec )
2756 if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
2757 BOUNDS( aIdx2, CUR.zp1.n_points ) )
2759 if ( CUR.pedantic_hinting )
2760 CUR.error = FT_THROW( Invalid_Reference );
2764 p1 = CUR.zp1.cur + aIdx2;
2765 p2 = CUR.zp2.cur + aIdx1;
2770 /* If p1 == p2, SPVTL and SFVTL behave the same as */
2771 /* SPVTCA[X] and SFVTCA[X], respectively. */
2773 /* Confirmed by Greg Hitchcock. */
2775 if ( A == 0 && B == 0 )
2781 if ( ( aOpc & 1 ) != 0 )
2783 C = B; /* counter clockwise rotation */
2788 NORMalize( A, B, Vec );
2794 /* When not using the big switch statements, the interpreter uses a */
2795 /* call table defined later below in this source. Each opcode must */
2796 /* thus have a corresponding function, even trivial ones. */
2798 /* They are all defined there. */
2805 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2806 B = A ^ (FT_Short)0x4000; \
2808 CUR.GS.freeVector.x = A; \
2809 CUR.GS.projVector.x = A; \
2810 CUR.GS.dualVector.x = A; \
2812 CUR.GS.freeVector.y = B; \
2813 CUR.GS.projVector.y = B; \
2814 CUR.GS.dualVector.y = B; \
2825 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2826 B = A ^ (FT_Short)0x4000; \
2828 CUR.GS.projVector.x = A; \
2829 CUR.GS.dualVector.x = A; \
2831 CUR.GS.projVector.y = B; \
2832 CUR.GS.dualVector.y = B; \
2834 GUESS_VECTOR( freeVector ); \
2845 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2846 B = A ^ (FT_Short)0x4000; \
2848 CUR.GS.freeVector.x = A; \
2849 CUR.GS.freeVector.y = B; \
2851 GUESS_VECTOR( projVector ); \
2858 if ( INS_SxVTL( (FT_UShort)args[1], \
2859 (FT_UShort)args[0], \
2861 &CUR.GS.projVector ) == SUCCESS ) \
2863 CUR.GS.dualVector = CUR.GS.projVector; \
2864 GUESS_VECTOR( freeVector ); \
2870 if ( INS_SxVTL( (FT_UShort)args[1], \
2871 (FT_UShort)args[0], \
2873 &CUR.GS.freeVector ) == SUCCESS ) \
2875 GUESS_VECTOR( projVector ); \
2881 GUESS_VECTOR( projVector ); \
2882 CUR.GS.freeVector = CUR.GS.projVector; \
2892 /* Only use low 16bits, then sign extend */ \
2893 S = (FT_Short)args[1]; \
2895 S = (FT_Short)args[0]; \
2898 NORMalize( X, Y, &CUR.GS.projVector ); \
2900 CUR.GS.dualVector = CUR.GS.projVector; \
2901 GUESS_VECTOR( freeVector ); \
2912 /* Only use low 16bits, then sign extend */ \
2913 S = (FT_Short)args[1]; \
2915 S = (FT_Short)args[0]; \
2918 NORMalize( X, Y, &CUR.GS.freeVector ); \
2919 GUESS_VECTOR( projVector ); \
2924 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2926 if ( CUR.face->unpatented_hinting ) \
2928 args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
2929 args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
2933 args[0] = CUR.GS.projVector.x; \
2934 args[1] = CUR.GS.projVector.y; \
2938 args[0] = CUR.GS.projVector.x; \
2939 args[1] = CUR.GS.projVector.y;
2943 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2945 if ( CUR.face->unpatented_hinting ) \
2947 args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
2948 args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
2952 args[0] = CUR.GS.freeVector.x; \
2953 args[1] = CUR.GS.freeVector.y; \
2957 args[0] = CUR.GS.freeVector.x; \
2958 args[1] = CUR.GS.freeVector.y;
2963 CUR.GS.rp0 = (FT_UShort)args[0];
2967 CUR.GS.rp1 = (FT_UShort)args[0];
2971 CUR.GS.rp2 = (FT_UShort)args[0];
2975 CUR.GS.round_state = TT_Round_To_Half_Grid; \
2976 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2980 CUR.GS.round_state = TT_Round_To_Grid; \
2981 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2985 CUR.GS.round_state = TT_Round_To_Double_Grid; \
2986 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2990 CUR.GS.round_state = TT_Round_Up_To_Grid; \
2991 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2995 CUR.GS.round_state = TT_Round_Down_To_Grid; \
2996 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
3000 CUR.GS.round_state = TT_Round_Off; \
3001 CUR.func_round = (TT_Round_Func)Round_None;
3005 SET_SuperRound( 0x4000, args[0] ); \
3006 CUR.GS.round_state = TT_Round_Super; \
3007 CUR.func_round = (TT_Round_Func)Round_Super;
3010 #define DO_S45ROUND \
3011 SET_SuperRound( 0x2D41, args[0] ); \
3012 CUR.GS.round_state = TT_Round_Super_45; \
3013 CUR.func_round = (TT_Round_Func)Round_Super_45;
3017 if ( args[0] < 0 ) \
3018 CUR.error = FT_THROW( Bad_Argument ); \
3020 CUR.GS.loop = args[0];
3024 CUR.GS.minimum_distance = args[0];
3028 CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
3032 CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
3036 CUR.GS.single_width_value = FT_MulFix( args[0], \
3037 CUR.tt_metrics.scale );
3041 CUR.GS.auto_flip = TRUE;
3044 #define DO_FLIPOFF \
3045 CUR.GS.auto_flip = FALSE;
3049 CUR.GS.delta_base = (FT_UShort)args[0];
3053 if ( (FT_ULong)args[0] > 6UL ) \
3054 CUR.error = FT_THROW( Bad_Argument ); \
3056 CUR.GS.delta_shift = (FT_UShort)args[0];
3059 #define DO_MD /* nothing */
3063 args[0] = CUR_Func_cur_ppem();
3066 /* Note: The pointSize should be irrelevant in a given font program; */
3067 /* we thus decide to return only the ppem. */
3071 args[0] = CUR.metrics.pointSize;
3076 args[0] = CUR_Func_cur_ppem();
3095 args[0] = args[1]; \
3111 if ( L <= 0 || L > CUR.args ) \
3113 if ( CUR.pedantic_hinting ) \
3114 CUR.error = FT_THROW( Invalid_Reference ); \
3118 args[0] = CUR.stack[CUR.args - L]; \
3123 if ( args[1] != 0 ) \
3125 if ( args[0] == 0 && CUR.args == 0 ) \
3126 CUR.error = FT_THROW( Bad_Argument ); \
3127 CUR.IP += args[0]; \
3128 if ( CUR.IP < 0 || \
3129 ( CUR.callTop > 0 && \
3130 CUR.IP > CUR.callStack[CUR.callTop - 1].Def->end ) ) \
3131 CUR.error = FT_THROW( Bad_Argument ); \
3132 CUR.step_ins = FALSE; \
3137 if ( args[0] == 0 && CUR.args == 0 ) \
3138 CUR.error = FT_THROW( Bad_Argument ); \
3139 CUR.IP += args[0]; \
3140 if ( CUR.IP < 0 || \
3141 ( CUR.callTop > 0 && \
3142 CUR.IP > CUR.callStack[CUR.callTop - 1].Def->end ) ) \
3143 CUR.error = FT_THROW( Bad_Argument ); \
3144 CUR.step_ins = FALSE;
3148 if ( args[1] == 0 ) \
3150 if ( args[0] == 0 && CUR.args == 0 ) \
3151 CUR.error = FT_THROW( Bad_Argument ); \
3152 CUR.IP += args[0]; \
3153 if ( CUR.IP < 0 || \
3154 ( CUR.callTop > 0 && \
3155 CUR.IP > CUR.callStack[CUR.callTop - 1].Def->end ) ) \
3156 CUR.error = FT_THROW( Bad_Argument ); \
3157 CUR.step_ins = FALSE; \
3162 args[0] = ( args[0] < args[1] );
3166 args[0] = ( args[0] <= args[1] );
3170 args[0] = ( args[0] > args[1] );
3174 args[0] = ( args[0] >= args[1] );
3178 args[0] = ( args[0] == args[1] );
3182 args[0] = ( args[0] != args[1] );
3186 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
3190 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
3194 args[0] = ( args[0] && args[1] );
3198 args[0] = ( args[0] || args[1] );
3214 if ( args[1] == 0 ) \
3215 CUR.error = FT_THROW( Divide_By_Zero ); \
3217 args[0] = FT_MulDiv_No_Round( args[0], 64L, args[1] );
3221 args[0] = FT_MulDiv( args[0], args[1], 64L );
3225 args[0] = FT_ABS( args[0] );
3233 args[0] = FT_PIX_FLOOR( args[0] );
3236 #define DO_CEILING \
3237 args[0] = FT_PIX_CEIL( args[0] );
3239 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
3243 FT_ULong I = (FT_ULong)args[0]; \
3246 if ( BOUNDSL( I, CUR.storeSize ) ) \
3248 if ( CUR.pedantic_hinting ) \
3249 ARRAY_BOUND_ERROR; \
3255 /* subpixel hinting - avoid Typeman Dstroke and */ \
3256 /* IStroke and Vacuform rounds */ \
3258 if ( SUBPIXEL_HINTING && \
3259 CUR.ignore_x_mode && \
3261 ( CUR.face->sph_found_func_flags & \
3262 ( SPH_FDEF_SPACING_1 | \
3263 SPH_FDEF_SPACING_2 ) ) ) || \
3265 ( CUR.sph_in_func_flags & \
3266 SPH_FDEF_TYPEMAN_STROKES ) ) || \
3268 ( CUR.face->sph_found_func_flags & \
3269 SPH_FDEF_VACUFORM_ROUND_1 ) && \
3270 CUR.iup_called ) ) ) \
3273 args[0] = CUR.storage[I]; \
3277 #else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
3281 FT_ULong I = (FT_ULong)args[0]; \
3284 if ( BOUNDSL( I, CUR.storeSize ) ) \
3286 if ( CUR.pedantic_hinting ) \
3288 ARRAY_BOUND_ERROR; \
3294 args[0] = CUR.storage[I]; \
3297 #endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
3302 FT_ULong I = (FT_ULong)args[0]; \
3305 if ( BOUNDSL( I, CUR.storeSize ) ) \
3307 if ( CUR.pedantic_hinting ) \
3309 ARRAY_BOUND_ERROR; \
3313 CUR.storage[I] = args[1]; \
3319 FT_ULong I = (FT_ULong)args[0]; \
3322 if ( BOUNDSL( I, CUR.cvtSize ) ) \
3324 if ( CUR.pedantic_hinting ) \
3326 ARRAY_BOUND_ERROR; \
3332 args[0] = CUR_Func_read_cvt( I ); \
3338 FT_ULong I = (FT_ULong)args[0]; \
3341 if ( BOUNDSL( I, CUR.cvtSize ) ) \
3343 if ( CUR.pedantic_hinting ) \
3345 ARRAY_BOUND_ERROR; \
3349 CUR_Func_write_cvt( I, args[1] ); \
3355 FT_ULong I = (FT_ULong)args[0]; \
3358 if ( BOUNDSL( I, CUR.cvtSize ) ) \
3360 if ( CUR.pedantic_hinting ) \
3362 ARRAY_BOUND_ERROR; \
3366 CUR.cvt[I] = FT_MulFix( args[1], CUR.tt_metrics.scale ); \
3371 CUR.error = FT_THROW( Debug_OpCode );
3375 args[0] = CUR_Func_round( \
3377 CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
3381 args[0] = ROUND_None( args[0], \
3382 CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
3386 if ( args[1] > args[0] ) \
3391 if ( args[1] < args[0] ) \
3395 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
3398 #undef ARRAY_BOUND_ERROR
3399 #define ARRAY_BOUND_ERROR \
3401 CUR.error = FT_THROW( Invalid_Reference ); \
3406 /*************************************************************************/
3408 /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
3409 /* Opcode range: 0x00-0x01 */
3413 Ins_SVTCA( INS_ARG )
3419 /*************************************************************************/
3421 /* SPVTCA[a]: Set PVector to Coordinate Axis */
3422 /* Opcode range: 0x02-0x03 */
3426 Ins_SPVTCA( INS_ARG )
3432 /*************************************************************************/
3434 /* SFVTCA[a]: Set FVector to Coordinate Axis */
3435 /* Opcode range: 0x04-0x05 */
3439 Ins_SFVTCA( INS_ARG )
3445 /*************************************************************************/
3447 /* SPVTL[a]: Set PVector To Line */
3448 /* Opcode range: 0x06-0x07 */
3449 /* Stack: uint32 uint32 --> */
3452 Ins_SPVTL( INS_ARG )
3458 /*************************************************************************/
3460 /* SFVTL[a]: Set FVector To Line */
3461 /* Opcode range: 0x08-0x09 */
3462 /* Stack: uint32 uint32 --> */
3465 Ins_SFVTL( INS_ARG )
3471 /*************************************************************************/
3473 /* SFVTPV[]: Set FVector To PVector */
3474 /* Opcode range: 0x0E */
3478 Ins_SFVTPV( INS_ARG )
3484 /*************************************************************************/
3486 /* SPVFS[]: Set PVector From Stack */
3487 /* Opcode range: 0x0A */
3488 /* Stack: f2.14 f2.14 --> */
3491 Ins_SPVFS( INS_ARG )
3497 /*************************************************************************/
3499 /* SFVFS[]: Set FVector From Stack */
3500 /* Opcode range: 0x0B */
3501 /* Stack: f2.14 f2.14 --> */
3504 Ins_SFVFS( INS_ARG )
3510 /*************************************************************************/
3512 /* GPV[]: Get Projection Vector */
3513 /* Opcode range: 0x0C */
3514 /* Stack: ef2.14 --> ef2.14 */
3523 /*************************************************************************/
3524 /* GFV[]: Get Freedom Vector */
3525 /* Opcode range: 0x0D */
3526 /* Stack: ef2.14 --> ef2.14 */
3535 /*************************************************************************/
3537 /* SRP0[]: Set Reference Point 0 */
3538 /* Opcode range: 0x10 */
3539 /* Stack: uint32 --> */
3548 /*************************************************************************/
3550 /* SRP1[]: Set Reference Point 1 */
3551 /* Opcode range: 0x11 */
3552 /* Stack: uint32 --> */
3561 /*************************************************************************/
3563 /* SRP2[]: Set Reference Point 2 */
3564 /* Opcode range: 0x12 */
3565 /* Stack: uint32 --> */
3574 /*************************************************************************/
3576 /* RTHG[]: Round To Half Grid */
3577 /* Opcode range: 0x19 */
3587 /*************************************************************************/
3589 /* RTG[]: Round To Grid */
3590 /* Opcode range: 0x18 */
3600 /*************************************************************************/
3601 /* RTDG[]: Round To Double Grid */
3602 /* Opcode range: 0x3D */
3612 /*************************************************************************/
3613 /* RUTG[]: Round Up To Grid */
3614 /* Opcode range: 0x7C */
3624 /*************************************************************************/
3626 /* RDTG[]: Round Down To Grid */
3627 /* Opcode range: 0x7D */
3637 /*************************************************************************/
3639 /* ROFF[]: Round OFF */
3640 /* Opcode range: 0x7A */
3650 /*************************************************************************/
3652 /* SROUND[]: Super ROUND */
3653 /* Opcode range: 0x76 */
3654 /* Stack: Eint8 --> */
3657 Ins_SROUND( INS_ARG )
3663 /*************************************************************************/
3665 /* S45ROUND[]: Super ROUND 45 degrees */
3666 /* Opcode range: 0x77 */
3667 /* Stack: uint32 --> */
3670 Ins_S45ROUND( INS_ARG )
3676 /*************************************************************************/
3678 /* SLOOP[]: Set LOOP variable */
3679 /* Opcode range: 0x17 */
3680 /* Stack: int32? --> */
3683 Ins_SLOOP( INS_ARG )
3689 /*************************************************************************/
3691 /* SMD[]: Set Minimum Distance */
3692 /* Opcode range: 0x1A */
3693 /* Stack: f26.6 --> */
3702 /*************************************************************************/
3704 /* SCVTCI[]: Set Control Value Table Cut In */
3705 /* Opcode range: 0x1D */
3706 /* Stack: f26.6 --> */
3709 Ins_SCVTCI( INS_ARG )
3715 /*************************************************************************/
3717 /* SSWCI[]: Set Single Width Cut In */
3718 /* Opcode range: 0x1E */
3719 /* Stack: f26.6 --> */
3722 Ins_SSWCI( INS_ARG )
3728 /*************************************************************************/
3730 /* SSW[]: Set Single Width */
3731 /* Opcode range: 0x1F */
3732 /* Stack: int32? --> */
3741 /*************************************************************************/
3743 /* FLIPON[]: Set auto-FLIP to ON */
3744 /* Opcode range: 0x4D */
3748 Ins_FLIPON( INS_ARG )
3754 /*************************************************************************/
3756 /* FLIPOFF[]: Set auto-FLIP to OFF */
3757 /* Opcode range: 0x4E */
3761 Ins_FLIPOFF( INS_ARG )
3767 /*************************************************************************/
3769 /* SANGW[]: Set ANGle Weight */
3770 /* Opcode range: 0x7E */
3771 /* Stack: uint32 --> */
3774 Ins_SANGW( INS_ARG )
3776 /* instruction not supported anymore */
3780 /*************************************************************************/
3782 /* SDB[]: Set Delta Base */
3783 /* Opcode range: 0x5E */
3784 /* Stack: uint32 --> */
3793 /*************************************************************************/
3795 /* SDS[]: Set Delta Shift */
3796 /* Opcode range: 0x5F */
3797 /* Stack: uint32 --> */
3806 /*************************************************************************/
3808 /* MPPEM[]: Measure Pixel Per EM */
3809 /* Opcode range: 0x4B */
3810 /* Stack: --> Euint16 */
3813 Ins_MPPEM( INS_ARG )
3819 /*************************************************************************/
3821 /* MPS[]: Measure Point Size */
3822 /* Opcode range: 0x4C */
3823 /* Stack: --> Euint16 */
3832 /*************************************************************************/
3834 /* DUP[]: DUPlicate the top stack's element */
3835 /* Opcode range: 0x20 */
3836 /* Stack: StkElt --> StkElt StkElt */
3845 /*************************************************************************/
3847 /* POP[]: POP the stack's top element */
3848 /* Opcode range: 0x21 */
3849 /* Stack: StkElt --> */
3858 /*************************************************************************/
3860 /* CLEAR[]: CLEAR the entire stack */
3861 /* Opcode range: 0x22 */
3862 /* Stack: StkElt... --> */
3865 Ins_CLEAR( INS_ARG )
3871 /*************************************************************************/
3873 /* SWAP[]: SWAP the stack's top two elements */
3874 /* Opcode range: 0x23 */
3875 /* Stack: 2 * StkElt --> 2 * StkElt */
3884 /*************************************************************************/
3886 /* DEPTH[]: return the stack DEPTH */
3887 /* Opcode range: 0x24 */
3888 /* Stack: --> uint32 */
3891 Ins_DEPTH( INS_ARG )
3897 /*************************************************************************/
3899 /* CINDEX[]: Copy INDEXed element */
3900 /* Opcode range: 0x25 */
3901 /* Stack: int32 --> StkElt */
3904 Ins_CINDEX( INS_ARG )
3910 /*************************************************************************/
3913 /* Opcode range: 0x59 */
3923 /*************************************************************************/
3925 /* JROT[]: Jump Relative On True */
3926 /* Opcode range: 0x78 */
3927 /* Stack: StkElt int32 --> */
3936 /*************************************************************************/
3938 /* JMPR[]: JuMP Relative */
3939 /* Opcode range: 0x1C */
3940 /* Stack: int32 --> */
3949 /*************************************************************************/
3951 /* JROF[]: Jump Relative On False */
3952 /* Opcode range: 0x79 */
3953 /* Stack: StkElt int32 --> */
3962 /*************************************************************************/
3964 /* LT[]: Less Than */
3965 /* Opcode range: 0x50 */
3966 /* Stack: int32? int32? --> bool */
3975 /*************************************************************************/
3977 /* LTEQ[]: Less Than or EQual */
3978 /* Opcode range: 0x51 */
3979 /* Stack: int32? int32? --> bool */
3988 /*************************************************************************/
3990 /* GT[]: Greater Than */
3991 /* Opcode range: 0x52 */
3992 /* Stack: int32? int32? --> bool */
4001 /*************************************************************************/
4003 /* GTEQ[]: Greater Than or EQual */
4004 /* Opcode range: 0x53 */
4005 /* Stack: int32? int32? --> bool */
4014 /*************************************************************************/
4017 /* Opcode range: 0x54 */
4018 /* Stack: StkElt StkElt --> bool */
4027 /*************************************************************************/
4029 /* NEQ[]: Not EQual */
4030 /* Opcode range: 0x55 */
4031 /* Stack: StkElt StkElt --> bool */
4040 /*************************************************************************/
4043 /* Opcode range: 0x56 */
4044 /* Stack: f26.6 --> bool */
4053 /*************************************************************************/
4055 /* EVEN[]: Is EVEN */
4056 /* Opcode range: 0x57 */
4057 /* Stack: f26.6 --> bool */
4066 /*************************************************************************/
4068 /* AND[]: logical AND */
4069 /* Opcode range: 0x5A */
4070 /* Stack: uint32 uint32 --> uint32 */
4079 /*************************************************************************/
4081 /* OR[]: logical OR */
4082 /* Opcode range: 0x5B */
4083 /* Stack: uint32 uint32 --> uint32 */
4092 /*************************************************************************/
4094 /* NOT[]: logical NOT */
4095 /* Opcode range: 0x5C */
4096 /* Stack: StkElt --> uint32 */
4105 /*************************************************************************/
4108 /* Opcode range: 0x60 */
4109 /* Stack: f26.6 f26.6 --> f26.6 */
4118 /*************************************************************************/
4120 /* SUB[]: SUBtract */
4121 /* Opcode range: 0x61 */
4122 /* Stack: f26.6 f26.6 --> f26.6 */
4131 /*************************************************************************/
4134 /* Opcode range: 0x62 */
4135 /* Stack: f26.6 f26.6 --> f26.6 */
4144 /*************************************************************************/
4146 /* MUL[]: MULtiply */
4147 /* Opcode range: 0x63 */
4148 /* Stack: f26.6 f26.6 --> f26.6 */
4157 /*************************************************************************/
4159 /* ABS[]: ABSolute value */
4160 /* Opcode range: 0x64 */
4161 /* Stack: f26.6 --> f26.6 */
4170 /*************************************************************************/
4173 /* Opcode range: 0x65 */
4174 /* Stack: f26.6 --> f26.6 */
4183 /*************************************************************************/
4185 /* FLOOR[]: FLOOR */
4186 /* Opcode range: 0x66 */
4187 /* Stack: f26.6 --> f26.6 */
4190 Ins_FLOOR( INS_ARG )
4196 /*************************************************************************/
4198 /* CEILING[]: CEILING */
4199 /* Opcode range: 0x67 */
4200 /* Stack: f26.6 --> f26.6 */
4203 Ins_CEILING( INS_ARG )
4209 /*************************************************************************/
4211 /* RS[]: Read Store */
4212 /* Opcode range: 0x43 */
4213 /* Stack: uint32 --> uint32 */
4222 /*************************************************************************/
4224 /* WS[]: Write Store */
4225 /* Opcode range: 0x42 */
4226 /* Stack: uint32 uint32 --> */
4235 /*************************************************************************/
4237 /* WCVTP[]: Write CVT in Pixel units */
4238 /* Opcode range: 0x44 */
4239 /* Stack: f26.6 uint32 --> */
4242 Ins_WCVTP( INS_ARG )
4248 /*************************************************************************/
4250 /* WCVTF[]: Write CVT in Funits */
4251 /* Opcode range: 0x70 */
4252 /* Stack: uint32 uint32 --> */
4255 Ins_WCVTF( INS_ARG )
4261 /*************************************************************************/
4263 /* RCVT[]: Read CVT */
4264 /* Opcode range: 0x45 */
4265 /* Stack: uint32 --> f26.6 */
4274 /*************************************************************************/
4276 /* AA[]: Adjust Angle */
4277 /* Opcode range: 0x7F */
4278 /* Stack: uint32 --> */
4283 /* intentionally no longer supported */
4287 /*************************************************************************/
4289 /* DEBUG[]: DEBUG. Unsupported. */
4290 /* Opcode range: 0x4F */
4291 /* Stack: uint32 --> */
4293 /* Note: The original instruction pops a value from the stack. */
4296 Ins_DEBUG( INS_ARG )
4302 /*************************************************************************/
4304 /* ROUND[ab]: ROUND value */
4305 /* Opcode range: 0x68-0x6B */
4306 /* Stack: f26.6 --> f26.6 */
4309 Ins_ROUND( INS_ARG )
4315 /*************************************************************************/
4317 /* NROUND[ab]: No ROUNDing of value */
4318 /* Opcode range: 0x6C-0x6F */
4319 /* Stack: f26.6 --> f26.6 */
4322 Ins_NROUND( INS_ARG )
4328 /*************************************************************************/
4330 /* MAX[]: MAXimum */
4331 /* Opcode range: 0x68 */
4332 /* Stack: int32? int32? --> int32 */
4341 /*************************************************************************/
4343 /* MIN[]: MINimum */
4344 /* Opcode range: 0x69 */
4345 /* Stack: int32? int32? --> int32 */
4354 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
4357 /*************************************************************************/
4359 /* The following functions are called as is within the switch statement. */
4361 /*************************************************************************/
4364 /*************************************************************************/
4366 /* MINDEX[]: Move INDEXed element */
4367 /* Opcode range: 0x26 */
4368 /* Stack: int32? --> StkElt */
4371 Ins_MINDEX( INS_ARG )
4378 if ( L <= 0 || L > CUR.args )
4380 if ( CUR.pedantic_hinting )
4381 CUR.error = FT_THROW( Invalid_Reference );
4385 K = CUR.stack[CUR.args - L];
4387 FT_ARRAY_MOVE( &CUR.stack[CUR.args - L ],
4388 &CUR.stack[CUR.args - L + 1],
4391 CUR.stack[CUR.args - 1] = K;
4396 /*************************************************************************/
4398 /* ROLL[]: ROLL top three elements */
4399 /* Opcode range: 0x8A */
4400 /* Stack: 3 * StkElt --> 3 * StkElt */
4420 /*************************************************************************/
4422 /* MANAGING THE FLOW OF CONTROL */
4424 /* Instructions appear in the specification's order. */
4426 /*************************************************************************/
4432 CUR.IP += CUR.length;
4434 if ( CUR.IP < CUR.codeSize )
4436 CUR.opcode = CUR.code[CUR.IP];
4438 CUR.length = opcode_length[CUR.opcode];
4439 if ( CUR.length < 0 )
4441 if ( CUR.IP + 1 >= CUR.codeSize )
4443 CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
4446 if ( CUR.IP + CUR.length <= CUR.codeSize )
4451 CUR.error = FT_THROW( Code_Overflow );
4456 /*************************************************************************/
4459 /* Opcode range: 0x58 */
4460 /* Stack: StkElt --> */
4477 if ( SKIP_Code() == FAILURE )
4480 switch ( CUR.opcode )
4486 case 0x1B: /* ELSE */
4487 Out = FT_BOOL( nIfs == 1 );
4490 case 0x59: /* EIF */
4492 Out = FT_BOOL( nIfs == 0 );
4495 } while ( Out == 0 );
4499 /*************************************************************************/
4502 /* Opcode range: 0x1B */
4517 if ( SKIP_Code() == FAILURE )
4520 switch ( CUR.opcode )
4526 case 0x59: /* EIF */
4530 } while ( nIfs != 0 );
4534 /*************************************************************************/
4536 /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
4538 /* Instructions appear in the specification's order. */
4540 /*************************************************************************/
4543 /*************************************************************************/
4545 /* FDEF[]: Function DEFinition */
4546 /* Opcode range: 0x2C */
4547 /* Stack: uint32 --> */
4554 TT_DefRecord* limit;
4556 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
4557 /* arguments to opcodes are skipped by `SKIP_Code' */
4558 FT_Byte opcode_pattern[9][12] = {
4559 /* #0 inline delta function 1 */
4574 /* #1 inline delta function 2 */
4585 /* #2 diagonal stroke function */
4598 /* #3 VacuFormRound function */
4608 /* #4 TTFautohint bytecode (old) */
4619 /* #5 spacing function 1 */
4627 /* #6 spacing function 2 */
4636 /* #7 TypeMan Talk DiagEndCtrl function */
4644 /* #8 TypeMan Talk Align */
4650 FT_UShort opcode_patterns = 9;
4651 FT_UShort opcode_pointer[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
4652 FT_UShort opcode_size[9] = { 12, 8, 8, 6, 7, 4, 5, 4, 2 };
4654 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
4657 /* some font programs are broken enough to redefine functions! */
4658 /* We will then parse the current table. */
4661 limit = rec + CUR.numFDefs;
4664 for ( ; rec < limit; rec++ )
4666 if ( rec->opc == n )
4672 /* check that there is enough room for new functions */
4673 if ( CUR.numFDefs >= CUR.maxFDefs )
4675 CUR.error = FT_THROW( Too_Many_Function_Defs );
4681 /* Although FDEF takes unsigned 32-bit integer, */
4682 /* func # must be within unsigned 16-bit integer */
4685 CUR.error = FT_THROW( Too_Many_Function_Defs );
4689 rec->range = CUR.curRange;
4690 rec->opc = (FT_UInt16)n;
4691 rec->start = CUR.IP + 1;
4693 rec->inline_delta = FALSE;
4694 rec->sph_fdef_flags = 0x0000;
4696 if ( n > CUR.maxFunc )
4697 CUR.maxFunc = (FT_UInt16)n;
4699 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
4700 /* We don't know for sure these are typeman functions, */
4701 /* however they are only active when RS 22 is called */
4702 if ( n >= 64 && n <= 66 )
4703 rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_STROKES;
4706 /* Now skip the whole function definition. */
4707 /* We don't allow nested IDEFS & FDEFs. */
4709 while ( SKIP_Code() == SUCCESS )
4712 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
4714 if ( SUBPIXEL_HINTING )
4716 for ( i = 0; i < opcode_patterns; i++ )
4718 if ( opcode_pointer[i] < opcode_size[i] &&
4719 CUR.opcode == opcode_pattern[i][opcode_pointer[i]] )
4721 opcode_pointer[i] += 1;
4723 if ( opcode_pointer[i] == opcode_size[i] )
4725 FT_TRACE7(( "sph: Function %d, opcode ptrn: %d, %s %s\n",
4727 CUR.face->root.family_name,
4728 CUR.face->root.style_name ));
4733 rec->sph_fdef_flags |= SPH_FDEF_INLINE_DELTA_1;
4734 CUR.face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_1;
4738 rec->sph_fdef_flags |= SPH_FDEF_INLINE_DELTA_2;
4739 CUR.face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_2;
4745 /* needs to be implemented still */
4747 rec->sph_fdef_flags |= SPH_FDEF_DIAGONAL_STROKE;
4748 CUR.face->sph_found_func_flags |= SPH_FDEF_DIAGONAL_STROKE;
4756 rec->sph_fdef_flags |= SPH_FDEF_VACUFORM_ROUND_1;
4757 CUR.face->sph_found_func_flags |= SPH_FDEF_VACUFORM_ROUND_1;
4762 /* probably not necessary to detect anymore */
4763 rec->sph_fdef_flags |= SPH_FDEF_TTFAUTOHINT_1;
4764 CUR.face->sph_found_func_flags |= SPH_FDEF_TTFAUTOHINT_1;
4776 rec->sph_fdef_flags |= SPH_FDEF_SPACING_1;
4777 CUR.face->sph_found_func_flags |= SPH_FDEF_SPACING_1;
4790 rec->sph_fdef_flags |= SPH_FDEF_SPACING_2;
4791 CUR.face->sph_found_func_flags |= SPH_FDEF_SPACING_2;
4796 rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
4797 CUR.face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
4802 rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
4803 CUR.face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
4807 opcode_pointer[i] = 0;
4812 opcode_pointer[i] = 0;
4815 /* Set sph_compatibility_mode only when deltas are detected */
4816 CUR.face->sph_compatibility_mode =
4817 ( ( CUR.face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_1 ) |
4818 ( CUR.face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_2 ) );
4821 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
4823 switch ( CUR.opcode )
4825 case 0x89: /* IDEF */
4826 case 0x2C: /* FDEF */
4827 CUR.error = FT_THROW( Nested_DEFS );
4830 case 0x2D: /* ENDF */
4838 /*************************************************************************/
4840 /* ENDF[]: END Function definition */
4841 /* Opcode range: 0x2D */
4852 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
4853 CUR.sph_in_func_flags = 0x0000;
4854 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
4856 if ( CUR.callTop <= 0 ) /* We encountered an ENDF without a call */
4858 CUR.error = FT_THROW( ENDF_In_Exec_Stream );
4864 pRec = &CUR.callStack[CUR.callTop];
4868 CUR.step_ins = FALSE;
4870 if ( pRec->Cur_Count > 0 )
4873 CUR.IP = pRec->Def->start;
4876 /* Loop through the current function */
4877 INS_Goto_CodeRange( pRec->Caller_Range,
4880 /* Exit the current call frame. */
4882 /* NOTE: If the last instruction of a program is a */
4883 /* CALL or LOOPCALL, the return address is */
4884 /* always out of the code range. This is a */
4885 /* valid address, and it is why we do not test */
4886 /* the result of Ins_Goto_CodeRange() here! */
4890 /*************************************************************************/
4892 /* CALL[]: CALL function */
4893 /* Opcode range: 0x2B */
4894 /* Stack: uint32? --> */
4904 /* first of all, check the index */
4907 if ( BOUNDSL( F, CUR.maxFunc + 1 ) )
4910 /* Except for some old Apple fonts, all functions in a TrueType */
4911 /* font are defined in increasing order, starting from 0. This */
4912 /* means that we normally have */
4914 /* CUR.maxFunc+1 == CUR.numFDefs */
4915 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4917 /* If this isn't true, we need to look up the function table. */
4919 def = CUR.FDefs + F;
4920 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
4922 /* look up the FDefs table */
4923 TT_DefRecord* limit;
4927 limit = def + CUR.numFDefs;
4929 while ( def < limit && def->opc != F )
4936 /* check that the function is active */
4940 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
4941 if ( SUBPIXEL_HINTING &&
4942 CUR.ignore_x_mode &&
4943 ( ( CUR.iup_called &&
4944 ( CUR.sph_tweak_flags & SPH_TWEAK_NO_CALL_AFTER_IUP ) ) ||
4945 ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) ) )
4948 CUR.sph_in_func_flags = def->sph_fdef_flags;
4949 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
4951 /* check the call stack */
4952 if ( CUR.callTop >= CUR.callSize )
4954 CUR.error = FT_THROW( Stack_Overflow );
4958 pCrec = CUR.callStack + CUR.callTop;
4960 pCrec->Caller_Range = CUR.curRange;
4961 pCrec->Caller_IP = CUR.IP + 1;
4962 pCrec->Cur_Count = 1;
4967 INS_Goto_CodeRange( def->range,
4970 CUR.step_ins = FALSE;
4975 CUR.error = FT_THROW( Invalid_Reference );
4979 /*************************************************************************/
4981 /* LOOPCALL[]: LOOP and CALL function */
4982 /* Opcode range: 0x2A */
4983 /* Stack: uint32? Eint16? --> */
4986 Ins_LOOPCALL( INS_ARG )
4993 /* first of all, check the index */
4995 if ( BOUNDSL( F, CUR.maxFunc + 1 ) )
4998 /* Except for some old Apple fonts, all functions in a TrueType */
4999 /* font are defined in increasing order, starting from 0. This */
5000 /* means that we normally have */
5002 /* CUR.maxFunc+1 == CUR.numFDefs */
5003 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
5005 /* If this isn't true, we need to look up the function table. */
5007 def = CUR.FDefs + F;
5008 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
5010 /* look up the FDefs table */
5011 TT_DefRecord* limit;
5015 limit = def + CUR.numFDefs;
5017 while ( def < limit && def->opc != F )
5024 /* check that the function is active */
5028 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
5029 if ( SUBPIXEL_HINTING &&
5030 CUR.ignore_x_mode &&
5031 ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) )
5034 CUR.sph_in_func_flags = def->sph_fdef_flags;
5035 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
5038 if ( CUR.callTop >= CUR.callSize )
5040 CUR.error = FT_THROW( Stack_Overflow );
5046 pCrec = CUR.callStack + CUR.callTop;
5048 pCrec->Caller_Range = CUR.curRange;
5049 pCrec->Caller_IP = CUR.IP + 1;
5050 pCrec->Cur_Count = (FT_Int)args[0];
5055 INS_Goto_CodeRange( def->range, def->start );
5057 CUR.step_ins = FALSE;
5063 CUR.error = FT_THROW( Invalid_Reference );
5067 /*************************************************************************/
5069 /* IDEF[]: Instruction DEFinition */
5070 /* Opcode range: 0x89 */
5071 /* Stack: Eint8 --> */
5077 TT_DefRecord* limit;
5080 /* First of all, look for the same function in our table */
5083 limit = def + CUR.numIDefs;
5085 for ( ; def < limit; def++ )
5086 if ( def->opc == (FT_ULong)args[0] )
5091 /* check that there is enough room for a new instruction */
5092 if ( CUR.numIDefs >= CUR.maxIDefs )
5094 CUR.error = FT_THROW( Too_Many_Instruction_Defs );
5100 /* opcode must be unsigned 8-bit integer */
5101 if ( 0 > args[0] || args[0] > 0x00FF )
5103 CUR.error = FT_THROW( Too_Many_Instruction_Defs );
5107 def->opc = (FT_Byte)args[0];
5108 def->start = CUR.IP + 1;
5109 def->range = CUR.curRange;
5112 if ( (FT_ULong)args[0] > CUR.maxIns )
5113 CUR.maxIns = (FT_Byte)args[0];
5115 /* Now skip the whole function definition. */
5116 /* We don't allow nested IDEFs & FDEFs. */
5118 while ( SKIP_Code() == SUCCESS )
5120 switch ( CUR.opcode )
5122 case 0x89: /* IDEF */
5123 case 0x2C: /* FDEF */
5124 CUR.error = FT_THROW( Nested_DEFS );
5126 case 0x2D: /* ENDF */
5133 /*************************************************************************/
5135 /* PUSHING DATA ONTO THE INTERPRETER STACK */
5137 /* Instructions appear in the specification's order. */
5139 /*************************************************************************/
5142 /*************************************************************************/
5144 /* NPUSHB[]: PUSH N Bytes */
5145 /* Opcode range: 0x40 */
5146 /* Stack: --> uint32... */
5149 Ins_NPUSHB( INS_ARG )
5154 L = (FT_UShort)CUR.code[CUR.IP + 1];
5156 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
5158 CUR.error = FT_THROW( Stack_Overflow );
5162 for ( K = 1; K <= L; K++ )
5163 args[K - 1] = CUR.code[CUR.IP + K + 1];
5169 /*************************************************************************/
5171 /* NPUSHW[]: PUSH N Words */
5172 /* Opcode range: 0x41 */
5173 /* Stack: --> int32... */
5176 Ins_NPUSHW( INS_ARG )
5181 L = (FT_UShort)CUR.code[CUR.IP + 1];
5183 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
5185 CUR.error = FT_THROW( Stack_Overflow );
5191 for ( K = 0; K < L; K++ )
5192 args[K] = GET_ShortIns();
5194 CUR.step_ins = FALSE;
5199 /*************************************************************************/
5201 /* PUSHB[abc]: PUSH Bytes */
5202 /* Opcode range: 0xB0-0xB7 */
5203 /* Stack: --> uint32... */
5206 Ins_PUSHB( INS_ARG )
5211 L = (FT_UShort)( CUR.opcode - 0xB0 + 1 );
5213 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
5215 CUR.error = FT_THROW( Stack_Overflow );
5219 for ( K = 1; K <= L; K++ )
5220 args[K - 1] = CUR.code[CUR.IP + K];
5224 /*************************************************************************/
5226 /* PUSHW[abc]: PUSH Words */
5227 /* Opcode range: 0xB8-0xBF */
5228 /* Stack: --> int32... */
5231 Ins_PUSHW( INS_ARG )
5236 L = (FT_UShort)( CUR.opcode - 0xB8 + 1 );
5238 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
5240 CUR.error = FT_THROW( Stack_Overflow );
5246 for ( K = 0; K < L; K++ )
5247 args[K] = GET_ShortIns();
5249 CUR.step_ins = FALSE;
5253 /*************************************************************************/
5255 /* MANAGING THE GRAPHICS STATE */
5257 /* Instructions appear in the specs' order. */
5259 /*************************************************************************/
5262 /*************************************************************************/
5264 /* GC[a]: Get Coordinate projected onto */
5265 /* Opcode range: 0x46-0x47 */
5266 /* Stack: uint32 --> f26.6 */
5268 /* XXX: UNDOCUMENTED: Measures from the original glyph must be taken */
5269 /* along the dual projection vector! */
5278 L = (FT_ULong)args[0];
5280 if ( BOUNDSL( L, CUR.zp2.n_points ) )
5282 if ( CUR.pedantic_hinting )
5283 CUR.error = FT_THROW( Invalid_Reference );
5288 if ( CUR.opcode & 1 )
5289 R = CUR_fast_dualproj( &CUR.zp2.org[L] );
5291 R = CUR_fast_project( &CUR.zp2.cur[L] );
5298 /*************************************************************************/
5300 /* SCFS[]: Set Coordinate From Stack */
5301 /* Opcode range: 0x48 */
5302 /* Stack: f26.6 uint32 --> */
5306 /* OA := OA + ( value - OA.p )/( f.p ) * f */
5315 L = (FT_UShort)args[0];
5317 if ( BOUNDS( L, CUR.zp2.n_points ) )
5319 if ( CUR.pedantic_hinting )
5320 CUR.error = FT_THROW( Invalid_Reference );
5324 K = CUR_fast_project( &CUR.zp2.cur[L] );
5326 CUR_Func_move( &CUR.zp2, L, args[1] - K );
5328 /* UNDOCUMENTED! The MS rasterizer does that with */
5329 /* twilight points (confirmed by Greg Hitchcock) */
5330 if ( CUR.GS.gep2 == 0 )
5331 CUR.zp2.org[L] = CUR.zp2.cur[L];
5335 /*************************************************************************/
5337 /* MD[a]: Measure Distance */
5338 /* Opcode range: 0x49-0x4A */
5339 /* Stack: uint32 uint32 --> f26.6 */
5341 /* XXX: UNDOCUMENTED: Measure taken in the original glyph must be along */
5342 /* the dual projection vector. */
5344 /* XXX: UNDOCUMENTED: Flag attributes are inverted! */
5345 /* 0 => measure distance in original outline */
5346 /* 1 => measure distance in grid-fitted outline */
5348 /* XXX: UNDOCUMENTED: `zp0 - zp1', and not `zp2 - zp1! */
5357 K = (FT_UShort)args[1];
5358 L = (FT_UShort)args[0];
5360 if ( BOUNDS( L, CUR.zp0.n_points ) ||
5361 BOUNDS( K, CUR.zp1.n_points ) )
5363 if ( CUR.pedantic_hinting )
5364 CUR.error = FT_THROW( Invalid_Reference );
5369 if ( CUR.opcode & 1 )
5370 D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
5373 /* XXX: UNDOCUMENTED: twilight zone special case */
5375 if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
5377 FT_Vector* vec1 = CUR.zp0.org + L;
5378 FT_Vector* vec2 = CUR.zp1.org + K;
5381 D = CUR_Func_dualproj( vec1, vec2 );
5385 FT_Vector* vec1 = CUR.zp0.orus + L;
5386 FT_Vector* vec2 = CUR.zp1.orus + K;
5389 if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
5391 /* this should be faster */
5392 D = CUR_Func_dualproj( vec1, vec2 );
5393 D = FT_MulFix( D, CUR.metrics.x_scale );
5400 vec.x = FT_MulFix( vec1->x - vec2->x, CUR.metrics.x_scale );
5401 vec.y = FT_MulFix( vec1->y - vec2->y, CUR.metrics.y_scale );
5403 D = CUR_fast_dualproj( &vec );
5409 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
5410 /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */
5411 if ( SUBPIXEL_HINTING &&
5412 CUR.ignore_x_mode && FT_ABS( D ) == 64 )
5414 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
5420 /*************************************************************************/
5422 /* SDPVTL[a]: Set Dual PVector to Line */
5423 /* Opcode range: 0x86-0x87 */
5424 /* Stack: uint32 uint32 --> */
5427 Ins_SDPVTL( INS_ARG )
5430 FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
5431 FT_Int aOpc = CUR.opcode;
5434 p1 = (FT_UShort)args[1];
5435 p2 = (FT_UShort)args[0];
5437 if ( BOUNDS( p2, CUR.zp1.n_points ) ||
5438 BOUNDS( p1, CUR.zp2.n_points ) )
5440 if ( CUR.pedantic_hinting )
5441 CUR.error = FT_THROW( Invalid_Reference );
5446 FT_Vector* v1 = CUR.zp1.org + p2;
5447 FT_Vector* v2 = CUR.zp2.org + p1;
5453 /* If v1 == v2, SDPVTL behaves the same as */
5454 /* SVTCA[X], respectively. */
5456 /* Confirmed by Greg Hitchcock. */
5458 if ( A == 0 && B == 0 )
5465 if ( ( aOpc & 1 ) != 0 )
5467 C = B; /* counter clockwise rotation */
5472 NORMalize( A, B, &CUR.GS.dualVector );
5475 FT_Vector* v1 = CUR.zp1.cur + p2;
5476 FT_Vector* v2 = CUR.zp2.cur + p1;
5482 if ( A == 0 && B == 0 )
5489 if ( ( aOpc & 1 ) != 0 )
5491 C = B; /* counter clockwise rotation */
5496 NORMalize( A, B, &CUR.GS.projVector );
5498 GUESS_VECTOR( freeVector );
5504 /*************************************************************************/
5506 /* SZP0[]: Set Zone Pointer 0 */
5507 /* Opcode range: 0x13 */
5508 /* Stack: uint32 --> */
5513 switch ( (FT_Int)args[0] )
5516 CUR.zp0 = CUR.twilight;
5524 if ( CUR.pedantic_hinting )
5525 CUR.error = FT_THROW( Invalid_Reference );
5529 CUR.GS.gep0 = (FT_UShort)args[0];
5533 /*************************************************************************/
5535 /* SZP1[]: Set Zone Pointer 1 */
5536 /* Opcode range: 0x14 */
5537 /* Stack: uint32 --> */
5542 switch ( (FT_Int)args[0] )
5545 CUR.zp1 = CUR.twilight;
5553 if ( CUR.pedantic_hinting )
5554 CUR.error = FT_THROW( Invalid_Reference );
5558 CUR.GS.gep1 = (FT_UShort)args[0];
5562 /*************************************************************************/
5564 /* SZP2[]: Set Zone Pointer 2 */
5565 /* Opcode range: 0x15 */
5566 /* Stack: uint32 --> */
5571 switch ( (FT_Int)args[0] )
5574 CUR.zp2 = CUR.twilight;
5582 if ( CUR.pedantic_hinting )
5583 CUR.error = FT_THROW( Invalid_Reference );
5587 CUR.GS.gep2 = (FT_UShort)args[0];
5591 /*************************************************************************/
5593 /* SZPS[]: Set Zone PointerS */
5594 /* Opcode range: 0x16 */
5595 /* Stack: uint32 --> */
5600 switch ( (FT_Int)args[0] )
5603 CUR.zp0 = CUR.twilight;
5611 if ( CUR.pedantic_hinting )
5612 CUR.error = FT_THROW( Invalid_Reference );
5619 CUR.GS.gep0 = (FT_UShort)args[0];
5620 CUR.GS.gep1 = (FT_UShort)args[0];
5621 CUR.GS.gep2 = (FT_UShort)args[0];
5625 /*************************************************************************/
5627 /* INSTCTRL[]: INSTruction ConTRoL */
5628 /* Opcode range: 0x8E */
5629 /* Stack: int32 int32 --> */
5632 Ins_INSTCTRL( INS_ARG )
5640 if ( K < 1 || K > 2 )
5642 if ( CUR.pedantic_hinting )
5643 CUR.error = FT_THROW( Invalid_Reference );
5650 CUR.GS.instruct_control = FT_BOOL(
5651 ( (FT_Byte)CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L );
5655 /*************************************************************************/
5657 /* SCANCTRL[]: SCAN ConTRoL */
5658 /* Opcode range: 0x85 */
5659 /* Stack: uint32? --> */
5662 Ins_SCANCTRL( INS_ARG )
5668 A = (FT_Int)( args[0] & 0xFF );
5672 CUR.GS.scan_control = TRUE;
5677 CUR.GS.scan_control = FALSE;
5681 if ( ( args[0] & 0x100 ) != 0 && CUR.tt_metrics.ppem <= A )
5682 CUR.GS.scan_control = TRUE;
5684 if ( ( args[0] & 0x200 ) != 0 && CUR.tt_metrics.rotated )
5685 CUR.GS.scan_control = TRUE;
5687 if ( ( args[0] & 0x400 ) != 0 && CUR.tt_metrics.stretched )
5688 CUR.GS.scan_control = TRUE;
5690 if ( ( args[0] & 0x800 ) != 0 && CUR.tt_metrics.ppem > A )
5691 CUR.GS.scan_control = FALSE;
5693 if ( ( args[0] & 0x1000 ) != 0 && CUR.tt_metrics.rotated )
5694 CUR.GS.scan_control = FALSE;
5696 if ( ( args[0] & 0x2000 ) != 0 && CUR.tt_metrics.stretched )
5697 CUR.GS.scan_control = FALSE;
5701 /*************************************************************************/
5703 /* SCANTYPE[]: SCAN TYPE */
5704 /* Opcode range: 0x8D */
5705 /* Stack: uint32? --> */
5708 Ins_SCANTYPE( INS_ARG )
5711 CUR.GS.scan_type = (FT_Int)args[0];
5715 /*************************************************************************/
5717 /* MANAGING OUTLINES */
5719 /* Instructions appear in the specification's order. */
5721 /*************************************************************************/
5724 /*************************************************************************/
5726 /* FLIPPT[]: FLIP PoinT */
5727 /* Opcode range: 0x80 */
5728 /* Stack: uint32... --> */
5731 Ins_FLIPPT( INS_ARG )
5738 if ( CUR.top < CUR.GS.loop )
5740 if ( CUR.pedantic_hinting )
5741 CUR.error = FT_THROW( Too_Few_Arguments );
5745 while ( CUR.GS.loop > 0 )
5749 point = (FT_UShort)CUR.stack[CUR.args];
5751 if ( BOUNDS( point, CUR.pts.n_points ) )
5753 if ( CUR.pedantic_hinting )
5755 CUR.error = FT_THROW( Invalid_Reference );
5760 CUR.pts.tags[point] ^= FT_CURVE_TAG_ON;
5767 CUR.new_top = CUR.args;
5771 /*************************************************************************/
5773 /* FLIPRGON[]: FLIP RanGe ON */
5774 /* Opcode range: 0x81 */
5775 /* Stack: uint32 uint32 --> */
5778 Ins_FLIPRGON( INS_ARG )
5783 K = (FT_UShort)args[1];
5784 L = (FT_UShort)args[0];
5786 if ( BOUNDS( K, CUR.pts.n_points ) ||
5787 BOUNDS( L, CUR.pts.n_points ) )
5789 if ( CUR.pedantic_hinting )
5790 CUR.error = FT_THROW( Invalid_Reference );
5794 for ( I = L; I <= K; I++ )
5795 CUR.pts.tags[I] |= FT_CURVE_TAG_ON;
5799 /*************************************************************************/
5801 /* FLIPRGOFF: FLIP RanGe OFF */
5802 /* Opcode range: 0x82 */
5803 /* Stack: uint32 uint32 --> */
5806 Ins_FLIPRGOFF( INS_ARG )
5811 K = (FT_UShort)args[1];
5812 L = (FT_UShort)args[0];
5814 if ( BOUNDS( K, CUR.pts.n_points ) ||
5815 BOUNDS( L, CUR.pts.n_points ) )
5817 if ( CUR.pedantic_hinting )
5818 CUR.error = FT_THROW( Invalid_Reference );
5822 for ( I = L; I <= K; I++ )
5823 CUR.pts.tags[I] &= ~FT_CURVE_TAG_ON;
5828 Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6* x,
5838 if ( CUR.opcode & 1 )
5849 if ( BOUNDS( p, zp.n_points ) )
5851 if ( CUR.pedantic_hinting )
5852 CUR.error = FT_THROW( Invalid_Reference );
5860 d = CUR_Func_project( zp.cur + p, zp.org + p );
5862 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5863 if ( CUR.face->unpatented_hinting )
5865 if ( CUR.GS.both_x_axis )
5879 *x = FT_MulDiv( d, (FT_Long)CUR.GS.freeVector.x, CUR.F_dot_P );
5880 *y = FT_MulDiv( d, (FT_Long)CUR.GS.freeVector.y, CUR.F_dot_P );
5888 Move_Zp2_Point( EXEC_OP_ FT_UShort point,
5893 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5894 if ( CUR.face->unpatented_hinting )
5896 if ( CUR.GS.both_x_axis )
5898 CUR.zp2.cur[point].x += dx;
5900 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
5904 CUR.zp2.cur[point].y += dy;
5906 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
5912 if ( CUR.GS.freeVector.x != 0 )
5914 CUR.zp2.cur[point].x += dx;
5916 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
5919 if ( CUR.GS.freeVector.y != 0 )
5921 CUR.zp2.cur[point].y += dy;
5923 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
5928 /*************************************************************************/
5930 /* SHP[a]: SHift Point by the last point */
5931 /* Opcode range: 0x32-0x33 */
5932 /* Stack: uint32... --> */
5947 if ( CUR.top < CUR.GS.loop )
5949 if ( CUR.pedantic_hinting )
5950 CUR.error = FT_THROW( Invalid_Reference );
5954 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5957 while ( CUR.GS.loop > 0 )
5960 point = (FT_UShort)CUR.stack[CUR.args];
5962 if ( BOUNDS( point, CUR.zp2.n_points ) )
5964 if ( CUR.pedantic_hinting )
5966 CUR.error = FT_THROW( Invalid_Reference );
5971 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
5972 /* doesn't follow Cleartype spec but produces better result */
5973 if ( SUBPIXEL_HINTING &&
5975 MOVE_Zp2_Point( point, 0, dy, TRUE );
5977 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
5978 MOVE_Zp2_Point( point, dx, dy, TRUE );
5985 CUR.new_top = CUR.args;
5989 /*************************************************************************/
5991 /* SHC[a]: SHift Contour */
5992 /* Opcode range: 0x34-35 */
5993 /* Stack: uint32 --> */
5995 /* UNDOCUMENTED: According to Greg Hitchcock, there is one (virtual) */
5996 /* contour in the twilight zone, namely contour number */
5997 /* zero which includes all points of it. */
6006 FT_Short contour, bounds;
6007 FT_UShort start, limit, i;
6010 contour = (FT_UShort)args[0];
6011 bounds = ( CUR.GS.gep2 == 0 ) ? 1 : CUR.zp2.n_contours;
6013 if ( BOUNDS( contour, bounds ) )
6015 if ( CUR.pedantic_hinting )
6016 CUR.error = FT_THROW( Invalid_Reference );
6020 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
6026 start = (FT_UShort)( CUR.zp2.contours[contour - 1] + 1 -
6027 CUR.zp2.first_point );
6029 /* we use the number of points if in the twilight zone */
6030 if ( CUR.GS.gep2 == 0 )
6031 limit = CUR.zp2.n_points;
6033 limit = (FT_UShort)( CUR.zp2.contours[contour] -
6034 CUR.zp2.first_point + 1 );
6036 for ( i = start; i < limit; i++ )
6038 if ( zp.cur != CUR.zp2.cur || refp != i )
6039 MOVE_Zp2_Point( i, dx, dy, TRUE );
6044 /*************************************************************************/
6046 /* SHZ[a]: SHift Zone */
6047 /* Opcode range: 0x36-37 */
6048 /* Stack: uint32 --> */
6061 if ( BOUNDS( args[0], 2 ) )
6063 if ( CUR.pedantic_hinting )
6064 CUR.error = FT_THROW( Invalid_Reference );
6068 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
6071 /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */
6072 /* Twilight zone has no real contours, so use `n_points'. */
6073 /* Normal zone's `n_points' includes phantoms, so must */
6074 /* use end of last contour. */
6075 if ( CUR.GS.gep2 == 0 )
6076 limit = (FT_UShort)CUR.zp2.n_points;
6077 else if ( CUR.GS.gep2 == 1 && CUR.zp2.n_contours > 0 )
6078 limit = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] + 1 );
6082 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
6083 for ( i = 0; i < limit; i++ )
6085 if ( zp.cur != CUR.zp2.cur || refp != i )
6086 MOVE_Zp2_Point( i, dx, dy, FALSE );
6091 /*************************************************************************/
6093 /* SHPIX[]: SHift points by a PIXel amount */
6094 /* Opcode range: 0x38 */
6095 /* Stack: f26.6 uint32... --> */
6098 Ins_SHPIX( INS_ARG )
6102 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6107 if ( CUR.top < CUR.GS.loop + 1 )
6109 if ( CUR.pedantic_hinting )
6110 CUR.error = FT_THROW( Invalid_Reference );
6114 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
6115 if ( CUR.face->unpatented_hinting )
6117 if ( CUR.GS.both_x_axis )
6119 dx = (FT_UInt32)args[0];
6125 dy = (FT_UInt32)args[0];
6131 dx = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.x );
6132 dy = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.y );
6135 while ( CUR.GS.loop > 0 )
6139 point = (FT_UShort)CUR.stack[CUR.args];
6141 if ( BOUNDS( point, CUR.zp2.n_points ) )
6143 if ( CUR.pedantic_hinting )
6145 CUR.error = FT_THROW( Invalid_Reference );
6150 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6152 /* If not using ignore_x_mode rendering, allow ZP2 move. */
6153 /* If inline deltas aren't allowed, skip ZP2 move. */
6154 /* If using ignore_x_mode rendering, allow ZP2 point move if: */
6155 /* - freedom vector is y and sph_compatibility_mode is off */
6156 /* - the glyph is composite and the move is in the Y direction */
6157 /* - the glyph is specifically set to allow SHPIX moves */
6158 /* - the move is on a previously Y-touched point */
6160 if ( SUBPIXEL_HINTING &&
6163 /* save point for later comparison */
6164 if ( CUR.GS.freeVector.y != 0 )
6165 B1 = CUR.zp2.cur[point].y;
6167 B1 = CUR.zp2.cur[point].x;
6169 if ( !CUR.face->sph_compatibility_mode &&
6170 CUR.GS.freeVector.y != 0 )
6172 MOVE_Zp2_Point( point, dx, dy, TRUE );
6174 /* save new point */
6175 if ( CUR.GS.freeVector.y != 0 )
6177 B2 = CUR.zp2.cur[point].y;
6179 /* reverse any disallowed moves */
6180 if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
6184 MOVE_Zp2_Point( point, -dx, -dy, TRUE );
6187 else if ( CUR.face->sph_compatibility_mode )
6189 if ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
6191 dx = FT_PIX_ROUND( B1 + dx ) - B1;
6192 dy = FT_PIX_ROUND( B1 + dy ) - B1;
6195 /* skip post-iup deltas */
6196 if ( CUR.iup_called &&
6197 ( ( CUR.sph_in_func_flags & SPH_FDEF_INLINE_DELTA_1 ) ||
6198 ( CUR.sph_in_func_flags & SPH_FDEF_INLINE_DELTA_2 ) ) )
6201 if ( !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) &&
6202 ( ( CUR.is_composite && CUR.GS.freeVector.y != 0 ) ||
6203 ( CUR.zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) ||
6204 ( CUR.sph_tweak_flags & SPH_TWEAK_DO_SHPIX ) ) )
6205 MOVE_Zp2_Point( point, 0, dy, TRUE );
6207 /* save new point */
6208 if ( CUR.GS.freeVector.y != 0 )
6210 B2 = CUR.zp2.cur[point].y;
6212 /* reverse any disallowed moves */
6213 if ( ( B1 & 63 ) == 0 &&
6216 MOVE_Zp2_Point( point, 0, -dy, TRUE );
6219 else if ( CUR.sph_in_func_flags & SPH_FDEF_TYPEMAN_DIAGENDCTRL )
6220 MOVE_Zp2_Point( point, dx, dy, TRUE );
6223 MOVE_Zp2_Point( point, dx, dy, TRUE );
6228 #else /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6230 MOVE_Zp2_Point( point, dx, dy, TRUE );
6232 #endif /* !TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6239 CUR.new_top = CUR.args;
6243 /*************************************************************************/
6245 /* MSIRP[a]: Move Stack Indirect Relative Position */
6246 /* Opcode range: 0x3A-0x3B */
6247 /* Stack: f26.6 uint32 --> */
6250 Ins_MSIRP( INS_ARG )
6253 FT_F26Dot6 distance;
6255 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6256 FT_F26Dot6 control_value_cutin = 0; /* pacify compiler */
6259 if ( SUBPIXEL_HINTING )
6261 control_value_cutin = CUR.GS.control_value_cutin;
6263 if ( CUR.ignore_x_mode &&
6264 CUR.GS.freeVector.x != 0 &&
6265 !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6266 control_value_cutin = 0;
6269 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6271 point = (FT_UShort)args[0];
6273 if ( BOUNDS( point, CUR.zp1.n_points ) ||
6274 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
6276 if ( CUR.pedantic_hinting )
6277 CUR.error = FT_THROW( Invalid_Reference );
6281 /* UNDOCUMENTED! The MS rasterizer does that with */
6282 /* twilight points (confirmed by Greg Hitchcock) */
6283 if ( CUR.GS.gep1 == 0 )
6285 CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
6286 CUR_Func_move_orig( &CUR.zp1, point, args[1] );
6287 CUR.zp1.cur[point] = CUR.zp1.org[point];
6290 distance = CUR_Func_project( CUR.zp1.cur + point,
6291 CUR.zp0.cur + CUR.GS.rp0 );
6293 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6294 /* subpixel hinting - make MSIRP respect CVT cut-in; */
6295 if ( SUBPIXEL_HINTING &&
6296 CUR.ignore_x_mode &&
6297 CUR.GS.freeVector.x != 0 &&
6298 FT_ABS( distance - args[1] ) >= control_value_cutin )
6300 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6302 CUR_Func_move( &CUR.zp1, point, args[1] - distance );
6304 CUR.GS.rp1 = CUR.GS.rp0;
6307 if ( ( CUR.opcode & 1 ) != 0 )
6312 /*************************************************************************/
6314 /* MDAP[a]: Move Direct Absolute Point */
6315 /* Opcode range: 0x2E-0x2F */
6316 /* Stack: uint32 --> */
6322 FT_F26Dot6 cur_dist;
6323 FT_F26Dot6 distance;
6326 point = (FT_UShort)args[0];
6328 if ( BOUNDS( point, CUR.zp0.n_points ) )
6330 if ( CUR.pedantic_hinting )
6331 CUR.error = FT_THROW( Invalid_Reference );
6335 if ( ( CUR.opcode & 1 ) != 0 )
6337 cur_dist = CUR_fast_project( &CUR.zp0.cur[point] );
6338 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6339 if ( SUBPIXEL_HINTING &&
6340 CUR.ignore_x_mode &&
6341 CUR.GS.freeVector.x != 0 )
6342 distance = ROUND_None(
6344 CUR.tt_metrics.compensations[0] ) - cur_dist;
6347 distance = CUR_Func_round(
6349 CUR.tt_metrics.compensations[0] ) - cur_dist;
6354 CUR_Func_move( &CUR.zp0, point, distance );
6361 /*************************************************************************/
6363 /* MIAP[a]: Move Indirect Absolute Point */
6364 /* Opcode range: 0x3E-0x3F */
6365 /* Stack: uint32 uint32 --> */
6372 FT_F26Dot6 distance;
6373 FT_F26Dot6 org_dist;
6374 FT_F26Dot6 control_value_cutin;
6377 control_value_cutin = CUR.GS.control_value_cutin;
6378 cvtEntry = (FT_ULong)args[1];
6379 point = (FT_UShort)args[0];
6381 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6382 if ( SUBPIXEL_HINTING &&
6383 CUR.ignore_x_mode &&
6384 CUR.GS.freeVector.x != 0 &&
6385 CUR.GS.freeVector.y == 0 &&
6386 !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6387 control_value_cutin = 0;
6388 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6390 if ( BOUNDS( point, CUR.zp0.n_points ) ||
6391 BOUNDSL( cvtEntry, CUR.cvtSize ) )
6393 if ( CUR.pedantic_hinting )
6394 CUR.error = FT_THROW( Invalid_Reference );
6400 /* The behaviour of an MIAP instruction is quite different when used */
6401 /* in the twilight zone. */
6403 /* First, no control value cut-in test is performed as it would fail */
6404 /* anyway. Second, the original point, i.e. (org_x,org_y) of */
6405 /* zp0.point, is set to the absolute, unrounded distance found in the */
6408 /* This is used in the CVT programs of the Microsoft fonts Arial, */
6409 /* Times, etc., in order to re-adjust some key font heights. It */
6410 /* allows the use of the IP instruction in the twilight zone, which */
6411 /* otherwise would be invalid according to the specification. */
6413 /* We implement it with a special sequence for the twilight zone. */
6414 /* This is a bad hack, but it seems to work. */
6416 /* Confirmed by Greg Hitchcock. */
6418 distance = CUR_Func_read_cvt( cvtEntry );
6420 if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */
6422 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6423 /* Only adjust if not in sph_compatibility_mode or ignore_x_mode. */
6424 /* Determined via experimentation and may be incorrect... */
6425 if ( !SUBPIXEL_HINTING ||
6426 ( !CUR.ignore_x_mode ||
6427 !CUR.face->sph_compatibility_mode ) )
6428 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6429 CUR.zp0.org[point].x = TT_MulFix14( (FT_UInt32)distance,
6430 CUR.GS.freeVector.x );
6431 CUR.zp0.org[point].y = TT_MulFix14( (FT_UInt32)distance,
6432 CUR.GS.freeVector.y ),
6433 CUR.zp0.cur[point] = CUR.zp0.org[point];
6435 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6436 if ( SUBPIXEL_HINTING &&
6437 CUR.ignore_x_mode &&
6438 ( CUR.sph_tweak_flags & SPH_TWEAK_MIAP_HACK ) &&
6440 CUR.GS.freeVector.y != 0 )
6442 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6444 org_dist = CUR_fast_project( &CUR.zp0.cur[point] );
6446 if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cut-in flag */
6448 if ( FT_ABS( distance - org_dist ) > control_value_cutin )
6449 distance = org_dist;
6451 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6452 if ( SUBPIXEL_HINTING &&
6453 CUR.ignore_x_mode &&
6454 CUR.GS.freeVector.x != 0 )
6455 distance = ROUND_None( distance,
6456 CUR.tt_metrics.compensations[0] );
6459 distance = CUR_Func_round( distance,
6460 CUR.tt_metrics.compensations[0] );
6463 CUR_Func_move( &CUR.zp0, point, distance - org_dist );
6471 /*************************************************************************/
6473 /* MDRP[abcde]: Move Direct Relative Point */
6474 /* Opcode range: 0xC0-0xDF */
6475 /* Stack: uint32 --> */
6481 FT_F26Dot6 org_dist, distance, minimum_distance;
6484 minimum_distance = CUR.GS.minimum_distance;
6486 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6487 if ( SUBPIXEL_HINTING &&
6488 CUR.ignore_x_mode &&
6489 CUR.GS.freeVector.x != 0 &&
6490 !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6491 minimum_distance = 0;
6492 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6494 point = (FT_UShort)args[0];
6496 if ( BOUNDS( point, CUR.zp1.n_points ) ||
6497 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
6499 if ( CUR.pedantic_hinting )
6500 CUR.error = FT_THROW( Invalid_Reference );
6504 /* XXX: Is there some undocumented feature while in the */
6505 /* twilight zone? */
6507 /* XXX: UNDOCUMENTED: twilight zone special case */
6509 if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
6511 FT_Vector* vec1 = &CUR.zp1.org[point];
6512 FT_Vector* vec2 = &CUR.zp0.org[CUR.GS.rp0];
6515 org_dist = CUR_Func_dualproj( vec1, vec2 );
6519 FT_Vector* vec1 = &CUR.zp1.orus[point];
6520 FT_Vector* vec2 = &CUR.zp0.orus[CUR.GS.rp0];
6523 if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
6525 /* this should be faster */
6526 org_dist = CUR_Func_dualproj( vec1, vec2 );
6527 org_dist = FT_MulFix( org_dist, CUR.metrics.x_scale );
6534 vec.x = FT_MulFix( vec1->x - vec2->x, CUR.metrics.x_scale );
6535 vec.y = FT_MulFix( vec1->y - vec2->y, CUR.metrics.y_scale );
6537 org_dist = CUR_fast_dualproj( &vec );
6541 /* single width cut-in test */
6543 if ( FT_ABS( org_dist - CUR.GS.single_width_value ) <
6544 CUR.GS.single_width_cutin )
6546 if ( org_dist >= 0 )
6547 org_dist = CUR.GS.single_width_value;
6549 org_dist = -CUR.GS.single_width_value;
6554 if ( ( CUR.opcode & 4 ) != 0 )
6556 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6557 if ( SUBPIXEL_HINTING &&
6558 CUR.ignore_x_mode &&
6559 CUR.GS.freeVector.x != 0 )
6560 distance = ROUND_None(
6562 CUR.tt_metrics.compensations[CUR.opcode & 3] );
6565 distance = CUR_Func_round(
6567 CUR.tt_metrics.compensations[CUR.opcode & 3] );
6570 distance = ROUND_None(
6572 CUR.tt_metrics.compensations[CUR.opcode & 3] );
6574 /* minimum distance flag */
6576 if ( ( CUR.opcode & 8 ) != 0 )
6578 if ( org_dist >= 0 )
6580 if ( distance < minimum_distance )
6581 distance = minimum_distance;
6585 if ( distance > -minimum_distance )
6586 distance = -minimum_distance;
6590 /* now move the point */
6592 org_dist = CUR_Func_project( CUR.zp1.cur + point,
6593 CUR.zp0.cur + CUR.GS.rp0 );
6595 CUR_Func_move( &CUR.zp1, point, distance - org_dist );
6598 CUR.GS.rp1 = CUR.GS.rp0;
6601 if ( ( CUR.opcode & 16 ) != 0 )
6606 /*************************************************************************/
6608 /* MIRP[abcde]: Move Indirect Relative Point */
6609 /* Opcode range: 0xE0-0xFF */
6610 /* Stack: int32? uint32 --> */
6618 FT_F26Dot6 cvt_dist,
6622 control_value_cutin,
6624 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6625 FT_Int B1 = 0; /* pacify compiler */
6627 FT_Bool reverse_move = FALSE;
6628 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6631 minimum_distance = CUR.GS.minimum_distance;
6632 control_value_cutin = CUR.GS.control_value_cutin;
6633 point = (FT_UShort)args[0];
6634 cvtEntry = (FT_ULong)( args[1] + 1 );
6636 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6637 if ( SUBPIXEL_HINTING &&
6638 CUR.ignore_x_mode &&
6639 CUR.GS.freeVector.x != 0 &&
6640 !( CUR.sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
6641 control_value_cutin = minimum_distance = 0;
6642 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6644 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
6646 if ( BOUNDS( point, CUR.zp1.n_points ) ||
6647 BOUNDSL( cvtEntry, CUR.cvtSize + 1 ) ||
6648 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
6650 if ( CUR.pedantic_hinting )
6651 CUR.error = FT_THROW( Invalid_Reference );
6658 cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
6660 /* single width test */
6662 if ( FT_ABS( cvt_dist - CUR.GS.single_width_value ) <
6663 CUR.GS.single_width_cutin )
6665 if ( cvt_dist >= 0 )
6666 cvt_dist = CUR.GS.single_width_value;
6668 cvt_dist = -CUR.GS.single_width_value;
6671 /* UNDOCUMENTED! The MS rasterizer does that with */
6672 /* twilight points (confirmed by Greg Hitchcock) */
6673 if ( CUR.GS.gep1 == 0 )
6675 CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +
6676 TT_MulFix14( (FT_UInt32)cvt_dist,
6677 CUR.GS.freeVector.x );
6678 CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
6679 TT_MulFix14( (FT_UInt32)cvt_dist,
6680 CUR.GS.freeVector.y );
6681 CUR.zp1.cur[point] = CUR.zp1.org[point];
6684 org_dist = CUR_Func_dualproj( &CUR.zp1.org[point],
6685 &CUR.zp0.org[CUR.GS.rp0] );
6686 cur_dist = CUR_Func_project ( &CUR.zp1.cur[point],
6687 &CUR.zp0.cur[CUR.GS.rp0] );
6689 /* auto-flip test */
6691 if ( CUR.GS.auto_flip )
6693 if ( ( org_dist ^ cvt_dist ) < 0 )
6694 cvt_dist = -cvt_dist;
6697 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6698 if ( SUBPIXEL_HINTING &&
6699 CUR.ignore_x_mode &&
6700 CUR.GS.freeVector.y != 0 &&
6701 ( CUR.sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) )
6703 if ( cur_dist < -64 )
6705 else if ( cur_dist > 64 && cur_dist < 84 )
6708 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6710 /* control value cut-in and round */
6712 if ( ( CUR.opcode & 4 ) != 0 )
6714 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
6715 /* refer to the same zone. */
6717 if ( CUR.GS.gep0 == CUR.GS.gep1 )
6719 /* XXX: According to Greg Hitchcock, the following wording is */
6720 /* the right one: */
6722 /* When the absolute difference between the value in */
6723 /* the table [CVT] and the measurement directly from */
6724 /* the outline is _greater_ than the cut_in value, the */
6725 /* outline measurement is used. */
6727 /* This is from `instgly.doc'. The description in */
6728 /* `ttinst2.doc', version 1.66, is thus incorrect since */
6729 /* it implies `>=' instead of `>'. */
6731 if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin )
6732 cvt_dist = org_dist;
6735 distance = CUR_Func_round(
6737 CUR.tt_metrics.compensations[CUR.opcode & 3] );
6742 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6743 /* do cvt cut-in always in MIRP for sph */
6744 if ( SUBPIXEL_HINTING &&
6745 CUR.ignore_x_mode &&
6746 CUR.GS.gep0 == CUR.GS.gep1 )
6748 if ( FT_ABS( cvt_dist - org_dist ) > control_value_cutin )
6749 cvt_dist = org_dist;
6751 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6753 distance = ROUND_None(
6755 CUR.tt_metrics.compensations[CUR.opcode & 3] );
6758 /* minimum distance test */
6760 if ( ( CUR.opcode & 8 ) != 0 )
6762 if ( org_dist >= 0 )
6764 if ( distance < minimum_distance )
6765 distance = minimum_distance;
6769 if ( distance > -minimum_distance )
6770 distance = -minimum_distance;
6774 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6775 if ( SUBPIXEL_HINTING )
6777 B1 = CUR.zp1.cur[point].y;
6779 /* Round moves if necessary */
6780 if ( CUR.ignore_x_mode &&
6781 CUR.GS.freeVector.y != 0 &&
6782 ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES ) )
6783 distance = FT_PIX_ROUND( B1 + distance - cur_dist ) - B1 + cur_dist;
6785 if ( CUR.ignore_x_mode &&
6786 CUR.GS.freeVector.y != 0 &&
6787 ( CUR.opcode & 16 ) == 0 &&
6788 ( CUR.opcode & 8 ) == 0 &&
6789 ( CUR.sph_tweak_flags & SPH_TWEAK_COURIER_NEW_2_HACK ) )
6792 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6794 CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
6796 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6797 if ( SUBPIXEL_HINTING )
6799 B2 = CUR.zp1.cur[point].y;
6801 /* Reverse move if necessary */
6802 if ( CUR.ignore_x_mode )
6804 if ( CUR.face->sph_compatibility_mode &&
6805 CUR.GS.freeVector.y != 0 &&
6808 reverse_move = TRUE;
6810 if ( ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
6811 CUR.GS.freeVector.y != 0 &&
6814 reverse_move = TRUE;
6818 CUR_Func_move( &CUR.zp1, point, -( distance - cur_dist ) );
6821 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6824 CUR.GS.rp1 = CUR.GS.rp0;
6826 if ( ( CUR.opcode & 16 ) != 0 )
6833 /*************************************************************************/
6835 /* ALIGNRP[]: ALIGN Relative Point */
6836 /* Opcode range: 0x3C */
6837 /* Stack: uint32 uint32... --> */
6840 Ins_ALIGNRP( INS_ARG )
6843 FT_F26Dot6 distance;
6848 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
6849 if ( SUBPIXEL_HINTING &&
6850 CUR.ignore_x_mode &&
6852 ( CUR.sph_tweak_flags & SPH_TWEAK_NO_ALIGNRP_AFTER_IUP ) )
6854 CUR.error = FT_THROW( Invalid_Reference );
6857 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
6859 if ( CUR.top < CUR.GS.loop ||
6860 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
6862 if ( CUR.pedantic_hinting )
6863 CUR.error = FT_THROW( Invalid_Reference );
6867 while ( CUR.GS.loop > 0 )
6871 point = (FT_UShort)CUR.stack[CUR.args];
6873 if ( BOUNDS( point, CUR.zp1.n_points ) )
6875 if ( CUR.pedantic_hinting )
6877 CUR.error = FT_THROW( Invalid_Reference );
6883 distance = CUR_Func_project( CUR.zp1.cur + point,
6884 CUR.zp0.cur + CUR.GS.rp0 );
6886 CUR_Func_move( &CUR.zp1, point, -distance );
6894 CUR.new_top = CUR.args;
6898 /*************************************************************************/
6900 /* ISECT[]: moves point to InterSECTion */
6901 /* Opcode range: 0x0F */
6902 /* Stack: 5 * uint32 --> */
6905 Ins_ISECT( INS_ARG )
6911 FT_F26Dot6 discriminant, dotproduct;
6922 point = (FT_UShort)args[0];
6924 a0 = (FT_UShort)args[1];
6925 a1 = (FT_UShort)args[2];
6926 b0 = (FT_UShort)args[3];
6927 b1 = (FT_UShort)args[4];
6929 if ( BOUNDS( b0, CUR.zp0.n_points ) ||
6930 BOUNDS( b1, CUR.zp0.n_points ) ||
6931 BOUNDS( a0, CUR.zp1.n_points ) ||
6932 BOUNDS( a1, CUR.zp1.n_points ) ||
6933 BOUNDS( point, CUR.zp2.n_points ) )
6935 if ( CUR.pedantic_hinting )
6936 CUR.error = FT_THROW( Invalid_Reference );
6942 dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
6943 dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
6945 dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;
6946 day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;
6948 dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;
6949 dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;
6951 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
6953 discriminant = FT_MulDiv( dax, -dby, 0x40 ) +
6954 FT_MulDiv( day, dbx, 0x40 );
6955 dotproduct = FT_MulDiv( dax, dbx, 0x40 ) +
6956 FT_MulDiv( day, dby, 0x40 );
6958 /* The discriminant above is actually a cross product of vectors */
6959 /* da and db. Together with the dot product, they can be used as */
6960 /* surrogates for sine and cosine of the angle between the vectors. */
6962 /* dotproduct = |da||db|cos(angle) */
6963 /* discriminant = |da||db|sin(angle) . */
6964 /* We use these equations to reject grazing intersections by */
6965 /* thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. */
6966 if ( 19 * FT_ABS( discriminant ) > FT_ABS( dotproduct ) )
6968 val = FT_MulDiv( dx, -dby, 0x40 ) + FT_MulDiv( dy, dbx, 0x40 );
6970 R.x = FT_MulDiv( val, dax, discriminant );
6971 R.y = FT_MulDiv( val, day, discriminant );
6973 CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
6974 CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
6978 /* else, take the middle of the middles of A and B */
6980 CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +
6983 CUR.zp0.cur[b1].x ) / 4;
6984 CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +
6987 CUR.zp0.cur[b1].y ) / 4;
6992 /*************************************************************************/
6994 /* ALIGNPTS[]: ALIGN PoinTS */
6995 /* Opcode range: 0x27 */
6996 /* Stack: uint32 uint32 --> */
6999 Ins_ALIGNPTS( INS_ARG )
7002 FT_F26Dot6 distance;
7005 p1 = (FT_UShort)args[0];
7006 p2 = (FT_UShort)args[1];
7008 if ( BOUNDS( p1, CUR.zp1.n_points ) ||
7009 BOUNDS( p2, CUR.zp0.n_points ) )
7011 if ( CUR.pedantic_hinting )
7012 CUR.error = FT_THROW( Invalid_Reference );
7016 distance = CUR_Func_project( CUR.zp0.cur + p2,
7017 CUR.zp1.cur + p1 ) / 2;
7019 CUR_Func_move( &CUR.zp1, p1, distance );
7020 CUR_Func_move( &CUR.zp0, p2, -distance );
7024 /*************************************************************************/
7026 /* IP[]: Interpolate Point */
7027 /* Opcode range: 0x39 */
7028 /* Stack: uint32... --> */
7031 /* SOMETIMES, DUMBER CODE IS BETTER CODE */
7036 FT_F26Dot6 old_range, cur_range;
7037 FT_Vector* orus_base;
7038 FT_Vector* cur_base;
7044 if ( CUR.top < CUR.GS.loop )
7046 if ( CUR.pedantic_hinting )
7047 CUR.error = FT_THROW( Invalid_Reference );
7052 * We need to deal in a special way with the twilight zone.
7053 * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0),
7056 twilight = CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 || CUR.GS.gep2 == 0;
7058 if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) )
7060 if ( CUR.pedantic_hinting )
7061 CUR.error = FT_THROW( Invalid_Reference );
7066 orus_base = &CUR.zp0.org[CUR.GS.rp1];
7068 orus_base = &CUR.zp0.orus[CUR.GS.rp1];
7070 cur_base = &CUR.zp0.cur[CUR.GS.rp1];
7072 /* XXX: There are some glyphs in some braindead but popular */
7073 /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
7074 /* calling IP[] with bad values of rp[12]. */
7075 /* Do something sane when this odd thing happens. */
7076 if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
7077 BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
7085 old_range = CUR_Func_dualproj( &CUR.zp1.org[CUR.GS.rp2],
7087 else if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
7088 old_range = CUR_Func_dualproj( &CUR.zp1.orus[CUR.GS.rp2],
7095 vec.x = FT_MulFix( CUR.zp1.orus[CUR.GS.rp2].x - orus_base->x,
7096 CUR.metrics.x_scale );
7097 vec.y = FT_MulFix( CUR.zp1.orus[CUR.GS.rp2].y - orus_base->y,
7098 CUR.metrics.y_scale );
7100 old_range = CUR_fast_dualproj( &vec );
7103 cur_range = CUR_Func_project ( &CUR.zp1.cur[CUR.GS.rp2], cur_base );
7106 for ( ; CUR.GS.loop > 0; --CUR.GS.loop )
7108 FT_UInt point = (FT_UInt)CUR.stack[--CUR.args];
7109 FT_F26Dot6 org_dist, cur_dist, new_dist;
7112 /* check point bounds */
7113 if ( BOUNDS( point, CUR.zp2.n_points ) )
7115 if ( CUR.pedantic_hinting )
7117 CUR.error = FT_THROW( Invalid_Reference );
7124 org_dist = CUR_Func_dualproj( &CUR.zp2.org[point], orus_base );
7125 else if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
7126 org_dist = CUR_Func_dualproj( &CUR.zp2.orus[point], orus_base );
7132 vec.x = FT_MulFix( CUR.zp2.orus[point].x - orus_base->x,
7133 CUR.metrics.x_scale );
7134 vec.y = FT_MulFix( CUR.zp2.orus[point].y - orus_base->y,
7135 CUR.metrics.y_scale );
7137 org_dist = CUR_fast_dualproj( &vec );
7140 cur_dist = CUR_Func_project( &CUR.zp2.cur[point], cur_base );
7145 new_dist = FT_MulDiv( org_dist, cur_range, old_range );
7148 /* This is the same as what MS does for the invalid case: */
7150 /* delta = (Original_Pt - Original_RP1) - */
7151 /* (Current_Pt - Current_RP1) ; */
7153 /* In FreeType speak: */
7155 /* delta = org_dist - cur_dist . */
7157 /* We move `point' by `new_dist - cur_dist' after leaving */
7158 /* this block, thus we have */
7160 /* new_dist - cur_dist = delta , */
7161 /* new_dist - cur_dist = org_dist - cur_dist , */
7162 /* new_dist = org_dist . */
7164 new_dist = org_dist;
7170 CUR_Func_move( &CUR.zp2, (FT_UShort)point, new_dist - cur_dist );
7175 CUR.new_top = CUR.args;
7179 /*************************************************************************/
7181 /* UTP[a]: UnTouch Point */
7182 /* Opcode range: 0x29 */
7183 /* Stack: uint32 --> */
7192 point = (FT_UShort)args[0];
7194 if ( BOUNDS( point, CUR.zp0.n_points ) )
7196 if ( CUR.pedantic_hinting )
7197 CUR.error = FT_THROW( Invalid_Reference );
7203 if ( CUR.GS.freeVector.x != 0 )
7204 mask &= ~FT_CURVE_TAG_TOUCH_X;
7206 if ( CUR.GS.freeVector.y != 0 )
7207 mask &= ~FT_CURVE_TAG_TOUCH_Y;
7209 CUR.zp0.tags[point] &= mask;
7213 /* Local variables for Ins_IUP: */
7214 typedef struct IUP_WorkerRec_
7216 FT_Vector* orgs; /* original and current coordinate */
7217 FT_Vector* curs; /* arrays */
7221 } IUP_WorkerRec, *IUP_Worker;
7225 _iup_worker_shift( IUP_Worker worker,
7234 dx = worker->curs[p].x - worker->orgs[p].x;
7237 for ( i = p1; i < p; i++ )
7238 worker->curs[i].x += dx;
7240 for ( i = p + 1; i <= p2; i++ )
7241 worker->curs[i].x += dx;
7247 _iup_worker_interpolate( IUP_Worker worker,
7254 FT_F26Dot6 orus1, orus2, org1, org2, delta1, delta2;
7260 if ( BOUNDS( ref1, worker->max_points ) ||
7261 BOUNDS( ref2, worker->max_points ) )
7264 orus1 = worker->orus[ref1].x;
7265 orus2 = worker->orus[ref2].x;
7267 if ( orus1 > orus2 )
7282 org1 = worker->orgs[ref1].x;
7283 org2 = worker->orgs[ref2].x;
7284 delta1 = worker->curs[ref1].x - org1;
7285 delta2 = worker->curs[ref2].x - org2;
7287 if ( orus1 == orus2 )
7289 /* simple shift of untouched points */
7290 for ( i = p1; i <= p2; i++ )
7292 FT_F26Dot6 x = worker->orgs[i].x;
7300 worker->curs[i].x = x;
7306 FT_Bool scale_valid = 0;
7310 for ( i = p1; i <= p2; i++ )
7312 FT_F26Dot6 x = worker->orgs[i].x;
7318 else if ( x >= org2 )
7326 scale = FT_DivFix( org2 + delta2 - ( org1 + delta1 ),
7330 x = ( org1 + delta1 ) +
7331 FT_MulFix( worker->orus[i].x - orus1, scale );
7333 worker->curs[i].x = x;
7339 /*************************************************************************/
7341 /* IUP[a]: Interpolate Untouched Points */
7342 /* Opcode range: 0x30-0x31 */
7351 FT_UInt first_point; /* first point of contour */
7352 FT_UInt end_point; /* end point (last+1) of contour */
7354 FT_UInt first_touched; /* first touched point in contour */
7355 FT_UInt cur_touched; /* current touched point in contour */
7357 FT_UInt point; /* current point */
7358 FT_Short contour; /* current contour */
7363 /* ignore empty outlines */
7364 if ( CUR.pts.n_contours == 0 )
7367 if ( CUR.opcode & 1 )
7369 mask = FT_CURVE_TAG_TOUCH_X;
7370 V.orgs = CUR.pts.org;
7371 V.curs = CUR.pts.cur;
7372 V.orus = CUR.pts.orus;
7376 mask = FT_CURVE_TAG_TOUCH_Y;
7377 V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
7378 V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
7379 V.orus = (FT_Vector*)( (FT_Pos*)CUR.pts.orus + 1 );
7381 V.max_points = CUR.pts.n_points;
7386 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
7387 if ( SUBPIXEL_HINTING &&
7390 CUR.iup_called = TRUE;
7391 if ( CUR.sph_tweak_flags & SPH_TWEAK_SKIP_IUP )
7394 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
7398 end_point = CUR.pts.contours[contour] - CUR.pts.first_point;
7399 first_point = point;
7401 if ( BOUNDS ( end_point, CUR.pts.n_points ) )
7402 end_point = CUR.pts.n_points - 1;
7404 while ( point <= end_point && ( CUR.pts.tags[point] & mask ) == 0 )
7407 if ( point <= end_point )
7409 first_touched = point;
7410 cur_touched = point;
7414 while ( point <= end_point )
7416 if ( ( CUR.pts.tags[point] & mask ) != 0 )
7418 _iup_worker_interpolate( &V,
7423 cur_touched = point;
7429 if ( cur_touched == first_touched )
7430 _iup_worker_shift( &V, first_point, end_point, cur_touched );
7433 _iup_worker_interpolate( &V,
7434 (FT_UShort)( cur_touched + 1 ),
7439 if ( first_touched > 0 )
7440 _iup_worker_interpolate( &V,
7448 } while ( contour < CUR.pts.n_contours );
7452 /*************************************************************************/
7454 /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
7455 /* Opcode range: 0x5D,0x71,0x72 */
7456 /* Stack: uint32 (2 * uint32)... --> */
7459 Ins_DELTAP( INS_ARG )
7465 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
7469 if ( SUBPIXEL_HINTING &&
7470 CUR.ignore_x_mode &&
7472 ( CUR.sph_tweak_flags & SPH_TWEAK_NO_DELTAP_AFTER_IUP ) )
7474 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
7477 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
7478 /* Delta hinting is covered by US Patent 5159668. */
7479 if ( CUR.face->unpatented_hinting )
7481 FT_Long n = args[0] * 2;
7486 if ( CUR.pedantic_hinting )
7487 CUR.error = FT_THROW( Too_Few_Arguments );
7492 CUR.new_top = CUR.args;
7497 P = (FT_ULong)CUR_Func_cur_ppem();
7498 nump = (FT_ULong)args[0]; /* some points theoretically may occur more
7499 than once, thus UShort isn't enough */
7501 for ( k = 1; k <= nump; k++ )
7505 if ( CUR.pedantic_hinting )
7506 CUR.error = FT_THROW( Too_Few_Arguments );
7513 A = (FT_UShort)CUR.stack[CUR.args + 1];
7514 B = CUR.stack[CUR.args];
7516 /* XXX: Because some popular fonts contain some invalid DeltaP */
7517 /* instructions, we simply ignore them when the stacked */
7518 /* point reference is off limit, rather than returning an */
7519 /* error. As a delta instruction doesn't change a glyph */
7520 /* in great ways, this shouldn't be a problem. */
7522 if ( !BOUNDS( A, CUR.zp0.n_points ) )
7524 C = ( (FT_ULong)B & 0xF0 ) >> 4;
7526 switch ( CUR.opcode )
7540 C += CUR.GS.delta_base;
7544 B = ( (FT_ULong)B & 0xF ) - 8;
7547 B *= 1L << ( 6 - CUR.GS.delta_shift );
7549 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
7551 if ( SUBPIXEL_HINTING )
7554 * Allow delta move if
7556 * - not using ignore_x_mode rendering,
7557 * - glyph is specifically set to allow it, or
7558 * - glyph is composite and freedom vector is not in subpixel
7561 if ( !CUR.ignore_x_mode ||
7562 ( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_DO_DELTAP ) ||
7563 ( CUR.is_composite && CUR.GS.freeVector.y != 0 ) )
7564 CUR_Func_move( &CUR.zp0, A, B );
7566 /* Otherwise, apply subpixel hinting and compatibility mode */
7567 /* rules, always skipping deltas in subpixel direction. */
7568 else if ( CUR.ignore_x_mode && CUR.GS.freeVector.y != 0 )
7570 /* save the y value of the point now; compare after move */
7571 B1 = (FT_UShort)CUR.zp0.cur[A].y;
7573 /* Standard subpixel hinting: Allow y move for y-touched */
7574 /* points. This messes up DejaVu ... */
7575 if ( !CUR.face->sph_compatibility_mode &&
7576 ( CUR.zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) )
7577 CUR_Func_move( &CUR.zp0, A, B );
7579 /* compatibility mode */
7580 else if ( CUR.face->sph_compatibility_mode &&
7581 !( CUR.sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) )
7583 if ( CUR.sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
7584 B = FT_PIX_ROUND( B1 + B ) - B1;
7586 /* Allow delta move if using sph_compatibility_mode, */
7587 /* IUP has not been called, and point is touched on Y. */
7588 if ( !CUR.iup_called &&
7589 ( CUR.zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) )
7590 CUR_Func_move( &CUR.zp0, A, B );
7593 B2 = (FT_UShort)CUR.zp0.cur[A].y;
7595 /* Reverse this move if it results in a disallowed move */
7596 if ( CUR.GS.freeVector.y != 0 &&
7597 ( ( CUR.face->sph_compatibility_mode &&
7599 ( B2 & 63 ) != 0 ) ||
7600 ( ( CUR.sph_tweak_flags &
7601 SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP ) &&
7603 ( B2 & 63 ) != 0 ) ) )
7604 CUR_Func_move( &CUR.zp0, A, -B );
7608 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
7610 CUR_Func_move( &CUR.zp0, A, B );
7614 if ( CUR.pedantic_hinting )
7615 CUR.error = FT_THROW( Invalid_Reference );
7619 CUR.new_top = CUR.args;
7623 /*************************************************************************/
7625 /* DELTACn[]: DELTA exceptions C1, C2, C3 */
7626 /* Opcode range: 0x73,0x74,0x75 */
7627 /* Stack: uint32 (2 * uint32)... --> */
7630 Ins_DELTAC( INS_ARG )
7637 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
7638 /* Delta hinting is covered by US Patent 5159668. */
7639 if ( CUR.face->unpatented_hinting )
7641 FT_Long n = args[0] * 2;
7646 if ( CUR.pedantic_hinting )
7647 CUR.error = FT_THROW( Too_Few_Arguments );
7652 CUR.new_top = CUR.args;
7657 P = (FT_ULong)CUR_Func_cur_ppem();
7658 nump = (FT_ULong)args[0];
7660 for ( k = 1; k <= nump; k++ )
7664 if ( CUR.pedantic_hinting )
7665 CUR.error = FT_THROW( Too_Few_Arguments );
7672 A = (FT_ULong)CUR.stack[CUR.args + 1];
7673 B = CUR.stack[CUR.args];
7675 if ( BOUNDSL( A, CUR.cvtSize ) )
7677 if ( CUR.pedantic_hinting )
7679 CUR.error = FT_THROW( Invalid_Reference );
7685 C = ( (FT_ULong)B & 0xF0 ) >> 4;
7687 switch ( CUR.opcode )
7701 C += CUR.GS.delta_base;
7705 B = ( (FT_ULong)B & 0xF ) - 8;
7708 B *= 1L << ( 6 - CUR.GS.delta_shift );
7710 CUR_Func_move_cvt( A, B );
7716 CUR.new_top = CUR.args;
7720 /*************************************************************************/
7722 /* MISC. INSTRUCTIONS */
7724 /*************************************************************************/
7727 /*************************************************************************/
7729 /* GETINFO[]: GET INFOrmation */
7730 /* Opcode range: 0x88 */
7731 /* Stack: uint32 --> uint32 */
7734 Ins_GETINFO( INS_ARG )
7741 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
7742 /********************************/
7743 /* RASTERIZER VERSION */
7744 /* Selector Bit: 0 */
7745 /* Return Bit(s): 0-7 */
7747 if ( SUBPIXEL_HINTING &&
7748 ( args[0] & 1 ) != 0 &&
7751 K = CUR.rasterizer_version;
7752 FT_TRACE7(( "Setting rasterizer version %d\n",
7753 CUR.rasterizer_version ));
7756 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
7757 if ( ( args[0] & 1 ) != 0 )
7758 K = TT_INTERPRETER_VERSION_35;
7760 /********************************/
7762 /* Selector Bit: 1 */
7763 /* Return Bit(s): 8 */
7765 if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated )
7768 /********************************/
7769 /* GLYPH STRETCHED */
7770 /* Selector Bit: 2 */
7771 /* Return Bit(s): 9 */
7773 if ( ( args[0] & 4 ) != 0 && CUR.tt_metrics.stretched )
7776 /********************************/
7777 /* HINTING FOR GRAYSCALE */
7778 /* Selector Bit: 5 */
7779 /* Return Bit(s): 12 */
7781 if ( ( args[0] & 32 ) != 0 && CUR.grayscale )
7784 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
7786 if ( SUBPIXEL_HINTING &&
7787 CUR.ignore_x_mode &&
7788 CUR.rasterizer_version >= TT_INTERPRETER_VERSION_35 )
7791 if ( CUR.rasterizer_version >= 37 )
7793 /********************************/
7794 /* HINTING FOR SUBPIXEL */
7795 /* Selector Bit: 6 */
7796 /* Return Bit(s): 13 */
7798 if ( ( args[0] & 64 ) != 0 && CUR.subpixel )
7801 /********************************/
7802 /* COMPATIBLE WIDTHS ENABLED */
7803 /* Selector Bit: 7 */
7804 /* Return Bit(s): 14 */
7806 /* Functionality still needs to be added */
7807 if ( ( args[0] & 128 ) != 0 && CUR.compatible_widths )
7810 /********************************/
7811 /* SYMMETRICAL SMOOTHING */
7812 /* Selector Bit: 8 */
7813 /* Return Bit(s): 15 */
7815 /* Functionality still needs to be added */
7816 if ( ( args[0] & 256 ) != 0 && CUR.symmetrical_smoothing )
7819 /********************************/
7820 /* HINTING FOR BGR? */
7821 /* Selector Bit: 9 */
7822 /* Return Bit(s): 16 */
7824 /* Functionality still needs to be added */
7825 if ( ( args[0] & 512 ) != 0 && CUR.bgr )
7828 if ( CUR.rasterizer_version >= 38 )
7830 /********************************/
7831 /* SUBPIXEL POSITIONED? */
7832 /* Selector Bit: 10 */
7833 /* Return Bit(s): 17 */
7835 /* Functionality still needs to be added */
7836 if ( ( args[0] & 1024 ) != 0 && CUR.subpixel_positioned )
7842 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
7849 Ins_UNKNOWN( INS_ARG )
7851 TT_DefRecord* def = CUR.IDefs;
7852 TT_DefRecord* limit = def + CUR.numIDefs;
7857 for ( ; def < limit; def++ )
7859 if ( (FT_Byte)def->opc == CUR.opcode && def->active )
7864 if ( CUR.callTop >= CUR.callSize )
7866 CUR.error = FT_THROW( Stack_Overflow );
7870 call = CUR.callStack + CUR.callTop++;
7872 call->Caller_Range = CUR.curRange;
7873 call->Caller_IP = CUR.IP + 1;
7874 call->Cur_Count = 1;
7877 INS_Goto_CodeRange( def->range, def->start );
7879 CUR.step_ins = FALSE;
7884 CUR.error = FT_THROW( Invalid_Opcode );
7888 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
7892 TInstruction_Function Instruct_Dispatch[256] =
7894 /* Opcodes are gathered in groups of 16. */
7895 /* Please keep the spaces as they are. */
7897 /* SVTCA y */ Ins_SVTCA,
7898 /* SVTCA x */ Ins_SVTCA,
7899 /* SPvTCA y */ Ins_SPVTCA,
7900 /* SPvTCA x */ Ins_SPVTCA,
7901 /* SFvTCA y */ Ins_SFVTCA,
7902 /* SFvTCA x */ Ins_SFVTCA,
7903 /* SPvTL // */ Ins_SPVTL,
7904 /* SPvTL + */ Ins_SPVTL,
7905 /* SFvTL // */ Ins_SFVTL,
7906 /* SFvTL + */ Ins_SFVTL,
7907 /* SPvFS */ Ins_SPVFS,
7908 /* SFvFS */ Ins_SFVFS,
7911 /* SFvTPv */ Ins_SFVTPV,
7912 /* ISECT */ Ins_ISECT,
7914 /* SRP0 */ Ins_SRP0,
7915 /* SRP1 */ Ins_SRP1,
7916 /* SRP2 */ Ins_SRP2,
7917 /* SZP0 */ Ins_SZP0,
7918 /* SZP1 */ Ins_SZP1,
7919 /* SZP2 */ Ins_SZP2,
7920 /* SZPS */ Ins_SZPS,
7921 /* SLOOP */ Ins_SLOOP,
7923 /* RTHG */ Ins_RTHG,
7925 /* ELSE */ Ins_ELSE,
7926 /* JMPR */ Ins_JMPR,
7927 /* SCvTCi */ Ins_SCVTCI,
7928 /* SSwCi */ Ins_SSWCI,
7933 /* CLEAR */ Ins_CLEAR,
7934 /* SWAP */ Ins_SWAP,
7935 /* DEPTH */ Ins_DEPTH,
7936 /* CINDEX */ Ins_CINDEX,
7937 /* MINDEX */ Ins_MINDEX,
7938 /* AlignPTS */ Ins_ALIGNPTS,
7939 /* INS_0x28 */ Ins_UNKNOWN,
7941 /* LOOPCALL */ Ins_LOOPCALL,
7942 /* CALL */ Ins_CALL,
7943 /* FDEF */ Ins_FDEF,
7944 /* ENDF */ Ins_ENDF,
7945 /* MDAP[0] */ Ins_MDAP,
7946 /* MDAP[1] */ Ins_MDAP,
7948 /* IUP[0] */ Ins_IUP,
7949 /* IUP[1] */ Ins_IUP,
7950 /* SHP[0] */ Ins_SHP,
7951 /* SHP[1] */ Ins_SHP,
7952 /* SHC[0] */ Ins_SHC,
7953 /* SHC[1] */ Ins_SHC,
7954 /* SHZ[0] */ Ins_SHZ,
7955 /* SHZ[1] */ Ins_SHZ,
7956 /* SHPIX */ Ins_SHPIX,
7958 /* MSIRP[0] */ Ins_MSIRP,
7959 /* MSIRP[1] */ Ins_MSIRP,
7960 /* AlignRP */ Ins_ALIGNRP,
7961 /* RTDG */ Ins_RTDG,
7962 /* MIAP[0] */ Ins_MIAP,
7963 /* MIAP[1] */ Ins_MIAP,
7965 /* NPushB */ Ins_NPUSHB,
7966 /* NPushW */ Ins_NPUSHW,
7969 /* WCvtP */ Ins_WCVTP,
7970 /* RCvt */ Ins_RCVT,
7973 /* SCFS */ Ins_SCFS,
7976 /* MPPEM */ Ins_MPPEM,
7978 /* FlipON */ Ins_FLIPON,
7979 /* FlipOFF */ Ins_FLIPOFF,
7980 /* DEBUG */ Ins_DEBUG,
7983 /* LTEQ */ Ins_LTEQ,
7985 /* GTEQ */ Ins_GTEQ,
7989 /* EVEN */ Ins_EVEN,
7995 /* DeltaP1 */ Ins_DELTAP,
8005 /* FLOOR */ Ins_FLOOR,
8006 /* CEILING */ Ins_CEILING,
8007 /* ROUND[0] */ Ins_ROUND,
8008 /* ROUND[1] */ Ins_ROUND,
8009 /* ROUND[2] */ Ins_ROUND,
8010 /* ROUND[3] */ Ins_ROUND,
8011 /* NROUND[0] */ Ins_NROUND,
8012 /* NROUND[1] */ Ins_NROUND,
8013 /* NROUND[2] */ Ins_NROUND,
8014 /* NROUND[3] */ Ins_NROUND,
8016 /* WCvtF */ Ins_WCVTF,
8017 /* DeltaP2 */ Ins_DELTAP,
8018 /* DeltaP3 */ Ins_DELTAP,
8019 /* DeltaCn[0] */ Ins_DELTAC,
8020 /* DeltaCn[1] */ Ins_DELTAC,
8021 /* DeltaCn[2] */ Ins_DELTAC,
8022 /* SROUND */ Ins_SROUND,
8023 /* S45Round */ Ins_S45ROUND,
8024 /* JROT */ Ins_JROT,
8025 /* JROF */ Ins_JROF,
8026 /* ROFF */ Ins_ROFF,
8027 /* INS_0x7B */ Ins_UNKNOWN,
8028 /* RUTG */ Ins_RUTG,
8029 /* RDTG */ Ins_RDTG,
8030 /* SANGW */ Ins_SANGW,
8033 /* FlipPT */ Ins_FLIPPT,
8034 /* FlipRgON */ Ins_FLIPRGON,
8035 /* FlipRgOFF */ Ins_FLIPRGOFF,
8036 /* INS_0x83 */ Ins_UNKNOWN,
8037 /* INS_0x84 */ Ins_UNKNOWN,
8038 /* ScanCTRL */ Ins_SCANCTRL,
8039 /* SDPVTL[0] */ Ins_SDPVTL,
8040 /* SDPVTL[1] */ Ins_SDPVTL,
8041 /* GetINFO */ Ins_GETINFO,
8042 /* IDEF */ Ins_IDEF,
8043 /* ROLL */ Ins_ROLL,
8046 /* ScanTYPE */ Ins_SCANTYPE,
8047 /* InstCTRL */ Ins_INSTCTRL,
8048 /* INS_0x8F */ Ins_UNKNOWN,
8050 /* INS_0x90 */ Ins_UNKNOWN,
8051 /* INS_0x91 */ Ins_UNKNOWN,
8052 /* INS_0x92 */ Ins_UNKNOWN,
8053 /* INS_0x93 */ Ins_UNKNOWN,
8054 /* INS_0x94 */ Ins_UNKNOWN,
8055 /* INS_0x95 */ Ins_UNKNOWN,
8056 /* INS_0x96 */ Ins_UNKNOWN,
8057 /* INS_0x97 */ Ins_UNKNOWN,
8058 /* INS_0x98 */ Ins_UNKNOWN,
8059 /* INS_0x99 */ Ins_UNKNOWN,
8060 /* INS_0x9A */ Ins_UNKNOWN,
8061 /* INS_0x9B */ Ins_UNKNOWN,
8062 /* INS_0x9C */ Ins_UNKNOWN,
8063 /* INS_0x9D */ Ins_UNKNOWN,
8064 /* INS_0x9E */ Ins_UNKNOWN,
8065 /* INS_0x9F */ Ins_UNKNOWN,
8067 /* INS_0xA0 */ Ins_UNKNOWN,
8068 /* INS_0xA1 */ Ins_UNKNOWN,
8069 /* INS_0xA2 */ Ins_UNKNOWN,
8070 /* INS_0xA3 */ Ins_UNKNOWN,
8071 /* INS_0xA4 */ Ins_UNKNOWN,
8072 /* INS_0xA5 */ Ins_UNKNOWN,
8073 /* INS_0xA6 */ Ins_UNKNOWN,
8074 /* INS_0xA7 */ Ins_UNKNOWN,
8075 /* INS_0xA8 */ Ins_UNKNOWN,
8076 /* INS_0xA9 */ Ins_UNKNOWN,
8077 /* INS_0xAA */ Ins_UNKNOWN,
8078 /* INS_0xAB */ Ins_UNKNOWN,
8079 /* INS_0xAC */ Ins_UNKNOWN,
8080 /* INS_0xAD */ Ins_UNKNOWN,
8081 /* INS_0xAE */ Ins_UNKNOWN,
8082 /* INS_0xAF */ Ins_UNKNOWN,
8084 /* PushB[0] */ Ins_PUSHB,
8085 /* PushB[1] */ Ins_PUSHB,
8086 /* PushB[2] */ Ins_PUSHB,
8087 /* PushB[3] */ Ins_PUSHB,
8088 /* PushB[4] */ Ins_PUSHB,
8089 /* PushB[5] */ Ins_PUSHB,
8090 /* PushB[6] */ Ins_PUSHB,
8091 /* PushB[7] */ Ins_PUSHB,
8092 /* PushW[0] */ Ins_PUSHW,
8093 /* PushW[1] */ Ins_PUSHW,
8094 /* PushW[2] */ Ins_PUSHW,
8095 /* PushW[3] */ Ins_PUSHW,
8096 /* PushW[4] */ Ins_PUSHW,
8097 /* PushW[5] */ Ins_PUSHW,
8098 /* PushW[6] */ Ins_PUSHW,
8099 /* PushW[7] */ Ins_PUSHW,
8101 /* MDRP[00] */ Ins_MDRP,
8102 /* MDRP[01] */ Ins_MDRP,
8103 /* MDRP[02] */ Ins_MDRP,
8104 /* MDRP[03] */ Ins_MDRP,
8105 /* MDRP[04] */ Ins_MDRP,
8106 /* MDRP[05] */ Ins_MDRP,
8107 /* MDRP[06] */ Ins_MDRP,
8108 /* MDRP[07] */ Ins_MDRP,
8109 /* MDRP[08] */ Ins_MDRP,
8110 /* MDRP[09] */ Ins_MDRP,
8111 /* MDRP[10] */ Ins_MDRP,
8112 /* MDRP[11] */ Ins_MDRP,
8113 /* MDRP[12] */ Ins_MDRP,
8114 /* MDRP[13] */ Ins_MDRP,
8115 /* MDRP[14] */ Ins_MDRP,
8116 /* MDRP[15] */ Ins_MDRP,
8118 /* MDRP[16] */ Ins_MDRP,
8119 /* MDRP[17] */ Ins_MDRP,
8120 /* MDRP[18] */ Ins_MDRP,
8121 /* MDRP[19] */ Ins_MDRP,
8122 /* MDRP[20] */ Ins_MDRP,
8123 /* MDRP[21] */ Ins_MDRP,
8124 /* MDRP[22] */ Ins_MDRP,
8125 /* MDRP[23] */ Ins_MDRP,
8126 /* MDRP[24] */ Ins_MDRP,
8127 /* MDRP[25] */ Ins_MDRP,
8128 /* MDRP[26] */ Ins_MDRP,
8129 /* MDRP[27] */ Ins_MDRP,
8130 /* MDRP[28] */ Ins_MDRP,
8131 /* MDRP[29] */ Ins_MDRP,
8132 /* MDRP[30] */ Ins_MDRP,
8133 /* MDRP[31] */ Ins_MDRP,
8135 /* MIRP[00] */ Ins_MIRP,
8136 /* MIRP[01] */ Ins_MIRP,
8137 /* MIRP[02] */ Ins_MIRP,
8138 /* MIRP[03] */ Ins_MIRP,
8139 /* MIRP[04] */ Ins_MIRP,
8140 /* MIRP[05] */ Ins_MIRP,
8141 /* MIRP[06] */ Ins_MIRP,
8142 /* MIRP[07] */ Ins_MIRP,
8143 /* MIRP[08] */ Ins_MIRP,
8144 /* MIRP[09] */ Ins_MIRP,
8145 /* MIRP[10] */ Ins_MIRP,
8146 /* MIRP[11] */ Ins_MIRP,
8147 /* MIRP[12] */ Ins_MIRP,
8148 /* MIRP[13] */ Ins_MIRP,
8149 /* MIRP[14] */ Ins_MIRP,
8150 /* MIRP[15] */ Ins_MIRP,
8152 /* MIRP[16] */ Ins_MIRP,
8153 /* MIRP[17] */ Ins_MIRP,
8154 /* MIRP[18] */ Ins_MIRP,
8155 /* MIRP[19] */ Ins_MIRP,
8156 /* MIRP[20] */ Ins_MIRP,
8157 /* MIRP[21] */ Ins_MIRP,
8158 /* MIRP[22] */ Ins_MIRP,
8159 /* MIRP[23] */ Ins_MIRP,
8160 /* MIRP[24] */ Ins_MIRP,
8161 /* MIRP[25] */ Ins_MIRP,
8162 /* MIRP[26] */ Ins_MIRP,
8163 /* MIRP[27] */ Ins_MIRP,
8164 /* MIRP[28] */ Ins_MIRP,
8165 /* MIRP[29] */ Ins_MIRP,
8166 /* MIRP[30] */ Ins_MIRP,
8167 /* MIRP[31] */ Ins_MIRP
8171 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
8174 /*************************************************************************/
8178 /* This function executes a run of opcodes. It will exit in the */
8179 /* following cases: */
8181 /* - Errors (in which case it returns FALSE). */
8183 /* - Reaching the end of the main code range (returns TRUE). */
8184 /* Reaching the end of a code range within a function call is an */
8187 /* - After executing one single opcode, if the flag `Instruction_Trap' */
8188 /* is set to TRUE (returns TRUE). */
8190 /* On exit with TRUE, test IP < CodeSize to know whether it comes from */
8191 /* an instruction trap or a normal termination. */
8194 /* Note: The documented DEBUG opcode pops a value from the stack. This */
8195 /* behaviour is unsupported; here a DEBUG opcode is always an */
8199 /* THIS IS THE INTERPRETER'S MAIN LOOP. */
8201 /* Instructions appear in the specification's order. */
8203 /*************************************************************************/
8206 /* documentation is in ttinterp.h */
8208 FT_EXPORT_DEF( FT_Error )
8209 TT_RunIns( TT_ExecContext exc )
8211 FT_Long ins_counter = 0; /* executed instructions counter */
8214 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
8215 FT_Byte opcode_pattern[1][2] = {
8216 /* #8 TypeMan Talk Align */
8222 FT_UShort opcode_patterns = 1;
8223 FT_UShort opcode_pointer[1] = { 0 };
8224 FT_UShort opcode_size[1] = { 1 };
8225 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
8228 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
8230 return FT_THROW( Invalid_Argument );
8235 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
8236 CUR.iup_called = FALSE;
8237 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
8239 /* set PPEM and CVT functions */
8240 CUR.tt_metrics.ratio = 0;
8241 if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
8243 /* non-square pixels, use the stretched routines */
8244 CUR.func_cur_ppem = Current_Ppem_Stretched;
8245 CUR.func_read_cvt = Read_CVT_Stretched;
8246 CUR.func_write_cvt = Write_CVT_Stretched;
8247 CUR.func_move_cvt = Move_CVT_Stretched;
8251 /* square pixels, use normal routines */
8252 CUR.func_cur_ppem = Current_Ppem;
8253 CUR.func_read_cvt = Read_CVT;
8254 CUR.func_write_cvt = Write_CVT;
8255 CUR.func_move_cvt = Move_CVT;
8259 COMPUTE_Round( (FT_Byte)exc->GS.round_state );
8263 CUR.opcode = CUR.code[CUR.IP];
8266 FT_TRACE7(( opcode_name[CUR.opcode] ));
8267 FT_TRACE7(( "\n" ));
8269 if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )
8271 if ( CUR.IP + 1 >= CUR.codeSize )
8272 goto LErrorCodeOverflow_;
8274 CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
8277 if ( CUR.IP + CUR.length > CUR.codeSize )
8278 goto LErrorCodeOverflow_;
8280 /* First, let's check for empty stack and overflow */
8281 CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 );
8283 /* `args' is the top of the stack once arguments have been popped. */
8284 /* One can also interpret it as the index of the last argument. */
8287 if ( CUR.pedantic_hinting )
8289 CUR.error = FT_THROW( Too_Few_Arguments );
8293 /* push zeroes onto the stack */
8294 for ( i = 0; i < Pop_Push_Count[CUR.opcode] >> 4; i++ )
8299 CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 );
8301 /* `new_top' is the new top of the stack, after the instruction's */
8302 /* execution. `top' will be set to `new_top' after the `switch' */
8304 if ( CUR.new_top > CUR.stackSize )
8306 CUR.error = FT_THROW( Stack_Overflow );
8310 CUR.step_ins = TRUE;
8311 CUR.error = FT_Err_Ok;
8313 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
8315 if ( SUBPIXEL_HINTING )
8317 for ( i = 0; i < opcode_patterns; i++ )
8319 if ( opcode_pointer[i] < opcode_size[i] &&
8320 CUR.opcode == opcode_pattern[i][opcode_pointer[i]] )
8322 opcode_pointer[i] += 1;
8324 if ( opcode_pointer[i] == opcode_size[i] )
8326 FT_TRACE7(( "sph: opcode ptrn: %d, %s %s\n",
8328 CUR.face->root.family_name,
8329 CUR.face->root.style_name ));
8336 opcode_pointer[i] = 0;
8340 opcode_pointer[i] = 0;
8344 #endif /* TT_CONFIG_OPTION_SUBPIXEL_HINTING */
8346 #ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
8349 FT_Long* args = CUR.stack + CUR.args;
8350 FT_Byte opcode = CUR.opcode;
8353 #undef ARRAY_BOUND_ERROR
8354 #define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
8359 case 0x00: /* SVTCA y */
8360 case 0x01: /* SVTCA x */
8361 case 0x02: /* SPvTCA y */
8362 case 0x03: /* SPvTCA x */
8363 case 0x04: /* SFvTCA y */
8364 case 0x05: /* SFvTCA x */
8369 AA = (FT_Short)( ( opcode & 1 ) << 14 );
8370 BB = (FT_Short)( AA ^ 0x4000 );
8374 CUR.GS.projVector.x = AA;
8375 CUR.GS.projVector.y = BB;
8377 CUR.GS.dualVector.x = AA;
8378 CUR.GS.dualVector.y = BB;
8382 GUESS_VECTOR( projVector );
8385 if ( ( opcode & 2 ) == 0 )
8387 CUR.GS.freeVector.x = AA;
8388 CUR.GS.freeVector.y = BB;
8392 GUESS_VECTOR( freeVector );
8399 case 0x06: /* SPvTL // */
8400 case 0x07: /* SPvTL + */
8404 case 0x08: /* SFvTL // */
8405 case 0x09: /* SFvTL + */
8409 case 0x0A: /* SPvFS */
8413 case 0x0B: /* SFvFS */
8417 case 0x0C: /* GPV */
8421 case 0x0D: /* GFV */
8425 case 0x0E: /* SFvTPv */
8429 case 0x0F: /* ISECT */
8430 Ins_ISECT( EXEC_ARG_ args );
8433 case 0x10: /* SRP0 */
8437 case 0x11: /* SRP1 */
8441 case 0x12: /* SRP2 */
8445 case 0x13: /* SZP0 */
8446 Ins_SZP0( EXEC_ARG_ args );
8449 case 0x14: /* SZP1 */
8450 Ins_SZP1( EXEC_ARG_ args );
8453 case 0x15: /* SZP2 */
8454 Ins_SZP2( EXEC_ARG_ args );
8457 case 0x16: /* SZPS */
8458 Ins_SZPS( EXEC_ARG_ args );
8461 case 0x17: /* SLOOP */
8465 case 0x18: /* RTG */
8469 case 0x19: /* RTHG */
8473 case 0x1A: /* SMD */
8477 case 0x1B: /* ELSE */
8478 Ins_ELSE( EXEC_ARG_ args );
8481 case 0x1C: /* JMPR */
8485 case 0x1D: /* SCVTCI */
8489 case 0x1E: /* SSWCI */
8493 case 0x1F: /* SSW */
8497 case 0x20: /* DUP */
8501 case 0x21: /* POP */
8505 case 0x22: /* CLEAR */
8509 case 0x23: /* SWAP */
8513 case 0x24: /* DEPTH */
8517 case 0x25: /* CINDEX */
8521 case 0x26: /* MINDEX */
8522 Ins_MINDEX( EXEC_ARG_ args );
8525 case 0x27: /* ALIGNPTS */
8526 Ins_ALIGNPTS( EXEC_ARG_ args );
8529 case 0x28: /* ???? */
8530 Ins_UNKNOWN( EXEC_ARG_ args );
8533 case 0x29: /* UTP */
8534 Ins_UTP( EXEC_ARG_ args );
8537 case 0x2A: /* LOOPCALL */
8538 Ins_LOOPCALL( EXEC_ARG_ args );
8541 case 0x2B: /* CALL */
8542 Ins_CALL( EXEC_ARG_ args );
8545 case 0x2C: /* FDEF */
8546 Ins_FDEF( EXEC_ARG_ args );
8549 case 0x2D: /* ENDF */
8550 Ins_ENDF( EXEC_ARG_ args );
8553 case 0x2E: /* MDAP */
8554 case 0x2F: /* MDAP */
8555 Ins_MDAP( EXEC_ARG_ args );
8558 case 0x30: /* IUP */
8559 case 0x31: /* IUP */
8560 Ins_IUP( EXEC_ARG_ args );
8563 case 0x32: /* SHP */
8564 case 0x33: /* SHP */
8565 Ins_SHP( EXEC_ARG_ args );
8568 case 0x34: /* SHC */
8569 case 0x35: /* SHC */
8570 Ins_SHC( EXEC_ARG_ args );
8573 case 0x36: /* SHZ */
8574 case 0x37: /* SHZ */
8575 Ins_SHZ( EXEC_ARG_ args );
8578 case 0x38: /* SHPIX */
8579 Ins_SHPIX( EXEC_ARG_ args );
8583 Ins_IP( EXEC_ARG_ args );
8586 case 0x3A: /* MSIRP */
8587 case 0x3B: /* MSIRP */
8588 Ins_MSIRP( EXEC_ARG_ args );
8591 case 0x3C: /* AlignRP */
8592 Ins_ALIGNRP( EXEC_ARG_ args );
8595 case 0x3D: /* RTDG */
8599 case 0x3E: /* MIAP */
8600 case 0x3F: /* MIAP */
8601 Ins_MIAP( EXEC_ARG_ args );
8604 case 0x40: /* NPUSHB */
8605 Ins_NPUSHB( EXEC_ARG_ args );
8608 case 0x41: /* NPUSHW */
8609 Ins_NPUSHW( EXEC_ARG_ args );
8617 CUR.error = FT_THROW( Invalid_Reference );
8624 case 0x44: /* WCVTP */
8628 case 0x45: /* RCVT */
8634 Ins_GC( EXEC_ARG_ args );
8637 case 0x48: /* SCFS */
8638 Ins_SCFS( EXEC_ARG_ args );
8643 Ins_MD( EXEC_ARG_ args );
8646 case 0x4B: /* MPPEM */
8650 case 0x4C: /* MPS */
8654 case 0x4D: /* FLIPON */
8658 case 0x4E: /* FLIPOFF */
8662 case 0x4F: /* DEBUG */
8670 case 0x51: /* LTEQ */
8678 case 0x53: /* GTEQ */
8686 case 0x55: /* NEQ */
8690 case 0x56: /* ODD */
8694 case 0x57: /* EVEN */
8699 Ins_IF( EXEC_ARG_ args );
8702 case 0x59: /* EIF */
8706 case 0x5A: /* AND */
8714 case 0x5C: /* NOT */
8718 case 0x5D: /* DELTAP1 */
8719 Ins_DELTAP( EXEC_ARG_ args );
8722 case 0x5E: /* SDB */
8726 case 0x5F: /* SDS */
8730 case 0x60: /* ADD */
8734 case 0x61: /* SUB */
8738 case 0x62: /* DIV */
8742 case 0x63: /* MUL */
8746 case 0x64: /* ABS */
8750 case 0x65: /* NEG */
8754 case 0x66: /* FLOOR */
8758 case 0x67: /* CEILING */
8762 case 0x68: /* ROUND */
8763 case 0x69: /* ROUND */
8764 case 0x6A: /* ROUND */
8765 case 0x6B: /* ROUND */
8769 case 0x6C: /* NROUND */
8770 case 0x6D: /* NROUND */
8771 case 0x6E: /* NRRUND */
8772 case 0x6F: /* NROUND */
8776 case 0x70: /* WCVTF */
8780 case 0x71: /* DELTAP2 */
8781 case 0x72: /* DELTAP3 */
8782 Ins_DELTAP( EXEC_ARG_ args );
8785 case 0x73: /* DELTAC0 */
8786 case 0x74: /* DELTAC1 */
8787 case 0x75: /* DELTAC2 */
8788 Ins_DELTAC( EXEC_ARG_ args );
8791 case 0x76: /* SROUND */
8795 case 0x77: /* S45Round */
8799 case 0x78: /* JROT */
8803 case 0x79: /* JROF */
8807 case 0x7A: /* ROFF */
8811 case 0x7B: /* ???? */
8812 Ins_UNKNOWN( EXEC_ARG_ args );
8815 case 0x7C: /* RUTG */
8819 case 0x7D: /* RDTG */
8823 case 0x7E: /* SANGW */
8825 /* nothing - obsolete */
8828 case 0x80: /* FLIPPT */
8829 Ins_FLIPPT( EXEC_ARG_ args );
8832 case 0x81: /* FLIPRGON */
8833 Ins_FLIPRGON( EXEC_ARG_ args );
8836 case 0x82: /* FLIPRGOFF */
8837 Ins_FLIPRGOFF( EXEC_ARG_ args );
8840 case 0x83: /* UNKNOWN */
8841 case 0x84: /* UNKNOWN */
8842 Ins_UNKNOWN( EXEC_ARG_ args );
8845 case 0x85: /* SCANCTRL */
8846 Ins_SCANCTRL( EXEC_ARG_ args );
8849 case 0x86: /* SDPVTL */
8850 case 0x87: /* SDPVTL */
8851 Ins_SDPVTL( EXEC_ARG_ args );
8854 case 0x88: /* GETINFO */
8855 Ins_GETINFO( EXEC_ARG_ args );
8858 case 0x89: /* IDEF */
8859 Ins_IDEF( EXEC_ARG_ args );
8862 case 0x8A: /* ROLL */
8863 Ins_ROLL( EXEC_ARG_ args );
8866 case 0x8B: /* MAX */
8870 case 0x8C: /* MIN */
8874 case 0x8D: /* SCANTYPE */
8875 Ins_SCANTYPE( EXEC_ARG_ args );
8878 case 0x8E: /* INSTCTRL */
8879 Ins_INSTCTRL( EXEC_ARG_ args );
8883 Ins_UNKNOWN( EXEC_ARG_ args );
8887 if ( opcode >= 0xE0 )
8888 Ins_MIRP( EXEC_ARG_ args );
8889 else if ( opcode >= 0xC0 )
8890 Ins_MDRP( EXEC_ARG_ args );
8891 else if ( opcode >= 0xB8 )
8892 Ins_PUSHW( EXEC_ARG_ args );
8893 else if ( opcode >= 0xB0 )
8894 Ins_PUSHB( EXEC_ARG_ args );
8896 Ins_UNKNOWN( EXEC_ARG_ args );
8903 Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );
8905 #endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
8909 switch ( CUR.error )
8911 /* looking for redefined instructions */
8912 case FT_ERR( Invalid_Opcode ):
8914 TT_DefRecord* def = CUR.IDefs;
8915 TT_DefRecord* limit = def + CUR.numIDefs;
8918 for ( ; def < limit; def++ )
8920 if ( def->active && CUR.opcode == (FT_Byte)def->opc )
8922 TT_CallRec* callrec;
8925 if ( CUR.callTop >= CUR.callSize )
8927 CUR.error = FT_THROW( Invalid_Reference );
8931 callrec = &CUR.callStack[CUR.callTop];
8933 callrec->Caller_Range = CUR.curRange;
8934 callrec->Caller_IP = CUR.IP + 1;
8935 callrec->Cur_Count = 1;
8938 if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
8946 CUR.error = FT_THROW( Invalid_Opcode );
8950 break; /* Unreachable code warning suppression. */
8951 /* Leave to remind in case a later change the editor */
8952 /* to consider break; */
8964 CUR.top = CUR.new_top;
8967 CUR.IP += CUR.length;
8969 /* increment instruction counter and check if we didn't */
8970 /* run this program for too long (e.g. infinite loops). */
8971 if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
8972 return FT_THROW( Execution_Too_Long );
8975 if ( CUR.IP >= CUR.codeSize )
8977 if ( CUR.callTop > 0 )
8979 CUR.error = FT_THROW( Code_Overflow );
8985 } while ( !CUR.instruction_trap );
8989 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
8995 LErrorCodeOverflow_:
8996 CUR.error = FT_THROW( Code_Overflow );
9000 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
9004 /* If any errors have occurred, function tables may be broken. */
9005 /* Force a re-execution of `prep' and `fpgm' tables if no */
9006 /* bytecode debugger is run. */
9008 !CUR.instruction_trap &&
9009 CUR.curRange == tt_coderange_glyph )
9011 FT_TRACE1(( " The interpreter returned error 0x%x\n", CUR.error ));
9012 exc->size->bytecode_ready = -1;
9013 exc->size->cvt_ready = -1;
9020 #endif /* TT_USE_BYTECODE_INTERPRETER */