Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / modules / freetype2 / src / truetype / ttinterp.c
blob2ab0c0940e3ccee585db4ff55b0be96b1b798813
1 /***************************************************************************/
2 /* */
3 /* ttinterp.c */
4 /* */
5 /* TrueType bytecode interpreter (body). */
6 /* */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
9 /* */
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. */
15 /* */
16 /***************************************************************************/
19 #include <ft2build.h>
20 #include FT_INTERNAL_DEBUG_H
21 #include FT_INTERNAL_CALC_H
22 #include FT_TRIGONOMETRY_H
23 #include FT_SYSTEM_H
25 #include "ttinterp.h"
27 #include "tterrors.h"
30 #ifdef TT_USE_BYTECODE_INTERPRETER
33 #define TT_MULFIX FT_MulFix
34 #define TT_MULDIV FT_MulDiv
35 #define TT_MULDIV_NO_ROUND FT_MulDiv_No_Round
38 /*************************************************************************/
39 /* */
40 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
41 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
42 /* messages during execution. */
43 /* */
44 #undef FT_COMPONENT
45 #define FT_COMPONENT trace_ttinterp
47 /*************************************************************************/
48 /* */
49 /* In order to detect infinite loops in the code, we set up a counter */
50 /* within the run loop. A single stroke of interpretation is now */
51 /* limited to a maximal number of opcodes defined below. */
52 /* */
53 #define MAX_RUNNABLE_OPCODES 1000000L
56 /*************************************************************************/
57 /* */
58 /* There are two kinds of implementations: */
59 /* */
60 /* a. static implementation */
61 /* */
62 /* The current execution context is a static variable, which fields */
63 /* are accessed directly by the interpreter during execution. The */
64 /* context is named `cur'. */
65 /* */
66 /* This version is non-reentrant, of course. */
67 /* */
68 /* b. indirect implementation */
69 /* */
70 /* The current execution context is passed to _each_ function as its */
71 /* first argument, and each field is thus accessed indirectly. */
72 /* */
73 /* This version is fully re-entrant. */
74 /* */
75 /* The idea is that an indirect implementation may be slower to execute */
76 /* on low-end processors that are used in some systems (like 386s or */
77 /* even 486s). */
78 /* */
79 /* As a consequence, the indirect implementation is now the default, as */
80 /* its performance costs can be considered negligible in our context. */
81 /* Note, however, that we kept the same source with macros because: */
82 /* */
83 /* - The code is kept very close in design to the Pascal code used for */
84 /* development. */
85 /* */
86 /* - It's much more readable that way! */
87 /* */
88 /* - It's still open to experimentation and tuning. */
89 /* */
90 /*************************************************************************/
93 #ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */
95 #define CUR (*exc) /* see ttobjs.h */
97 /*************************************************************************/
98 /* */
99 /* This macro is used whenever `exec' is unused in a function, to avoid */
100 /* stupid warnings from pedantic compilers. */
101 /* */
102 #define FT_UNUSED_EXEC FT_UNUSED( exc )
104 #else /* static implementation */
106 #define CUR cur
108 #define FT_UNUSED_EXEC int __dummy = __dummy
110 static
111 TT_ExecContextRec cur; /* static exec. context variable */
113 /* apparently, we have a _lot_ of direct indexing when accessing */
114 /* the static `cur', which makes the code bigger (due to all the */
115 /* four bytes addresses). */
117 #endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
120 /*************************************************************************/
121 /* */
122 /* The instruction argument stack. */
123 /* */
124 #define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */
127 /*************************************************************************/
128 /* */
129 /* This macro is used whenever `args' is unused in a function, to avoid */
130 /* stupid warnings from pedantic compilers. */
131 /* */
132 #define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args )
135 /*************************************************************************/
136 /* */
137 /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */
138 /* increase readability of the code. */
139 /* */
140 /*************************************************************************/
143 #define SKIP_Code() \
144 SkipCode( EXEC_ARG )
146 #define GET_ShortIns() \
147 GetShortIns( EXEC_ARG )
149 #define NORMalize( x, y, v ) \
150 Normalize( EXEC_ARG_ x, y, v )
152 #define SET_SuperRound( scale, flags ) \
153 SetSuperRound( EXEC_ARG_ scale, flags )
155 #define ROUND_None( d, c ) \
156 Round_None( EXEC_ARG_ d, c )
158 #define INS_Goto_CodeRange( range, ip ) \
159 Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
161 #define CUR_Func_move( z, p, d ) \
162 CUR.func_move( EXEC_ARG_ z, p, d )
164 #define CUR_Func_move_orig( z, p, d ) \
165 CUR.func_move_orig( EXEC_ARG_ z, p, d )
167 #define CUR_Func_round( d, c ) \
168 CUR.func_round( EXEC_ARG_ d, c )
170 #define CUR_Func_read_cvt( index ) \
171 CUR.func_read_cvt( EXEC_ARG_ index )
173 #define CUR_Func_write_cvt( index, val ) \
174 CUR.func_write_cvt( EXEC_ARG_ index, val )
176 #define CUR_Func_move_cvt( index, val ) \
177 CUR.func_move_cvt( EXEC_ARG_ index, val )
179 #define CURRENT_Ratio() \
180 Current_Ratio( EXEC_ARG )
182 #define CURRENT_Ppem() \
183 Current_Ppem( EXEC_ARG )
185 #define CUR_Ppem() \
186 Cur_PPEM( EXEC_ARG )
188 #define INS_SxVTL( a, b, c, d ) \
189 Ins_SxVTL( EXEC_ARG_ a, b, c, d )
191 #define COMPUTE_Funcs() \
192 Compute_Funcs( EXEC_ARG )
194 #define COMPUTE_Round( a ) \
195 Compute_Round( EXEC_ARG_ a )
197 #define COMPUTE_Point_Displacement( a, b, c, d ) \
198 Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
200 #define MOVE_Zp2_Point( a, b, c, t ) \
201 Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
204 #define CUR_Func_project( v1, v2 ) \
205 CUR.func_project( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
207 #define CUR_Func_dualproj( v1, v2 ) \
208 CUR.func_dualproj( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
210 #define CUR_fast_project( v ) \
211 CUR.func_project( EXEC_ARG_ (v)->x, (v)->y )
213 #define CUR_fast_dualproj( v ) \
214 CUR.func_dualproj( EXEC_ARG_ (v)->x, (v)->y )
217 /*************************************************************************/
218 /* */
219 /* Instruction dispatch function, as used by the interpreter. */
220 /* */
221 typedef void (*TInstruction_Function)( INS_ARG );
224 /*************************************************************************/
225 /* */
226 /* A simple bounds-checking macro. */
227 /* */
228 #define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
230 #undef SUCCESS
231 #define SUCCESS 0
233 #undef FAILURE
234 #define FAILURE 1
236 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
237 #define GUESS_VECTOR( V ) \
238 if ( CUR.face->unpatented_hinting ) \
240 CUR.GS.V.x = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0x4000 : 0 ); \
241 CUR.GS.V.y = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0 : 0x4000 ); \
243 #else
244 #define GUESS_VECTOR( V )
245 #endif
247 /*************************************************************************/
248 /* */
249 /* CODERANGE FUNCTIONS */
250 /* */
251 /*************************************************************************/
254 /*************************************************************************/
255 /* */
256 /* <Function> */
257 /* TT_Goto_CodeRange */
258 /* */
259 /* <Description> */
260 /* Switches to a new code range (updates the code related elements in */
261 /* `exec', and `IP'). */
262 /* */
263 /* <Input> */
264 /* range :: The new execution code range. */
265 /* */
266 /* IP :: The new IP in the new code range. */
267 /* */
268 /* <InOut> */
269 /* exec :: The target execution context. */
270 /* */
271 /* <Return> */
272 /* FreeType error code. 0 means success. */
273 /* */
274 FT_LOCAL_DEF( FT_Error )
275 TT_Goto_CodeRange( TT_ExecContext exec,
276 FT_Int range,
277 FT_Long IP )
279 TT_CodeRange* coderange;
282 FT_ASSERT( range >= 1 && range <= 3 );
284 coderange = &exec->codeRangeTable[range - 1];
286 FT_ASSERT( coderange->base != NULL );
288 /* NOTE: Because the last instruction of a program may be a CALL */
289 /* which will return to the first byte *after* the code */
290 /* range, we test for IP <= Size instead of IP < Size. */
291 /* */
292 FT_ASSERT( (FT_ULong)IP <= coderange->size );
294 exec->code = coderange->base;
295 exec->codeSize = coderange->size;
296 exec->IP = IP;
297 exec->curRange = range;
299 return TT_Err_Ok;
303 /*************************************************************************/
304 /* */
305 /* <Function> */
306 /* TT_Set_CodeRange */
307 /* */
308 /* <Description> */
309 /* Sets a code range. */
310 /* */
311 /* <Input> */
312 /* range :: The code range index. */
313 /* */
314 /* base :: The new code base. */
315 /* */
316 /* length :: The range size in bytes. */
317 /* */
318 /* <InOut> */
319 /* exec :: The target execution context. */
320 /* */
321 /* <Return> */
322 /* FreeType error code. 0 means success. */
323 /* */
324 FT_LOCAL_DEF( FT_Error )
325 TT_Set_CodeRange( TT_ExecContext exec,
326 FT_Int range,
327 void* base,
328 FT_Long length )
330 FT_ASSERT( range >= 1 && range <= 3 );
332 exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
333 exec->codeRangeTable[range - 1].size = length;
335 return TT_Err_Ok;
339 /*************************************************************************/
340 /* */
341 /* <Function> */
342 /* TT_Clear_CodeRange */
343 /* */
344 /* <Description> */
345 /* Clears a code range. */
346 /* */
347 /* <Input> */
348 /* range :: The code range index. */
349 /* */
350 /* <InOut> */
351 /* exec :: The target execution context. */
352 /* */
353 /* <Return> */
354 /* FreeType error code. 0 means success. */
355 /* */
356 /* <Note> */
357 /* Does not set the Error variable. */
358 /* */
359 FT_LOCAL_DEF( FT_Error )
360 TT_Clear_CodeRange( TT_ExecContext exec,
361 FT_Int range )
363 FT_ASSERT( range >= 1 && range <= 3 );
365 exec->codeRangeTable[range - 1].base = NULL;
366 exec->codeRangeTable[range - 1].size = 0;
368 return TT_Err_Ok;
372 /*************************************************************************/
373 /* */
374 /* EXECUTION CONTEXT ROUTINES */
375 /* */
376 /*************************************************************************/
379 /*************************************************************************/
380 /* */
381 /* <Function> */
382 /* TT_Done_Context */
383 /* */
384 /* <Description> */
385 /* Destroys a given context. */
386 /* */
387 /* <Input> */
388 /* exec :: A handle to the target execution context. */
389 /* */
390 /* memory :: A handle to the parent memory object. */
391 /* */
392 /* <Return> */
393 /* FreeType error code. 0 means success. */
394 /* */
395 /* <Note> */
396 /* Only the glyph loader and debugger should call this function. */
397 /* */
398 FT_LOCAL_DEF( FT_Error )
399 TT_Done_Context( TT_ExecContext exec )
401 FT_Memory memory = exec->memory;
404 /* points zone */
405 exec->maxPoints = 0;
406 exec->maxContours = 0;
408 /* free stack */
409 FT_FREE( exec->stack );
410 exec->stackSize = 0;
412 /* free call stack */
413 FT_FREE( exec->callStack );
414 exec->callSize = 0;
415 exec->callTop = 0;
417 /* free glyph code range */
418 FT_FREE( exec->glyphIns );
419 exec->glyphSize = 0;
421 exec->size = NULL;
422 exec->face = NULL;
424 FT_FREE( exec );
426 return TT_Err_Ok;
430 /*************************************************************************/
431 /* */
432 /* <Function> */
433 /* Init_Context */
434 /* */
435 /* <Description> */
436 /* Initializes a context object. */
437 /* */
438 /* <Input> */
439 /* memory :: A handle to the parent memory object. */
440 /* */
441 /* <InOut> */
442 /* exec :: A handle to the target execution context. */
443 /* */
444 /* <Return> */
445 /* FreeType error code. 0 means success. */
446 /* */
447 static FT_Error
448 Init_Context( TT_ExecContext exec,
449 FT_Memory memory )
451 FT_Error error;
454 FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec ));
456 exec->memory = memory;
457 exec->callSize = 32;
459 if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )
460 goto Fail_Memory;
462 /* all values in the context are set to 0 already, but this is */
463 /* here as a remainder */
464 exec->maxPoints = 0;
465 exec->maxContours = 0;
467 exec->stackSize = 0;
468 exec->glyphSize = 0;
470 exec->stack = NULL;
471 exec->glyphIns = NULL;
473 exec->face = NULL;
474 exec->size = NULL;
476 return TT_Err_Ok;
478 Fail_Memory:
479 FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n",
480 (FT_Long)exec ));
481 TT_Done_Context( exec );
483 return error;
487 /*************************************************************************/
488 /* */
489 /* <Function> */
490 /* Update_Max */
491 /* */
492 /* <Description> */
493 /* Checks the size of a buffer and reallocates it if necessary. */
494 /* */
495 /* <Input> */
496 /* memory :: A handle to the parent memory object. */
497 /* */
498 /* multiplier :: The size in bytes of each element in the buffer. */
499 /* */
500 /* new_max :: The new capacity (size) of the buffer. */
501 /* */
502 /* <InOut> */
503 /* size :: The address of the buffer's current size expressed */
504 /* in elements. */
505 /* */
506 /* buff :: The address of the buffer base pointer. */
507 /* */
508 /* <Return> */
509 /* FreeType error code. 0 means success. */
510 /* */
511 static FT_Error
512 Update_Max( FT_Memory memory,
513 FT_ULong* size,
514 FT_Long multiplier,
515 void* _pbuff,
516 FT_ULong new_max )
518 FT_Error error;
519 void** pbuff = (void**)_pbuff;
522 if ( *size < new_max )
524 if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )
525 return error;
526 *size = new_max;
529 return TT_Err_Ok;
533 /*************************************************************************/
534 /* */
535 /* <Function> */
536 /* TT_Load_Context */
537 /* */
538 /* <Description> */
539 /* Prepare an execution context for glyph hinting. */
540 /* */
541 /* <Input> */
542 /* face :: A handle to the source face object. */
543 /* */
544 /* size :: A handle to the source size object. */
545 /* */
546 /* <InOut> */
547 /* exec :: A handle to the target execution context. */
548 /* */
549 /* <Return> */
550 /* FreeType error code. 0 means success. */
551 /* */
552 /* <Note> */
553 /* Only the glyph loader and debugger should call this function. */
554 /* */
555 FT_LOCAL_DEF( FT_Error )
556 TT_Load_Context( TT_ExecContext exec,
557 TT_Face face,
558 TT_Size size )
560 FT_Int i;
561 FT_ULong tmp;
562 TT_MaxProfile* maxp;
563 FT_Error error;
566 exec->face = face;
567 maxp = &face->max_profile;
568 exec->size = size;
570 if ( size )
572 exec->numFDefs = size->num_function_defs;
573 exec->maxFDefs = size->max_function_defs;
574 exec->numIDefs = size->num_instruction_defs;
575 exec->maxIDefs = size->max_instruction_defs;
576 exec->FDefs = size->function_defs;
577 exec->IDefs = size->instruction_defs;
578 exec->tt_metrics = size->ttmetrics;
579 exec->metrics = size->metrics;
581 exec->maxFunc = size->max_func;
582 exec->maxIns = size->max_ins;
584 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
585 exec->codeRangeTable[i] = size->codeRangeTable[i];
587 /* set graphics state */
588 exec->GS = size->GS;
590 exec->cvtSize = size->cvt_size;
591 exec->cvt = size->cvt;
593 exec->storeSize = size->storage_size;
594 exec->storage = size->storage;
596 exec->twilight = size->twilight;
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,
603 &tmp,
604 sizeof ( FT_F26Dot6 ),
605 (void*)&exec->stack,
606 maxp->maxStackElements + 32 );
607 exec->stackSize = (FT_UInt)tmp;
608 if ( error )
609 return error;
611 tmp = exec->glyphSize;
612 error = Update_Max( exec->memory,
613 &tmp,
614 sizeof ( FT_Byte ),
615 (void*)&exec->glyphIns,
616 maxp->maxSizeOfInstructions );
617 exec->glyphSize = (FT_UShort)tmp;
618 if ( error )
619 return error;
621 exec->pts.n_points = 0;
622 exec->pts.n_contours = 0;
624 exec->zp1 = exec->pts;
625 exec->zp2 = exec->pts;
626 exec->zp0 = exec->pts;
628 exec->instruction_trap = FALSE;
630 return TT_Err_Ok;
634 /*************************************************************************/
635 /* */
636 /* <Function> */
637 /* TT_Save_Context */
638 /* */
639 /* <Description> */
640 /* Saves the code ranges in a `size' object. */
641 /* */
642 /* <Input> */
643 /* exec :: A handle to the source execution context. */
644 /* */
645 /* <InOut> */
646 /* size :: A handle to the target size object. */
647 /* */
648 /* <Return> */
649 /* FreeType error code. 0 means success. */
650 /* */
651 /* <Note> */
652 /* Only the glyph loader and debugger should call this function. */
653 /* */
654 FT_LOCAL_DEF( FT_Error )
655 TT_Save_Context( TT_ExecContext exec,
656 TT_Size size )
658 FT_Int i;
661 /* XXXX: Will probably disappear soon with all the code range */
662 /* management, which is now rather obsolete. */
663 /* */
664 size->num_function_defs = exec->numFDefs;
665 size->num_instruction_defs = exec->numIDefs;
667 size->max_func = exec->maxFunc;
668 size->max_ins = exec->maxIns;
670 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
671 size->codeRangeTable[i] = exec->codeRangeTable[i];
673 return TT_Err_Ok;
677 /*************************************************************************/
678 /* */
679 /* <Function> */
680 /* TT_Run_Context */
681 /* */
682 /* <Description> */
683 /* Executes one or more instructions in the execution context. */
684 /* */
685 /* <Input> */
686 /* debug :: A Boolean flag. If set, the function sets some internal */
687 /* variables and returns immediately, otherwise TT_RunIns() */
688 /* is called. */
689 /* */
690 /* This is commented out currently. */
691 /* */
692 /* <Input> */
693 /* exec :: A handle to the target execution context. */
694 /* */
695 /* <Return> */
696 /* TrueType error code. 0 means success. */
697 /* */
698 /* <Note> */
699 /* Only the glyph loader and debugger should call this function. */
700 /* */
701 FT_LOCAL_DEF( FT_Error )
702 TT_Run_Context( TT_ExecContext exec,
703 FT_Bool debug )
705 FT_Error error;
708 if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) )
709 != TT_Err_Ok )
710 return error;
712 exec->zp0 = exec->pts;
713 exec->zp1 = exec->pts;
714 exec->zp2 = exec->pts;
716 exec->GS.gep0 = 1;
717 exec->GS.gep1 = 1;
718 exec->GS.gep2 = 1;
720 exec->GS.projVector.x = 0x4000;
721 exec->GS.projVector.y = 0x0000;
723 exec->GS.freeVector = exec->GS.projVector;
724 exec->GS.dualVector = exec->GS.projVector;
726 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
727 exec->GS.both_x_axis = TRUE;
728 #endif
730 exec->GS.round_state = 1;
731 exec->GS.loop = 1;
733 /* some glyphs leave something on the stack. so we clean it */
734 /* before a new execution. */
735 exec->top = 0;
736 exec->callTop = 0;
738 #if 1
739 FT_UNUSED( debug );
741 return exec->face->interpreter( exec );
742 #else
743 if ( !debug )
744 return TT_RunIns( exec );
745 else
746 return TT_Err_Ok;
747 #endif
751 const TT_GraphicsState tt_default_graphics_state =
753 0, 0, 0,
754 { 0x4000, 0 },
755 { 0x4000, 0 },
756 { 0x4000, 0 },
758 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
759 TRUE,
760 #endif
762 1, 64, 1,
763 TRUE, 68, 0, 0, 9, 3,
764 0, FALSE, 2, 1, 1, 1
768 /* documentation is in ttinterp.h */
770 FT_EXPORT_DEF( TT_ExecContext )
771 TT_New_Context( TT_Driver driver )
773 TT_ExecContext exec;
774 FT_Memory memory;
777 memory = driver->root.root.memory;
778 exec = driver->context;
780 if ( !driver->context )
782 FT_Error error;
785 /* allocate object */
786 if ( FT_NEW( exec ) )
787 goto Exit;
789 /* initialize it */
790 error = Init_Context( exec, memory );
791 if ( error )
792 goto Fail;
794 /* store it into the driver */
795 driver->context = exec;
798 Exit:
799 return driver->context;
801 Fail:
802 FT_FREE( exec );
804 return 0;
808 /*************************************************************************/
809 /* */
810 /* Before an opcode is executed, the interpreter verifies that there are */
811 /* enough arguments on the stack, with the help of the `Pop_Push_Count' */
812 /* table. */
813 /* */
814 /* For each opcode, the first column gives the number of arguments that */
815 /* are popped from the stack; the second one gives the number of those */
816 /* that are pushed in result. */
817 /* */
818 /* Opcodes which have a varying number of parameters in the data stream */
819 /* (NPUSHB, NPUSHW) are handled specially; they have a negative value in */
820 /* the `opcode_length' table, and the value in `Pop_Push_Count' is set */
821 /* to zero. */
822 /* */
823 /*************************************************************************/
826 #undef PACK
827 #define PACK( x, y ) ( ( x << 4 ) | y )
830 static
831 const FT_Byte Pop_Push_Count[256] =
833 /* opcodes are gathered in groups of 16 */
834 /* please keep the spaces as they are */
836 /* SVTCA y */ PACK( 0, 0 ),
837 /* SVTCA x */ PACK( 0, 0 ),
838 /* SPvTCA y */ PACK( 0, 0 ),
839 /* SPvTCA x */ PACK( 0, 0 ),
840 /* SFvTCA y */ PACK( 0, 0 ),
841 /* SFvTCA x */ PACK( 0, 0 ),
842 /* SPvTL // */ PACK( 2, 0 ),
843 /* SPvTL + */ PACK( 2, 0 ),
844 /* SFvTL // */ PACK( 2, 0 ),
845 /* SFvTL + */ PACK( 2, 0 ),
846 /* SPvFS */ PACK( 2, 0 ),
847 /* SFvFS */ PACK( 2, 0 ),
848 /* GPV */ PACK( 0, 2 ),
849 /* GFV */ PACK( 0, 2 ),
850 /* SFvTPv */ PACK( 0, 0 ),
851 /* ISECT */ PACK( 5, 0 ),
853 /* SRP0 */ PACK( 1, 0 ),
854 /* SRP1 */ PACK( 1, 0 ),
855 /* SRP2 */ PACK( 1, 0 ),
856 /* SZP0 */ PACK( 1, 0 ),
857 /* SZP1 */ PACK( 1, 0 ),
858 /* SZP2 */ PACK( 1, 0 ),
859 /* SZPS */ PACK( 1, 0 ),
860 /* SLOOP */ PACK( 1, 0 ),
861 /* RTG */ PACK( 0, 0 ),
862 /* RTHG */ PACK( 0, 0 ),
863 /* SMD */ PACK( 1, 0 ),
864 /* ELSE */ PACK( 0, 0 ),
865 /* JMPR */ PACK( 1, 0 ),
866 /* SCvTCi */ PACK( 1, 0 ),
867 /* SSwCi */ PACK( 1, 0 ),
868 /* SSW */ PACK( 1, 0 ),
870 /* DUP */ PACK( 1, 2 ),
871 /* POP */ PACK( 1, 0 ),
872 /* CLEAR */ PACK( 0, 0 ),
873 /* SWAP */ PACK( 2, 2 ),
874 /* DEPTH */ PACK( 0, 1 ),
875 /* CINDEX */ PACK( 1, 1 ),
876 /* MINDEX */ PACK( 1, 0 ),
877 /* AlignPTS */ PACK( 2, 0 ),
878 /* INS_$28 */ PACK( 0, 0 ),
879 /* UTP */ PACK( 1, 0 ),
880 /* LOOPCALL */ PACK( 2, 0 ),
881 /* CALL */ PACK( 1, 0 ),
882 /* FDEF */ PACK( 1, 0 ),
883 /* ENDF */ PACK( 0, 0 ),
884 /* MDAP[0] */ PACK( 1, 0 ),
885 /* MDAP[1] */ PACK( 1, 0 ),
887 /* IUP[0] */ PACK( 0, 0 ),
888 /* IUP[1] */ PACK( 0, 0 ),
889 /* SHP[0] */ PACK( 0, 0 ),
890 /* SHP[1] */ PACK( 0, 0 ),
891 /* SHC[0] */ PACK( 1, 0 ),
892 /* SHC[1] */ PACK( 1, 0 ),
893 /* SHZ[0] */ PACK( 1, 0 ),
894 /* SHZ[1] */ PACK( 1, 0 ),
895 /* SHPIX */ PACK( 1, 0 ),
896 /* IP */ PACK( 0, 0 ),
897 /* MSIRP[0] */ PACK( 2, 0 ),
898 /* MSIRP[1] */ PACK( 2, 0 ),
899 /* AlignRP */ PACK( 0, 0 ),
900 /* RTDG */ PACK( 0, 0 ),
901 /* MIAP[0] */ PACK( 2, 0 ),
902 /* MIAP[1] */ PACK( 2, 0 ),
904 /* NPushB */ PACK( 0, 0 ),
905 /* NPushW */ PACK( 0, 0 ),
906 /* WS */ PACK( 2, 0 ),
907 /* RS */ PACK( 1, 1 ),
908 /* WCvtP */ PACK( 2, 0 ),
909 /* RCvt */ PACK( 1, 1 ),
910 /* GC[0] */ PACK( 1, 1 ),
911 /* GC[1] */ PACK( 1, 1 ),
912 /* SCFS */ PACK( 2, 0 ),
913 /* MD[0] */ PACK( 2, 1 ),
914 /* MD[1] */ PACK( 2, 1 ),
915 /* MPPEM */ PACK( 0, 1 ),
916 /* MPS */ PACK( 0, 1 ),
917 /* FlipON */ PACK( 0, 0 ),
918 /* FlipOFF */ PACK( 0, 0 ),
919 /* DEBUG */ PACK( 1, 0 ),
921 /* LT */ PACK( 2, 1 ),
922 /* LTEQ */ PACK( 2, 1 ),
923 /* GT */ PACK( 2, 1 ),
924 /* GTEQ */ PACK( 2, 1 ),
925 /* EQ */ PACK( 2, 1 ),
926 /* NEQ */ PACK( 2, 1 ),
927 /* ODD */ PACK( 1, 1 ),
928 /* EVEN */ PACK( 1, 1 ),
929 /* IF */ PACK( 1, 0 ),
930 /* EIF */ PACK( 0, 0 ),
931 /* AND */ PACK( 2, 1 ),
932 /* OR */ PACK( 2, 1 ),
933 /* NOT */ PACK( 1, 1 ),
934 /* DeltaP1 */ PACK( 1, 0 ),
935 /* SDB */ PACK( 1, 0 ),
936 /* SDS */ PACK( 1, 0 ),
938 /* ADD */ PACK( 2, 1 ),
939 /* SUB */ PACK( 2, 1 ),
940 /* DIV */ PACK( 2, 1 ),
941 /* MUL */ PACK( 2, 1 ),
942 /* ABS */ PACK( 1, 1 ),
943 /* NEG */ PACK( 1, 1 ),
944 /* FLOOR */ PACK( 1, 1 ),
945 /* CEILING */ PACK( 1, 1 ),
946 /* ROUND[0] */ PACK( 1, 1 ),
947 /* ROUND[1] */ PACK( 1, 1 ),
948 /* ROUND[2] */ PACK( 1, 1 ),
949 /* ROUND[3] */ PACK( 1, 1 ),
950 /* NROUND[0] */ PACK( 1, 1 ),
951 /* NROUND[1] */ PACK( 1, 1 ),
952 /* NROUND[2] */ PACK( 1, 1 ),
953 /* NROUND[3] */ PACK( 1, 1 ),
955 /* WCvtF */ PACK( 2, 0 ),
956 /* DeltaP2 */ PACK( 1, 0 ),
957 /* DeltaP3 */ PACK( 1, 0 ),
958 /* DeltaCn[0] */ PACK( 1, 0 ),
959 /* DeltaCn[1] */ PACK( 1, 0 ),
960 /* DeltaCn[2] */ PACK( 1, 0 ),
961 /* SROUND */ PACK( 1, 0 ),
962 /* S45Round */ PACK( 1, 0 ),
963 /* JROT */ PACK( 2, 0 ),
964 /* JROF */ PACK( 2, 0 ),
965 /* ROFF */ PACK( 0, 0 ),
966 /* INS_$7B */ PACK( 0, 0 ),
967 /* RUTG */ PACK( 0, 0 ),
968 /* RDTG */ PACK( 0, 0 ),
969 /* SANGW */ PACK( 1, 0 ),
970 /* AA */ PACK( 1, 0 ),
972 /* FlipPT */ PACK( 0, 0 ),
973 /* FlipRgON */ PACK( 2, 0 ),
974 /* FlipRgOFF */ PACK( 2, 0 ),
975 /* INS_$83 */ PACK( 0, 0 ),
976 /* INS_$84 */ PACK( 0, 0 ),
977 /* ScanCTRL */ PACK( 1, 0 ),
978 /* SDVPTL[0] */ PACK( 2, 0 ),
979 /* SDVPTL[1] */ PACK( 2, 0 ),
980 /* GetINFO */ PACK( 1, 1 ),
981 /* IDEF */ PACK( 1, 0 ),
982 /* ROLL */ PACK( 3, 3 ),
983 /* MAX */ PACK( 2, 1 ),
984 /* MIN */ PACK( 2, 1 ),
985 /* ScanTYPE */ PACK( 1, 0 ),
986 /* InstCTRL */ PACK( 2, 0 ),
987 /* INS_$8F */ PACK( 0, 0 ),
989 /* INS_$90 */ PACK( 0, 0 ),
990 /* INS_$91 */ PACK( 0, 0 ),
991 /* INS_$92 */ PACK( 0, 0 ),
992 /* INS_$93 */ PACK( 0, 0 ),
993 /* INS_$94 */ PACK( 0, 0 ),
994 /* INS_$95 */ PACK( 0, 0 ),
995 /* INS_$96 */ PACK( 0, 0 ),
996 /* INS_$97 */ PACK( 0, 0 ),
997 /* INS_$98 */ PACK( 0, 0 ),
998 /* INS_$99 */ PACK( 0, 0 ),
999 /* INS_$9A */ PACK( 0, 0 ),
1000 /* INS_$9B */ PACK( 0, 0 ),
1001 /* INS_$9C */ PACK( 0, 0 ),
1002 /* INS_$9D */ PACK( 0, 0 ),
1003 /* INS_$9E */ PACK( 0, 0 ),
1004 /* INS_$9F */ PACK( 0, 0 ),
1006 /* INS_$A0 */ PACK( 0, 0 ),
1007 /* INS_$A1 */ PACK( 0, 0 ),
1008 /* INS_$A2 */ PACK( 0, 0 ),
1009 /* INS_$A3 */ PACK( 0, 0 ),
1010 /* INS_$A4 */ PACK( 0, 0 ),
1011 /* INS_$A5 */ PACK( 0, 0 ),
1012 /* INS_$A6 */ PACK( 0, 0 ),
1013 /* INS_$A7 */ PACK( 0, 0 ),
1014 /* INS_$A8 */ PACK( 0, 0 ),
1015 /* INS_$A9 */ PACK( 0, 0 ),
1016 /* INS_$AA */ PACK( 0, 0 ),
1017 /* INS_$AB */ PACK( 0, 0 ),
1018 /* INS_$AC */ PACK( 0, 0 ),
1019 /* INS_$AD */ PACK( 0, 0 ),
1020 /* INS_$AE */ PACK( 0, 0 ),
1021 /* INS_$AF */ PACK( 0, 0 ),
1023 /* PushB[0] */ PACK( 0, 1 ),
1024 /* PushB[1] */ PACK( 0, 2 ),
1025 /* PushB[2] */ PACK( 0, 3 ),
1026 /* PushB[3] */ PACK( 0, 4 ),
1027 /* PushB[4] */ PACK( 0, 5 ),
1028 /* PushB[5] */ PACK( 0, 6 ),
1029 /* PushB[6] */ PACK( 0, 7 ),
1030 /* PushB[7] */ PACK( 0, 8 ),
1031 /* PushW[0] */ PACK( 0, 1 ),
1032 /* PushW[1] */ PACK( 0, 2 ),
1033 /* PushW[2] */ PACK( 0, 3 ),
1034 /* PushW[3] */ PACK( 0, 4 ),
1035 /* PushW[4] */ PACK( 0, 5 ),
1036 /* PushW[5] */ PACK( 0, 6 ),
1037 /* PushW[6] */ PACK( 0, 7 ),
1038 /* PushW[7] */ PACK( 0, 8 ),
1040 /* MDRP[00] */ PACK( 1, 0 ),
1041 /* MDRP[01] */ PACK( 1, 0 ),
1042 /* MDRP[02] */ PACK( 1, 0 ),
1043 /* MDRP[03] */ PACK( 1, 0 ),
1044 /* MDRP[04] */ PACK( 1, 0 ),
1045 /* MDRP[05] */ PACK( 1, 0 ),
1046 /* MDRP[06] */ PACK( 1, 0 ),
1047 /* MDRP[07] */ PACK( 1, 0 ),
1048 /* MDRP[08] */ PACK( 1, 0 ),
1049 /* MDRP[09] */ PACK( 1, 0 ),
1050 /* MDRP[10] */ PACK( 1, 0 ),
1051 /* MDRP[11] */ PACK( 1, 0 ),
1052 /* MDRP[12] */ PACK( 1, 0 ),
1053 /* MDRP[13] */ PACK( 1, 0 ),
1054 /* MDRP[14] */ PACK( 1, 0 ),
1055 /* MDRP[15] */ PACK( 1, 0 ),
1057 /* MDRP[16] */ PACK( 1, 0 ),
1058 /* MDRP[17] */ PACK( 1, 0 ),
1059 /* MDRP[18] */ PACK( 1, 0 ),
1060 /* MDRP[19] */ PACK( 1, 0 ),
1061 /* MDRP[20] */ PACK( 1, 0 ),
1062 /* MDRP[21] */ PACK( 1, 0 ),
1063 /* MDRP[22] */ PACK( 1, 0 ),
1064 /* MDRP[23] */ PACK( 1, 0 ),
1065 /* MDRP[24] */ PACK( 1, 0 ),
1066 /* MDRP[25] */ PACK( 1, 0 ),
1067 /* MDRP[26] */ PACK( 1, 0 ),
1068 /* MDRP[27] */ PACK( 1, 0 ),
1069 /* MDRP[28] */ PACK( 1, 0 ),
1070 /* MDRP[29] */ PACK( 1, 0 ),
1071 /* MDRP[30] */ PACK( 1, 0 ),
1072 /* MDRP[31] */ PACK( 1, 0 ),
1074 /* MIRP[00] */ PACK( 2, 0 ),
1075 /* MIRP[01] */ PACK( 2, 0 ),
1076 /* MIRP[02] */ PACK( 2, 0 ),
1077 /* MIRP[03] */ PACK( 2, 0 ),
1078 /* MIRP[04] */ PACK( 2, 0 ),
1079 /* MIRP[05] */ PACK( 2, 0 ),
1080 /* MIRP[06] */ PACK( 2, 0 ),
1081 /* MIRP[07] */ PACK( 2, 0 ),
1082 /* MIRP[08] */ PACK( 2, 0 ),
1083 /* MIRP[09] */ PACK( 2, 0 ),
1084 /* MIRP[10] */ PACK( 2, 0 ),
1085 /* MIRP[11] */ PACK( 2, 0 ),
1086 /* MIRP[12] */ PACK( 2, 0 ),
1087 /* MIRP[13] */ PACK( 2, 0 ),
1088 /* MIRP[14] */ PACK( 2, 0 ),
1089 /* MIRP[15] */ PACK( 2, 0 ),
1091 /* MIRP[16] */ PACK( 2, 0 ),
1092 /* MIRP[17] */ PACK( 2, 0 ),
1093 /* MIRP[18] */ PACK( 2, 0 ),
1094 /* MIRP[19] */ PACK( 2, 0 ),
1095 /* MIRP[20] */ PACK( 2, 0 ),
1096 /* MIRP[21] */ PACK( 2, 0 ),
1097 /* MIRP[22] */ PACK( 2, 0 ),
1098 /* MIRP[23] */ PACK( 2, 0 ),
1099 /* MIRP[24] */ PACK( 2, 0 ),
1100 /* MIRP[25] */ PACK( 2, 0 ),
1101 /* MIRP[26] */ PACK( 2, 0 ),
1102 /* MIRP[27] */ PACK( 2, 0 ),
1103 /* MIRP[28] */ PACK( 2, 0 ),
1104 /* MIRP[29] */ PACK( 2, 0 ),
1105 /* MIRP[30] */ PACK( 2, 0 ),
1106 /* MIRP[31] */ PACK( 2, 0 )
1110 static
1111 const FT_Char opcode_length[256] =
1113 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1114 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1115 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1116 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1118 -1,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1119 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1120 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1121 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1123 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1124 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1125 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1126 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
1128 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1129 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1130 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1131 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1134 #undef PACK
1136 #if 1
1138 static FT_Int32
1139 TT_MulFix14( FT_Int32 a,
1140 FT_Int b )
1142 FT_Int32 sign;
1143 FT_UInt32 ah, al, mid, lo, hi;
1146 sign = a ^ b;
1148 if ( a < 0 )
1149 a = -a;
1150 if ( b < 0 )
1151 b = -b;
1153 ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU );
1154 al = (FT_UInt32)( a & 0xFFFFU );
1156 lo = al * b;
1157 mid = ah * b;
1158 hi = mid >> 16;
1159 mid = ( mid << 16 ) + ( 1 << 13 ); /* rounding */
1160 lo += mid;
1161 if ( lo < mid )
1162 hi += 1;
1164 mid = ( lo >> 14 ) | ( hi << 18 );
1166 return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid;
1169 #else
1171 /* compute (a*b)/2^14 with maximal accuracy and rounding */
1172 static FT_Int32
1173 TT_MulFix14( FT_Int32 a,
1174 FT_Int b )
1176 FT_Int32 m, s, hi;
1177 FT_UInt32 l, lo;
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 */
1188 s = hi >> 31;
1189 l = lo + (FT_UInt32)s;
1190 hi += s + ( l < lo );
1191 lo = l;
1193 l = lo + 0x2000U;
1194 hi += l < lo;
1196 return ( hi << 18 ) | ( l >> 14 );
1198 #endif
1201 /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */
1202 static FT_Int32
1203 TT_DotFix14( FT_Int32 ax,
1204 FT_Int32 ay,
1205 FT_Int bx,
1206 FT_Int by )
1208 FT_Int32 m, s, hi1, hi2, hi;
1209 FT_UInt32 l, lo1, lo2, lo;
1212 /* compute ax*bx as 64-bit value */
1213 l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );
1214 m = ( ax >> 16 ) * bx;
1216 lo1 = l + (FT_UInt32)( m << 16 );
1217 hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l );
1219 /* compute ay*by as 64-bit value */
1220 l = (FT_UInt32)( ( ay & 0xFFFFU ) * by );
1221 m = ( ay >> 16 ) * by;
1223 lo2 = l + (FT_UInt32)( m << 16 );
1224 hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l );
1226 /* add them */
1227 lo = lo1 + lo2;
1228 hi = hi1 + hi2 + ( lo < lo1 );
1230 /* divide the result by 2^14 with rounding */
1231 s = hi >> 31;
1232 l = lo + (FT_UInt32)s;
1233 hi += s + ( l < lo );
1234 lo = l;
1236 l = lo + 0x2000U;
1237 hi += ( l < lo );
1239 return ( hi << 18 ) | ( l >> 14 );
1243 /* return length of given vector */
1245 #if 0
1247 static FT_Int32
1248 TT_VecLen( FT_Int32 x,
1249 FT_Int32 y )
1251 FT_Int32 m, hi1, hi2, hi;
1252 FT_UInt32 l, lo1, lo2, lo;
1255 /* compute x*x as 64-bit value */
1256 lo = (FT_UInt32)( x & 0xFFFFU );
1257 hi = x >> 16;
1259 l = lo * lo;
1260 m = hi * lo;
1261 hi = hi * hi;
1263 lo1 = l + (FT_UInt32)( m << 17 );
1264 hi1 = hi + ( m >> 15 ) + ( lo1 < l );
1266 /* compute y*y as 64-bit value */
1267 lo = (FT_UInt32)( y & 0xFFFFU );
1268 hi = y >> 16;
1270 l = lo * lo;
1271 m = hi * lo;
1272 hi = hi * hi;
1274 lo2 = l + (FT_UInt32)( m << 17 );
1275 hi2 = hi + ( m >> 15 ) + ( lo2 < l );
1277 /* add them to get 'x*x+y*y' as 64-bit value */
1278 lo = lo1 + lo2;
1279 hi = hi1 + hi2 + ( lo < lo1 );
1281 /* compute the square root of this value */
1283 FT_UInt32 root, rem, test_div;
1284 FT_Int count;
1287 root = 0;
1290 rem = 0;
1291 count = 32;
1294 rem = ( rem << 2 ) | ( (FT_UInt32)hi >> 30 );
1295 hi = ( hi << 2 ) | ( lo >> 30 );
1296 lo <<= 2;
1297 root <<= 1;
1298 test_div = ( root << 1 ) + 1;
1300 if ( rem >= test_div )
1302 rem -= test_div;
1303 root += 1;
1305 } while ( --count );
1308 return (FT_Int32)root;
1312 #else
1314 /* this version uses FT_Vector_Length which computes the same value */
1315 /* much, much faster.. */
1316 /* */
1317 static FT_F26Dot6
1318 TT_VecLen( FT_F26Dot6 X,
1319 FT_F26Dot6 Y )
1321 FT_Vector v;
1324 v.x = X;
1325 v.y = Y;
1327 return FT_Vector_Length( &v );
1330 #endif
1333 /*************************************************************************/
1334 /* */
1335 /* <Function> */
1336 /* Current_Ratio */
1337 /* */
1338 /* <Description> */
1339 /* Returns the current aspect ratio scaling factor depending on the */
1340 /* projection vector's state and device resolutions. */
1341 /* */
1342 /* <Return> */
1343 /* The aspect ratio in 16.16 format, always <= 1.0 . */
1344 /* */
1345 static FT_Long
1346 Current_Ratio( EXEC_OP )
1348 if ( !CUR.tt_metrics.ratio )
1350 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1351 if ( CUR.face->unpatented_hinting )
1353 if ( CUR.GS.both_x_axis )
1354 CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
1355 else
1356 CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
1358 else
1359 #endif
1361 if ( CUR.GS.projVector.y == 0 )
1362 CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
1364 else if ( CUR.GS.projVector.x == 0 )
1365 CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
1367 else
1369 FT_Long x, y;
1372 x = TT_MULDIV( CUR.GS.projVector.x,
1373 CUR.tt_metrics.x_ratio, 0x4000 );
1374 y = TT_MULDIV( CUR.GS.projVector.y,
1375 CUR.tt_metrics.y_ratio, 0x4000 );
1376 CUR.tt_metrics.ratio = TT_VecLen( x, y );
1380 return CUR.tt_metrics.ratio;
1384 static FT_Long
1385 Current_Ppem( EXEC_OP )
1387 return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );
1391 /*************************************************************************/
1392 /* */
1393 /* Functions related to the control value table (CVT). */
1394 /* */
1395 /*************************************************************************/
1398 FT_CALLBACK_DEF( FT_F26Dot6 )
1399 Read_CVT( EXEC_OP_ FT_ULong idx )
1401 return CUR.cvt[idx];
1405 FT_CALLBACK_DEF( FT_F26Dot6 )
1406 Read_CVT_Stretched( EXEC_OP_ FT_ULong idx )
1408 return TT_MULFIX( CUR.cvt[idx], CURRENT_Ratio() );
1412 FT_CALLBACK_DEF( void )
1413 Write_CVT( EXEC_OP_ FT_ULong idx,
1414 FT_F26Dot6 value )
1416 CUR.cvt[idx] = value;
1420 FT_CALLBACK_DEF( void )
1421 Write_CVT_Stretched( EXEC_OP_ FT_ULong idx,
1422 FT_F26Dot6 value )
1424 CUR.cvt[idx] = FT_DivFix( value, CURRENT_Ratio() );
1428 FT_CALLBACK_DEF( void )
1429 Move_CVT( EXEC_OP_ FT_ULong idx,
1430 FT_F26Dot6 value )
1432 CUR.cvt[idx] += value;
1436 FT_CALLBACK_DEF( void )
1437 Move_CVT_Stretched( EXEC_OP_ FT_ULong idx,
1438 FT_F26Dot6 value )
1440 CUR.cvt[idx] += FT_DivFix( value, CURRENT_Ratio() );
1444 /*************************************************************************/
1445 /* */
1446 /* <Function> */
1447 /* GetShortIns */
1448 /* */
1449 /* <Description> */
1450 /* Returns a short integer taken from the instruction stream at */
1451 /* address IP. */
1452 /* */
1453 /* <Return> */
1454 /* Short read at code[IP]. */
1455 /* */
1456 /* <Note> */
1457 /* This one could become a macro. */
1458 /* */
1459 static FT_Short
1460 GetShortIns( EXEC_OP )
1462 /* Reading a byte stream so there is no endianess (DaveP) */
1463 CUR.IP += 2;
1464 return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) +
1465 CUR.code[CUR.IP - 1] );
1469 /*************************************************************************/
1470 /* */
1471 /* <Function> */
1472 /* Ins_Goto_CodeRange */
1473 /* */
1474 /* <Description> */
1475 /* Goes to a certain code range in the instruction stream. */
1476 /* */
1477 /* <Input> */
1478 /* aRange :: The index of the code range. */
1479 /* */
1480 /* aIP :: The new IP address in the code range. */
1481 /* */
1482 /* <Return> */
1483 /* SUCCESS or FAILURE. */
1484 /* */
1485 static FT_Bool
1486 Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange,
1487 FT_ULong aIP )
1489 TT_CodeRange* range;
1492 if ( aRange < 1 || aRange > 3 )
1494 CUR.error = TT_Err_Bad_Argument;
1495 return FAILURE;
1498 range = &CUR.codeRangeTable[aRange - 1];
1500 if ( range->base == NULL ) /* invalid coderange */
1502 CUR.error = TT_Err_Invalid_CodeRange;
1503 return FAILURE;
1506 /* NOTE: Because the last instruction of a program may be a CALL */
1507 /* which will return to the first byte *after* the code */
1508 /* range, we test for AIP <= Size, instead of AIP < Size. */
1510 if ( aIP > range->size )
1512 CUR.error = TT_Err_Code_Overflow;
1513 return FAILURE;
1516 CUR.code = range->base;
1517 CUR.codeSize = range->size;
1518 CUR.IP = aIP;
1519 CUR.curRange = aRange;
1521 return SUCCESS;
1525 /*************************************************************************/
1526 /* */
1527 /* <Function> */
1528 /* Direct_Move */
1529 /* */
1530 /* <Description> */
1531 /* Moves a point by a given distance along the freedom vector. The */
1532 /* point will be `touched'. */
1533 /* */
1534 /* <Input> */
1535 /* point :: The index of the point to move. */
1536 /* */
1537 /* distance :: The distance to apply. */
1538 /* */
1539 /* <InOut> */
1540 /* zone :: The affected glyph zone. */
1541 /* */
1542 static void
1543 Direct_Move( EXEC_OP_ TT_GlyphZone zone,
1544 FT_UShort point,
1545 FT_F26Dot6 distance )
1547 FT_F26Dot6 v;
1550 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1551 FT_ASSERT( !CUR.face->unpatented_hinting );
1552 #endif
1554 v = CUR.GS.freeVector.x;
1556 if ( v != 0 )
1558 zone->cur[point].x += TT_MULDIV( distance,
1559 v * 0x10000L,
1560 CUR.F_dot_P );
1562 zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
1565 v = CUR.GS.freeVector.y;
1567 if ( v != 0 )
1569 zone->cur[point].y += TT_MULDIV( distance,
1570 v * 0x10000L,
1571 CUR.F_dot_P );
1573 zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1578 /*************************************************************************/
1579 /* */
1580 /* <Function> */
1581 /* Direct_Move_Orig */
1582 /* */
1583 /* <Description> */
1584 /* Moves the *original* position of a point by a given distance along */
1585 /* the freedom vector. Obviously, the point will not be `touched'. */
1586 /* */
1587 /* <Input> */
1588 /* point :: The index of the point to move. */
1589 /* */
1590 /* distance :: The distance to apply. */
1591 /* */
1592 /* <InOut> */
1593 /* zone :: The affected glyph zone. */
1594 /* */
1595 static void
1596 Direct_Move_Orig( EXEC_OP_ TT_GlyphZone zone,
1597 FT_UShort point,
1598 FT_F26Dot6 distance )
1600 FT_F26Dot6 v;
1603 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1604 FT_ASSERT( !CUR.face->unpatented_hinting );
1605 #endif
1607 v = CUR.GS.freeVector.x;
1609 if ( v != 0 )
1610 zone->org[point].x += TT_MULDIV( distance,
1611 v * 0x10000L,
1612 CUR.F_dot_P );
1614 v = CUR.GS.freeVector.y;
1616 if ( v != 0 )
1617 zone->org[point].y += TT_MULDIV( distance,
1618 v * 0x10000L,
1619 CUR.F_dot_P );
1623 /*************************************************************************/
1624 /* */
1625 /* Special versions of Direct_Move() */
1626 /* */
1627 /* The following versions are used whenever both vectors are both */
1628 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1629 /* */
1630 /*************************************************************************/
1633 static void
1634 Direct_Move_X( EXEC_OP_ TT_GlyphZone zone,
1635 FT_UShort point,
1636 FT_F26Dot6 distance )
1638 FT_UNUSED_EXEC;
1640 zone->cur[point].x += distance;
1641 zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
1645 static void
1646 Direct_Move_Y( EXEC_OP_ TT_GlyphZone zone,
1647 FT_UShort point,
1648 FT_F26Dot6 distance )
1650 FT_UNUSED_EXEC;
1652 zone->cur[point].y += distance;
1653 zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1657 /*************************************************************************/
1658 /* */
1659 /* Special versions of Direct_Move_Orig() */
1660 /* */
1661 /* The following versions are used whenever both vectors are both */
1662 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1663 /* */
1664 /*************************************************************************/
1667 static void
1668 Direct_Move_Orig_X( EXEC_OP_ TT_GlyphZone zone,
1669 FT_UShort point,
1670 FT_F26Dot6 distance )
1672 FT_UNUSED_EXEC;
1674 zone->org[point].x += distance;
1678 static void
1679 Direct_Move_Orig_Y( EXEC_OP_ TT_GlyphZone zone,
1680 FT_UShort point,
1681 FT_F26Dot6 distance )
1683 FT_UNUSED_EXEC;
1685 zone->org[point].y += distance;
1689 /*************************************************************************/
1690 /* */
1691 /* <Function> */
1692 /* Round_None */
1693 /* */
1694 /* <Description> */
1695 /* Does not round, but adds engine compensation. */
1696 /* */
1697 /* <Input> */
1698 /* distance :: The distance (not) to round. */
1699 /* */
1700 /* compensation :: The engine compensation. */
1701 /* */
1702 /* <Return> */
1703 /* The compensated distance. */
1704 /* */
1705 /* <Note> */
1706 /* The TrueType specification says very few about the relationship */
1707 /* between rounding and engine compensation. However, it seems from */
1708 /* the description of super round that we should add the compensation */
1709 /* before rounding. */
1710 /* */
1711 static FT_F26Dot6
1712 Round_None( EXEC_OP_ FT_F26Dot6 distance,
1713 FT_F26Dot6 compensation )
1715 FT_F26Dot6 val;
1717 FT_UNUSED_EXEC;
1720 if ( distance >= 0 )
1722 val = distance + compensation;
1723 if ( distance && val < 0 )
1724 val = 0;
1726 else {
1727 val = distance - compensation;
1728 if ( val > 0 )
1729 val = 0;
1731 return val;
1735 /*************************************************************************/
1736 /* */
1737 /* <Function> */
1738 /* Round_To_Grid */
1739 /* */
1740 /* <Description> */
1741 /* Rounds value to grid after adding engine compensation. */
1742 /* */
1743 /* <Input> */
1744 /* distance :: The distance to round. */
1745 /* */
1746 /* compensation :: The engine compensation. */
1747 /* */
1748 /* <Return> */
1749 /* Rounded distance. */
1750 /* */
1751 static FT_F26Dot6
1752 Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1753 FT_F26Dot6 compensation )
1755 FT_F26Dot6 val;
1757 FT_UNUSED_EXEC;
1760 if ( distance >= 0 )
1762 val = distance + compensation + 32;
1763 if ( distance && val > 0 )
1764 val &= ~63;
1765 else
1766 val = 0;
1768 else
1770 val = -FT_PIX_ROUND( compensation - distance );
1771 if ( val > 0 )
1772 val = 0;
1775 return val;
1779 /*************************************************************************/
1780 /* */
1781 /* <Function> */
1782 /* Round_To_Half_Grid */
1783 /* */
1784 /* <Description> */
1785 /* Rounds value to half grid after adding engine compensation. */
1786 /* */
1787 /* <Input> */
1788 /* distance :: The distance to round. */
1789 /* */
1790 /* compensation :: The engine compensation. */
1791 /* */
1792 /* <Return> */
1793 /* Rounded distance. */
1794 /* */
1795 static FT_F26Dot6
1796 Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance,
1797 FT_F26Dot6 compensation )
1799 FT_F26Dot6 val;
1801 FT_UNUSED_EXEC;
1804 if ( distance >= 0 )
1806 val = FT_PIX_FLOOR( distance + compensation ) + 32;
1807 if ( distance && val < 0 )
1808 val = 0;
1810 else
1812 val = -( FT_PIX_FLOOR( compensation - distance ) + 32 );
1813 if ( val > 0 )
1814 val = 0;
1817 return val;
1821 /*************************************************************************/
1822 /* */
1823 /* <Function> */
1824 /* Round_Down_To_Grid */
1825 /* */
1826 /* <Description> */
1827 /* Rounds value down to grid after adding engine compensation. */
1828 /* */
1829 /* <Input> */
1830 /* distance :: The distance to round. */
1831 /* */
1832 /* compensation :: The engine compensation. */
1833 /* */
1834 /* <Return> */
1835 /* Rounded distance. */
1836 /* */
1837 static FT_F26Dot6
1838 Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1839 FT_F26Dot6 compensation )
1841 FT_F26Dot6 val;
1843 FT_UNUSED_EXEC;
1846 if ( distance >= 0 )
1848 val = distance + compensation;
1849 if ( distance && val > 0 )
1850 val &= ~63;
1851 else
1852 val = 0;
1854 else
1856 val = -( ( compensation - distance ) & -64 );
1857 if ( val > 0 )
1858 val = 0;
1861 return val;
1865 /*************************************************************************/
1866 /* */
1867 /* <Function> */
1868 /* Round_Up_To_Grid */
1869 /* */
1870 /* <Description> */
1871 /* Rounds value up to grid after adding engine compensation. */
1872 /* */
1873 /* <Input> */
1874 /* distance :: The distance to round. */
1875 /* */
1876 /* compensation :: The engine compensation. */
1877 /* */
1878 /* <Return> */
1879 /* Rounded distance. */
1880 /* */
1881 static FT_F26Dot6
1882 Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1883 FT_F26Dot6 compensation )
1885 FT_F26Dot6 val;
1887 FT_UNUSED_EXEC;
1890 if ( distance >= 0 )
1892 val = distance + compensation + 63;
1893 if ( distance && val > 0 )
1894 val &= ~63;
1895 else
1896 val = 0;
1898 else
1900 val = - FT_PIX_CEIL( compensation - distance );
1901 if ( val > 0 )
1902 val = 0;
1905 return val;
1909 /*************************************************************************/
1910 /* */
1911 /* <Function> */
1912 /* Round_To_Double_Grid */
1913 /* */
1914 /* <Description> */
1915 /* Rounds value to double grid after adding engine compensation. */
1916 /* */
1917 /* <Input> */
1918 /* distance :: The distance to round. */
1919 /* */
1920 /* compensation :: The engine compensation. */
1921 /* */
1922 /* <Return> */
1923 /* Rounded distance. */
1924 /* */
1925 static FT_F26Dot6
1926 Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance,
1927 FT_F26Dot6 compensation )
1929 FT_F26Dot6 val;
1931 FT_UNUSED_EXEC;
1934 if ( distance >= 0 )
1936 val = distance + compensation + 16;
1937 if ( distance && val > 0 )
1938 val &= ~31;
1939 else
1940 val = 0;
1942 else
1944 val = -FT_PAD_ROUND( compensation - distance, 32 );
1945 if ( val > 0 )
1946 val = 0;
1949 return val;
1953 /*************************************************************************/
1954 /* */
1955 /* <Function> */
1956 /* Round_Super */
1957 /* */
1958 /* <Description> */
1959 /* Super-rounds value to grid after adding engine compensation. */
1960 /* */
1961 /* <Input> */
1962 /* distance :: The distance to round. */
1963 /* */
1964 /* compensation :: The engine compensation. */
1965 /* */
1966 /* <Return> */
1967 /* Rounded distance. */
1968 /* */
1969 /* <Note> */
1970 /* The TrueType specification says very few about the relationship */
1971 /* between rounding and engine compensation. However, it seems from */
1972 /* the description of super round that we should add the compensation */
1973 /* before rounding. */
1974 /* */
1975 static FT_F26Dot6
1976 Round_Super( EXEC_OP_ FT_F26Dot6 distance,
1977 FT_F26Dot6 compensation )
1979 FT_F26Dot6 val;
1982 if ( distance >= 0 )
1984 val = ( distance - CUR.phase + CUR.threshold + compensation ) &
1985 -CUR.period;
1986 if ( distance && val < 0 )
1987 val = 0;
1988 val += CUR.phase;
1990 else
1992 val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &
1993 -CUR.period );
1994 if ( val > 0 )
1995 val = 0;
1996 val -= CUR.phase;
1999 return val;
2003 /*************************************************************************/
2004 /* */
2005 /* <Function> */
2006 /* Round_Super_45 */
2007 /* */
2008 /* <Description> */
2009 /* Super-rounds value to grid after adding engine compensation. */
2010 /* */
2011 /* <Input> */
2012 /* distance :: The distance to round. */
2013 /* */
2014 /* compensation :: The engine compensation. */
2015 /* */
2016 /* <Return> */
2017 /* Rounded distance. */
2018 /* */
2019 /* <Note> */
2020 /* There is a separate function for Round_Super_45() as we may need */
2021 /* greater precision. */
2022 /* */
2023 static FT_F26Dot6
2024 Round_Super_45( EXEC_OP_ FT_F26Dot6 distance,
2025 FT_F26Dot6 compensation )
2027 FT_F26Dot6 val;
2030 if ( distance >= 0 )
2032 val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
2033 CUR.period ) * CUR.period;
2034 if ( distance && val < 0 )
2035 val = 0;
2036 val += CUR.phase;
2038 else
2040 val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /
2041 CUR.period ) * CUR.period );
2042 if ( val > 0 )
2043 val = 0;
2044 val -= CUR.phase;
2047 return val;
2051 /*************************************************************************/
2052 /* */
2053 /* <Function> */
2054 /* Compute_Round */
2055 /* */
2056 /* <Description> */
2057 /* Sets the rounding mode. */
2058 /* */
2059 /* <Input> */
2060 /* round_mode :: The rounding mode to be used. */
2061 /* */
2062 static void
2063 Compute_Round( EXEC_OP_ FT_Byte round_mode )
2065 switch ( round_mode )
2067 case TT_Round_Off:
2068 CUR.func_round = (TT_Round_Func)Round_None;
2069 break;
2071 case TT_Round_To_Grid:
2072 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2073 break;
2075 case TT_Round_Up_To_Grid:
2076 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2077 break;
2079 case TT_Round_Down_To_Grid:
2080 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2081 break;
2083 case TT_Round_To_Half_Grid:
2084 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2085 break;
2087 case TT_Round_To_Double_Grid:
2088 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2089 break;
2091 case TT_Round_Super:
2092 CUR.func_round = (TT_Round_Func)Round_Super;
2093 break;
2095 case TT_Round_Super_45:
2096 CUR.func_round = (TT_Round_Func)Round_Super_45;
2097 break;
2102 /*************************************************************************/
2103 /* */
2104 /* <Function> */
2105 /* SetSuperRound */
2106 /* */
2107 /* <Description> */
2108 /* Sets Super Round parameters. */
2109 /* */
2110 /* <Input> */
2111 /* GridPeriod :: Grid period */
2112 /* selector :: SROUND opcode */
2113 /* */
2114 static void
2115 SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod,
2116 FT_Long selector )
2118 switch ( (FT_Int)( selector & 0xC0 ) )
2120 case 0:
2121 CUR.period = GridPeriod / 2;
2122 break;
2124 case 0x40:
2125 CUR.period = GridPeriod;
2126 break;
2128 case 0x80:
2129 CUR.period = GridPeriod * 2;
2130 break;
2132 /* This opcode is reserved, but... */
2134 case 0xC0:
2135 CUR.period = GridPeriod;
2136 break;
2139 switch ( (FT_Int)( selector & 0x30 ) )
2141 case 0:
2142 CUR.phase = 0;
2143 break;
2145 case 0x10:
2146 CUR.phase = CUR.period / 4;
2147 break;
2149 case 0x20:
2150 CUR.phase = CUR.period / 2;
2151 break;
2153 case 0x30:
2154 CUR.phase = CUR.period * 3 / 4;
2155 break;
2158 if ( ( selector & 0x0F ) == 0 )
2159 CUR.threshold = CUR.period - 1;
2160 else
2161 CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8;
2163 CUR.period /= 256;
2164 CUR.phase /= 256;
2165 CUR.threshold /= 256;
2169 /*************************************************************************/
2170 /* */
2171 /* <Function> */
2172 /* Project */
2173 /* */
2174 /* <Description> */
2175 /* Computes the projection of vector given by (v2-v1) along the */
2176 /* current projection vector. */
2177 /* */
2178 /* <Input> */
2179 /* v1 :: First input vector. */
2180 /* v2 :: Second input vector. */
2181 /* */
2182 /* <Return> */
2183 /* The distance in F26dot6 format. */
2184 /* */
2185 static FT_F26Dot6
2186 Project( EXEC_OP_ FT_Pos dx,
2187 FT_Pos dy )
2189 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2190 FT_ASSERT( !CUR.face->unpatented_hinting );
2191 #endif
2193 return TT_DotFix14( dx, dy,
2194 CUR.GS.projVector.x,
2195 CUR.GS.projVector.y );
2199 /*************************************************************************/
2200 /* */
2201 /* <Function> */
2202 /* Dual_Project */
2203 /* */
2204 /* <Description> */
2205 /* Computes the projection of the vector given by (v2-v1) along the */
2206 /* current dual vector. */
2207 /* */
2208 /* <Input> */
2209 /* v1 :: First input vector. */
2210 /* v2 :: Second input vector. */
2211 /* */
2212 /* <Return> */
2213 /* The distance in F26dot6 format. */
2214 /* */
2215 static FT_F26Dot6
2216 Dual_Project( EXEC_OP_ FT_Pos dx,
2217 FT_Pos dy )
2219 return TT_DotFix14( dx, dy,
2220 CUR.GS.dualVector.x,
2221 CUR.GS.dualVector.y );
2225 /*************************************************************************/
2226 /* */
2227 /* <Function> */
2228 /* Project_x */
2229 /* */
2230 /* <Description> */
2231 /* Computes the projection of the vector given by (v2-v1) along the */
2232 /* horizontal axis. */
2233 /* */
2234 /* <Input> */
2235 /* v1 :: First input vector. */
2236 /* v2 :: Second input vector. */
2237 /* */
2238 /* <Return> */
2239 /* The distance in F26dot6 format. */
2240 /* */
2241 static FT_F26Dot6
2242 Project_x( EXEC_OP_ FT_Pos dx,
2243 FT_Pos dy )
2245 FT_UNUSED_EXEC;
2246 FT_UNUSED( dy );
2248 return dx;
2252 /*************************************************************************/
2253 /* */
2254 /* <Function> */
2255 /* Project_y */
2256 /* */
2257 /* <Description> */
2258 /* Computes the projection of the vector given by (v2-v1) along the */
2259 /* vertical axis. */
2260 /* */
2261 /* <Input> */
2262 /* v1 :: First input vector. */
2263 /* v2 :: Second input vector. */
2264 /* */
2265 /* <Return> */
2266 /* The distance in F26dot6 format. */
2267 /* */
2268 static FT_F26Dot6
2269 Project_y( EXEC_OP_ FT_Pos dx,
2270 FT_Pos dy )
2272 FT_UNUSED_EXEC;
2273 FT_UNUSED( dx );
2275 return dy;
2279 /*************************************************************************/
2280 /* */
2281 /* <Function> */
2282 /* Compute_Funcs */
2283 /* */
2284 /* <Description> */
2285 /* Computes the projection and movement function pointers according */
2286 /* to the current graphics state. */
2287 /* */
2288 static void
2289 Compute_Funcs( EXEC_OP )
2291 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2292 if ( CUR.face->unpatented_hinting )
2294 /* If both vectors point rightwards along the x axis, set */
2295 /* `both-x-axis' true, otherwise set it false. The x values only */
2296 /* need be tested because the vector has been normalised to a unit */
2297 /* vector of length 0x4000 = unity. */
2298 CUR.GS.both_x_axis = (FT_Bool)( CUR.GS.projVector.x == 0x4000 &&
2299 CUR.GS.freeVector.x == 0x4000 );
2301 /* Throw away projection and freedom vector information */
2302 /* because the patents don't allow them to be stored. */
2303 /* The relevant US Patents are 5155805 and 5325479. */
2304 CUR.GS.projVector.x = 0;
2305 CUR.GS.projVector.y = 0;
2306 CUR.GS.freeVector.x = 0;
2307 CUR.GS.freeVector.y = 0;
2309 if ( CUR.GS.both_x_axis )
2311 CUR.func_project = Project_x;
2312 CUR.func_move = Direct_Move_X;
2313 CUR.func_move_orig = Direct_Move_Orig_X;
2315 else
2317 CUR.func_project = Project_y;
2318 CUR.func_move = Direct_Move_Y;
2319 CUR.func_move_orig = Direct_Move_Orig_Y;
2322 if ( CUR.GS.dualVector.x == 0x4000 )
2323 CUR.func_dualproj = Project_x;
2324 else
2326 if ( CUR.GS.dualVector.y == 0x4000 )
2327 CUR.func_dualproj = Project_y;
2328 else
2329 CUR.func_dualproj = Dual_Project;
2332 /* Force recalculation of cached aspect ratio */
2333 CUR.tt_metrics.ratio = 0;
2335 return;
2337 #endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING */
2339 if ( CUR.GS.freeVector.x == 0x4000 )
2340 CUR.F_dot_P = CUR.GS.projVector.x * 0x10000L;
2341 else
2343 if ( CUR.GS.freeVector.y == 0x4000 )
2344 CUR.F_dot_P = CUR.GS.projVector.y * 0x10000L;
2345 else
2346 CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
2347 (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
2350 if ( CUR.GS.projVector.x == 0x4000 )
2351 CUR.func_project = (TT_Project_Func)Project_x;
2352 else
2354 if ( CUR.GS.projVector.y == 0x4000 )
2355 CUR.func_project = (TT_Project_Func)Project_y;
2356 else
2357 CUR.func_project = (TT_Project_Func)Project;
2360 if ( CUR.GS.dualVector.x == 0x4000 )
2361 CUR.func_dualproj = (TT_Project_Func)Project_x;
2362 else
2364 if ( CUR.GS.dualVector.y == 0x4000 )
2365 CUR.func_dualproj = (TT_Project_Func)Project_y;
2366 else
2367 CUR.func_dualproj = (TT_Project_Func)Dual_Project;
2370 CUR.func_move = (TT_Move_Func)Direct_Move;
2371 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig;
2373 if ( CUR.F_dot_P == 0x40000000L )
2375 if ( CUR.GS.freeVector.x == 0x4000 )
2377 CUR.func_move = (TT_Move_Func)Direct_Move_X;
2378 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;
2380 else
2382 if ( CUR.GS.freeVector.y == 0x4000 )
2384 CUR.func_move = (TT_Move_Func)Direct_Move_Y;
2385 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
2390 /* at small sizes, F_dot_P can become too small, resulting */
2391 /* in overflows and `spikes' in a number of glyphs like `w'. */
2393 if ( FT_ABS( CUR.F_dot_P ) < 0x4000000L )
2394 CUR.F_dot_P = 0x40000000L;
2396 /* Disable cached aspect ratio */
2397 CUR.tt_metrics.ratio = 0;
2401 /*************************************************************************/
2402 /* */
2403 /* <Function> */
2404 /* Normalize */
2405 /* */
2406 /* <Description> */
2407 /* Norms a vector. */
2408 /* */
2409 /* <Input> */
2410 /* Vx :: The horizontal input vector coordinate. */
2411 /* Vy :: The vertical input vector coordinate. */
2412 /* */
2413 /* <Output> */
2414 /* R :: The normed unit vector. */
2415 /* */
2416 /* <Return> */
2417 /* Returns FAILURE if a vector parameter is zero. */
2418 /* */
2419 /* <Note> */
2420 /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
2421 /* R is undefined. */
2422 /* */
2425 static FT_Bool
2426 Normalize( EXEC_OP_ FT_F26Dot6 Vx,
2427 FT_F26Dot6 Vy,
2428 FT_UnitVector* R )
2430 FT_F26Dot6 W;
2431 FT_Bool S1, S2;
2433 FT_UNUSED_EXEC;
2436 if ( FT_ABS( Vx ) < 0x10000L && FT_ABS( Vy ) < 0x10000L )
2438 Vx *= 0x100;
2439 Vy *= 0x100;
2441 W = TT_VecLen( Vx, Vy );
2443 if ( W == 0 )
2445 /* XXX: UNDOCUMENTED! It seems that it is possible to try */
2446 /* to normalize the vector (0,0). Return immediately. */
2447 return SUCCESS;
2450 R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W );
2451 R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W );
2453 return SUCCESS;
2456 W = TT_VecLen( Vx, Vy );
2458 Vx = FT_MulDiv( Vx, 0x4000L, W );
2459 Vy = FT_MulDiv( Vy, 0x4000L, W );
2461 W = Vx * Vx + Vy * Vy;
2463 /* Now, we want that Sqrt( W ) = 0x4000 */
2464 /* Or 0x10000000 <= W < 0x10004000 */
2466 if ( Vx < 0 )
2468 Vx = -Vx;
2469 S1 = TRUE;
2471 else
2472 S1 = FALSE;
2474 if ( Vy < 0 )
2476 Vy = -Vy;
2477 S2 = TRUE;
2479 else
2480 S2 = FALSE;
2482 while ( W < 0x10000000L )
2484 /* We need to increase W by a minimal amount */
2485 if ( Vx < Vy )
2486 Vx++;
2487 else
2488 Vy++;
2490 W = Vx * Vx + Vy * Vy;
2493 while ( W >= 0x10004000L )
2495 /* We need to decrease W by a minimal amount */
2496 if ( Vx < Vy )
2497 Vx--;
2498 else
2499 Vy--;
2501 W = Vx * Vx + Vy * Vy;
2504 /* Note that in various cases, we can only */
2505 /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
2507 if ( S1 )
2508 Vx = -Vx;
2510 if ( S2 )
2511 Vy = -Vy;
2513 R->x = (FT_F2Dot14)Vx; /* Type conversion */
2514 R->y = (FT_F2Dot14)Vy; /* Type conversion */
2516 return SUCCESS;
2520 /*************************************************************************/
2521 /* */
2522 /* Here we start with the implementation of the various opcodes. */
2523 /* */
2524 /*************************************************************************/
2527 static FT_Bool
2528 Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1,
2529 FT_UShort aIdx2,
2530 FT_Int aOpc,
2531 FT_UnitVector* Vec )
2533 FT_Long A, B, C;
2534 FT_Vector* p1;
2535 FT_Vector* p2;
2538 if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
2539 BOUNDS( aIdx2, CUR.zp1.n_points ) )
2541 if ( CUR.pedantic_hinting )
2542 CUR.error = TT_Err_Invalid_Reference;
2543 return FAILURE;
2546 p1 = CUR.zp1.cur + aIdx2;
2547 p2 = CUR.zp2.cur + aIdx1;
2549 A = p1->x - p2->x;
2550 B = p1->y - p2->y;
2552 if ( ( aOpc & 1 ) != 0 )
2554 C = B; /* counter clockwise rotation */
2555 B = A;
2556 A = -C;
2559 NORMalize( A, B, Vec );
2561 return SUCCESS;
2565 /* When not using the big switch statements, the interpreter uses a */
2566 /* call table defined later below in this source. Each opcode must */
2567 /* thus have a corresponding function, even trivial ones. */
2568 /* */
2569 /* They are all defined there. */
2571 #define DO_SVTCA \
2573 FT_Short A, B; \
2576 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2577 B = A ^ (FT_Short)0x4000; \
2579 CUR.GS.freeVector.x = A; \
2580 CUR.GS.projVector.x = A; \
2581 CUR.GS.dualVector.x = A; \
2583 CUR.GS.freeVector.y = B; \
2584 CUR.GS.projVector.y = B; \
2585 CUR.GS.dualVector.y = B; \
2587 COMPUTE_Funcs(); \
2591 #define DO_SPVTCA \
2593 FT_Short A, B; \
2596 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2597 B = A ^ (FT_Short)0x4000; \
2599 CUR.GS.projVector.x = A; \
2600 CUR.GS.dualVector.x = A; \
2602 CUR.GS.projVector.y = B; \
2603 CUR.GS.dualVector.y = B; \
2605 GUESS_VECTOR( freeVector ); \
2607 COMPUTE_Funcs(); \
2611 #define DO_SFVTCA \
2613 FT_Short A, B; \
2616 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2617 B = A ^ (FT_Short)0x4000; \
2619 CUR.GS.freeVector.x = A; \
2620 CUR.GS.freeVector.y = B; \
2622 GUESS_VECTOR( projVector ); \
2624 COMPUTE_Funcs(); \
2628 #define DO_SPVTL \
2629 if ( INS_SxVTL( (FT_UShort)args[1], \
2630 (FT_UShort)args[0], \
2631 CUR.opcode, \
2632 &CUR.GS.projVector ) == SUCCESS ) \
2634 CUR.GS.dualVector = CUR.GS.projVector; \
2635 GUESS_VECTOR( freeVector ); \
2636 COMPUTE_Funcs(); \
2640 #define DO_SFVTL \
2641 if ( INS_SxVTL( (FT_UShort)args[1], \
2642 (FT_UShort)args[0], \
2643 CUR.opcode, \
2644 &CUR.GS.freeVector ) == SUCCESS ) \
2646 GUESS_VECTOR( projVector ); \
2647 COMPUTE_Funcs(); \
2651 #define DO_SFVTPV \
2652 GUESS_VECTOR( projVector ); \
2653 CUR.GS.freeVector = CUR.GS.projVector; \
2654 COMPUTE_Funcs();
2657 #define DO_SPVFS \
2659 FT_Short S; \
2660 FT_Long X, Y; \
2663 /* Only use low 16bits, then sign extend */ \
2664 S = (FT_Short)args[1]; \
2665 Y = (FT_Long)S; \
2666 S = (FT_Short)args[0]; \
2667 X = (FT_Long)S; \
2669 NORMalize( X, Y, &CUR.GS.projVector ); \
2671 CUR.GS.dualVector = CUR.GS.projVector; \
2672 GUESS_VECTOR( freeVector ); \
2673 COMPUTE_Funcs(); \
2677 #define DO_SFVFS \
2679 FT_Short S; \
2680 FT_Long X, Y; \
2683 /* Only use low 16bits, then sign extend */ \
2684 S = (FT_Short)args[1]; \
2685 Y = (FT_Long)S; \
2686 S = (FT_Short)args[0]; \
2687 X = S; \
2689 NORMalize( X, Y, &CUR.GS.freeVector ); \
2690 GUESS_VECTOR( projVector ); \
2691 COMPUTE_Funcs(); \
2695 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2696 #define DO_GPV \
2697 if ( CUR.face->unpatented_hinting ) \
2699 args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
2700 args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
2702 else \
2704 args[0] = CUR.GS.projVector.x; \
2705 args[1] = CUR.GS.projVector.y; \
2707 #else
2708 #define DO_GPV \
2709 args[0] = CUR.GS.projVector.x; \
2710 args[1] = CUR.GS.projVector.y;
2711 #endif
2714 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2715 #define DO_GFV \
2716 if ( CUR.face->unpatented_hinting ) \
2718 args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
2719 args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
2721 else \
2723 args[0] = CUR.GS.freeVector.x; \
2724 args[1] = CUR.GS.freeVector.y; \
2726 #else
2727 #define DO_GFV \
2728 args[0] = CUR.GS.freeVector.x; \
2729 args[1] = CUR.GS.freeVector.y;
2730 #endif
2733 #define DO_SRP0 \
2734 CUR.GS.rp0 = (FT_UShort)args[0];
2737 #define DO_SRP1 \
2738 CUR.GS.rp1 = (FT_UShort)args[0];
2741 #define DO_SRP2 \
2742 CUR.GS.rp2 = (FT_UShort)args[0];
2745 #define DO_RTHG \
2746 CUR.GS.round_state = TT_Round_To_Half_Grid; \
2747 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2750 #define DO_RTG \
2751 CUR.GS.round_state = TT_Round_To_Grid; \
2752 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2755 #define DO_RTDG \
2756 CUR.GS.round_state = TT_Round_To_Double_Grid; \
2757 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2760 #define DO_RUTG \
2761 CUR.GS.round_state = TT_Round_Up_To_Grid; \
2762 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2765 #define DO_RDTG \
2766 CUR.GS.round_state = TT_Round_Down_To_Grid; \
2767 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2770 #define DO_ROFF \
2771 CUR.GS.round_state = TT_Round_Off; \
2772 CUR.func_round = (TT_Round_Func)Round_None;
2775 #define DO_SROUND \
2776 SET_SuperRound( 0x4000, args[0] ); \
2777 CUR.GS.round_state = TT_Round_Super; \
2778 CUR.func_round = (TT_Round_Func)Round_Super;
2781 #define DO_S45ROUND \
2782 SET_SuperRound( 0x2D41, args[0] ); \
2783 CUR.GS.round_state = TT_Round_Super_45; \
2784 CUR.func_round = (TT_Round_Func)Round_Super_45;
2787 #define DO_SLOOP \
2788 if ( args[0] < 0 ) \
2789 CUR.error = TT_Err_Bad_Argument; \
2790 else \
2791 CUR.GS.loop = args[0];
2794 #define DO_SMD \
2795 CUR.GS.minimum_distance = args[0];
2798 #define DO_SCVTCI \
2799 CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
2802 #define DO_SSWCI \
2803 CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
2806 /* XXX: UNDOCUMENTED! or bug in the Windows engine? */
2807 /* */
2808 /* It seems that the value that is read here is */
2809 /* expressed in 16.16 format rather than in font */
2810 /* units. */
2811 /* */
2812 #define DO_SSW \
2813 CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
2816 #define DO_FLIPON \
2817 CUR.GS.auto_flip = TRUE;
2820 #define DO_FLIPOFF \
2821 CUR.GS.auto_flip = FALSE;
2824 #define DO_SDB \
2825 CUR.GS.delta_base = (FT_Short)args[0];
2828 #define DO_SDS \
2829 CUR.GS.delta_shift = (FT_Short)args[0];
2832 #define DO_MD /* nothing */
2835 #define DO_MPPEM \
2836 args[0] = CURRENT_Ppem();
2839 /* Note: The pointSize should be irrelevant in a given font program; */
2840 /* we thus decide to return only the ppem. */
2841 #if 0
2843 #define DO_MPS \
2844 args[0] = CUR.metrics.pointSize;
2846 #else
2848 #define DO_MPS \
2849 args[0] = CURRENT_Ppem();
2851 #endif /* 0 */
2854 #define DO_DUP \
2855 args[1] = args[0];
2858 #define DO_CLEAR \
2859 CUR.new_top = 0;
2862 #define DO_SWAP \
2864 FT_Long L; \
2867 L = args[0]; \
2868 args[0] = args[1]; \
2869 args[1] = L; \
2873 #define DO_DEPTH \
2874 args[0] = CUR.top;
2877 #define DO_CINDEX \
2879 FT_Long L; \
2882 L = args[0]; \
2884 if ( L <= 0 || L > CUR.args ) \
2885 CUR.error = TT_Err_Invalid_Reference; \
2886 else \
2887 args[0] = CUR.stack[CUR.args - L]; \
2891 #define DO_JROT \
2892 if ( args[1] != 0 ) \
2894 CUR.IP += args[0]; \
2895 CUR.step_ins = FALSE; \
2899 #define DO_JMPR \
2900 CUR.IP += args[0]; \
2901 CUR.step_ins = FALSE;
2904 #define DO_JROF \
2905 if ( args[1] == 0 ) \
2907 CUR.IP += args[0]; \
2908 CUR.step_ins = FALSE; \
2912 #define DO_LT \
2913 args[0] = ( args[0] < args[1] );
2916 #define DO_LTEQ \
2917 args[0] = ( args[0] <= args[1] );
2920 #define DO_GT \
2921 args[0] = ( args[0] > args[1] );
2924 #define DO_GTEQ \
2925 args[0] = ( args[0] >= args[1] );
2928 #define DO_EQ \
2929 args[0] = ( args[0] == args[1] );
2932 #define DO_NEQ \
2933 args[0] = ( args[0] != args[1] );
2936 #define DO_ODD \
2937 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
2940 #define DO_EVEN \
2941 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
2944 #define DO_AND \
2945 args[0] = ( args[0] && args[1] );
2948 #define DO_OR \
2949 args[0] = ( args[0] || args[1] );
2952 #define DO_NOT \
2953 args[0] = !args[0];
2956 #define DO_ADD \
2957 args[0] += args[1];
2960 #define DO_SUB \
2961 args[0] -= args[1];
2964 #define DO_DIV \
2965 if ( args[1] == 0 ) \
2966 CUR.error = TT_Err_Divide_By_Zero; \
2967 else \
2968 args[0] = TT_MULDIV_NO_ROUND( args[0], 64L, args[1] );
2971 #define DO_MUL \
2972 args[0] = TT_MULDIV( args[0], args[1], 64L );
2975 #define DO_ABS \
2976 args[0] = FT_ABS( args[0] );
2979 #define DO_NEG \
2980 args[0] = -args[0];
2983 #define DO_FLOOR \
2984 args[0] = FT_PIX_FLOOR( args[0] );
2987 #define DO_CEILING \
2988 args[0] = FT_PIX_CEIL( args[0] );
2991 #define DO_RS \
2993 FT_ULong I = (FT_ULong)args[0]; \
2996 if ( BOUNDS( I, CUR.storeSize ) ) \
2998 if ( CUR.pedantic_hinting ) \
3000 ARRAY_BOUND_ERROR; \
3002 else \
3003 args[0] = 0; \
3005 else \
3006 args[0] = CUR.storage[I]; \
3010 #define DO_WS \
3012 FT_ULong I = (FT_ULong)args[0]; \
3015 if ( BOUNDS( I, CUR.storeSize ) ) \
3017 if ( CUR.pedantic_hinting ) \
3019 ARRAY_BOUND_ERROR; \
3022 else \
3023 CUR.storage[I] = args[1]; \
3027 #define DO_RCVT \
3029 FT_ULong I = (FT_ULong)args[0]; \
3032 if ( BOUNDS( I, CUR.cvtSize ) ) \
3034 if ( CUR.pedantic_hinting ) \
3036 ARRAY_BOUND_ERROR; \
3038 else \
3039 args[0] = 0; \
3041 else \
3042 args[0] = CUR_Func_read_cvt( I ); \
3046 #define DO_WCVTP \
3048 FT_ULong I = (FT_ULong)args[0]; \
3051 if ( BOUNDS( I, CUR.cvtSize ) ) \
3053 if ( CUR.pedantic_hinting ) \
3055 ARRAY_BOUND_ERROR; \
3058 else \
3059 CUR_Func_write_cvt( I, args[1] ); \
3063 #define DO_WCVTF \
3065 FT_ULong I = (FT_ULong)args[0]; \
3068 if ( BOUNDS( I, CUR.cvtSize ) ) \
3070 if ( CUR.pedantic_hinting ) \
3072 ARRAY_BOUND_ERROR; \
3075 else \
3076 CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
3080 #define DO_DEBUG \
3081 CUR.error = TT_Err_Debug_OpCode;
3084 #define DO_ROUND \
3085 args[0] = CUR_Func_round( \
3086 args[0], \
3087 CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
3090 #define DO_NROUND \
3091 args[0] = ROUND_None( args[0], \
3092 CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
3095 #define DO_MAX \
3096 if ( args[1] > args[0] ) \
3097 args[0] = args[1];
3100 #define DO_MIN \
3101 if ( args[1] < args[0] ) \
3102 args[0] = args[1];
3105 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
3108 #undef ARRAY_BOUND_ERROR
3109 #define ARRAY_BOUND_ERROR \
3111 CUR.error = TT_Err_Invalid_Reference; \
3112 return; \
3116 /*************************************************************************/
3117 /* */
3118 /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
3119 /* Opcode range: 0x00-0x01 */
3120 /* Stack: --> */
3121 /* */
3122 static void
3123 Ins_SVTCA( INS_ARG )
3125 DO_SVTCA
3129 /*************************************************************************/
3130 /* */
3131 /* SPVTCA[a]: Set PVector to Coordinate Axis */
3132 /* Opcode range: 0x02-0x03 */
3133 /* Stack: --> */
3134 /* */
3135 static void
3136 Ins_SPVTCA( INS_ARG )
3138 DO_SPVTCA
3142 /*************************************************************************/
3143 /* */
3144 /* SFVTCA[a]: Set FVector to Coordinate Axis */
3145 /* Opcode range: 0x04-0x05 */
3146 /* Stack: --> */
3147 /* */
3148 static void
3149 Ins_SFVTCA( INS_ARG )
3151 DO_SFVTCA
3155 /*************************************************************************/
3156 /* */
3157 /* SPVTL[a]: Set PVector To Line */
3158 /* Opcode range: 0x06-0x07 */
3159 /* Stack: uint32 uint32 --> */
3160 /* */
3161 static void
3162 Ins_SPVTL( INS_ARG )
3164 DO_SPVTL
3168 /*************************************************************************/
3169 /* */
3170 /* SFVTL[a]: Set FVector To Line */
3171 /* Opcode range: 0x08-0x09 */
3172 /* Stack: uint32 uint32 --> */
3173 /* */
3174 static void
3175 Ins_SFVTL( INS_ARG )
3177 DO_SFVTL
3181 /*************************************************************************/
3182 /* */
3183 /* SFVTPV[]: Set FVector To PVector */
3184 /* Opcode range: 0x0E */
3185 /* Stack: --> */
3186 /* */
3187 static void
3188 Ins_SFVTPV( INS_ARG )
3190 DO_SFVTPV
3194 /*************************************************************************/
3195 /* */
3196 /* SPVFS[]: Set PVector From Stack */
3197 /* Opcode range: 0x0A */
3198 /* Stack: f2.14 f2.14 --> */
3199 /* */
3200 static void
3201 Ins_SPVFS( INS_ARG )
3203 DO_SPVFS
3207 /*************************************************************************/
3208 /* */
3209 /* SFVFS[]: Set FVector From Stack */
3210 /* Opcode range: 0x0B */
3211 /* Stack: f2.14 f2.14 --> */
3212 /* */
3213 static void
3214 Ins_SFVFS( INS_ARG )
3216 DO_SFVFS
3220 /*************************************************************************/
3221 /* */
3222 /* GPV[]: Get Projection Vector */
3223 /* Opcode range: 0x0C */
3224 /* Stack: ef2.14 --> ef2.14 */
3225 /* */
3226 static void
3227 Ins_GPV( INS_ARG )
3229 DO_GPV
3233 /*************************************************************************/
3234 /* GFV[]: Get Freedom Vector */
3235 /* Opcode range: 0x0D */
3236 /* Stack: ef2.14 --> ef2.14 */
3237 /* */
3238 static void
3239 Ins_GFV( INS_ARG )
3241 DO_GFV
3245 /*************************************************************************/
3246 /* */
3247 /* SRP0[]: Set Reference Point 0 */
3248 /* Opcode range: 0x10 */
3249 /* Stack: uint32 --> */
3250 /* */
3251 static void
3252 Ins_SRP0( INS_ARG )
3254 DO_SRP0
3258 /*************************************************************************/
3259 /* */
3260 /* SRP1[]: Set Reference Point 1 */
3261 /* Opcode range: 0x11 */
3262 /* Stack: uint32 --> */
3263 /* */
3264 static void
3265 Ins_SRP1( INS_ARG )
3267 DO_SRP1
3271 /*************************************************************************/
3272 /* */
3273 /* SRP2[]: Set Reference Point 2 */
3274 /* Opcode range: 0x12 */
3275 /* Stack: uint32 --> */
3276 /* */
3277 static void
3278 Ins_SRP2( INS_ARG )
3280 DO_SRP2
3284 /*************************************************************************/
3285 /* */
3286 /* RTHG[]: Round To Half Grid */
3287 /* Opcode range: 0x19 */
3288 /* Stack: --> */
3289 /* */
3290 static void
3291 Ins_RTHG( INS_ARG )
3293 DO_RTHG
3297 /*************************************************************************/
3298 /* */
3299 /* RTG[]: Round To Grid */
3300 /* Opcode range: 0x18 */
3301 /* Stack: --> */
3302 /* */
3303 static void
3304 Ins_RTG( INS_ARG )
3306 DO_RTG
3310 /*************************************************************************/
3311 /* RTDG[]: Round To Double Grid */
3312 /* Opcode range: 0x3D */
3313 /* Stack: --> */
3314 /* */
3315 static void
3316 Ins_RTDG( INS_ARG )
3318 DO_RTDG
3322 /*************************************************************************/
3323 /* RUTG[]: Round Up To Grid */
3324 /* Opcode range: 0x7C */
3325 /* Stack: --> */
3326 /* */
3327 static void
3328 Ins_RUTG( INS_ARG )
3330 DO_RUTG
3334 /*************************************************************************/
3335 /* */
3336 /* RDTG[]: Round Down To Grid */
3337 /* Opcode range: 0x7D */
3338 /* Stack: --> */
3339 /* */
3340 static void
3341 Ins_RDTG( INS_ARG )
3343 DO_RDTG
3347 /*************************************************************************/
3348 /* */
3349 /* ROFF[]: Round OFF */
3350 /* Opcode range: 0x7A */
3351 /* Stack: --> */
3352 /* */
3353 static void
3354 Ins_ROFF( INS_ARG )
3356 DO_ROFF
3360 /*************************************************************************/
3361 /* */
3362 /* SROUND[]: Super ROUND */
3363 /* Opcode range: 0x76 */
3364 /* Stack: Eint8 --> */
3365 /* */
3366 static void
3367 Ins_SROUND( INS_ARG )
3369 DO_SROUND
3373 /*************************************************************************/
3374 /* */
3375 /* S45ROUND[]: Super ROUND 45 degrees */
3376 /* Opcode range: 0x77 */
3377 /* Stack: uint32 --> */
3378 /* */
3379 static void
3380 Ins_S45ROUND( INS_ARG )
3382 DO_S45ROUND
3386 /*************************************************************************/
3387 /* */
3388 /* SLOOP[]: Set LOOP variable */
3389 /* Opcode range: 0x17 */
3390 /* Stack: int32? --> */
3391 /* */
3392 static void
3393 Ins_SLOOP( INS_ARG )
3395 DO_SLOOP
3399 /*************************************************************************/
3400 /* */
3401 /* SMD[]: Set Minimum Distance */
3402 /* Opcode range: 0x1A */
3403 /* Stack: f26.6 --> */
3404 /* */
3405 static void
3406 Ins_SMD( INS_ARG )
3408 DO_SMD
3412 /*************************************************************************/
3413 /* */
3414 /* SCVTCI[]: Set Control Value Table Cut In */
3415 /* Opcode range: 0x1D */
3416 /* Stack: f26.6 --> */
3417 /* */
3418 static void
3419 Ins_SCVTCI( INS_ARG )
3421 DO_SCVTCI
3425 /*************************************************************************/
3426 /* */
3427 /* SSWCI[]: Set Single Width Cut In */
3428 /* Opcode range: 0x1E */
3429 /* Stack: f26.6 --> */
3430 /* */
3431 static void
3432 Ins_SSWCI( INS_ARG )
3434 DO_SSWCI
3438 /*************************************************************************/
3439 /* */
3440 /* SSW[]: Set Single Width */
3441 /* Opcode range: 0x1F */
3442 /* Stack: int32? --> */
3443 /* */
3444 static void
3445 Ins_SSW( INS_ARG )
3447 DO_SSW
3451 /*************************************************************************/
3452 /* */
3453 /* FLIPON[]: Set auto-FLIP to ON */
3454 /* Opcode range: 0x4D */
3455 /* Stack: --> */
3456 /* */
3457 static void
3458 Ins_FLIPON( INS_ARG )
3460 DO_FLIPON
3464 /*************************************************************************/
3465 /* */
3466 /* FLIPOFF[]: Set auto-FLIP to OFF */
3467 /* Opcode range: 0x4E */
3468 /* Stack: --> */
3469 /* */
3470 static void
3471 Ins_FLIPOFF( INS_ARG )
3473 DO_FLIPOFF
3477 /*************************************************************************/
3478 /* */
3479 /* SANGW[]: Set ANGle Weight */
3480 /* Opcode range: 0x7E */
3481 /* Stack: uint32 --> */
3482 /* */
3483 static void
3484 Ins_SANGW( INS_ARG )
3486 /* instruction not supported anymore */
3490 /*************************************************************************/
3491 /* */
3492 /* SDB[]: Set Delta Base */
3493 /* Opcode range: 0x5E */
3494 /* Stack: uint32 --> */
3495 /* */
3496 static void
3497 Ins_SDB( INS_ARG )
3499 DO_SDB
3503 /*************************************************************************/
3504 /* */
3505 /* SDS[]: Set Delta Shift */
3506 /* Opcode range: 0x5F */
3507 /* Stack: uint32 --> */
3508 /* */
3509 static void
3510 Ins_SDS( INS_ARG )
3512 DO_SDS
3516 /*************************************************************************/
3517 /* */
3518 /* MPPEM[]: Measure Pixel Per EM */
3519 /* Opcode range: 0x4B */
3520 /* Stack: --> Euint16 */
3521 /* */
3522 static void
3523 Ins_MPPEM( INS_ARG )
3525 DO_MPPEM
3529 /*************************************************************************/
3530 /* */
3531 /* MPS[]: Measure Point Size */
3532 /* Opcode range: 0x4C */
3533 /* Stack: --> Euint16 */
3534 /* */
3535 static void
3536 Ins_MPS( INS_ARG )
3538 DO_MPS
3542 /*************************************************************************/
3543 /* */
3544 /* DUP[]: DUPlicate the top stack's element */
3545 /* Opcode range: 0x20 */
3546 /* Stack: StkElt --> StkElt StkElt */
3547 /* */
3548 static void
3549 Ins_DUP( INS_ARG )
3551 DO_DUP
3555 /*************************************************************************/
3556 /* */
3557 /* POP[]: POP the stack's top element */
3558 /* Opcode range: 0x21 */
3559 /* Stack: StkElt --> */
3560 /* */
3561 static void
3562 Ins_POP( INS_ARG )
3564 /* nothing to do */
3568 /*************************************************************************/
3569 /* */
3570 /* CLEAR[]: CLEAR the entire stack */
3571 /* Opcode range: 0x22 */
3572 /* Stack: StkElt... --> */
3573 /* */
3574 static void
3575 Ins_CLEAR( INS_ARG )
3577 DO_CLEAR
3581 /*************************************************************************/
3582 /* */
3583 /* SWAP[]: SWAP the stack's top two elements */
3584 /* Opcode range: 0x23 */
3585 /* Stack: 2 * StkElt --> 2 * StkElt */
3586 /* */
3587 static void
3588 Ins_SWAP( INS_ARG )
3590 DO_SWAP
3594 /*************************************************************************/
3595 /* */
3596 /* DEPTH[]: return the stack DEPTH */
3597 /* Opcode range: 0x24 */
3598 /* Stack: --> uint32 */
3599 /* */
3600 static void
3601 Ins_DEPTH( INS_ARG )
3603 DO_DEPTH
3607 /*************************************************************************/
3608 /* */
3609 /* CINDEX[]: Copy INDEXed element */
3610 /* Opcode range: 0x25 */
3611 /* Stack: int32 --> StkElt */
3612 /* */
3613 static void
3614 Ins_CINDEX( INS_ARG )
3616 DO_CINDEX
3620 /*************************************************************************/
3621 /* */
3622 /* EIF[]: End IF */
3623 /* Opcode range: 0x59 */
3624 /* Stack: --> */
3625 /* */
3626 static void
3627 Ins_EIF( INS_ARG )
3629 /* nothing to do */
3633 /*************************************************************************/
3634 /* */
3635 /* JROT[]: Jump Relative On True */
3636 /* Opcode range: 0x78 */
3637 /* Stack: StkElt int32 --> */
3638 /* */
3639 static void
3640 Ins_JROT( INS_ARG )
3642 DO_JROT
3646 /*************************************************************************/
3647 /* */
3648 /* JMPR[]: JuMP Relative */
3649 /* Opcode range: 0x1C */
3650 /* Stack: int32 --> */
3651 /* */
3652 static void
3653 Ins_JMPR( INS_ARG )
3655 DO_JMPR
3659 /*************************************************************************/
3660 /* */
3661 /* JROF[]: Jump Relative On False */
3662 /* Opcode range: 0x79 */
3663 /* Stack: StkElt int32 --> */
3664 /* */
3665 static void
3666 Ins_JROF( INS_ARG )
3668 DO_JROF
3672 /*************************************************************************/
3673 /* */
3674 /* LT[]: Less Than */
3675 /* Opcode range: 0x50 */
3676 /* Stack: int32? int32? --> bool */
3677 /* */
3678 static void
3679 Ins_LT( INS_ARG )
3681 DO_LT
3685 /*************************************************************************/
3686 /* */
3687 /* LTEQ[]: Less Than or EQual */
3688 /* Opcode range: 0x51 */
3689 /* Stack: int32? int32? --> bool */
3690 /* */
3691 static void
3692 Ins_LTEQ( INS_ARG )
3694 DO_LTEQ
3698 /*************************************************************************/
3699 /* */
3700 /* GT[]: Greater Than */
3701 /* Opcode range: 0x52 */
3702 /* Stack: int32? int32? --> bool */
3703 /* */
3704 static void
3705 Ins_GT( INS_ARG )
3707 DO_GT
3711 /*************************************************************************/
3712 /* */
3713 /* GTEQ[]: Greater Than or EQual */
3714 /* Opcode range: 0x53 */
3715 /* Stack: int32? int32? --> bool */
3716 /* */
3717 static void
3718 Ins_GTEQ( INS_ARG )
3720 DO_GTEQ
3724 /*************************************************************************/
3725 /* */
3726 /* EQ[]: EQual */
3727 /* Opcode range: 0x54 */
3728 /* Stack: StkElt StkElt --> bool */
3729 /* */
3730 static void
3731 Ins_EQ( INS_ARG )
3733 DO_EQ
3737 /*************************************************************************/
3738 /* */
3739 /* NEQ[]: Not EQual */
3740 /* Opcode range: 0x55 */
3741 /* Stack: StkElt StkElt --> bool */
3742 /* */
3743 static void
3744 Ins_NEQ( INS_ARG )
3746 DO_NEQ
3750 /*************************************************************************/
3751 /* */
3752 /* ODD[]: Is ODD */
3753 /* Opcode range: 0x56 */
3754 /* Stack: f26.6 --> bool */
3755 /* */
3756 static void
3757 Ins_ODD( INS_ARG )
3759 DO_ODD
3763 /*************************************************************************/
3764 /* */
3765 /* EVEN[]: Is EVEN */
3766 /* Opcode range: 0x57 */
3767 /* Stack: f26.6 --> bool */
3768 /* */
3769 static void
3770 Ins_EVEN( INS_ARG )
3772 DO_EVEN
3776 /*************************************************************************/
3777 /* */
3778 /* AND[]: logical AND */
3779 /* Opcode range: 0x5A */
3780 /* Stack: uint32 uint32 --> uint32 */
3781 /* */
3782 static void
3783 Ins_AND( INS_ARG )
3785 DO_AND
3789 /*************************************************************************/
3790 /* */
3791 /* OR[]: logical OR */
3792 /* Opcode range: 0x5B */
3793 /* Stack: uint32 uint32 --> uint32 */
3794 /* */
3795 static void
3796 Ins_OR( INS_ARG )
3798 DO_OR
3802 /*************************************************************************/
3803 /* */
3804 /* NOT[]: logical NOT */
3805 /* Opcode range: 0x5C */
3806 /* Stack: StkElt --> uint32 */
3807 /* */
3808 static void
3809 Ins_NOT( INS_ARG )
3811 DO_NOT
3815 /*************************************************************************/
3816 /* */
3817 /* ADD[]: ADD */
3818 /* Opcode range: 0x60 */
3819 /* Stack: f26.6 f26.6 --> f26.6 */
3820 /* */
3821 static void
3822 Ins_ADD( INS_ARG )
3824 DO_ADD
3828 /*************************************************************************/
3829 /* */
3830 /* SUB[]: SUBtract */
3831 /* Opcode range: 0x61 */
3832 /* Stack: f26.6 f26.6 --> f26.6 */
3833 /* */
3834 static void
3835 Ins_SUB( INS_ARG )
3837 DO_SUB
3841 /*************************************************************************/
3842 /* */
3843 /* DIV[]: DIVide */
3844 /* Opcode range: 0x62 */
3845 /* Stack: f26.6 f26.6 --> f26.6 */
3846 /* */
3847 static void
3848 Ins_DIV( INS_ARG )
3850 DO_DIV
3854 /*************************************************************************/
3855 /* */
3856 /* MUL[]: MULtiply */
3857 /* Opcode range: 0x63 */
3858 /* Stack: f26.6 f26.6 --> f26.6 */
3859 /* */
3860 static void
3861 Ins_MUL( INS_ARG )
3863 DO_MUL
3867 /*************************************************************************/
3868 /* */
3869 /* ABS[]: ABSolute value */
3870 /* Opcode range: 0x64 */
3871 /* Stack: f26.6 --> f26.6 */
3872 /* */
3873 static void
3874 Ins_ABS( INS_ARG )
3876 DO_ABS
3880 /*************************************************************************/
3881 /* */
3882 /* NEG[]: NEGate */
3883 /* Opcode range: 0x65 */
3884 /* Stack: f26.6 --> f26.6 */
3885 /* */
3886 static void
3887 Ins_NEG( INS_ARG )
3889 DO_NEG
3893 /*************************************************************************/
3894 /* */
3895 /* FLOOR[]: FLOOR */
3896 /* Opcode range: 0x66 */
3897 /* Stack: f26.6 --> f26.6 */
3898 /* */
3899 static void
3900 Ins_FLOOR( INS_ARG )
3902 DO_FLOOR
3906 /*************************************************************************/
3907 /* */
3908 /* CEILING[]: CEILING */
3909 /* Opcode range: 0x67 */
3910 /* Stack: f26.6 --> f26.6 */
3911 /* */
3912 static void
3913 Ins_CEILING( INS_ARG )
3915 DO_CEILING
3919 /*************************************************************************/
3920 /* */
3921 /* RS[]: Read Store */
3922 /* Opcode range: 0x43 */
3923 /* Stack: uint32 --> uint32 */
3924 /* */
3925 static void
3926 Ins_RS( INS_ARG )
3928 DO_RS
3932 /*************************************************************************/
3933 /* */
3934 /* WS[]: Write Store */
3935 /* Opcode range: 0x42 */
3936 /* Stack: uint32 uint32 --> */
3937 /* */
3938 static void
3939 Ins_WS( INS_ARG )
3941 DO_WS
3945 /*************************************************************************/
3946 /* */
3947 /* WCVTP[]: Write CVT in Pixel units */
3948 /* Opcode range: 0x44 */
3949 /* Stack: f26.6 uint32 --> */
3950 /* */
3951 static void
3952 Ins_WCVTP( INS_ARG )
3954 DO_WCVTP
3958 /*************************************************************************/
3959 /* */
3960 /* WCVTF[]: Write CVT in Funits */
3961 /* Opcode range: 0x70 */
3962 /* Stack: uint32 uint32 --> */
3963 /* */
3964 static void
3965 Ins_WCVTF( INS_ARG )
3967 DO_WCVTF
3971 /*************************************************************************/
3972 /* */
3973 /* RCVT[]: Read CVT */
3974 /* Opcode range: 0x45 */
3975 /* Stack: uint32 --> f26.6 */
3976 /* */
3977 static void
3978 Ins_RCVT( INS_ARG )
3980 DO_RCVT
3984 /*************************************************************************/
3985 /* */
3986 /* AA[]: Adjust Angle */
3987 /* Opcode range: 0x7F */
3988 /* Stack: uint32 --> */
3989 /* */
3990 static void
3991 Ins_AA( INS_ARG )
3993 /* intentionally no longer supported */
3997 /*************************************************************************/
3998 /* */
3999 /* DEBUG[]: DEBUG. Unsupported. */
4000 /* Opcode range: 0x4F */
4001 /* Stack: uint32 --> */
4002 /* */
4003 /* Note: The original instruction pops a value from the stack. */
4004 /* */
4005 static void
4006 Ins_DEBUG( INS_ARG )
4008 DO_DEBUG
4012 /*************************************************************************/
4013 /* */
4014 /* ROUND[ab]: ROUND value */
4015 /* Opcode range: 0x68-0x6B */
4016 /* Stack: f26.6 --> f26.6 */
4017 /* */
4018 static void
4019 Ins_ROUND( INS_ARG )
4021 DO_ROUND
4025 /*************************************************************************/
4026 /* */
4027 /* NROUND[ab]: No ROUNDing of value */
4028 /* Opcode range: 0x6C-0x6F */
4029 /* Stack: f26.6 --> f26.6 */
4030 /* */
4031 static void
4032 Ins_NROUND( INS_ARG )
4034 DO_NROUND
4038 /*************************************************************************/
4039 /* */
4040 /* MAX[]: MAXimum */
4041 /* Opcode range: 0x68 */
4042 /* Stack: int32? int32? --> int32 */
4043 /* */
4044 static void
4045 Ins_MAX( INS_ARG )
4047 DO_MAX
4051 /*************************************************************************/
4052 /* */
4053 /* MIN[]: MINimum */
4054 /* Opcode range: 0x69 */
4055 /* Stack: int32? int32? --> int32 */
4056 /* */
4057 static void
4058 Ins_MIN( INS_ARG )
4060 DO_MIN
4064 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
4067 /*************************************************************************/
4068 /* */
4069 /* The following functions are called as is within the switch statement. */
4070 /* */
4071 /*************************************************************************/
4074 /*************************************************************************/
4075 /* */
4076 /* MINDEX[]: Move INDEXed element */
4077 /* Opcode range: 0x26 */
4078 /* Stack: int32? --> StkElt */
4079 /* */
4080 static void
4081 Ins_MINDEX( INS_ARG )
4083 FT_Long L, K;
4086 L = args[0];
4088 if ( L <= 0 || L > CUR.args )
4090 CUR.error = TT_Err_Invalid_Reference;
4091 return;
4094 K = CUR.stack[CUR.args - L];
4096 FT_ARRAY_MOVE( &CUR.stack[CUR.args - L ],
4097 &CUR.stack[CUR.args - L + 1],
4098 ( L - 1 ) );
4100 CUR.stack[CUR.args - 1] = K;
4104 /*************************************************************************/
4105 /* */
4106 /* ROLL[]: ROLL top three elements */
4107 /* Opcode range: 0x8A */
4108 /* Stack: 3 * StkElt --> 3 * StkElt */
4109 /* */
4110 static void
4111 Ins_ROLL( INS_ARG )
4113 FT_Long A, B, C;
4115 FT_UNUSED_EXEC;
4118 A = args[2];
4119 B = args[1];
4120 C = args[0];
4122 args[2] = C;
4123 args[1] = A;
4124 args[0] = B;
4128 /*************************************************************************/
4129 /* */
4130 /* MANAGING THE FLOW OF CONTROL */
4131 /* */
4132 /* Instructions appear in the specification's order. */
4133 /* */
4134 /*************************************************************************/
4137 static FT_Bool
4138 SkipCode( EXEC_OP )
4140 CUR.IP += CUR.length;
4142 if ( CUR.IP < CUR.codeSize )
4144 CUR.opcode = CUR.code[CUR.IP];
4146 CUR.length = opcode_length[CUR.opcode];
4147 if ( CUR.length < 0 )
4149 if ( CUR.IP + 1 > CUR.codeSize )
4150 goto Fail_Overflow;
4151 CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
4154 if ( CUR.IP + CUR.length <= CUR.codeSize )
4155 return SUCCESS;
4158 Fail_Overflow:
4159 CUR.error = TT_Err_Code_Overflow;
4160 return FAILURE;
4164 /*************************************************************************/
4165 /* */
4166 /* IF[]: IF test */
4167 /* Opcode range: 0x58 */
4168 /* Stack: StkElt --> */
4169 /* */
4170 static void
4171 Ins_IF( INS_ARG )
4173 FT_Int nIfs;
4174 FT_Bool Out;
4177 if ( args[0] != 0 )
4178 return;
4180 nIfs = 1;
4181 Out = 0;
4185 if ( SKIP_Code() == FAILURE )
4186 return;
4188 switch ( CUR.opcode )
4190 case 0x58: /* IF */
4191 nIfs++;
4192 break;
4194 case 0x1B: /* ELSE */
4195 Out = FT_BOOL( nIfs == 1 );
4196 break;
4198 case 0x59: /* EIF */
4199 nIfs--;
4200 Out = FT_BOOL( nIfs == 0 );
4201 break;
4203 } while ( Out == 0 );
4207 /*************************************************************************/
4208 /* */
4209 /* ELSE[]: ELSE */
4210 /* Opcode range: 0x1B */
4211 /* Stack: --> */
4212 /* */
4213 static void
4214 Ins_ELSE( INS_ARG )
4216 FT_Int nIfs;
4218 FT_UNUSED_ARG;
4221 nIfs = 1;
4225 if ( SKIP_Code() == FAILURE )
4226 return;
4228 switch ( CUR.opcode )
4230 case 0x58: /* IF */
4231 nIfs++;
4232 break;
4234 case 0x59: /* EIF */
4235 nIfs--;
4236 break;
4238 } while ( nIfs != 0 );
4242 /*************************************************************************/
4243 /* */
4244 /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
4245 /* */
4246 /* Instructions appear in the specification's order. */
4247 /* */
4248 /*************************************************************************/
4251 /*************************************************************************/
4252 /* */
4253 /* FDEF[]: Function DEFinition */
4254 /* Opcode range: 0x2C */
4255 /* Stack: uint32 --> */
4256 /* */
4257 static void
4258 Ins_FDEF( INS_ARG )
4260 FT_ULong n;
4261 TT_DefRecord* rec;
4262 TT_DefRecord* limit;
4265 /* some font programs are broken enough to redefine functions! */
4266 /* We will then parse the current table. */
4268 rec = CUR.FDefs;
4269 limit = rec + CUR.numFDefs;
4270 n = args[0];
4272 for ( ; rec < limit; rec++ )
4274 if ( rec->opc == n )
4275 break;
4278 if ( rec == limit )
4280 /* check that there is enough room for new functions */
4281 if ( CUR.numFDefs >= CUR.maxFDefs )
4283 CUR.error = TT_Err_Too_Many_Function_Defs;
4284 return;
4286 CUR.numFDefs++;
4289 rec->range = CUR.curRange;
4290 rec->opc = n;
4291 rec->start = CUR.IP + 1;
4292 rec->active = TRUE;
4294 if ( n > CUR.maxFunc )
4295 CUR.maxFunc = n;
4297 /* Now skip the whole function definition. */
4298 /* We don't allow nested IDEFS & FDEFs. */
4300 while ( SKIP_Code() == SUCCESS )
4302 switch ( CUR.opcode )
4304 case 0x89: /* IDEF */
4305 case 0x2C: /* FDEF */
4306 CUR.error = TT_Err_Nested_DEFS;
4307 return;
4309 case 0x2D: /* ENDF */
4310 return;
4316 /*************************************************************************/
4317 /* */
4318 /* ENDF[]: END Function definition */
4319 /* Opcode range: 0x2D */
4320 /* Stack: --> */
4321 /* */
4322 static void
4323 Ins_ENDF( INS_ARG )
4325 TT_CallRec* pRec;
4327 FT_UNUSED_ARG;
4330 if ( CUR.callTop <= 0 ) /* We encountered an ENDF without a call */
4332 CUR.error = TT_Err_ENDF_In_Exec_Stream;
4333 return;
4336 CUR.callTop--;
4338 pRec = &CUR.callStack[CUR.callTop];
4340 pRec->Cur_Count--;
4342 CUR.step_ins = FALSE;
4344 if ( pRec->Cur_Count > 0 )
4346 CUR.callTop++;
4347 CUR.IP = pRec->Cur_Restart;
4349 else
4350 /* Loop through the current function */
4351 INS_Goto_CodeRange( pRec->Caller_Range,
4352 pRec->Caller_IP );
4354 /* Exit the current call frame. */
4356 /* NOTE: If the last instruction of a program is a */
4357 /* CALL or LOOPCALL, the return address is */
4358 /* always out of the code range. This is a */
4359 /* valid address, and it is why we do not test */
4360 /* the result of Ins_Goto_CodeRange() here! */
4364 /*************************************************************************/
4365 /* */
4366 /* CALL[]: CALL function */
4367 /* Opcode range: 0x2B */
4368 /* Stack: uint32? --> */
4369 /* */
4370 static void
4371 Ins_CALL( INS_ARG )
4373 FT_ULong F;
4374 TT_CallRec* pCrec;
4375 TT_DefRecord* def;
4378 /* first of all, check the index */
4380 F = args[0];
4381 if ( BOUNDS( F, CUR.maxFunc + 1 ) )
4382 goto Fail;
4384 /* Except for some old Apple fonts, all functions in a TrueType */
4385 /* font are defined in increasing order, starting from 0. This */
4386 /* means that we normally have */
4387 /* */
4388 /* CUR.maxFunc+1 == CUR.numFDefs */
4389 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4390 /* */
4391 /* If this isn't true, we need to look up the function table. */
4393 def = CUR.FDefs + F;
4394 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
4396 /* look up the FDefs table */
4397 TT_DefRecord* limit;
4400 def = CUR.FDefs;
4401 limit = def + CUR.numFDefs;
4403 while ( def < limit && def->opc != F )
4404 def++;
4406 if ( def == limit )
4407 goto Fail;
4410 /* check that the function is active */
4411 if ( !def->active )
4412 goto Fail;
4414 /* check the call stack */
4415 if ( CUR.callTop >= CUR.callSize )
4417 CUR.error = TT_Err_Stack_Overflow;
4418 return;
4421 pCrec = CUR.callStack + CUR.callTop;
4423 pCrec->Caller_Range = CUR.curRange;
4424 pCrec->Caller_IP = CUR.IP + 1;
4425 pCrec->Cur_Count = 1;
4426 pCrec->Cur_Restart = def->start;
4428 CUR.callTop++;
4430 INS_Goto_CodeRange( def->range,
4431 def->start );
4433 CUR.step_ins = FALSE;
4434 return;
4436 Fail:
4437 CUR.error = TT_Err_Invalid_Reference;
4441 /*************************************************************************/
4442 /* */
4443 /* LOOPCALL[]: LOOP and CALL function */
4444 /* Opcode range: 0x2A */
4445 /* Stack: uint32? Eint16? --> */
4446 /* */
4447 static void
4448 Ins_LOOPCALL( INS_ARG )
4450 FT_ULong F;
4451 TT_CallRec* pCrec;
4452 TT_DefRecord* def;
4455 /* first of all, check the index */
4456 F = args[1];
4457 if ( BOUNDS( F, CUR.maxFunc + 1 ) )
4458 goto Fail;
4460 /* Except for some old Apple fonts, all functions in a TrueType */
4461 /* font are defined in increasing order, starting from 0. This */
4462 /* means that we normally have */
4463 /* */
4464 /* CUR.maxFunc+1 == CUR.numFDefs */
4465 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4466 /* */
4467 /* If this isn't true, we need to look up the function table. */
4469 def = CUR.FDefs + F;
4470 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
4472 /* look up the FDefs table */
4473 TT_DefRecord* limit;
4476 def = CUR.FDefs;
4477 limit = def + CUR.numFDefs;
4479 while ( def < limit && def->opc != F )
4480 def++;
4482 if ( def == limit )
4483 goto Fail;
4486 /* check that the function is active */
4487 if ( !def->active )
4488 goto Fail;
4490 /* check stack */
4491 if ( CUR.callTop >= CUR.callSize )
4493 CUR.error = TT_Err_Stack_Overflow;
4494 return;
4497 if ( args[0] > 0 )
4499 pCrec = CUR.callStack + CUR.callTop;
4501 pCrec->Caller_Range = CUR.curRange;
4502 pCrec->Caller_IP = CUR.IP + 1;
4503 pCrec->Cur_Count = (FT_Int)args[0];
4504 pCrec->Cur_Restart = def->start;
4506 CUR.callTop++;
4508 INS_Goto_CodeRange( def->range, def->start );
4510 CUR.step_ins = FALSE;
4512 return;
4514 Fail:
4515 CUR.error = TT_Err_Invalid_Reference;
4519 /*************************************************************************/
4520 /* */
4521 /* IDEF[]: Instruction DEFinition */
4522 /* Opcode range: 0x89 */
4523 /* Stack: Eint8 --> */
4524 /* */
4525 static void
4526 Ins_IDEF( INS_ARG )
4528 TT_DefRecord* def;
4529 TT_DefRecord* limit;
4532 /* First of all, look for the same function in our table */
4534 def = CUR.IDefs;
4535 limit = def + CUR.numIDefs;
4537 for ( ; def < limit; def++ )
4538 if ( def->opc == (FT_ULong)args[0] )
4539 break;
4541 if ( def == limit )
4543 /* check that there is enough room for a new instruction */
4544 if ( CUR.numIDefs >= CUR.maxIDefs )
4546 CUR.error = TT_Err_Too_Many_Instruction_Defs;
4547 return;
4549 CUR.numIDefs++;
4552 def->opc = args[0];
4553 def->start = CUR.IP+1;
4554 def->range = CUR.curRange;
4555 def->active = TRUE;
4557 if ( (FT_ULong)args[0] > CUR.maxIns )
4558 CUR.maxIns = args[0];
4560 /* Now skip the whole function definition. */
4561 /* We don't allow nested IDEFs & FDEFs. */
4563 while ( SKIP_Code() == SUCCESS )
4565 switch ( CUR.opcode )
4567 case 0x89: /* IDEF */
4568 case 0x2C: /* FDEF */
4569 CUR.error = TT_Err_Nested_DEFS;
4570 return;
4571 case 0x2D: /* ENDF */
4572 return;
4578 /*************************************************************************/
4579 /* */
4580 /* PUSHING DATA ONTO THE INTERPRETER STACK */
4581 /* */
4582 /* Instructions appear in the specification's order. */
4583 /* */
4584 /*************************************************************************/
4587 /*************************************************************************/
4588 /* */
4589 /* NPUSHB[]: PUSH N Bytes */
4590 /* Opcode range: 0x40 */
4591 /* Stack: --> uint32... */
4592 /* */
4593 static void
4594 Ins_NPUSHB( INS_ARG )
4596 FT_UShort L, K;
4599 L = (FT_UShort)CUR.code[CUR.IP + 1];
4601 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4603 CUR.error = TT_Err_Stack_Overflow;
4604 return;
4607 for ( K = 1; K <= L; K++ )
4608 args[K - 1] = CUR.code[CUR.IP + K + 1];
4610 CUR.new_top += L;
4614 /*************************************************************************/
4615 /* */
4616 /* NPUSHW[]: PUSH N Words */
4617 /* Opcode range: 0x41 */
4618 /* Stack: --> int32... */
4619 /* */
4620 static void
4621 Ins_NPUSHW( INS_ARG )
4623 FT_UShort L, K;
4626 L = (FT_UShort)CUR.code[CUR.IP + 1];
4628 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4630 CUR.error = TT_Err_Stack_Overflow;
4631 return;
4634 CUR.IP += 2;
4636 for ( K = 0; K < L; K++ )
4637 args[K] = GET_ShortIns();
4639 CUR.step_ins = FALSE;
4640 CUR.new_top += L;
4644 /*************************************************************************/
4645 /* */
4646 /* PUSHB[abc]: PUSH Bytes */
4647 /* Opcode range: 0xB0-0xB7 */
4648 /* Stack: --> uint32... */
4649 /* */
4650 static void
4651 Ins_PUSHB( INS_ARG )
4653 FT_UShort L, K;
4656 L = (FT_UShort)( CUR.opcode - 0xB0 + 1 );
4658 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4660 CUR.error = TT_Err_Stack_Overflow;
4661 return;
4664 for ( K = 1; K <= L; K++ )
4665 args[K - 1] = CUR.code[CUR.IP + K];
4669 /*************************************************************************/
4670 /* */
4671 /* PUSHW[abc]: PUSH Words */
4672 /* Opcode range: 0xB8-0xBF */
4673 /* Stack: --> int32... */
4674 /* */
4675 static void
4676 Ins_PUSHW( INS_ARG )
4678 FT_UShort L, K;
4681 L = (FT_UShort)( CUR.opcode - 0xB8 + 1 );
4683 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4685 CUR.error = TT_Err_Stack_Overflow;
4686 return;
4689 CUR.IP++;
4691 for ( K = 0; K < L; K++ )
4692 args[K] = GET_ShortIns();
4694 CUR.step_ins = FALSE;
4698 /*************************************************************************/
4699 /* */
4700 /* MANAGING THE GRAPHICS STATE */
4701 /* */
4702 /* Instructions appear in the specs' order. */
4703 /* */
4704 /*************************************************************************/
4707 /*************************************************************************/
4708 /* */
4709 /* GC[a]: Get Coordinate projected onto */
4710 /* Opcode range: 0x46-0x47 */
4711 /* Stack: uint32 --> f26.6 */
4712 /* */
4713 /* BULLSHIT: Measures from the original glyph must be taken along the */
4714 /* dual projection vector! */
4715 /* */
4716 static void
4717 Ins_GC( INS_ARG )
4719 FT_ULong L;
4720 FT_F26Dot6 R;
4723 L = (FT_ULong)args[0];
4725 if ( BOUNDS( L, CUR.zp2.n_points ) )
4727 if ( CUR.pedantic_hinting )
4729 CUR.error = TT_Err_Invalid_Reference;
4730 return;
4732 else
4733 R = 0;
4735 else
4737 if ( CUR.opcode & 1 )
4738 R = CUR_fast_dualproj( &CUR.zp2.org[L] );
4739 else
4740 R = CUR_fast_project( &CUR.zp2.cur[L] );
4743 args[0] = R;
4747 /*************************************************************************/
4748 /* */
4749 /* SCFS[]: Set Coordinate From Stack */
4750 /* Opcode range: 0x48 */
4751 /* Stack: f26.6 uint32 --> */
4752 /* */
4753 /* Formula: */
4754 /* */
4755 /* OA := OA + ( value - OA.p )/( f.p ) * f */
4756 /* */
4757 static void
4758 Ins_SCFS( INS_ARG )
4760 FT_Long K;
4761 FT_UShort L;
4764 L = (FT_UShort)args[0];
4766 if ( BOUNDS( L, CUR.zp2.n_points ) )
4768 if ( CUR.pedantic_hinting )
4769 CUR.error = TT_Err_Invalid_Reference;
4770 return;
4773 K = CUR_fast_project( &CUR.zp2.cur[L] );
4775 CUR_Func_move( &CUR.zp2, L, args[1] - K );
4777 /* not part of the specs, but here for safety */
4779 if ( CUR.GS.gep2 == 0 )
4780 CUR.zp2.org[L] = CUR.zp2.cur[L];
4784 /*************************************************************************/
4785 /* */
4786 /* MD[a]: Measure Distance */
4787 /* Opcode range: 0x49-0x4A */
4788 /* Stack: uint32 uint32 --> f26.6 */
4789 /* */
4790 /* BULLSHIT: Measure taken in the original glyph must be along the dual */
4791 /* projection vector. */
4792 /* */
4793 /* Second BULLSHIT: Flag attributes are inverted! */
4794 /* 0 => measure distance in original outline */
4795 /* 1 => measure distance in grid-fitted outline */
4796 /* */
4797 /* Third one: `zp0 - zp1', and not `zp2 - zp1! */
4798 /* */
4799 static void
4800 Ins_MD( INS_ARG )
4802 FT_UShort K, L;
4803 FT_F26Dot6 D;
4806 K = (FT_UShort)args[1];
4807 L = (FT_UShort)args[0];
4809 if( BOUNDS( L, CUR.zp0.n_points ) ||
4810 BOUNDS( K, CUR.zp1.n_points ) )
4812 if ( CUR.pedantic_hinting )
4814 CUR.error = TT_Err_Invalid_Reference;
4815 return;
4817 D = 0;
4819 else
4821 if ( CUR.opcode & 1 )
4822 D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
4823 else
4825 FT_Vector* vec1 = CUR.zp0.orus + L;
4826 FT_Vector* vec2 = CUR.zp1.orus + K;
4829 if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
4831 /* this should be faster */
4832 D = CUR_Func_dualproj( vec1, vec2 );
4833 D = TT_MULFIX( D, CUR.metrics.x_scale );
4835 else
4837 FT_Vector vec;
4840 vec.x = TT_MULFIX( vec1->x - vec2->x, CUR.metrics.x_scale );
4841 vec.y = TT_MULFIX( vec1->y - vec2->y, CUR.metrics.y_scale );
4843 D = CUR_fast_dualproj( &vec );
4848 args[0] = D;
4852 /*************************************************************************/
4853 /* */
4854 /* SDPVTL[a]: Set Dual PVector to Line */
4855 /* Opcode range: 0x86-0x87 */
4856 /* Stack: uint32 uint32 --> */
4857 /* */
4858 static void
4859 Ins_SDPVTL( INS_ARG )
4861 FT_Long A, B, C;
4862 FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
4865 p1 = (FT_UShort)args[1];
4866 p2 = (FT_UShort)args[0];
4868 if ( BOUNDS( p2, CUR.zp1.n_points ) ||
4869 BOUNDS( p1, CUR.zp2.n_points ) )
4871 if ( CUR.pedantic_hinting )
4872 CUR.error = TT_Err_Invalid_Reference;
4873 return;
4877 FT_Vector* v1 = CUR.zp1.org + p2;
4878 FT_Vector* v2 = CUR.zp2.org + p1;
4881 A = v1->x - v2->x;
4882 B = v1->y - v2->y;
4885 if ( ( CUR.opcode & 1 ) != 0 )
4887 C = B; /* counter clockwise rotation */
4888 B = A;
4889 A = -C;
4892 NORMalize( A, B, &CUR.GS.dualVector );
4895 FT_Vector* v1 = CUR.zp1.cur + p2;
4896 FT_Vector* v2 = CUR.zp2.cur + p1;
4899 A = v1->x - v2->x;
4900 B = v1->y - v2->y;
4903 if ( ( CUR.opcode & 1 ) != 0 )
4905 C = B; /* counter clockwise rotation */
4906 B = A;
4907 A = -C;
4910 NORMalize( A, B, &CUR.GS.projVector );
4912 GUESS_VECTOR( freeVector );
4914 COMPUTE_Funcs();
4918 /*************************************************************************/
4919 /* */
4920 /* SZP0[]: Set Zone Pointer 0 */
4921 /* Opcode range: 0x13 */
4922 /* Stack: uint32 --> */
4923 /* */
4924 static void
4925 Ins_SZP0( INS_ARG )
4927 switch ( (FT_Int)args[0] )
4929 case 0:
4930 CUR.zp0 = CUR.twilight;
4931 break;
4933 case 1:
4934 CUR.zp0 = CUR.pts;
4935 break;
4937 default:
4938 if ( CUR.pedantic_hinting )
4939 CUR.error = TT_Err_Invalid_Reference;
4940 return;
4943 CUR.GS.gep0 = (FT_UShort)args[0];
4947 /*************************************************************************/
4948 /* */
4949 /* SZP1[]: Set Zone Pointer 1 */
4950 /* Opcode range: 0x14 */
4951 /* Stack: uint32 --> */
4952 /* */
4953 static void
4954 Ins_SZP1( INS_ARG )
4956 switch ( (FT_Int)args[0] )
4958 case 0:
4959 CUR.zp1 = CUR.twilight;
4960 break;
4962 case 1:
4963 CUR.zp1 = CUR.pts;
4964 break;
4966 default:
4967 if ( CUR.pedantic_hinting )
4968 CUR.error = TT_Err_Invalid_Reference;
4969 return;
4972 CUR.GS.gep1 = (FT_UShort)args[0];
4976 /*************************************************************************/
4977 /* */
4978 /* SZP2[]: Set Zone Pointer 2 */
4979 /* Opcode range: 0x15 */
4980 /* Stack: uint32 --> */
4981 /* */
4982 static void
4983 Ins_SZP2( INS_ARG )
4985 switch ( (FT_Int)args[0] )
4987 case 0:
4988 CUR.zp2 = CUR.twilight;
4989 break;
4991 case 1:
4992 CUR.zp2 = CUR.pts;
4993 break;
4995 default:
4996 if ( CUR.pedantic_hinting )
4997 CUR.error = TT_Err_Invalid_Reference;
4998 return;
5001 CUR.GS.gep2 = (FT_UShort)args[0];
5005 /*************************************************************************/
5006 /* */
5007 /* SZPS[]: Set Zone PointerS */
5008 /* Opcode range: 0x16 */
5009 /* Stack: uint32 --> */
5010 /* */
5011 static void
5012 Ins_SZPS( INS_ARG )
5014 switch ( (FT_Int)args[0] )
5016 case 0:
5017 CUR.zp0 = CUR.twilight;
5018 break;
5020 case 1:
5021 CUR.zp0 = CUR.pts;
5022 break;
5024 default:
5025 if ( CUR.pedantic_hinting )
5026 CUR.error = TT_Err_Invalid_Reference;
5027 return;
5030 CUR.zp1 = CUR.zp0;
5031 CUR.zp2 = CUR.zp0;
5033 CUR.GS.gep0 = (FT_UShort)args[0];
5034 CUR.GS.gep1 = (FT_UShort)args[0];
5035 CUR.GS.gep2 = (FT_UShort)args[0];
5039 /*************************************************************************/
5040 /* */
5041 /* INSTCTRL[]: INSTruction ConTRoL */
5042 /* Opcode range: 0x8e */
5043 /* Stack: int32 int32 --> */
5044 /* */
5045 static void
5046 Ins_INSTCTRL( INS_ARG )
5048 FT_Long K, L;
5051 K = args[1];
5052 L = args[0];
5054 if ( K < 1 || K > 2 )
5056 if ( CUR.pedantic_hinting )
5057 CUR.error = TT_Err_Invalid_Reference;
5058 return;
5061 if ( L != 0 )
5062 L = K;
5064 CUR.GS.instruct_control = FT_BOOL(
5065 ( (FT_Byte)CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L );
5069 /*************************************************************************/
5070 /* */
5071 /* SCANCTRL[]: SCAN ConTRoL */
5072 /* Opcode range: 0x85 */
5073 /* Stack: uint32? --> */
5074 /* */
5075 static void
5076 Ins_SCANCTRL( INS_ARG )
5078 FT_Int A;
5081 /* Get Threshold */
5082 A = (FT_Int)( args[0] & 0xFF );
5084 if ( A == 0xFF )
5086 CUR.GS.scan_control = TRUE;
5087 return;
5089 else if ( A == 0 )
5091 CUR.GS.scan_control = FALSE;
5092 return;
5095 if ( ( args[0] & 0x100 ) != 0 && CUR.tt_metrics.ppem < A )
5096 CUR.GS.scan_control = TRUE;
5098 if ( ( args[0] & 0x200 ) != 0 && CUR.tt_metrics.rotated )
5099 CUR.GS.scan_control = TRUE;
5101 if ( ( args[0] & 0x400 ) != 0 && CUR.tt_metrics.stretched )
5102 CUR.GS.scan_control = TRUE;
5104 if ( ( args[0] & 0x800 ) != 0 && CUR.tt_metrics.ppem >= A )
5105 CUR.GS.scan_control = FALSE;
5107 if ( ( args[0] & 0x1000 ) != 0 && CUR.tt_metrics.rotated )
5108 CUR.GS.scan_control = FALSE;
5110 if ( ( args[0] & 0x2000 ) != 0 && CUR.tt_metrics.stretched )
5111 CUR.GS.scan_control = FALSE;
5115 /*************************************************************************/
5116 /* */
5117 /* SCANTYPE[]: SCAN TYPE */
5118 /* Opcode range: 0x8D */
5119 /* Stack: uint32? --> */
5120 /* */
5121 static void
5122 Ins_SCANTYPE( INS_ARG )
5124 if ( args[0] >= 0 )
5125 CUR.GS.scan_type = (FT_Int)args[0];
5129 /*************************************************************************/
5130 /* */
5131 /* MANAGING OUTLINES */
5132 /* */
5133 /* Instructions appear in the specification's order. */
5134 /* */
5135 /*************************************************************************/
5138 /*************************************************************************/
5139 /* */
5140 /* FLIPPT[]: FLIP PoinT */
5141 /* Opcode range: 0x80 */
5142 /* Stack: uint32... --> */
5143 /* */
5144 static void
5145 Ins_FLIPPT( INS_ARG )
5147 FT_UShort point;
5149 FT_UNUSED_ARG;
5152 if ( CUR.top < CUR.GS.loop )
5154 CUR.error = TT_Err_Too_Few_Arguments;
5155 return;
5158 while ( CUR.GS.loop > 0 )
5160 CUR.args--;
5162 point = (FT_UShort)CUR.stack[CUR.args];
5164 if ( BOUNDS( point, CUR.pts.n_points ) )
5166 if ( CUR.pedantic_hinting )
5168 CUR.error = TT_Err_Invalid_Reference;
5169 return;
5172 else
5173 CUR.pts.tags[point] ^= FT_CURVE_TAG_ON;
5175 CUR.GS.loop--;
5178 CUR.GS.loop = 1;
5179 CUR.new_top = CUR.args;
5183 /*************************************************************************/
5184 /* */
5185 /* FLIPRGON[]: FLIP RanGe ON */
5186 /* Opcode range: 0x81 */
5187 /* Stack: uint32 uint32 --> */
5188 /* */
5189 static void
5190 Ins_FLIPRGON( INS_ARG )
5192 FT_UShort I, K, L;
5195 K = (FT_UShort)args[1];
5196 L = (FT_UShort)args[0];
5198 if ( BOUNDS( K, CUR.pts.n_points ) ||
5199 BOUNDS( L, CUR.pts.n_points ) )
5201 if ( CUR.pedantic_hinting )
5202 CUR.error = TT_Err_Invalid_Reference;
5203 return;
5206 for ( I = L; I <= K; I++ )
5207 CUR.pts.tags[I] |= FT_CURVE_TAG_ON;
5211 /*************************************************************************/
5212 /* */
5213 /* FLIPRGOFF: FLIP RanGe OFF */
5214 /* Opcode range: 0x82 */
5215 /* Stack: uint32 uint32 --> */
5216 /* */
5217 static void
5218 Ins_FLIPRGOFF( INS_ARG )
5220 FT_UShort I, K, L;
5223 K = (FT_UShort)args[1];
5224 L = (FT_UShort)args[0];
5226 if ( BOUNDS( K, CUR.pts.n_points ) ||
5227 BOUNDS( L, CUR.pts.n_points ) )
5229 if ( CUR.pedantic_hinting )
5230 CUR.error = TT_Err_Invalid_Reference;
5231 return;
5234 for ( I = L; I <= K; I++ )
5235 CUR.pts.tags[I] &= ~FT_CURVE_TAG_ON;
5239 static FT_Bool
5240 Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6* x,
5241 FT_F26Dot6* y,
5242 TT_GlyphZone zone,
5243 FT_UShort* refp )
5245 TT_GlyphZoneRec zp;
5246 FT_UShort p;
5247 FT_F26Dot6 d;
5250 if ( CUR.opcode & 1 )
5252 zp = CUR.zp0;
5253 p = CUR.GS.rp1;
5255 else
5257 zp = CUR.zp1;
5258 p = CUR.GS.rp2;
5261 if ( BOUNDS( p, zp.n_points ) )
5263 if ( CUR.pedantic_hinting )
5264 CUR.error = TT_Err_Invalid_Reference;
5265 *refp = 0;
5266 return FAILURE;
5269 *zone = zp;
5270 *refp = p;
5272 d = CUR_Func_project( zp.cur + p, zp.org + p );
5274 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5275 if ( CUR.face->unpatented_hinting )
5277 if ( CUR.GS.both_x_axis )
5279 *x = d;
5280 *y = 0;
5282 else
5284 *x = 0;
5285 *y = d;
5288 else
5289 #endif
5291 *x = TT_MULDIV( d,
5292 (FT_Long)CUR.GS.freeVector.x * 0x10000L,
5293 CUR.F_dot_P );
5294 *y = TT_MULDIV( d,
5295 (FT_Long)CUR.GS.freeVector.y * 0x10000L,
5296 CUR.F_dot_P );
5299 return SUCCESS;
5303 static void
5304 Move_Zp2_Point( EXEC_OP_ FT_UShort point,
5305 FT_F26Dot6 dx,
5306 FT_F26Dot6 dy,
5307 FT_Bool touch )
5309 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5310 if ( CUR.face->unpatented_hinting )
5312 if ( CUR.GS.both_x_axis )
5314 CUR.zp2.cur[point].x += dx;
5315 if ( touch )
5316 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
5318 else
5320 CUR.zp2.cur[point].y += dy;
5321 if ( touch )
5322 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
5324 return;
5326 #endif
5328 if ( CUR.GS.freeVector.x != 0 )
5330 CUR.zp2.cur[point].x += dx;
5331 if ( touch )
5332 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
5335 if ( CUR.GS.freeVector.y != 0 )
5337 CUR.zp2.cur[point].y += dy;
5338 if ( touch )
5339 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
5344 /*************************************************************************/
5345 /* */
5346 /* SHP[a]: SHift Point by the last point */
5347 /* Opcode range: 0x32-0x33 */
5348 /* Stack: uint32... --> */
5349 /* */
5350 static void
5351 Ins_SHP( INS_ARG )
5353 TT_GlyphZoneRec zp;
5354 FT_UShort refp;
5356 FT_F26Dot6 dx,
5358 FT_UShort point;
5360 FT_UNUSED_ARG;
5363 if ( CUR.top < CUR.GS.loop )
5365 CUR.error = TT_Err_Invalid_Reference;
5366 return;
5369 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5370 return;
5372 while ( CUR.GS.loop > 0 )
5374 CUR.args--;
5375 point = (FT_UShort)CUR.stack[CUR.args];
5377 if ( BOUNDS( point, CUR.zp2.n_points ) )
5379 if ( CUR.pedantic_hinting )
5381 CUR.error = TT_Err_Invalid_Reference;
5382 return;
5385 else
5386 /* XXX: UNDOCUMENTED! SHP touches the points */
5387 MOVE_Zp2_Point( point, dx, dy, TRUE );
5389 CUR.GS.loop--;
5392 CUR.GS.loop = 1;
5393 CUR.new_top = CUR.args;
5397 /*************************************************************************/
5398 /* */
5399 /* SHC[a]: SHift Contour */
5400 /* Opcode range: 0x34-35 */
5401 /* Stack: uint32 --> */
5402 /* */
5403 static void
5404 Ins_SHC( INS_ARG )
5406 TT_GlyphZoneRec zp;
5407 FT_UShort refp;
5408 FT_F26Dot6 dx,
5411 FT_Short contour;
5412 FT_UShort first_point, last_point, i;
5415 contour = (FT_UShort)args[0];
5417 if ( BOUNDS( contour, CUR.pts.n_contours ) )
5419 if ( CUR.pedantic_hinting )
5420 CUR.error = TT_Err_Invalid_Reference;
5421 return;
5424 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5425 return;
5427 if ( contour == 0 )
5428 first_point = 0;
5429 else
5430 first_point = (FT_UShort)( CUR.pts.contours[contour - 1] + 1 -
5431 CUR.pts.first_point );
5433 last_point = (FT_UShort)( CUR.pts.contours[contour] -
5434 CUR.pts.first_point );
5436 /* XXX: this is probably wrong... at least it prevents memory */
5437 /* corruption when zp2 is the twilight zone */
5438 if ( BOUNDS( last_point, CUR.zp2.n_points ) )
5440 if ( CUR.zp2.n_points > 0 )
5441 last_point = (FT_UShort)(CUR.zp2.n_points - 1);
5442 else
5443 last_point = 0;
5446 /* XXX: UNDOCUMENTED! SHC touches the points */
5447 for ( i = first_point; i <= last_point; i++ )
5449 if ( zp.cur != CUR.zp2.cur || refp != i )
5450 MOVE_Zp2_Point( i, dx, dy, TRUE );
5455 /*************************************************************************/
5456 /* */
5457 /* SHZ[a]: SHift Zone */
5458 /* Opcode range: 0x36-37 */
5459 /* Stack: uint32 --> */
5460 /* */
5461 static void
5462 Ins_SHZ( INS_ARG )
5464 TT_GlyphZoneRec zp;
5465 FT_UShort refp;
5466 FT_F26Dot6 dx,
5469 FT_UShort last_point, i;
5472 if ( BOUNDS( args[0], 2 ) )
5474 if ( CUR.pedantic_hinting )
5475 CUR.error = TT_Err_Invalid_Reference;
5476 return;
5479 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5480 return;
5482 /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */
5483 /* Twilight zone has no contours, so use `n_points'. */
5484 /* Normal zone's `n_points' includes phantoms, so must */
5485 /* use end of last contour. */
5486 if ( CUR.GS.gep2 == 0 && CUR.zp2.n_points > 0 )
5487 last_point = (FT_UShort)( CUR.zp2.n_points - 1 );
5488 else if ( CUR.GS.gep2 == 1 && CUR.zp2.n_contours > 0 )
5489 last_point = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] );
5490 else
5491 last_point = 0;
5493 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
5494 for ( i = 0; i <= last_point; i++ )
5496 if ( zp.cur != CUR.zp2.cur || refp != i )
5497 MOVE_Zp2_Point( i, dx, dy, FALSE );
5502 /*************************************************************************/
5503 /* */
5504 /* SHPIX[]: SHift points by a PIXel amount */
5505 /* Opcode range: 0x38 */
5506 /* Stack: f26.6 uint32... --> */
5507 /* */
5508 static void
5509 Ins_SHPIX( INS_ARG )
5511 FT_F26Dot6 dx, dy;
5512 FT_UShort point;
5515 if ( CUR.top < CUR.GS.loop + 1 )
5517 CUR.error = TT_Err_Invalid_Reference;
5518 return;
5521 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5522 if ( CUR.face->unpatented_hinting )
5524 if ( CUR.GS.both_x_axis )
5526 dx = TT_MulFix14( args[0], 0x4000 );
5527 dy = 0;
5529 else
5531 dx = 0;
5532 dy = TT_MulFix14( args[0], 0x4000 );
5535 else
5536 #endif
5538 dx = TT_MulFix14( args[0], CUR.GS.freeVector.x );
5539 dy = TT_MulFix14( args[0], CUR.GS.freeVector.y );
5542 while ( CUR.GS.loop > 0 )
5544 CUR.args--;
5546 point = (FT_UShort)CUR.stack[CUR.args];
5548 if ( BOUNDS( point, CUR.zp2.n_points ) )
5550 if ( CUR.pedantic_hinting )
5552 CUR.error = TT_Err_Invalid_Reference;
5553 return;
5556 else
5557 MOVE_Zp2_Point( point, dx, dy, TRUE );
5559 CUR.GS.loop--;
5562 CUR.GS.loop = 1;
5563 CUR.new_top = CUR.args;
5567 /*************************************************************************/
5568 /* */
5569 /* MSIRP[a]: Move Stack Indirect Relative Position */
5570 /* Opcode range: 0x3A-0x3B */
5571 /* Stack: f26.6 uint32 --> */
5572 /* */
5573 static void
5574 Ins_MSIRP( INS_ARG )
5576 FT_UShort point;
5577 FT_F26Dot6 distance;
5580 point = (FT_UShort)args[0];
5582 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5583 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5585 if ( CUR.pedantic_hinting )
5586 CUR.error = TT_Err_Invalid_Reference;
5587 return;
5590 /* XXX: UNDOCUMENTED! behaviour */
5591 if ( CUR.GS.gep1 == 0 ) /* if the point that is to be moved */
5592 /* is in twilight zone */
5594 CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
5595 CUR_Func_move_orig( &CUR.zp1, point, args[1] );
5596 CUR.zp1.cur[point] = CUR.zp1.org[point];
5599 distance = CUR_Func_project( CUR.zp1.cur + point,
5600 CUR.zp0.cur + CUR.GS.rp0 );
5602 CUR_Func_move( &CUR.zp1, point, args[1] - distance );
5604 CUR.GS.rp1 = CUR.GS.rp0;
5605 CUR.GS.rp2 = point;
5607 if ( ( CUR.opcode & 1 ) != 0 )
5608 CUR.GS.rp0 = point;
5612 /*************************************************************************/
5613 /* */
5614 /* MDAP[a]: Move Direct Absolute Point */
5615 /* Opcode range: 0x2E-0x2F */
5616 /* Stack: uint32 --> */
5617 /* */
5618 static void
5619 Ins_MDAP( INS_ARG )
5621 FT_UShort point;
5622 FT_F26Dot6 cur_dist,
5623 distance;
5626 point = (FT_UShort)args[0];
5628 if ( BOUNDS( point, CUR.zp0.n_points ) )
5630 if ( CUR.pedantic_hinting )
5631 CUR.error = TT_Err_Invalid_Reference;
5632 return;
5635 /* XXX: Is there some undocumented feature while in the */
5636 /* twilight zone? ? */
5637 if ( ( CUR.opcode & 1 ) != 0 )
5639 cur_dist = CUR_fast_project( &CUR.zp0.cur[point] );
5640 distance = CUR_Func_round( cur_dist,
5641 CUR.tt_metrics.compensations[0] ) - cur_dist;
5643 else
5644 distance = 0;
5646 CUR_Func_move( &CUR.zp0, point, distance );
5648 CUR.GS.rp0 = point;
5649 CUR.GS.rp1 = point;
5653 /*************************************************************************/
5654 /* */
5655 /* MIAP[a]: Move Indirect Absolute Point */
5656 /* Opcode range: 0x3E-0x3F */
5657 /* Stack: uint32 uint32 --> */
5658 /* */
5659 static void
5660 Ins_MIAP( INS_ARG )
5662 FT_ULong cvtEntry;
5663 FT_UShort point;
5664 FT_F26Dot6 distance,
5665 org_dist;
5668 cvtEntry = (FT_ULong)args[1];
5669 point = (FT_UShort)args[0];
5671 if ( BOUNDS( point, CUR.zp0.n_points ) ||
5672 BOUNDS( cvtEntry, CUR.cvtSize ) )
5674 if ( CUR.pedantic_hinting )
5675 CUR.error = TT_Err_Invalid_Reference;
5676 return;
5679 /* XXX: UNDOCUMENTED! */
5680 /* */
5681 /* The behaviour of an MIAP instruction is quite */
5682 /* different when used in the twilight zone. */
5683 /* */
5684 /* First, no control value cut-in test is performed */
5685 /* as it would fail anyway. Second, the original */
5686 /* point, i.e. (org_x,org_y) of zp0.point, is set */
5687 /* to the absolute, unrounded distance found in */
5688 /* the CVT. */
5689 /* */
5690 /* This is used in the CVT programs of the Microsoft */
5691 /* fonts Arial, Times, etc., in order to re-adjust */
5692 /* some key font heights. It allows the use of the */
5693 /* IP instruction in the twilight zone, which */
5694 /* otherwise would be `illegal' according to the */
5695 /* specification. */
5696 /* */
5697 /* We implement it with a special sequence for the */
5698 /* twilight zone. This is a bad hack, but it seems */
5699 /* to work. */
5701 distance = CUR_Func_read_cvt( cvtEntry );
5703 if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */
5705 CUR.zp0.org[point].x = TT_MulFix14( distance, CUR.GS.freeVector.x );
5706 CUR.zp0.org[point].y = TT_MulFix14( distance, CUR.GS.freeVector.y ),
5707 CUR.zp0.cur[point] = CUR.zp0.org[point];
5710 org_dist = CUR_fast_project( &CUR.zp0.cur[point] );
5712 if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */
5714 if ( FT_ABS( distance - org_dist ) > CUR.GS.control_value_cutin )
5715 distance = org_dist;
5717 distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] );
5720 CUR_Func_move( &CUR.zp0, point, distance - org_dist );
5722 CUR.GS.rp0 = point;
5723 CUR.GS.rp1 = point;
5727 /*************************************************************************/
5728 /* */
5729 /* MDRP[abcde]: Move Direct Relative Point */
5730 /* Opcode range: 0xC0-0xDF */
5731 /* Stack: uint32 --> */
5732 /* */
5733 static void
5734 Ins_MDRP( INS_ARG )
5736 FT_UShort point;
5737 FT_F26Dot6 org_dist, distance;
5740 point = (FT_UShort)args[0];
5742 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5743 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5745 if ( CUR.pedantic_hinting )
5746 CUR.error = TT_Err_Invalid_Reference;
5747 return;
5750 /* XXX: Is there some undocumented feature while in the */
5751 /* twilight zone? */
5753 /* XXX: UNDOCUMENTED: twilight zone special case */
5755 if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
5757 FT_Vector* vec1 = &CUR.zp1.org[point];
5758 FT_Vector* vec2 = &CUR.zp0.org[CUR.GS.rp0];
5761 org_dist = CUR_Func_dualproj( vec1, vec2 );
5763 else
5765 FT_Vector* vec1 = &CUR.zp1.orus[point];
5766 FT_Vector* vec2 = &CUR.zp0.orus[CUR.GS.rp0];
5769 if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
5771 /* this should be faster */
5772 org_dist = CUR_Func_dualproj( vec1, vec2 );
5773 org_dist = TT_MULFIX( org_dist, CUR.metrics.x_scale );
5775 else
5777 FT_Vector vec;
5780 vec.x = TT_MULFIX( vec1->x - vec2->x, CUR.metrics.x_scale );
5781 vec.y = TT_MULFIX( vec1->y - vec2->y, CUR.metrics.y_scale );
5783 org_dist = CUR_fast_dualproj( &vec );
5787 /* single width cut-in test */
5789 if ( FT_ABS( org_dist - CUR.GS.single_width_value ) <
5790 CUR.GS.single_width_cutin )
5792 if ( org_dist >= 0 )
5793 org_dist = CUR.GS.single_width_value;
5794 else
5795 org_dist = -CUR.GS.single_width_value;
5798 /* round flag */
5800 if ( ( CUR.opcode & 4 ) != 0 )
5801 distance = CUR_Func_round(
5802 org_dist,
5803 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5804 else
5805 distance = ROUND_None(
5806 org_dist,
5807 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5809 /* minimum distance flag */
5811 if ( ( CUR.opcode & 8 ) != 0 )
5813 if ( org_dist >= 0 )
5815 if ( distance < CUR.GS.minimum_distance )
5816 distance = CUR.GS.minimum_distance;
5818 else
5820 if ( distance > -CUR.GS.minimum_distance )
5821 distance = -CUR.GS.minimum_distance;
5825 /* now move the point */
5827 org_dist = CUR_Func_project( CUR.zp1.cur + point,
5828 CUR.zp0.cur + CUR.GS.rp0 );
5830 CUR_Func_move( &CUR.zp1, point, distance - org_dist );
5832 CUR.GS.rp1 = CUR.GS.rp0;
5833 CUR.GS.rp2 = point;
5835 if ( ( CUR.opcode & 16 ) != 0 )
5836 CUR.GS.rp0 = point;
5840 /*************************************************************************/
5841 /* */
5842 /* MIRP[abcde]: Move Indirect Relative Point */
5843 /* Opcode range: 0xE0-0xFF */
5844 /* Stack: int32? uint32 --> */
5845 /* */
5846 static void
5847 Ins_MIRP( INS_ARG )
5849 FT_UShort point;
5850 FT_ULong cvtEntry;
5852 FT_F26Dot6 cvt_dist,
5853 distance,
5854 cur_dist,
5855 org_dist;
5858 point = (FT_UShort)args[0];
5859 cvtEntry = (FT_ULong)( args[1] + 1 );
5861 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
5863 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5864 BOUNDS( cvtEntry, CUR.cvtSize + 1 ) ||
5865 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5867 if ( CUR.pedantic_hinting )
5868 CUR.error = TT_Err_Invalid_Reference;
5869 return;
5872 if ( !cvtEntry )
5873 cvt_dist = 0;
5874 else
5875 cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
5877 /* single width test */
5879 if ( FT_ABS( cvt_dist - CUR.GS.single_width_value ) <
5880 CUR.GS.single_width_cutin )
5882 if ( cvt_dist >= 0 )
5883 cvt_dist = CUR.GS.single_width_value;
5884 else
5885 cvt_dist = -CUR.GS.single_width_value;
5888 /* XXX: UNDOCUMENTED! -- twilight zone */
5890 if ( CUR.GS.gep1 == 0 )
5892 CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +
5893 TT_MulFix14( cvt_dist, CUR.GS.freeVector.x );
5895 CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
5896 TT_MulFix14( cvt_dist, CUR.GS.freeVector.y );
5898 CUR.zp1.cur[point] = CUR.zp0.cur[point];
5901 org_dist = CUR_Func_dualproj( &CUR.zp1.org[point],
5902 &CUR.zp0.org[CUR.GS.rp0] );
5903 cur_dist = CUR_Func_project ( &CUR.zp1.cur[point],
5904 &CUR.zp0.cur[CUR.GS.rp0] );
5906 /* auto-flip test */
5908 if ( CUR.GS.auto_flip )
5910 if ( ( org_dist ^ cvt_dist ) < 0 )
5911 cvt_dist = -cvt_dist;
5914 /* control value cutin and round */
5916 if ( ( CUR.opcode & 4 ) != 0 )
5918 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
5919 /* refer to the same zone. */
5921 if ( CUR.GS.gep0 == CUR.GS.gep1 )
5922 if ( FT_ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin )
5923 cvt_dist = org_dist;
5925 distance = CUR_Func_round(
5926 cvt_dist,
5927 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5929 else
5930 distance = ROUND_None(
5931 cvt_dist,
5932 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5934 /* minimum distance test */
5936 if ( ( CUR.opcode & 8 ) != 0 )
5938 if ( org_dist >= 0 )
5940 if ( distance < CUR.GS.minimum_distance )
5941 distance = CUR.GS.minimum_distance;
5943 else
5945 if ( distance > -CUR.GS.minimum_distance )
5946 distance = -CUR.GS.minimum_distance;
5950 CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
5952 CUR.GS.rp1 = CUR.GS.rp0;
5954 if ( ( CUR.opcode & 16 ) != 0 )
5955 CUR.GS.rp0 = point;
5957 /* XXX: UNDOCUMENTED! */
5958 CUR.GS.rp2 = point;
5962 /*************************************************************************/
5963 /* */
5964 /* ALIGNRP[]: ALIGN Relative Point */
5965 /* Opcode range: 0x3C */
5966 /* Stack: uint32 uint32... --> */
5967 /* */
5968 static void
5969 Ins_ALIGNRP( INS_ARG )
5971 FT_UShort point;
5972 FT_F26Dot6 distance;
5974 FT_UNUSED_ARG;
5977 if ( CUR.top < CUR.GS.loop ||
5978 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5980 if ( CUR.pedantic_hinting )
5981 CUR.error = TT_Err_Invalid_Reference;
5982 return;
5985 while ( CUR.GS.loop > 0 )
5987 CUR.args--;
5989 point = (FT_UShort)CUR.stack[CUR.args];
5991 if ( BOUNDS( point, CUR.zp1.n_points ) )
5993 if ( CUR.pedantic_hinting )
5995 CUR.error = TT_Err_Invalid_Reference;
5996 return;
5999 else
6001 distance = CUR_Func_project( CUR.zp1.cur + point,
6002 CUR.zp0.cur + CUR.GS.rp0 );
6004 CUR_Func_move( &CUR.zp1, point, -distance );
6007 CUR.GS.loop--;
6010 CUR.GS.loop = 1;
6011 CUR.new_top = CUR.args;
6015 /*************************************************************************/
6016 /* */
6017 /* ISECT[]: moves point to InterSECTion */
6018 /* Opcode range: 0x0F */
6019 /* Stack: 5 * uint32 --> */
6020 /* */
6021 static void
6022 Ins_ISECT( INS_ARG )
6024 FT_UShort point,
6025 a0, a1,
6026 b0, b1;
6028 FT_F26Dot6 discriminant;
6030 FT_F26Dot6 dx, dy,
6031 dax, day,
6032 dbx, dby;
6034 FT_F26Dot6 val;
6036 FT_Vector R;
6039 point = (FT_UShort)args[0];
6041 a0 = (FT_UShort)args[1];
6042 a1 = (FT_UShort)args[2];
6043 b0 = (FT_UShort)args[3];
6044 b1 = (FT_UShort)args[4];
6046 if ( BOUNDS( b0, CUR.zp0.n_points ) ||
6047 BOUNDS( b1, CUR.zp0.n_points ) ||
6048 BOUNDS( a0, CUR.zp1.n_points ) ||
6049 BOUNDS( a1, CUR.zp1.n_points ) ||
6050 BOUNDS( point, CUR.zp2.n_points ) )
6052 if ( CUR.pedantic_hinting )
6053 CUR.error = TT_Err_Invalid_Reference;
6054 return;
6057 dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
6058 dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
6060 dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;
6061 day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;
6063 dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;
6064 dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;
6066 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
6068 discriminant = TT_MULDIV( dax, -dby, 0x40 ) +
6069 TT_MULDIV( day, dbx, 0x40 );
6071 if ( FT_ABS( discriminant ) >= 0x40 )
6073 val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 );
6075 R.x = TT_MULDIV( val, dax, discriminant );
6076 R.y = TT_MULDIV( val, day, discriminant );
6078 CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
6079 CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
6081 else
6083 /* else, take the middle of the middles of A and B */
6085 CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +
6086 CUR.zp1.cur[a1].x +
6087 CUR.zp0.cur[b0].x +
6088 CUR.zp0.cur[b1].x ) / 4;
6089 CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +
6090 CUR.zp1.cur[a1].y +
6091 CUR.zp0.cur[b0].y +
6092 CUR.zp0.cur[b1].y ) / 4;
6097 /*************************************************************************/
6098 /* */
6099 /* ALIGNPTS[]: ALIGN PoinTS */
6100 /* Opcode range: 0x27 */
6101 /* Stack: uint32 uint32 --> */
6102 /* */
6103 static void
6104 Ins_ALIGNPTS( INS_ARG )
6106 FT_UShort p1, p2;
6107 FT_F26Dot6 distance;
6110 p1 = (FT_UShort)args[0];
6111 p2 = (FT_UShort)args[1];
6113 if ( BOUNDS( args[0], CUR.zp1.n_points ) ||
6114 BOUNDS( args[1], CUR.zp0.n_points ) )
6116 if ( CUR.pedantic_hinting )
6117 CUR.error = TT_Err_Invalid_Reference;
6118 return;
6121 distance = CUR_Func_project( CUR.zp0.cur + p2,
6122 CUR.zp1.cur + p1 ) / 2;
6124 CUR_Func_move( &CUR.zp1, p1, distance );
6125 CUR_Func_move( &CUR.zp0, p2, -distance );
6129 /*************************************************************************/
6130 /* */
6131 /* IP[]: Interpolate Point */
6132 /* Opcode range: 0x39 */
6133 /* Stack: uint32... --> */
6134 /* */
6136 /* SOMETIMES, DUMBER CODE IS BETTER CODE */
6138 static void
6139 Ins_IP( INS_ARG )
6141 FT_F26Dot6 old_range, cur_range;
6142 FT_Vector* orus_base;
6143 FT_Vector* cur_base;
6144 FT_Int twilight;
6146 FT_UNUSED_ARG;
6149 if ( CUR.top < CUR.GS.loop )
6151 CUR.error = TT_Err_Invalid_Reference;
6152 return;
6156 * We need to deal in a special way with the twilight zone.
6157 * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0),
6158 * for every n.
6160 twilight = CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 || CUR.GS.gep2 == 0;
6162 if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) )
6164 if ( CUR.pedantic_hinting )
6165 CUR.error = TT_Err_Invalid_Reference;
6166 return;
6169 if ( twilight )
6170 orus_base = &CUR.zp0.org[CUR.GS.rp1];
6171 else
6172 orus_base = &CUR.zp0.orus[CUR.GS.rp1];
6174 cur_base = &CUR.zp0.cur[CUR.GS.rp1];
6176 /* XXX: There are some glyphs in some braindead but popular */
6177 /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
6178 /* calling IP[] with bad values of rp[12]. */
6179 /* Do something sane when this odd thing happens. */
6180 if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
6181 BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
6183 old_range = 0;
6184 cur_range = 0;
6186 else
6188 if ( twilight )
6189 old_range = CUR_Func_dualproj( &CUR.zp1.org[CUR.GS.rp2],
6190 orus_base );
6191 else
6192 old_range = CUR_Func_dualproj( &CUR.zp1.orus[CUR.GS.rp2],
6193 orus_base );
6195 cur_range = CUR_Func_project ( &CUR.zp1.cur[CUR.GS.rp2], cur_base );
6198 for ( ; CUR.GS.loop > 0; --CUR.GS.loop )
6200 FT_UInt point = (FT_UInt)CUR.stack[--CUR.args];
6201 FT_F26Dot6 org_dist, cur_dist, new_dist;
6204 /* check point bounds */
6205 if ( BOUNDS( point, CUR.zp2.n_points ) )
6207 if ( CUR.pedantic_hinting )
6209 CUR.error = TT_Err_Invalid_Reference;
6210 return;
6212 continue;
6215 if ( twilight )
6216 org_dist = CUR_Func_dualproj( &CUR.zp2.org[point], orus_base );
6217 else
6218 org_dist = CUR_Func_dualproj( &CUR.zp2.orus[point], orus_base );
6220 cur_dist = CUR_Func_project ( &CUR.zp2.cur[point], cur_base );
6222 if ( org_dist )
6223 new_dist = ( old_range != 0 )
6224 ? TT_MULDIV( org_dist, cur_range, old_range )
6225 : cur_dist;
6226 else
6227 new_dist = 0;
6229 CUR_Func_move( &CUR.zp2, (FT_UShort)point, new_dist - cur_dist );
6231 CUR.GS.loop = 1;
6232 CUR.new_top = CUR.args;
6236 /*************************************************************************/
6237 /* */
6238 /* UTP[a]: UnTouch Point */
6239 /* Opcode range: 0x29 */
6240 /* Stack: uint32 --> */
6241 /* */
6242 static void
6243 Ins_UTP( INS_ARG )
6245 FT_UShort point;
6246 FT_Byte mask;
6249 point = (FT_UShort)args[0];
6251 if ( BOUNDS( point, CUR.zp0.n_points ) )
6253 if ( CUR.pedantic_hinting )
6254 CUR.error = TT_Err_Invalid_Reference;
6255 return;
6258 mask = 0xFF;
6260 if ( CUR.GS.freeVector.x != 0 )
6261 mask &= ~FT_CURVE_TAG_TOUCH_X;
6263 if ( CUR.GS.freeVector.y != 0 )
6264 mask &= ~FT_CURVE_TAG_TOUCH_Y;
6266 CUR.zp0.tags[point] &= mask;
6270 /* Local variables for Ins_IUP: */
6271 typedef struct IUP_WorkerRec_
6273 FT_Vector* orgs; /* original and current coordinate */
6274 FT_Vector* curs; /* arrays */
6275 FT_Vector* orus;
6276 FT_UInt max_points;
6278 } IUP_WorkerRec, *IUP_Worker;
6281 static void
6282 _iup_worker_shift( IUP_Worker worker,
6283 FT_UInt p1,
6284 FT_UInt p2,
6285 FT_UInt p )
6287 FT_UInt i;
6288 FT_F26Dot6 dx;
6291 dx = worker->curs[p].x - worker->orgs[p].x;
6292 if ( dx != 0 )
6294 for ( i = p1; i < p; i++ )
6295 worker->curs[i].x += dx;
6297 for ( i = p + 1; i <= p2; i++ )
6298 worker->curs[i].x += dx;
6303 static void
6304 _iup_worker_interpolate( IUP_Worker worker,
6305 FT_UInt p1,
6306 FT_UInt p2,
6307 FT_UInt ref1,
6308 FT_UInt ref2 )
6310 FT_UInt i;
6311 FT_F26Dot6 orus1, orus2, org1, org2, delta1, delta2;
6314 if ( p1 > p2 )
6315 return;
6317 if ( BOUNDS( ref1, worker->max_points ) ||
6318 BOUNDS( ref2, worker->max_points ) )
6319 return;
6321 orus1 = worker->orus[ref1].x;
6322 orus2 = worker->orus[ref2].x;
6324 if ( orus1 > orus2 )
6326 FT_F26Dot6 tmp_o;
6327 FT_UInt tmp_r;
6330 tmp_o = orus1;
6331 orus1 = orus2;
6332 orus2 = tmp_o;
6334 tmp_r = ref1;
6335 ref1 = ref2;
6336 ref2 = tmp_r;
6339 org1 = worker->orgs[ref1].x;
6340 org2 = worker->orgs[ref2].x;
6341 delta1 = worker->curs[ref1].x - org1;
6342 delta2 = worker->curs[ref2].x - org2;
6344 if ( orus1 == orus2 )
6346 /* simple shift of untouched points */
6347 for ( i = p1; i <= p2; i++ )
6349 FT_F26Dot6 x = worker->orgs[i].x;
6352 if ( x <= org1 )
6353 x += delta1;
6354 else
6355 x += delta2;
6357 worker->curs[i].x = x;
6360 else
6362 FT_Fixed scale = 0;
6363 FT_Bool scale_valid = 0;
6366 /* interpolation */
6367 for ( i = p1; i <= p2; i++ )
6369 FT_F26Dot6 x = worker->orgs[i].x;
6372 if ( x <= org1 )
6373 x += delta1;
6375 else if ( x >= org2 )
6376 x += delta2;
6378 else
6380 if ( !scale_valid )
6382 scale_valid = 1;
6383 scale = TT_MULDIV( org2 + delta2 - ( org1 + delta1 ),
6384 0x10000, orus2 - orus1 );
6387 x = ( org1 + delta1 ) +
6388 TT_MULFIX( worker->orus[i].x - orus1, scale );
6390 worker->curs[i].x = x;
6396 /*************************************************************************/
6397 /* */
6398 /* IUP[a]: Interpolate Untouched Points */
6399 /* Opcode range: 0x30-0x31 */
6400 /* Stack: --> */
6401 /* */
6402 static void
6403 Ins_IUP( INS_ARG )
6405 IUP_WorkerRec V;
6406 FT_Byte mask;
6408 FT_UInt first_point; /* first point of contour */
6409 FT_UInt end_point; /* end point (last+1) of contour */
6411 FT_UInt first_touched; /* first touched point in contour */
6412 FT_UInt cur_touched; /* current touched point in contour */
6414 FT_UInt point; /* current point */
6415 FT_Short contour; /* current contour */
6417 FT_UNUSED_ARG;
6420 /* ignore empty outlines */
6421 if ( CUR.pts.n_contours == 0 )
6422 return;
6424 if ( CUR.opcode & 1 )
6426 mask = FT_CURVE_TAG_TOUCH_X;
6427 V.orgs = CUR.pts.org;
6428 V.curs = CUR.pts.cur;
6429 V.orus = CUR.pts.orus;
6431 else
6433 mask = FT_CURVE_TAG_TOUCH_Y;
6434 V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
6435 V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
6436 V.orus = (FT_Vector*)( (FT_Pos*)CUR.pts.orus + 1 );
6438 V.max_points = CUR.pts.n_points;
6440 contour = 0;
6441 point = 0;
6445 end_point = CUR.pts.contours[contour] - CUR.pts.first_point;
6446 first_point = point;
6448 if ( CUR.pts.n_points <= end_point )
6449 end_point = CUR.pts.n_points;
6451 while ( point <= end_point && ( CUR.pts.tags[point] & mask ) == 0 )
6452 point++;
6454 if ( point <= end_point )
6456 first_touched = point;
6457 cur_touched = point;
6459 point++;
6461 while ( point <= end_point )
6463 if ( ( CUR.pts.tags[point] & mask ) != 0 )
6465 if ( point > 0 )
6466 _iup_worker_interpolate( &V,
6467 cur_touched + 1,
6468 point - 1,
6469 cur_touched,
6470 point );
6471 cur_touched = point;
6474 point++;
6477 if ( cur_touched == first_touched )
6478 _iup_worker_shift( &V, first_point, end_point, cur_touched );
6479 else
6481 _iup_worker_interpolate( &V,
6482 (FT_UShort)( cur_touched + 1 ),
6483 end_point,
6484 cur_touched,
6485 first_touched );
6487 if ( first_touched > 0 )
6488 _iup_worker_interpolate( &V,
6489 first_point,
6490 first_touched - 1,
6491 cur_touched,
6492 first_touched );
6495 contour++;
6496 } while ( contour < CUR.pts.n_contours );
6500 /*************************************************************************/
6501 /* */
6502 /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
6503 /* Opcode range: 0x5D,0x71,0x72 */
6504 /* Stack: uint32 (2 * uint32)... --> */
6505 /* */
6506 static void
6507 Ins_DELTAP( INS_ARG )
6509 FT_ULong k, nump;
6510 FT_UShort A;
6511 FT_ULong C;
6512 FT_Long B;
6515 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
6516 /* Delta hinting is covered by US Patent 5159668. */
6517 if ( CUR.face->unpatented_hinting )
6519 FT_Long n = args[0] * 2;
6522 if ( CUR.args < n )
6524 CUR.error = TT_Err_Too_Few_Arguments;
6525 return;
6528 CUR.args -= n;
6529 CUR.new_top = CUR.args;
6530 return;
6532 #endif
6534 nump = (FT_ULong)args[0]; /* some points theoretically may occur more
6535 than once, thus UShort isn't enough */
6537 for ( k = 1; k <= nump; k++ )
6539 if ( CUR.args < 2 )
6541 CUR.error = TT_Err_Too_Few_Arguments;
6542 return;
6545 CUR.args -= 2;
6547 A = (FT_UShort)CUR.stack[CUR.args + 1];
6548 B = CUR.stack[CUR.args];
6550 /* XXX: Because some popular fonts contain some invalid DeltaP */
6551 /* instructions, we simply ignore them when the stacked */
6552 /* point reference is off limit, rather than returning an */
6553 /* error. As a delta instruction doesn't change a glyph */
6554 /* in great ways, this shouldn't be a problem. */
6556 if ( !BOUNDS( A, CUR.zp0.n_points ) )
6558 C = ( (FT_ULong)B & 0xF0 ) >> 4;
6560 switch ( CUR.opcode )
6562 case 0x5D:
6563 break;
6565 case 0x71:
6566 C += 16;
6567 break;
6569 case 0x72:
6570 C += 32;
6571 break;
6574 C += CUR.GS.delta_base;
6576 if ( CURRENT_Ppem() == (FT_Long)C )
6578 B = ( (FT_ULong)B & 0xF ) - 8;
6579 if ( B >= 0 )
6580 B++;
6581 B = B * 64 / ( 1L << CUR.GS.delta_shift );
6583 CUR_Func_move( &CUR.zp0, A, B );
6586 else
6587 if ( CUR.pedantic_hinting )
6588 CUR.error = TT_Err_Invalid_Reference;
6591 CUR.new_top = CUR.args;
6595 /*************************************************************************/
6596 /* */
6597 /* DELTACn[]: DELTA exceptions C1, C2, C3 */
6598 /* Opcode range: 0x73,0x74,0x75 */
6599 /* Stack: uint32 (2 * uint32)... --> */
6600 /* */
6601 static void
6602 Ins_DELTAC( INS_ARG )
6604 FT_ULong nump, k;
6605 FT_ULong A, C;
6606 FT_Long B;
6609 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
6610 /* Delta hinting is covered by US Patent 5159668. */
6611 if ( CUR.face->unpatented_hinting )
6613 FT_Long n = args[0] * 2;
6616 if ( CUR.args < n )
6618 CUR.error = TT_Err_Too_Few_Arguments;
6619 return;
6622 CUR.args -= n;
6623 CUR.new_top = CUR.args;
6624 return;
6626 #endif
6628 nump = (FT_ULong)args[0];
6630 for ( k = 1; k <= nump; k++ )
6632 if ( CUR.args < 2 )
6634 CUR.error = TT_Err_Too_Few_Arguments;
6635 return;
6638 CUR.args -= 2;
6640 A = (FT_ULong)CUR.stack[CUR.args + 1];
6641 B = CUR.stack[CUR.args];
6643 if ( BOUNDS( A, CUR.cvtSize ) )
6645 if ( CUR.pedantic_hinting )
6647 CUR.error = TT_Err_Invalid_Reference;
6648 return;
6651 else
6653 C = ( (FT_ULong)B & 0xF0 ) >> 4;
6655 switch ( CUR.opcode )
6657 case 0x73:
6658 break;
6660 case 0x74:
6661 C += 16;
6662 break;
6664 case 0x75:
6665 C += 32;
6666 break;
6669 C += CUR.GS.delta_base;
6671 if ( CURRENT_Ppem() == (FT_Long)C )
6673 B = ( (FT_ULong)B & 0xF ) - 8;
6674 if ( B >= 0 )
6675 B++;
6676 B = B * 64 / ( 1L << CUR.GS.delta_shift );
6678 CUR_Func_move_cvt( A, B );
6683 CUR.new_top = CUR.args;
6687 /*************************************************************************/
6688 /* */
6689 /* MISC. INSTRUCTIONS */
6690 /* */
6691 /*************************************************************************/
6694 /*************************************************************************/
6695 /* */
6696 /* GETINFO[]: GET INFOrmation */
6697 /* Opcode range: 0x88 */
6698 /* Stack: uint32 --> uint32 */
6699 /* */
6700 static void
6701 Ins_GETINFO( INS_ARG )
6703 FT_Long K;
6706 K = 0;
6708 /* We return MS rasterizer version 1.7 for the font scaler. */
6709 if ( ( args[0] & 1 ) != 0 )
6710 K = 35;
6712 /* Has the glyph been rotated? */
6713 if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated )
6714 K |= 0x80;
6716 /* Has the glyph been stretched? */
6717 if ( ( args[0] & 4 ) != 0 && CUR.tt_metrics.stretched )
6718 K |= 1 << 8;
6720 /* Are we hinting for grayscale? */
6721 if ( ( args[0] & 32 ) != 0 && CUR.grayscale )
6722 K |= 1 << 12;
6724 args[0] = K;
6728 static void
6729 Ins_UNKNOWN( INS_ARG )
6731 TT_DefRecord* def = CUR.IDefs;
6732 TT_DefRecord* limit = def + CUR.numIDefs;
6734 FT_UNUSED_ARG;
6737 for ( ; def < limit; def++ )
6739 if ( (FT_Byte)def->opc == CUR.opcode && def->active )
6741 TT_CallRec* call;
6744 if ( CUR.callTop >= CUR.callSize )
6746 CUR.error = TT_Err_Stack_Overflow;
6747 return;
6750 call = CUR.callStack + CUR.callTop++;
6752 call->Caller_Range = CUR.curRange;
6753 call->Caller_IP = CUR.IP+1;
6754 call->Cur_Count = 1;
6755 call->Cur_Restart = def->start;
6757 INS_Goto_CodeRange( def->range, def->start );
6759 CUR.step_ins = FALSE;
6760 return;
6764 CUR.error = TT_Err_Invalid_Opcode;
6768 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
6771 static
6772 TInstruction_Function Instruct_Dispatch[256] =
6774 /* Opcodes are gathered in groups of 16. */
6775 /* Please keep the spaces as they are. */
6777 /* SVTCA y */ Ins_SVTCA,
6778 /* SVTCA x */ Ins_SVTCA,
6779 /* SPvTCA y */ Ins_SPVTCA,
6780 /* SPvTCA x */ Ins_SPVTCA,
6781 /* SFvTCA y */ Ins_SFVTCA,
6782 /* SFvTCA x */ Ins_SFVTCA,
6783 /* SPvTL // */ Ins_SPVTL,
6784 /* SPvTL + */ Ins_SPVTL,
6785 /* SFvTL // */ Ins_SFVTL,
6786 /* SFvTL + */ Ins_SFVTL,
6787 /* SPvFS */ Ins_SPVFS,
6788 /* SFvFS */ Ins_SFVFS,
6789 /* GPV */ Ins_GPV,
6790 /* GFV */ Ins_GFV,
6791 /* SFvTPv */ Ins_SFVTPV,
6792 /* ISECT */ Ins_ISECT,
6794 /* SRP0 */ Ins_SRP0,
6795 /* SRP1 */ Ins_SRP1,
6796 /* SRP2 */ Ins_SRP2,
6797 /* SZP0 */ Ins_SZP0,
6798 /* SZP1 */ Ins_SZP1,
6799 /* SZP2 */ Ins_SZP2,
6800 /* SZPS */ Ins_SZPS,
6801 /* SLOOP */ Ins_SLOOP,
6802 /* RTG */ Ins_RTG,
6803 /* RTHG */ Ins_RTHG,
6804 /* SMD */ Ins_SMD,
6805 /* ELSE */ Ins_ELSE,
6806 /* JMPR */ Ins_JMPR,
6807 /* SCvTCi */ Ins_SCVTCI,
6808 /* SSwCi */ Ins_SSWCI,
6809 /* SSW */ Ins_SSW,
6811 /* DUP */ Ins_DUP,
6812 /* POP */ Ins_POP,
6813 /* CLEAR */ Ins_CLEAR,
6814 /* SWAP */ Ins_SWAP,
6815 /* DEPTH */ Ins_DEPTH,
6816 /* CINDEX */ Ins_CINDEX,
6817 /* MINDEX */ Ins_MINDEX,
6818 /* AlignPTS */ Ins_ALIGNPTS,
6819 /* INS_0x28 */ Ins_UNKNOWN,
6820 /* UTP */ Ins_UTP,
6821 /* LOOPCALL */ Ins_LOOPCALL,
6822 /* CALL */ Ins_CALL,
6823 /* FDEF */ Ins_FDEF,
6824 /* ENDF */ Ins_ENDF,
6825 /* MDAP[0] */ Ins_MDAP,
6826 /* MDAP[1] */ Ins_MDAP,
6828 /* IUP[0] */ Ins_IUP,
6829 /* IUP[1] */ Ins_IUP,
6830 /* SHP[0] */ Ins_SHP,
6831 /* SHP[1] */ Ins_SHP,
6832 /* SHC[0] */ Ins_SHC,
6833 /* SHC[1] */ Ins_SHC,
6834 /* SHZ[0] */ Ins_SHZ,
6835 /* SHZ[1] */ Ins_SHZ,
6836 /* SHPIX */ Ins_SHPIX,
6837 /* IP */ Ins_IP,
6838 /* MSIRP[0] */ Ins_MSIRP,
6839 /* MSIRP[1] */ Ins_MSIRP,
6840 /* AlignRP */ Ins_ALIGNRP,
6841 /* RTDG */ Ins_RTDG,
6842 /* MIAP[0] */ Ins_MIAP,
6843 /* MIAP[1] */ Ins_MIAP,
6845 /* NPushB */ Ins_NPUSHB,
6846 /* NPushW */ Ins_NPUSHW,
6847 /* WS */ Ins_WS,
6848 /* RS */ Ins_RS,
6849 /* WCvtP */ Ins_WCVTP,
6850 /* RCvt */ Ins_RCVT,
6851 /* GC[0] */ Ins_GC,
6852 /* GC[1] */ Ins_GC,
6853 /* SCFS */ Ins_SCFS,
6854 /* MD[0] */ Ins_MD,
6855 /* MD[1] */ Ins_MD,
6856 /* MPPEM */ Ins_MPPEM,
6857 /* MPS */ Ins_MPS,
6858 /* FlipON */ Ins_FLIPON,
6859 /* FlipOFF */ Ins_FLIPOFF,
6860 /* DEBUG */ Ins_DEBUG,
6862 /* LT */ Ins_LT,
6863 /* LTEQ */ Ins_LTEQ,
6864 /* GT */ Ins_GT,
6865 /* GTEQ */ Ins_GTEQ,
6866 /* EQ */ Ins_EQ,
6867 /* NEQ */ Ins_NEQ,
6868 /* ODD */ Ins_ODD,
6869 /* EVEN */ Ins_EVEN,
6870 /* IF */ Ins_IF,
6871 /* EIF */ Ins_EIF,
6872 /* AND */ Ins_AND,
6873 /* OR */ Ins_OR,
6874 /* NOT */ Ins_NOT,
6875 /* DeltaP1 */ Ins_DELTAP,
6876 /* SDB */ Ins_SDB,
6877 /* SDS */ Ins_SDS,
6879 /* ADD */ Ins_ADD,
6880 /* SUB */ Ins_SUB,
6881 /* DIV */ Ins_DIV,
6882 /* MUL */ Ins_MUL,
6883 /* ABS */ Ins_ABS,
6884 /* NEG */ Ins_NEG,
6885 /* FLOOR */ Ins_FLOOR,
6886 /* CEILING */ Ins_CEILING,
6887 /* ROUND[0] */ Ins_ROUND,
6888 /* ROUND[1] */ Ins_ROUND,
6889 /* ROUND[2] */ Ins_ROUND,
6890 /* ROUND[3] */ Ins_ROUND,
6891 /* NROUND[0] */ Ins_NROUND,
6892 /* NROUND[1] */ Ins_NROUND,
6893 /* NROUND[2] */ Ins_NROUND,
6894 /* NROUND[3] */ Ins_NROUND,
6896 /* WCvtF */ Ins_WCVTF,
6897 /* DeltaP2 */ Ins_DELTAP,
6898 /* DeltaP3 */ Ins_DELTAP,
6899 /* DeltaCn[0] */ Ins_DELTAC,
6900 /* DeltaCn[1] */ Ins_DELTAC,
6901 /* DeltaCn[2] */ Ins_DELTAC,
6902 /* SROUND */ Ins_SROUND,
6903 /* S45Round */ Ins_S45ROUND,
6904 /* JROT */ Ins_JROT,
6905 /* JROF */ Ins_JROF,
6906 /* ROFF */ Ins_ROFF,
6907 /* INS_0x7B */ Ins_UNKNOWN,
6908 /* RUTG */ Ins_RUTG,
6909 /* RDTG */ Ins_RDTG,
6910 /* SANGW */ Ins_SANGW,
6911 /* AA */ Ins_AA,
6913 /* FlipPT */ Ins_FLIPPT,
6914 /* FlipRgON */ Ins_FLIPRGON,
6915 /* FlipRgOFF */ Ins_FLIPRGOFF,
6916 /* INS_0x83 */ Ins_UNKNOWN,
6917 /* INS_0x84 */ Ins_UNKNOWN,
6918 /* ScanCTRL */ Ins_SCANCTRL,
6919 /* SDPVTL[0] */ Ins_SDPVTL,
6920 /* SDPVTL[1] */ Ins_SDPVTL,
6921 /* GetINFO */ Ins_GETINFO,
6922 /* IDEF */ Ins_IDEF,
6923 /* ROLL */ Ins_ROLL,
6924 /* MAX */ Ins_MAX,
6925 /* MIN */ Ins_MIN,
6926 /* ScanTYPE */ Ins_SCANTYPE,
6927 /* InstCTRL */ Ins_INSTCTRL,
6928 /* INS_0x8F */ Ins_UNKNOWN,
6930 /* INS_0x90 */ Ins_UNKNOWN,
6931 /* INS_0x91 */ Ins_UNKNOWN,
6932 /* INS_0x92 */ Ins_UNKNOWN,
6933 /* INS_0x93 */ Ins_UNKNOWN,
6934 /* INS_0x94 */ Ins_UNKNOWN,
6935 /* INS_0x95 */ Ins_UNKNOWN,
6936 /* INS_0x96 */ Ins_UNKNOWN,
6937 /* INS_0x97 */ Ins_UNKNOWN,
6938 /* INS_0x98 */ Ins_UNKNOWN,
6939 /* INS_0x99 */ Ins_UNKNOWN,
6940 /* INS_0x9A */ Ins_UNKNOWN,
6941 /* INS_0x9B */ Ins_UNKNOWN,
6942 /* INS_0x9C */ Ins_UNKNOWN,
6943 /* INS_0x9D */ Ins_UNKNOWN,
6944 /* INS_0x9E */ Ins_UNKNOWN,
6945 /* INS_0x9F */ Ins_UNKNOWN,
6947 /* INS_0xA0 */ Ins_UNKNOWN,
6948 /* INS_0xA1 */ Ins_UNKNOWN,
6949 /* INS_0xA2 */ Ins_UNKNOWN,
6950 /* INS_0xA3 */ Ins_UNKNOWN,
6951 /* INS_0xA4 */ Ins_UNKNOWN,
6952 /* INS_0xA5 */ Ins_UNKNOWN,
6953 /* INS_0xA6 */ Ins_UNKNOWN,
6954 /* INS_0xA7 */ Ins_UNKNOWN,
6955 /* INS_0xA8 */ Ins_UNKNOWN,
6956 /* INS_0xA9 */ Ins_UNKNOWN,
6957 /* INS_0xAA */ Ins_UNKNOWN,
6958 /* INS_0xAB */ Ins_UNKNOWN,
6959 /* INS_0xAC */ Ins_UNKNOWN,
6960 /* INS_0xAD */ Ins_UNKNOWN,
6961 /* INS_0xAE */ Ins_UNKNOWN,
6962 /* INS_0xAF */ Ins_UNKNOWN,
6964 /* PushB[0] */ Ins_PUSHB,
6965 /* PushB[1] */ Ins_PUSHB,
6966 /* PushB[2] */ Ins_PUSHB,
6967 /* PushB[3] */ Ins_PUSHB,
6968 /* PushB[4] */ Ins_PUSHB,
6969 /* PushB[5] */ Ins_PUSHB,
6970 /* PushB[6] */ Ins_PUSHB,
6971 /* PushB[7] */ Ins_PUSHB,
6972 /* PushW[0] */ Ins_PUSHW,
6973 /* PushW[1] */ Ins_PUSHW,
6974 /* PushW[2] */ Ins_PUSHW,
6975 /* PushW[3] */ Ins_PUSHW,
6976 /* PushW[4] */ Ins_PUSHW,
6977 /* PushW[5] */ Ins_PUSHW,
6978 /* PushW[6] */ Ins_PUSHW,
6979 /* PushW[7] */ Ins_PUSHW,
6981 /* MDRP[00] */ Ins_MDRP,
6982 /* MDRP[01] */ Ins_MDRP,
6983 /* MDRP[02] */ Ins_MDRP,
6984 /* MDRP[03] */ Ins_MDRP,
6985 /* MDRP[04] */ Ins_MDRP,
6986 /* MDRP[05] */ Ins_MDRP,
6987 /* MDRP[06] */ Ins_MDRP,
6988 /* MDRP[07] */ Ins_MDRP,
6989 /* MDRP[08] */ Ins_MDRP,
6990 /* MDRP[09] */ Ins_MDRP,
6991 /* MDRP[10] */ Ins_MDRP,
6992 /* MDRP[11] */ Ins_MDRP,
6993 /* MDRP[12] */ Ins_MDRP,
6994 /* MDRP[13] */ Ins_MDRP,
6995 /* MDRP[14] */ Ins_MDRP,
6996 /* MDRP[15] */ Ins_MDRP,
6998 /* MDRP[16] */ Ins_MDRP,
6999 /* MDRP[17] */ Ins_MDRP,
7000 /* MDRP[18] */ Ins_MDRP,
7001 /* MDRP[19] */ Ins_MDRP,
7002 /* MDRP[20] */ Ins_MDRP,
7003 /* MDRP[21] */ Ins_MDRP,
7004 /* MDRP[22] */ Ins_MDRP,
7005 /* MDRP[23] */ Ins_MDRP,
7006 /* MDRP[24] */ Ins_MDRP,
7007 /* MDRP[25] */ Ins_MDRP,
7008 /* MDRP[26] */ Ins_MDRP,
7009 /* MDRP[27] */ Ins_MDRP,
7010 /* MDRP[28] */ Ins_MDRP,
7011 /* MDRP[29] */ Ins_MDRP,
7012 /* MDRP[30] */ Ins_MDRP,
7013 /* MDRP[31] */ Ins_MDRP,
7015 /* MIRP[00] */ Ins_MIRP,
7016 /* MIRP[01] */ Ins_MIRP,
7017 /* MIRP[02] */ Ins_MIRP,
7018 /* MIRP[03] */ Ins_MIRP,
7019 /* MIRP[04] */ Ins_MIRP,
7020 /* MIRP[05] */ Ins_MIRP,
7021 /* MIRP[06] */ Ins_MIRP,
7022 /* MIRP[07] */ Ins_MIRP,
7023 /* MIRP[08] */ Ins_MIRP,
7024 /* MIRP[09] */ Ins_MIRP,
7025 /* MIRP[10] */ Ins_MIRP,
7026 /* MIRP[11] */ Ins_MIRP,
7027 /* MIRP[12] */ Ins_MIRP,
7028 /* MIRP[13] */ Ins_MIRP,
7029 /* MIRP[14] */ Ins_MIRP,
7030 /* MIRP[15] */ Ins_MIRP,
7032 /* MIRP[16] */ Ins_MIRP,
7033 /* MIRP[17] */ Ins_MIRP,
7034 /* MIRP[18] */ Ins_MIRP,
7035 /* MIRP[19] */ Ins_MIRP,
7036 /* MIRP[20] */ Ins_MIRP,
7037 /* MIRP[21] */ Ins_MIRP,
7038 /* MIRP[22] */ Ins_MIRP,
7039 /* MIRP[23] */ Ins_MIRP,
7040 /* MIRP[24] */ Ins_MIRP,
7041 /* MIRP[25] */ Ins_MIRP,
7042 /* MIRP[26] */ Ins_MIRP,
7043 /* MIRP[27] */ Ins_MIRP,
7044 /* MIRP[28] */ Ins_MIRP,
7045 /* MIRP[29] */ Ins_MIRP,
7046 /* MIRP[30] */ Ins_MIRP,
7047 /* MIRP[31] */ Ins_MIRP
7051 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7054 /*************************************************************************/
7055 /* */
7056 /* RUN */
7057 /* */
7058 /* This function executes a run of opcodes. It will exit in the */
7059 /* following cases: */
7060 /* */
7061 /* - Errors (in which case it returns FALSE). */
7062 /* */
7063 /* - Reaching the end of the main code range (returns TRUE). */
7064 /* Reaching the end of a code range within a function call is an */
7065 /* error. */
7066 /* */
7067 /* - After executing one single opcode, if the flag `Instruction_Trap' */
7068 /* is set to TRUE (returns TRUE). */
7069 /* */
7070 /* On exit with TRUE, test IP < CodeSize to know whether it comes from */
7071 /* an instruction trap or a normal termination. */
7072 /* */
7073 /* */
7074 /* Note: The documented DEBUG opcode pops a value from the stack. This */
7075 /* behaviour is unsupported; here a DEBUG opcode is always an */
7076 /* error. */
7077 /* */
7078 /* */
7079 /* THIS IS THE INTERPRETER'S MAIN LOOP. */
7080 /* */
7081 /* Instructions appear in the specification's order. */
7082 /* */
7083 /*************************************************************************/
7086 /* documentation is in ttinterp.h */
7088 FT_EXPORT_DEF( FT_Error )
7089 TT_RunIns( TT_ExecContext exc )
7091 FT_Long ins_counter = 0; /* executed instructions counter */
7094 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7095 cur = *exc;
7096 #endif
7098 /* set CVT functions */
7099 CUR.tt_metrics.ratio = 0;
7100 if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
7102 /* non-square pixels, use the stretched routines */
7103 CUR.func_read_cvt = Read_CVT_Stretched;
7104 CUR.func_write_cvt = Write_CVT_Stretched;
7105 CUR.func_move_cvt = Move_CVT_Stretched;
7107 else
7109 /* square pixels, use normal routines */
7110 CUR.func_read_cvt = Read_CVT;
7111 CUR.func_write_cvt = Write_CVT;
7112 CUR.func_move_cvt = Move_CVT;
7115 COMPUTE_Funcs();
7116 COMPUTE_Round( (FT_Byte)exc->GS.round_state );
7120 CUR.opcode = CUR.code[CUR.IP];
7122 if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )
7124 if ( CUR.IP + 1 > CUR.codeSize )
7125 goto LErrorCodeOverflow_;
7127 CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
7130 if ( CUR.IP + CUR.length > CUR.codeSize )
7131 goto LErrorCodeOverflow_;
7133 /* First, let's check for empty stack and overflow */
7134 CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 );
7136 /* `args' is the top of the stack once arguments have been popped. */
7137 /* One can also interpret it as the index of the last argument. */
7138 if ( CUR.args < 0 )
7140 CUR.error = TT_Err_Too_Few_Arguments;
7141 goto LErrorLabel_;
7144 CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 );
7146 /* `new_top' is the new top of the stack, after the instruction's */
7147 /* execution. `top' will be set to `new_top' after the `switch' */
7148 /* statement. */
7149 if ( CUR.new_top > CUR.stackSize )
7151 CUR.error = TT_Err_Stack_Overflow;
7152 goto LErrorLabel_;
7155 CUR.step_ins = TRUE;
7156 CUR.error = TT_Err_Ok;
7158 #ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
7161 FT_Long* args = CUR.stack + CUR.args;
7162 FT_Byte opcode = CUR.opcode;
7165 #undef ARRAY_BOUND_ERROR
7166 #define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
7169 switch ( opcode )
7171 case 0x00: /* SVTCA y */
7172 case 0x01: /* SVTCA x */
7173 case 0x02: /* SPvTCA y */
7174 case 0x03: /* SPvTCA x */
7175 case 0x04: /* SFvTCA y */
7176 case 0x05: /* SFvTCA x */
7178 FT_Short AA, BB;
7181 AA = (FT_Short)( ( opcode & 1 ) << 14 );
7182 BB = (FT_Short)( AA ^ 0x4000 );
7184 if ( opcode < 4 )
7186 CUR.GS.projVector.x = AA;
7187 CUR.GS.projVector.y = BB;
7189 CUR.GS.dualVector.x = AA;
7190 CUR.GS.dualVector.y = BB;
7192 else
7194 GUESS_VECTOR( projVector );
7197 if ( ( opcode & 2 ) == 0 )
7199 CUR.GS.freeVector.x = AA;
7200 CUR.GS.freeVector.y = BB;
7202 else
7204 GUESS_VECTOR( freeVector );
7207 COMPUTE_Funcs();
7209 break;
7211 case 0x06: /* SPvTL // */
7212 case 0x07: /* SPvTL + */
7213 DO_SPVTL
7214 break;
7216 case 0x08: /* SFvTL // */
7217 case 0x09: /* SFvTL + */
7218 DO_SFVTL
7219 break;
7221 case 0x0A: /* SPvFS */
7222 DO_SPVFS
7223 break;
7225 case 0x0B: /* SFvFS */
7226 DO_SFVFS
7227 break;
7229 case 0x0C: /* GPV */
7230 DO_GPV
7231 break;
7233 case 0x0D: /* GFV */
7234 DO_GFV
7235 break;
7237 case 0x0E: /* SFvTPv */
7238 DO_SFVTPV
7239 break;
7241 case 0x0F: /* ISECT */
7242 Ins_ISECT( EXEC_ARG_ args );
7243 break;
7245 case 0x10: /* SRP0 */
7246 DO_SRP0
7247 break;
7249 case 0x11: /* SRP1 */
7250 DO_SRP1
7251 break;
7253 case 0x12: /* SRP2 */
7254 DO_SRP2
7255 break;
7257 case 0x13: /* SZP0 */
7258 Ins_SZP0( EXEC_ARG_ args );
7259 break;
7261 case 0x14: /* SZP1 */
7262 Ins_SZP1( EXEC_ARG_ args );
7263 break;
7265 case 0x15: /* SZP2 */
7266 Ins_SZP2( EXEC_ARG_ args );
7267 break;
7269 case 0x16: /* SZPS */
7270 Ins_SZPS( EXEC_ARG_ args );
7271 break;
7273 case 0x17: /* SLOOP */
7274 DO_SLOOP
7275 break;
7277 case 0x18: /* RTG */
7278 DO_RTG
7279 break;
7281 case 0x19: /* RTHG */
7282 DO_RTHG
7283 break;
7285 case 0x1A: /* SMD */
7286 DO_SMD
7287 break;
7289 case 0x1B: /* ELSE */
7290 Ins_ELSE( EXEC_ARG_ args );
7291 break;
7293 case 0x1C: /* JMPR */
7294 DO_JMPR
7295 break;
7297 case 0x1D: /* SCVTCI */
7298 DO_SCVTCI
7299 break;
7301 case 0x1E: /* SSWCI */
7302 DO_SSWCI
7303 break;
7305 case 0x1F: /* SSW */
7306 DO_SSW
7307 break;
7309 case 0x20: /* DUP */
7310 DO_DUP
7311 break;
7313 case 0x21: /* POP */
7314 /* nothing :-) */
7315 break;
7317 case 0x22: /* CLEAR */
7318 DO_CLEAR
7319 break;
7321 case 0x23: /* SWAP */
7322 DO_SWAP
7323 break;
7325 case 0x24: /* DEPTH */
7326 DO_DEPTH
7327 break;
7329 case 0x25: /* CINDEX */
7330 DO_CINDEX
7331 break;
7333 case 0x26: /* MINDEX */
7334 Ins_MINDEX( EXEC_ARG_ args );
7335 break;
7337 case 0x27: /* ALIGNPTS */
7338 Ins_ALIGNPTS( EXEC_ARG_ args );
7339 break;
7341 case 0x28: /* ???? */
7342 Ins_UNKNOWN( EXEC_ARG_ args );
7343 break;
7345 case 0x29: /* UTP */
7346 Ins_UTP( EXEC_ARG_ args );
7347 break;
7349 case 0x2A: /* LOOPCALL */
7350 Ins_LOOPCALL( EXEC_ARG_ args );
7351 break;
7353 case 0x2B: /* CALL */
7354 Ins_CALL( EXEC_ARG_ args );
7355 break;
7357 case 0x2C: /* FDEF */
7358 Ins_FDEF( EXEC_ARG_ args );
7359 break;
7361 case 0x2D: /* ENDF */
7362 Ins_ENDF( EXEC_ARG_ args );
7363 break;
7365 case 0x2E: /* MDAP */
7366 case 0x2F: /* MDAP */
7367 Ins_MDAP( EXEC_ARG_ args );
7368 break;
7371 case 0x30: /* IUP */
7372 case 0x31: /* IUP */
7373 Ins_IUP( EXEC_ARG_ args );
7374 break;
7376 case 0x32: /* SHP */
7377 case 0x33: /* SHP */
7378 Ins_SHP( EXEC_ARG_ args );
7379 break;
7381 case 0x34: /* SHC */
7382 case 0x35: /* SHC */
7383 Ins_SHC( EXEC_ARG_ args );
7384 break;
7386 case 0x36: /* SHZ */
7387 case 0x37: /* SHZ */
7388 Ins_SHZ( EXEC_ARG_ args );
7389 break;
7391 case 0x38: /* SHPIX */
7392 Ins_SHPIX( EXEC_ARG_ args );
7393 break;
7395 case 0x39: /* IP */
7396 Ins_IP( EXEC_ARG_ args );
7397 break;
7399 case 0x3A: /* MSIRP */
7400 case 0x3B: /* MSIRP */
7401 Ins_MSIRP( EXEC_ARG_ args );
7402 break;
7404 case 0x3C: /* AlignRP */
7405 Ins_ALIGNRP( EXEC_ARG_ args );
7406 break;
7408 case 0x3D: /* RTDG */
7409 DO_RTDG
7410 break;
7412 case 0x3E: /* MIAP */
7413 case 0x3F: /* MIAP */
7414 Ins_MIAP( EXEC_ARG_ args );
7415 break;
7417 case 0x40: /* NPUSHB */
7418 Ins_NPUSHB( EXEC_ARG_ args );
7419 break;
7421 case 0x41: /* NPUSHW */
7422 Ins_NPUSHW( EXEC_ARG_ args );
7423 break;
7425 case 0x42: /* WS */
7426 DO_WS
7427 break;
7429 Set_Invalid_Ref:
7430 CUR.error = TT_Err_Invalid_Reference;
7431 break;
7433 case 0x43: /* RS */
7434 DO_RS
7435 break;
7437 case 0x44: /* WCVTP */
7438 DO_WCVTP
7439 break;
7441 case 0x45: /* RCVT */
7442 DO_RCVT
7443 break;
7445 case 0x46: /* GC */
7446 case 0x47: /* GC */
7447 Ins_GC( EXEC_ARG_ args );
7448 break;
7450 case 0x48: /* SCFS */
7451 Ins_SCFS( EXEC_ARG_ args );
7452 break;
7454 case 0x49: /* MD */
7455 case 0x4A: /* MD */
7456 Ins_MD( EXEC_ARG_ args );
7457 break;
7459 case 0x4B: /* MPPEM */
7460 DO_MPPEM
7461 break;
7463 case 0x4C: /* MPS */
7464 DO_MPS
7465 break;
7467 case 0x4D: /* FLIPON */
7468 DO_FLIPON
7469 break;
7471 case 0x4E: /* FLIPOFF */
7472 DO_FLIPOFF
7473 break;
7475 case 0x4F: /* DEBUG */
7476 DO_DEBUG
7477 break;
7479 case 0x50: /* LT */
7480 DO_LT
7481 break;
7483 case 0x51: /* LTEQ */
7484 DO_LTEQ
7485 break;
7487 case 0x52: /* GT */
7488 DO_GT
7489 break;
7491 case 0x53: /* GTEQ */
7492 DO_GTEQ
7493 break;
7495 case 0x54: /* EQ */
7496 DO_EQ
7497 break;
7499 case 0x55: /* NEQ */
7500 DO_NEQ
7501 break;
7503 case 0x56: /* ODD */
7504 DO_ODD
7505 break;
7507 case 0x57: /* EVEN */
7508 DO_EVEN
7509 break;
7511 case 0x58: /* IF */
7512 Ins_IF( EXEC_ARG_ args );
7513 break;
7515 case 0x59: /* EIF */
7516 /* do nothing */
7517 break;
7519 case 0x5A: /* AND */
7520 DO_AND
7521 break;
7523 case 0x5B: /* OR */
7524 DO_OR
7525 break;
7527 case 0x5C: /* NOT */
7528 DO_NOT
7529 break;
7531 case 0x5D: /* DELTAP1 */
7532 Ins_DELTAP( EXEC_ARG_ args );
7533 break;
7535 case 0x5E: /* SDB */
7536 DO_SDB
7537 break;
7539 case 0x5F: /* SDS */
7540 DO_SDS
7541 break;
7543 case 0x60: /* ADD */
7544 DO_ADD
7545 break;
7547 case 0x61: /* SUB */
7548 DO_SUB
7549 break;
7551 case 0x62: /* DIV */
7552 DO_DIV
7553 break;
7555 case 0x63: /* MUL */
7556 DO_MUL
7557 break;
7559 case 0x64: /* ABS */
7560 DO_ABS
7561 break;
7563 case 0x65: /* NEG */
7564 DO_NEG
7565 break;
7567 case 0x66: /* FLOOR */
7568 DO_FLOOR
7569 break;
7571 case 0x67: /* CEILING */
7572 DO_CEILING
7573 break;
7575 case 0x68: /* ROUND */
7576 case 0x69: /* ROUND */
7577 case 0x6A: /* ROUND */
7578 case 0x6B: /* ROUND */
7579 DO_ROUND
7580 break;
7582 case 0x6C: /* NROUND */
7583 case 0x6D: /* NROUND */
7584 case 0x6E: /* NRRUND */
7585 case 0x6F: /* NROUND */
7586 DO_NROUND
7587 break;
7589 case 0x70: /* WCVTF */
7590 DO_WCVTF
7591 break;
7593 case 0x71: /* DELTAP2 */
7594 case 0x72: /* DELTAP3 */
7595 Ins_DELTAP( EXEC_ARG_ args );
7596 break;
7598 case 0x73: /* DELTAC0 */
7599 case 0x74: /* DELTAC1 */
7600 case 0x75: /* DELTAC2 */
7601 Ins_DELTAC( EXEC_ARG_ args );
7602 break;
7604 case 0x76: /* SROUND */
7605 DO_SROUND
7606 break;
7608 case 0x77: /* S45Round */
7609 DO_S45ROUND
7610 break;
7612 case 0x78: /* JROT */
7613 DO_JROT
7614 break;
7616 case 0x79: /* JROF */
7617 DO_JROF
7618 break;
7620 case 0x7A: /* ROFF */
7621 DO_ROFF
7622 break;
7624 case 0x7B: /* ???? */
7625 Ins_UNKNOWN( EXEC_ARG_ args );
7626 break;
7628 case 0x7C: /* RUTG */
7629 DO_RUTG
7630 break;
7632 case 0x7D: /* RDTG */
7633 DO_RDTG
7634 break;
7636 case 0x7E: /* SANGW */
7637 case 0x7F: /* AA */
7638 /* nothing - obsolete */
7639 break;
7641 case 0x80: /* FLIPPT */
7642 Ins_FLIPPT( EXEC_ARG_ args );
7643 break;
7645 case 0x81: /* FLIPRGON */
7646 Ins_FLIPRGON( EXEC_ARG_ args );
7647 break;
7649 case 0x82: /* FLIPRGOFF */
7650 Ins_FLIPRGOFF( EXEC_ARG_ args );
7651 break;
7653 case 0x83: /* UNKNOWN */
7654 case 0x84: /* UNKNOWN */
7655 Ins_UNKNOWN( EXEC_ARG_ args );
7656 break;
7658 case 0x85: /* SCANCTRL */
7659 Ins_SCANCTRL( EXEC_ARG_ args );
7660 break;
7662 case 0x86: /* SDPVTL */
7663 case 0x87: /* SDPVTL */
7664 Ins_SDPVTL( EXEC_ARG_ args );
7665 break;
7667 case 0x88: /* GETINFO */
7668 Ins_GETINFO( EXEC_ARG_ args );
7669 break;
7671 case 0x89: /* IDEF */
7672 Ins_IDEF( EXEC_ARG_ args );
7673 break;
7675 case 0x8A: /* ROLL */
7676 Ins_ROLL( EXEC_ARG_ args );
7677 break;
7679 case 0x8B: /* MAX */
7680 DO_MAX
7681 break;
7683 case 0x8C: /* MIN */
7684 DO_MIN
7685 break;
7687 case 0x8D: /* SCANTYPE */
7688 Ins_SCANTYPE( EXEC_ARG_ args );
7689 break;
7691 case 0x8E: /* INSTCTRL */
7692 Ins_INSTCTRL( EXEC_ARG_ args );
7693 break;
7695 case 0x8F:
7696 Ins_UNKNOWN( EXEC_ARG_ args );
7697 break;
7699 default:
7700 if ( opcode >= 0xE0 )
7701 Ins_MIRP( EXEC_ARG_ args );
7702 else if ( opcode >= 0xC0 )
7703 Ins_MDRP( EXEC_ARG_ args );
7704 else if ( opcode >= 0xB8 )
7705 Ins_PUSHW( EXEC_ARG_ args );
7706 else if ( opcode >= 0xB0 )
7707 Ins_PUSHB( EXEC_ARG_ args );
7708 else
7709 Ins_UNKNOWN( EXEC_ARG_ args );
7714 #else
7716 Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );
7718 #endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7720 if ( CUR.error != TT_Err_Ok )
7722 switch ( CUR.error )
7724 case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
7726 TT_DefRecord* def = CUR.IDefs;
7727 TT_DefRecord* limit = def + CUR.numIDefs;
7730 for ( ; def < limit; def++ )
7732 if ( def->active && CUR.opcode == (FT_Byte)def->opc )
7734 TT_CallRec* callrec;
7737 if ( CUR.callTop >= CUR.callSize )
7739 CUR.error = TT_Err_Invalid_Reference;
7740 goto LErrorLabel_;
7743 callrec = &CUR.callStack[CUR.callTop];
7745 callrec->Caller_Range = CUR.curRange;
7746 callrec->Caller_IP = CUR.IP + 1;
7747 callrec->Cur_Count = 1;
7748 callrec->Cur_Restart = def->start;
7750 if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
7751 goto LErrorLabel_;
7753 goto LSuiteLabel_;
7758 CUR.error = TT_Err_Invalid_Opcode;
7759 goto LErrorLabel_;
7761 #if 0
7762 break; /* Unreachable code warning suppression. */
7763 /* Leave to remind in case a later change the editor */
7764 /* to consider break; */
7765 #endif
7767 default:
7768 goto LErrorLabel_;
7770 #if 0
7771 break;
7772 #endif
7776 CUR.top = CUR.new_top;
7778 if ( CUR.step_ins )
7779 CUR.IP += CUR.length;
7781 /* increment instruction counter and check if we didn't */
7782 /* run this program for too long (e.g. infinite loops). */
7783 if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
7784 return TT_Err_Execution_Too_Long;
7786 LSuiteLabel_:
7787 if ( CUR.IP >= CUR.codeSize )
7789 if ( CUR.callTop > 0 )
7791 CUR.error = TT_Err_Code_Overflow;
7792 goto LErrorLabel_;
7794 else
7795 goto LNo_Error_;
7797 } while ( !CUR.instruction_trap );
7799 LNo_Error_:
7801 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7802 *exc = cur;
7803 #endif
7805 return TT_Err_Ok;
7807 LErrorCodeOverflow_:
7808 CUR.error = TT_Err_Code_Overflow;
7810 LErrorLabel_:
7812 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7813 *exc = cur;
7814 #endif
7816 return CUR.error;
7820 #endif /* TT_USE_BYTECODE_INTERPRETER */
7823 /* END */