Suggestion from "mgh".
[open-ps2-loader.git] / thirdparty / freetype-2.3.12 / src / truetype / ttinterp.c
blob13aa9a27c4c44e8c4934cc764235be04dd9f4fa0
1 /***************************************************************************/
2 /* */
3 /* ttinterp.c */
4 /* */
5 /* TrueType bytecode interpreter (body). */
6 /* */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 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 /* The default value for `scan_control' is documented as FALSE in the */
752 /* TrueType specification. This is confusing since it implies a */
753 /* Boolean value. However, this is not the case, thus both the */
754 /* default values of our `scan_type' and `scan_control' fields (which */
755 /* the documentation's `scan_control' variable is split into) are */
756 /* zero. */
758 const TT_GraphicsState tt_default_graphics_state =
760 0, 0, 0,
761 { 0x4000, 0 },
762 { 0x4000, 0 },
763 { 0x4000, 0 },
765 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
766 TRUE,
767 #endif
769 1, 64, 1,
770 TRUE, 68, 0, 0, 9, 3,
771 0, FALSE, 0, 1, 1, 1
775 /* documentation is in ttinterp.h */
777 FT_EXPORT_DEF( TT_ExecContext )
778 TT_New_Context( TT_Driver driver )
780 TT_ExecContext exec;
781 FT_Memory memory;
784 memory = driver->root.root.memory;
785 exec = driver->context;
787 if ( !driver->context )
789 FT_Error error;
792 /* allocate object */
793 if ( FT_NEW( exec ) )
794 goto Fail;
796 /* initialize it; in case of error this deallocates `exec' too */
797 error = Init_Context( exec, memory );
798 if ( error )
799 goto Fail;
801 /* store it into the driver */
802 driver->context = exec;
805 return driver->context;
807 Fail:
808 return NULL;
812 /*************************************************************************/
813 /* */
814 /* Before an opcode is executed, the interpreter verifies that there are */
815 /* enough arguments on the stack, with the help of the `Pop_Push_Count' */
816 /* table. */
817 /* */
818 /* For each opcode, the first column gives the number of arguments that */
819 /* are popped from the stack; the second one gives the number of those */
820 /* that are pushed in result. */
821 /* */
822 /* Opcodes which have a varying number of parameters in the data stream */
823 /* (NPUSHB, NPUSHW) are handled specially; they have a negative value in */
824 /* the `opcode_length' table, and the value in `Pop_Push_Count' is set */
825 /* to zero. */
826 /* */
827 /*************************************************************************/
830 #undef PACK
831 #define PACK( x, y ) ( ( x << 4 ) | y )
834 static
835 const FT_Byte Pop_Push_Count[256] =
837 /* opcodes are gathered in groups of 16 */
838 /* please keep the spaces as they are */
840 /* SVTCA y */ PACK( 0, 0 ),
841 /* SVTCA x */ PACK( 0, 0 ),
842 /* SPvTCA y */ PACK( 0, 0 ),
843 /* SPvTCA x */ PACK( 0, 0 ),
844 /* SFvTCA y */ PACK( 0, 0 ),
845 /* SFvTCA x */ PACK( 0, 0 ),
846 /* SPvTL // */ PACK( 2, 0 ),
847 /* SPvTL + */ PACK( 2, 0 ),
848 /* SFvTL // */ PACK( 2, 0 ),
849 /* SFvTL + */ PACK( 2, 0 ),
850 /* SPvFS */ PACK( 2, 0 ),
851 /* SFvFS */ PACK( 2, 0 ),
852 /* GPV */ PACK( 0, 2 ),
853 /* GFV */ PACK( 0, 2 ),
854 /* SFvTPv */ PACK( 0, 0 ),
855 /* ISECT */ PACK( 5, 0 ),
857 /* SRP0 */ PACK( 1, 0 ),
858 /* SRP1 */ PACK( 1, 0 ),
859 /* SRP2 */ PACK( 1, 0 ),
860 /* SZP0 */ PACK( 1, 0 ),
861 /* SZP1 */ PACK( 1, 0 ),
862 /* SZP2 */ PACK( 1, 0 ),
863 /* SZPS */ PACK( 1, 0 ),
864 /* SLOOP */ PACK( 1, 0 ),
865 /* RTG */ PACK( 0, 0 ),
866 /* RTHG */ PACK( 0, 0 ),
867 /* SMD */ PACK( 1, 0 ),
868 /* ELSE */ PACK( 0, 0 ),
869 /* JMPR */ PACK( 1, 0 ),
870 /* SCvTCi */ PACK( 1, 0 ),
871 /* SSwCi */ PACK( 1, 0 ),
872 /* SSW */ PACK( 1, 0 ),
874 /* DUP */ PACK( 1, 2 ),
875 /* POP */ PACK( 1, 0 ),
876 /* CLEAR */ PACK( 0, 0 ),
877 /* SWAP */ PACK( 2, 2 ),
878 /* DEPTH */ PACK( 0, 1 ),
879 /* CINDEX */ PACK( 1, 1 ),
880 /* MINDEX */ PACK( 1, 0 ),
881 /* AlignPTS */ PACK( 2, 0 ),
882 /* INS_$28 */ PACK( 0, 0 ),
883 /* UTP */ PACK( 1, 0 ),
884 /* LOOPCALL */ PACK( 2, 0 ),
885 /* CALL */ PACK( 1, 0 ),
886 /* FDEF */ PACK( 1, 0 ),
887 /* ENDF */ PACK( 0, 0 ),
888 /* MDAP[0] */ PACK( 1, 0 ),
889 /* MDAP[1] */ PACK( 1, 0 ),
891 /* IUP[0] */ PACK( 0, 0 ),
892 /* IUP[1] */ PACK( 0, 0 ),
893 /* SHP[0] */ PACK( 0, 0 ),
894 /* SHP[1] */ PACK( 0, 0 ),
895 /* SHC[0] */ PACK( 1, 0 ),
896 /* SHC[1] */ PACK( 1, 0 ),
897 /* SHZ[0] */ PACK( 1, 0 ),
898 /* SHZ[1] */ PACK( 1, 0 ),
899 /* SHPIX */ PACK( 1, 0 ),
900 /* IP */ PACK( 0, 0 ),
901 /* MSIRP[0] */ PACK( 2, 0 ),
902 /* MSIRP[1] */ PACK( 2, 0 ),
903 /* AlignRP */ PACK( 0, 0 ),
904 /* RTDG */ PACK( 0, 0 ),
905 /* MIAP[0] */ PACK( 2, 0 ),
906 /* MIAP[1] */ PACK( 2, 0 ),
908 /* NPushB */ PACK( 0, 0 ),
909 /* NPushW */ PACK( 0, 0 ),
910 /* WS */ PACK( 2, 0 ),
911 /* RS */ PACK( 1, 1 ),
912 /* WCvtP */ PACK( 2, 0 ),
913 /* RCvt */ PACK( 1, 1 ),
914 /* GC[0] */ PACK( 1, 1 ),
915 /* GC[1] */ PACK( 1, 1 ),
916 /* SCFS */ PACK( 2, 0 ),
917 /* MD[0] */ PACK( 2, 1 ),
918 /* MD[1] */ PACK( 2, 1 ),
919 /* MPPEM */ PACK( 0, 1 ),
920 /* MPS */ PACK( 0, 1 ),
921 /* FlipON */ PACK( 0, 0 ),
922 /* FlipOFF */ PACK( 0, 0 ),
923 /* DEBUG */ PACK( 1, 0 ),
925 /* LT */ PACK( 2, 1 ),
926 /* LTEQ */ PACK( 2, 1 ),
927 /* GT */ PACK( 2, 1 ),
928 /* GTEQ */ PACK( 2, 1 ),
929 /* EQ */ PACK( 2, 1 ),
930 /* NEQ */ PACK( 2, 1 ),
931 /* ODD */ PACK( 1, 1 ),
932 /* EVEN */ PACK( 1, 1 ),
933 /* IF */ PACK( 1, 0 ),
934 /* EIF */ PACK( 0, 0 ),
935 /* AND */ PACK( 2, 1 ),
936 /* OR */ PACK( 2, 1 ),
937 /* NOT */ PACK( 1, 1 ),
938 /* DeltaP1 */ PACK( 1, 0 ),
939 /* SDB */ PACK( 1, 0 ),
940 /* SDS */ PACK( 1, 0 ),
942 /* ADD */ PACK( 2, 1 ),
943 /* SUB */ PACK( 2, 1 ),
944 /* DIV */ PACK( 2, 1 ),
945 /* MUL */ PACK( 2, 1 ),
946 /* ABS */ PACK( 1, 1 ),
947 /* NEG */ PACK( 1, 1 ),
948 /* FLOOR */ PACK( 1, 1 ),
949 /* CEILING */ PACK( 1, 1 ),
950 /* ROUND[0] */ PACK( 1, 1 ),
951 /* ROUND[1] */ PACK( 1, 1 ),
952 /* ROUND[2] */ PACK( 1, 1 ),
953 /* ROUND[3] */ PACK( 1, 1 ),
954 /* NROUND[0] */ PACK( 1, 1 ),
955 /* NROUND[1] */ PACK( 1, 1 ),
956 /* NROUND[2] */ PACK( 1, 1 ),
957 /* NROUND[3] */ PACK( 1, 1 ),
959 /* WCvtF */ PACK( 2, 0 ),
960 /* DeltaP2 */ PACK( 1, 0 ),
961 /* DeltaP3 */ PACK( 1, 0 ),
962 /* DeltaCn[0] */ PACK( 1, 0 ),
963 /* DeltaCn[1] */ PACK( 1, 0 ),
964 /* DeltaCn[2] */ PACK( 1, 0 ),
965 /* SROUND */ PACK( 1, 0 ),
966 /* S45Round */ PACK( 1, 0 ),
967 /* JROT */ PACK( 2, 0 ),
968 /* JROF */ PACK( 2, 0 ),
969 /* ROFF */ PACK( 0, 0 ),
970 /* INS_$7B */ PACK( 0, 0 ),
971 /* RUTG */ PACK( 0, 0 ),
972 /* RDTG */ PACK( 0, 0 ),
973 /* SANGW */ PACK( 1, 0 ),
974 /* AA */ PACK( 1, 0 ),
976 /* FlipPT */ PACK( 0, 0 ),
977 /* FlipRgON */ PACK( 2, 0 ),
978 /* FlipRgOFF */ PACK( 2, 0 ),
979 /* INS_$83 */ PACK( 0, 0 ),
980 /* INS_$84 */ PACK( 0, 0 ),
981 /* ScanCTRL */ PACK( 1, 0 ),
982 /* SDVPTL[0] */ PACK( 2, 0 ),
983 /* SDVPTL[1] */ PACK( 2, 0 ),
984 /* GetINFO */ PACK( 1, 1 ),
985 /* IDEF */ PACK( 1, 0 ),
986 /* ROLL */ PACK( 3, 3 ),
987 /* MAX */ PACK( 2, 1 ),
988 /* MIN */ PACK( 2, 1 ),
989 /* ScanTYPE */ PACK( 1, 0 ),
990 /* InstCTRL */ PACK( 2, 0 ),
991 /* INS_$8F */ PACK( 0, 0 ),
993 /* INS_$90 */ PACK( 0, 0 ),
994 /* INS_$91 */ PACK( 0, 0 ),
995 /* INS_$92 */ PACK( 0, 0 ),
996 /* INS_$93 */ PACK( 0, 0 ),
997 /* INS_$94 */ PACK( 0, 0 ),
998 /* INS_$95 */ PACK( 0, 0 ),
999 /* INS_$96 */ PACK( 0, 0 ),
1000 /* INS_$97 */ PACK( 0, 0 ),
1001 /* INS_$98 */ PACK( 0, 0 ),
1002 /* INS_$99 */ PACK( 0, 0 ),
1003 /* INS_$9A */ PACK( 0, 0 ),
1004 /* INS_$9B */ PACK( 0, 0 ),
1005 /* INS_$9C */ PACK( 0, 0 ),
1006 /* INS_$9D */ PACK( 0, 0 ),
1007 /* INS_$9E */ PACK( 0, 0 ),
1008 /* INS_$9F */ PACK( 0, 0 ),
1010 /* INS_$A0 */ PACK( 0, 0 ),
1011 /* INS_$A1 */ PACK( 0, 0 ),
1012 /* INS_$A2 */ PACK( 0, 0 ),
1013 /* INS_$A3 */ PACK( 0, 0 ),
1014 /* INS_$A4 */ PACK( 0, 0 ),
1015 /* INS_$A5 */ PACK( 0, 0 ),
1016 /* INS_$A6 */ PACK( 0, 0 ),
1017 /* INS_$A7 */ PACK( 0, 0 ),
1018 /* INS_$A8 */ PACK( 0, 0 ),
1019 /* INS_$A9 */ PACK( 0, 0 ),
1020 /* INS_$AA */ PACK( 0, 0 ),
1021 /* INS_$AB */ PACK( 0, 0 ),
1022 /* INS_$AC */ PACK( 0, 0 ),
1023 /* INS_$AD */ PACK( 0, 0 ),
1024 /* INS_$AE */ PACK( 0, 0 ),
1025 /* INS_$AF */ PACK( 0, 0 ),
1027 /* PushB[0] */ PACK( 0, 1 ),
1028 /* PushB[1] */ PACK( 0, 2 ),
1029 /* PushB[2] */ PACK( 0, 3 ),
1030 /* PushB[3] */ PACK( 0, 4 ),
1031 /* PushB[4] */ PACK( 0, 5 ),
1032 /* PushB[5] */ PACK( 0, 6 ),
1033 /* PushB[6] */ PACK( 0, 7 ),
1034 /* PushB[7] */ PACK( 0, 8 ),
1035 /* PushW[0] */ PACK( 0, 1 ),
1036 /* PushW[1] */ PACK( 0, 2 ),
1037 /* PushW[2] */ PACK( 0, 3 ),
1038 /* PushW[3] */ PACK( 0, 4 ),
1039 /* PushW[4] */ PACK( 0, 5 ),
1040 /* PushW[5] */ PACK( 0, 6 ),
1041 /* PushW[6] */ PACK( 0, 7 ),
1042 /* PushW[7] */ PACK( 0, 8 ),
1044 /* MDRP[00] */ PACK( 1, 0 ),
1045 /* MDRP[01] */ PACK( 1, 0 ),
1046 /* MDRP[02] */ PACK( 1, 0 ),
1047 /* MDRP[03] */ PACK( 1, 0 ),
1048 /* MDRP[04] */ PACK( 1, 0 ),
1049 /* MDRP[05] */ PACK( 1, 0 ),
1050 /* MDRP[06] */ PACK( 1, 0 ),
1051 /* MDRP[07] */ PACK( 1, 0 ),
1052 /* MDRP[08] */ PACK( 1, 0 ),
1053 /* MDRP[09] */ PACK( 1, 0 ),
1054 /* MDRP[10] */ PACK( 1, 0 ),
1055 /* MDRP[11] */ PACK( 1, 0 ),
1056 /* MDRP[12] */ PACK( 1, 0 ),
1057 /* MDRP[13] */ PACK( 1, 0 ),
1058 /* MDRP[14] */ PACK( 1, 0 ),
1059 /* MDRP[15] */ PACK( 1, 0 ),
1061 /* MDRP[16] */ PACK( 1, 0 ),
1062 /* MDRP[17] */ PACK( 1, 0 ),
1063 /* MDRP[18] */ PACK( 1, 0 ),
1064 /* MDRP[19] */ PACK( 1, 0 ),
1065 /* MDRP[20] */ PACK( 1, 0 ),
1066 /* MDRP[21] */ PACK( 1, 0 ),
1067 /* MDRP[22] */ PACK( 1, 0 ),
1068 /* MDRP[23] */ PACK( 1, 0 ),
1069 /* MDRP[24] */ PACK( 1, 0 ),
1070 /* MDRP[25] */ PACK( 1, 0 ),
1071 /* MDRP[26] */ PACK( 1, 0 ),
1072 /* MDRP[27] */ PACK( 1, 0 ),
1073 /* MDRP[28] */ PACK( 1, 0 ),
1074 /* MDRP[29] */ PACK( 1, 0 ),
1075 /* MDRP[30] */ PACK( 1, 0 ),
1076 /* MDRP[31] */ PACK( 1, 0 ),
1078 /* MIRP[00] */ PACK( 2, 0 ),
1079 /* MIRP[01] */ PACK( 2, 0 ),
1080 /* MIRP[02] */ PACK( 2, 0 ),
1081 /* MIRP[03] */ PACK( 2, 0 ),
1082 /* MIRP[04] */ PACK( 2, 0 ),
1083 /* MIRP[05] */ PACK( 2, 0 ),
1084 /* MIRP[06] */ PACK( 2, 0 ),
1085 /* MIRP[07] */ PACK( 2, 0 ),
1086 /* MIRP[08] */ PACK( 2, 0 ),
1087 /* MIRP[09] */ PACK( 2, 0 ),
1088 /* MIRP[10] */ PACK( 2, 0 ),
1089 /* MIRP[11] */ PACK( 2, 0 ),
1090 /* MIRP[12] */ PACK( 2, 0 ),
1091 /* MIRP[13] */ PACK( 2, 0 ),
1092 /* MIRP[14] */ PACK( 2, 0 ),
1093 /* MIRP[15] */ PACK( 2, 0 ),
1095 /* MIRP[16] */ PACK( 2, 0 ),
1096 /* MIRP[17] */ PACK( 2, 0 ),
1097 /* MIRP[18] */ PACK( 2, 0 ),
1098 /* MIRP[19] */ PACK( 2, 0 ),
1099 /* MIRP[20] */ PACK( 2, 0 ),
1100 /* MIRP[21] */ PACK( 2, 0 ),
1101 /* MIRP[22] */ PACK( 2, 0 ),
1102 /* MIRP[23] */ PACK( 2, 0 ),
1103 /* MIRP[24] */ PACK( 2, 0 ),
1104 /* MIRP[25] */ PACK( 2, 0 ),
1105 /* MIRP[26] */ PACK( 2, 0 ),
1106 /* MIRP[27] */ PACK( 2, 0 ),
1107 /* MIRP[28] */ PACK( 2, 0 ),
1108 /* MIRP[29] */ PACK( 2, 0 ),
1109 /* MIRP[30] */ PACK( 2, 0 ),
1110 /* MIRP[31] */ PACK( 2, 0 )
1114 static
1115 const FT_Char opcode_length[256] =
1117 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1118 1, 1, 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,
1122 -1,-2, 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,
1127 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
1132 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1133 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1134 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1135 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1138 #undef PACK
1140 #if 1
1142 static FT_Int32
1143 TT_MulFix14( FT_Int32 a,
1144 FT_Int b )
1146 FT_Int32 sign;
1147 FT_UInt32 ah, al, mid, lo, hi;
1150 sign = a ^ b;
1152 if ( a < 0 )
1153 a = -a;
1154 if ( b < 0 )
1155 b = -b;
1157 ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU );
1158 al = (FT_UInt32)( a & 0xFFFFU );
1160 lo = al * b;
1161 mid = ah * b;
1162 hi = mid >> 16;
1163 mid = ( mid << 16 ) + ( 1 << 13 ); /* rounding */
1164 lo += mid;
1165 if ( lo < mid )
1166 hi += 1;
1168 mid = ( lo >> 14 ) | ( hi << 18 );
1170 return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid;
1173 #else
1175 /* compute (a*b)/2^14 with maximal accuracy and rounding */
1176 static FT_Int32
1177 TT_MulFix14( FT_Int32 a,
1178 FT_Int b )
1180 FT_Int32 m, s, hi;
1181 FT_UInt32 l, lo;
1184 /* compute ax*bx as 64-bit value */
1185 l = (FT_UInt32)( ( a & 0xFFFFU ) * b );
1186 m = ( a >> 16 ) * b;
1188 lo = l + (FT_UInt32)( m << 16 );
1189 hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l );
1191 /* divide the result by 2^14 with rounding */
1192 s = hi >> 31;
1193 l = lo + (FT_UInt32)s;
1194 hi += s + ( l < lo );
1195 lo = l;
1197 l = lo + 0x2000U;
1198 hi += l < lo;
1200 return ( hi << 18 ) | ( l >> 14 );
1202 #endif
1205 /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */
1206 static FT_Int32
1207 TT_DotFix14( FT_Int32 ax,
1208 FT_Int32 ay,
1209 FT_Int bx,
1210 FT_Int by )
1212 FT_Int32 m, s, hi1, hi2, hi;
1213 FT_UInt32 l, lo1, lo2, lo;
1216 /* compute ax*bx as 64-bit value */
1217 l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );
1218 m = ( ax >> 16 ) * bx;
1220 lo1 = l + (FT_UInt32)( m << 16 );
1221 hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l );
1223 /* compute ay*by as 64-bit value */
1224 l = (FT_UInt32)( ( ay & 0xFFFFU ) * by );
1225 m = ( ay >> 16 ) * by;
1227 lo2 = l + (FT_UInt32)( m << 16 );
1228 hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l );
1230 /* add them */
1231 lo = lo1 + lo2;
1232 hi = hi1 + hi2 + ( lo < lo1 );
1234 /* divide the result by 2^14 with rounding */
1235 s = hi >> 31;
1236 l = lo + (FT_UInt32)s;
1237 hi += s + ( l < lo );
1238 lo = l;
1240 l = lo + 0x2000U;
1241 hi += ( l < lo );
1243 return ( hi << 18 ) | ( l >> 14 );
1247 /* return length of given vector */
1249 #if 0
1251 static FT_Int32
1252 TT_VecLen( FT_Int32 x,
1253 FT_Int32 y )
1255 FT_Int32 m, hi1, hi2, hi;
1256 FT_UInt32 l, lo1, lo2, lo;
1259 /* compute x*x as 64-bit value */
1260 lo = (FT_UInt32)( x & 0xFFFFU );
1261 hi = x >> 16;
1263 l = lo * lo;
1264 m = hi * lo;
1265 hi = hi * hi;
1267 lo1 = l + (FT_UInt32)( m << 17 );
1268 hi1 = hi + ( m >> 15 ) + ( lo1 < l );
1270 /* compute y*y as 64-bit value */
1271 lo = (FT_UInt32)( y & 0xFFFFU );
1272 hi = y >> 16;
1274 l = lo * lo;
1275 m = hi * lo;
1276 hi = hi * hi;
1278 lo2 = l + (FT_UInt32)( m << 17 );
1279 hi2 = hi + ( m >> 15 ) + ( lo2 < l );
1281 /* add them to get 'x*x+y*y' as 64-bit value */
1282 lo = lo1 + lo2;
1283 hi = hi1 + hi2 + ( lo < lo1 );
1285 /* compute the square root of this value */
1287 FT_UInt32 root, rem, test_div;
1288 FT_Int count;
1291 root = 0;
1294 rem = 0;
1295 count = 32;
1298 rem = ( rem << 2 ) | ( (FT_UInt32)hi >> 30 );
1299 hi = ( hi << 2 ) | ( lo >> 30 );
1300 lo <<= 2;
1301 root <<= 1;
1302 test_div = ( root << 1 ) + 1;
1304 if ( rem >= test_div )
1306 rem -= test_div;
1307 root += 1;
1309 } while ( --count );
1312 return (FT_Int32)root;
1316 #else
1318 /* this version uses FT_Vector_Length which computes the same value */
1319 /* much, much faster.. */
1320 /* */
1321 static FT_F26Dot6
1322 TT_VecLen( FT_F26Dot6 X,
1323 FT_F26Dot6 Y )
1325 FT_Vector v;
1328 v.x = X;
1329 v.y = Y;
1331 return FT_Vector_Length( &v );
1334 #endif
1337 /*************************************************************************/
1338 /* */
1339 /* <Function> */
1340 /* Current_Ratio */
1341 /* */
1342 /* <Description> */
1343 /* Returns the current aspect ratio scaling factor depending on the */
1344 /* projection vector's state and device resolutions. */
1345 /* */
1346 /* <Return> */
1347 /* The aspect ratio in 16.16 format, always <= 1.0 . */
1348 /* */
1349 static FT_Long
1350 Current_Ratio( EXEC_OP )
1352 if ( !CUR.tt_metrics.ratio )
1354 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1355 if ( CUR.face->unpatented_hinting )
1357 if ( CUR.GS.both_x_axis )
1358 CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
1359 else
1360 CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
1362 else
1363 #endif
1365 if ( CUR.GS.projVector.y == 0 )
1366 CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
1368 else if ( CUR.GS.projVector.x == 0 )
1369 CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
1371 else
1373 FT_Long x, y;
1376 x = TT_MULDIV( CUR.GS.projVector.x,
1377 CUR.tt_metrics.x_ratio, 0x4000 );
1378 y = TT_MULDIV( CUR.GS.projVector.y,
1379 CUR.tt_metrics.y_ratio, 0x4000 );
1380 CUR.tt_metrics.ratio = TT_VecLen( x, y );
1384 return CUR.tt_metrics.ratio;
1388 static FT_Long
1389 Current_Ppem( EXEC_OP )
1391 return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );
1395 /*************************************************************************/
1396 /* */
1397 /* Functions related to the control value table (CVT). */
1398 /* */
1399 /*************************************************************************/
1402 FT_CALLBACK_DEF( FT_F26Dot6 )
1403 Read_CVT( EXEC_OP_ FT_ULong idx )
1405 return CUR.cvt[idx];
1409 FT_CALLBACK_DEF( FT_F26Dot6 )
1410 Read_CVT_Stretched( EXEC_OP_ FT_ULong idx )
1412 return TT_MULFIX( CUR.cvt[idx], CURRENT_Ratio() );
1416 FT_CALLBACK_DEF( void )
1417 Write_CVT( EXEC_OP_ FT_ULong idx,
1418 FT_F26Dot6 value )
1420 CUR.cvt[idx] = value;
1424 FT_CALLBACK_DEF( void )
1425 Write_CVT_Stretched( EXEC_OP_ FT_ULong idx,
1426 FT_F26Dot6 value )
1428 CUR.cvt[idx] = FT_DivFix( value, CURRENT_Ratio() );
1432 FT_CALLBACK_DEF( void )
1433 Move_CVT( EXEC_OP_ FT_ULong idx,
1434 FT_F26Dot6 value )
1436 CUR.cvt[idx] += value;
1440 FT_CALLBACK_DEF( void )
1441 Move_CVT_Stretched( EXEC_OP_ FT_ULong idx,
1442 FT_F26Dot6 value )
1444 CUR.cvt[idx] += FT_DivFix( value, CURRENT_Ratio() );
1448 /*************************************************************************/
1449 /* */
1450 /* <Function> */
1451 /* GetShortIns */
1452 /* */
1453 /* <Description> */
1454 /* Returns a short integer taken from the instruction stream at */
1455 /* address IP. */
1456 /* */
1457 /* <Return> */
1458 /* Short read at code[IP]. */
1459 /* */
1460 /* <Note> */
1461 /* This one could become a macro. */
1462 /* */
1463 static FT_Short
1464 GetShortIns( EXEC_OP )
1466 /* Reading a byte stream so there is no endianess (DaveP) */
1467 CUR.IP += 2;
1468 return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) +
1469 CUR.code[CUR.IP - 1] );
1473 /*************************************************************************/
1474 /* */
1475 /* <Function> */
1476 /* Ins_Goto_CodeRange */
1477 /* */
1478 /* <Description> */
1479 /* Goes to a certain code range in the instruction stream. */
1480 /* */
1481 /* <Input> */
1482 /* aRange :: The index of the code range. */
1483 /* */
1484 /* aIP :: The new IP address in the code range. */
1485 /* */
1486 /* <Return> */
1487 /* SUCCESS or FAILURE. */
1488 /* */
1489 static FT_Bool
1490 Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange,
1491 FT_ULong aIP )
1493 TT_CodeRange* range;
1496 if ( aRange < 1 || aRange > 3 )
1498 CUR.error = TT_Err_Bad_Argument;
1499 return FAILURE;
1502 range = &CUR.codeRangeTable[aRange - 1];
1504 if ( range->base == NULL ) /* invalid coderange */
1506 CUR.error = TT_Err_Invalid_CodeRange;
1507 return FAILURE;
1510 /* NOTE: Because the last instruction of a program may be a CALL */
1511 /* which will return to the first byte *after* the code */
1512 /* range, we test for AIP <= Size, instead of AIP < Size. */
1514 if ( aIP > range->size )
1516 CUR.error = TT_Err_Code_Overflow;
1517 return FAILURE;
1520 CUR.code = range->base;
1521 CUR.codeSize = range->size;
1522 CUR.IP = aIP;
1523 CUR.curRange = aRange;
1525 return SUCCESS;
1529 /*************************************************************************/
1530 /* */
1531 /* <Function> */
1532 /* Direct_Move */
1533 /* */
1534 /* <Description> */
1535 /* Moves a point by a given distance along the freedom vector. The */
1536 /* point will be `touched'. */
1537 /* */
1538 /* <Input> */
1539 /* point :: The index of the point to move. */
1540 /* */
1541 /* distance :: The distance to apply. */
1542 /* */
1543 /* <InOut> */
1544 /* zone :: The affected glyph zone. */
1545 /* */
1546 static void
1547 Direct_Move( EXEC_OP_ TT_GlyphZone zone,
1548 FT_UShort point,
1549 FT_F26Dot6 distance )
1551 FT_F26Dot6 v;
1554 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1555 FT_ASSERT( !CUR.face->unpatented_hinting );
1556 #endif
1558 v = CUR.GS.freeVector.x;
1560 if ( v != 0 )
1562 zone->cur[point].x += TT_MULDIV( distance,
1563 v * 0x10000L,
1564 CUR.F_dot_P );
1566 zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
1569 v = CUR.GS.freeVector.y;
1571 if ( v != 0 )
1573 zone->cur[point].y += TT_MULDIV( distance,
1574 v * 0x10000L,
1575 CUR.F_dot_P );
1577 zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1582 /*************************************************************************/
1583 /* */
1584 /* <Function> */
1585 /* Direct_Move_Orig */
1586 /* */
1587 /* <Description> */
1588 /* Moves the *original* position of a point by a given distance along */
1589 /* the freedom vector. Obviously, the point will not be `touched'. */
1590 /* */
1591 /* <Input> */
1592 /* point :: The index of the point to move. */
1593 /* */
1594 /* distance :: The distance to apply. */
1595 /* */
1596 /* <InOut> */
1597 /* zone :: The affected glyph zone. */
1598 /* */
1599 static void
1600 Direct_Move_Orig( EXEC_OP_ TT_GlyphZone zone,
1601 FT_UShort point,
1602 FT_F26Dot6 distance )
1604 FT_F26Dot6 v;
1607 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1608 FT_ASSERT( !CUR.face->unpatented_hinting );
1609 #endif
1611 v = CUR.GS.freeVector.x;
1613 if ( v != 0 )
1614 zone->org[point].x += TT_MULDIV( distance,
1615 v * 0x10000L,
1616 CUR.F_dot_P );
1618 v = CUR.GS.freeVector.y;
1620 if ( v != 0 )
1621 zone->org[point].y += TT_MULDIV( distance,
1622 v * 0x10000L,
1623 CUR.F_dot_P );
1627 /*************************************************************************/
1628 /* */
1629 /* Special versions of Direct_Move() */
1630 /* */
1631 /* The following versions are used whenever both vectors are both */
1632 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1633 /* */
1634 /*************************************************************************/
1637 static void
1638 Direct_Move_X( EXEC_OP_ TT_GlyphZone zone,
1639 FT_UShort point,
1640 FT_F26Dot6 distance )
1642 FT_UNUSED_EXEC;
1644 zone->cur[point].x += distance;
1645 zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
1649 static void
1650 Direct_Move_Y( EXEC_OP_ TT_GlyphZone zone,
1651 FT_UShort point,
1652 FT_F26Dot6 distance )
1654 FT_UNUSED_EXEC;
1656 zone->cur[point].y += distance;
1657 zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1661 /*************************************************************************/
1662 /* */
1663 /* Special versions of Direct_Move_Orig() */
1664 /* */
1665 /* The following versions are used whenever both vectors are both */
1666 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1667 /* */
1668 /*************************************************************************/
1671 static void
1672 Direct_Move_Orig_X( EXEC_OP_ TT_GlyphZone zone,
1673 FT_UShort point,
1674 FT_F26Dot6 distance )
1676 FT_UNUSED_EXEC;
1678 zone->org[point].x += distance;
1682 static void
1683 Direct_Move_Orig_Y( EXEC_OP_ TT_GlyphZone zone,
1684 FT_UShort point,
1685 FT_F26Dot6 distance )
1687 FT_UNUSED_EXEC;
1689 zone->org[point].y += distance;
1693 /*************************************************************************/
1694 /* */
1695 /* <Function> */
1696 /* Round_None */
1697 /* */
1698 /* <Description> */
1699 /* Does not round, but adds engine compensation. */
1700 /* */
1701 /* <Input> */
1702 /* distance :: The distance (not) to round. */
1703 /* */
1704 /* compensation :: The engine compensation. */
1705 /* */
1706 /* <Return> */
1707 /* The compensated distance. */
1708 /* */
1709 /* <Note> */
1710 /* The TrueType specification says very few about the relationship */
1711 /* between rounding and engine compensation. However, it seems from */
1712 /* the description of super round that we should add the compensation */
1713 /* before rounding. */
1714 /* */
1715 static FT_F26Dot6
1716 Round_None( EXEC_OP_ FT_F26Dot6 distance,
1717 FT_F26Dot6 compensation )
1719 FT_F26Dot6 val;
1721 FT_UNUSED_EXEC;
1724 if ( distance >= 0 )
1726 val = distance + compensation;
1727 if ( distance && val < 0 )
1728 val = 0;
1730 else {
1731 val = distance - compensation;
1732 if ( val > 0 )
1733 val = 0;
1735 return val;
1739 /*************************************************************************/
1740 /* */
1741 /* <Function> */
1742 /* Round_To_Grid */
1743 /* */
1744 /* <Description> */
1745 /* Rounds value to grid after adding engine compensation. */
1746 /* */
1747 /* <Input> */
1748 /* distance :: The distance to round. */
1749 /* */
1750 /* compensation :: The engine compensation. */
1751 /* */
1752 /* <Return> */
1753 /* Rounded distance. */
1754 /* */
1755 static FT_F26Dot6
1756 Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1757 FT_F26Dot6 compensation )
1759 FT_F26Dot6 val;
1761 FT_UNUSED_EXEC;
1764 if ( distance >= 0 )
1766 val = distance + compensation + 32;
1767 if ( distance && val > 0 )
1768 val &= ~63;
1769 else
1770 val = 0;
1772 else
1774 val = -FT_PIX_ROUND( compensation - distance );
1775 if ( val > 0 )
1776 val = 0;
1779 return val;
1783 /*************************************************************************/
1784 /* */
1785 /* <Function> */
1786 /* Round_To_Half_Grid */
1787 /* */
1788 /* <Description> */
1789 /* Rounds value to half grid after adding engine compensation. */
1790 /* */
1791 /* <Input> */
1792 /* distance :: The distance to round. */
1793 /* */
1794 /* compensation :: The engine compensation. */
1795 /* */
1796 /* <Return> */
1797 /* Rounded distance. */
1798 /* */
1799 static FT_F26Dot6
1800 Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance,
1801 FT_F26Dot6 compensation )
1803 FT_F26Dot6 val;
1805 FT_UNUSED_EXEC;
1808 if ( distance >= 0 )
1810 val = FT_PIX_FLOOR( distance + compensation ) + 32;
1811 if ( distance && val < 0 )
1812 val = 0;
1814 else
1816 val = -( FT_PIX_FLOOR( compensation - distance ) + 32 );
1817 if ( val > 0 )
1818 val = 0;
1821 return val;
1825 /*************************************************************************/
1826 /* */
1827 /* <Function> */
1828 /* Round_Down_To_Grid */
1829 /* */
1830 /* <Description> */
1831 /* Rounds value down to grid after adding engine compensation. */
1832 /* */
1833 /* <Input> */
1834 /* distance :: The distance to round. */
1835 /* */
1836 /* compensation :: The engine compensation. */
1837 /* */
1838 /* <Return> */
1839 /* Rounded distance. */
1840 /* */
1841 static FT_F26Dot6
1842 Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1843 FT_F26Dot6 compensation )
1845 FT_F26Dot6 val;
1847 FT_UNUSED_EXEC;
1850 if ( distance >= 0 )
1852 val = distance + compensation;
1853 if ( distance && val > 0 )
1854 val &= ~63;
1855 else
1856 val = 0;
1858 else
1860 val = -( ( compensation - distance ) & -64 );
1861 if ( val > 0 )
1862 val = 0;
1865 return val;
1869 /*************************************************************************/
1870 /* */
1871 /* <Function> */
1872 /* Round_Up_To_Grid */
1873 /* */
1874 /* <Description> */
1875 /* Rounds value up to grid after adding engine compensation. */
1876 /* */
1877 /* <Input> */
1878 /* distance :: The distance to round. */
1879 /* */
1880 /* compensation :: The engine compensation. */
1881 /* */
1882 /* <Return> */
1883 /* Rounded distance. */
1884 /* */
1885 static FT_F26Dot6
1886 Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1887 FT_F26Dot6 compensation )
1889 FT_F26Dot6 val;
1891 FT_UNUSED_EXEC;
1894 if ( distance >= 0 )
1896 val = distance + compensation + 63;
1897 if ( distance && val > 0 )
1898 val &= ~63;
1899 else
1900 val = 0;
1902 else
1904 val = - FT_PIX_CEIL( compensation - distance );
1905 if ( val > 0 )
1906 val = 0;
1909 return val;
1913 /*************************************************************************/
1914 /* */
1915 /* <Function> */
1916 /* Round_To_Double_Grid */
1917 /* */
1918 /* <Description> */
1919 /* Rounds value to double grid after adding engine compensation. */
1920 /* */
1921 /* <Input> */
1922 /* distance :: The distance to round. */
1923 /* */
1924 /* compensation :: The engine compensation. */
1925 /* */
1926 /* <Return> */
1927 /* Rounded distance. */
1928 /* */
1929 static FT_F26Dot6
1930 Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance,
1931 FT_F26Dot6 compensation )
1933 FT_F26Dot6 val;
1935 FT_UNUSED_EXEC;
1938 if ( distance >= 0 )
1940 val = distance + compensation + 16;
1941 if ( distance && val > 0 )
1942 val &= ~31;
1943 else
1944 val = 0;
1946 else
1948 val = -FT_PAD_ROUND( compensation - distance, 32 );
1949 if ( val > 0 )
1950 val = 0;
1953 return val;
1957 /*************************************************************************/
1958 /* */
1959 /* <Function> */
1960 /* Round_Super */
1961 /* */
1962 /* <Description> */
1963 /* Super-rounds value to grid after adding engine compensation. */
1964 /* */
1965 /* <Input> */
1966 /* distance :: The distance to round. */
1967 /* */
1968 /* compensation :: The engine compensation. */
1969 /* */
1970 /* <Return> */
1971 /* Rounded distance. */
1972 /* */
1973 /* <Note> */
1974 /* The TrueType specification says very few about the relationship */
1975 /* between rounding and engine compensation. However, it seems from */
1976 /* the description of super round that we should add the compensation */
1977 /* before rounding. */
1978 /* */
1979 static FT_F26Dot6
1980 Round_Super( EXEC_OP_ FT_F26Dot6 distance,
1981 FT_F26Dot6 compensation )
1983 FT_F26Dot6 val;
1986 if ( distance >= 0 )
1988 val = ( distance - CUR.phase + CUR.threshold + compensation ) &
1989 -CUR.period;
1990 if ( distance && val < 0 )
1991 val = 0;
1992 val += CUR.phase;
1994 else
1996 val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &
1997 -CUR.period );
1998 if ( val > 0 )
1999 val = 0;
2000 val -= CUR.phase;
2003 return val;
2007 /*************************************************************************/
2008 /* */
2009 /* <Function> */
2010 /* Round_Super_45 */
2011 /* */
2012 /* <Description> */
2013 /* Super-rounds value to grid after adding engine compensation. */
2014 /* */
2015 /* <Input> */
2016 /* distance :: The distance to round. */
2017 /* */
2018 /* compensation :: The engine compensation. */
2019 /* */
2020 /* <Return> */
2021 /* Rounded distance. */
2022 /* */
2023 /* <Note> */
2024 /* There is a separate function for Round_Super_45() as we may need */
2025 /* greater precision. */
2026 /* */
2027 static FT_F26Dot6
2028 Round_Super_45( EXEC_OP_ FT_F26Dot6 distance,
2029 FT_F26Dot6 compensation )
2031 FT_F26Dot6 val;
2034 if ( distance >= 0 )
2036 val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
2037 CUR.period ) * CUR.period;
2038 if ( distance && val < 0 )
2039 val = 0;
2040 val += CUR.phase;
2042 else
2044 val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /
2045 CUR.period ) * CUR.period );
2046 if ( val > 0 )
2047 val = 0;
2048 val -= CUR.phase;
2051 return val;
2055 /*************************************************************************/
2056 /* */
2057 /* <Function> */
2058 /* Compute_Round */
2059 /* */
2060 /* <Description> */
2061 /* Sets the rounding mode. */
2062 /* */
2063 /* <Input> */
2064 /* round_mode :: The rounding mode to be used. */
2065 /* */
2066 static void
2067 Compute_Round( EXEC_OP_ FT_Byte round_mode )
2069 switch ( round_mode )
2071 case TT_Round_Off:
2072 CUR.func_round = (TT_Round_Func)Round_None;
2073 break;
2075 case TT_Round_To_Grid:
2076 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2077 break;
2079 case TT_Round_Up_To_Grid:
2080 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2081 break;
2083 case TT_Round_Down_To_Grid:
2084 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2085 break;
2087 case TT_Round_To_Half_Grid:
2088 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2089 break;
2091 case TT_Round_To_Double_Grid:
2092 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2093 break;
2095 case TT_Round_Super:
2096 CUR.func_round = (TT_Round_Func)Round_Super;
2097 break;
2099 case TT_Round_Super_45:
2100 CUR.func_round = (TT_Round_Func)Round_Super_45;
2101 break;
2106 /*************************************************************************/
2107 /* */
2108 /* <Function> */
2109 /* SetSuperRound */
2110 /* */
2111 /* <Description> */
2112 /* Sets Super Round parameters. */
2113 /* */
2114 /* <Input> */
2115 /* GridPeriod :: Grid period */
2116 /* selector :: SROUND opcode */
2117 /* */
2118 static void
2119 SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod,
2120 FT_Long selector )
2122 switch ( (FT_Int)( selector & 0xC0 ) )
2124 case 0:
2125 CUR.period = GridPeriod / 2;
2126 break;
2128 case 0x40:
2129 CUR.period = GridPeriod;
2130 break;
2132 case 0x80:
2133 CUR.period = GridPeriod * 2;
2134 break;
2136 /* This opcode is reserved, but... */
2138 case 0xC0:
2139 CUR.period = GridPeriod;
2140 break;
2143 switch ( (FT_Int)( selector & 0x30 ) )
2145 case 0:
2146 CUR.phase = 0;
2147 break;
2149 case 0x10:
2150 CUR.phase = CUR.period / 4;
2151 break;
2153 case 0x20:
2154 CUR.phase = CUR.period / 2;
2155 break;
2157 case 0x30:
2158 CUR.phase = CUR.period * 3 / 4;
2159 break;
2162 if ( ( selector & 0x0F ) == 0 )
2163 CUR.threshold = CUR.period - 1;
2164 else
2165 CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8;
2167 CUR.period /= 256;
2168 CUR.phase /= 256;
2169 CUR.threshold /= 256;
2173 /*************************************************************************/
2174 /* */
2175 /* <Function> */
2176 /* Project */
2177 /* */
2178 /* <Description> */
2179 /* Computes the projection of vector given by (v2-v1) along the */
2180 /* current projection vector. */
2181 /* */
2182 /* <Input> */
2183 /* v1 :: First input vector. */
2184 /* v2 :: Second input vector. */
2185 /* */
2186 /* <Return> */
2187 /* The distance in F26dot6 format. */
2188 /* */
2189 static FT_F26Dot6
2190 Project( EXEC_OP_ FT_Pos dx,
2191 FT_Pos dy )
2193 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2194 FT_ASSERT( !CUR.face->unpatented_hinting );
2195 #endif
2197 return TT_DotFix14( (FT_UInt32)dx, (FT_UInt32)dy,
2198 CUR.GS.projVector.x,
2199 CUR.GS.projVector.y );
2203 /*************************************************************************/
2204 /* */
2205 /* <Function> */
2206 /* Dual_Project */
2207 /* */
2208 /* <Description> */
2209 /* Computes the projection of the vector given by (v2-v1) along the */
2210 /* current dual vector. */
2211 /* */
2212 /* <Input> */
2213 /* v1 :: First input vector. */
2214 /* v2 :: Second input vector. */
2215 /* */
2216 /* <Return> */
2217 /* The distance in F26dot6 format. */
2218 /* */
2219 static FT_F26Dot6
2220 Dual_Project( EXEC_OP_ FT_Pos dx,
2221 FT_Pos dy )
2223 return TT_DotFix14( (FT_UInt32)dx, (FT_UInt32)dy,
2224 CUR.GS.dualVector.x,
2225 CUR.GS.dualVector.y );
2229 /*************************************************************************/
2230 /* */
2231 /* <Function> */
2232 /* Project_x */
2233 /* */
2234 /* <Description> */
2235 /* Computes the projection of the vector given by (v2-v1) along the */
2236 /* horizontal axis. */
2237 /* */
2238 /* <Input> */
2239 /* v1 :: First input vector. */
2240 /* v2 :: Second input vector. */
2241 /* */
2242 /* <Return> */
2243 /* The distance in F26dot6 format. */
2244 /* */
2245 static FT_F26Dot6
2246 Project_x( EXEC_OP_ FT_Pos dx,
2247 FT_Pos dy )
2249 FT_UNUSED_EXEC;
2250 FT_UNUSED( dy );
2252 return dx;
2256 /*************************************************************************/
2257 /* */
2258 /* <Function> */
2259 /* Project_y */
2260 /* */
2261 /* <Description> */
2262 /* Computes the projection of the vector given by (v2-v1) along the */
2263 /* vertical axis. */
2264 /* */
2265 /* <Input> */
2266 /* v1 :: First input vector. */
2267 /* v2 :: Second input vector. */
2268 /* */
2269 /* <Return> */
2270 /* The distance in F26dot6 format. */
2271 /* */
2272 static FT_F26Dot6
2273 Project_y( EXEC_OP_ FT_Pos dx,
2274 FT_Pos dy )
2276 FT_UNUSED_EXEC;
2277 FT_UNUSED( dx );
2279 return dy;
2283 /*************************************************************************/
2284 /* */
2285 /* <Function> */
2286 /* Compute_Funcs */
2287 /* */
2288 /* <Description> */
2289 /* Computes the projection and movement function pointers according */
2290 /* to the current graphics state. */
2291 /* */
2292 static void
2293 Compute_Funcs( EXEC_OP )
2295 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2296 if ( CUR.face->unpatented_hinting )
2298 /* If both vectors point rightwards along the x axis, set */
2299 /* `both-x-axis' true, otherwise set it false. The x values only */
2300 /* need be tested because the vector has been normalised to a unit */
2301 /* vector of length 0x4000 = unity. */
2302 CUR.GS.both_x_axis = (FT_Bool)( CUR.GS.projVector.x == 0x4000 &&
2303 CUR.GS.freeVector.x == 0x4000 );
2305 /* Throw away projection and freedom vector information */
2306 /* because the patents don't allow them to be stored. */
2307 /* The relevant US Patents are 5155805 and 5325479. */
2308 CUR.GS.projVector.x = 0;
2309 CUR.GS.projVector.y = 0;
2310 CUR.GS.freeVector.x = 0;
2311 CUR.GS.freeVector.y = 0;
2313 if ( CUR.GS.both_x_axis )
2315 CUR.func_project = Project_x;
2316 CUR.func_move = Direct_Move_X;
2317 CUR.func_move_orig = Direct_Move_Orig_X;
2319 else
2321 CUR.func_project = Project_y;
2322 CUR.func_move = Direct_Move_Y;
2323 CUR.func_move_orig = Direct_Move_Orig_Y;
2326 if ( CUR.GS.dualVector.x == 0x4000 )
2327 CUR.func_dualproj = Project_x;
2328 else
2330 if ( CUR.GS.dualVector.y == 0x4000 )
2331 CUR.func_dualproj = Project_y;
2332 else
2333 CUR.func_dualproj = Dual_Project;
2336 /* Force recalculation of cached aspect ratio */
2337 CUR.tt_metrics.ratio = 0;
2339 return;
2341 #endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING */
2343 if ( CUR.GS.freeVector.x == 0x4000 )
2344 CUR.F_dot_P = CUR.GS.projVector.x * 0x10000L;
2345 else
2347 if ( CUR.GS.freeVector.y == 0x4000 )
2348 CUR.F_dot_P = CUR.GS.projVector.y * 0x10000L;
2349 else
2350 CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
2351 (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
2354 if ( CUR.GS.projVector.x == 0x4000 )
2355 CUR.func_project = (TT_Project_Func)Project_x;
2356 else
2358 if ( CUR.GS.projVector.y == 0x4000 )
2359 CUR.func_project = (TT_Project_Func)Project_y;
2360 else
2361 CUR.func_project = (TT_Project_Func)Project;
2364 if ( CUR.GS.dualVector.x == 0x4000 )
2365 CUR.func_dualproj = (TT_Project_Func)Project_x;
2366 else
2368 if ( CUR.GS.dualVector.y == 0x4000 )
2369 CUR.func_dualproj = (TT_Project_Func)Project_y;
2370 else
2371 CUR.func_dualproj = (TT_Project_Func)Dual_Project;
2374 CUR.func_move = (TT_Move_Func)Direct_Move;
2375 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig;
2377 if ( CUR.F_dot_P == 0x40000000L )
2379 if ( CUR.GS.freeVector.x == 0x4000 )
2381 CUR.func_move = (TT_Move_Func)Direct_Move_X;
2382 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;
2384 else
2386 if ( CUR.GS.freeVector.y == 0x4000 )
2388 CUR.func_move = (TT_Move_Func)Direct_Move_Y;
2389 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
2394 /* at small sizes, F_dot_P can become too small, resulting */
2395 /* in overflows and `spikes' in a number of glyphs like `w'. */
2397 if ( FT_ABS( CUR.F_dot_P ) < 0x4000000L )
2398 CUR.F_dot_P = 0x40000000L;
2400 /* Disable cached aspect ratio */
2401 CUR.tt_metrics.ratio = 0;
2405 /*************************************************************************/
2406 /* */
2407 /* <Function> */
2408 /* Normalize */
2409 /* */
2410 /* <Description> */
2411 /* Norms a vector. */
2412 /* */
2413 /* <Input> */
2414 /* Vx :: The horizontal input vector coordinate. */
2415 /* Vy :: The vertical input vector coordinate. */
2416 /* */
2417 /* <Output> */
2418 /* R :: The normed unit vector. */
2419 /* */
2420 /* <Return> */
2421 /* Returns FAILURE if a vector parameter is zero. */
2422 /* */
2423 /* <Note> */
2424 /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
2425 /* R is undefined. */
2426 /* */
2429 static FT_Bool
2430 Normalize( EXEC_OP_ FT_F26Dot6 Vx,
2431 FT_F26Dot6 Vy,
2432 FT_UnitVector* R )
2434 FT_F26Dot6 W;
2435 FT_Bool S1, S2;
2437 FT_UNUSED_EXEC;
2440 if ( FT_ABS( Vx ) < 0x10000L && FT_ABS( Vy ) < 0x10000L )
2442 Vx *= 0x100;
2443 Vy *= 0x100;
2445 W = TT_VecLen( Vx, Vy );
2447 if ( W == 0 )
2449 /* XXX: UNDOCUMENTED! It seems that it is possible to try */
2450 /* to normalize the vector (0,0). Return immediately. */
2451 return SUCCESS;
2454 R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W );
2455 R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W );
2457 return SUCCESS;
2460 W = TT_VecLen( Vx, Vy );
2462 Vx = FT_MulDiv( Vx, 0x4000L, W );
2463 Vy = FT_MulDiv( Vy, 0x4000L, W );
2465 W = Vx * Vx + Vy * Vy;
2467 /* Now, we want that Sqrt( W ) = 0x4000 */
2468 /* Or 0x10000000 <= W < 0x10004000 */
2470 if ( Vx < 0 )
2472 Vx = -Vx;
2473 S1 = TRUE;
2475 else
2476 S1 = FALSE;
2478 if ( Vy < 0 )
2480 Vy = -Vy;
2481 S2 = TRUE;
2483 else
2484 S2 = FALSE;
2486 while ( W < 0x10000000L )
2488 /* We need to increase W by a minimal amount */
2489 if ( Vx < Vy )
2490 Vx++;
2491 else
2492 Vy++;
2494 W = Vx * Vx + Vy * Vy;
2497 while ( W >= 0x10004000L )
2499 /* We need to decrease W by a minimal amount */
2500 if ( Vx < Vy )
2501 Vx--;
2502 else
2503 Vy--;
2505 W = Vx * Vx + Vy * Vy;
2508 /* Note that in various cases, we can only */
2509 /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
2511 if ( S1 )
2512 Vx = -Vx;
2514 if ( S2 )
2515 Vy = -Vy;
2517 R->x = (FT_F2Dot14)Vx; /* Type conversion */
2518 R->y = (FT_F2Dot14)Vy; /* Type conversion */
2520 return SUCCESS;
2524 /*************************************************************************/
2525 /* */
2526 /* Here we start with the implementation of the various opcodes. */
2527 /* */
2528 /*************************************************************************/
2531 static FT_Bool
2532 Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1,
2533 FT_UShort aIdx2,
2534 FT_Int aOpc,
2535 FT_UnitVector* Vec )
2537 FT_Long A, B, C;
2538 FT_Vector* p1;
2539 FT_Vector* p2;
2542 if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
2543 BOUNDS( aIdx2, CUR.zp1.n_points ) )
2545 if ( CUR.pedantic_hinting )
2546 CUR.error = TT_Err_Invalid_Reference;
2547 return FAILURE;
2550 p1 = CUR.zp1.cur + aIdx2;
2551 p2 = CUR.zp2.cur + aIdx1;
2553 A = p1->x - p2->x;
2554 B = p1->y - p2->y;
2556 if ( ( aOpc & 1 ) != 0 )
2558 C = B; /* counter clockwise rotation */
2559 B = A;
2560 A = -C;
2563 NORMalize( A, B, Vec );
2565 return SUCCESS;
2569 /* When not using the big switch statements, the interpreter uses a */
2570 /* call table defined later below in this source. Each opcode must */
2571 /* thus have a corresponding function, even trivial ones. */
2572 /* */
2573 /* They are all defined there. */
2575 #define DO_SVTCA \
2577 FT_Short A, B; \
2580 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2581 B = A ^ (FT_Short)0x4000; \
2583 CUR.GS.freeVector.x = A; \
2584 CUR.GS.projVector.x = A; \
2585 CUR.GS.dualVector.x = A; \
2587 CUR.GS.freeVector.y = B; \
2588 CUR.GS.projVector.y = B; \
2589 CUR.GS.dualVector.y = B; \
2591 COMPUTE_Funcs(); \
2595 #define DO_SPVTCA \
2597 FT_Short A, B; \
2600 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2601 B = A ^ (FT_Short)0x4000; \
2603 CUR.GS.projVector.x = A; \
2604 CUR.GS.dualVector.x = A; \
2606 CUR.GS.projVector.y = B; \
2607 CUR.GS.dualVector.y = B; \
2609 GUESS_VECTOR( freeVector ); \
2611 COMPUTE_Funcs(); \
2615 #define DO_SFVTCA \
2617 FT_Short A, B; \
2620 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2621 B = A ^ (FT_Short)0x4000; \
2623 CUR.GS.freeVector.x = A; \
2624 CUR.GS.freeVector.y = B; \
2626 GUESS_VECTOR( projVector ); \
2628 COMPUTE_Funcs(); \
2632 #define DO_SPVTL \
2633 if ( INS_SxVTL( (FT_UShort)args[1], \
2634 (FT_UShort)args[0], \
2635 CUR.opcode, \
2636 &CUR.GS.projVector ) == SUCCESS ) \
2638 CUR.GS.dualVector = CUR.GS.projVector; \
2639 GUESS_VECTOR( freeVector ); \
2640 COMPUTE_Funcs(); \
2644 #define DO_SFVTL \
2645 if ( INS_SxVTL( (FT_UShort)args[1], \
2646 (FT_UShort)args[0], \
2647 CUR.opcode, \
2648 &CUR.GS.freeVector ) == SUCCESS ) \
2650 GUESS_VECTOR( projVector ); \
2651 COMPUTE_Funcs(); \
2655 #define DO_SFVTPV \
2656 GUESS_VECTOR( projVector ); \
2657 CUR.GS.freeVector = CUR.GS.projVector; \
2658 COMPUTE_Funcs();
2661 #define DO_SPVFS \
2663 FT_Short S; \
2664 FT_Long X, Y; \
2667 /* Only use low 16bits, then sign extend */ \
2668 S = (FT_Short)args[1]; \
2669 Y = (FT_Long)S; \
2670 S = (FT_Short)args[0]; \
2671 X = (FT_Long)S; \
2673 NORMalize( X, Y, &CUR.GS.projVector ); \
2675 CUR.GS.dualVector = CUR.GS.projVector; \
2676 GUESS_VECTOR( freeVector ); \
2677 COMPUTE_Funcs(); \
2681 #define DO_SFVFS \
2683 FT_Short S; \
2684 FT_Long X, Y; \
2687 /* Only use low 16bits, then sign extend */ \
2688 S = (FT_Short)args[1]; \
2689 Y = (FT_Long)S; \
2690 S = (FT_Short)args[0]; \
2691 X = S; \
2693 NORMalize( X, Y, &CUR.GS.freeVector ); \
2694 GUESS_VECTOR( projVector ); \
2695 COMPUTE_Funcs(); \
2699 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2700 #define DO_GPV \
2701 if ( CUR.face->unpatented_hinting ) \
2703 args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
2704 args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
2706 else \
2708 args[0] = CUR.GS.projVector.x; \
2709 args[1] = CUR.GS.projVector.y; \
2711 #else
2712 #define DO_GPV \
2713 args[0] = CUR.GS.projVector.x; \
2714 args[1] = CUR.GS.projVector.y;
2715 #endif
2718 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2719 #define DO_GFV \
2720 if ( CUR.face->unpatented_hinting ) \
2722 args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
2723 args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
2725 else \
2727 args[0] = CUR.GS.freeVector.x; \
2728 args[1] = CUR.GS.freeVector.y; \
2730 #else
2731 #define DO_GFV \
2732 args[0] = CUR.GS.freeVector.x; \
2733 args[1] = CUR.GS.freeVector.y;
2734 #endif
2737 #define DO_SRP0 \
2738 CUR.GS.rp0 = (FT_UShort)args[0];
2741 #define DO_SRP1 \
2742 CUR.GS.rp1 = (FT_UShort)args[0];
2745 #define DO_SRP2 \
2746 CUR.GS.rp2 = (FT_UShort)args[0];
2749 #define DO_RTHG \
2750 CUR.GS.round_state = TT_Round_To_Half_Grid; \
2751 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2754 #define DO_RTG \
2755 CUR.GS.round_state = TT_Round_To_Grid; \
2756 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2759 #define DO_RTDG \
2760 CUR.GS.round_state = TT_Round_To_Double_Grid; \
2761 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2764 #define DO_RUTG \
2765 CUR.GS.round_state = TT_Round_Up_To_Grid; \
2766 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2769 #define DO_RDTG \
2770 CUR.GS.round_state = TT_Round_Down_To_Grid; \
2771 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2774 #define DO_ROFF \
2775 CUR.GS.round_state = TT_Round_Off; \
2776 CUR.func_round = (TT_Round_Func)Round_None;
2779 #define DO_SROUND \
2780 SET_SuperRound( 0x4000, args[0] ); \
2781 CUR.GS.round_state = TT_Round_Super; \
2782 CUR.func_round = (TT_Round_Func)Round_Super;
2785 #define DO_S45ROUND \
2786 SET_SuperRound( 0x2D41, args[0] ); \
2787 CUR.GS.round_state = TT_Round_Super_45; \
2788 CUR.func_round = (TT_Round_Func)Round_Super_45;
2791 #define DO_SLOOP \
2792 if ( args[0] < 0 ) \
2793 CUR.error = TT_Err_Bad_Argument; \
2794 else \
2795 CUR.GS.loop = args[0];
2798 #define DO_SMD \
2799 CUR.GS.minimum_distance = args[0];
2802 #define DO_SCVTCI \
2803 CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
2806 #define DO_SSWCI \
2807 CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
2810 /* XXX: UNDOCUMENTED! or bug in the Windows engine? */
2811 /* */
2812 /* It seems that the value that is read here is */
2813 /* expressed in 16.16 format rather than in font */
2814 /* units. */
2815 /* */
2816 #define DO_SSW \
2817 CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
2820 #define DO_FLIPON \
2821 CUR.GS.auto_flip = TRUE;
2824 #define DO_FLIPOFF \
2825 CUR.GS.auto_flip = FALSE;
2828 #define DO_SDB \
2829 CUR.GS.delta_base = (FT_Short)args[0];
2832 #define DO_SDS \
2833 CUR.GS.delta_shift = (FT_Short)args[0];
2836 #define DO_MD /* nothing */
2839 #define DO_MPPEM \
2840 args[0] = CURRENT_Ppem();
2843 /* Note: The pointSize should be irrelevant in a given font program; */
2844 /* we thus decide to return only the ppem. */
2845 #if 0
2847 #define DO_MPS \
2848 args[0] = CUR.metrics.pointSize;
2850 #else
2852 #define DO_MPS \
2853 args[0] = CURRENT_Ppem();
2855 #endif /* 0 */
2858 #define DO_DUP \
2859 args[1] = args[0];
2862 #define DO_CLEAR \
2863 CUR.new_top = 0;
2866 #define DO_SWAP \
2868 FT_Long L; \
2871 L = args[0]; \
2872 args[0] = args[1]; \
2873 args[1] = L; \
2877 #define DO_DEPTH \
2878 args[0] = CUR.top;
2881 #define DO_CINDEX \
2883 FT_Long L; \
2886 L = args[0]; \
2888 if ( L <= 0 || L > CUR.args ) \
2889 CUR.error = TT_Err_Invalid_Reference; \
2890 else \
2891 args[0] = CUR.stack[CUR.args - L]; \
2895 #define DO_JROT \
2896 if ( args[1] != 0 ) \
2898 CUR.IP += args[0]; \
2899 CUR.step_ins = FALSE; \
2903 #define DO_JMPR \
2904 CUR.IP += args[0]; \
2905 CUR.step_ins = FALSE;
2908 #define DO_JROF \
2909 if ( args[1] == 0 ) \
2911 CUR.IP += args[0]; \
2912 CUR.step_ins = FALSE; \
2916 #define DO_LT \
2917 args[0] = ( args[0] < args[1] );
2920 #define DO_LTEQ \
2921 args[0] = ( args[0] <= args[1] );
2924 #define DO_GT \
2925 args[0] = ( args[0] > args[1] );
2928 #define DO_GTEQ \
2929 args[0] = ( args[0] >= args[1] );
2932 #define DO_EQ \
2933 args[0] = ( args[0] == args[1] );
2936 #define DO_NEQ \
2937 args[0] = ( args[0] != args[1] );
2940 #define DO_ODD \
2941 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
2944 #define DO_EVEN \
2945 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
2948 #define DO_AND \
2949 args[0] = ( args[0] && args[1] );
2952 #define DO_OR \
2953 args[0] = ( args[0] || args[1] );
2956 #define DO_NOT \
2957 args[0] = !args[0];
2960 #define DO_ADD \
2961 args[0] += args[1];
2964 #define DO_SUB \
2965 args[0] -= args[1];
2968 #define DO_DIV \
2969 if ( args[1] == 0 ) \
2970 CUR.error = TT_Err_Divide_By_Zero; \
2971 else \
2972 args[0] = TT_MULDIV_NO_ROUND( args[0], 64L, args[1] );
2975 #define DO_MUL \
2976 args[0] = TT_MULDIV( args[0], args[1], 64L );
2979 #define DO_ABS \
2980 args[0] = FT_ABS( args[0] );
2983 #define DO_NEG \
2984 args[0] = -args[0];
2987 #define DO_FLOOR \
2988 args[0] = FT_PIX_FLOOR( args[0] );
2991 #define DO_CEILING \
2992 args[0] = FT_PIX_CEIL( args[0] );
2995 #define DO_RS \
2997 FT_ULong I = (FT_ULong)args[0]; \
3000 if ( BOUNDS( I, CUR.storeSize ) ) \
3002 if ( CUR.pedantic_hinting ) \
3004 ARRAY_BOUND_ERROR; \
3006 else \
3007 args[0] = 0; \
3009 else \
3010 args[0] = CUR.storage[I]; \
3014 #define DO_WS \
3016 FT_ULong I = (FT_ULong)args[0]; \
3019 if ( BOUNDS( I, CUR.storeSize ) ) \
3021 if ( CUR.pedantic_hinting ) \
3023 ARRAY_BOUND_ERROR; \
3026 else \
3027 CUR.storage[I] = args[1]; \
3031 #define DO_RCVT \
3033 FT_ULong I = (FT_ULong)args[0]; \
3036 if ( BOUNDS( I, CUR.cvtSize ) ) \
3038 if ( CUR.pedantic_hinting ) \
3040 ARRAY_BOUND_ERROR; \
3042 else \
3043 args[0] = 0; \
3045 else \
3046 args[0] = CUR_Func_read_cvt( I ); \
3050 #define DO_WCVTP \
3052 FT_ULong I = (FT_ULong)args[0]; \
3055 if ( BOUNDS( I, CUR.cvtSize ) ) \
3057 if ( CUR.pedantic_hinting ) \
3059 ARRAY_BOUND_ERROR; \
3062 else \
3063 CUR_Func_write_cvt( I, args[1] ); \
3067 #define DO_WCVTF \
3069 FT_ULong I = (FT_ULong)args[0]; \
3072 if ( BOUNDS( I, CUR.cvtSize ) ) \
3074 if ( CUR.pedantic_hinting ) \
3076 ARRAY_BOUND_ERROR; \
3079 else \
3080 CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
3084 #define DO_DEBUG \
3085 CUR.error = TT_Err_Debug_OpCode;
3088 #define DO_ROUND \
3089 args[0] = CUR_Func_round( \
3090 args[0], \
3091 CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
3094 #define DO_NROUND \
3095 args[0] = ROUND_None( args[0], \
3096 CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
3099 #define DO_MAX \
3100 if ( args[1] > args[0] ) \
3101 args[0] = args[1];
3104 #define DO_MIN \
3105 if ( args[1] < args[0] ) \
3106 args[0] = args[1];
3109 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
3112 #undef ARRAY_BOUND_ERROR
3113 #define ARRAY_BOUND_ERROR \
3115 CUR.error = TT_Err_Invalid_Reference; \
3116 return; \
3120 /*************************************************************************/
3121 /* */
3122 /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
3123 /* Opcode range: 0x00-0x01 */
3124 /* Stack: --> */
3125 /* */
3126 static void
3127 Ins_SVTCA( INS_ARG )
3129 DO_SVTCA
3133 /*************************************************************************/
3134 /* */
3135 /* SPVTCA[a]: Set PVector to Coordinate Axis */
3136 /* Opcode range: 0x02-0x03 */
3137 /* Stack: --> */
3138 /* */
3139 static void
3140 Ins_SPVTCA( INS_ARG )
3142 DO_SPVTCA
3146 /*************************************************************************/
3147 /* */
3148 /* SFVTCA[a]: Set FVector to Coordinate Axis */
3149 /* Opcode range: 0x04-0x05 */
3150 /* Stack: --> */
3151 /* */
3152 static void
3153 Ins_SFVTCA( INS_ARG )
3155 DO_SFVTCA
3159 /*************************************************************************/
3160 /* */
3161 /* SPVTL[a]: Set PVector To Line */
3162 /* Opcode range: 0x06-0x07 */
3163 /* Stack: uint32 uint32 --> */
3164 /* */
3165 static void
3166 Ins_SPVTL( INS_ARG )
3168 DO_SPVTL
3172 /*************************************************************************/
3173 /* */
3174 /* SFVTL[a]: Set FVector To Line */
3175 /* Opcode range: 0x08-0x09 */
3176 /* Stack: uint32 uint32 --> */
3177 /* */
3178 static void
3179 Ins_SFVTL( INS_ARG )
3181 DO_SFVTL
3185 /*************************************************************************/
3186 /* */
3187 /* SFVTPV[]: Set FVector To PVector */
3188 /* Opcode range: 0x0E */
3189 /* Stack: --> */
3190 /* */
3191 static void
3192 Ins_SFVTPV( INS_ARG )
3194 DO_SFVTPV
3198 /*************************************************************************/
3199 /* */
3200 /* SPVFS[]: Set PVector From Stack */
3201 /* Opcode range: 0x0A */
3202 /* Stack: f2.14 f2.14 --> */
3203 /* */
3204 static void
3205 Ins_SPVFS( INS_ARG )
3207 DO_SPVFS
3211 /*************************************************************************/
3212 /* */
3213 /* SFVFS[]: Set FVector From Stack */
3214 /* Opcode range: 0x0B */
3215 /* Stack: f2.14 f2.14 --> */
3216 /* */
3217 static void
3218 Ins_SFVFS( INS_ARG )
3220 DO_SFVFS
3224 /*************************************************************************/
3225 /* */
3226 /* GPV[]: Get Projection Vector */
3227 /* Opcode range: 0x0C */
3228 /* Stack: ef2.14 --> ef2.14 */
3229 /* */
3230 static void
3231 Ins_GPV( INS_ARG )
3233 DO_GPV
3237 /*************************************************************************/
3238 /* GFV[]: Get Freedom Vector */
3239 /* Opcode range: 0x0D */
3240 /* Stack: ef2.14 --> ef2.14 */
3241 /* */
3242 static void
3243 Ins_GFV( INS_ARG )
3245 DO_GFV
3249 /*************************************************************************/
3250 /* */
3251 /* SRP0[]: Set Reference Point 0 */
3252 /* Opcode range: 0x10 */
3253 /* Stack: uint32 --> */
3254 /* */
3255 static void
3256 Ins_SRP0( INS_ARG )
3258 DO_SRP0
3262 /*************************************************************************/
3263 /* */
3264 /* SRP1[]: Set Reference Point 1 */
3265 /* Opcode range: 0x11 */
3266 /* Stack: uint32 --> */
3267 /* */
3268 static void
3269 Ins_SRP1( INS_ARG )
3271 DO_SRP1
3275 /*************************************************************************/
3276 /* */
3277 /* SRP2[]: Set Reference Point 2 */
3278 /* Opcode range: 0x12 */
3279 /* Stack: uint32 --> */
3280 /* */
3281 static void
3282 Ins_SRP2( INS_ARG )
3284 DO_SRP2
3288 /*************************************************************************/
3289 /* */
3290 /* RTHG[]: Round To Half Grid */
3291 /* Opcode range: 0x19 */
3292 /* Stack: --> */
3293 /* */
3294 static void
3295 Ins_RTHG( INS_ARG )
3297 DO_RTHG
3301 /*************************************************************************/
3302 /* */
3303 /* RTG[]: Round To Grid */
3304 /* Opcode range: 0x18 */
3305 /* Stack: --> */
3306 /* */
3307 static void
3308 Ins_RTG( INS_ARG )
3310 DO_RTG
3314 /*************************************************************************/
3315 /* RTDG[]: Round To Double Grid */
3316 /* Opcode range: 0x3D */
3317 /* Stack: --> */
3318 /* */
3319 static void
3320 Ins_RTDG( INS_ARG )
3322 DO_RTDG
3326 /*************************************************************************/
3327 /* RUTG[]: Round Up To Grid */
3328 /* Opcode range: 0x7C */
3329 /* Stack: --> */
3330 /* */
3331 static void
3332 Ins_RUTG( INS_ARG )
3334 DO_RUTG
3338 /*************************************************************************/
3339 /* */
3340 /* RDTG[]: Round Down To Grid */
3341 /* Opcode range: 0x7D */
3342 /* Stack: --> */
3343 /* */
3344 static void
3345 Ins_RDTG( INS_ARG )
3347 DO_RDTG
3351 /*************************************************************************/
3352 /* */
3353 /* ROFF[]: Round OFF */
3354 /* Opcode range: 0x7A */
3355 /* Stack: --> */
3356 /* */
3357 static void
3358 Ins_ROFF( INS_ARG )
3360 DO_ROFF
3364 /*************************************************************************/
3365 /* */
3366 /* SROUND[]: Super ROUND */
3367 /* Opcode range: 0x76 */
3368 /* Stack: Eint8 --> */
3369 /* */
3370 static void
3371 Ins_SROUND( INS_ARG )
3373 DO_SROUND
3377 /*************************************************************************/
3378 /* */
3379 /* S45ROUND[]: Super ROUND 45 degrees */
3380 /* Opcode range: 0x77 */
3381 /* Stack: uint32 --> */
3382 /* */
3383 static void
3384 Ins_S45ROUND( INS_ARG )
3386 DO_S45ROUND
3390 /*************************************************************************/
3391 /* */
3392 /* SLOOP[]: Set LOOP variable */
3393 /* Opcode range: 0x17 */
3394 /* Stack: int32? --> */
3395 /* */
3396 static void
3397 Ins_SLOOP( INS_ARG )
3399 DO_SLOOP
3403 /*************************************************************************/
3404 /* */
3405 /* SMD[]: Set Minimum Distance */
3406 /* Opcode range: 0x1A */
3407 /* Stack: f26.6 --> */
3408 /* */
3409 static void
3410 Ins_SMD( INS_ARG )
3412 DO_SMD
3416 /*************************************************************************/
3417 /* */
3418 /* SCVTCI[]: Set Control Value Table Cut In */
3419 /* Opcode range: 0x1D */
3420 /* Stack: f26.6 --> */
3421 /* */
3422 static void
3423 Ins_SCVTCI( INS_ARG )
3425 DO_SCVTCI
3429 /*************************************************************************/
3430 /* */
3431 /* SSWCI[]: Set Single Width Cut In */
3432 /* Opcode range: 0x1E */
3433 /* Stack: f26.6 --> */
3434 /* */
3435 static void
3436 Ins_SSWCI( INS_ARG )
3438 DO_SSWCI
3442 /*************************************************************************/
3443 /* */
3444 /* SSW[]: Set Single Width */
3445 /* Opcode range: 0x1F */
3446 /* Stack: int32? --> */
3447 /* */
3448 static void
3449 Ins_SSW( INS_ARG )
3451 DO_SSW
3455 /*************************************************************************/
3456 /* */
3457 /* FLIPON[]: Set auto-FLIP to ON */
3458 /* Opcode range: 0x4D */
3459 /* Stack: --> */
3460 /* */
3461 static void
3462 Ins_FLIPON( INS_ARG )
3464 DO_FLIPON
3468 /*************************************************************************/
3469 /* */
3470 /* FLIPOFF[]: Set auto-FLIP to OFF */
3471 /* Opcode range: 0x4E */
3472 /* Stack: --> */
3473 /* */
3474 static void
3475 Ins_FLIPOFF( INS_ARG )
3477 DO_FLIPOFF
3481 /*************************************************************************/
3482 /* */
3483 /* SANGW[]: Set ANGle Weight */
3484 /* Opcode range: 0x7E */
3485 /* Stack: uint32 --> */
3486 /* */
3487 static void
3488 Ins_SANGW( INS_ARG )
3490 /* instruction not supported anymore */
3494 /*************************************************************************/
3495 /* */
3496 /* SDB[]: Set Delta Base */
3497 /* Opcode range: 0x5E */
3498 /* Stack: uint32 --> */
3499 /* */
3500 static void
3501 Ins_SDB( INS_ARG )
3503 DO_SDB
3507 /*************************************************************************/
3508 /* */
3509 /* SDS[]: Set Delta Shift */
3510 /* Opcode range: 0x5F */
3511 /* Stack: uint32 --> */
3512 /* */
3513 static void
3514 Ins_SDS( INS_ARG )
3516 DO_SDS
3520 /*************************************************************************/
3521 /* */
3522 /* MPPEM[]: Measure Pixel Per EM */
3523 /* Opcode range: 0x4B */
3524 /* Stack: --> Euint16 */
3525 /* */
3526 static void
3527 Ins_MPPEM( INS_ARG )
3529 DO_MPPEM
3533 /*************************************************************************/
3534 /* */
3535 /* MPS[]: Measure Point Size */
3536 /* Opcode range: 0x4C */
3537 /* Stack: --> Euint16 */
3538 /* */
3539 static void
3540 Ins_MPS( INS_ARG )
3542 DO_MPS
3546 /*************************************************************************/
3547 /* */
3548 /* DUP[]: DUPlicate the top stack's element */
3549 /* Opcode range: 0x20 */
3550 /* Stack: StkElt --> StkElt StkElt */
3551 /* */
3552 static void
3553 Ins_DUP( INS_ARG )
3555 DO_DUP
3559 /*************************************************************************/
3560 /* */
3561 /* POP[]: POP the stack's top element */
3562 /* Opcode range: 0x21 */
3563 /* Stack: StkElt --> */
3564 /* */
3565 static void
3566 Ins_POP( INS_ARG )
3568 /* nothing to do */
3572 /*************************************************************************/
3573 /* */
3574 /* CLEAR[]: CLEAR the entire stack */
3575 /* Opcode range: 0x22 */
3576 /* Stack: StkElt... --> */
3577 /* */
3578 static void
3579 Ins_CLEAR( INS_ARG )
3581 DO_CLEAR
3585 /*************************************************************************/
3586 /* */
3587 /* SWAP[]: SWAP the stack's top two elements */
3588 /* Opcode range: 0x23 */
3589 /* Stack: 2 * StkElt --> 2 * StkElt */
3590 /* */
3591 static void
3592 Ins_SWAP( INS_ARG )
3594 DO_SWAP
3598 /*************************************************************************/
3599 /* */
3600 /* DEPTH[]: return the stack DEPTH */
3601 /* Opcode range: 0x24 */
3602 /* Stack: --> uint32 */
3603 /* */
3604 static void
3605 Ins_DEPTH( INS_ARG )
3607 DO_DEPTH
3611 /*************************************************************************/
3612 /* */
3613 /* CINDEX[]: Copy INDEXed element */
3614 /* Opcode range: 0x25 */
3615 /* Stack: int32 --> StkElt */
3616 /* */
3617 static void
3618 Ins_CINDEX( INS_ARG )
3620 DO_CINDEX
3624 /*************************************************************************/
3625 /* */
3626 /* EIF[]: End IF */
3627 /* Opcode range: 0x59 */
3628 /* Stack: --> */
3629 /* */
3630 static void
3631 Ins_EIF( INS_ARG )
3633 /* nothing to do */
3637 /*************************************************************************/
3638 /* */
3639 /* JROT[]: Jump Relative On True */
3640 /* Opcode range: 0x78 */
3641 /* Stack: StkElt int32 --> */
3642 /* */
3643 static void
3644 Ins_JROT( INS_ARG )
3646 DO_JROT
3650 /*************************************************************************/
3651 /* */
3652 /* JMPR[]: JuMP Relative */
3653 /* Opcode range: 0x1C */
3654 /* Stack: int32 --> */
3655 /* */
3656 static void
3657 Ins_JMPR( INS_ARG )
3659 DO_JMPR
3663 /*************************************************************************/
3664 /* */
3665 /* JROF[]: Jump Relative On False */
3666 /* Opcode range: 0x79 */
3667 /* Stack: StkElt int32 --> */
3668 /* */
3669 static void
3670 Ins_JROF( INS_ARG )
3672 DO_JROF
3676 /*************************************************************************/
3677 /* */
3678 /* LT[]: Less Than */
3679 /* Opcode range: 0x50 */
3680 /* Stack: int32? int32? --> bool */
3681 /* */
3682 static void
3683 Ins_LT( INS_ARG )
3685 DO_LT
3689 /*************************************************************************/
3690 /* */
3691 /* LTEQ[]: Less Than or EQual */
3692 /* Opcode range: 0x51 */
3693 /* Stack: int32? int32? --> bool */
3694 /* */
3695 static void
3696 Ins_LTEQ( INS_ARG )
3698 DO_LTEQ
3702 /*************************************************************************/
3703 /* */
3704 /* GT[]: Greater Than */
3705 /* Opcode range: 0x52 */
3706 /* Stack: int32? int32? --> bool */
3707 /* */
3708 static void
3709 Ins_GT( INS_ARG )
3711 DO_GT
3715 /*************************************************************************/
3716 /* */
3717 /* GTEQ[]: Greater Than or EQual */
3718 /* Opcode range: 0x53 */
3719 /* Stack: int32? int32? --> bool */
3720 /* */
3721 static void
3722 Ins_GTEQ( INS_ARG )
3724 DO_GTEQ
3728 /*************************************************************************/
3729 /* */
3730 /* EQ[]: EQual */
3731 /* Opcode range: 0x54 */
3732 /* Stack: StkElt StkElt --> bool */
3733 /* */
3734 static void
3735 Ins_EQ( INS_ARG )
3737 DO_EQ
3741 /*************************************************************************/
3742 /* */
3743 /* NEQ[]: Not EQual */
3744 /* Opcode range: 0x55 */
3745 /* Stack: StkElt StkElt --> bool */
3746 /* */
3747 static void
3748 Ins_NEQ( INS_ARG )
3750 DO_NEQ
3754 /*************************************************************************/
3755 /* */
3756 /* ODD[]: Is ODD */
3757 /* Opcode range: 0x56 */
3758 /* Stack: f26.6 --> bool */
3759 /* */
3760 static void
3761 Ins_ODD( INS_ARG )
3763 DO_ODD
3767 /*************************************************************************/
3768 /* */
3769 /* EVEN[]: Is EVEN */
3770 /* Opcode range: 0x57 */
3771 /* Stack: f26.6 --> bool */
3772 /* */
3773 static void
3774 Ins_EVEN( INS_ARG )
3776 DO_EVEN
3780 /*************************************************************************/
3781 /* */
3782 /* AND[]: logical AND */
3783 /* Opcode range: 0x5A */
3784 /* Stack: uint32 uint32 --> uint32 */
3785 /* */
3786 static void
3787 Ins_AND( INS_ARG )
3789 DO_AND
3793 /*************************************************************************/
3794 /* */
3795 /* OR[]: logical OR */
3796 /* Opcode range: 0x5B */
3797 /* Stack: uint32 uint32 --> uint32 */
3798 /* */
3799 static void
3800 Ins_OR( INS_ARG )
3802 DO_OR
3806 /*************************************************************************/
3807 /* */
3808 /* NOT[]: logical NOT */
3809 /* Opcode range: 0x5C */
3810 /* Stack: StkElt --> uint32 */
3811 /* */
3812 static void
3813 Ins_NOT( INS_ARG )
3815 DO_NOT
3819 /*************************************************************************/
3820 /* */
3821 /* ADD[]: ADD */
3822 /* Opcode range: 0x60 */
3823 /* Stack: f26.6 f26.6 --> f26.6 */
3824 /* */
3825 static void
3826 Ins_ADD( INS_ARG )
3828 DO_ADD
3832 /*************************************************************************/
3833 /* */
3834 /* SUB[]: SUBtract */
3835 /* Opcode range: 0x61 */
3836 /* Stack: f26.6 f26.6 --> f26.6 */
3837 /* */
3838 static void
3839 Ins_SUB( INS_ARG )
3841 DO_SUB
3845 /*************************************************************************/
3846 /* */
3847 /* DIV[]: DIVide */
3848 /* Opcode range: 0x62 */
3849 /* Stack: f26.6 f26.6 --> f26.6 */
3850 /* */
3851 static void
3852 Ins_DIV( INS_ARG )
3854 DO_DIV
3858 /*************************************************************************/
3859 /* */
3860 /* MUL[]: MULtiply */
3861 /* Opcode range: 0x63 */
3862 /* Stack: f26.6 f26.6 --> f26.6 */
3863 /* */
3864 static void
3865 Ins_MUL( INS_ARG )
3867 DO_MUL
3871 /*************************************************************************/
3872 /* */
3873 /* ABS[]: ABSolute value */
3874 /* Opcode range: 0x64 */
3875 /* Stack: f26.6 --> f26.6 */
3876 /* */
3877 static void
3878 Ins_ABS( INS_ARG )
3880 DO_ABS
3884 /*************************************************************************/
3885 /* */
3886 /* NEG[]: NEGate */
3887 /* Opcode range: 0x65 */
3888 /* Stack: f26.6 --> f26.6 */
3889 /* */
3890 static void
3891 Ins_NEG( INS_ARG )
3893 DO_NEG
3897 /*************************************************************************/
3898 /* */
3899 /* FLOOR[]: FLOOR */
3900 /* Opcode range: 0x66 */
3901 /* Stack: f26.6 --> f26.6 */
3902 /* */
3903 static void
3904 Ins_FLOOR( INS_ARG )
3906 DO_FLOOR
3910 /*************************************************************************/
3911 /* */
3912 /* CEILING[]: CEILING */
3913 /* Opcode range: 0x67 */
3914 /* Stack: f26.6 --> f26.6 */
3915 /* */
3916 static void
3917 Ins_CEILING( INS_ARG )
3919 DO_CEILING
3923 /*************************************************************************/
3924 /* */
3925 /* RS[]: Read Store */
3926 /* Opcode range: 0x43 */
3927 /* Stack: uint32 --> uint32 */
3928 /* */
3929 static void
3930 Ins_RS( INS_ARG )
3932 DO_RS
3936 /*************************************************************************/
3937 /* */
3938 /* WS[]: Write Store */
3939 /* Opcode range: 0x42 */
3940 /* Stack: uint32 uint32 --> */
3941 /* */
3942 static void
3943 Ins_WS( INS_ARG )
3945 DO_WS
3949 /*************************************************************************/
3950 /* */
3951 /* WCVTP[]: Write CVT in Pixel units */
3952 /* Opcode range: 0x44 */
3953 /* Stack: f26.6 uint32 --> */
3954 /* */
3955 static void
3956 Ins_WCVTP( INS_ARG )
3958 DO_WCVTP
3962 /*************************************************************************/
3963 /* */
3964 /* WCVTF[]: Write CVT in Funits */
3965 /* Opcode range: 0x70 */
3966 /* Stack: uint32 uint32 --> */
3967 /* */
3968 static void
3969 Ins_WCVTF( INS_ARG )
3971 DO_WCVTF
3975 /*************************************************************************/
3976 /* */
3977 /* RCVT[]: Read CVT */
3978 /* Opcode range: 0x45 */
3979 /* Stack: uint32 --> f26.6 */
3980 /* */
3981 static void
3982 Ins_RCVT( INS_ARG )
3984 DO_RCVT
3988 /*************************************************************************/
3989 /* */
3990 /* AA[]: Adjust Angle */
3991 /* Opcode range: 0x7F */
3992 /* Stack: uint32 --> */
3993 /* */
3994 static void
3995 Ins_AA( INS_ARG )
3997 /* intentionally no longer supported */
4001 /*************************************************************************/
4002 /* */
4003 /* DEBUG[]: DEBUG. Unsupported. */
4004 /* Opcode range: 0x4F */
4005 /* Stack: uint32 --> */
4006 /* */
4007 /* Note: The original instruction pops a value from the stack. */
4008 /* */
4009 static void
4010 Ins_DEBUG( INS_ARG )
4012 DO_DEBUG
4016 /*************************************************************************/
4017 /* */
4018 /* ROUND[ab]: ROUND value */
4019 /* Opcode range: 0x68-0x6B */
4020 /* Stack: f26.6 --> f26.6 */
4021 /* */
4022 static void
4023 Ins_ROUND( INS_ARG )
4025 DO_ROUND
4029 /*************************************************************************/
4030 /* */
4031 /* NROUND[ab]: No ROUNDing of value */
4032 /* Opcode range: 0x6C-0x6F */
4033 /* Stack: f26.6 --> f26.6 */
4034 /* */
4035 static void
4036 Ins_NROUND( INS_ARG )
4038 DO_NROUND
4042 /*************************************************************************/
4043 /* */
4044 /* MAX[]: MAXimum */
4045 /* Opcode range: 0x68 */
4046 /* Stack: int32? int32? --> int32 */
4047 /* */
4048 static void
4049 Ins_MAX( INS_ARG )
4051 DO_MAX
4055 /*************************************************************************/
4056 /* */
4057 /* MIN[]: MINimum */
4058 /* Opcode range: 0x69 */
4059 /* Stack: int32? int32? --> int32 */
4060 /* */
4061 static void
4062 Ins_MIN( INS_ARG )
4064 DO_MIN
4068 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
4071 /*************************************************************************/
4072 /* */
4073 /* The following functions are called as is within the switch statement. */
4074 /* */
4075 /*************************************************************************/
4078 /*************************************************************************/
4079 /* */
4080 /* MINDEX[]: Move INDEXed element */
4081 /* Opcode range: 0x26 */
4082 /* Stack: int32? --> StkElt */
4083 /* */
4084 static void
4085 Ins_MINDEX( INS_ARG )
4087 FT_Long L, K;
4090 L = args[0];
4092 if ( L <= 0 || L > CUR.args )
4094 CUR.error = TT_Err_Invalid_Reference;
4095 return;
4098 K = CUR.stack[CUR.args - L];
4100 FT_ARRAY_MOVE( &CUR.stack[CUR.args - L ],
4101 &CUR.stack[CUR.args - L + 1],
4102 ( L - 1 ) );
4104 CUR.stack[CUR.args - 1] = K;
4108 /*************************************************************************/
4109 /* */
4110 /* ROLL[]: ROLL top three elements */
4111 /* Opcode range: 0x8A */
4112 /* Stack: 3 * StkElt --> 3 * StkElt */
4113 /* */
4114 static void
4115 Ins_ROLL( INS_ARG )
4117 FT_Long A, B, C;
4119 FT_UNUSED_EXEC;
4122 A = args[2];
4123 B = args[1];
4124 C = args[0];
4126 args[2] = C;
4127 args[1] = A;
4128 args[0] = B;
4132 /*************************************************************************/
4133 /* */
4134 /* MANAGING THE FLOW OF CONTROL */
4135 /* */
4136 /* Instructions appear in the specification's order. */
4137 /* */
4138 /*************************************************************************/
4141 static FT_Bool
4142 SkipCode( EXEC_OP )
4144 CUR.IP += CUR.length;
4146 if ( CUR.IP < CUR.codeSize )
4148 CUR.opcode = CUR.code[CUR.IP];
4150 CUR.length = opcode_length[CUR.opcode];
4151 if ( CUR.length < 0 )
4153 if ( CUR.IP + 1 > CUR.codeSize )
4154 goto Fail_Overflow;
4155 CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
4158 if ( CUR.IP + CUR.length <= CUR.codeSize )
4159 return SUCCESS;
4162 Fail_Overflow:
4163 CUR.error = TT_Err_Code_Overflow;
4164 return FAILURE;
4168 /*************************************************************************/
4169 /* */
4170 /* IF[]: IF test */
4171 /* Opcode range: 0x58 */
4172 /* Stack: StkElt --> */
4173 /* */
4174 static void
4175 Ins_IF( INS_ARG )
4177 FT_Int nIfs;
4178 FT_Bool Out;
4181 if ( args[0] != 0 )
4182 return;
4184 nIfs = 1;
4185 Out = 0;
4189 if ( SKIP_Code() == FAILURE )
4190 return;
4192 switch ( CUR.opcode )
4194 case 0x58: /* IF */
4195 nIfs++;
4196 break;
4198 case 0x1B: /* ELSE */
4199 Out = FT_BOOL( nIfs == 1 );
4200 break;
4202 case 0x59: /* EIF */
4203 nIfs--;
4204 Out = FT_BOOL( nIfs == 0 );
4205 break;
4207 } while ( Out == 0 );
4211 /*************************************************************************/
4212 /* */
4213 /* ELSE[]: ELSE */
4214 /* Opcode range: 0x1B */
4215 /* Stack: --> */
4216 /* */
4217 static void
4218 Ins_ELSE( INS_ARG )
4220 FT_Int nIfs;
4222 FT_UNUSED_ARG;
4225 nIfs = 1;
4229 if ( SKIP_Code() == FAILURE )
4230 return;
4232 switch ( CUR.opcode )
4234 case 0x58: /* IF */
4235 nIfs++;
4236 break;
4238 case 0x59: /* EIF */
4239 nIfs--;
4240 break;
4242 } while ( nIfs != 0 );
4246 /*************************************************************************/
4247 /* */
4248 /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
4249 /* */
4250 /* Instructions appear in the specification's order. */
4251 /* */
4252 /*************************************************************************/
4255 /*************************************************************************/
4256 /* */
4257 /* FDEF[]: Function DEFinition */
4258 /* Opcode range: 0x2C */
4259 /* Stack: uint32 --> */
4260 /* */
4261 static void
4262 Ins_FDEF( INS_ARG )
4264 FT_ULong n;
4265 TT_DefRecord* rec;
4266 TT_DefRecord* limit;
4269 /* some font programs are broken enough to redefine functions! */
4270 /* We will then parse the current table. */
4272 rec = CUR.FDefs;
4273 limit = rec + CUR.numFDefs;
4274 n = args[0];
4276 for ( ; rec < limit; rec++ )
4278 if ( rec->opc == n )
4279 break;
4282 if ( rec == limit )
4284 /* check that there is enough room for new functions */
4285 if ( CUR.numFDefs >= CUR.maxFDefs )
4287 CUR.error = TT_Err_Too_Many_Function_Defs;
4288 return;
4290 CUR.numFDefs++;
4293 /* Although FDEF takes unsigned 32-bit integer, */
4294 /* func # must be within unsigned 16-bit integer */
4295 if ( n > 0xFFFFU )
4297 CUR.error = TT_Err_Too_Many_Function_Defs;
4298 return;
4301 rec->range = CUR.curRange;
4302 rec->opc = (FT_UInt16)n;
4303 rec->start = CUR.IP + 1;
4304 rec->active = TRUE;
4306 if ( n > CUR.maxFunc )
4307 CUR.maxFunc = (FT_UInt16)n;
4309 /* Now skip the whole function definition. */
4310 /* We don't allow nested IDEFS & FDEFs. */
4312 while ( SKIP_Code() == SUCCESS )
4314 switch ( CUR.opcode )
4316 case 0x89: /* IDEF */
4317 case 0x2C: /* FDEF */
4318 CUR.error = TT_Err_Nested_DEFS;
4319 return;
4321 case 0x2D: /* ENDF */
4322 return;
4328 /*************************************************************************/
4329 /* */
4330 /* ENDF[]: END Function definition */
4331 /* Opcode range: 0x2D */
4332 /* Stack: --> */
4333 /* */
4334 static void
4335 Ins_ENDF( INS_ARG )
4337 TT_CallRec* pRec;
4339 FT_UNUSED_ARG;
4342 if ( CUR.callTop <= 0 ) /* We encountered an ENDF without a call */
4344 CUR.error = TT_Err_ENDF_In_Exec_Stream;
4345 return;
4348 CUR.callTop--;
4350 pRec = &CUR.callStack[CUR.callTop];
4352 pRec->Cur_Count--;
4354 CUR.step_ins = FALSE;
4356 if ( pRec->Cur_Count > 0 )
4358 CUR.callTop++;
4359 CUR.IP = pRec->Cur_Restart;
4361 else
4362 /* Loop through the current function */
4363 INS_Goto_CodeRange( pRec->Caller_Range,
4364 pRec->Caller_IP );
4366 /* Exit the current call frame. */
4368 /* NOTE: If the last instruction of a program is a */
4369 /* CALL or LOOPCALL, the return address is */
4370 /* always out of the code range. This is a */
4371 /* valid address, and it is why we do not test */
4372 /* the result of Ins_Goto_CodeRange() here! */
4376 /*************************************************************************/
4377 /* */
4378 /* CALL[]: CALL function */
4379 /* Opcode range: 0x2B */
4380 /* Stack: uint32? --> */
4381 /* */
4382 static void
4383 Ins_CALL( INS_ARG )
4385 FT_ULong F;
4386 TT_CallRec* pCrec;
4387 TT_DefRecord* def;
4390 /* first of all, check the index */
4392 F = args[0];
4393 if ( BOUNDS( F, CUR.maxFunc + 1 ) )
4394 goto Fail;
4396 /* Except for some old Apple fonts, all functions in a TrueType */
4397 /* font are defined in increasing order, starting from 0. This */
4398 /* means that we normally have */
4399 /* */
4400 /* CUR.maxFunc+1 == CUR.numFDefs */
4401 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4402 /* */
4403 /* If this isn't true, we need to look up the function table. */
4405 def = CUR.FDefs + F;
4406 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
4408 /* look up the FDefs table */
4409 TT_DefRecord* limit;
4412 def = CUR.FDefs;
4413 limit = def + CUR.numFDefs;
4415 while ( def < limit && def->opc != F )
4416 def++;
4418 if ( def == limit )
4419 goto Fail;
4422 /* check that the function is active */
4423 if ( !def->active )
4424 goto Fail;
4426 /* check the call stack */
4427 if ( CUR.callTop >= CUR.callSize )
4429 CUR.error = TT_Err_Stack_Overflow;
4430 return;
4433 pCrec = CUR.callStack + CUR.callTop;
4435 pCrec->Caller_Range = CUR.curRange;
4436 pCrec->Caller_IP = CUR.IP + 1;
4437 pCrec->Cur_Count = 1;
4438 pCrec->Cur_Restart = def->start;
4440 CUR.callTop++;
4442 INS_Goto_CodeRange( def->range,
4443 def->start );
4445 CUR.step_ins = FALSE;
4446 return;
4448 Fail:
4449 CUR.error = TT_Err_Invalid_Reference;
4453 /*************************************************************************/
4454 /* */
4455 /* LOOPCALL[]: LOOP and CALL function */
4456 /* Opcode range: 0x2A */
4457 /* Stack: uint32? Eint16? --> */
4458 /* */
4459 static void
4460 Ins_LOOPCALL( INS_ARG )
4462 FT_ULong F;
4463 TT_CallRec* pCrec;
4464 TT_DefRecord* def;
4467 /* first of all, check the index */
4468 F = args[1];
4469 if ( BOUNDS( F, CUR.maxFunc + 1 ) )
4470 goto Fail;
4472 /* Except for some old Apple fonts, all functions in a TrueType */
4473 /* font are defined in increasing order, starting from 0. This */
4474 /* means that we normally have */
4475 /* */
4476 /* CUR.maxFunc+1 == CUR.numFDefs */
4477 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4478 /* */
4479 /* If this isn't true, we need to look up the function table. */
4481 def = CUR.FDefs + F;
4482 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
4484 /* look up the FDefs table */
4485 TT_DefRecord* limit;
4488 def = CUR.FDefs;
4489 limit = def + CUR.numFDefs;
4491 while ( def < limit && def->opc != F )
4492 def++;
4494 if ( def == limit )
4495 goto Fail;
4498 /* check that the function is active */
4499 if ( !def->active )
4500 goto Fail;
4502 /* check stack */
4503 if ( CUR.callTop >= CUR.callSize )
4505 CUR.error = TT_Err_Stack_Overflow;
4506 return;
4509 if ( args[0] > 0 )
4511 pCrec = CUR.callStack + CUR.callTop;
4513 pCrec->Caller_Range = CUR.curRange;
4514 pCrec->Caller_IP = CUR.IP + 1;
4515 pCrec->Cur_Count = (FT_Int)args[0];
4516 pCrec->Cur_Restart = def->start;
4518 CUR.callTop++;
4520 INS_Goto_CodeRange( def->range, def->start );
4522 CUR.step_ins = FALSE;
4524 return;
4526 Fail:
4527 CUR.error = TT_Err_Invalid_Reference;
4531 /*************************************************************************/
4532 /* */
4533 /* IDEF[]: Instruction DEFinition */
4534 /* Opcode range: 0x89 */
4535 /* Stack: Eint8 --> */
4536 /* */
4537 static void
4538 Ins_IDEF( INS_ARG )
4540 TT_DefRecord* def;
4541 TT_DefRecord* limit;
4544 /* First of all, look for the same function in our table */
4546 def = CUR.IDefs;
4547 limit = def + CUR.numIDefs;
4549 for ( ; def < limit; def++ )
4550 if ( def->opc == (FT_ULong)args[0] )
4551 break;
4553 if ( def == limit )
4555 /* check that there is enough room for a new instruction */
4556 if ( CUR.numIDefs >= CUR.maxIDefs )
4558 CUR.error = TT_Err_Too_Many_Instruction_Defs;
4559 return;
4561 CUR.numIDefs++;
4564 /* opcode must be unsigned 8-bit integer */
4565 if ( 0 > args[0] || args[0] > 0x00FF )
4567 CUR.error = TT_Err_Too_Many_Instruction_Defs;
4568 return;
4571 def->opc = (FT_Byte)args[0];
4572 def->start = CUR.IP+1;
4573 def->range = CUR.curRange;
4574 def->active = TRUE;
4576 if ( (FT_ULong)args[0] > CUR.maxIns )
4577 CUR.maxIns = (FT_Byte)args[0];
4579 /* Now skip the whole function definition. */
4580 /* We don't allow nested IDEFs & FDEFs. */
4582 while ( SKIP_Code() == SUCCESS )
4584 switch ( CUR.opcode )
4586 case 0x89: /* IDEF */
4587 case 0x2C: /* FDEF */
4588 CUR.error = TT_Err_Nested_DEFS;
4589 return;
4590 case 0x2D: /* ENDF */
4591 return;
4597 /*************************************************************************/
4598 /* */
4599 /* PUSHING DATA ONTO THE INTERPRETER STACK */
4600 /* */
4601 /* Instructions appear in the specification's order. */
4602 /* */
4603 /*************************************************************************/
4606 /*************************************************************************/
4607 /* */
4608 /* NPUSHB[]: PUSH N Bytes */
4609 /* Opcode range: 0x40 */
4610 /* Stack: --> uint32... */
4611 /* */
4612 static void
4613 Ins_NPUSHB( INS_ARG )
4615 FT_UShort L, K;
4618 L = (FT_UShort)CUR.code[CUR.IP + 1];
4620 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4622 CUR.error = TT_Err_Stack_Overflow;
4623 return;
4626 for ( K = 1; K <= L; K++ )
4627 args[K - 1] = CUR.code[CUR.IP + K + 1];
4629 CUR.new_top += L;
4633 /*************************************************************************/
4634 /* */
4635 /* NPUSHW[]: PUSH N Words */
4636 /* Opcode range: 0x41 */
4637 /* Stack: --> int32... */
4638 /* */
4639 static void
4640 Ins_NPUSHW( INS_ARG )
4642 FT_UShort L, K;
4645 L = (FT_UShort)CUR.code[CUR.IP + 1];
4647 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4649 CUR.error = TT_Err_Stack_Overflow;
4650 return;
4653 CUR.IP += 2;
4655 for ( K = 0; K < L; K++ )
4656 args[K] = GET_ShortIns();
4658 CUR.step_ins = FALSE;
4659 CUR.new_top += L;
4663 /*************************************************************************/
4664 /* */
4665 /* PUSHB[abc]: PUSH Bytes */
4666 /* Opcode range: 0xB0-0xB7 */
4667 /* Stack: --> uint32... */
4668 /* */
4669 static void
4670 Ins_PUSHB( INS_ARG )
4672 FT_UShort L, K;
4675 L = (FT_UShort)( CUR.opcode - 0xB0 + 1 );
4677 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4679 CUR.error = TT_Err_Stack_Overflow;
4680 return;
4683 for ( K = 1; K <= L; K++ )
4684 args[K - 1] = CUR.code[CUR.IP + K];
4688 /*************************************************************************/
4689 /* */
4690 /* PUSHW[abc]: PUSH Words */
4691 /* Opcode range: 0xB8-0xBF */
4692 /* Stack: --> int32... */
4693 /* */
4694 static void
4695 Ins_PUSHW( INS_ARG )
4697 FT_UShort L, K;
4700 L = (FT_UShort)( CUR.opcode - 0xB8 + 1 );
4702 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4704 CUR.error = TT_Err_Stack_Overflow;
4705 return;
4708 CUR.IP++;
4710 for ( K = 0; K < L; K++ )
4711 args[K] = GET_ShortIns();
4713 CUR.step_ins = FALSE;
4717 /*************************************************************************/
4718 /* */
4719 /* MANAGING THE GRAPHICS STATE */
4720 /* */
4721 /* Instructions appear in the specs' order. */
4722 /* */
4723 /*************************************************************************/
4726 /*************************************************************************/
4727 /* */
4728 /* GC[a]: Get Coordinate projected onto */
4729 /* Opcode range: 0x46-0x47 */
4730 /* Stack: uint32 --> f26.6 */
4731 /* */
4732 /* BULLSHIT: Measures from the original glyph must be taken along the */
4733 /* dual projection vector! */
4734 /* */
4735 static void
4736 Ins_GC( INS_ARG )
4738 FT_ULong L;
4739 FT_F26Dot6 R;
4742 L = (FT_ULong)args[0];
4744 if ( BOUNDS( L, CUR.zp2.n_points ) )
4746 if ( CUR.pedantic_hinting )
4748 CUR.error = TT_Err_Invalid_Reference;
4749 return;
4751 else
4752 R = 0;
4754 else
4756 if ( CUR.opcode & 1 )
4757 R = CUR_fast_dualproj( &CUR.zp2.org[L] );
4758 else
4759 R = CUR_fast_project( &CUR.zp2.cur[L] );
4762 args[0] = R;
4766 /*************************************************************************/
4767 /* */
4768 /* SCFS[]: Set Coordinate From Stack */
4769 /* Opcode range: 0x48 */
4770 /* Stack: f26.6 uint32 --> */
4771 /* */
4772 /* Formula: */
4773 /* */
4774 /* OA := OA + ( value - OA.p )/( f.p ) * f */
4775 /* */
4776 static void
4777 Ins_SCFS( INS_ARG )
4779 FT_Long K;
4780 FT_UShort L;
4783 L = (FT_UShort)args[0];
4785 if ( BOUNDS( L, CUR.zp2.n_points ) )
4787 if ( CUR.pedantic_hinting )
4788 CUR.error = TT_Err_Invalid_Reference;
4789 return;
4792 K = CUR_fast_project( &CUR.zp2.cur[L] );
4794 CUR_Func_move( &CUR.zp2, L, args[1] - K );
4796 /* not part of the specs, but here for safety */
4798 if ( CUR.GS.gep2 == 0 )
4799 CUR.zp2.org[L] = CUR.zp2.cur[L];
4803 /*************************************************************************/
4804 /* */
4805 /* MD[a]: Measure Distance */
4806 /* Opcode range: 0x49-0x4A */
4807 /* Stack: uint32 uint32 --> f26.6 */
4808 /* */
4809 /* BULLSHIT: Measure taken in the original glyph must be along the dual */
4810 /* projection vector. */
4811 /* */
4812 /* Second BULLSHIT: Flag attributes are inverted! */
4813 /* 0 => measure distance in original outline */
4814 /* 1 => measure distance in grid-fitted outline */
4815 /* */
4816 /* Third one: `zp0 - zp1', and not `zp2 - zp1! */
4817 /* */
4818 static void
4819 Ins_MD( INS_ARG )
4821 FT_UShort K, L;
4822 FT_F26Dot6 D;
4825 K = (FT_UShort)args[1];
4826 L = (FT_UShort)args[0];
4828 if( BOUNDS( L, CUR.zp0.n_points ) ||
4829 BOUNDS( K, CUR.zp1.n_points ) )
4831 if ( CUR.pedantic_hinting )
4833 CUR.error = TT_Err_Invalid_Reference;
4834 return;
4836 D = 0;
4838 else
4840 if ( CUR.opcode & 1 )
4841 D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
4842 else
4844 FT_Vector* vec1 = CUR.zp0.orus + L;
4845 FT_Vector* vec2 = CUR.zp1.orus + K;
4848 if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
4850 /* this should be faster */
4851 D = CUR_Func_dualproj( vec1, vec2 );
4852 D = TT_MULFIX( D, CUR.metrics.x_scale );
4854 else
4856 FT_Vector vec;
4859 vec.x = TT_MULFIX( vec1->x - vec2->x, CUR.metrics.x_scale );
4860 vec.y = TT_MULFIX( vec1->y - vec2->y, CUR.metrics.y_scale );
4862 D = CUR_fast_dualproj( &vec );
4867 args[0] = D;
4871 /*************************************************************************/
4872 /* */
4873 /* SDPVTL[a]: Set Dual PVector to Line */
4874 /* Opcode range: 0x86-0x87 */
4875 /* Stack: uint32 uint32 --> */
4876 /* */
4877 static void
4878 Ins_SDPVTL( INS_ARG )
4880 FT_Long A, B, C;
4881 FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
4884 p1 = (FT_UShort)args[1];
4885 p2 = (FT_UShort)args[0];
4887 if ( BOUNDS( p2, CUR.zp1.n_points ) ||
4888 BOUNDS( p1, CUR.zp2.n_points ) )
4890 if ( CUR.pedantic_hinting )
4891 CUR.error = TT_Err_Invalid_Reference;
4892 return;
4896 FT_Vector* v1 = CUR.zp1.org + p2;
4897 FT_Vector* v2 = CUR.zp2.org + p1;
4900 A = v1->x - v2->x;
4901 B = v1->y - v2->y;
4904 if ( ( CUR.opcode & 1 ) != 0 )
4906 C = B; /* counter clockwise rotation */
4907 B = A;
4908 A = -C;
4911 NORMalize( A, B, &CUR.GS.dualVector );
4914 FT_Vector* v1 = CUR.zp1.cur + p2;
4915 FT_Vector* v2 = CUR.zp2.cur + p1;
4918 A = v1->x - v2->x;
4919 B = v1->y - v2->y;
4922 if ( ( CUR.opcode & 1 ) != 0 )
4924 C = B; /* counter clockwise rotation */
4925 B = A;
4926 A = -C;
4929 NORMalize( A, B, &CUR.GS.projVector );
4931 GUESS_VECTOR( freeVector );
4933 COMPUTE_Funcs();
4937 /*************************************************************************/
4938 /* */
4939 /* SZP0[]: Set Zone Pointer 0 */
4940 /* Opcode range: 0x13 */
4941 /* Stack: uint32 --> */
4942 /* */
4943 static void
4944 Ins_SZP0( INS_ARG )
4946 switch ( (FT_Int)args[0] )
4948 case 0:
4949 CUR.zp0 = CUR.twilight;
4950 break;
4952 case 1:
4953 CUR.zp0 = CUR.pts;
4954 break;
4956 default:
4957 if ( CUR.pedantic_hinting )
4958 CUR.error = TT_Err_Invalid_Reference;
4959 return;
4962 CUR.GS.gep0 = (FT_UShort)args[0];
4966 /*************************************************************************/
4967 /* */
4968 /* SZP1[]: Set Zone Pointer 1 */
4969 /* Opcode range: 0x14 */
4970 /* Stack: uint32 --> */
4971 /* */
4972 static void
4973 Ins_SZP1( INS_ARG )
4975 switch ( (FT_Int)args[0] )
4977 case 0:
4978 CUR.zp1 = CUR.twilight;
4979 break;
4981 case 1:
4982 CUR.zp1 = CUR.pts;
4983 break;
4985 default:
4986 if ( CUR.pedantic_hinting )
4987 CUR.error = TT_Err_Invalid_Reference;
4988 return;
4991 CUR.GS.gep1 = (FT_UShort)args[0];
4995 /*************************************************************************/
4996 /* */
4997 /* SZP2[]: Set Zone Pointer 2 */
4998 /* Opcode range: 0x15 */
4999 /* Stack: uint32 --> */
5000 /* */
5001 static void
5002 Ins_SZP2( INS_ARG )
5004 switch ( (FT_Int)args[0] )
5006 case 0:
5007 CUR.zp2 = CUR.twilight;
5008 break;
5010 case 1:
5011 CUR.zp2 = CUR.pts;
5012 break;
5014 default:
5015 if ( CUR.pedantic_hinting )
5016 CUR.error = TT_Err_Invalid_Reference;
5017 return;
5020 CUR.GS.gep2 = (FT_UShort)args[0];
5024 /*************************************************************************/
5025 /* */
5026 /* SZPS[]: Set Zone PointerS */
5027 /* Opcode range: 0x16 */
5028 /* Stack: uint32 --> */
5029 /* */
5030 static void
5031 Ins_SZPS( INS_ARG )
5033 switch ( (FT_Int)args[0] )
5035 case 0:
5036 CUR.zp0 = CUR.twilight;
5037 break;
5039 case 1:
5040 CUR.zp0 = CUR.pts;
5041 break;
5043 default:
5044 if ( CUR.pedantic_hinting )
5045 CUR.error = TT_Err_Invalid_Reference;
5046 return;
5049 CUR.zp1 = CUR.zp0;
5050 CUR.zp2 = CUR.zp0;
5052 CUR.GS.gep0 = (FT_UShort)args[0];
5053 CUR.GS.gep1 = (FT_UShort)args[0];
5054 CUR.GS.gep2 = (FT_UShort)args[0];
5058 /*************************************************************************/
5059 /* */
5060 /* INSTCTRL[]: INSTruction ConTRoL */
5061 /* Opcode range: 0x8e */
5062 /* Stack: int32 int32 --> */
5063 /* */
5064 static void
5065 Ins_INSTCTRL( INS_ARG )
5067 FT_Long K, L;
5070 K = args[1];
5071 L = args[0];
5073 if ( K < 1 || K > 2 )
5075 if ( CUR.pedantic_hinting )
5076 CUR.error = TT_Err_Invalid_Reference;
5077 return;
5080 if ( L != 0 )
5081 L = K;
5083 CUR.GS.instruct_control = FT_BOOL(
5084 ( (FT_Byte)CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L );
5088 /*************************************************************************/
5089 /* */
5090 /* SCANCTRL[]: SCAN ConTRoL */
5091 /* Opcode range: 0x85 */
5092 /* Stack: uint32? --> */
5093 /* */
5094 static void
5095 Ins_SCANCTRL( INS_ARG )
5097 FT_Int A;
5100 /* Get Threshold */
5101 A = (FT_Int)( args[0] & 0xFF );
5103 if ( A == 0xFF )
5105 CUR.GS.scan_control = TRUE;
5106 return;
5108 else if ( A == 0 )
5110 CUR.GS.scan_control = FALSE;
5111 return;
5114 if ( ( args[0] & 0x100 ) != 0 && CUR.tt_metrics.ppem <= A )
5115 CUR.GS.scan_control = TRUE;
5117 if ( ( args[0] & 0x200 ) != 0 && CUR.tt_metrics.rotated )
5118 CUR.GS.scan_control = TRUE;
5120 if ( ( args[0] & 0x400 ) != 0 && CUR.tt_metrics.stretched )
5121 CUR.GS.scan_control = TRUE;
5123 if ( ( args[0] & 0x800 ) != 0 && CUR.tt_metrics.ppem > A )
5124 CUR.GS.scan_control = FALSE;
5126 if ( ( args[0] & 0x1000 ) != 0 && CUR.tt_metrics.rotated )
5127 CUR.GS.scan_control = FALSE;
5129 if ( ( args[0] & 0x2000 ) != 0 && CUR.tt_metrics.stretched )
5130 CUR.GS.scan_control = FALSE;
5134 /*************************************************************************/
5135 /* */
5136 /* SCANTYPE[]: SCAN TYPE */
5137 /* Opcode range: 0x8D */
5138 /* Stack: uint32? --> */
5139 /* */
5140 static void
5141 Ins_SCANTYPE( INS_ARG )
5143 if ( args[0] >= 0 )
5144 CUR.GS.scan_type = (FT_Int)args[0];
5148 /*************************************************************************/
5149 /* */
5150 /* MANAGING OUTLINES */
5151 /* */
5152 /* Instructions appear in the specification's order. */
5153 /* */
5154 /*************************************************************************/
5157 /*************************************************************************/
5158 /* */
5159 /* FLIPPT[]: FLIP PoinT */
5160 /* Opcode range: 0x80 */
5161 /* Stack: uint32... --> */
5162 /* */
5163 static void
5164 Ins_FLIPPT( INS_ARG )
5166 FT_UShort point;
5168 FT_UNUSED_ARG;
5171 if ( CUR.top < CUR.GS.loop )
5173 CUR.error = TT_Err_Too_Few_Arguments;
5174 return;
5177 while ( CUR.GS.loop > 0 )
5179 CUR.args--;
5181 point = (FT_UShort)CUR.stack[CUR.args];
5183 if ( BOUNDS( point, CUR.pts.n_points ) )
5185 if ( CUR.pedantic_hinting )
5187 CUR.error = TT_Err_Invalid_Reference;
5188 return;
5191 else
5192 CUR.pts.tags[point] ^= FT_CURVE_TAG_ON;
5194 CUR.GS.loop--;
5197 CUR.GS.loop = 1;
5198 CUR.new_top = CUR.args;
5202 /*************************************************************************/
5203 /* */
5204 /* FLIPRGON[]: FLIP RanGe ON */
5205 /* Opcode range: 0x81 */
5206 /* Stack: uint32 uint32 --> */
5207 /* */
5208 static void
5209 Ins_FLIPRGON( INS_ARG )
5211 FT_UShort I, K, L;
5214 K = (FT_UShort)args[1];
5215 L = (FT_UShort)args[0];
5217 if ( BOUNDS( K, CUR.pts.n_points ) ||
5218 BOUNDS( L, CUR.pts.n_points ) )
5220 if ( CUR.pedantic_hinting )
5221 CUR.error = TT_Err_Invalid_Reference;
5222 return;
5225 for ( I = L; I <= K; I++ )
5226 CUR.pts.tags[I] |= FT_CURVE_TAG_ON;
5230 /*************************************************************************/
5231 /* */
5232 /* FLIPRGOFF: FLIP RanGe OFF */
5233 /* Opcode range: 0x82 */
5234 /* Stack: uint32 uint32 --> */
5235 /* */
5236 static void
5237 Ins_FLIPRGOFF( INS_ARG )
5239 FT_UShort I, K, L;
5242 K = (FT_UShort)args[1];
5243 L = (FT_UShort)args[0];
5245 if ( BOUNDS( K, CUR.pts.n_points ) ||
5246 BOUNDS( L, CUR.pts.n_points ) )
5248 if ( CUR.pedantic_hinting )
5249 CUR.error = TT_Err_Invalid_Reference;
5250 return;
5253 for ( I = L; I <= K; I++ )
5254 CUR.pts.tags[I] &= ~FT_CURVE_TAG_ON;
5258 static FT_Bool
5259 Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6* x,
5260 FT_F26Dot6* y,
5261 TT_GlyphZone zone,
5262 FT_UShort* refp )
5264 TT_GlyphZoneRec zp;
5265 FT_UShort p;
5266 FT_F26Dot6 d;
5269 if ( CUR.opcode & 1 )
5271 zp = CUR.zp0;
5272 p = CUR.GS.rp1;
5274 else
5276 zp = CUR.zp1;
5277 p = CUR.GS.rp2;
5280 if ( BOUNDS( p, zp.n_points ) )
5282 if ( CUR.pedantic_hinting )
5283 CUR.error = TT_Err_Invalid_Reference;
5284 *refp = 0;
5285 return FAILURE;
5288 *zone = zp;
5289 *refp = p;
5291 d = CUR_Func_project( zp.cur + p, zp.org + p );
5293 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5294 if ( CUR.face->unpatented_hinting )
5296 if ( CUR.GS.both_x_axis )
5298 *x = d;
5299 *y = 0;
5301 else
5303 *x = 0;
5304 *y = d;
5307 else
5308 #endif
5310 *x = TT_MULDIV( d,
5311 (FT_Long)CUR.GS.freeVector.x * 0x10000L,
5312 CUR.F_dot_P );
5313 *y = TT_MULDIV( d,
5314 (FT_Long)CUR.GS.freeVector.y * 0x10000L,
5315 CUR.F_dot_P );
5318 return SUCCESS;
5322 static void
5323 Move_Zp2_Point( EXEC_OP_ FT_UShort point,
5324 FT_F26Dot6 dx,
5325 FT_F26Dot6 dy,
5326 FT_Bool touch )
5328 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5329 if ( CUR.face->unpatented_hinting )
5331 if ( CUR.GS.both_x_axis )
5333 CUR.zp2.cur[point].x += dx;
5334 if ( touch )
5335 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
5337 else
5339 CUR.zp2.cur[point].y += dy;
5340 if ( touch )
5341 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
5343 return;
5345 #endif
5347 if ( CUR.GS.freeVector.x != 0 )
5349 CUR.zp2.cur[point].x += dx;
5350 if ( touch )
5351 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
5354 if ( CUR.GS.freeVector.y != 0 )
5356 CUR.zp2.cur[point].y += dy;
5357 if ( touch )
5358 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
5363 /*************************************************************************/
5364 /* */
5365 /* SHP[a]: SHift Point by the last point */
5366 /* Opcode range: 0x32-0x33 */
5367 /* Stack: uint32... --> */
5368 /* */
5369 static void
5370 Ins_SHP( INS_ARG )
5372 TT_GlyphZoneRec zp;
5373 FT_UShort refp;
5375 FT_F26Dot6 dx,
5377 FT_UShort point;
5379 FT_UNUSED_ARG;
5382 if ( CUR.top < CUR.GS.loop )
5384 CUR.error = TT_Err_Invalid_Reference;
5385 return;
5388 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5389 return;
5391 while ( CUR.GS.loop > 0 )
5393 CUR.args--;
5394 point = (FT_UShort)CUR.stack[CUR.args];
5396 if ( BOUNDS( point, CUR.zp2.n_points ) )
5398 if ( CUR.pedantic_hinting )
5400 CUR.error = TT_Err_Invalid_Reference;
5401 return;
5404 else
5405 /* XXX: UNDOCUMENTED! SHP touches the points */
5406 MOVE_Zp2_Point( point, dx, dy, TRUE );
5408 CUR.GS.loop--;
5411 CUR.GS.loop = 1;
5412 CUR.new_top = CUR.args;
5416 /*************************************************************************/
5417 /* */
5418 /* SHC[a]: SHift Contour */
5419 /* Opcode range: 0x34-35 */
5420 /* Stack: uint32 --> */
5421 /* */
5422 static void
5423 Ins_SHC( INS_ARG )
5425 TT_GlyphZoneRec zp;
5426 FT_UShort refp;
5427 FT_F26Dot6 dx,
5430 FT_Short contour;
5431 FT_UShort first_point, last_point, i;
5434 contour = (FT_UShort)args[0];
5436 if ( BOUNDS( contour, CUR.pts.n_contours ) )
5438 if ( CUR.pedantic_hinting )
5439 CUR.error = TT_Err_Invalid_Reference;
5440 return;
5443 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5444 return;
5446 if ( contour == 0 )
5447 first_point = 0;
5448 else
5449 first_point = (FT_UShort)( CUR.pts.contours[contour - 1] + 1 -
5450 CUR.pts.first_point );
5452 last_point = (FT_UShort)( CUR.pts.contours[contour] -
5453 CUR.pts.first_point );
5455 /* XXX: this is probably wrong... at least it prevents memory */
5456 /* corruption when zp2 is the twilight zone */
5457 if ( BOUNDS( last_point, CUR.zp2.n_points ) )
5459 if ( CUR.zp2.n_points > 0 )
5460 last_point = (FT_UShort)(CUR.zp2.n_points - 1);
5461 else
5462 last_point = 0;
5465 /* XXX: UNDOCUMENTED! SHC touches the points */
5466 for ( i = first_point; i <= last_point; i++ )
5468 if ( zp.cur != CUR.zp2.cur || refp != i )
5469 MOVE_Zp2_Point( i, dx, dy, TRUE );
5474 /*************************************************************************/
5475 /* */
5476 /* SHZ[a]: SHift Zone */
5477 /* Opcode range: 0x36-37 */
5478 /* Stack: uint32 --> */
5479 /* */
5480 static void
5481 Ins_SHZ( INS_ARG )
5483 TT_GlyphZoneRec zp;
5484 FT_UShort refp;
5485 FT_F26Dot6 dx,
5488 FT_UShort last_point, i;
5491 if ( BOUNDS( args[0], 2 ) )
5493 if ( CUR.pedantic_hinting )
5494 CUR.error = TT_Err_Invalid_Reference;
5495 return;
5498 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5499 return;
5501 /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */
5502 /* Twilight zone has no contours, so use `n_points'. */
5503 /* Normal zone's `n_points' includes phantoms, so must */
5504 /* use end of last contour. */
5505 if ( CUR.GS.gep2 == 0 && CUR.zp2.n_points > 0 )
5506 last_point = (FT_UShort)( CUR.zp2.n_points - 1 );
5507 else if ( CUR.GS.gep2 == 1 && CUR.zp2.n_contours > 0 )
5508 last_point = (FT_UShort)( CUR.zp2.contours[CUR.zp2.n_contours - 1] );
5509 else
5510 last_point = 0;
5512 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
5513 for ( i = 0; i <= last_point; i++ )
5515 if ( zp.cur != CUR.zp2.cur || refp != i )
5516 MOVE_Zp2_Point( i, dx, dy, FALSE );
5521 /*************************************************************************/
5522 /* */
5523 /* SHPIX[]: SHift points by a PIXel amount */
5524 /* Opcode range: 0x38 */
5525 /* Stack: f26.6 uint32... --> */
5526 /* */
5527 static void
5528 Ins_SHPIX( INS_ARG )
5530 FT_F26Dot6 dx, dy;
5531 FT_UShort point;
5534 if ( CUR.top < CUR.GS.loop + 1 )
5536 CUR.error = TT_Err_Invalid_Reference;
5537 return;
5540 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
5541 if ( CUR.face->unpatented_hinting )
5543 if ( CUR.GS.both_x_axis )
5545 dx = TT_MulFix14( (FT_UInt32)args[0], 0x4000 );
5546 dy = 0;
5548 else
5550 dx = 0;
5551 dy = TT_MulFix14( (FT_UInt32)args[0], 0x4000 );
5554 else
5555 #endif
5557 dx = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.x );
5558 dy = TT_MulFix14( (FT_UInt32)args[0], CUR.GS.freeVector.y );
5561 while ( CUR.GS.loop > 0 )
5563 CUR.args--;
5565 point = (FT_UShort)CUR.stack[CUR.args];
5567 if ( BOUNDS( point, CUR.zp2.n_points ) )
5569 if ( CUR.pedantic_hinting )
5571 CUR.error = TT_Err_Invalid_Reference;
5572 return;
5575 else
5576 MOVE_Zp2_Point( point, dx, dy, TRUE );
5578 CUR.GS.loop--;
5581 CUR.GS.loop = 1;
5582 CUR.new_top = CUR.args;
5586 /*************************************************************************/
5587 /* */
5588 /* MSIRP[a]: Move Stack Indirect Relative Position */
5589 /* Opcode range: 0x3A-0x3B */
5590 /* Stack: f26.6 uint32 --> */
5591 /* */
5592 static void
5593 Ins_MSIRP( INS_ARG )
5595 FT_UShort point;
5596 FT_F26Dot6 distance;
5599 point = (FT_UShort)args[0];
5601 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5602 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5604 if ( CUR.pedantic_hinting )
5605 CUR.error = TT_Err_Invalid_Reference;
5606 return;
5609 /* XXX: UNDOCUMENTED! behaviour */
5610 if ( CUR.GS.gep1 == 0 ) /* if the point that is to be moved */
5611 /* is in twilight zone */
5613 CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
5614 CUR_Func_move_orig( &CUR.zp1, point, args[1] );
5615 CUR.zp1.cur[point] = CUR.zp1.org[point];
5618 distance = CUR_Func_project( CUR.zp1.cur + point,
5619 CUR.zp0.cur + CUR.GS.rp0 );
5621 CUR_Func_move( &CUR.zp1, point, args[1] - distance );
5623 CUR.GS.rp1 = CUR.GS.rp0;
5624 CUR.GS.rp2 = point;
5626 if ( ( CUR.opcode & 1 ) != 0 )
5627 CUR.GS.rp0 = point;
5631 /*************************************************************************/
5632 /* */
5633 /* MDAP[a]: Move Direct Absolute Point */
5634 /* Opcode range: 0x2E-0x2F */
5635 /* Stack: uint32 --> */
5636 /* */
5637 static void
5638 Ins_MDAP( INS_ARG )
5640 FT_UShort point;
5641 FT_F26Dot6 cur_dist,
5642 distance;
5645 point = (FT_UShort)args[0];
5647 if ( BOUNDS( point, CUR.zp0.n_points ) )
5649 if ( CUR.pedantic_hinting )
5650 CUR.error = TT_Err_Invalid_Reference;
5651 return;
5654 /* XXX: Is there some undocumented feature while in the */
5655 /* twilight zone? ? */
5656 if ( ( CUR.opcode & 1 ) != 0 )
5658 cur_dist = CUR_fast_project( &CUR.zp0.cur[point] );
5659 distance = CUR_Func_round( cur_dist,
5660 CUR.tt_metrics.compensations[0] ) - cur_dist;
5662 else
5663 distance = 0;
5665 CUR_Func_move( &CUR.zp0, point, distance );
5667 CUR.GS.rp0 = point;
5668 CUR.GS.rp1 = point;
5672 /*************************************************************************/
5673 /* */
5674 /* MIAP[a]: Move Indirect Absolute Point */
5675 /* Opcode range: 0x3E-0x3F */
5676 /* Stack: uint32 uint32 --> */
5677 /* */
5678 static void
5679 Ins_MIAP( INS_ARG )
5681 FT_ULong cvtEntry;
5682 FT_UShort point;
5683 FT_F26Dot6 distance,
5684 org_dist;
5687 cvtEntry = (FT_ULong)args[1];
5688 point = (FT_UShort)args[0];
5690 if ( BOUNDS( point, CUR.zp0.n_points ) ||
5691 BOUNDS( cvtEntry, CUR.cvtSize ) )
5693 if ( CUR.pedantic_hinting )
5694 CUR.error = TT_Err_Invalid_Reference;
5695 return;
5698 /* XXX: UNDOCUMENTED! */
5699 /* */
5700 /* The behaviour of an MIAP instruction is quite */
5701 /* different when used in the twilight zone. */
5702 /* */
5703 /* First, no control value cut-in test is performed */
5704 /* as it would fail anyway. Second, the original */
5705 /* point, i.e. (org_x,org_y) of zp0.point, is set */
5706 /* to the absolute, unrounded distance found in */
5707 /* the CVT. */
5708 /* */
5709 /* This is used in the CVT programs of the Microsoft */
5710 /* fonts Arial, Times, etc., in order to re-adjust */
5711 /* some key font heights. It allows the use of the */
5712 /* IP instruction in the twilight zone, which */
5713 /* otherwise would be `illegal' according to the */
5714 /* specification. */
5715 /* */
5716 /* We implement it with a special sequence for the */
5717 /* twilight zone. This is a bad hack, but it seems */
5718 /* to work. */
5720 distance = CUR_Func_read_cvt( cvtEntry );
5722 if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */
5724 CUR.zp0.org[point].x = TT_MulFix14( (FT_UInt32)distance, CUR.GS.freeVector.x );
5725 CUR.zp0.org[point].y = TT_MulFix14( (FT_UInt32)distance, CUR.GS.freeVector.y ),
5726 CUR.zp0.cur[point] = CUR.zp0.org[point];
5729 org_dist = CUR_fast_project( &CUR.zp0.cur[point] );
5731 if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */
5733 if ( FT_ABS( distance - org_dist ) > CUR.GS.control_value_cutin )
5734 distance = org_dist;
5736 distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] );
5739 CUR_Func_move( &CUR.zp0, point, distance - org_dist );
5741 CUR.GS.rp0 = point;
5742 CUR.GS.rp1 = point;
5746 /*************************************************************************/
5747 /* */
5748 /* MDRP[abcde]: Move Direct Relative Point */
5749 /* Opcode range: 0xC0-0xDF */
5750 /* Stack: uint32 --> */
5751 /* */
5752 static void
5753 Ins_MDRP( INS_ARG )
5755 FT_UShort point;
5756 FT_F26Dot6 org_dist, distance;
5759 point = (FT_UShort)args[0];
5761 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5762 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5764 if ( CUR.pedantic_hinting )
5765 CUR.error = TT_Err_Invalid_Reference;
5766 return;
5769 /* XXX: Is there some undocumented feature while in the */
5770 /* twilight zone? */
5772 /* XXX: UNDOCUMENTED: twilight zone special case */
5774 if ( CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 )
5776 FT_Vector* vec1 = &CUR.zp1.org[point];
5777 FT_Vector* vec2 = &CUR.zp0.org[CUR.GS.rp0];
5780 org_dist = CUR_Func_dualproj( vec1, vec2 );
5782 else
5784 FT_Vector* vec1 = &CUR.zp1.orus[point];
5785 FT_Vector* vec2 = &CUR.zp0.orus[CUR.GS.rp0];
5788 if ( CUR.metrics.x_scale == CUR.metrics.y_scale )
5790 /* this should be faster */
5791 org_dist = CUR_Func_dualproj( vec1, vec2 );
5792 org_dist = TT_MULFIX( org_dist, CUR.metrics.x_scale );
5794 else
5796 FT_Vector vec;
5799 vec.x = TT_MULFIX( vec1->x - vec2->x, CUR.metrics.x_scale );
5800 vec.y = TT_MULFIX( vec1->y - vec2->y, CUR.metrics.y_scale );
5802 org_dist = CUR_fast_dualproj( &vec );
5806 /* single width cut-in test */
5808 if ( FT_ABS( org_dist - CUR.GS.single_width_value ) <
5809 CUR.GS.single_width_cutin )
5811 if ( org_dist >= 0 )
5812 org_dist = CUR.GS.single_width_value;
5813 else
5814 org_dist = -CUR.GS.single_width_value;
5817 /* round flag */
5819 if ( ( CUR.opcode & 4 ) != 0 )
5820 distance = CUR_Func_round(
5821 org_dist,
5822 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5823 else
5824 distance = ROUND_None(
5825 org_dist,
5826 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5828 /* minimum distance flag */
5830 if ( ( CUR.opcode & 8 ) != 0 )
5832 if ( org_dist >= 0 )
5834 if ( distance < CUR.GS.minimum_distance )
5835 distance = CUR.GS.minimum_distance;
5837 else
5839 if ( distance > -CUR.GS.minimum_distance )
5840 distance = -CUR.GS.minimum_distance;
5844 /* now move the point */
5846 org_dist = CUR_Func_project( CUR.zp1.cur + point,
5847 CUR.zp0.cur + CUR.GS.rp0 );
5849 CUR_Func_move( &CUR.zp1, point, distance - org_dist );
5851 CUR.GS.rp1 = CUR.GS.rp0;
5852 CUR.GS.rp2 = point;
5854 if ( ( CUR.opcode & 16 ) != 0 )
5855 CUR.GS.rp0 = point;
5859 /*************************************************************************/
5860 /* */
5861 /* MIRP[abcde]: Move Indirect Relative Point */
5862 /* Opcode range: 0xE0-0xFF */
5863 /* Stack: int32? uint32 --> */
5864 /* */
5865 static void
5866 Ins_MIRP( INS_ARG )
5868 FT_UShort point;
5869 FT_ULong cvtEntry;
5871 FT_F26Dot6 cvt_dist,
5872 distance,
5873 cur_dist,
5874 org_dist;
5877 point = (FT_UShort)args[0];
5878 cvtEntry = (FT_ULong)( args[1] + 1 );
5880 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
5882 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5883 BOUNDS( cvtEntry, CUR.cvtSize + 1 ) ||
5884 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5886 if ( CUR.pedantic_hinting )
5887 CUR.error = TT_Err_Invalid_Reference;
5888 return;
5891 if ( !cvtEntry )
5892 cvt_dist = 0;
5893 else
5894 cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
5896 /* single width test */
5898 if ( FT_ABS( cvt_dist - CUR.GS.single_width_value ) <
5899 CUR.GS.single_width_cutin )
5901 if ( cvt_dist >= 0 )
5902 cvt_dist = CUR.GS.single_width_value;
5903 else
5904 cvt_dist = -CUR.GS.single_width_value;
5907 /* XXX: UNDOCUMENTED! -- twilight zone */
5909 if ( CUR.GS.gep1 == 0 )
5911 CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +
5912 TT_MulFix14( (FT_UInt32)cvt_dist,
5913 CUR.GS.freeVector.x );
5915 CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
5916 TT_MulFix14( (FT_UInt32)cvt_dist,
5917 CUR.GS.freeVector.y );
5919 CUR.zp1.cur[point] = CUR.zp0.cur[point];
5922 org_dist = CUR_Func_dualproj( &CUR.zp1.org[point],
5923 &CUR.zp0.org[CUR.GS.rp0] );
5924 cur_dist = CUR_Func_project ( &CUR.zp1.cur[point],
5925 &CUR.zp0.cur[CUR.GS.rp0] );
5927 /* auto-flip test */
5929 if ( CUR.GS.auto_flip )
5931 if ( ( org_dist ^ cvt_dist ) < 0 )
5932 cvt_dist = -cvt_dist;
5935 /* control value cutin and round */
5937 if ( ( CUR.opcode & 4 ) != 0 )
5939 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
5940 /* refer to the same zone. */
5942 if ( CUR.GS.gep0 == CUR.GS.gep1 )
5943 if ( FT_ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin )
5944 cvt_dist = org_dist;
5946 distance = CUR_Func_round(
5947 cvt_dist,
5948 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5950 else
5951 distance = ROUND_None(
5952 cvt_dist,
5953 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5955 /* minimum distance test */
5957 if ( ( CUR.opcode & 8 ) != 0 )
5959 if ( org_dist >= 0 )
5961 if ( distance < CUR.GS.minimum_distance )
5962 distance = CUR.GS.minimum_distance;
5964 else
5966 if ( distance > -CUR.GS.minimum_distance )
5967 distance = -CUR.GS.minimum_distance;
5971 CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
5973 CUR.GS.rp1 = CUR.GS.rp0;
5975 if ( ( CUR.opcode & 16 ) != 0 )
5976 CUR.GS.rp0 = point;
5978 /* XXX: UNDOCUMENTED! */
5979 CUR.GS.rp2 = point;
5983 /*************************************************************************/
5984 /* */
5985 /* ALIGNRP[]: ALIGN Relative Point */
5986 /* Opcode range: 0x3C */
5987 /* Stack: uint32 uint32... --> */
5988 /* */
5989 static void
5990 Ins_ALIGNRP( INS_ARG )
5992 FT_UShort point;
5993 FT_F26Dot6 distance;
5995 FT_UNUSED_ARG;
5998 if ( CUR.top < CUR.GS.loop ||
5999 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
6001 if ( CUR.pedantic_hinting )
6002 CUR.error = TT_Err_Invalid_Reference;
6003 return;
6006 while ( CUR.GS.loop > 0 )
6008 CUR.args--;
6010 point = (FT_UShort)CUR.stack[CUR.args];
6012 if ( BOUNDS( point, CUR.zp1.n_points ) )
6014 if ( CUR.pedantic_hinting )
6016 CUR.error = TT_Err_Invalid_Reference;
6017 return;
6020 else
6022 distance = CUR_Func_project( CUR.zp1.cur + point,
6023 CUR.zp0.cur + CUR.GS.rp0 );
6025 CUR_Func_move( &CUR.zp1, point, -distance );
6028 CUR.GS.loop--;
6031 CUR.GS.loop = 1;
6032 CUR.new_top = CUR.args;
6036 /*************************************************************************/
6037 /* */
6038 /* ISECT[]: moves point to InterSECTion */
6039 /* Opcode range: 0x0F */
6040 /* Stack: 5 * uint32 --> */
6041 /* */
6042 static void
6043 Ins_ISECT( INS_ARG )
6045 FT_UShort point,
6046 a0, a1,
6047 b0, b1;
6049 FT_F26Dot6 discriminant;
6051 FT_F26Dot6 dx, dy,
6052 dax, day,
6053 dbx, dby;
6055 FT_F26Dot6 val;
6057 FT_Vector R;
6060 point = (FT_UShort)args[0];
6062 a0 = (FT_UShort)args[1];
6063 a1 = (FT_UShort)args[2];
6064 b0 = (FT_UShort)args[3];
6065 b1 = (FT_UShort)args[4];
6067 if ( BOUNDS( b0, CUR.zp0.n_points ) ||
6068 BOUNDS( b1, CUR.zp0.n_points ) ||
6069 BOUNDS( a0, CUR.zp1.n_points ) ||
6070 BOUNDS( a1, CUR.zp1.n_points ) ||
6071 BOUNDS( point, CUR.zp2.n_points ) )
6073 if ( CUR.pedantic_hinting )
6074 CUR.error = TT_Err_Invalid_Reference;
6075 return;
6078 dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
6079 dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
6081 dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;
6082 day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;
6084 dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;
6085 dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;
6087 CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
6089 discriminant = TT_MULDIV( dax, -dby, 0x40 ) +
6090 TT_MULDIV( day, dbx, 0x40 );
6092 if ( FT_ABS( discriminant ) >= 0x40 )
6094 val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 );
6096 R.x = TT_MULDIV( val, dax, discriminant );
6097 R.y = TT_MULDIV( val, day, discriminant );
6099 CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
6100 CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
6102 else
6104 /* else, take the middle of the middles of A and B */
6106 CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +
6107 CUR.zp1.cur[a1].x +
6108 CUR.zp0.cur[b0].x +
6109 CUR.zp0.cur[b1].x ) / 4;
6110 CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +
6111 CUR.zp1.cur[a1].y +
6112 CUR.zp0.cur[b0].y +
6113 CUR.zp0.cur[b1].y ) / 4;
6118 /*************************************************************************/
6119 /* */
6120 /* ALIGNPTS[]: ALIGN PoinTS */
6121 /* Opcode range: 0x27 */
6122 /* Stack: uint32 uint32 --> */
6123 /* */
6124 static void
6125 Ins_ALIGNPTS( INS_ARG )
6127 FT_UShort p1, p2;
6128 FT_F26Dot6 distance;
6131 p1 = (FT_UShort)args[0];
6132 p2 = (FT_UShort)args[1];
6134 if ( BOUNDS( args[0], CUR.zp1.n_points ) ||
6135 BOUNDS( args[1], CUR.zp0.n_points ) )
6137 if ( CUR.pedantic_hinting )
6138 CUR.error = TT_Err_Invalid_Reference;
6139 return;
6142 distance = CUR_Func_project( CUR.zp0.cur + p2,
6143 CUR.zp1.cur + p1 ) / 2;
6145 CUR_Func_move( &CUR.zp1, p1, distance );
6146 CUR_Func_move( &CUR.zp0, p2, -distance );
6150 /*************************************************************************/
6151 /* */
6152 /* IP[]: Interpolate Point */
6153 /* Opcode range: 0x39 */
6154 /* Stack: uint32... --> */
6155 /* */
6157 /* SOMETIMES, DUMBER CODE IS BETTER CODE */
6159 static void
6160 Ins_IP( INS_ARG )
6162 FT_F26Dot6 old_range, cur_range;
6163 FT_Vector* orus_base;
6164 FT_Vector* cur_base;
6165 FT_Int twilight;
6167 FT_UNUSED_ARG;
6170 if ( CUR.top < CUR.GS.loop )
6172 CUR.error = TT_Err_Invalid_Reference;
6173 return;
6177 * We need to deal in a special way with the twilight zone.
6178 * Otherwise, by definition, the value of CUR.twilight.orus[n] is (0,0),
6179 * for every n.
6181 twilight = CUR.GS.gep0 == 0 || CUR.GS.gep1 == 0 || CUR.GS.gep2 == 0;
6183 if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) )
6185 if ( CUR.pedantic_hinting )
6186 CUR.error = TT_Err_Invalid_Reference;
6187 return;
6190 if ( twilight )
6191 orus_base = &CUR.zp0.org[CUR.GS.rp1];
6192 else
6193 orus_base = &CUR.zp0.orus[CUR.GS.rp1];
6195 cur_base = &CUR.zp0.cur[CUR.GS.rp1];
6197 /* XXX: There are some glyphs in some braindead but popular */
6198 /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
6199 /* calling IP[] with bad values of rp[12]. */
6200 /* Do something sane when this odd thing happens. */
6201 if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
6202 BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
6204 old_range = 0;
6205 cur_range = 0;
6207 else
6209 if ( twilight )
6210 old_range = CUR_Func_dualproj( &CUR.zp1.org[CUR.GS.rp2],
6211 orus_base );
6212 else
6213 old_range = CUR_Func_dualproj( &CUR.zp1.orus[CUR.GS.rp2],
6214 orus_base );
6216 cur_range = CUR_Func_project ( &CUR.zp1.cur[CUR.GS.rp2], cur_base );
6219 for ( ; CUR.GS.loop > 0; --CUR.GS.loop )
6221 FT_UInt point = (FT_UInt)CUR.stack[--CUR.args];
6222 FT_F26Dot6 org_dist, cur_dist, new_dist;
6225 /* check point bounds */
6226 if ( BOUNDS( point, CUR.zp2.n_points ) )
6228 if ( CUR.pedantic_hinting )
6230 CUR.error = TT_Err_Invalid_Reference;
6231 return;
6233 continue;
6236 if ( twilight )
6237 org_dist = CUR_Func_dualproj( &CUR.zp2.org[point], orus_base );
6238 else
6239 org_dist = CUR_Func_dualproj( &CUR.zp2.orus[point], orus_base );
6241 cur_dist = CUR_Func_project ( &CUR.zp2.cur[point], cur_base );
6243 if ( org_dist )
6244 new_dist = ( old_range != 0 )
6245 ? TT_MULDIV( org_dist, cur_range, old_range )
6246 : cur_dist;
6247 else
6248 new_dist = 0;
6250 CUR_Func_move( &CUR.zp2, (FT_UShort)point, new_dist - cur_dist );
6252 CUR.GS.loop = 1;
6253 CUR.new_top = CUR.args;
6257 /*************************************************************************/
6258 /* */
6259 /* UTP[a]: UnTouch Point */
6260 /* Opcode range: 0x29 */
6261 /* Stack: uint32 --> */
6262 /* */
6263 static void
6264 Ins_UTP( INS_ARG )
6266 FT_UShort point;
6267 FT_Byte mask;
6270 point = (FT_UShort)args[0];
6272 if ( BOUNDS( point, CUR.zp0.n_points ) )
6274 if ( CUR.pedantic_hinting )
6275 CUR.error = TT_Err_Invalid_Reference;
6276 return;
6279 mask = 0xFF;
6281 if ( CUR.GS.freeVector.x != 0 )
6282 mask &= ~FT_CURVE_TAG_TOUCH_X;
6284 if ( CUR.GS.freeVector.y != 0 )
6285 mask &= ~FT_CURVE_TAG_TOUCH_Y;
6287 CUR.zp0.tags[point] &= mask;
6291 /* Local variables for Ins_IUP: */
6292 typedef struct IUP_WorkerRec_
6294 FT_Vector* orgs; /* original and current coordinate */
6295 FT_Vector* curs; /* arrays */
6296 FT_Vector* orus;
6297 FT_UInt max_points;
6299 } IUP_WorkerRec, *IUP_Worker;
6302 static void
6303 _iup_worker_shift( IUP_Worker worker,
6304 FT_UInt p1,
6305 FT_UInt p2,
6306 FT_UInt p )
6308 FT_UInt i;
6309 FT_F26Dot6 dx;
6312 dx = worker->curs[p].x - worker->orgs[p].x;
6313 if ( dx != 0 )
6315 for ( i = p1; i < p; i++ )
6316 worker->curs[i].x += dx;
6318 for ( i = p + 1; i <= p2; i++ )
6319 worker->curs[i].x += dx;
6324 static void
6325 _iup_worker_interpolate( IUP_Worker worker,
6326 FT_UInt p1,
6327 FT_UInt p2,
6328 FT_UInt ref1,
6329 FT_UInt ref2 )
6331 FT_UInt i;
6332 FT_F26Dot6 orus1, orus2, org1, org2, delta1, delta2;
6335 if ( p1 > p2 )
6336 return;
6338 if ( BOUNDS( ref1, worker->max_points ) ||
6339 BOUNDS( ref2, worker->max_points ) )
6340 return;
6342 orus1 = worker->orus[ref1].x;
6343 orus2 = worker->orus[ref2].x;
6345 if ( orus1 > orus2 )
6347 FT_F26Dot6 tmp_o;
6348 FT_UInt tmp_r;
6351 tmp_o = orus1;
6352 orus1 = orus2;
6353 orus2 = tmp_o;
6355 tmp_r = ref1;
6356 ref1 = ref2;
6357 ref2 = tmp_r;
6360 org1 = worker->orgs[ref1].x;
6361 org2 = worker->orgs[ref2].x;
6362 delta1 = worker->curs[ref1].x - org1;
6363 delta2 = worker->curs[ref2].x - org2;
6365 if ( orus1 == orus2 )
6367 /* simple shift of untouched points */
6368 for ( i = p1; i <= p2; i++ )
6370 FT_F26Dot6 x = worker->orgs[i].x;
6373 if ( x <= org1 )
6374 x += delta1;
6375 else
6376 x += delta2;
6378 worker->curs[i].x = x;
6381 else
6383 FT_Fixed scale = 0;
6384 FT_Bool scale_valid = 0;
6387 /* interpolation */
6388 for ( i = p1; i <= p2; i++ )
6390 FT_F26Dot6 x = worker->orgs[i].x;
6393 if ( x <= org1 )
6394 x += delta1;
6396 else if ( x >= org2 )
6397 x += delta2;
6399 else
6401 if ( !scale_valid )
6403 scale_valid = 1;
6404 scale = TT_MULDIV( org2 + delta2 - ( org1 + delta1 ),
6405 0x10000L, orus2 - orus1 );
6408 x = ( org1 + delta1 ) +
6409 TT_MULFIX( worker->orus[i].x - orus1, scale );
6411 worker->curs[i].x = x;
6417 /*************************************************************************/
6418 /* */
6419 /* IUP[a]: Interpolate Untouched Points */
6420 /* Opcode range: 0x30-0x31 */
6421 /* Stack: --> */
6422 /* */
6423 static void
6424 Ins_IUP( INS_ARG )
6426 IUP_WorkerRec V;
6427 FT_Byte mask;
6429 FT_UInt first_point; /* first point of contour */
6430 FT_UInt end_point; /* end point (last+1) of contour */
6432 FT_UInt first_touched; /* first touched point in contour */
6433 FT_UInt cur_touched; /* current touched point in contour */
6435 FT_UInt point; /* current point */
6436 FT_Short contour; /* current contour */
6438 FT_UNUSED_ARG;
6441 /* ignore empty outlines */
6442 if ( CUR.pts.n_contours == 0 )
6443 return;
6445 if ( CUR.opcode & 1 )
6447 mask = FT_CURVE_TAG_TOUCH_X;
6448 V.orgs = CUR.pts.org;
6449 V.curs = CUR.pts.cur;
6450 V.orus = CUR.pts.orus;
6452 else
6454 mask = FT_CURVE_TAG_TOUCH_Y;
6455 V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
6456 V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
6457 V.orus = (FT_Vector*)( (FT_Pos*)CUR.pts.orus + 1 );
6459 V.max_points = CUR.pts.n_points;
6461 contour = 0;
6462 point = 0;
6466 end_point = CUR.pts.contours[contour] - CUR.pts.first_point;
6467 first_point = point;
6469 if ( CUR.pts.n_points <= end_point )
6470 end_point = CUR.pts.n_points;
6472 while ( point <= end_point && ( CUR.pts.tags[point] & mask ) == 0 )
6473 point++;
6475 if ( point <= end_point )
6477 first_touched = point;
6478 cur_touched = point;
6480 point++;
6482 while ( point <= end_point )
6484 if ( ( CUR.pts.tags[point] & mask ) != 0 )
6486 if ( point > 0 )
6487 _iup_worker_interpolate( &V,
6488 cur_touched + 1,
6489 point - 1,
6490 cur_touched,
6491 point );
6492 cur_touched = point;
6495 point++;
6498 if ( cur_touched == first_touched )
6499 _iup_worker_shift( &V, first_point, end_point, cur_touched );
6500 else
6502 _iup_worker_interpolate( &V,
6503 (FT_UShort)( cur_touched + 1 ),
6504 end_point,
6505 cur_touched,
6506 first_touched );
6508 if ( first_touched > 0 )
6509 _iup_worker_interpolate( &V,
6510 first_point,
6511 first_touched - 1,
6512 cur_touched,
6513 first_touched );
6516 contour++;
6517 } while ( contour < CUR.pts.n_contours );
6521 /*************************************************************************/
6522 /* */
6523 /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
6524 /* Opcode range: 0x5D,0x71,0x72 */
6525 /* Stack: uint32 (2 * uint32)... --> */
6526 /* */
6527 static void
6528 Ins_DELTAP( INS_ARG )
6530 FT_ULong k, nump;
6531 FT_UShort A;
6532 FT_ULong C;
6533 FT_Long B;
6536 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
6537 /* Delta hinting is covered by US Patent 5159668. */
6538 if ( CUR.face->unpatented_hinting )
6540 FT_Long n = args[0] * 2;
6543 if ( CUR.args < n )
6545 CUR.error = TT_Err_Too_Few_Arguments;
6546 return;
6549 CUR.args -= n;
6550 CUR.new_top = CUR.args;
6551 return;
6553 #endif
6555 nump = (FT_ULong)args[0]; /* some points theoretically may occur more
6556 than once, thus UShort isn't enough */
6558 for ( k = 1; k <= nump; k++ )
6560 if ( CUR.args < 2 )
6562 CUR.error = TT_Err_Too_Few_Arguments;
6563 return;
6566 CUR.args -= 2;
6568 A = (FT_UShort)CUR.stack[CUR.args + 1];
6569 B = CUR.stack[CUR.args];
6571 /* XXX: Because some popular fonts contain some invalid DeltaP */
6572 /* instructions, we simply ignore them when the stacked */
6573 /* point reference is off limit, rather than returning an */
6574 /* error. As a delta instruction doesn't change a glyph */
6575 /* in great ways, this shouldn't be a problem. */
6577 if ( !BOUNDS( A, CUR.zp0.n_points ) )
6579 C = ( (FT_ULong)B & 0xF0 ) >> 4;
6581 switch ( CUR.opcode )
6583 case 0x5D:
6584 break;
6586 case 0x71:
6587 C += 16;
6588 break;
6590 case 0x72:
6591 C += 32;
6592 break;
6595 C += CUR.GS.delta_base;
6597 if ( CURRENT_Ppem() == (FT_Long)C )
6599 B = ( (FT_ULong)B & 0xF ) - 8;
6600 if ( B >= 0 )
6601 B++;
6602 B = B * 64 / ( 1L << CUR.GS.delta_shift );
6604 CUR_Func_move( &CUR.zp0, A, B );
6607 else
6608 if ( CUR.pedantic_hinting )
6609 CUR.error = TT_Err_Invalid_Reference;
6612 CUR.new_top = CUR.args;
6616 /*************************************************************************/
6617 /* */
6618 /* DELTACn[]: DELTA exceptions C1, C2, C3 */
6619 /* Opcode range: 0x73,0x74,0x75 */
6620 /* Stack: uint32 (2 * uint32)... --> */
6621 /* */
6622 static void
6623 Ins_DELTAC( INS_ARG )
6625 FT_ULong nump, k;
6626 FT_ULong A, C;
6627 FT_Long B;
6630 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
6631 /* Delta hinting is covered by US Patent 5159668. */
6632 if ( CUR.face->unpatented_hinting )
6634 FT_Long n = args[0] * 2;
6637 if ( CUR.args < n )
6639 CUR.error = TT_Err_Too_Few_Arguments;
6640 return;
6643 CUR.args -= n;
6644 CUR.new_top = CUR.args;
6645 return;
6647 #endif
6649 nump = (FT_ULong)args[0];
6651 for ( k = 1; k <= nump; k++ )
6653 if ( CUR.args < 2 )
6655 CUR.error = TT_Err_Too_Few_Arguments;
6656 return;
6659 CUR.args -= 2;
6661 A = (FT_ULong)CUR.stack[CUR.args + 1];
6662 B = CUR.stack[CUR.args];
6664 if ( BOUNDS( A, CUR.cvtSize ) )
6666 if ( CUR.pedantic_hinting )
6668 CUR.error = TT_Err_Invalid_Reference;
6669 return;
6672 else
6674 C = ( (FT_ULong)B & 0xF0 ) >> 4;
6676 switch ( CUR.opcode )
6678 case 0x73:
6679 break;
6681 case 0x74:
6682 C += 16;
6683 break;
6685 case 0x75:
6686 C += 32;
6687 break;
6690 C += CUR.GS.delta_base;
6692 if ( CURRENT_Ppem() == (FT_Long)C )
6694 B = ( (FT_ULong)B & 0xF ) - 8;
6695 if ( B >= 0 )
6696 B++;
6697 B = B * 64 / ( 1L << CUR.GS.delta_shift );
6699 CUR_Func_move_cvt( A, B );
6704 CUR.new_top = CUR.args;
6708 /*************************************************************************/
6709 /* */
6710 /* MISC. INSTRUCTIONS */
6711 /* */
6712 /*************************************************************************/
6715 /*************************************************************************/
6716 /* */
6717 /* GETINFO[]: GET INFOrmation */
6718 /* Opcode range: 0x88 */
6719 /* Stack: uint32 --> uint32 */
6720 /* */
6721 static void
6722 Ins_GETINFO( INS_ARG )
6724 FT_Long K;
6727 K = 0;
6729 /* We return MS rasterizer version 1.7 for the font scaler. */
6730 if ( ( args[0] & 1 ) != 0 )
6731 K = 35;
6733 /* Has the glyph been rotated? */
6734 if ( ( args[0] & 2 ) != 0 && CUR.tt_metrics.rotated )
6735 K |= 0x80;
6737 /* Has the glyph been stretched? */
6738 if ( ( args[0] & 4 ) != 0 && CUR.tt_metrics.stretched )
6739 K |= 1 << 8;
6741 /* Are we hinting for grayscale? */
6742 if ( ( args[0] & 32 ) != 0 && CUR.grayscale )
6743 K |= 1 << 12;
6745 args[0] = K;
6749 static void
6750 Ins_UNKNOWN( INS_ARG )
6752 TT_DefRecord* def = CUR.IDefs;
6753 TT_DefRecord* limit = def + CUR.numIDefs;
6755 FT_UNUSED_ARG;
6758 for ( ; def < limit; def++ )
6760 if ( (FT_Byte)def->opc == CUR.opcode && def->active )
6762 TT_CallRec* call;
6765 if ( CUR.callTop >= CUR.callSize )
6767 CUR.error = TT_Err_Stack_Overflow;
6768 return;
6771 call = CUR.callStack + CUR.callTop++;
6773 call->Caller_Range = CUR.curRange;
6774 call->Caller_IP = CUR.IP+1;
6775 call->Cur_Count = 1;
6776 call->Cur_Restart = def->start;
6778 INS_Goto_CodeRange( def->range, def->start );
6780 CUR.step_ins = FALSE;
6781 return;
6785 CUR.error = TT_Err_Invalid_Opcode;
6789 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
6792 static
6793 TInstruction_Function Instruct_Dispatch[256] =
6795 /* Opcodes are gathered in groups of 16. */
6796 /* Please keep the spaces as they are. */
6798 /* SVTCA y */ Ins_SVTCA,
6799 /* SVTCA x */ Ins_SVTCA,
6800 /* SPvTCA y */ Ins_SPVTCA,
6801 /* SPvTCA x */ Ins_SPVTCA,
6802 /* SFvTCA y */ Ins_SFVTCA,
6803 /* SFvTCA x */ Ins_SFVTCA,
6804 /* SPvTL // */ Ins_SPVTL,
6805 /* SPvTL + */ Ins_SPVTL,
6806 /* SFvTL // */ Ins_SFVTL,
6807 /* SFvTL + */ Ins_SFVTL,
6808 /* SPvFS */ Ins_SPVFS,
6809 /* SFvFS */ Ins_SFVFS,
6810 /* GPV */ Ins_GPV,
6811 /* GFV */ Ins_GFV,
6812 /* SFvTPv */ Ins_SFVTPV,
6813 /* ISECT */ Ins_ISECT,
6815 /* SRP0 */ Ins_SRP0,
6816 /* SRP1 */ Ins_SRP1,
6817 /* SRP2 */ Ins_SRP2,
6818 /* SZP0 */ Ins_SZP0,
6819 /* SZP1 */ Ins_SZP1,
6820 /* SZP2 */ Ins_SZP2,
6821 /* SZPS */ Ins_SZPS,
6822 /* SLOOP */ Ins_SLOOP,
6823 /* RTG */ Ins_RTG,
6824 /* RTHG */ Ins_RTHG,
6825 /* SMD */ Ins_SMD,
6826 /* ELSE */ Ins_ELSE,
6827 /* JMPR */ Ins_JMPR,
6828 /* SCvTCi */ Ins_SCVTCI,
6829 /* SSwCi */ Ins_SSWCI,
6830 /* SSW */ Ins_SSW,
6832 /* DUP */ Ins_DUP,
6833 /* POP */ Ins_POP,
6834 /* CLEAR */ Ins_CLEAR,
6835 /* SWAP */ Ins_SWAP,
6836 /* DEPTH */ Ins_DEPTH,
6837 /* CINDEX */ Ins_CINDEX,
6838 /* MINDEX */ Ins_MINDEX,
6839 /* AlignPTS */ Ins_ALIGNPTS,
6840 /* INS_0x28 */ Ins_UNKNOWN,
6841 /* UTP */ Ins_UTP,
6842 /* LOOPCALL */ Ins_LOOPCALL,
6843 /* CALL */ Ins_CALL,
6844 /* FDEF */ Ins_FDEF,
6845 /* ENDF */ Ins_ENDF,
6846 /* MDAP[0] */ Ins_MDAP,
6847 /* MDAP[1] */ Ins_MDAP,
6849 /* IUP[0] */ Ins_IUP,
6850 /* IUP[1] */ Ins_IUP,
6851 /* SHP[0] */ Ins_SHP,
6852 /* SHP[1] */ Ins_SHP,
6853 /* SHC[0] */ Ins_SHC,
6854 /* SHC[1] */ Ins_SHC,
6855 /* SHZ[0] */ Ins_SHZ,
6856 /* SHZ[1] */ Ins_SHZ,
6857 /* SHPIX */ Ins_SHPIX,
6858 /* IP */ Ins_IP,
6859 /* MSIRP[0] */ Ins_MSIRP,
6860 /* MSIRP[1] */ Ins_MSIRP,
6861 /* AlignRP */ Ins_ALIGNRP,
6862 /* RTDG */ Ins_RTDG,
6863 /* MIAP[0] */ Ins_MIAP,
6864 /* MIAP[1] */ Ins_MIAP,
6866 /* NPushB */ Ins_NPUSHB,
6867 /* NPushW */ Ins_NPUSHW,
6868 /* WS */ Ins_WS,
6869 /* RS */ Ins_RS,
6870 /* WCvtP */ Ins_WCVTP,
6871 /* RCvt */ Ins_RCVT,
6872 /* GC[0] */ Ins_GC,
6873 /* GC[1] */ Ins_GC,
6874 /* SCFS */ Ins_SCFS,
6875 /* MD[0] */ Ins_MD,
6876 /* MD[1] */ Ins_MD,
6877 /* MPPEM */ Ins_MPPEM,
6878 /* MPS */ Ins_MPS,
6879 /* FlipON */ Ins_FLIPON,
6880 /* FlipOFF */ Ins_FLIPOFF,
6881 /* DEBUG */ Ins_DEBUG,
6883 /* LT */ Ins_LT,
6884 /* LTEQ */ Ins_LTEQ,
6885 /* GT */ Ins_GT,
6886 /* GTEQ */ Ins_GTEQ,
6887 /* EQ */ Ins_EQ,
6888 /* NEQ */ Ins_NEQ,
6889 /* ODD */ Ins_ODD,
6890 /* EVEN */ Ins_EVEN,
6891 /* IF */ Ins_IF,
6892 /* EIF */ Ins_EIF,
6893 /* AND */ Ins_AND,
6894 /* OR */ Ins_OR,
6895 /* NOT */ Ins_NOT,
6896 /* DeltaP1 */ Ins_DELTAP,
6897 /* SDB */ Ins_SDB,
6898 /* SDS */ Ins_SDS,
6900 /* ADD */ Ins_ADD,
6901 /* SUB */ Ins_SUB,
6902 /* DIV */ Ins_DIV,
6903 /* MUL */ Ins_MUL,
6904 /* ABS */ Ins_ABS,
6905 /* NEG */ Ins_NEG,
6906 /* FLOOR */ Ins_FLOOR,
6907 /* CEILING */ Ins_CEILING,
6908 /* ROUND[0] */ Ins_ROUND,
6909 /* ROUND[1] */ Ins_ROUND,
6910 /* ROUND[2] */ Ins_ROUND,
6911 /* ROUND[3] */ Ins_ROUND,
6912 /* NROUND[0] */ Ins_NROUND,
6913 /* NROUND[1] */ Ins_NROUND,
6914 /* NROUND[2] */ Ins_NROUND,
6915 /* NROUND[3] */ Ins_NROUND,
6917 /* WCvtF */ Ins_WCVTF,
6918 /* DeltaP2 */ Ins_DELTAP,
6919 /* DeltaP3 */ Ins_DELTAP,
6920 /* DeltaCn[0] */ Ins_DELTAC,
6921 /* DeltaCn[1] */ Ins_DELTAC,
6922 /* DeltaCn[2] */ Ins_DELTAC,
6923 /* SROUND */ Ins_SROUND,
6924 /* S45Round */ Ins_S45ROUND,
6925 /* JROT */ Ins_JROT,
6926 /* JROF */ Ins_JROF,
6927 /* ROFF */ Ins_ROFF,
6928 /* INS_0x7B */ Ins_UNKNOWN,
6929 /* RUTG */ Ins_RUTG,
6930 /* RDTG */ Ins_RDTG,
6931 /* SANGW */ Ins_SANGW,
6932 /* AA */ Ins_AA,
6934 /* FlipPT */ Ins_FLIPPT,
6935 /* FlipRgON */ Ins_FLIPRGON,
6936 /* FlipRgOFF */ Ins_FLIPRGOFF,
6937 /* INS_0x83 */ Ins_UNKNOWN,
6938 /* INS_0x84 */ Ins_UNKNOWN,
6939 /* ScanCTRL */ Ins_SCANCTRL,
6940 /* SDPVTL[0] */ Ins_SDPVTL,
6941 /* SDPVTL[1] */ Ins_SDPVTL,
6942 /* GetINFO */ Ins_GETINFO,
6943 /* IDEF */ Ins_IDEF,
6944 /* ROLL */ Ins_ROLL,
6945 /* MAX */ Ins_MAX,
6946 /* MIN */ Ins_MIN,
6947 /* ScanTYPE */ Ins_SCANTYPE,
6948 /* InstCTRL */ Ins_INSTCTRL,
6949 /* INS_0x8F */ Ins_UNKNOWN,
6951 /* INS_0x90 */ Ins_UNKNOWN,
6952 /* INS_0x91 */ Ins_UNKNOWN,
6953 /* INS_0x92 */ Ins_UNKNOWN,
6954 /* INS_0x93 */ Ins_UNKNOWN,
6955 /* INS_0x94 */ Ins_UNKNOWN,
6956 /* INS_0x95 */ Ins_UNKNOWN,
6957 /* INS_0x96 */ Ins_UNKNOWN,
6958 /* INS_0x97 */ Ins_UNKNOWN,
6959 /* INS_0x98 */ Ins_UNKNOWN,
6960 /* INS_0x99 */ Ins_UNKNOWN,
6961 /* INS_0x9A */ Ins_UNKNOWN,
6962 /* INS_0x9B */ Ins_UNKNOWN,
6963 /* INS_0x9C */ Ins_UNKNOWN,
6964 /* INS_0x9D */ Ins_UNKNOWN,
6965 /* INS_0x9E */ Ins_UNKNOWN,
6966 /* INS_0x9F */ Ins_UNKNOWN,
6968 /* INS_0xA0 */ Ins_UNKNOWN,
6969 /* INS_0xA1 */ Ins_UNKNOWN,
6970 /* INS_0xA2 */ Ins_UNKNOWN,
6971 /* INS_0xA3 */ Ins_UNKNOWN,
6972 /* INS_0xA4 */ Ins_UNKNOWN,
6973 /* INS_0xA5 */ Ins_UNKNOWN,
6974 /* INS_0xA6 */ Ins_UNKNOWN,
6975 /* INS_0xA7 */ Ins_UNKNOWN,
6976 /* INS_0xA8 */ Ins_UNKNOWN,
6977 /* INS_0xA9 */ Ins_UNKNOWN,
6978 /* INS_0xAA */ Ins_UNKNOWN,
6979 /* INS_0xAB */ Ins_UNKNOWN,
6980 /* INS_0xAC */ Ins_UNKNOWN,
6981 /* INS_0xAD */ Ins_UNKNOWN,
6982 /* INS_0xAE */ Ins_UNKNOWN,
6983 /* INS_0xAF */ Ins_UNKNOWN,
6985 /* PushB[0] */ Ins_PUSHB,
6986 /* PushB[1] */ Ins_PUSHB,
6987 /* PushB[2] */ Ins_PUSHB,
6988 /* PushB[3] */ Ins_PUSHB,
6989 /* PushB[4] */ Ins_PUSHB,
6990 /* PushB[5] */ Ins_PUSHB,
6991 /* PushB[6] */ Ins_PUSHB,
6992 /* PushB[7] */ Ins_PUSHB,
6993 /* PushW[0] */ Ins_PUSHW,
6994 /* PushW[1] */ Ins_PUSHW,
6995 /* PushW[2] */ Ins_PUSHW,
6996 /* PushW[3] */ Ins_PUSHW,
6997 /* PushW[4] */ Ins_PUSHW,
6998 /* PushW[5] */ Ins_PUSHW,
6999 /* PushW[6] */ Ins_PUSHW,
7000 /* PushW[7] */ Ins_PUSHW,
7002 /* MDRP[00] */ Ins_MDRP,
7003 /* MDRP[01] */ Ins_MDRP,
7004 /* MDRP[02] */ Ins_MDRP,
7005 /* MDRP[03] */ Ins_MDRP,
7006 /* MDRP[04] */ Ins_MDRP,
7007 /* MDRP[05] */ Ins_MDRP,
7008 /* MDRP[06] */ Ins_MDRP,
7009 /* MDRP[07] */ Ins_MDRP,
7010 /* MDRP[08] */ Ins_MDRP,
7011 /* MDRP[09] */ Ins_MDRP,
7012 /* MDRP[10] */ Ins_MDRP,
7013 /* MDRP[11] */ Ins_MDRP,
7014 /* MDRP[12] */ Ins_MDRP,
7015 /* MDRP[13] */ Ins_MDRP,
7016 /* MDRP[14] */ Ins_MDRP,
7017 /* MDRP[15] */ Ins_MDRP,
7019 /* MDRP[16] */ Ins_MDRP,
7020 /* MDRP[17] */ Ins_MDRP,
7021 /* MDRP[18] */ Ins_MDRP,
7022 /* MDRP[19] */ Ins_MDRP,
7023 /* MDRP[20] */ Ins_MDRP,
7024 /* MDRP[21] */ Ins_MDRP,
7025 /* MDRP[22] */ Ins_MDRP,
7026 /* MDRP[23] */ Ins_MDRP,
7027 /* MDRP[24] */ Ins_MDRP,
7028 /* MDRP[25] */ Ins_MDRP,
7029 /* MDRP[26] */ Ins_MDRP,
7030 /* MDRP[27] */ Ins_MDRP,
7031 /* MDRP[28] */ Ins_MDRP,
7032 /* MDRP[29] */ Ins_MDRP,
7033 /* MDRP[30] */ Ins_MDRP,
7034 /* MDRP[31] */ Ins_MDRP,
7036 /* MIRP[00] */ Ins_MIRP,
7037 /* MIRP[01] */ Ins_MIRP,
7038 /* MIRP[02] */ Ins_MIRP,
7039 /* MIRP[03] */ Ins_MIRP,
7040 /* MIRP[04] */ Ins_MIRP,
7041 /* MIRP[05] */ Ins_MIRP,
7042 /* MIRP[06] */ Ins_MIRP,
7043 /* MIRP[07] */ Ins_MIRP,
7044 /* MIRP[08] */ Ins_MIRP,
7045 /* MIRP[09] */ Ins_MIRP,
7046 /* MIRP[10] */ Ins_MIRP,
7047 /* MIRP[11] */ Ins_MIRP,
7048 /* MIRP[12] */ Ins_MIRP,
7049 /* MIRP[13] */ Ins_MIRP,
7050 /* MIRP[14] */ Ins_MIRP,
7051 /* MIRP[15] */ Ins_MIRP,
7053 /* MIRP[16] */ Ins_MIRP,
7054 /* MIRP[17] */ Ins_MIRP,
7055 /* MIRP[18] */ Ins_MIRP,
7056 /* MIRP[19] */ Ins_MIRP,
7057 /* MIRP[20] */ Ins_MIRP,
7058 /* MIRP[21] */ Ins_MIRP,
7059 /* MIRP[22] */ Ins_MIRP,
7060 /* MIRP[23] */ Ins_MIRP,
7061 /* MIRP[24] */ Ins_MIRP,
7062 /* MIRP[25] */ Ins_MIRP,
7063 /* MIRP[26] */ Ins_MIRP,
7064 /* MIRP[27] */ Ins_MIRP,
7065 /* MIRP[28] */ Ins_MIRP,
7066 /* MIRP[29] */ Ins_MIRP,
7067 /* MIRP[30] */ Ins_MIRP,
7068 /* MIRP[31] */ Ins_MIRP
7072 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7075 /*************************************************************************/
7076 /* */
7077 /* RUN */
7078 /* */
7079 /* This function executes a run of opcodes. It will exit in the */
7080 /* following cases: */
7081 /* */
7082 /* - Errors (in which case it returns FALSE). */
7083 /* */
7084 /* - Reaching the end of the main code range (returns TRUE). */
7085 /* Reaching the end of a code range within a function call is an */
7086 /* error. */
7087 /* */
7088 /* - After executing one single opcode, if the flag `Instruction_Trap' */
7089 /* is set to TRUE (returns TRUE). */
7090 /* */
7091 /* On exit with TRUE, test IP < CodeSize to know whether it comes from */
7092 /* an instruction trap or a normal termination. */
7093 /* */
7094 /* */
7095 /* Note: The documented DEBUG opcode pops a value from the stack. This */
7096 /* behaviour is unsupported; here a DEBUG opcode is always an */
7097 /* error. */
7098 /* */
7099 /* */
7100 /* THIS IS THE INTERPRETER'S MAIN LOOP. */
7101 /* */
7102 /* Instructions appear in the specification's order. */
7103 /* */
7104 /*************************************************************************/
7107 /* documentation is in ttinterp.h */
7109 FT_EXPORT_DEF( FT_Error )
7110 TT_RunIns( TT_ExecContext exc )
7112 FT_Long ins_counter = 0; /* executed instructions counter */
7115 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7116 cur = *exc;
7117 #endif
7119 /* set CVT functions */
7120 CUR.tt_metrics.ratio = 0;
7121 if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
7123 /* non-square pixels, use the stretched routines */
7124 CUR.func_read_cvt = Read_CVT_Stretched;
7125 CUR.func_write_cvt = Write_CVT_Stretched;
7126 CUR.func_move_cvt = Move_CVT_Stretched;
7128 else
7130 /* square pixels, use normal routines */
7131 CUR.func_read_cvt = Read_CVT;
7132 CUR.func_write_cvt = Write_CVT;
7133 CUR.func_move_cvt = Move_CVT;
7136 COMPUTE_Funcs();
7137 COMPUTE_Round( (FT_Byte)exc->GS.round_state );
7141 CUR.opcode = CUR.code[CUR.IP];
7143 if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )
7145 if ( CUR.IP + 1 > CUR.codeSize )
7146 goto LErrorCodeOverflow_;
7148 CUR.length = 2 - CUR.length * CUR.code[CUR.IP + 1];
7151 if ( CUR.IP + CUR.length > CUR.codeSize )
7152 goto LErrorCodeOverflow_;
7154 /* First, let's check for empty stack and overflow */
7155 CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 );
7157 /* `args' is the top of the stack once arguments have been popped. */
7158 /* One can also interpret it as the index of the last argument. */
7159 if ( CUR.args < 0 )
7161 CUR.error = TT_Err_Too_Few_Arguments;
7162 goto LErrorLabel_;
7165 CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 );
7167 /* `new_top' is the new top of the stack, after the instruction's */
7168 /* execution. `top' will be set to `new_top' after the `switch' */
7169 /* statement. */
7170 if ( CUR.new_top > CUR.stackSize )
7172 CUR.error = TT_Err_Stack_Overflow;
7173 goto LErrorLabel_;
7176 CUR.step_ins = TRUE;
7177 CUR.error = TT_Err_Ok;
7179 #ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
7182 FT_Long* args = CUR.stack + CUR.args;
7183 FT_Byte opcode = CUR.opcode;
7186 #undef ARRAY_BOUND_ERROR
7187 #define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
7190 switch ( opcode )
7192 case 0x00: /* SVTCA y */
7193 case 0x01: /* SVTCA x */
7194 case 0x02: /* SPvTCA y */
7195 case 0x03: /* SPvTCA x */
7196 case 0x04: /* SFvTCA y */
7197 case 0x05: /* SFvTCA x */
7199 FT_Short AA, BB;
7202 AA = (FT_Short)( ( opcode & 1 ) << 14 );
7203 BB = (FT_Short)( AA ^ 0x4000 );
7205 if ( opcode < 4 )
7207 CUR.GS.projVector.x = AA;
7208 CUR.GS.projVector.y = BB;
7210 CUR.GS.dualVector.x = AA;
7211 CUR.GS.dualVector.y = BB;
7213 else
7215 GUESS_VECTOR( projVector );
7218 if ( ( opcode & 2 ) == 0 )
7220 CUR.GS.freeVector.x = AA;
7221 CUR.GS.freeVector.y = BB;
7223 else
7225 GUESS_VECTOR( freeVector );
7228 COMPUTE_Funcs();
7230 break;
7232 case 0x06: /* SPvTL // */
7233 case 0x07: /* SPvTL + */
7234 DO_SPVTL
7235 break;
7237 case 0x08: /* SFvTL // */
7238 case 0x09: /* SFvTL + */
7239 DO_SFVTL
7240 break;
7242 case 0x0A: /* SPvFS */
7243 DO_SPVFS
7244 break;
7246 case 0x0B: /* SFvFS */
7247 DO_SFVFS
7248 break;
7250 case 0x0C: /* GPV */
7251 DO_GPV
7252 break;
7254 case 0x0D: /* GFV */
7255 DO_GFV
7256 break;
7258 case 0x0E: /* SFvTPv */
7259 DO_SFVTPV
7260 break;
7262 case 0x0F: /* ISECT */
7263 Ins_ISECT( EXEC_ARG_ args );
7264 break;
7266 case 0x10: /* SRP0 */
7267 DO_SRP0
7268 break;
7270 case 0x11: /* SRP1 */
7271 DO_SRP1
7272 break;
7274 case 0x12: /* SRP2 */
7275 DO_SRP2
7276 break;
7278 case 0x13: /* SZP0 */
7279 Ins_SZP0( EXEC_ARG_ args );
7280 break;
7282 case 0x14: /* SZP1 */
7283 Ins_SZP1( EXEC_ARG_ args );
7284 break;
7286 case 0x15: /* SZP2 */
7287 Ins_SZP2( EXEC_ARG_ args );
7288 break;
7290 case 0x16: /* SZPS */
7291 Ins_SZPS( EXEC_ARG_ args );
7292 break;
7294 case 0x17: /* SLOOP */
7295 DO_SLOOP
7296 break;
7298 case 0x18: /* RTG */
7299 DO_RTG
7300 break;
7302 case 0x19: /* RTHG */
7303 DO_RTHG
7304 break;
7306 case 0x1A: /* SMD */
7307 DO_SMD
7308 break;
7310 case 0x1B: /* ELSE */
7311 Ins_ELSE( EXEC_ARG_ args );
7312 break;
7314 case 0x1C: /* JMPR */
7315 DO_JMPR
7316 break;
7318 case 0x1D: /* SCVTCI */
7319 DO_SCVTCI
7320 break;
7322 case 0x1E: /* SSWCI */
7323 DO_SSWCI
7324 break;
7326 case 0x1F: /* SSW */
7327 DO_SSW
7328 break;
7330 case 0x20: /* DUP */
7331 DO_DUP
7332 break;
7334 case 0x21: /* POP */
7335 /* nothing :-) */
7336 break;
7338 case 0x22: /* CLEAR */
7339 DO_CLEAR
7340 break;
7342 case 0x23: /* SWAP */
7343 DO_SWAP
7344 break;
7346 case 0x24: /* DEPTH */
7347 DO_DEPTH
7348 break;
7350 case 0x25: /* CINDEX */
7351 DO_CINDEX
7352 break;
7354 case 0x26: /* MINDEX */
7355 Ins_MINDEX( EXEC_ARG_ args );
7356 break;
7358 case 0x27: /* ALIGNPTS */
7359 Ins_ALIGNPTS( EXEC_ARG_ args );
7360 break;
7362 case 0x28: /* ???? */
7363 Ins_UNKNOWN( EXEC_ARG_ args );
7364 break;
7366 case 0x29: /* UTP */
7367 Ins_UTP( EXEC_ARG_ args );
7368 break;
7370 case 0x2A: /* LOOPCALL */
7371 Ins_LOOPCALL( EXEC_ARG_ args );
7372 break;
7374 case 0x2B: /* CALL */
7375 Ins_CALL( EXEC_ARG_ args );
7376 break;
7378 case 0x2C: /* FDEF */
7379 Ins_FDEF( EXEC_ARG_ args );
7380 break;
7382 case 0x2D: /* ENDF */
7383 Ins_ENDF( EXEC_ARG_ args );
7384 break;
7386 case 0x2E: /* MDAP */
7387 case 0x2F: /* MDAP */
7388 Ins_MDAP( EXEC_ARG_ args );
7389 break;
7392 case 0x30: /* IUP */
7393 case 0x31: /* IUP */
7394 Ins_IUP( EXEC_ARG_ args );
7395 break;
7397 case 0x32: /* SHP */
7398 case 0x33: /* SHP */
7399 Ins_SHP( EXEC_ARG_ args );
7400 break;
7402 case 0x34: /* SHC */
7403 case 0x35: /* SHC */
7404 Ins_SHC( EXEC_ARG_ args );
7405 break;
7407 case 0x36: /* SHZ */
7408 case 0x37: /* SHZ */
7409 Ins_SHZ( EXEC_ARG_ args );
7410 break;
7412 case 0x38: /* SHPIX */
7413 Ins_SHPIX( EXEC_ARG_ args );
7414 break;
7416 case 0x39: /* IP */
7417 Ins_IP( EXEC_ARG_ args );
7418 break;
7420 case 0x3A: /* MSIRP */
7421 case 0x3B: /* MSIRP */
7422 Ins_MSIRP( EXEC_ARG_ args );
7423 break;
7425 case 0x3C: /* AlignRP */
7426 Ins_ALIGNRP( EXEC_ARG_ args );
7427 break;
7429 case 0x3D: /* RTDG */
7430 DO_RTDG
7431 break;
7433 case 0x3E: /* MIAP */
7434 case 0x3F: /* MIAP */
7435 Ins_MIAP( EXEC_ARG_ args );
7436 break;
7438 case 0x40: /* NPUSHB */
7439 Ins_NPUSHB( EXEC_ARG_ args );
7440 break;
7442 case 0x41: /* NPUSHW */
7443 Ins_NPUSHW( EXEC_ARG_ args );
7444 break;
7446 case 0x42: /* WS */
7447 DO_WS
7448 break;
7450 Set_Invalid_Ref:
7451 CUR.error = TT_Err_Invalid_Reference;
7452 break;
7454 case 0x43: /* RS */
7455 DO_RS
7456 break;
7458 case 0x44: /* WCVTP */
7459 DO_WCVTP
7460 break;
7462 case 0x45: /* RCVT */
7463 DO_RCVT
7464 break;
7466 case 0x46: /* GC */
7467 case 0x47: /* GC */
7468 Ins_GC( EXEC_ARG_ args );
7469 break;
7471 case 0x48: /* SCFS */
7472 Ins_SCFS( EXEC_ARG_ args );
7473 break;
7475 case 0x49: /* MD */
7476 case 0x4A: /* MD */
7477 Ins_MD( EXEC_ARG_ args );
7478 break;
7480 case 0x4B: /* MPPEM */
7481 DO_MPPEM
7482 break;
7484 case 0x4C: /* MPS */
7485 DO_MPS
7486 break;
7488 case 0x4D: /* FLIPON */
7489 DO_FLIPON
7490 break;
7492 case 0x4E: /* FLIPOFF */
7493 DO_FLIPOFF
7494 break;
7496 case 0x4F: /* DEBUG */
7497 DO_DEBUG
7498 break;
7500 case 0x50: /* LT */
7501 DO_LT
7502 break;
7504 case 0x51: /* LTEQ */
7505 DO_LTEQ
7506 break;
7508 case 0x52: /* GT */
7509 DO_GT
7510 break;
7512 case 0x53: /* GTEQ */
7513 DO_GTEQ
7514 break;
7516 case 0x54: /* EQ */
7517 DO_EQ
7518 break;
7520 case 0x55: /* NEQ */
7521 DO_NEQ
7522 break;
7524 case 0x56: /* ODD */
7525 DO_ODD
7526 break;
7528 case 0x57: /* EVEN */
7529 DO_EVEN
7530 break;
7532 case 0x58: /* IF */
7533 Ins_IF( EXEC_ARG_ args );
7534 break;
7536 case 0x59: /* EIF */
7537 /* do nothing */
7538 break;
7540 case 0x5A: /* AND */
7541 DO_AND
7542 break;
7544 case 0x5B: /* OR */
7545 DO_OR
7546 break;
7548 case 0x5C: /* NOT */
7549 DO_NOT
7550 break;
7552 case 0x5D: /* DELTAP1 */
7553 Ins_DELTAP( EXEC_ARG_ args );
7554 break;
7556 case 0x5E: /* SDB */
7557 DO_SDB
7558 break;
7560 case 0x5F: /* SDS */
7561 DO_SDS
7562 break;
7564 case 0x60: /* ADD */
7565 DO_ADD
7566 break;
7568 case 0x61: /* SUB */
7569 DO_SUB
7570 break;
7572 case 0x62: /* DIV */
7573 DO_DIV
7574 break;
7576 case 0x63: /* MUL */
7577 DO_MUL
7578 break;
7580 case 0x64: /* ABS */
7581 DO_ABS
7582 break;
7584 case 0x65: /* NEG */
7585 DO_NEG
7586 break;
7588 case 0x66: /* FLOOR */
7589 DO_FLOOR
7590 break;
7592 case 0x67: /* CEILING */
7593 DO_CEILING
7594 break;
7596 case 0x68: /* ROUND */
7597 case 0x69: /* ROUND */
7598 case 0x6A: /* ROUND */
7599 case 0x6B: /* ROUND */
7600 DO_ROUND
7601 break;
7603 case 0x6C: /* NROUND */
7604 case 0x6D: /* NROUND */
7605 case 0x6E: /* NRRUND */
7606 case 0x6F: /* NROUND */
7607 DO_NROUND
7608 break;
7610 case 0x70: /* WCVTF */
7611 DO_WCVTF
7612 break;
7614 case 0x71: /* DELTAP2 */
7615 case 0x72: /* DELTAP3 */
7616 Ins_DELTAP( EXEC_ARG_ args );
7617 break;
7619 case 0x73: /* DELTAC0 */
7620 case 0x74: /* DELTAC1 */
7621 case 0x75: /* DELTAC2 */
7622 Ins_DELTAC( EXEC_ARG_ args );
7623 break;
7625 case 0x76: /* SROUND */
7626 DO_SROUND
7627 break;
7629 case 0x77: /* S45Round */
7630 DO_S45ROUND
7631 break;
7633 case 0x78: /* JROT */
7634 DO_JROT
7635 break;
7637 case 0x79: /* JROF */
7638 DO_JROF
7639 break;
7641 case 0x7A: /* ROFF */
7642 DO_ROFF
7643 break;
7645 case 0x7B: /* ???? */
7646 Ins_UNKNOWN( EXEC_ARG_ args );
7647 break;
7649 case 0x7C: /* RUTG */
7650 DO_RUTG
7651 break;
7653 case 0x7D: /* RDTG */
7654 DO_RDTG
7655 break;
7657 case 0x7E: /* SANGW */
7658 case 0x7F: /* AA */
7659 /* nothing - obsolete */
7660 break;
7662 case 0x80: /* FLIPPT */
7663 Ins_FLIPPT( EXEC_ARG_ args );
7664 break;
7666 case 0x81: /* FLIPRGON */
7667 Ins_FLIPRGON( EXEC_ARG_ args );
7668 break;
7670 case 0x82: /* FLIPRGOFF */
7671 Ins_FLIPRGOFF( EXEC_ARG_ args );
7672 break;
7674 case 0x83: /* UNKNOWN */
7675 case 0x84: /* UNKNOWN */
7676 Ins_UNKNOWN( EXEC_ARG_ args );
7677 break;
7679 case 0x85: /* SCANCTRL */
7680 Ins_SCANCTRL( EXEC_ARG_ args );
7681 break;
7683 case 0x86: /* SDPVTL */
7684 case 0x87: /* SDPVTL */
7685 Ins_SDPVTL( EXEC_ARG_ args );
7686 break;
7688 case 0x88: /* GETINFO */
7689 Ins_GETINFO( EXEC_ARG_ args );
7690 break;
7692 case 0x89: /* IDEF */
7693 Ins_IDEF( EXEC_ARG_ args );
7694 break;
7696 case 0x8A: /* ROLL */
7697 Ins_ROLL( EXEC_ARG_ args );
7698 break;
7700 case 0x8B: /* MAX */
7701 DO_MAX
7702 break;
7704 case 0x8C: /* MIN */
7705 DO_MIN
7706 break;
7708 case 0x8D: /* SCANTYPE */
7709 Ins_SCANTYPE( EXEC_ARG_ args );
7710 break;
7712 case 0x8E: /* INSTCTRL */
7713 Ins_INSTCTRL( EXEC_ARG_ args );
7714 break;
7716 case 0x8F:
7717 Ins_UNKNOWN( EXEC_ARG_ args );
7718 break;
7720 default:
7721 if ( opcode >= 0xE0 )
7722 Ins_MIRP( EXEC_ARG_ args );
7723 else if ( opcode >= 0xC0 )
7724 Ins_MDRP( EXEC_ARG_ args );
7725 else if ( opcode >= 0xB8 )
7726 Ins_PUSHW( EXEC_ARG_ args );
7727 else if ( opcode >= 0xB0 )
7728 Ins_PUSHB( EXEC_ARG_ args );
7729 else
7730 Ins_UNKNOWN( EXEC_ARG_ args );
7735 #else
7737 Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );
7739 #endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7741 if ( CUR.error != TT_Err_Ok )
7743 switch ( CUR.error )
7745 case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
7747 TT_DefRecord* def = CUR.IDefs;
7748 TT_DefRecord* limit = def + CUR.numIDefs;
7751 for ( ; def < limit; def++ )
7753 if ( def->active && CUR.opcode == (FT_Byte)def->opc )
7755 TT_CallRec* callrec;
7758 if ( CUR.callTop >= CUR.callSize )
7760 CUR.error = TT_Err_Invalid_Reference;
7761 goto LErrorLabel_;
7764 callrec = &CUR.callStack[CUR.callTop];
7766 callrec->Caller_Range = CUR.curRange;
7767 callrec->Caller_IP = CUR.IP + 1;
7768 callrec->Cur_Count = 1;
7769 callrec->Cur_Restart = def->start;
7771 if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
7772 goto LErrorLabel_;
7774 goto LSuiteLabel_;
7779 CUR.error = TT_Err_Invalid_Opcode;
7780 goto LErrorLabel_;
7782 #if 0
7783 break; /* Unreachable code warning suppression. */
7784 /* Leave to remind in case a later change the editor */
7785 /* to consider break; */
7786 #endif
7788 default:
7789 goto LErrorLabel_;
7791 #if 0
7792 break;
7793 #endif
7797 CUR.top = CUR.new_top;
7799 if ( CUR.step_ins )
7800 CUR.IP += CUR.length;
7802 /* increment instruction counter and check if we didn't */
7803 /* run this program for too long (e.g. infinite loops). */
7804 if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
7805 return TT_Err_Execution_Too_Long;
7807 LSuiteLabel_:
7808 if ( CUR.IP >= CUR.codeSize )
7810 if ( CUR.callTop > 0 )
7812 CUR.error = TT_Err_Code_Overflow;
7813 goto LErrorLabel_;
7815 else
7816 goto LNo_Error_;
7818 } while ( !CUR.instruction_trap );
7820 LNo_Error_:
7822 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7823 *exc = cur;
7824 #endif
7826 return TT_Err_Ok;
7828 LErrorCodeOverflow_:
7829 CUR.error = TT_Err_Code_Overflow;
7831 LErrorLabel_:
7833 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7834 *exc = cur;
7835 #endif
7837 return CUR.error;
7841 #endif /* TT_USE_BYTECODE_INTERPRETER */
7844 /* END */