1 /***************************************************************************/
5 /* TrueType bytecode interpreter (body). */
7 /* Copyright 1996-2001, 2002 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
16 /***************************************************************************/
20 #include FT_INTERNAL_DEBUG_H
21 #include FT_INTERNAL_CALC_H
22 #include FT_TRIGONOMETRY_H
30 #ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
33 #define TT_MULFIX FT_MulFix
34 #define TT_MULDIV FT_MulDiv
35 #define TT_INT64 FT_Int64
37 /*************************************************************************/
39 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
40 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
41 /* messages during execution. */
44 #define FT_COMPONENT trace_ttinterp
46 #undef NO_APPLE_PATENT
47 #define APPLE_THRESHOLD 0x4000000L
49 /*************************************************************************/
51 /* In order to detect infinite loops in the code, we set up a counter */
52 /* within the run loop. A single stroke of interpretation is now */
53 /* limitet to a maximal number of opcodes defined below. */
55 #define MAX_RUNNABLE_OPCODES 1000000L
58 /*************************************************************************/
60 /* There are two kinds of implementations: */
62 /* a. static implementation */
64 /* The current execution context is a static variable, which fields */
65 /* are accessed directly by the interpreter during execution. The */
66 /* context is named `cur'. */
68 /* This version is non-reentrant, of course. */
70 /* b. indirect implementation */
72 /* The current execution context is passed to _each_ function as its */
73 /* first argument, and each field is thus accessed indirectly. */
75 /* This version is fully re-entrant. */
77 /* The idea is that an indirect implementation may be slower to execute */
78 /* on low-end processors that are used in some systems (like 386s or */
81 /* As a consequence, the indirect implementation is now the default, as */
82 /* its performance costs can be considered negligible in our context. */
83 /* Note, however, that we kept the same source with macros because: */
85 /* - The code is kept very close in design to the Pascal code used for */
88 /* - It's much more readable that way! */
90 /* - It's still open to experimentation and tuning. */
92 /*************************************************************************/
95 #ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */
97 #define CUR (*exc) /* see ttobjs.h */
99 #else /* static implementation */
104 TT_ExecContextRec cur
; /* static exec. context variable */
106 /* apparently, we have a _lot_ of direct indexing when accessing */
107 /* the static `cur', which makes the code bigger (due to all the */
108 /* four bytes addresses). */
110 #endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
113 /*************************************************************************/
115 /* The instruction argument stack. */
117 #define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */
120 /*************************************************************************/
122 /* This macro is used whenever `exec' is unused in a function, to avoid */
123 /* stupid warnings from pedantic compilers. */
125 #define FT_UNUSED_EXEC FT_UNUSED( CUR )
128 /*************************************************************************/
130 /* This macro is used whenever `args' is unused in a function, to avoid */
131 /* stupid warnings from pedantic compilers. */
133 #define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args )
136 /*************************************************************************/
138 /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */
139 /* increase readabilty of the code. */
141 /*************************************************************************/
144 #define SKIP_Code() \
147 #define GET_ShortIns() \
148 GetShortIns( EXEC_ARG )
150 #define NORMalize( x, y, v ) \
151 Normalize( EXEC_ARG_ x, y, v )
153 #define SET_SuperRound( scale, flags ) \
154 SetSuperRound( EXEC_ARG_ scale, flags )
156 #define ROUND_None( d, c ) \
157 Round_None( EXEC_ARG_ d, c )
159 #define INS_Goto_CodeRange( range, ip ) \
160 Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
162 #define CUR_Func_project( x, y ) \
163 CUR.func_project( EXEC_ARG_ x, y )
165 #define CUR_Func_move( z, p, d ) \
166 CUR.func_move( EXEC_ARG_ z, p, d )
168 #define CUR_Func_dualproj( x, y ) \
169 CUR.func_dualproj( EXEC_ARG_ x, y )
171 #define CUR_Func_freeProj( x, y ) \
172 CUR.func_freeProj( EXEC_ARG_ x, y )
174 #define CUR_Func_round( d, c ) \
175 CUR.func_round( EXEC_ARG_ d, c )
177 #define CUR_Func_read_cvt( index ) \
178 CUR.func_read_cvt( EXEC_ARG_ index )
180 #define CUR_Func_write_cvt( index, val ) \
181 CUR.func_write_cvt( EXEC_ARG_ index, val )
183 #define CUR_Func_move_cvt( index, val ) \
184 CUR.func_move_cvt( EXEC_ARG_ index, val )
186 #define CURRENT_Ratio() \
187 Current_Ratio( EXEC_ARG )
189 #define CURRENT_Ppem() \
190 Current_Ppem( EXEC_ARG )
195 #define INS_SxVTL( a, b, c, d ) \
196 Ins_SxVTL( EXEC_ARG_ a, b, c, d )
198 #define COMPUTE_Funcs() \
199 Compute_Funcs( EXEC_ARG )
201 #define COMPUTE_Round( a ) \
202 Compute_Round( EXEC_ARG_ a )
204 #define COMPUTE_Point_Displacement( a, b, c, d ) \
205 Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
207 #define MOVE_Zp2_Point( a, b, c, t ) \
208 Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
211 /*************************************************************************/
213 /* Instruction dispatch function, as used by the interpreter. */
215 typedef void (*TInstruction_Function
)( INS_ARG
);
218 /*************************************************************************/
220 /* A simple bounds-checking macro. */
222 #define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
232 /*************************************************************************/
234 /* CODERANGE FUNCTIONS */
236 /*************************************************************************/
239 /*************************************************************************/
242 /* TT_Goto_CodeRange */
245 /* Switches to a new code range (updates the code related elements in */
246 /* `exec', and `IP'). */
249 /* range :: The new execution code range. */
251 /* IP :: The new IP in the new code range. */
254 /* exec :: The target execution context. */
257 /* FreeType error code. 0 means success. */
259 FT_LOCAL_DEF( FT_Error
)
260 TT_Goto_CodeRange( TT_ExecContext exec
,
264 TT_CodeRange
* coderange
;
267 FT_ASSERT( range
>= 1 && range
<= 3 );
269 coderange
= &exec
->codeRangeTable
[range
- 1];
271 FT_ASSERT( coderange
->base
!= NULL
);
273 /* NOTE: Because the last instruction of a program may be a CALL */
274 /* which will return to the first byte *after* the code */
275 /* range, we test for IP <= Size instead of IP < Size. */
277 FT_ASSERT( (FT_ULong
)IP
<= coderange
->size
);
279 exec
->code
= coderange
->base
;
280 exec
->codeSize
= coderange
->size
;
282 exec
->curRange
= range
;
288 /*************************************************************************/
291 /* TT_Set_CodeRange */
294 /* Sets a code range. */
297 /* range :: The code range index. */
299 /* base :: The new code base. */
301 /* length :: The range size in bytes. */
304 /* exec :: The target execution context. */
307 /* FreeType error code. 0 means success. */
309 FT_LOCAL_DEF( FT_Error
)
310 TT_Set_CodeRange( TT_ExecContext exec
,
315 FT_ASSERT( range
>= 1 && range
<= 3 );
317 exec
->codeRangeTable
[range
- 1].base
= (FT_Byte
*)base
;
318 exec
->codeRangeTable
[range
- 1].size
= length
;
324 /*************************************************************************/
327 /* TT_Clear_CodeRange */
330 /* Clears a code range. */
333 /* range :: The code range index. */
336 /* exec :: The target execution context. */
339 /* FreeType error code. 0 means success. */
342 /* Does not set the Error variable. */
344 FT_LOCAL_DEF( FT_Error
)
345 TT_Clear_CodeRange( TT_ExecContext exec
,
348 FT_ASSERT( range
>= 1 && range
<= 3 );
350 exec
->codeRangeTable
[range
- 1].base
= NULL
;
351 exec
->codeRangeTable
[range
- 1].size
= 0;
357 /*************************************************************************/
359 /* EXECUTION CONTEXT ROUTINES */
361 /*************************************************************************/
364 /*************************************************************************/
367 /* TT_Destroy_Context */
370 /* Destroys a given context. */
373 /* exec :: A handle to the target execution context. */
375 /* memory :: A handle to the parent memory object. */
378 /* FreeType error code. 0 means success. */
381 /* Only the glyph loader and debugger should call this function. */
383 FT_LOCAL_DEF( FT_Error
)
384 TT_Destroy_Context( TT_ExecContext exec
,
387 /* free composite load stack */
388 FT_FREE( exec
->loadStack
);
393 exec
->maxContours
= 0;
396 FT_FREE( exec
->stack
);
399 /* free call stack */
400 FT_FREE( exec
->callStack
);
404 /* free glyph code range */
405 FT_FREE( exec
->glyphIns
);
416 /*************************************************************************/
422 /* Initializes a context object. */
425 /* memory :: A handle to the parent memory object. */
427 /* face :: A handle to the source TrueType face object. */
430 /* exec :: A handle to the target execution context. */
433 /* FreeType error code. 0 means success. */
436 Init_Context( TT_ExecContext exec
,
443 FT_TRACE1(( "Init_Context: new object at 0x%08p, parent = 0x%08p\n",
446 exec
->memory
= memory
;
449 if ( FT_NEW_ARRAY( exec
->callStack
, exec
->callSize
) )
452 /* all values in the context are set to 0 already, but this is */
453 /* here as a remainder */
455 exec
->maxContours
= 0;
462 exec
->loadStack
= NULL
;
463 exec
->glyphIns
= NULL
;
471 FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n",
473 TT_Destroy_Context( exec
, memory
);
479 /*************************************************************************/
485 /* Checks the size of a buffer and reallocates it if necessary. */
488 /* memory :: A handle to the parent memory object. */
490 /* multiplier :: The size in bytes of each element in the buffer. */
492 /* new_max :: The new capacity (size) of the buffer. */
495 /* size :: The address of the buffer's current size expressed */
498 /* buff :: The address of the buffer base pointer. */
501 /* FreeType error code. 0 means success. */
504 Update_Max( FT_Memory memory
,
513 if ( *size
< new_max
)
516 if ( FT_ALLOC( *buff
, new_max
* multiplier
) )
525 /*************************************************************************/
528 /* TT_Load_Context */
531 /* Prepare an execution context for glyph hinting. */
534 /* face :: A handle to the source face object. */
536 /* size :: A handle to the source size object. */
539 /* exec :: A handle to the target execution context. */
542 /* FreeType error code. 0 means success. */
545 /* Only the glyph loader and debugger should call this function. */
547 FT_LOCAL_DEF( FT_Error
)
548 TT_Load_Context( TT_ExecContext exec
,
559 maxp
= &face
->max_profile
;
564 exec
->numFDefs
= size
->num_function_defs
;
565 exec
->maxFDefs
= size
->max_function_defs
;
566 exec
->numIDefs
= size
->num_instruction_defs
;
567 exec
->maxIDefs
= size
->max_instruction_defs
;
568 exec
->FDefs
= size
->function_defs
;
569 exec
->IDefs
= size
->instruction_defs
;
570 exec
->tt_metrics
= size
->ttmetrics
;
571 exec
->metrics
= size
->root
.metrics
;
573 exec
->maxFunc
= size
->max_func
;
574 exec
->maxIns
= size
->max_ins
;
576 for ( i
= 0; i
< TT_MAX_CODE_RANGES
; i
++ )
577 exec
->codeRangeTable
[i
] = size
->codeRangeTable
[i
];
579 /* set graphics state */
582 exec
->cvtSize
= size
->cvt_size
;
583 exec
->cvt
= size
->cvt
;
585 exec
->storeSize
= size
->storage_size
;
586 exec
->storage
= size
->storage
;
588 exec
->twilight
= size
->twilight
;
591 error
= Update_Max( exec
->memory
,
593 sizeof ( TT_SubGlyphRec
),
594 (void**)&exec
->loadStack
,
595 exec
->face
->max_components
+ 1 );
599 /* XXX: We reserve a little more elements on the stack to deal safely */
600 /* with broken fonts like arialbs, courbs, timesbs, etc. */
601 tmp
= exec
->stackSize
;
602 error
= Update_Max( exec
->memory
,
604 sizeof ( FT_F26Dot6
),
605 (void**)&exec
->stack
,
606 maxp
->maxStackElements
+ 32 );
607 exec
->stackSize
= (FT_UInt
)tmp
;
611 tmp
= exec
->glyphSize
;
612 error
= Update_Max( exec
->memory
,
615 (void**)&exec
->glyphIns
,
616 maxp
->maxSizeOfInstructions
);
617 exec
->glyphSize
= (FT_UShort
)tmp
;
621 exec
->pts
.n_points
= 0;
622 exec
->pts
.n_contours
= 0;
624 exec
->instruction_trap
= FALSE
;
630 /*************************************************************************/
633 /* TT_Save_Context */
636 /* Saves the code ranges in a `size' object. */
639 /* exec :: A handle to the source execution context. */
642 /* size :: A handle to the target size object. */
645 /* FreeType error code. 0 means success. */
648 /* Only the glyph loader and debugger should call this function. */
650 FT_LOCAL_DEF( FT_Error
)
651 TT_Save_Context( TT_ExecContext exec
,
657 /* XXXX: Will probably disappear soon with all the code range */
658 /* management, which is now rather obsolete. */
660 size
->num_function_defs
= exec
->numFDefs
;
661 size
->num_instruction_defs
= exec
->numIDefs
;
663 size
->max_func
= exec
->maxFunc
;
664 size
->max_ins
= exec
->maxIns
;
666 for ( i
= 0; i
< TT_MAX_CODE_RANGES
; i
++ )
667 size
->codeRangeTable
[i
] = exec
->codeRangeTable
[i
];
673 /*************************************************************************/
679 /* Executes one or more instructions in the execution context. */
682 /* debug :: A Boolean flag. If set, the function sets some internal */
683 /* variables and returns immediately, otherwise TT_RunIns() */
686 /* This is commented out currently. */
689 /* exec :: A handle to the target execution context. */
692 /* TrueTyoe error code. 0 means success. */
695 /* Only the glyph loader and debugger should call this function. */
697 FT_LOCAL_DEF( FT_Error
)
698 TT_Run_Context( TT_ExecContext exec
,
704 if ( ( error
= TT_Goto_CodeRange( exec
, tt_coderange_glyph
, 0 ) )
708 exec
->zp0
= exec
->pts
;
709 exec
->zp1
= exec
->pts
;
710 exec
->zp2
= exec
->pts
;
716 exec
->GS
.projVector
.x
= 0x4000;
717 exec
->GS
.projVector
.y
= 0x0000;
719 exec
->GS
.freeVector
= exec
->GS
.projVector
;
720 exec
->GS
.dualVector
= exec
->GS
.projVector
;
722 exec
->GS
.round_state
= 1;
725 /* some glyphs leave something on the stack. so we clean it */
726 /* before a new execution. */
733 return exec
->face
->interpreter( exec
);
736 return TT_RunIns( exec
);
743 const TT_GraphicsState tt_default_graphics_state
=
750 TRUE
, 68, 0, 0, 9, 3,
755 /* documentation is in ttinterp.h */
757 FT_EXPORT_DEF( TT_ExecContext
)
758 TT_New_Context( TT_Face face
)
768 driver
= (TT_Driver
)face
->root
.driver
;
770 memory
= driver
->root
.root
.memory
;
771 exec
= driver
->context
;
773 if ( !driver
->context
)
778 /* allocate object */
779 if ( FT_NEW( exec
) )
783 error
= Init_Context( exec
, face
, memory
);
787 /* store it into the driver */
788 driver
->context
= exec
;
792 return driver
->context
;
801 /*************************************************************************/
804 /* TT_Done_Context */
807 /* Discards an execution context. */
810 /* exec :: A handle to the target execution context. */
813 /* FreeType error code. 0 means success. */
816 /* Only the glyph loader and debugger should call this function. */
818 FT_LOCAL_DEF( FT_Error
)
819 TT_Done_Context( TT_ExecContext exec
)
821 /* Nothing at all for now */
829 /*************************************************************************/
831 /* Before an opcode is executed, the interpreter verifies that there are */
832 /* enough arguments on the stack, with the help of the Pop_Push_Count */
835 /* For each opcode, the first column gives the number of arguments that */
836 /* are popped from the stack; the second one gives the number of those */
837 /* that are pushed in result. */
839 /* Note that for opcodes with a varying number of parameters, either 0 */
840 /* or 1 arg is verified before execution, depending on the nature of the */
843 /* - if the number of arguments is given by the bytecode stream or the */
844 /* loop variable, 0 is chosen. */
846 /* - if the first argument is a count n that is followed by arguments */
847 /* a1 .. an, then 1 is chosen. */
849 /*************************************************************************/
853 #define PACK( x, y ) ( ( x << 4 ) | y )
857 const FT_Byte Pop_Push_Count
[256] =
859 /* opcodes are gathered in groups of 16 */
860 /* please keep the spaces as they are */
862 /* SVTCA y */ PACK( 0, 0 ),
863 /* SVTCA x */ PACK( 0, 0 ),
864 /* SPvTCA y */ PACK( 0, 0 ),
865 /* SPvTCA x */ PACK( 0, 0 ),
866 /* SFvTCA y */ PACK( 0, 0 ),
867 /* SFvTCA x */ PACK( 0, 0 ),
868 /* SPvTL // */ PACK( 2, 0 ),
869 /* SPvTL + */ PACK( 2, 0 ),
870 /* SFvTL // */ PACK( 2, 0 ),
871 /* SFvTL + */ PACK( 2, 0 ),
872 /* SPvFS */ PACK( 2, 0 ),
873 /* SFvFS */ PACK( 2, 0 ),
874 /* GPV */ PACK( 0, 2 ),
875 /* GFV */ PACK( 0, 2 ),
876 /* SFvTPv */ PACK( 0, 0 ),
877 /* ISECT */ PACK( 5, 0 ),
879 /* SRP0 */ PACK( 1, 0 ),
880 /* SRP1 */ PACK( 1, 0 ),
881 /* SRP2 */ PACK( 1, 0 ),
882 /* SZP0 */ PACK( 1, 0 ),
883 /* SZP1 */ PACK( 1, 0 ),
884 /* SZP2 */ PACK( 1, 0 ),
885 /* SZPS */ PACK( 1, 0 ),
886 /* SLOOP */ PACK( 1, 0 ),
887 /* RTG */ PACK( 0, 0 ),
888 /* RTHG */ PACK( 0, 0 ),
889 /* SMD */ PACK( 1, 0 ),
890 /* ELSE */ PACK( 0, 0 ),
891 /* JMPR */ PACK( 1, 0 ),
892 /* SCvTCi */ PACK( 1, 0 ),
893 /* SSwCi */ PACK( 1, 0 ),
894 /* SSW */ PACK( 1, 0 ),
896 /* DUP */ PACK( 1, 2 ),
897 /* POP */ PACK( 1, 0 ),
898 /* CLEAR */ PACK( 0, 0 ),
899 /* SWAP */ PACK( 2, 2 ),
900 /* DEPTH */ PACK( 0, 1 ),
901 /* CINDEX */ PACK( 1, 1 ),
902 /* MINDEX */ PACK( 1, 0 ),
903 /* AlignPTS */ PACK( 2, 0 ),
904 /* INS_$28 */ PACK( 0, 0 ),
905 /* UTP */ PACK( 1, 0 ),
906 /* LOOPCALL */ PACK( 2, 0 ),
907 /* CALL */ PACK( 1, 0 ),
908 /* FDEF */ PACK( 1, 0 ),
909 /* ENDF */ PACK( 0, 0 ),
910 /* MDAP[0] */ PACK( 1, 0 ),
911 /* MDAP[1] */ PACK( 1, 0 ),
913 /* IUP[0] */ PACK( 0, 0 ),
914 /* IUP[1] */ PACK( 0, 0 ),
915 /* SHP[0] */ PACK( 0, 0 ),
916 /* SHP[1] */ PACK( 0, 0 ),
917 /* SHC[0] */ PACK( 1, 0 ),
918 /* SHC[1] */ PACK( 1, 0 ),
919 /* SHZ[0] */ PACK( 1, 0 ),
920 /* SHZ[1] */ PACK( 1, 0 ),
921 /* SHPIX */ PACK( 1, 0 ),
922 /* IP */ PACK( 0, 0 ),
923 /* MSIRP[0] */ PACK( 2, 0 ),
924 /* MSIRP[1] */ PACK( 2, 0 ),
925 /* AlignRP */ PACK( 0, 0 ),
926 /* RTDG */ PACK( 0, 0 ),
927 /* MIAP[0] */ PACK( 2, 0 ),
928 /* MIAP[1] */ PACK( 2, 0 ),
930 /* NPushB */ PACK( 0, 0 ),
931 /* NPushW */ PACK( 0, 0 ),
932 /* WS */ PACK( 2, 0 ),
933 /* RS */ PACK( 1, 1 ),
934 /* WCvtP */ PACK( 2, 0 ),
935 /* RCvt */ PACK( 1, 1 ),
936 /* GC[0] */ PACK( 1, 1 ),
937 /* GC[1] */ PACK( 1, 1 ),
938 /* SCFS */ PACK( 2, 0 ),
939 /* MD[0] */ PACK( 2, 1 ),
940 /* MD[1] */ PACK( 2, 1 ),
941 /* MPPEM */ PACK( 0, 1 ),
942 /* MPS */ PACK( 0, 1 ),
943 /* FlipON */ PACK( 0, 0 ),
944 /* FlipOFF */ PACK( 0, 0 ),
945 /* DEBUG */ PACK( 1, 0 ),
947 /* LT */ PACK( 2, 1 ),
948 /* LTEQ */ PACK( 2, 1 ),
949 /* GT */ PACK( 2, 1 ),
950 /* GTEQ */ PACK( 2, 1 ),
951 /* EQ */ PACK( 2, 1 ),
952 /* NEQ */ PACK( 2, 1 ),
953 /* ODD */ PACK( 1, 1 ),
954 /* EVEN */ PACK( 1, 1 ),
955 /* IF */ PACK( 1, 0 ),
956 /* EIF */ PACK( 0, 0 ),
957 /* AND */ PACK( 2, 1 ),
958 /* OR */ PACK( 2, 1 ),
959 /* NOT */ PACK( 1, 1 ),
960 /* DeltaP1 */ PACK( 1, 0 ),
961 /* SDB */ PACK( 1, 0 ),
962 /* SDS */ PACK( 1, 0 ),
964 /* ADD */ PACK( 2, 1 ),
965 /* SUB */ PACK( 2, 1 ),
966 /* DIV */ PACK( 2, 1 ),
967 /* MUL */ PACK( 2, 1 ),
968 /* ABS */ PACK( 1, 1 ),
969 /* NEG */ PACK( 1, 1 ),
970 /* FLOOR */ PACK( 1, 1 ),
971 /* CEILING */ PACK( 1, 1 ),
972 /* ROUND[0] */ PACK( 1, 1 ),
973 /* ROUND[1] */ PACK( 1, 1 ),
974 /* ROUND[2] */ PACK( 1, 1 ),
975 /* ROUND[3] */ PACK( 1, 1 ),
976 /* NROUND[0] */ PACK( 1, 1 ),
977 /* NROUND[1] */ PACK( 1, 1 ),
978 /* NROUND[2] */ PACK( 1, 1 ),
979 /* NROUND[3] */ PACK( 1, 1 ),
981 /* WCvtF */ PACK( 2, 0 ),
982 /* DeltaP2 */ PACK( 1, 0 ),
983 /* DeltaP3 */ PACK( 1, 0 ),
984 /* DeltaCn[0] */ PACK( 1, 0 ),
985 /* DeltaCn[1] */ PACK( 1, 0 ),
986 /* DeltaCn[2] */ PACK( 1, 0 ),
987 /* SROUND */ PACK( 1, 0 ),
988 /* S45Round */ PACK( 1, 0 ),
989 /* JROT */ PACK( 2, 0 ),
990 /* JROF */ PACK( 2, 0 ),
991 /* ROFF */ PACK( 0, 0 ),
992 /* INS_$7B */ PACK( 0, 0 ),
993 /* RUTG */ PACK( 0, 0 ),
994 /* RDTG */ PACK( 0, 0 ),
995 /* SANGW */ PACK( 1, 0 ),
996 /* AA */ PACK( 1, 0 ),
998 /* FlipPT */ PACK( 0, 0 ),
999 /* FlipRgON */ PACK( 2, 0 ),
1000 /* FlipRgOFF */ PACK( 2, 0 ),
1001 /* INS_$83 */ PACK( 0, 0 ),
1002 /* INS_$84 */ PACK( 0, 0 ),
1003 /* ScanCTRL */ PACK( 1, 0 ),
1004 /* SDVPTL[0] */ PACK( 2, 0 ),
1005 /* SDVPTL[1] */ PACK( 2, 0 ),
1006 /* GetINFO */ PACK( 1, 1 ),
1007 /* IDEF */ PACK( 1, 0 ),
1008 /* ROLL */ PACK( 3, 3 ),
1009 /* MAX */ PACK( 2, 1 ),
1010 /* MIN */ PACK( 2, 1 ),
1011 /* ScanTYPE */ PACK( 1, 0 ),
1012 /* InstCTRL */ PACK( 2, 0 ),
1013 /* INS_$8F */ PACK( 0, 0 ),
1015 /* INS_$90 */ PACK( 0, 0 ),
1016 /* INS_$91 */ PACK( 0, 0 ),
1017 /* INS_$92 */ PACK( 0, 0 ),
1018 /* INS_$93 */ PACK( 0, 0 ),
1019 /* INS_$94 */ PACK( 0, 0 ),
1020 /* INS_$95 */ PACK( 0, 0 ),
1021 /* INS_$96 */ PACK( 0, 0 ),
1022 /* INS_$97 */ PACK( 0, 0 ),
1023 /* INS_$98 */ PACK( 0, 0 ),
1024 /* INS_$99 */ PACK( 0, 0 ),
1025 /* INS_$9A */ PACK( 0, 0 ),
1026 /* INS_$9B */ PACK( 0, 0 ),
1027 /* INS_$9C */ PACK( 0, 0 ),
1028 /* INS_$9D */ PACK( 0, 0 ),
1029 /* INS_$9E */ PACK( 0, 0 ),
1030 /* INS_$9F */ PACK( 0, 0 ),
1032 /* INS_$A0 */ PACK( 0, 0 ),
1033 /* INS_$A1 */ PACK( 0, 0 ),
1034 /* INS_$A2 */ PACK( 0, 0 ),
1035 /* INS_$A3 */ PACK( 0, 0 ),
1036 /* INS_$A4 */ PACK( 0, 0 ),
1037 /* INS_$A5 */ PACK( 0, 0 ),
1038 /* INS_$A6 */ PACK( 0, 0 ),
1039 /* INS_$A7 */ PACK( 0, 0 ),
1040 /* INS_$A8 */ PACK( 0, 0 ),
1041 /* INS_$A9 */ PACK( 0, 0 ),
1042 /* INS_$AA */ PACK( 0, 0 ),
1043 /* INS_$AB */ PACK( 0, 0 ),
1044 /* INS_$AC */ PACK( 0, 0 ),
1045 /* INS_$AD */ PACK( 0, 0 ),
1046 /* INS_$AE */ PACK( 0, 0 ),
1047 /* INS_$AF */ PACK( 0, 0 ),
1049 /* PushB[0] */ PACK( 0, 1 ),
1050 /* PushB[1] */ PACK( 0, 2 ),
1051 /* PushB[2] */ PACK( 0, 3 ),
1052 /* PushB[3] */ PACK( 0, 4 ),
1053 /* PushB[4] */ PACK( 0, 5 ),
1054 /* PushB[5] */ PACK( 0, 6 ),
1055 /* PushB[6] */ PACK( 0, 7 ),
1056 /* PushB[7] */ PACK( 0, 8 ),
1057 /* PushW[0] */ PACK( 0, 1 ),
1058 /* PushW[1] */ PACK( 0, 2 ),
1059 /* PushW[2] */ PACK( 0, 3 ),
1060 /* PushW[3] */ PACK( 0, 4 ),
1061 /* PushW[4] */ PACK( 0, 5 ),
1062 /* PushW[5] */ PACK( 0, 6 ),
1063 /* PushW[6] */ PACK( 0, 7 ),
1064 /* PushW[7] */ PACK( 0, 8 ),
1066 /* MDRP[00] */ PACK( 1, 0 ),
1067 /* MDRP[01] */ PACK( 1, 0 ),
1068 /* MDRP[02] */ PACK( 1, 0 ),
1069 /* MDRP[03] */ PACK( 1, 0 ),
1070 /* MDRP[04] */ PACK( 1, 0 ),
1071 /* MDRP[05] */ PACK( 1, 0 ),
1072 /* MDRP[06] */ PACK( 1, 0 ),
1073 /* MDRP[07] */ PACK( 1, 0 ),
1074 /* MDRP[08] */ PACK( 1, 0 ),
1075 /* MDRP[09] */ PACK( 1, 0 ),
1076 /* MDRP[10] */ PACK( 1, 0 ),
1077 /* MDRP[11] */ PACK( 1, 0 ),
1078 /* MDRP[12] */ PACK( 1, 0 ),
1079 /* MDRP[13] */ PACK( 1, 0 ),
1080 /* MDRP[14] */ PACK( 1, 0 ),
1081 /* MDRP[15] */ PACK( 1, 0 ),
1083 /* MDRP[16] */ PACK( 1, 0 ),
1084 /* MDRP[17] */ PACK( 1, 0 ),
1085 /* MDRP[18] */ PACK( 1, 0 ),
1086 /* MDRP[19] */ PACK( 1, 0 ),
1087 /* MDRP[20] */ PACK( 1, 0 ),
1088 /* MDRP[21] */ PACK( 1, 0 ),
1089 /* MDRP[22] */ PACK( 1, 0 ),
1090 /* MDRP[23] */ PACK( 1, 0 ),
1091 /* MDRP[24] */ PACK( 1, 0 ),
1092 /* MDRP[25] */ PACK( 1, 0 ),
1093 /* MDRP[26] */ PACK( 1, 0 ),
1094 /* MDRP[27] */ PACK( 1, 0 ),
1095 /* MDRP[28] */ PACK( 1, 0 ),
1096 /* MDRP[29] */ PACK( 1, 0 ),
1097 /* MDRP[30] */ PACK( 1, 0 ),
1098 /* MDRP[31] */ PACK( 1, 0 ),
1100 /* MIRP[00] */ PACK( 2, 0 ),
1101 /* MIRP[01] */ PACK( 2, 0 ),
1102 /* MIRP[02] */ PACK( 2, 0 ),
1103 /* MIRP[03] */ PACK( 2, 0 ),
1104 /* MIRP[04] */ PACK( 2, 0 ),
1105 /* MIRP[05] */ PACK( 2, 0 ),
1106 /* MIRP[06] */ PACK( 2, 0 ),
1107 /* MIRP[07] */ PACK( 2, 0 ),
1108 /* MIRP[08] */ PACK( 2, 0 ),
1109 /* MIRP[09] */ PACK( 2, 0 ),
1110 /* MIRP[10] */ PACK( 2, 0 ),
1111 /* MIRP[11] */ PACK( 2, 0 ),
1112 /* MIRP[12] */ PACK( 2, 0 ),
1113 /* MIRP[13] */ PACK( 2, 0 ),
1114 /* MIRP[14] */ PACK( 2, 0 ),
1115 /* MIRP[15] */ PACK( 2, 0 ),
1117 /* MIRP[16] */ PACK( 2, 0 ),
1118 /* MIRP[17] */ PACK( 2, 0 ),
1119 /* MIRP[18] */ PACK( 2, 0 ),
1120 /* MIRP[19] */ PACK( 2, 0 ),
1121 /* MIRP[20] */ PACK( 2, 0 ),
1122 /* MIRP[21] */ PACK( 2, 0 ),
1123 /* MIRP[22] */ PACK( 2, 0 ),
1124 /* MIRP[23] */ PACK( 2, 0 ),
1125 /* MIRP[24] */ PACK( 2, 0 ),
1126 /* MIRP[25] */ PACK( 2, 0 ),
1127 /* MIRP[26] */ PACK( 2, 0 ),
1128 /* MIRP[27] */ PACK( 2, 0 ),
1129 /* MIRP[28] */ PACK( 2, 0 ),
1130 /* MIRP[29] */ PACK( 2, 0 ),
1131 /* MIRP[30] */ PACK( 2, 0 ),
1132 /* MIRP[31] */ PACK( 2, 0 )
1137 const FT_Char opcode_length
[256] =
1139 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1140 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1141 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1142 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1144 -1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1145 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1146 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1147 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1149 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1150 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1151 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1152 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
1154 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1155 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1156 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1157 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1161 const FT_Vector Null_Vector
= {0,0};
1168 #define NULL_Vector (FT_Vector*)&Null_Vector
1171 /* compute (a*b)/2^14 with maximal accuracy and rounding */
1173 TT_MulFix14( FT_Int32 a
,
1180 /* compute ax*bx as 64-bit value */
1181 l
= (FT_UInt32
)( ( a
& 0xFFFFU
) * b
);
1182 m
= ( a
>> 16 ) * b
;
1184 lo
= l
+ (FT_UInt32
)( m
<< 16 );
1185 hi
= ( m
>> 16 ) + ( (FT_Int32
)l
>> 31 ) + ( lo
< l
);
1187 /* divide the result by 2^14 with rounding */
1189 l
= lo
+ (FT_UInt32
)s
;
1190 hi
+= s
+ ( l
< lo
);
1196 return ( hi
<< 18 ) | ( l
>> 14 );
1200 /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */
1202 TT_DotFix14( FT_Int32 ax
,
1207 FT_Int32 m
, s
, hi1
, hi2
, hi
;
1208 FT_UInt32 l
, lo1
, lo2
, lo
;
1211 /* compute ax*bx as 64-bit value */
1212 l
= (FT_UInt32
)( ( ax
& 0xFFFFU
) * bx
);
1213 m
= ( ax
>> 16 ) * bx
;
1215 lo1
= l
+ (FT_UInt32
)( m
<< 16 );
1216 hi1
= ( m
>> 16 ) + ( (FT_Int32
)l
>> 31 ) + ( lo1
< l
);
1218 /* compute ay*by as 64-bit value */
1219 l
= (FT_UInt32
)( ( ay
& 0xFFFFU
) * by
);
1220 m
= ( ay
>> 16 ) * by
;
1222 lo2
= l
+ (FT_UInt32
)( m
<< 16 );
1223 hi2
= ( m
>> 16 ) + ( (FT_Int32
)l
>> 31 ) + ( lo2
< l
);
1227 hi
= hi1
+ hi2
+ ( lo
< lo1
);
1229 /* divide the result by 2^14 with rounding */
1231 l
= lo
+ (FT_UInt32
)s
;
1232 hi
+= s
+ ( l
< lo
);
1238 return ( hi
<< 18 ) | ( l
>> 14 );
1242 /* return length of given vector */
1247 TT_VecLen( FT_Int32 x
,
1250 FT_Int32 m
, hi1
, hi2
, hi
;
1251 FT_UInt32 l
, lo1
, lo2
, lo
;
1254 /* compute x*x as 64-bit value */
1255 lo
= (FT_UInt32
)( x
& 0xFFFFU
);
1262 lo1
= l
+ (FT_UInt32
)( m
<< 17 );
1263 hi1
= hi
+ ( m
>> 15 ) + ( lo1
< l
);
1265 /* compute y*y as 64-bit value */
1266 lo
= (FT_UInt32
)( y
& 0xFFFFU
);
1273 lo2
= l
+ (FT_UInt32
)( m
<< 17 );
1274 hi2
= hi
+ ( m
>> 15 ) + ( lo2
< l
);
1276 /* add them to get 'x*x+y*y' as 64-bit value */
1278 hi
= hi1
+ hi2
+ ( lo
< lo1
);
1280 /* compute the square root of this value */
1282 FT_UInt32 root
, rem
, test_div
;
1293 rem
= ( rem
<< 2 ) | ( (FT_UInt32
)hi
>> 30 );
1294 hi
= ( hi
<< 2 ) | ( lo
>> 30 );
1297 test_div
= ( root
<< 1 ) + 1;
1299 if ( rem
>= test_div
)
1304 } while ( --count
);
1307 return (FT_Int32
)root
;
1313 /* this version uses FT_Vector_Length which computes the same value */
1314 /* much, much faster.. */
1317 TT_VecLen( FT_F26Dot6 X
,
1326 return FT_Vector_Length( &v
);
1332 /*************************************************************************/
1338 /* Returns the current aspect ratio scaling factor depending on the */
1339 /* projection vector's state and device resolutions. */
1342 /* The aspect ratio in 16.16 format, always <= 1.0 . */
1345 Current_Ratio( EXEC_OP
)
1347 if ( CUR
.tt_metrics
.ratio
)
1348 return CUR
.tt_metrics
.ratio
;
1350 if ( CUR
.GS
.projVector
.y
== 0 )
1351 CUR
.tt_metrics
.ratio
= CUR
.tt_metrics
.x_ratio
;
1353 else if ( CUR
.GS
.projVector
.x
== 0 )
1354 CUR
.tt_metrics
.ratio
= CUR
.tt_metrics
.y_ratio
;
1360 x
= TT_MULDIV( CUR
.GS
.projVector
.x
, CUR
.tt_metrics
.x_ratio
, 0x4000 );
1361 y
= TT_MULDIV( CUR
.GS
.projVector
.y
, CUR
.tt_metrics
.y_ratio
, 0x4000 );
1362 CUR
.tt_metrics
.ratio
= TT_VecLen( x
, y
);
1365 return CUR
.tt_metrics
.ratio
;
1370 Current_Ppem( EXEC_OP
)
1372 return TT_MULFIX( CUR
.tt_metrics
.ppem
, CURRENT_Ratio() );
1376 /*************************************************************************/
1378 /* Functions related to the control value table (CVT). */
1380 /*************************************************************************/
1383 FT_CALLBACK_DEF( FT_F26Dot6
)
1384 Read_CVT( EXEC_OP_ FT_ULong idx
)
1386 return CUR
.cvt
[idx
];
1390 FT_CALLBACK_DEF( FT_F26Dot6
)
1391 Read_CVT_Stretched( EXEC_OP_ FT_ULong idx
)
1393 return TT_MULFIX( CUR
.cvt
[idx
], CURRENT_Ratio() );
1397 FT_CALLBACK_DEF( void )
1398 Write_CVT( EXEC_OP_ FT_ULong idx
,
1401 CUR
.cvt
[idx
] = value
;
1405 FT_CALLBACK_DEF( void )
1406 Write_CVT_Stretched( EXEC_OP_ FT_ULong idx
,
1409 CUR
.cvt
[idx
] = FT_DivFix( value
, CURRENT_Ratio() );
1413 FT_CALLBACK_DEF( void )
1414 Move_CVT( EXEC_OP_ FT_ULong idx
,
1417 CUR
.cvt
[idx
] += value
;
1421 FT_CALLBACK_DEF( void )
1422 Move_CVT_Stretched( EXEC_OP_ FT_ULong idx
,
1425 CUR
.cvt
[idx
] += FT_DivFix( value
, CURRENT_Ratio() );
1429 /*************************************************************************/
1435 /* Returns a short integer taken from the instruction stream at */
1439 /* Short read at code[IP]. */
1442 /* This one could become a macro. */
1445 GetShortIns( EXEC_OP
)
1447 /* Reading a byte stream so there is no endianess (DaveP) */
1449 return (FT_Short
)( ( CUR
.code
[CUR
.IP
- 2] << 8 ) +
1450 CUR
.code
[CUR
.IP
- 1] );
1454 /*************************************************************************/
1457 /* Ins_Goto_CodeRange */
1460 /* Goes to a certain code range in the instruction stream. */
1463 /* aRange :: The index of the code range. */
1465 /* aIP :: The new IP address in the code range. */
1468 /* SUCCESS or FAILURE. */
1471 Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange
,
1474 TT_CodeRange
* range
;
1477 if ( aRange
< 1 || aRange
> 3 )
1479 CUR
.error
= TT_Err_Bad_Argument
;
1483 range
= &CUR
.codeRangeTable
[aRange
- 1];
1485 if ( range
->base
== NULL
) /* invalid coderange */
1487 CUR
.error
= TT_Err_Invalid_CodeRange
;
1491 /* NOTE: Because the last instruction of a program may be a CALL */
1492 /* which will return to the first byte *after* the code */
1493 /* range, we test for AIP <= Size, instead of AIP < Size. */
1495 if ( aIP
> range
->size
)
1497 CUR
.error
= TT_Err_Code_Overflow
;
1501 CUR
.code
= range
->base
;
1502 CUR
.codeSize
= range
->size
;
1504 CUR
.curRange
= aRange
;
1510 /*************************************************************************/
1516 /* Moves a point by a given distance along the freedom vector. The */
1517 /* point will be `touched'. */
1520 /* point :: The index of the point to move. */
1522 /* distance :: The distance to apply. */
1525 /* zone :: The affected glyph zone. */
1528 Direct_Move( EXEC_OP_ TT_GlyphZone zone
,
1530 FT_F26Dot6 distance
)
1535 v
= CUR
.GS
.freeVector
.x
;
1540 #ifdef NO_APPLE_PATENT
1542 if ( ABS( CUR
.F_dot_P
) > APPLE_THRESHOLD
)
1543 zone
->cur
[point
].x
+= distance
;
1547 zone
->cur
[point
].x
+= TT_MULDIV( distance
,
1553 zone
->tags
[point
] |= FT_Curve_Tag_Touch_X
;
1556 v
= CUR
.GS
.freeVector
.y
;
1561 #ifdef NO_APPLE_PATENT
1563 if ( ABS( CUR
.F_dot_P
) > APPLE_THRESHOLD
)
1564 zone
->cur
[point
].y
+= distance
;
1568 zone
->cur
[point
].y
+= TT_MULDIV( distance
,
1574 zone
->tags
[point
] |= FT_Curve_Tag_Touch_Y
;
1579 /*************************************************************************/
1581 /* Special versions of Direct_Move() */
1583 /* The following versions are used whenever both vectors are both */
1584 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1586 /*************************************************************************/
1590 Direct_Move_X( EXEC_OP_ TT_GlyphZone zone
,
1592 FT_F26Dot6 distance
)
1596 zone
->cur
[point
].x
+= distance
;
1597 zone
->tags
[point
] |= FT_Curve_Tag_Touch_X
;
1602 Direct_Move_Y( EXEC_OP_ TT_GlyphZone zone
,
1604 FT_F26Dot6 distance
)
1608 zone
->cur
[point
].y
+= distance
;
1609 zone
->tags
[point
] |= FT_Curve_Tag_Touch_Y
;
1613 /*************************************************************************/
1619 /* Does not round, but adds engine compensation. */
1622 /* distance :: The distance (not) to round. */
1624 /* compensation :: The engine compensation. */
1627 /* The compensated distance. */
1630 /* The TrueType specification says very few about the relationship */
1631 /* between rounding and engine compensation. However, it seems from */
1632 /* the description of super round that we should add the compensation */
1633 /* before rounding. */
1636 Round_None( EXEC_OP_ FT_F26Dot6 distance
,
1637 FT_F26Dot6 compensation
)
1644 if ( distance
>= 0 )
1646 val
= distance
+ compensation
;
1651 val
= distance
- compensation
;
1659 /*************************************************************************/
1665 /* Rounds value to grid after adding engine compensation. */
1668 /* distance :: The distance to round. */
1670 /* compensation :: The engine compensation. */
1673 /* Rounded distance. */
1676 Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1677 FT_F26Dot6 compensation
)
1684 if ( distance
>= 0 )
1686 val
= distance
+ compensation
+ 32;
1694 val
= -( ( compensation
- distance
+ 32 ) & -64 );
1703 /*************************************************************************/
1706 /* Round_To_Half_Grid */
1709 /* Rounds value to half grid after adding engine compensation. */
1712 /* distance :: The distance to round. */
1714 /* compensation :: The engine compensation. */
1717 /* Rounded distance. */
1720 Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1721 FT_F26Dot6 compensation
)
1728 if ( distance
>= 0 )
1730 val
= ( ( distance
+ compensation
) & -64 ) + 32;
1736 val
= -( ( (compensation
- distance
) & -64 ) + 32 );
1745 /*************************************************************************/
1748 /* Round_Down_To_Grid */
1751 /* Rounds value down to grid after adding engine compensation. */
1754 /* distance :: The distance to round. */
1756 /* compensation :: The engine compensation. */
1759 /* Rounded distance. */
1762 Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1763 FT_F26Dot6 compensation
)
1770 if ( distance
>= 0 )
1772 val
= distance
+ compensation
;
1780 val
= -( ( compensation
- distance
) & -64 );
1789 /*************************************************************************/
1792 /* Round_Up_To_Grid */
1795 /* Rounds value up to grid after adding engine compensation. */
1798 /* distance :: The distance to round. */
1800 /* compensation :: The engine compensation. */
1803 /* Rounded distance. */
1806 Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1807 FT_F26Dot6 compensation
)
1814 if ( distance
>= 0 )
1816 val
= distance
+ compensation
+ 63;
1824 val
= -( ( compensation
- distance
+ 63 ) & -64 );
1833 /*************************************************************************/
1836 /* Round_To_Double_Grid */
1839 /* Rounds value to double grid after adding engine compensation. */
1842 /* distance :: The distance to round. */
1844 /* compensation :: The engine compensation. */
1847 /* Rounded distance. */
1850 Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance
,
1851 FT_F26Dot6 compensation
)
1858 if ( distance
>= 0 )
1860 val
= distance
+ compensation
+ 16;
1868 val
= -( ( compensation
- distance
+ 16 ) & -32 );
1877 /*************************************************************************/
1883 /* Super-rounds value to grid after adding engine compensation. */
1886 /* distance :: The distance to round. */
1888 /* compensation :: The engine compensation. */
1891 /* Rounded distance. */
1894 /* The TrueType specification says very few about the relationship */
1895 /* between rounding and engine compensation. However, it seems from */
1896 /* the description of super round that we should add the compensation */
1897 /* before rounding. */
1900 Round_Super( EXEC_OP_ FT_F26Dot6 distance
,
1901 FT_F26Dot6 compensation
)
1906 if ( distance
>= 0 )
1908 val
= ( distance
- CUR
.phase
+ CUR
.threshold
+ compensation
) &
1916 val
= -( ( CUR
.threshold
- CUR
.phase
- distance
+ compensation
) &
1927 /*************************************************************************/
1930 /* Round_Super_45 */
1933 /* Super-rounds value to grid after adding engine compensation. */
1936 /* distance :: The distance to round. */
1938 /* compensation :: The engine compensation. */
1941 /* Rounded distance. */
1944 /* There is a separate function for Round_Super_45() as we may need */
1945 /* greater precision. */
1948 Round_Super_45( EXEC_OP_ FT_F26Dot6 distance
,
1949 FT_F26Dot6 compensation
)
1954 if ( distance
>= 0 )
1956 val
= ( ( distance
- CUR
.phase
+ CUR
.threshold
+ compensation
) /
1957 CUR
.period
) * CUR
.period
;
1964 val
= -( ( ( CUR
.threshold
- CUR
.phase
- distance
+ compensation
) /
1965 CUR
.period
) * CUR
.period
);
1975 /*************************************************************************/
1981 /* Sets the rounding mode. */
1984 /* round_mode :: The rounding mode to be used. */
1987 Compute_Round( EXEC_OP_ FT_Byte round_mode
)
1989 switch ( round_mode
)
1992 CUR
.func_round
= (TT_Round_Func
)Round_None
;
1995 case TT_Round_To_Grid
:
1996 CUR
.func_round
= (TT_Round_Func
)Round_To_Grid
;
1999 case TT_Round_Up_To_Grid
:
2000 CUR
.func_round
= (TT_Round_Func
)Round_Up_To_Grid
;
2003 case TT_Round_Down_To_Grid
:
2004 CUR
.func_round
= (TT_Round_Func
)Round_Down_To_Grid
;
2007 case TT_Round_To_Half_Grid
:
2008 CUR
.func_round
= (TT_Round_Func
)Round_To_Half_Grid
;
2011 case TT_Round_To_Double_Grid
:
2012 CUR
.func_round
= (TT_Round_Func
)Round_To_Double_Grid
;
2015 case TT_Round_Super
:
2016 CUR
.func_round
= (TT_Round_Func
)Round_Super
;
2019 case TT_Round_Super_45
:
2020 CUR
.func_round
= (TT_Round_Func
)Round_Super_45
;
2026 /*************************************************************************/
2032 /* Sets Super Round parameters. */
2035 /* GridPeriod :: Grid period */
2036 /* selector :: SROUND opcode */
2039 SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod
,
2042 switch ( (FT_Int
)( selector
& 0xC0 ) )
2045 CUR
.period
= GridPeriod
/ 2;
2049 CUR
.period
= GridPeriod
;
2053 CUR
.period
= GridPeriod
* 2;
2056 /* This opcode is reserved, but... */
2059 CUR
.period
= GridPeriod
;
2063 switch ( (FT_Int
)( selector
& 0x30 ) )
2070 CUR
.phase
= CUR
.period
/ 4;
2074 CUR
.phase
= CUR
.period
/ 2;
2078 CUR
.phase
= GridPeriod
* 3 / 4;
2082 if ( (selector
& 0x0F) == 0 )
2083 CUR
.threshold
= CUR
.period
- 1;
2085 CUR
.threshold
= ( (FT_Int
)( selector
& 0x0F ) - 4 ) * CUR
.period
/ 8;
2089 CUR
.threshold
/= 256;
2093 /*************************************************************************/
2099 /* Computes the projection of vector given by (v2-v1) along the */
2100 /* current projection vector. */
2103 /* v1 :: First input vector. */
2104 /* v2 :: Second input vector. */
2107 /* The distance in F26dot6 format. */
2110 Project( EXEC_OP_ FT_Vector
* v1
,
2113 return TT_DotFix14( v1
->x
- v2
->x
,
2115 CUR
.GS
.projVector
.x
,
2116 CUR
.GS
.projVector
.y
);
2120 /*************************************************************************/
2126 /* Computes the projection of the vector given by (v2-v1) along the */
2127 /* current dual vector. */
2130 /* v1 :: First input vector. */
2131 /* v2 :: Second input vector. */
2134 /* The distance in F26dot6 format. */
2137 Dual_Project( EXEC_OP_ FT_Vector
* v1
,
2140 return TT_DotFix14( v1
->x
- v2
->x
,
2142 CUR
.GS
.dualVector
.x
,
2143 CUR
.GS
.dualVector
.y
);
2147 /*************************************************************************/
2153 /* Computes the projection of the vector given by (v2-v1) along the */
2154 /* current freedom vector. */
2157 /* v1 :: First input vector. */
2158 /* v2 :: Second input vector. */
2161 /* The distance in F26dot6 format. */
2164 Free_Project( EXEC_OP_ FT_Vector
* v1
,
2167 return TT_DotFix14( v1
->x
- v2
->x
,
2169 CUR
.GS
.freeVector
.x
,
2170 CUR
.GS
.freeVector
.y
);
2174 /*************************************************************************/
2180 /* Computes the projection of the vector given by (v2-v1) along the */
2181 /* horizontal axis. */
2184 /* v1 :: First input vector. */
2185 /* v2 :: Second input vector. */
2188 /* The distance in F26dot6 format. */
2191 Project_x( EXEC_OP_ FT_Vector
* v1
,
2196 return ( v1
->x
- v2
->x
);
2200 /*************************************************************************/
2206 /* Computes the projection of the vector given by (v2-v1) along the */
2207 /* vertical axis. */
2210 /* v1 :: First input vector. */
2211 /* v2 :: Second input vector. */
2214 /* The distance in F26dot6 format. */
2217 Project_y( EXEC_OP_ FT_Vector
* v1
,
2222 return ( v1
->y
- v2
->y
);
2226 /*************************************************************************/
2232 /* Computes the projection and movement function pointers according */
2233 /* to the current graphics state. */
2236 Compute_Funcs( EXEC_OP
)
2238 if ( CUR
.GS
.freeVector
.x
== 0x4000 )
2240 CUR
.func_freeProj
= (TT_Project_Func
)Project_x
;
2241 CUR
.F_dot_P
= CUR
.GS
.projVector
.x
* 0x10000L
;
2245 if ( CUR
.GS
.freeVector
.y
== 0x4000 )
2247 CUR
.func_freeProj
= (TT_Project_Func
)Project_y
;
2248 CUR
.F_dot_P
= CUR
.GS
.projVector
.y
* 0x10000L
;
2252 CUR
.func_freeProj
= (TT_Project_Func
)Free_Project
;
2253 CUR
.F_dot_P
= (FT_Long
)CUR
.GS
.projVector
.x
* CUR
.GS
.freeVector
.x
* 4 +
2254 (FT_Long
)CUR
.GS
.projVector
.y
* CUR
.GS
.freeVector
.y
* 4;
2258 if ( CUR
.GS
.projVector
.x
== 0x4000 )
2259 CUR
.func_project
= (TT_Project_Func
)Project_x
;
2262 if ( CUR
.GS
.projVector
.y
== 0x4000 )
2263 CUR
.func_project
= (TT_Project_Func
)Project_y
;
2265 CUR
.func_project
= (TT_Project_Func
)Project
;
2268 if ( CUR
.GS
.dualVector
.x
== 0x4000 )
2269 CUR
.func_dualproj
= (TT_Project_Func
)Project_x
;
2272 if ( CUR
.GS
.dualVector
.y
== 0x4000 )
2273 CUR
.func_dualproj
= (TT_Project_Func
)Project_y
;
2275 CUR
.func_dualproj
= (TT_Project_Func
)Dual_Project
;
2278 CUR
.func_move
= (TT_Move_Func
)Direct_Move
;
2280 if ( CUR
.F_dot_P
== 0x40000000L
)
2282 if ( CUR
.GS
.freeVector
.x
== 0x4000 )
2283 CUR
.func_move
= (TT_Move_Func
)Direct_Move_X
;
2286 if ( CUR
.GS
.freeVector
.y
== 0x4000 )
2287 CUR
.func_move
= (TT_Move_Func
)Direct_Move_Y
;
2291 /* at small sizes, F_dot_P can become too small, resulting */
2292 /* in overflows and `spikes' in a number of glyphs like `w'. */
2294 if ( ABS( CUR
.F_dot_P
) < 0x4000000L
)
2295 CUR
.F_dot_P
= 0x40000000L
;
2297 /* Disable cached aspect ratio */
2298 CUR
.tt_metrics
.ratio
= 0;
2302 /*************************************************************************/
2308 /* Norms a vector. */
2311 /* Vx :: The horizontal input vector coordinate. */
2312 /* Vy :: The vertical input vector coordinate. */
2315 /* R :: The normed unit vector. */
2318 /* Returns FAILURE if a vector parameter is zero. */
2321 /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
2322 /* R is undefined. */
2327 Normalize( EXEC_OP_ FT_F26Dot6 Vx
,
2337 if ( ABS( Vx
) < 0x10000L
&& ABS( Vy
) < 0x10000L
)
2342 W
= TT_VecLen( Vx
, Vy
);
2346 /* XXX: UNDOCUMENTED! It seems that it is possible to try */
2347 /* to normalize the vector (0,0). Return immediately. */
2351 R
->x
= (FT_F2Dot14
)FT_MulDiv( Vx
, 0x4000L
, W
);
2352 R
->y
= (FT_F2Dot14
)FT_MulDiv( Vy
, 0x4000L
, W
);
2357 W
= TT_VecLen( Vx
, Vy
);
2359 Vx
= FT_MulDiv( Vx
, 0x4000L
, W
);
2360 Vy
= FT_MulDiv( Vy
, 0x4000L
, W
);
2362 W
= Vx
* Vx
+ Vy
* Vy
;
2364 /* Now, we want that Sqrt( W ) = 0x4000 */
2365 /* Or 0x1000000 <= W < 0x1004000 */
2383 while ( W
< 0x1000000L
)
2385 /* We need to increase W by a minimal amount */
2391 W
= Vx
* Vx
+ Vy
* Vy
;
2394 while ( W
>= 0x1004000L
)
2396 /* We need to decrease W by a minimal amount */
2402 W
= Vx
* Vx
+ Vy
* Vy
;
2405 /* Note that in various cases, we can only */
2406 /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
2414 R
->x
= (FT_F2Dot14
)Vx
; /* Type conversion */
2415 R
->y
= (FT_F2Dot14
)Vy
; /* Type conversion */
2421 /*************************************************************************/
2423 /* Here we start with the implementation of the various opcodes. */
2425 /*************************************************************************/
2429 Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1
,
2432 FT_UnitVector
* Vec
)
2439 if ( BOUNDS( aIdx1
, CUR
.zp2
.n_points
) ||
2440 BOUNDS( aIdx2
, CUR
.zp1
.n_points
) )
2442 if ( CUR
.pedantic_hinting
)
2443 CUR
.error
= TT_Err_Invalid_Reference
;
2447 p1
= CUR
.zp1
.cur
+ aIdx2
;
2448 p2
= CUR
.zp2
.cur
+ aIdx1
;
2453 if ( ( aOpc
& 1 ) != 0 )
2455 C
= B
; /* counter clockwise rotation */
2460 NORMalize( A
, B
, Vec
);
2466 /* When not using the big switch statements, the interpreter uses a */
2467 /* call table defined later below in this source. Each opcode must */
2468 /* thus have a corresponding function, even trivial ones. */
2470 /* They are all defined there. */
2477 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2478 B = A ^ (FT_Short)0x4000; \
2480 CUR.GS.freeVector.x = A; \
2481 CUR.GS.projVector.x = A; \
2482 CUR.GS.dualVector.x = A; \
2484 CUR.GS.freeVector.y = B; \
2485 CUR.GS.projVector.y = B; \
2486 CUR.GS.dualVector.y = B; \
2497 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2498 B = A ^ (FT_Short)0x4000; \
2500 CUR.GS.projVector.x = A; \
2501 CUR.GS.dualVector.x = A; \
2503 CUR.GS.projVector.y = B; \
2504 CUR.GS.dualVector.y = B; \
2515 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2516 B = A ^ (FT_Short)0x4000; \
2518 CUR.GS.freeVector.x = A; \
2519 CUR.GS.freeVector.y = B; \
2526 if ( INS_SxVTL( (FT_UShort)args[1], \
2527 (FT_UShort)args[0], \
2529 &CUR.GS.projVector ) == SUCCESS ) \
2531 CUR.GS.dualVector = CUR.GS.projVector; \
2537 if ( INS_SxVTL( (FT_UShort)args[1], \
2538 (FT_UShort)args[0], \
2540 &CUR.GS.freeVector ) == SUCCESS ) \
2545 CUR.GS.freeVector = CUR.GS.projVector; \
2555 /* Only use low 16bits, then sign extend */ \
2556 S = (FT_Short)args[1]; \
2558 S = (FT_Short)args[0]; \
2561 NORMalize( X, Y, &CUR.GS.projVector ); \
2563 CUR.GS.dualVector = CUR.GS.projVector; \
2574 /* Only use low 16bits, then sign extend */ \
2575 S = (FT_Short)args[1]; \
2577 S = (FT_Short)args[0]; \
2580 NORMalize( X, Y, &CUR.GS.freeVector ); \
2586 args[0] = CUR.GS.projVector.x; \
2587 args[1] = CUR.GS.projVector.y;
2591 args[0] = CUR.GS.freeVector.x; \
2592 args[1] = CUR.GS.freeVector.y;
2596 CUR.GS.rp0 = (FT_UShort)args[0];
2600 CUR.GS.rp1 = (FT_UShort)args[0];
2604 CUR.GS.rp2 = (FT_UShort)args[0];
2608 CUR.GS.round_state = TT_Round_To_Half_Grid; \
2609 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2613 CUR.GS.round_state = TT_Round_To_Grid; \
2614 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2618 CUR.GS.round_state = TT_Round_To_Double_Grid; \
2619 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2623 CUR.GS.round_state = TT_Round_Up_To_Grid; \
2624 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2628 CUR.GS.round_state = TT_Round_Down_To_Grid; \
2629 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2633 CUR.GS.round_state = TT_Round_Off; \
2634 CUR.func_round = (TT_Round_Func)Round_None;
2638 SET_SuperRound( 0x4000, args[0] ); \
2639 CUR.GS.round_state = TT_Round_Super; \
2640 CUR.func_round = (TT_Round_Func)Round_Super;
2643 #define DO_S45ROUND \
2644 SET_SuperRound( 0x2D41, args[0] ); \
2645 CUR.GS.round_state = TT_Round_Super_45; \
2646 CUR.func_round = (TT_Round_Func)Round_Super_45;
2650 if ( args[0] < 0 ) \
2651 CUR.error = TT_Err_Bad_Argument; \
2653 CUR.GS.loop = args[0];
2657 CUR.GS.minimum_distance = args[0];
2661 CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
2665 CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
2668 /* XXX: UNDOCUMENTED! or bug in the Windows engine? */
2670 /* It seems that the value that is read here is */
2671 /* expressed in 16.16 format rather than in font */
2675 CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
2679 CUR.GS.auto_flip = TRUE;
2682 #define DO_FLIPOFF \
2683 CUR.GS.auto_flip = FALSE;
2687 CUR.GS.delta_base = (FT_Short)args[0];
2691 CUR.GS.delta_shift = (FT_Short)args[0];
2694 #define DO_MD /* nothing */
2698 args[0] = CURRENT_Ppem();
2701 /* Note: The pointSize should be irrelevant in a given font program; */
2702 /* we thus decide to return only the ppem. */
2706 args[0] = CUR.metrics.pointSize;
2711 args[0] = CURRENT_Ppem();
2730 args[0] = args[1]; \
2746 if ( L <= 0 || L > CUR.args ) \
2747 CUR.error = TT_Err_Invalid_Reference; \
2749 args[0] = CUR.stack[CUR.args - L]; \
2754 if ( args[1] != 0 ) \
2756 CUR.IP += args[0]; \
2757 CUR.step_ins = FALSE; \
2762 CUR.IP += args[0]; \
2763 CUR.step_ins = FALSE;
2767 if ( args[1] == 0 ) \
2769 CUR.IP += args[0]; \
2770 CUR.step_ins = FALSE; \
2775 args[0] = ( args[0] < args[1] );
2779 args[0] = ( args[0] <= args[1] );
2783 args[0] = ( args[0] > args[1] );
2787 args[0] = ( args[0] >= args[1] );
2791 args[0] = ( args[0] == args[1] );
2795 args[0] = ( args[0] != args[1] );
2799 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
2803 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
2807 args[0] = ( args[0] && args[1] );
2811 args[0] = ( args[0] || args[1] );
2827 if ( args[1] == 0 ) \
2828 CUR.error = TT_Err_Divide_By_Zero; \
2830 args[0] = TT_MULDIV( args[0], 64L, args[1] );
2834 args[0] = TT_MULDIV( args[0], args[1], 64L );
2838 args[0] = ABS( args[0] );
2849 #define DO_CEILING \
2850 args[0] = ( args[0] + 63 ) & -64;
2855 FT_ULong I = (FT_ULong)args[0]; \
2858 if ( BOUNDS( I, CUR.storeSize ) ) \
2860 if ( CUR.pedantic_hinting ) \
2862 ARRAY_BOUND_ERROR; \
2868 args[0] = CUR.storage[I]; \
2874 FT_ULong I = (FT_ULong)args[0]; \
2877 if ( BOUNDS( I, CUR.storeSize ) ) \
2879 if ( CUR.pedantic_hinting ) \
2881 ARRAY_BOUND_ERROR; \
2885 CUR.storage[I] = args[1]; \
2891 FT_ULong I = (FT_ULong)args[0]; \
2894 if ( BOUNDS( I, CUR.cvtSize ) ) \
2896 if ( CUR.pedantic_hinting ) \
2898 ARRAY_BOUND_ERROR; \
2904 args[0] = CUR_Func_read_cvt( I ); \
2910 FT_ULong I = (FT_ULong)args[0]; \
2913 if ( BOUNDS( I, CUR.cvtSize ) ) \
2915 if ( CUR.pedantic_hinting ) \
2917 ARRAY_BOUND_ERROR; \
2921 CUR_Func_write_cvt( I, args[1] ); \
2927 FT_ULong I = (FT_ULong)args[0]; \
2930 if ( BOUNDS( I, CUR.cvtSize ) ) \
2932 if ( CUR.pedantic_hinting ) \
2934 ARRAY_BOUND_ERROR; \
2938 CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
2943 CUR.error = TT_Err_Debug_OpCode;
2947 args[0] = CUR_Func_round( \
2949 CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
2953 args[0] = ROUND_None( args[0], \
2954 CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
2958 if ( args[1] > args[0] ) \
2963 if ( args[1] < args[0] ) \
2967 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
2970 #undef ARRAY_BOUND_ERROR
2971 #define ARRAY_BOUND_ERROR \
2973 CUR.error = TT_Err_Invalid_Reference; \
2978 /*************************************************************************/
2980 /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
2981 /* Opcode range: 0x00-0x01 */
2985 Ins_SVTCA( INS_ARG
)
2991 /*************************************************************************/
2993 /* SPVTCA[a]: Set PVector to Coordinate Axis */
2994 /* Opcode range: 0x02-0x03 */
2998 Ins_SPVTCA( INS_ARG
)
3004 /*************************************************************************/
3006 /* SFVTCA[a]: Set FVector to Coordinate Axis */
3007 /* Opcode range: 0x04-0x05 */
3011 Ins_SFVTCA( INS_ARG
)
3017 /*************************************************************************/
3019 /* SPVTL[a]: Set PVector To Line */
3020 /* Opcode range: 0x06-0x07 */
3021 /* Stack: uint32 uint32 --> */
3024 Ins_SPVTL( INS_ARG
)
3030 /*************************************************************************/
3032 /* SFVTL[a]: Set FVector To Line */
3033 /* Opcode range: 0x08-0x09 */
3034 /* Stack: uint32 uint32 --> */
3037 Ins_SFVTL( INS_ARG
)
3043 /*************************************************************************/
3045 /* SFVTPV[]: Set FVector To PVector */
3046 /* Opcode range: 0x0E */
3050 Ins_SFVTPV( INS_ARG
)
3056 /*************************************************************************/
3058 /* SPVFS[]: Set PVector From Stack */
3059 /* Opcode range: 0x0A */
3060 /* Stack: f2.14 f2.14 --> */
3063 Ins_SPVFS( INS_ARG
)
3069 /*************************************************************************/
3071 /* SFVFS[]: Set FVector From Stack */
3072 /* Opcode range: 0x0B */
3073 /* Stack: f2.14 f2.14 --> */
3076 Ins_SFVFS( INS_ARG
)
3082 /*************************************************************************/
3084 /* GPV[]: Get Projection Vector */
3085 /* Opcode range: 0x0C */
3086 /* Stack: ef2.14 --> ef2.14 */
3095 /*************************************************************************/
3096 /* GFV[]: Get Freedom Vector */
3097 /* Opcode range: 0x0D */
3098 /* Stack: ef2.14 --> ef2.14 */
3107 /*************************************************************************/
3109 /* SRP0[]: Set Reference Point 0 */
3110 /* Opcode range: 0x10 */
3111 /* Stack: uint32 --> */
3120 /*************************************************************************/
3122 /* SRP1[]: Set Reference Point 1 */
3123 /* Opcode range: 0x11 */
3124 /* Stack: uint32 --> */
3133 /*************************************************************************/
3135 /* SRP2[]: Set Reference Point 2 */
3136 /* Opcode range: 0x12 */
3137 /* Stack: uint32 --> */
3146 /*************************************************************************/
3148 /* RTHG[]: Round To Half Grid */
3149 /* Opcode range: 0x19 */
3159 /*************************************************************************/
3161 /* RTG[]: Round To Grid */
3162 /* Opcode range: 0x18 */
3172 /*************************************************************************/
3173 /* RTDG[]: Round To Double Grid */
3174 /* Opcode range: 0x3D */
3184 /*************************************************************************/
3185 /* RUTG[]: Round Up To Grid */
3186 /* Opcode range: 0x7C */
3196 /*************************************************************************/
3198 /* RDTG[]: Round Down To Grid */
3199 /* Opcode range: 0x7D */
3209 /*************************************************************************/
3211 /* ROFF[]: Round OFF */
3212 /* Opcode range: 0x7A */
3222 /*************************************************************************/
3224 /* SROUND[]: Super ROUND */
3225 /* Opcode range: 0x76 */
3226 /* Stack: Eint8 --> */
3229 Ins_SROUND( INS_ARG
)
3235 /*************************************************************************/
3237 /* S45ROUND[]: Super ROUND 45 degrees */
3238 /* Opcode range: 0x77 */
3239 /* Stack: uint32 --> */
3242 Ins_S45ROUND( INS_ARG
)
3248 /*************************************************************************/
3250 /* SLOOP[]: Set LOOP variable */
3251 /* Opcode range: 0x17 */
3252 /* Stack: int32? --> */
3255 Ins_SLOOP( INS_ARG
)
3261 /*************************************************************************/
3263 /* SMD[]: Set Minimum Distance */
3264 /* Opcode range: 0x1A */
3265 /* Stack: f26.6 --> */
3274 /*************************************************************************/
3276 /* SCVTCI[]: Set Control Value Table Cut In */
3277 /* Opcode range: 0x1D */
3278 /* Stack: f26.6 --> */
3281 Ins_SCVTCI( INS_ARG
)
3287 /*************************************************************************/
3289 /* SSWCI[]: Set Single Width Cut In */
3290 /* Opcode range: 0x1E */
3291 /* Stack: f26.6 --> */
3294 Ins_SSWCI( INS_ARG
)
3300 /*************************************************************************/
3302 /* SSW[]: Set Single Width */
3303 /* Opcode range: 0x1F */
3304 /* Stack: int32? --> */
3313 /*************************************************************************/
3315 /* FLIPON[]: Set auto-FLIP to ON */
3316 /* Opcode range: 0x4D */
3320 Ins_FLIPON( INS_ARG
)
3326 /*************************************************************************/
3328 /* FLIPOFF[]: Set auto-FLIP to OFF */
3329 /* Opcode range: 0x4E */
3333 Ins_FLIPOFF( INS_ARG
)
3339 /*************************************************************************/
3341 /* SANGW[]: Set ANGle Weight */
3342 /* Opcode range: 0x7E */
3343 /* Stack: uint32 --> */
3346 Ins_SANGW( INS_ARG
)
3348 /* instruction not supported anymore */
3352 /*************************************************************************/
3354 /* SDB[]: Set Delta Base */
3355 /* Opcode range: 0x5E */
3356 /* Stack: uint32 --> */
3365 /*************************************************************************/
3367 /* SDS[]: Set Delta Shift */
3368 /* Opcode range: 0x5F */
3369 /* Stack: uint32 --> */
3378 /*************************************************************************/
3380 /* MPPEM[]: Measure Pixel Per EM */
3381 /* Opcode range: 0x4B */
3382 /* Stack: --> Euint16 */
3385 Ins_MPPEM( INS_ARG
)
3391 /*************************************************************************/
3393 /* MPS[]: Measure Point Size */
3394 /* Opcode range: 0x4C */
3395 /* Stack: --> Euint16 */
3404 /*************************************************************************/
3406 /* DUP[]: DUPlicate the top stack's element */
3407 /* Opcode range: 0x20 */
3408 /* Stack: StkElt --> StkElt StkElt */
3417 /*************************************************************************/
3419 /* POP[]: POP the stack's top element */
3420 /* Opcode range: 0x21 */
3421 /* Stack: StkElt --> */
3430 /*************************************************************************/
3432 /* CLEAR[]: CLEAR the entire stack */
3433 /* Opcode range: 0x22 */
3434 /* Stack: StkElt... --> */
3437 Ins_CLEAR( INS_ARG
)
3443 /*************************************************************************/
3445 /* SWAP[]: SWAP the stack's top two elements */
3446 /* Opcode range: 0x23 */
3447 /* Stack: 2 * StkElt --> 2 * StkElt */
3456 /*************************************************************************/
3458 /* DEPTH[]: return the stack DEPTH */
3459 /* Opcode range: 0x24 */
3460 /* Stack: --> uint32 */
3463 Ins_DEPTH( INS_ARG
)
3469 /*************************************************************************/
3471 /* CINDEX[]: Copy INDEXed element */
3472 /* Opcode range: 0x25 */
3473 /* Stack: int32 --> StkElt */
3476 Ins_CINDEX( INS_ARG
)
3482 /*************************************************************************/
3485 /* Opcode range: 0x59 */
3495 /*************************************************************************/
3497 /* JROT[]: Jump Relative On True */
3498 /* Opcode range: 0x78 */
3499 /* Stack: StkElt int32 --> */
3508 /*************************************************************************/
3510 /* JMPR[]: JuMP Relative */
3511 /* Opcode range: 0x1C */
3512 /* Stack: int32 --> */
3521 /*************************************************************************/
3523 /* JROF[]: Jump Relative On False */
3524 /* Opcode range: 0x79 */
3525 /* Stack: StkElt int32 --> */
3534 /*************************************************************************/
3536 /* LT[]: Less Than */
3537 /* Opcode range: 0x50 */
3538 /* Stack: int32? int32? --> bool */
3547 /*************************************************************************/
3549 /* LTEQ[]: Less Than or EQual */
3550 /* Opcode range: 0x51 */
3551 /* Stack: int32? int32? --> bool */
3560 /*************************************************************************/
3562 /* GT[]: Greater Than */
3563 /* Opcode range: 0x52 */
3564 /* Stack: int32? int32? --> bool */
3573 /*************************************************************************/
3575 /* GTEQ[]: Greater Than or EQual */
3576 /* Opcode range: 0x53 */
3577 /* Stack: int32? int32? --> bool */
3586 /*************************************************************************/
3589 /* Opcode range: 0x54 */
3590 /* Stack: StkElt StkElt --> bool */
3599 /*************************************************************************/
3601 /* NEQ[]: Not EQual */
3602 /* Opcode range: 0x55 */
3603 /* Stack: StkElt StkElt --> bool */
3612 /*************************************************************************/
3615 /* Opcode range: 0x56 */
3616 /* Stack: f26.6 --> bool */
3625 /*************************************************************************/
3627 /* EVEN[]: Is EVEN */
3628 /* Opcode range: 0x57 */
3629 /* Stack: f26.6 --> bool */
3638 /*************************************************************************/
3640 /* AND[]: logical AND */
3641 /* Opcode range: 0x5A */
3642 /* Stack: uint32 uint32 --> uint32 */
3651 /*************************************************************************/
3653 /* OR[]: logical OR */
3654 /* Opcode range: 0x5B */
3655 /* Stack: uint32 uint32 --> uint32 */
3664 /*************************************************************************/
3666 /* NOT[]: logical NOT */
3667 /* Opcode range: 0x5C */
3668 /* Stack: StkElt --> uint32 */
3677 /*************************************************************************/
3680 /* Opcode range: 0x60 */
3681 /* Stack: f26.6 f26.6 --> f26.6 */
3690 /*************************************************************************/
3692 /* SUB[]: SUBtract */
3693 /* Opcode range: 0x61 */
3694 /* Stack: f26.6 f26.6 --> f26.6 */
3703 /*************************************************************************/
3706 /* Opcode range: 0x62 */
3707 /* Stack: f26.6 f26.6 --> f26.6 */
3716 /*************************************************************************/
3718 /* MUL[]: MULtiply */
3719 /* Opcode range: 0x63 */
3720 /* Stack: f26.6 f26.6 --> f26.6 */
3729 /*************************************************************************/
3731 /* ABS[]: ABSolute value */
3732 /* Opcode range: 0x64 */
3733 /* Stack: f26.6 --> f26.6 */
3742 /*************************************************************************/
3745 /* Opcode range: 0x65 */
3746 /* Stack: f26.6 --> f26.6 */
3755 /*************************************************************************/
3757 /* FLOOR[]: FLOOR */
3758 /* Opcode range: 0x66 */
3759 /* Stack: f26.6 --> f26.6 */
3762 Ins_FLOOR( INS_ARG
)
3768 /*************************************************************************/
3770 /* CEILING[]: CEILING */
3771 /* Opcode range: 0x67 */
3772 /* Stack: f26.6 --> f26.6 */
3775 Ins_CEILING( INS_ARG
)
3781 /*************************************************************************/
3783 /* RS[]: Read Store */
3784 /* Opcode range: 0x43 */
3785 /* Stack: uint32 --> uint32 */
3794 /*************************************************************************/
3796 /* WS[]: Write Store */
3797 /* Opcode range: 0x42 */
3798 /* Stack: uint32 uint32 --> */
3807 /*************************************************************************/
3809 /* WCVTP[]: Write CVT in Pixel units */
3810 /* Opcode range: 0x44 */
3811 /* Stack: f26.6 uint32 --> */
3814 Ins_WCVTP( INS_ARG
)
3820 /*************************************************************************/
3822 /* WCVTF[]: Write CVT in Funits */
3823 /* Opcode range: 0x70 */
3824 /* Stack: uint32 uint32 --> */
3827 Ins_WCVTF( INS_ARG
)
3833 /*************************************************************************/
3835 /* RCVT[]: Read CVT */
3836 /* Opcode range: 0x45 */
3837 /* Stack: uint32 --> f26.6 */
3846 /*************************************************************************/
3848 /* AA[]: Adjust Angle */
3849 /* Opcode range: 0x7F */
3850 /* Stack: uint32 --> */
3855 /* intentionally no longer supported */
3859 /*************************************************************************/
3861 /* DEBUG[]: DEBUG. Unsupported. */
3862 /* Opcode range: 0x4F */
3863 /* Stack: uint32 --> */
3865 /* Note: The original instruction pops a value from the stack. */
3868 Ins_DEBUG( INS_ARG
)
3874 /*************************************************************************/
3876 /* ROUND[ab]: ROUND value */
3877 /* Opcode range: 0x68-0x6B */
3878 /* Stack: f26.6 --> f26.6 */
3881 Ins_ROUND( INS_ARG
)
3887 /*************************************************************************/
3889 /* NROUND[ab]: No ROUNDing of value */
3890 /* Opcode range: 0x6C-0x6F */
3891 /* Stack: f26.6 --> f26.6 */
3894 Ins_NROUND( INS_ARG
)
3900 /*************************************************************************/
3902 /* MAX[]: MAXimum */
3903 /* Opcode range: 0x68 */
3904 /* Stack: int32? int32? --> int32 */
3913 /*************************************************************************/
3915 /* MIN[]: MINimum */
3916 /* Opcode range: 0x69 */
3917 /* Stack: int32? int32? --> int32 */
3926 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
3929 /*************************************************************************/
3931 /* The following functions are called as is within the switch statement. */
3933 /*************************************************************************/
3936 /*************************************************************************/
3938 /* MINDEX[]: Move INDEXed element */
3939 /* Opcode range: 0x26 */
3940 /* Stack: int32? --> StkElt */
3943 Ins_MINDEX( INS_ARG
)
3950 if ( L
<= 0 || L
> CUR
.args
)
3952 CUR
.error
= TT_Err_Invalid_Reference
;
3956 K
= CUR
.stack
[CUR
.args
- L
];
3958 FT_MEM_MOVE( &CUR
.stack
[CUR
.args
- L
],
3959 &CUR
.stack
[CUR
.args
- L
+ 1],
3960 ( L
- 1 ) * sizeof ( FT_Long
) );
3962 CUR
.stack
[CUR
.args
- 1] = K
;
3966 /*************************************************************************/
3968 /* ROLL[]: ROLL top three elements */
3969 /* Opcode range: 0x8A */
3970 /* Stack: 3 * StkElt --> 3 * StkElt */
3990 /*************************************************************************/
3992 /* MANAGING THE FLOW OF CONTROL */
3994 /* Instructions appear in the specification's order. */
3996 /*************************************************************************/
4002 CUR
.IP
+= CUR
.length
;
4004 if ( CUR
.IP
< CUR
.codeSize
)
4006 CUR
.opcode
= CUR
.code
[CUR
.IP
];
4008 CUR
.length
= opcode_length
[CUR
.opcode
];
4009 if ( CUR
.length
< 0 )
4011 if ( CUR
.IP
+ 1 > CUR
.codeSize
)
4013 CUR
.length
= CUR
.code
[CUR
.IP
+ 1] + 2;
4016 if ( CUR
.IP
+ CUR
.length
<= CUR
.codeSize
)
4021 CUR
.error
= TT_Err_Code_Overflow
;
4026 /*************************************************************************/
4029 /* Opcode range: 0x58 */
4030 /* Stack: StkElt --> */
4047 if ( SKIP_Code() == FAILURE
)
4050 switch ( CUR
.opcode
)
4056 case 0x1B: /* ELSE */
4057 Out
= FT_BOOL( nIfs
== 1 );
4060 case 0x59: /* EIF */
4062 Out
= FT_BOOL( nIfs
== 0 );
4065 } while ( Out
== 0 );
4069 /*************************************************************************/
4072 /* Opcode range: 0x1B */
4087 if ( SKIP_Code() == FAILURE
)
4090 switch ( CUR
.opcode
)
4096 case 0x59: /* EIF */
4100 } while ( nIfs
!= 0 );
4104 /*************************************************************************/
4106 /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
4108 /* Instructions appear in the specification's order. */
4110 /*************************************************************************/
4113 /*************************************************************************/
4115 /* FDEF[]: Function DEFinition */
4116 /* Opcode range: 0x2C */
4117 /* Stack: uint32 --> */
4124 TT_DefRecord
* limit
;
4127 /* some font programs are broken enough to redefine functions! */
4128 /* We will then parse the current table. */
4131 limit
= rec
+ CUR
.numFDefs
;
4134 for ( ; rec
< limit
; rec
++ )
4136 if ( rec
->opc
== n
)
4142 /* check that there is enough room for new functions */
4143 if ( CUR
.numFDefs
>= CUR
.maxFDefs
)
4145 CUR
.error
= TT_Err_Too_Many_Function_Defs
;
4151 rec
->range
= CUR
.curRange
;
4153 rec
->start
= CUR
.IP
+ 1;
4156 if ( n
> CUR
.maxFunc
)
4159 /* Now skip the whole function definition. */
4160 /* We don't allow nested IDEFS & FDEFs. */
4162 while ( SKIP_Code() == SUCCESS
)
4164 switch ( CUR
.opcode
)
4166 case 0x89: /* IDEF */
4167 case 0x2C: /* FDEF */
4168 CUR
.error
= TT_Err_Nested_DEFS
;
4171 case 0x2D: /* ENDF */
4178 /*************************************************************************/
4180 /* ENDF[]: END Function definition */
4181 /* Opcode range: 0x2D */
4192 if ( CUR
.callTop
<= 0 ) /* We encountered an ENDF without a call */
4194 CUR
.error
= TT_Err_ENDF_In_Exec_Stream
;
4200 pRec
= &CUR
.callStack
[CUR
.callTop
];
4204 CUR
.step_ins
= FALSE
;
4206 if ( pRec
->Cur_Count
> 0 )
4209 CUR
.IP
= pRec
->Cur_Restart
;
4212 /* Loop through the current function */
4213 INS_Goto_CodeRange( pRec
->Caller_Range
,
4216 /* Exit the current call frame. */
4218 /* NOTE: If the last intruction of a program is a */
4219 /* CALL or LOOPCALL, the return address is */
4220 /* always out of the code range. This is a */
4221 /* valid address, and it is why we do not test */
4222 /* the result of Ins_Goto_CodeRange() here! */
4226 /*************************************************************************/
4228 /* CALL[]: CALL function */
4229 /* Opcode range: 0x2B */
4230 /* Stack: uint32? --> */
4240 /* first of all, check the index */
4243 if ( BOUNDS( F
, CUR
.maxFunc
+ 1 ) )
4246 /* Except for some old Apple fonts, all functions in a TrueType */
4247 /* font are defined in increasing order, starting from 0. This */
4248 /* means that we normally have */
4250 /* CUR.maxFunc+1 == CUR.numFDefs */
4251 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4253 /* If this isn't true, we need to look up the function table. */
4255 def
= CUR
.FDefs
+ F
;
4256 if ( CUR
.maxFunc
+ 1 != CUR
.numFDefs
|| def
->opc
!= F
)
4258 /* look up the FDefs table */
4259 TT_DefRecord
* limit
;
4263 limit
= def
+ CUR
.numFDefs
;
4265 while ( def
< limit
&& def
->opc
!= F
)
4272 /* check that the function is active */
4276 /* check the call stack */
4277 if ( CUR
.callTop
>= CUR
.callSize
)
4279 CUR
.error
= TT_Err_Stack_Overflow
;
4283 pCrec
= CUR
.callStack
+ CUR
.callTop
;
4285 pCrec
->Caller_Range
= CUR
.curRange
;
4286 pCrec
->Caller_IP
= CUR
.IP
+ 1;
4287 pCrec
->Cur_Count
= 1;
4288 pCrec
->Cur_Restart
= def
->start
;
4292 INS_Goto_CodeRange( def
->range
,
4295 CUR
.step_ins
= FALSE
;
4299 CUR
.error
= TT_Err_Invalid_Reference
;
4303 /*************************************************************************/
4305 /* LOOPCALL[]: LOOP and CALL function */
4306 /* Opcode range: 0x2A */
4307 /* Stack: uint32? Eint16? --> */
4310 Ins_LOOPCALL( INS_ARG
)
4317 /* first of all, check the index */
4319 if ( BOUNDS( F
, CUR
.maxFunc
+ 1 ) )
4322 /* Except for some old Apple fonts, all functions in a TrueType */
4323 /* font are defined in increasing order, starting from 0. This */
4324 /* means that we normally have */
4326 /* CUR.maxFunc+1 == CUR.numFDefs */
4327 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4329 /* If this isn't true, we need to look up the function table. */
4331 def
= CUR
.FDefs
+ F
;
4332 if ( CUR
.maxFunc
+ 1 != CUR
.numFDefs
|| def
->opc
!= F
)
4334 /* look up the FDefs table */
4335 TT_DefRecord
* limit
;
4339 limit
= def
+ CUR
.numFDefs
;
4341 while ( def
< limit
&& def
->opc
!= F
)
4348 /* check that the function is active */
4353 if ( CUR
.callTop
>= CUR
.callSize
)
4355 CUR
.error
= TT_Err_Stack_Overflow
;
4361 pCrec
= CUR
.callStack
+ CUR
.callTop
;
4363 pCrec
->Caller_Range
= CUR
.curRange
;
4364 pCrec
->Caller_IP
= CUR
.IP
+ 1;
4365 pCrec
->Cur_Count
= (FT_Int
)args
[0];
4366 pCrec
->Cur_Restart
= def
->start
;
4370 INS_Goto_CodeRange( def
->range
, def
->start
);
4372 CUR
.step_ins
= FALSE
;
4377 CUR
.error
= TT_Err_Invalid_Reference
;
4381 /*************************************************************************/
4383 /* IDEF[]: Instruction DEFinition */
4384 /* Opcode range: 0x89 */
4385 /* Stack: Eint8 --> */
4391 TT_DefRecord
* limit
;
4394 /* First of all, look for the same function in our table */
4397 limit
= def
+ CUR
.numIDefs
;
4399 for ( ; def
< limit
; def
++ )
4400 if ( def
->opc
== (FT_ULong
)args
[0] )
4405 /* check that there is enough room for a new instruction */
4406 if ( CUR
.numIDefs
>= CUR
.maxIDefs
)
4408 CUR
.error
= TT_Err_Too_Many_Instruction_Defs
;
4415 def
->start
= CUR
.IP
+1;
4416 def
->range
= CUR
.curRange
;
4419 if ( (FT_ULong
)args
[0] > CUR
.maxIns
)
4420 CUR
.maxIns
= args
[0];
4422 /* Now skip the whole function definition. */
4423 /* We don't allow nested IDEFs & FDEFs. */
4425 while ( SKIP_Code() == SUCCESS
)
4427 switch ( CUR
.opcode
)
4429 case 0x89: /* IDEF */
4430 case 0x2C: /* FDEF */
4431 CUR
.error
= TT_Err_Nested_DEFS
;
4433 case 0x2D: /* ENDF */
4440 /*************************************************************************/
4442 /* PUSHING DATA ONTO THE INTERPRETER STACK */
4444 /* Instructions appear in the specification's order. */
4446 /*************************************************************************/
4449 /*************************************************************************/
4451 /* NPUSHB[]: PUSH N Bytes */
4452 /* Opcode range: 0x40 */
4453 /* Stack: --> uint32... */
4456 Ins_NPUSHB( INS_ARG
)
4461 L
= (FT_UShort
)CUR
.code
[CUR
.IP
+ 1];
4463 if ( BOUNDS( L
, CUR
.stackSize
+ 1 - CUR
.top
) )
4465 CUR
.error
= TT_Err_Stack_Overflow
;
4469 for ( K
= 1; K
<= L
; K
++ )
4470 args
[K
- 1] = CUR
.code
[CUR
.IP
+ K
+ 1];
4476 /*************************************************************************/
4478 /* NPUSHW[]: PUSH N Words */
4479 /* Opcode range: 0x41 */
4480 /* Stack: --> int32... */
4483 Ins_NPUSHW( INS_ARG
)
4488 L
= (FT_UShort
)CUR
.code
[CUR
.IP
+ 1];
4490 if ( BOUNDS( L
, CUR
.stackSize
+ 1 - CUR
.top
) )
4492 CUR
.error
= TT_Err_Stack_Overflow
;
4498 for ( K
= 0; K
< L
; K
++ )
4499 args
[K
] = GET_ShortIns();
4501 CUR
.step_ins
= FALSE
;
4506 /*************************************************************************/
4508 /* PUSHB[abc]: PUSH Bytes */
4509 /* Opcode range: 0xB0-0xB7 */
4510 /* Stack: --> uint32... */
4513 Ins_PUSHB( INS_ARG
)
4518 L
= (FT_UShort
)(CUR
.opcode
- 0xB0 + 1);
4520 if ( BOUNDS( L
, CUR
.stackSize
+ 1 - CUR
.top
) )
4522 CUR
.error
= TT_Err_Stack_Overflow
;
4526 for ( K
= 1; K
<= L
; K
++ )
4527 args
[K
- 1] = CUR
.code
[CUR
.IP
+ K
];
4531 /*************************************************************************/
4533 /* PUSHW[abc]: PUSH Words */
4534 /* Opcode range: 0xB8-0xBF */
4535 /* Stack: --> int32... */
4538 Ins_PUSHW( INS_ARG
)
4543 L
= (FT_UShort
)(CUR
.opcode
- 0xB8 + 1);
4545 if ( BOUNDS( L
, CUR
.stackSize
+ 1 - CUR
.top
) )
4547 CUR
.error
= TT_Err_Stack_Overflow
;
4553 for ( K
= 0; K
< L
; K
++ )
4554 args
[K
] = GET_ShortIns();
4556 CUR
.step_ins
= FALSE
;
4560 /*************************************************************************/
4562 /* MANAGING THE GRAPHICS STATE */
4564 /* Instructions appear in the specs' order. */
4566 /*************************************************************************/
4569 /*************************************************************************/
4571 /* GC[a]: Get Coordinate projected onto */
4572 /* Opcode range: 0x46-0x47 */
4573 /* Stack: uint32 --> f26.6 */
4575 /* BULLSHIT: Measures from the original glyph must be taken along the */
4576 /* dual projection vector! */
4585 L
= (FT_ULong
)args
[0];
4587 if ( BOUNDS( L
, CUR
.zp2
.n_points
) )
4589 if ( CUR
.pedantic_hinting
)
4591 CUR
.error
= TT_Err_Invalid_Reference
;
4599 if ( CUR
.opcode
& 1 )
4600 R
= CUR_Func_dualproj( CUR
.zp2
.org
+ L
, NULL_Vector
);
4602 R
= CUR_Func_project( CUR
.zp2
.cur
+ L
, NULL_Vector
);
4609 /*************************************************************************/
4611 /* SCFS[]: Set Coordinate From Stack */
4612 /* Opcode range: 0x48 */
4613 /* Stack: f26.6 uint32 --> */
4617 /* OA := OA + ( value - OA.p )/( f.p ) * f */
4626 L
= (FT_UShort
)args
[0];
4628 if ( BOUNDS( L
, CUR
.zp2
.n_points
) )
4630 if ( CUR
.pedantic_hinting
)
4631 CUR
.error
= TT_Err_Invalid_Reference
;
4635 K
= CUR_Func_project( CUR
.zp2
.cur
+ L
, NULL_Vector
);
4637 CUR_Func_move( &CUR
.zp2
, L
, args
[1] - K
);
4639 /* not part of the specs, but here for safety */
4641 if ( CUR
.GS
.gep2
== 0 )
4642 CUR
.zp2
.org
[L
] = CUR
.zp2
.cur
[L
];
4646 /*************************************************************************/
4648 /* MD[a]: Measure Distance */
4649 /* Opcode range: 0x49-0x4A */
4650 /* Stack: uint32 uint32 --> f26.6 */
4652 /* BULLSHIT: Measure taken in the original glyph must be along the dual */
4653 /* projection vector. */
4655 /* Second BULLSHIT: Flag attributes are inverted! */
4656 /* 0 => measure distance in original outline */
4657 /* 1 => measure distance in grid-fitted outline */
4659 /* Third one: `zp0 - zp1', and not `zp2 - zp1! */
4668 K
= (FT_UShort
)args
[1];
4669 L
= (FT_UShort
)args
[0];
4671 if( BOUNDS( L
, CUR
.zp0
.n_points
) ||
4672 BOUNDS( K
, CUR
.zp1
.n_points
) )
4674 if ( CUR
.pedantic_hinting
)
4676 CUR
.error
= TT_Err_Invalid_Reference
;
4683 if ( CUR
.opcode
& 1 )
4684 D
= CUR_Func_project( CUR
.zp0
.cur
+ L
, CUR
.zp1
.cur
+ K
);
4686 D
= CUR_Func_dualproj( CUR
.zp0
.org
+ L
, CUR
.zp1
.org
+ K
);
4693 /*************************************************************************/
4695 /* SDPVTL[a]: Set Dual PVector to Line */
4696 /* Opcode range: 0x86-0x87 */
4697 /* Stack: uint32 uint32 --> */
4700 Ins_SDPVTL( INS_ARG
)
4703 FT_UShort p1
, p2
; /* was FT_Int in pas type ERROR */
4706 p1
= (FT_UShort
)args
[1];
4707 p2
= (FT_UShort
)args
[0];
4709 if ( BOUNDS( p2
, CUR
.zp1
.n_points
) ||
4710 BOUNDS( p1
, CUR
.zp2
.n_points
) )
4712 if ( CUR
.pedantic_hinting
)
4713 CUR
.error
= TT_Err_Invalid_Reference
;
4718 FT_Vector
* v1
= CUR
.zp1
.org
+ p2
;
4719 FT_Vector
* v2
= CUR
.zp2
.org
+ p1
;
4726 if ( ( CUR
.opcode
& 1 ) != 0 )
4728 C
= B
; /* counter clockwise rotation */
4733 NORMalize( A
, B
, &CUR
.GS
.dualVector
);
4736 FT_Vector
* v1
= CUR
.zp1
.cur
+ p2
;
4737 FT_Vector
* v2
= CUR
.zp2
.cur
+ p1
;
4744 if ( ( CUR
.opcode
& 1 ) != 0 )
4746 C
= B
; /* counter clockwise rotation */
4751 NORMalize( A
, B
, &CUR
.GS
.projVector
);
4757 /*************************************************************************/
4759 /* SZP0[]: Set Zone Pointer 0 */
4760 /* Opcode range: 0x13 */
4761 /* Stack: uint32 --> */
4766 switch ( (FT_Int
)args
[0] )
4769 CUR
.zp0
= CUR
.twilight
;
4777 if ( CUR
.pedantic_hinting
)
4778 CUR
.error
= TT_Err_Invalid_Reference
;
4782 CUR
.GS
.gep0
= (FT_UShort
)args
[0];
4786 /*************************************************************************/
4788 /* SZP1[]: Set Zone Pointer 1 */
4789 /* Opcode range: 0x14 */
4790 /* Stack: uint32 --> */
4795 switch ( (FT_Int
)args
[0] )
4798 CUR
.zp1
= CUR
.twilight
;
4806 if ( CUR
.pedantic_hinting
)
4807 CUR
.error
= TT_Err_Invalid_Reference
;
4811 CUR
.GS
.gep1
= (FT_UShort
)args
[0];
4815 /*************************************************************************/
4817 /* SZP2[]: Set Zone Pointer 2 */
4818 /* Opcode range: 0x15 */
4819 /* Stack: uint32 --> */
4824 switch ( (FT_Int
)args
[0] )
4827 CUR
.zp2
= CUR
.twilight
;
4835 if ( CUR
.pedantic_hinting
)
4836 CUR
.error
= TT_Err_Invalid_Reference
;
4840 CUR
.GS
.gep2
= (FT_UShort
)args
[0];
4844 /*************************************************************************/
4846 /* SZPS[]: Set Zone PointerS */
4847 /* Opcode range: 0x16 */
4848 /* Stack: uint32 --> */
4853 switch ( (FT_Int
)args
[0] )
4856 CUR
.zp0
= CUR
.twilight
;
4864 if ( CUR
.pedantic_hinting
)
4865 CUR
.error
= TT_Err_Invalid_Reference
;
4872 CUR
.GS
.gep0
= (FT_UShort
)args
[0];
4873 CUR
.GS
.gep1
= (FT_UShort
)args
[0];
4874 CUR
.GS
.gep2
= (FT_UShort
)args
[0];
4878 /*************************************************************************/
4880 /* INSTCTRL[]: INSTruction ConTRoL */
4881 /* Opcode range: 0x8e */
4882 /* Stack: int32 int32 --> */
4885 Ins_INSTCTRL( INS_ARG
)
4893 if ( K
< 1 || K
> 2 )
4895 if ( CUR
.pedantic_hinting
)
4896 CUR
.error
= TT_Err_Invalid_Reference
;
4903 CUR
.GS
.instruct_control
= FT_BOOL(
4904 ( (FT_Byte
)CUR
.GS
.instruct_control
& ~(FT_Byte
)K
) | (FT_Byte
)L
);
4908 /*************************************************************************/
4910 /* SCANCTRL[]: SCAN ConTRoL */
4911 /* Opcode range: 0x85 */
4912 /* Stack: uint32? --> */
4915 Ins_SCANCTRL( INS_ARG
)
4921 A
= (FT_Int
)( args
[0] & 0xFF );
4925 CUR
.GS
.scan_control
= TRUE
;
4930 CUR
.GS
.scan_control
= FALSE
;
4937 if ( (args
[0] & 0x100) != 0 && CUR
.metrics
.pointSize
<= A
)
4938 CUR
.GS
.scan_control
= TRUE
;
4941 if ( (args
[0] & 0x200) != 0 && CUR
.tt_metrics
.rotated
)
4942 CUR
.GS
.scan_control
= TRUE
;
4944 if ( (args
[0] & 0x400) != 0 && CUR
.tt_metrics
.stretched
)
4945 CUR
.GS
.scan_control
= TRUE
;
4948 if ( (args
[0] & 0x800) != 0 && CUR
.metrics
.pointSize
> A
)
4949 CUR
.GS
.scan_control
= FALSE
;
4952 if ( (args
[0] & 0x1000) != 0 && CUR
.tt_metrics
.rotated
)
4953 CUR
.GS
.scan_control
= FALSE
;
4955 if ( (args
[0] & 0x2000) != 0 && CUR
.tt_metrics
.stretched
)
4956 CUR
.GS
.scan_control
= FALSE
;
4960 /*************************************************************************/
4962 /* SCANTYPE[]: SCAN TYPE */
4963 /* Opcode range: 0x8D */
4964 /* Stack: uint32? --> */
4967 Ins_SCANTYPE( INS_ARG
)
4969 /* for compatibility with future enhancements, */
4970 /* we must ignore new modes */
4972 if ( args
[0] >= 0 && args
[0] <= 5 )
4977 CUR
.GS
.scan_type
= (FT_Int
)args
[0];
4982 /*************************************************************************/
4984 /* MANAGING OUTLINES */
4986 /* Instructions appear in the specification's order. */
4988 /*************************************************************************/
4991 /*************************************************************************/
4993 /* FLIPPT[]: FLIP PoinT */
4994 /* Opcode range: 0x80 */
4995 /* Stack: uint32... --> */
4998 Ins_FLIPPT( INS_ARG
)
5005 if ( CUR
.top
< CUR
.GS
.loop
)
5007 CUR
.error
= TT_Err_Too_Few_Arguments
;
5011 while ( CUR
.GS
.loop
> 0 )
5015 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5017 if ( BOUNDS( point
, CUR
.pts
.n_points
) )
5019 if ( CUR
.pedantic_hinting
)
5021 CUR
.error
= TT_Err_Invalid_Reference
;
5026 CUR
.pts
.tags
[point
] ^= FT_Curve_Tag_On
;
5032 CUR
.new_top
= CUR
.args
;
5036 /*************************************************************************/
5038 /* FLIPRGON[]: FLIP RanGe ON */
5039 /* Opcode range: 0x81 */
5040 /* Stack: uint32 uint32 --> */
5043 Ins_FLIPRGON( INS_ARG
)
5048 K
= (FT_UShort
)args
[1];
5049 L
= (FT_UShort
)args
[0];
5051 if ( BOUNDS( K
, CUR
.pts
.n_points
) ||
5052 BOUNDS( L
, CUR
.pts
.n_points
) )
5054 if ( CUR
.pedantic_hinting
)
5055 CUR
.error
= TT_Err_Invalid_Reference
;
5059 for ( I
= L
; I
<= K
; I
++ )
5060 CUR
.pts
.tags
[I
] |= FT_Curve_Tag_On
;
5064 /*************************************************************************/
5066 /* FLIPRGOFF: FLIP RanGe OFF */
5067 /* Opcode range: 0x82 */
5068 /* Stack: uint32 uint32 --> */
5071 Ins_FLIPRGOFF( INS_ARG
)
5076 K
= (FT_UShort
)args
[1];
5077 L
= (FT_UShort
)args
[0];
5079 if ( BOUNDS( K
, CUR
.pts
.n_points
) ||
5080 BOUNDS( L
, CUR
.pts
.n_points
) )
5082 if ( CUR
.pedantic_hinting
)
5083 CUR
.error
= TT_Err_Invalid_Reference
;
5087 for ( I
= L
; I
<= K
; I
++ )
5088 CUR
.pts
.tags
[I
] &= ~FT_Curve_Tag_On
;
5093 Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6
* x
,
5103 if ( CUR
.opcode
& 1 )
5114 if ( BOUNDS( p
, zp
.n_points
) )
5116 if ( CUR
.pedantic_hinting
)
5117 CUR
.error
= TT_Err_Invalid_Reference
;
5124 d
= CUR_Func_project( zp
.cur
+ p
, zp
.org
+ p
);
5126 #ifdef NO_APPLE_PATENT
5128 *x
= TT_MulFix14( d
, CUR
.GS
.freeVector
.x
);
5129 *y
= TT_MulFix14( d
, CUR
.GS
.freeVector
.y
);
5134 (FT_Long
)CUR
.GS
.freeVector
.x
* 0x10000L
,
5137 (FT_Long
)CUR
.GS
.freeVector
.y
* 0x10000L
,
5140 #endif /* NO_APPLE_PATENT */
5147 Move_Zp2_Point( EXEC_OP_ FT_UShort point
,
5152 if ( CUR
.GS
.freeVector
.x
!= 0 )
5154 CUR
.zp2
.cur
[point
].x
+= dx
;
5156 CUR
.zp2
.tags
[point
] |= FT_Curve_Tag_Touch_X
;
5159 if ( CUR
.GS
.freeVector
.y
!= 0 )
5161 CUR
.zp2
.cur
[point
].y
+= dy
;
5163 CUR
.zp2
.tags
[point
] |= FT_Curve_Tag_Touch_Y
;
5168 /*************************************************************************/
5170 /* SHP[a]: SHift Point by the last point */
5171 /* Opcode range: 0x32-0x33 */
5172 /* Stack: uint32... --> */
5187 if ( CUR
.top
< CUR
.GS
.loop
)
5189 CUR
.error
= TT_Err_Invalid_Reference
;
5193 if ( COMPUTE_Point_Displacement( &dx
, &dy
, &zp
, &refp
) )
5196 while ( CUR
.GS
.loop
> 0 )
5199 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5201 if ( BOUNDS( point
, CUR
.zp2
.n_points
) )
5203 if ( CUR
.pedantic_hinting
)
5205 CUR
.error
= TT_Err_Invalid_Reference
;
5210 /* XXX: UNDOCUMENTED! SHP touches the points */
5211 MOVE_Zp2_Point( point
, dx
, dy
, TRUE
);
5217 CUR
.new_top
= CUR
.args
;
5221 /*************************************************************************/
5223 /* SHC[a]: SHift Contour */
5224 /* Opcode range: 0x34-35 */
5225 /* Stack: uint32 --> */
5236 FT_UShort first_point
, last_point
, i
;
5239 contour
= (FT_UShort
)args
[0];
5241 if ( BOUNDS( contour
, CUR
.pts
.n_contours
) )
5243 if ( CUR
.pedantic_hinting
)
5244 CUR
.error
= TT_Err_Invalid_Reference
;
5248 if ( COMPUTE_Point_Displacement( &dx
, &dy
, &zp
, &refp
) )
5254 first_point
= (FT_UShort
)(CUR
.pts
.contours
[contour
- 1] + 1);
5256 last_point
= CUR
.pts
.contours
[contour
];
5258 /* XXX: this is probably wrong... at least it prevents memory */
5259 /* corruption when zp2 is the twilight zone */
5260 if ( last_point
> CUR
.zp2
.n_points
)
5262 if ( CUR
.zp2
.n_points
> 0 )
5263 last_point
= (FT_UShort
)(CUR
.zp2
.n_points
- 1);
5268 /* XXX: UNDOCUMENTED! SHC doesn't touch the points */
5269 for ( i
= first_point
; i
<= last_point
; i
++ )
5271 if ( zp
.cur
!= CUR
.zp2
.cur
|| refp
!= i
)
5272 MOVE_Zp2_Point( i
, dx
, dy
, FALSE
);
5277 /*************************************************************************/
5279 /* SHZ[a]: SHift Zone */
5280 /* Opcode range: 0x36-37 */
5281 /* Stack: uint32 --> */
5291 FT_UShort last_point
, i
;
5294 if ( BOUNDS( args
[0], 2 ) )
5296 if ( CUR
.pedantic_hinting
)
5297 CUR
.error
= TT_Err_Invalid_Reference
;
5301 if ( COMPUTE_Point_Displacement( &dx
, &dy
, &zp
, &refp
) )
5304 if ( CUR
.zp2
.n_points
> 0 )
5305 last_point
= (FT_UShort
)(CUR
.zp2
.n_points
- 1);
5309 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
5310 for ( i
= 0; i
<= last_point
; i
++ )
5312 if ( zp
.cur
!= CUR
.zp2
.cur
|| refp
!= i
)
5313 MOVE_Zp2_Point( i
, dx
, dy
, FALSE
);
5318 /*************************************************************************/
5320 /* SHPIX[]: SHift points by a PIXel amount */
5321 /* Opcode range: 0x38 */
5322 /* Stack: f26.6 uint32... --> */
5325 Ins_SHPIX( INS_ARG
)
5331 if ( CUR
.top
< CUR
.GS
.loop
+ 1 )
5333 CUR
.error
= TT_Err_Invalid_Reference
;
5337 dx
= TT_MulFix14( args
[0], CUR
.GS
.freeVector
.x
);
5338 dy
= TT_MulFix14( args
[0], CUR
.GS
.freeVector
.y
);
5340 while ( CUR
.GS
.loop
> 0 )
5344 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5346 if ( BOUNDS( point
, CUR
.zp2
.n_points
) )
5348 if ( CUR
.pedantic_hinting
)
5350 CUR
.error
= TT_Err_Invalid_Reference
;
5355 MOVE_Zp2_Point( point
, dx
, dy
, TRUE
);
5361 CUR
.new_top
= CUR
.args
;
5365 /*************************************************************************/
5367 /* MSIRP[a]: Move Stack Indirect Relative Position */
5368 /* Opcode range: 0x3A-0x3B */
5369 /* Stack: f26.6 uint32 --> */
5372 Ins_MSIRP( INS_ARG
)
5375 FT_F26Dot6 distance
;
5378 point
= (FT_UShort
)args
[0];
5380 if ( BOUNDS( point
, CUR
.zp1
.n_points
) ||
5381 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5383 if ( CUR
.pedantic_hinting
)
5384 CUR
.error
= TT_Err_Invalid_Reference
;
5388 /* XXX: UNDOCUMENTED! behaviour */
5389 if ( CUR
.GS
.gep0
== 0 ) /* if in twilight zone */
5391 CUR
.zp1
.org
[point
] = CUR
.zp0
.org
[CUR
.GS
.rp0
];
5392 CUR
.zp1
.cur
[point
] = CUR
.zp1
.org
[point
];
5395 distance
= CUR_Func_project( CUR
.zp1
.cur
+ point
,
5396 CUR
.zp0
.cur
+ CUR
.GS
.rp0
);
5398 CUR_Func_move( &CUR
.zp1
, point
, args
[1] - distance
);
5400 CUR
.GS
.rp1
= CUR
.GS
.rp0
;
5403 if ( (CUR
.opcode
& 1) != 0 )
5408 /*************************************************************************/
5410 /* MDAP[a]: Move Direct Absolute Point */
5411 /* Opcode range: 0x2E-0x2F */
5412 /* Stack: uint32 --> */
5418 FT_F26Dot6 cur_dist
,
5422 point
= (FT_UShort
)args
[0];
5424 if ( BOUNDS( point
, CUR
.zp0
.n_points
) )
5426 if ( CUR
.pedantic_hinting
)
5427 CUR
.error
= TT_Err_Invalid_Reference
;
5431 /* XXX: Is there some undocumented feature while in the */
5432 /* twilight zone? ? */
5433 if ( ( CUR
.opcode
& 1 ) != 0 )
5435 cur_dist
= CUR_Func_project( CUR
.zp0
.cur
+ point
, NULL_Vector
);
5436 distance
= CUR_Func_round( cur_dist
,
5437 CUR
.tt_metrics
.compensations
[0] ) - cur_dist
;
5442 CUR_Func_move( &CUR
.zp0
, point
, distance
);
5449 /*************************************************************************/
5451 /* MIAP[a]: Move Indirect Absolute Point */
5452 /* Opcode range: 0x3E-0x3F */
5453 /* Stack: uint32 uint32 --> */
5460 FT_F26Dot6 distance
,
5464 cvtEntry
= (FT_ULong
)args
[1];
5465 point
= (FT_UShort
)args
[0];
5467 if ( BOUNDS( point
, CUR
.zp0
.n_points
) ||
5468 BOUNDS( cvtEntry
, CUR
.cvtSize
) )
5470 if ( CUR
.pedantic_hinting
)
5471 CUR
.error
= TT_Err_Invalid_Reference
;
5477 /* The behaviour of an MIAP instruction is quite */
5478 /* different when used in the twilight zone. */
5480 /* First, no control value cutin test is performed */
5481 /* as it would fail anyway. Second, the original */
5482 /* point, i.e. (org_x,org_y) of zp0.point, is set */
5483 /* to the absolute, unrounded distance found in */
5486 /* This is used in the CVT programs of the Microsoft */
5487 /* fonts Arial, Times, etc., in order to re-adjust */
5488 /* some key font heights. It allows the use of the */
5489 /* IP instruction in the twilight zone, which */
5490 /* otherwise would be `illegal' according to the */
5491 /* specification. */
5493 /* We implement it with a special sequence for the */
5494 /* twilight zone. This is a bad hack, but it seems */
5497 distance
= CUR_Func_read_cvt( cvtEntry
);
5499 if ( CUR
.GS
.gep0
== 0 ) /* If in twilight zone */
5501 CUR
.zp0
.org
[point
].x
= TT_MulFix14( distance
, CUR
.GS
.freeVector
.x
);
5502 CUR
.zp0
.org
[point
].y
= TT_MulFix14( distance
, CUR
.GS
.freeVector
.y
),
5503 CUR
.zp0
.cur
[point
] = CUR
.zp0
.org
[point
];
5506 org_dist
= CUR_Func_project( CUR
.zp0
.cur
+ point
, NULL_Vector
);
5508 if ( ( CUR
.opcode
& 1 ) != 0 ) /* rounding and control cutin flag */
5510 if ( ABS( distance
- org_dist
) > CUR
.GS
.control_value_cutin
)
5511 distance
= org_dist
;
5513 distance
= CUR_Func_round( distance
, CUR
.tt_metrics
.compensations
[0] );
5516 CUR_Func_move( &CUR
.zp0
, point
, distance
- org_dist
);
5523 /*************************************************************************/
5525 /* MDRP[abcde]: Move Direct Relative Point */
5526 /* Opcode range: 0xC0-0xDF */
5527 /* Stack: uint32 --> */
5533 FT_F26Dot6 org_dist
, distance
;
5536 point
= (FT_UShort
)args
[0];
5538 if ( BOUNDS( point
, CUR
.zp1
.n_points
) ||
5539 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5541 if ( CUR
.pedantic_hinting
)
5542 CUR
.error
= TT_Err_Invalid_Reference
;
5546 /* XXX: Is there some undocumented feature while in the */
5547 /* twilight zone? */
5549 org_dist
= CUR_Func_dualproj( CUR
.zp1
.org
+ point
,
5550 CUR
.zp0
.org
+ CUR
.GS
.rp0
);
5552 /* single width cutin test */
5554 if ( ABS( org_dist
) < CUR
.GS
.single_width_cutin
)
5556 if ( org_dist
>= 0 )
5557 org_dist
= CUR
.GS
.single_width_value
;
5559 org_dist
= -CUR
.GS
.single_width_value
;
5564 if ( ( CUR
.opcode
& 4 ) != 0 )
5565 distance
= CUR_Func_round(
5567 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5569 distance
= ROUND_None(
5571 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5573 /* minimum distance flag */
5575 if ( ( CUR
.opcode
& 8 ) != 0 )
5577 if ( org_dist
>= 0 )
5579 if ( distance
< CUR
.GS
.minimum_distance
)
5580 distance
= CUR
.GS
.minimum_distance
;
5584 if ( distance
> -CUR
.GS
.minimum_distance
)
5585 distance
= -CUR
.GS
.minimum_distance
;
5589 /* now move the point */
5591 org_dist
= CUR_Func_project( CUR
.zp1
.cur
+ point
,
5592 CUR
.zp0
.cur
+ CUR
.GS
.rp0
);
5594 CUR_Func_move( &CUR
.zp1
, point
, distance
- org_dist
);
5596 CUR
.GS
.rp1
= CUR
.GS
.rp0
;
5599 if ( ( CUR
.opcode
& 16 ) != 0 )
5604 /*************************************************************************/
5606 /* MIRP[abcde]: Move Indirect Relative Point */
5607 /* Opcode range: 0xE0-0xFF */
5608 /* Stack: int32? uint32 --> */
5616 FT_F26Dot6 cvt_dist
,
5622 point
= (FT_UShort
)args
[0];
5623 cvtEntry
= (FT_ULong
)( args
[1] + 1 );
5625 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
5627 if ( BOUNDS( point
, CUR
.zp1
.n_points
) ||
5628 BOUNDS( cvtEntry
, CUR
.cvtSize
+ 1 ) ||
5629 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5631 if ( CUR
.pedantic_hinting
)
5632 CUR
.error
= TT_Err_Invalid_Reference
;
5639 cvt_dist
= CUR_Func_read_cvt( cvtEntry
- 1 );
5641 /* single width test */
5643 if ( ABS( cvt_dist
) < CUR
.GS
.single_width_cutin
)
5645 if ( cvt_dist
>= 0 )
5646 cvt_dist
= CUR
.GS
.single_width_value
;
5648 cvt_dist
= -CUR
.GS
.single_width_value
;
5651 /* XXX: UNDOCUMENTED! -- twilight zone */
5653 if ( CUR
.GS
.gep1
== 0 )
5655 CUR
.zp1
.org
[point
].x
= CUR
.zp0
.org
[CUR
.GS
.rp0
].x
+
5656 TT_MulFix14( cvt_dist
, CUR
.GS
.freeVector
.x
);
5658 CUR
.zp1
.org
[point
].y
= CUR
.zp0
.org
[CUR
.GS
.rp0
].y
+
5659 TT_MulFix14( cvt_dist
, CUR
.GS
.freeVector
.y
);
5661 CUR
.zp1
.cur
[point
] = CUR
.zp1
.org
[point
];
5664 org_dist
= CUR_Func_dualproj( CUR
.zp1
.org
+ point
,
5665 CUR
.zp0
.org
+ CUR
.GS
.rp0
);
5667 cur_dist
= CUR_Func_project( CUR
.zp1
.cur
+ point
,
5668 CUR
.zp0
.cur
+ CUR
.GS
.rp0
);
5670 /* auto-flip test */
5672 if ( CUR
.GS
.auto_flip
)
5674 if ( ( org_dist
^ cvt_dist
) < 0 )
5675 cvt_dist
= -cvt_dist
;
5678 /* control value cutin and round */
5680 if ( ( CUR
.opcode
& 4 ) != 0 )
5682 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
5683 /* refer to the same zone. */
5685 if ( CUR
.GS
.gep0
== CUR
.GS
.gep1
)
5686 if ( ABS( cvt_dist
- org_dist
) >= CUR
.GS
.control_value_cutin
)
5687 cvt_dist
= org_dist
;
5689 distance
= CUR_Func_round(
5691 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5694 distance
= ROUND_None(
5696 CUR
.tt_metrics
.compensations
[CUR
.opcode
& 3] );
5698 /* minimum distance test */
5700 if ( ( CUR
.opcode
& 8 ) != 0 )
5702 if ( org_dist
>= 0 )
5704 if ( distance
< CUR
.GS
.minimum_distance
)
5705 distance
= CUR
.GS
.minimum_distance
;
5709 if ( distance
> -CUR
.GS
.minimum_distance
)
5710 distance
= -CUR
.GS
.minimum_distance
;
5714 CUR_Func_move( &CUR
.zp1
, point
, distance
- cur_dist
);
5716 CUR
.GS
.rp1
= CUR
.GS
.rp0
;
5718 if ( ( CUR
.opcode
& 16 ) != 0 )
5721 /* XXX: UNDOCUMENTED! */
5727 /*************************************************************************/
5729 /* ALIGNRP[]: ALIGN Relative Point */
5730 /* Opcode range: 0x3C */
5731 /* Stack: uint32 uint32... --> */
5734 Ins_ALIGNRP( INS_ARG
)
5737 FT_F26Dot6 distance
;
5742 if ( CUR
.top
< CUR
.GS
.loop
||
5743 BOUNDS( CUR
.GS
.rp0
, CUR
.zp0
.n_points
) )
5745 if ( CUR
.pedantic_hinting
)
5746 CUR
.error
= TT_Err_Invalid_Reference
;
5750 while ( CUR
.GS
.loop
> 0 )
5754 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5756 if ( BOUNDS( point
, CUR
.zp1
.n_points
) )
5758 if ( CUR
.pedantic_hinting
)
5760 CUR
.error
= TT_Err_Invalid_Reference
;
5766 distance
= CUR_Func_project( CUR
.zp1
.cur
+ point
,
5767 CUR
.zp0
.cur
+ CUR
.GS
.rp0
);
5769 CUR_Func_move( &CUR
.zp1
, point
, -distance
);
5776 CUR
.new_top
= CUR
.args
;
5780 /*************************************************************************/
5782 /* ISECT[]: moves point to InterSECTion */
5783 /* Opcode range: 0x0F */
5784 /* Stack: 5 * uint32 --> */
5787 Ins_ISECT( INS_ARG
)
5793 FT_F26Dot6 discriminant
;
5804 point
= (FT_UShort
)args
[0];
5806 a0
= (FT_UShort
)args
[1];
5807 a1
= (FT_UShort
)args
[2];
5808 b0
= (FT_UShort
)args
[3];
5809 b1
= (FT_UShort
)args
[4];
5811 if ( BOUNDS( b0
, CUR
.zp0
.n_points
) ||
5812 BOUNDS( b1
, CUR
.zp0
.n_points
) ||
5813 BOUNDS( a0
, CUR
.zp1
.n_points
) ||
5814 BOUNDS( a1
, CUR
.zp1
.n_points
) ||
5815 BOUNDS( point
, CUR
.zp2
.n_points
) )
5817 if ( CUR
.pedantic_hinting
)
5818 CUR
.error
= TT_Err_Invalid_Reference
;
5822 dbx
= CUR
.zp0
.cur
[b1
].x
- CUR
.zp0
.cur
[b0
].x
;
5823 dby
= CUR
.zp0
.cur
[b1
].y
- CUR
.zp0
.cur
[b0
].y
;
5825 dax
= CUR
.zp1
.cur
[a1
].x
- CUR
.zp1
.cur
[a0
].x
;
5826 day
= CUR
.zp1
.cur
[a1
].y
- CUR
.zp1
.cur
[a0
].y
;
5828 dx
= CUR
.zp0
.cur
[b0
].x
- CUR
.zp1
.cur
[a0
].x
;
5829 dy
= CUR
.zp0
.cur
[b0
].y
- CUR
.zp1
.cur
[a0
].y
;
5831 CUR
.zp2
.tags
[point
] |= FT_Curve_Tag_Touch_Both
;
5833 discriminant
= TT_MULDIV( dax
, -dby
, 0x40 ) +
5834 TT_MULDIV( day
, dbx
, 0x40 );
5836 if ( ABS( discriminant
) >= 0x40 )
5838 val
= TT_MULDIV( dx
, -dby
, 0x40 ) + TT_MULDIV( dy
, dbx
, 0x40 );
5840 R
.x
= TT_MULDIV( val
, dax
, discriminant
);
5841 R
.y
= TT_MULDIV( val
, day
, discriminant
);
5843 CUR
.zp2
.cur
[point
].x
= CUR
.zp1
.cur
[a0
].x
+ R
.x
;
5844 CUR
.zp2
.cur
[point
].y
= CUR
.zp1
.cur
[a0
].y
+ R
.y
;
5848 /* else, take the middle of the middles of A and B */
5850 CUR
.zp2
.cur
[point
].x
= ( CUR
.zp1
.cur
[a0
].x
+
5853 CUR
.zp0
.cur
[b1
].x
) / 4;
5854 CUR
.zp2
.cur
[point
].y
= ( CUR
.zp1
.cur
[a0
].y
+
5857 CUR
.zp0
.cur
[b1
].y
) / 4;
5862 /*************************************************************************/
5864 /* ALIGNPTS[]: ALIGN PoinTS */
5865 /* Opcode range: 0x27 */
5866 /* Stack: uint32 uint32 --> */
5869 Ins_ALIGNPTS( INS_ARG
)
5872 FT_F26Dot6 distance
;
5875 p1
= (FT_UShort
)args
[0];
5876 p2
= (FT_UShort
)args
[1];
5878 if ( BOUNDS( args
[0], CUR
.zp1
.n_points
) ||
5879 BOUNDS( args
[1], CUR
.zp0
.n_points
) )
5881 if ( CUR
.pedantic_hinting
)
5882 CUR
.error
= TT_Err_Invalid_Reference
;
5886 distance
= CUR_Func_project( CUR
.zp0
.cur
+ p2
,
5887 CUR
.zp1
.cur
+ p1
) / 2;
5889 CUR_Func_move( &CUR
.zp1
, p1
, distance
);
5890 CUR_Func_move( &CUR
.zp0
, p2
, -distance
);
5894 /*************************************************************************/
5896 /* IP[]: Interpolate Point */
5897 /* Opcode range: 0x39 */
5898 /* Stack: uint32... --> */
5903 FT_F26Dot6 org_a
, org_b
, org_x
,
5904 cur_a
, cur_b
, cur_x
,
5911 if ( CUR
.top
< CUR
.GS
.loop
)
5913 CUR
.error
= TT_Err_Invalid_Reference
;
5917 /* XXX: There are some glyphs in some braindead but popular */
5918 /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
5919 /* calling IP[] with bad values of rp[12]. */
5920 /* Do something sane when this odd thing happens. */
5922 if ( BOUNDS( CUR
.GS
.rp1
, CUR
.zp0
.n_points
) ||
5923 BOUNDS( CUR
.GS
.rp2
, CUR
.zp1
.n_points
) )
5930 org_a
= CUR_Func_dualproj( CUR
.zp0
.org
+ CUR
.GS
.rp1
, NULL_Vector
);
5931 org_b
= CUR_Func_dualproj( CUR
.zp1
.org
+ CUR
.GS
.rp2
, NULL_Vector
);
5933 cur_a
= CUR_Func_project( CUR
.zp0
.cur
+ CUR
.GS
.rp1
, NULL_Vector
);
5934 cur_b
= CUR_Func_project( CUR
.zp1
.cur
+ CUR
.GS
.rp2
, NULL_Vector
);
5937 while ( CUR
.GS
.loop
> 0 )
5941 point
= (FT_UShort
)CUR
.stack
[CUR
.args
];
5942 if ( BOUNDS( point
, CUR
.zp2
.n_points
) )
5944 if ( CUR
.pedantic_hinting
)
5946 CUR
.error
= TT_Err_Invalid_Reference
;
5952 org_x
= CUR_Func_dualproj( CUR
.zp2
.org
+ point
, NULL_Vector
);
5953 cur_x
= CUR_Func_project ( CUR
.zp2
.cur
+ point
, NULL_Vector
);
5955 if ( ( org_a
<= org_b
&& org_x
<= org_a
) ||
5956 ( org_a
> org_b
&& org_x
>= org_a
) )
5958 distance
= ( cur_a
- org_a
) + ( org_x
- cur_x
);
5960 else if ( ( org_a
<= org_b
&& org_x
>= org_b
) ||
5961 ( org_a
> org_b
&& org_x
< org_b
) )
5963 distance
= ( cur_b
- org_b
) + ( org_x
- cur_x
);
5966 /* note: it seems that rounding this value isn't a good */
5967 /* idea (cf. width of capital `S' in Times) */
5969 distance
= TT_MULDIV( cur_b
- cur_a
,
5971 org_b
- org_a
) + ( cur_a
- cur_x
);
5973 CUR_Func_move( &CUR
.zp2
, point
, distance
);
5980 CUR
.new_top
= CUR
.args
;
5984 /*************************************************************************/
5986 /* UTP[a]: UnTouch Point */
5987 /* Opcode range: 0x29 */
5988 /* Stack: uint32 --> */
5997 point
= (FT_UShort
)args
[0];
5999 if ( BOUNDS( point
, CUR
.zp0
.n_points
) )
6001 if ( CUR
.pedantic_hinting
)
6002 CUR
.error
= TT_Err_Invalid_Reference
;
6008 if ( CUR
.GS
.freeVector
.x
!= 0 )
6009 mask
&= ~FT_Curve_Tag_Touch_X
;
6011 if ( CUR
.GS
.freeVector
.y
!= 0 )
6012 mask
&= ~FT_Curve_Tag_Touch_Y
;
6014 CUR
.zp0
.tags
[point
] &= mask
;
6018 /* Local variables for Ins_IUP: */
6021 FT_Vector
* orgs
; /* original and current coordinate */
6022 FT_Vector
* curs
; /* arrays */
6030 struct LOC_Ins_IUP
* LINK
)
6036 x
= LINK
->curs
[p
].x
- LINK
->orgs
[p
].x
;
6038 for ( i
= p1
; i
< p
; i
++ )
6039 LINK
->curs
[i
].x
+= x
;
6041 for ( i
= p
+ 1; i
<= p2
; i
++ )
6042 LINK
->curs
[i
].x
+= x
;
6051 struct LOC_Ins_IUP
* LINK
)
6054 FT_F26Dot6 x
, x1
, x2
, d1
, d2
;
6060 x1
= LINK
->orgs
[ref1
].x
;
6061 d1
= LINK
->curs
[ref1
].x
- LINK
->orgs
[ref1
].x
;
6062 x2
= LINK
->orgs
[ref2
].x
;
6063 d2
= LINK
->curs
[ref2
].x
- LINK
->orgs
[ref2
].x
;
6067 for ( i
= p1
; i
<= p2
; i
++ )
6069 x
= LINK
->orgs
[i
].x
;
6076 LINK
->curs
[i
].x
= x
;
6083 for ( i
= p1
; i
<= p2
; i
++ )
6085 x
= LINK
->orgs
[i
].x
;
6094 x
= LINK
->curs
[ref1
].x
+
6096 LINK
->curs
[ref2
].x
- LINK
->curs
[ref1
].x
,
6099 LINK
->curs
[i
].x
= x
;
6106 for ( i
= p1
; i
<= p2
; i
++ )
6108 x
= LINK
->orgs
[i
].x
;
6116 x
= LINK
->curs
[ref1
].x
+
6118 LINK
->curs
[ref2
].x
- LINK
->curs
[ref1
].x
,
6121 LINK
->curs
[i
].x
= x
;
6126 /*************************************************************************/
6128 /* IUP[a]: Interpolate Untouched Points */
6129 /* Opcode range: 0x30-0x31 */
6135 struct LOC_Ins_IUP V
;
6138 FT_UInt first_point
; /* first point of contour */
6139 FT_UInt end_point
; /* end point (last+1) of contour */
6141 FT_UInt first_touched
; /* first touched point in contour */
6142 FT_UInt cur_touched
; /* current touched point in contour */
6144 FT_UInt point
; /* current point */
6145 FT_Short contour
; /* current contour */
6150 if ( CUR
.opcode
& 1 )
6152 mask
= FT_Curve_Tag_Touch_X
;
6153 V
.orgs
= CUR
.pts
.org
;
6154 V
.curs
= CUR
.pts
.cur
;
6158 mask
= FT_Curve_Tag_Touch_Y
;
6159 V
.orgs
= (FT_Vector
*)( (FT_Pos
*)CUR
.pts
.org
+ 1 );
6160 V
.curs
= (FT_Vector
*)( (FT_Pos
*)CUR
.pts
.cur
+ 1 );
6168 end_point
= CUR
.pts
.contours
[contour
];
6169 first_point
= point
;
6171 while ( point
<= end_point
&& (CUR
.pts
.tags
[point
] & mask
) == 0 )
6174 if ( point
<= end_point
)
6176 first_touched
= point
;
6177 cur_touched
= point
;
6181 while ( point
<= end_point
)
6183 if ( ( CUR
.pts
.tags
[point
] & mask
) != 0 )
6186 Interp( cur_touched
+ 1,
6191 cur_touched
= point
;
6197 if ( cur_touched
== first_touched
)
6198 Shift( first_point
, end_point
, cur_touched
, &V
);
6201 Interp( (FT_UShort
)( cur_touched
+ 1 ),
6207 if ( first_touched
> 0 )
6208 Interp( first_point
,
6216 } while ( contour
< CUR
.pts
.n_contours
);
6220 /*************************************************************************/
6222 /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
6223 /* Opcode range: 0x5D,0x71,0x72 */
6224 /* Stack: uint32 (2 * uint32)... --> */
6227 Ins_DELTAP( INS_ARG
)
6235 nump
= (FT_ULong
)args
[0]; /* some points theoretically may occur more
6236 than once, thus UShort isn't enough */
6238 for ( k
= 1; k
<= nump
; k
++ )
6242 CUR
.error
= TT_Err_Too_Few_Arguments
;
6248 A
= (FT_UShort
)CUR
.stack
[CUR
.args
+ 1];
6249 B
= CUR
.stack
[CUR
.args
];
6251 /* XXX: Because some popular fonts contain some invalid DeltaP */
6252 /* instructions, we simply ignore them when the stacked */
6253 /* point reference is off limit, rather than returning an */
6254 /* error. As a delta instruction doesn't change a glyph */
6255 /* in great ways, this shouldn't be a problem. */
6257 if ( !BOUNDS( A
, CUR
.zp0
.n_points
) )
6259 C
= ( (FT_ULong
)B
& 0xF0 ) >> 4;
6261 switch ( CUR
.opcode
)
6275 C
+= CUR
.GS
.delta_base
;
6277 if ( CURRENT_Ppem() == (FT_Long
)C
)
6279 B
= ( (FT_ULong
)B
& 0xF ) - 8;
6282 B
= B
* 64 / ( 1L << CUR
.GS
.delta_shift
);
6284 CUR_Func_move( &CUR
.zp0
, A
, B
);
6288 if ( CUR
.pedantic_hinting
)
6289 CUR
.error
= TT_Err_Invalid_Reference
;
6292 CUR
.new_top
= CUR
.args
;
6296 /*************************************************************************/
6298 /* DELTACn[]: DELTA exceptions C1, C2, C3 */
6299 /* Opcode range: 0x73,0x74,0x75 */
6300 /* Stack: uint32 (2 * uint32)... --> */
6303 Ins_DELTAC( INS_ARG
)
6310 nump
= (FT_ULong
)args
[0];
6312 for ( k
= 1; k
<= nump
; k
++ )
6316 CUR
.error
= TT_Err_Too_Few_Arguments
;
6322 A
= (FT_ULong
)CUR
.stack
[CUR
.args
+ 1];
6323 B
= CUR
.stack
[CUR
.args
];
6325 if ( BOUNDS( A
, CUR
.cvtSize
) )
6327 if ( CUR
.pedantic_hinting
)
6329 CUR
.error
= TT_Err_Invalid_Reference
;
6335 C
= ( (FT_ULong
)B
& 0xF0 ) >> 4;
6337 switch ( CUR
.opcode
)
6351 C
+= CUR
.GS
.delta_base
;
6353 if ( CURRENT_Ppem() == (FT_Long
)C
)
6355 B
= ( (FT_ULong
)B
& 0xF ) - 8;
6358 B
= B
* 64 / ( 1L << CUR
.GS
.delta_shift
);
6360 CUR_Func_move_cvt( A
, B
);
6365 CUR
.new_top
= CUR
.args
;
6369 /*************************************************************************/
6371 /* MISC. INSTRUCTIONS */
6373 /*************************************************************************/
6376 /*************************************************************************/
6378 /* GETINFO[]: GET INFOrmation */
6379 /* Opcode range: 0x88 */
6380 /* Stack: uint32 --> uint32 */
6382 /* XXX: According to Apple specs, bits 1 & 2 of the argument ought to be */
6383 /* consulted before rotated/stretched info is returned. */
6385 Ins_GETINFO( INS_ARG
)
6392 /* We return then Windows 3.1 version number */
6393 /* for the font scaler */
6394 if ( ( args
[0] & 1 ) != 0 )
6397 /* Has the glyph been rotated ? */
6398 if ( CUR
.tt_metrics
.rotated
)
6401 /* Has the glyph been stretched ? */
6402 if ( CUR
.tt_metrics
.stretched
)
6410 Ins_UNKNOWN( INS_ARG
)
6412 TT_DefRecord
* def
= CUR
.IDefs
;
6413 TT_DefRecord
* limit
= def
+ CUR
.numIDefs
;
6418 for ( ; def
< limit
; def
++ )
6420 if ( (FT_Byte
)def
->opc
== CUR
.opcode
&& def
->active
)
6425 if ( CUR
.callTop
>= CUR
.callSize
)
6427 CUR
.error
= TT_Err_Stack_Overflow
;
6431 call
= CUR
.callStack
+ CUR
.callTop
++;
6433 call
->Caller_Range
= CUR
.curRange
;
6434 call
->Caller_IP
= CUR
.IP
+1;
6435 call
->Cur_Count
= 1;
6436 call
->Cur_Restart
= def
->start
;
6438 INS_Goto_CodeRange( def
->range
, def
->start
);
6440 CUR
.step_ins
= FALSE
;
6445 CUR
.error
= TT_Err_Invalid_Opcode
;
6449 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
6453 TInstruction_Function Instruct_Dispatch
[256] =
6455 /* Opcodes are gathered in groups of 16. */
6456 /* Please keep the spaces as they are. */
6458 /* SVTCA y */ Ins_SVTCA
,
6459 /* SVTCA x */ Ins_SVTCA
,
6460 /* SPvTCA y */ Ins_SPVTCA
,
6461 /* SPvTCA x */ Ins_SPVTCA
,
6462 /* SFvTCA y */ Ins_SFVTCA
,
6463 /* SFvTCA x */ Ins_SFVTCA
,
6464 /* SPvTL // */ Ins_SPVTL
,
6465 /* SPvTL + */ Ins_SPVTL
,
6466 /* SFvTL // */ Ins_SFVTL
,
6467 /* SFvTL + */ Ins_SFVTL
,
6468 /* SPvFS */ Ins_SPVFS
,
6469 /* SFvFS */ Ins_SFVFS
,
6472 /* SFvTPv */ Ins_SFVTPV
,
6473 /* ISECT */ Ins_ISECT
,
6475 /* SRP0 */ Ins_SRP0
,
6476 /* SRP1 */ Ins_SRP1
,
6477 /* SRP2 */ Ins_SRP2
,
6478 /* SZP0 */ Ins_SZP0
,
6479 /* SZP1 */ Ins_SZP1
,
6480 /* SZP2 */ Ins_SZP2
,
6481 /* SZPS */ Ins_SZPS
,
6482 /* SLOOP */ Ins_SLOOP
,
6484 /* RTHG */ Ins_RTHG
,
6486 /* ELSE */ Ins_ELSE
,
6487 /* JMPR */ Ins_JMPR
,
6488 /* SCvTCi */ Ins_SCVTCI
,
6489 /* SSwCi */ Ins_SSWCI
,
6494 /* CLEAR */ Ins_CLEAR
,
6495 /* SWAP */ Ins_SWAP
,
6496 /* DEPTH */ Ins_DEPTH
,
6497 /* CINDEX */ Ins_CINDEX
,
6498 /* MINDEX */ Ins_MINDEX
,
6499 /* AlignPTS */ Ins_ALIGNPTS
,
6500 /* INS_0x28 */ Ins_UNKNOWN
,
6502 /* LOOPCALL */ Ins_LOOPCALL
,
6503 /* CALL */ Ins_CALL
,
6504 /* FDEF */ Ins_FDEF
,
6505 /* ENDF */ Ins_ENDF
,
6506 /* MDAP[0] */ Ins_MDAP
,
6507 /* MDAP[1] */ Ins_MDAP
,
6509 /* IUP[0] */ Ins_IUP
,
6510 /* IUP[1] */ Ins_IUP
,
6511 /* SHP[0] */ Ins_SHP
,
6512 /* SHP[1] */ Ins_SHP
,
6513 /* SHC[0] */ Ins_SHC
,
6514 /* SHC[1] */ Ins_SHC
,
6515 /* SHZ[0] */ Ins_SHZ
,
6516 /* SHZ[1] */ Ins_SHZ
,
6517 /* SHPIX */ Ins_SHPIX
,
6519 /* MSIRP[0] */ Ins_MSIRP
,
6520 /* MSIRP[1] */ Ins_MSIRP
,
6521 /* AlignRP */ Ins_ALIGNRP
,
6522 /* RTDG */ Ins_RTDG
,
6523 /* MIAP[0] */ Ins_MIAP
,
6524 /* MIAP[1] */ Ins_MIAP
,
6526 /* NPushB */ Ins_NPUSHB
,
6527 /* NPushW */ Ins_NPUSHW
,
6530 /* WCvtP */ Ins_WCVTP
,
6531 /* RCvt */ Ins_RCVT
,
6534 /* SCFS */ Ins_SCFS
,
6537 /* MPPEM */ Ins_MPPEM
,
6539 /* FlipON */ Ins_FLIPON
,
6540 /* FlipOFF */ Ins_FLIPOFF
,
6541 /* DEBUG */ Ins_DEBUG
,
6544 /* LTEQ */ Ins_LTEQ
,
6546 /* GTEQ */ Ins_GTEQ
,
6550 /* EVEN */ Ins_EVEN
,
6556 /* DeltaP1 */ Ins_DELTAP
,
6566 /* FLOOR */ Ins_FLOOR
,
6567 /* CEILING */ Ins_CEILING
,
6568 /* ROUND[0] */ Ins_ROUND
,
6569 /* ROUND[1] */ Ins_ROUND
,
6570 /* ROUND[2] */ Ins_ROUND
,
6571 /* ROUND[3] */ Ins_ROUND
,
6572 /* NROUND[0] */ Ins_NROUND
,
6573 /* NROUND[1] */ Ins_NROUND
,
6574 /* NROUND[2] */ Ins_NROUND
,
6575 /* NROUND[3] */ Ins_NROUND
,
6577 /* WCvtF */ Ins_WCVTF
,
6578 /* DeltaP2 */ Ins_DELTAP
,
6579 /* DeltaP3 */ Ins_DELTAP
,
6580 /* DeltaCn[0] */ Ins_DELTAC
,
6581 /* DeltaCn[1] */ Ins_DELTAC
,
6582 /* DeltaCn[2] */ Ins_DELTAC
,
6583 /* SROUND */ Ins_SROUND
,
6584 /* S45Round */ Ins_S45ROUND
,
6585 /* JROT */ Ins_JROT
,
6586 /* JROF */ Ins_JROF
,
6587 /* ROFF */ Ins_ROFF
,
6588 /* INS_0x7B */ Ins_UNKNOWN
,
6589 /* RUTG */ Ins_RUTG
,
6590 /* RDTG */ Ins_RDTG
,
6591 /* SANGW */ Ins_SANGW
,
6594 /* FlipPT */ Ins_FLIPPT
,
6595 /* FlipRgON */ Ins_FLIPRGON
,
6596 /* FlipRgOFF */ Ins_FLIPRGOFF
,
6597 /* INS_0x83 */ Ins_UNKNOWN
,
6598 /* INS_0x84 */ Ins_UNKNOWN
,
6599 /* ScanCTRL */ Ins_SCANCTRL
,
6600 /* SDPVTL[0] */ Ins_SDPVTL
,
6601 /* SDPVTL[1] */ Ins_SDPVTL
,
6602 /* GetINFO */ Ins_GETINFO
,
6603 /* IDEF */ Ins_IDEF
,
6604 /* ROLL */ Ins_ROLL
,
6607 /* ScanTYPE */ Ins_SCANTYPE
,
6608 /* InstCTRL */ Ins_INSTCTRL
,
6609 /* INS_0x8F */ Ins_UNKNOWN
,
6611 /* INS_0x90 */ Ins_UNKNOWN
,
6612 /* INS_0x91 */ Ins_UNKNOWN
,
6613 /* INS_0x92 */ Ins_UNKNOWN
,
6614 /* INS_0x93 */ Ins_UNKNOWN
,
6615 /* INS_0x94 */ Ins_UNKNOWN
,
6616 /* INS_0x95 */ Ins_UNKNOWN
,
6617 /* INS_0x96 */ Ins_UNKNOWN
,
6618 /* INS_0x97 */ Ins_UNKNOWN
,
6619 /* INS_0x98 */ Ins_UNKNOWN
,
6620 /* INS_0x99 */ Ins_UNKNOWN
,
6621 /* INS_0x9A */ Ins_UNKNOWN
,
6622 /* INS_0x9B */ Ins_UNKNOWN
,
6623 /* INS_0x9C */ Ins_UNKNOWN
,
6624 /* INS_0x9D */ Ins_UNKNOWN
,
6625 /* INS_0x9E */ Ins_UNKNOWN
,
6626 /* INS_0x9F */ Ins_UNKNOWN
,
6628 /* INS_0xA0 */ Ins_UNKNOWN
,
6629 /* INS_0xA1 */ Ins_UNKNOWN
,
6630 /* INS_0xA2 */ Ins_UNKNOWN
,
6631 /* INS_0xA3 */ Ins_UNKNOWN
,
6632 /* INS_0xA4 */ Ins_UNKNOWN
,
6633 /* INS_0xA5 */ Ins_UNKNOWN
,
6634 /* INS_0xA6 */ Ins_UNKNOWN
,
6635 /* INS_0xA7 */ Ins_UNKNOWN
,
6636 /* INS_0xA8 */ Ins_UNKNOWN
,
6637 /* INS_0xA9 */ Ins_UNKNOWN
,
6638 /* INS_0xAA */ Ins_UNKNOWN
,
6639 /* INS_0xAB */ Ins_UNKNOWN
,
6640 /* INS_0xAC */ Ins_UNKNOWN
,
6641 /* INS_0xAD */ Ins_UNKNOWN
,
6642 /* INS_0xAE */ Ins_UNKNOWN
,
6643 /* INS_0xAF */ Ins_UNKNOWN
,
6645 /* PushB[0] */ Ins_PUSHB
,
6646 /* PushB[1] */ Ins_PUSHB
,
6647 /* PushB[2] */ Ins_PUSHB
,
6648 /* PushB[3] */ Ins_PUSHB
,
6649 /* PushB[4] */ Ins_PUSHB
,
6650 /* PushB[5] */ Ins_PUSHB
,
6651 /* PushB[6] */ Ins_PUSHB
,
6652 /* PushB[7] */ Ins_PUSHB
,
6653 /* PushW[0] */ Ins_PUSHW
,
6654 /* PushW[1] */ Ins_PUSHW
,
6655 /* PushW[2] */ Ins_PUSHW
,
6656 /* PushW[3] */ Ins_PUSHW
,
6657 /* PushW[4] */ Ins_PUSHW
,
6658 /* PushW[5] */ Ins_PUSHW
,
6659 /* PushW[6] */ Ins_PUSHW
,
6660 /* PushW[7] */ Ins_PUSHW
,
6662 /* MDRP[00] */ Ins_MDRP
,
6663 /* MDRP[01] */ Ins_MDRP
,
6664 /* MDRP[02] */ Ins_MDRP
,
6665 /* MDRP[03] */ Ins_MDRP
,
6666 /* MDRP[04] */ Ins_MDRP
,
6667 /* MDRP[05] */ Ins_MDRP
,
6668 /* MDRP[06] */ Ins_MDRP
,
6669 /* MDRP[07] */ Ins_MDRP
,
6670 /* MDRP[08] */ Ins_MDRP
,
6671 /* MDRP[09] */ Ins_MDRP
,
6672 /* MDRP[10] */ Ins_MDRP
,
6673 /* MDRP[11] */ Ins_MDRP
,
6674 /* MDRP[12] */ Ins_MDRP
,
6675 /* MDRP[13] */ Ins_MDRP
,
6676 /* MDRP[14] */ Ins_MDRP
,
6677 /* MDRP[15] */ Ins_MDRP
,
6679 /* MDRP[16] */ Ins_MDRP
,
6680 /* MDRP[17] */ Ins_MDRP
,
6681 /* MDRP[18] */ Ins_MDRP
,
6682 /* MDRP[19] */ Ins_MDRP
,
6683 /* MDRP[20] */ Ins_MDRP
,
6684 /* MDRP[21] */ Ins_MDRP
,
6685 /* MDRP[22] */ Ins_MDRP
,
6686 /* MDRP[23] */ Ins_MDRP
,
6687 /* MDRP[24] */ Ins_MDRP
,
6688 /* MDRP[25] */ Ins_MDRP
,
6689 /* MDRP[26] */ Ins_MDRP
,
6690 /* MDRP[27] */ Ins_MDRP
,
6691 /* MDRP[28] */ Ins_MDRP
,
6692 /* MDRP[29] */ Ins_MDRP
,
6693 /* MDRP[30] */ Ins_MDRP
,
6694 /* MDRP[31] */ Ins_MDRP
,
6696 /* MIRP[00] */ Ins_MIRP
,
6697 /* MIRP[01] */ Ins_MIRP
,
6698 /* MIRP[02] */ Ins_MIRP
,
6699 /* MIRP[03] */ Ins_MIRP
,
6700 /* MIRP[04] */ Ins_MIRP
,
6701 /* MIRP[05] */ Ins_MIRP
,
6702 /* MIRP[06] */ Ins_MIRP
,
6703 /* MIRP[07] */ Ins_MIRP
,
6704 /* MIRP[08] */ Ins_MIRP
,
6705 /* MIRP[09] */ Ins_MIRP
,
6706 /* MIRP[10] */ Ins_MIRP
,
6707 /* MIRP[11] */ Ins_MIRP
,
6708 /* MIRP[12] */ Ins_MIRP
,
6709 /* MIRP[13] */ Ins_MIRP
,
6710 /* MIRP[14] */ Ins_MIRP
,
6711 /* MIRP[15] */ Ins_MIRP
,
6713 /* MIRP[16] */ Ins_MIRP
,
6714 /* MIRP[17] */ Ins_MIRP
,
6715 /* MIRP[18] */ Ins_MIRP
,
6716 /* MIRP[19] */ Ins_MIRP
,
6717 /* MIRP[20] */ Ins_MIRP
,
6718 /* MIRP[21] */ Ins_MIRP
,
6719 /* MIRP[22] */ Ins_MIRP
,
6720 /* MIRP[23] */ Ins_MIRP
,
6721 /* MIRP[24] */ Ins_MIRP
,
6722 /* MIRP[25] */ Ins_MIRP
,
6723 /* MIRP[26] */ Ins_MIRP
,
6724 /* MIRP[27] */ Ins_MIRP
,
6725 /* MIRP[28] */ Ins_MIRP
,
6726 /* MIRP[29] */ Ins_MIRP
,
6727 /* MIRP[30] */ Ins_MIRP
,
6728 /* MIRP[31] */ Ins_MIRP
6732 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
6735 /*************************************************************************/
6739 /* This function executes a run of opcodes. It will exit in the */
6740 /* following cases: */
6742 /* - Errors (in which case it returns FALSE). */
6744 /* - Reaching the end of the main code range (returns TRUE). */
6745 /* Reaching the end of a code range within a function call is an */
6748 /* - After executing one single opcode, if the flag `Instruction_Trap' */
6749 /* is set to TRUE (returns TRUE). */
6751 /* On exit whith TRUE, test IP < CodeSize to know wether it comes from */
6752 /* an instruction trap or a normal termination. */
6755 /* Note: The documented DEBUG opcode pops a value from the stack. This */
6756 /* behaviour is unsupported; here a DEBUG opcode is always an */
6760 /* THIS IS THE INTERPRETER'S MAIN LOOP. */
6762 /* Instructions appear in the specification's order. */
6764 /*************************************************************************/
6767 /* documentation is in ttinterp.h */
6769 FT_EXPORT_DEF( FT_Error
)
6770 TT_RunIns( TT_ExecContext exc
)
6772 FT_Long ins_counter
= 0; /* executed instructions counter */
6775 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
6779 /* set CVT functions */
6780 CUR
.tt_metrics
.ratio
= 0;
6781 if ( CUR
.metrics
.x_ppem
!= CUR
.metrics
.y_ppem
)
6783 /* non-square pixels, use the stretched routines */
6784 CUR
.func_read_cvt
= Read_CVT_Stretched
;
6785 CUR
.func_write_cvt
= Write_CVT_Stretched
;
6786 CUR
.func_move_cvt
= Move_CVT_Stretched
;
6790 /* square pixels, use normal routines */
6791 CUR
.func_read_cvt
= Read_CVT
;
6792 CUR
.func_write_cvt
= Write_CVT
;
6793 CUR
.func_move_cvt
= Move_CVT
;
6797 COMPUTE_Round( (FT_Byte
)exc
->GS
.round_state
);
6801 CUR
.opcode
= CUR
.code
[CUR
.IP
];
6803 if ( ( CUR
.length
= opcode_length
[CUR
.opcode
] ) < 0 )
6805 if ( CUR
.IP
+ 1 > CUR
.codeSize
)
6806 goto LErrorCodeOverflow_
;
6808 CUR
.length
= CUR
.code
[CUR
.IP
+ 1] + 2;
6811 if ( CUR
.IP
+ CUR
.length
> CUR
.codeSize
)
6812 goto LErrorCodeOverflow_
;
6814 /* First, let's check for empty stack and overflow */
6815 CUR
.args
= CUR
.top
- ( Pop_Push_Count
[CUR
.opcode
] >> 4 );
6817 /* `args' is the top of the stack once arguments have been popped. */
6818 /* One can also interpret it as the index of the last argument. */
6821 CUR
.error
= TT_Err_Too_Few_Arguments
;
6825 CUR
.new_top
= CUR
.args
+ ( Pop_Push_Count
[CUR
.opcode
] & 15 );
6827 /* `new_top' is the new top of the stack, after the instruction's */
6828 /* execution. `top' will be set to `new_top' after the `switch' */
6830 if ( CUR
.new_top
> CUR
.stackSize
)
6832 CUR
.error
= TT_Err_Stack_Overflow
;
6836 CUR
.step_ins
= TRUE
;
6837 CUR
.error
= TT_Err_Ok
;
6839 #ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
6842 FT_Long
* args
= CUR
.stack
+ CUR
.args
;
6843 FT_Byte opcode
= CUR
.opcode
;
6846 #undef ARRAY_BOUND_ERROR
6847 #define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
6852 case 0x00: /* SVTCA y */
6853 case 0x01: /* SVTCA x */
6854 case 0x02: /* SPvTCA y */
6855 case 0x03: /* SPvTCA x */
6856 case 0x04: /* SFvTCA y */
6857 case 0x05: /* SFvTCA x */
6862 AA
= (FT_Short
)( ( opcode
& 1 ) << 14 );
6863 BB
= (FT_Short
)( AA
^ 0x4000 );
6867 CUR
.GS
.projVector
.x
= AA
;
6868 CUR
.GS
.projVector
.y
= BB
;
6870 CUR
.GS
.dualVector
.x
= AA
;
6871 CUR
.GS
.dualVector
.y
= BB
;
6874 if ( ( opcode
& 2 ) == 0 )
6876 CUR
.GS
.freeVector
.x
= AA
;
6877 CUR
.GS
.freeVector
.y
= BB
;
6884 case 0x06: /* SPvTL // */
6885 case 0x07: /* SPvTL + */
6889 case 0x08: /* SFvTL // */
6890 case 0x09: /* SFvTL + */
6894 case 0x0A: /* SPvFS */
6898 case 0x0B: /* SFvFS */
6902 case 0x0C: /* GPV */
6906 case 0x0D: /* GFV */
6910 case 0x0E: /* SFvTPv */
6914 case 0x0F: /* ISECT */
6915 Ins_ISECT( EXEC_ARG_ args
);
6918 case 0x10: /* SRP0 */
6922 case 0x11: /* SRP1 */
6926 case 0x12: /* SRP2 */
6930 case 0x13: /* SZP0 */
6931 Ins_SZP0( EXEC_ARG_ args
);
6934 case 0x14: /* SZP1 */
6935 Ins_SZP1( EXEC_ARG_ args
);
6938 case 0x15: /* SZP2 */
6939 Ins_SZP2( EXEC_ARG_ args
);
6942 case 0x16: /* SZPS */
6943 Ins_SZPS( EXEC_ARG_ args
);
6946 case 0x17: /* SLOOP */
6950 case 0x18: /* RTG */
6954 case 0x19: /* RTHG */
6958 case 0x1A: /* SMD */
6962 case 0x1B: /* ELSE */
6963 Ins_ELSE( EXEC_ARG_ args
);
6966 case 0x1C: /* JMPR */
6970 case 0x1D: /* SCVTCI */
6974 case 0x1E: /* SSWCI */
6978 case 0x1F: /* SSW */
6982 case 0x20: /* DUP */
6986 case 0x21: /* POP */
6990 case 0x22: /* CLEAR */
6994 case 0x23: /* SWAP */
6998 case 0x24: /* DEPTH */
7002 case 0x25: /* CINDEX */
7006 case 0x26: /* MINDEX */
7007 Ins_MINDEX( EXEC_ARG_ args
);
7010 case 0x27: /* ALIGNPTS */
7011 Ins_ALIGNPTS( EXEC_ARG_ args
);
7014 case 0x28: /* ???? */
7015 Ins_UNKNOWN( EXEC_ARG_ args
);
7018 case 0x29: /* UTP */
7019 Ins_UTP( EXEC_ARG_ args
);
7022 case 0x2A: /* LOOPCALL */
7023 Ins_LOOPCALL( EXEC_ARG_ args
);
7026 case 0x2B: /* CALL */
7027 Ins_CALL( EXEC_ARG_ args
);
7030 case 0x2C: /* FDEF */
7031 Ins_FDEF( EXEC_ARG_ args
);
7034 case 0x2D: /* ENDF */
7035 Ins_ENDF( EXEC_ARG_ args
);
7038 case 0x2E: /* MDAP */
7039 case 0x2F: /* MDAP */
7040 Ins_MDAP( EXEC_ARG_ args
);
7044 case 0x30: /* IUP */
7045 case 0x31: /* IUP */
7046 Ins_IUP( EXEC_ARG_ args
);
7049 case 0x32: /* SHP */
7050 case 0x33: /* SHP */
7051 Ins_SHP( EXEC_ARG_ args
);
7054 case 0x34: /* SHC */
7055 case 0x35: /* SHC */
7056 Ins_SHC( EXEC_ARG_ args
);
7059 case 0x36: /* SHZ */
7060 case 0x37: /* SHZ */
7061 Ins_SHZ( EXEC_ARG_ args
);
7064 case 0x38: /* SHPIX */
7065 Ins_SHPIX( EXEC_ARG_ args
);
7069 Ins_IP( EXEC_ARG_ args
);
7072 case 0x3A: /* MSIRP */
7073 case 0x3B: /* MSIRP */
7074 Ins_MSIRP( EXEC_ARG_ args
);
7077 case 0x3C: /* AlignRP */
7078 Ins_ALIGNRP( EXEC_ARG_ args
);
7081 case 0x3D: /* RTDG */
7085 case 0x3E: /* MIAP */
7086 case 0x3F: /* MIAP */
7087 Ins_MIAP( EXEC_ARG_ args
);
7090 case 0x40: /* NPUSHB */
7091 Ins_NPUSHB( EXEC_ARG_ args
);
7094 case 0x41: /* NPUSHW */
7095 Ins_NPUSHW( EXEC_ARG_ args
);
7103 CUR
.error
= TT_Err_Invalid_Reference
;
7110 case 0x44: /* WCVTP */
7114 case 0x45: /* RCVT */
7120 Ins_GC( EXEC_ARG_ args
);
7123 case 0x48: /* SCFS */
7124 Ins_SCFS( EXEC_ARG_ args
);
7129 Ins_MD( EXEC_ARG_ args
);
7132 case 0x4B: /* MPPEM */
7136 case 0x4C: /* MPS */
7140 case 0x4D: /* FLIPON */
7144 case 0x4E: /* FLIPOFF */
7148 case 0x4F: /* DEBUG */
7156 case 0x51: /* LTEQ */
7164 case 0x53: /* GTEQ */
7172 case 0x55: /* NEQ */
7176 case 0x56: /* ODD */
7180 case 0x57: /* EVEN */
7185 Ins_IF( EXEC_ARG_ args
);
7188 case 0x59: /* EIF */
7192 case 0x5A: /* AND */
7200 case 0x5C: /* NOT */
7204 case 0x5D: /* DELTAP1 */
7205 Ins_DELTAP( EXEC_ARG_ args
);
7208 case 0x5E: /* SDB */
7212 case 0x5F: /* SDS */
7216 case 0x60: /* ADD */
7220 case 0x61: /* SUB */
7224 case 0x62: /* DIV */
7228 case 0x63: /* MUL */
7232 case 0x64: /* ABS */
7236 case 0x65: /* NEG */
7240 case 0x66: /* FLOOR */
7244 case 0x67: /* CEILING */
7248 case 0x68: /* ROUND */
7249 case 0x69: /* ROUND */
7250 case 0x6A: /* ROUND */
7251 case 0x6B: /* ROUND */
7255 case 0x6C: /* NROUND */
7256 case 0x6D: /* NROUND */
7257 case 0x6E: /* NRRUND */
7258 case 0x6F: /* NROUND */
7262 case 0x70: /* WCVTF */
7266 case 0x71: /* DELTAP2 */
7267 case 0x72: /* DELTAP3 */
7268 Ins_DELTAP( EXEC_ARG_ args
);
7271 case 0x73: /* DELTAC0 */
7272 case 0x74: /* DELTAC1 */
7273 case 0x75: /* DELTAC2 */
7274 Ins_DELTAC( EXEC_ARG_ args
);
7277 case 0x76: /* SROUND */
7281 case 0x77: /* S45Round */
7285 case 0x78: /* JROT */
7289 case 0x79: /* JROF */
7293 case 0x7A: /* ROFF */
7297 case 0x7B: /* ???? */
7298 Ins_UNKNOWN( EXEC_ARG_ args
);
7301 case 0x7C: /* RUTG */
7305 case 0x7D: /* RDTG */
7309 case 0x7E: /* SANGW */
7311 /* nothing - obsolete */
7314 case 0x80: /* FLIPPT */
7315 Ins_FLIPPT( EXEC_ARG_ args
);
7318 case 0x81: /* FLIPRGON */
7319 Ins_FLIPRGON( EXEC_ARG_ args
);
7322 case 0x82: /* FLIPRGOFF */
7323 Ins_FLIPRGOFF( EXEC_ARG_ args
);
7326 case 0x83: /* UNKNOWN */
7327 case 0x84: /* UNKNOWN */
7328 Ins_UNKNOWN( EXEC_ARG_ args
);
7331 case 0x85: /* SCANCTRL */
7332 Ins_SCANCTRL( EXEC_ARG_ args
);
7335 case 0x86: /* SDPVTL */
7336 case 0x87: /* SDPVTL */
7337 Ins_SDPVTL( EXEC_ARG_ args
);
7340 case 0x88: /* GETINFO */
7341 Ins_GETINFO( EXEC_ARG_ args
);
7344 case 0x89: /* IDEF */
7345 Ins_IDEF( EXEC_ARG_ args
);
7348 case 0x8A: /* ROLL */
7349 Ins_ROLL( EXEC_ARG_ args
);
7352 case 0x8B: /* MAX */
7356 case 0x8C: /* MIN */
7360 case 0x8D: /* SCANTYPE */
7361 Ins_SCANTYPE( EXEC_ARG_ args
);
7364 case 0x8E: /* INSTCTRL */
7365 Ins_INSTCTRL( EXEC_ARG_ args
);
7369 Ins_UNKNOWN( EXEC_ARG_ args
);
7373 if ( opcode
>= 0xE0 )
7374 Ins_MIRP( EXEC_ARG_ args
);
7375 else if ( opcode
>= 0xC0 )
7376 Ins_MDRP( EXEC_ARG_ args
);
7377 else if ( opcode
>= 0xB8 )
7378 Ins_PUSHW( EXEC_ARG_ args
);
7379 else if ( opcode
>= 0xB0 )
7380 Ins_PUSHB( EXEC_ARG_ args
);
7382 Ins_UNKNOWN( EXEC_ARG_ args
);
7389 Instruct_Dispatch
[CUR
.opcode
]( EXEC_ARG_
&CUR
.stack
[CUR
.args
] );
7391 #endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7393 if ( CUR
.error
!= TT_Err_Ok
)
7395 switch ( CUR
.error
)
7397 case TT_Err_Invalid_Opcode
: /* looking for redefined instructions */
7399 TT_DefRecord
* def
= CUR
.IDefs
;
7400 TT_DefRecord
* limit
= def
+ CUR
.numIDefs
;
7403 for ( ; def
< limit
; def
++ )
7405 if ( def
->active
&& CUR
.opcode
== (FT_Byte
)def
->opc
)
7407 TT_CallRec
* callrec
;
7410 if ( CUR
.callTop
>= CUR
.callSize
)
7412 CUR
.error
= TT_Err_Invalid_Reference
;
7416 callrec
= &CUR
.callStack
[CUR
.callTop
];
7418 callrec
->Caller_Range
= CUR
.curRange
;
7419 callrec
->Caller_IP
= CUR
.IP
+ 1;
7420 callrec
->Cur_Count
= 1;
7421 callrec
->Cur_Restart
= def
->start
;
7423 if ( INS_Goto_CodeRange( def
->range
, def
->start
) == FAILURE
)
7431 CUR
.error
= TT_Err_Invalid_Opcode
;
7435 break; /* Unreachable code warning suppression. */
7436 /* Leave to remind in case a later change the editor */
7437 /* to consider break; */
7449 CUR
.top
= CUR
.new_top
;
7452 CUR
.IP
+= CUR
.length
;
7454 /* increment instruction counter and check if we didn't */
7455 /* run this program for too long (e.g. infinite loops). */
7456 if ( ++ins_counter
> MAX_RUNNABLE_OPCODES
)
7457 return TT_Err_Execution_Too_Long
;
7460 if ( CUR
.IP
>= CUR
.codeSize
)
7462 if ( CUR
.callTop
> 0 )
7464 CUR
.error
= TT_Err_Code_Overflow
;
7470 } while ( !CUR
.instruction_trap
);
7474 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7480 LErrorCodeOverflow_
:
7481 CUR
.error
= TT_Err_Code_Overflow
;
7485 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7493 #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */