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