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