Bringing apdf from vendor into main branch.
[AROS-Contrib.git] / apdf / freetype2 / truetype / ttinterp.c
blob28587e6143e204268d3dfa62aadf5cb51010d8d1
1 /***************************************************************************/
2 /* */
3 /* ttinterp.c */
4 /* */
5 /* TrueType bytecode interpreter (body). */
6 /* */
7 /* Copyright 1996-2001, 2002 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 )
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;
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 )
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;
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 )
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;
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 )
387 /* free composite load stack */
388 FT_FREE( exec->loadStack );
389 exec->loadSize = 0;
391 /* points zone */
392 exec->maxPoints = 0;
393 exec->maxContours = 0;
395 /* free stack */
396 FT_FREE( exec->stack );
397 exec->stackSize = 0;
399 /* free call stack */
400 FT_FREE( exec->callStack );
401 exec->callSize = 0;
402 exec->callTop = 0;
404 /* free glyph code range */
405 FT_FREE( exec->glyphIns );
406 exec->glyphSize = 0;
408 exec->size = NULL;
409 exec->face = NULL;
411 FT_FREE( exec );
412 return TT_Err_Ok;
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 )
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 ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )
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;
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 )
510 FT_Error error;
513 if ( *size < new_max )
515 FT_FREE( *buff );
516 if ( FT_ALLOC( *buff, new_max * multiplier ) )
517 return error;
518 *size = new_max;
521 return TT_Err_Ok;
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 )
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 )
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;
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;
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 )
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;
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 )
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
743 const TT_GraphicsState tt_default_graphics_state =
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
755 /* documentation is in ttinterp.h */
757 FT_EXPORT_DEF( TT_ExecContext )
758 TT_New_Context( TT_Face face )
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 )
775 FT_Error error;
778 /* allocate object */
779 if ( FT_NEW( 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;
791 Exit:
792 return driver->context;
794 Fail:
795 FT_FREE( exec );
797 return 0;
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 )
821 /* Nothing at all for now */
822 FT_UNUSED( exec );
824 return TT_Err_Ok;
829 /*************************************************************************/
830 /* */
831 /* Before an opcode is executed, the interpreter verifies that there are */
832 /* enough arguments on the stack, with the help of the Pop_Push_Count */
833 /* table. */
834 /* */
835 /* For each opcode, the first column gives the number of arguments that */
836 /* are popped from the stack; the second one gives the number of those */
837 /* that are pushed in result. */
838 /* */
839 /* Note that for opcodes with a varying number of parameters, either 0 */
840 /* or 1 arg is verified before execution, depending on the nature of the */
841 /* instruction: */
842 /* */
843 /* - if the number of arguments is given by the bytecode stream or the */
844 /* loop variable, 0 is chosen. */
845 /* */
846 /* - if the first argument is a count n that is followed by arguments */
847 /* a1 .. an, then 1 is chosen. */
848 /* */
849 /*************************************************************************/
852 #undef PACK
853 #define PACK( x, y ) ( ( x << 4 ) | y )
856 static
857 const FT_Byte Pop_Push_Count[256] =
859 /* opcodes are gathered in groups of 16 */
860 /* please keep the spaces as they are */
862 /* SVTCA y */ PACK( 0, 0 ),
863 /* SVTCA x */ PACK( 0, 0 ),
864 /* SPvTCA y */ PACK( 0, 0 ),
865 /* SPvTCA x */ PACK( 0, 0 ),
866 /* SFvTCA y */ PACK( 0, 0 ),
867 /* SFvTCA x */ PACK( 0, 0 ),
868 /* SPvTL // */ PACK( 2, 0 ),
869 /* SPvTL + */ PACK( 2, 0 ),
870 /* SFvTL // */ PACK( 2, 0 ),
871 /* SFvTL + */ PACK( 2, 0 ),
872 /* SPvFS */ PACK( 2, 0 ),
873 /* SFvFS */ PACK( 2, 0 ),
874 /* GPV */ PACK( 0, 2 ),
875 /* GFV */ PACK( 0, 2 ),
876 /* SFvTPv */ PACK( 0, 0 ),
877 /* ISECT */ PACK( 5, 0 ),
879 /* SRP0 */ PACK( 1, 0 ),
880 /* SRP1 */ PACK( 1, 0 ),
881 /* SRP2 */ PACK( 1, 0 ),
882 /* SZP0 */ PACK( 1, 0 ),
883 /* SZP1 */ PACK( 1, 0 ),
884 /* SZP2 */ PACK( 1, 0 ),
885 /* SZPS */ PACK( 1, 0 ),
886 /* SLOOP */ PACK( 1, 0 ),
887 /* RTG */ PACK( 0, 0 ),
888 /* RTHG */ PACK( 0, 0 ),
889 /* SMD */ PACK( 1, 0 ),
890 /* ELSE */ PACK( 0, 0 ),
891 /* JMPR */ PACK( 1, 0 ),
892 /* SCvTCi */ PACK( 1, 0 ),
893 /* SSwCi */ PACK( 1, 0 ),
894 /* SSW */ PACK( 1, 0 ),
896 /* DUP */ PACK( 1, 2 ),
897 /* POP */ PACK( 1, 0 ),
898 /* CLEAR */ PACK( 0, 0 ),
899 /* SWAP */ PACK( 2, 2 ),
900 /* DEPTH */ PACK( 0, 1 ),
901 /* CINDEX */ PACK( 1, 1 ),
902 /* MINDEX */ PACK( 1, 0 ),
903 /* AlignPTS */ PACK( 2, 0 ),
904 /* INS_$28 */ PACK( 0, 0 ),
905 /* UTP */ PACK( 1, 0 ),
906 /* LOOPCALL */ PACK( 2, 0 ),
907 /* CALL */ PACK( 1, 0 ),
908 /* FDEF */ PACK( 1, 0 ),
909 /* ENDF */ PACK( 0, 0 ),
910 /* MDAP[0] */ PACK( 1, 0 ),
911 /* MDAP[1] */ PACK( 1, 0 ),
913 /* IUP[0] */ PACK( 0, 0 ),
914 /* IUP[1] */ PACK( 0, 0 ),
915 /* SHP[0] */ PACK( 0, 0 ),
916 /* SHP[1] */ PACK( 0, 0 ),
917 /* SHC[0] */ PACK( 1, 0 ),
918 /* SHC[1] */ PACK( 1, 0 ),
919 /* SHZ[0] */ PACK( 1, 0 ),
920 /* SHZ[1] */ PACK( 1, 0 ),
921 /* SHPIX */ PACK( 1, 0 ),
922 /* IP */ PACK( 0, 0 ),
923 /* MSIRP[0] */ PACK( 2, 0 ),
924 /* MSIRP[1] */ PACK( 2, 0 ),
925 /* AlignRP */ PACK( 0, 0 ),
926 /* RTDG */ PACK( 0, 0 ),
927 /* MIAP[0] */ PACK( 2, 0 ),
928 /* MIAP[1] */ PACK( 2, 0 ),
930 /* NPushB */ PACK( 0, 0 ),
931 /* NPushW */ PACK( 0, 0 ),
932 /* WS */ PACK( 2, 0 ),
933 /* RS */ PACK( 1, 1 ),
934 /* WCvtP */ PACK( 2, 0 ),
935 /* RCvt */ PACK( 1, 1 ),
936 /* GC[0] */ PACK( 1, 1 ),
937 /* GC[1] */ PACK( 1, 1 ),
938 /* SCFS */ PACK( 2, 0 ),
939 /* MD[0] */ PACK( 2, 1 ),
940 /* MD[1] */ PACK( 2, 1 ),
941 /* MPPEM */ PACK( 0, 1 ),
942 /* MPS */ PACK( 0, 1 ),
943 /* FlipON */ PACK( 0, 0 ),
944 /* FlipOFF */ PACK( 0, 0 ),
945 /* DEBUG */ PACK( 1, 0 ),
947 /* LT */ PACK( 2, 1 ),
948 /* LTEQ */ PACK( 2, 1 ),
949 /* GT */ PACK( 2, 1 ),
950 /* GTEQ */ PACK( 2, 1 ),
951 /* EQ */ PACK( 2, 1 ),
952 /* NEQ */ PACK( 2, 1 ),
953 /* ODD */ PACK( 1, 1 ),
954 /* EVEN */ PACK( 1, 1 ),
955 /* IF */ PACK( 1, 0 ),
956 /* EIF */ PACK( 0, 0 ),
957 /* AND */ PACK( 2, 1 ),
958 /* OR */ PACK( 2, 1 ),
959 /* NOT */ PACK( 1, 1 ),
960 /* DeltaP1 */ PACK( 1, 0 ),
961 /* SDB */ PACK( 1, 0 ),
962 /* SDS */ PACK( 1, 0 ),
964 /* ADD */ PACK( 2, 1 ),
965 /* SUB */ PACK( 2, 1 ),
966 /* DIV */ PACK( 2, 1 ),
967 /* MUL */ PACK( 2, 1 ),
968 /* ABS */ PACK( 1, 1 ),
969 /* NEG */ PACK( 1, 1 ),
970 /* FLOOR */ PACK( 1, 1 ),
971 /* CEILING */ PACK( 1, 1 ),
972 /* ROUND[0] */ PACK( 1, 1 ),
973 /* ROUND[1] */ PACK( 1, 1 ),
974 /* ROUND[2] */ PACK( 1, 1 ),
975 /* ROUND[3] */ PACK( 1, 1 ),
976 /* NROUND[0] */ PACK( 1, 1 ),
977 /* NROUND[1] */ PACK( 1, 1 ),
978 /* NROUND[2] */ PACK( 1, 1 ),
979 /* NROUND[3] */ PACK( 1, 1 ),
981 /* WCvtF */ PACK( 2, 0 ),
982 /* DeltaP2 */ PACK( 1, 0 ),
983 /* DeltaP3 */ PACK( 1, 0 ),
984 /* DeltaCn[0] */ PACK( 1, 0 ),
985 /* DeltaCn[1] */ PACK( 1, 0 ),
986 /* DeltaCn[2] */ PACK( 1, 0 ),
987 /* SROUND */ PACK( 1, 0 ),
988 /* S45Round */ PACK( 1, 0 ),
989 /* JROT */ PACK( 2, 0 ),
990 /* JROF */ PACK( 2, 0 ),
991 /* ROFF */ PACK( 0, 0 ),
992 /* INS_$7B */ PACK( 0, 0 ),
993 /* RUTG */ PACK( 0, 0 ),
994 /* RDTG */ PACK( 0, 0 ),
995 /* SANGW */ PACK( 1, 0 ),
996 /* AA */ PACK( 1, 0 ),
998 /* FlipPT */ PACK( 0, 0 ),
999 /* FlipRgON */ PACK( 2, 0 ),
1000 /* FlipRgOFF */ PACK( 2, 0 ),
1001 /* INS_$83 */ PACK( 0, 0 ),
1002 /* INS_$84 */ PACK( 0, 0 ),
1003 /* ScanCTRL */ PACK( 1, 0 ),
1004 /* SDVPTL[0] */ PACK( 2, 0 ),
1005 /* SDVPTL[1] */ PACK( 2, 0 ),
1006 /* GetINFO */ PACK( 1, 1 ),
1007 /* IDEF */ PACK( 1, 0 ),
1008 /* ROLL */ PACK( 3, 3 ),
1009 /* MAX */ PACK( 2, 1 ),
1010 /* MIN */ PACK( 2, 1 ),
1011 /* ScanTYPE */ PACK( 1, 0 ),
1012 /* InstCTRL */ PACK( 2, 0 ),
1013 /* INS_$8F */ PACK( 0, 0 ),
1015 /* INS_$90 */ PACK( 0, 0 ),
1016 /* INS_$91 */ PACK( 0, 0 ),
1017 /* INS_$92 */ PACK( 0, 0 ),
1018 /* INS_$93 */ PACK( 0, 0 ),
1019 /* INS_$94 */ PACK( 0, 0 ),
1020 /* INS_$95 */ PACK( 0, 0 ),
1021 /* INS_$96 */ PACK( 0, 0 ),
1022 /* INS_$97 */ PACK( 0, 0 ),
1023 /* INS_$98 */ PACK( 0, 0 ),
1024 /* INS_$99 */ PACK( 0, 0 ),
1025 /* INS_$9A */ PACK( 0, 0 ),
1026 /* INS_$9B */ PACK( 0, 0 ),
1027 /* INS_$9C */ PACK( 0, 0 ),
1028 /* INS_$9D */ PACK( 0, 0 ),
1029 /* INS_$9E */ PACK( 0, 0 ),
1030 /* INS_$9F */ PACK( 0, 0 ),
1032 /* INS_$A0 */ PACK( 0, 0 ),
1033 /* INS_$A1 */ PACK( 0, 0 ),
1034 /* INS_$A2 */ PACK( 0, 0 ),
1035 /* INS_$A3 */ PACK( 0, 0 ),
1036 /* INS_$A4 */ PACK( 0, 0 ),
1037 /* INS_$A5 */ PACK( 0, 0 ),
1038 /* INS_$A6 */ PACK( 0, 0 ),
1039 /* INS_$A7 */ PACK( 0, 0 ),
1040 /* INS_$A8 */ PACK( 0, 0 ),
1041 /* INS_$A9 */ PACK( 0, 0 ),
1042 /* INS_$AA */ PACK( 0, 0 ),
1043 /* INS_$AB */ PACK( 0, 0 ),
1044 /* INS_$AC */ PACK( 0, 0 ),
1045 /* INS_$AD */ PACK( 0, 0 ),
1046 /* INS_$AE */ PACK( 0, 0 ),
1047 /* INS_$AF */ PACK( 0, 0 ),
1049 /* PushB[0] */ PACK( 0, 1 ),
1050 /* PushB[1] */ PACK( 0, 2 ),
1051 /* PushB[2] */ PACK( 0, 3 ),
1052 /* PushB[3] */ PACK( 0, 4 ),
1053 /* PushB[4] */ PACK( 0, 5 ),
1054 /* PushB[5] */ PACK( 0, 6 ),
1055 /* PushB[6] */ PACK( 0, 7 ),
1056 /* PushB[7] */ PACK( 0, 8 ),
1057 /* PushW[0] */ PACK( 0, 1 ),
1058 /* PushW[1] */ PACK( 0, 2 ),
1059 /* PushW[2] */ PACK( 0, 3 ),
1060 /* PushW[3] */ PACK( 0, 4 ),
1061 /* PushW[4] */ PACK( 0, 5 ),
1062 /* PushW[5] */ PACK( 0, 6 ),
1063 /* PushW[6] */ PACK( 0, 7 ),
1064 /* PushW[7] */ PACK( 0, 8 ),
1066 /* MDRP[00] */ PACK( 1, 0 ),
1067 /* MDRP[01] */ PACK( 1, 0 ),
1068 /* MDRP[02] */ PACK( 1, 0 ),
1069 /* MDRP[03] */ PACK( 1, 0 ),
1070 /* MDRP[04] */ PACK( 1, 0 ),
1071 /* MDRP[05] */ PACK( 1, 0 ),
1072 /* MDRP[06] */ PACK( 1, 0 ),
1073 /* MDRP[07] */ PACK( 1, 0 ),
1074 /* MDRP[08] */ PACK( 1, 0 ),
1075 /* MDRP[09] */ PACK( 1, 0 ),
1076 /* MDRP[10] */ PACK( 1, 0 ),
1077 /* MDRP[11] */ PACK( 1, 0 ),
1078 /* MDRP[12] */ PACK( 1, 0 ),
1079 /* MDRP[13] */ PACK( 1, 0 ),
1080 /* MDRP[14] */ PACK( 1, 0 ),
1081 /* MDRP[15] */ PACK( 1, 0 ),
1083 /* MDRP[16] */ PACK( 1, 0 ),
1084 /* MDRP[17] */ PACK( 1, 0 ),
1085 /* MDRP[18] */ PACK( 1, 0 ),
1086 /* MDRP[19] */ PACK( 1, 0 ),
1087 /* MDRP[20] */ PACK( 1, 0 ),
1088 /* MDRP[21] */ PACK( 1, 0 ),
1089 /* MDRP[22] */ PACK( 1, 0 ),
1090 /* MDRP[23] */ PACK( 1, 0 ),
1091 /* MDRP[24] */ PACK( 1, 0 ),
1092 /* MDRP[25] */ PACK( 1, 0 ),
1093 /* MDRP[26] */ PACK( 1, 0 ),
1094 /* MDRP[27] */ PACK( 1, 0 ),
1095 /* MDRP[28] */ PACK( 1, 0 ),
1096 /* MDRP[29] */ PACK( 1, 0 ),
1097 /* MDRP[30] */ PACK( 1, 0 ),
1098 /* MDRP[31] */ PACK( 1, 0 ),
1100 /* MIRP[00] */ PACK( 2, 0 ),
1101 /* MIRP[01] */ PACK( 2, 0 ),
1102 /* MIRP[02] */ PACK( 2, 0 ),
1103 /* MIRP[03] */ PACK( 2, 0 ),
1104 /* MIRP[04] */ PACK( 2, 0 ),
1105 /* MIRP[05] */ PACK( 2, 0 ),
1106 /* MIRP[06] */ PACK( 2, 0 ),
1107 /* MIRP[07] */ PACK( 2, 0 ),
1108 /* MIRP[08] */ PACK( 2, 0 ),
1109 /* MIRP[09] */ PACK( 2, 0 ),
1110 /* MIRP[10] */ PACK( 2, 0 ),
1111 /* MIRP[11] */ PACK( 2, 0 ),
1112 /* MIRP[12] */ PACK( 2, 0 ),
1113 /* MIRP[13] */ PACK( 2, 0 ),
1114 /* MIRP[14] */ PACK( 2, 0 ),
1115 /* MIRP[15] */ PACK( 2, 0 ),
1117 /* MIRP[16] */ PACK( 2, 0 ),
1118 /* MIRP[17] */ PACK( 2, 0 ),
1119 /* MIRP[18] */ PACK( 2, 0 ),
1120 /* MIRP[19] */ PACK( 2, 0 ),
1121 /* MIRP[20] */ PACK( 2, 0 ),
1122 /* MIRP[21] */ PACK( 2, 0 ),
1123 /* MIRP[22] */ PACK( 2, 0 ),
1124 /* MIRP[23] */ PACK( 2, 0 ),
1125 /* MIRP[24] */ PACK( 2, 0 ),
1126 /* MIRP[25] */ PACK( 2, 0 ),
1127 /* MIRP[26] */ PACK( 2, 0 ),
1128 /* MIRP[27] */ PACK( 2, 0 ),
1129 /* MIRP[28] */ PACK( 2, 0 ),
1130 /* MIRP[29] */ PACK( 2, 0 ),
1131 /* MIRP[30] */ PACK( 2, 0 ),
1132 /* MIRP[31] */ PACK( 2, 0 )
1136 static
1137 const FT_Char opcode_length[256] =
1139 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1140 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1141 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1142 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1144 -1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1145 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1146 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1147 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1149 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1150 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1151 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1152 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
1154 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1155 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1156 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1157 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1160 static
1161 const FT_Vector Null_Vector = {0,0};
1164 #undef PACK
1167 #undef NULL_Vector
1168 #define NULL_Vector (FT_Vector*)&Null_Vector
1171 /* compute (a*b)/2^14 with maximal accuracy and rounding */
1172 static FT_Int32
1173 TT_MulFix14( FT_Int32 a,
1174 FT_Int b )
1176 FT_Int32 m, s, hi;
1177 FT_UInt32 l, lo;
1180 /* compute ax*bx as 64-bit value */
1181 l = (FT_UInt32)( ( a & 0xFFFFU ) * b );
1182 m = ( a >> 16 ) * b;
1184 lo = l + (FT_UInt32)( m << 16 );
1185 hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l );
1187 /* divide the result by 2^14 with rounding */
1188 s = hi >> 31;
1189 l = lo + (FT_UInt32)s;
1190 hi += s + ( l < lo );
1191 lo = l;
1193 l = lo + 0x2000U;
1194 hi += (l < lo);
1196 return ( hi << 18 ) | ( l >> 14 );
1200 /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */
1201 static FT_Int32
1202 TT_DotFix14( FT_Int32 ax,
1203 FT_Int32 ay,
1204 FT_Int bx,
1205 FT_Int by )
1207 FT_Int32 m, s, hi1, hi2, hi;
1208 FT_UInt32 l, lo1, lo2, lo;
1211 /* compute ax*bx as 64-bit value */
1212 l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );
1213 m = ( ax >> 16 ) * bx;
1215 lo1 = l + (FT_UInt32)( m << 16 );
1216 hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l );
1218 /* compute ay*by as 64-bit value */
1219 l = (FT_UInt32)( ( ay & 0xFFFFU ) * by );
1220 m = ( ay >> 16 ) * by;
1222 lo2 = l + (FT_UInt32)( m << 16 );
1223 hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l );
1225 /* add them */
1226 lo = lo1 + lo2;
1227 hi = hi1 + hi2 + ( lo < lo1 );
1229 /* divide the result by 2^14 with rounding */
1230 s = hi >> 31;
1231 l = lo + (FT_UInt32)s;
1232 hi += s + ( l < lo );
1233 lo = l;
1235 l = lo + 0x2000U;
1236 hi += ( l < lo );
1238 return ( hi << 18 ) | ( l >> 14 );
1242 /* return length of given vector */
1244 #if 0
1246 static FT_Int32
1247 TT_VecLen( FT_Int32 x,
1248 FT_Int32 y )
1250 FT_Int32 m, hi1, hi2, hi;
1251 FT_UInt32 l, lo1, lo2, lo;
1254 /* compute x*x as 64-bit value */
1255 lo = (FT_UInt32)( x & 0xFFFFU );
1256 hi = x >> 16;
1258 l = lo * lo;
1259 m = hi * lo;
1260 hi = hi * hi;
1262 lo1 = l + (FT_UInt32)( m << 17 );
1263 hi1 = hi + ( m >> 15 ) + ( lo1 < l );
1265 /* compute y*y as 64-bit value */
1266 lo = (FT_UInt32)( y & 0xFFFFU );
1267 hi = y >> 16;
1269 l = lo * lo;
1270 m = hi * lo;
1271 hi = hi * hi;
1273 lo2 = l + (FT_UInt32)( m << 17 );
1274 hi2 = hi + ( m >> 15 ) + ( lo2 < l );
1276 /* add them to get 'x*x+y*y' as 64-bit value */
1277 lo = lo1 + lo2;
1278 hi = hi1 + hi2 + ( lo < lo1 );
1280 /* compute the square root of this value */
1282 FT_UInt32 root, rem, test_div;
1283 FT_Int count;
1286 root = 0;
1289 rem = 0;
1290 count = 32;
1293 rem = ( rem << 2 ) | ( (FT_UInt32)hi >> 30 );
1294 hi = ( hi << 2 ) | ( lo >> 30 );
1295 lo <<= 2;
1296 root <<= 1;
1297 test_div = ( root << 1 ) + 1;
1299 if ( rem >= test_div )
1301 rem -= test_div;
1302 root += 1;
1304 } while ( --count );
1307 return (FT_Int32)root;
1311 #else
1313 /* this version uses FT_Vector_Length which computes the same value */
1314 /* much, much faster.. */
1315 /* */
1316 static FT_F26Dot6
1317 TT_VecLen( FT_F26Dot6 X,
1318 FT_F26Dot6 Y )
1320 FT_Vector v;
1323 v.x = X;
1324 v.y = Y;
1326 return FT_Vector_Length( &v );
1329 #endif
1332 /*************************************************************************/
1333 /* */
1334 /* <Function> */
1335 /* Current_Ratio */
1336 /* */
1337 /* <Description> */
1338 /* Returns the current aspect ratio scaling factor depending on the */
1339 /* projection vector's state and device resolutions. */
1340 /* */
1341 /* <Return> */
1342 /* The aspect ratio in 16.16 format, always <= 1.0 . */
1343 /* */
1344 static FT_Long
1345 Current_Ratio( EXEC_OP )
1347 if ( CUR.tt_metrics.ratio )
1348 return CUR.tt_metrics.ratio;
1350 if ( CUR.GS.projVector.y == 0 )
1351 CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
1353 else if ( CUR.GS.projVector.x == 0 )
1354 CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
1356 else
1358 FT_Long x, y;
1360 x = TT_MULDIV( CUR.GS.projVector.x, CUR.tt_metrics.x_ratio, 0x4000 );
1361 y = TT_MULDIV( CUR.GS.projVector.y, CUR.tt_metrics.y_ratio, 0x4000 );
1362 CUR.tt_metrics.ratio = TT_VecLen( x, y );
1365 return CUR.tt_metrics.ratio;
1369 static FT_Long
1370 Current_Ppem( EXEC_OP )
1372 return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );
1376 /*************************************************************************/
1377 /* */
1378 /* Functions related to the control value table (CVT). */
1379 /* */
1380 /*************************************************************************/
1383 FT_CALLBACK_DEF( FT_F26Dot6 )
1384 Read_CVT( EXEC_OP_ FT_ULong idx )
1386 return CUR.cvt[idx];
1390 FT_CALLBACK_DEF( FT_F26Dot6 )
1391 Read_CVT_Stretched( EXEC_OP_ FT_ULong idx )
1393 return TT_MULFIX( CUR.cvt[idx], CURRENT_Ratio() );
1397 FT_CALLBACK_DEF( void )
1398 Write_CVT( EXEC_OP_ FT_ULong idx,
1399 FT_F26Dot6 value )
1401 CUR.cvt[idx] = value;
1405 FT_CALLBACK_DEF( void )
1406 Write_CVT_Stretched( EXEC_OP_ FT_ULong idx,
1407 FT_F26Dot6 value )
1409 CUR.cvt[idx] = FT_DivFix( value, CURRENT_Ratio() );
1413 FT_CALLBACK_DEF( void )
1414 Move_CVT( EXEC_OP_ FT_ULong idx,
1415 FT_F26Dot6 value )
1417 CUR.cvt[idx] += value;
1421 FT_CALLBACK_DEF( void )
1422 Move_CVT_Stretched( EXEC_OP_ FT_ULong idx,
1423 FT_F26Dot6 value )
1425 CUR.cvt[idx] += FT_DivFix( value, CURRENT_Ratio() );
1429 /*************************************************************************/
1430 /* */
1431 /* <Function> */
1432 /* GetShortIns */
1433 /* */
1434 /* <Description> */
1435 /* Returns a short integer taken from the instruction stream at */
1436 /* address IP. */
1437 /* */
1438 /* <Return> */
1439 /* Short read at code[IP]. */
1440 /* */
1441 /* <Note> */
1442 /* This one could become a macro. */
1443 /* */
1444 static FT_Short
1445 GetShortIns( EXEC_OP )
1447 /* Reading a byte stream so there is no endianess (DaveP) */
1448 CUR.IP += 2;
1449 return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) +
1450 CUR.code[CUR.IP - 1] );
1454 /*************************************************************************/
1455 /* */
1456 /* <Function> */
1457 /* Ins_Goto_CodeRange */
1458 /* */
1459 /* <Description> */
1460 /* Goes to a certain code range in the instruction stream. */
1461 /* */
1462 /* <Input> */
1463 /* aRange :: The index of the code range. */
1464 /* */
1465 /* aIP :: The new IP address in the code range. */
1466 /* */
1467 /* <Return> */
1468 /* SUCCESS or FAILURE. */
1469 /* */
1470 static FT_Bool
1471 Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange,
1472 FT_ULong aIP )
1474 TT_CodeRange* range;
1477 if ( aRange < 1 || aRange > 3 )
1479 CUR.error = TT_Err_Bad_Argument;
1480 return FAILURE;
1483 range = &CUR.codeRangeTable[aRange - 1];
1485 if ( range->base == NULL ) /* invalid coderange */
1487 CUR.error = TT_Err_Invalid_CodeRange;
1488 return FAILURE;
1491 /* NOTE: Because the last instruction of a program may be a CALL */
1492 /* which will return to the first byte *after* the code */
1493 /* range, we test for AIP <= Size, instead of AIP < Size. */
1495 if ( aIP > range->size )
1497 CUR.error = TT_Err_Code_Overflow;
1498 return FAILURE;
1501 CUR.code = range->base;
1502 CUR.codeSize = range->size;
1503 CUR.IP = aIP;
1504 CUR.curRange = aRange;
1506 return SUCCESS;
1510 /*************************************************************************/
1511 /* */
1512 /* <Function> */
1513 /* Direct_Move */
1514 /* */
1515 /* <Description> */
1516 /* Moves a point by a given distance along the freedom vector. The */
1517 /* point will be `touched'. */
1518 /* */
1519 /* <Input> */
1520 /* point :: The index of the point to move. */
1521 /* */
1522 /* distance :: The distance to apply. */
1523 /* */
1524 /* <InOut> */
1525 /* zone :: The affected glyph zone. */
1526 /* */
1527 static void
1528 Direct_Move( EXEC_OP_ TT_GlyphZone zone,
1529 FT_UShort point,
1530 FT_F26Dot6 distance )
1532 FT_F26Dot6 v;
1535 v = CUR.GS.freeVector.x;
1537 if ( v != 0 )
1540 #ifdef NO_APPLE_PATENT
1542 if ( ABS( CUR.F_dot_P ) > APPLE_THRESHOLD )
1543 zone->cur[point].x += distance;
1545 #else
1547 zone->cur[point].x += TT_MULDIV( distance,
1548 v * 0x10000L,
1549 CUR.F_dot_P );
1551 #endif
1553 zone->tags[point] |= FT_Curve_Tag_Touch_X;
1556 v = CUR.GS.freeVector.y;
1558 if ( v != 0 )
1561 #ifdef NO_APPLE_PATENT
1563 if ( ABS( CUR.F_dot_P ) > APPLE_THRESHOLD )
1564 zone->cur[point].y += distance;
1566 #else
1568 zone->cur[point].y += TT_MULDIV( distance,
1569 v * 0x10000L,
1570 CUR.F_dot_P );
1572 #endif
1574 zone->tags[point] |= FT_Curve_Tag_Touch_Y;
1579 /*************************************************************************/
1580 /* */
1581 /* Special versions of Direct_Move() */
1582 /* */
1583 /* The following versions are used whenever both vectors are both */
1584 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1585 /* */
1586 /*************************************************************************/
1589 static void
1590 Direct_Move_X( EXEC_OP_ TT_GlyphZone zone,
1591 FT_UShort point,
1592 FT_F26Dot6 distance )
1594 FT_UNUSED_EXEC;
1596 zone->cur[point].x += distance;
1597 zone->tags[point] |= FT_Curve_Tag_Touch_X;
1601 static void
1602 Direct_Move_Y( EXEC_OP_ TT_GlyphZone zone,
1603 FT_UShort point,
1604 FT_F26Dot6 distance )
1606 FT_UNUSED_EXEC;
1608 zone->cur[point].y += distance;
1609 zone->tags[point] |= FT_Curve_Tag_Touch_Y;
1613 /*************************************************************************/
1614 /* */
1615 /* <Function> */
1616 /* Round_None */
1617 /* */
1618 /* <Description> */
1619 /* Does not round, but adds engine compensation. */
1620 /* */
1621 /* <Input> */
1622 /* distance :: The distance (not) to round. */
1623 /* */
1624 /* compensation :: The engine compensation. */
1625 /* */
1626 /* <Return> */
1627 /* The compensated distance. */
1628 /* */
1629 /* <Note> */
1630 /* The TrueType specification says very few about the relationship */
1631 /* between rounding and engine compensation. However, it seems from */
1632 /* the description of super round that we should add the compensation */
1633 /* before rounding. */
1634 /* */
1635 static FT_F26Dot6
1636 Round_None( EXEC_OP_ FT_F26Dot6 distance,
1637 FT_F26Dot6 compensation )
1639 FT_F26Dot6 val;
1641 FT_UNUSED_EXEC;
1644 if ( distance >= 0 )
1646 val = distance + compensation;
1647 if ( val < 0 )
1648 val = 0;
1650 else {
1651 val = distance - compensation;
1652 if ( val > 0 )
1653 val = 0;
1655 return val;
1659 /*************************************************************************/
1660 /* */
1661 /* <Function> */
1662 /* Round_To_Grid */
1663 /* */
1664 /* <Description> */
1665 /* Rounds value to grid after adding engine compensation. */
1666 /* */
1667 /* <Input> */
1668 /* distance :: The distance to round. */
1669 /* */
1670 /* compensation :: The engine compensation. */
1671 /* */
1672 /* <Return> */
1673 /* Rounded distance. */
1674 /* */
1675 static FT_F26Dot6
1676 Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1677 FT_F26Dot6 compensation )
1679 FT_F26Dot6 val;
1681 FT_UNUSED_EXEC;
1684 if ( distance >= 0 )
1686 val = distance + compensation + 32;
1687 if ( val > 0 )
1688 val &= ~63;
1689 else
1690 val = 0;
1692 else
1694 val = -( ( compensation - distance + 32 ) & -64 );
1695 if ( val > 0 )
1696 val = 0;
1699 return val;
1703 /*************************************************************************/
1704 /* */
1705 /* <Function> */
1706 /* Round_To_Half_Grid */
1707 /* */
1708 /* <Description> */
1709 /* Rounds value to half grid after adding engine compensation. */
1710 /* */
1711 /* <Input> */
1712 /* distance :: The distance to round. */
1713 /* */
1714 /* compensation :: The engine compensation. */
1715 /* */
1716 /* <Return> */
1717 /* Rounded distance. */
1718 /* */
1719 static FT_F26Dot6
1720 Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance,
1721 FT_F26Dot6 compensation )
1723 FT_F26Dot6 val;
1725 FT_UNUSED_EXEC;
1728 if ( distance >= 0 )
1730 val = ( ( distance + compensation ) & -64 ) + 32;
1731 if ( val < 0 )
1732 val = 0;
1734 else
1736 val = -( ( (compensation - distance) & -64 ) + 32 );
1737 if ( val > 0 )
1738 val = 0;
1741 return val;
1745 /*************************************************************************/
1746 /* */
1747 /* <Function> */
1748 /* Round_Down_To_Grid */
1749 /* */
1750 /* <Description> */
1751 /* Rounds value down to grid after adding engine compensation. */
1752 /* */
1753 /* <Input> */
1754 /* distance :: The distance to round. */
1755 /* */
1756 /* compensation :: The engine compensation. */
1757 /* */
1758 /* <Return> */
1759 /* Rounded distance. */
1760 /* */
1761 static FT_F26Dot6
1762 Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1763 FT_F26Dot6 compensation )
1765 FT_F26Dot6 val;
1767 FT_UNUSED_EXEC;
1770 if ( distance >= 0 )
1772 val = distance + compensation;
1773 if ( val > 0 )
1774 val &= ~63;
1775 else
1776 val = 0;
1778 else
1780 val = -( ( compensation - distance ) & -64 );
1781 if ( val > 0 )
1782 val = 0;
1785 return val;
1789 /*************************************************************************/
1790 /* */
1791 /* <Function> */
1792 /* Round_Up_To_Grid */
1793 /* */
1794 /* <Description> */
1795 /* Rounds value up to grid after adding engine compensation. */
1796 /* */
1797 /* <Input> */
1798 /* distance :: The distance to round. */
1799 /* */
1800 /* compensation :: The engine compensation. */
1801 /* */
1802 /* <Return> */
1803 /* Rounded distance. */
1804 /* */
1805 static FT_F26Dot6
1806 Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1807 FT_F26Dot6 compensation )
1809 FT_F26Dot6 val;
1812 FT_UNUSED_EXEC;
1814 if ( distance >= 0 )
1816 val = distance + compensation + 63;
1817 if ( val > 0 )
1818 val &= ~63;
1819 else
1820 val = 0;
1822 else
1824 val = -( ( compensation - distance + 63 ) & -64 );
1825 if ( val > 0 )
1826 val = 0;
1829 return val;
1833 /*************************************************************************/
1834 /* */
1835 /* <Function> */
1836 /* Round_To_Double_Grid */
1837 /* */
1838 /* <Description> */
1839 /* Rounds value to double grid after adding engine compensation. */
1840 /* */
1841 /* <Input> */
1842 /* distance :: The distance to round. */
1843 /* */
1844 /* compensation :: The engine compensation. */
1845 /* */
1846 /* <Return> */
1847 /* Rounded distance. */
1848 /* */
1849 static FT_F26Dot6
1850 Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance,
1851 FT_F26Dot6 compensation )
1853 FT_F26Dot6 val;
1855 FT_UNUSED_EXEC;
1858 if ( distance >= 0 )
1860 val = distance + compensation + 16;
1861 if ( val > 0 )
1862 val &= ~31;
1863 else
1864 val = 0;
1866 else
1868 val = -( ( compensation - distance + 16 ) & -32 );
1869 if ( val > 0 )
1870 val = 0;
1873 return val;
1877 /*************************************************************************/
1878 /* */
1879 /* <Function> */
1880 /* Round_Super */
1881 /* */
1882 /* <Description> */
1883 /* Super-rounds value to grid after adding engine compensation. */
1884 /* */
1885 /* <Input> */
1886 /* distance :: The distance to round. */
1887 /* */
1888 /* compensation :: The engine compensation. */
1889 /* */
1890 /* <Return> */
1891 /* Rounded distance. */
1892 /* */
1893 /* <Note> */
1894 /* The TrueType specification says very few about the relationship */
1895 /* between rounding and engine compensation. However, it seems from */
1896 /* the description of super round that we should add the compensation */
1897 /* before rounding. */
1898 /* */
1899 static FT_F26Dot6
1900 Round_Super( EXEC_OP_ FT_F26Dot6 distance,
1901 FT_F26Dot6 compensation )
1903 FT_F26Dot6 val;
1906 if ( distance >= 0 )
1908 val = ( distance - CUR.phase + CUR.threshold + compensation ) &
1909 -CUR.period;
1910 if ( val < 0 )
1911 val = 0;
1912 val += CUR.phase;
1914 else
1916 val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &
1917 -CUR.period );
1918 if ( val > 0 )
1919 val = 0;
1920 val -= CUR.phase;
1923 return val;
1927 /*************************************************************************/
1928 /* */
1929 /* <Function> */
1930 /* Round_Super_45 */
1931 /* */
1932 /* <Description> */
1933 /* Super-rounds value to grid after adding engine compensation. */
1934 /* */
1935 /* <Input> */
1936 /* distance :: The distance to round. */
1937 /* */
1938 /* compensation :: The engine compensation. */
1939 /* */
1940 /* <Return> */
1941 /* Rounded distance. */
1942 /* */
1943 /* <Note> */
1944 /* There is a separate function for Round_Super_45() as we may need */
1945 /* greater precision. */
1946 /* */
1947 static FT_F26Dot6
1948 Round_Super_45( EXEC_OP_ FT_F26Dot6 distance,
1949 FT_F26Dot6 compensation )
1951 FT_F26Dot6 val;
1954 if ( distance >= 0 )
1956 val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
1957 CUR.period ) * CUR.period;
1958 if ( val < 0 )
1959 val = 0;
1960 val += CUR.phase;
1962 else
1964 val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /
1965 CUR.period ) * CUR.period );
1966 if ( val > 0 )
1967 val = 0;
1968 val -= CUR.phase;
1971 return val;
1975 /*************************************************************************/
1976 /* */
1977 /* <Function> */
1978 /* Compute_Round */
1979 /* */
1980 /* <Description> */
1981 /* Sets the rounding mode. */
1982 /* */
1983 /* <Input> */
1984 /* round_mode :: The rounding mode to be used. */
1985 /* */
1986 static void
1987 Compute_Round( EXEC_OP_ FT_Byte round_mode )
1989 switch ( round_mode )
1991 case TT_Round_Off:
1992 CUR.func_round = (TT_Round_Func)Round_None;
1993 break;
1995 case TT_Round_To_Grid:
1996 CUR.func_round = (TT_Round_Func)Round_To_Grid;
1997 break;
1999 case TT_Round_Up_To_Grid:
2000 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2001 break;
2003 case TT_Round_Down_To_Grid:
2004 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2005 break;
2007 case TT_Round_To_Half_Grid:
2008 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2009 break;
2011 case TT_Round_To_Double_Grid:
2012 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2013 break;
2015 case TT_Round_Super:
2016 CUR.func_round = (TT_Round_Func)Round_Super;
2017 break;
2019 case TT_Round_Super_45:
2020 CUR.func_round = (TT_Round_Func)Round_Super_45;
2021 break;
2026 /*************************************************************************/
2027 /* */
2028 /* <Function> */
2029 /* SetSuperRound */
2030 /* */
2031 /* <Description> */
2032 /* Sets Super Round parameters. */
2033 /* */
2034 /* <Input> */
2035 /* GridPeriod :: Grid period */
2036 /* selector :: SROUND opcode */
2037 /* */
2038 static void
2039 SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod,
2040 FT_Long selector )
2042 switch ( (FT_Int)( selector & 0xC0 ) )
2044 case 0:
2045 CUR.period = GridPeriod / 2;
2046 break;
2048 case 0x40:
2049 CUR.period = GridPeriod;
2050 break;
2052 case 0x80:
2053 CUR.period = GridPeriod * 2;
2054 break;
2056 /* This opcode is reserved, but... */
2058 case 0xC0:
2059 CUR.period = GridPeriod;
2060 break;
2063 switch ( (FT_Int)( selector & 0x30 ) )
2065 case 0:
2066 CUR.phase = 0;
2067 break;
2069 case 0x10:
2070 CUR.phase = CUR.period / 4;
2071 break;
2073 case 0x20:
2074 CUR.phase = CUR.period / 2;
2075 break;
2077 case 0x30:
2078 CUR.phase = GridPeriod * 3 / 4;
2079 break;
2082 if ( (selector & 0x0F) == 0 )
2083 CUR.threshold = CUR.period - 1;
2084 else
2085 CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8;
2087 CUR.period /= 256;
2088 CUR.phase /= 256;
2089 CUR.threshold /= 256;
2093 /*************************************************************************/
2094 /* */
2095 /* <Function> */
2096 /* Project */
2097 /* */
2098 /* <Description> */
2099 /* Computes the projection of vector given by (v2-v1) along the */
2100 /* current projection vector. */
2101 /* */
2102 /* <Input> */
2103 /* v1 :: First input vector. */
2104 /* v2 :: Second input vector. */
2105 /* */
2106 /* <Return> */
2107 /* The distance in F26dot6 format. */
2108 /* */
2109 static FT_F26Dot6
2110 Project( EXEC_OP_ FT_Vector* v1,
2111 FT_Vector* v2 )
2113 return TT_DotFix14( v1->x - v2->x,
2114 v1->y - v2->y,
2115 CUR.GS.projVector.x,
2116 CUR.GS.projVector.y );
2120 /*************************************************************************/
2121 /* */
2122 /* <Function> */
2123 /* Dual_Project */
2124 /* */
2125 /* <Description> */
2126 /* Computes the projection of the vector given by (v2-v1) along the */
2127 /* current dual vector. */
2128 /* */
2129 /* <Input> */
2130 /* v1 :: First input vector. */
2131 /* v2 :: Second input vector. */
2132 /* */
2133 /* <Return> */
2134 /* The distance in F26dot6 format. */
2135 /* */
2136 static FT_F26Dot6
2137 Dual_Project( EXEC_OP_ FT_Vector* v1,
2138 FT_Vector* v2 )
2140 return TT_DotFix14( v1->x - v2->x,
2141 v1->y - v2->y,
2142 CUR.GS.dualVector.x,
2143 CUR.GS.dualVector.y );
2147 /*************************************************************************/
2148 /* */
2149 /* <Function> */
2150 /* Free_Project */
2151 /* */
2152 /* <Description> */
2153 /* Computes the projection of the vector given by (v2-v1) along the */
2154 /* current freedom vector. */
2155 /* */
2156 /* <Input> */
2157 /* v1 :: First input vector. */
2158 /* v2 :: Second input vector. */
2159 /* */
2160 /* <Return> */
2161 /* The distance in F26dot6 format. */
2162 /* */
2163 static FT_F26Dot6
2164 Free_Project( EXEC_OP_ FT_Vector* v1,
2165 FT_Vector* v2 )
2167 return TT_DotFix14( v1->x - v2->x,
2168 v1->y - v2->y,
2169 CUR.GS.freeVector.x,
2170 CUR.GS.freeVector.y );
2174 /*************************************************************************/
2175 /* */
2176 /* <Function> */
2177 /* Project_x */
2178 /* */
2179 /* <Description> */
2180 /* Computes the projection of the vector given by (v2-v1) along the */
2181 /* horizontal axis. */
2182 /* */
2183 /* <Input> */
2184 /* v1 :: First input vector. */
2185 /* v2 :: Second input vector. */
2186 /* */
2187 /* <Return> */
2188 /* The distance in F26dot6 format. */
2189 /* */
2190 static FT_F26Dot6
2191 Project_x( EXEC_OP_ FT_Vector* v1,
2192 FT_Vector* v2 )
2194 FT_UNUSED_EXEC;
2196 return ( v1->x - v2->x );
2200 /*************************************************************************/
2201 /* */
2202 /* <Function> */
2203 /* Project_y */
2204 /* */
2205 /* <Description> */
2206 /* Computes the projection of the vector given by (v2-v1) along the */
2207 /* vertical axis. */
2208 /* */
2209 /* <Input> */
2210 /* v1 :: First input vector. */
2211 /* v2 :: Second input vector. */
2212 /* */
2213 /* <Return> */
2214 /* The distance in F26dot6 format. */
2215 /* */
2216 static FT_F26Dot6
2217 Project_y( EXEC_OP_ FT_Vector* v1,
2218 FT_Vector* v2 )
2220 FT_UNUSED_EXEC;
2222 return ( v1->y - v2->y );
2226 /*************************************************************************/
2227 /* */
2228 /* <Function> */
2229 /* Compute_Funcs */
2230 /* */
2231 /* <Description> */
2232 /* Computes the projection and movement function pointers according */
2233 /* to the current graphics state. */
2234 /* */
2235 static void
2236 Compute_Funcs( EXEC_OP )
2238 if ( CUR.GS.freeVector.x == 0x4000 )
2240 CUR.func_freeProj = (TT_Project_Func)Project_x;
2241 CUR.F_dot_P = CUR.GS.projVector.x * 0x10000L;
2243 else
2245 if ( CUR.GS.freeVector.y == 0x4000 )
2247 CUR.func_freeProj = (TT_Project_Func)Project_y;
2248 CUR.F_dot_P = CUR.GS.projVector.y * 0x10000L;
2250 else
2252 CUR.func_freeProj = (TT_Project_Func)Free_Project;
2253 CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
2254 (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
2258 if ( CUR.GS.projVector.x == 0x4000 )
2259 CUR.func_project = (TT_Project_Func)Project_x;
2260 else
2262 if ( CUR.GS.projVector.y == 0x4000 )
2263 CUR.func_project = (TT_Project_Func)Project_y;
2264 else
2265 CUR.func_project = (TT_Project_Func)Project;
2268 if ( CUR.GS.dualVector.x == 0x4000 )
2269 CUR.func_dualproj = (TT_Project_Func)Project_x;
2270 else
2272 if ( CUR.GS.dualVector.y == 0x4000 )
2273 CUR.func_dualproj = (TT_Project_Func)Project_y;
2274 else
2275 CUR.func_dualproj = (TT_Project_Func)Dual_Project;
2278 CUR.func_move = (TT_Move_Func)Direct_Move;
2280 if ( CUR.F_dot_P == 0x40000000L )
2282 if ( CUR.GS.freeVector.x == 0x4000 )
2283 CUR.func_move = (TT_Move_Func)Direct_Move_X;
2284 else
2286 if ( CUR.GS.freeVector.y == 0x4000 )
2287 CUR.func_move = (TT_Move_Func)Direct_Move_Y;
2291 /* at small sizes, F_dot_P can become too small, resulting */
2292 /* in overflows and `spikes' in a number of glyphs like `w'. */
2294 if ( ABS( CUR.F_dot_P ) < 0x4000000L )
2295 CUR.F_dot_P = 0x40000000L;
2297 /* Disable cached aspect ratio */
2298 CUR.tt_metrics.ratio = 0;
2302 /*************************************************************************/
2303 /* */
2304 /* <Function> */
2305 /* Normalize */
2306 /* */
2307 /* <Description> */
2308 /* Norms a vector. */
2309 /* */
2310 /* <Input> */
2311 /* Vx :: The horizontal input vector coordinate. */
2312 /* Vy :: The vertical input vector coordinate. */
2313 /* */
2314 /* <Output> */
2315 /* R :: The normed unit vector. */
2316 /* */
2317 /* <Return> */
2318 /* Returns FAILURE if a vector parameter is zero. */
2319 /* */
2320 /* <Note> */
2321 /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
2322 /* R is undefined. */
2323 /* */
2326 static FT_Bool
2327 Normalize( EXEC_OP_ FT_F26Dot6 Vx,
2328 FT_F26Dot6 Vy,
2329 FT_UnitVector* R )
2331 FT_F26Dot6 W;
2332 FT_Bool S1, S2;
2334 FT_UNUSED_EXEC;
2337 if ( ABS( Vx ) < 0x10000L && ABS( Vy ) < 0x10000L )
2339 Vx *= 0x100;
2340 Vy *= 0x100;
2342 W = TT_VecLen( Vx, Vy );
2344 if ( W == 0 )
2346 /* XXX: UNDOCUMENTED! It seems that it is possible to try */
2347 /* to normalize the vector (0,0). Return immediately. */
2348 return SUCCESS;
2351 R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W );
2352 R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W );
2354 return SUCCESS;
2357 W = TT_VecLen( Vx, Vy );
2359 Vx = FT_MulDiv( Vx, 0x4000L, W );
2360 Vy = FT_MulDiv( Vy, 0x4000L, W );
2362 W = Vx * Vx + Vy * Vy;
2364 /* Now, we want that Sqrt( W ) = 0x4000 */
2365 /* Or 0x1000000 <= W < 0x1004000 */
2367 if ( Vx < 0 )
2369 Vx = -Vx;
2370 S1 = TRUE;
2372 else
2373 S1 = FALSE;
2375 if ( Vy < 0 )
2377 Vy = -Vy;
2378 S2 = TRUE;
2380 else
2381 S2 = FALSE;
2383 while ( W < 0x1000000L )
2385 /* We need to increase W by a minimal amount */
2386 if ( Vx < Vy )
2387 Vx++;
2388 else
2389 Vy++;
2391 W = Vx * Vx + Vy * Vy;
2394 while ( W >= 0x1004000L )
2396 /* We need to decrease W by a minimal amount */
2397 if ( Vx < Vy )
2398 Vx--;
2399 else
2400 Vy--;
2402 W = Vx * Vx + Vy * Vy;
2405 /* Note that in various cases, we can only */
2406 /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
2408 if ( S1 )
2409 Vx = -Vx;
2411 if ( S2 )
2412 Vy = -Vy;
2414 R->x = (FT_F2Dot14)Vx; /* Type conversion */
2415 R->y = (FT_F2Dot14)Vy; /* Type conversion */
2417 return SUCCESS;
2421 /*************************************************************************/
2422 /* */
2423 /* Here we start with the implementation of the various opcodes. */
2424 /* */
2425 /*************************************************************************/
2428 static FT_Bool
2429 Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1,
2430 FT_UShort aIdx2,
2431 FT_Int aOpc,
2432 FT_UnitVector* Vec )
2434 FT_Long A, B, C;
2435 FT_Vector* p1;
2436 FT_Vector* p2;
2439 if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
2440 BOUNDS( aIdx2, CUR.zp1.n_points ) )
2442 if ( CUR.pedantic_hinting )
2443 CUR.error = TT_Err_Invalid_Reference;
2444 return FAILURE;
2447 p1 = CUR.zp1.cur + aIdx2;
2448 p2 = CUR.zp2.cur + aIdx1;
2450 A = p1->x - p2->x;
2451 B = p1->y - p2->y;
2453 if ( ( aOpc & 1 ) != 0 )
2455 C = B; /* counter clockwise rotation */
2456 B = A;
2457 A = -C;
2460 NORMalize( A, B, Vec );
2462 return SUCCESS;
2466 /* When not using the big switch statements, the interpreter uses a */
2467 /* call table defined later below in this source. Each opcode must */
2468 /* thus have a corresponding function, even trivial ones. */
2469 /* */
2470 /* They are all defined there. */
2472 #define DO_SVTCA \
2474 FT_Short A, B; \
2477 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2478 B = A ^ (FT_Short)0x4000; \
2480 CUR.GS.freeVector.x = A; \
2481 CUR.GS.projVector.x = A; \
2482 CUR.GS.dualVector.x = A; \
2484 CUR.GS.freeVector.y = B; \
2485 CUR.GS.projVector.y = B; \
2486 CUR.GS.dualVector.y = B; \
2488 COMPUTE_Funcs(); \
2492 #define DO_SPVTCA \
2494 FT_Short A, B; \
2497 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2498 B = A ^ (FT_Short)0x4000; \
2500 CUR.GS.projVector.x = A; \
2501 CUR.GS.dualVector.x = A; \
2503 CUR.GS.projVector.y = B; \
2504 CUR.GS.dualVector.y = B; \
2506 COMPUTE_Funcs(); \
2510 #define DO_SFVTCA \
2512 FT_Short A, B; \
2515 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2516 B = A ^ (FT_Short)0x4000; \
2518 CUR.GS.freeVector.x = A; \
2519 CUR.GS.freeVector.y = B; \
2521 COMPUTE_Funcs(); \
2525 #define DO_SPVTL \
2526 if ( INS_SxVTL( (FT_UShort)args[1], \
2527 (FT_UShort)args[0], \
2528 CUR.opcode, \
2529 &CUR.GS.projVector ) == SUCCESS ) \
2531 CUR.GS.dualVector = CUR.GS.projVector; \
2532 COMPUTE_Funcs(); \
2536 #define DO_SFVTL \
2537 if ( INS_SxVTL( (FT_UShort)args[1], \
2538 (FT_UShort)args[0], \
2539 CUR.opcode, \
2540 &CUR.GS.freeVector ) == SUCCESS ) \
2541 COMPUTE_Funcs();
2544 #define DO_SFVTPV \
2545 CUR.GS.freeVector = CUR.GS.projVector; \
2546 COMPUTE_Funcs();
2549 #define DO_SPVFS \
2551 FT_Short S; \
2552 FT_Long X, Y; \
2555 /* Only use low 16bits, then sign extend */ \
2556 S = (FT_Short)args[1]; \
2557 Y = (FT_Long)S; \
2558 S = (FT_Short)args[0]; \
2559 X = (FT_Long)S; \
2561 NORMalize( X, Y, &CUR.GS.projVector ); \
2563 CUR.GS.dualVector = CUR.GS.projVector; \
2564 COMPUTE_Funcs(); \
2568 #define DO_SFVFS \
2570 FT_Short S; \
2571 FT_Long X, Y; \
2574 /* Only use low 16bits, then sign extend */ \
2575 S = (FT_Short)args[1]; \
2576 Y = (FT_Long)S; \
2577 S = (FT_Short)args[0]; \
2578 X = S; \
2580 NORMalize( X, Y, &CUR.GS.freeVector ); \
2581 COMPUTE_Funcs(); \
2585 #define DO_GPV \
2586 args[0] = CUR.GS.projVector.x; \
2587 args[1] = CUR.GS.projVector.y;
2590 #define DO_GFV \
2591 args[0] = CUR.GS.freeVector.x; \
2592 args[1] = CUR.GS.freeVector.y;
2595 #define DO_SRP0 \
2596 CUR.GS.rp0 = (FT_UShort)args[0];
2599 #define DO_SRP1 \
2600 CUR.GS.rp1 = (FT_UShort)args[0];
2603 #define DO_SRP2 \
2604 CUR.GS.rp2 = (FT_UShort)args[0];
2607 #define DO_RTHG \
2608 CUR.GS.round_state = TT_Round_To_Half_Grid; \
2609 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2612 #define DO_RTG \
2613 CUR.GS.round_state = TT_Round_To_Grid; \
2614 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2617 #define DO_RTDG \
2618 CUR.GS.round_state = TT_Round_To_Double_Grid; \
2619 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2622 #define DO_RUTG \
2623 CUR.GS.round_state = TT_Round_Up_To_Grid; \
2624 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2627 #define DO_RDTG \
2628 CUR.GS.round_state = TT_Round_Down_To_Grid; \
2629 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2632 #define DO_ROFF \
2633 CUR.GS.round_state = TT_Round_Off; \
2634 CUR.func_round = (TT_Round_Func)Round_None;
2637 #define DO_SROUND \
2638 SET_SuperRound( 0x4000, args[0] ); \
2639 CUR.GS.round_state = TT_Round_Super; \
2640 CUR.func_round = (TT_Round_Func)Round_Super;
2643 #define DO_S45ROUND \
2644 SET_SuperRound( 0x2D41, args[0] ); \
2645 CUR.GS.round_state = TT_Round_Super_45; \
2646 CUR.func_round = (TT_Round_Func)Round_Super_45;
2649 #define DO_SLOOP \
2650 if ( args[0] < 0 ) \
2651 CUR.error = TT_Err_Bad_Argument; \
2652 else \
2653 CUR.GS.loop = args[0];
2656 #define DO_SMD \
2657 CUR.GS.minimum_distance = args[0];
2660 #define DO_SCVTCI \
2661 CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
2664 #define DO_SSWCI \
2665 CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
2668 /* XXX: UNDOCUMENTED! or bug in the Windows engine? */
2669 /* */
2670 /* It seems that the value that is read here is */
2671 /* expressed in 16.16 format rather than in font */
2672 /* units. */
2673 /* */
2674 #define DO_SSW \
2675 CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
2678 #define DO_FLIPON \
2679 CUR.GS.auto_flip = TRUE;
2682 #define DO_FLIPOFF \
2683 CUR.GS.auto_flip = FALSE;
2686 #define DO_SDB \
2687 CUR.GS.delta_base = (FT_Short)args[0];
2690 #define DO_SDS \
2691 CUR.GS.delta_shift = (FT_Short)args[0];
2694 #define DO_MD /* nothing */
2697 #define DO_MPPEM \
2698 args[0] = CURRENT_Ppem();
2701 /* Note: The pointSize should be irrelevant in a given font program; */
2702 /* we thus decide to return only the ppem. */
2703 #if 0
2705 #define DO_MPS \
2706 args[0] = CUR.metrics.pointSize;
2708 #else
2710 #define DO_MPS \
2711 args[0] = CURRENT_Ppem();
2713 #endif /* 0 */
2716 #define DO_DUP \
2717 args[1] = args[0];
2720 #define DO_CLEAR \
2721 CUR.new_top = 0;
2724 #define DO_SWAP \
2726 FT_Long L; \
2729 L = args[0]; \
2730 args[0] = args[1]; \
2731 args[1] = L; \
2735 #define DO_DEPTH \
2736 args[0] = CUR.top;
2739 #define DO_CINDEX \
2741 FT_Long L; \
2744 L = args[0]; \
2746 if ( L <= 0 || L > CUR.args ) \
2747 CUR.error = TT_Err_Invalid_Reference; \
2748 else \
2749 args[0] = CUR.stack[CUR.args - L]; \
2753 #define DO_JROT \
2754 if ( args[1] != 0 ) \
2756 CUR.IP += args[0]; \
2757 CUR.step_ins = FALSE; \
2761 #define DO_JMPR \
2762 CUR.IP += args[0]; \
2763 CUR.step_ins = FALSE;
2766 #define DO_JROF \
2767 if ( args[1] == 0 ) \
2769 CUR.IP += args[0]; \
2770 CUR.step_ins = FALSE; \
2774 #define DO_LT \
2775 args[0] = ( args[0] < args[1] );
2778 #define DO_LTEQ \
2779 args[0] = ( args[0] <= args[1] );
2782 #define DO_GT \
2783 args[0] = ( args[0] > args[1] );
2786 #define DO_GTEQ \
2787 args[0] = ( args[0] >= args[1] );
2790 #define DO_EQ \
2791 args[0] = ( args[0] == args[1] );
2794 #define DO_NEQ \
2795 args[0] = ( args[0] != args[1] );
2798 #define DO_ODD \
2799 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
2802 #define DO_EVEN \
2803 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
2806 #define DO_AND \
2807 args[0] = ( args[0] && args[1] );
2810 #define DO_OR \
2811 args[0] = ( args[0] || args[1] );
2814 #define DO_NOT \
2815 args[0] = !args[0];
2818 #define DO_ADD \
2819 args[0] += args[1];
2822 #define DO_SUB \
2823 args[0] -= args[1];
2826 #define DO_DIV \
2827 if ( args[1] == 0 ) \
2828 CUR.error = TT_Err_Divide_By_Zero; \
2829 else \
2830 args[0] = TT_MULDIV( args[0], 64L, args[1] );
2833 #define DO_MUL \
2834 args[0] = TT_MULDIV( args[0], args[1], 64L );
2837 #define DO_ABS \
2838 args[0] = ABS( args[0] );
2841 #define DO_NEG \
2842 args[0] = -args[0];
2845 #define DO_FLOOR \
2846 args[0] &= -64;
2849 #define DO_CEILING \
2850 args[0] = ( args[0] + 63 ) & -64;
2853 #define DO_RS \
2855 FT_ULong I = (FT_ULong)args[0]; \
2858 if ( BOUNDS( I, CUR.storeSize ) ) \
2860 if ( CUR.pedantic_hinting ) \
2862 ARRAY_BOUND_ERROR; \
2864 else \
2865 args[0] = 0; \
2867 else \
2868 args[0] = CUR.storage[I]; \
2872 #define DO_WS \
2874 FT_ULong I = (FT_ULong)args[0]; \
2877 if ( BOUNDS( I, CUR.storeSize ) ) \
2879 if ( CUR.pedantic_hinting ) \
2881 ARRAY_BOUND_ERROR; \
2884 else \
2885 CUR.storage[I] = args[1]; \
2889 #define DO_RCVT \
2891 FT_ULong I = (FT_ULong)args[0]; \
2894 if ( BOUNDS( I, CUR.cvtSize ) ) \
2896 if ( CUR.pedantic_hinting ) \
2898 ARRAY_BOUND_ERROR; \
2900 else \
2901 args[0] = 0; \
2903 else \
2904 args[0] = CUR_Func_read_cvt( I ); \
2908 #define DO_WCVTP \
2910 FT_ULong I = (FT_ULong)args[0]; \
2913 if ( BOUNDS( I, CUR.cvtSize ) ) \
2915 if ( CUR.pedantic_hinting ) \
2917 ARRAY_BOUND_ERROR; \
2920 else \
2921 CUR_Func_write_cvt( I, args[1] ); \
2925 #define DO_WCVTF \
2927 FT_ULong I = (FT_ULong)args[0]; \
2930 if ( BOUNDS( I, CUR.cvtSize ) ) \
2932 if ( CUR.pedantic_hinting ) \
2934 ARRAY_BOUND_ERROR; \
2937 else \
2938 CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
2942 #define DO_DEBUG \
2943 CUR.error = TT_Err_Debug_OpCode;
2946 #define DO_ROUND \
2947 args[0] = CUR_Func_round( \
2948 args[0], \
2949 CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
2952 #define DO_NROUND \
2953 args[0] = ROUND_None( args[0], \
2954 CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
2957 #define DO_MAX \
2958 if ( args[1] > args[0] ) \
2959 args[0] = args[1];
2962 #define DO_MIN \
2963 if ( args[1] < args[0] ) \
2964 args[0] = args[1];
2967 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
2970 #undef ARRAY_BOUND_ERROR
2971 #define ARRAY_BOUND_ERROR \
2973 CUR.error = TT_Err_Invalid_Reference; \
2974 return; \
2978 /*************************************************************************/
2979 /* */
2980 /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
2981 /* Opcode range: 0x00-0x01 */
2982 /* Stack: --> */
2983 /* */
2984 static void
2985 Ins_SVTCA( INS_ARG )
2987 DO_SVTCA
2991 /*************************************************************************/
2992 /* */
2993 /* SPVTCA[a]: Set PVector to Coordinate Axis */
2994 /* Opcode range: 0x02-0x03 */
2995 /* Stack: --> */
2996 /* */
2997 static void
2998 Ins_SPVTCA( INS_ARG )
3000 DO_SPVTCA
3004 /*************************************************************************/
3005 /* */
3006 /* SFVTCA[a]: Set FVector to Coordinate Axis */
3007 /* Opcode range: 0x04-0x05 */
3008 /* Stack: --> */
3009 /* */
3010 static void
3011 Ins_SFVTCA( INS_ARG )
3013 DO_SFVTCA
3017 /*************************************************************************/
3018 /* */
3019 /* SPVTL[a]: Set PVector To Line */
3020 /* Opcode range: 0x06-0x07 */
3021 /* Stack: uint32 uint32 --> */
3022 /* */
3023 static void
3024 Ins_SPVTL( INS_ARG )
3026 DO_SPVTL
3030 /*************************************************************************/
3031 /* */
3032 /* SFVTL[a]: Set FVector To Line */
3033 /* Opcode range: 0x08-0x09 */
3034 /* Stack: uint32 uint32 --> */
3035 /* */
3036 static void
3037 Ins_SFVTL( INS_ARG )
3039 DO_SFVTL
3043 /*************************************************************************/
3044 /* */
3045 /* SFVTPV[]: Set FVector To PVector */
3046 /* Opcode range: 0x0E */
3047 /* Stack: --> */
3048 /* */
3049 static void
3050 Ins_SFVTPV( INS_ARG )
3052 DO_SFVTPV
3056 /*************************************************************************/
3057 /* */
3058 /* SPVFS[]: Set PVector From Stack */
3059 /* Opcode range: 0x0A */
3060 /* Stack: f2.14 f2.14 --> */
3061 /* */
3062 static void
3063 Ins_SPVFS( INS_ARG )
3065 DO_SPVFS
3069 /*************************************************************************/
3070 /* */
3071 /* SFVFS[]: Set FVector From Stack */
3072 /* Opcode range: 0x0B */
3073 /* Stack: f2.14 f2.14 --> */
3074 /* */
3075 static void
3076 Ins_SFVFS( INS_ARG )
3078 DO_SFVFS
3082 /*************************************************************************/
3083 /* */
3084 /* GPV[]: Get Projection Vector */
3085 /* Opcode range: 0x0C */
3086 /* Stack: ef2.14 --> ef2.14 */
3087 /* */
3088 static void
3089 Ins_GPV( INS_ARG )
3091 DO_GPV
3095 /*************************************************************************/
3096 /* GFV[]: Get Freedom Vector */
3097 /* Opcode range: 0x0D */
3098 /* Stack: ef2.14 --> ef2.14 */
3099 /* */
3100 static void
3101 Ins_GFV( INS_ARG )
3103 DO_GFV
3107 /*************************************************************************/
3108 /* */
3109 /* SRP0[]: Set Reference Point 0 */
3110 /* Opcode range: 0x10 */
3111 /* Stack: uint32 --> */
3112 /* */
3113 static void
3114 Ins_SRP0( INS_ARG )
3116 DO_SRP0
3120 /*************************************************************************/
3121 /* */
3122 /* SRP1[]: Set Reference Point 1 */
3123 /* Opcode range: 0x11 */
3124 /* Stack: uint32 --> */
3125 /* */
3126 static void
3127 Ins_SRP1( INS_ARG )
3129 DO_SRP1
3133 /*************************************************************************/
3134 /* */
3135 /* SRP2[]: Set Reference Point 2 */
3136 /* Opcode range: 0x12 */
3137 /* Stack: uint32 --> */
3138 /* */
3139 static void
3140 Ins_SRP2( INS_ARG )
3142 DO_SRP2
3146 /*************************************************************************/
3147 /* */
3148 /* RTHG[]: Round To Half Grid */
3149 /* Opcode range: 0x19 */
3150 /* Stack: --> */
3151 /* */
3152 static void
3153 Ins_RTHG( INS_ARG )
3155 DO_RTHG
3159 /*************************************************************************/
3160 /* */
3161 /* RTG[]: Round To Grid */
3162 /* Opcode range: 0x18 */
3163 /* Stack: --> */
3164 /* */
3165 static void
3166 Ins_RTG( INS_ARG )
3168 DO_RTG
3172 /*************************************************************************/
3173 /* RTDG[]: Round To Double Grid */
3174 /* Opcode range: 0x3D */
3175 /* Stack: --> */
3176 /* */
3177 static void
3178 Ins_RTDG( INS_ARG )
3180 DO_RTDG
3184 /*************************************************************************/
3185 /* RUTG[]: Round Up To Grid */
3186 /* Opcode range: 0x7C */
3187 /* Stack: --> */
3188 /* */
3189 static void
3190 Ins_RUTG( INS_ARG )
3192 DO_RUTG
3196 /*************************************************************************/
3197 /* */
3198 /* RDTG[]: Round Down To Grid */
3199 /* Opcode range: 0x7D */
3200 /* Stack: --> */
3201 /* */
3202 static void
3203 Ins_RDTG( INS_ARG )
3205 DO_RDTG
3209 /*************************************************************************/
3210 /* */
3211 /* ROFF[]: Round OFF */
3212 /* Opcode range: 0x7A */
3213 /* Stack: --> */
3214 /* */
3215 static void
3216 Ins_ROFF( INS_ARG )
3218 DO_ROFF
3222 /*************************************************************************/
3223 /* */
3224 /* SROUND[]: Super ROUND */
3225 /* Opcode range: 0x76 */
3226 /* Stack: Eint8 --> */
3227 /* */
3228 static void
3229 Ins_SROUND( INS_ARG )
3231 DO_SROUND
3235 /*************************************************************************/
3236 /* */
3237 /* S45ROUND[]: Super ROUND 45 degrees */
3238 /* Opcode range: 0x77 */
3239 /* Stack: uint32 --> */
3240 /* */
3241 static void
3242 Ins_S45ROUND( INS_ARG )
3244 DO_S45ROUND
3248 /*************************************************************************/
3249 /* */
3250 /* SLOOP[]: Set LOOP variable */
3251 /* Opcode range: 0x17 */
3252 /* Stack: int32? --> */
3253 /* */
3254 static void
3255 Ins_SLOOP( INS_ARG )
3257 DO_SLOOP
3261 /*************************************************************************/
3262 /* */
3263 /* SMD[]: Set Minimum Distance */
3264 /* Opcode range: 0x1A */
3265 /* Stack: f26.6 --> */
3266 /* */
3267 static void
3268 Ins_SMD( INS_ARG )
3270 DO_SMD
3274 /*************************************************************************/
3275 /* */
3276 /* SCVTCI[]: Set Control Value Table Cut In */
3277 /* Opcode range: 0x1D */
3278 /* Stack: f26.6 --> */
3279 /* */
3280 static void
3281 Ins_SCVTCI( INS_ARG )
3283 DO_SCVTCI
3287 /*************************************************************************/
3288 /* */
3289 /* SSWCI[]: Set Single Width Cut In */
3290 /* Opcode range: 0x1E */
3291 /* Stack: f26.6 --> */
3292 /* */
3293 static void
3294 Ins_SSWCI( INS_ARG )
3296 DO_SSWCI
3300 /*************************************************************************/
3301 /* */
3302 /* SSW[]: Set Single Width */
3303 /* Opcode range: 0x1F */
3304 /* Stack: int32? --> */
3305 /* */
3306 static void
3307 Ins_SSW( INS_ARG )
3309 DO_SSW
3313 /*************************************************************************/
3314 /* */
3315 /* FLIPON[]: Set auto-FLIP to ON */
3316 /* Opcode range: 0x4D */
3317 /* Stack: --> */
3318 /* */
3319 static void
3320 Ins_FLIPON( INS_ARG )
3322 DO_FLIPON
3326 /*************************************************************************/
3327 /* */
3328 /* FLIPOFF[]: Set auto-FLIP to OFF */
3329 /* Opcode range: 0x4E */
3330 /* Stack: --> */
3331 /* */
3332 static void
3333 Ins_FLIPOFF( INS_ARG )
3335 DO_FLIPOFF
3339 /*************************************************************************/
3340 /* */
3341 /* SANGW[]: Set ANGle Weight */
3342 /* Opcode range: 0x7E */
3343 /* Stack: uint32 --> */
3344 /* */
3345 static void
3346 Ins_SANGW( INS_ARG )
3348 /* instruction not supported anymore */
3352 /*************************************************************************/
3353 /* */
3354 /* SDB[]: Set Delta Base */
3355 /* Opcode range: 0x5E */
3356 /* Stack: uint32 --> */
3357 /* */
3358 static void
3359 Ins_SDB( INS_ARG )
3361 DO_SDB
3365 /*************************************************************************/
3366 /* */
3367 /* SDS[]: Set Delta Shift */
3368 /* Opcode range: 0x5F */
3369 /* Stack: uint32 --> */
3370 /* */
3371 static void
3372 Ins_SDS( INS_ARG )
3374 DO_SDS
3378 /*************************************************************************/
3379 /* */
3380 /* MPPEM[]: Measure Pixel Per EM */
3381 /* Opcode range: 0x4B */
3382 /* Stack: --> Euint16 */
3383 /* */
3384 static void
3385 Ins_MPPEM( INS_ARG )
3387 DO_MPPEM
3391 /*************************************************************************/
3392 /* */
3393 /* MPS[]: Measure Point Size */
3394 /* Opcode range: 0x4C */
3395 /* Stack: --> Euint16 */
3396 /* */
3397 static void
3398 Ins_MPS( INS_ARG )
3400 DO_MPS
3404 /*************************************************************************/
3405 /* */
3406 /* DUP[]: DUPlicate the top stack's element */
3407 /* Opcode range: 0x20 */
3408 /* Stack: StkElt --> StkElt StkElt */
3409 /* */
3410 static void
3411 Ins_DUP( INS_ARG )
3413 DO_DUP
3417 /*************************************************************************/
3418 /* */
3419 /* POP[]: POP the stack's top element */
3420 /* Opcode range: 0x21 */
3421 /* Stack: StkElt --> */
3422 /* */
3423 static void
3424 Ins_POP( INS_ARG )
3426 /* nothing to do */
3430 /*************************************************************************/
3431 /* */
3432 /* CLEAR[]: CLEAR the entire stack */
3433 /* Opcode range: 0x22 */
3434 /* Stack: StkElt... --> */
3435 /* */
3436 static void
3437 Ins_CLEAR( INS_ARG )
3439 DO_CLEAR
3443 /*************************************************************************/
3444 /* */
3445 /* SWAP[]: SWAP the stack's top two elements */
3446 /* Opcode range: 0x23 */
3447 /* Stack: 2 * StkElt --> 2 * StkElt */
3448 /* */
3449 static void
3450 Ins_SWAP( INS_ARG )
3452 DO_SWAP
3456 /*************************************************************************/
3457 /* */
3458 /* DEPTH[]: return the stack DEPTH */
3459 /* Opcode range: 0x24 */
3460 /* Stack: --> uint32 */
3461 /* */
3462 static void
3463 Ins_DEPTH( INS_ARG )
3465 DO_DEPTH
3469 /*************************************************************************/
3470 /* */
3471 /* CINDEX[]: Copy INDEXed element */
3472 /* Opcode range: 0x25 */
3473 /* Stack: int32 --> StkElt */
3474 /* */
3475 static void
3476 Ins_CINDEX( INS_ARG )
3478 DO_CINDEX
3482 /*************************************************************************/
3483 /* */
3484 /* EIF[]: End IF */
3485 /* Opcode range: 0x59 */
3486 /* Stack: --> */
3487 /* */
3488 static void
3489 Ins_EIF( INS_ARG )
3491 /* nothing to do */
3495 /*************************************************************************/
3496 /* */
3497 /* JROT[]: Jump Relative On True */
3498 /* Opcode range: 0x78 */
3499 /* Stack: StkElt int32 --> */
3500 /* */
3501 static void
3502 Ins_JROT( INS_ARG )
3504 DO_JROT
3508 /*************************************************************************/
3509 /* */
3510 /* JMPR[]: JuMP Relative */
3511 /* Opcode range: 0x1C */
3512 /* Stack: int32 --> */
3513 /* */
3514 static void
3515 Ins_JMPR( INS_ARG )
3517 DO_JMPR
3521 /*************************************************************************/
3522 /* */
3523 /* JROF[]: Jump Relative On False */
3524 /* Opcode range: 0x79 */
3525 /* Stack: StkElt int32 --> */
3526 /* */
3527 static void
3528 Ins_JROF( INS_ARG )
3530 DO_JROF
3534 /*************************************************************************/
3535 /* */
3536 /* LT[]: Less Than */
3537 /* Opcode range: 0x50 */
3538 /* Stack: int32? int32? --> bool */
3539 /* */
3540 static void
3541 Ins_LT( INS_ARG )
3543 DO_LT
3547 /*************************************************************************/
3548 /* */
3549 /* LTEQ[]: Less Than or EQual */
3550 /* Opcode range: 0x51 */
3551 /* Stack: int32? int32? --> bool */
3552 /* */
3553 static void
3554 Ins_LTEQ( INS_ARG )
3556 DO_LTEQ
3560 /*************************************************************************/
3561 /* */
3562 /* GT[]: Greater Than */
3563 /* Opcode range: 0x52 */
3564 /* Stack: int32? int32? --> bool */
3565 /* */
3566 static void
3567 Ins_GT( INS_ARG )
3569 DO_GT
3573 /*************************************************************************/
3574 /* */
3575 /* GTEQ[]: Greater Than or EQual */
3576 /* Opcode range: 0x53 */
3577 /* Stack: int32? int32? --> bool */
3578 /* */
3579 static void
3580 Ins_GTEQ( INS_ARG )
3582 DO_GTEQ
3586 /*************************************************************************/
3587 /* */
3588 /* EQ[]: EQual */
3589 /* Opcode range: 0x54 */
3590 /* Stack: StkElt StkElt --> bool */
3591 /* */
3592 static void
3593 Ins_EQ( INS_ARG )
3595 DO_EQ
3599 /*************************************************************************/
3600 /* */
3601 /* NEQ[]: Not EQual */
3602 /* Opcode range: 0x55 */
3603 /* Stack: StkElt StkElt --> bool */
3604 /* */
3605 static void
3606 Ins_NEQ( INS_ARG )
3608 DO_NEQ
3612 /*************************************************************************/
3613 /* */
3614 /* ODD[]: Is ODD */
3615 /* Opcode range: 0x56 */
3616 /* Stack: f26.6 --> bool */
3617 /* */
3618 static void
3619 Ins_ODD( INS_ARG )
3621 DO_ODD
3625 /*************************************************************************/
3626 /* */
3627 /* EVEN[]: Is EVEN */
3628 /* Opcode range: 0x57 */
3629 /* Stack: f26.6 --> bool */
3630 /* */
3631 static void
3632 Ins_EVEN( INS_ARG )
3634 DO_EVEN
3638 /*************************************************************************/
3639 /* */
3640 /* AND[]: logical AND */
3641 /* Opcode range: 0x5A */
3642 /* Stack: uint32 uint32 --> uint32 */
3643 /* */
3644 static void
3645 Ins_AND( INS_ARG )
3647 DO_AND
3651 /*************************************************************************/
3652 /* */
3653 /* OR[]: logical OR */
3654 /* Opcode range: 0x5B */
3655 /* Stack: uint32 uint32 --> uint32 */
3656 /* */
3657 static void
3658 Ins_OR( INS_ARG )
3660 DO_OR
3664 /*************************************************************************/
3665 /* */
3666 /* NOT[]: logical NOT */
3667 /* Opcode range: 0x5C */
3668 /* Stack: StkElt --> uint32 */
3669 /* */
3670 static void
3671 Ins_NOT( INS_ARG )
3673 DO_NOT
3677 /*************************************************************************/
3678 /* */
3679 /* ADD[]: ADD */
3680 /* Opcode range: 0x60 */
3681 /* Stack: f26.6 f26.6 --> f26.6 */
3682 /* */
3683 static void
3684 Ins_ADD( INS_ARG )
3686 DO_ADD
3690 /*************************************************************************/
3691 /* */
3692 /* SUB[]: SUBtract */
3693 /* Opcode range: 0x61 */
3694 /* Stack: f26.6 f26.6 --> f26.6 */
3695 /* */
3696 static void
3697 Ins_SUB( INS_ARG )
3699 DO_SUB
3703 /*************************************************************************/
3704 /* */
3705 /* DIV[]: DIVide */
3706 /* Opcode range: 0x62 */
3707 /* Stack: f26.6 f26.6 --> f26.6 */
3708 /* */
3709 static void
3710 Ins_DIV( INS_ARG )
3712 DO_DIV
3716 /*************************************************************************/
3717 /* */
3718 /* MUL[]: MULtiply */
3719 /* Opcode range: 0x63 */
3720 /* Stack: f26.6 f26.6 --> f26.6 */
3721 /* */
3722 static void
3723 Ins_MUL( INS_ARG )
3725 DO_MUL
3729 /*************************************************************************/
3730 /* */
3731 /* ABS[]: ABSolute value */
3732 /* Opcode range: 0x64 */
3733 /* Stack: f26.6 --> f26.6 */
3734 /* */
3735 static void
3736 Ins_ABS( INS_ARG )
3738 DO_ABS
3742 /*************************************************************************/
3743 /* */
3744 /* NEG[]: NEGate */
3745 /* Opcode range: 0x65 */
3746 /* Stack: f26.6 --> f26.6 */
3747 /* */
3748 static void
3749 Ins_NEG( INS_ARG )
3751 DO_NEG
3755 /*************************************************************************/
3756 /* */
3757 /* FLOOR[]: FLOOR */
3758 /* Opcode range: 0x66 */
3759 /* Stack: f26.6 --> f26.6 */
3760 /* */
3761 static void
3762 Ins_FLOOR( INS_ARG )
3764 DO_FLOOR
3768 /*************************************************************************/
3769 /* */
3770 /* CEILING[]: CEILING */
3771 /* Opcode range: 0x67 */
3772 /* Stack: f26.6 --> f26.6 */
3773 /* */
3774 static void
3775 Ins_CEILING( INS_ARG )
3777 DO_CEILING
3781 /*************************************************************************/
3782 /* */
3783 /* RS[]: Read Store */
3784 /* Opcode range: 0x43 */
3785 /* Stack: uint32 --> uint32 */
3786 /* */
3787 static void
3788 Ins_RS( INS_ARG )
3790 DO_RS
3794 /*************************************************************************/
3795 /* */
3796 /* WS[]: Write Store */
3797 /* Opcode range: 0x42 */
3798 /* Stack: uint32 uint32 --> */
3799 /* */
3800 static void
3801 Ins_WS( INS_ARG )
3803 DO_WS
3807 /*************************************************************************/
3808 /* */
3809 /* WCVTP[]: Write CVT in Pixel units */
3810 /* Opcode range: 0x44 */
3811 /* Stack: f26.6 uint32 --> */
3812 /* */
3813 static void
3814 Ins_WCVTP( INS_ARG )
3816 DO_WCVTP
3820 /*************************************************************************/
3821 /* */
3822 /* WCVTF[]: Write CVT in Funits */
3823 /* Opcode range: 0x70 */
3824 /* Stack: uint32 uint32 --> */
3825 /* */
3826 static void
3827 Ins_WCVTF( INS_ARG )
3829 DO_WCVTF
3833 /*************************************************************************/
3834 /* */
3835 /* RCVT[]: Read CVT */
3836 /* Opcode range: 0x45 */
3837 /* Stack: uint32 --> f26.6 */
3838 /* */
3839 static void
3840 Ins_RCVT( INS_ARG )
3842 DO_RCVT
3846 /*************************************************************************/
3847 /* */
3848 /* AA[]: Adjust Angle */
3849 /* Opcode range: 0x7F */
3850 /* Stack: uint32 --> */
3851 /* */
3852 static void
3853 Ins_AA( INS_ARG )
3855 /* intentionally no longer supported */
3859 /*************************************************************************/
3860 /* */
3861 /* DEBUG[]: DEBUG. Unsupported. */
3862 /* Opcode range: 0x4F */
3863 /* Stack: uint32 --> */
3864 /* */
3865 /* Note: The original instruction pops a value from the stack. */
3866 /* */
3867 static void
3868 Ins_DEBUG( INS_ARG )
3870 DO_DEBUG
3874 /*************************************************************************/
3875 /* */
3876 /* ROUND[ab]: ROUND value */
3877 /* Opcode range: 0x68-0x6B */
3878 /* Stack: f26.6 --> f26.6 */
3879 /* */
3880 static void
3881 Ins_ROUND( INS_ARG )
3883 DO_ROUND
3887 /*************************************************************************/
3888 /* */
3889 /* NROUND[ab]: No ROUNDing of value */
3890 /* Opcode range: 0x6C-0x6F */
3891 /* Stack: f26.6 --> f26.6 */
3892 /* */
3893 static void
3894 Ins_NROUND( INS_ARG )
3896 DO_NROUND
3900 /*************************************************************************/
3901 /* */
3902 /* MAX[]: MAXimum */
3903 /* Opcode range: 0x68 */
3904 /* Stack: int32? int32? --> int32 */
3905 /* */
3906 static void
3907 Ins_MAX( INS_ARG )
3909 DO_MAX
3913 /*************************************************************************/
3914 /* */
3915 /* MIN[]: MINimum */
3916 /* Opcode range: 0x69 */
3917 /* Stack: int32? int32? --> int32 */
3918 /* */
3919 static void
3920 Ins_MIN( INS_ARG )
3922 DO_MIN
3926 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
3929 /*************************************************************************/
3930 /* */
3931 /* The following functions are called as is within the switch statement. */
3932 /* */
3933 /*************************************************************************/
3936 /*************************************************************************/
3937 /* */
3938 /* MINDEX[]: Move INDEXed element */
3939 /* Opcode range: 0x26 */
3940 /* Stack: int32? --> StkElt */
3941 /* */
3942 static void
3943 Ins_MINDEX( INS_ARG )
3945 FT_Long L, K;
3948 L = args[0];
3950 if ( L <= 0 || L > CUR.args )
3952 CUR.error = TT_Err_Invalid_Reference;
3953 return;
3956 K = CUR.stack[CUR.args - L];
3958 FT_MEM_MOVE( &CUR.stack[CUR.args - L ],
3959 &CUR.stack[CUR.args - L + 1],
3960 ( L - 1 ) * sizeof ( FT_Long ) );
3962 CUR.stack[CUR.args - 1] = K;
3966 /*************************************************************************/
3967 /* */
3968 /* ROLL[]: ROLL top three elements */
3969 /* Opcode range: 0x8A */
3970 /* Stack: 3 * StkElt --> 3 * StkElt */
3971 /* */
3972 static void
3973 Ins_ROLL( INS_ARG )
3975 FT_Long A, B, C;
3977 FT_UNUSED_EXEC;
3980 A = args[2];
3981 B = args[1];
3982 C = args[0];
3984 args[2] = C;
3985 args[1] = A;
3986 args[0] = B;
3990 /*************************************************************************/
3991 /* */
3992 /* MANAGING THE FLOW OF CONTROL */
3993 /* */
3994 /* Instructions appear in the specification's order. */
3995 /* */
3996 /*************************************************************************/
3999 static FT_Bool
4000 SkipCode( EXEC_OP )
4002 CUR.IP += CUR.length;
4004 if ( CUR.IP < CUR.codeSize )
4006 CUR.opcode = CUR.code[CUR.IP];
4008 CUR.length = opcode_length[CUR.opcode];
4009 if ( CUR.length < 0 )
4011 if ( CUR.IP + 1 > CUR.codeSize )
4012 goto Fail_Overflow;
4013 CUR.length = CUR.code[CUR.IP + 1] + 2;
4016 if ( CUR.IP + CUR.length <= CUR.codeSize )
4017 return SUCCESS;
4020 Fail_Overflow:
4021 CUR.error = TT_Err_Code_Overflow;
4022 return FAILURE;
4026 /*************************************************************************/
4027 /* */
4028 /* IF[]: IF test */
4029 /* Opcode range: 0x58 */
4030 /* Stack: StkElt --> */
4031 /* */
4032 static void
4033 Ins_IF( INS_ARG )
4035 FT_Int nIfs;
4036 FT_Bool Out;
4039 if ( args[0] != 0 )
4040 return;
4042 nIfs = 1;
4043 Out = 0;
4047 if ( SKIP_Code() == FAILURE )
4048 return;
4050 switch ( CUR.opcode )
4052 case 0x58: /* IF */
4053 nIfs++;
4054 break;
4056 case 0x1B: /* ELSE */
4057 Out = FT_BOOL( nIfs == 1 );
4058 break;
4060 case 0x59: /* EIF */
4061 nIfs--;
4062 Out = FT_BOOL( nIfs == 0 );
4063 break;
4065 } while ( Out == 0 );
4069 /*************************************************************************/
4070 /* */
4071 /* ELSE[]: ELSE */
4072 /* Opcode range: 0x1B */
4073 /* Stack: --> */
4074 /* */
4075 static void
4076 Ins_ELSE( INS_ARG )
4078 FT_Int nIfs;
4080 FT_UNUSED_ARG;
4083 nIfs = 1;
4087 if ( SKIP_Code() == FAILURE )
4088 return;
4090 switch ( CUR.opcode )
4092 case 0x58: /* IF */
4093 nIfs++;
4094 break;
4096 case 0x59: /* EIF */
4097 nIfs--;
4098 break;
4100 } while ( nIfs != 0 );
4104 /*************************************************************************/
4105 /* */
4106 /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
4107 /* */
4108 /* Instructions appear in the specification's order. */
4109 /* */
4110 /*************************************************************************/
4113 /*************************************************************************/
4114 /* */
4115 /* FDEF[]: Function DEFinition */
4116 /* Opcode range: 0x2C */
4117 /* Stack: uint32 --> */
4118 /* */
4119 static void
4120 Ins_FDEF( INS_ARG )
4122 FT_ULong n;
4123 TT_DefRecord* rec;
4124 TT_DefRecord* limit;
4127 /* some font programs are broken enough to redefine functions! */
4128 /* We will then parse the current table. */
4130 rec = CUR.FDefs;
4131 limit = rec + CUR.numFDefs;
4132 n = args[0];
4134 for ( ; rec < limit; rec++ )
4136 if ( rec->opc == n )
4137 break;
4140 if ( rec == limit )
4142 /* check that there is enough room for new functions */
4143 if ( CUR.numFDefs >= CUR.maxFDefs )
4145 CUR.error = TT_Err_Too_Many_Function_Defs;
4146 return;
4148 CUR.numFDefs++;
4151 rec->range = CUR.curRange;
4152 rec->opc = n;
4153 rec->start = CUR.IP + 1;
4154 rec->active = TRUE;
4156 if ( n > CUR.maxFunc )
4157 CUR.maxFunc = n;
4159 /* Now skip the whole function definition. */
4160 /* We don't allow nested IDEFS & FDEFs. */
4162 while ( SKIP_Code() == SUCCESS )
4164 switch ( CUR.opcode )
4166 case 0x89: /* IDEF */
4167 case 0x2C: /* FDEF */
4168 CUR.error = TT_Err_Nested_DEFS;
4169 return;
4171 case 0x2D: /* ENDF */
4172 return;
4178 /*************************************************************************/
4179 /* */
4180 /* ENDF[]: END Function definition */
4181 /* Opcode range: 0x2D */
4182 /* Stack: --> */
4183 /* */
4184 static void
4185 Ins_ENDF( INS_ARG )
4187 TT_CallRec* pRec;
4189 FT_UNUSED_ARG;
4192 if ( CUR.callTop <= 0 ) /* We encountered an ENDF without a call */
4194 CUR.error = TT_Err_ENDF_In_Exec_Stream;
4195 return;
4198 CUR.callTop--;
4200 pRec = &CUR.callStack[CUR.callTop];
4202 pRec->Cur_Count--;
4204 CUR.step_ins = FALSE;
4206 if ( pRec->Cur_Count > 0 )
4208 CUR.callTop++;
4209 CUR.IP = pRec->Cur_Restart;
4211 else
4212 /* Loop through the current function */
4213 INS_Goto_CodeRange( pRec->Caller_Range,
4214 pRec->Caller_IP );
4216 /* Exit the current call frame. */
4218 /* NOTE: If the last intruction of a program is a */
4219 /* CALL or LOOPCALL, the return address is */
4220 /* always out of the code range. This is a */
4221 /* valid address, and it is why we do not test */
4222 /* the result of Ins_Goto_CodeRange() here! */
4226 /*************************************************************************/
4227 /* */
4228 /* CALL[]: CALL function */
4229 /* Opcode range: 0x2B */
4230 /* Stack: uint32? --> */
4231 /* */
4232 static void
4233 Ins_CALL( INS_ARG )
4235 FT_ULong F;
4236 TT_CallRec* pCrec;
4237 TT_DefRecord* def;
4240 /* first of all, check the index */
4242 F = args[0];
4243 if ( BOUNDS( F, CUR.maxFunc + 1 ) )
4244 goto Fail;
4246 /* Except for some old Apple fonts, all functions in a TrueType */
4247 /* font are defined in increasing order, starting from 0. This */
4248 /* means that we normally have */
4249 /* */
4250 /* CUR.maxFunc+1 == CUR.numFDefs */
4251 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4252 /* */
4253 /* If this isn't true, we need to look up the function table. */
4255 def = CUR.FDefs + F;
4256 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
4258 /* look up the FDefs table */
4259 TT_DefRecord* limit;
4262 def = CUR.FDefs;
4263 limit = def + CUR.numFDefs;
4265 while ( def < limit && def->opc != F )
4266 def++;
4268 if ( def == limit )
4269 goto Fail;
4272 /* check that the function is active */
4273 if ( !def->active )
4274 goto Fail;
4276 /* check the call stack */
4277 if ( CUR.callTop >= CUR.callSize )
4279 CUR.error = TT_Err_Stack_Overflow;
4280 return;
4283 pCrec = CUR.callStack + CUR.callTop;
4285 pCrec->Caller_Range = CUR.curRange;
4286 pCrec->Caller_IP = CUR.IP + 1;
4287 pCrec->Cur_Count = 1;
4288 pCrec->Cur_Restart = def->start;
4290 CUR.callTop++;
4292 INS_Goto_CodeRange( def->range,
4293 def->start );
4295 CUR.step_ins = FALSE;
4296 return;
4298 Fail:
4299 CUR.error = TT_Err_Invalid_Reference;
4303 /*************************************************************************/
4304 /* */
4305 /* LOOPCALL[]: LOOP and CALL function */
4306 /* Opcode range: 0x2A */
4307 /* Stack: uint32? Eint16? --> */
4308 /* */
4309 static void
4310 Ins_LOOPCALL( INS_ARG )
4312 FT_ULong F;
4313 TT_CallRec* pCrec;
4314 TT_DefRecord* def;
4317 /* first of all, check the index */
4318 F = args[1];
4319 if ( BOUNDS( F, CUR.maxFunc + 1 ) )
4320 goto Fail;
4322 /* Except for some old Apple fonts, all functions in a TrueType */
4323 /* font are defined in increasing order, starting from 0. This */
4324 /* means that we normally have */
4325 /* */
4326 /* CUR.maxFunc+1 == CUR.numFDefs */
4327 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4328 /* */
4329 /* If this isn't true, we need to look up the function table. */
4331 def = CUR.FDefs + F;
4332 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
4334 /* look up the FDefs table */
4335 TT_DefRecord* limit;
4338 def = CUR.FDefs;
4339 limit = def + CUR.numFDefs;
4341 while ( def < limit && def->opc != F )
4342 def++;
4344 if ( def == limit )
4345 goto Fail;
4348 /* check that the function is active */
4349 if ( !def->active )
4350 goto Fail;
4352 /* check stack */
4353 if ( CUR.callTop >= CUR.callSize )
4355 CUR.error = TT_Err_Stack_Overflow;
4356 return;
4359 if ( args[0] > 0 )
4361 pCrec = CUR.callStack + CUR.callTop;
4363 pCrec->Caller_Range = CUR.curRange;
4364 pCrec->Caller_IP = CUR.IP + 1;
4365 pCrec->Cur_Count = (FT_Int)args[0];
4366 pCrec->Cur_Restart = def->start;
4368 CUR.callTop++;
4370 INS_Goto_CodeRange( def->range, def->start );
4372 CUR.step_ins = FALSE;
4374 return;
4376 Fail:
4377 CUR.error = TT_Err_Invalid_Reference;
4381 /*************************************************************************/
4382 /* */
4383 /* IDEF[]: Instruction DEFinition */
4384 /* Opcode range: 0x89 */
4385 /* Stack: Eint8 --> */
4386 /* */
4387 static void
4388 Ins_IDEF( INS_ARG )
4390 TT_DefRecord* def;
4391 TT_DefRecord* limit;
4394 /* First of all, look for the same function in our table */
4396 def = CUR.IDefs;
4397 limit = def + CUR.numIDefs;
4399 for ( ; def < limit; def++ )
4400 if ( def->opc == (FT_ULong)args[0] )
4401 break;
4403 if ( def == limit )
4405 /* check that there is enough room for a new instruction */
4406 if ( CUR.numIDefs >= CUR.maxIDefs )
4408 CUR.error = TT_Err_Too_Many_Instruction_Defs;
4409 return;
4411 CUR.numIDefs++;
4414 def->opc = args[0];
4415 def->start = CUR.IP+1;
4416 def->range = CUR.curRange;
4417 def->active = TRUE;
4419 if ( (FT_ULong)args[0] > CUR.maxIns )
4420 CUR.maxIns = args[0];
4422 /* Now skip the whole function definition. */
4423 /* We don't allow nested IDEFs & FDEFs. */
4425 while ( SKIP_Code() == SUCCESS )
4427 switch ( CUR.opcode )
4429 case 0x89: /* IDEF */
4430 case 0x2C: /* FDEF */
4431 CUR.error = TT_Err_Nested_DEFS;
4432 return;
4433 case 0x2D: /* ENDF */
4434 return;
4440 /*************************************************************************/
4441 /* */
4442 /* PUSHING DATA ONTO THE INTERPRETER STACK */
4443 /* */
4444 /* Instructions appear in the specification's order. */
4445 /* */
4446 /*************************************************************************/
4449 /*************************************************************************/
4450 /* */
4451 /* NPUSHB[]: PUSH N Bytes */
4452 /* Opcode range: 0x40 */
4453 /* Stack: --> uint32... */
4454 /* */
4455 static void
4456 Ins_NPUSHB( INS_ARG )
4458 FT_UShort L, K;
4461 L = (FT_UShort)CUR.code[CUR.IP + 1];
4463 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4465 CUR.error = TT_Err_Stack_Overflow;
4466 return;
4469 for ( K = 1; K <= L; K++ )
4470 args[K - 1] = CUR.code[CUR.IP + K + 1];
4472 CUR.new_top += L;
4476 /*************************************************************************/
4477 /* */
4478 /* NPUSHW[]: PUSH N Words */
4479 /* Opcode range: 0x41 */
4480 /* Stack: --> int32... */
4481 /* */
4482 static void
4483 Ins_NPUSHW( INS_ARG )
4485 FT_UShort L, K;
4488 L = (FT_UShort)CUR.code[CUR.IP + 1];
4490 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4492 CUR.error = TT_Err_Stack_Overflow;
4493 return;
4496 CUR.IP += 2;
4498 for ( K = 0; K < L; K++ )
4499 args[K] = GET_ShortIns();
4501 CUR.step_ins = FALSE;
4502 CUR.new_top += L;
4506 /*************************************************************************/
4507 /* */
4508 /* PUSHB[abc]: PUSH Bytes */
4509 /* Opcode range: 0xB0-0xB7 */
4510 /* Stack: --> uint32... */
4511 /* */
4512 static void
4513 Ins_PUSHB( INS_ARG )
4515 FT_UShort L, K;
4518 L = (FT_UShort)(CUR.opcode - 0xB0 + 1);
4520 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4522 CUR.error = TT_Err_Stack_Overflow;
4523 return;
4526 for ( K = 1; K <= L; K++ )
4527 args[K - 1] = CUR.code[CUR.IP + K];
4531 /*************************************************************************/
4532 /* */
4533 /* PUSHW[abc]: PUSH Words */
4534 /* Opcode range: 0xB8-0xBF */
4535 /* Stack: --> int32... */
4536 /* */
4537 static void
4538 Ins_PUSHW( INS_ARG )
4540 FT_UShort L, K;
4543 L = (FT_UShort)(CUR.opcode - 0xB8 + 1);
4545 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4547 CUR.error = TT_Err_Stack_Overflow;
4548 return;
4551 CUR.IP++;
4553 for ( K = 0; K < L; K++ )
4554 args[K] = GET_ShortIns();
4556 CUR.step_ins = FALSE;
4560 /*************************************************************************/
4561 /* */
4562 /* MANAGING THE GRAPHICS STATE */
4563 /* */
4564 /* Instructions appear in the specs' order. */
4565 /* */
4566 /*************************************************************************/
4569 /*************************************************************************/
4570 /* */
4571 /* GC[a]: Get Coordinate projected onto */
4572 /* Opcode range: 0x46-0x47 */
4573 /* Stack: uint32 --> f26.6 */
4574 /* */
4575 /* BULLSHIT: Measures from the original glyph must be taken along the */
4576 /* dual projection vector! */
4577 /* */
4578 static void
4579 Ins_GC( INS_ARG )
4581 FT_ULong L;
4582 FT_F26Dot6 R;
4585 L = (FT_ULong)args[0];
4587 if ( BOUNDS( L, CUR.zp2.n_points ) )
4589 if ( CUR.pedantic_hinting )
4591 CUR.error = TT_Err_Invalid_Reference;
4592 return;
4594 else
4595 R = 0;
4597 else
4599 if ( CUR.opcode & 1 )
4600 R = CUR_Func_dualproj( CUR.zp2.org + L, NULL_Vector );
4601 else
4602 R = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
4605 args[0] = R;
4609 /*************************************************************************/
4610 /* */
4611 /* SCFS[]: Set Coordinate From Stack */
4612 /* Opcode range: 0x48 */
4613 /* Stack: f26.6 uint32 --> */
4614 /* */
4615 /* Formula: */
4616 /* */
4617 /* OA := OA + ( value - OA.p )/( f.p ) * f */
4618 /* */
4619 static void
4620 Ins_SCFS( INS_ARG )
4622 FT_Long K;
4623 FT_UShort L;
4626 L = (FT_UShort)args[0];
4628 if ( BOUNDS( L, CUR.zp2.n_points ) )
4630 if ( CUR.pedantic_hinting )
4631 CUR.error = TT_Err_Invalid_Reference;
4632 return;
4635 K = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
4637 CUR_Func_move( &CUR.zp2, L, args[1] - K );
4639 /* not part of the specs, but here for safety */
4641 if ( CUR.GS.gep2 == 0 )
4642 CUR.zp2.org[L] = CUR.zp2.cur[L];
4646 /*************************************************************************/
4647 /* */
4648 /* MD[a]: Measure Distance */
4649 /* Opcode range: 0x49-0x4A */
4650 /* Stack: uint32 uint32 --> f26.6 */
4651 /* */
4652 /* BULLSHIT: Measure taken in the original glyph must be along the dual */
4653 /* projection vector. */
4654 /* */
4655 /* Second BULLSHIT: Flag attributes are inverted! */
4656 /* 0 => measure distance in original outline */
4657 /* 1 => measure distance in grid-fitted outline */
4658 /* */
4659 /* Third one: `zp0 - zp1', and not `zp2 - zp1! */
4660 /* */
4661 static void
4662 Ins_MD( INS_ARG )
4664 FT_UShort K, L;
4665 FT_F26Dot6 D;
4668 K = (FT_UShort)args[1];
4669 L = (FT_UShort)args[0];
4671 if( BOUNDS( L, CUR.zp0.n_points ) ||
4672 BOUNDS( K, CUR.zp1.n_points ) )
4674 if ( CUR.pedantic_hinting )
4676 CUR.error = TT_Err_Invalid_Reference;
4677 return;
4679 D = 0;
4681 else
4683 if ( CUR.opcode & 1 )
4684 D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
4685 else
4686 D = CUR_Func_dualproj( CUR.zp0.org + L, CUR.zp1.org + K );
4689 args[0] = D;
4693 /*************************************************************************/
4694 /* */
4695 /* SDPVTL[a]: Set Dual PVector to Line */
4696 /* Opcode range: 0x86-0x87 */
4697 /* Stack: uint32 uint32 --> */
4698 /* */
4699 static void
4700 Ins_SDPVTL( INS_ARG )
4702 FT_Long A, B, C;
4703 FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
4706 p1 = (FT_UShort)args[1];
4707 p2 = (FT_UShort)args[0];
4709 if ( BOUNDS( p2, CUR.zp1.n_points ) ||
4710 BOUNDS( p1, CUR.zp2.n_points ) )
4712 if ( CUR.pedantic_hinting )
4713 CUR.error = TT_Err_Invalid_Reference;
4714 return;
4718 FT_Vector* v1 = CUR.zp1.org + p2;
4719 FT_Vector* v2 = CUR.zp2.org + p1;
4722 A = v1->x - v2->x;
4723 B = v1->y - v2->y;
4726 if ( ( CUR.opcode & 1 ) != 0 )
4728 C = B; /* counter clockwise rotation */
4729 B = A;
4730 A = -C;
4733 NORMalize( A, B, &CUR.GS.dualVector );
4736 FT_Vector* v1 = CUR.zp1.cur + p2;
4737 FT_Vector* v2 = CUR.zp2.cur + p1;
4740 A = v1->x - v2->x;
4741 B = v1->y - v2->y;
4744 if ( ( CUR.opcode & 1 ) != 0 )
4746 C = B; /* counter clockwise rotation */
4747 B = A;
4748 A = -C;
4751 NORMalize( A, B, &CUR.GS.projVector );
4753 COMPUTE_Funcs();
4757 /*************************************************************************/
4758 /* */
4759 /* SZP0[]: Set Zone Pointer 0 */
4760 /* Opcode range: 0x13 */
4761 /* Stack: uint32 --> */
4762 /* */
4763 static void
4764 Ins_SZP0( INS_ARG )
4766 switch ( (FT_Int)args[0] )
4768 case 0:
4769 CUR.zp0 = CUR.twilight;
4770 break;
4772 case 1:
4773 CUR.zp0 = CUR.pts;
4774 break;
4776 default:
4777 if ( CUR.pedantic_hinting )
4778 CUR.error = TT_Err_Invalid_Reference;
4779 return;
4782 CUR.GS.gep0 = (FT_UShort)args[0];
4786 /*************************************************************************/
4787 /* */
4788 /* SZP1[]: Set Zone Pointer 1 */
4789 /* Opcode range: 0x14 */
4790 /* Stack: uint32 --> */
4791 /* */
4792 static void
4793 Ins_SZP1( INS_ARG )
4795 switch ( (FT_Int)args[0] )
4797 case 0:
4798 CUR.zp1 = CUR.twilight;
4799 break;
4801 case 1:
4802 CUR.zp1 = CUR.pts;
4803 break;
4805 default:
4806 if ( CUR.pedantic_hinting )
4807 CUR.error = TT_Err_Invalid_Reference;
4808 return;
4811 CUR.GS.gep1 = (FT_UShort)args[0];
4815 /*************************************************************************/
4816 /* */
4817 /* SZP2[]: Set Zone Pointer 2 */
4818 /* Opcode range: 0x15 */
4819 /* Stack: uint32 --> */
4820 /* */
4821 static void
4822 Ins_SZP2( INS_ARG )
4824 switch ( (FT_Int)args[0] )
4826 case 0:
4827 CUR.zp2 = CUR.twilight;
4828 break;
4830 case 1:
4831 CUR.zp2 = CUR.pts;
4832 break;
4834 default:
4835 if ( CUR.pedantic_hinting )
4836 CUR.error = TT_Err_Invalid_Reference;
4837 return;
4840 CUR.GS.gep2 = (FT_UShort)args[0];
4844 /*************************************************************************/
4845 /* */
4846 /* SZPS[]: Set Zone PointerS */
4847 /* Opcode range: 0x16 */
4848 /* Stack: uint32 --> */
4849 /* */
4850 static void
4851 Ins_SZPS( INS_ARG )
4853 switch ( (FT_Int)args[0] )
4855 case 0:
4856 CUR.zp0 = CUR.twilight;
4857 break;
4859 case 1:
4860 CUR.zp0 = CUR.pts;
4861 break;
4863 default:
4864 if ( CUR.pedantic_hinting )
4865 CUR.error = TT_Err_Invalid_Reference;
4866 return;
4869 CUR.zp1 = CUR.zp0;
4870 CUR.zp2 = CUR.zp0;
4872 CUR.GS.gep0 = (FT_UShort)args[0];
4873 CUR.GS.gep1 = (FT_UShort)args[0];
4874 CUR.GS.gep2 = (FT_UShort)args[0];
4878 /*************************************************************************/
4879 /* */
4880 /* INSTCTRL[]: INSTruction ConTRoL */
4881 /* Opcode range: 0x8e */
4882 /* Stack: int32 int32 --> */
4883 /* */
4884 static void
4885 Ins_INSTCTRL( INS_ARG )
4887 FT_Long K, L;
4890 K = args[1];
4891 L = args[0];
4893 if ( K < 1 || K > 2 )
4895 if ( CUR.pedantic_hinting )
4896 CUR.error = TT_Err_Invalid_Reference;
4897 return;
4900 if ( L != 0 )
4901 L = K;
4903 CUR.GS.instruct_control = FT_BOOL(
4904 ( (FT_Byte)CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L );
4908 /*************************************************************************/
4909 /* */
4910 /* SCANCTRL[]: SCAN ConTRoL */
4911 /* Opcode range: 0x85 */
4912 /* Stack: uint32? --> */
4913 /* */
4914 static void
4915 Ins_SCANCTRL( INS_ARG )
4917 FT_Int A;
4920 /* Get Threshold */
4921 A = (FT_Int)( args[0] & 0xFF );
4923 if ( A == 0xFF )
4925 CUR.GS.scan_control = TRUE;
4926 return;
4928 else if ( A == 0 )
4930 CUR.GS.scan_control = FALSE;
4931 return;
4934 A *= 64;
4936 #if 0
4937 if ( (args[0] & 0x100) != 0 && CUR.metrics.pointSize <= A )
4938 CUR.GS.scan_control = TRUE;
4939 #endif
4941 if ( (args[0] & 0x200) != 0 && CUR.tt_metrics.rotated )
4942 CUR.GS.scan_control = TRUE;
4944 if ( (args[0] & 0x400) != 0 && CUR.tt_metrics.stretched )
4945 CUR.GS.scan_control = TRUE;
4947 #if 0
4948 if ( (args[0] & 0x800) != 0 && CUR.metrics.pointSize > A )
4949 CUR.GS.scan_control = FALSE;
4950 #endif
4952 if ( (args[0] & 0x1000) != 0 && CUR.tt_metrics.rotated )
4953 CUR.GS.scan_control = FALSE;
4955 if ( (args[0] & 0x2000) != 0 && CUR.tt_metrics.stretched )
4956 CUR.GS.scan_control = FALSE;
4960 /*************************************************************************/
4961 /* */
4962 /* SCANTYPE[]: SCAN TYPE */
4963 /* Opcode range: 0x8D */
4964 /* Stack: uint32? --> */
4965 /* */
4966 static void
4967 Ins_SCANTYPE( INS_ARG )
4969 /* for compatibility with future enhancements, */
4970 /* we must ignore new modes */
4972 if ( args[0] >= 0 && args[0] <= 5 )
4974 if ( args[0] == 3 )
4975 args[0] = 2;
4977 CUR.GS.scan_type = (FT_Int)args[0];
4982 /*************************************************************************/
4983 /* */
4984 /* MANAGING OUTLINES */
4985 /* */
4986 /* Instructions appear in the specification's order. */
4987 /* */
4988 /*************************************************************************/
4991 /*************************************************************************/
4992 /* */
4993 /* FLIPPT[]: FLIP PoinT */
4994 /* Opcode range: 0x80 */
4995 /* Stack: uint32... --> */
4996 /* */
4997 static void
4998 Ins_FLIPPT( INS_ARG )
5000 FT_UShort point;
5002 FT_UNUSED_ARG;
5005 if ( CUR.top < CUR.GS.loop )
5007 CUR.error = TT_Err_Too_Few_Arguments;
5008 return;
5011 while ( CUR.GS.loop > 0 )
5013 CUR.args--;
5015 point = (FT_UShort)CUR.stack[CUR.args];
5017 if ( BOUNDS( point, CUR.pts.n_points ) )
5019 if ( CUR.pedantic_hinting )
5021 CUR.error = TT_Err_Invalid_Reference;
5022 return;
5025 else
5026 CUR.pts.tags[point] ^= FT_Curve_Tag_On;
5028 CUR.GS.loop--;
5031 CUR.GS.loop = 1;
5032 CUR.new_top = CUR.args;
5036 /*************************************************************************/
5037 /* */
5038 /* FLIPRGON[]: FLIP RanGe ON */
5039 /* Opcode range: 0x81 */
5040 /* Stack: uint32 uint32 --> */
5041 /* */
5042 static void
5043 Ins_FLIPRGON( INS_ARG )
5045 FT_UShort I, K, L;
5048 K = (FT_UShort)args[1];
5049 L = (FT_UShort)args[0];
5051 if ( BOUNDS( K, CUR.pts.n_points ) ||
5052 BOUNDS( L, CUR.pts.n_points ) )
5054 if ( CUR.pedantic_hinting )
5055 CUR.error = TT_Err_Invalid_Reference;
5056 return;
5059 for ( I = L; I <= K; I++ )
5060 CUR.pts.tags[I] |= FT_Curve_Tag_On;
5064 /*************************************************************************/
5065 /* */
5066 /* FLIPRGOFF: FLIP RanGe OFF */
5067 /* Opcode range: 0x82 */
5068 /* Stack: uint32 uint32 --> */
5069 /* */
5070 static void
5071 Ins_FLIPRGOFF( INS_ARG )
5073 FT_UShort I, K, L;
5076 K = (FT_UShort)args[1];
5077 L = (FT_UShort)args[0];
5079 if ( BOUNDS( K, CUR.pts.n_points ) ||
5080 BOUNDS( L, CUR.pts.n_points ) )
5082 if ( CUR.pedantic_hinting )
5083 CUR.error = TT_Err_Invalid_Reference;
5084 return;
5087 for ( I = L; I <= K; I++ )
5088 CUR.pts.tags[I] &= ~FT_Curve_Tag_On;
5092 static FT_Bool
5093 Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6* x,
5094 FT_F26Dot6* y,
5095 TT_GlyphZone zone,
5096 FT_UShort* refp )
5098 TT_GlyphZoneRec zp;
5099 FT_UShort p;
5100 FT_F26Dot6 d;
5103 if ( CUR.opcode & 1 )
5105 zp = CUR.zp0;
5106 p = CUR.GS.rp1;
5108 else
5110 zp = CUR.zp1;
5111 p = CUR.GS.rp2;
5114 if ( BOUNDS( p, zp.n_points ) )
5116 if ( CUR.pedantic_hinting )
5117 CUR.error = TT_Err_Invalid_Reference;
5118 return FAILURE;
5121 *zone = zp;
5122 *refp = p;
5124 d = CUR_Func_project( zp.cur + p, zp.org + p );
5126 #ifdef NO_APPLE_PATENT
5128 *x = TT_MulFix14( d, CUR.GS.freeVector.x );
5129 *y = TT_MulFix14( d, CUR.GS.freeVector.y );
5131 #else
5133 *x = TT_MULDIV( d,
5134 (FT_Long)CUR.GS.freeVector.x * 0x10000L,
5135 CUR.F_dot_P );
5136 *y = TT_MULDIV( d,
5137 (FT_Long)CUR.GS.freeVector.y * 0x10000L,
5138 CUR.F_dot_P );
5140 #endif /* NO_APPLE_PATENT */
5142 return SUCCESS;
5146 static void
5147 Move_Zp2_Point( EXEC_OP_ FT_UShort point,
5148 FT_F26Dot6 dx,
5149 FT_F26Dot6 dy,
5150 FT_Bool touch )
5152 if ( CUR.GS.freeVector.x != 0 )
5154 CUR.zp2.cur[point].x += dx;
5155 if ( touch )
5156 CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_X;
5159 if ( CUR.GS.freeVector.y != 0 )
5161 CUR.zp2.cur[point].y += dy;
5162 if ( touch )
5163 CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_Y;
5168 /*************************************************************************/
5169 /* */
5170 /* SHP[a]: SHift Point by the last point */
5171 /* Opcode range: 0x32-0x33 */
5172 /* Stack: uint32... --> */
5173 /* */
5174 static void
5175 Ins_SHP( INS_ARG )
5177 TT_GlyphZoneRec zp;
5178 FT_UShort refp;
5180 FT_F26Dot6 dx,
5182 FT_UShort point;
5184 FT_UNUSED_ARG;
5187 if ( CUR.top < CUR.GS.loop )
5189 CUR.error = TT_Err_Invalid_Reference;
5190 return;
5193 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5194 return;
5196 while ( CUR.GS.loop > 0 )
5198 CUR.args--;
5199 point = (FT_UShort)CUR.stack[CUR.args];
5201 if ( BOUNDS( point, CUR.zp2.n_points ) )
5203 if ( CUR.pedantic_hinting )
5205 CUR.error = TT_Err_Invalid_Reference;
5206 return;
5209 else
5210 /* XXX: UNDOCUMENTED! SHP touches the points */
5211 MOVE_Zp2_Point( point, dx, dy, TRUE );
5213 CUR.GS.loop--;
5216 CUR.GS.loop = 1;
5217 CUR.new_top = CUR.args;
5221 /*************************************************************************/
5222 /* */
5223 /* SHC[a]: SHift Contour */
5224 /* Opcode range: 0x34-35 */
5225 /* Stack: uint32 --> */
5226 /* */
5227 static void
5228 Ins_SHC( INS_ARG )
5230 TT_GlyphZoneRec zp;
5231 FT_UShort refp;
5232 FT_F26Dot6 dx,
5235 FT_Short contour;
5236 FT_UShort first_point, last_point, i;
5239 contour = (FT_UShort)args[0];
5241 if ( BOUNDS( contour, CUR.pts.n_contours ) )
5243 if ( CUR.pedantic_hinting )
5244 CUR.error = TT_Err_Invalid_Reference;
5245 return;
5248 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5249 return;
5251 if ( contour == 0 )
5252 first_point = 0;
5253 else
5254 first_point = (FT_UShort)(CUR.pts.contours[contour - 1] + 1);
5256 last_point = CUR.pts.contours[contour];
5258 /* XXX: this is probably wrong... at least it prevents memory */
5259 /* corruption when zp2 is the twilight zone */
5260 if ( last_point > CUR.zp2.n_points )
5262 if ( CUR.zp2.n_points > 0 )
5263 last_point = (FT_UShort)(CUR.zp2.n_points - 1);
5264 else
5265 last_point = 0;
5268 /* XXX: UNDOCUMENTED! SHC doesn't touch the points */
5269 for ( i = first_point; i <= last_point; i++ )
5271 if ( zp.cur != CUR.zp2.cur || refp != i )
5272 MOVE_Zp2_Point( i, dx, dy, FALSE );
5277 /*************************************************************************/
5278 /* */
5279 /* SHZ[a]: SHift Zone */
5280 /* Opcode range: 0x36-37 */
5281 /* Stack: uint32 --> */
5282 /* */
5283 static void
5284 Ins_SHZ( INS_ARG )
5286 TT_GlyphZoneRec zp;
5287 FT_UShort refp;
5288 FT_F26Dot6 dx,
5291 FT_UShort last_point, i;
5294 if ( BOUNDS( args[0], 2 ) )
5296 if ( CUR.pedantic_hinting )
5297 CUR.error = TT_Err_Invalid_Reference;
5298 return;
5301 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5302 return;
5304 if ( CUR.zp2.n_points > 0 )
5305 last_point = (FT_UShort)(CUR.zp2.n_points - 1);
5306 else
5307 last_point = 0;
5309 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
5310 for ( i = 0; i <= last_point; i++ )
5312 if ( zp.cur != CUR.zp2.cur || refp != i )
5313 MOVE_Zp2_Point( i, dx, dy, FALSE );
5318 /*************************************************************************/
5319 /* */
5320 /* SHPIX[]: SHift points by a PIXel amount */
5321 /* Opcode range: 0x38 */
5322 /* Stack: f26.6 uint32... --> */
5323 /* */
5324 static void
5325 Ins_SHPIX( INS_ARG )
5327 FT_F26Dot6 dx, dy;
5328 FT_UShort point;
5331 if ( CUR.top < CUR.GS.loop + 1 )
5333 CUR.error = TT_Err_Invalid_Reference;
5334 return;
5337 dx = TT_MulFix14( args[0], CUR.GS.freeVector.x );
5338 dy = TT_MulFix14( args[0], CUR.GS.freeVector.y );
5340 while ( CUR.GS.loop > 0 )
5342 CUR.args--;
5344 point = (FT_UShort)CUR.stack[CUR.args];
5346 if ( BOUNDS( point, CUR.zp2.n_points ) )
5348 if ( CUR.pedantic_hinting )
5350 CUR.error = TT_Err_Invalid_Reference;
5351 return;
5354 else
5355 MOVE_Zp2_Point( point, dx, dy, TRUE );
5357 CUR.GS.loop--;
5360 CUR.GS.loop = 1;
5361 CUR.new_top = CUR.args;
5365 /*************************************************************************/
5366 /* */
5367 /* MSIRP[a]: Move Stack Indirect Relative Position */
5368 /* Opcode range: 0x3A-0x3B */
5369 /* Stack: f26.6 uint32 --> */
5370 /* */
5371 static void
5372 Ins_MSIRP( INS_ARG )
5374 FT_UShort point;
5375 FT_F26Dot6 distance;
5378 point = (FT_UShort)args[0];
5380 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5381 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5383 if ( CUR.pedantic_hinting )
5384 CUR.error = TT_Err_Invalid_Reference;
5385 return;
5388 /* XXX: UNDOCUMENTED! behaviour */
5389 if ( CUR.GS.gep0 == 0 ) /* if in twilight zone */
5391 CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
5392 CUR.zp1.cur[point] = CUR.zp1.org[point];
5395 distance = CUR_Func_project( CUR.zp1.cur + point,
5396 CUR.zp0.cur + CUR.GS.rp0 );
5398 CUR_Func_move( &CUR.zp1, point, args[1] - distance );
5400 CUR.GS.rp1 = CUR.GS.rp0;
5401 CUR.GS.rp2 = point;
5403 if ( (CUR.opcode & 1) != 0 )
5404 CUR.GS.rp0 = point;
5408 /*************************************************************************/
5409 /* */
5410 /* MDAP[a]: Move Direct Absolute Point */
5411 /* Opcode range: 0x2E-0x2F */
5412 /* Stack: uint32 --> */
5413 /* */
5414 static void
5415 Ins_MDAP( INS_ARG )
5417 FT_UShort point;
5418 FT_F26Dot6 cur_dist,
5419 distance;
5422 point = (FT_UShort)args[0];
5424 if ( BOUNDS( point, CUR.zp0.n_points ) )
5426 if ( CUR.pedantic_hinting )
5427 CUR.error = TT_Err_Invalid_Reference;
5428 return;
5431 /* XXX: Is there some undocumented feature while in the */
5432 /* twilight zone? ? */
5433 if ( ( CUR.opcode & 1 ) != 0 )
5435 cur_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
5436 distance = CUR_Func_round( cur_dist,
5437 CUR.tt_metrics.compensations[0] ) - cur_dist;
5439 else
5440 distance = 0;
5442 CUR_Func_move( &CUR.zp0, point, distance );
5444 CUR.GS.rp0 = point;
5445 CUR.GS.rp1 = point;
5449 /*************************************************************************/
5450 /* */
5451 /* MIAP[a]: Move Indirect Absolute Point */
5452 /* Opcode range: 0x3E-0x3F */
5453 /* Stack: uint32 uint32 --> */
5454 /* */
5455 static void
5456 Ins_MIAP( INS_ARG )
5458 FT_ULong cvtEntry;
5459 FT_UShort point;
5460 FT_F26Dot6 distance,
5461 org_dist;
5464 cvtEntry = (FT_ULong)args[1];
5465 point = (FT_UShort)args[0];
5467 if ( BOUNDS( point, CUR.zp0.n_points ) ||
5468 BOUNDS( cvtEntry, CUR.cvtSize ) )
5470 if ( CUR.pedantic_hinting )
5471 CUR.error = TT_Err_Invalid_Reference;
5472 return;
5475 /* UNDOCUMENTED! */
5476 /* */
5477 /* The behaviour of an MIAP instruction is quite */
5478 /* different when used in the twilight zone. */
5479 /* */
5480 /* First, no control value cutin test is performed */
5481 /* as it would fail anyway. Second, the original */
5482 /* point, i.e. (org_x,org_y) of zp0.point, is set */
5483 /* to the absolute, unrounded distance found in */
5484 /* the CVT. */
5485 /* */
5486 /* This is used in the CVT programs of the Microsoft */
5487 /* fonts Arial, Times, etc., in order to re-adjust */
5488 /* some key font heights. It allows the use of the */
5489 /* IP instruction in the twilight zone, which */
5490 /* otherwise would be `illegal' according to the */
5491 /* specification. */
5492 /* */
5493 /* We implement it with a special sequence for the */
5494 /* twilight zone. This is a bad hack, but it seems */
5495 /* to work. */
5497 distance = CUR_Func_read_cvt( cvtEntry );
5499 if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */
5501 CUR.zp0.org[point].x = TT_MulFix14( distance, CUR.GS.freeVector.x );
5502 CUR.zp0.org[point].y = TT_MulFix14( distance, CUR.GS.freeVector.y ),
5503 CUR.zp0.cur[point] = CUR.zp0.org[point];
5506 org_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
5508 if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */
5510 if ( ABS( distance - org_dist ) > CUR.GS.control_value_cutin )
5511 distance = org_dist;
5513 distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] );
5516 CUR_Func_move( &CUR.zp0, point, distance - org_dist );
5518 CUR.GS.rp0 = point;
5519 CUR.GS.rp1 = point;
5523 /*************************************************************************/
5524 /* */
5525 /* MDRP[abcde]: Move Direct Relative Point */
5526 /* Opcode range: 0xC0-0xDF */
5527 /* Stack: uint32 --> */
5528 /* */
5529 static void
5530 Ins_MDRP( INS_ARG )
5532 FT_UShort point;
5533 FT_F26Dot6 org_dist, distance;
5536 point = (FT_UShort)args[0];
5538 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5539 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5541 if ( CUR.pedantic_hinting )
5542 CUR.error = TT_Err_Invalid_Reference;
5543 return;
5546 /* XXX: Is there some undocumented feature while in the */
5547 /* twilight zone? */
5549 org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
5550 CUR.zp0.org + CUR.GS.rp0 );
5552 /* single width cutin test */
5554 if ( ABS( org_dist ) < CUR.GS.single_width_cutin )
5556 if ( org_dist >= 0 )
5557 org_dist = CUR.GS.single_width_value;
5558 else
5559 org_dist = -CUR.GS.single_width_value;
5562 /* round flag */
5564 if ( ( CUR.opcode & 4 ) != 0 )
5565 distance = CUR_Func_round(
5566 org_dist,
5567 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5568 else
5569 distance = ROUND_None(
5570 org_dist,
5571 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5573 /* minimum distance flag */
5575 if ( ( CUR.opcode & 8 ) != 0 )
5577 if ( org_dist >= 0 )
5579 if ( distance < CUR.GS.minimum_distance )
5580 distance = CUR.GS.minimum_distance;
5582 else
5584 if ( distance > -CUR.GS.minimum_distance )
5585 distance = -CUR.GS.minimum_distance;
5589 /* now move the point */
5591 org_dist = CUR_Func_project( CUR.zp1.cur + point,
5592 CUR.zp0.cur + CUR.GS.rp0 );
5594 CUR_Func_move( &CUR.zp1, point, distance - org_dist );
5596 CUR.GS.rp1 = CUR.GS.rp0;
5597 CUR.GS.rp2 = point;
5599 if ( ( CUR.opcode & 16 ) != 0 )
5600 CUR.GS.rp0 = point;
5604 /*************************************************************************/
5605 /* */
5606 /* MIRP[abcde]: Move Indirect Relative Point */
5607 /* Opcode range: 0xE0-0xFF */
5608 /* Stack: int32? uint32 --> */
5609 /* */
5610 static void
5611 Ins_MIRP( INS_ARG )
5613 FT_UShort point;
5614 FT_ULong cvtEntry;
5616 FT_F26Dot6 cvt_dist,
5617 distance,
5618 cur_dist,
5619 org_dist;
5622 point = (FT_UShort)args[0];
5623 cvtEntry = (FT_ULong)( args[1] + 1 );
5625 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
5627 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5628 BOUNDS( cvtEntry, CUR.cvtSize + 1 ) ||
5629 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5631 if ( CUR.pedantic_hinting )
5632 CUR.error = TT_Err_Invalid_Reference;
5633 return;
5636 if ( !cvtEntry )
5637 cvt_dist = 0;
5638 else
5639 cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
5641 /* single width test */
5643 if ( ABS( cvt_dist ) < CUR.GS.single_width_cutin )
5645 if ( cvt_dist >= 0 )
5646 cvt_dist = CUR.GS.single_width_value;
5647 else
5648 cvt_dist = -CUR.GS.single_width_value;
5651 /* XXX: UNDOCUMENTED! -- twilight zone */
5653 if ( CUR.GS.gep1 == 0 )
5655 CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +
5656 TT_MulFix14( cvt_dist, CUR.GS.freeVector.x );
5658 CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
5659 TT_MulFix14( cvt_dist, CUR.GS.freeVector.y );
5661 CUR.zp1.cur[point] = CUR.zp1.org[point];
5664 org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
5665 CUR.zp0.org + CUR.GS.rp0 );
5667 cur_dist = CUR_Func_project( CUR.zp1.cur + point,
5668 CUR.zp0.cur + CUR.GS.rp0 );
5670 /* auto-flip test */
5672 if ( CUR.GS.auto_flip )
5674 if ( ( org_dist ^ cvt_dist ) < 0 )
5675 cvt_dist = -cvt_dist;
5678 /* control value cutin and round */
5680 if ( ( CUR.opcode & 4 ) != 0 )
5682 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
5683 /* refer to the same zone. */
5685 if ( CUR.GS.gep0 == CUR.GS.gep1 )
5686 if ( ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin )
5687 cvt_dist = org_dist;
5689 distance = CUR_Func_round(
5690 cvt_dist,
5691 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5693 else
5694 distance = ROUND_None(
5695 cvt_dist,
5696 CUR.tt_metrics.compensations[CUR.opcode & 3] );
5698 /* minimum distance test */
5700 if ( ( CUR.opcode & 8 ) != 0 )
5702 if ( org_dist >= 0 )
5704 if ( distance < CUR.GS.minimum_distance )
5705 distance = CUR.GS.minimum_distance;
5707 else
5709 if ( distance > -CUR.GS.minimum_distance )
5710 distance = -CUR.GS.minimum_distance;
5714 CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
5716 CUR.GS.rp1 = CUR.GS.rp0;
5718 if ( ( CUR.opcode & 16 ) != 0 )
5719 CUR.GS.rp0 = point;
5721 /* XXX: UNDOCUMENTED! */
5723 CUR.GS.rp2 = point;
5727 /*************************************************************************/
5728 /* */
5729 /* ALIGNRP[]: ALIGN Relative Point */
5730 /* Opcode range: 0x3C */
5731 /* Stack: uint32 uint32... --> */
5732 /* */
5733 static void
5734 Ins_ALIGNRP( INS_ARG )
5736 FT_UShort point;
5737 FT_F26Dot6 distance;
5739 FT_UNUSED_ARG;
5742 if ( CUR.top < CUR.GS.loop ||
5743 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5745 if ( CUR.pedantic_hinting )
5746 CUR.error = TT_Err_Invalid_Reference;
5747 return;
5750 while ( CUR.GS.loop > 0 )
5752 CUR.args--;
5754 point = (FT_UShort)CUR.stack[CUR.args];
5756 if ( BOUNDS( point, CUR.zp1.n_points ) )
5758 if ( CUR.pedantic_hinting )
5760 CUR.error = TT_Err_Invalid_Reference;
5761 return;
5764 else
5766 distance = CUR_Func_project( CUR.zp1.cur + point,
5767 CUR.zp0.cur + CUR.GS.rp0 );
5769 CUR_Func_move( &CUR.zp1, point, -distance );
5772 CUR.GS.loop--;
5775 CUR.GS.loop = 1;
5776 CUR.new_top = CUR.args;
5780 /*************************************************************************/
5781 /* */
5782 /* ISECT[]: moves point to InterSECTion */
5783 /* Opcode range: 0x0F */
5784 /* Stack: 5 * uint32 --> */
5785 /* */
5786 static void
5787 Ins_ISECT( INS_ARG )
5789 FT_UShort point,
5790 a0, a1,
5791 b0, b1;
5793 FT_F26Dot6 discriminant;
5795 FT_F26Dot6 dx, dy,
5796 dax, day,
5797 dbx, dby;
5799 FT_F26Dot6 val;
5801 FT_Vector R;
5804 point = (FT_UShort)args[0];
5806 a0 = (FT_UShort)args[1];
5807 a1 = (FT_UShort)args[2];
5808 b0 = (FT_UShort)args[3];
5809 b1 = (FT_UShort)args[4];
5811 if ( BOUNDS( b0, CUR.zp0.n_points ) ||
5812 BOUNDS( b1, CUR.zp0.n_points ) ||
5813 BOUNDS( a0, CUR.zp1.n_points ) ||
5814 BOUNDS( a1, CUR.zp1.n_points ) ||
5815 BOUNDS( point, CUR.zp2.n_points ) )
5817 if ( CUR.pedantic_hinting )
5818 CUR.error = TT_Err_Invalid_Reference;
5819 return;
5822 dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
5823 dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
5825 dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;
5826 day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;
5828 dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;
5829 dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;
5831 CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_Both;
5833 discriminant = TT_MULDIV( dax, -dby, 0x40 ) +
5834 TT_MULDIV( day, dbx, 0x40 );
5836 if ( ABS( discriminant ) >= 0x40 )
5838 val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 );
5840 R.x = TT_MULDIV( val, dax, discriminant );
5841 R.y = TT_MULDIV( val, day, discriminant );
5843 CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
5844 CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
5846 else
5848 /* else, take the middle of the middles of A and B */
5850 CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +
5851 CUR.zp1.cur[a1].x +
5852 CUR.zp0.cur[b0].x +
5853 CUR.zp0.cur[b1].x ) / 4;
5854 CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +
5855 CUR.zp1.cur[a1].y +
5856 CUR.zp0.cur[b0].y +
5857 CUR.zp0.cur[b1].y ) / 4;
5862 /*************************************************************************/
5863 /* */
5864 /* ALIGNPTS[]: ALIGN PoinTS */
5865 /* Opcode range: 0x27 */
5866 /* Stack: uint32 uint32 --> */
5867 /* */
5868 static void
5869 Ins_ALIGNPTS( INS_ARG )
5871 FT_UShort p1, p2;
5872 FT_F26Dot6 distance;
5875 p1 = (FT_UShort)args[0];
5876 p2 = (FT_UShort)args[1];
5878 if ( BOUNDS( args[0], CUR.zp1.n_points ) ||
5879 BOUNDS( args[1], CUR.zp0.n_points ) )
5881 if ( CUR.pedantic_hinting )
5882 CUR.error = TT_Err_Invalid_Reference;
5883 return;
5886 distance = CUR_Func_project( CUR.zp0.cur + p2,
5887 CUR.zp1.cur + p1 ) / 2;
5889 CUR_Func_move( &CUR.zp1, p1, distance );
5890 CUR_Func_move( &CUR.zp0, p2, -distance );
5894 /*************************************************************************/
5895 /* */
5896 /* IP[]: Interpolate Point */
5897 /* Opcode range: 0x39 */
5898 /* Stack: uint32... --> */
5899 /* */
5900 static void
5901 Ins_IP( INS_ARG )
5903 FT_F26Dot6 org_a, org_b, org_x,
5904 cur_a, cur_b, cur_x,
5905 distance;
5906 FT_UShort point;
5908 FT_UNUSED_ARG;
5911 if ( CUR.top < CUR.GS.loop )
5913 CUR.error = TT_Err_Invalid_Reference;
5914 return;
5917 /* XXX: There are some glyphs in some braindead but popular */
5918 /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
5919 /* calling IP[] with bad values of rp[12]. */
5920 /* Do something sane when this odd thing happens. */
5922 if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
5923 BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
5925 org_a = cur_a = 0;
5926 org_b = cur_b = 0;
5928 else
5930 org_a = CUR_Func_dualproj( CUR.zp0.org + CUR.GS.rp1, NULL_Vector );
5931 org_b = CUR_Func_dualproj( CUR.zp1.org + CUR.GS.rp2, NULL_Vector );
5933 cur_a = CUR_Func_project( CUR.zp0.cur + CUR.GS.rp1, NULL_Vector );
5934 cur_b = CUR_Func_project( CUR.zp1.cur + CUR.GS.rp2, NULL_Vector );
5937 while ( CUR.GS.loop > 0 )
5939 CUR.args--;
5941 point = (FT_UShort)CUR.stack[CUR.args];
5942 if ( BOUNDS( point, CUR.zp2.n_points ) )
5944 if ( CUR.pedantic_hinting )
5946 CUR.error = TT_Err_Invalid_Reference;
5947 return;
5950 else
5952 org_x = CUR_Func_dualproj( CUR.zp2.org + point, NULL_Vector );
5953 cur_x = CUR_Func_project ( CUR.zp2.cur + point, NULL_Vector );
5955 if ( ( org_a <= org_b && org_x <= org_a ) ||
5956 ( org_a > org_b && org_x >= org_a ) )
5958 distance = ( cur_a - org_a ) + ( org_x - cur_x );
5960 else if ( ( org_a <= org_b && org_x >= org_b ) ||
5961 ( org_a > org_b && org_x < org_b ) )
5963 distance = ( cur_b - org_b ) + ( org_x - cur_x );
5965 else
5966 /* note: it seems that rounding this value isn't a good */
5967 /* idea (cf. width of capital `S' in Times) */
5969 distance = TT_MULDIV( cur_b - cur_a,
5970 org_x - org_a,
5971 org_b - org_a ) + ( cur_a - cur_x );
5973 CUR_Func_move( &CUR.zp2, point, distance );
5976 CUR.GS.loop--;
5979 CUR.GS.loop = 1;
5980 CUR.new_top = CUR.args;
5984 /*************************************************************************/
5985 /* */
5986 /* UTP[a]: UnTouch Point */
5987 /* Opcode range: 0x29 */
5988 /* Stack: uint32 --> */
5989 /* */
5990 static void
5991 Ins_UTP( INS_ARG )
5993 FT_UShort point;
5994 FT_Byte mask;
5997 point = (FT_UShort)args[0];
5999 if ( BOUNDS( point, CUR.zp0.n_points ) )
6001 if ( CUR.pedantic_hinting )
6002 CUR.error = TT_Err_Invalid_Reference;
6003 return;
6006 mask = 0xFF;
6008 if ( CUR.GS.freeVector.x != 0 )
6009 mask &= ~FT_Curve_Tag_Touch_X;
6011 if ( CUR.GS.freeVector.y != 0 )
6012 mask &= ~FT_Curve_Tag_Touch_Y;
6014 CUR.zp0.tags[point] &= mask;
6018 /* Local variables for Ins_IUP: */
6019 struct LOC_Ins_IUP
6021 FT_Vector* orgs; /* original and current coordinate */
6022 FT_Vector* curs; /* arrays */
6026 static void
6027 Shift( FT_UInt p1,
6028 FT_UInt p2,
6029 FT_UInt p,
6030 struct LOC_Ins_IUP* LINK )
6032 FT_UInt i;
6033 FT_F26Dot6 x;
6036 x = LINK->curs[p].x - LINK->orgs[p].x;
6038 for ( i = p1; i < p; i++ )
6039 LINK->curs[i].x += x;
6041 for ( i = p + 1; i <= p2; i++ )
6042 LINK->curs[i].x += x;
6046 static void
6047 Interp( FT_UInt p1,
6048 FT_UInt p2,
6049 FT_UInt ref1,
6050 FT_UInt ref2,
6051 struct LOC_Ins_IUP* LINK )
6053 FT_UInt i;
6054 FT_F26Dot6 x, x1, x2, d1, d2;
6057 if ( p1 > p2 )
6058 return;
6060 x1 = LINK->orgs[ref1].x;
6061 d1 = LINK->curs[ref1].x - LINK->orgs[ref1].x;
6062 x2 = LINK->orgs[ref2].x;
6063 d2 = LINK->curs[ref2].x - LINK->orgs[ref2].x;
6065 if ( x1 == x2 )
6067 for ( i = p1; i <= p2; i++ )
6069 x = LINK->orgs[i].x;
6071 if ( x <= x1 )
6072 x += d1;
6073 else
6074 x += d2;
6076 LINK->curs[i].x = x;
6078 return;
6081 if ( x1 < x2 )
6083 for ( i = p1; i <= p2; i++ )
6085 x = LINK->orgs[i].x;
6087 if ( x <= x1 )
6088 x += d1;
6089 else
6091 if ( x >= x2 )
6092 x += d2;
6093 else
6094 x = LINK->curs[ref1].x +
6095 TT_MULDIV( x - x1,
6096 LINK->curs[ref2].x - LINK->curs[ref1].x,
6097 x2 - x1 );
6099 LINK->curs[i].x = x;
6101 return;
6104 /* x2 < x1 */
6106 for ( i = p1; i <= p2; i++ )
6108 x = LINK->orgs[i].x;
6109 if ( x <= x2 )
6110 x += d2;
6111 else
6113 if ( x >= x1 )
6114 x += d1;
6115 else
6116 x = LINK->curs[ref1].x +
6117 TT_MULDIV( x - x1,
6118 LINK->curs[ref2].x - LINK->curs[ref1].x,
6119 x2 - x1 );
6121 LINK->curs[i].x = x;
6126 /*************************************************************************/
6127 /* */
6128 /* IUP[a]: Interpolate Untouched Points */
6129 /* Opcode range: 0x30-0x31 */
6130 /* Stack: --> */
6131 /* */
6132 static void
6133 Ins_IUP( INS_ARG )
6135 struct LOC_Ins_IUP V;
6136 FT_Byte mask;
6138 FT_UInt first_point; /* first point of contour */
6139 FT_UInt end_point; /* end point (last+1) of contour */
6141 FT_UInt first_touched; /* first touched point in contour */
6142 FT_UInt cur_touched; /* current touched point in contour */
6144 FT_UInt point; /* current point */
6145 FT_Short contour; /* current contour */
6147 FT_UNUSED_ARG;
6150 if ( CUR.opcode & 1 )
6152 mask = FT_Curve_Tag_Touch_X;
6153 V.orgs = CUR.pts.org;
6154 V.curs = CUR.pts.cur;
6156 else
6158 mask = FT_Curve_Tag_Touch_Y;
6159 V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
6160 V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
6163 contour = 0;
6164 point = 0;
6168 end_point = CUR.pts.contours[contour];
6169 first_point = point;
6171 while ( point <= end_point && (CUR.pts.tags[point] & mask) == 0 )
6172 point++;
6174 if ( point <= end_point )
6176 first_touched = point;
6177 cur_touched = point;
6179 point++;
6181 while ( point <= end_point )
6183 if ( ( CUR.pts.tags[point] & mask ) != 0 )
6185 if ( point > 0 )
6186 Interp( cur_touched + 1,
6187 point - 1,
6188 cur_touched,
6189 point,
6190 &V );
6191 cur_touched = point;
6194 point++;
6197 if ( cur_touched == first_touched )
6198 Shift( first_point, end_point, cur_touched, &V );
6199 else
6201 Interp( (FT_UShort)( cur_touched + 1 ),
6202 end_point,
6203 cur_touched,
6204 first_touched,
6205 &V );
6207 if ( first_touched > 0 )
6208 Interp( first_point,
6209 first_touched - 1,
6210 cur_touched,
6211 first_touched,
6212 &V );
6215 contour++;
6216 } while ( contour < CUR.pts.n_contours );
6220 /*************************************************************************/
6221 /* */
6222 /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
6223 /* Opcode range: 0x5D,0x71,0x72 */
6224 /* Stack: uint32 (2 * uint32)... --> */
6225 /* */
6226 static void
6227 Ins_DELTAP( INS_ARG )
6229 FT_ULong k, nump;
6230 FT_UShort A;
6231 FT_ULong C;
6232 FT_Long B;
6235 nump = (FT_ULong)args[0]; /* some points theoretically may occur more
6236 than once, thus UShort isn't enough */
6238 for ( k = 1; k <= nump; k++ )
6240 if ( CUR.args < 2 )
6242 CUR.error = TT_Err_Too_Few_Arguments;
6243 return;
6246 CUR.args -= 2;
6248 A = (FT_UShort)CUR.stack[CUR.args + 1];
6249 B = CUR.stack[CUR.args];
6251 /* XXX: Because some popular fonts contain some invalid DeltaP */
6252 /* instructions, we simply ignore them when the stacked */
6253 /* point reference is off limit, rather than returning an */
6254 /* error. As a delta instruction doesn't change a glyph */
6255 /* in great ways, this shouldn't be a problem. */
6257 if ( !BOUNDS( A, CUR.zp0.n_points ) )
6259 C = ( (FT_ULong)B & 0xF0 ) >> 4;
6261 switch ( CUR.opcode )
6263 case 0x5D:
6264 break;
6266 case 0x71:
6267 C += 16;
6268 break;
6270 case 0x72:
6271 C += 32;
6272 break;
6275 C += CUR.GS.delta_base;
6277 if ( CURRENT_Ppem() == (FT_Long)C )
6279 B = ( (FT_ULong)B & 0xF ) - 8;
6280 if ( B >= 0 )
6281 B++;
6282 B = B * 64 / ( 1L << CUR.GS.delta_shift );
6284 CUR_Func_move( &CUR.zp0, A, B );
6287 else
6288 if ( CUR.pedantic_hinting )
6289 CUR.error = TT_Err_Invalid_Reference;
6292 CUR.new_top = CUR.args;
6296 /*************************************************************************/
6297 /* */
6298 /* DELTACn[]: DELTA exceptions C1, C2, C3 */
6299 /* Opcode range: 0x73,0x74,0x75 */
6300 /* Stack: uint32 (2 * uint32)... --> */
6301 /* */
6302 static void
6303 Ins_DELTAC( INS_ARG )
6305 FT_ULong nump, k;
6306 FT_ULong A, C;
6307 FT_Long B;
6310 nump = (FT_ULong)args[0];
6312 for ( k = 1; k <= nump; k++ )
6314 if ( CUR.args < 2 )
6316 CUR.error = TT_Err_Too_Few_Arguments;
6317 return;
6320 CUR.args -= 2;
6322 A = (FT_ULong)CUR.stack[CUR.args + 1];
6323 B = CUR.stack[CUR.args];
6325 if ( BOUNDS( A, CUR.cvtSize ) )
6327 if ( CUR.pedantic_hinting )
6329 CUR.error = TT_Err_Invalid_Reference;
6330 return;
6333 else
6335 C = ( (FT_ULong)B & 0xF0 ) >> 4;
6337 switch ( CUR.opcode )
6339 case 0x73:
6340 break;
6342 case 0x74:
6343 C += 16;
6344 break;
6346 case 0x75:
6347 C += 32;
6348 break;
6351 C += CUR.GS.delta_base;
6353 if ( CURRENT_Ppem() == (FT_Long)C )
6355 B = ( (FT_ULong)B & 0xF ) - 8;
6356 if ( B >= 0 )
6357 B++;
6358 B = B * 64 / ( 1L << CUR.GS.delta_shift );
6360 CUR_Func_move_cvt( A, B );
6365 CUR.new_top = CUR.args;
6369 /*************************************************************************/
6370 /* */
6371 /* MISC. INSTRUCTIONS */
6372 /* */
6373 /*************************************************************************/
6376 /*************************************************************************/
6377 /* */
6378 /* GETINFO[]: GET INFOrmation */
6379 /* Opcode range: 0x88 */
6380 /* Stack: uint32 --> uint32 */
6381 /* */
6382 /* XXX: According to Apple specs, bits 1 & 2 of the argument ought to be */
6383 /* consulted before rotated/stretched info is returned. */
6384 static void
6385 Ins_GETINFO( INS_ARG )
6387 FT_Long K;
6390 K = 0;
6392 /* We return then Windows 3.1 version number */
6393 /* for the font scaler */
6394 if ( ( args[0] & 1 ) != 0 )
6395 K = 3;
6397 /* Has the glyph been rotated ? */
6398 if ( CUR.tt_metrics.rotated )
6399 K |= 0x80;
6401 /* Has the glyph been stretched ? */
6402 if ( CUR.tt_metrics.stretched )
6403 K |= 0x100;
6405 args[0] = K;
6409 static void
6410 Ins_UNKNOWN( INS_ARG )
6412 TT_DefRecord* def = CUR.IDefs;
6413 TT_DefRecord* limit = def + CUR.numIDefs;
6415 FT_UNUSED_ARG;
6418 for ( ; def < limit; def++ )
6420 if ( (FT_Byte)def->opc == CUR.opcode && def->active )
6422 TT_CallRec* call;
6425 if ( CUR.callTop >= CUR.callSize )
6427 CUR.error = TT_Err_Stack_Overflow;
6428 return;
6431 call = CUR.callStack + CUR.callTop++;
6433 call->Caller_Range = CUR.curRange;
6434 call->Caller_IP = CUR.IP+1;
6435 call->Cur_Count = 1;
6436 call->Cur_Restart = def->start;
6438 INS_Goto_CodeRange( def->range, def->start );
6440 CUR.step_ins = FALSE;
6441 return;
6445 CUR.error = TT_Err_Invalid_Opcode;
6449 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
6452 static
6453 TInstruction_Function Instruct_Dispatch[256] =
6455 /* Opcodes are gathered in groups of 16. */
6456 /* Please keep the spaces as they are. */
6458 /* SVTCA y */ Ins_SVTCA,
6459 /* SVTCA x */ Ins_SVTCA,
6460 /* SPvTCA y */ Ins_SPVTCA,
6461 /* SPvTCA x */ Ins_SPVTCA,
6462 /* SFvTCA y */ Ins_SFVTCA,
6463 /* SFvTCA x */ Ins_SFVTCA,
6464 /* SPvTL // */ Ins_SPVTL,
6465 /* SPvTL + */ Ins_SPVTL,
6466 /* SFvTL // */ Ins_SFVTL,
6467 /* SFvTL + */ Ins_SFVTL,
6468 /* SPvFS */ Ins_SPVFS,
6469 /* SFvFS */ Ins_SFVFS,
6470 /* GPV */ Ins_GPV,
6471 /* GFV */ Ins_GFV,
6472 /* SFvTPv */ Ins_SFVTPV,
6473 /* ISECT */ Ins_ISECT,
6475 /* SRP0 */ Ins_SRP0,
6476 /* SRP1 */ Ins_SRP1,
6477 /* SRP2 */ Ins_SRP2,
6478 /* SZP0 */ Ins_SZP0,
6479 /* SZP1 */ Ins_SZP1,
6480 /* SZP2 */ Ins_SZP2,
6481 /* SZPS */ Ins_SZPS,
6482 /* SLOOP */ Ins_SLOOP,
6483 /* RTG */ Ins_RTG,
6484 /* RTHG */ Ins_RTHG,
6485 /* SMD */ Ins_SMD,
6486 /* ELSE */ Ins_ELSE,
6487 /* JMPR */ Ins_JMPR,
6488 /* SCvTCi */ Ins_SCVTCI,
6489 /* SSwCi */ Ins_SSWCI,
6490 /* SSW */ Ins_SSW,
6492 /* DUP */ Ins_DUP,
6493 /* POP */ Ins_POP,
6494 /* CLEAR */ Ins_CLEAR,
6495 /* SWAP */ Ins_SWAP,
6496 /* DEPTH */ Ins_DEPTH,
6497 /* CINDEX */ Ins_CINDEX,
6498 /* MINDEX */ Ins_MINDEX,
6499 /* AlignPTS */ Ins_ALIGNPTS,
6500 /* INS_0x28 */ Ins_UNKNOWN,
6501 /* UTP */ Ins_UTP,
6502 /* LOOPCALL */ Ins_LOOPCALL,
6503 /* CALL */ Ins_CALL,
6504 /* FDEF */ Ins_FDEF,
6505 /* ENDF */ Ins_ENDF,
6506 /* MDAP[0] */ Ins_MDAP,
6507 /* MDAP[1] */ Ins_MDAP,
6509 /* IUP[0] */ Ins_IUP,
6510 /* IUP[1] */ Ins_IUP,
6511 /* SHP[0] */ Ins_SHP,
6512 /* SHP[1] */ Ins_SHP,
6513 /* SHC[0] */ Ins_SHC,
6514 /* SHC[1] */ Ins_SHC,
6515 /* SHZ[0] */ Ins_SHZ,
6516 /* SHZ[1] */ Ins_SHZ,
6517 /* SHPIX */ Ins_SHPIX,
6518 /* IP */ Ins_IP,
6519 /* MSIRP[0] */ Ins_MSIRP,
6520 /* MSIRP[1] */ Ins_MSIRP,
6521 /* AlignRP */ Ins_ALIGNRP,
6522 /* RTDG */ Ins_RTDG,
6523 /* MIAP[0] */ Ins_MIAP,
6524 /* MIAP[1] */ Ins_MIAP,
6526 /* NPushB */ Ins_NPUSHB,
6527 /* NPushW */ Ins_NPUSHW,
6528 /* WS */ Ins_WS,
6529 /* RS */ Ins_RS,
6530 /* WCvtP */ Ins_WCVTP,
6531 /* RCvt */ Ins_RCVT,
6532 /* GC[0] */ Ins_GC,
6533 /* GC[1] */ Ins_GC,
6534 /* SCFS */ Ins_SCFS,
6535 /* MD[0] */ Ins_MD,
6536 /* MD[1] */ Ins_MD,
6537 /* MPPEM */ Ins_MPPEM,
6538 /* MPS */ Ins_MPS,
6539 /* FlipON */ Ins_FLIPON,
6540 /* FlipOFF */ Ins_FLIPOFF,
6541 /* DEBUG */ Ins_DEBUG,
6543 /* LT */ Ins_LT,
6544 /* LTEQ */ Ins_LTEQ,
6545 /* GT */ Ins_GT,
6546 /* GTEQ */ Ins_GTEQ,
6547 /* EQ */ Ins_EQ,
6548 /* NEQ */ Ins_NEQ,
6549 /* ODD */ Ins_ODD,
6550 /* EVEN */ Ins_EVEN,
6551 /* IF */ Ins_IF,
6552 /* EIF */ Ins_EIF,
6553 /* AND */ Ins_AND,
6554 /* OR */ Ins_OR,
6555 /* NOT */ Ins_NOT,
6556 /* DeltaP1 */ Ins_DELTAP,
6557 /* SDB */ Ins_SDB,
6558 /* SDS */ Ins_SDS,
6560 /* ADD */ Ins_ADD,
6561 /* SUB */ Ins_SUB,
6562 /* DIV */ Ins_DIV,
6563 /* MUL */ Ins_MUL,
6564 /* ABS */ Ins_ABS,
6565 /* NEG */ Ins_NEG,
6566 /* FLOOR */ Ins_FLOOR,
6567 /* CEILING */ Ins_CEILING,
6568 /* ROUND[0] */ Ins_ROUND,
6569 /* ROUND[1] */ Ins_ROUND,
6570 /* ROUND[2] */ Ins_ROUND,
6571 /* ROUND[3] */ Ins_ROUND,
6572 /* NROUND[0] */ Ins_NROUND,
6573 /* NROUND[1] */ Ins_NROUND,
6574 /* NROUND[2] */ Ins_NROUND,
6575 /* NROUND[3] */ Ins_NROUND,
6577 /* WCvtF */ Ins_WCVTF,
6578 /* DeltaP2 */ Ins_DELTAP,
6579 /* DeltaP3 */ Ins_DELTAP,
6580 /* DeltaCn[0] */ Ins_DELTAC,
6581 /* DeltaCn[1] */ Ins_DELTAC,
6582 /* DeltaCn[2] */ Ins_DELTAC,
6583 /* SROUND */ Ins_SROUND,
6584 /* S45Round */ Ins_S45ROUND,
6585 /* JROT */ Ins_JROT,
6586 /* JROF */ Ins_JROF,
6587 /* ROFF */ Ins_ROFF,
6588 /* INS_0x7B */ Ins_UNKNOWN,
6589 /* RUTG */ Ins_RUTG,
6590 /* RDTG */ Ins_RDTG,
6591 /* SANGW */ Ins_SANGW,
6592 /* AA */ Ins_AA,
6594 /* FlipPT */ Ins_FLIPPT,
6595 /* FlipRgON */ Ins_FLIPRGON,
6596 /* FlipRgOFF */ Ins_FLIPRGOFF,
6597 /* INS_0x83 */ Ins_UNKNOWN,
6598 /* INS_0x84 */ Ins_UNKNOWN,
6599 /* ScanCTRL */ Ins_SCANCTRL,
6600 /* SDPVTL[0] */ Ins_SDPVTL,
6601 /* SDPVTL[1] */ Ins_SDPVTL,
6602 /* GetINFO */ Ins_GETINFO,
6603 /* IDEF */ Ins_IDEF,
6604 /* ROLL */ Ins_ROLL,
6605 /* MAX */ Ins_MAX,
6606 /* MIN */ Ins_MIN,
6607 /* ScanTYPE */ Ins_SCANTYPE,
6608 /* InstCTRL */ Ins_INSTCTRL,
6609 /* INS_0x8F */ Ins_UNKNOWN,
6611 /* INS_0x90 */ Ins_UNKNOWN,
6612 /* INS_0x91 */ Ins_UNKNOWN,
6613 /* INS_0x92 */ Ins_UNKNOWN,
6614 /* INS_0x93 */ Ins_UNKNOWN,
6615 /* INS_0x94 */ Ins_UNKNOWN,
6616 /* INS_0x95 */ Ins_UNKNOWN,
6617 /* INS_0x96 */ Ins_UNKNOWN,
6618 /* INS_0x97 */ Ins_UNKNOWN,
6619 /* INS_0x98 */ Ins_UNKNOWN,
6620 /* INS_0x99 */ Ins_UNKNOWN,
6621 /* INS_0x9A */ Ins_UNKNOWN,
6622 /* INS_0x9B */ Ins_UNKNOWN,
6623 /* INS_0x9C */ Ins_UNKNOWN,
6624 /* INS_0x9D */ Ins_UNKNOWN,
6625 /* INS_0x9E */ Ins_UNKNOWN,
6626 /* INS_0x9F */ Ins_UNKNOWN,
6628 /* INS_0xA0 */ Ins_UNKNOWN,
6629 /* INS_0xA1 */ Ins_UNKNOWN,
6630 /* INS_0xA2 */ Ins_UNKNOWN,
6631 /* INS_0xA3 */ Ins_UNKNOWN,
6632 /* INS_0xA4 */ Ins_UNKNOWN,
6633 /* INS_0xA5 */ Ins_UNKNOWN,
6634 /* INS_0xA6 */ Ins_UNKNOWN,
6635 /* INS_0xA7 */ Ins_UNKNOWN,
6636 /* INS_0xA8 */ Ins_UNKNOWN,
6637 /* INS_0xA9 */ Ins_UNKNOWN,
6638 /* INS_0xAA */ Ins_UNKNOWN,
6639 /* INS_0xAB */ Ins_UNKNOWN,
6640 /* INS_0xAC */ Ins_UNKNOWN,
6641 /* INS_0xAD */ Ins_UNKNOWN,
6642 /* INS_0xAE */ Ins_UNKNOWN,
6643 /* INS_0xAF */ Ins_UNKNOWN,
6645 /* PushB[0] */ Ins_PUSHB,
6646 /* PushB[1] */ Ins_PUSHB,
6647 /* PushB[2] */ Ins_PUSHB,
6648 /* PushB[3] */ Ins_PUSHB,
6649 /* PushB[4] */ Ins_PUSHB,
6650 /* PushB[5] */ Ins_PUSHB,
6651 /* PushB[6] */ Ins_PUSHB,
6652 /* PushB[7] */ Ins_PUSHB,
6653 /* PushW[0] */ Ins_PUSHW,
6654 /* PushW[1] */ Ins_PUSHW,
6655 /* PushW[2] */ Ins_PUSHW,
6656 /* PushW[3] */ Ins_PUSHW,
6657 /* PushW[4] */ Ins_PUSHW,
6658 /* PushW[5] */ Ins_PUSHW,
6659 /* PushW[6] */ Ins_PUSHW,
6660 /* PushW[7] */ Ins_PUSHW,
6662 /* MDRP[00] */ Ins_MDRP,
6663 /* MDRP[01] */ Ins_MDRP,
6664 /* MDRP[02] */ Ins_MDRP,
6665 /* MDRP[03] */ Ins_MDRP,
6666 /* MDRP[04] */ Ins_MDRP,
6667 /* MDRP[05] */ Ins_MDRP,
6668 /* MDRP[06] */ Ins_MDRP,
6669 /* MDRP[07] */ Ins_MDRP,
6670 /* MDRP[08] */ Ins_MDRP,
6671 /* MDRP[09] */ Ins_MDRP,
6672 /* MDRP[10] */ Ins_MDRP,
6673 /* MDRP[11] */ Ins_MDRP,
6674 /* MDRP[12] */ Ins_MDRP,
6675 /* MDRP[13] */ Ins_MDRP,
6676 /* MDRP[14] */ Ins_MDRP,
6677 /* MDRP[15] */ Ins_MDRP,
6679 /* MDRP[16] */ Ins_MDRP,
6680 /* MDRP[17] */ Ins_MDRP,
6681 /* MDRP[18] */ Ins_MDRP,
6682 /* MDRP[19] */ Ins_MDRP,
6683 /* MDRP[20] */ Ins_MDRP,
6684 /* MDRP[21] */ Ins_MDRP,
6685 /* MDRP[22] */ Ins_MDRP,
6686 /* MDRP[23] */ Ins_MDRP,
6687 /* MDRP[24] */ Ins_MDRP,
6688 /* MDRP[25] */ Ins_MDRP,
6689 /* MDRP[26] */ Ins_MDRP,
6690 /* MDRP[27] */ Ins_MDRP,
6691 /* MDRP[28] */ Ins_MDRP,
6692 /* MDRP[29] */ Ins_MDRP,
6693 /* MDRP[30] */ Ins_MDRP,
6694 /* MDRP[31] */ Ins_MDRP,
6696 /* MIRP[00] */ Ins_MIRP,
6697 /* MIRP[01] */ Ins_MIRP,
6698 /* MIRP[02] */ Ins_MIRP,
6699 /* MIRP[03] */ Ins_MIRP,
6700 /* MIRP[04] */ Ins_MIRP,
6701 /* MIRP[05] */ Ins_MIRP,
6702 /* MIRP[06] */ Ins_MIRP,
6703 /* MIRP[07] */ Ins_MIRP,
6704 /* MIRP[08] */ Ins_MIRP,
6705 /* MIRP[09] */ Ins_MIRP,
6706 /* MIRP[10] */ Ins_MIRP,
6707 /* MIRP[11] */ Ins_MIRP,
6708 /* MIRP[12] */ Ins_MIRP,
6709 /* MIRP[13] */ Ins_MIRP,
6710 /* MIRP[14] */ Ins_MIRP,
6711 /* MIRP[15] */ Ins_MIRP,
6713 /* MIRP[16] */ Ins_MIRP,
6714 /* MIRP[17] */ Ins_MIRP,
6715 /* MIRP[18] */ Ins_MIRP,
6716 /* MIRP[19] */ Ins_MIRP,
6717 /* MIRP[20] */ Ins_MIRP,
6718 /* MIRP[21] */ Ins_MIRP,
6719 /* MIRP[22] */ Ins_MIRP,
6720 /* MIRP[23] */ Ins_MIRP,
6721 /* MIRP[24] */ Ins_MIRP,
6722 /* MIRP[25] */ Ins_MIRP,
6723 /* MIRP[26] */ Ins_MIRP,
6724 /* MIRP[27] */ Ins_MIRP,
6725 /* MIRP[28] */ Ins_MIRP,
6726 /* MIRP[29] */ Ins_MIRP,
6727 /* MIRP[30] */ Ins_MIRP,
6728 /* MIRP[31] */ Ins_MIRP
6732 #endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
6735 /*************************************************************************/
6736 /* */
6737 /* RUN */
6738 /* */
6739 /* This function executes a run of opcodes. It will exit in the */
6740 /* following cases: */
6741 /* */
6742 /* - Errors (in which case it returns FALSE). */
6743 /* */
6744 /* - Reaching the end of the main code range (returns TRUE). */
6745 /* Reaching the end of a code range within a function call is an */
6746 /* error. */
6747 /* */
6748 /* - After executing one single opcode, if the flag `Instruction_Trap' */
6749 /* is set to TRUE (returns TRUE). */
6750 /* */
6751 /* On exit whith TRUE, test IP < CodeSize to know wether it comes from */
6752 /* an instruction trap or a normal termination. */
6753 /* */
6754 /* */
6755 /* Note: The documented DEBUG opcode pops a value from the stack. This */
6756 /* behaviour is unsupported; here a DEBUG opcode is always an */
6757 /* error. */
6758 /* */
6759 /* */
6760 /* THIS IS THE INTERPRETER'S MAIN LOOP. */
6761 /* */
6762 /* Instructions appear in the specification's order. */
6763 /* */
6764 /*************************************************************************/
6767 /* documentation is in ttinterp.h */
6769 FT_EXPORT_DEF( FT_Error )
6770 TT_RunIns( TT_ExecContext exc )
6772 FT_Long ins_counter = 0; /* executed instructions counter */
6775 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
6776 cur = *exc;
6777 #endif
6779 /* set CVT functions */
6780 CUR.tt_metrics.ratio = 0;
6781 if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
6783 /* non-square pixels, use the stretched routines */
6784 CUR.func_read_cvt = Read_CVT_Stretched;
6785 CUR.func_write_cvt = Write_CVT_Stretched;
6786 CUR.func_move_cvt = Move_CVT_Stretched;
6788 else
6790 /* square pixels, use normal routines */
6791 CUR.func_read_cvt = Read_CVT;
6792 CUR.func_write_cvt = Write_CVT;
6793 CUR.func_move_cvt = Move_CVT;
6796 COMPUTE_Funcs();
6797 COMPUTE_Round( (FT_Byte)exc->GS.round_state );
6801 CUR.opcode = CUR.code[CUR.IP];
6803 if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )
6805 if ( CUR.IP + 1 > CUR.codeSize )
6806 goto LErrorCodeOverflow_;
6808 CUR.length = CUR.code[CUR.IP + 1] + 2;
6811 if ( CUR.IP + CUR.length > CUR.codeSize )
6812 goto LErrorCodeOverflow_;
6814 /* First, let's check for empty stack and overflow */
6815 CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 );
6817 /* `args' is the top of the stack once arguments have been popped. */
6818 /* One can also interpret it as the index of the last argument. */
6819 if ( CUR.args < 0 )
6821 CUR.error = TT_Err_Too_Few_Arguments;
6822 goto LErrorLabel_;
6825 CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 );
6827 /* `new_top' is the new top of the stack, after the instruction's */
6828 /* execution. `top' will be set to `new_top' after the `switch' */
6829 /* statement. */
6830 if ( CUR.new_top > CUR.stackSize )
6832 CUR.error = TT_Err_Stack_Overflow;
6833 goto LErrorLabel_;
6836 CUR.step_ins = TRUE;
6837 CUR.error = TT_Err_Ok;
6839 #ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
6842 FT_Long* args = CUR.stack + CUR.args;
6843 FT_Byte opcode = CUR.opcode;
6846 #undef ARRAY_BOUND_ERROR
6847 #define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
6850 switch ( opcode )
6852 case 0x00: /* SVTCA y */
6853 case 0x01: /* SVTCA x */
6854 case 0x02: /* SPvTCA y */
6855 case 0x03: /* SPvTCA x */
6856 case 0x04: /* SFvTCA y */
6857 case 0x05: /* SFvTCA x */
6859 FT_Short AA, BB;
6862 AA = (FT_Short)( ( opcode & 1 ) << 14 );
6863 BB = (FT_Short)( AA ^ 0x4000 );
6865 if ( opcode < 4 )
6867 CUR.GS.projVector.x = AA;
6868 CUR.GS.projVector.y = BB;
6870 CUR.GS.dualVector.x = AA;
6871 CUR.GS.dualVector.y = BB;
6874 if ( ( opcode & 2 ) == 0 )
6876 CUR.GS.freeVector.x = AA;
6877 CUR.GS.freeVector.y = BB;
6880 COMPUTE_Funcs();
6882 break;
6884 case 0x06: /* SPvTL // */
6885 case 0x07: /* SPvTL + */
6886 DO_SPVTL
6887 break;
6889 case 0x08: /* SFvTL // */
6890 case 0x09: /* SFvTL + */
6891 DO_SFVTL
6892 break;
6894 case 0x0A: /* SPvFS */
6895 DO_SPVFS
6896 break;
6898 case 0x0B: /* SFvFS */
6899 DO_SFVFS
6900 break;
6902 case 0x0C: /* GPV */
6903 DO_GPV
6904 break;
6906 case 0x0D: /* GFV */
6907 DO_GFV
6908 break;
6910 case 0x0E: /* SFvTPv */
6911 DO_SFVTPV
6912 break;
6914 case 0x0F: /* ISECT */
6915 Ins_ISECT( EXEC_ARG_ args );
6916 break;
6918 case 0x10: /* SRP0 */
6919 DO_SRP0
6920 break;
6922 case 0x11: /* SRP1 */
6923 DO_SRP1
6924 break;
6926 case 0x12: /* SRP2 */
6927 DO_SRP2
6928 break;
6930 case 0x13: /* SZP0 */
6931 Ins_SZP0( EXEC_ARG_ args );
6932 break;
6934 case 0x14: /* SZP1 */
6935 Ins_SZP1( EXEC_ARG_ args );
6936 break;
6938 case 0x15: /* SZP2 */
6939 Ins_SZP2( EXEC_ARG_ args );
6940 break;
6942 case 0x16: /* SZPS */
6943 Ins_SZPS( EXEC_ARG_ args );
6944 break;
6946 case 0x17: /* SLOOP */
6947 DO_SLOOP
6948 break;
6950 case 0x18: /* RTG */
6951 DO_RTG
6952 break;
6954 case 0x19: /* RTHG */
6955 DO_RTHG
6956 break;
6958 case 0x1A: /* SMD */
6959 DO_SMD
6960 break;
6962 case 0x1B: /* ELSE */
6963 Ins_ELSE( EXEC_ARG_ args );
6964 break;
6966 case 0x1C: /* JMPR */
6967 DO_JMPR
6968 break;
6970 case 0x1D: /* SCVTCI */
6971 DO_SCVTCI
6972 break;
6974 case 0x1E: /* SSWCI */
6975 DO_SSWCI
6976 break;
6978 case 0x1F: /* SSW */
6979 DO_SSW
6980 break;
6982 case 0x20: /* DUP */
6983 DO_DUP
6984 break;
6986 case 0x21: /* POP */
6987 /* nothing :-) */
6988 break;
6990 case 0x22: /* CLEAR */
6991 DO_CLEAR
6992 break;
6994 case 0x23: /* SWAP */
6995 DO_SWAP
6996 break;
6998 case 0x24: /* DEPTH */
6999 DO_DEPTH
7000 break;
7002 case 0x25: /* CINDEX */
7003 DO_CINDEX
7004 break;
7006 case 0x26: /* MINDEX */
7007 Ins_MINDEX( EXEC_ARG_ args );
7008 break;
7010 case 0x27: /* ALIGNPTS */
7011 Ins_ALIGNPTS( EXEC_ARG_ args );
7012 break;
7014 case 0x28: /* ???? */
7015 Ins_UNKNOWN( EXEC_ARG_ args );
7016 break;
7018 case 0x29: /* UTP */
7019 Ins_UTP( EXEC_ARG_ args );
7020 break;
7022 case 0x2A: /* LOOPCALL */
7023 Ins_LOOPCALL( EXEC_ARG_ args );
7024 break;
7026 case 0x2B: /* CALL */
7027 Ins_CALL( EXEC_ARG_ args );
7028 break;
7030 case 0x2C: /* FDEF */
7031 Ins_FDEF( EXEC_ARG_ args );
7032 break;
7034 case 0x2D: /* ENDF */
7035 Ins_ENDF( EXEC_ARG_ args );
7036 break;
7038 case 0x2E: /* MDAP */
7039 case 0x2F: /* MDAP */
7040 Ins_MDAP( EXEC_ARG_ args );
7041 break;
7044 case 0x30: /* IUP */
7045 case 0x31: /* IUP */
7046 Ins_IUP( EXEC_ARG_ args );
7047 break;
7049 case 0x32: /* SHP */
7050 case 0x33: /* SHP */
7051 Ins_SHP( EXEC_ARG_ args );
7052 break;
7054 case 0x34: /* SHC */
7055 case 0x35: /* SHC */
7056 Ins_SHC( EXEC_ARG_ args );
7057 break;
7059 case 0x36: /* SHZ */
7060 case 0x37: /* SHZ */
7061 Ins_SHZ( EXEC_ARG_ args );
7062 break;
7064 case 0x38: /* SHPIX */
7065 Ins_SHPIX( EXEC_ARG_ args );
7066 break;
7068 case 0x39: /* IP */
7069 Ins_IP( EXEC_ARG_ args );
7070 break;
7072 case 0x3A: /* MSIRP */
7073 case 0x3B: /* MSIRP */
7074 Ins_MSIRP( EXEC_ARG_ args );
7075 break;
7077 case 0x3C: /* AlignRP */
7078 Ins_ALIGNRP( EXEC_ARG_ args );
7079 break;
7081 case 0x3D: /* RTDG */
7082 DO_RTDG
7083 break;
7085 case 0x3E: /* MIAP */
7086 case 0x3F: /* MIAP */
7087 Ins_MIAP( EXEC_ARG_ args );
7088 break;
7090 case 0x40: /* NPUSHB */
7091 Ins_NPUSHB( EXEC_ARG_ args );
7092 break;
7094 case 0x41: /* NPUSHW */
7095 Ins_NPUSHW( EXEC_ARG_ args );
7096 break;
7098 case 0x42: /* WS */
7099 DO_WS
7100 break;
7102 Set_Invalid_Ref:
7103 CUR.error = TT_Err_Invalid_Reference;
7104 break;
7106 case 0x43: /* RS */
7107 DO_RS
7108 break;
7110 case 0x44: /* WCVTP */
7111 DO_WCVTP
7112 break;
7114 case 0x45: /* RCVT */
7115 DO_RCVT
7116 break;
7118 case 0x46: /* GC */
7119 case 0x47: /* GC */
7120 Ins_GC( EXEC_ARG_ args );
7121 break;
7123 case 0x48: /* SCFS */
7124 Ins_SCFS( EXEC_ARG_ args );
7125 break;
7127 case 0x49: /* MD */
7128 case 0x4A: /* MD */
7129 Ins_MD( EXEC_ARG_ args );
7130 break;
7132 case 0x4B: /* MPPEM */
7133 DO_MPPEM
7134 break;
7136 case 0x4C: /* MPS */
7137 DO_MPS
7138 break;
7140 case 0x4D: /* FLIPON */
7141 DO_FLIPON
7142 break;
7144 case 0x4E: /* FLIPOFF */
7145 DO_FLIPOFF
7146 break;
7148 case 0x4F: /* DEBUG */
7149 DO_DEBUG
7150 break;
7152 case 0x50: /* LT */
7153 DO_LT
7154 break;
7156 case 0x51: /* LTEQ */
7157 DO_LTEQ
7158 break;
7160 case 0x52: /* GT */
7161 DO_GT
7162 break;
7164 case 0x53: /* GTEQ */
7165 DO_GTEQ
7166 break;
7168 case 0x54: /* EQ */
7169 DO_EQ
7170 break;
7172 case 0x55: /* NEQ */
7173 DO_NEQ
7174 break;
7176 case 0x56: /* ODD */
7177 DO_ODD
7178 break;
7180 case 0x57: /* EVEN */
7181 DO_EVEN
7182 break;
7184 case 0x58: /* IF */
7185 Ins_IF( EXEC_ARG_ args );
7186 break;
7188 case 0x59: /* EIF */
7189 /* do nothing */
7190 break;
7192 case 0x5A: /* AND */
7193 DO_AND
7194 break;
7196 case 0x5B: /* OR */
7197 DO_OR
7198 break;
7200 case 0x5C: /* NOT */
7201 DO_NOT
7202 break;
7204 case 0x5D: /* DELTAP1 */
7205 Ins_DELTAP( EXEC_ARG_ args );
7206 break;
7208 case 0x5E: /* SDB */
7209 DO_SDB
7210 break;
7212 case 0x5F: /* SDS */
7213 DO_SDS
7214 break;
7216 case 0x60: /* ADD */
7217 DO_ADD
7218 break;
7220 case 0x61: /* SUB */
7221 DO_SUB
7222 break;
7224 case 0x62: /* DIV */
7225 DO_DIV
7226 break;
7228 case 0x63: /* MUL */
7229 DO_MUL
7230 break;
7232 case 0x64: /* ABS */
7233 DO_ABS
7234 break;
7236 case 0x65: /* NEG */
7237 DO_NEG
7238 break;
7240 case 0x66: /* FLOOR */
7241 DO_FLOOR
7242 break;
7244 case 0x67: /* CEILING */
7245 DO_CEILING
7246 break;
7248 case 0x68: /* ROUND */
7249 case 0x69: /* ROUND */
7250 case 0x6A: /* ROUND */
7251 case 0x6B: /* ROUND */
7252 DO_ROUND
7253 break;
7255 case 0x6C: /* NROUND */
7256 case 0x6D: /* NROUND */
7257 case 0x6E: /* NRRUND */
7258 case 0x6F: /* NROUND */
7259 DO_NROUND
7260 break;
7262 case 0x70: /* WCVTF */
7263 DO_WCVTF
7264 break;
7266 case 0x71: /* DELTAP2 */
7267 case 0x72: /* DELTAP3 */
7268 Ins_DELTAP( EXEC_ARG_ args );
7269 break;
7271 case 0x73: /* DELTAC0 */
7272 case 0x74: /* DELTAC1 */
7273 case 0x75: /* DELTAC2 */
7274 Ins_DELTAC( EXEC_ARG_ args );
7275 break;
7277 case 0x76: /* SROUND */
7278 DO_SROUND
7279 break;
7281 case 0x77: /* S45Round */
7282 DO_S45ROUND
7283 break;
7285 case 0x78: /* JROT */
7286 DO_JROT
7287 break;
7289 case 0x79: /* JROF */
7290 DO_JROF
7291 break;
7293 case 0x7A: /* ROFF */
7294 DO_ROFF
7295 break;
7297 case 0x7B: /* ???? */
7298 Ins_UNKNOWN( EXEC_ARG_ args );
7299 break;
7301 case 0x7C: /* RUTG */
7302 DO_RUTG
7303 break;
7305 case 0x7D: /* RDTG */
7306 DO_RDTG
7307 break;
7309 case 0x7E: /* SANGW */
7310 case 0x7F: /* AA */
7311 /* nothing - obsolete */
7312 break;
7314 case 0x80: /* FLIPPT */
7315 Ins_FLIPPT( EXEC_ARG_ args );
7316 break;
7318 case 0x81: /* FLIPRGON */
7319 Ins_FLIPRGON( EXEC_ARG_ args );
7320 break;
7322 case 0x82: /* FLIPRGOFF */
7323 Ins_FLIPRGOFF( EXEC_ARG_ args );
7324 break;
7326 case 0x83: /* UNKNOWN */
7327 case 0x84: /* UNKNOWN */
7328 Ins_UNKNOWN( EXEC_ARG_ args );
7329 break;
7331 case 0x85: /* SCANCTRL */
7332 Ins_SCANCTRL( EXEC_ARG_ args );
7333 break;
7335 case 0x86: /* SDPVTL */
7336 case 0x87: /* SDPVTL */
7337 Ins_SDPVTL( EXEC_ARG_ args );
7338 break;
7340 case 0x88: /* GETINFO */
7341 Ins_GETINFO( EXEC_ARG_ args );
7342 break;
7344 case 0x89: /* IDEF */
7345 Ins_IDEF( EXEC_ARG_ args );
7346 break;
7348 case 0x8A: /* ROLL */
7349 Ins_ROLL( EXEC_ARG_ args );
7350 break;
7352 case 0x8B: /* MAX */
7353 DO_MAX
7354 break;
7356 case 0x8C: /* MIN */
7357 DO_MIN
7358 break;
7360 case 0x8D: /* SCANTYPE */
7361 Ins_SCANTYPE( EXEC_ARG_ args );
7362 break;
7364 case 0x8E: /* INSTCTRL */
7365 Ins_INSTCTRL( EXEC_ARG_ args );
7366 break;
7368 case 0x8F:
7369 Ins_UNKNOWN( EXEC_ARG_ args );
7370 break;
7372 default:
7373 if ( opcode >= 0xE0 )
7374 Ins_MIRP( EXEC_ARG_ args );
7375 else if ( opcode >= 0xC0 )
7376 Ins_MDRP( EXEC_ARG_ args );
7377 else if ( opcode >= 0xB8 )
7378 Ins_PUSHW( EXEC_ARG_ args );
7379 else if ( opcode >= 0xB0 )
7380 Ins_PUSHB( EXEC_ARG_ args );
7381 else
7382 Ins_UNKNOWN( EXEC_ARG_ args );
7387 #else
7389 Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );
7391 #endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7393 if ( CUR.error != TT_Err_Ok )
7395 switch ( CUR.error )
7397 case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
7399 TT_DefRecord* def = CUR.IDefs;
7400 TT_DefRecord* limit = def + CUR.numIDefs;
7403 for ( ; def < limit; def++ )
7405 if ( def->active && CUR.opcode == (FT_Byte)def->opc )
7407 TT_CallRec* callrec;
7410 if ( CUR.callTop >= CUR.callSize )
7412 CUR.error = TT_Err_Invalid_Reference;
7413 goto LErrorLabel_;
7416 callrec = &CUR.callStack[CUR.callTop];
7418 callrec->Caller_Range = CUR.curRange;
7419 callrec->Caller_IP = CUR.IP + 1;
7420 callrec->Cur_Count = 1;
7421 callrec->Cur_Restart = def->start;
7423 if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
7424 goto LErrorLabel_;
7426 goto LSuiteLabel_;
7431 CUR.error = TT_Err_Invalid_Opcode;
7432 goto LErrorLabel_;
7434 #if 0
7435 break; /* Unreachable code warning suppression. */
7436 /* Leave to remind in case a later change the editor */
7437 /* to consider break; */
7438 #endif
7440 default:
7441 goto LErrorLabel_;
7443 #if 0
7444 break;
7445 #endif
7449 CUR.top = CUR.new_top;
7451 if ( CUR.step_ins )
7452 CUR.IP += CUR.length;
7454 /* increment instruction counter and check if we didn't */
7455 /* run this program for too long (e.g. infinite loops). */
7456 if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
7457 return TT_Err_Execution_Too_Long;
7459 LSuiteLabel_:
7460 if ( CUR.IP >= CUR.codeSize )
7462 if ( CUR.callTop > 0 )
7464 CUR.error = TT_Err_Code_Overflow;
7465 goto LErrorLabel_;
7467 else
7468 goto LNo_Error_;
7470 } while ( !CUR.instruction_trap );
7472 LNo_Error_:
7474 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7475 *exc = cur;
7476 #endif
7478 return TT_Err_Ok;
7480 LErrorCodeOverflow_:
7481 CUR.error = TT_Err_Code_Overflow;
7483 LErrorLabel_:
7485 #ifdef TT_CONFIG_OPTION_STATIC_RASTER
7486 *exc = cur;
7487 #endif
7489 return CUR.error;
7493 #endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
7496 /* END */