Sync with trunk r47367
[reactos.git] / lib / 3rdparty / freetype / src / truetype / ttinterp.c
1 /***************************************************************************/
2 /* */
3 /* ttinterp.c */
4 /* */
5 /* TrueType bytecode interpreter (body). */
6 /* */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
9 /* */
10 /* This file is part of the FreeType project, and may only be used, */
11 /* modified, and distributed under the terms of the FreeType project */
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13 /* this file you indicate that you have read the license and */
14 /* understand and accept it fully. */
15 /* */
16 /***************************************************************************/
17
18
19 #include <ft2build.h>
20 #include FT_INTERNAL_DEBUG_H
21 #include FT_INTERNAL_CALC_H
22 #include FT_TRIGONOMETRY_H
23 #include FT_SYSTEM_H
24
25 #include "ttinterp.h"
26
27 #include "tterrors.h"
28
29
30 #ifdef TT_USE_BYTECODE_INTERPRETER
31
32
33 #define TT_MULFIX FT_MulFix
34 #define TT_MULDIV FT_MulDiv
35 #define TT_MULDIV_NO_ROUND FT_MulDiv_No_Round
36
37
38 /*************************************************************************/
39 /* */
40 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
41 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
42 /* messages during execution. */
43 /* */
44 #undef FT_COMPONENT
45 #define FT_COMPONENT trace_ttinterp
46
47 /*************************************************************************/
48 /* */
49 /* In order to detect infinite loops in the code, we set up a counter */
50 /* within the run loop. A single stroke of interpretation is now */
51 /* limited to a maximal number of opcodes defined below. */
52 /* */
53 #define MAX_RUNNABLE_OPCODES 1000000L
54
55
56 /*************************************************************************/
57 /* */
58 /* There are two kinds of implementations: */
59 /* */
60 /* a. static implementation */
61 /* */
62 /* The current execution context is a static variable, which fields */
63 /* are accessed directly by the interpreter during execution. The */
64 /* context is named `cur'. */
65 /* */
66 /* This version is non-reentrant, of course. */
67 /* */
68 /* b. indirect implementation */
69 /* */
70 /* The current execution context is passed to _each_ function as its */
71 /* first argument, and each field is thus accessed indirectly. */
72 /* */
73 /* This version is fully re-entrant. */
74 /* */
75 /* The idea is that an indirect implementation may be slower to execute */
76 /* on low-end processors that are used in some systems (like 386s or */
77 /* even 486s). */
78 /* */
79 /* As a consequence, the indirect implementation is now the default, as */
80 /* its performance costs can be considered negligible in our context. */
81 /* Note, however, that we kept the same source with macros because: */
82 /* */
83 /* - The code is kept very close in design to the Pascal code used for */
84 /* development. */
85 /* */
86 /* - It's much more readable that way! */
87 /* */
88 /* - It's still open to experimentation and tuning. */
89 /* */
90 /*************************************************************************/
91
92
93 #ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */
94
95 #define CUR (*exc) /* see ttobjs.h */
96
97 /*************************************************************************/
98 /* */
99 /* This macro is used whenever `exec' is unused in a function, to avoid */
100 /* stupid warnings from pedantic compilers. */
101 /* */
102 #define FT_UNUSED_EXEC FT_UNUSED( exc )
103
104 #else /* static implementation */
105
106 #define CUR cur
107
108 #define FT_UNUSED_EXEC int __dummy = __dummy
109
110 static
111 TT_ExecContextRec cur; /* static exec. context variable */
112
113 /* apparently, we have a _lot_ of direct indexing when accessing */
114 /* the static `cur', which makes the code bigger (due to all the */
115 /* four bytes addresses). */
116
117 #endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
118
119
120 /*************************************************************************/
121 /* */
122 /* The instruction argument stack. */
123 /* */
124 #define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */
125
126
127 /*************************************************************************/
128 /* */
129 /* This macro is used whenever `args' is unused in a function, to avoid */
130 /* stupid warnings from pedantic compilers. */
131 /* */
132 #define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args )
133
134
135 /*************************************************************************/
136 /* */
137 /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */
138 /* increase readability of the code. */
139 /* */
140 /*************************************************************************/
141
142
143 #define SKIP_Code() \
144 SkipCode( EXEC_ARG )
145
146 #define GET_ShortIns() \
147 GetShortIns( EXEC_ARG )
148
149 #define NORMalize( x, y, v ) \
150 Normalize( EXEC_ARG_ x, y, v )
151
152 #define SET_SuperRound( scale, flags ) \
153 SetSuperRound( EXEC_ARG_ scale, flags )
154
155 #define ROUND_None( d, c ) \
156 Round_None( EXEC_ARG_ d, c )
157
158 #define INS_Goto_CodeRange( range, ip ) \
159 Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
160
161 #define CUR_Func_move( z, p, d ) \
162 CUR.func_move( EXEC_ARG_ z, p, d )
163
164 #define CUR_Func_move_orig( z, p, d ) \
165 CUR.func_move_orig( EXEC_ARG_ z, p, d )
166
167 #define CUR_Func_round( d, c ) \
168 CUR.func_round( EXEC_ARG_ d, c )
169
170 #define CUR_Func_read_cvt( index ) \
171 CUR.func_read_cvt( EXEC_ARG_ index )
172
173 #define CUR_Func_write_cvt( index, val ) \
174 CUR.func_write_cvt( EXEC_ARG_ index, val )
175
176 #define CUR_Func_move_cvt( index, val ) \
177 CUR.func_move_cvt( EXEC_ARG_ index, val )
178
179 #define CURRENT_Ratio() \
180 Current_Ratio( EXEC_ARG )
181
182 #define CURRENT_Ppem() \
183 Current_Ppem( EXEC_ARG )
184
185 #define CUR_Ppem() \
186 Cur_PPEM( EXEC_ARG )
187
188 #define INS_SxVTL( a, b, c, d ) \
189 Ins_SxVTL( EXEC_ARG_ a, b, c, d )
190
191 #define COMPUTE_Funcs() \
192 Compute_Funcs( EXEC_ARG )
193
194 #define COMPUTE_Round( a ) \
195 Compute_Round( EXEC_ARG_ a )
196
197 #define COMPUTE_Point_Displacement( a, b, c, d ) \
198 Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
199
200 #define MOVE_Zp2_Point( a, b, c, t ) \
201 Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
202
203
204 #define CUR_Func_project( v1, v2 ) \
205 CUR.func_project( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
206
207 #define CUR_Func_dualproj( v1, v2 ) \
208 CUR.func_dualproj( EXEC_ARG_ (v1)->x - (v2)->x, (v1)->y - (v2)->y )
209
210 #define CUR_fast_project( v ) \
211 CUR.func_project( EXEC_ARG_ (v)->x, (v)->y )
212
213 #define CUR_fast_dualproj( v ) \
214 CUR.func_dualproj( EXEC_ARG_ (v)->x, (v)->y )
215
216
217 /*************************************************************************/
218 /* */
219 /* Instruction dispatch function, as used by the interpreter. */
220 /* */
221 typedef void (*TInstruction_Function)( INS_ARG );
222
223
224 /*************************************************************************/
225 /* */
226 /* A simple bounds-checking macro. */
227 /* */
228 #define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
229
230 #undef SUCCESS
231 #define SUCCESS 0
232
233 #undef FAILURE
234 #define FAILURE 1
235
236 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
237 #define GUESS_VECTOR( V ) \
238 if ( CUR.face->unpatented_hinting ) \
239 { \
240 CUR.GS.V.x = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0x4000 : 0 ); \
241 CUR.GS.V.y = (FT_F2Dot14)( CUR.GS.both_x_axis ? 0 : 0x4000 ); \
242 }
243 #else
244 #define GUESS_VECTOR( V )
245 #endif
246
247 /*************************************************************************/
248 /* */
249 /* CODERANGE FUNCTIONS */
250 /* */
251 /*************************************************************************/
252
253
254 /*************************************************************************/
255 /* */
256 /* <Function> */
257 /* TT_Goto_CodeRange */
258 /* */
259 /* <Description> */
260 /* Switches to a new code range (updates the code related elements in */
261 /* `exec', and `IP'). */
262 /* */
263 /* <Input> */
264 /* range :: The new execution code range. */
265 /* */
266 /* IP :: The new IP in the new code range. */
267 /* */
268 /* <InOut> */
269 /* exec :: The target execution context. */
270 /* */
271 /* <Return> */
272 /* FreeType error code. 0 means success. */
273 /* */
274 FT_LOCAL_DEF( FT_Error )
275 TT_Goto_CodeRange( TT_ExecContext exec,
276 FT_Int range,
277 FT_Long IP )
278 {
279 TT_CodeRange* coderange;
280
281
282 FT_ASSERT( range >= 1 && range <= 3 );
283
284 coderange = &exec->codeRangeTable[range - 1];
285
286 FT_ASSERT( coderange->base != NULL );
287
288 /* NOTE: Because the last instruction of a program may be a CALL */
289 /* which will return to the first byte *after* the code */
290 /* range, we test for IP <= Size instead of IP < Size. */
291 /* */
292 FT_ASSERT( (FT_ULong)IP <= coderange->size );
293
294 exec->code = coderange->base;
295 exec->codeSize = coderange->size;
296 exec->IP = IP;
297 exec->curRange = range;
298
299 return TT_Err_Ok;
300 }
301
302
303 /*************************************************************************/
304 /* */
305 /* <Function> */
306 /* TT_Set_CodeRange */
307 /* */
308 /* <Description> */
309 /* Sets a code range. */
310 /* */
311 /* <Input> */
312 /* range :: The code range index. */
313 /* */
314 /* base :: The new code base. */
315 /* */
316 /* length :: The range size in bytes. */
317 /* */
318 /* <InOut> */
319 /* exec :: The target execution context. */
320 /* */
321 /* <Return> */
322 /* FreeType error code. 0 means success. */
323 /* */
324 FT_LOCAL_DEF( FT_Error )
325 TT_Set_CodeRange( TT_ExecContext exec,
326 FT_Int range,
327 void* base,
328 FT_Long length )
329 {
330 FT_ASSERT( range >= 1 && range <= 3 );
331
332 exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
333 exec->codeRangeTable[range - 1].size = length;
334
335 return TT_Err_Ok;
336 }
337
338
339 /*************************************************************************/
340 /* */
341 /* <Function> */
342 /* TT_Clear_CodeRange */
343 /* */
344 /* <Description> */
345 /* Clears a code range. */
346 /* */
347 /* <Input> */
348 /* range :: The code range index. */
349 /* */
350 /* <InOut> */
351 /* exec :: The target execution context. */
352 /* */
353 /* <Return> */
354 /* FreeType error code. 0 means success. */
355 /* */
356 /* <Note> */
357 /* Does not set the Error variable. */
358 /* */
359 FT_LOCAL_DEF( FT_Error )
360 TT_Clear_CodeRange( TT_ExecContext exec,
361 FT_Int range )
362 {
363 FT_ASSERT( range >= 1 && range <= 3 );
364
365 exec->codeRangeTable[range - 1].base = NULL;
366 exec->codeRangeTable[range - 1].size = 0;
367
368 return TT_Err_Ok;
369 }
370
371
372 /*************************************************************************/
373 /* */
374 /* EXECUTION CONTEXT ROUTINES */
375 /* */
376 /*************************************************************************/
377
378
379 /*************************************************************************/
380 /* */
381 /* <Function> */
382 /* TT_Done_Context */
383 /* */
384 /* <Description> */
385 /* Destroys a given context. */
386 /* */
387 /* <Input> */
388 /* exec :: A handle to the target execution context. */
389 /* */
390 /* memory :: A handle to the parent memory object. */
391 /* */
392 /* <Return> */
393 /* FreeType error code. 0 means success. */
394 /* */
395 /* <Note> */
396 /* Only the glyph loader and debugger should call this function. */
397 /* */
398 FT_LOCAL_DEF( FT_Error )
399 TT_Done_Context( TT_ExecContext exec )
400 {
401 FT_Memory memory = exec->memory;
402
403
404 /* points zone */
405 exec->maxPoints = 0;
406 exec->maxContours = 0;
407
408 /* free stack */
409 FT_FREE( exec->stack );
410 exec->stackSize = 0;
411
412 /* free call stack */
413 FT_FREE( exec->callStack );
414 exec->callSize = 0;
415 exec->callTop = 0;
416
417 /* free glyph code range */
418 FT_FREE( exec->glyphIns );
419 exec->glyphSize = 0;
420
421 exec->size = NULL;
422 exec->face = NULL;
423
424 FT_FREE( exec );
425
426 return TT_Err_Ok;
427 }
428
429
430 /*************************************************************************/
431 /* */
432 /* <Function> */
433 /* Init_Context */
434 /* */
435 /* <Description> */
436 /* Initializes a context object. */
437 /* */
438 /* <Input> */
439 /* memory :: A handle to the parent memory object. */
440 /* */
441 /* <InOut> */
442 /* exec :: A handle to the target execution context. */
443 /* */
444 /* <Return> */
445 /* FreeType error code. 0 means success. */
446 /* */
447 static FT_Error
448 Init_Context( TT_ExecContext exec,
449 FT_Memory memory )
450 {
451 FT_Error error;
452
453
454 FT_TRACE1(( "Init_Context: new object at 0x%08p\n", exec ));
455
456 exec->memory = memory;
457 exec->callSize = 32;
458
459 if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )
460 goto Fail_Memory;
461
462 /* all values in the context are set to 0 already, but this is */
463 /* here as a remainder */
464 exec->maxPoints = 0;
465 exec->maxContours = 0;
466
467 exec->stackSize = 0;
468 exec->glyphSize = 0;
469
470 exec->stack = NULL;
471 exec->glyphIns = NULL;
472
473 exec->face = NULL;
474 exec->size = NULL;
475
476 return TT_Err_Ok;
477
478 Fail_Memory:
479 FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n",
480 (FT_Long)exec ));
481 TT_Done_Context( exec );
482
483 return error;
484 }
485
486
487 /*************************************************************************/
488 /* */
489 /* <Function> */
490 /* Update_Max */
491 /* */
492 /* <Description> */
493 /* Checks the size of a buffer and reallocates it if necessary. */
494 /* */
495 /* <Input> */
496 /* memory :: A handle to the parent memory object. */
497 /* */
498 /* multiplier :: The size in bytes of each element in the buffer. */
499 /* */
500 /* new_max :: The new capacity (size) of the buffer. */
501 /* */
502 /* <InOut> */
503 /* size :: The address of the buffer's current size expressed */
504 /* in elements. */
505 /* */
506 /* buff :: The address of the buffer base pointer. */
507 /* */
508 /* <Return> */
509 /* FreeType error code. 0 means success. */
510 /* */
511 static FT_Error
512 Update_Max( FT_Memory memory,
513 FT_ULong* size,
514 FT_Long multiplier,
515 void* _pbuff,
516 FT_ULong new_max )
517 {
518 FT_Error error;
519 void** pbuff = (void**)_pbuff;
520
521
522 if ( *size < new_max )
523 {
524 if ( FT_REALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )
525 return error;
526 *size = new_max;
527 }
528
529 return TT_Err_Ok;
530 }
531
532
533 /*************************************************************************/
534 /* */
535 /* <Function> */
536 /* TT_Load_Context */
537 /* */
538 /* <Description> */
539 /* Prepare an execution context for glyph hinting. */
540 /* */
541 /* <Input> */
542 /* face :: A handle to the source face object. */
543 /* */
544 /* size :: A handle to the source size object. */
545 /* */
546 /* <InOut> */
547 /* exec :: A handle to the target execution context. */
548 /* */
549 /* <Return> */
550 /* FreeType error code. 0 means success. */
551 /* */
552 /* <Note> */
553 /* Only the glyph loader and debugger should call this function. */
554 /* */
555 FT_LOCAL_DEF( FT_Error )
556 TT_Load_Context( TT_ExecContext exec,
557 TT_Face face,
558 TT_Size size )
559 {
560 FT_Int i;
561 FT_ULong tmp;
562 TT_MaxProfile* maxp;
563 FT_Error error;
564
565
566 exec->face = face;
567 maxp = &face->max_profile;
568 exec->size = size;
569
570 if ( size )
571 {
572 exec->numFDefs = size->num_function_defs;
573 exec->maxFDefs = size->max_function_defs;
574 exec->numIDefs = size->num_instruction_defs;
575 exec->maxIDefs = size->max_instruction_defs;
576 exec->FDefs = size->function_defs;
577 exec->IDefs = size->instruction_defs;
578 exec->tt_metrics = size->ttmetrics;
579 exec->metrics = size->metrics;
580
581 exec->maxFunc = size->max_func;
582 exec->maxIns = size->max_ins;
583
584 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
585 exec->codeRangeTable[i] = size->codeRangeTable[i];
586
587 /* set graphics state */
588 exec->GS = size->GS;
589
590 exec->cvtSize = size->cvt_size;
591 exec->cvt = size->cvt;
592
593 exec->storeSize = size->storage_size;
594 exec->storage = size->storage;
595
596 exec->twilight = size->twilight;
597 }
598
599 /* XXX: We reserve a little more elements on the stack to deal safely */
600 /* with broken fonts like arialbs, courbs, timesbs, etc. */
601 tmp = exec->stackSize;
602 error = Update_Max( exec->memory,
603 &tmp,
604 sizeof ( FT_F26Dot6 ),
605 (void*)&exec->stack,
606 maxp->maxStackElements + 32 );
607 exec->stackSize = (FT_UInt)tmp;
608 if ( error )
609 return error;
610
611 tmp = exec->glyphSize;
612 error = Update_Max( exec->memory,
613 &tmp,
614 sizeof ( FT_Byte ),
615 (void*)&exec->glyphIns,
616 maxp->maxSizeOfInstructions );
617 exec->glyphSize = (FT_UShort)tmp;
618 if ( error )
619 return error;
620
621 exec->pts.n_points = 0;
622 exec->pts.n_contours = 0;
623
624 exec->zp1 = exec->pts;
625 exec->zp2 = exec->pts;
626 exec->zp0 = exec->pts;
627
628 exec->instruction_trap = FALSE;
629
630 return TT_Err_Ok;
631 }
632
633
634 /*************************************************************************/
635 /* */
636 /* <Function> */
637 /* TT_Save_Context */
638 /* */
639 /* <Description> */
640 /* Saves the code ranges in a `size' object. */
641 /* */
642 /* <Input> */
643 /* exec :: A handle to the source execution context. */
644 /* */
645 /* <InOut> */
646 /* size :: A handle to the target size object. */
647 /* */
648 /* <Return> */
649 /* FreeType error code. 0 means success. */
650 /* */
651 /* <Note> */
652 /* Only the glyph loader and debugger should call this function. */
653 /* */
654 FT_LOCAL_DEF( FT_Error )
655 TT_Save_Context( TT_ExecContext exec,
656 TT_Size size )
657 {
658 FT_Int i;
659
660
661 /* XXXX: Will probably disappear soon with all the code range */
662 /* management, which is now rather obsolete. */
663 /* */
664 size->num_function_defs = exec->numFDefs;
665 size->num_instruction_defs = exec->numIDefs;
666
667 size->max_func = exec->maxFunc;
668 size->max_ins = exec->maxIns;
669
670 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
671 size->codeRangeTable[i] = exec->codeRangeTable[i];
672
673 return TT_Err_Ok;
674 }
675
676
677 /*************************************************************************/
678 /* */
679 /* <Function> */
680 /* TT_Run_Context */
681 /* */
682 /* <Description> */
683 /* Executes one or more instructions in the execution context. */
684 /* */
685 /* <Input> */
686 /* debug :: A Boolean flag. If set, the function sets some internal */
687 /* variables and returns immediately, otherwise TT_RunIns() */
688 /* is called. */
689 /* */
690 /* This is commented out currently. */
691 /* */
692 /* <Input> */
693 /* exec :: A handle to the target execution context. */
694 /* */
695 /* <Return> */
696 /* TrueType error code. 0 means success. */
697 /* */
698 /* <Note> */
699 /* Only the glyph loader and debugger should call this function. */
700 /* */
701 FT_LOCAL_DEF( FT_Error )
702 TT_Run_Context( TT_ExecContext exec,
703 FT_Bool debug )
704 {
705 FT_Error error;
706
707
708 if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) )
709 != TT_Err_Ok )
710 return error;
711
712 exec->zp0 = exec->pts;
713 exec->zp1 = exec->pts;
714 exec->zp2 = exec->pts;
715
716 exec->GS.gep0 = 1;
717 exec->GS.gep1 = 1;
718 exec->GS.gep2 = 1;
719
720 exec->GS.projVector.x = 0x4000;
721 exec->GS.projVector.y = 0x0000;
722
723 exec->GS.freeVector = exec->GS.projVector;
724 exec->GS.dualVector = exec->GS.projVector;
725
726 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
727 exec->GS.both_x_axis = TRUE;
728 #endif
729
730 exec->GS.round_state = 1;
731 exec->GS.loop = 1;
732
733 /* some glyphs leave something on the stack. so we clean it */
734 /* before a new execution. */
735 exec->top = 0;
736 exec->callTop = 0;
737
738 #if 1
739 FT_UNUSED( debug );
740
741 return exec->face->interpreter( exec );
742 #else
743 if ( !debug )
744 return TT_RunIns( exec );
745 else
746 return TT_Err_Ok;
747 #endif
748 }
749
750
751 /* The default value for `scan_control' is documented as FALSE in the */
752 /* TrueType specification. This is confusing since it implies a */
753 /* Boolean value. However, this is not the case, thus both the */
754 /* default values of our `scan_type' and `scan_control' fields (which */
755 /* the documentation's `scan_control' variable is split into) are */
756 /* zero. */
757
758 const TT_GraphicsState tt_default_graphics_state =
759 {
760 0, 0, 0,
761 { 0x4000, 0 },
762 { 0x4000, 0 },
763 { 0x4000, 0 },
764
765 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
766 TRUE,
767 #endif
768
769 1, 64, 1,
770 TRUE, 68, 0, 0, 9, 3,
771 0, FALSE, 0, 1, 1, 1
772 };
773
774
775 /* documentation is in ttinterp.h */
776
777 FT_EXPORT_DEF( TT_ExecContext )
778 TT_New_Context( TT_Driver driver )
779 {
780 TT_ExecContext exec;
781 FT_Memory memory;
782
783
784 memory = driver->root.root.memory;
785 exec = driver->context;
786
787 if ( !driver->context )
788 {
789 FT_Error error;
790
791
792 /* allocate object */
793 if ( FT_NEW( exec ) )
794 goto Fail;
795
796 /* initialize it; in case of error this deallocates `exec' too */
797 error = Init_Context( exec, memory );
798 if ( error )
799 goto Fail;
800
801 /* store it into the driver */
802 driver->context = exec;
803 }
804
805 return driver->context;
806
807 Fail:
808 return NULL;
809 }
810
811
812 /*************************************************************************/
813 /* */
814 /* Before an opcode is executed, the interpreter verifies that there are */
815 /* enough arguments on the stack, with the help of the `Pop_Push_Count' */
816 /* table. */
817 /* */
818 /* For each opcode, the first column gives the number of arguments that */
819 /* are popped from the stack; the second one gives the number of those */
820 /* that are pushed in result. */
821 /* */
822 /* Opcodes which have a varying number of parameters in the data stream */
823 /* (NPUSHB, NPUSHW) are handled specially; they have a negative value in */
824 /* the `opcode_length' table, and the value in `Pop_Push_Count' is set */
825 /* to zero. */
826 /* */
827 /*************************************************************************/
828
829
830 #undef PACK
831 #define PACK( x, y ) ( ( x << 4 ) | y )
832
833
834 static
835 const FT_Byte Pop_Push_Count[256] =
836 {
837 /* opcodes are gathered in groups of 16 */
838 /* please keep the spaces as they are */
839
840 /* SVTCA y */ PACK( 0, 0 ),
841 /* SVTCA x */ PACK( 0, 0 ),
842 /* SPvTCA y */ PACK( 0, 0 ),
843 /* SPvTCA x */ PACK( 0, 0 ),
844 /* SFvTCA y */ PACK( 0, 0 ),
845 /* SFvTCA x */ PACK( 0, 0 ),
846 /* SPvTL // */ PACK( 2, 0 ),
847 /* SPvTL + */ PACK( 2, 0 ),
848 /* SFvTL // */ PACK( 2, 0 ),
849 /* SFvTL + */ PACK( 2, 0 ),
850 /* SPvFS */ PACK( 2, 0 ),
851 /* SFvFS */ PACK( 2, 0 ),
852 /* GPV */ PACK( 0, 2 ),
853 /* GFV */ PACK( 0, 2 ),
854 /* SFvTPv */ PACK( 0, 0 ),
855 /* ISECT */ PACK( 5, 0 ),
856
857 /* SRP0 */ PACK( 1, 0 ),
858 /* SRP1 */ PACK( 1, 0 ),
859 /* SRP2 */ PACK( 1, 0 ),
860 /* SZP0 */ PACK( 1, 0 ),
861 /* SZP1 */ PACK( 1, 0 ),
862 /* SZP2 */ PACK( 1, 0 ),
863 /* SZPS */ PACK( 1, 0 ),
864 /* SLOOP */ PACK( 1, 0 ),
865 /* RTG */ PACK( 0, 0 ),
866 /* RTHG */ PACK( 0, 0 ),
867 /* SMD */ PACK( 1, 0 ),
868 /* ELSE */ PACK( 0, 0 ),
869 /* JMPR */ PACK( 1, 0 ),
870 /* SCvTCi */ PACK( 1, 0 ),
871 /* SSwCi */ PACK( 1, 0 ),
872 /* SSW */ PACK( 1, 0 ),
873
874 /* DUP */ PACK( 1, 2 ),
875 /* POP */ PACK( 1, 0 ),
876 /* CLEAR */ PACK( 0, 0 ),
877 /* SWAP */ PACK( 2, 2 ),
878 /* DEPTH */ PACK( 0, 1 ),
879 /* CINDEX */ PACK( 1, 1 ),
880 /* MINDEX */ PACK( 1, 0 ),
881 /* AlignPTS */ PACK( 2, 0 ),
882 /* INS_$28 */ PACK( 0, 0 ),
883 /* UTP */ PACK( 1, 0 ),
884 /* LOOPCALL */ PACK( 2, 0 ),
885 /* CALL */ PACK( 1, 0 ),
886 /* FDEF */ PACK( 1, 0 ),
887 /* ENDF */ PACK( 0, 0 ),
888 /* MDAP[0] */ PACK( 1, 0 ),
889 /* MDAP[1] */ PACK( 1, 0 ),
890
891 /* IUP[0] */ PACK( 0, 0 ),
892 /* IUP[1] */ PACK( 0, 0 ),
893 /* SHP[0] */ PACK( 0, 0 ),
894 /* SHP[1] */ PACK( 0, 0 ),
895 /* SHC[0] */ PACK( 1, 0 ),
896 /* SHC[1] */ PACK( 1, 0 ),
897 /* SHZ[0] */ PACK( 1, 0 ),
898 /* SHZ[1] */ PACK( 1, 0 ),
899 /* SHPIX */ PACK( 1, 0 ),
900 /* IP */ PACK( 0, 0 ),
901 /* MSIRP[0] */ PACK( 2, 0 ),
902 /* MSIRP[1] */ PACK( 2, 0 ),
903 /* AlignRP */ PACK( 0, 0 ),
904 /* RTDG */ PACK( 0, 0 ),
905 /* MIAP[0] */ PACK( 2, 0 ),
906 /* MIAP[1] */ PACK( 2, 0 ),
907
908 /* NPushB */ PACK( 0, 0 ),
909 /* NPushW */ PACK( 0, 0 ),
910 /* WS */ PACK( 2, 0 ),
911 /* RS */ PACK( 1, 1 ),
912 /* WCvtP */ PACK( 2, 0 ),
913 /* RCvt */ PACK( 1, 1 ),
914 /* GC[0] */ PACK( 1, 1 ),
915 /* GC[1] */ PACK( 1, 1 ),
916 /* SCFS */ PACK( 2, 0 ),
917 /* MD[0] */ PACK( 2, 1 ),
918 /* MD[1] */ PACK( 2, 1 ),
919 /* MPPEM */ PACK( 0, 1 ),
920 /* MPS */ PACK( 0, 1 ),
921 /* FlipON */ PACK( 0, 0 ),
922 /* FlipOFF */ PACK( 0, 0 ),
923 /* DEBUG */ PACK( 1, 0 ),
924
925 /* LT */ PACK( 2, 1 ),
926 /* LTEQ */ PACK( 2, 1 ),
927 /* GT */ PACK( 2, 1 ),
928 /* GTEQ */ PACK( 2, 1 ),
929 /* EQ */ PACK( 2, 1 ),
930 /* NEQ */ PACK( 2, 1 ),
931 /* ODD */ PACK( 1, 1 ),
932 /* EVEN */ PACK( 1, 1 ),
933 /* IF */ PACK( 1, 0 ),
934 /* EIF */ PACK( 0, 0 ),
935 /* AND */ PACK( 2, 1 ),
936 /* OR */ PACK( 2, 1 ),
937 /* NOT */ PACK( 1, 1 ),
938 /* DeltaP1 */ PACK( 1, 0 ),
939 /* SDB */ PACK( 1, 0 ),
940 /* SDS */ PACK( 1, 0 ),
941
942 /* ADD */ PACK( 2, 1 ),
943 /* SUB */ PACK( 2, 1 ),
944 /* DIV */ PACK( 2, 1 ),
945 /* MUL */ PACK( 2, 1 ),
946 /* ABS */ PACK( 1, 1 ),
947 /* NEG */ PACK( 1, 1 ),
948 /* FLOOR */ PACK( 1, 1 ),
949 /* CEILING */ PACK( 1, 1 ),
950 /* ROUND[0] */ PACK( 1, 1 ),
951 /* ROUND[1] */ PACK( 1, 1 ),
952 /* ROUND[2] */ PACK( 1, 1 ),
953 /* ROUND[3] */ PACK( 1, 1 ),
954 /* NROUND[0] */ PACK( 1, 1 ),
955 /* NROUND[1] */ PACK( 1, 1 ),
956 /* NROUND[2] */ PACK( 1, 1 ),
957 /* NROUND[3] */ PACK( 1, 1 ),
958
959 /* WCvtF */ PACK( 2, 0 ),
960 /* DeltaP2 */ PACK( 1, 0 ),
961 /* DeltaP3 */ PACK( 1, 0 ),
962 /* DeltaCn[0] */ PACK( 1, 0 ),
963 /* DeltaCn[1] */ PACK( 1, 0 ),
964 /* DeltaCn[2] */ PACK( 1, 0 ),
965 /* SROUND */ PACK( 1, 0 ),
966 /* S45Round */ PACK( 1, 0 ),
967 /* JROT */ PACK( 2, 0 ),
968 /* JROF */ PACK( 2, 0 ),
969 /* ROFF */ PACK( 0, 0 ),
970 /* INS_$7B */ PACK( 0, 0 ),
971 /* RUTG */ PACK( 0, 0 ),
972 /* RDTG */ PACK( 0, 0 ),
973 /* SANGW */ PACK( 1, 0 ),
974 /* AA */ PACK( 1, 0 ),
975
976 /* FlipPT */ PACK( 0, 0 ),
977 /* FlipRgON */ PACK( 2, 0 ),
978 /* FlipRgOFF */ PACK( 2, 0 ),
979 /* INS_$83 */ PACK( 0, 0 ),
980 /* INS_$84 */ PACK( 0, 0 ),
981 /* ScanCTRL */ PACK( 1, 0 ),
982 /* SDVPTL[0] */ PACK( 2, 0 ),
983 /* SDVPTL[1] */ PACK( 2, 0 ),
984 /* GetINFO */ PACK( 1, 1 ),
985 /* IDEF */ PACK( 1, 0 ),
986 /* ROLL */ PACK( 3, 3 ),
987 /* MAX */ PACK( 2, 1 ),
988 /* MIN */ PACK( 2, 1 ),
989 /* ScanTYPE */ PACK( 1, 0 ),
990 /* InstCTRL */ PACK( 2, 0 ),
991 /* INS_$8F */ PACK( 0, 0 ),
992
993 /* INS_$90 */ PACK( 0, 0 ),
994 /* INS_$91 */ PACK( 0, 0 ),
995 /* INS_$92 */ PACK( 0, 0 ),
996 /* INS_$93 */ PACK( 0, 0 ),
997 /* INS_$94 */ PACK( 0, 0 ),
998 /* INS_$95 */ PACK( 0, 0 ),
999 /* INS_$96 */ PACK( 0, 0 ),
1000 /* INS_$97 */ PACK( 0, 0 ),
1001 /* INS_$98 */ PACK( 0, 0 ),
1002 /* INS_$99 */ PACK( 0, 0 ),
1003 /* INS_$9A */ PACK( 0, 0 ),
1004 /* INS_$9B */ PACK( 0, 0 ),
1005 /* INS_$9C */ PACK( 0, 0 ),
1006 /* INS_$9D */ PACK( 0, 0 ),
1007 /* INS_$9E */ PACK( 0, 0 ),
1008 /* INS_$9F */ PACK( 0, 0 ),
1009
1010 /* INS_$A0 */ PACK( 0, 0 ),
1011 /* INS_$A1 */ PACK( 0, 0 ),
1012 /* INS_$A2 */ PACK( 0, 0 ),
1013 /* INS_$A3 */ PACK( 0, 0 ),
1014 /* INS_$A4 */ PACK( 0, 0 ),
1015 /* INS_$A5 */ PACK( 0, 0 ),
1016 /* INS_$A6 */ PACK( 0, 0 ),
1017 /* INS_$A7 */ PACK( 0, 0 ),
1018 /* INS_$A8 */ PACK( 0, 0 ),
1019 /* INS_$A9 */ PACK( 0, 0 ),
1020 /* INS_$AA */ PACK( 0, 0 ),
1021 /* INS_$AB */ PACK( 0, 0 ),
1022 /* INS_$AC */ PACK( 0, 0 ),
1023 /* INS_$AD */ PACK( 0, 0 ),
1024 /* INS_$AE */ PACK( 0, 0 ),
1025 /* INS_$AF */ PACK( 0, 0 ),
1026
1027 /* PushB[0] */ PACK( 0, 1 ),
1028 /* PushB[1] */ PACK( 0, 2 ),
1029 /* PushB[2] */ PACK( 0, 3 ),
1030 /* PushB[3] */ PACK( 0, 4 ),
1031 /* PushB[4] */ PACK( 0, 5 ),
1032 /* PushB[5] */ PACK( 0, 6 ),
1033 /* PushB[6] */ PACK( 0, 7 ),
1034 /* PushB[7] */ PACK( 0, 8 ),
1035 /* PushW[0] */ PACK( 0, 1 ),
1036 /* PushW[1] */ PACK( 0, 2 ),
1037 /* PushW[2] */ PACK( 0, 3 ),
1038 /* PushW[3] */ PACK( 0, 4 ),
1039 /* PushW[4] */ PACK( 0, 5 ),
1040 /* PushW[5] */ PACK( 0, 6 ),
1041 /* PushW[6] */ PACK( 0, 7 ),
1042 /* PushW[7] */ PACK( 0, 8 ),
1043
1044 /* MDRP[00] */ PACK( 1, 0 ),
1045 /* MDRP[01] */ PACK( 1, 0 ),
1046 /* MDRP[02] */ PACK( 1, 0 ),
1047 /* MDRP[03] */ PACK( 1, 0 ),
1048 /* MDRP[04] */ PACK( 1, 0 ),
1049 /* MDRP[05] */ PACK( 1, 0 ),
1050 /* MDRP[06] */ PACK( 1, 0 ),
1051 /* MDRP[07] */ PACK( 1, 0 ),
1052 /* MDRP[08] */ PACK( 1, 0 ),
1053 /* MDRP[09] */ PACK( 1, 0 ),
1054 /* MDRP[10] */ PACK( 1, 0 ),
1055 /* MDRP[11] */ PACK( 1, 0 ),
1056 /* MDRP[12] */ PACK( 1, 0 ),
1057 /* MDRP[13] */ PACK( 1, 0 ),
1058 /* MDRP[14] */ PACK( 1, 0 ),
1059 /* MDRP[15] */ PACK( 1, 0 ),
1060
1061 /* MDRP[16] */ PACK( 1, 0 ),
1062 /* MDRP[17] */ PACK( 1, 0 ),
1063 /* MDRP[18] */ PACK( 1, 0 ),
1064 /* MDRP[19] */ PACK( 1, 0 ),
1065 /* MDRP[20] */ PACK( 1, 0 ),
1066 /* MDRP[21] */ PACK( 1, 0 ),
1067 /* MDRP[22] */ PACK( 1, 0 ),
1068 /* MDRP[23] */ PACK( 1, 0 ),
1069 /* MDRP[24] */ PACK( 1, 0 ),
1070 /* MDRP[25] */ PACK( 1, 0 ),
1071 /* MDRP[26] */ PACK( 1, 0 ),
1072 /* MDRP[27] */ PACK( 1, 0 ),
1073 /* MDRP[28] */ PACK( 1, 0 ),
1074 /* MDRP[29] */ PACK( 1, 0 ),
1075 /* MDRP[30] */ PACK( 1, 0 ),
1076 /* MDRP[31] */ PACK( 1, 0 ),
1077
1078 /* MIRP[00] */ PACK( 2, 0 ),
1079 /* MIRP[01] */ PACK( 2, 0 ),
1080 /* MIRP[02] */ PACK( 2, 0 ),
1081 /* MIRP[03] */ PACK( 2, 0 ),
1082 /* MIRP[04] */ PACK( 2, 0 ),
1083 /* MIRP[05] */ PACK( 2, 0 ),
1084 /* MIRP[06] */ PACK( 2, 0 ),
1085 /* MIRP[07] */ PACK( 2, 0 ),
1086 /* MIRP[08] */ PACK( 2, 0 ),
1087 /* MIRP[09] */ PACK( 2, 0 ),
1088 /* MIRP[10] */ PACK( 2, 0 ),
1089 /* MIRP[11] */ PACK( 2, 0 ),
1090 /* MIRP[12] */ PACK( 2, 0 ),
1091 /* MIRP[13] */ PACK( 2, 0 ),
1092 /* MIRP[14] */ PACK( 2, 0 ),
1093 /* MIRP[15] */ PACK( 2, 0 ),
1094
1095 /* MIRP[16] */ PACK( 2, 0 ),
1096 /* MIRP[17] */ PACK( 2, 0 ),
1097 /* MIRP[18] */ PACK( 2, 0 ),
1098 /* MIRP[19] */ PACK( 2, 0 ),
1099 /* MIRP[20] */ PACK( 2, 0 ),
1100 /* MIRP[21] */ PACK( 2, 0 ),
1101 /* MIRP[22] */ PACK( 2, 0 ),
1102 /* MIRP[23] */ PACK( 2, 0 ),
1103 /* MIRP[24] */ PACK( 2, 0 ),
1104 /* MIRP[25] */ PACK( 2, 0 ),
1105 /* MIRP[26] */ PACK( 2, 0 ),
1106 /* MIRP[27] */ PACK( 2, 0 ),
1107 /* MIRP[28] */ PACK( 2, 0 ),
1108 /* MIRP[29] */ PACK( 2, 0 ),
1109 /* MIRP[30] */ PACK( 2, 0 ),
1110 /* MIRP[31] */ PACK( 2, 0 )
1111 };
1112
1113
1114 static
1115 const FT_Char opcode_length[256] =
1116 {
1117 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1118 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1119 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1120 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1121
1122 -1,-2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1123 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1124 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1125 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1126
1127 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1128 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1129 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1130 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
1131
1132 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1133 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1134 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1135 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1136 };
1137
1138 #undef PACK
1139
1140 #if 1
1141
1142 static FT_Int32
1143 TT_MulFix14( FT_Int32 a,
1144 FT_Int b )
1145 {
1146 FT_Int32 sign;
1147 FT_UInt32 ah, al, mid, lo, hi;
1148
1149
1150 sign = a ^ b;
1151
1152 if ( a < 0 )
1153 a = -a;
1154 if ( b < 0 )
1155 b = -b;
1156
1157 ah = (FT_UInt32)( ( a >> 16 ) & 0xFFFFU );
1158 al = (FT_UInt32)( a & 0xFFFFU );
1159
1160 lo = al * b;
1161 mid = ah * b;
1162 hi = mid >> 16;
1163 mid = ( mid << 16 ) + ( 1 << 13 ); /* rounding */
1164 lo += mid;
1165 if ( lo < mid )
1166 hi += 1;
1167
1168 mid = ( lo >> 14 ) | ( hi << 18 );
1169
1170 return sign >= 0 ? (FT_Int32)mid : -(FT_Int32)mid;
1171 }
1172
1173 #else
1174
1175 /* compute (a*b)/2^14 with maximal accuracy and rounding */
1176 static FT_Int32
1177 TT_MulFix14( FT_Int32 a,
1178 FT_Int b )
1179 {
1180 FT_Int32 m, s, hi;
1181 FT_UInt32 l, lo;
1182
1183
1184 /* compute ax*bx as 64-bit value */
1185 l = (FT_UInt32)( ( a & 0xFFFFU ) * b );
1186 m = ( a >> 16 ) * b;
1187
1188 lo = l + (FT_UInt32)( m << 16 );
1189 hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l );
1190
1191 /* divide the result by 2^14 with rounding */
1192 s = hi >> 31;
1193 l = lo + (FT_UInt32)s;
1194 hi += s + ( l < lo );
1195 lo = l;
1196
1197 l = lo + 0x2000U;
1198 hi += l < lo;
1199
1200 return ( hi << 18 ) | ( l >> 14 );
1201 }
1202 #endif
1203
1204
1205 /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */
1206 static FT_Int32
1207 TT_DotFix14( FT_Int32 ax,
1208 FT_Int32 ay,
1209 FT_Int bx,
1210 FT_Int by )
1211 {
1212 FT_Int32 m, s, hi1, hi2, hi;
1213 FT_UInt32 l, lo1, lo2, lo;
1214
1215
1216 /* compute ax*bx as 64-bit value */
1217 l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );
1218 m = ( ax >> 16 ) * bx;
1219
1220 lo1 = l + (FT_UInt32)( m << 16 );
1221 hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l );
1222
1223 /* compute ay*by as 64-bit value */
1224 l = (FT_UInt32)( ( ay & 0xFFFFU ) * by );
1225 m = ( ay >> 16 ) * by;
1226
1227 lo2 = l + (FT_UInt32)( m << 16 );
1228 hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l );
1229
1230 /* add them */
1231 lo = lo1 + lo2;
1232 hi = hi1 + hi2 + ( lo < lo1 );
1233
1234 /* divide the result by 2^14 with rounding */
1235 s = hi >> 31;
1236 l = lo + (FT_UInt32)s;
1237 hi += s + ( l < lo );
1238 lo = l;
1239
1240 l = lo + 0x2000U;
1241 hi += ( l < lo );
1242
1243 return ( hi << 18 ) | ( l >> 14 );
1244 }
1245
1246
1247 /* return length of given vector */
1248
1249 #if 0
1250
1251 static FT_Int32
1252 TT_VecLen( FT_Int32 x,
1253 FT_Int32 y )
1254 {
1255 FT_Int32 m, hi1, hi2, hi;
1256 FT_UInt32 l, lo1, lo2, lo;
1257
1258
1259 /* compute x*x as 64-bit value */
1260 lo = (FT_UInt32)( x & 0xFFFFU );
1261 hi = x >> 16;
1262
1263 l = lo * lo;
1264 m = hi * lo;
1265 hi = hi * hi;
1266
1267 lo1 = l + (FT_UInt32)( m << 17 );
1268 hi1 = hi + ( m >> 15 ) + ( lo1 < l );
1269
1270 /* compute y*y as 64-bit value */
1271 lo = (FT_UInt32)( y & 0xFFFFU );
1272 hi = y >> 16;
1273
1274 l = lo * lo;
1275 m = hi * lo;
1276 hi = hi * hi;
1277
1278 lo2 = l + (FT_UInt32)( m << 17 );
1279 hi2 = hi + ( m >> 15 ) + ( lo2 < l );
1280
1281 /* add them to get 'x*x+y*y' as 64-bit value */
1282 lo = lo1 + lo2;
1283 hi = hi1 + hi2 + ( lo < lo1 );
1284
1285 /* compute the square root of this value */
1286 {
1287 FT_UInt32 root, rem, test_div;
1288 FT_Int count;
1289
1290
1291 root = 0;
1292
1293 {
1294 rem = 0;
1295 count = 32;
1296 do
1297 {
1298 rem = ( rem << 2 ) | ( (FT_UInt32)hi >> 30 );
1299 hi = ( hi << 2 ) | ( lo >> 30 );
1300 lo <<= 2;
1301 root <<= 1;
1302 test_div = ( root << 1 ) + 1;
1303
1304 if ( rem >= test_div )
1305 {
1306 rem -= test_div;
1307 root += 1;
1308 }
1309 } while ( --count );
1310 }
1311
1312 return (FT_Int32)root;
1313 }
1314 }
1315
1316 #else
1317
1318 /* this version uses FT_Vector_Length which computes the same value */
1319 /* much, much faster.. */
1320 /* */
1321 static FT_F26Dot6
1322 TT_VecLen( FT_F26Dot6 X,
1323 FT_F26Dot6 Y )
1324 {
1325 FT_Vector v;
1326
1327
1328 v.x = X;
1329 v.y = Y;
1330
1331 return FT_Vector_Length( &v );
1332 }
1333
1334 #endif
1335
1336
1337 /*************************************************************************/
1338 /* */
1339 /* <Function> */
1340 /* Current_Ratio */
1341 /* */
1342 /* <Description> */
1343 /* Returns the current aspect ratio scaling factor depending on the */
1344 /* projection vector's state and device resolutions. */
1345 /* */
1346 /* <Return> */
1347 /* The aspect ratio in 16.16 format, always <= 1.0 . */
1348 /* */
1349 static FT_Long
1350 Current_Ratio( EXEC_OP )
1351 {
1352 if ( !CUR.tt_metrics.ratio )
1353 {
1354 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1355 if ( CUR.face->unpatented_hinting )
1356 {
1357 if ( CUR.GS.both_x_axis )
1358 CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
1359 else
1360 CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
1361 }
1362 else
1363 #endif
1364 {
1365 if ( CUR.GS.projVector.y == 0 )
1366 CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
1367
1368 else if ( CUR.GS.projVector.x == 0 )
1369 CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
1370
1371 else
1372 {
1373 FT_Long x, y;
1374
1375
1376 x = TT_MULDIV( CUR.GS.projVector.x,
1377 CUR.tt_metrics.x_ratio, 0x4000 );
1378 y = TT_MULDIV( CUR.GS.projVector.y,
1379 CUR.tt_metrics.y_ratio, 0x4000 );
1380 CUR.tt_metrics.ratio = TT_VecLen( x, y );
1381 }
1382 }
1383 }
1384 return CUR.tt_metrics.ratio;
1385 }
1386
1387
1388 static FT_Long
1389 Current_Ppem( EXEC_OP )
1390 {
1391 return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );
1392 }
1393
1394
1395 /*************************************************************************/
1396 /* */
1397 /* Functions related to the control value table (CVT). */
1398 /* */
1399 /*************************************************************************/
1400
1401
1402 FT_CALLBACK_DEF( FT_F26Dot6 )
1403 Read_CVT( EXEC_OP_ FT_ULong idx )
1404 {
1405 return CUR.cvt[idx];
1406 }
1407
1408
1409 FT_CALLBACK_DEF( FT_F26Dot6 )
1410 Read_CVT_Stretched( EXEC_OP_ FT_ULong idx )
1411 {
1412 return TT_MULFIX( CUR.cvt[idx], CURRENT_Ratio() );
1413 }
1414
1415
1416 FT_CALLBACK_DEF( void )
1417 Write_CVT( EXEC_OP_ FT_ULong idx,
1418 FT_F26Dot6 value )
1419 {
1420 CUR.cvt[idx] = value;
1421 }
1422
1423
1424 FT_CALLBACK_DEF( void )
1425 Write_CVT_Stretched( EXEC_OP_ FT_ULong idx,
1426 FT_F26Dot6 value )
1427 {
1428 CUR.cvt[idx] = FT_DivFix( value, CURRENT_Ratio() );
1429 }
1430
1431
1432 FT_CALLBACK_DEF( void )
1433 Move_CVT( EXEC_OP_ FT_ULong idx,
1434 FT_F26Dot6 value )
1435 {
1436 CUR.cvt[idx] += value;
1437 }
1438
1439
1440 FT_CALLBACK_DEF( void )
1441 Move_CVT_Stretched( EXEC_OP_ FT_ULong idx,
1442 FT_F26Dot6 value )
1443 {
1444 CUR.cvt[idx] += FT_DivFix( value, CURRENT_Ratio() );
1445 }
1446
1447
1448 /*************************************************************************/
1449 /* */
1450 /* <Function> */
1451 /* GetShortIns */
1452 /* */
1453 /* <Description> */
1454 /* Returns a short integer taken from the instruction stream at */
1455 /* address IP. */
1456 /* */
1457 /* <Return> */
1458 /* Short read at code[IP]. */
1459 /* */
1460 /* <Note> */
1461 /* This one could become a macro. */
1462 /* */
1463 static FT_Short
1464 GetShortIns( EXEC_OP )
1465 {
1466 /* Reading a byte stream so there is no endianess (DaveP) */
1467 CUR.IP += 2;
1468 return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) +
1469 CUR.code[CUR.IP - 1] );
1470 }
1471
1472
1473 /*************************************************************************/
1474 /* */
1475 /* <Function> */
1476 /* Ins_Goto_CodeRange */
1477 /* */
1478 /* <Description> */
1479 /* Goes to a certain code range in the instruction stream. */
1480 /* */
1481 /* <Input> */
1482 /* aRange :: The index of the code range. */
1483 /* */
1484 /* aIP :: The new IP address in the code range. */
1485 /* */
1486 /* <Return> */
1487 /* SUCCESS or FAILURE. */
1488 /* */
1489 static FT_Bool
1490 Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange,
1491 FT_ULong aIP )
1492 {
1493 TT_CodeRange* range;
1494
1495
1496 if ( aRange < 1 || aRange > 3 )
1497 {
1498 CUR.error = TT_Err_Bad_Argument;
1499 return FAILURE;
1500 }
1501
1502 range = &CUR.codeRangeTable[aRange - 1];
1503
1504 if ( range->base == NULL ) /* invalid coderange */
1505 {
1506 CUR.error = TT_Err_Invalid_CodeRange;
1507 return FAILURE;
1508 }
1509
1510 /* NOTE: Because the last instruction of a program may be a CALL */
1511 /* which will return to the first byte *after* the code */
1512 /* range, we test for AIP <= Size, instead of AIP < Size. */
1513
1514 if ( aIP > range->size )
1515 {
1516 CUR.error = TT_Err_Code_Overflow;
1517 return FAILURE;
1518 }
1519
1520 CUR.code = range->base;
1521 CUR.codeSize = range->size;
1522 CUR.IP = aIP;
1523 CUR.curRange = aRange;
1524
1525 return SUCCESS;
1526 }
1527
1528
1529 /*************************************************************************/
1530 /* */
1531 /* <Function> */
1532 /* Direct_Move */
1533 /* */
1534 /* <Description> */
1535 /* Moves a point by a given distance along the freedom vector. The */
1536 /* point will be `touched'. */
1537 /* */
1538 /* <Input> */
1539 /* point :: The index of the point to move. */
1540 /* */
1541 /* distance :: The distance to apply. */
1542 /* */
1543 /* <InOut> */
1544 /* zone :: The affected glyph zone. */
1545 /* */
1546 static void
1547 Direct_Move( EXEC_OP_ TT_GlyphZone zone,
1548 FT_UShort point,
1549 FT_F26Dot6 distance )
1550 {
1551 FT_F26Dot6 v;
1552
1553
1554 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1555 FT_ASSERT( !CUR.face->unpatented_hinting );
1556 #endif
1557
1558 v = CUR.GS.freeVector.x;
1559
1560 if ( v != 0 )
1561 {
1562 zone->cur[point].x += TT_MULDIV( distance,
1563 v * 0x10000L,
1564 CUR.F_dot_P );
1565
1566 zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
1567 }
1568
1569 v = CUR.GS.freeVector.y;
1570
1571 if ( v != 0 )
1572 {
1573 zone->cur[point].y += TT_MULDIV( distance,
1574 v * 0x10000L,
1575 CUR.F_dot_P );
1576
1577 zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1578 }
1579 }
1580
1581
1582 /*************************************************************************/
1583 /* */
1584 /* <Function> */
1585 /* Direct_Move_Orig */
1586 /* */
1587 /* <Description> */
1588 /* Moves the *original* position of a point by a given distance along */
1589 /* the freedom vector. Obviously, the point will not be `touched'. */
1590 /* */
1591 /* <Input> */
1592 /* point :: The index of the point to move. */
1593 /* */
1594 /* distance :: The distance to apply. */
1595 /* */
1596 /* <InOut> */
1597 /* zone :: The affected glyph zone. */
1598 /* */
1599 static void
1600 Direct_Move_Orig( EXEC_OP_ TT_GlyphZone zone,
1601 FT_UShort point,
1602 FT_F26Dot6 distance )
1603 {
1604 FT_F26Dot6 v;
1605
1606
1607 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
1608 FT_ASSERT( !CUR.face->unpatented_hinting );
1609 #endif
1610
1611 v = CUR.GS.freeVector.x;
1612
1613 if ( v != 0 )
1614 zone->org[point].x += TT_MULDIV( distance,
1615 v * 0x10000L,
1616 CUR.F_dot_P );
1617
1618 v = CUR.GS.freeVector.y;
1619
1620 if ( v != 0 )
1621 zone->org[point].y += TT_MULDIV( distance,
1622 v * 0x10000L,
1623 CUR.F_dot_P );
1624 }
1625
1626
1627 /*************************************************************************/
1628 /* */
1629 /* Special versions of Direct_Move() */
1630 /* */
1631 /* The following versions are used whenever both vectors are both */
1632 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1633 /* */
1634 /*************************************************************************/
1635
1636
1637 static void
1638 Direct_Move_X( EXEC_OP_ TT_GlyphZone zone,
1639 FT_UShort point,
1640 FT_F26Dot6 distance )
1641 {
1642 FT_UNUSED_EXEC;
1643
1644 zone->cur[point].x += distance;
1645 zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
1646 }
1647
1648
1649 static void
1650 Direct_Move_Y( EXEC_OP_ TT_GlyphZone zone,
1651 FT_UShort point,
1652 FT_F26Dot6 distance )
1653 {
1654 FT_UNUSED_EXEC;
1655
1656 zone->cur[point].y += distance;
1657 zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
1658 }
1659
1660
1661 /*************************************************************************/
1662 /* */
1663 /* Special versions of Direct_Move_Orig() */
1664 /* */
1665 /* The following versions are used whenever both vectors are both */
1666 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
1667 /* */
1668 /*************************************************************************/
1669
1670
1671 static void
1672 Direct_Move_Orig_X( EXEC_OP_ TT_GlyphZone zone,
1673 FT_UShort point,
1674 FT_F26Dot6 distance )
1675 {
1676 FT_UNUSED_EXEC;
1677
1678 zone->org[point].x += distance;
1679 }
1680
1681
1682 static void
1683 Direct_Move_Orig_Y( EXEC_OP_ TT_GlyphZone zone,
1684 FT_UShort point,
1685 FT_F26Dot6 distance )
1686 {
1687 FT_UNUSED_EXEC;
1688
1689 zone->org[point].y += distance;
1690 }
1691
1692
1693 /*************************************************************************/
1694 /* */
1695 /* <Function> */
1696 /* Round_None */
1697 /* */
1698 /* <Description> */
1699 /* Does not round, but adds engine compensation. */
1700 /* */
1701 /* <Input> */
1702 /* distance :: The distance (not) to round. */
1703 /* */
1704 /* compensation :: The engine compensation. */
1705 /* */
1706 /* <Return> */
1707 /* The compensated distance. */
1708 /* */
1709 /* <Note> */
1710 /* The TrueType specification says very few about the relationship */
1711 /* between rounding and engine compensation. However, it seems from */
1712 /* the description of super round that we should add the compensation */
1713 /* before rounding. */
1714 /* */
1715 static FT_F26Dot6
1716 Round_None( EXEC_OP_ FT_F26Dot6 distance,
1717 FT_F26Dot6 compensation )
1718 {
1719 FT_F26Dot6 val;
1720
1721 FT_UNUSED_EXEC;
1722
1723
1724 if ( distance >= 0 )
1725 {
1726 val = distance + compensation;
1727 if ( distance && val < 0 )
1728 val = 0;
1729 }
1730 else {
1731 val = distance - compensation;
1732 if ( val > 0 )
1733 val = 0;
1734 }
1735 return val;
1736 }
1737
1738
1739 /*************************************************************************/
1740 /* */
1741 /* <Function> */
1742 /* Round_To_Grid */
1743 /* */
1744 /* <Description> */
1745 /* Rounds value to grid after adding engine compensation. */
1746 /* */
1747 /* <Input> */
1748 /* distance :: The distance to round. */
1749 /* */
1750 /* compensation :: The engine compensation. */
1751 /* */
1752 /* <Return> */
1753 /* Rounded distance. */
1754 /* */
1755 static FT_F26Dot6
1756 Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1757 FT_F26Dot6 compensation )
1758 {
1759 FT_F26Dot6 val;
1760
1761 FT_UNUSED_EXEC;
1762
1763
1764 if ( distance >= 0 )
1765 {
1766 val = distance + compensation + 32;
1767 if ( distance && val > 0 )
1768 val &= ~63;
1769 else
1770 val = 0;
1771 }
1772 else
1773 {
1774 val = -FT_PIX_ROUND( compensation - distance );
1775 if ( val > 0 )
1776 val = 0;
1777 }
1778
1779 return val;
1780 }
1781
1782
1783 /*************************************************************************/
1784 /* */
1785 /* <Function> */
1786 /* Round_To_Half_Grid */
1787 /* */
1788 /* <Description> */
1789 /* Rounds value to half grid after adding engine compensation. */
1790 /* */
1791 /* <Input> */
1792 /* distance :: The distance to round. */
1793 /* */
1794 /* compensation :: The engine compensation. */
1795 /* */
1796 /* <Return> */
1797 /* Rounded distance. */
1798 /* */
1799 static FT_F26Dot6
1800 Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance,
1801 FT_F26Dot6 compensation )
1802 {
1803 FT_F26Dot6 val;
1804
1805 FT_UNUSED_EXEC;
1806
1807
1808 if ( distance >= 0 )
1809 {
1810 val = FT_PIX_FLOOR( distance + compensation ) + 32;
1811 if ( distance && val < 0 )
1812 val = 0;
1813 }
1814 else
1815 {
1816 val = -( FT_PIX_FLOOR( compensation - distance ) + 32 );
1817 if ( val > 0 )
1818 val = 0;
1819 }
1820
1821 return val;
1822 }
1823
1824
1825 /*************************************************************************/
1826 /* */
1827 /* <Function> */
1828 /* Round_Down_To_Grid */
1829 /* */
1830 /* <Description> */
1831 /* Rounds value down to grid after adding engine compensation. */
1832 /* */
1833 /* <Input> */
1834 /* distance :: The distance to round. */
1835 /* */
1836 /* compensation :: The engine compensation. */
1837 /* */
1838 /* <Return> */
1839 /* Rounded distance. */
1840 /* */
1841 static FT_F26Dot6
1842 Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1843 FT_F26Dot6 compensation )
1844 {
1845 FT_F26Dot6 val;
1846
1847 FT_UNUSED_EXEC;
1848
1849
1850 if ( distance >= 0 )
1851 {
1852 val = distance + compensation;
1853 if ( distance && val > 0 )
1854 val &= ~63;
1855 else
1856 val = 0;
1857 }
1858 else
1859 {
1860 val = -( ( compensation - distance ) & -64 );
1861 if ( val > 0 )
1862 val = 0;
1863 }
1864
1865 return val;
1866 }
1867
1868
1869 /*************************************************************************/
1870 /* */
1871 /* <Function> */
1872 /* Round_Up_To_Grid */
1873 /* */
1874 /* <Description> */
1875 /* Rounds value up to grid after adding engine compensation. */
1876 /* */
1877 /* <Input> */
1878 /* distance :: The distance to round. */
1879 /* */
1880 /* compensation :: The engine compensation. */
1881 /* */
1882 /* <Return> */
1883 /* Rounded distance. */
1884 /* */
1885 static FT_F26Dot6
1886 Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1887 FT_F26Dot6 compensation )
1888 {
1889 FT_F26Dot6 val;
1890
1891 FT_UNUSED_EXEC;
1892
1893
1894 if ( distance >= 0 )
1895 {
1896 val = distance + compensation + 63;
1897 if ( distance && val > 0 )
1898 val &= ~63;
1899 else
1900 val = 0;
1901 }
1902 else
1903 {
1904 val = - FT_PIX_CEIL( compensation - distance );
1905 if ( val > 0 )
1906 val = 0;
1907 }
1908
1909 return val;
1910 }
1911
1912
1913 /*************************************************************************/
1914 /* */
1915 /* <Function> */
1916 /* Round_To_Double_Grid */
1917 /* */
1918 /* <Description> */
1919 /* Rounds value to double grid after adding engine compensation. */
1920 /* */
1921 /* <Input> */
1922 /* distance :: The distance to round. */
1923 /* */
1924 /* compensation :: The engine compensation. */
1925 /* */
1926 /* <Return> */
1927 /* Rounded distance. */
1928 /* */
1929 static FT_F26Dot6
1930 Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance,
1931 FT_F26Dot6 compensation )
1932 {
1933 FT_F26Dot6 val;
1934
1935 FT_UNUSED_EXEC;
1936
1937
1938 if ( distance >= 0 )
1939 {
1940 val = distance + compensation + 16;
1941 if ( distance && val > 0 )
1942 val &= ~31;
1943 else
1944 val = 0;
1945 }
1946 else
1947 {
1948 val = -FT_PAD_ROUND( compensation - distance, 32 );
1949 if ( val > 0 )
1950 val = 0;
1951 }
1952
1953 return val;
1954 }
1955
1956
1957 /*************************************************************************/
1958 /* */
1959 /* <Function> */
1960 /* Round_Super */
1961 /* */
1962 /* <Description> */
1963 /* Super-rounds value to grid after adding engine compensation. */
1964 /* */
1965 /* <Input> */
1966 /* distance :: The distance to round. */
1967 /* */
1968 /* compensation :: The engine compensation. */
1969 /* */
1970 /* <Return> */
1971 /* Rounded distance. */
1972 /* */
1973 /* <Note> */
1974 /* The TrueType specification says very few about the relationship */
1975 /* between rounding and engine compensation. However, it seems from */
1976 /* the description of super round that we should add the compensation */
1977 /* before rounding. */
1978 /* */
1979 static FT_F26Dot6
1980 Round_Super( EXEC_OP_ FT_F26Dot6 distance,
1981 FT_F26Dot6 compensation )
1982 {
1983 FT_F26Dot6 val;
1984
1985
1986 if ( distance >= 0 )
1987 {
1988 val = ( distance - CUR.phase + CUR.threshold + compensation ) &
1989 -CUR.period;
1990 if ( distance && val < 0 )
1991 val = 0;
1992 val += CUR.phase;
1993 }
1994 else
1995 {
1996 val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &
1997 -CUR.period );
1998 if ( val > 0 )
1999 val = 0;
2000 val -= CUR.phase;
2001 }
2002
2003 return val;
2004 }
2005
2006
2007 /*************************************************************************/
2008 /* */
2009 /* <Function> */
2010 /* Round_Super_45 */
2011 /* */
2012 /* <Description> */
2013 /* Super-rounds value to grid after adding engine compensation. */
2014 /* */
2015 /* <Input> */
2016 /* distance :: The distance to round. */
2017 /* */
2018 /* compensation :: The engine compensation. */
2019 /* */
2020 /* <Return> */
2021 /* Rounded distance. */
2022 /* */
2023 /* <Note> */
2024 /* There is a separate function for Round_Super_45() as we may need */
2025 /* greater precision. */
2026 /* */
2027 static FT_F26Dot6
2028 Round_Super_45( EXEC_OP_ FT_F26Dot6 distance,
2029 FT_F26Dot6 compensation )
2030 {
2031 FT_F26Dot6 val;
2032
2033
2034 if ( distance >= 0 )
2035 {
2036 val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
2037 CUR.period ) * CUR.period;
2038 if ( distance && val < 0 )
2039 val = 0;
2040 val += CUR.phase;
2041 }
2042 else
2043 {
2044 val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /
2045 CUR.period ) * CUR.period );
2046 if ( val > 0 )
2047 val = 0;
2048 val -= CUR.phase;
2049 }
2050
2051 return val;
2052 }
2053
2054
2055 /*************************************************************************/
2056 /* */
2057 /* <Function> */
2058 /* Compute_Round */
2059 /* */
2060 /* <Description> */
2061 /* Sets the rounding mode. */
2062 /* */
2063 /* <Input> */
2064 /* round_mode :: The rounding mode to be used. */
2065 /* */
2066 static void
2067 Compute_Round( EXEC_OP_ FT_Byte round_mode )
2068 {
2069 switch ( round_mode )
2070 {
2071 case TT_Round_Off:
2072 CUR.func_round = (TT_Round_Func)Round_None;
2073 break;
2074
2075 case TT_Round_To_Grid:
2076 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2077 break;
2078
2079 case TT_Round_Up_To_Grid:
2080 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2081 break;
2082
2083 case TT_Round_Down_To_Grid:
2084 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2085 break;
2086
2087 case TT_Round_To_Half_Grid:
2088 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2089 break;
2090
2091 case TT_Round_To_Double_Grid:
2092 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2093 break;
2094
2095 case TT_Round_Super:
2096 CUR.func_round = (TT_Round_Func)Round_Super;
2097 break;
2098
2099 case TT_Round_Super_45:
2100 CUR.func_round = (TT_Round_Func)Round_Super_45;
2101 break;
2102 }
2103 }
2104
2105
2106 /*************************************************************************/
2107 /* */
2108 /* <Function> */
2109 /* SetSuperRound */
2110 /* */
2111 /* <Description> */
2112 /* Sets Super Round parameters. */
2113 /* */
2114 /* <Input> */
2115 /* GridPeriod :: Grid period */
2116 /* selector :: SROUND opcode */
2117 /* */
2118 static void
2119 SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod,
2120 FT_Long selector )
2121 {
2122 switch ( (FT_Int)( selector & 0xC0 ) )
2123 {
2124 case 0:
2125 CUR.period = GridPeriod / 2;
2126 break;
2127
2128 case 0x40:
2129 CUR.period = GridPeriod;
2130 break;
2131
2132 case 0x80:
2133 CUR.period = GridPeriod * 2;
2134 break;
2135
2136 /* This opcode is reserved, but... */
2137
2138 case 0xC0:
2139 CUR.period = GridPeriod;
2140 break;
2141 }
2142
2143 switch ( (FT_Int)( selector & 0x30 ) )
2144 {
2145 case 0:
2146 CUR.phase = 0;
2147 break;
2148
2149 case 0x10:
2150 CUR.phase = CUR.period / 4;
2151 break;
2152
2153 case 0x20:
2154 CUR.phase = CUR.period / 2;
2155 break;
2156
2157 case 0x30:
2158 CUR.phase = CUR.period * 3 / 4;
2159 break;
2160 }
2161
2162 if ( ( selector & 0x0F ) == 0 )
2163 CUR.threshold = CUR.period - 1;
2164 else
2165 CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8;
2166
2167 CUR.period /= 256;
2168 CUR.phase /= 256;
2169 CUR.threshold /= 256;
2170 }
2171
2172
2173 /*************************************************************************/
2174 /* */
2175 /* <Function> */
2176 /* Project */
2177 /* */
2178 /* <Description> */
2179 /* Computes the projection of vector given by (v2-v1) along the */
2180 /* current projection vector. */
2181 /* */
2182 /* <Input> */
2183 /* v1 :: First input vector. */
2184 /* v2 :: Second input vector. */
2185 /* */
2186 /* <Return> */
2187 /* The distance in F26dot6 format. */
2188 /* */
2189 static FT_F26Dot6
2190 Project( EXEC_OP_ FT_Pos dx,
2191 FT_Pos dy )
2192 {
2193 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2194 FT_ASSERT( !CUR.face->unpatented_hinting );
2195 #endif
2196
2197 return TT_DotFix14( (FT_UInt32)dx, (FT_UInt32)dy,
2198 CUR.GS.projVector.x,
2199 CUR.GS.projVector.y );
2200 }
2201
2202
2203 /*************************************************************************/
2204 /* */
2205 /* <Function> */
2206 /* Dual_Project */
2207 /* */
2208 /* <Description> */
2209 /* Computes the projection of the vector given by (v2-v1) along the */
2210 /* current dual vector. */
2211 /* */
2212 /* <Input> */
2213 /* v1 :: First input vector. */
2214 /* v2 :: Second input vector. */
2215 /* */
2216 /* <Return> */
2217 /* The distance in F26dot6 format. */
2218 /* */
2219 static FT_F26Dot6
2220 Dual_Project( EXEC_OP_ FT_Pos dx,
2221 FT_Pos dy )
2222 {
2223 return TT_DotFix14( (FT_UInt32)dx, (FT_UInt32)dy,
2224 CUR.GS.dualVector.x,
2225 CUR.GS.dualVector.y );
2226 }
2227
2228
2229 /*************************************************************************/
2230 /* */
2231 /* <Function> */
2232 /* Project_x */
2233 /* */
2234 /* <Description> */
2235 /* Computes the projection of the vector given by (v2-v1) along the */
2236 /* horizontal axis. */
2237 /* */
2238 /* <Input> */
2239 /* v1 :: First input vector. */
2240 /* v2 :: Second input vector. */
2241 /* */
2242 /* <Return> */
2243 /* The distance in F26dot6 format. */
2244 /* */
2245 static FT_F26Dot6
2246 Project_x( EXEC_OP_ FT_Pos dx,
2247 FT_Pos dy )
2248 {
2249 FT_UNUSED_EXEC;
2250 FT_UNUSED( dy );
2251
2252 return dx;
2253 }
2254
2255
2256 /*************************************************************************/
2257 /* */
2258 /* <Function> */
2259 /* Project_y */
2260 /* */
2261 /* <Description> */
2262 /* Computes the projection of the vector given by (v2-v1) along the */
2263 /* vertical axis. */
2264 /* */
2265 /* <Input> */
2266 /* v1 :: First input vector. */
2267 /* v2 :: Second input vector. */
2268 /* */
2269 /* <Return> */
2270 /* The distance in F26dot6 format. */
2271 /* */
2272 static FT_F26Dot6
2273 Project_y( EXEC_OP_ FT_Pos dx,
2274 FT_Pos dy )
2275 {
2276 FT_UNUSED_EXEC;
2277 FT_UNUSED( dx );
2278
2279 return dy;
2280 }
2281
2282
2283 /*************************************************************************/
2284 /* */
2285 /* <Function> */
2286 /* Compute_Funcs */
2287 /* */
2288 /* <Description> */
2289 /* Computes the projection and movement function pointers according */
2290 /* to the current graphics state. */
2291 /* */
2292 static void
2293 Compute_Funcs( EXEC_OP )
2294 {
2295 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2296 if ( CUR.face->unpatented_hinting )
2297 {
2298 /* If both vectors point rightwards along the x axis, set */
2299 /* `both-x-axis' true, otherwise set it false. The x values only */
2300 /* need be tested because the vector has been normalised to a unit */
2301 /* vector of length 0x4000 = unity. */
2302 CUR.GS.both_x_axis = (FT_Bool)( CUR.GS.projVector.x == 0x4000 &&
2303 CUR.GS.freeVector.x == 0x4000 );
2304
2305 /* Throw away projection and freedom vector information */
2306 /* because the patents don't allow them to be stored. */
2307 /* The relevant US Patents are 5155805 and 5325479. */
2308 CUR.GS.projVector.x = 0;
2309 CUR.GS.projVector.y = 0;
2310 CUR.GS.freeVector.x = 0;
2311 CUR.GS.freeVector.y = 0;
2312
2313 if ( CUR.GS.both_x_axis )
2314 {
2315 CUR.func_project = Project_x;
2316 CUR.func_move = Direct_Move_X;
2317 CUR.func_move_orig = Direct_Move_Orig_X;
2318 }
2319 else
2320 {
2321 CUR.func_project = Project_y;
2322 CUR.func_move = Direct_Move_Y;
2323 CUR.func_move_orig = Direct_Move_Orig_Y;
2324 }
2325
2326 if ( CUR.GS.dualVector.x == 0x4000 )
2327 CUR.func_dualproj = Project_x;
2328 else
2329 {
2330 if ( CUR.GS.dualVector.y == 0x4000 )
2331 CUR.func_dualproj = Project_y;
2332 else
2333 CUR.func_dualproj = Dual_Project;
2334 }
2335
2336 /* Force recalculation of cached aspect ratio */
2337 CUR.tt_metrics.ratio = 0;
2338
2339 return;
2340 }
2341 #endif /* TT_CONFIG_OPTION_UNPATENTED_HINTING */
2342
2343 if ( CUR.GS.freeVector.x == 0x4000 )
2344 CUR.F_dot_P = CUR.GS.projVector.x * 0x10000L;
2345 else
2346 {
2347 if ( CUR.GS.freeVector.y == 0x4000 )
2348 CUR.F_dot_P = CUR.GS.projVector.y * 0x10000L;
2349 else
2350 CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
2351 (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
2352 }
2353
2354 if ( CUR.GS.projVector.x == 0x4000 )
2355 CUR.func_project = (TT_Project_Func)Project_x;
2356 else
2357 {
2358 if ( CUR.GS.projVector.y == 0x4000 )
2359 CUR.func_project = (TT_Project_Func)Project_y;
2360 else
2361 CUR.func_project = (TT_Project_Func)Project;
2362 }
2363
2364 if ( CUR.GS.dualVector.x == 0x4000 )
2365 CUR.func_dualproj = (TT_Project_Func)Project_x;
2366 else
2367 {
2368 if ( CUR.GS.dualVector.y == 0x4000 )
2369 CUR.func_dualproj = (TT_Project_Func)Project_y;
2370 else
2371 CUR.func_dualproj = (TT_Project_Func)Dual_Project;
2372 }
2373
2374 CUR.func_move = (TT_Move_Func)Direct_Move;
2375 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig;
2376
2377 if ( CUR.F_dot_P == 0x40000000L )
2378 {
2379 if ( CUR.GS.freeVector.x == 0x4000 )
2380 {
2381 CUR.func_move = (TT_Move_Func)Direct_Move_X;
2382 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_X;
2383 }
2384 else
2385 {
2386 if ( CUR.GS.freeVector.y == 0x4000 )
2387 {
2388 CUR.func_move = (TT_Move_Func)Direct_Move_Y;
2389 CUR.func_move_orig = (TT_Move_Func)Direct_Move_Orig_Y;
2390 }
2391 }
2392 }
2393
2394 /* at small sizes, F_dot_P can become too small, resulting */
2395 /* in overflows and `spikes' in a number of glyphs like `w'. */
2396
2397 if ( FT_ABS( CUR.F_dot_P ) < 0x4000000L )
2398 CUR.F_dot_P = 0x40000000L;
2399
2400 /* Disable cached aspect ratio */
2401 CUR.tt_metrics.ratio = 0;
2402 }
2403
2404
2405 /*************************************************************************/
2406 /* */
2407 /* <Function> */
2408 /* Normalize */
2409 /* */
2410 /* <Description> */
2411 /* Norms a vector. */
2412 /* */
2413 /* <Input> */
2414 /* Vx :: The horizontal input vector coordinate. */
2415 /* Vy :: The vertical input vector coordinate. */
2416 /* */
2417 /* <Output> */
2418 /* R :: The normed unit vector. */
2419 /* */
2420 /* <Return> */
2421 /* Returns FAILURE if a vector parameter is zero. */
2422 /* */
2423 /* <Note> */
2424 /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
2425 /* R is undefined. */
2426 /* */
2427
2428
2429 static FT_Bool
2430 Normalize( EXEC_OP_ FT_F26Dot6 Vx,
2431 FT_F26Dot6 Vy,
2432 FT_UnitVector* R )
2433 {
2434 FT_F26Dot6 W;
2435 FT_Bool S1, S2;
2436
2437 FT_UNUSED_EXEC;
2438
2439
2440 if ( FT_ABS( Vx ) < 0x10000L && FT_ABS( Vy ) < 0x10000L )
2441 {
2442 Vx *= 0x100;
2443 Vy *= 0x100;
2444
2445 W = TT_VecLen( Vx, Vy );
2446
2447 if ( W == 0 )
2448 {
2449 /* XXX: UNDOCUMENTED! It seems that it is possible to try */
2450 /* to normalize the vector (0,0). Return immediately. */
2451 return SUCCESS;
2452 }
2453
2454 R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W );
2455 R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W );
2456
2457 return SUCCESS;
2458 }
2459
2460 W = TT_VecLen( Vx, Vy );
2461
2462 Vx = FT_MulDiv( Vx, 0x4000L, W );
2463 Vy = FT_MulDiv( Vy, 0x4000L, W );
2464
2465 W = Vx * Vx + Vy * Vy;
2466
2467 /* Now, we want that Sqrt( W ) = 0x4000 */
2468 /* Or 0x10000000 <= W < 0x10004000 */
2469
2470 if ( Vx < 0 )
2471 {
2472 Vx = -Vx;
2473 S1 = TRUE;
2474 }
2475 else
2476 S1 = FALSE;
2477
2478 if ( Vy < 0 )
2479 {
2480 Vy = -Vy;
2481 S2 = TRUE;
2482 }
2483 else
2484 S2 = FALSE;
2485
2486 while ( W < 0x10000000L )
2487 {
2488 /* We need to increase W by a minimal amount */
2489 if ( Vx < Vy )
2490 Vx++;
2491 else
2492 Vy++;
2493
2494 W = Vx * Vx + Vy * Vy;
2495 }
2496
2497 while ( W >= 0x10004000L )
2498 {
2499 /* We need to decrease W by a minimal amount */
2500 if ( Vx < Vy )
2501 Vx--;
2502 else
2503 Vy--;
2504
2505 W = Vx * Vx + Vy * Vy;
2506 }
2507
2508 /* Note that in various cases, we can only */
2509 /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
2510
2511 if ( S1 )
2512 Vx = -Vx;
2513
2514 if ( S2 )
2515 Vy = -Vy;
2516
2517 R->x = (FT_F2Dot14)Vx; /* Type conversion */
2518 R->y = (FT_F2Dot14)Vy; /* Type conversion */
2519
2520 return SUCCESS;
2521 }
2522
2523
2524 /*************************************************************************/
2525 /* */
2526 /* Here we start with the implementation of the various opcodes. */
2527 /* */
2528 /*************************************************************************/
2529
2530
2531 static FT_Bool
2532 Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1,
2533 FT_UShort aIdx2,
2534 FT_Int aOpc,
2535 FT_UnitVector* Vec )
2536 {
2537 FT_Long A, B, C;
2538 FT_Vector* p1;
2539 FT_Vector* p2;
2540
2541
2542 if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
2543 BOUNDS( aIdx2, CUR.zp1.n_points ) )
2544 {
2545 if ( CUR.pedantic_hinting )
2546 CUR.error = TT_Err_Invalid_Reference;
2547 return FAILURE;
2548 }
2549
2550 p1 = CUR.zp1.cur + aIdx2;
2551 p2 = CUR.zp2.cur + aIdx1;
2552
2553 A = p1->x - p2->x;
2554 B = p1->y - p2->y;
2555
2556 if ( ( aOpc & 1 ) != 0 )
2557 {
2558 C = B; /* counter clockwise rotation */
2559 B = A;
2560 A = -C;
2561 }
2562
2563 NORMalize( A, B, Vec );
2564
2565 return SUCCESS;
2566 }
2567
2568
2569 /* When not using the big switch statements, the interpreter uses a */
2570 /* call table defined later below in this source. Each opcode must */
2571 /* thus have a corresponding function, even trivial ones. */
2572 /* */
2573 /* They are all defined there. */
2574
2575 #define DO_SVTCA \
2576 { \
2577 FT_Short A, B; \
2578 \
2579 \
2580 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2581 B = A ^ (FT_Short)0x4000; \
2582 \
2583 CUR.GS.freeVector.x = A; \
2584 CUR.GS.projVector.x = A; \
2585 CUR.GS.dualVector.x = A; \
2586 \
2587 CUR.GS.freeVector.y = B; \
2588 CUR.GS.projVector.y = B; \
2589 CUR.GS.dualVector.y = B; \
2590 \
2591 COMPUTE_Funcs(); \
2592 }
2593
2594
2595 #define DO_SPVTCA \
2596 { \
2597 FT_Short A, B; \
2598 \
2599 \
2600 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2601 B = A ^ (FT_Short)0x4000; \
2602 \
2603 CUR.GS.projVector.x = A; \
2604 CUR.GS.dualVector.x = A; \
2605 \
2606 CUR.GS.projVector.y = B; \
2607 CUR.GS.dualVector.y = B; \
2608 \
2609 GUESS_VECTOR( freeVector ); \
2610 \
2611 COMPUTE_Funcs(); \
2612 }
2613
2614
2615 #define DO_SFVTCA \
2616 { \
2617 FT_Short A, B; \
2618 \
2619 \
2620 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2621 B = A ^ (FT_Short)0x4000; \
2622 \
2623 CUR.GS.freeVector.x = A; \
2624 CUR.GS.freeVector.y = B; \
2625 \
2626 GUESS_VECTOR( projVector ); \
2627 \
2628 COMPUTE_Funcs(); \
2629 }
2630
2631
2632 #define DO_SPVTL \
2633 if ( INS_SxVTL( (FT_UShort)args[1], \
2634 (FT_UShort)args[0], \
2635 CUR.opcode, \
2636 &CUR.GS.projVector ) == SUCCESS ) \
2637 { \
2638 CUR.GS.dualVector = CUR.GS.projVector; \
2639 GUESS_VECTOR( freeVector ); \
2640 COMPUTE_Funcs(); \
2641 }
2642
2643
2644 #define DO_SFVTL \
2645 if ( INS_SxVTL( (FT_UShort)args[1], \
2646 (FT_UShort)args[0], \
2647 CUR.opcode, \
2648 &CUR.GS.freeVector ) == SUCCESS ) \
2649 { \
2650 GUESS_VECTOR( projVector ); \
2651 COMPUTE_Funcs(); \
2652 }
2653
2654
2655 #define DO_SFVTPV \
2656 GUESS_VECTOR( projVector ); \
2657 CUR.GS.freeVector = CUR.GS.projVector; \
2658 COMPUTE_Funcs();
2659
2660
2661 #define DO_SPVFS \
2662 { \
2663 FT_Short S; \
2664 FT_Long X, Y; \
2665 \
2666 \
2667 /* Only use low 16bits, then sign extend */ \
2668 S = (FT_Short)args[1]; \
2669 Y = (FT_Long)S; \
2670 S = (FT_Short)args[0]; \
2671 X = (FT_Long)S; \
2672 \
2673 NORMalize( X, Y, &CUR.GS.projVector ); \
2674 \
2675 CUR.GS.dualVector = CUR.GS.projVector; \
2676 GUESS_VECTOR( freeVector ); \
2677 COMPUTE_Funcs(); \
2678 }
2679
2680
2681 #define DO_SFVFS \
2682 { \
2683 FT_Short S; \
2684 FT_Long X, Y; \
2685 \
2686 \
2687 /* Only use low 16bits, then sign extend */ \
2688 S = (FT_Short)args[1]; \
2689 Y = (FT_Long)S; \
2690 S = (FT_Short)args[0]; \
2691 X = S; \
2692 \
2693 NORMalize( X, Y, &CUR.GS.freeVector ); \
2694 GUESS_VECTOR( projVector ); \
2695 COMPUTE_Funcs(); \
2696 }
2697
2698
2699 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2700 #define DO_GPV \
2701 if ( CUR.face->unpatented_hinting ) \
2702 { \
2703 args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
2704 args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
2705 } \
2706 else \
2707 { \
2708 args[0] = CUR.GS.projVector.x; \
2709 args[1] = CUR.GS.projVector.y; \
2710 }
2711 #else
2712 #define DO_GPV \
2713 args[0] = CUR.GS.projVector.x; \
2714 args[1] = CUR.GS.projVector.y;
2715 #endif
2716
2717
2718 #ifdef TT_CONFIG_OPTION_UNPATENTED_HINTING
2719 #define DO_GFV \
2720 if ( CUR.face->unpatented_hinting ) \
2721 { \
2722 args[0] = CUR.GS.both_x_axis ? 0x4000 : 0; \
2723 args[1] = CUR.GS.both_x_axis ? 0 : 0x4000; \
2724 } \
2725 else \
2726 { \
2727 args[0] = CUR.GS.freeVector.x; \
2728 args[1] = CUR.GS.freeVector.y; \
2729 }
2730 #else
2731 #define DO_GFV \
2732 args[0] = CUR.GS.freeVector.x; \
2733 args[1] = CUR.GS.freeVector.y;
2734 #endif
2735
2736
2737 #define DO_SRP0 \
2738 CUR.GS.rp0 = (FT_UShort)args[0];
2739
2740
2741 #define DO_SRP1 \
2742 CUR.GS.rp1 = (FT_UShort)args[0];
2743
2744
2745 #define DO_SRP2 \
2746 CUR.GS.rp2 = (FT_UShort)args[0];
2747
2748
2749 #define DO_RTHG \
2750 CUR.GS.round_state = TT_Round_To_Half_Grid; \
2751 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2752
2753
2754 #define DO_RTG \
2755 CUR.GS.round_state = TT_Round_To_Grid; \
2756 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2757
2758
2759 #define DO_RTDG \
2760 CUR.GS.round_state = TT_Round_To_Double_Grid; \
2761 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2762
2763
2764 #define DO_RUTG \
2765 CUR.GS.round_state = TT_Round_Up_To_Grid; \
2766 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2767
2768
2769 #define DO_RDTG \
2770 CUR.GS.round_state = TT_Round_Down_To_Grid; \
2771 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2772
2773
2774 #define DO_ROFF \
2775 CUR.GS.round_state = TT_Round_Off; \
2776 CUR.func_round = (TT_Round_Func)Round_None;
2777
2778
2779 #define DO_SROUND \
2780 SET_SuperRound( 0x4000, args[0] ); \
2781 CUR.GS.round_state = TT_Round_Super; \
2782 CUR.func_round = (TT_Round_Func)Round_Super;
2783
2784
2785 #define DO_S45ROUND \
2786 SET_SuperRound( 0x2D41, args[0] ); \
2787 CUR.GS.round_state = TT_Round_Super_45; \
2788 CUR.func_round = (TT_Round_Func)Round_Super_45;
2789
2790
2791 #define DO_SLOOP \
2792 if ( args[0] < 0 ) \
2793 CUR.error = TT_Err_Bad_Argument; \
2794 else \
2795 CUR.GS.loop = args[0];
2796
2797
2798 #define DO_SMD \
2799 CUR.GS.minimum_distance = args[0];
2800
2801
2802 #define DO_SCVTCI \
2803 CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
2804
2805
2806 #define DO_SSWCI \
2807 CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
2808
2809
2810 /* XXX: UNDOCUMENTED! or bug in the Windows engine? */
2811 /* */
2812 /* It seems that the value that is read here is */
2813 /* expressed in 16.16 format rather than in font */
2814 /* units. */
2815 /* */
2816 #define DO_SSW \
2817 CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
2818
2819
2820 #define DO_FLIPON \
2821 CUR.GS.auto_flip = TRUE;
2822
2823
2824 #define DO_FLIPOFF \
2825 CUR.GS.auto_flip = FALSE;
2826
2827
2828 #define DO_SDB \
2829 CUR.GS.delta_base = (FT_Short)args[0];
2830
2831
2832 #define DO_SDS \
2833 CUR.GS.delta_shift = (FT_Short)args[0];
2834
2835
2836 #define DO_MD /* nothing */
2837
2838
2839 #define DO_MPPEM \
2840 args[0] = CURRENT_Ppem();
2841
2842
2843 /* Note: The pointSize should be irrelevant in a given font program; */
2844 /* we thus decide to return only the ppem. */
2845 #if 0
2846
2847 #define DO_MPS \
2848 args[0] = CUR.metrics.pointSize;
2849
2850 #else
2851
2852 #define DO_MPS \
2853 args[0] = CURRENT_Ppem();
2854
2855 #endif /* 0 */
2856
2857
2858 #define DO_DUP \
2859 args[1] = args[0];
2860
2861
2862 #define DO_CLEAR \
2863 CUR.new_top = 0;
2864
2865
2866 #define DO_SWAP \
2867 { \
2868 FT_Long L; \
2869 \
2870 \
2871 L = args[0]; \
2872 args[0] = args[1]; \
2873 args[1] = L; \
2874 }
2875
2876
2877 #define DO_DEPTH \
2878 args[0] = CUR.top;
2879
2880
2881 #define DO_CINDEX \
2882 { \
2883 FT_Long L; \
2884 \
2885 \
2886 L = args[0]; \
2887 \
2888 if ( L <= 0 || L > CUR.args ) \
2889 CUR.error = TT_Err_Invalid_Reference; \
2890 else \
2891 args[0] = CUR.stack[CUR.args - L]; \
2892 }
2893
2894
2895 #define DO_JROT \
2896 if ( args[1] != 0 ) \
2897 { \
2898 CUR.IP += args[0]; \
2899 CUR.step_ins = FALSE; \
2900 }
2901
2902
2903 #define DO_JMPR \
2904 CUR.IP += args[0]; \
2905 CUR.step_ins = FALSE;
2906
2907
2908 #define DO_JROF \
2909 if ( args[1] == 0 ) \
2910 { \
2911 CUR.IP += args[0]; \
2912 CUR.step_ins = FALSE; \
2913 }
2914
2915
2916 #define DO_LT \
2917 args[0] = ( args[0] < args[1] );
2918
2919
2920 #define DO_LTEQ \
2921 args[0] = ( args[0] <= args[1] );
2922
2923
2924 #define DO_GT \
2925 args[0] = ( args[0] > args[1] );
2926
2927
2928 #define DO_GTEQ \
2929 args[0] = ( args[0] >= args[1] );
2930
2931
2932 #define DO_EQ \
2933 args[0] = ( args[0] == args[1] );
2934
2935
2936 #define DO_NEQ \
2937 args[0] = ( args[0] != args[1] );
2938
2939
2940 #define DO_ODD \
2941 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
2942
2943
2944 #define DO_EVEN \
2945 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
2946
2947
2948 #define DO_AND \
2949 args[0] = ( args[0] && args[1] );
2950
2951
2952 #define DO_OR \
2953 args[0] = ( args[0] || args[1] );
2954
2955
2956 #define DO_NOT \
2957 args[0] = !args[0];
2958
2959
2960 #define DO_ADD \
2961 args[0] += args[1];
2962
2963
2964 #define DO_SUB \
2965 args[0] -= args[1];
2966
2967
2968 #define DO_DIV \
2969 if ( args[1] == 0 ) \
2970 CUR.error = TT_Err_Divide_By_Zero; \
2971 else \
2972 args[0] = TT_MULDIV_NO_ROUND( args[0], 64L, args[1] );
2973
2974
2975 #define DO_MUL \
2976 args[0] = TT_MULDIV( args[0], args[1], 64L );
2977
2978
2979 #define DO_ABS \
2980 args[0] = FT_ABS( args[0] );
2981
2982
2983 #define DO_NEG \
2984 args[0] = -args[0];
2985
2986
2987 #define DO_FLOOR \
2988 args[0] = FT_PIX_FLOOR( args[0] );
2989
2990
2991 #define DO_CEILING \
2992 args[0] = FT_PIX_CEIL( args[0] );
2993
2994
2995 #define DO_RS \
2996 { \
2997 FT_ULong I = (FT_ULong)args[0]; \
2998 \
2999 \
3000 if ( BOUNDS( I, CUR.storeSize ) ) \
3001 { \
3002 if ( CUR.pedantic_hinting ) \
3003 { \
3004 ARRAY_BOUND_ERROR; \
3005 } \
3006 else \
3007 args[0] = 0; \
3008 } \
3009 else \
3010 args[0] = CUR.storage[I]; \
3011 }
3012
3013
3014 #define DO_WS \
3015 { \
3016 FT_ULong I = (FT_ULong)args[0]; \
3017 \
3018 \
3019 if ( BOUNDS( I, CUR.storeSize ) ) \
3020 { \
3021 if ( CUR.pedantic_hinting ) \
3022 { \
3023 ARRAY_BOUND_ERROR; \
3024 } \
3025 } \
3026 else \
3027 CUR.storage[I] = args[1]; \
3028 }
3029
3030
3031 #define DO_RCVT \
3032 { \
3033 FT_ULong I = (FT_ULong)args[0]; \
3034 \
3035 \
3036 if ( BOUNDS( I, CUR.cvtSize ) ) \
3037 { \
3038 if ( CUR.pedantic_hinting ) \
3039 { \
3040 ARRAY_BOUND_ERROR; \
3041 } \
3042 else \
3043 args[0] = 0; \
3044 } \
3045 else \
3046 args[0] = CUR_Func_read_cvt( I ); \
3047 }
3048
3049
3050 #define DO_WCVTP \
3051 { \
3052 FT_ULong I = (FT_ULong)args[0]; \
3053 \
3054 \
3055 if ( BOUNDS( I, CUR.cvtSize ) ) \
3056 { \
3057 if ( CUR.pedantic_hinting ) \
3058 { \
3059 ARRAY_BOUND_ERROR; \
3060 } \
3061 } \
3062 else \
3063 CUR_Func_write_cvt( I, args[1] ); \
3064 }
3065
3066
3067 #define DO_WCVTF \
3068 { \
3069 FT_ULong I = (FT_ULong)args[0]; \
3070 \
3071 \
3072 if ( BOUNDS( I, CUR.cvtSize ) ) \
3073 { \
3074 if ( CUR.pedantic_hinting ) \
3075 { \
3076 ARRAY_BOUND_ERROR; \
3077 } \
3078 } \
3079 else \
3080 CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
3081 }
3082
3083
3084 #define DO_DEBUG \
3085 CUR.error = TT_Err_Debug_OpCode;
3086
3087
3088 #define DO_ROUND \
3089 args[0] = CUR_Func_round( \
3090 args[0], \
3091 CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
3092
3093
3094 #define DO_NROUND \
3095 args[0] = ROUND_None( args[0], \
3096 CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
3097
3098
3099 #define DO_MAX \
3100 if ( args[1] > args[0] ) \
3101 args[0] = args[1];
3102
3103
3104 #define DO_MIN \
3105 if ( args[1] < args[0] ) \
3106 args[0] = args[1];
3107
3108
3109 #ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
3110
3111
3112 #undef ARRAY_BOUND_ERROR
3113 #define ARRAY_BOUND_ERROR \
3114 { \
3115 CUR.error = TT_Err_Invalid_Reference; \
3116 return; \
3117 }
3118
3119
3120 /*************************************************************************/
3121 /* */
3122 /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
3123 /* Opcode range: 0x00-0x01 */
3124 /* Stack: --> */
3125 /* */
3126 static void
3127 Ins_SVTCA( INS_ARG )
3128 {
3129 DO_SVTCA
3130 }
3131
3132
3133 /*************************************************************************/
3134 /* */
3135 /* SPVTCA[a]: Set PVector to Coordinate Axis */
3136 /* Opcode range: 0x02-0x03 */
3137 /* Stack: --> */
3138 /* */
3139 static void
3140 Ins_SPVTCA( INS_ARG )
3141 {
3142 DO_SPVTCA
3143 }
3144
3145
3146 /*************************************************************************/
3147 /* */
3148 /* SFVTCA[a]: Set FVector to Coordinate Axis */
3149 /* Opcode range: 0x04-0x05 */
3150 /* Stack: --> */
3151 /* */
3152 static void
3153 Ins_SFVTCA( INS_ARG )
3154 {
3155 DO_SFVTCA
3156 }
3157
3158
3159 /*************************************************************************/
3160 /* */
3161 /* SPVTL[a]: Set PVector To Line */
3162 /* Opcode range: 0x06-0x07 */
3163 /* Stack: uint32 uint32 --> */
3164 /* */
3165 static void
3166 Ins_SPVTL( INS_ARG )
3167 {
3168 DO_SPVTL
3169 }
3170
3171
3172 /*************************************************************************/
3173 /* */
3174 /* SFVTL[a]: Set FVector To Line */
3175 /* Opcode range: 0x08-0x09 */
3176 /* Stack: uint32 uint32 --> */
3177 /* */
3178 static void
3179 Ins_SFVTL( INS_ARG )
3180 {
3181 DO_SFVTL
3182 }
3183
3184
3185 /*************************************************************************/
3186 /*