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