1 /***************************************************************************/
2 /* */
3 /* ttinterp.c */
4 /* */
5 /* TrueType bytecode interpreter (body). */
6 /* */
7 /* Copyright 1996-2001 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_CONFIG_OPTION_BYTECODE_INTERPRETER
33 #define TT_MULFIX FT_MulFix
34 #define TT_MULDIV FT_MulDiv
35 #define TT_INT64 FT_Int64
37 /*************************************************************************/
38 /* */
39 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
40 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
41 /* messages during execution. */
42 /* */
43 #undef FT_COMPONENT
44 #define FT_COMPONENT trace_ttinterp
46 #undef NO_APPLE_PATENT
47 #define APPLE_THRESHOLD 0x4000000L
49 /*************************************************************************/
50 /* */
51 /* In order to detect infinite loops in the code, we set up a counter */
52 /* within the run loop. A single stroke of interpretation is now */
53 /* limitet to a maximal number of opcodes defined below. */
54 /* */
55 #define MAX_RUNNABLE_OPCODES 1000000L
58 /*************************************************************************/
59 /* */
60 /* There are two kinds of implementations: */
61 /* */
62 /* a. static implementation */
63 /* */
64 /* The current execution context is a static variable, which fields */
65 /* are accessed directly by the interpreter during execution. The */
66 /* context is named `cur'. */
67 /* */
68 /* This version is non-reentrant, of course. */
69 /* */
70 /* b. indirect implementation */
71 /* */
72 /* The current execution context is passed to _each_ function as its */
73 /* first argument, and each field is thus accessed indirectly. */
74 /* */
75 /* This version is fully re-entrant. */
76 /* */
77 /* The idea is that an indirect implementation may be slower to execute */
78 /* on low-end processors that are used in some systems (like 386s or */
79 /* even 486s). */
80 /* */
81 /* As a consequence, the indirect implementation is now the default, as */
82 /* its performance costs can be considered negligible in our context. */
83 /* Note, however, that we kept the same source with macros because: */
84 /* */
85 /* - The code is kept very close in design to the Pascal code used for */
86 /* development. */
87 /* */
88 /* - It's much more readable that way! */
89 /* */
90 /* - It's still open to experimentation and tuning. */
91 /* */
92 /*************************************************************************/
95 #ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */
97 #define CUR (*exc) /* see ttobjs.h */
99 #else /* static implementation */
101 #define CUR cur
103 static
104 TT_ExecContextRec cur; /* static exec. context variable */
106 /* apparently, we have a _lot_ of direct indexing when accessing */
107 /* the static `cur', which makes the code bigger (due to all the */
108 /* four bytes addresses). */
110 #endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
113 /*************************************************************************/
114 /* */
115 /* The instruction argument stack. */
116 /* */
117 #define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */
120 /*************************************************************************/
121 /* */
122 /* This macro is used whenever `exec' is unused in a function, to avoid */
123 /* stupid warnings from pedantic compilers. */
124 /* */
125 #define FT_UNUSED_EXEC FT_UNUSED( CUR )
128 /*************************************************************************/
129 /* */
130 /* This macro is used whenever `args' is unused in a function, to avoid */
131 /* stupid warnings from pedantic compilers. */
132 /* */
133 #define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args )
136 /*************************************************************************/
137 /* */
138 /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */
139 /* increase readabilty of the code. */
140 /* */
141 /*************************************************************************/
144 #define SKIP_Code() \
145 SkipCode( EXEC_ARG )
147 #define GET_ShortIns() \
148 GetShortIns( EXEC_ARG )
150 #define NORMalize( x, y, v ) \
151 Normalize( EXEC_ARG_ x, y, v )
153 #define SET_SuperRound( scale, flags ) \
154 SetSuperRound( EXEC_ARG_ scale, flags )
156 #define ROUND_None( d, c ) \
157 Round_None( EXEC_ARG_ d, c )
159 #define INS_Goto_CodeRange( range, ip ) \
160 Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
162 #define CUR_Func_project( x, y ) \
163 CUR.func_project( EXEC_ARG_ x, y )
165 #define CUR_Func_move( z, p, d ) \
166 CUR.func_move( EXEC_ARG_ z, p, d )
168 #define CUR_Func_dualproj( x, y ) \
169 CUR.func_dualproj( EXEC_ARG_ x, y )
171 #define CUR_Func_freeProj( x, y ) \
172 CUR.func_freeProj( EXEC_ARG_ x, y )
174 #define CUR_Func_round( d, c ) \
175 CUR.func_round( EXEC_ARG_ d, c )
177 #define CUR_Func_read_cvt( index ) \
178 CUR.func_read_cvt( EXEC_ARG_ index )
180 #define CUR_Func_write_cvt( index, val ) \
181 CUR.func_write_cvt( EXEC_ARG_ index, val )
183 #define CUR_Func_move_cvt( index, val ) \
184 CUR.func_move_cvt( EXEC_ARG_ index, val )
186 #define CURRENT_Ratio() \
187 Current_Ratio( EXEC_ARG )
189 #define CURRENT_Ppem() \
190 Current_Ppem( EXEC_ARG )
192 #define CUR_Ppem() \
193 Cur_PPEM( EXEC_ARG )
195 #define INS_SxVTL( a, b, c, d ) \
196 Ins_SxVTL( EXEC_ARG_ a, b, c, d )
198 #define COMPUTE_Funcs() \
199 Compute_Funcs( EXEC_ARG )
201 #define COMPUTE_Round( a ) \
202 Compute_Round( EXEC_ARG_ a )
204 #define COMPUTE_Point_Displacement( a, b, c, d ) \
205 Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
207 #define MOVE_Zp2_Point( a, b, c, t ) \
208 Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
211 /*************************************************************************/
212 /* */
213 /* Instruction dispatch function, as used by the interpreter. */
214 /* */
215 typedef void (*TInstruction_Function)( INS_ARG );
218 /*************************************************************************/
219 /* */
220 /* A simple bounds-checking macro. */
221 /* */
222 #define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
225 #undef SUCCESS
226 #define SUCCESS 0
228 #undef FAILURE
229 #define FAILURE 1
232 /*************************************************************************/
233 /* */
234 /* CODERANGE FUNCTIONS */
235 /* */
236 /*************************************************************************/
239 /*************************************************************************/
240 /* */
241 /* <Function> */
242 /* TT_Goto_CodeRange */
243 /* */
244 /* <Description> */
245 /* Switches to a new code range (updates the code related elements in */
246 /* `exec', and `IP'). */
247 /* */
248 /* <Input> */
249 /* range :: The new execution code range. */
250 /* */
251 /* IP :: The new IP in the new code range. */
252 /* */
253 /* <InOut> */
254 /* exec :: The target execution context. */
255 /* */
256 /* <Return> */
257 /* FreeType error code. 0 means success. */
258 /* */
259 FT_LOCAL_DEF FT_Error
260 TT_Goto_CodeRange( TT_ExecContext exec,
261 FT_Int range,
262 FT_Long IP )
263 {
264 TT_CodeRange* coderange;
267 FT_Assert( range >= 1 && range <= 3 );
269 coderange = &exec->codeRangeTable[range - 1];
271 FT_Assert( coderange->base != NULL );
273 /* NOTE: Because the last instruction of a program may be a CALL */
274 /* which will return to the first byte *after* the code */
275 /* range, we test for IP <= Size instead of IP < Size. */
276 /* */
277 FT_Assert( (FT_ULong)IP <= coderange->size );
279 exec->code = coderange->base;
280 exec->codeSize = coderange->size;
281 exec->IP = IP;
282 exec->curRange = range;
284 return TT_Err_Ok;
285 }
288 /*************************************************************************/
289 /* */
290 /* <Function> */
291 /* TT_Set_CodeRange */
292 /* */
293 /* <Description> */
294 /* Sets a code range. */
295 /* */
296 /* <Input> */
297 /* range :: The code range index. */
298 /* */
299 /* base :: The new code base. */
300 /* */
301 /* length :: The range size in bytes. */
302 /* */
303 /* <InOut> */
304 /* exec :: The target execution context. */
305 /* */
306 /* <Return> */
307 /* FreeType error code. 0 means success. */
308 /* */
309 FT_LOCAL_DEF FT_Error
310 TT_Set_CodeRange( TT_ExecContext exec,
311 FT_Int range,
312 void* base,
313 FT_Long length )
314 {
315 FT_Assert( range >= 1 && range <= 3 );
317 exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
318 exec->codeRangeTable[range - 1].size = length;
320 return TT_Err_Ok;
321 }
324 /*************************************************************************/
325 /* */
326 /* <Function> */
327 /* TT_Clear_CodeRange */
328 /* */
329 /* <Description> */
330 /* Clears a code range. */
331 /* */
332 /* <Input> */
333 /* range :: The code range index. */
334 /* */
335 /* <InOut> */
336 /* exec :: The target execution context. */
337 /* */
338 /* <Return> */
339 /* FreeType error code. 0 means success. */
340 /* */
341 /* <Note> */
342 /* Does not set the Error variable. */
343 /* */
344 FT_LOCAL_DEF FT_Error
345 TT_Clear_CodeRange( TT_ExecContext exec,
346 FT_Int range )
347 {
348 FT_Assert( range >= 1 && range <= 3 );
350 exec->codeRangeTable[range - 1].base = NULL;
351 exec->codeRangeTable[range - 1].size = 0;
353 return TT_Err_Ok;
354 }
357 /*************************************************************************/
358 /* */
359 /* EXECUTION CONTEXT ROUTINES */
360 /* */
361 /*************************************************************************/
364 /*************************************************************************/
365 /* */
366 /* <Function> */
367 /* TT_Destroy_Context */
368 /* */
369 /* <Description> */
370 /* Destroys a given context. */
371 /* */
372 /* <Input> */
373 /* exec :: A handle to the target execution context. */
374 /* */
375 /* memory :: A handle to the parent memory object. */
376 /* */
377 /* <Return> */
378 /* FreeType error code. 0 means success. */
379 /* */
380 /* <Note> */
381 /* Only the glyph loader and debugger should call this function. */
382 /* */
383 FT_LOCAL_DEF FT_Error
384 TT_Destroy_Context( TT_ExecContext exec,
385 FT_Memory memory )
386 {
387 /* free composite load stack */
388 FREE( exec->loadStack );
389 exec->loadSize = 0;
391 /* points zone */
392 exec->maxPoints = 0;
393 exec->maxContours = 0;
395 /* free stack */
396 FREE( exec->stack );
397 exec->stackSize = 0;
399 /* free call stack */
400 FREE( exec->callStack );
401 exec->callSize = 0;
402 exec->callTop = 0;
404 /* free glyph code range */
405 FREE( exec->glyphIns );
406 exec->glyphSize = 0;
408 exec->size = NULL;
409 exec->face = NULL;
411 FREE( exec );
412 return TT_Err_Ok;
413 }
416 /*************************************************************************/
417 /* */
418 /* <Function> */
419 /* Init_Context */
420 /* */
421 /* <Description> */
422 /* Initializes a context object. */
423 /* */
424 /* <Input> */
425 /* memory :: A handle to the parent memory object. */
426 /* */
427 /* face :: A handle to the source TrueType face object. */
428 /* */
429 /* <InOut> */
430 /* exec :: A handle to the target execution context. */
431 /* */
432 /* <Return> */
433 /* FreeType error code. 0 means success. */
434 /* */
435 static FT_Error
436 Init_Context( TT_ExecContext exec,
437 TT_Face face,
438 FT_Memory memory )
439 {
440 FT_Error error;
443 FT_TRACE1(( "Init_Context: new object at 0x%08p, parent = 0x%08p\n",
444 exec, face ));
446 exec->memory = memory;
447 exec->callSize = 32;
449 if ( ALLOC_ARRAY( exec->callStack, exec->callSize, TT_CallRec ) )
450 goto Fail_Memory;
452 /* all values in the context are set to 0 already, but this is */
453 /* here as a remainder */
454 exec->maxPoints = 0;
455 exec->maxContours = 0;
457 exec->stackSize = 0;
458 exec->loadSize = 0;
459 exec->glyphSize = 0;
461 exec->stack = NULL;
462 exec->loadStack = NULL;
463 exec->glyphIns = NULL;
465 exec->face = face;
466 exec->size = NULL;
468 return TT_Err_Ok;
470 Fail_Memory:
471 FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n",
472 (FT_Long)exec ));
473 TT_Destroy_Context( exec, memory );
475 return error;
476 }
479 /*************************************************************************/
480 /* */
481 /* <Function> */
482 /* Update_Max */
483 /* */
484 /* <Description> */
485 /* Checks the size of a buffer and reallocates it if necessary. */
486 /* */
487 /* <Input> */
488 /* memory :: A handle to the parent memory object. */
489 /* */
490 /* multiplier :: The size in bytes of each element in the buffer. */
491 /* */
492 /* new_max :: The new capacity (size) of the buffer. */
493 /* */
494 /* <InOut> */
495 /* size :: The address of the buffer's current size expressed */
496 /* in elements. */
497 /* */
498 /* buff :: The address of the buffer base pointer. */
499 /* */
500 /* <Return> */
501 /* FreeType error code. 0 means success. */
502 /* */
503 static FT_Error
504 Update_Max( FT_Memory memory,
505 FT_ULong* size,
506 FT_Long multiplier,
507 void** buff,
508 FT_ULong new_max )
509 {
510 FT_Error error;
513 if ( *size < new_max )
514 {
515 FREE( *buff );
516 if ( ALLOC( *buff, new_max * multiplier ) )
517 return error;
518 *size = new_max;
519 }
521 return TT_Err_Ok;
522 }
525 /*************************************************************************/
526 /* */
527 /* <Function> */
528 /* TT_Load_Context */
529 /* */
530 /* <Description> */
531 /* Prepare an execution context for glyph hinting. */
532 /* */
533 /* <Input> */
534 /* face :: A handle to the source face object. */
535 /* */
536 /* size :: A handle to the source size object. */
537 /* */
538 /* <InOut> */
539 /* exec :: A handle to the target execution context. */
540 /* */
541 /* <Return> */
542 /* FreeType error code. 0 means success. */
543 /* */
544 /* <Note> */
545 /* Only the glyph loader and debugger should call this function. */
546 /* */
547 FT_LOCAL_DEF FT_Error
548 TT_Load_Context( TT_ExecContext exec,
549 TT_Face face,
550 TT_Size size )
551 {
552 FT_Int i;
553 FT_ULong tmp;
554 TT_MaxProfile* maxp;
555 FT_Error error;
558 exec->face = face;
559 maxp = &face->max_profile;
560 exec->size = size;
562 if ( size )
563 {
564 exec->numFDefs = size->num_function_defs;
565 exec->maxFDefs = size->max_function_defs;
566 exec->numIDefs = size->num_instruction_defs;
567 exec->maxIDefs = size->max_instruction_defs;
568 exec->FDefs = size->function_defs;
569 exec->IDefs = size->instruction_defs;
570 exec->tt_metrics = size->ttmetrics;
571 exec->metrics = size->root.metrics;
573 exec->maxFunc = size->max_func;
574 exec->maxIns = size->max_ins;
576 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
577 exec->codeRangeTable[i] = size->codeRangeTable[i];
579 /* set graphics state */
580 exec->GS = size->GS;
582 exec->cvtSize = size->cvt_size;
583 exec->cvt = size->cvt;
585 exec->storeSize = size->storage_size;
586 exec->storage = size->storage;
588 exec->twilight = size->twilight;
589 }
591 error = Update_Max( exec->memory,
592 &exec->loadSize,
593 sizeof ( TT_SubGlyphRec ),
594 (void**)&exec->loadStack,
595 exec->face->max_components + 1 );
596 if ( error )
597 return error;
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->instruction_trap = FALSE;
626 return TT_Err_Ok;
627 }
630 /*************************************************************************/
631 /* */
632 /* <Function> */
633 /* TT_Save_Context */
634 /* */
635 /* <Description> */
636 /* Saves the code ranges in a `size' object. */
637 /* */
638 /* <Input> */
639 /* exec :: A handle to the source execution context. */
640 /* */
641 /* <InOut> */
642 /* size :: A handle to the target size object. */
643 /* */
644 /* <Return> */
645 /* FreeType error code. 0 means success. */
646 /* */
647 /* <Note> */
648 /* Only the glyph loader and debugger should call this function. */
649 /* */
650 FT_LOCAL_DEF FT_Error
651 TT_Save_Context( TT_ExecContext exec,
652 TT_Size size )
653 {
654 FT_Int i;
657 /* XXXX: Will probably disappear soon with all the code range */
658 /* management, which is now rather obsolete. */
659 /* */
660 size->num_function_defs = exec->numFDefs;
661 size->num_instruction_defs = exec->numIDefs;
663 size->max_func = exec->maxFunc;
664 size->max_ins = exec->maxIns;
666 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
667 size->codeRangeTable[i] = exec->codeRangeTable[i];
669 return TT_Err_Ok;
670 }
673 /*************************************************************************/
674 /* */
675 /* <Function> */
676 /* TT_Run_Context */
677 /* */
678 /* <Description> */
679 /* Executes one or more instructions in the execution context. */
680 /* */
681 /* <Input> */
682 /* debug :: A Boolean flag. If set, the function sets some internal */
683 /* variables and returns immediately, otherwise TT_RunIns() */
684 /* is called. */
685 /* */
686 /* This is commented out currently. */
687 /* */
688 /* <Input> */
689 /* exec :: A handle to the target execution context. */
690 /* */
691 /* <Return> */
692 /* TrueTyoe error code. 0 means success. */
693 /* */
694 /* <Note> */
695 /* Only the glyph loader and debugger should call this function. */
696 /* */
697 FT_LOCAL_DEF FT_Error
698 TT_Run_Context( TT_ExecContext exec,
699 FT_Bool debug )
700 {
701 FT_Error error;
704 if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) )
705 != TT_Err_Ok )
706 return error;
708 exec->zp0 = exec->pts;
709 exec->zp1 = exec->pts;
710 exec->zp2 = exec->pts;
712 exec->GS.gep0 = 1;
713 exec->GS.gep1 = 1;
714 exec->GS.gep2 = 1;
716 exec->GS.projVector.x = 0x4000;
717 exec->GS.projVector.y = 0x0000;
719 exec->GS.freeVector = exec->GS.projVector;
720 exec->GS.dualVector = exec->GS.projVector;
722 exec->GS.round_state = 1;
723 exec->GS.loop = 1;
725 /* some glyphs leave something on the stack. so we clean it */
726 /* before a new execution. */
727 exec->top = 0;
728 exec->callTop = 0;
730 #if 1
731 FT_UNUSED( debug );
733 return exec->face->interpreter( exec );
734 #else
735 if ( !debug )
736 return TT_RunIns( exec );
737 else
738 return TT_Err_Ok;
739 #endif
740 }
743 const TT_GraphicsState tt_default_graphics_state =
744 {
745 0, 0, 0,
746 { 0x4000, 0 },
747 { 0x4000, 0 },
748 { 0x4000, 0 },
749 1, 64, 1,
750 TRUE, 68, 0, 0, 9, 3,
751 0, FALSE, 2, 1, 1, 1
752 };
755 /* documentation is in ttinterp.h */
757 FT_EXPORT_DEF( TT_ExecContext )
758 TT_New_Context( TT_Face face )
759 {
760 TT_Driver driver;
761 TT_ExecContext exec;
762 FT_Memory memory;
765 if ( !face )
766 return 0;
768 driver = (TT_Driver)face->root.driver;
770 memory = driver->root.root.memory;
771 exec = driver->context;
773 if ( !driver->context )
774 {
775 FT_Error error;
778 /* allocate object */
779 if ( ALLOC( exec, sizeof ( *exec ) ) )
780 goto Exit;
782 /* initialize it */
783 error = Init_Context( exec, face, memory );
784 if ( error )
785 goto Fail;
787 /* store it into the driver */
788 driver->context = exec;
789 }
791 Exit:
792 return driver->context;
794 Fail:
795 FREE( exec );
797 return 0;
798 }
801 /*************************************************************************/
802 /* */
803 /* <Function> */
804 /* TT_Done_Context */
805 /* */
806 /* <Description> */
807 /* Discards an execution context. */
808 /* */
809 /* <Input> */
810 /* exec :: A handle to the target execution context. */
811 /* */
812 /* <Return> */
813 /* FreeType error code. 0 means success. */
814 /* */
815 /* <Note> */
816 /* Only the glyph loader and debugger should call this function. */
817 /* */
818 FT_LOCAL_DEF FT_Error
819 TT_Done_Context( TT_ExecContext exec )
820 {
821 /* Nothing at all for now */
822 FT_UNUSED( exec );
824 return TT_Err_Ok;
825 }
828 /* return length of given vector */
829 #ifdef FT_CONFIG_OPTION_OLD_CALCS
831 static FT_F26Dot6
832 Norm( FT_F26Dot6 X,
833 FT_F26Dot6 Y )
834 {
835 TT_INT64 T1, T2;
838 MUL_64( X, X, T1 );
839 MUL_64( Y, Y, T2 );
841 ADD_64( T1, T2, T1 );
843 return (FT_F26Dot6)SQRT_64( T1 );
844 }
846 #else /* !FT_CONFIG_OPTION_OLD_CALCS */
848 static FT_F26Dot6
849 Norm( FT_F26Dot6 X,
850 FT_F26Dot6 Y )
851 {
852 FT_Vector v;
854 v.x = X;
855 v.y = Y;
856 return FT_Vector_Length( &v );
857 }
859 #endif /* FT_CONFIG_OPTION_OLD_CALCS */
862 /*************************************************************************/
863 /* */
864 /* Before an opcode is executed, the interpreter verifies that there are */
865 /* enough arguments on the stack, with the help of the Pop_Push_Count */
866 /* table. */
867 /* */
868 /* For each opcode, the first column gives the number of arguments that */
869 /* are popped from the stack; the second one gives the number of those */
870 /* that are pushed in result. */
871 /* */
872 /* Note that for opcodes with a varying number of parameters, either 0 */
873 /* or 1 arg is verified before execution, depending on the nature of the */
874 /* instruction: */
875 /* */
876 /* - if the number of arguments is given by the bytecode stream or the */
877 /* loop variable, 0 is chosen. */
878 /* */
879 /* - if the first argument is a count n that is followed by arguments */
880 /* a1 .. an, then 1 is chosen. */
881 /* */
882 /*************************************************************************/
885 #undef PACK
886 #define PACK( x, y ) ( ( x << 4 ) | y )
889 static
890 const FT_Byte Pop_Push_Count[256] =
891 {
892 /* opcodes are gathered in groups of 16 */
893 /* please keep the spaces as they are */
895 /* SVTCA y */ PACK( 0, 0 ),
896 /* SVTCA x */ PACK( 0, 0 ),
897 /* SPvTCA y */ PACK( 0, 0 ),
898 /* SPvTCA x */ PACK( 0, 0 ),
899 /* SFvTCA y */ PACK( 0, 0 ),
900 /* SFvTCA x */ PACK( 0, 0 ),
901 /* SPvTL // */ PACK( 2, 0 ),
902 /* SPvTL + */ PACK( 2, 0 ),
903 /* SFvTL // */ PACK( 2, 0 ),
904 /* SFvTL + */ PACK( 2, 0 ),
905 /* SPvFS */ PACK( 2, 0 ),
906 /* SFvFS */ PACK( 2, 0 ),
907 /* GPV */ PACK( 0, 2 ),
908 /* GFV */ PACK( 0, 2 ),
909 /* SFvTPv */ PACK( 0, 0 ),
910 /* ISECT */ PACK( 5, 0 ),
912 /* SRP0 */ PACK( 1, 0 ),
913 /* SRP1 */ PACK( 1, 0 ),
914 /* SRP2 */ PACK( 1, 0 ),
915 /* SZP0 */ PACK( 1, 0 ),
916 /* SZP1 */ PACK( 1, 0 ),
917 /* SZP2 */ PACK( 1, 0 ),
918 /* SZPS */ PACK( 1, 0 ),
919 /* SLOOP */ PACK( 1, 0 ),
920 /* RTG */ PACK( 0, 0 ),
921 /* RTHG */ PACK( 0, 0 ),
922 /* SMD */ PACK( 1, 0 ),
923 /* ELSE */ PACK( 0, 0 ),
924 /* JMPR */ PACK( 1, 0 ),
925 /* SCvTCi */ PACK( 1, 0 ),
926 /* SSwCi */ PACK( 1, 0 ),
927 /* SSW */ PACK( 1, 0 ),
929 /* DUP */ PACK( 1, 2 ),
930 /* POP */ PACK( 1, 0 ),
931 /* CLEAR */ PACK( 0, 0 ),
932 /* SWAP */ PACK( 2, 2 ),
933 /* DEPTH */ PACK( 0, 1 ),
934 /* CINDEX */ PACK( 1, 1 ),
935 /* MINDEX */ PACK( 1, 0 ),
936 /* AlignPTS */ PACK( 2, 0 ),
937 /* INS_$28 */ PACK( 0, 0 ),
938 /* UTP */ PACK( 1, 0 ),
939 /* LOOPCALL */ PACK( 2, 0 ),
940 /* CALL */ PACK( 1, 0 ),
941 /* FDEF */ PACK( 1, 0 ),
942 /* ENDF */ PACK( 0, 0 ),
943 /* MDAP[0] */ PACK( 1, 0 ),
944 /* MDAP[1] */ PACK( 1, 0 ),
946 /* IUP[0] */ PACK( 0, 0 ),
947 /* IUP[1] */ PACK( 0, 0 ),
948 /* SHP[0] */ PACK( 0, 0 ),
949 /* SHP[1] */ PACK( 0, 0 ),
950 /* SHC[0] */ PACK( 1, 0 ),
951 /* SHC[1] */ PACK( 1, 0 ),
952 /* SHZ[0] */ PACK( 1, 0 ),
953 /* SHZ[1] */ PACK( 1, 0 ),
954 /* SHPIX */ PACK( 1, 0 ),
955 /* IP */ PACK( 0, 0 ),
956 /* MSIRP[0] */ PACK( 2, 0 ),
957 /* MSIRP[1] */ PACK( 2, 0 ),
958 /* AlignRP */ PACK( 0, 0 ),
959 /* RTDG */ PACK( 0, 0 ),
960 /* MIAP[0] */ PACK( 2, 0 ),
961 /* MIAP[1] */ PACK( 2, 0 ),
963 /* NPushB */ PACK( 0, 0 ),
964 /* NPushW */ PACK( 0, 0 ),
965 /* WS */ PACK( 2, 0 ),
966 /* RS */ PACK( 1, 1 ),
967 /* WCvtP */ PACK( 2, 0 ),
968 /* RCvt */ PACK( 1, 1 ),
969 /* GC[0] */ PACK( 1, 1 ),
970 /* GC[1] */ PACK( 1, 1 ),
971 /* SCFS */ PACK( 2, 0 ),
972 /* MD[0] */ PACK( 2, 1 ),
973 /* MD[1] */ PACK( 2, 1 ),
974 /* MPPEM */ PACK( 0, 1 ),
975 /* MPS */ PACK( 0, 1 ),
976 /* FlipON */ PACK( 0, 0 ),
977 /* FlipOFF */ PACK( 0, 0 ),
978 /* DEBUG */ PACK( 1, 0 ),
980 /* LT */ PACK( 2, 1 ),
981 /* LTEQ */ PACK( 2, 1 ),
982 /* GT */ PACK( 2, 1 ),
983 /* GTEQ */ PACK( 2, 1 ),
984 /* EQ */ PACK( 2, 1 ),
985 /* NEQ */ PACK( 2, 1 ),
986 /* ODD */ PACK( 1, 1 ),
987 /* EVEN */ PACK( 1, 1 ),
988 /* IF */ PACK( 1, 0 ),
989 /* EIF */ PACK( 0, 0 ),
990 /* AND */ PACK( 2, 1 ),
991 /* OR */ PACK( 2, 1 ),
992 /* NOT */ PACK( 1, 1 ),
993 /* DeltaP1 */ PACK( 1, 0 ),
994 /* SDB */ PACK( 1, 0 ),
995 /* SDS */ PACK( 1, 0 ),
997 /* ADD */ PACK( 2, 1 ),
998 /* SUB */ PACK( 2, 1 ),
999 /* DIV */ PACK( 2, 1 ),
1000 /* MUL */ PACK( 2, 1 ),
1001 /* ABS */ PACK( 1, 1 ),
1002 /* NEG */ PACK( 1, 1 ),
1003 /* FLOOR */ PACK( 1, 1 ),
1004 /* CEILING */ PACK( 1, 1 ),
1005 /* ROUND[0] */ PACK( 1, 1 ),
1006 /* ROUND[1] */ PACK( 1, 1 ),
1007 /* ROUND[2] */ PACK( 1, 1 ),
1008 /* ROUND[3] */ PACK( 1, 1 ),
1009 /* NROUND[0] */ PACK( 1, 1 ),
1010 /* NROUND[1] */ PACK( 1, 1 ),
1011 /* NROUND[2] */ PACK( 1, 1 ),
1012 /* NROUND[3] */ PACK( 1, 1 ),
1014 /* WCvtF */ PACK( 2, 0 ),
1015 /* DeltaP2 */ PACK( 1, 0 ),
1016 /* DeltaP3 */ PACK( 1, 0 ),
1017 /* DeltaCn[0] */ PACK( 1, 0 ),
1018 /* DeltaCn[1] */ PACK( 1, 0 ),
1019 /* DeltaCn[2] */ PACK( 1, 0 ),
1020 /* SROUND */ PACK( 1, 0 ),
1021 /* S45Round */ PACK( 1, 0 ),
1022 /* JROT */ PACK( 2, 0 ),
1023 /* JROF */ PACK( 2, 0 ),
1024 /* ROFF */ PACK( 0, 0 ),
1025 /* INS_$7B */ PACK( 0, 0 ),
1026 /* RUTG */ PACK( 0, 0 ),
1027 /* RDTG */ PACK( 0, 0 ),
1028 /* SANGW */ PACK( 1, 0 ),
1029 /* AA */ PACK( 1, 0 ),
1031 /* FlipPT */ PACK( 0, 0 ),
1032 /* FlipRgON */ PACK( 2, 0 ),
1033 /* FlipRgOFF */ PACK( 2, 0 ),
1034 /* INS_$83 */ PACK( 0, 0 ),
1035 /* INS_$84 */ PACK( 0, 0 ),
1036 /* ScanCTRL */ PACK( 1, 0 ),
1037 /* SDVPTL[0] */ PACK( 2, 0 ),
1038 /* SDVPTL[1] */ PACK( 2, 0 ),
1039 /* GetINFO */ PACK( 1, 1 ),
1040 /* IDEF */ PACK( 1, 0 ),
1041 /* ROLL */ PACK( 3, 3 ),
1042 /* MAX */ PACK( 2, 1 ),
1043 /* MIN */ PACK( 2, 1 ),
1044 /* ScanTYPE */ PACK( 1, 0 ),
1045 /* InstCTRL */ PACK( 2, 0 ),
1046 /* INS_$8F */ PACK( 0, 0 ),
1048 /* INS_$90 */ PACK( 0, 0 ),
1049 /* INS_$91 */ PACK( 0, 0 ),
1050 /* INS_$92 */ PACK( 0, 0 ),
1051 /* INS_$93 */ PACK( 0, 0 ),
1052 /* INS_$94 */ PACK( 0, 0 ),
1053 /* INS_$95 */ PACK( 0, 0 ),
1054 /* INS_$96 */ PACK( 0, 0 ),
1055 /* INS_$97 */ PACK( 0, 0 ),
1056 /* INS_$98 */ PACK( 0, 0 ),
1057 /* INS_$99 */ PACK( 0, 0 ),
1058 /* INS_$9A */ PACK( 0, 0 ),
1059 /* INS_$9B */ PACK( 0, 0 ),
1060 /* INS_$9C */ PACK( 0, 0 ),
1061 /* INS_$9D */ PACK( 0, 0 ),
1062 /* INS_$9E */ PACK( 0, 0 ),
1063 /* INS_$9F */ PACK( 0, 0 ),
1065 /* INS_$A0 */ PACK( 0, 0 ),
1066 /* INS_$A1 */ PACK( 0, 0 ),
1067 /* INS_$A2 */ PACK( 0, 0 ),
1068 /* INS_$A3 */ PACK( 0, 0 ),
1069 /* INS_$A4 */ PACK( 0, 0 ),
1070 /* INS_$A5 */ PACK( 0, 0 ),
1071 /* INS_$A6 */ PACK( 0, 0 ),
1072 /* INS_$A7 */ PACK( 0, 0 ),
1073 /* INS_$A8 */ PACK( 0, 0 ),
1074 /* INS_$A9 */ PACK( 0, 0 ),
1075 /* INS_$AA */ PACK( 0, 0 ),
1076 /* INS_$AB */ PACK( 0, 0 ),
1077 /* INS_$AC */ PACK( 0, 0 ),
1078 /* INS_$AD */ PACK( 0, 0 ),
1079 /* INS_$AE */ PACK( 0, 0 ),
1080 /* INS_$AF */ PACK( 0, 0 ),
1082 /* PushB[0] */ PACK( 0, 1 ),
1083 /* PushB[1] */ PACK( 0, 2 ),
1084 /* PushB[2] */ PACK( 0, 3 ),
1085 /* PushB[3] */ PACK( 0, 4 ),
1086 /* PushB[4] */ PACK( 0, 5 ),
1087 /* PushB[5] */ PACK( 0, 6 ),
1088 /* PushB[6] */ PACK( 0, 7 ),
1089 /* PushB[7] */ PACK( 0, 8 ),
1090 /* PushW[0] */ PACK( 0, 1 ),
1091 /* PushW[1] */ PACK( 0, 2 ),
1092 /* PushW[2] */ PACK( 0, 3 ),
1093 /* PushW[3] */ PACK( 0, 4 ),
1094 /* PushW[4] */ PACK( 0, 5 ),
1095 /* PushW[5] */ PACK( 0, 6 ),
1096 /* PushW[6] */ PACK( 0, 7 ),
1097 /* PushW[7] */ PACK( 0, 8 ),
1099 /* MDRP[00] */ PACK( 1, 0 ),
1100 /* MDRP[01] */ PACK( 1, 0 ),
1101 /* MDRP[02] */ PACK( 1, 0 ),
1102 /* MDRP[03] */ PACK( 1, 0 ),
1103 /* MDRP[04] */ PACK( 1, 0 ),
1104 /* MDRP[05] */ PACK( 1, 0 ),
1105 /* MDRP[06] */ PACK( 1, 0 ),
1106 /* MDRP[07] */ PACK( 1, 0 ),
1107 /* MDRP[08] */ PACK( 1, 0 ),
1108 /* MDRP[09] */ PACK( 1, 0 ),
1109 /* MDRP[10] */ PACK( 1, 0 ),
1110 /* MDRP[11] */ PACK( 1, 0 ),
1111 /* MDRP[12] */ PACK( 1, 0 ),
1112 /* MDRP[13] */ PACK( 1, 0 ),
1113 /* MDRP[14] */ PACK( 1, 0 ),
1114 /* MDRP[15] */ PACK( 1, 0 ),
1116 /* MDRP[16] */ PACK( 1, 0 ),
1117 /* MDRP[17] */ PACK( 1, 0 ),
1118 /* MDRP[18] */ PACK( 1, 0 ),
1119 /* MDRP[19] */ PACK( 1, 0 ),
1120 /* MDRP[20] */ PACK( 1, 0 ),
1121 /* MDRP[21] */ PACK( 1, 0 ),
1122 /* MDRP[22] */ PACK( 1, 0 ),
1123 /* MDRP[23] */ PACK( 1, 0 ),
1124 /* MDRP[24] */ PACK( 1, 0 ),
1125 /* MDRP[25] */ PACK( 1, 0 ),
1126 /* MDRP[26] */ PACK( 1, 0 ),
1127 /* MDRP[27] */ PACK( 1, 0 ),
1128 /* MDRP[28] */ PACK( 1, 0 ),
1129 /* MDRP[29] */ PACK( 1, 0 ),
1130 /* MDRP[30] */ PACK( 1, 0 ),
1131 /* MDRP[31] */ PACK( 1, 0 ),
1133 /* MIRP[00] */ PACK( 2, 0 ),
1134 /* MIRP[01] */ PACK( 2, 0 ),
1135 /* MIRP[02] */ PACK( 2, 0 ),
1136 /* MIRP[03] */ PACK( 2, 0 ),
1137 /* MIRP[04] */ PACK( 2, 0 ),
1138 /* MIRP[05] */ PACK( 2, 0 ),
1139 /* MIRP[06] */ PACK( 2, 0 ),
1140 /* MIRP[07] */ PACK( 2, 0 ),
1141 /* MIRP[08] */ PACK( 2, 0 ),
1142 /* MIRP[09] */ PACK( 2, 0 ),
1143 /* MIRP[10] */ PACK( 2, 0 ),
1144 /* MIRP[11] */ PACK( 2, 0 ),
1145 /* MIRP[12] */ PACK( 2, 0 ),
1146 /* MIRP[13] */ PACK( 2, 0 ),
1147 /* MIRP[14] */ PACK( 2, 0 ),
1148 /* MIRP[15] */ PACK( 2, 0 ),
1150 /* MIRP[16] */ PACK( 2, 0 ),
1151 /* MIRP[17] */ PACK( 2, 0 ),
1152 /* MIRP[18] */ PACK( 2, 0 ),
1153 /* MIRP[19] */ PACK( 2, 0 ),
1154 /* MIRP[20] */ PACK( 2, 0 ),
1155 /* MIRP[21] */ PACK( 2, 0 ),
1156 /* MIRP[22] */ PACK( 2, 0 ),
1157 /* MIRP[23] */ PACK( 2, 0 ),
1158 /* MIRP[24] */ PACK( 2, 0 ),
1159 /* MIRP[25] */ PACK( 2, 0 ),
1160 /* MIRP[26] */ PACK( 2, 0 ),
1161 /* MIRP[27] */ PACK( 2, 0 ),
1162 /* MIRP[28] */ PACK( 2, 0 ),
1163 /* MIRP[29] */ PACK( 2, 0 ),
1164 /* MIRP[30] */ PACK( 2, 0 ),
1165 /* MIRP[31] */ PACK( 2, 0 )
1166 };
1169 static
1170 const FT_Char opcode_length[256] =
1171 {
1172 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1173 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1174 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1175 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1177 -1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1178 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1179 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1180 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1182 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1183 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1184 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1185 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
1187 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1188 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1189 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1190 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1191 };
1193 static
1194 const FT_Vector Null_Vector = {0,0};
1197 #undef PACK
1200 #undef NULL_Vector
1201 #define NULL_Vector (FT_Vector*)&Null_Vector
1204 /*************************************************************************/
1205 /* */
1206 /* <Function> */
1207 /* Current_Ratio */
1208 /* */
1209 /* <Description> */
1210 /* Returns the current aspect ratio scaling factor depending on the */
1211 /* projection vector's state and device resolutions. */
1212 /* */
1213 /* <Return> */
1214 /* The aspect ratio in 16.16 format, always <= 1.0 . */
1215 /* */
1216 static FT_Long
1217 Current_Ratio( EXEC_OP )
1218 {
1219 if ( CUR.tt_metrics.ratio )
1220 return CUR.tt_metrics.ratio;
1222 if ( CUR.GS.projVector.y == 0 )
1223 CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
1225 else if ( CUR.GS.projVector.x == 0 )
1226 CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
1228 else
1229 {
1230 FT_Long x, y;
1232 x = TT_MULDIV( CUR.GS.projVector.x, CUR.tt_metrics.x_ratio, 0x4000 );
1233 y = TT_MULDIV( CUR.GS.projVector.y, CUR.tt_metrics.y_ratio, 0x4000 );
1234 CUR.tt_metrics.ratio = Norm( x, y );
1235 }
1237 return CUR.tt_metrics.ratio;
1238 }
1241 static FT_Long
1242 Current_Ppem( EXEC_OP )
1243 {
1244 return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );
1245 }
1248 /*************************************************************************/
1249 /* */
1250 /* Functions related to the control value table (CVT). */
1251 /* */
1252 /*************************************************************************/
1255 FT_CALLBACK_DEF( FT_F26Dot6 )
1256 Read_CVT( EXEC_OP_ FT_ULong index )
1257 {
1258 return CUR.cvt[index];
1259 }
1262 FT_CALLBACK_DEF( FT_F26Dot6 )
1263 Read_CVT_Stretched( EXEC_OP_ FT_ULong index )
1264 {
1265 return TT_MULFIX( CUR.cvt[index], CURRENT_Ratio() );
1266 }
1269 FT_CALLBACK_DEF( void )
1270 Write_CVT( EXEC_OP_ FT_ULong index,
1271 FT_F26Dot6 value )
1272 {
1273 CUR.cvt[index] = value;
1274 }
1277 FT_CALLBACK_DEF( void )
1278 Write_CVT_Stretched( EXEC_OP_ FT_ULong index,
1279 FT_F26Dot6 value )
1280 {
1281 CUR.cvt[index] = FT_DivFix( value, CURRENT_Ratio() );
1282 }
1285 FT_CALLBACK_DEF( void )
1286 Move_CVT( EXEC_OP_ FT_ULong index,
1287 FT_F26Dot6 value )
1288 {
1289 CUR.cvt[index] += value;
1290 }
1293 FT_CALLBACK_DEF( void )
1294 Move_CVT_Stretched( EXEC_OP_ FT_ULong index,
1295 FT_F26Dot6 value )
1296 {
1297 CUR.cvt[index] += FT_DivFix( value, CURRENT_Ratio() );
1298 }
1301 /*************************************************************************/
1302 /* */
1303 /* <Function> */
1304 /* GetShortIns */
1305 /* */
1306 /* <Description> */
1307 /* Returns a short integer taken from the instruction stream at */
1308 /* address IP. */
1309 /* */
1310 /* <Return> */
1311 /* Short read at code[IP]. */
1312 /* */
1313 /* <Note> */
1314 /* This one could become a macro. */
1315 /* */
1316 static FT_Short
1317 GetShortIns( EXEC_OP )
1318 {
1319 /* Reading a byte stream so there is no endianess (DaveP) */
1320 CUR.IP += 2;
1321 return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) +
1322 CUR.code[CUR.IP - 1] );
1323 }
1326 /*************************************************************************/
1327 /* */
1328 /* <Function> */
1329 /* Ins_Goto_CodeRange */
1330 /* */
1331 /* <Description> */
1332 /* Goes to a certain code range in the instruction stream. */
1333 /* */
1334 /* <Input> */
1335 /* aRange :: The index of the code range. */
1336 /* */
1337 /* aIP :: The new IP address in the code range. */
1338 /* */
1339 /* <Return> */
1340 /* SUCCESS or FAILURE. */
1341 /* */
1342 static FT_Bool
1343 Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange,
1344 FT_ULong aIP )
1345 {
1346 TT_CodeRange* range;
1349 if ( aRange < 1 || aRange > 3 )
1350 {
1351 CUR.error = TT_Err_Bad_Argument;
1352 return FAILURE;
1353 }
1355 range = &CUR.codeRangeTable[aRange - 1];
1357 if ( range->base == NULL ) /* invalid coderange */
1358 {
1359 CUR.error = TT_Err_Invalid_CodeRange;
1360 return FAILURE;
1361 }
1363 /* NOTE: Because the last instruction of a program may be a CALL */
1364 /* which will return to the first byte *after* the code */
1365 /* range, we test for AIP <= Size, instead of AIP < Size. */
1367 if ( aIP > range->size )
1368 {
1369 CUR.error = TT_Err_Code_Overflow;
1370 return FAILURE;
1371 }
1373 CUR.code = range->base;
1374 CUR.codeSize = range->size;
1375 CUR.IP = aIP;
1376 CUR.curRange = aRange;
1378 return SUCCESS;
1379 }
1382 /*************************************************************************/
1383 /* */
1384 /* <Function> */
1385 /* Direct_Move */
1386 /* */
1387 /* <Description> */
1388 /* Moves a point by a given distance along the freedom vector. The */
1389 /* point will be `touched'. */
1390 /* */
1391 /* <Input> */
1392 /* point :: The index of the point to move. */
1393 /* */
1394 /* distance :: The distance to apply. */
1395 /* */
1396 /* <InOut> */
1397 /* zone :: The affected glyph zone. */
1398 /* */
1399 static void
1400 Direct_Move( EXEC_OP_ TT_GlyphZone* zone,
1401 FT_UShort point,
1402 FT_F26Dot6 distance )
1403 {
1404 FT_F26Dot6 v;
1407 v = CUR.GS.freeVector.x;
1409 if ( v != 0 )
1410 {
1412 #ifdef NO_APPLE_PATENT
1414 if ( ABS( CUR.F_dot_P ) > APPLE_THRESHOLD )
1415 zone->cur[point].x += distance;
1417 #else
1419 zone->cur[point].x += TT_MULDIV( distance,
1420 v * 0x10000L,
1421 CUR.F_dot_P );
1423 #endif
1425 zone->tags[point] |= FT_Curve_Tag_Touch_X;
1426 }
1428 v = CUR.GS.freeVector.y;
1430 if ( v != 0 )
1431 {
1433 #ifdef NO_APPLE_PATENT
1435 if ( ABS( CUR.F_dot_P ) > APPLE_THRESHOLD )
1436 zone->cur[point].y += distance;
1438 #else
1440 zone->cur[point].y += TT_MULDIV( distance,
1441 v * 0x10000L,
1442 CUR.F_dot_P );
1444 #endif
1446 zone->tags[point] |= FT_Curve_Tag_Touch_Y;
1447 }
1448 }
1451 /*************************************************************************/
1452 /* */
1453 /* Special versions of Direct_Move() */
1454 /* */
1455 /* The following versions are used whenever both vectors are both */
1456 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1457 /* */
1458 /*************************************************************************/
1461 static void
1462 Direct_Move_X( EXEC_OP_ TT_GlyphZone* zone,
1463 FT_UShort point,
1464 FT_F26Dot6 distance )
1465 {
1466 FT_UNUSED_EXEC;
1468 zone->cur[point].x += distance;
1469 zone->tags[point] |= FT_Curve_Tag_Touch_X;
1470 }
1473 static void
1474 Direct_Move_Y( EXEC_OP_ TT_GlyphZone* zone,
1475 FT_UShort point,
1476 FT_F26Dot6 distance )
1477 {
1478 FT_UNUSED_EXEC;
1480 zone->cur[point].y += distance;
1481 zone->tags[point] |= FT_Curve_Tag_Touch_Y;
1482 }
1485 /*************************************************************************/
1486 /* */
1487 /* <Function> */
1488 /* Round_None */
1489 /* */
1490 /* <Description> */
1491 /* Does not round, but adds engine compensation. */
1492 /* */
1493 /* <Input> */
1494 /* distance :: The distance (not) to round. */
1495 /* */
1496 /* compensation :: The engine compensation. */
1497 /* */
1498 /* <Return> */
1499 /* The compensated distance. */
1500 /* */
1501 /* <Note> */
1502 /* The TrueType specification says very few about the relationship */
1503 /* between rounding and engine compensation. However, it seems from */
1504 /* the description of super round that we should add the compensation */
1505 /* before rounding. */
1506 /* */
1507 static FT_F26Dot6
1508 Round_None( EXEC_OP_ FT_F26Dot6 distance,
1509 FT_F26Dot6 compensation )
1510 {
1511 FT_F26Dot6 val;
1513 FT_UNUSED_EXEC;
1516 if ( distance >= 0 )
1517 {
1518 val = distance + compensation;
1519 if ( val < 0 )
1520 val = 0;
1521 }
1522 else {
1523 val = distance - compensation;
1524 if ( val > 0 )
1525 val = 0;
1526 }
1527 return val;
1528 }
1531 /*************************************************************************/
1532 /* */
1533 /* <Function> */
1534 /* Round_To_Grid */
1535 /* */
1536 /* <Description> */
1537 /* Rounds value to grid after adding engine compensation. */
1538 /* */
1539 /* <Input> */
1540 /* distance :: The distance to round. */
1541 /* */
1542 /* compensation :: The engine compensation. */
1543 /* */
1544 /* <Return> */
1545 /* Rounded distance. */
1546 /* */
1547 static FT_F26Dot6
1548 Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1549 FT_F26Dot6 compensation )
1550 {
1551 FT_F26Dot6 val;
1553 FT_UNUSED_EXEC;
1556 if ( distance >= 0 )
1557 {
1558 val = distance + compensation + 32;
1559 if ( val > 0 )
1560 val &= ~63;
1561 else
1562 val = 0;
1563 }
1564 else
1565 {
1566 val = -( ( compensation - distance + 32 ) & -64 );
1567 if ( val > 0 )
1568 val = 0;
1569 }
1571 return val;
1572 }
1575 /*************************************************************************/
1576 /* */
1577 /* <Function> */
1578 /* Round_To_Half_Grid */
1579 /* */
1580 /* <Description> */
1581 /* Rounds value to half grid after adding engine compensation. */
1582 /* */
1583 /* <Input> */
1584 /* distance :: The distance to round. */
1585 /* */
1586 /* compensation :: The engine compensation. */
1587 /* */
1588 /* <Return> */
1589 /* Rounded distance. */
1590 /* */
1591 static FT_F26Dot6
1592 Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance,
1593 FT_F26Dot6 compensation )
1594 {
1595 FT_F26Dot6 val;
1597 FT_UNUSED_EXEC;
1600 if ( distance >= 0 )
1601 {
1602 val = ( ( distance + compensation ) & -64 ) + 32;
1603 if ( val < 0 )
1604 val = 0;
1605 }
1606 else
1607 {
1608 val = -( ( (compensation - distance) & -64 ) + 32 );
1609 if ( val > 0 )
1610 val = 0;
1611 }
1613 return val;
1614 }
1617 /*************************************************************************/
1618 /* */
1619 /* <Function> */
1620 /* Round_Down_To_Grid */
1621 /* */
1622 /* <Description> */
1623 /* Rounds value down to grid after adding engine compensation. */
1624 /* */
1625 /* <Input> */
1626 /* distance :: The distance to round. */
1627 /* */
1628 /* compensation :: The engine compensation. */
1629 /* */
1630 /* <Return> */
1631 /* Rounded distance. */
1632 /* */
1633 static FT_F26Dot6
1634 Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1635 FT_F26Dot6 compensation )
1636 {
1637 FT_F26Dot6 val;
1639 FT_UNUSED_EXEC;
1642 if ( distance >= 0 )
1643 {
1644 val = distance + compensation;
1645 if ( val > 0 )
1646 val &= ~63;
1647 else
1648 val = 0;
1649 }
1650 else
1651 {
1652 val = -( ( compensation - distance ) & -64 );
1653 if ( val > 0 )
1654 val = 0;
1655 }
1657 return val;
1658 }
1661 /*************************************************************************/
1662 /* */
1663 /* <Function> */
1664 /* Round_Up_To_Grid */
1665 /* */
1666 /* <Description> */
1667 /* Rounds value up to grid after adding engine compensation. */
1668 /* */
1669 /* <Input> */
1670 /* distance :: The distance to round. */
1671 /* */
1672 /* compensation :: The engine compensation. */
1673 /* */
1674 /* <Return> */
1675 /* Rounded distance. */
1676 /* */
1677 static FT_F26Dot6
1678 Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1679 FT_F26Dot6 compensation )
1680 {
1681 FT_F26Dot6 val;
1684 FT_UNUSED_EXEC;
1686 if ( distance >= 0 )
1687 {
1688 val = distance + compensation + 63;
1689 if ( val > 0 )
1690 val &= ~63;
1691 else
1692 val = 0;
1693 }
1694 else
1695 {
1696 val = -( ( compensation - distance + 63 ) & -64 );
1697 if ( val > 0 )
1698 val = 0;
1699 }
1701 return val;
1702 }
1705 /*************************************************************************/
1706 /* */
1707 /* <Function> */
1708 /* Round_To_Double_Grid */
1709 /* */
1710 /* <Description> */
1711 /* Rounds value to double grid after adding engine compensation. */
1712 /* */
1713 /* <Input> */
1714 /* distance :: The distance to round. */
1715 /* */
1716 /* compensation :: The engine compensation. */
1717 /* */
1718 /* <Return> */
1719 /* Rounded distance. */
1720 /* */
1721 static FT_F26Dot6
1722 Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance,
1723 FT_F26Dot6 compensation )
1724 {
1725 FT_F26Dot6 val;
1727 FT_UNUSED_EXEC;
1730 if ( distance >= 0 )
1731 {
1732 val = distance + compensation + 16;
1733 if ( val > 0 )
1734 val &= ~31;
1735 else
1736 val = 0;
1737 }
1738 else
1739 {
1740 val = -( ( compensation - distance + 16 ) & -32 );
1741 if ( val > 0 )
1742 val = 0;
1743 }
1745 return val;
1746 }
1749 /*************************************************************************/
1750 /* */
1751 /* <Function> */
1752 /* Round_Super */
1753 /* */
1754 /* <Description> */
1755 /* Super-rounds value to grid after adding engine compensation. */
1756 /* */
1757 /* <Input> */
1758 /* distance :: The distance to round. */
1759 /* */
1760 /* compensation :: The engine compensation. */
1761 /* */
1762 /* <Return> */
1763 /* Rounded distance. */
1764 /* */
1765 /* <Note> */
1766 /* The TrueType specification says very few about the relationship */
1767 /* between rounding and engine compensation. However, it seems from */
1768 /* the description of super round that we should add the compensation */
1769 /* before rounding. */
1770 /* */
1771 static FT_F26Dot6
1772 Round_Super( EXEC_OP_ FT_F26Dot6 distance,
1773 FT_F26Dot6 compensation )
1774 {
1775 FT_F26Dot6 val;
1778 if ( distance >= 0 )
1779 {
1780 val = ( distance - CUR.phase + CUR.threshold + compensation ) &
1781 -CUR.period;
1782 if ( val < 0 )
1783 val = 0;
1784 val += CUR.phase;
1785 }
1786 else
1787 {
1788 val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &
1789 -CUR.period );
1790 if ( val > 0 )
1791 val = 0;
1792 val -= CUR.phase;
1793 }
1795 return val;
1796 }
1799 /*************************************************************************/
1800 /* */
1801 /* <Function> */
1802 /* Round_Super_45 */
1803 /* */
1804 /* <Description> */
1805 /* Super-rounds value to grid after adding engine compensation. */
1806 /* */
1807 /* <Input> */
1808 /* distance :: The distance to round. */
1809 /* */
1810 /* compensation :: The engine compensation. */
1811 /* */
1812 /* <Return> */
1813 /* Rounded distance. */
1814 /* */
1815 /* <Note> */
1816 /* There is a separate function for Round_Super_45() as we may need */
1817 /* greater precision. */
1818 /* */
1819 static FT_F26Dot6
1820 Round_Super_45( EXEC_OP_ FT_F26Dot6 distance,
1821 FT_F26Dot6 compensation )
1822 {
1823 FT_F26Dot6 val;
1826 if ( distance >= 0 )
1827 {
1828 val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
1829 CUR.period ) * CUR.period;
1830 if ( val < 0 )
1831 val = 0;
1832 val += CUR.phase;
1833 }
1834 else
1835 {
1836 val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /
1837 CUR.period ) * CUR.period );
1838 if ( val > 0 )
1839 val = 0;
1840 val -= CUR.phase;
1841 }
1843 return val;
1844 }
1847 /*************************************************************************/
1848 /* */
1849 /* <Function> */
1850 /* Compute_Round */
1851 /* */
1852 /* <Description> */
1853 /* Sets the rounding mode. */
1854 /* */
1855 /* <Input> */
1856 /* round_mode :: The rounding mode to be used. */
1857 /* */
1858 static void
1859 Compute_Round( EXEC_OP_ FT_Byte round_mode )
1860 {
1861 switch ( round_mode )
1862 {
1863 case TT_Round_Off:
1864 CUR.func_round = (TT_Round_Func)Round_None;
1865 break;
1867 case TT_Round_To_Grid:
1868 CUR.func_round = (TT_Round_Func)Round_To_Grid;
1869 break;
1871 case TT_Round_Up_To_Grid:
1872 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
1873 break;
1875 case TT_Round_Down_To_Grid:
1876 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
1877 break;
1879 case TT_Round_To_Half_Grid:
1880 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
1881 break;
1883 case TT_Round_To_Double_Grid:
1884 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
1885 break;
1887 case TT_Round_Super:
1888 CUR.func_round = (TT_Round_Func)Round_Super;
1889 break;
1891 case TT_Round_Super_45:
1892 CUR.func_round = (TT_Round_Func)Round_Super_45;
1893 break;
1894 }
1895 }
1898 /*************************************************************************/
1899 /* */
1900 /* <Function> */
1901 /* SetSuperRound */
1902 /* */
1903 /* <Description> */
1904 /* Sets Super Round parameters. */
1905 /* */
1906 /* <Input> */
1907 /* GridPeriod :: Grid period */
1908 /* selector :: SROUND opcode */
1909 /* */
1910 static void
1911 SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod,
1912 FT_Long selector )
1913 {
1914 switch ( (FT_Int)( selector & 0xC0 ) )
1915 {
1916 case 0:
1917 CUR.period = GridPeriod / 2;
1918 break;
1920 case 0x40:
1921 CUR.period = GridPeriod;
1922 break;
1924 case 0x80:
1925 CUR.period = GridPeriod * 2;
1926 break;
1928 /* This opcode is reserved, but... */
1930 case 0xC0:
1931 CUR.period = GridPeriod;
1932 break;
1933 }
1935 switch ( (FT_Int)( selector & 0x30 ) )
1936 {
1937 case 0:
1938 CUR.phase = 0;
1939 break;
1941 case 0x10:
1942 CUR.phase = CUR.period / 4;
1943 break;
1945 case 0x20:
1946 CUR.phase = CUR.period / 2;
1947 break;
1949 case 0x30:
1950 CUR.phase = GridPeriod * 3 / 4;
1951 break;
1952 }
1954 if ( (selector & 0x0F) == 0 )
1955 CUR.threshold = CUR.period - 1;
1956 else
1957 CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8;
1959 CUR.period /= 256;
1960 CUR.phase /= 256;
1961 CUR.threshold /= 256;
1962 }
1965 /*************************************************************************/
1966 /* */
1967 /* <Function> */
1968 /* Project */
1969 /* */
1970 /* <Description> */
1971 /* Computes the projection of vector given by (v2-v1) along the */
1972 /* current projection vector. */
1973 /* */
1974 /* <Input> */
1975 /* v1 :: First input vector. */
1976 /* v2 :: Second input vector. */
1977 /* */
1978 /* <Return> */
1979 /* The distance in F26dot6 format. */
1980 /* */
1981 static FT_F26Dot6
1982 Project( EXEC_OP_ FT_Vector* v1,
1983 FT_Vector* v2 )
1984 {
1985 return TT_MULDIV( v1->x - v2->x, CUR.GS.projVector.x, 0x4000 ) +
1986 TT_MULDIV( v1->y - v2->y, CUR.GS.projVector.y, 0x4000 );
1987 }
1990 /*************************************************************************/
1991 /* */
1992 /* <Function> */
1993 /* Dual_Project */
1994 /* */
1995 /* <Description> */
1996 /* Computes the projection of the vector given by (v2-v1) along the */
1997 /* current dual vector. */
1998 /* */
1999 /* <Input> */
2000 /* v1 :: First input vector. */
2001 /* v2 :: Second input vector. */
2002 /* */
2003 /* <Return> */
2004 /* The distance in F26dot6 format. */
2005 /* */
2006 static FT_F26Dot6
2007 Dual_Project( EXEC_OP_ FT_Vector* v1,
2008 FT_Vector* v2 )
2009 {
2010 return TT_MULDIV( v1->x - v2->x, CUR.GS.dualVector.x, 0x4000 ) +
2011 TT_MULDIV( v1->y - v2->y, CUR.GS.dualVector.y, 0x4000 );
2012 }
2015 /*************************************************************************/
2016 /* */
2017 /* <Function> */
2018 /* Free_Project */
2019 /* */
2020 /* <Description> */
2021 /* Computes the projection of the vector given by (v2-v1) along the */
2022 /* current freedom vector. */
2023 /* */
2024 /* <Input> */
2025 /* v1 :: First input vector. */
2026 /* v2 :: Second input vector. */
2027 /* */
2028 /* <Return> */
2029 /* The distance in F26dot6 format. */
2030 /* */
2031 static FT_F26Dot6
2032 Free_Project( EXEC_OP_ FT_Vector* v1,
2033 FT_Vector* v2 )
2034 {
2035 return TT_MULDIV( v1->x - v2->x, CUR.GS.freeVector.x, 0x4000 ) +
2036 TT_MULDIV( v1->y - v2->y, CUR.GS.freeVector.y, 0x4000 );
2037 }
2040 /*************************************************************************/
2041 /* */
2042 /* <Function> */
2043 /* Project_x */
2044 /* */
2045 /* <Description> */
2046 /* Computes the projection of the vector given by (v2-v1) along the */
2047 /* horizontal axis. */
2048 /* */
2049 /* <Input> */
2050 /* v1 :: First input vector. */
2051 /* v2 :: Second input vector. */
2052 /* */
2053 /* <Return> */
2054 /* The distance in F26dot6 format. */
2055 /* */
2056 static FT_F26Dot6
2057 Project_x( EXEC_OP_ FT_Vector* v1,
2058 FT_Vector* v2 )
2059 {
2060 FT_UNUSED_EXEC;
2062 return ( v1->x - v2->x );
2063 }
2066 /*************************************************************************/
2067 /* */
2068 /* <Function> */
2069 /* Project_y */
2070 /* */
2071 /* <Description> */
2072 /* Computes the projection of the vector given by (v2-v1) along the */
2073 /* vertical axis. */
2074 /* */
2075 /* <Input> */
2076 /* v1 :: First input vector. */
2077 /* v2 :: Second input vector. */
2078 /* */
2079 /* <Return> */
2080 /* The distance in F26dot6 format. */
2081 /* */
2082 static FT_F26Dot6
2083 Project_y( EXEC_OP_ FT_Vector* v1,
2084 FT_Vector* v2 )
2085 {
2086 FT_UNUSED_EXEC;
2088 return ( v1->y - v2->y );
2089 }
2092 /*************************************************************************/
2093 /* */
2094 /* <Function> */
2095 /* Compute_Funcs */
2096 /* */
2097 /* <Description> */
2098 /* Computes the projection and movement function pointers according */
2099 /* to the current graphics state. */
2100 /* */
2101 static void
2102 Compute_Funcs( EXEC_OP )
2103 {
2104 if ( CUR.GS.freeVector.x == 0x4000 )
2105 {
2106 CUR.func_freeProj = (TT_Project_Func)Project_x;
2107 CUR.F_dot_P = CUR.GS.projVector.x * 0x10000L;
2108 }
2109 else
2110 {
2111 if ( CUR.GS.freeVector.y == 0x4000 )
2112 {
2113 CUR.func_freeProj = (TT_Project_Func)Project_y;
2114 CUR.F_dot_P = CUR.GS.projVector.y * 0x10000L;
2115 }
2116 else
2117 {
2118 CUR.func_freeProj = (TT_Project_Func)Free_Project;
2119 CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
2120 (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
2121 }
2122 }
2124 if ( CUR.GS.projVector.x == 0x4000 )
2125 CUR.func_project = (TT_Project_Func)Project_x;
2126 else
2127 {
2128 if ( CUR.GS.projVector.y == 0x4000 )
2129 CUR.func_project = (TT_Project_Func)Project_y;
2130 else
2131 CUR.func_project = (TT_Project_Func)Project;
2132 }
2134 if ( CUR.GS.dualVector.x == 0x4000 )
2135 CUR.func_dualproj = (TT_Project_Func)Project_x;
2136 else
2137 {
2138 if ( CUR.GS.dualVector.y == 0x4000 )
2139 CUR.func_dualproj = (TT_Project_Func)Project_y;
2140 else
2141 CUR.func_dualproj = (TT_Project_Func)Dual_Project;
2142 }
2144 CUR.func_move = (TT_Move_Func)Direct_Move;
2146 if ( CUR.F_dot_P == 0x40000000L )
2147 {
2148 if ( CUR.GS.freeVector.x == 0x4000 )
2149 CUR.func_move = (TT_Move_Func)Direct_Move_X;
2150 else
2151 {
2152 if ( CUR.GS.freeVector.y == 0x4000 )
2153 CUR.func_move = (TT_Move_Func)Direct_Move_Y;
2154 }
2155 }
2157 /* at small sizes, F_dot_P can become too small, resulting */
2158 /* in overflows and `spikes' in a number of glyphs like `w'. */
2160 if ( ABS( CUR.F_dot_P ) < 0x4000000L )
2161 CUR.F_dot_P = 0x40000000L;
2163 /* Disable cached aspect ratio */
2164 CUR.tt_metrics.ratio = 0;
2165 }
2168 /*************************************************************************/
2169 /* */
2170 /* <Function> */
2171 /* Normalize */
2172 /* */
2173 /* <Description> */
2174 /* Norms a vector. */
2175 /* */
2176 /* <Input> */
2177 /* Vx :: The horizontal input vector coordinate. */
2178 /* Vy :: The vertical input vector coordinate. */
2179 /* */
2180 /* <Output> */
2181 /* R :: The normed unit vector. */
2182 /* */
2183 /* <Return> */
2184 /* Returns FAILURE if a vector parameter is zero. */
2185 /* */
2186 /* <Note> */
2187 /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
2188 /* R is undefined. */
2189 /* */
2191 #ifdef FT_CONFIG_OPTION_OLD_CALCS
2193 static FT_Bool
2194 Normalize( EXEC_OP_ FT_F26Dot6 Vx,
2195 FT_F26Dot6 Vy,
2196 FT_UnitVector* R )
2197 {
2198 FT_F26Dot6 W;
2199 FT_Bool S1, S2;
2201 FT_UNUSED_EXEC;
2204 if ( ABS( Vx ) < 0x10000L && ABS( Vy ) < 0x10000L )
2205 {
2206 Vx *= 0x100;
2207 Vy *= 0x100;
2209 W = Norm( Vx, Vy );
2211 if ( W == 0 )
2212 {
2213 /* XXX: UNDOCUMENTED! It seems that it is possible to try */
2214 /* to normalize the vector (0,0). Return immediately. */
2215 return SUCCESS;
2216 }
2218 R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W );
2219 R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W );
2221 return SUCCESS;
2222 }
2224 W = Norm( Vx, Vy );
2226 Vx = FT_MulDiv( Vx, 0x4000L, W );
2227 Vy = FT_MulDiv( Vy, 0x4000L, W );
2229 W = Vx * Vx + Vy * Vy;
2231 /* Now, we want that Sqrt( W ) = 0x4000 */
2232 /* Or 0x1000000 <= W < 0x1004000 */
2234 if ( Vx < 0 )
2235 {
2236 Vx = -Vx;
2237 S1 = TRUE;
2238 }
2239 else
2240 S1 = FALSE;
2242 if ( Vy < 0 )
2243 {
2244 Vy = -Vy;
2245 S2 = TRUE;
2246 }
2247 else
2248 S2 = FALSE;
2250 while ( W < 0x1000000L )
2251 {
2252 /* We need to increase W by a minimal amount */
2253 if ( Vx < Vy )
2254 Vx++;
2255 else
2256 Vy++;
2258 W = Vx * Vx + Vy * Vy;
2259 }
2261 while ( W >= 0x1004000L )
2262 {
2263 /* We need to decrease W by a minimal amount */
2264 if ( Vx < Vy )
2265 Vx--;
2266 else
2267 Vy--;
2269 W = Vx * Vx + Vy * Vy;
2270 }
2272 /* Note that in various cases, we can only */
2273 /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
2275 if ( S1 )
2276 Vx = -Vx;
2278 if ( S2 )
2279 Vy = -Vy;
2281 R->x = (FT_F2Dot14)Vx; /* Type conversion */
2282 R->y = (FT_F2Dot14)Vy; /* Type conversion */
2284 return SUCCESS;
2285 }
2287 #else
2289 static FT_Bool
2290 Normalize( EXEC_OP_ FT_F26Dot6 Vx,
2291 FT_F26Dot6 Vy,
2292 FT_UnitVector* R )
2293 {
2294 FT_Vector v;
2295 FT_Angle angle;
2297 FT_UNUSED_EXEC;
2299 angle = FT_Atan2( Vx, Vy );
2301 FT_Vector_Unit( &v, angle );
2303 R->x = (short)(v.x >> 2);
2304 R->y = (short)(v.y >> 2);
2306 return SUCCESS;
2307 }
2309 #endif /* FT_CONFIG_OPTION_OLD_CALCS */
2312 /*************************************************************************/
2313 /* */
2314 /* Here we start with the implementation of the various opcodes. */
2315 /* */
2316 /*************************************************************************/
2319 static FT_Bool
2320 Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1,
2321 FT_UShort aIdx2,
2322 FT_Int aOpc,
2323 FT_UnitVector* Vec )
2324 {
2325 FT_Long A, B, C;
2326 FT_Vector* p1;
2327 FT_Vector* p2;
2330 if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
2331 BOUNDS( aIdx2, CUR.zp1.n_points ) )
2332 {
2333 if ( CUR.pedantic_hinting )
2334 CUR.error = TT_Err_Invalid_Reference;
2335 return FAILURE;
2336 }
2338 p1 = CUR.zp1.cur + aIdx2;
2339 p2 = CUR.zp2.cur + aIdx1;
2341 A = p1->x - p2->x;
2342 B = p1->y - p2->y;
2344 if ( ( aOpc & 1 ) != 0 )
2345 {
2346 C = B; /* counter clockwise rotation */
2347 B = A;
2348 A = -C;
2349 }
2351 NORMalize( A, B, Vec );
2353 return SUCCESS;
2354 }
2357 /* When not using the big switch statements, the interpreter uses a */
2358 /* call table defined later below in this source. Each opcode must */
2359 /* thus have a corresponding function, even trivial ones. */
2360 /* */
2361 /* They are all defined there. */
2363 #define DO_SVTCA \
2364 { \
2365 FT_Short A, B; \
2366 \
2367 \
2368 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2369 B = A ^ (FT_Short)0x4000; \
2370 \
2371 CUR.GS.freeVector.x = A; \
2372 CUR.GS.projVector.x = A; \
2373 CUR.GS.dualVector.x = A; \
2374 \
2375 CUR.GS.freeVector.y = B; \
2376 CUR.GS.projVector.y = B; \
2377 CUR.GS.dualVector.y = B; \
2378 \
2379 COMPUTE_Funcs(); \
2380 }
2383 #define DO_SPVTCA \
2384 { \
2385 FT_Short A, B; \
2386 \
2387 \
2388 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2389 B = A ^ (FT_Short)0x4000; \
2390 \
2391 CUR.GS.projVector.x = A; \
2392 CUR.GS.dualVector.x = A; \
2393 \
2394 CUR.GS.projVector.y = B; \
2395 CUR.GS.dualVector.y = B; \
2396 \
2397 COMPUTE_Funcs(); \
2398 }
2401 #define DO_SFVTCA \
2402 { \
2403 FT_Short A, B; \
2404 \
2405 \
2406 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2407 B = A ^ (FT_Short)0x4000; \
2408 \
2409 CUR.GS.freeVector.x = A; \
2410 CUR.GS.freeVector.y = B; \
2411 \
2412 COMPUTE_Funcs(); \
2413 }
2416 #define DO_SPVTL \
2417 if ( INS_SxVTL( (FT_UShort)args[1], \
2418 (FT_UShort)args[0], \
2419 CUR.opcode, \
2420 &CUR.GS.projVector ) == SUCCESS ) \
2421 { \
2422 CUR.GS.dualVector = CUR.GS.projVector; \
2423 COMPUTE_Funcs(); \
2424 }
2427 #define DO_SFVTL \
2428 if ( INS_SxVTL( (FT_UShort)args[1], \
2429 (FT_UShort)args[0], \
2430 CUR.opcode, \
2431 &CUR.GS.freeVector ) == SUCCESS ) \
2432 COMPUTE_Funcs();
2435 #define DO_SFVTPV \
2436 CUR.GS.freeVector = CUR.GS.projVector; \
2437 COMPUTE_Funcs();
2440 #define DO_SPVFS \
2441 { \
2442 FT_Short S; \
2443 FT_Long X, Y; \
2444 \
2445 \
2446 /* Only use low 16bits, then sign extend */ \
2447 S = (FT_Short)args[1]; \
2448 Y = (FT_Long)S; \
2449 S = (FT_Short)args[0]; \
2450 X = (FT_Long)S; \
2451 \
2452 NORMalize( X, Y, &CUR.GS.projVector ); \
2453 \
2454 CUR.GS.dualVector = CUR.GS.projVector; \
2455 COMPUTE_Funcs(); \
2456 }
2459 #define DO_SFVFS \
2460 { \
2461 FT_Short S; \
2462 FT_Long X, Y; \
2463 \
2464 \
2465 /* Only use low 16bits, then sign extend */ \
2466 S = (FT_Short)args[1]; \
2467 Y = (FT_Long)S; \
2468 S = (FT_Short)args[0]; \
2469 X = S; \
2470 \
2471 NORMalize( X, Y, &CUR.GS.freeVector ); \
2472 COMPUTE_Funcs(); \
2473 }
2476 #define DO_GPV \
2477 args[0] = CUR.GS.projVector.x; \
2478 args[1] = CUR.GS.projVector.y;
2481 #define DO_GFV \
2482 args[0] = CUR.GS.freeVector.x; \
2483 args[1] = CUR.GS.freeVector.y;
2486 #define DO_SRP0 \
2487 CUR.GS.rp0 = (FT_UShort)args[0];
2490 #define DO_SRP1 \
2491 CUR.GS.rp1 = (FT_UShort)args[0];
2494 #define DO_SRP2 \
2495 CUR.GS.rp2 = (FT_UShort)args[0];
2498 #define DO_RTHG \
2499 CUR.GS.round_state = TT_Round_To_Half_Grid; \
2500 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2503 #define DO_RTG \
2504 CUR.GS.round_state = TT_Round_To_Grid; \
2505 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2508 #define DO_RTDG \
2509 CUR.GS.round_state = TT_Round_To_Double_Grid; \
2510 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2513 #define DO_RUTG \
2514 CUR.GS.round_state = TT_Round_Up_To_Grid; \
2515 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2518 #define DO_RDTG \
2519 CUR.GS.round_state = TT_Round_Down_To_Grid; \
2520 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2523 #define DO_ROFF \
2524 CUR.GS.round_state = TT_Round_Off; \
2525 CUR.func_round = (TT_Round_Func)Round_None;
2528 #define DO_SROUND \
2529 SET_SuperRound( 0x4000, args[0] ); \
2530 CUR.GS.round_state = TT_Round_Super; \
2531 CUR.func_round = (TT_Round_Func)Round_Super;
2534 #define DO_S45ROUND \
2535 SET_SuperRound( 0x2D41, args[0] ); \
2536 CUR.GS.round_state = TT_Round_Super_45; \
2537 CUR.func_round = (TT_Round_Func)Round_Super_45;
2540 #define DO_SLOOP \
2541 if ( args[0] < 0 ) \
2542 CUR.error = TT_Err_Bad_Argument; \
2543 else \
2544 CUR.GS.loop = args[0];
2547 #define DO_SMD \
2548 CUR.GS.minimum_distance = args[0];
2551 #define DO_SCVTCI \
2552 CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
2555 #define DO_SSWCI \
2556 CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
2559 /* XXX: UNDOCUMENTED! or bug in the Windows engine? */
2560 /* */
2561 /* It seems that the value that is read here is */
2562 /* expressed in 16.16 format rather than in font */
2563 /* units. */
2564 /* */
2565 #define DO_SSW \
2566 CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
2569 #define DO_FLIPON \
2570 CUR.GS.auto_flip = TRUE;
2573 #define DO_FLIPOFF \
2574 CUR.GS.auto_flip = FALSE;
2577 #define DO_SDB \
2578 CUR.GS.delta_base = (FT_Short)args[0];
2581 #define DO_SDS \
2582 CUR.GS.delta_shift = (FT_Short)args[0];
2585 #define DO_MD /* nothing */
2588 #define DO_MPPEM \
2589 args[0] = CURRENT_Ppem();
2592 /* Note: The pointSize should be irrelevant in a given font program; */
2593 /* we thus decide to return only the ppem. */
2594 #if 0
2596 #define DO_MPS \
2597 args[0] = CUR.metrics.pointSize;
2599 #else
2601 #define DO_MPS \
2602 args[0] = CURRENT_Ppem();
2604 #endif /* 0 */
2607 #define DO_DUP \
2608 args[1] = args[0];
2611 #define DO_CLEAR \
2612 CUR.new_top = 0;
2615 #define DO_SWAP \
2616 { \
2617 FT_Long L; \
2618 \
2619 \
2620 L = args[0]; \
2621 args[0] = args[1]; \
2622 args[1] = L; \
2623 }
2626 #define DO_DEPTH \
2627 args[0] = CUR.top;
2630 #define DO_CINDEX \
2631 { \
2632 FT_Long L; \
2633 \
2634 \
2635 L = args[0]; \
2636 \
2637 if ( L <= 0 || L > CUR.args ) \
2638 CUR.error = TT_Err_Invalid_Reference; \
2639 else \
2640 args[0] = CUR.stack[CUR.args - L]; \
2641 }
2644 #define DO_JROT \
2645 if ( args[1] != 0 ) \
2646 { \
2647 CUR.IP += args[0]; \
2648 CUR.step_ins = FALSE; \
2649 }
2652 #define DO_JMPR \
2653 CUR.IP += args[0]; \
2654 CUR.step_ins = FALSE;
2657 #define DO_JROF \
2658 if ( args[1] == 0 ) \
2659 { \
2660 CUR.IP += args[0]; \
2661 CUR.step_ins = FALSE; \
2662 }
2665 #define DO_LT \
2666 args[0] = ( args[0] < args[1] );
2669 #define DO_LTEQ \
2670 args[0] = ( args[0] <= args[1] );
2673 #define DO_GT \
2674 args[0] = ( args[0] > args[1] );
2677 #define DO_GTEQ \
2678 args[0] = ( args[0] >= args[1] );
2681 #define DO_EQ \
2682 args[0] = ( args[0] == args[1] );
2685 #define DO_NEQ \
2686 args[0] = ( args[0] != args[1] );
2689 #define DO_ODD \
2690 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
2693 #define DO_EVEN \
2694 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
2697 #define DO_AND \
2698 args[0] = ( args[0] && args[1] );
2701 #define DO_OR \
2702 args[0] = ( args[0] || args[1] );
2705 #define DO_NOT \
2706 args[0] = !args[0];
2709 #define DO_ADD \
2710 args[0] += args[1];
2713 #define DO_SUB \
2714 args[0] -= args[1];
2717 #define DO_DIV \
2718 if ( args[1] == 0 ) \
2719 CUR.error = TT_Err_Divide_By_Zero; \
2720 else \
2721 args[0] = TT_MULDIV( args[0], 64L, args[1] );
2724 #define DO_MUL \
2725 args[0] = TT_MULDIV( args[0], args[1], 64L );
2728 #define DO_ABS \
2729 args[0] = ABS( args[0] );
2732 #define DO_NEG \
2733 args[0] = -args[0];
2736 #define DO_FLOOR \
2737 args[0] &= -64;
2740 #define DO_CEILING \
2741 args[0] = ( args[0] + 63 ) & -64;
2744 #define DO_RS \
2745 { \
2746 FT_ULong I = (FT_ULong)args[0]; \
2747 \
2748 \
2749 if ( BOUNDS( I, CUR.storeSize ) ) \
2750 { \
2751 if ( CUR.pedantic_hinting ) \
2752 { \
2753 ARRAY_BOUND_ERROR; \
2754 } \
2755 else \
2756 args[0] = 0; \
2757 } \
2758 else \
2759 args[0] = CUR.storage[I]; \
2760 }
2763 #define DO_WS \
2764 { \
2765 FT_ULong I = (FT_ULong)args[0]; \
2766 \
2767 \
2768 if ( BOUNDS( I, CUR.storeSize ) ) \
2769 { \
2770 if ( CUR.pedantic_hinting ) \
2771 { \
2772 ARRAY_BOUND_ERROR; \
2773 } \
2774 } \
2775 else \
2776 CUR.storage[I] = args[1]; \
2777 }
2780 #define DO_RCVT \
2781 { \
2782 FT_ULong I = (FT_ULong)args[0]; \
2783 \
2784 \
2785 if ( BOUNDS( I, CUR.cvtSize ) ) \
2786 { \
2787 if ( CUR.pedantic_hinting ) \
2788 { \
2789 ARRAY_BOUND_ERROR; \
2790 } \
2791 else \
2792 args[0] = 0; \
2793 } \
2794 else \
2795 args[0] = CUR_Func_read_cvt( I ); \
2796 }
2799 #define DO_WCVTP \
2800 { \
2801 FT_ULong I = (FT_ULong)args[0]; \
2802 \
2803 \
2804 if ( BOUNDS( I, CUR.cvtSize ) ) \
2805 { \
2806 if ( CUR.pedantic_hinting ) \
2807 { \
2808 ARRAY_BOUND_ERROR; \
2809 } \
2810 } \
2811 else \
2812 CUR_Func_write_cvt( I, args[1] ); \
2813 }
2816 #define DO_WCVTF \
2817 { \
2818 FT_ULong I = (FT_ULong)args[0]; \
2819 \
2820 \
2821 if ( BOUNDS( I, CUR.cvtSize ) ) \
2822 { \
2823 if ( CUR.pedantic_hinting ) \
2824 { \
2825 ARRAY_BOUND_ERROR; \
2826 } \
2827 } \
2828 else \
2829 CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
2830 }
2833 #define DO_DEBUG \
2834 CUR.error = TT_Err_Debug_OpCode;
2837 #define DO_ROUND \
2838 args[0] = CUR_Func_round( \
2839 args[0], \
2840 CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
2843 #define DO_NROUND \
2844 args[0] = ROUND_None( args[0], \
2845 CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
2848 #define DO_MAX \
2849 if ( args[1] > args[0] ) \
2850 args[0] = args[1];
2853 #define DO_MIN \
2854 if ( args[1] < args[0] ) \
2855 args[0] = args[1];
2858 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
2861 #undef ARRAY_BOUND_ERROR
2862 #define ARRAY_BOUND_ERROR \
2863 { \
2864 CUR.error = TT_Err_Invalid_Reference; \
2865 return; \
2866 }
2869 /*************************************************************************/
2870 /* */
2871 /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
2872 /* Opcode range: 0x00-0x01 */
2873 /* Stack: --> */
2874 /* */
2875 static void
2876 Ins_SVTCA( INS_ARG )
2877 {
2878 DO_SVTCA
2879 }
2882 /*************************************************************************/
2883 /* */
2884 /* SPVTCA[a]: Set PVector to Coordinate Axis */
2885 /* Opcode range: 0x02-0x03 */
2886 /* Stack: --> */
2887 /* */
2888 static void
2889 Ins_SPVTCA( INS_ARG )
2890 {
2891 DO_SPVTCA
2892 }
2895 /*************************************************************************/
2896 /* */
2897 /* SFVTCA[a]: Set FVector to Coordinate Axis */
2898 /* Opcode range: 0x04-0x05 */
2899 /* Stack: --> */
2900 /* */
2901 static void
2902 Ins_SFVTCA( INS_ARG )
2903 {
2904 DO_SFVTCA
2905 }
2908 /*************************************************************************/
2909 /* */
2910 /* SPVTL[a]: Set PVector To Line */
2911 /* Opcode range: 0x06-0x07 */
2912 /* Stack: uint32 uint32 --> */
2913 /* */
2914 static void
2915 Ins_SPVTL( INS_ARG )
2916 {
2917 DO_SPVTL
2918 }
2921 /*************************************************************************/
2922 /* */
2923 /* SFVTL[a]: Set FVector To Line */
2924 /* Opcode range: 0x08-0x09 */
2925 /* Stack: uint32 uint32 --> */
2926 /* */
2927 static void
2928 Ins_SFVTL( INS_ARG )
2929 {
2930 DO_SFVTL
2931 }
2934 /*************************************************************************/
2935 /* */
2936 /* SFVTPV[]: Set FVector To PVector */
2937 /* Opcode range: 0x0E */
2938 /* Stack: --> */
2939 /* */
2940 static void
2941 Ins_SFVTPV( INS_ARG )
2942 {
2943 DO_SFVTPV
2944 }
2947 /*************************************************************************/
2948 /* */
2949 /* SPVFS[]: Set PVector From Stack */
2950 /* Opcode range: 0x0A */
2951 /* Stack: f2.14 f2.14 --> */
2952 /* */
2953 static void
2954 Ins_SPVFS( INS_ARG )
2955 {
2956 DO_SPVFS
2957 }
2960 /*************************************************************************/
2961 /* */
2962 /* SFVFS[]: Set FVector From Stack */
2963 /* Opcode range: 0x0B */
2964 /* Stack: f2.14 f2.14 --> */
2965 /* */
2966 static void
2967 Ins_SFVFS( INS_ARG )
2968 {
2969 DO_SFVFS
2970 }
2973 /*************************************************************************/
2974 /* */
2975 /* GPV[]: Get Projection Vector */
2976 /* Opcode range: 0x0C */
2977 /* Stack: ef2.14 --> ef2.14 */
2978 /* */
2979 static void
2980 Ins_GPV( INS_ARG )
2981 {
2982 DO_GPV
2983 }
2986 /*************************************************************************/
2987 /* GFV[]: Get Freedom Vector */
2988 /* Opcode range: 0x0D */
2989 /* Stack: ef2.14 --> ef2.14 */
2990 /* */
2991 static void
2992 Ins_GFV( INS_ARG )
2993 {
2994 DO_GFV
2995 }
2998 /*************************************************************************/
2999 /* */
3000 /* SRP0[]: Set Reference Point 0 */
3001 /* Opcode range: 0x10 */
3002 /* Stack: uint32 --> */
3003 /* */
3004 static void
3005 Ins_SRP0( INS_ARG )
3006 {
3007 DO_SRP0
3008 }
3011 /*************************************************************************/
3012 /* */
3013 /* SRP1[]: Set Reference Point 1 */
3014 /* Opcode range: 0x11 */
3015 /* Stack: uint32 --> */
3016 /* */
3017 static void
3018 Ins_SRP1( INS_ARG )
3019 {
3020 DO_SRP1
3021 }
3024 /*************************************************************************/
3025 /* */
3026 /* SRP2[]: Set Reference Point 2 */
3027 /* Opcode range: 0x12 */
3028 /* Stack: uint32 --> */
3029 /* */
3030 static void
3031 Ins_SRP2( INS_ARG )
3032 {
3033 DO_SRP2
3034 }
3037 /*************************************************************************/
3038 /* */
3039 /* RTHG[]: Round To Half Grid */
3040 /* Opcode range: 0x19 */
3041 /* Stack: --> */
3042 /* */
3043 static void
3044 Ins_RTHG( INS_ARG )
3045 {
3046 DO_RTHG
3047 }
3050 /*************************************************************************/
3051 /* */
3052 /* RTG[]: Round To Grid */
3053 /* Opcode range: 0x18 */
3054 /* Stack: --> */
3055 /* */
3056 static void
3057 Ins_RTG( INS_ARG )
3058 {
3059 DO_RTG
3060 }
3063 /*************************************************************************/
3064 /* RTDG[]: Round To Double Grid */
3065 /* Opcode range: 0x3D */
3066 /* Stack: --> */
3067 /* */
3068 static void
3069 Ins_RTDG( INS_ARG )
3070 {
3071 DO_RTDG
3072 }
3075 /*************************************************************************/
3076 /* RUTG[]: Round Up To Grid */
3077 /* Opcode range: 0x7C */
3078 /* Stack: --> */
3079 /* */
3080 static void
3081 Ins_RUTG( INS_ARG )
3082 {
3083 DO_RUTG
3084 }
3087 /*************************************************************************/
3088 /* */
3089 /* RDTG[]: Round Down To Grid */
3090 /* Opcode range: 0x7D */
3091 /* Stack: --> */
3092 /* */
3093 static void
3094 Ins_RDTG( INS_ARG )
3095 {
3096 DO_RDTG
3097 }
3100 /*************************************************************************/
3101 /* */
3102 /* ROFF[]: Round OFF */
3103 /* Opcode range: 0x7A */
3104 /* Stack: --> */
3105 /* */
3106 static void
3107 Ins_ROFF( INS_ARG )
3108 {
3109 DO_ROFF
3110 }
3113 /*************************************************************************/
3114 /* */
3115 /* SROUND[]: Super ROUND */
3116 /* Opcode range: 0x76 */
3117 /* Stack: Eint8 --> */
3118 /* */
3119 static void
3120 Ins_SROUND( INS_ARG )
3121 {
3122 DO_SROUND
3123 }
3126 /*************************************************************************/
3127 /* */
3128 /* S45ROUND[]: Super ROUND 45 degrees */
3129 /* Opcode range: 0x77 */
3130 /* Stack: uint32 --> */
3131 /* */
3132 static void
3133 Ins_S45ROUND( INS_ARG )
3134 {
3135 DO_S45ROUND
3136 }
3139 /*************************************************************************/
3140 /* */
3141 /* SLOOP[]: Set LOOP variable */
3142 /* Opcode range: 0x17 */
3143 /* Stack: int32? --> */
3144 /* */
3145 static void
3146 Ins_SLOOP( INS_ARG )
3147 {
3148 DO_SLOOP
3149 }
3152 /*************************************************************************/
3153 /* */
3154 /* SMD[]: Set Minimum Distance */
3155 /* Opcode range: 0x1A */
3156 /* Stack: f26.6 --> */
3157 /* */
3158 static void
3159 Ins_SMD( INS_ARG )
3160 {
3161 DO_SMD
3162 }
3165 /*************************************************************************/
3166 /* */
3167 /* SCVTCI[]: Set Control Value Table Cut In */
3168 /* Opcode range: 0x1D */
3169 /* Stack: f26.6 --> */
3170 /* */
3171 static void
3172 Ins_SCVTCI( INS_ARG )
3173 {
3174 DO_SCVTCI
3175 }
3178 /*************************************************************************/
3179 /* */
3180 /* SSWCI[]: Set Single Width Cut In */
3181 /* Opcode range: 0x1E */
3182 /* Stack: f26.6 --> */
3183 /* */
3184 static void
3185 Ins_SSWCI( INS_ARG )
3186 {
3187 DO_SSWCI
3188 }
3191 /*************************************************************************/
3192 /* */
3193 /* SSW[]: Set Single Width */
3194 /* Opcode range: 0x1F */
3195 /* Stack: int32? --> */
3196 /* */
3197 static void
3198 Ins_SSW( INS_ARG )
3199 {
3200 DO_SSW
3201 }
3204 /*************************************************************************/
3205 /* */
3206 /* FLIPON[]: Set auto-FLIP to ON */
3207 /* Opcode range: 0x4D */
3208 /* Stack: --> */
3209 /* */
3210 static void
3211 Ins_FLIPON( INS_ARG )
3212 {
3213 DO_FLIPON
3214 }
3217 /*************************************************************************/
3218 /* */
3219 /* FLIPOFF[]: Set auto-FLIP to OFF */
3220 /* Opcode range: 0x4E */
3221 /* Stack: --> */
3222 /* */
3223 static void
3224 Ins_FLIPOFF( INS_ARG )
3225 {
3226 DO_FLIPOFF
3227 }
3230 /*************************************************************************/
3231 /* */
3232 /* SANGW[]: Set ANGle Weight */
3233 /* Opcode range: 0x7E */
3234 /* Stack: uint32 --> */
3235 /* */
3236 static void
3237 Ins_SANGW( INS_ARG )
3238 {
3239 /* instruction not supported anymore */
3240 }
3243 /*************************************************************************/
3244 /* */
3245 /* SDB[]: Set Delta Base */
3246 /* Opcode range: 0x5E */
3247 /* Stack: uint32 --> */
3248 /* */
3249 static void
3250 Ins_SDB( INS_ARG )
3251 {
3252 DO_SDB
3253 }
3256 /*************************************************************************/
3257 /* */
3258 /* SDS[]: Set Delta Shift */
3259 /* Opcode range: 0x5F */
3260 /* Stack: uint32 --> */
3261 /* */
3262 static void
3263 Ins_SDS( INS_ARG )
3264 {
3265 DO_SDS
3266 }
3269 /*************************************************************************/
3270 /* */
3271 /* MPPEM[]: Measure Pixel Per EM */
3272 /* Opcode range: 0x4B */
3273 /* Stack: --> Euint16 */
3274 /* */
3275 static void
3276 Ins_MPPEM( INS_ARG )
3277 {
3278 DO_MPPEM
3279 }
3282 /*************************************************************************/
3283 /* */
3284 /* MPS[]: Measure Point Size */
3285 /* Opcode range: 0x4C */
3286 /* Stack: --> Euint16 */
3287 /* */
3288 static void
3289 Ins_MPS( INS_ARG )
3290 {
3291 DO_MPS
3292 }
3295 /*************************************************************************/
3296 /* */
3297 /* DUP[]: DUPlicate the top stack's element */
3298 /* Opcode range: 0x20 */
3299 /* Stack: StkElt --> StkElt StkElt */
3300 /* */
3301 static void
3302 Ins_DUP( INS_ARG )
3303 {
3304 DO_DUP
3305 }
3308 /*************************************************************************/
3309 /* */
3310 /* POP[]: POP the stack's top element */
3311 /* Opcode range: 0x21 */
3312 /* Stack: StkElt --> */
3313 /* */
3314 static void
3315 Ins_POP( INS_ARG )
3316 {
3317 /* nothing to do */
3318 }
3321 /*************************************************************************/
3322 /* */
3323 /* CLEAR[]: CLEAR the entire stack */
3324 /* Opcode range: 0x22 */
3325 /* Stack: StkElt... --> */
3326 /* */
3327 static void
3328 Ins_CLEAR( INS_ARG )
3329 {
3330 DO_CLEAR
3331 }
3334 /*************************************************************************/
3335 /* */
3336 /* SWAP[]: SWAP the stack's top two elements */
3337 /* Opcode range: 0x23 */
3338 /* Stack: 2 * StkElt --> 2 * StkElt */
3339 /* */
3340 static void
3341 Ins_SWAP( INS_ARG )
3342 {
3343 DO_SWAP
3344 }
3347 /*************************************************************************/
3348 /* */
3349 /* DEPTH[]: return the stack DEPTH */
3350 /* Opcode range: 0x24 */
3351 /* Stack: --> uint32 */
3352 /* */
3353 static void
3354 Ins_DEPTH( INS_ARG )
3355 {
3356 DO_DEPTH
3357 }
3360 /*************************************************************************/
3361 /* */
3362 /* CINDEX[]: Copy INDEXed element */
3363 /* Opcode range: 0x25 */
3364 /* Stack: int32 --> StkElt */
3365 /* */
3366 static void
3367 Ins_CINDEX( INS_ARG )
3368 {
3369 DO_CINDEX
3370 }
3373 /*************************************************************************/
3374 /* */
3375 /* EIF[]: End IF */
3376 /* Opcode range: 0x59 */
3377 /* Stack: --> */
3378 /* */
3379 static void
3380 Ins_EIF( INS_ARG )
3381 {
3382 /* nothing to do */
3383 }
3386 /*************************************************************************/
3387 /* */
3388 /* JROT[]: Jump Relative On True */
3389 /* Opcode range: 0x78 */
3390 /* Stack: StkElt int32 --> */
3391 /* */
3392 static void
3393 Ins_JROT( INS_ARG )
3394 {
3395 DO_JROT
3396 }
3399 /*************************************************************************/
3400 /* */
3401 /* JMPR[]: JuMP Relative */
3402 /* Opcode range: 0x1C */
3403 /* Stack: int32 --> */
3404 /* */
3405 static void
3406 Ins_JMPR( INS_ARG )
3407 {
3408 DO_JMPR
3409 }
3412 /*************************************************************************/
3413 /* */
3414 /* JROF[]: Jump Relative On False */
3415 /* Opcode range: 0x79 */
3416 /* Stack: StkElt int32 --> */
3417 /* */
3418 static void
3419 Ins_JROF( INS_ARG )
3420 {
3421 DO_JROF
3422 }
3425 /*************************************************************************/
3426 /* */
3427 /* LT[]: Less Than */
3428 /* Opcode range: 0x50 */
3429 /* Stack: int32? int32? --> bool */
3430 /* */
3431 static void
3432 Ins_LT( INS_ARG )
3433 {
3434 DO_LT
3435 }
3438 /*************************************************************************/
3439 /* */
3440 /* LTEQ[]: Less Than or EQual */
3441 /* Opcode range: 0x51 */
3442 /* Stack: int32? int32? --> bool */
3443 /* */
3444 static void
3445 Ins_LTEQ( INS_ARG )
3446 {
3447 DO_LTEQ
3448 }
3451 /*************************************************************************/
3452 /* */
3453 /* GT[]: Greater Than */
3454 /* Opcode range: 0x52 */
3455 /* Stack: int32? int32? --> bool */
3456 /* */
3457 static void
3458 Ins_GT( INS_ARG )
3459 {
3460 DO_GT
3461 }
3464 /*************************************************************************/
3465 /* */
3466 /* GTEQ[]: Greater Than or EQual */
3467 /* Opcode range: 0x53 */
3468 /* Stack: int32? int32? --> bool */
3469 /* */
3470 static void
3471 Ins_GTEQ( INS_ARG )
3472 {
3473 DO_GTEQ
3474 }
3477 /*************************************************************************/
3478 /* */
3479 /* EQ[]: EQual */
3480 /* Opcode range: 0x54 */
3481 /* Stack: StkElt StkElt --> bool */
3482 /* */
3483 static void
3484 Ins_EQ( INS_ARG )
3485 {
3486 DO_EQ
3487 }
3490 /*************************************************************************/
3491 /* */
3492 /* NEQ[]: Not EQual */
3493 /* Opcode range: 0x55 */
3494 /* Stack: StkElt StkElt --> bool */
3495 /* */
3496 static void
3497 Ins_NEQ( INS_ARG )
3498 {
3499 DO_NEQ
3500 }
3503 /*************************************************************************/
3504 /* */
3505 /* ODD[]: Is ODD */
3506 /* Opcode range: 0x56 */
3507 /* Stack: f26.6 --> bool */
3508 /* */
3509 static void
3510 Ins_ODD( INS_ARG )
3511 {
3512 DO_ODD
3513 }
3516 /*************************************************************************/
3517 /* */
3518 /* EVEN[]: Is EVEN */
3519 /* Opcode range: 0x57 */
3520 /* Stack: f26.6 --> bool */
3521 /* */
3522 static void
3523 Ins_EVEN( INS_ARG )
3524 {
3525 DO_EVEN
3526 }
3529 /*************************************************************************/
3530 /* */
3531 /* AND[]: logical AND */
3532 /* Opcode range: 0x5A */
3533 /* Stack: uint32 uint32 --> uint32 */
3534 /* */
3535 static void
3536 Ins_AND( INS_ARG )
3537 {
3538 DO_AND
3539 }
3542 /*************************************************************************/
3543 /* */
3544 /* OR[]: logical OR */
3545 /* Opcode range: 0x5B */
3546 /* Stack: uint32 uint32 --> uint32 */
3547 /* */
3548 static void
3549 Ins_OR( INS_ARG )
3550 {
3551 DO_OR
3552 }
3555 /*************************************************************************/
3556 /* */
3557 /* NOT[]: logical NOT */
3558 /* Opcode range: 0x5C */
3559 /* Stack: StkElt --> uint32 */
3560 /* */
3561 static void
3562 Ins_NOT( INS_ARG )
3563 {
3564 DO_NOT
3565 }
3568 /*************************************************************************/
3569 /* */
3570 /* ADD[]: ADD */
3571 /* Opcode range: 0x60 */
3572 /* Stack: f26.6 f26.6 --> f26.6 */
3573 /* */
3574 static void
3575 Ins_ADD( INS_ARG )
3576 {
3577 DO_ADD
3578 }
3581 /*************************************************************************/
3582 /* */
3583 /* SUB[]: SUBtract */
3584 /* Opcode range: 0x61 */
3585 /* Stack: f26.6 f26.6 --> f26.6 */
3586 /* */
3587 static void
3588 Ins_SUB( INS_ARG )
3589 {
3590 DO_SUB
3591 }
3594 /*************************************************************************/
3595 /* */
3596 /* DIV[]: DIVide */
3597 /* Opcode range: 0x62 */
3598 /* Stack: f26.6 f26.6 --> f26.6 */
3599 /* */
3600 static void
3601 Ins_DIV( INS_ARG )
3602 {
3603 DO_DIV
3604 }
3607 /*************************************************************************/
3608 /* */
3609 /* MUL[]: MULtiply */
3610 /* Opcode range: 0x63 */
3611 /* Stack: f26.6 f26.6 --> f26.6 */
3612 /* */
3613 static void
3614 Ins_MUL( INS_ARG )
3615 {
3616 DO_MUL
3617 }
3620 /*************************************************************************/
3621 /* */
3622 /* ABS[]: ABSolute value */
3623 /* Opcode range: 0x64 */
3624 /* Stack: f26.6 --> f26.6 */
3625 /* */
3626 static void
3627 Ins_ABS( INS_ARG )
3628 {
3629 DO_ABS
3630 }
3633 /*************************************************************************/
3634 /* */
3635 /* NEG[]: NEGate */
3636 /* Opcode range: 0x65 */
3637 /* Stack: f26.6 --> f26.6 */
3638 /* */
3639 static void
3640 Ins_NEG( INS_ARG )
3641 {
3642 DO_NEG
3643 }
3646 /*************************************************************************/
3647 /* */
3648 /* FLOOR[]: FLOOR */
3649 /* Opcode range: 0x66 */
3650 /* Stack: f26.6 --> f26.6 */
3651 /* */
3652 static void
3653 Ins_FLOOR( INS_ARG )
3654 {
3655 DO_FLOOR
3656 }
3659 /*************************************************************************/
3660 /* */
3661 /* CEILING[]: CEILING */
3662 /* Opcode range: 0x67 */
3663 /* Stack: f26.6 --> f26.6 */
3664 /* */
3665 static void
3666 Ins_CEILING( INS_ARG )
3667 {
3668 DO_CEILING
3669 }
3672 /*************************************************************************/
3673 /* */
3674 /* RS[]: Read Store */
3675 /* Opcode range: 0x43 */
3676 /* Stack: uint32 --> uint32 */
3677 /* */
3678 static void
3679 Ins_RS( INS_ARG )
3680 {
3681 DO_RS
3682 }
3685 /*************************************************************************/
3686 /* */
3687 /* WS[]: Write Store */
3688 /* Opcode range: 0x42 */
3689 /* Stack: uint32 uint32 --> */
3690 /* */
3691 static void
3692 Ins_WS( INS_ARG )
3693 {
3694 DO_WS
3695 }
3698 /*************************************************************************/
3699 /* */
3700 /* WCVTP[]: Write CVT in Pixel units */
3701 /* Opcode range: 0x44 */
3702 /* Stack: f26.6 uint32 --> */
3703 /* */
3704 static void
3705 Ins_WCVTP( INS_ARG )
3706 {
3707 DO_WCVTP
3708 }
3711 /*************************************************************************/
3712 /* */
3713 /* WCVTF[]: Write CVT in Funits */
3714 /* Opcode range: 0x70 */
3715 /* Stack: uint32 uint32 --> */
3716 /* */
3717 static void
3718 Ins_WCVTF( INS_ARG )
3719 {
3720 DO_WCVTF
3721 }
3724 /*************************************************************************/
3725 /* */
3726 /* RCVT[]: Read CVT */
3727 /* Opcode range: 0x45 */
3728 /* Stack: uint32 --> f26.6 */
3729 /* */
3730 static void
3731 Ins_RCVT( INS_ARG )
3732 {
3733 DO_RCVT
3734 }
3737 /*************************************************************************/
3738 /* */
3739 /* AA[]: Adjust Angle */
3740 /* Opcode range: 0x7F */
3741 /* Stack: uint32 --> */
3742 /* */
3743 static void
3744 Ins_AA( INS_ARG )
3745 {
3746 /* intentionally no longer supported */
3747 }
3750 /*************************************************************************/
3751 /* */
3752 /* DEBUG[]: DEBUG. Unsupported. */
3753 /* Opcode range: 0x4F */
3754 /* Stack: uint32 --> */
3755 /* */
3756 /* Note: The original instruction pops a value from the stack. */
3757 /* */
3758 static void
3759 Ins_DEBUG( INS_ARG )
3760 {
3761 DO_DEBUG
3762 }
3765 /*************************************************************************/
3766 /* */
3767 /* ROUND[ab]: ROUND value */
3768 /* Opcode range: 0x68-0x6B */
3769 /* Stack: f26.6 --> f26.6 */
3770 /* */
3771 static void
3772 Ins_ROUND( INS_ARG )
3773 {
3774 DO_ROUND
3775 }
3778 /*************************************************************************/
3779 /* */
3780 /* NROUND[ab]: No ROUNDing of value */
3781 /* Opcode range: 0x6C-0x6F */
3782 /* Stack: f26.6 --> f26.6 */
3783 /* */
3784 static void
3785 Ins_NROUND( INS_ARG )
3786 {
3787 DO_NROUND
3788 }
3791 /*************************************************************************/
3792 /* */
3793 /* MAX[]: MAXimum */
3794 /* Opcode range: 0x68 */
3795 /* Stack: int32? int32? --> int32 */
3796 /* */
3797 static void
3798 Ins_MAX( INS_ARG )
3799 {
3800 DO_MAX
3801 }
3804 /*************************************************************************/
3805 /* */
3806 /* MIN[]: MINimum */
3807 /* Opcode range: 0x69 */
3808 /* Stack: int32? int32? --> int32 */
3809 /* */
3810 static void
3811 Ins_MIN( INS_ARG )
3812 {
3813 DO_MIN
3814 }
3817 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
3820 /*************************************************************************/
3821 /* */
3822 /* The following functions are called as is within the switch statement. */
3823 /* */
3824 /*************************************************************************/
3827 /*************************************************************************/
3828 /* */
3829 /* MINDEX[]: Move INDEXed element */
3830 /* Opcode range: 0x26 */
3831 /* Stack: int32? --> StkElt */
3832 /* */
3833 static void
3834 Ins_MINDEX( INS_ARG )
3835 {
3836 FT_Long L, K;
3839 L = args[0];
3841 if ( L <= 0 || L > CUR.args )
3842 {
3843 CUR.error = TT_Err_Invalid_Reference;
3844 return;
3845 }
3847 K = CUR.stack[CUR.args - L];
3849 MEM_Move( &CUR.stack[CUR.args - L ],
3850 &CUR.stack[CUR.args - L + 1],
3851 ( L - 1 ) * sizeof ( FT_Long ) );
3853 CUR.stack[CUR.args - 1] = K;
3854 }
3857 /*************************************************************************/
3858 /* */
3859 /* ROLL[]: ROLL top three elements */
3860 /* Opcode range: 0x8A */
3861 /* Stack: 3 * StkElt --> 3 * StkElt */
3862 /* */
3863 static void
3864 Ins_ROLL( INS_ARG )
3865 {
3866 FT_Long A, B, C;
3868 FT_UNUSED_EXEC;
3871 A = args[2];
3872 B = args[1];
3873 C = args[0];
3875 args[2] = C;
3876 args[1] = A;
3877 args[0] = B;
3878 }
3881 /*************************************************************************/
3882 /* */
3883 /* MANAGING THE FLOW OF CONTROL */
3884 /* */
3885 /* Instructions appear in the specification's order. */
3886 /* */
3887 /*************************************************************************/
3890 static FT_Bool
3891 SkipCode( EXEC_OP )
3892 {
3893 CUR.IP += CUR.length;
3895 if ( CUR.IP < CUR.codeSize )
3896 {
3897 CUR.opcode = CUR.code[CUR.IP];
3899 CUR.length = opcode_length[CUR.opcode];
3900 if ( CUR.length < 0 )
3901 {
3902 if ( CUR.IP + 1 > CUR.codeSize )
3903 goto Fail_Overflow;
3904 CUR.length = CUR.code[CUR.IP + 1] + 2;
3905 }
3907 if ( CUR.IP + CUR.length <= CUR.codeSize )
3908 return SUCCESS;
3909 }
3911 Fail_Overflow:
3912 CUR.error = TT_Err_Code_Overflow;
3913 return FAILURE;
3914 }
3917 /*************************************************************************/
3918 /* */
3919 /* IF[]: IF test */
3920 /* Opcode range: 0x58 */
3921 /* Stack: StkElt --> */
3922 /* */
3923 static void
3924 Ins_IF( INS_ARG )
3925 {
3926 FT_Int nIfs;
3927 FT_Bool Out;
3930 if ( args[0] != 0 )
3931 return;
3933 nIfs = 1;
3934 Out = 0;
3936 do
3937 {
3938 if ( SKIP_Code() == FAILURE )
3939 return;
3941 switch ( CUR.opcode )
3942 {
3943 case 0x58: /* IF */
3944 nIfs++;
3945 break;
3947 case 0x1B: /* ELSE */
3948 Out = FT_BOOL( nIfs == 1 );
3949 break;
3951 case 0x59: /* EIF */
3952 nIfs--;
3953 Out = FT_BOOL( nIfs == 0 );
3954 break;
3955 }
3956 } while ( Out == 0 );
3957 }
3960 /*************************************************************************/
3961 /* */
3962 /* ELSE[]: ELSE */
3963 /* Opcode range: 0x1B */
3964 /* Stack: --> */
3965 /* */
3966 static void
3967 Ins_ELSE( INS_ARG )
3968 {
3969 FT_Int nIfs;
3971 FT_UNUSED_ARG;
3974 nIfs = 1;
3976 do
3977 {
3978 if ( SKIP_Code() == FAILURE )
3979 return;
3981 switch ( CUR.opcode )
3982 {
3983 case 0x58: /* IF */
3984 nIfs++;
3985 break;
3987 case 0x59: /* EIF */
3988 nIfs--;
3989 break;
3990 }
3991 } while ( nIfs != 0 );
3992 }
3995 /*************************************************************************/
3996 /* */
3997 /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
3998 /* */
3999 /* Instructions appear in the specification's order. */
4000 /* */
4001 /*************************************************************************/
4004 /*************************************************************************/
4005 /* */
4006 /* FDEF[]: Function DEFinition */
4007 /* Opcode range: 0x2C */
4008 /* Stack: uint32 --> */
4009 /* */
4010 static void
4011 Ins_FDEF( INS_ARG )
4012 {
4013 FT_ULong n;
4014 TT_DefRecord* rec;
4015 TT_DefRecord* limit;
4018 /* some font programs are broken enough to redefine functions! */
4019 /* We will then parse the current table. */
4021 rec = CUR.FDefs;
4022 limit = rec + CUR.numFDefs;
4023 n = args[0];
4025 for ( ; rec < limit; rec++ )
4026 {
4027 if ( rec->opc == n )
4028 break;
4029 }
4031 if ( rec == limit )
4032 {
4033 /* check that there is enough room for new functions */
4034 if ( CUR.numFDefs >= CUR.maxFDefs )
4035 {
4036 CUR.error = TT_Err_Too_Many_Function_Defs;
4037 return;
4038 }
4039 CUR.numFDefs++;
4040 }
4042 rec->range = CUR.curRange;
4043 rec->opc = n;
4044 rec->start = CUR.IP + 1;
4045 rec->active = TRUE;
4047 if ( n > CUR.maxFunc )
4048 CUR.maxFunc = n;
4050 /* Now skip the whole function definition. */
4051 /* We don't allow nested IDEFS & FDEFs. */
4053 while ( SKIP_Code() == SUCCESS )
4054 {
4055 switch ( CUR.opcode )
4056 {
4057 case 0x89: /* IDEF */
4058 case 0x2C: /* FDEF */
4059 CUR.error = TT_Err_Nested_DEFS;
4060 return;
4062 case 0x2D: /* ENDF */
4063 return;
4064 }
4065 }
4066 }
4069 /*************************************************************************/
4070 /* */
4071 /* ENDF[]: END Function definition */
4072 /* Opcode range: 0x2D */
4073 /* Stack: --> */
4074 /* */
4075 static void
4076 Ins_ENDF( INS_ARG )
4077 {
4078 TT_CallRec* pRec;
4080 FT_UNUSED_ARG;
4083 if ( CUR.callTop <= 0 ) /* We encountered an ENDF without a call */
4084 {
4085 CUR.error = TT_Err_ENDF_In_Exec_Stream;
4086 return;
4087 }
4089 CUR.callTop--;
4091 pRec = &CUR.callStack[CUR.callTop];
4093 pRec->Cur_Count--;
4095 CUR.step_ins = FALSE;
4097 if ( pRec->Cur_Count > 0 )
4098 {
4099 CUR.callTop++;
4100 CUR.IP = pRec->Cur_Restart;
4101 }
4102 else
4103 /* Loop through the current function */
4104 INS_Goto_CodeRange( pRec->Caller_Range,
4105 pRec->Caller_IP );
4107 /* Exit the current call frame. */
4109 /* NOTE: If the last intruction of a program is a */
4110 /* CALL or LOOPCALL, the return address is */
4111 /* always out of the code range. This is a */
4112 /* valid address, and it is why we do not test */
4113 /* the result of Ins_Goto_CodeRange() here! */
4114 }
4117 /*************************************************************************/
4118 /* */
4119 /* CALL[]: CALL function */
4120 /* Opcode range: 0x2B */
4121 /* Stack: uint32? --> */
4122 /* */
4123 static void
4124 Ins_CALL( INS_ARG )
4125 {
4126 FT_ULong F;
4127 TT_CallRec* pCrec;
4128 TT_DefRecord* def;
4131 /* first of all, check the index */
4133 F = args[0];
4134 if ( BOUNDS( F, CUR.maxFunc + 1 ) )
4135 goto Fail;
4137 /* Except for some old Apple fonts, all functions in a TrueType */
4138 /* font are defined in increasing order, starting from 0. This */
4139 /* means that we normally have */
4140 /* */
4141 /* CUR.maxFunc+1 == CUR.numFDefs */
4142 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4143 /* */
4144 /* If this isn't true, we need to look up the function table. */
4146 def = CUR.FDefs + F;
4147 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
4148 {
4149 /* look up the FDefs table */
4150 TT_DefRecord* limit;
4153 def = CUR.FDefs;
4154 limit = def + CUR.numFDefs;
4156 while ( def < limit && def->opc != F )
4157 def++;
4159 if ( def == limit )
4160 goto Fail;
4161 }
4163 /* check that the function is active */
4164 if ( !def->active )
4165 goto Fail;
4167 /* check the call stack */
4168 if ( CUR.callTop >= CUR.callSize )
4169 {
4170 CUR.error = TT_Err_Stack_Overflow;
4171 return;
4172 }
4174 pCrec = CUR.callStack + CUR.callTop;
4176 pCrec->Caller_Range = CUR.curRange;
4177 pCrec->Caller_IP = CUR.IP + 1;
4178 pCrec->Cur_Count = 1;
4179 pCrec->Cur_Restart = def->start;
4181 CUR.callTop++;
4183 INS_Goto_CodeRange( def->range,
4184 def->start );
4186 CUR.step_ins = FALSE;
4187 return;
4189 Fail:
4190 CUR.error = TT_Err_Invalid_Reference;
4191 }
4194 /*************************************************************************/
4195 /* */
4196 /* LOOPCALL[]: LOOP and CALL function */
4197 /* Opcode range: 0x2A */
4198 /* Stack: uint32? Eint16? --> */
4199 /* */
4200 static void
4201 Ins_LOOPCALL( INS_ARG )
4202 {
4203 FT_ULong F;
4204 TT_CallRec* pCrec;
4205 TT_DefRecord* def;
4208 /* first of all, check the index */
4209 F = args[1];
4210 if ( BOUNDS( F, CUR.maxFunc + 1 ) )
4211 goto Fail;
4213 /* Except for some old Apple fonts, all functions in a TrueType */
4214 /* font are defined in increasing order, starting from 0. This */
4215 /* means that we normally have */
4216 /* */
4217 /* CUR.maxFunc+1 == CUR.numFDefs */
4218 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4219 /* */
4220 /* If this isn't true, we need to look up the function table. */
4222 def = CUR.FDefs + F;
4223 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
4224 {
4225 /* look up the FDefs table */
4226 TT_DefRecord* limit;
4229 def = CUR.FDefs;
4230 limit = def + CUR.numFDefs;
4232 while ( def < limit && def->opc != F )
4233 def++;
4235 if ( def == limit )
4236 goto Fail;
4237 }
4239 /* check that the function is active */
4240 if ( !def->active )
4241 goto Fail;
4243 /* check stack */
4244 if ( CUR.callTop >= CUR.callSize )
4245 {
4246 CUR.error = TT_Err_Stack_Overflow;
4247 return;
4248 }
4250 if ( args[0] > 0 )
4251 {
4252 pCrec = CUR.callStack + CUR.callTop;
4254 pCrec->Caller_Range = CUR.curRange;
4255 pCrec->Caller_IP = CUR.IP + 1;
4256 pCrec->Cur_Count = (FT_Int)args[0];
4257 pCrec->Cur_Restart = def->start;
4259 CUR.callTop++;
4261 INS_Goto_CodeRange( def->range, def->start );
4263 CUR.step_ins = FALSE;
4264 }
4265 return;
4267 Fail:
4268 CUR.error = TT_Err_Invalid_Reference;
4269 }
4272 /*************************************************************************/
4273 /* */
4274 /* IDEF[]: Instruction DEFinition */
4275 /* Opcode range: 0x89 */
4276 /* Stack: Eint8 --> */
4277 /* */
4278 static void
4279 Ins_IDEF( INS_ARG )
4280 {
4281 TT_DefRecord* def;
4282 TT_DefRecord* limit;
4285 /* First of all, look for the same function in our table */
4287 def = CUR.IDefs;
4288 limit = def + CUR.numIDefs;
4290 for ( ; def < limit; def++ )
4291 if ( def->opc == (FT_ULong)args[0] )
4292 break;
4294 if ( def == limit )
4295 {
4296 /* check that there is enough room for a new instruction */
4297 if ( CUR.numIDefs >= CUR.maxIDefs )
4298 {
4299 CUR.error = TT_Err_Too_Many_Instruction_Defs;
4300 return;
4301 }
4302 CUR.numIDefs++;
4303 }
4305 def->opc = args[0];
4306 def->start = CUR.IP+1;
4307 def->range = CUR.curRange;
4308 def->active = TRUE;
4310 if ( (FT_ULong)args[0] > CUR.maxIns )
4311 CUR.maxIns = args[0];
4313 /* Now skip the whole function definition. */
4314 /* We don't allow nested IDEFs & FDEFs. */
4316 while ( SKIP_Code() == SUCCESS )
4317 {
4318 switch ( CUR.opcode )
4319 {
4320 case 0x89: /* IDEF */
4321 case 0x2C: /* FDEF */
4322 CUR.error = TT_Err_Nested_DEFS;
4323 return;
4324 case 0x2D: /* ENDF */
4325 return;
4326 }
4327 }
4328 }
4331 /*************************************************************************/
4332 /* */
4333 /* PUSHING DATA ONTO THE INTERPRETER STACK */
4334 /* */
4335 /* Instructions appear in the specification's order. */
4336 /* */
4337 /*************************************************************************/
4340 /*************************************************************************/
4341 /* */
4342 /* NPUSHB[]: PUSH N Bytes */
4343 /* Opcode range: 0x40 */
4344 /* Stack: --> uint32... */
4345 /* */
4346 static void
4347 Ins_NPUSHB( INS_ARG )
4348 {
4349 FT_UShort L, K;
4352 L = (FT_UShort)CUR.code[CUR.IP + 1];
4354 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4355 {
4356 CUR.error = TT_Err_Stack_Overflow;
4357 return;
4358 }
4360 for ( K = 1; K <= L; K++ )
4361 args[K - 1] = CUR.code[CUR.IP + K + 1];
4363 CUR.new_top += L;
4364 }
4367 /*************************************************************************/
4368 /* */
4369 /* NPUSHW[]: PUSH N Words */
4370 /* Opcode range: 0x41 */
4371 /* Stack: --> int32... */
4372 /* */
4373 static void
4374 Ins_NPUSHW( INS_ARG )
4375 {
4376 FT_UShort L, K;
4379 L = (FT_UShort)CUR.code[CUR.IP + 1];
4381 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4382 {
4383 CUR.error = TT_Err_Stack_Overflow;
4384 return;
4385 }
4387 CUR.IP += 2;
4389 for ( K = 0; K < L; K++ )
4390 args[K] = GET_ShortIns();
4392 CUR.step_ins = FALSE;
4393 CUR.new_top += L;
4394 }
4397 /*************************************************************************/
4398 /* */
4399 /* PUSHB[abc]: PUSH Bytes */
4400 /* Opcode range: 0xB0-0xB7 */
4401 /* Stack: --> uint32... */
4402 /* */
4403 static void
4404 Ins_PUSHB( INS_ARG )
4405 {
4406 FT_UShort L, K;
4409 L = (FT_UShort)(CUR.opcode - 0xB0 + 1);
4411 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4412 {
4413 CUR.error = TT_Err_Stack_Overflow;
4414 return;
4415 }
4417 for ( K = 1; K <= L; K++ )
4418 args[K - 1] = CUR.code[CUR.IP + K];
4419 }
4422 /*************************************************************************/
4423 /* */
4424 /* PUSHW[abc]: PUSH Words */
4425 /* Opcode range: 0xB8-0xBF */
4426 /* Stack: --> int32... */
4427 /* */
4428 static void
4429 Ins_PUSHW( INS_ARG )
4430 {
4431 FT_UShort L, K;
4434 L = (FT_UShort)(CUR.opcode - 0xB8 + 1);
4436 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4437 {
4438 CUR.error = TT_Err_Stack_Overflow;
4439 return;
4440 }
4442 CUR.IP++;
4444 for ( K = 0; K < L; K++ )
4445 args[K] = GET_ShortIns();
4447 CUR.step_ins = FALSE;
4448 }
4451 /*************************************************************************/
4452 /* */
4453 /* MANAGING THE GRAPHICS STATE */
4454 /* */
4455 /* Instructions appear in the specs' order. */
4456 /* */
4457 /*************************************************************************/
4460 /*************************************************************************/
4461 /* */
4462 /* GC[a]: Get Coordinate projected onto */
4463 /* Opcode range: 0x46-0x47 */
4464 /* Stack: uint32 --> f26.6 */
4465 /* */
4466 /* BULLSHIT: Measures from the original glyph must be taken along the */
4467 /* dual projection vector! */
4468 /* */
4469 static void
4470 Ins_GC( INS_ARG )
4471 {
4472 FT_ULong L;
4473 FT_F26Dot6 R;
4476 L = (FT_ULong)args[0];
4478 if ( BOUNDS( L, CUR.zp2.n_points ) )
4479 {
4480 if ( CUR.pedantic_hinting )
4481 {
4482 CUR.error = TT_Err_Invalid_Reference;
4483 return;
4484 }
4485 else
4486 R = 0;
4487 }
4488 else
4489 {
4490 if ( CUR.opcode & 1 )
4491 R = CUR_Func_dualproj( CUR.zp2.org + L, NULL_Vector );
4492 else
4493 R = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
4494 }
4496 args[0] = R;
4497 }
4500 /*************************************************************************/
4501 /* */
4502 /* SCFS[]: Set Coordinate From Stack */
4503 /* Opcode range: 0x48 */
4504 /* Stack: f26.6 uint32 --> */
4505 /* */
4506 /* Formula: */
4507 /* */
4508 /* OA := OA + ( value - OA.p )/( f.p ) * f */
4509 /* */
4510 static void
4511 Ins_SCFS( INS_ARG )
4512 {
4513 FT_Long K;
4514 FT_UShort L;
4517 L = (FT_UShort)args[0];
4519 if ( BOUNDS( L, CUR.zp2.n_points ) )
4520 {
4521 if ( CUR.pedantic_hinting )
4522 CUR.error = TT_Err_Invalid_Reference;
4523 return;
4524 }
4526 K = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
4528 CUR_Func_move( &CUR.zp2, L, args[1] - K );
4530 /* not part of the specs, but here for safety */
4532 if ( CUR.GS.gep2 == 0 )
4533 CUR.zp2.org[L] = CUR.zp2.cur[L];
4534 }
4537 /*************************************************************************/
4538 /* */
4539 /* MD[a]: Measure Distance */
4540 /* Opcode range: 0x49-0x4A */
4541 /* Stack: uint32 uint32 --> f26.6 */
4542 /* */
4543 /* BULLSHIT: Measure taken in the original glyph must be along the dual */
4544 /* projection vector. */
4545 /* */
4546 /* Second BULLSHIT: Flag attributes are inverted! */
4547 /* 0 => measure distance in original outline */
4548 /* 1 => measure distance in grid-fitted outline */
4549 /* */
4550 /* Third one: `zp0 - zp1', and not `zp2 - zp1! */
4551 /* */
4552 static void
4553 Ins_MD( INS_ARG )
4554 {
4555 FT_UShort K, L;
4556 FT_F26Dot6 D;
4559 K = (FT_UShort)args[1];
4560 L = (FT_UShort)args[0];
4562 if( BOUNDS( L, CUR.zp0.n_points ) ||
4563 BOUNDS( K, CUR.zp1.n_points ) )
4564 {
4565 if ( CUR.pedantic_hinting )
4566 {
4567 CUR.error = TT_Err_Invalid_Reference;
4568 return;
4569 }
4570 D = 0;
4571 }
4572 else
4573 {
4574 if ( CUR.opcode & 1 )
4575 D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
4576 else
4577 D = CUR_Func_dualproj( CUR.zp0.org + L, CUR.zp1.org + K );
4578 }
4580 args[0] = D;
4581 }
4584 /*************************************************************************/
4585 /* */
4586 /* SDPVTL[a]: Set Dual PVector to Line */
4587 /* Opcode range: 0x86-0x87 */
4588 /* Stack: uint32 uint32 --> */
4589 /* */
4590 static void
4591 Ins_SDPVTL( INS_ARG )
4592 {
4593 FT_Long A, B, C;
4594 FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
4597 p1 = (FT_UShort)args[1];
4598 p2 = (FT_UShort)args[0];
4600 if ( BOUNDS( p2, CUR.zp1.n_points ) ||
4601 BOUNDS( p1, CUR.zp2.n_points ) )
4602 {
4603 if ( CUR.pedantic_hinting )
4604 CUR.error = TT_Err_Invalid_Reference;
4605 return;
4606 }
4608 {
4609 FT_Vector* v1 = CUR.zp1.org + p2;
4610 FT_Vector* v2 = CUR.zp2.org + p1;
4613 A = v1->x - v2->x;
4614 B = v1->y - v2->y;
4615 }
4617 if ( ( CUR.opcode & 1 ) != 0 )
4618 {
4619 C = B; /* counter clockwise rotation */
4620 B = A;
4621 A = -C;
4622 }
4624 NORMalize( A, B, &CUR.GS.dualVector );
4626 {
4627 FT_Vector* v1 = CUR.zp1.cur + p2;
4628 FT_Vector* v2 = CUR.zp2.cur + p1;
4631 A = v1->x - v2->x;
4632 B = v1->y - v2->y;
4633 }
4635 if ( ( CUR.opcode & 1 ) != 0 )
4636 {
4637 C = B; /* counter clockwise rotation */
4638 B = A;
4639 A = -C;
4640 }
4642 NORMalize( A, B, &CUR.GS.projVector );
4644 COMPUTE_Funcs();
4645 }
4648 /*************************************************************************/
4649 /* */
4650 /* SZP0[]: Set Zone Pointer 0 */
4651 /* Opcode range: 0x13 */
4652 /* Stack: uint32 --> */
4653 /* */
4654 static void
4655 Ins_SZP0( INS_ARG )
4656 {
4657 switch ( (FT_Int)args[0] )
4658 {
4659 case 0:
4660 CUR.zp0 = CUR.twilight;
4661 break;
4663 case 1:
4664 CUR.zp0 = CUR.pts;
4665 break;
4667 default:
4668 if ( CUR.pedantic_hinting )
4669 CUR.error = TT_Err_Invalid_Reference;
4670 return;
4671 }
4673 CUR.GS.gep0 = (FT_UShort)args[0];
4674 }
4677 /*************************************************************************/
4678 /* */
4679 /* SZP1[]: Set Zone Pointer 1 */
4680 /* Opcode range: 0x14 */
4681 /* Stack: uint32 --> */
4682 /* */
4683 static void
4684 Ins_SZP1( INS_ARG )
4685 {
4686 switch ( (FT_Int)args[0] )
4687 {
4688 case 0:
4689 CUR.zp1 = CUR.twilight;
4690 break;
4692 case 1:
4693 CUR.zp1 = CUR.pts;
4694 break;
4696 default:
4697 if ( CUR.pedantic_hinting )
4698 CUR.error = TT_Err_Invalid_Reference;
4699 return;
4700 }
4702 CUR.GS.gep1 = (FT_UShort)args[0];
4703 }
4706 /*************************************************************************/
4707 /* */
4708 /* SZP2[]: Set Zone Pointer 2 */
4709 /* Opcode range: 0x15 */
4710 /* Stack: uint32 --> */
4711 /* */
4712 static void
4713 Ins_SZP2( INS_ARG )
4714 {
4715 switch ( (FT_Int)args[0] )
4716 {
4717 case 0:
4718 CUR.zp2 = CUR.twilight;
4719 break;
4721 case 1:
4722 CUR.zp2 = CUR.pts;
4723 break;
4725 default:
4726 if ( CUR.pedantic_hinting )
4727 CUR.error = TT_Err_Invalid_Reference;
4728 return;
4729 }
4731 CUR.GS.gep2 = (FT_UShort)args[0];
4732 }
4735 /*************************************************************************/
4736 /* */
4737 /* SZPS[]: Set Zone PointerS */
4738 /* Opcode range: 0x16 */
4739 /* Stack: uint32 --> */
4740 /* */
4741 static void
4742 Ins_SZPS( INS_ARG )
4743 {
4744 switch ( (FT_Int)args[0] )
4745 {
4746 case 0:
4747 CUR.zp0 = CUR.twilight;
4748 break;
4750 case 1:
4751 CUR.zp0 = CUR.pts;
4752 break;
4754 default:
4755 if ( CUR.pedantic_hinting )
4756 CUR.error = TT_Err_Invalid_Reference;
4757 return;
4758 }
4760 CUR.zp1 = CUR.zp0;
4761 CUR.zp2 = CUR.zp0;
4763 CUR.GS.gep0 = (FT_UShort)args[0];
4764 CUR.GS.gep1 = (FT_UShort)args[0];
4765 CUR.GS.gep2 = (FT_UShort)args[0];
4766 }
4769 /*************************************************************************/
4770 /* */
4771 /* INSTCTRL[]: INSTruction ConTRoL */
4772 /* Opcode range: 0x8e */
4773 /* Stack: int32 int32 --> */
4774 /* */
4775 static void
4776 Ins_INSTCTRL( INS_ARG )
4777 {
4778 FT_Long K, L;
4781 K = args[1];
4782 L = args[0];
4784 if ( K < 1 || K > 2 )
4785 {
4786 if ( CUR.pedantic_hinting )
4787 CUR.error = TT_Err_Invalid_Reference;
4788 return;
4789 }
4791 if ( L != 0 )
4792 L = K;
4794 CUR.GS.instruct_control = FT_BOOL(
4795 ( (FT_Byte)CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L );
4796 }
4799 /*************************************************************************/
4800 /* */
4801 /* SCANCTRL[]: SCAN ConTRoL */
4802 /* Opcode range: 0x85 */
4803 /* Stack: uint32? --> */
4804 /* */
4805 static void
4806 Ins_SCANCTRL( INS_ARG )
4807 {
4808 FT_Int A;
4811 /* Get Threshold */
4812 A = (FT_Int)( args[0] & 0xFF );
4814 if ( A == 0xFF )
4815 {
4816 CUR.GS.scan_control = TRUE;
4817 return;
4818 }
4819 else if ( A == 0 )
4820 {
4821 CUR.GS.scan_control = FALSE;
4822 return;
4823 }
4825 A *= 64;
4827 #if 0
4828 if ( (args[0] & 0x100) != 0 && CUR.metrics.pointSize <= A )
4829 CUR.GS.scan_control = TRUE;
4830 #endif
4832 if ( (args[0] & 0x200) != 0 && CUR.tt_metrics.rotated )
4833 CUR.GS.scan_control = TRUE;
4835 if ( (args[0] & 0x400) != 0 && CUR.tt_metrics.stretched )
4836 CUR.GS.scan_control = TRUE;
4838 #if 0
4839 if ( (args[0] & 0x800) != 0 && CUR.metrics.pointSize > A )
4840 CUR.GS.scan_control = FALSE;
4841 #endif
4843 if ( (args[0] & 0x1000) != 0 && CUR.tt_metrics.rotated )
4844 CUR.GS.scan_control = FALSE;
4846 if ( (args[0] & 0x2000) != 0 && CUR.tt_metrics.stretched )
4847 CUR.GS.scan_control = FALSE;
4848 }
4851 /*************************************************************************/
4852 /* */
4853 /* SCANTYPE[]: SCAN TYPE */
4854 /* Opcode range: 0x8D */
4855 /* Stack: uint32? --> */
4856 /* */
4857 static void
4858 Ins_SCANTYPE( INS_ARG )
4859 {
4860 /* for compatibility with future enhancements, */
4861 /* we must ignore new modes */
4863 if ( args[0] >= 0 && args[0] <= 5 )
4864 {
4865 if ( args[0] == 3 )
4866 args[0] = 2;
4868 CUR.GS.scan_type = (FT_Int)args[0];
4869 }
4870 }
4873 /*************************************************************************/
4874 /* */
4875 /* MANAGING OUTLINES */
4876 /* */
4877 /* Instructions appear in the specification's order. */
4878 /* */
4879 /*************************************************************************/
4882 /*************************************************************************/
4883 /* */
4884 /* FLIPPT[]: FLIP PoinT */
4885 /* Opcode range: 0x80 */
4886 /* Stack: uint32... --> */
4887 /* */
4888 static void
4889 Ins_FLIPPT( INS_ARG )
4890 {
4891 FT_UShort point;
4893 FT_UNUSED_ARG;
4896 if ( CUR.top < CUR.GS.loop )
4897 {
4898 CUR.error = TT_Err_Too_Few_Arguments;
4899 return;
4900 }
4902 while ( CUR.GS.loop > 0 )
4903 {
4904 CUR.args--;
4906 point = (FT_UShort)CUR.stack[CUR.args];
4908 if ( BOUNDS( point, CUR.pts.n_points ) )
4909 {
4910 if ( CUR.pedantic_hinting )
4911 {
4912 CUR.error = TT_Err_Invalid_Reference;
4913 return;
4914 }
4915 }
4916 else
4917 CUR.pts.tags[point] ^= FT_Curve_Tag_On;
4919 CUR.GS.loop--;
4920 }
4922 CUR.GS.loop = 1;
4923 CUR.new_top = CUR.args;
4924 }
4927 /*************************************************************************/
4928 /* */
4929 /* FLIPRGON[]: FLIP RanGe ON */
4930 /* Opcode range: 0x81 */
4931 /* Stack: uint32 uint32 --> */
4932 /* */
4933 static void
4934 Ins_FLIPRGON( INS_ARG )
4935 {
4936 FT_UShort I, K, L;
4939 K = (FT_UShort)args[1];
4940 L = (FT_UShort)args[0];
4942 if ( BOUNDS( K, CUR.pts.n_points ) ||
4943 BOUNDS( L, CUR.pts.n_points ) )
4944 {
4945 if ( CUR.pedantic_hinting )
4946 CUR.error = TT_Err_Invalid_Reference;
4947 return;
4948 }
4950 for ( I = L; I <= K; I++ )
4951 CUR.pts.tags[I] |= FT_Curve_Tag_On;
4952 }
4955 /*************************************************************************/
4956 /* */
4957 /* FLIPRGOFF: FLIP RanGe OFF */
4958 /* Opcode range: 0x82 */
4959 /* Stack: uint32 uint32 --> */
4960 /* */
4961 static void
4962 Ins_FLIPRGOFF( INS_ARG )
4963 {
4964 FT_UShort I, K, L;
4967 K = (FT_UShort)args[1];
4968 L = (FT_UShort)args[0];
4970 if ( BOUNDS( K, CUR.pts.n_points ) ||
4971 BOUNDS( L, CUR.pts.n_points ) )
4972 {
4973 if ( CUR.pedantic_hinting )
4974 CUR.error = TT_Err_Invalid_Reference;
4975 return;
4976 }
4978 for ( I = L; I <= K; I++ )
4979 CUR.pts.tags[I] &= ~FT_Curve_Tag_On;
4980 }
4983 static FT_Bool
4984 Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6* x,
4985 FT_F26Dot6* y,
4986 TT_GlyphZone* zone,
4987 FT_UShort* refp )
4988 {
4989 TT_GlyphZone zp;
4990 FT_UShort p;
4991 FT_F26Dot6 d;
4994 if ( CUR.opcode & 1 )
4995 {
4996 zp = CUR.zp0;
4997 p = CUR.GS.rp1;
4998 }
4999 else
5000 {
5001 zp = CUR.zp1;
5002 p = CUR.GS.rp2;
5003 }
5005 if ( BOUNDS( p, zp.n_points ) )
5006 {
5007 if ( CUR.pedantic_hinting )
5008 CUR.error = TT_Err_Invalid_Reference;
5009 return FAILURE;
5010 }
5012 *zone = zp;
5013 *refp = p;
5015 d = CUR_Func_project( zp.cur + p, zp.org + p );
5017 #ifdef NO_APPLE_PATENT
5019 *x = TT_MULDIV( d, CUR.GS.freeVector.x, 0x4000 );
5020 *y = TT_MULDIV( d, CUR.GS.freeVector.y, 0x4000 );
5022 #else
5024 *x = TT_MULDIV( d,
5025 (FT_Long)CUR.GS.freeVector.x * 0x10000L,
5026 CUR.F_dot_P );
5027 *y = TT_MULDIV( d,
5028 (FT_Long)CUR.GS.freeVector.y * 0x10000L,
5029 CUR.F_dot_P );
5031 #endif /* NO_APPLE_PATENT */
5033 return SUCCESS;
5034 }
5037 static void
5038 Move_Zp2_Point( EXEC_OP_ FT_UShort point,
5039 FT_F26Dot6 dx,
5040 FT_F26Dot6 dy,
5041 FT_Bool touch )
5042 {
5043 if ( CUR.GS.freeVector.x != 0 )
5044 {
5045 CUR.zp2.cur[point].x += dx;
5046 if ( touch )
5047 CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_X;
5048 }
5050 if ( CUR.GS.freeVector.y != 0 )
5051 {
5052 CUR.zp2.cur[point].y += dy;
5053 if ( touch )
5054 CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_Y;
5055 }
5056 }
5059 /*************************************************************************/
5060 /* */
5061 /* SHP[a]: SHift Point by the last point */
5062 /* Opcode range: 0x32-0x33 */
5063 /* Stack: uint32... --> */
5064 /* */
5065 static void
5066 Ins_SHP( INS_ARG )
5067 {
5068 TT_GlyphZone zp;
5069 FT_UShort refp;
5071 FT_F26Dot6 dx,
5072 dy;
5073 FT_UShort point;
5075 FT_UNUSED_ARG;
5078 if ( CUR.top < CUR.GS.loop )
5079 {
5080 CUR.error = TT_Err_Invalid_Reference;
5081 return;
5082 }
5084 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5085 return;
5087 while ( CUR.GS.loop > 0 )
5088 {
5089 CUR.args--;
5090 point = (FT_UShort)CUR.stack[CUR.args];
5092 if ( BOUNDS( point, CUR.zp2.n_points ) )
5093 {
5094 if ( CUR.pedantic_hinting )
5095 {
5096 CUR.error = TT_Err_Invalid_Reference;
5097 return;
5098 }
5099 }
5100 else
5101 /* XXX: UNDOCUMENTED! SHP touches the points */
5102 MOVE_Zp2_Point( point, dx, dy, TRUE );
5104 CUR.GS.loop--;
5105 }
5107 CUR.GS.loop = 1;
5108 CUR.new_top = CUR.args;
5109 }
5112 /*************************************************************************/
5113 /* */
5114 /* SHC[a]: SHift Contour */
5115 /* Opcode range: 0x34-35 */
5116 /* Stack: uint32 --> */
5117 /* */
5118 static void
5119 Ins_SHC( INS_ARG )
5120 {
5121 TT_GlyphZone zp;
5122 FT_UShort refp;
5123 FT_F26Dot6 dx,
5124 dy;
5126 FT_Short contour;
5127 FT_UShort first_point, last_point, i;
5130 contour = (FT_UShort)args[0];
5132 if ( BOUNDS( contour, CUR.pts.n_contours ) )
5133 {
5134 if ( CUR.pedantic_hinting )
5135 CUR.error = TT_Err_Invalid_Reference;
5136 return;
5137 }
5139 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5140 return;
5142 if ( contour == 0 )
5143 first_point = 0;
5144 else
5145 first_point = (FT_UShort)(CUR.pts.contours[contour - 1] + 1);
5147 last_point = CUR.pts.contours[contour];
5149 /* XXX: this is probably wrong... at least it prevents memory */
5150 /* corruption when zp2 is the twilight zone */
5151 if ( last_point > CUR.zp2.n_points )
5152 {
5153 if ( CUR.zp2.n_points > 0 )
5154 last_point = (FT_UShort)(CUR.zp2.n_points - 1);
5155 else
5156 last_point = 0;
5157 }
5159 /* XXX: UNDOCUMENTED! SHC doesn't touch the points */
5160 for ( i = first_point; i <= last_point; i++ )
5161 {
5162 if ( zp.cur != CUR.zp2.cur || refp != i )
5163 MOVE_Zp2_Point( i, dx, dy, FALSE );
5164 }
5165 }
5168 /*************************************************************************/
5169 /* */
5170 /* SHZ[a]: SHift Zone */
5171 /* Opcode range: 0x36-37 */
5172 /* Stack: uint32 --> */
5173 /* */
5174 static void
5175 Ins_SHZ( INS_ARG )
5176 {
5177 TT_GlyphZone zp;
5178 FT_UShort refp;
5179 FT_F26Dot6 dx,
5180 dy;
5182 FT_UShort last_point, i;
5185 if ( BOUNDS( args[0], 2 ) )
5186 {
5187 if ( CUR.pedantic_hinting )
5188 CUR.error = TT_Err_Invalid_Reference;
5189 return;
5190 }
5192 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5193 return;
5195 if ( CUR.zp2.n_points > 0 )
5196 last_point = (FT_UShort)(CUR.zp2.n_points - 1);
5197 else
5198 last_point = 0;
5200 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
5201 for ( i = 0; i <= last_point; i++ )
5202 {
5203 if ( zp.cur != CUR.zp2.cur || refp != i )
5204 MOVE_Zp2_Point( i, dx, dy, FALSE );
5205 }
5206 }
5209 /*************************************************************************/
5210 /* */
5211 /* SHPIX[]: SHift points by a PIXel amount */
5212 /* Opcode range: 0x38 */
5213 /* Stack: f26.6 uint32... --> */
5214 /* */
5215 static void
5216 Ins_SHPIX( INS_ARG )
5217 {
5218 FT_F26Dot6 dx, dy;
5219 FT_UShort point;
5222 if ( CUR.top < CUR.GS.loop + 1 )
5223 {
5224 CUR.error = TT_Err_Invalid_Reference;
5225 return;
5226 }
5228 dx = TT_MULDIV( args[0],
5229 (FT_Long)CUR.GS.freeVector.x,
5230 0x4000 );
5231 dy = TT_MULDIV( args[0],
5232 (FT_Long)CUR.GS.freeVector.y,
5233 0x4000 );
5235 while ( CUR.GS.loop > 0 )
5236 {
5237 CUR.args--;
5239 point = (FT_UShort)CUR.stack[CUR.args];
5241 if ( BOUNDS( point, CUR.zp2.n_points ) )
5242 {
5243 if ( CUR.pedantic_hinting )
5244 {
5245 CUR.error = TT_Err_Invalid_Reference;
5246 return;
5247 }
5248 }
5249 else
5250 MOVE_Zp2_Point( point, dx, dy, TRUE );
5252 CUR.GS.loop--;
5253 }
5255 CUR.GS.loop = 1;
5256 CUR.new_top = CUR.args;
5257 }
5260 /*************************************************************************/
5261 /* */
5262 /* MSIRP[a]: Move Stack Indirect Relative Position */
5263 /* Opcode range: 0x3A-0x3B */
5264 /* Stack: f26.6 uint32 --> */
5265 /* */
5266 static void
5267 Ins_MSIRP( INS_ARG )
5268 {
5269 FT_UShort point;
5270 FT_F26Dot6 distance;
5273 point = (FT_UShort)args[0];
5275 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5276 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5277 {
5278 if ( CUR.pedantic_hinting )
5279 CUR.error = TT_Err_Invalid_Reference;
5280 return;
5281 }
5283 /* XXX: UNDOCUMENTED! behaviour */
5284 if ( CUR.GS.gep0 == 0 ) /* if in twilight zone */
5285 {
5286 CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
5287 CUR.zp1.cur[point] = CUR.zp1.org[point];
5288 }
5290 distance = CUR_Func_project( CUR.zp1.cur + point,
5291 CUR.zp0.cur + CUR.GS.rp0 );
5293 CUR_Func_move( &CUR.zp1, point, args[1] - distance );
5295 CUR.GS.rp1 = CUR.GS.rp0;
5296 CUR.GS.rp2 = point;
5298 if ( (CUR.opcode & 1) != 0 )
5299 CUR.GS.rp0 = point;
5300 }
5303 /*************************************************************************/
5304 /* */
5305 /* MDAP[a]: Move Direct Absolute Point */
5306 /* Opcode range: 0x2E-0x2F */
5307 /* Stack: uint32 --> */
5308 /* */
5309 static void
5310 Ins_MDAP( INS_ARG )
5311 {
5312 FT_UShort point;
5313 FT_F26Dot6 cur_dist,
5314 distance;
5317 point = (FT_UShort)args[0];
5319 if ( BOUNDS( point, CUR.zp0.n_points ) )
5320 {
5321 if ( CUR.pedantic_hinting )
5322 CUR.error = TT_Err_Invalid_Reference;
5323 return;
5324 }
5326 /* XXX: Is there some undocumented feature while in the */
5327 /* twilight zone? ? */
5328 if ( ( CUR.opcode & 1 ) != 0 )
5329 {
5330 cur_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
5331 distance = CUR_Func_round( cur_dist,
5332 CUR.tt_metrics.compensations[0] ) - cur_dist;
5333 }
5334 else
5335 distance = 0;
5337 CUR_Func_move( &CUR.zp0, point, distance );
5339 CUR.GS.rp0 = point;
5340 CUR.GS.rp1 = point;
5341 }
5344 /*************************************************************************/
5345 /* */
5346 /* MIAP[a]: Move Indirect Absolute Point */
5347 /* Opcode range: 0x3E-0x3F */
5348 /* Stack: uint32 uint32 --> */
5349 /* */
5350 static void
5351 Ins_MIAP( INS_ARG )
5352 {
5353 FT_ULong cvtEntry;
5354 FT_UShort point;
5355 FT_F26Dot6 distance,
5356 org_dist;
5359 cvtEntry = (FT_ULong)args[1];
5360 point = (FT_UShort)args[0];
5362 if ( BOUNDS( point, CUR.zp0.n_points ) ||
5363 BOUNDS( cvtEntry, CUR.cvtSize ) )
5364 {
5365 if ( CUR.pedantic_hinting )
5366 CUR.error = TT_Err_Invalid_Reference;
5367 return;
5368 }
5370 /* UNDOCUMENTED! */
5371 /* */
5372 /* The behaviour of an MIAP instruction is quite */
5373 /* different when used in the twilight zone. */
5374 /* */
5375 /* First, no control value cutin test is performed */
5376 /* as it would fail anyway. Second, the original */
5377 /* point, i.e. (org_x,org_y) of zp0.point, is set */
5378 /* to the absolute, unrounded distance found in */
5379 /* the CVT. */
5380 /* */
5381 /* This is used in the CVT programs of the Microsoft */
5382 /* fonts Arial, Times, etc., in order to re-adjust */
5383 /* some key font heights. It allows the use of the */
5384 /* IP instruction in the twilight zone, which */
5385 /* otherwise would be `illegal' according to the */
5386 /* specification. */
5387 /* */
5388 /* We implement it with a special sequence for the */
5389 /* twilight zone. This is a bad hack, but it seems */
5390 /* to work. */
5392 distance = CUR_Func_read_cvt( cvtEntry );
5394 if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */
5395 {
5396 CUR.zp0.org[point].x = TT_MULDIV( CUR.GS.freeVector.x,
5397 distance, 0x4000 );
5398 CUR.zp0.org[point].y = TT_MULDIV( CUR.GS.freeVector.y,
5399 distance, 0x4000 );
5400 CUR.zp0.cur[point] = CUR.zp0.org[point];
5401 }
5403 org_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
5405 if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */
5406 {
5407 if ( ABS( distance - org_dist ) > CUR.GS.control_value_cutin )
5408 distance = org_dist;
5410 distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] );
5411 }
5413 CUR_Func_move( &CUR.zp0, point, distance - org_dist );
5415 CUR.GS.rp0 = point;
5416 CUR.GS.rp1 = point;
5417 }
5420 /*************************************************************************/
5421 /* */
5422 /* MDRP[abcde]: Move Direct Relative Point */
5423 /* Opcode range: 0xC0-0xDF */
5424 /* Stack: uint32 --> */
5425 /* */
5426 static void
5427 Ins_MDRP( INS_ARG )
5428 {
5429 FT_UShort point;
5430 FT_F26Dot6 org_dist, distance;
5433 point = (FT_UShort)args[0];
5435 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5436 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5437 {
5438 if ( CUR.pedantic_hinting )
5439 CUR.error = TT_Err_Invalid_Reference;
5440 return;
5441 }
5443 /* XXX: Is there some undocumented feature while in the */
5444 /* twilight zone? */
5446 org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
5447 CUR.zp0.org + CUR.GS.rp0 );
5449 /* single width cutin test */
5451 if ( ABS( org_dist ) < CUR.GS.single_width_cutin )
5452 {
5453 if ( org_dist >= 0 )
5454 org_dist = CUR.GS.single_width_value;
5455 else
5456 org_dist = -CUR.GS.single_width_value;
5457 }
5459 /* round flag */
5461 if ( ( CUR.opcode & 4 ) != 0 )
5462 distance = CUR_Func_round(
5463 org_dist,
5464 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5465 else
5466 distance = ROUND_None(
5467 org_dist,
5468 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5470 /* minimum distance flag */
5472 if ( ( CUR.opcode & 8 ) != 0 )
5473 {
5474 if ( org_dist >= 0 )
5475 {
5476 if ( distance < CUR.GS.minimum_distance )
5477 distance = CUR.GS.minimum_distance;
5478 }
5479 else
5480 {
5481 if ( distance > -CUR.GS.minimum_distance )
5482 distance = -CUR.GS.minimum_distance;
5483 }
5484 }
5486 /* now move the point */
5488 org_dist = CUR_Func_project( CUR.zp1.cur + point,
5489 CUR.zp0.cur + CUR.GS.rp0 );
5491 CUR_Func_move( &CUR.zp1, point, distance - org_dist );
5493 CUR.GS.rp1 = CUR.GS.rp0;
5494 CUR.GS.rp2 = point;
5496 if ( ( CUR.opcode & 16 ) != 0 )
5497 CUR.GS.rp0 = point;
5498 }
5501 /*************************************************************************/
5502 /* */
5503 /* MIRP[abcde]: Move Indirect Relative Point */
5504 /* Opcode range: 0xE0-0xFF */
5505 /* Stack: int32? uint32 --> */
5506 /* */
5507 static void
5508 Ins_MIRP( INS_ARG )
5509 {
5510 FT_UShort point;
5511 FT_ULong cvtEntry;
5513 FT_F26Dot6 cvt_dist,
5514 distance,
5515 cur_dist,
5516 org_dist;
5519 point = (FT_UShort)args[0];
5520 cvtEntry = (FT_ULong)( args[1] + 1 );
5522 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
5524 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5525 BOUNDS( cvtEntry, CUR.cvtSize + 1 ) ||
5526 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5527 {
5528 if ( CUR.pedantic_hinting )
5529 CUR.error = TT_Err_Invalid_Reference;
5530 return;
5531 }
5533 if ( !cvtEntry )
5534 cvt_dist = 0;
5535 else
5536 cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
5538 /* single width test */
5540 if ( ABS( cvt_dist ) < CUR.GS.single_width_cutin )
5541 {
5542 if ( cvt_dist >= 0 )
5543 cvt_dist = CUR.GS.single_width_value;
5544 else
5545 cvt_dist = -CUR.GS.single_width_value;
5546 }
5548 /* XXX: UNDOCUMENTED! -- twilight zone */
5550 if ( CUR.GS.gep1 == 0 )
5551 {
5552 CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +
5553 TT_MULDIV( cvt_dist,
5554 CUR.GS.freeVector.x,
5555 0x4000 );
5557 CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
5558 TT_MULDIV( cvt_dist,
5559 CUR.GS.freeVector.y,
5560 0x4000 );
5562 CUR.zp1.cur[point] = CUR.zp1.org[point];
5563 }
5565 org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
5566 CUR.zp0.org + CUR.GS.rp0 );
5568 cur_dist = CUR_Func_project( CUR.zp1.cur + point,
5569 CUR.zp0.cur + CUR.GS.rp0 );
5571 /* auto-flip test */
5573 if ( CUR.GS.auto_flip )
5574 {
5575 if ( ( org_dist ^ cvt_dist ) < 0 )
5576 cvt_dist = -cvt_dist;
5577 }
5579 /* control value cutin and round */
5581 if ( ( CUR.opcode & 4 ) != 0 )
5582 {
5583 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
5584 /* refer to the same zone. */
5586 if ( CUR.GS.gep0 == CUR.GS.gep1 )
5587 if ( ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin )
5588 cvt_dist = org_dist;
5590 distance = CUR_Func_round(
5591 cvt_dist,
5592 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5593 }
5594 else
5595 distance = ROUND_None(
5596 cvt_dist,
5597 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5599 /* minimum distance test */
5601 if ( ( CUR.opcode & 8 ) != 0 )
5602 {
5603 if ( org_dist >= 0 )
5604 {
5605 if ( distance < CUR.GS.minimum_distance )
5606 distance = CUR.GS.minimum_distance;
5607 }
5608 else
5609 {
5610 if ( distance > -CUR.GS.minimum_distance )
5611 distance = -CUR.GS.minimum_distance;
5612 }
5613 }
5615 CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
5617 CUR.GS.rp1 = CUR.GS.rp0;
5619 if ( ( CUR.opcode & 16 ) != 0 )
5620 CUR.GS.rp0 = point;
5622 /* XXX: UNDOCUMENTED! */
5624 CUR.GS.rp2 = point;
5625 }
5628 /*************************************************************************/
5629 /* */
5630 /* ALIGNRP[]: ALIGN Relative Point */
5631 /* Opcode range: 0x3C */
5632 /* Stack: uint32 uint32... --> */
5633 /* */
5634 static void
5635 Ins_ALIGNRP( INS_ARG )
5636 {
5637 FT_UShort point;
5638 FT_F26Dot6 distance;
5640 FT_UNUSED_ARG;
5643 if ( CUR.top < CUR.GS.loop ||
5644 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5645 {
5646 if ( CUR.pedantic_hinting )
5647 CUR.error = TT_Err_Invalid_Reference;
5648 return;
5649 }
5651 while ( CUR.GS.loop > 0 )
5652 {
5653 CUR.args--;
5655 point = (FT_UShort)CUR.stack[CUR.args];
5657 if ( BOUNDS( point, CUR.zp1.n_points ) )
5658 {
5659 if ( CUR.pedantic_hinting )
5660 {
5661 CUR.error = TT_Err_Invalid_Reference;
5662 return;
5663 }
5664 }
5665 else
5666 {
5667 distance = CUR_Func_project( CUR.zp1.cur + point,
5668 CUR.zp0.cur + CUR.GS.rp0 );
5670 CUR_Func_move( &CUR.zp1, point, -distance );
5671 }
5673 CUR.GS.loop--;
5674 }
5676 CUR.GS.loop = 1;
5677 CUR.new_top = CUR.args;
5678 }
5681 /*************************************************************************/
5682 /* */
5683 /* ISECT[]: moves point to InterSECTion */
5684 /* Opcode range: 0x0F */
5685 /* Stack: 5 * uint32 --> */
5686 /* */
5687 static void
5688 Ins_ISECT( INS_ARG )
5689 {
5690 FT_UShort point,
5691 a0, a1,
5692 b0, b1;
5694 FT_F26Dot6 discriminant;
5696 FT_F26Dot6 dx, dy,
5697 dax, day,
5698 dbx, dby;
5700 FT_F26Dot6 val;
5702 FT_Vector R;
5705 point = (FT_UShort)args[0];
5707 a0 = (FT_UShort)args[1];
5708 a1 = (FT_UShort)args[2];
5709 b0 = (FT_UShort)args[3];
5710 b1 = (FT_UShort)args[4];
5712 if ( BOUNDS( b0, CUR.zp0.n_points ) ||
5713 BOUNDS( b1, CUR.zp0.n_points ) ||
5714 BOUNDS( a0, CUR.zp1.n_points ) ||
5715 BOUNDS( a1, CUR.zp1.n_points ) ||
5716 BOUNDS( point, CUR.zp2.n_points ) )
5717 {
5718 if ( CUR.pedantic_hinting )
5719 CUR.error = TT_Err_Invalid_Reference;
5720 return;
5721 }
5723 dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
5724 dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
5726 dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;
5727 day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;
5729 dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;
5730 dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;
5732 CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_Both;
5734 discriminant = TT_MULDIV( dax, -dby, 0x40 ) +
5735 TT_MULDIV( day, dbx, 0x40 );
5737 if ( ABS( discriminant ) >= 0x40 )
5738 {
5739 val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 );
5741 R.x = TT_MULDIV( val, dax, discriminant );
5742 R.y = TT_MULDIV( val, day, discriminant );
5744 CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
5745 CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
5746 }
5747 else
5748 {
5749 /* else, take the middle of the middles of A and B */
5751 CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +
5752 CUR.zp1.cur[a1].x +
5753 CUR.zp0.cur[b0].x +
5754 CUR.zp0.cur[b1].x ) / 4;
5755 CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +
5756 CUR.zp1.cur[a1].y +
5757 CUR.zp0.cur[b0].y +
5758 CUR.zp0.cur[b1].y ) / 4;
5759 }
5760 }
5763 /*************************************************************************/
5764 /* */
5765 /* ALIGNPTS[]: ALIGN PoinTS */
5766 /* Opcode range: 0x27 */
5767 /* Stack: uint32 uint32 --> */
5768 /* */
5769 static void
5770 Ins_ALIGNPTS( INS_ARG )
5771 {
5772 FT_UShort p1, p2;
5773 FT_F26Dot6 distance;
5776 p1 = (FT_UShort)args[0];
5777 p2 = (FT_UShort)args[1];
5779 if ( BOUNDS( args[0], CUR.zp1.n_points ) ||
5780 BOUNDS( args[1], CUR.zp0.n_points ) )
5781 {
5782 if ( CUR.pedantic_hinting )
5783 CUR.error = TT_Err_Invalid_Reference;
5784 return;
5785 }
5787 distance = CUR_Func_project( CUR.zp0.cur + p2,
5788 CUR.zp1.cur + p1 ) / 2;
5790 CUR_Func_move( &CUR.zp1, p1, distance );
5791 CUR_Func_move( &CUR.zp0, p2, -distance );
5792 }
5795 /*************************************************************************/
5796 /* */
5797 /* IP[]: Interpolate Point */
5798 /* Opcode range: 0x39 */
5799 /* Stack: uint32... --> */
5800 /* */
5801 static void
5802 Ins_IP( INS_ARG )
5803 {
5804 FT_F26Dot6 org_a, org_b, org_x,
5805 cur_a, cur_b, cur_x,
5806 distance;
5807 FT_UShort point;
5809 FT_UNUSED_ARG;
5812 if ( CUR.top < CUR.GS.loop )
5813 {
5814 CUR.error = TT_Err_Invalid_Reference;
5815 return;
5816 }
5818 /* XXX: There are some glyphs in some braindead but popular */
5819 /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
5820 /* calling IP[] with bad values of rp[12]. */
5821 /* Do something sane when this odd thing happens. */
5823 if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
5824 BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
5825 {
5826 org_a = cur_a = 0;
5827 org_b = cur_b = 0;
5828 }
5829 else
5830 {
5831 org_a = CUR_Func_dualproj( CUR.zp0.org + CUR.GS.rp1, NULL_Vector );
5832 org_b = CUR_Func_dualproj( CUR.zp1.org + CUR.GS.rp2, NULL_Vector );
5834 cur_a = CUR_Func_project( CUR.zp0.cur + CUR.GS.rp1, NULL_Vector );
5835 cur_b = CUR_Func_project( CUR.zp1.cur + CUR.GS.rp2, NULL_Vector );
5836 }
5838 while ( CUR.GS.loop > 0 )
5839 {
5840 CUR.args--;
5842 point = (FT_UShort)CUR.stack[CUR.args];
5843 if ( BOUNDS( point, CUR.zp2.n_points ) )
5844 {
5845 if ( CUR.pedantic_hinting )
5846 {
5847 CUR.error = TT_Err_Invalid_Reference;
5848 return;
5849 }
5850 }
5851 else
5852 {
5853 org_x = CUR_Func_dualproj( CUR.zp2.org + point, NULL_Vector );
5854 cur_x = CUR_Func_project ( CUR.zp2.cur + point, NULL_Vector );
5856 if ( ( org_a <= org_b && org_x <= org_a ) ||
5857 ( org_a > org_b && org_x >= org_a ) )
5859 distance = ( cur_a - org_a ) + ( org_x - cur_x );
5861 else if ( ( org_a <= org_b && org_x >= org_b ) ||
5862 ( org_a > org_b && org_x < org_b ) )
5864 distance = ( cur_b - org_b ) + ( org_x - cur_x );
5866 else
5867 /* note: it seems that rounding this value isn't a good */
5868 /* idea (cf. width of capital `S' in Times) */
5870 distance = TT_MULDIV( cur_b - cur_a,
5871 org_x - org_a,
5872 org_b - org_a ) + ( cur_a - cur_x );
5874 CUR_Func_move( &CUR.zp2, point, distance );
5875 }
5877 CUR.GS.loop--;
5878 }
5880 CUR.GS.loop = 1;
5881 CUR.new_top = CUR.args;
5882 }
5885 /*************************************************************************/
5886 /* */
5887 /* UTP[a]: UnTouch Point */
5888 /* Opcode range: 0x29 */
5889 /* Stack: uint32 --> */
5890 /* */
5891 static void
5892 Ins_UTP( INS_ARG )
5893 {
5894 FT_UShort point;
5895 FT_Byte mask;
5898 point = (FT_UShort)args[0];
5900 if ( BOUNDS( point, CUR.zp0.n_points ) )
5901 {
5902 if ( CUR.pedantic_hinting )
5903 CUR.error = TT_Err_Invalid_Reference;
5904 return;
5905 }
5907 mask = 0xFF;
5909 if ( CUR.GS.freeVector.x != 0 )
5910 mask &= ~FT_Curve_Tag_Touch_X;
5912 if ( CUR.GS.freeVector.y != 0 )
5913 mask &= ~FT_Curve_Tag_Touch_Y;
5915 CUR.zp0.tags[point] &= mask;
5916 }
5919 /* Local variables for Ins_IUP: */
5920 struct LOC_Ins_IUP
5921 {
5922 FT_Vector* orgs; /* original and current coordinate */
5923 FT_Vector* curs; /* arrays */
5924 };
5927 static void
5928 Shift( FT_UInt p1,
5929 FT_UInt p2,
5930 FT_UInt p,
5931 struct LOC_Ins_IUP* LINK )
5932 {
5933 FT_UInt i;
5934 FT_F26Dot6 x;
5937 x = LINK->curs[p].x - LINK->orgs[p].x;
5939 for ( i = p1; i < p; i++ )
5940 LINK->curs[i].x += x;
5942 for ( i = p + 1; i <= p2; i++ )
5943 LINK->curs[i].x += x;
5944 }
5947 static void
5948 Interp( FT_UInt p1,
5949 FT_UInt p2,
5950 FT_UInt ref1,
5951 FT_UInt ref2,
5952 struct LOC_Ins_IUP* LINK )
5953 {
5954 FT_UInt i;
5955 FT_F26Dot6 x, x1, x2, d1, d2;
5958 if ( p1 > p2 )
5959 return;
5961 x1 = LINK->orgs[ref1].x;
5962 d1 = LINK->curs[ref1].x - LINK->orgs[ref1].x;
5963 x2 = LINK->orgs[ref2].x;
5964 d2 = LINK->curs[ref2].x - LINK->orgs[ref2].x;
5966 if ( x1 == x2 )
5967 {
5968 for ( i = p1; i <= p2; i++ )
5969 {
5970 x = LINK->orgs[i].x;
5972 if ( x <= x1 )
5973 x += d1;
5974 else
5975 x += d2;
5977 LINK->curs[i].x = x;
5978 }
5979 return;
5980 }
5982 if ( x1 < x2 )
5983 {
5984 for ( i = p1; i <= p2; i++ )
5985 {
5986 x = LINK->orgs[i].x;
5988 if ( x <= x1 )
5989 x += d1;
5990 else
5991 {
5992 if ( x >= x2 )
5993 x += d2;
5994 else
5995 x = LINK->curs[ref1].x +
5996 TT_MULDIV( x - x1,
5997 LINK->curs[ref2].x - LINK->curs[ref1].x,
5998 x2 - x1 );
5999 }
6000 LINK->curs[i].x = x;
6001 }
6002 return;
6003 }
6005 /* x2 < x1 */
6007 for ( i = p1; i <= p2; i++ )
6008 {
6009 x = LINK->orgs[i].x;
6010 if ( x <= x2 )
6011 x += d2;
6012 else
6013 {
6014 if ( x >= x1 )
6015 x += d1;
6016 else
6017 x = LINK->curs[ref1].x +
6018 TT_MULDIV( x - x1,
6019 LINK->curs[ref2].x - LINK->curs[ref1].x,
6020 x2 - x1 );
6021 }
6022 LINK->curs[i].x = x;
6023 }
6024 }
6027 /*************************************************************************/
6028 /* */
6029 /* IUP[a]: Interpolate Untouched Points */
6030 /* Opcode range: 0x30-0x31 */
6031 /* Stack: --> */
6032 /* */
6033 static void
6034 Ins_IUP( INS_ARG )
6035 {
6036 struct LOC_Ins_IUP V;
6037 FT_Byte mask;
6039 FT_UInt first_point; /* first point of contour */
6040 FT_UInt end_point; /* end point (last+1) of contour */
6042 FT_UInt first_touched; /* first touched point in contour */
6043 FT_UInt cur_touched; /* current touched point in contour */
6045 FT_UInt point; /* current point */
6046 FT_Short contour; /* current contour */
6048 FT_UNUSED_ARG;
6051 if ( CUR.opcode & 1 )
6052 {
6053 mask = FT_Curve_Tag_Touch_X;
6054 V.orgs = CUR.pts.org;
6055 V.curs = CUR.pts.cur;
6056 }
6057 else
6058 {
6059 mask = FT_Curve_Tag_Touch_Y;
6060 V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
6061 V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
6062 }
6064 contour = 0;
6065 point = 0;
6067 do
6068 {
6069 end_point = CUR.pts.contours[contour];
6070 first_point = point;
6072 while ( point <= end_point && (CUR.pts.tags[point] & mask) == 0 )
6073 point++;
6075 if ( point <= end_point )
6076 {
6077 first_touched = point;
6078 cur_touched = point;
6080 point++;
6082 while ( point <= end_point )
6083 {
6084 if ( ( CUR.pts.tags[point] & mask ) != 0 )
6085 {
6086 if ( point > 0 )
6087 Interp( cur_touched + 1,
6088 point - 1,
6089 cur_touched,
6090 point,
6091 &V );
6092 cur_touched = point;
6093 }
6095 point++;
6096 }
6098 if ( cur_touched == first_touched )
6099 Shift( first_point, end_point, cur_touched, &V );
6100 else
6101 {
6102 Interp( (FT_UShort)( cur_touched + 1 ),
6103 end_point,
6104 cur_touched,
6105 first_touched,
6106 &V );
6108 if ( first_touched > 0 )
6109 Interp( first_point,
6110 first_touched - 1,
6111 cur_touched,
6112 first_touched,
6113 &V );
6114 }
6115 }
6116 contour++;
6117 } while ( contour < CUR.pts.n_contours );
6118 }
6121 /*************************************************************************/
6122 /* */
6123 /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
6124 /* Opcode range: 0x5D,0x71,0x72 */
6125 /* Stack: uint32 (2 * uint32)... --> */
6126 /* */
6127 static void
6128 Ins_DELTAP( INS_ARG )
6129 {
6130 FT_ULong k, nump;
6131 FT_UShort A;
6132 FT_ULong C;
6133 FT_Long B;
6136 nump = (FT_ULong)args[0]; /* some points theoretically may occur more
6137 than once, thus UShort isn't enough */
6139 for ( k = 1; k <= nump; k++ )
6140 {
6141 if ( CUR.args < 2 )
6142 {
6143 CUR.error = TT_Err_Too_Few_Arguments;
6144 return;
6145 }
6147 CUR.args -= 2;
6149 A = (FT_UShort)CUR.stack[CUR.args + 1];
6150 B = CUR.stack[CUR.args];
6152 /* XXX: Because some popular fonts contain some invalid DeltaP */
6153 /* instructions, we simply ignore them when the stacked */
6154 /* point reference is off limit, rather than returning an */
6155 /* error. As a delta instruction doesn't change a glyph */
6156 /* in great ways, this shouldn't be a problem. */
6158 if ( !BOUNDS( A, CUR.zp0.n_points ) )
6159 {
6160 C = ( (FT_ULong)B & 0xF0 ) >> 4;
6162 switch ( CUR.opcode )
6163 {
6164 case 0x5D:
6165 break;
6167 case 0x71:
6168 C += 16;
6169 break;
6171 case 0x72:
6172 C += 32;
6173 break;
6174 }
6176 C += CUR.GS.delta_base;
6178 if ( CURRENT_Ppem() == (FT_Long)C )
6179 {
6180 B = ( (FT_ULong)B & 0xF ) - 8;
6181 if ( B >= 0 )
6182 B++;
6183 B = B * 64 / ( 1L << CUR.GS.delta_shift );
6185 CUR_Func_move( &CUR.zp0, A, B );
6186 }
6187 }
6188 else
6189 if ( CUR.pedantic_hinting )
6190 CUR.error = TT_Err_Invalid_Reference;
6191 }
6193 CUR.new_top = CUR.args;
6194 }
6197 /*************************************************************************/
6198 /* */
6199 /* DELTACn[]: DELTA exceptions C1, C2, C3 */
6200 /* Opcode range: 0x73,0x74,0x75 */
6201 /* Stack: uint32 (2 * uint32)... --> */
6202 /* */
6203 static void
6204 Ins_DELTAC( INS_ARG )
6205 {
6206 FT_ULong nump, k;
6207 FT_ULong A, C;
6208 FT_Long B;
6211 nump = (FT_ULong)args[0];
6213 for ( k = 1; k <= nump; k++ )
6214 {
6215 if ( CUR.args < 2 )
6216 {
6217 CUR.error = TT_Err_Too_Few_Arguments;
6218 return;
6219 }
6221 CUR.args -= 2;
6223 A = (FT_ULong)CUR.stack[CUR.args + 1];
6224 B = CUR.stack[CUR.args];
6226 if ( BOUNDS( A, CUR.cvtSize ) )
6227 {
6228 if ( CUR.pedantic_hinting )
6229 {
6230 CUR.error = TT_Err_Invalid_Reference;
6231 return;
6232 }
6233 }
6234 else
6235 {
6236 C = ( (FT_ULong)B & 0xF0 ) >> 4;
6238 switch ( CUR.opcode )
6239 {
6240 case 0x73:
6241 break;
6243 case 0x74:
6244 C += 16;
6245 break;
6247 case 0x75:
6248 C += 32;
6249 break;
6250 }
6252 C += CUR.GS.delta_base;
6254 if ( CURRENT_Ppem() == (FT_Long)C )
6255 {
6256 B = ( (FT_ULong)B & 0xF ) - 8;
6257 if ( B >= 0 )
6258 B++;
6259 B = B * 64 / ( 1L << CUR.GS.delta_shift );
6261 CUR_Func_move_cvt( A, B );
6262 }
6263 }
6264 }
6266 CUR.new_top = CUR.args;
6267 }
6270 /*************************************************************************/
6271 /* */
6272 /* MISC. INSTRUCTIONS */
6273 /* */
6274 /*************************************************************************/
6277 /*************************************************************************/
6278 /* */
6279 /* GETINFO[]: GET INFOrmation */
6280 /* Opcode range: 0x88 */
6281 /* Stack: uint32 --> uint32 */
6282 /* */
6283 /* XXX: According to Apple specs, bits 1 & 2 of the argument ought to be */
6284 /* consulted before rotated/stretched info is returned. */
6285 static void
6286 Ins_GETINFO( INS_ARG )
6287 {
6288 FT_Long K;
6291 K = 0;
6293 /* We return then Windows 3.1 version number */
6294 /* for the font scaler */
6295 if ( ( args[0] & 1 ) != 0 )
6296 K = 3;
6298 /* Has the glyph been rotated ? */
6299 if ( CUR.tt_metrics.rotated )
6300 K |= 0x80;
6302 /* Has the glyph been stretched ? */
6303 if ( CUR.tt_metrics.stretched )
6304 K |= 0x100;
6306 args[0] = K;
6307 }
6310 static void
6311 Ins_UNKNOWN( INS_ARG )
6312 {
6313 TT_DefRecord* def = CUR.IDefs;
6314 TT_DefRecord* limit = def + CUR.numIDefs;
6316 FT_UNUSED_ARG;
6319 for ( ; def < limit; def++ )
6320 {
6321 if ( (FT_Byte)def->opc == CUR.opcode && def->active )
6322 {
6323 TT_CallRec* call;
6326 if ( CUR.callTop >= CUR.callSize )
6327 {
6328 CUR.error = TT_Err_Stack_Overflow;
6329 return;
6330 }
6332 call = CUR.callStack + CUR.callTop++;
6334 call->Caller_Range = CUR.curRange;
6335 call->Caller_IP = CUR.IP+1;
6336 call->Cur_Count = 1;
6337 call->Cur_Restart = def->start;
6339 INS_Goto_CodeRange( def->range, def->start );
6341 CUR.step_ins = FALSE;
6342 return;
6343 }
6344 }
6346 CUR.error = TT_Err_Invalid_Opcode;
6347 }
6350 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
6353 static
6354 TInstruction_Function Instruct_Dispatch[256] =
6355 {
6356 /* Opcodes are gathered in groups of 16. */
6357 /* Please keep the spaces as they are. */
6359 /* SVTCA y */ Ins_SVTCA,
6360 /* SVTCA x */ Ins_SVTCA,
6361 /* SPvTCA y */ Ins_SPVTCA,
6362 /* SPvTCA x */ Ins_SPVTCA,
6363 /* SFvTCA y */ Ins_SFVTCA,
6364 /* SFvTCA x */ Ins_SFVTCA,
6365 /* SPvTL // */ Ins_SPVTL,
6366 /* SPvTL + */ Ins_SPVTL,
6367 /* SFvTL // */ Ins_SFVTL,
6368 /* SFvTL + */ Ins_SFVTL,
6369 /* SPvFS */ Ins_SPVFS,
6370 /* SFvFS */ Ins_SFVFS,
6371 /* GPV */ Ins_GPV,
6372 /* GFV */ Ins_GFV,
6373 /* SFvTPv */ Ins_SFVTPV,
6374 /* ISECT */ Ins_ISECT,
6376 /* SRP0 */ Ins_SRP0,
6377 /* SRP1 */ Ins_SRP1,
6378 /* SRP2 */ Ins_SRP2,
6379 /* SZP0 */ Ins_SZP0,
6380 /* SZP1 */ Ins_SZP1,
6381 /* SZP2 */ Ins_SZP2,
6382 /* SZPS */ Ins_SZPS,
6383 /* SLOOP */ Ins_SLOOP,
6384 /* RTG */ Ins_RTG,
6385 /* RTHG */ Ins_RTHG,
6386 /* SMD */ Ins_SMD,
6387 /* ELSE */ Ins_ELSE,
6388 /* JMPR */ Ins_JMPR,
6389 /* SCvTCi */ Ins_SCVTCI,
6390 /* SSwCi */ Ins_SSWCI,
6391 /* SSW */ Ins_SSW,
6393 /* DUP */ Ins_DUP,
6394 /* POP */ Ins_POP,
6395 /* CLEAR */ Ins_CLEAR,
6396 /* SWAP */ Ins_SWAP,
6397 /* DEPTH */ Ins_DEPTH,
6398 /* CINDEX */ Ins_CINDEX,
6399 /* MINDEX */ Ins_MINDEX,
6400 /* AlignPTS */ Ins_ALIGNPTS,
6401 /* INS_0x28 */ Ins_UNKNOWN,
6402 /* UTP */ Ins_UTP,
6403 /* LOOPCALL */ Ins_LOOPCALL,
6404 /* CALL */ Ins_CALL,
6405 /* FDEF */ Ins_FDEF,
6406 /* ENDF */ Ins_ENDF,
6407 /* MDAP[0] */ Ins_MDAP,
6408 /* MDAP[1] */ Ins_MDAP,
6410 /* IUP[0] */ Ins_IUP,
6411 /* IUP[1] */ Ins_IUP,
6412 /* SHP[0] */ Ins_SHP,
6413 /* SHP[1] */ Ins_SHP,
6414 /* SHC[0] */ Ins_SHC,
6415 /* SHC[1] */ Ins_SHC,
6416 /* SHZ[0] */ Ins_SHZ,
6417 /* SHZ[1] */ Ins_SHZ,
6418 /* SHPIX */ Ins_SHPIX,
6419 /* IP */ Ins_IP,
6420 /* MSIRP[0] */ Ins_MSIRP,
6421 /* MSIRP[1] */ Ins_MSIRP,
6422 /* AlignRP */ Ins_ALIGNRP,
6423 /* RTDG */ Ins_RTDG,
6424 /* MIAP[0] */ Ins_MIAP,
6425 /* MIAP[1] */ Ins_MIAP,
6427 /* NPushB */ Ins_NPUSHB,
6428 /* NPushW */ Ins_NPUSHW,
6429 /* WS */ Ins_WS,
6430 /* RS */ Ins_RS,
6431 /* WCvtP */ Ins_WCVTP,
6432 /* RCvt */ Ins_RCVT,
6433 /* GC[0] */ Ins_GC,
6434 /* GC[1] */ Ins_GC,
6435 /* SCFS */ Ins_SCFS,
6436 /* MD[0] */ Ins_MD,
6437 /* MD[1] */ Ins_MD,
6438 /* MPPEM */ Ins_MPPEM,
6439 /* MPS */ Ins_MPS,
6440 /* FlipON */ Ins_FLIPON,
6441 /* FlipOFF */ Ins_FLIPOFF,
6442 /* DEBUG */ Ins_DEBUG,
6444 /* LT */ Ins_LT,
6445 /* LTEQ */ Ins_LTEQ,
6446 /* GT */ Ins_GT,
6447 /* GTEQ */ Ins_GTEQ,
6448 /* EQ */ Ins_EQ,
6449 /* NEQ */ Ins_NEQ,
6450 /* ODD */ Ins_ODD,
6451 /* EVEN */ Ins_EVEN,
6452 /* IF */ Ins_IF,
6453 /* EIF */ Ins_EIF,
6454 /* AND */ Ins_AND,
6455 /* OR */ Ins_OR,
6456 /* NOT */ Ins_NOT,
6457 /* DeltaP1 */ Ins_DELTAP,
6458 /* SDB */ Ins_SDB,
6459 /* SDS */ Ins_SDS,
6461 /* ADD */ Ins_ADD,
6462 /* SUB */ Ins_SUB,
6463 /* DIV */ Ins_DIV,
6464 /* MUL */ Ins_MUL,
6465 /* ABS */ Ins_ABS,
6466 /* NEG */ Ins_NEG,
6467 /* FLOOR */ Ins_FLOOR,
6468 /* CEILING */ Ins_CEILING,
6469 /* ROUND[0] */ Ins_ROUND,
6470 /* ROUND[1] */ Ins_ROUND,
6471 /* ROUND[2] */ Ins_ROUND,
6472 /* ROUND[3] */ Ins_ROUND,
6473 /* NROUND[0] */ Ins_NROUND,
6474 /* NROUND[1] */ Ins_NROUND,
6475 /* NROUND[2] */ Ins_NROUND,
6476 /* NROUND[3] */ Ins_NROUND,
6478 /* WCvtF */ Ins_WCVTF,
6479 /* DeltaP2 */ Ins_DELTAP,
6480 /* DeltaP3 */ Ins_DELTAP,
6481 /* DeltaCn[0] */ Ins_DELTAC,
6482 /* DeltaCn[1] */ Ins_DELTAC,
6483 /* DeltaCn[2] */ Ins_DELTAC,
6484 /* SROUND */ Ins_SROUND,
6485 /* S45Round */ Ins_S45ROUND,
6486 /* JROT */ Ins_JROT,
6487 /* JROF */ Ins_JROF,
6488 /* ROFF */ Ins_ROFF,
6489 /* INS_0x7B */ Ins_UNKNOWN,
6490 /* RUTG */ Ins_RUTG,
6491 /* RDTG */ Ins_RDTG,
6492 /* SANGW */ Ins_SANGW,
6493 /* AA */ Ins_AA,
6495 /* FlipPT */ Ins_FLIPPT,
6496 /* FlipRgON */ Ins_FLIPRGON,
6497 /* FlipRgOFF */ Ins_FLIPRGOFF,
6498 /* INS_0x83 */ Ins_UNKNOWN,
6499 /* INS_0x84 */ Ins_UNKNOWN,
6500 /* ScanCTRL */ Ins_SCANCTRL,
6501 /* SDPVTL[0] */ Ins_SDPVTL,
6502 /* SDPVTL[1] */ Ins_SDPVTL,
6503 /* GetINFO */ Ins_GETINFO,
6504 /* IDEF */ Ins_IDEF,
6505 /* ROLL */ Ins_ROLL,
6506 /* MAX */ Ins_MAX,
6507 /* MIN */ Ins_MIN,
6508 /* ScanTYPE */ Ins_SCANTYPE,
6509 /* InstCTRL */ Ins_INSTCTRL,
6510 /* INS_0x8F */ Ins_UNKNOWN,
6512 /* INS_0x90 */ Ins_UNKNOWN,
6513 /* INS_0x91 */ Ins_UNKNOWN,
6514 /* INS_0x92 */ Ins_UNKNOWN,
6515 /* INS_0x93 */ Ins_UNKNOWN,
6516 /* INS_0x94 */ Ins_UNKNOWN,
6517 /* INS_0x95 */ Ins_UNKNOWN,
6518 /* INS_0x96 */ Ins_UNKNOWN,
6519 /* INS_0x97 */ Ins_UNKNOWN,
6520 /* INS_0x98 */ Ins_UNKNOWN,
6521 /* INS_0x99 */ Ins_UNKNOWN,
6522 /* INS_0x9A */ Ins_UNKNOWN,
6523 /* INS_0x9B */ Ins_UNKNOWN,
6524 /* INS_0x9C */ Ins_UNKNOWN,
6525 /* INS_0x9D */ Ins_UNKNOWN,
6526 /* INS_0x9E */ Ins_UNKNOWN,
6527 /* INS_0x9F */ Ins_UNKNOWN,
6529 /* INS_0xA0 */ Ins_UNKNOWN,
6530 /* INS_0xA1 */ Ins_UNKNOWN,
6531 /* INS_0xA2 */ Ins_UNKNOWN,
6532 /* INS_0xA3 */ Ins_UNKNOWN,
6533 /* INS_0xA4 */ Ins_UNKNOWN,
6534 /* INS_0xA5 */ Ins_UNKNOWN,
6535 /* INS_0xA6 */ Ins_UNKNOWN,
6536 /* INS_0xA7 */ Ins_UNKNOWN,
6537 /* INS_0xA8 */ Ins_UNKNOWN,
6538 /* INS_0xA9 */ Ins_UNKNOWN,
6539 /* INS_0xAA */ Ins_UNKNOWN,
6540 /* INS_0xAB */ Ins_UNKNOWN,
6541 /* INS_0xAC */ Ins_UNKNOWN,
6542 /* INS_0xAD */ Ins_UNKNOWN,
6543 /* INS_0xAE */ Ins_UNKNOWN,
6544 /* INS_0xAF */ Ins_UNKNOWN,
6546 /* PushB[0] */ Ins_PUSHB,
6547 /* PushB[1] */ Ins_PUSHB,
6548 /* PushB[2] */ Ins_PUSHB,
6549 /* PushB[3] */ Ins_PUSHB,
6550 /* PushB[4] */ Ins_PUSHB,
6551 /* PushB[5] */ Ins_PUSHB,
6552 /* PushB[6] */ Ins_PUSHB,
6553 /* PushB[7] */ Ins_PUSHB,
6554 /* PushW[0] */ Ins_PUSHW,
6555 /* PushW[1] */ Ins_PUSHW,
6556 /* PushW[2] */ Ins_PUSHW,
6557 /* PushW[3] */ Ins_PUSHW,
6558 /* PushW[4] */ Ins_PUSHW,
6559 /* PushW[5] */ Ins_PUSHW,
6560 /* PushW[6] */ Ins_PUSHW,
6561 /* PushW[7] */ Ins_PUSHW,
6563 /* MDRP[00] */ Ins_MDRP,
6564 /* MDRP[01] */ Ins_MDRP,
6565 /* MDRP[02] */ Ins_MDRP,
6566 /* MDRP[03] */ Ins_MDRP,
6567 /* MDRP[04] */ Ins_MDRP,
6568 /* MDRP[05] */ Ins_MDRP,
6569 /* MDRP[06] */ Ins_MDRP,
6570 /* MDRP[07] */ Ins_MDRP,
6571 /* MDRP[08] */ Ins_MDRP,
6572 /* MDRP[09] */ Ins_MDRP,
6573 /* MDRP[10] */ Ins_MDRP,
6574 /* MDRP[11] */ Ins_MDRP,
6575 /* MDRP[12] */ Ins_MDRP,
6576 /* MDRP[13] */ Ins_MDRP,
6577 /* MDRP[14] */ Ins_MDRP,
6578 /* MDRP[15] */ Ins_MDRP,
6580 /* MDRP[16] */ Ins_MDRP,
6581 /* MDRP[17] */ Ins_MDRP,
6582 /* MDRP[18] */ Ins_MDRP,
6583 /* MDRP[19] */ Ins_MDRP,
6584 /* MDRP[20] */ Ins_MDRP,
6585 /* MDRP[21] */ Ins_MDRP,
6586 /* MDRP[22] */ Ins_MDRP,
6587 /* MDRP[23] */ Ins_MDRP,
6588 /* MDRP[24] */ Ins_MDRP,
6589 /* MDRP[25] */ Ins_MDRP,
6590 /* MDRP[26] */ Ins_MDRP,
6591 /* MDRP[27] */ Ins_MDRP,
6592 /* MDRP[28] */ Ins_MDRP,
6593 /* MDRP[29] */ Ins_MDRP,
6594 /* MDRP[30] */ Ins_MDRP,
6595 /* MDRP[31] */ Ins_MDRP,
6597 /* MIRP[00] */ Ins_MIRP,
6598 /* MIRP[01] */ Ins_MIRP,
6599 /* MIRP[02] */ Ins_MIRP,
6600 /* MIRP[03] */ Ins_MIRP,
6601 /* MIRP[04] */ Ins_MIRP,
6602 /* MIRP[05] */ Ins_MIRP,
6603 /* MIRP[06] */ Ins_MIRP,
6604 /* MIRP[07] */ Ins_MIRP,
6605 /* MIRP[08] */ Ins_MIRP,
6606 /* MIRP[09] */ Ins_MIRP,
6607 /* MIRP[10] */ Ins_MIRP,
6608 /* MIRP[11] */ Ins_MIRP,
6609 /* MIRP[12] */ Ins_MIRP,
6610 /* MIRP[13] */ Ins_MIRP,
6611 /* MIRP[14] */ Ins_MIRP,
6612 /* MIRP[15] */ Ins_MIRP,
6614 /* MIRP[16] */ Ins_MIRP,
6615 /* MIRP[17] */ Ins_MIRP,
6616 /* MIRP[18] */ Ins_MIRP,
6617 /* MIRP[19] */ Ins_MIRP,
6618 /* MIRP[20] */ Ins_MIRP,
6619 /* MIRP[21] */ Ins_MIRP,
6620 /* MIRP[22] */ Ins_MIRP,
6621 /* MIRP[23] */ Ins_MIRP,
6622 /* MIRP[24] */ Ins_MIRP,
6623 /* MIRP[25] */ Ins_MIRP,
6624 /* MIRP[26] */ Ins_MIRP,
6625 /* MIRP[27] */ Ins_MIRP,
6626 /* MIRP[28] */ Ins_MIRP,
6627 /* MIRP[29] */ Ins_MIRP,
6628 /* MIRP[30] */ Ins_MIRP,
6629 /* MIRP[31] */ Ins_MIRP
6630 };
6633 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
6636 /*************************************************************************/
6637 /* */
6638 /* RUN */
6639 /* */
6640 /* This function executes a run of opcodes. It will exit in the */
6641 /* following cases: */
6642 /* */
6643 /* - Errors (in which case it returns FALSE). */
6644 /* */
6645 /* - Reaching the end of the main code range (returns TRUE). */
6646 /* Reaching the end of a code range within a function call is an */
6647 /* error. */
6648 /* */
6649 /* - After executing one single opcode, if the flag `Instruction_Trap' */
6650 /* is set to TRUE (returns TRUE). */
6651 /* */
6652 /* On exit whith TRUE, test IP < CodeSize to know wether it comes from */
6653 /* an instruction trap or a normal termination. */
6654 /* */
6655 /* */
6656 /* Note: The documented DEBUG opcode pops a value from the stack. This */
6657 /* behaviour is unsupported; here a DEBUG opcode is always an */
6658 /* error. */
6659 /* */
6660 /* */
6661 /* THIS IS THE INTERPRETER'S MAIN LOOP. */
6662 /* */
6663 /* Instructions appear in the specification's order. */
6664 /* */
6665 /*************************************************************************/
6668 /* documentation is in ttinterp.h */
6670 FT_EXPORT_DEF( FT_Error )
6671 TT_RunIns( TT_ExecContext exc )
6672 {
6673 FT_Long ins_counter = 0; /* executed instructions counter */
6676 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
6677 cur = *exc;
6678 #endif
6680 /* set CVT functions */
6681 CUR.tt_metrics.ratio = 0;
6682 if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
6683 {
6684 /* non-square pixels, use the stretched routines */
6685 CUR.func_read_cvt = Read_CVT_Stretched;
6686 CUR.func_write_cvt = Write_CVT_Stretched;
6687 CUR.func_move_cvt = Move_CVT_Stretched;
6688 }
6689 else
6690 {
6691 /* square pixels, use normal routines */
6692 CUR.func_read_cvt = Read_CVT;
6693 CUR.func_write_cvt = Write_CVT;
6694 CUR.func_move_cvt = Move_CVT;
6695 }
6697 COMPUTE_Funcs();
6698 COMPUTE_Round( (FT_Byte)exc->GS.round_state );
6700 do
6701 {
6702 CUR.opcode = CUR.code[CUR.IP];
6704 if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )
6705 {
6706 if ( CUR.IP + 1 > CUR.codeSize )
6707 goto LErrorCodeOverflow_;
6709 CUR.length = CUR.code[CUR.IP + 1] + 2;
6710 }
6712 if ( CUR.IP + CUR.length > CUR.codeSize )
6713 goto LErrorCodeOverflow_;
6715 /* First, let's check for empty stack and overflow */
6716 CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 );
6718 /* `args' is the top of the stack once arguments have been popped. */
6719 /* One can also interpret it as the index of the last argument. */
6720 if ( CUR.args < 0 )
6721 {
6722 CUR.error = TT_Err_Too_Few_Arguments;
6723 goto LErrorLabel_;
6724 }
6726 CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 );
6728 /* `new_top' is the new top of the stack, after the instruction's */
6729 /* execution. `top' will be set to `new_top' after the `switch' */
6730 /* statement. */
6731 if ( CUR.new_top > CUR.stackSize )
6732 {
6733 CUR.error = TT_Err_Stack_Overflow;
6734 goto LErrorLabel_;
6735 }
6737 CUR.step_ins = TRUE;
6738 CUR.error = TT_Err_Ok;
6740 #ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
6742 {
6743 FT_Long* args = CUR.stack + CUR.args;
6744 FT_Byte opcode = CUR.opcode;
6747 #undef ARRAY_BOUND_ERROR
6748 #define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
6751 switch ( opcode )
6752 {
6753 case 0x00: /* SVTCA y */
6754 case 0x01: /* SVTCA x */
6755 case 0x02: /* SPvTCA y */
6756 case 0x03: /* SPvTCA x */
6757 case 0x04: /* SFvTCA y */
6758 case 0x05: /* SFvTCA x */
6759 {
6760 FT_Short AA, BB;
6763 AA = (FT_Short)( ( opcode & 1 ) << 14 );
6764 BB = (FT_Short)( AA ^ 0x4000 );
6766 if ( opcode < 4 )
6767 {
6768 CUR.GS.projVector.x = AA;
6769 CUR.GS.projVector.y = BB;
6771 CUR.GS.dualVector.x = AA;
6772 CUR.GS.dualVector.y = BB;
6773 }
6775 if ( ( opcode & 2 ) == 0 )
6776 {
6777 CUR.GS.freeVector.x = AA;
6778 CUR.GS.freeVector.y = BB;
6779 }
6781 COMPUTE_Funcs();
6782 }
6783 break;
6785 case 0x06: /* SPvTL // */
6786 case 0x07: /* SPvTL + */
6787 DO_SPVTL
6788 break;
6790 case 0x08: /* SFvTL // */
6791 case 0x09: /* SFvTL + */
6792 DO_SFVTL
6793 break;
6795 case 0x0A: /* SPvFS */
6796 DO_SPVFS
6797 break;
6799 case 0x0B: /* SFvFS */
6800 DO_SFVFS
6801 break;
6803 case 0x0C: /* GPV */
6804 DO_GPV
6805 break;
6807 case 0x0D: /* GFV */
6808 DO_GFV
6809 break;
6811 case 0x0E: /* SFvTPv */
6812 DO_SFVTPV
6813 break;
6815 case 0x0F: /* ISECT */
6816 Ins_ISECT( EXEC_ARG_ args );
6817 break;
6819 case 0x10: /* SRP0 */
6820 DO_SRP0
6821 break;
6823 case 0x11: /* SRP1 */
6824 DO_SRP1
6825 break;
6827 case 0x12: /* SRP2 */
6828 DO_SRP2
6829 break;
6831 case 0x13: /* SZP0 */
6832 Ins_SZP0( EXEC_ARG_ args );
6833 break;
6835 case 0x14: /* SZP1 */
6836 Ins_SZP1( EXEC_ARG_ args );
6837 break;
6839 case 0x15: /* SZP2 */
6840 Ins_SZP2( EXEC_ARG_ args );
6841 break;
6843 case 0x16: /* SZPS */
6844 Ins_SZPS( EXEC_ARG_ args );
6845 break;
6847 case 0x17: /* SLOOP */
6848 DO_SLOOP
6849 break;
6851 case 0x18: /* RTG */
6852 DO_RTG
6853 break;
6855 case 0x19: /* RTHG */
6856 DO_RTHG
6857 break;
6859 case 0x1A: /* SMD */
6860 DO_SMD
6861 break;
6863 case 0x1B: /* ELSE */
6864 Ins_ELSE( EXEC_ARG_ args );
6865 break;
6867 case 0x1C: /* JMPR */
6868 DO_JMPR
6869 break;
6871 case 0x1D: /* SCVTCI */
6872 DO_SCVTCI
6873 break;
6875 case 0x1E: /* SSWCI */
6876 DO_SSWCI
6877 break;
6879 case 0x1F: /* SSW */
6880 DO_SSW
6881 break;
6883 case 0x20: /* DUP */
6884 DO_DUP
6885 break;
6887 case 0x21: /* POP */
6888 /* nothing :-) */
6889 break;
6891 case 0x22: /* CLEAR */
6892 DO_CLEAR
6893 break;
6895 case 0x23: /* SWAP */
6896 DO_SWAP
6897 break;
6899 case 0x24: /* DEPTH */
6900 DO_DEPTH
6901 break;
6903 case 0x25: /* CINDEX */
6904 DO_CINDEX
6905 break;
6907 case 0x26: /* MINDEX */
6908 Ins_MINDEX( EXEC_ARG_ args );
6909 break;
6911 case 0x27: /* ALIGNPTS */
6912 Ins_ALIGNPTS( EXEC_ARG_ args );
6913 break;
6915 case 0x28: /* ???? */
6916 Ins_UNKNOWN( EXEC_ARG_ args );
6917 break;
6919 case 0x29: /* UTP */
6920 Ins_UTP( EXEC_ARG_ args );
6921 break;
6923 case 0x2A: /* LOOPCALL */
6924 Ins_LOOPCALL( EXEC_ARG_ args );
6925 break;
6927 case 0x2B: /* CALL */
6928 Ins_CALL( EXEC_ARG_ args );
6929 break;
6931 case 0x2C: /* FDEF */
6932 Ins_FDEF( EXEC_ARG_ args );
6933 break;
6935 case 0x2D: /* ENDF */
6936 Ins_ENDF( EXEC_ARG_ args );
6937 break;
6939 case 0x2E: /* MDAP */
6940 case 0x2F: /* MDAP */
6941 Ins_MDAP( EXEC_ARG_ args );
6942 break;
6945 case 0x30: /* IUP */
6946 case 0x31: /* IUP */
6947 Ins_IUP( EXEC_ARG_ args );
6948 break;
6950 case 0x32: /* SHP */
6951 case 0x33: /* SHP */
6952 Ins_SHP( EXEC_ARG_ args );
6953 break;
6955 case 0x34: /* SHC */
6956 case 0x35: /* SHC */
6957 Ins_SHC( EXEC_ARG_ args );
6958 break;
6960 case 0x36: /* SHZ */
6961 case 0x37: /* SHZ */
6962 Ins_SHZ( EXEC_ARG_ args );
6963 break;
6965 case 0x38: /* SHPIX */
6966 Ins_SHPIX( EXEC_ARG_ args );
6967 break;
6969 case 0x39: /* IP */
6970 Ins_IP( EXEC_ARG_ args );
6971 break;
6973 case 0x3A: /* MSIRP */
6974 case 0x3B: /* MSIRP */
6975 Ins_MSIRP( EXEC_ARG_ args );
6976 break;
6978 case 0x3C: /* AlignRP */
6979 Ins_ALIGNRP( EXEC_ARG_ args );
6980 break;
6982 case 0x3D: /* RTDG */
6983 DO_RTDG
6984 break;
6986 case 0x3E: /* MIAP */
6987 case 0x3F: /* MIAP */
6988 Ins_MIAP( EXEC_ARG_ args );
6989 break;
6991 case 0x40: /* NPUSHB */
6992 Ins_NPUSHB( EXEC_ARG_ args );
6993 break;
6995 case 0x41: /* NPUSHW */
6996 Ins_NPUSHW( EXEC_ARG_ args );
6997 break;
6999 case 0x42: /* WS */
7000 DO_WS
7001 break;
7003 Set_Invalid_Ref:
7004 CUR.error = TT_Err_Invalid_Reference;
7005 break;
7007 case 0x43: /* RS */
7008 DO_RS
7009 break;
7011 case 0x44: /* WCVTP */
7012 DO_WCVTP
7013 break;
7015 case 0x45: /* RCVT */
7016 DO_RCVT
7017 break;
7019 case 0x46: /* GC */
7020 case 0x47: /* GC */
7021 Ins_GC( EXEC_ARG_ args );
7022 break;
7024 case 0x48: /* SCFS */
7025 Ins_SCFS( EXEC_ARG_ args );
7026 break;
7028 case 0x49: /* MD */
7029 case 0x4A: /* MD */
7030 Ins_MD( EXEC_ARG_ args );
7031 break;
7033 case 0x4B: /* MPPEM */
7034 DO_MPPEM
7035 break;
7037 case 0x4C: /* MPS */
7038 DO_MPS
7039 break;
7041 case 0x4D: /* FLIPON */
7042 DO_FLIPON
7043 break;
7045 case 0x4E: /* FLIPOFF */
7046 DO_FLIPOFF
7047 break;
7049 case 0x4F: /* DEBUG */
7050 DO_DEBUG
7051 break;
7053 case 0x50: /* LT */
7054 DO_LT
7055 break;
7057 case 0x51: /* LTEQ */
7058 DO_LTEQ
7059 break;
7061 case 0x52: /* GT */
7062 DO_GT
7063 break;
7065 case 0x53: /* GTEQ */
7066 DO_GTEQ
7067 break;
7069 case 0x54: /* EQ */
7070 DO_EQ
7071 break;
7073 case 0x55: /* NEQ */
7074 DO_NEQ
7075 break;
7077 case 0x56: /* ODD */
7078 DO_ODD
7079 break;
7081 case 0x57: /* EVEN */
7082 DO_EVEN
7083 break;
7085 case 0x58: /* IF */
7086 Ins_IF( EXEC_ARG_ args );
7087 break;
7089 case 0x59: /* EIF */
7090 /* do nothing */
7091 break;
7093 case 0x5A: /* AND */
7094 DO_AND
7095 break;
7097 case 0x5B: /* OR */
7098 DO_OR
7099 break;
7101 case 0x5C: /* NOT */
7102 DO_NOT
7103 break;
7105 case 0x5D: /* DELTAP1 */
7106 Ins_DELTAP( EXEC_ARG_ args );
7107 break;
7109 case 0x5E: /* SDB */
7110 DO_SDB
7111 break;
7113 case 0x5F: /* SDS */
7114 DO_SDS
7115 break;
7117 case 0x60: /* ADD */
7118 DO_ADD
7119 break;
7121 case 0x61: /* SUB */
7122 DO_SUB
7123 break;
7125 case 0x62: /* DIV */
7126 DO_DIV
7127 break;
7129 case 0x63: /* MUL */
7130 DO_MUL
7131 break;
7133 case 0x64: /* ABS */
7134 DO_ABS
7135 break;
7137 case 0x65: /* NEG */
7138 DO_NEG
7139 break;
7141 case 0x66: /* FLOOR */
7142 DO_FLOOR
7143 break;
7145 case 0x67: /* CEILING */
7146 DO_CEILING
7147 break;
7149 case 0x68: /* ROUND */
7150 case 0x69: /* ROUND */
7151 case 0x6A: /* ROUND */
7152 case 0x6B: /* ROUND */
7153 DO_ROUND
7154 break;
7156 case 0x6C: /* NROUND */
7157 case 0x6D: /* NROUND */
7158 case 0x6E: /* NRRUND */
7159 case 0x6F: /* NROUND */
7160 DO_NROUND
7161 break;
7163 case 0x70: /* WCVTF */
7164 DO_WCVTF
7165 break;
7167 case 0x71: /* DELTAP2 */
7168 case 0x72: /* DELTAP3 */
7169 Ins_DELTAP( EXEC_ARG_ args );
7170 break;
7172 case 0x73: /* DELTAC0 */
7173 case 0x74: /* DELTAC1 */
7174 case 0x75: /* DELTAC2 */
7175 Ins_DELTAC( EXEC_ARG_ args );
7176 break;
7178 case 0x76: /* SROUND */
7179 DO_SROUND
7180 break;
7182 case 0x77: /* S45Round */
7183 DO_S45ROUND
7184 break;
7186 case 0x78: /* JROT */
7187 DO_JROT
7188 break;
7190 case 0x79: /* JROF */
7191 DO_JROF
7192 break;
7194 case 0x7A: /* ROFF */
7195 DO_ROFF
7196 break;
7198 case 0x7B: /* ???? */
7199 Ins_UNKNOWN( EXEC_ARG_ args );
7200 break;
7202 case 0x7C: /* RUTG */
7203 DO_RUTG
7204 break;
7206 case 0x7D: /* RDTG */
7207 DO_RDTG
7208 break;
7210 case 0x7E: /* SANGW */
7211 case 0x7F: /* AA */
7212 /* nothing - obsolete */
7213 break;
7215 case 0x80: /* FLIPPT */
7216 Ins_FLIPPT( EXEC_ARG_ args );
7217 break;
7219 case 0x81: /* FLIPRGON */
7220 Ins_FLIPRGON( EXEC_ARG_ args );
7221 break;
7223 case 0x82: /* FLIPRGOFF */
7224 Ins_FLIPRGOFF( EXEC_ARG_ args );
7225 break;
7227 case 0x83: /* UNKNOWN */
7228 case 0x84: /* UNKNOWN */
7229 Ins_UNKNOWN( EXEC_ARG_ args );
7230 break;
7232 case 0x85: /* SCANCTRL */
7233 Ins_SCANCTRL( EXEC_ARG_ args );
7234 break;
7236 case 0x86: /* SDPVTL */
7237 case 0x87: /* SDPVTL */
7238 Ins_SDPVTL( EXEC_ARG_ args );
7239 break;
7241 case 0x88: /* GETINFO */
7242 Ins_GETINFO( EXEC_ARG_ args );
7243 break;
7245 case 0x89: /* IDEF */
7246 Ins_IDEF( EXEC_ARG_ args );
7247 break;
7249 case 0x8A: /* ROLL */
7250 Ins_ROLL( EXEC_ARG_ args );
7251 break;
7253 case 0x8B: /* MAX */
7254 DO_MAX
7255 break;
7257 case 0x8C: /* MIN */
7258 DO_MIN
7259 break;
7261 case 0x8D: /* SCANTYPE */
7262 Ins_SCANTYPE( EXEC_ARG_ args );
7263 break;
7265 case 0x8E: /* INSTCTRL */
7266 Ins_INSTCTRL( EXEC_ARG_ args );
7267 break;
7269 case 0x8F:
7270 Ins_UNKNOWN( EXEC_ARG_ args );
7271 break;
7273 default:
7274 if ( opcode >= 0xE0 )
7275 Ins_MIRP( EXEC_ARG_ args );
7276 else if ( opcode >= 0xC0 )
7277 Ins_MDRP( EXEC_ARG_ args );
7278 else if ( opcode >= 0xB8 )
7279 Ins_PUSHW( EXEC_ARG_ args );
7280 else if ( opcode >= 0xB0 )
7281 Ins_PUSHB( EXEC_ARG_ args );
7282 else
7283 Ins_UNKNOWN( EXEC_ARG_ args );
7284 }
7286 }
7288 #else
7290 Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );
7292 #endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7294 if ( CUR.error != TT_Err_Ok )
7295 {
7296 switch ( CUR.error )
7297 {
7298 case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
7299 {
7300 TT_DefRecord* def = CUR.IDefs;
7301 TT_DefRecord* limit = def + CUR.numIDefs;
7304 for ( ; def < limit; def++ )
7305 {
7306 if ( def->active && CUR.opcode == (FT_Byte)def->opc )
7307 {
7308 TT_CallRec* callrec;
7311 if ( CUR.callTop >= CUR.callSize )
7312 {
7313 CUR.error = TT_Err_Invalid_Reference;
7314 goto LErrorLabel_;
7315 }
7317 callrec = &CUR.callStack[CUR.callTop];
7319 callrec->Caller_Range = CUR.curRange;
7320 callrec->Caller_IP = CUR.IP + 1;
7321 callrec->Cur_Count = 1;
7322 callrec->Cur_Restart = def->start;
7324 if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
7325 goto LErrorLabel_;
7327 goto LSuiteLabel_;
7328 }
7329 }
7330 }
7332 CUR.error = TT_Err_Invalid_Opcode;
7333 goto LErrorLabel_;
7335 #if 0
7336 break; /* Unreachable code warning suppression. */
7337 /* Leave to remind in case a later change the editor */
7338 /* to consider break; */
7339 #endif
7341 default:
7342 goto LErrorLabel_;
7344 #if 0
7345 break;
7346 #endif
7347 }
7348 }
7350 CUR.top = CUR.new_top;
7352 if ( CUR.step_ins )
7353 CUR.IP += CUR.length;
7355 /* increment instruction counter and check if we didn't */
7356 /* run this program for too long (e.g. infinite loops). */
7357 if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
7358 return TT_Err_Execution_Too_Long;
7360 LSuiteLabel_:
7361 if ( CUR.IP >= CUR.codeSize )
7362 {
7363 if ( CUR.callTop > 0 )
7364 {
7365 CUR.error = TT_Err_Code_Overflow;
7366 goto LErrorLabel_;
7367 }
7368 else
7369 goto LNo_Error_;
7370 }
7371 } while ( !CUR.instruction_trap );
7373 LNo_Error_:
7375 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7376 *exc = cur;
7377 #endif
7379 return TT_Err_Ok;
7381 LErrorCodeOverflow_:
7382 CUR.error = TT_Err_Code_Overflow;
7384 LErrorLabel_:
7386 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7387 *exc = cur;
7388 #endif
7390 return CUR.error;
7391 }
7394 #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
7397 /* END */