blob: 43f57677957fff1aa3e303cee0ba500a00900581 [file] [log] [blame]
David Turnerd2b1f351999-12-16 23:11:37 +00001/***************************************************************************/
2/* */
3/* ttinterp.c */
4/* */
Werner Lemberg78575dc2000-06-12 19:36:41 +00005/* TrueType bytecode interpreter (body). */
David Turnerd2b1f351999-12-16 23:11:37 +00006/* */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007/* Copyright 1996-2000 by */
David Turnerd2b1f351999-12-16 23:11:37 +00008/* David Turner, Robert Wilhelm, and Werner Lemberg. */
9/* */
Werner Lemberg78575dc2000-06-12 19:36:41 +000010/* This file is part of the FreeType project, and may only be used, */
11/* modified, and distributed under the terms of the FreeType project */
David Turnerd2b1f351999-12-16 23:11:37 +000012/* 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
Werner Lembergcc069be2000-12-08 16:17:16 +000018
David Turner19ed8af2000-12-08 02:42:29 +000019#include <ft2build.h>
20#include FT_INTERNAL_DEBUG_H
21#include FT_INTERNAL_CALC_H
David Turnerac6cc412001-06-14 12:34:00 +000022#include FT_TRIGONOMETRY_H
David Turner19ed8af2000-12-08 02:42:29 +000023#include FT_SYSTEM_H
Werner Lemberg1f7f0e82001-06-06 17:30:41 +000024
David Turner8d3a4012001-03-20 11:14:24 +000025#include "ttinterp.h"
Werner Lemberg1f7f0e82001-06-06 17:30:41 +000026
27#include "tterrors.h"
David Turnerd2b1f351999-12-16 23:11:37 +000028
Werner Lemberg78575dc2000-06-12 19:36:41 +000029
David Turner1ab77fd2000-02-10 18:08:17 +000030#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
31
32
Werner Lembergcc069be2000-12-08 16:17:16 +000033#define TT_MULFIX FT_MulFix
34#define TT_MULDIV FT_MulDiv
Werner Lembergcc069be2000-12-08 16:17:16 +000035#define TT_INT64 FT_Int64
David Turnerd2b1f351999-12-16 23:11:37 +000036
David Turnerd2b1f351999-12-16 23:11:37 +000037 /*************************************************************************/
38 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +000039 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
40 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
41 /* messages during execution. */
David Turnerd2b1f351999-12-16 23:11:37 +000042 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +000043#undef FT_COMPONENT
44#define FT_COMPONENT trace_ttinterp
45
46#undef NO_APPLE_PATENT
47#define APPLE_THRESHOLD 0x4000000L
48
49 /*************************************************************************/
50 /* */
51 /* In order to detect infinite loops in the code, we set up a counter */
52 /* within the run loop. A single stroke of interpretation is now */
53 /* limitet to a maximal number of opcodes defined below. */
54 /* */
55#define MAX_RUNNABLE_OPCODES 1000000L
David Turnerd2b1f351999-12-16 23:11:37 +000056
57
58 /*************************************************************************/
59 /* */
60 /* There are two kinds of implementations: */
61 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +000062 /* a. static implementation */
David Turnerd2b1f351999-12-16 23:11:37 +000063 /* */
64 /* The current execution context is a static variable, which fields */
65 /* are accessed directly by the interpreter during execution. The */
66 /* context is named `cur'. */
67 /* */
68 /* This version is non-reentrant, of course. */
69 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +000070 /* b. indirect implementation */
David Turnerd2b1f351999-12-16 23:11:37 +000071 /* */
72 /* The current execution context is passed to _each_ function as its */
73 /* first argument, and each field is thus accessed indirectly. */
74 /* */
75 /* This version is fully re-entrant. */
76 /* */
77 /* The idea is that an indirect implementation may be slower to execute */
78 /* on low-end processors that are used in some systems (like 386s or */
79 /* even 486s). */
80 /* */
81 /* As a consequence, the indirect implementation is now the default, as */
82 /* its performance costs can be considered negligible in our context. */
83 /* Note, however, that we kept the same source with macros because: */
84 /* */
85 /* - The code is kept very close in design to the Pascal code used for */
86 /* development. */
87 /* */
88 /* - It's much more readable that way! */
89 /* */
90 /* - It's still open to experimentation and tuning. */
91 /* */
92 /*************************************************************************/
93
94
Werner Lemberg78575dc2000-06-12 19:36:41 +000095#ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER /* indirect implementation */
David Turnerd2b1f351999-12-16 23:11:37 +000096
Werner Lemberg78575dc2000-06-12 19:36:41 +000097#define CUR (*exc) /* see ttobjs.h */
David Turnerd2b1f351999-12-16 23:11:37 +000098
Werner Lemberg78575dc2000-06-12 19:36:41 +000099#else /* static implementation */
David Turnerd2b1f351999-12-16 23:11:37 +0000100
Werner Lemberg78575dc2000-06-12 19:36:41 +0000101#define CUR cur
David Turnerd2b1f351999-12-16 23:11:37 +0000102
103 static
104 TT_ExecContextRec cur; /* static exec. context variable */
105
106 /* apparently, we have a _lot_ of direct indexing when accessing */
107 /* the static `cur', which makes the code bigger (due to all the */
108 /* four bytes addresses). */
109
110#endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
111
112
113 /*************************************************************************/
114 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000115 /* The instruction argument stack. */
David Turnerd2b1f351999-12-16 23:11:37 +0000116 /* */
David Turnerf9b8dec2000-06-16 19:34:52 +0000117#define INS_ARG EXEC_OP_ FT_Long* args /* see ttobjs.h for EXEC_OP_ */
David Turnerd2b1f351999-12-16 23:11:37 +0000118
119
120 /*************************************************************************/
121 /* */
122 /* This macro is used whenever `exec' is unused in a function, to avoid */
123 /* stupid warnings from pedantic compilers. */
124 /* */
David Turnerc6a92202000-07-04 18:12:13 +0000125#define FT_UNUSED_EXEC FT_UNUSED( CUR )
David Turnerd2b1f351999-12-16 23:11:37 +0000126
127
128 /*************************************************************************/
129 /* */
130 /* This macro is used whenever `args' is unused in a function, to avoid */
131 /* stupid warnings from pedantic compilers. */
132 /* */
David Turnerc6a92202000-07-04 18:12:13 +0000133#define FT_UNUSED_ARG FT_UNUSED_EXEC; FT_UNUSED( args )
David Turnerd2b1f351999-12-16 23:11:37 +0000134
135
136 /*************************************************************************/
137 /* */
138 /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000139 /* increase readabilty of the code. */
David Turnerd2b1f351999-12-16 23:11:37 +0000140 /* */
141 /*************************************************************************/
142
143
144#define SKIP_Code() \
145 SkipCode( EXEC_ARG )
146
147#define GET_ShortIns() \
148 GetShortIns( EXEC_ARG )
149
150#define NORMalize( x, y, v ) \
151 Normalize( EXEC_ARG_ x, y, v )
152
153#define SET_SuperRound( scale, flags ) \
154 SetSuperRound( EXEC_ARG_ scale, flags )
155
156#define ROUND_None( d, c ) \
157 Round_None( EXEC_ARG_ d, c )
158
159#define INS_Goto_CodeRange( range, ip ) \
160 Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
161
162#define CUR_Func_project( x, y ) \
163 CUR.func_project( EXEC_ARG_ x, y )
164
165#define CUR_Func_move( z, p, d ) \
166 CUR.func_move( EXEC_ARG_ z, p, d )
167
168#define CUR_Func_dualproj( x, y ) \
169 CUR.func_dualproj( EXEC_ARG_ x, y )
170
171#define CUR_Func_freeProj( x, y ) \
172 CUR.func_freeProj( EXEC_ARG_ x, y )
173
174#define CUR_Func_round( d, c ) \
175 CUR.func_round( EXEC_ARG_ d, c )
176
177#define CUR_Func_read_cvt( index ) \
178 CUR.func_read_cvt( EXEC_ARG_ index )
179
180#define CUR_Func_write_cvt( index, val ) \
181 CUR.func_write_cvt( EXEC_ARG_ index, val )
182
183#define CUR_Func_move_cvt( index, val ) \
184 CUR.func_move_cvt( EXEC_ARG_ index, val )
185
186#define CURRENT_Ratio() \
187 Current_Ratio( EXEC_ARG )
188
189#define CURRENT_Ppem() \
190 Current_Ppem( EXEC_ARG )
191
192#define CUR_Ppem() \
193 Cur_PPEM( EXEC_ARG )
194
David Turnerd2b1f351999-12-16 23:11:37 +0000195#define INS_SxVTL( a, b, c, d ) \
196 Ins_SxVTL( EXEC_ARG_ a, b, c, d )
197
198#define COMPUTE_Funcs() \
199 Compute_Funcs( EXEC_ARG )
200
201#define COMPUTE_Round( a ) \
202 Compute_Round( EXEC_ARG_ a )
203
204#define COMPUTE_Point_Displacement( a, b, c, d ) \
205 Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
206
207#define MOVE_Zp2_Point( a, b, c, t ) \
208 Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
209
210
David Turnerd2b1f351999-12-16 23:11:37 +0000211 /*************************************************************************/
212 /* */
213 /* Instruction dispatch function, as used by the interpreter. */
214 /* */
215 typedef void (*TInstruction_Function)( INS_ARG );
216
217
218 /*************************************************************************/
219 /* */
220 /* A simple bounds-checking macro. */
221 /* */
David Turnerf9b8dec2000-06-16 19:34:52 +0000222#define BOUNDS( x, n ) ( (FT_UInt)(x) >= (FT_UInt)(n) )
David Turnerd2b1f351999-12-16 23:11:37 +0000223
224
Werner Lemberg78575dc2000-06-12 19:36:41 +0000225#undef SUCCESS
226#define SUCCESS 0
David Turnerd2b1f351999-12-16 23:11:37 +0000227
Werner Lemberg78575dc2000-06-12 19:36:41 +0000228#undef FAILURE
229#define FAILURE 1
David Turnerd2b1f351999-12-16 23:11:37 +0000230
231
232 /*************************************************************************/
233 /* */
234 /* CODERANGE FUNCTIONS */
235 /* */
236 /*************************************************************************/
237
238
239 /*************************************************************************/
240 /* */
241 /* <Function> */
242 /* TT_Goto_CodeRange */
243 /* */
244 /* <Description> */
245 /* Switches to a new code range (updates the code related elements in */
246 /* `exec', and `IP'). */
247 /* */
248 /* <Input> */
249 /* range :: The new execution code range. */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000250 /* */
251 /* IP :: The new IP in the new code range. */
David Turnerd2b1f351999-12-16 23:11:37 +0000252 /* */
253 /* <InOut> */
254 /* exec :: The target execution context. */
255 /* */
256 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000257 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000258 /* */
David Turner76a5f622000-11-04 01:55:49 +0000259 FT_LOCAL_DEF
David Turnerf9b8dec2000-06-16 19:34:52 +0000260 FT_Error TT_Goto_CodeRange( TT_ExecContext exec,
261 FT_Int range,
262 FT_Long IP )
David Turnerd2b1f351999-12-16 23:11:37 +0000263 {
264 TT_CodeRange* coderange;
265
266
267 FT_Assert( range >= 1 && range <= 3 );
268
269 coderange = &exec->codeRangeTable[range - 1];
270
271 FT_Assert( coderange->base != NULL );
272
273 /* NOTE: Because the last instruction of a program may be a CALL */
274 /* which will return to the first byte *after* the code */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000275 /* range, we test for IP <= Size instead of IP < Size. */
David Turnerd2b1f351999-12-16 23:11:37 +0000276 /* */
David Turnerf9b8dec2000-06-16 19:34:52 +0000277 FT_Assert( (FT_ULong)IP <= coderange->size );
David Turnerd2b1f351999-12-16 23:11:37 +0000278
279 exec->code = coderange->base;
280 exec->codeSize = coderange->size;
281 exec->IP = IP;
282 exec->curRange = range;
283
284 return TT_Err_Ok;
285 }
286
287
288 /*************************************************************************/
289 /* */
290 /* <Function> */
291 /* TT_Set_CodeRange */
292 /* */
293 /* <Description> */
294 /* Sets a code range. */
295 /* */
296 /* <Input> */
297 /* range :: The code range index. */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000298 /* */
David Turnerd2b1f351999-12-16 23:11:37 +0000299 /* base :: The new code base. */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000300 /* */
David Turnerd2b1f351999-12-16 23:11:37 +0000301 /* length :: The range size in bytes. */
302 /* */
303 /* <InOut> */
304 /* exec :: The target execution context. */
305 /* */
306 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000307 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000308 /* */
David Turner76a5f622000-11-04 01:55:49 +0000309 FT_LOCAL_DEF
David Turnerf9b8dec2000-06-16 19:34:52 +0000310 FT_Error TT_Set_CodeRange( TT_ExecContext exec,
311 FT_Int range,
David Turnerd2b1f351999-12-16 23:11:37 +0000312 void* base,
David Turnerf9b8dec2000-06-16 19:34:52 +0000313 FT_Long length )
David Turnerd2b1f351999-12-16 23:11:37 +0000314 {
315 FT_Assert( range >= 1 && range <= 3 );
316
David Turnerf9b8dec2000-06-16 19:34:52 +0000317 exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
David Turnerd2b1f351999-12-16 23:11:37 +0000318 exec->codeRangeTable[range - 1].size = length;
319
320 return TT_Err_Ok;
321 }
322
323
324 /*************************************************************************/
325 /* */
326 /* <Function> */
327 /* TT_Clear_CodeRange */
328 /* */
329 /* <Description> */
330 /* Clears a code range. */
331 /* */
332 /* <Input> */
333 /* range :: The code range index. */
334 /* */
335 /* <InOut> */
336 /* exec :: The target execution context. */
337 /* */
338 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000339 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000340 /* */
341 /* <Note> */
342 /* Does not set the Error variable. */
343 /* */
David Turner76a5f622000-11-04 01:55:49 +0000344 FT_LOCAL_DEF
David Turnerf9b8dec2000-06-16 19:34:52 +0000345 FT_Error TT_Clear_CodeRange( TT_ExecContext exec,
346 FT_Int range )
David Turnerd2b1f351999-12-16 23:11:37 +0000347 {
348 FT_Assert( range >= 1 && range <= 3 );
349
350 exec->codeRangeTable[range - 1].base = NULL;
351 exec->codeRangeTable[range - 1].size = 0;
352
353 return TT_Err_Ok;
354 }
355
356
357 /*************************************************************************/
358 /* */
359 /* EXECUTION CONTEXT ROUTINES */
360 /* */
361 /*************************************************************************/
362
363
364 /*************************************************************************/
365 /* */
366 /* <Function> */
367 /* TT_Destroy_Context */
368 /* */
369 /* <Description> */
370 /* Destroys a given context. */
371 /* */
372 /* <Input> */
373 /* exec :: A handle to the target execution context. */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000374 /* */
375 /* memory :: A handle to the parent memory object. */
David Turnerd2b1f351999-12-16 23:11:37 +0000376 /* */
377 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000378 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000379 /* */
380 /* <Note> */
381 /* Only the glyph loader and debugger should call this function. */
382 /* */
David Turner76a5f622000-11-04 01:55:49 +0000383 FT_LOCAL_DEF
David Turnerf9b8dec2000-06-16 19:34:52 +0000384 FT_Error TT_Destroy_Context( TT_ExecContext exec,
David Turnerd2b1f351999-12-16 23:11:37 +0000385 FT_Memory memory )
386 {
387 /* free composite load stack */
388 FREE( exec->loadStack );
389 exec->loadSize = 0;
390
391 /* points zone */
David Turnerd2b1f351999-12-16 23:11:37 +0000392 exec->maxPoints = 0;
393 exec->maxContours = 0;
394
395 /* free stack */
396 FREE( exec->stack );
397 exec->stackSize = 0;
398
399 /* free call stack */
400 FREE( exec->callStack );
401 exec->callSize = 0;
402 exec->callTop = 0;
403
404 /* free glyph code range */
405 FREE( exec->glyphIns );
406 exec->glyphSize = 0;
407
408 exec->size = NULL;
409 exec->face = NULL;
410
411 FREE( exec );
412 return TT_Err_Ok;
413 }
414
415
416 /*************************************************************************/
417 /* */
418 /* <Function> */
419 /* Init_Context */
420 /* */
421 /* <Description> */
422 /* Initializes a context object. */
423 /* */
424 /* <Input> */
425 /* memory :: A handle to the parent memory object. */
426 /* */
427 /* face :: A handle to the source TrueType face object. */
428 /* */
429 /* <InOut> */
430 /* exec :: A handle to the target execution context. */
431 /* */
432 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000433 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000434 /* */
435 static
David Turnerf9b8dec2000-06-16 19:34:52 +0000436 FT_Error Init_Context( TT_ExecContext exec,
David Turnerd2b1f351999-12-16 23:11:37 +0000437 TT_Face face,
438 FT_Memory memory )
439 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000440 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000441
442
Werner Lemberg5811c7c2000-07-02 13:53:16 +0000443 FT_TRACE1(( "Init_Context: new object at 0x%08p, parent = 0x%08p\n",
David Turner51179f02000-05-18 16:18:05 +0000444 exec, face ));
David Turnerd2b1f351999-12-16 23:11:37 +0000445
David Turnerd2b1f351999-12-16 23:11:37 +0000446 exec->memory = memory;
447 exec->callSize = 32;
448
449 if ( ALLOC_ARRAY( exec->callStack, exec->callSize, TT_CallRec ) )
450 goto Fail_Memory;
451
452 /* all values in the context are set to 0 already, but this is */
453 /* here as a remainder */
454 exec->maxPoints = 0;
455 exec->maxContours = 0;
456
457 exec->stackSize = 0;
458 exec->loadSize = 0;
459 exec->glyphSize = 0;
460
461 exec->stack = NULL;
462 exec->loadStack = NULL;
463 exec->glyphIns = NULL;
464
465 exec->face = face;
466 exec->size = NULL;
467
468 return TT_Err_Ok;
469
470 Fail_Memory:
Werner Lemberg5811c7c2000-07-02 13:53:16 +0000471 FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n",
472 (FT_Long)exec ));
David Turnerd2b1f351999-12-16 23:11:37 +0000473 TT_Destroy_Context( exec, memory );
474
475 return error;
476 }
477
478
479 /*************************************************************************/
480 /* */
481 /* <Function> */
482 /* Update_Max */
483 /* */
484 /* <Description> */
485 /* Checks the size of a buffer and reallocates it if necessary. */
486 /* */
487 /* <Input> */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000488 /* memory :: A handle to the parent memory object. */
489 /* */
David Turnerd2b1f351999-12-16 23:11:37 +0000490 /* multiplier :: The size in bytes of each element in the buffer. */
491 /* */
492 /* new_max :: The new capacity (size) of the buffer. */
493 /* */
494 /* <InOut> */
495 /* size :: The address of the buffer's current size expressed */
496 /* in elements. */
497 /* */
498 /* buff :: The address of the buffer base pointer. */
499 /* */
500 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000501 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000502 /* */
503 static
David Turnerf9b8dec2000-06-16 19:34:52 +0000504 FT_Error Update_Max( FT_Memory memory,
505 FT_ULong* size,
506 FT_Long multiplier,
David Turnerd2b1f351999-12-16 23:11:37 +0000507 void** buff,
David Turnerf9b8dec2000-06-16 19:34:52 +0000508 FT_ULong new_max )
David Turnerd2b1f351999-12-16 23:11:37 +0000509 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000510 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000511
512
513 if ( *size < new_max )
514 {
515 FREE( *buff );
516 if ( ALLOC( *buff, new_max * multiplier ) )
517 return error;
518 *size = new_max;
519 }
520
521 return TT_Err_Ok;
522 }
523
524
David Turnerd2b1f351999-12-16 23:11:37 +0000525 /*************************************************************************/
526 /* */
527 /* <Function> */
528 /* TT_Load_Context */
529 /* */
530 /* <Description> */
531 /* Prepare an execution context for glyph hinting. */
532 /* */
533 /* <Input> */
534 /* face :: A handle to the source face object. */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000535 /* */
David Turnerd2b1f351999-12-16 23:11:37 +0000536 /* size :: A handle to the source size object. */
537 /* */
538 /* <InOut> */
539 /* exec :: A handle to the target execution context. */
540 /* */
541 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000542 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000543 /* */
544 /* <Note> */
545 /* Only the glyph loader and debugger should call this function. */
546 /* */
David Turner76a5f622000-11-04 01:55:49 +0000547 FT_LOCAL_DEF
David Turnerf9b8dec2000-06-16 19:34:52 +0000548 FT_Error TT_Load_Context( TT_ExecContext exec,
David Turnerd2b1f351999-12-16 23:11:37 +0000549 TT_Face face,
550 TT_Size size )
551 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000552 FT_Int i;
553 FT_ULong tmp;
David Turnerd2b1f351999-12-16 23:11:37 +0000554 TT_MaxProfile* maxp;
David Turnerf9b8dec2000-06-16 19:34:52 +0000555 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000556
Werner Lemberg78575dc2000-06-12 19:36:41 +0000557
David Turnerd2b1f351999-12-16 23:11:37 +0000558 exec->face = face;
559 maxp = &face->max_profile;
560 exec->size = size;
561
562 if ( size )
563 {
564 exec->numFDefs = size->num_function_defs;
565 exec->maxFDefs = size->max_function_defs;
566 exec->numIDefs = size->num_instruction_defs;
567 exec->maxIDefs = size->max_instruction_defs;
568 exec->FDefs = size->function_defs;
569 exec->IDefs = size->instruction_defs;
570 exec->tt_metrics = size->ttmetrics;
571 exec->metrics = size->root.metrics;
572
573 exec->maxFunc = size->max_func;
574 exec->maxIns = size->max_ins;
575
576 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
577 exec->codeRangeTable[i] = size->codeRangeTable[i];
578
579 /* set graphics state */
580 exec->GS = size->GS;
581
582 exec->cvtSize = size->cvt_size;
583 exec->cvt = size->cvt;
584
585 exec->storeSize = size->storage_size;
586 exec->storage = size->storage;
587
588 exec->twilight = size->twilight;
589 }
590
591 error = Update_Max( exec->memory,
592 &exec->loadSize,
593 sizeof ( TT_SubGlyphRec ),
594 (void**)&exec->loadStack,
595 exec->face->max_components + 1 );
596 if ( error )
597 return error;
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,
David Turnerf9b8dec2000-06-16 19:34:52 +0000604 sizeof ( FT_F26Dot6 ),
David Turnerd2b1f351999-12-16 23:11:37 +0000605 (void**)&exec->stack,
606 maxp->maxStackElements + 32 );
David Turnerf9b8dec2000-06-16 19:34:52 +0000607 exec->stackSize = (FT_UInt)tmp;
David Turnerd2b1f351999-12-16 23:11:37 +0000608 if ( error )
609 return error;
610
611 tmp = exec->glyphSize;
612 error = Update_Max( exec->memory,
613 &tmp,
David Turnerf9b8dec2000-06-16 19:34:52 +0000614 sizeof ( FT_Byte ),
David Turnerd2b1f351999-12-16 23:11:37 +0000615 (void**)&exec->glyphIns,
616 maxp->maxSizeOfInstructions );
David Turnerf9b8dec2000-06-16 19:34:52 +0000617 exec->glyphSize = (FT_UShort)tmp;
David Turnerd2b1f351999-12-16 23:11:37 +0000618 if ( error )
619 return error;
620
David Turnerd2b1f351999-12-16 23:11:37 +0000621 exec->pts.n_points = 0;
622 exec->pts.n_contours = 0;
623
624 exec->instruction_trap = FALSE;
625
626 return TT_Err_Ok;
627 }
628
629
630 /*************************************************************************/
631 /* */
632 /* <Function> */
633 /* TT_Save_Context */
634 /* */
635 /* <Description> */
636 /* Saves the code ranges in a `size' object. */
637 /* */
638 /* <Input> */
639 /* exec :: A handle to the source execution context. */
640 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000641 /* <InOut> */
642 /* size :: A handle to the target size object. */
David Turnerd2b1f351999-12-16 23:11:37 +0000643 /* */
644 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000645 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000646 /* */
647 /* <Note> */
648 /* Only the glyph loader and debugger should call this function. */
649 /* */
David Turner76a5f622000-11-04 01:55:49 +0000650 FT_LOCAL_DEF
David Turnerf9b8dec2000-06-16 19:34:52 +0000651 FT_Error TT_Save_Context( TT_ExecContext exec,
David Turnerd2b1f351999-12-16 23:11:37 +0000652 TT_Size size )
653 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000654 FT_Int i;
David Turnerd2b1f351999-12-16 23:11:37 +0000655
Werner Lemberg78575dc2000-06-12 19:36:41 +0000656
David Turnerd2b1f351999-12-16 23:11:37 +0000657 /* XXXX: Will probably disappear soon with all the code range */
658 /* management, which is now rather obsolete. */
659 /* */
660 size->num_function_defs = exec->numFDefs;
661 size->num_instruction_defs = exec->numIDefs;
662
663 size->max_func = exec->maxFunc;
664 size->max_ins = exec->maxIns;
665
666 for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
667 size->codeRangeTable[i] = exec->codeRangeTable[i];
668
669 return TT_Err_Ok;
670 }
671
672
673 /*************************************************************************/
674 /* */
675 /* <Function> */
676 /* TT_Run_Context */
677 /* */
678 /* <Description> */
679 /* Executes one or more instructions in the execution context. */
680 /* */
681 /* <Input> */
682 /* debug :: A Boolean flag. If set, the function sets some internal */
683 /* variables and returns immediately, otherwise TT_RunIns() */
684 /* is called. */
685 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +0000686 /* This is commented out currently. */
687 /* */
David Turnerd2b1f351999-12-16 23:11:37 +0000688 /* <Input> */
689 /* exec :: A handle to the target execution context. */
690 /* */
691 /* <Return> */
David Turnerf0df85b2000-06-22 00:17:42 +0000692 /* TrueTyoe error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000693 /* */
694 /* <Note> */
695 /* Only the glyph loader and debugger should call this function. */
696 /* */
David Turner76a5f622000-11-04 01:55:49 +0000697 FT_LOCAL_DEF
David Turnerf9b8dec2000-06-16 19:34:52 +0000698 FT_Error TT_Run_Context( TT_ExecContext exec,
699 FT_Bool debug )
David Turnerd2b1f351999-12-16 23:11:37 +0000700 {
David Turnerf9b8dec2000-06-16 19:34:52 +0000701 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000702
Werner Lemberg78575dc2000-06-12 19:36:41 +0000703
704 if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0 ) )
David Turnerd2b1f351999-12-16 23:11:37 +0000705 != TT_Err_Ok )
706 return error;
707
708 exec->zp0 = exec->pts;
709 exec->zp1 = exec->pts;
710 exec->zp2 = exec->pts;
711
712 exec->GS.gep0 = 1;
713 exec->GS.gep1 = 1;
714 exec->GS.gep2 = 1;
715
716 exec->GS.projVector.x = 0x4000;
717 exec->GS.projVector.y = 0x0000;
718
719 exec->GS.freeVector = exec->GS.projVector;
720 exec->GS.dualVector = exec->GS.projVector;
721
722 exec->GS.round_state = 1;
723 exec->GS.loop = 1;
724
725 /* some glyphs leave something on the stack. so we clean it */
726 /* before a new execution. */
727 exec->top = 0;
728 exec->callTop = 0;
729
730#if 1
David Turnerc6a92202000-07-04 18:12:13 +0000731 FT_UNUSED( debug );
Werner Lemberg78575dc2000-06-12 19:36:41 +0000732
David Turnerd2b1f351999-12-16 23:11:37 +0000733 return exec->face->interpreter( exec );
734#else
735 if ( !debug )
736 return TT_RunIns( exec );
737 else
738 return TT_Err_Ok;
739#endif
740 }
741
742
David Turnerd2b1f351999-12-16 23:11:37 +0000743 const TT_GraphicsState tt_default_graphics_state =
744 {
745 0, 0, 0,
746 { 0x4000, 0 },
747 { 0x4000, 0 },
748 { 0x4000, 0 },
749 1, 64, 1,
750 TRUE, 68, 0, 0, 9, 3,
751 0, FALSE, 2, 1, 1, 1
752 };
753
754
Werner Lemberg90a03302000-11-07 17:21:11 +0000755 /* documentation is in ttinterp.h */
756
David Turner76a5f622000-11-04 01:55:49 +0000757 FT_EXPORT_DEF( TT_ExecContext ) TT_New_Context( TT_Face face )
David Turnerd2b1f351999-12-16 23:11:37 +0000758 {
Werner Lemberg78575dc2000-06-12 19:36:41 +0000759 TT_Driver driver;
David Turnerd2b1f351999-12-16 23:11:37 +0000760 TT_ExecContext exec;
Werner Lemberg78575dc2000-06-12 19:36:41 +0000761 FT_Memory memory;
David Turnerd2b1f351999-12-16 23:11:37 +0000762
763
Werner Lemberg78575dc2000-06-12 19:36:41 +0000764 if ( !face )
765 return 0;
766
767 driver = (TT_Driver)face->root.driver;
768
David Turnerf0df85b2000-06-22 00:17:42 +0000769 memory = driver->root.root.memory;
Werner Lemberg78575dc2000-06-12 19:36:41 +0000770 exec = driver->context;
David Turnerd2b1f351999-12-16 23:11:37 +0000771
772 if ( !driver->context )
773 {
Werner Lemberg5811c7c2000-07-02 13:53:16 +0000774 FT_Error error;
David Turnerd2b1f351999-12-16 23:11:37 +0000775
776
777 /* allocate object */
778 if ( ALLOC( exec, sizeof ( *exec ) ) )
779 goto Exit;
780
781 /* initialize it */
782 error = Init_Context( exec, face, memory );
783 if ( error )
784 goto Fail;
785
786 /* store it into the driver */
787 driver->context = exec;
788 }
789
790 Exit:
791 return driver->context;
792
793 Fail:
794 FREE( exec );
795
796 return 0;
797 }
798
799
800 /*************************************************************************/
801 /* */
802 /* <Function> */
803 /* TT_Done_Context */
804 /* */
805 /* <Description> */
806 /* Discards an execution context. */
807 /* */
808 /* <Input> */
809 /* exec :: A handle to the target execution context. */
810 /* */
811 /* <Return> */
Werner Lemberga929ba92000-06-25 06:47:11 +0000812 /* FreeType error code. 0 means success. */
David Turnerd2b1f351999-12-16 23:11:37 +0000813 /* */
814 /* <Note> */
815 /* Only the glyph loader and debugger should call this function. */
816 /* */
David Turner76a5f622000-11-04 01:55:49 +0000817 FT_LOCAL_DEF
David Turnerf9b8dec2000-06-16 19:34:52 +0000818 FT_Error TT_Done_Context( TT_ExecContext exec )
David Turnerd2b1f351999-12-16 23:11:37 +0000819 {
820 /* Nothing at all for now */
David Turnerc6a92202000-07-04 18:12:13 +0000821 FT_UNUSED( exec );
David Turnerd2b1f351999-12-16 23:11:37 +0000822
823 return TT_Err_Ok;
824 }
825
826
David Turnerac6cc412001-06-14 12:34:00 +0000827 /* return length of given vector */
David Turnerb7ef2b02000-05-02 11:01:12 +0000828#ifdef FT_CONFIG_OPTION_OLD_CALCS
829
David Turnerf9b8dec2000-06-16 19:34:52 +0000830 static FT_F26Dot6 Norm( FT_F26Dot6 X,
831 FT_F26Dot6 Y )
David Turnerb7ef2b02000-05-02 11:01:12 +0000832 {
Werner Lembergbd5ae402000-07-05 04:32:02 +0000833 TT_INT64 T1, T2;
Werner Lemberg78575dc2000-06-12 19:36:41 +0000834
David Turnerb7ef2b02000-05-02 11:01:12 +0000835
836 MUL_64( X, X, T1 );
837 MUL_64( Y, Y, T2 );
838
839 ADD_64( T1, T2, T1 );
840
David Turnerf9b8dec2000-06-16 19:34:52 +0000841 return (FT_F26Dot6)SQRT_64( T1 );
David Turnerb7ef2b02000-05-02 11:01:12 +0000842 }
Werner Lemberg78575dc2000-06-12 19:36:41 +0000843
David Turnerac6cc412001-06-14 12:34:00 +0000844#else /* !FT_CONFIG_OPTION_OLD_CALCS */
845
846 static FT_F26Dot6 Norm( FT_F26Dot6 X,
847 FT_F26Dot6 Y )
848 {
849 FT_Vector v;
850
851 v.x = X;
852 v.y = Y;
853 return FT_Vector_Length( &v );
854 }
855
Werner Lemberg78575dc2000-06-12 19:36:41 +0000856#endif /* FT_CONFIG_OPTION_OLD_CALCS */
David Turnerb7ef2b02000-05-02 11:01:12 +0000857
858
David Turnerd2b1f351999-12-16 23:11:37 +0000859 /*************************************************************************/
860 /* */
861 /* Before an opcode is executed, the interpreter verifies that there are */
862 /* enough arguments on the stack, with the help of the Pop_Push_Count */
863 /* table. */
864 /* */
865 /* For each opcode, the first column gives the number of arguments that */
866 /* are popped from the stack; the second one gives the number of those */
867 /* that are pushed in result. */
868 /* */
869 /* Note that for opcodes with a varying number of parameters, either 0 */
870 /* or 1 arg is verified before execution, depending on the nature of the */
871 /* instruction: */
872 /* */
873 /* - if the number of arguments is given by the bytecode stream or the */
874 /* loop variable, 0 is chosen. */
875 /* */
876 /* - if the first argument is a count n that is followed by arguments */
877 /* a1 .. an, then 1 is chosen. */
878 /* */
879 /*************************************************************************/
880
881
882#undef PACK
Werner Lemberg78575dc2000-06-12 19:36:41 +0000883#define PACK( x, y ) ( ( x << 4 ) | y )
David Turnerd2b1f351999-12-16 23:11:37 +0000884
885
886 static
David Turnerf9b8dec2000-06-16 19:34:52 +0000887 const FT_Byte Pop_Push_Count[256] =
David Turnerd2b1f351999-12-16 23:11:37 +0000888 {
889 /* opcodes are gathered in groups of 16 */
890 /* please keep the spaces as they are */
891
892 /* SVTCA y */ PACK( 0, 0 ),
893 /* SVTCA x */ PACK( 0, 0 ),
894 /* SPvTCA y */ PACK( 0, 0 ),
895 /* SPvTCA x */ PACK( 0, 0 ),
896 /* SFvTCA y */ PACK( 0, 0 ),
897 /* SFvTCA x */ PACK( 0, 0 ),
898 /* SPvTL // */ PACK( 2, 0 ),
899 /* SPvTL + */ PACK( 2, 0 ),
900 /* SFvTL // */ PACK( 2, 0 ),
901 /* SFvTL + */ PACK( 2, 0 ),
902 /* SPvFS */ PACK( 2, 0 ),
903 /* SFvFS */ PACK( 2, 0 ),
904 /* GPV */ PACK( 0, 2 ),
905 /* GFV */ PACK( 0, 2 ),
906 /* SFvTPv */ PACK( 0, 0 ),
907 /* ISECT */ PACK( 5, 0 ),
908
909 /* SRP0 */ PACK( 1, 0 ),
910 /* SRP1 */ PACK( 1, 0 ),
911 /* SRP2 */ PACK( 1, 0 ),
912 /* SZP0 */ PACK( 1, 0 ),
913 /* SZP1 */ PACK( 1, 0 ),
914 /* SZP2 */ PACK( 1, 0 ),
915 /* SZPS */ PACK( 1, 0 ),
916 /* SLOOP */ PACK( 1, 0 ),
917 /* RTG */ PACK( 0, 0 ),
918 /* RTHG */ PACK( 0, 0 ),
919 /* SMD */ PACK( 1, 0 ),
920 /* ELSE */ PACK( 0, 0 ),
921 /* JMPR */ PACK( 1, 0 ),
922 /* SCvTCi */ PACK( 1, 0 ),
923 /* SSwCi */ PACK( 1, 0 ),
924 /* SSW */ PACK( 1, 0 ),
925
926 /* DUP */ PACK( 1, 2 ),
927 /* POP */ PACK( 1, 0 ),
928 /* CLEAR */ PACK( 0, 0 ),
929 /* SWAP */ PACK( 2, 2 ),
930 /* DEPTH */ PACK( 0, 1 ),
931 /* CINDEX */ PACK( 1, 1 ),
932 /* MINDEX */ PACK( 1, 0 ),
933 /* AlignPTS */ PACK( 2, 0 ),
934 /* INS_$28 */ PACK( 0, 0 ),
935 /* UTP */ PACK( 1, 0 ),
936 /* LOOPCALL */ PACK( 2, 0 ),
937 /* CALL */ PACK( 1, 0 ),
938 /* FDEF */ PACK( 1, 0 ),
939 /* ENDF */ PACK( 0, 0 ),
940 /* MDAP[0] */ PACK( 1, 0 ),
941 /* MDAP[1] */ PACK( 1, 0 ),
942
943 /* IUP[0] */ PACK( 0, 0 ),
944 /* IUP[1] */ PACK( 0, 0 ),
945 /* SHP[0] */ PACK( 0, 0 ),
946 /* SHP[1] */ PACK( 0, 0 ),
947 /* SHC[0] */ PACK( 1, 0 ),
948 /* SHC[1] */ PACK( 1, 0 ),
949 /* SHZ[0] */ PACK( 1, 0 ),
950 /* SHZ[1] */ PACK( 1, 0 ),
951 /* SHPIX */ PACK( 1, 0 ),
952 /* IP */ PACK( 0, 0 ),
953 /* MSIRP[0] */ PACK( 2, 0 ),
954 /* MSIRP[1] */ PACK( 2, 0 ),
955 /* AlignRP */ PACK( 0, 0 ),
956 /* RTDG */ PACK( 0, 0 ),
957 /* MIAP[0] */ PACK( 2, 0 ),
958 /* MIAP[1] */ PACK( 2, 0 ),
959
960 /* NPushB */ PACK( 0, 0 ),
961 /* NPushW */ PACK( 0, 0 ),
962 /* WS */ PACK( 2, 0 ),
963 /* RS */ PACK( 1, 1 ),
964 /* WCvtP */ PACK( 2, 0 ),
965 /* RCvt */ PACK( 1, 1 ),
966 /* GC[0] */ PACK( 1, 1 ),
967 /* GC[1] */ PACK( 1, 1 ),
968 /* SCFS */ PACK( 2, 0 ),
969 /* MD[0] */ PACK( 2, 1 ),
970 /* MD[1] */ PACK( 2, 1 ),
971 /* MPPEM */ PACK( 0, 1 ),
972 /* MPS */ PACK( 0, 1 ),
973 /* FlipON */ PACK( 0, 0 ),
974 /* FlipOFF */ PACK( 0, 0 ),
975 /* DEBUG */ PACK( 1, 0 ),
976
977 /* LT */ PACK( 2, 1 ),
978 /* LTEQ */ PACK( 2, 1 ),
979 /* GT */ PACK( 2, 1 ),
980 /* GTEQ */ PACK( 2, 1 ),
981 /* EQ */ PACK( 2, 1 ),
982 /* NEQ */ PACK( 2, 1 ),
983 /* ODD */ PACK( 1, 1 ),
984 /* EVEN */ PACK( 1, 1 ),
985 /* IF */ PACK( 1, 0 ),
986 /* EIF */ PACK( 0, 0 ),
987 /* AND */ PACK( 2, 1 ),
988 /* OR */ PACK( 2, 1 ),
989 /* NOT */ PACK( 1, 1 ),
990 /* DeltaP1 */ PACK( 1, 0 ),
991 /* SDB */ PACK( 1, 0 ),
992 /* SDS */ PACK( 1, 0 ),
993
994 /* ADD */ PACK( 2, 1 ),
995 /* SUB */ PACK( 2, 1 ),
996 /* DIV */ PACK( 2, 1 ),
997 /* MUL */ PACK( 2, 1 ),
998 /* ABS */ PACK( 1, 1 ),
999 /* NEG */ PACK( 1, 1 ),
1000 /* FLOOR */ PACK( 1, 1 ),
1001 /* CEILING */ PACK( 1, 1 ),
1002 /* ROUND[0] */ PACK( 1, 1 ),
1003 /* ROUND[1] */ PACK( 1, 1 ),
1004 /* ROUND[2] */ PACK( 1, 1 ),
1005 /* ROUND[3] */ PACK( 1, 1 ),
1006 /* NROUND[0] */ PACK( 1, 1 ),
1007 /* NROUND[1] */ PACK( 1, 1 ),
1008 /* NROUND[2] */ PACK( 1, 1 ),
1009 /* NROUND[3] */ PACK( 1, 1 ),
1010
1011 /* WCvtF */ PACK( 2, 0 ),
1012 /* DeltaP2 */ PACK( 1, 0 ),
1013 /* DeltaP3 */ PACK( 1, 0 ),
1014 /* DeltaCn[0] */ PACK( 1, 0 ),
1015 /* DeltaCn[1] */ PACK( 1, 0 ),
1016 /* DeltaCn[2] */ PACK( 1, 0 ),
1017 /* SROUND */ PACK( 1, 0 ),
1018 /* S45Round */ PACK( 1, 0 ),
1019 /* JROT */ PACK( 2, 0 ),
1020 /* JROF */ PACK( 2, 0 ),
1021 /* ROFF */ PACK( 0, 0 ),
1022 /* INS_$7B */ PACK( 0, 0 ),
1023 /* RUTG */ PACK( 0, 0 ),
1024 /* RDTG */ PACK( 0, 0 ),
1025 /* SANGW */ PACK( 1, 0 ),
1026 /* AA */ PACK( 1, 0 ),
1027
1028 /* FlipPT */ PACK( 0, 0 ),
1029 /* FlipRgON */ PACK( 2, 0 ),
1030 /* FlipRgOFF */ PACK( 2, 0 ),
1031 /* INS_$83 */ PACK( 0, 0 ),
1032 /* INS_$84 */ PACK( 0, 0 ),
1033 /* ScanCTRL */ PACK( 1, 0 ),
1034 /* SDVPTL[0] */ PACK( 2, 0 ),
1035 /* SDVPTL[1] */ PACK( 2, 0 ),
1036 /* GetINFO */ PACK( 1, 1 ),
1037 /* IDEF */ PACK( 1, 0 ),
1038 /* ROLL */ PACK( 3, 3 ),
1039 /* MAX */ PACK( 2, 1 ),
1040 /* MIN */ PACK( 2, 1 ),
1041 /* ScanTYPE */ PACK( 1, 0 ),
1042 /* InstCTRL */ PACK( 2, 0 ),
1043 /* INS_$8F */ PACK( 0, 0 ),
1044
1045 /* INS_$90 */ PACK( 0, 0 ),
1046 /* INS_$91 */ PACK( 0, 0 ),
1047 /* INS_$92 */ PACK( 0, 0 ),
1048 /* INS_$93 */ PACK( 0, 0 ),
1049 /* INS_$94 */ PACK( 0, 0 ),
1050 /* INS_$95 */ PACK( 0, 0 ),
1051 /* INS_$96 */ PACK( 0, 0 ),
1052 /* INS_$97 */ PACK( 0, 0 ),
1053 /* INS_$98 */ PACK( 0, 0 ),
1054 /* INS_$99 */ PACK( 0, 0 ),
1055 /* INS_$9A */ PACK( 0, 0 ),
1056 /* INS_$9B */ PACK( 0, 0 ),
1057 /* INS_$9C */ PACK( 0, 0 ),
1058 /* INS_$9D */ PACK( 0, 0 ),
1059 /* INS_$9E */ PACK( 0, 0 ),
1060 /* INS_$9F */ PACK( 0, 0 ),
1061
1062 /* INS_$A0 */ PACK( 0, 0 ),
1063 /* INS_$A1 */ PACK( 0, 0 ),
1064 /* INS_$A2 */ PACK( 0, 0 ),
1065 /* INS_$A3 */ PACK( 0, 0 ),
1066 /* INS_$A4 */ PACK( 0, 0 ),
1067 /* INS_$A5 */ PACK( 0, 0 ),
1068 /* INS_$A6 */ PACK( 0, 0 ),
1069 /* INS_$A7 */ PACK( 0, 0 ),
1070 /* INS_$A8 */ PACK( 0, 0 ),
1071 /* INS_$A9 */ PACK( 0, 0 ),
1072 /* INS_$AA */ PACK( 0, 0 ),
1073 /* INS_$AB */ PACK( 0, 0 ),
1074 /* INS_$AC */ PACK( 0, 0 ),
1075 /* INS_$AD */ PACK( 0, 0 ),
1076 /* INS_$AE */ PACK( 0, 0 ),
1077 /* INS_$AF */ PACK( 0, 0 ),
1078
1079 /* PushB[0] */ PACK( 0, 1 ),
1080 /* PushB[1] */ PACK( 0, 2 ),
1081 /* PushB[2] */ PACK( 0, 3 ),
1082 /* PushB[3] */ PACK( 0, 4 ),
1083 /* PushB[4] */ PACK( 0, 5 ),
1084 /* PushB[5] */ PACK( 0, 6 ),
1085 /* PushB[6] */ PACK( 0, 7 ),
1086 /* PushB[7] */ PACK( 0, 8 ),
1087 /* PushW[0] */ PACK( 0, 1 ),
1088 /* PushW[1] */ PACK( 0, 2 ),
1089 /* PushW[2] */ PACK( 0, 3 ),
1090 /* PushW[3] */ PACK( 0, 4 ),
1091 /* PushW[4] */ PACK( 0, 5 ),
1092 /* PushW[5] */ PACK( 0, 6 ),
1093 /* PushW[6] */ PACK( 0, 7 ),
1094 /* PushW[7] */ PACK( 0, 8 ),
1095
1096 /* MDRP[00] */ PACK( 1, 0 ),
1097 /* MDRP[01] */ PACK( 1, 0 ),
1098 /* MDRP[02] */ PACK( 1, 0 ),
1099 /* MDRP[03] */ PACK( 1, 0 ),
1100 /* MDRP[04] */ PACK( 1, 0 ),
1101 /* MDRP[05] */ PACK( 1, 0 ),
1102 /* MDRP[06] */ PACK( 1, 0 ),
1103 /* MDRP[07] */ PACK( 1, 0 ),
1104 /* MDRP[08] */ PACK( 1, 0 ),
1105 /* MDRP[09] */ PACK( 1, 0 ),
1106 /* MDRP[10] */ PACK( 1, 0 ),
1107 /* MDRP[11] */ PACK( 1, 0 ),
1108 /* MDRP[12] */ PACK( 1, 0 ),
1109 /* MDRP[13] */ PACK( 1, 0 ),
1110 /* MDRP[14] */ PACK( 1, 0 ),
1111 /* MDRP[15] */ PACK( 1, 0 ),
1112
1113 /* MDRP[16] */ PACK( 1, 0 ),
1114 /* MDRP[17] */ PACK( 1, 0 ),
1115 /* MDRP[18] */ PACK( 1, 0 ),
1116 /* MDRP[19] */ PACK( 1, 0 ),
1117 /* MDRP[20] */ PACK( 1, 0 ),
1118 /* MDRP[21] */ PACK( 1, 0 ),
1119 /* MDRP[22] */ PACK( 1, 0 ),
1120 /* MDRP[23] */ PACK( 1, 0 ),
1121 /* MDRP[24] */ PACK( 1, 0 ),
1122 /* MDRP[25] */ PACK( 1, 0 ),
1123 /* MDRP[26] */ PACK( 1, 0 ),
1124 /* MDRP[27] */ PACK( 1, 0 ),
1125 /* MDRP[28] */ PACK( 1, 0 ),
1126 /* MDRP[29] */ PACK( 1, 0 ),
1127 /* MDRP[30] */ PACK( 1, 0 ),
1128 /* MDRP[31] */ PACK( 1, 0 ),
1129
1130 /* MIRP[00] */ PACK( 2, 0 ),
1131 /* MIRP[01] */ PACK( 2, 0 ),
1132 /* MIRP[02] */ PACK( 2, 0 ),
1133 /* MIRP[03] */ PACK( 2, 0 ),
1134 /* MIRP[04] */ PACK( 2, 0 ),
1135 /* MIRP[05] */ PACK( 2, 0 ),
1136 /* MIRP[06] */ PACK( 2, 0 ),
1137 /* MIRP[07] */ PACK( 2, 0 ),
1138 /* MIRP[08] */ PACK( 2, 0 ),
1139 /* MIRP[09] */ PACK( 2, 0 ),
1140 /* MIRP[10] */ PACK( 2, 0 ),
1141 /* MIRP[11] */ PACK( 2, 0 ),
1142 /* MIRP[12] */ PACK( 2, 0 ),
1143 /* MIRP[13] */ PACK( 2, 0 ),
1144 /* MIRP[14] */ PACK( 2, 0 ),
1145 /* MIRP[15] */ PACK( 2, 0 ),
1146
1147 /* MIRP[16] */ PACK( 2, 0 ),
1148 /* MIRP[17] */ PACK( 2, 0 ),
1149 /* MIRP[18] */ PACK( 2, 0 ),
1150 /* MIRP[19] */ PACK( 2, 0 ),
1151 /* MIRP[20] */ PACK( 2, 0 ),
1152 /* MIRP[21] */ PACK( 2, 0 ),
1153 /* MIRP[22] */ PACK( 2, 0 ),
1154 /* MIRP[23] */ PACK( 2, 0 ),
1155 /* MIRP[24] */ PACK( 2, 0 ),
1156 /* MIRP[25] */ PACK( 2, 0 ),
1157 /* MIRP[26] */ PACK( 2, 0 ),
1158 /* MIRP[27] */ PACK( 2, 0 ),
1159 /* MIRP[28] */ PACK( 2, 0 ),
1160 /* MIRP[29] */ PACK( 2, 0 ),
1161 /* MIRP[30] */ PACK( 2, 0 ),
1162 /* MIRP[31] */ PACK( 2, 0 )
1163 };
1164
1165
1166 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001167 const FT_Char opcode_length[256] =
David Turnerd2b1f351999-12-16 23:11:37 +00001168 {
1169 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1170 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1171 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1172 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1173
1174 -1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1175 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1176 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1177 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1178
1179 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1180 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1181 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1182 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11,13,15,17,
1183
1184 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1185 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1186 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1187 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1188 };
1189
1190 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001191 const FT_Vector Null_Vector = {0,0};
David Turnerd2b1f351999-12-16 23:11:37 +00001192
1193
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001194#undef PACK
David Turnerd2b1f351999-12-16 23:11:37 +00001195
1196
1197#undef NULL_Vector
David Turnerf9b8dec2000-06-16 19:34:52 +00001198#define NULL_Vector (FT_Vector*)&Null_Vector
David Turnerd2b1f351999-12-16 23:11:37 +00001199
1200
1201 /*************************************************************************/
1202 /* */
1203 /* <Function> */
1204 /* Current_Ratio */
1205 /* */
1206 /* <Description> */
1207 /* Returns the current aspect ratio scaling factor depending on the */
1208 /* projection vector's state and device resolutions. */
1209 /* */
1210 /* <Return> */
1211 /* The aspect ratio in 16.16 format, always <= 1.0 . */
1212 /* */
1213 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001214 FT_Long Current_Ratio( EXEC_OP )
David Turnerd2b1f351999-12-16 23:11:37 +00001215 {
1216 if ( CUR.tt_metrics.ratio )
1217 return CUR.tt_metrics.ratio;
1218
1219 if ( CUR.GS.projVector.y == 0 )
1220 CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
1221
1222 else if ( CUR.GS.projVector.x == 0 )
1223 CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
1224
1225 else
1226 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001227 FT_Long x, y;
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001228
David Turnerd2b1f351999-12-16 23:11:37 +00001229 x = TT_MULDIV( CUR.GS.projVector.x, CUR.tt_metrics.x_ratio, 0x4000 );
1230 y = TT_MULDIV( CUR.GS.projVector.y, CUR.tt_metrics.y_ratio, 0x4000 );
1231 CUR.tt_metrics.ratio = Norm( x, y );
David Turnerd2b1f351999-12-16 23:11:37 +00001232 }
1233
1234 return CUR.tt_metrics.ratio;
1235 }
1236
1237
1238 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001239 FT_Long Current_Ppem( EXEC_OP )
David Turnerd2b1f351999-12-16 23:11:37 +00001240 {
1241 return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );
1242 }
1243
1244
1245 /*************************************************************************/
1246 /* */
1247 /* Functions related to the control value table (CVT). */
1248 /* */
1249 /*************************************************************************/
1250
1251
David Turner76a5f622000-11-04 01:55:49 +00001252 FT_CALLBACK_DEF
David Turnerf9b8dec2000-06-16 19:34:52 +00001253 FT_F26Dot6 Read_CVT( EXEC_OP_ FT_ULong index )
David Turnerd2b1f351999-12-16 23:11:37 +00001254 {
1255 return CUR.cvt[index];
1256 }
1257
1258
David Turner76a5f622000-11-04 01:55:49 +00001259 FT_CALLBACK_DEF
David Turnerf9b8dec2000-06-16 19:34:52 +00001260 FT_F26Dot6 Read_CVT_Stretched( EXEC_OP_ FT_ULong index )
David Turnerd2b1f351999-12-16 23:11:37 +00001261 {
1262 return TT_MULFIX( CUR.cvt[index], CURRENT_Ratio() );
1263 }
1264
1265
David Turner76a5f622000-11-04 01:55:49 +00001266 FT_CALLBACK_DEF
David Turnerf9b8dec2000-06-16 19:34:52 +00001267 void Write_CVT( EXEC_OP_ FT_ULong index,
1268 FT_F26Dot6 value )
David Turnerd2b1f351999-12-16 23:11:37 +00001269 {
1270 CUR.cvt[index] = value;
1271 }
1272
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001273
David Turner76a5f622000-11-04 01:55:49 +00001274 FT_CALLBACK_DEF
David Turnerf9b8dec2000-06-16 19:34:52 +00001275 void Write_CVT_Stretched( EXEC_OP_ FT_ULong index,
1276 FT_F26Dot6 value )
David Turnerd2b1f351999-12-16 23:11:37 +00001277 {
1278 CUR.cvt[index] = FT_DivFix( value, CURRENT_Ratio() );
1279 }
1280
1281
David Turner76a5f622000-11-04 01:55:49 +00001282 FT_CALLBACK_DEF
David Turnerf9b8dec2000-06-16 19:34:52 +00001283 void Move_CVT( EXEC_OP_ FT_ULong index,
1284 FT_F26Dot6 value )
David Turnerd2b1f351999-12-16 23:11:37 +00001285 {
1286 CUR.cvt[index] += value;
1287 }
1288
1289
David Turner76a5f622000-11-04 01:55:49 +00001290 FT_CALLBACK_DEF
David Turnerf9b8dec2000-06-16 19:34:52 +00001291 void Move_CVT_Stretched( EXEC_OP_ FT_ULong index,
1292 FT_F26Dot6 value )
David Turnerd2b1f351999-12-16 23:11:37 +00001293 {
1294 CUR.cvt[index] += FT_DivFix( value, CURRENT_Ratio() );
1295 }
1296
1297
1298 /*************************************************************************/
1299 /* */
1300 /* <Function> */
1301 /* GetShortIns */
1302 /* */
1303 /* <Description> */
1304 /* Returns a short integer taken from the instruction stream at */
1305 /* address IP. */
1306 /* */
1307 /* <Return> */
1308 /* Short read at code[IP]. */
1309 /* */
1310 /* <Note> */
1311 /* This one could become a macro. */
1312 /* */
David Turnerf9b8dec2000-06-16 19:34:52 +00001313 static FT_Short GetShortIns( EXEC_OP )
David Turnerd2b1f351999-12-16 23:11:37 +00001314 {
1315 /* Reading a byte stream so there is no endianess (DaveP) */
1316 CUR.IP += 2;
David Turnerf9b8dec2000-06-16 19:34:52 +00001317 return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) +
Werner Lemberg78575dc2000-06-12 19:36:41 +00001318 CUR.code[CUR.IP - 1] );
David Turnerd2b1f351999-12-16 23:11:37 +00001319 }
1320
1321
1322 /*************************************************************************/
1323 /* */
1324 /* <Function> */
1325 /* Ins_Goto_CodeRange */
1326 /* */
1327 /* <Description> */
1328 /* Goes to a certain code range in the instruction stream. */
1329 /* */
1330 /* <Input> */
1331 /* aRange :: The index of the code range. */
1332 /* */
1333 /* aIP :: The new IP address in the code range. */
1334 /* */
1335 /* <Return> */
1336 /* SUCCESS or FAILURE. */
1337 /* */
1338 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001339 FT_Bool Ins_Goto_CodeRange( EXEC_OP_ FT_Int aRange,
1340 FT_ULong aIP )
David Turnerd2b1f351999-12-16 23:11:37 +00001341 {
1342 TT_CodeRange* range;
1343
1344
1345 if ( aRange < 1 || aRange > 3 )
1346 {
1347 CUR.error = TT_Err_Bad_Argument;
1348 return FAILURE;
1349 }
1350
1351 range = &CUR.codeRangeTable[aRange - 1];
1352
1353 if ( range->base == NULL ) /* invalid coderange */
1354 {
1355 CUR.error = TT_Err_Invalid_CodeRange;
1356 return FAILURE;
1357 }
1358
1359 /* NOTE: Because the last instruction of a program may be a CALL */
1360 /* which will return to the first byte *after* the code */
1361 /* range, we test for AIP <= Size, instead of AIP < Size. */
1362
1363 if ( aIP > range->size )
1364 {
1365 CUR.error = TT_Err_Code_Overflow;
1366 return FAILURE;
1367 }
1368
1369 CUR.code = range->base;
1370 CUR.codeSize = range->size;
1371 CUR.IP = aIP;
1372 CUR.curRange = aRange;
1373
1374 return SUCCESS;
1375 }
1376
1377
1378 /*************************************************************************/
1379 /* */
1380 /* <Function> */
1381 /* Direct_Move */
1382 /* */
1383 /* <Description> */
1384 /* Moves a point by a given distance along the freedom vector. The */
1385 /* point will be `touched'. */
1386 /* */
1387 /* <Input> */
1388 /* point :: The index of the point to move. */
Werner Lemberg78575dc2000-06-12 19:36:41 +00001389 /* */
David Turnerd2b1f351999-12-16 23:11:37 +00001390 /* distance :: The distance to apply. */
1391 /* */
1392 /* <InOut> */
1393 /* zone :: The affected glyph zone. */
1394 /* */
1395 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001396 void Direct_Move( EXEC_OP_ TT_GlyphZone* zone,
1397 FT_UShort point,
1398 FT_F26Dot6 distance )
David Turnerd2b1f351999-12-16 23:11:37 +00001399 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001400 FT_F26Dot6 v;
David Turnerd2b1f351999-12-16 23:11:37 +00001401
1402
1403 v = CUR.GS.freeVector.x;
1404
1405 if ( v != 0 )
1406 {
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001407
David Turnerd42c68e2000-01-27 13:56:02 +00001408#ifdef NO_APPLE_PATENT
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001409
Werner Lemberg78575dc2000-06-12 19:36:41 +00001410 if ( ABS( CUR.F_dot_P ) > APPLE_THRESHOLD )
David Turnerd42c68e2000-01-27 13:56:02 +00001411 zone->cur[point].x += distance;
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001412
David Turnerd42c68e2000-01-27 13:56:02 +00001413#else
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001414
David Turnerd2b1f351999-12-16 23:11:37 +00001415 zone->cur[point].x += TT_MULDIV( distance,
1416 v * 0x10000L,
1417 CUR.F_dot_P );
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001418
David Turnerd42c68e2000-01-27 13:56:02 +00001419#endif
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001420
David Turner41dbcbf2000-03-09 11:46:25 +00001421 zone->tags[point] |= FT_Curve_Tag_Touch_X;
David Turnerd2b1f351999-12-16 23:11:37 +00001422 }
1423
1424 v = CUR.GS.freeVector.y;
1425
1426 if ( v != 0 )
1427 {
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001428
David Turnerd42c68e2000-01-27 13:56:02 +00001429#ifdef NO_APPLE_PATENT
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001430
Werner Lemberg78575dc2000-06-12 19:36:41 +00001431 if ( ABS( CUR.F_dot_P ) > APPLE_THRESHOLD )
David Turnerd42c68e2000-01-27 13:56:02 +00001432 zone->cur[point].y += distance;
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001433
David Turnerd42c68e2000-01-27 13:56:02 +00001434#else
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001435
David Turnerd2b1f351999-12-16 23:11:37 +00001436 zone->cur[point].y += TT_MULDIV( distance,
1437 v * 0x10000L,
1438 CUR.F_dot_P );
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001439
David Turnerd42c68e2000-01-27 13:56:02 +00001440#endif
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001441
David Turner41dbcbf2000-03-09 11:46:25 +00001442 zone->tags[point] |= FT_Curve_Tag_Touch_Y;
David Turnerd2b1f351999-12-16 23:11:37 +00001443 }
1444 }
1445
1446
1447 /*************************************************************************/
1448 /* */
1449 /* Special versions of Direct_Move() */
1450 /* */
1451 /* The following versions are used whenever both vectors are both */
Werner Lemberg78575dc2000-06-12 19:36:41 +00001452 /* along one of the coordinate unit vectors, i.e. in 90% of the cases. */
David Turnerd2b1f351999-12-16 23:11:37 +00001453 /* */
1454 /*************************************************************************/
1455
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001456
David Turnerd2b1f351999-12-16 23:11:37 +00001457 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001458 void Direct_Move_X( EXEC_OP_ TT_GlyphZone* zone,
1459 FT_UShort point,
1460 FT_F26Dot6 distance )
David Turnerd2b1f351999-12-16 23:11:37 +00001461 {
David Turnerc6a92202000-07-04 18:12:13 +00001462 FT_UNUSED_EXEC;
David Turnerd2b1f351999-12-16 23:11:37 +00001463
1464 zone->cur[point].x += distance;
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001465 zone->tags[point] |= FT_Curve_Tag_Touch_X;
David Turnerd2b1f351999-12-16 23:11:37 +00001466 }
1467
1468
1469 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001470 void Direct_Move_Y( EXEC_OP_ TT_GlyphZone* zone,
1471 FT_UShort point,
1472 FT_F26Dot6 distance )
David Turnerd2b1f351999-12-16 23:11:37 +00001473 {
David Turnerc6a92202000-07-04 18:12:13 +00001474 FT_UNUSED_EXEC;
David Turnerd2b1f351999-12-16 23:11:37 +00001475
1476 zone->cur[point].y += distance;
Werner Lemberg5811c7c2000-07-02 13:53:16 +00001477 zone->tags[point] |= FT_Curve_Tag_Touch_Y;
David Turnerd2b1f351999-12-16 23:11:37 +00001478 }
1479
1480
1481 /*************************************************************************/
1482 /* */
1483 /* <Function> */
1484 /* Round_None */
1485 /* */
1486 /* <Description> */
1487 /* Does not round, but adds engine compensation. */
1488 /* */
1489 /* <Input> */
1490 /* distance :: The distance (not) to round. */
Werner Lemberg78575dc2000-06-12 19:36:41 +00001491 /* */
David Turnerd2b1f351999-12-16 23:11:37 +00001492 /* compensation :: The engine compensation. */
1493 /* */
1494 /* <Return> */
1495 /* The compensated distance. */
1496 /* */
1497 /* <Note> */
1498 /* The TrueType specification says very few about the relationship */
1499 /* between rounding and engine compensation. However, it seems from */
1500 /* the description of super round that we should add the compensation */
1501 /* before rounding. */
1502 /* */
1503 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001504 FT_F26Dot6 Round_None( EXEC_OP_ FT_F26Dot6 distance,
1505 FT_F26Dot6 compensation )
David Turnerd2b1f351999-12-16 23:11:37 +00001506 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001507 FT_F26Dot6 val;
David Turnerd2b1f351999-12-16 23:11:37 +00001508
David Turnerc6a92202000-07-04 18:12:13 +00001509 FT_UNUSED_EXEC;
David Turnerd2b1f351999-12-16 23:11:37 +00001510
Werner Lemberg78575dc2000-06-12 19:36:41 +00001511
David Turnerd2b1f351999-12-16 23:11:37 +00001512 if ( distance >= 0 )
1513 {
1514 val = distance + compensation;
1515 if ( val < 0 )
1516 val = 0;
1517 }
1518 else {
1519 val = distance - compensation;
1520 if ( val > 0 )
1521 val = 0;
1522 }
1523 return val;
1524 }
1525
1526
1527 /*************************************************************************/
1528 /* */
1529 /* <Function> */
1530 /* Round_To_Grid */
1531 /* */
1532 /* <Description> */
1533 /* Rounds value to grid after adding engine compensation. */
1534 /* */
1535 /* <Input> */
1536 /* distance :: The distance to round. */
Werner Lemberg78575dc2000-06-12 19:36:41 +00001537 /* */
David Turnerd2b1f351999-12-16 23:11:37 +00001538 /* compensation :: The engine compensation. */
1539 /* */
1540 /* <Return> */
1541 /* Rounded distance. */
1542 /* */
1543 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001544 FT_F26Dot6 Round_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1545 FT_F26Dot6 compensation )
David Turnerd2b1f351999-12-16 23:11:37 +00001546 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001547 FT_F26Dot6 val;
David Turnerd2b1f351999-12-16 23:11:37 +00001548
David Turnerc6a92202000-07-04 18:12:13 +00001549 FT_UNUSED_EXEC;
David Turnerd2b1f351999-12-16 23:11:37 +00001550
Werner Lemberg78575dc2000-06-12 19:36:41 +00001551
David Turnerd2b1f351999-12-16 23:11:37 +00001552 if ( distance >= 0 )
1553 {
1554 val = distance + compensation + 32;
1555 if ( val > 0 )
1556 val &= ~63;
1557 else
1558 val = 0;
1559 }
1560 else
1561 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00001562 val = -( ( compensation - distance + 32 ) & -64 );
David Turnerd2b1f351999-12-16 23:11:37 +00001563 if ( val > 0 )
1564 val = 0;
1565 }
Werner Lemberg78575dc2000-06-12 19:36:41 +00001566
David Turnerd2b1f351999-12-16 23:11:37 +00001567 return val;
1568 }
1569
1570
1571 /*************************************************************************/
1572 /* */
1573 /* <Function> */
1574 /* Round_To_Half_Grid */
1575 /* */
1576 /* <Description> */
1577 /* Rounds value to half grid after adding engine compensation. */
1578 /* */
1579 /* <Input> */
1580 /* distance :: The distance to round. */
Werner Lemberg78575dc2000-06-12 19:36:41 +00001581 /* */
David Turnerd2b1f351999-12-16 23:11:37 +00001582 /* compensation :: The engine compensation. */
1583 /* */
1584 /* <Return> */
1585 /* Rounded distance. */
1586 /* */
1587 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001588 FT_F26Dot6 Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6 distance,
1589 FT_F26Dot6 compensation )
David Turnerd2b1f351999-12-16 23:11:37 +00001590 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001591 FT_F26Dot6 val;
David Turnerd2b1f351999-12-16 23:11:37 +00001592
David Turnerc6a92202000-07-04 18:12:13 +00001593 FT_UNUSED_EXEC;
David Turnere49ab252000-05-16 23:44:38 +00001594
David Turnerd2b1f351999-12-16 23:11:37 +00001595
1596 if ( distance >= 0 )
1597 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00001598 val = ( ( distance + compensation ) & -64 ) + 32;
David Turnerd2b1f351999-12-16 23:11:37 +00001599 if ( val < 0 )
1600 val = 0;
1601 }
1602 else
1603 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00001604 val = -( ( (compensation - distance) & -64 ) + 32 );
David Turnerd2b1f351999-12-16 23:11:37 +00001605 if ( val > 0 )
1606 val = 0;
1607 }
Werner Lemberg78575dc2000-06-12 19:36:41 +00001608
David Turnerd2b1f351999-12-16 23:11:37 +00001609 return val;
1610 }
1611
1612
1613 /*************************************************************************/
1614 /* */
1615 /* <Function> */
1616 /* Round_Down_To_Grid */
1617 /* */
1618 /* <Description> */
1619 /* Rounds value down to grid after adding engine compensation. */
1620 /* */
1621 /* <Input> */
1622 /* distance :: The distance to round. */
Werner Lemberg78575dc2000-06-12 19:36:41 +00001623 /* */
David Turnerd2b1f351999-12-16 23:11:37 +00001624 /* compensation :: The engine compensation. */
1625 /* */
1626 /* <Return> */
1627 /* Rounded distance. */
1628 /* */
1629 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001630 FT_F26Dot6 Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1631 FT_F26Dot6 compensation )
David Turnerd2b1f351999-12-16 23:11:37 +00001632 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001633 FT_F26Dot6 val;
David Turnerd2b1f351999-12-16 23:11:37 +00001634
David Turnerc6a92202000-07-04 18:12:13 +00001635 FT_UNUSED_EXEC;
David Turnerd2b1f351999-12-16 23:11:37 +00001636
Werner Lemberg78575dc2000-06-12 19:36:41 +00001637
David Turnerd2b1f351999-12-16 23:11:37 +00001638 if ( distance >= 0 )
1639 {
1640 val = distance + compensation;
1641 if ( val > 0 )
1642 val &= ~63;
1643 else
1644 val = 0;
1645 }
1646 else
1647 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00001648 val = -( ( compensation - distance ) & -64 );
David Turnerd2b1f351999-12-16 23:11:37 +00001649 if ( val > 0 )
1650 val = 0;
1651 }
Werner Lemberg78575dc2000-06-12 19:36:41 +00001652
David Turnerd2b1f351999-12-16 23:11:37 +00001653 return val;
1654 }
1655
1656
1657 /*************************************************************************/
1658 /* */
1659 /* <Function> */
1660 /* Round_Up_To_Grid */
1661 /* */
1662 /* <Description> */
1663 /* Rounds value up to grid after adding engine compensation. */
1664 /* */
1665 /* <Input> */
1666 /* distance :: The distance to round. */
Werner Lemberg78575dc2000-06-12 19:36:41 +00001667 /* */
David Turnerd2b1f351999-12-16 23:11:37 +00001668 /* compensation :: The engine compensation. */
1669 /* */
1670 /* <Return> */
1671 /* Rounded distance. */
1672 /* */
1673 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001674 FT_F26Dot6 Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6 distance,
1675 FT_F26Dot6 compensation )
David Turnerd2b1f351999-12-16 23:11:37 +00001676 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001677 FT_F26Dot6 val;
David Turnerd2b1f351999-12-16 23:11:37 +00001678
1679
David Turnerc6a92202000-07-04 18:12:13 +00001680 FT_UNUSED_EXEC;
David Turnerd2b1f351999-12-16 23:11:37 +00001681
1682 if ( distance >= 0 )
1683 {
1684 val = distance + compensation + 63;
1685 if ( val > 0 )
1686 val &= ~63;
1687 else
1688 val = 0;
1689 }
1690 else
1691 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00001692 val = -( ( compensation - distance + 63 ) & -64 );
David Turnerd2b1f351999-12-16 23:11:37 +00001693 if ( val > 0 )
1694 val = 0;
1695 }
Werner Lemberg78575dc2000-06-12 19:36:41 +00001696
David Turnerd2b1f351999-12-16 23:11:37 +00001697 return val;
1698 }
1699
1700
1701 /*************************************************************************/
1702 /* */
1703 /* <Function> */
1704 /* Round_To_Double_Grid */
1705 /* */
1706 /* <Description> */
1707 /* Rounds value to double grid after adding engine compensation. */
1708 /* */
1709 /* <Input> */
1710 /* distance :: The distance to round. */
Werner Lemberg78575dc2000-06-12 19:36:41 +00001711 /* */
David Turnerd2b1f351999-12-16 23:11:37 +00001712 /* compensation :: The engine compensation. */
1713 /* */
1714 /* <Return> */
1715 /* Rounded distance. */
1716 /* */
1717 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001718 FT_F26Dot6 Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6 distance,
1719 FT_F26Dot6 compensation )
David Turnerd2b1f351999-12-16 23:11:37 +00001720 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001721 FT_F26Dot6 val;
David Turnerd2b1f351999-12-16 23:11:37 +00001722
David Turnerc6a92202000-07-04 18:12:13 +00001723 FT_UNUSED_EXEC;
David Turnerd2b1f351999-12-16 23:11:37 +00001724
Werner Lemberg78575dc2000-06-12 19:36:41 +00001725
David Turnerd2b1f351999-12-16 23:11:37 +00001726 if ( distance >= 0 )
1727 {
1728 val = distance + compensation + 16;
1729 if ( val > 0 )
1730 val &= ~31;
1731 else
1732 val = 0;
1733 }
1734 else
1735 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00001736 val = -( ( compensation - distance + 16 ) & -32 );
David Turnerd2b1f351999-12-16 23:11:37 +00001737 if ( val > 0 )
1738 val = 0;
1739 }
Werner Lemberg78575dc2000-06-12 19:36:41 +00001740
David Turnerd2b1f351999-12-16 23:11:37 +00001741 return val;
1742 }
1743
1744
1745 /*************************************************************************/
1746 /* */
1747 /* <Function> */
1748 /* Round_Super */
1749 /* */
1750 /* <Description> */
1751 /* Super-rounds value to grid after adding engine compensation. */
1752 /* */
1753 /* <Input> */
1754 /* distance :: The distance to round. */
Werner Lemberg78575dc2000-06-12 19:36:41 +00001755 /* */
David Turnerd2b1f351999-12-16 23:11:37 +00001756 /* compensation :: The engine compensation. */
1757 /* */
1758 /* <Return> */
1759 /* Rounded distance. */
1760 /* */
1761 /* <Note> */
1762 /* The TrueType specification says very few about the relationship */
1763 /* between rounding and engine compensation. However, it seems from */
1764 /* the description of super round that we should add the compensation */
1765 /* before rounding. */
1766 /* */
1767 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001768 FT_F26Dot6 Round_Super( EXEC_OP_ FT_F26Dot6 distance,
1769 FT_F26Dot6 compensation )
David Turnerd2b1f351999-12-16 23:11:37 +00001770 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001771 FT_F26Dot6 val;
David Turnerd2b1f351999-12-16 23:11:37 +00001772
1773
1774 if ( distance >= 0 )
1775 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00001776 val = ( distance - CUR.phase + CUR.threshold + compensation ) &
1777 -CUR.period;
David Turnerd2b1f351999-12-16 23:11:37 +00001778 if ( val < 0 )
1779 val = 0;
1780 val += CUR.phase;
1781 }
1782 else
1783 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00001784 val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &
1785 -CUR.period );
David Turnerd2b1f351999-12-16 23:11:37 +00001786 if ( val > 0 )
1787 val = 0;
1788 val -= CUR.phase;
1789 }
Werner Lemberg78575dc2000-06-12 19:36:41 +00001790
David Turnerd2b1f351999-12-16 23:11:37 +00001791 return val;
1792 }
1793
1794
1795 /*************************************************************************/
1796 /* */
1797 /* <Function> */
1798 /* Round_Super_45 */
1799 /* */
1800 /* <Description> */
1801 /* Super-rounds value to grid after adding engine compensation. */
1802 /* */
1803 /* <Input> */
1804 /* distance :: The distance to round. */
Werner Lemberg78575dc2000-06-12 19:36:41 +00001805 /* */
David Turnerd2b1f351999-12-16 23:11:37 +00001806 /* compensation :: The engine compensation. */
1807 /* */
1808 /* <Return> */
1809 /* Rounded distance. */
1810 /* */
1811 /* <Note> */
1812 /* There is a separate function for Round_Super_45() as we may need */
1813 /* greater precision. */
1814 /* */
1815 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001816 FT_F26Dot6 Round_Super_45( EXEC_OP_ FT_F26Dot6 distance,
1817 FT_F26Dot6 compensation )
David Turnerd2b1f351999-12-16 23:11:37 +00001818 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001819 FT_F26Dot6 val;
David Turnerd2b1f351999-12-16 23:11:37 +00001820
1821
1822 if ( distance >= 0 )
1823 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00001824 val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
David Turnerd2b1f351999-12-16 23:11:37 +00001825 CUR.period ) * CUR.period;
1826 if ( val < 0 )
1827 val = 0;
1828 val += CUR.phase;
1829 }
1830 else
1831 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00001832 val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /
David Turnerd2b1f351999-12-16 23:11:37 +00001833 CUR.period ) * CUR.period );
1834 if ( val > 0 )
1835 val = 0;
1836 val -= CUR.phase;
1837 }
1838
1839 return val;
1840 }
1841
1842
1843 /*************************************************************************/
1844 /* */
1845 /* <Function> */
1846 /* Compute_Round */
1847 /* */
1848 /* <Description> */
1849 /* Sets the rounding mode. */
1850 /* */
1851 /* <Input> */
1852 /* round_mode :: The rounding mode to be used. */
1853 /* */
1854 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001855 void Compute_Round( EXEC_OP_ FT_Byte round_mode )
David Turnerd2b1f351999-12-16 23:11:37 +00001856 {
1857 switch ( round_mode )
1858 {
1859 case TT_Round_Off:
1860 CUR.func_round = (TT_Round_Func)Round_None;
1861 break;
1862
1863 case TT_Round_To_Grid:
1864 CUR.func_round = (TT_Round_Func)Round_To_Grid;
1865 break;
1866
1867 case TT_Round_Up_To_Grid:
1868 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
1869 break;
1870
1871 case TT_Round_Down_To_Grid:
1872 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
1873 break;
1874
1875 case TT_Round_To_Half_Grid:
1876 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
1877 break;
1878
1879 case TT_Round_To_Double_Grid:
1880 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
1881 break;
1882
1883 case TT_Round_Super:
1884 CUR.func_round = (TT_Round_Func)Round_Super;
1885 break;
1886
1887 case TT_Round_Super_45:
1888 CUR.func_round = (TT_Round_Func)Round_Super_45;
1889 break;
1890 }
1891 }
1892
1893
1894 /*************************************************************************/
1895 /* */
1896 /* <Function> */
1897 /* SetSuperRound */
1898 /* */
1899 /* <Description> */
1900 /* Sets Super Round parameters. */
1901 /* */
1902 /* <Input> */
1903 /* GridPeriod :: Grid period */
1904 /* selector :: SROUND opcode */
1905 /* */
1906 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001907 void SetSuperRound( EXEC_OP_ FT_F26Dot6 GridPeriod,
1908 FT_Long selector )
David Turnerd2b1f351999-12-16 23:11:37 +00001909 {
David Turnerf9b8dec2000-06-16 19:34:52 +00001910 switch ( (FT_Int)( selector & 0xC0 ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001911 {
1912 case 0:
1913 CUR.period = GridPeriod / 2;
1914 break;
1915
1916 case 0x40:
1917 CUR.period = GridPeriod;
1918 break;
1919
1920 case 0x80:
1921 CUR.period = GridPeriod * 2;
1922 break;
1923
1924 /* This opcode is reserved, but... */
1925
1926 case 0xC0:
1927 CUR.period = GridPeriod;
1928 break;
1929 }
1930
David Turnerf9b8dec2000-06-16 19:34:52 +00001931 switch ( (FT_Int)( selector & 0x30 ) )
David Turnerd2b1f351999-12-16 23:11:37 +00001932 {
1933 case 0:
1934 CUR.phase = 0;
1935 break;
1936
1937 case 0x10:
1938 CUR.phase = CUR.period / 4;
1939 break;
1940
1941 case 0x20:
1942 CUR.phase = CUR.period / 2;
1943 break;
1944
1945 case 0x30:
1946 CUR.phase = GridPeriod * 3 / 4;
1947 break;
1948 }
1949
1950 if ( (selector & 0x0F) == 0 )
1951 CUR.threshold = CUR.period - 1;
1952 else
David Turnerf9b8dec2000-06-16 19:34:52 +00001953 CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8;
David Turnerd2b1f351999-12-16 23:11:37 +00001954
1955 CUR.period /= 256;
1956 CUR.phase /= 256;
1957 CUR.threshold /= 256;
1958 }
1959
1960
1961 /*************************************************************************/
1962 /* */
1963 /* <Function> */
1964 /* Project */
1965 /* */
1966 /* <Description> */
1967 /* Computes the projection of vector given by (v2-v1) along the */
1968 /* current projection vector. */
1969 /* */
1970 /* <Input> */
1971 /* v1 :: First input vector. */
1972 /* v2 :: Second input vector. */
1973 /* */
1974 /* <Return> */
1975 /* The distance in F26dot6 format. */
1976 /* */
1977 static
David Turnerf9b8dec2000-06-16 19:34:52 +00001978 FT_F26Dot6 Project( EXEC_OP_ FT_Vector* v1,
1979 FT_Vector* v2 )
David Turnerd2b1f351999-12-16 23:11:37 +00001980 {
1981 return TT_MULDIV( v1->x - v2->x, CUR.GS.projVector.x, 0x4000 ) +
1982 TT_MULDIV( v1->y - v2->y, CUR.GS.projVector.y, 0x4000 );
1983 }
1984
1985
1986 /*************************************************************************/
1987 /* */
1988 /* <Function> */
1989 /* Dual_Project */
1990 /* */
1991 /* <Description> */
1992 /* Computes the projection of the vector given by (v2-v1) along the */
1993 /* current dual vector. */
1994 /* */
1995 /* <Input> */
1996 /* v1 :: First input vector. */
1997 /* v2 :: Second input vector. */
1998 /* */
1999 /* <Return> */
2000 /* The distance in F26dot6 format. */
2001 /* */
2002 static
David Turnerf9b8dec2000-06-16 19:34:52 +00002003 FT_F26Dot6 Dual_Project( EXEC_OP_ FT_Vector* v1,
2004 FT_Vector* v2 )
David Turnerd2b1f351999-12-16 23:11:37 +00002005 {
2006 return TT_MULDIV( v1->x - v2->x, CUR.GS.dualVector.x, 0x4000 ) +
2007 TT_MULDIV( v1->y - v2->y, CUR.GS.dualVector.y, 0x4000 );
2008 }
2009
2010
2011 /*************************************************************************/
2012 /* */
2013 /* <Function> */
2014 /* Free_Project */
2015 /* */
2016 /* <Description> */
2017 /* Computes the projection of the vector given by (v2-v1) along the */
2018 /* current freedom vector. */
2019 /* */
2020 /* <Input> */
2021 /* v1 :: First input vector. */
2022 /* v2 :: Second input vector. */
2023 /* */
2024 /* <Return> */
2025 /* The distance in F26dot6 format. */
2026 /* */
2027 static
David Turnerf9b8dec2000-06-16 19:34:52 +00002028 FT_F26Dot6 Free_Project( EXEC_OP_ FT_Vector* v1,
2029 FT_Vector* v2 )
David Turnerd2b1f351999-12-16 23:11:37 +00002030 {
2031 return TT_MULDIV( v1->x - v2->x, CUR.GS.freeVector.x, 0x4000 ) +
2032 TT_MULDIV( v1->y - v2->y, CUR.GS.freeVector.y, 0x4000 );
2033 }
2034
2035
2036 /*************************************************************************/
2037 /* */
2038 /* <Function> */
2039 /* Project_x */
2040 /* */
2041 /* <Description> */
2042 /* Computes the projection of the vector given by (v2-v1) along the */
2043 /* horizontal axis. */
2044 /* */
2045 /* <Input> */
2046 /* v1 :: First input vector. */
2047 /* v2 :: Second input vector. */
2048 /* */
2049 /* <Return> */
2050 /* The distance in F26dot6 format. */
2051 /* */
2052 static
David Turnerf9b8dec2000-06-16 19:34:52 +00002053 FT_F26Dot6 Project_x( EXEC_OP_ FT_Vector* v1,
2054 FT_Vector* v2 )
David Turnerd2b1f351999-12-16 23:11:37 +00002055 {
David Turnerc6a92202000-07-04 18:12:13 +00002056 FT_UNUSED_EXEC;
David Turnerd2b1f351999-12-16 23:11:37 +00002057
Werner Lemberg78575dc2000-06-12 19:36:41 +00002058 return ( v1->x - v2->x );
David Turnerd2b1f351999-12-16 23:11:37 +00002059 }
2060
2061
2062 /*************************************************************************/
2063 /* */
2064 /* <Function> */
2065 /* Project_y */
2066 /* */
2067 /* <Description> */
2068 /* Computes the projection of the vector given by (v2-v1) along the */
2069 /* vertical axis. */
2070 /* */
2071 /* <Input> */
2072 /* v1 :: First input vector. */
2073 /* v2 :: Second input vector. */
2074 /* */
2075 /* <Return> */
2076 /* The distance in F26dot6 format. */
2077 /* */
2078 static
David Turnerf9b8dec2000-06-16 19:34:52 +00002079 FT_F26Dot6 Project_y( EXEC_OP_ FT_Vector* v1,
2080 FT_Vector* v2 )
David Turnerd2b1f351999-12-16 23:11:37 +00002081 {
David Turnerc6a92202000-07-04 18:12:13 +00002082 FT_UNUSED_EXEC;
David Turnere49ab252000-05-16 23:44:38 +00002083
Werner Lemberg78575dc2000-06-12 19:36:41 +00002084 return ( v1->y - v2->y );
David Turnerd2b1f351999-12-16 23:11:37 +00002085 }
2086
2087
2088 /*************************************************************************/
2089 /* */
2090 /* <Function> */
2091 /* Compute_Funcs */
2092 /* */
2093 /* <Description> */
2094 /* Computes the projection and movement function pointers according */
2095 /* to the current graphics state. */
2096 /* */
2097 static
2098 void Compute_Funcs( EXEC_OP )
2099 {
2100 if ( CUR.GS.freeVector.x == 0x4000 )
2101 {
2102 CUR.func_freeProj = (TT_Project_Func)Project_x;
2103 CUR.F_dot_P = CUR.GS.projVector.x * 0x10000L;
2104 }
2105 else
2106 {
2107 if ( CUR.GS.freeVector.y == 0x4000 )
2108 {
2109 CUR.func_freeProj = (TT_Project_Func)Project_y;
2110 CUR.F_dot_P = CUR.GS.projVector.y * 0x10000L;
2111 }
2112 else
2113 {
2114 CUR.func_freeProj = (TT_Project_Func)Free_Project;
David Turnerf9b8dec2000-06-16 19:34:52 +00002115 CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
2116 (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
David Turnerd2b1f351999-12-16 23:11:37 +00002117 }
2118 }
2119
2120 if ( CUR.GS.projVector.x == 0x4000 )
2121 CUR.func_project = (TT_Project_Func)Project_x;
2122 else
2123 {
2124 if ( CUR.GS.projVector.y == 0x4000 )
2125 CUR.func_project = (TT_Project_Func)Project_y;
2126 else
2127 CUR.func_project = (TT_Project_Func)Project;
2128 }
2129
2130 if ( CUR.GS.dualVector.x == 0x4000 )
2131 CUR.func_dualproj = (TT_Project_Func)Project_x;
2132 else
2133 {
2134 if ( CUR.GS.dualVector.y == 0x4000 )
2135 CUR.func_dualproj = (TT_Project_Func)Project_y;
2136 else
2137 CUR.func_dualproj = (TT_Project_Func)Dual_Project;
2138 }
2139
2140 CUR.func_move = (TT_Move_Func)Direct_Move;
2141
2142 if ( CUR.F_dot_P == 0x40000000L )
2143 {
2144 if ( CUR.GS.freeVector.x == 0x4000 )
2145 CUR.func_move = (TT_Move_Func)Direct_Move_X;
2146 else
2147 {
2148 if ( CUR.GS.freeVector.y == 0x4000 )
2149 CUR.func_move = (TT_Move_Func)Direct_Move_Y;
2150 }
2151 }
2152
2153 /* at small sizes, F_dot_P can become too small, resulting */
2154 /* in overflows and `spikes' in a number of glyphs like `w'. */
2155
2156 if ( ABS( CUR.F_dot_P ) < 0x4000000L )
2157 CUR.F_dot_P = 0x40000000L;
2158
2159 /* Disable cached aspect ratio */
2160 CUR.tt_metrics.ratio = 0;
2161 }
2162
2163
2164 /*************************************************************************/
2165 /* */
2166 /* <Function> */
2167 /* Normalize */
2168 /* */
2169 /* <Description> */
2170 /* Norms a vector. */
2171 /* */
2172 /* <Input> */
2173 /* Vx :: The horizontal input vector coordinate. */
2174 /* Vy :: The vertical input vector coordinate. */
2175 /* */
2176 /* <Output> */
2177 /* R :: The normed unit vector. */
2178 /* */
2179 /* <Return> */
2180 /* Returns FAILURE if a vector parameter is zero. */
2181 /* */
2182 /* <Note> */
2183 /* In case Vx and Vy are both zero, Normalize() returns SUCCESS, and */
2184 /* R is undefined. */
2185 /* */
David Turnerb7ef2b02000-05-02 11:01:12 +00002186
2187#ifdef FT_CONFIG_OPTION_OLD_CALCS
Werner Lemberg78575dc2000-06-12 19:36:41 +00002188
2189 static
David Turnerf9b8dec2000-06-16 19:34:52 +00002190 FT_Bool Normalize( EXEC_OP_ FT_F26Dot6 Vx,
2191 FT_F26Dot6 Vy,
2192 FT_UnitVector* R )
David Turnerb7ef2b02000-05-02 11:01:12 +00002193 {
David Turnerf9b8dec2000-06-16 19:34:52 +00002194 FT_F26Dot6 W;
2195 FT_Bool S1, S2;
David Turnerb7ef2b02000-05-02 11:01:12 +00002196
David Turnerc6a92202000-07-04 18:12:13 +00002197 FT_UNUSED_EXEC;
David Turnere49ab252000-05-16 23:44:38 +00002198
Werner Lemberg78575dc2000-06-12 19:36:41 +00002199
David Turnerb7ef2b02000-05-02 11:01:12 +00002200 if ( ABS( Vx ) < 0x10000L && ABS( Vy ) < 0x10000L )
2201 {
2202 Vx *= 0x100;
2203 Vy *= 0x100;
2204
2205 W = Norm( Vx, Vy );
2206
2207 if ( W == 0 )
2208 {
Werner Lemberg5811c7c2000-07-02 13:53:16 +00002209 /* XXX: UNDOCUMENTED! It seems that it is possible to try */
Werner Lemberg78575dc2000-06-12 19:36:41 +00002210 /* to normalize the vector (0,0). Return immediately. */
David Turnerb7ef2b02000-05-02 11:01:12 +00002211 return SUCCESS;
2212 }
2213
David Turnerf9b8dec2000-06-16 19:34:52 +00002214 R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W );
2215 R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W );
David Turnerb7ef2b02000-05-02 11:01:12 +00002216
2217 return SUCCESS;
2218 }
2219
2220 W = Norm( Vx, Vy );
2221
2222 Vx = FT_MulDiv( Vx, 0x4000L, W );
2223 Vy = FT_MulDiv( Vy, 0x4000L, W );
2224
2225 W = Vx * Vx + Vy * Vy;
2226
2227 /* Now, we want that Sqrt( W ) = 0x4000 */
2228 /* Or 0x1000000 <= W < 0x1004000 */
2229
2230 if ( Vx < 0 )
2231 {
2232 Vx = -Vx;
2233 S1 = TRUE;
2234 }
2235 else
2236 S1 = FALSE;
2237
2238 if ( Vy < 0 )
2239 {
2240 Vy = -Vy;
2241 S2 = TRUE;
2242 }
2243 else
2244 S2 = FALSE;
2245
2246 while ( W < 0x1000000L )
2247 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00002248 /* We need to increase W by a minimal amount */
David Turnerb7ef2b02000-05-02 11:01:12 +00002249 if ( Vx < Vy )
2250 Vx++;
2251 else
2252 Vy++;
2253
2254 W = Vx * Vx + Vy * Vy;
2255 }
2256
2257 while ( W >= 0x1004000L )
2258 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00002259 /* We need to decrease W by a minimal amount */
David Turnerb7ef2b02000-05-02 11:01:12 +00002260 if ( Vx < Vy )
2261 Vx--;
2262 else
2263 Vy--;
2264
2265 W = Vx * Vx + Vy * Vy;
2266 }
2267
2268 /* Note that in various cases, we can only */
2269 /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
2270
2271 if ( S1 )
2272 Vx = -Vx;
2273
2274 if ( S2 )
2275 Vy = -Vy;
2276
David Turnerf9b8dec2000-06-16 19:34:52 +00002277 R->x = (FT_F2Dot14)Vx; /* Type conversion */
2278 R->y = (FT_F2Dot14)Vy; /* Type conversion */
David Turnerb7ef2b02000-05-02 11:01:12 +00002279
2280 return SUCCESS;
2281 }
Werner Lemberg78575dc2000-06-12 19:36:41 +00002282
David Turnere49ab252000-05-16 23:44:38 +00002283#else
Werner Lemberg78575dc2000-06-12 19:36:41 +00002284
David Turnerd2b1f351999-12-16 23:11:37 +00002285 static
David Turnerf9b8dec2000-06-16 19:34:52 +00002286 FT_Bool Normalize( EXEC_OP_ FT_F26Dot6 Vx,
2287 FT_F26Dot6 Vy,
2288 FT_UnitVector* R )
David Turnerd2b1f351999-12-16 23:11:37 +00002289 {
David Turnerac6cc412001-06-14 12:34:00 +00002290 FT_Vector v;
2291 FT_Angle angle;
2292
2293 angle = FT_Atan2( Vx, Vy );
David Turnerd2b1f351999-12-16 23:11:37 +00002294
David Turnerac6cc412001-06-14 12:34:00 +00002295 FT_Vector_Unit( &v, angle );
2296
2297 R->x = v.x >> 2;
2298 R->y = v.y >> 2;
2299
David Turnerd2b1f351999-12-16 23:11:37 +00002300 return SUCCESS;
2301 }
Werner Lemberg78575dc2000-06-12 19:36:41 +00002302
2303#endif /* FT_CONFIG_OPTION_OLD_CALCS */
2304
David Turnerd2b1f351999-12-16 23:11:37 +00002305
2306 /*************************************************************************/
2307 /* */
2308 /* Here we start with the implementation of the various opcodes. */
2309 /* */
2310 /*************************************************************************/
2311
2312
2313 static
David Turnerf9b8dec2000-06-16 19:34:52 +00002314 FT_Bool Ins_SxVTL( EXEC_OP_ FT_UShort aIdx1,
2315 FT_UShort aIdx2,
2316 FT_Int aOpc,
2317 FT_UnitVector* Vec )
David Turnerd2b1f351999-12-16 23:11:37 +00002318 {
David Turnerf9b8dec2000-06-16 19:34:52 +00002319 FT_Long A, B, C;
2320 FT_Vector* p1;
2321 FT_Vector* p2;
David Turnerd2b1f351999-12-16 23:11:37 +00002322
2323
2324 if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
2325 BOUNDS( aIdx2, CUR.zp1.n_points ) )
2326 {
2327 if ( CUR.pedantic_hinting )
2328 CUR.error = TT_Err_Invalid_Reference;
2329 return FAILURE;
2330 }
2331
2332 p1 = CUR.zp1.cur + aIdx2;
2333 p2 = CUR.zp2.cur + aIdx1;
2334
2335 A = p1->x - p2->x;
2336 B = p1->y - p2->y;
2337
Werner Lemberg78575dc2000-06-12 19:36:41 +00002338 if ( ( aOpc & 1 ) != 0 )
David Turnerd2b1f351999-12-16 23:11:37 +00002339 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00002340 C = B; /* counter clockwise rotation */
David Turnerd2b1f351999-12-16 23:11:37 +00002341 B = A;
2342 A = -C;
2343 }
2344
2345 NORMalize( A, B, Vec );
2346
2347 return SUCCESS;
2348 }
2349
2350
2351 /* When not using the big switch statements, the interpreter uses a */
2352 /* call table defined later below in this source. Each opcode must */
2353 /* thus have a corresponding function, even trivial ones. */
2354 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +00002355 /* They are all defined there. */
David Turnerd2b1f351999-12-16 23:11:37 +00002356
Werner Lemberg78575dc2000-06-12 19:36:41 +00002357#define DO_SVTCA \
2358 { \
David Turnerf9b8dec2000-06-16 19:34:52 +00002359 FT_Short A, B; \
Werner Lemberg78575dc2000-06-12 19:36:41 +00002360 \
2361 \
David Turnerf9b8dec2000-06-16 19:34:52 +00002362 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2363 B = A ^ (FT_Short)0x4000; \
Werner Lemberg78575dc2000-06-12 19:36:41 +00002364 \
2365 CUR.GS.freeVector.x = A; \
2366 CUR.GS.projVector.x = A; \
2367 CUR.GS.dualVector.x = A; \
2368 \
2369 CUR.GS.freeVector.y = B; \
2370 CUR.GS.projVector.y = B; \
2371 CUR.GS.dualVector.y = B; \
2372 \
2373 COMPUTE_Funcs(); \
David Turnerd2b1f351999-12-16 23:11:37 +00002374 }
2375
2376
Werner Lemberg78575dc2000-06-12 19:36:41 +00002377#define DO_SPVTCA \
2378 { \
David Turnerf9b8dec2000-06-16 19:34:52 +00002379 FT_Short A, B; \
Werner Lemberg78575dc2000-06-12 19:36:41 +00002380 \
2381 \
David Turnerf9b8dec2000-06-16 19:34:52 +00002382 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2383 B = A ^ (FT_Short)0x4000; \
Werner Lemberg78575dc2000-06-12 19:36:41 +00002384 \
2385 CUR.GS.projVector.x = A; \
2386 CUR.GS.dualVector.x = A; \
2387 \
2388 CUR.GS.projVector.y = B; \
2389 CUR.GS.dualVector.y = B; \
2390 \
2391 COMPUTE_Funcs(); \
David Turnerd2b1f351999-12-16 23:11:37 +00002392 }
2393
2394
Werner Lemberg78575dc2000-06-12 19:36:41 +00002395#define DO_SFVTCA \
2396 { \
David Turnerf9b8dec2000-06-16 19:34:52 +00002397 FT_Short A, B; \
Werner Lemberg78575dc2000-06-12 19:36:41 +00002398 \
2399 \
David Turnerf9b8dec2000-06-16 19:34:52 +00002400 A = (FT_Short)( CUR.opcode & 1 ) << 14; \
2401 B = A ^ (FT_Short)0x4000; \
Werner Lemberg78575dc2000-06-12 19:36:41 +00002402 \
2403 CUR.GS.freeVector.x = A; \
2404 CUR.GS.freeVector.y = B; \
2405 \
2406 COMPUTE_Funcs(); \
David Turnerd2b1f351999-12-16 23:11:37 +00002407 }
2408
2409
Werner Lemberg78575dc2000-06-12 19:36:41 +00002410#define DO_SPVTL \
David Turnerf9b8dec2000-06-16 19:34:52 +00002411 if ( INS_SxVTL( (FT_UShort)args[1], \
2412 (FT_UShort)args[0], \
Werner Lemberg78575dc2000-06-12 19:36:41 +00002413 CUR.opcode, \
2414 &CUR.GS.projVector ) == SUCCESS ) \
2415 { \
2416 CUR.GS.dualVector = CUR.GS.projVector; \
2417 COMPUTE_Funcs(); \
David Turnerd2b1f351999-12-16 23:11:37 +00002418 }
2419
2420
Werner Lemberg78575dc2000-06-12 19:36:41 +00002421#define DO_SFVTL \
David Turnerf9b8dec2000-06-16 19:34:52 +00002422 if ( INS_SxVTL( (FT_UShort)args[1], \
2423 (FT_UShort)args[0], \
Werner Lemberg78575dc2000-06-12 19:36:41 +00002424 CUR.opcode, \
2425 &CUR.GS.freeVector ) == SUCCESS ) \
David Turnerd2b1f351999-12-16 23:11:37 +00002426 COMPUTE_Funcs();
2427
2428
2429#define DO_SFVTPV \
2430 CUR.GS.freeVector = CUR.GS.projVector; \
2431 COMPUTE_Funcs();
2432
2433
2434#define DO_SPVFS \
2435 { \
David Turnerf9b8dec2000-06-16 19:34:52 +00002436 FT_Short S; \
2437 FT_Long X, Y; \
David Turnerd2b1f351999-12-16 23:11:37 +00002438 \
2439 \
2440 /* Only use low 16bits, then sign extend */ \
David Turnerf9b8dec2000-06-16 19:34:52 +00002441 S = (FT_Short)args[1]; \
2442 Y = (FT_Long)S; \
2443 S = (FT_Short)args[0]; \
2444 X = (FT_Long)S; \
David Turnerd2b1f351999-12-16 23:11:37 +00002445 \
2446 NORMalize( X, Y, &CUR.GS.projVector ); \
2447 \
2448 CUR.GS.dualVector = CUR.GS.projVector; \
2449 COMPUTE_Funcs(); \
2450 }
2451
2452
2453#define DO_SFVFS \
2454 { \
David Turnerf9b8dec2000-06-16 19:34:52 +00002455 FT_Short S; \
2456 FT_Long X, Y; \
David Turnerd2b1f351999-12-16 23:11:37 +00002457 \
2458 \
2459 /* Only use low 16bits, then sign extend */ \
David Turnerf9b8dec2000-06-16 19:34:52 +00002460 S = (FT_Short)args[1]; \
2461 Y = (FT_Long)S; \
2462 S = (FT_Short)args[0]; \
David Turnerd2b1f351999-12-16 23:11:37 +00002463 X = S; \
2464 \
2465 NORMalize( X, Y, &CUR.GS.freeVector ); \
2466 COMPUTE_Funcs(); \
2467 }
2468
2469
2470#define DO_GPV \
2471 args[0] = CUR.GS.projVector.x; \
2472 args[1] = CUR.GS.projVector.y;
2473
2474
2475#define DO_GFV \
2476 args[0] = CUR.GS.freeVector.x; \
2477 args[1] = CUR.GS.freeVector.y;
2478
2479
Werner Lemberg78575dc2000-06-12 19:36:41 +00002480#define DO_SRP0 \
David Turnerf9b8dec2000-06-16 19:34:52 +00002481 CUR.GS.rp0 = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00002482
2483
Werner Lemberg78575dc2000-06-12 19:36:41 +00002484#define DO_SRP1 \
David Turnerf9b8dec2000-06-16 19:34:52 +00002485 CUR.GS.rp1 = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00002486
2487
Werner Lemberg78575dc2000-06-12 19:36:41 +00002488#define DO_SRP2 \
David Turnerf9b8dec2000-06-16 19:34:52 +00002489 CUR.GS.rp2 = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00002490
2491
2492#define DO_RTHG \
2493 CUR.GS.round_state = TT_Round_To_Half_Grid; \
2494 CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
2495
2496
2497#define DO_RTG \
2498 CUR.GS.round_state = TT_Round_To_Grid; \
2499 CUR.func_round = (TT_Round_Func)Round_To_Grid;
2500
2501
2502#define DO_RTDG \
2503 CUR.GS.round_state = TT_Round_To_Double_Grid; \
2504 CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
2505
2506
2507#define DO_RUTG \
2508 CUR.GS.round_state = TT_Round_Up_To_Grid; \
2509 CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
2510
2511
2512#define DO_RDTG \
2513 CUR.GS.round_state = TT_Round_Down_To_Grid; \
2514 CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
2515
2516
2517#define DO_ROFF \
2518 CUR.GS.round_state = TT_Round_Off; \
2519 CUR.func_round = (TT_Round_Func)Round_None;
2520
2521
2522#define DO_SROUND \
2523 SET_SuperRound( 0x4000, args[0] ); \
2524 CUR.GS.round_state = TT_Round_Super; \
2525 CUR.func_round = (TT_Round_Func)Round_Super;
2526
2527
2528#define DO_S45ROUND \
2529 SET_SuperRound( 0x2D41, args[0] ); \
2530 CUR.GS.round_state = TT_Round_Super_45; \
2531 CUR.func_round = (TT_Round_Func)Round_Super_45;
2532
2533
2534#define DO_SLOOP \
2535 if ( args[0] < 0 ) \
2536 CUR.error = TT_Err_Bad_Argument; \
2537 else \
2538 CUR.GS.loop = args[0];
2539
2540
2541#define DO_SMD \
2542 CUR.GS.minimum_distance = args[0];
2543
2544
2545#define DO_SCVTCI \
David Turnerf9b8dec2000-06-16 19:34:52 +00002546 CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00002547
2548
2549#define DO_SSWCI \
David Turnerf9b8dec2000-06-16 19:34:52 +00002550 CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00002551
2552
2553 /* XXX: UNDOCUMENTED! or bug in the Windows engine? */
2554 /* */
2555 /* It seems that the value that is read here is */
2556 /* expressed in 16.16 format rather than in font */
Werner Lemberg5811c7c2000-07-02 13:53:16 +00002557 /* units. */
David Turnerd2b1f351999-12-16 23:11:37 +00002558 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +00002559#define DO_SSW \
David Turnerf9b8dec2000-06-16 19:34:52 +00002560 CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
David Turnerd2b1f351999-12-16 23:11:37 +00002561
2562
2563#define DO_FLIPON \
2564 CUR.GS.auto_flip = TRUE;
2565
2566
2567#define DO_FLIPOFF \
2568 CUR.GS.auto_flip = FALSE;
2569
2570
2571#define DO_SDB \
David Turnerf9b8dec2000-06-16 19:34:52 +00002572 CUR.GS.delta_base = (FT_Short)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00002573
2574
2575#define DO_SDS \
David Turnerf9b8dec2000-06-16 19:34:52 +00002576 CUR.GS.delta_shift = (FT_Short)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00002577
2578
2579#define DO_MD /* nothing */
2580
2581
2582#define DO_MPPEM \
2583 args[0] = CURRENT_Ppem();
2584
2585
Werner Lemberg78575dc2000-06-12 19:36:41 +00002586 /* Note: The pointSize should be irrelevant in a given font program; */
2587 /* we thus decide to return only the ppem. */
David Turnerd2b1f351999-12-16 23:11:37 +00002588#if 0
Werner Lemberg78575dc2000-06-12 19:36:41 +00002589
David Turnerd2b1f351999-12-16 23:11:37 +00002590#define DO_MPS \
2591 args[0] = CUR.metrics.pointSize;
Werner Lemberg78575dc2000-06-12 19:36:41 +00002592
David Turnerd2b1f351999-12-16 23:11:37 +00002593#else
Werner Lemberg78575dc2000-06-12 19:36:41 +00002594
2595#define DO_MPS \
David Turnerd2b1f351999-12-16 23:11:37 +00002596 args[0] = CURRENT_Ppem();
Werner Lemberg78575dc2000-06-12 19:36:41 +00002597
2598#endif /* 0 */
2599
David Turnerd2b1f351999-12-16 23:11:37 +00002600
2601#define DO_DUP \
2602 args[1] = args[0];
2603
2604
2605#define DO_CLEAR \
2606 CUR.new_top = 0;
2607
2608
2609#define DO_SWAP \
2610 { \
David Turnerf9b8dec2000-06-16 19:34:52 +00002611 FT_Long L; \
David Turnerd2b1f351999-12-16 23:11:37 +00002612 \
Werner Lemberg78575dc2000-06-12 19:36:41 +00002613 \
David Turnerd2b1f351999-12-16 23:11:37 +00002614 L = args[0]; \
2615 args[0] = args[1]; \
2616 args[1] = L; \
2617 }
2618
2619
2620#define DO_DEPTH \
2621 args[0] = CUR.top;
2622
2623
2624#define DO_CINDEX \
2625 { \
David Turnerf9b8dec2000-06-16 19:34:52 +00002626 FT_Long L; \
David Turnerd2b1f351999-12-16 23:11:37 +00002627 \
2628 \
2629 L = args[0]; \
2630 \
2631 if ( L <= 0 || L > CUR.args ) \
2632 CUR.error = TT_Err_Invalid_Reference; \
2633 else \
2634 args[0] = CUR.stack[CUR.args - L]; \
2635 }
2636
2637
2638#define DO_JROT \
2639 if ( args[1] != 0 ) \
2640 { \
2641 CUR.IP += args[0]; \
2642 CUR.step_ins = FALSE; \
2643 }
2644
2645
2646#define DO_JMPR \
2647 CUR.IP += args[0]; \
2648 CUR.step_ins = FALSE;
2649
2650
2651#define DO_JROF \
2652 if ( args[1] == 0 ) \
2653 { \
2654 CUR.IP += args[0]; \
2655 CUR.step_ins = FALSE; \
2656 }
2657
2658
Werner Lemberg78575dc2000-06-12 19:36:41 +00002659#define DO_LT \
2660 args[0] = ( args[0] < args[1] );
David Turnerd2b1f351999-12-16 23:11:37 +00002661
2662
Werner Lemberg78575dc2000-06-12 19:36:41 +00002663#define DO_LTEQ \
2664 args[0] = ( args[0] <= args[1] );
David Turnerd2b1f351999-12-16 23:11:37 +00002665
2666
Werner Lemberg78575dc2000-06-12 19:36:41 +00002667#define DO_GT \
2668 args[0] = ( args[0] > args[1] );
David Turnerd2b1f351999-12-16 23:11:37 +00002669
2670
Werner Lemberg78575dc2000-06-12 19:36:41 +00002671#define DO_GTEQ \
2672 args[0] = ( args[0] >= args[1] );
David Turnerd2b1f351999-12-16 23:11:37 +00002673
2674
Werner Lemberg78575dc2000-06-12 19:36:41 +00002675#define DO_EQ \
2676 args[0] = ( args[0] == args[1] );
David Turnerd2b1f351999-12-16 23:11:37 +00002677
2678
Werner Lemberg78575dc2000-06-12 19:36:41 +00002679#define DO_NEQ \
2680 args[0] = ( args[0] != args[1] );
David Turnerd2b1f351999-12-16 23:11:37 +00002681
2682
Werner Lemberg78575dc2000-06-12 19:36:41 +00002683#define DO_ODD \
2684 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
David Turnerd2b1f351999-12-16 23:11:37 +00002685
2686
Werner Lemberg78575dc2000-06-12 19:36:41 +00002687#define DO_EVEN \
2688 args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
David Turnerd2b1f351999-12-16 23:11:37 +00002689
2690
2691#define DO_AND \
2692 args[0] = ( args[0] && args[1] );
2693
2694
2695#define DO_OR \
2696 args[0] = ( args[0] || args[1] );
2697
2698
2699#define DO_NOT \
2700 args[0] = !args[0];
2701
2702
2703#define DO_ADD \
2704 args[0] += args[1];
2705
2706
2707#define DO_SUB \
2708 args[0] -= args[1];
2709
2710
2711#define DO_DIV \
2712 if ( args[1] == 0 ) \
2713 CUR.error = TT_Err_Divide_By_Zero; \
2714 else \
2715 args[0] = TT_MULDIV( args[0], 64L, args[1] );
2716
2717
2718#define DO_MUL \
2719 args[0] = TT_MULDIV( args[0], args[1], 64L );
2720
2721
2722#define DO_ABS \
2723 args[0] = ABS( args[0] );
2724
2725
2726#define DO_NEG \
2727 args[0] = -args[0];
2728
2729
2730#define DO_FLOOR \
2731 args[0] &= -64;
2732
2733
2734#define DO_CEILING \
Werner Lemberg78575dc2000-06-12 19:36:41 +00002735 args[0] = ( args[0] + 63 ) & -64;
David Turnerd2b1f351999-12-16 23:11:37 +00002736
2737
2738#define DO_RS \
2739 { \
David Turnerf9b8dec2000-06-16 19:34:52 +00002740 FT_ULong I = (FT_ULong)args[0]; \
David Turnerd2b1f351999-12-16 23:11:37 +00002741 \
2742 \
2743 if ( BOUNDS( I, CUR.storeSize ) ) \
2744 { \
2745 if ( CUR.pedantic_hinting ) \
2746 { \
2747 ARRAY_BOUND_ERROR; \
2748 } \
2749 else \
2750 args[0] = 0; \
2751 } \
2752 else \
2753 args[0] = CUR.storage[I]; \
2754 }
2755
2756
2757#define DO_WS \
2758 { \
David Turnerf9b8dec2000-06-16 19:34:52 +00002759 FT_ULong I = (FT_ULong)args[0]; \
David Turnerd2b1f351999-12-16 23:11:37 +00002760 \
2761 \
2762 if ( BOUNDS( I, CUR.storeSize ) ) \
2763 { \
2764 if ( CUR.pedantic_hinting ) \
2765 { \
2766 ARRAY_BOUND_ERROR; \
2767 } \
2768 } \
2769 else \
2770 CUR.storage[I] = args[1]; \
2771 }
2772
2773
Werner Lemberg78575dc2000-06-12 19:36:41 +00002774#define DO_RCVT \
2775 { \
David Turnerf9b8dec2000-06-16 19:34:52 +00002776 FT_ULong I = (FT_ULong)args[0]; \
Werner Lemberg78575dc2000-06-12 19:36:41 +00002777 \
2778 \
2779 if ( BOUNDS( I, CUR.cvtSize ) ) \
2780 { \
2781 if ( CUR.pedantic_hinting ) \
2782 { \
2783 ARRAY_BOUND_ERROR; \
2784 } \
2785 else \
2786 args[0] = 0; \
2787 } \
2788 else \
2789 args[0] = CUR_Func_read_cvt( I ); \
David Turnerd2b1f351999-12-16 23:11:37 +00002790 }
2791
2792
2793#define DO_WCVTP \
2794 { \
David Turnerf9b8dec2000-06-16 19:34:52 +00002795 FT_ULong I = (FT_ULong)args[0]; \
David Turnerd2b1f351999-12-16 23:11:37 +00002796 \
2797 \
2798 if ( BOUNDS( I, CUR.cvtSize ) ) \
2799 { \
2800 if ( CUR.pedantic_hinting ) \
2801 { \
2802 ARRAY_BOUND_ERROR; \
2803 } \
2804 } \
2805 else \
2806 CUR_Func_write_cvt( I, args[1] ); \
2807 }
2808
2809
2810#define DO_WCVTF \
2811 { \
David Turnerf9b8dec2000-06-16 19:34:52 +00002812 FT_ULong I = (FT_ULong)args[0]; \
David Turnerd2b1f351999-12-16 23:11:37 +00002813 \
2814 \
2815 if ( BOUNDS( I, CUR.cvtSize ) ) \
2816 { \
2817 if ( CUR.pedantic_hinting ) \
2818 { \
2819 ARRAY_BOUND_ERROR; \
2820 } \
2821 } \
2822 else \
2823 CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
2824 }
2825
2826
2827#define DO_DEBUG \
2828 CUR.error = TT_Err_Debug_OpCode;
2829
2830
2831#define DO_ROUND \
2832 args[0] = CUR_Func_round( \
2833 args[0], \
2834 CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
2835
2836
2837#define DO_NROUND \
2838 args[0] = ROUND_None( args[0], \
2839 CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
2840
2841
2842#define DO_MAX \
2843 if ( args[1] > args[0] ) \
2844 args[0] = args[1];
2845
2846
2847#define DO_MIN \
2848 if ( args[1] < args[0] ) \
2849 args[0] = args[1];
2850
2851
2852#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
2853
2854
2855#undef ARRAY_BOUND_ERROR
Werner Lemberg78575dc2000-06-12 19:36:41 +00002856#define ARRAY_BOUND_ERROR \
2857 { \
2858 CUR.error = TT_Err_Invalid_Reference; \
2859 return; \
2860 }
David Turnerd2b1f351999-12-16 23:11:37 +00002861
2862
2863 /*************************************************************************/
2864 /* */
2865 /* SVTCA[a]: Set (F and P) Vectors to Coordinate Axis */
2866 /* Opcode range: 0x00-0x01 */
2867 /* Stack: --> */
2868 /* */
2869 static
2870 void Ins_SVTCA( INS_ARG )
2871 {
2872 DO_SVTCA
2873 }
2874
2875
2876 /*************************************************************************/
2877 /* */
2878 /* SPVTCA[a]: Set PVector to Coordinate Axis */
2879 /* Opcode range: 0x02-0x03 */
2880 /* Stack: --> */
2881 /* */
2882 static
2883 void Ins_SPVTCA( INS_ARG )
2884 {
2885 DO_SPVTCA
2886 }
2887
2888
2889 /*************************************************************************/
2890 /* */
2891 /* SFVTCA[a]: Set FVector to Coordinate Axis */
2892 /* Opcode range: 0x04-0x05 */
2893 /* Stack: --> */
2894 /* */
2895 static
2896 void Ins_SFVTCA( INS_ARG )
2897 {
2898 DO_SFVTCA
2899 }
2900
2901
2902 /*************************************************************************/
2903 /* */
2904 /* SPVTL[a]: Set PVector To Line */
2905 /* Opcode range: 0x06-0x07 */
2906 /* Stack: uint32 uint32 --> */
2907 /* */
2908 static
2909 void Ins_SPVTL( INS_ARG )
2910 {
2911 DO_SPVTL
2912 }
2913
2914
2915 /*************************************************************************/
2916 /* */
2917 /* SFVTL[a]: Set FVector To Line */
2918 /* Opcode range: 0x08-0x09 */
2919 /* Stack: uint32 uint32 --> */
2920 /* */
2921 static
2922 void Ins_SFVTL( INS_ARG )
2923 {
2924 DO_SFVTL
2925 }
2926
2927
2928 /*************************************************************************/
2929 /* */
2930 /* SFVTPV[]: Set FVector To PVector */
2931 /* Opcode range: 0x0E */
2932 /* Stack: --> */
2933 /* */
2934 static
2935 void Ins_SFVTPV( INS_ARG )
2936 {
2937 DO_SFVTPV
2938 }
2939
2940
2941 /*************************************************************************/
2942 /* */
2943 /* SPVFS[]: Set PVector From Stack */
2944 /* Opcode range: 0x0A */
2945 /* Stack: f2.14 f2.14 --> */
2946 /* */
2947 static
2948 void Ins_SPVFS( INS_ARG )
2949 {
2950 DO_SPVFS
2951 }
2952
2953
2954 /*************************************************************************/
2955 /* */
2956 /* SFVFS[]: Set FVector From Stack */
2957 /* Opcode range: 0x0B */
2958 /* Stack: f2.14 f2.14 --> */
2959 /* */
2960 static
2961 void Ins_SFVFS( INS_ARG )
2962 {
2963 DO_SFVFS
2964 }
2965
2966
2967 /*************************************************************************/
2968 /* */
2969 /* GPV[]: Get Projection Vector */
2970 /* Opcode range: 0x0C */
2971 /* Stack: ef2.14 --> ef2.14 */
2972 /* */
2973 static
2974 void Ins_GPV( INS_ARG )
2975 {
2976 DO_GPV
2977 }
2978
2979
2980 /*************************************************************************/
2981 /* GFV[]: Get Freedom Vector */
2982 /* Opcode range: 0x0D */
2983 /* Stack: ef2.14 --> ef2.14 */
2984 /* */
2985 static
2986 void Ins_GFV( INS_ARG )
2987 {
2988 DO_GFV
2989 }
2990
2991
2992 /*************************************************************************/
2993 /* */
2994 /* SRP0[]: Set Reference Point 0 */
2995 /* Opcode range: 0x10 */
2996 /* Stack: uint32 --> */
2997 /* */
2998 static
2999 void Ins_SRP0( INS_ARG )
3000 {
3001 DO_SRP0
3002 }
3003
3004
3005 /*************************************************************************/
3006 /* */
3007 /* SRP1[]: Set Reference Point 1 */
3008 /* Opcode range: 0x11 */
3009 /* Stack: uint32 --> */
3010 /* */
3011 static
3012 void Ins_SRP1( INS_ARG )
3013 {
3014 DO_SRP1
3015 }
3016
3017
3018 /*************************************************************************/
3019 /* */
3020 /* SRP2[]: Set Reference Point 2 */
3021 /* Opcode range: 0x12 */
3022 /* Stack: uint32 --> */
3023 /* */
3024 static
3025 void Ins_SRP2( INS_ARG )
3026 {
3027 DO_SRP2
3028 }
3029
3030
3031 /*************************************************************************/
3032 /* */
3033 /* RTHG[]: Round To Half Grid */
3034 /* Opcode range: 0x19 */
3035 /* Stack: --> */
3036 /* */
3037 static
3038 void Ins_RTHG( INS_ARG )
3039 {
3040 DO_RTHG
3041 }
3042
3043
3044 /*************************************************************************/
3045 /* */
3046 /* RTG[]: Round To Grid */
3047 /* Opcode range: 0x18 */
3048 /* Stack: --> */
3049 /* */
3050 static
3051 void Ins_RTG( INS_ARG )
3052 {
3053 DO_RTG
3054 }
3055
3056
3057 /*************************************************************************/
3058 /* RTDG[]: Round To Double Grid */
3059 /* Opcode range: 0x3D */
3060 /* Stack: --> */
3061 /* */
3062 static
3063 void Ins_RTDG( INS_ARG )
3064 {
3065 DO_RTDG
3066 }
3067
3068
3069 /*************************************************************************/
3070 /* RUTG[]: Round Up To Grid */
3071 /* Opcode range: 0x7C */
3072 /* Stack: --> */
3073 /* */
3074 static
3075 void Ins_RUTG( INS_ARG )
3076 {
3077 DO_RUTG
3078 }
3079
3080
3081 /*************************************************************************/
3082 /* */
3083 /* RDTG[]: Round Down To Grid */
3084 /* Opcode range: 0x7D */
3085 /* Stack: --> */
3086 /* */
3087 static
3088 void Ins_RDTG( INS_ARG )
3089 {
3090 DO_RDTG
3091 }
3092
3093
3094 /*************************************************************************/
3095 /* */
3096 /* ROFF[]: Round OFF */
3097 /* Opcode range: 0x7A */
3098 /* Stack: --> */
3099 /* */
3100 static
3101 void Ins_ROFF( INS_ARG )
3102 {
3103 DO_ROFF
3104 }
3105
3106
3107 /*************************************************************************/
3108 /* */
3109 /* SROUND[]: Super ROUND */
3110 /* Opcode range: 0x76 */
3111 /* Stack: Eint8 --> */
3112 /* */
3113 static
3114 void Ins_SROUND( INS_ARG )
3115 {
3116 DO_SROUND
3117 }
3118
3119
3120 /*************************************************************************/
3121 /* */
3122 /* S45ROUND[]: Super ROUND 45 degrees */
3123 /* Opcode range: 0x77 */
3124 /* Stack: uint32 --> */
3125 /* */
3126 static
3127 void Ins_S45ROUND( INS_ARG )
3128 {
3129 DO_S45ROUND
3130 }
3131
3132
3133 /*************************************************************************/
3134 /* */
3135 /* SLOOP[]: Set LOOP variable */
3136 /* Opcode range: 0x17 */
3137 /* Stack: int32? --> */
3138 /* */
3139 static
3140 void Ins_SLOOP( INS_ARG )
3141 {
3142 DO_SLOOP
3143 }
3144
3145
3146 /*************************************************************************/
3147 /* */
3148 /* SMD[]: Set Minimum Distance */
3149 /* Opcode range: 0x1A */
3150 /* Stack: f26.6 --> */
3151 /* */
3152 static
3153 void Ins_SMD( INS_ARG )
3154 {
3155 DO_SMD
3156 }
3157
3158
3159 /*************************************************************************/
3160 /* */
3161 /* SCVTCI[]: Set Control Value Table Cut In */
3162 /* Opcode range: 0x1D */
3163 /* Stack: f26.6 --> */
3164 /* */
3165 static
3166 void Ins_SCVTCI( INS_ARG )
3167 {
3168 DO_SCVTCI
3169 }
3170
3171
3172 /*************************************************************************/
3173 /* */
3174 /* SSWCI[]: Set Single Width Cut In */
3175 /* Opcode range: 0x1E */
3176 /* Stack: f26.6 --> */
3177 /* */
3178 static
3179 void Ins_SSWCI( INS_ARG )
3180 {
3181 DO_SSWCI
3182 }
3183
3184
3185 /*************************************************************************/
3186 /* */
3187 /* SSW[]: Set Single Width */
3188 /* Opcode range: 0x1F */
3189 /* Stack: int32? --> */
3190 /* */
3191 static
3192 void Ins_SSW( INS_ARG )
3193 {
3194 DO_SSW
3195 }
3196
3197
3198 /*************************************************************************/
3199 /* */
3200 /* FLIPON[]: Set auto-FLIP to ON */
3201 /* Opcode range: 0x4D */
3202 /* Stack: --> */
3203 /* */
3204 static
3205 void Ins_FLIPON( INS_ARG )
3206 {
3207 DO_FLIPON
3208 }
3209
3210
3211 /*************************************************************************/
3212 /* */
3213 /* FLIPOFF[]: Set auto-FLIP to OFF */
3214 /* Opcode range: 0x4E */
3215 /* Stack: --> */
3216 /* */
3217 static
3218 void Ins_FLIPOFF( INS_ARG )
3219 {
3220 DO_FLIPOFF
3221 }
3222
3223
3224 /*************************************************************************/
3225 /* */
3226 /* SANGW[]: Set ANGle Weight */
3227 /* Opcode range: 0x7E */
3228 /* Stack: uint32 --> */
3229 /* */
3230 static
3231 void Ins_SANGW( INS_ARG )
3232 {
3233 /* instruction not supported anymore */
3234 }
3235
3236
3237 /*************************************************************************/
3238 /* */
3239 /* SDB[]: Set Delta Base */
3240 /* Opcode range: 0x5E */
3241 /* Stack: uint32 --> */
3242 /* */
3243 static
3244 void Ins_SDB( INS_ARG )
3245 {
3246 DO_SDB
3247 }
3248
3249
3250 /*************************************************************************/
3251 /* */
3252 /* SDS[]: Set Delta Shift */
3253 /* Opcode range: 0x5F */
3254 /* Stack: uint32 --> */
3255 /* */
3256 static
3257 void Ins_SDS( INS_ARG )
3258 {
3259 DO_SDS
3260 }
3261
3262
3263 /*************************************************************************/
3264 /* */
3265 /* MPPEM[]: Measure Pixel Per EM */
3266 /* Opcode range: 0x4B */
3267 /* Stack: --> Euint16 */
3268 /* */
3269 static
3270 void Ins_MPPEM( INS_ARG )
3271 {
3272 DO_MPPEM
3273 }
3274
3275
3276 /*************************************************************************/
3277 /* */
3278 /* MPS[]: Measure Point Size */
3279 /* Opcode range: 0x4C */
3280 /* Stack: --> Euint16 */
3281 /* */
3282 static
3283 void Ins_MPS( INS_ARG )
3284 {
3285 DO_MPS
3286 }
3287
3288
3289 /*************************************************************************/
3290 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +00003291 /* DUP[]: DUPlicate the top stack's element */
David Turnerd2b1f351999-12-16 23:11:37 +00003292 /* Opcode range: 0x20 */
3293 /* Stack: StkElt --> StkElt StkElt */
3294 /* */
3295 static
3296 void Ins_DUP( INS_ARG )
3297 {
3298 DO_DUP
3299 }
3300
3301
3302 /*************************************************************************/
3303 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +00003304 /* POP[]: POP the stack's top element */
David Turnerd2b1f351999-12-16 23:11:37 +00003305 /* Opcode range: 0x21 */
3306 /* Stack: StkElt --> */
3307 /* */
3308 static
3309 void Ins_POP( INS_ARG )
3310 {
3311 /* nothing to do */
3312 }
3313
3314
3315 /*************************************************************************/
3316 /* */
3317 /* CLEAR[]: CLEAR the entire stack */
3318 /* Opcode range: 0x22 */
3319 /* Stack: StkElt... --> */
3320 /* */
3321 static
3322 void Ins_CLEAR( INS_ARG )
3323 {
3324 DO_CLEAR
3325 }
3326
3327
3328 /*************************************************************************/
3329 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +00003330 /* SWAP[]: SWAP the stack's top two elements */
David Turnerd2b1f351999-12-16 23:11:37 +00003331 /* Opcode range: 0x23 */
3332 /* Stack: 2 * StkElt --> 2 * StkElt */
3333 /* */
3334 static
3335 void Ins_SWAP( INS_ARG )
3336 {
3337 DO_SWAP
3338 }
3339
3340
3341 /*************************************************************************/
3342 /* */
3343 /* DEPTH[]: return the stack DEPTH */
3344 /* Opcode range: 0x24 */
3345 /* Stack: --> uint32 */
3346 /* */
3347 static
3348 void Ins_DEPTH( INS_ARG )
3349 {
3350 DO_DEPTH
3351 }
3352
3353
3354 /*************************************************************************/
3355 /* */
3356 /* CINDEX[]: Copy INDEXed element */
3357 /* Opcode range: 0x25 */
3358 /* Stack: int32 --> StkElt */
3359 /* */
3360 static
3361 void Ins_CINDEX( INS_ARG )
3362 {
3363 DO_CINDEX
3364 }
3365
3366
3367 /*************************************************************************/
3368 /* */
3369 /* EIF[]: End IF */
3370 /* Opcode range: 0x59 */
3371 /* Stack: --> */
3372 /* */
3373 static
3374 void Ins_EIF( INS_ARG )
3375 {
3376 /* nothing to do */
3377 }
3378
3379
3380 /*************************************************************************/
3381 /* */
3382 /* JROT[]: Jump Relative On True */
3383 /* Opcode range: 0x78 */
3384 /* Stack: StkElt int32 --> */
3385 /* */
3386 static
3387 void Ins_JROT( INS_ARG )
3388 {
3389 DO_JROT
3390 }
3391
3392
3393 /*************************************************************************/
3394 /* */
3395 /* JMPR[]: JuMP Relative */
3396 /* Opcode range: 0x1C */
3397 /* Stack: int32 --> */
3398 /* */
3399 static
3400 void Ins_JMPR( INS_ARG )
3401 {
3402 DO_JMPR
3403 }
3404
3405
3406 /*************************************************************************/
3407 /* */
3408 /* JROF[]: Jump Relative On False */
3409 /* Opcode range: 0x79 */
3410 /* Stack: StkElt int32 --> */
3411 /* */
3412 static
3413 void Ins_JROF( INS_ARG )
3414 {
3415 DO_JROF
3416 }
3417
3418
3419 /*************************************************************************/
3420 /* */
3421 /* LT[]: Less Than */
3422 /* Opcode range: 0x50 */
3423 /* Stack: int32? int32? --> bool */
3424 /* */
3425 static
3426 void Ins_LT( INS_ARG )
3427 {
3428 DO_LT
3429 }
3430
3431
3432 /*************************************************************************/
3433 /* */
3434 /* LTEQ[]: Less Than or EQual */
3435 /* Opcode range: 0x51 */
3436 /* Stack: int32? int32? --> bool */
3437 /* */
3438 static
3439 void Ins_LTEQ( INS_ARG )
3440 {
3441 DO_LTEQ
3442 }
3443
3444
3445 /*************************************************************************/
3446 /* */
3447 /* GT[]: Greater Than */
3448 /* Opcode range: 0x52 */
3449 /* Stack: int32? int32? --> bool */
3450 /* */
3451 static
3452 void Ins_GT( INS_ARG )
3453 {
3454 DO_GT
3455 }
3456
3457
3458 /*************************************************************************/
3459 /* */
3460 /* GTEQ[]: Greater Than or EQual */
3461 /* Opcode range: 0x53 */
3462 /* Stack: int32? int32? --> bool */
3463 /* */
3464 static
3465 void Ins_GTEQ( INS_ARG )
3466 {
3467 DO_GTEQ
3468 }
3469
3470
3471 /*************************************************************************/
3472 /* */
3473 /* EQ[]: EQual */
3474 /* Opcode range: 0x54 */
3475 /* Stack: StkElt StkElt --> bool */
3476 /* */
3477 static
3478 void Ins_EQ( INS_ARG )
3479 {
3480 DO_EQ
3481 }
3482
3483
3484 /*************************************************************************/
3485 /* */
3486 /* NEQ[]: Not EQual */
3487 /* Opcode range: 0x55 */
3488 /* Stack: StkElt StkElt --> bool */
3489 /* */
3490 static
3491 void Ins_NEQ( INS_ARG )
3492 {
3493 DO_NEQ
3494 }
3495
3496
3497 /*************************************************************************/
3498 /* */
3499 /* ODD[]: Is ODD */
3500 /* Opcode range: 0x56 */
3501 /* Stack: f26.6 --> bool */
3502 /* */
3503 static
3504 void Ins_ODD( INS_ARG )
3505 {
3506 DO_ODD
3507 }
3508
3509
3510 /*************************************************************************/
3511 /* */
3512 /* EVEN[]: Is EVEN */
3513 /* Opcode range: 0x57 */
3514 /* Stack: f26.6 --> bool */
3515 /* */
3516 static
3517 void Ins_EVEN( INS_ARG )
3518 {
3519 DO_EVEN
3520 }
3521
3522
3523 /*************************************************************************/
3524 /* */
3525 /* AND[]: logical AND */
3526 /* Opcode range: 0x5A */
3527 /* Stack: uint32 uint32 --> uint32 */
3528 /* */
3529 static
3530 void Ins_AND( INS_ARG )
3531 {
3532 DO_AND
3533 }
3534
3535
3536 /*************************************************************************/
3537 /* */
3538 /* OR[]: logical OR */
3539 /* Opcode range: 0x5B */
3540 /* Stack: uint32 uint32 --> uint32 */
3541 /* */
3542 static
3543 void Ins_OR( INS_ARG )
3544 {
3545 DO_OR
3546 }
3547
3548
3549 /*************************************************************************/
3550 /* */
3551 /* NOT[]: logical NOT */
3552 /* Opcode range: 0x5C */
3553 /* Stack: StkElt --> uint32 */
3554 /* */
3555 static
3556 void Ins_NOT( INS_ARG )
3557 {
3558 DO_NOT
3559 }
3560
3561
3562 /*************************************************************************/
3563 /* */
3564 /* ADD[]: ADD */
3565 /* Opcode range: 0x60 */
3566 /* Stack: f26.6 f26.6 --> f26.6 */
3567 /* */
3568 static
3569 void Ins_ADD( INS_ARG )
3570 {
3571 DO_ADD
3572 }
3573
3574
3575 /*************************************************************************/
3576 /* */
3577 /* SUB[]: SUBtract */
3578 /* Opcode range: 0x61 */
3579 /* Stack: f26.6 f26.6 --> f26.6 */
3580 /* */
3581 static
3582 void Ins_SUB( INS_ARG )
3583 {
3584 DO_SUB
3585 }
3586
3587
3588 /*************************************************************************/
3589 /* */
3590 /* DIV[]: DIVide */
3591 /* Opcode range: 0x62 */
3592 /* Stack: f26.6 f26.6 --> f26.6 */
3593 /* */
3594 static
3595 void Ins_DIV( INS_ARG )
3596 {
3597 DO_DIV
3598 }
3599
3600
3601 /*************************************************************************/
3602 /* */
3603 /* MUL[]: MULtiply */
3604 /* Opcode range: 0x63 */
3605 /* Stack: f26.6 f26.6 --> f26.6 */
3606 /* */
3607 static
3608 void Ins_MUL( INS_ARG )
3609 {
3610 DO_MUL
3611 }
3612
3613
3614 /*************************************************************************/
3615 /* */
3616 /* ABS[]: ABSolute value */
3617 /* Opcode range: 0x64 */
3618 /* Stack: f26.6 --> f26.6 */
3619 /* */
3620 static
3621 void Ins_ABS( INS_ARG )
3622 {
3623 DO_ABS
3624 }
3625
3626
3627 /*************************************************************************/
3628 /* */
3629 /* NEG[]: NEGate */
3630 /* Opcode range: 0x65 */
3631 /* Stack: f26.6 --> f26.6 */
3632 /* */
3633 static
3634 void Ins_NEG( INS_ARG )
3635 {
3636 DO_NEG
3637 }
3638
3639
3640 /*************************************************************************/
3641 /* */
3642 /* FLOOR[]: FLOOR */
3643 /* Opcode range: 0x66 */
3644 /* Stack: f26.6 --> f26.6 */
3645 /* */
3646 static
3647 void Ins_FLOOR( INS_ARG )
3648 {
3649 DO_FLOOR
3650 }
3651
3652
3653 /*************************************************************************/
3654 /* */
3655 /* CEILING[]: CEILING */
3656 /* Opcode range: 0x67 */
3657 /* Stack: f26.6 --> f26.6 */
3658 /* */
3659 static
3660 void Ins_CEILING( INS_ARG )
3661 {
3662 DO_CEILING
3663 }
3664
3665
3666 /*************************************************************************/
3667 /* */
3668 /* RS[]: Read Store */
3669 /* Opcode range: 0x43 */
3670 /* Stack: uint32 --> uint32 */
3671 /* */
3672 static
3673 void Ins_RS( INS_ARG )
3674 {
3675 DO_RS
3676 }
3677
3678
3679 /*************************************************************************/
3680 /* */
3681 /* WS[]: Write Store */
3682 /* Opcode range: 0x42 */
3683 /* Stack: uint32 uint32 --> */
3684 /* */
3685 static
3686 void Ins_WS( INS_ARG )
3687 {
3688 DO_WS
3689 }
3690
3691
3692 /*************************************************************************/
3693 /* */
3694 /* WCVTP[]: Write CVT in Pixel units */
3695 /* Opcode range: 0x44 */
3696 /* Stack: f26.6 uint32 --> */
3697 /* */
3698 static
3699 void Ins_WCVTP( INS_ARG )
3700 {
3701 DO_WCVTP
3702 }
3703
3704
3705 /*************************************************************************/
3706 /* */
3707 /* WCVTF[]: Write CVT in Funits */
3708 /* Opcode range: 0x70 */
3709 /* Stack: uint32 uint32 --> */
3710 /* */
3711 static
3712 void Ins_WCVTF( INS_ARG )
3713 {
3714 DO_WCVTF
3715 }
3716
3717
3718 /*************************************************************************/
3719 /* */
3720 /* RCVT[]: Read CVT */
3721 /* Opcode range: 0x45 */
3722 /* Stack: uint32 --> f26.6 */
3723 /* */
3724 static
3725 void Ins_RCVT( INS_ARG )
3726 {
3727 DO_RCVT
3728 }
3729
3730
3731 /*************************************************************************/
3732 /* */
3733 /* AA[]: Adjust Angle */
3734 /* Opcode range: 0x7F */
3735 /* Stack: uint32 --> */
3736 /* */
3737 static
3738 void Ins_AA( INS_ARG )
3739 {
Werner Lemberg5811c7c2000-07-02 13:53:16 +00003740 /* intentionally no longer supported */
David Turnerd2b1f351999-12-16 23:11:37 +00003741 }
3742
3743
3744 /*************************************************************************/
3745 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +00003746 /* DEBUG[]: DEBUG. Unsupported. */
David Turnerd2b1f351999-12-16 23:11:37 +00003747 /* Opcode range: 0x4F */
3748 /* Stack: uint32 --> */
3749 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +00003750 /* Note: The original instruction pops a value from the stack. */
David Turnerd2b1f351999-12-16 23:11:37 +00003751 /* */
3752 static
3753 void Ins_DEBUG( INS_ARG )
3754 {
3755 DO_DEBUG
3756 }
3757
3758
3759 /*************************************************************************/
3760 /* */
3761 /* ROUND[ab]: ROUND value */
3762 /* Opcode range: 0x68-0x6B */
3763 /* Stack: f26.6 --> f26.6 */
3764 /* */
3765 static
3766 void Ins_ROUND( INS_ARG )
3767 {
3768 DO_ROUND
3769 }
3770
3771
3772 /*************************************************************************/
3773 /* */
3774 /* NROUND[ab]: No ROUNDing of value */
3775 /* Opcode range: 0x6C-0x6F */
3776 /* Stack: f26.6 --> f26.6 */
3777 /* */
3778 static
3779 void Ins_NROUND( INS_ARG )
3780 {
3781 DO_NROUND
3782 }
3783
3784
3785 /*************************************************************************/
3786 /* */
3787 /* MAX[]: MAXimum */
3788 /* Opcode range: 0x68 */
3789 /* Stack: int32? int32? --> int32 */
3790 /* */
3791 static
3792 void Ins_MAX( INS_ARG )
3793 {
3794 DO_MAX
3795 }
3796
3797
3798 /*************************************************************************/
3799 /* */
3800 /* MIN[]: MINimum */
3801 /* Opcode range: 0x69 */
3802 /* Stack: int32? int32? --> int32 */
3803 /* */
3804 static
3805 void Ins_MIN( INS_ARG )
3806 {
3807 DO_MIN
3808 }
3809
3810
3811#endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
3812
3813
3814 /*************************************************************************/
3815 /* */
3816 /* The following functions are called as is within the switch statement. */
3817 /* */
3818 /*************************************************************************/
3819
3820
3821 /*************************************************************************/
3822 /* */
3823 /* MINDEX[]: Move INDEXed element */
3824 /* Opcode range: 0x26 */
3825 /* Stack: int32? --> StkElt */
3826 /* */
3827 static
3828 void Ins_MINDEX( INS_ARG )
3829 {
David Turnerf9b8dec2000-06-16 19:34:52 +00003830 FT_Long L, K;
David Turnerd2b1f351999-12-16 23:11:37 +00003831
3832
3833 L = args[0];
3834
3835 if ( L <= 0 || L > CUR.args )
3836 {
3837 CUR.error = TT_Err_Invalid_Reference;
3838 return;
3839 }
3840
3841 K = CUR.stack[CUR.args - L];
3842
Werner Lemberg78575dc2000-06-12 19:36:41 +00003843 MEM_Move( &CUR.stack[CUR.args - L ],
3844 &CUR.stack[CUR.args - L + 1],
David Turnerf9b8dec2000-06-16 19:34:52 +00003845 ( L - 1 ) * sizeof ( FT_Long ) );
David Turnerd2b1f351999-12-16 23:11:37 +00003846
3847 CUR.stack[CUR.args - 1] = K;
3848 }
3849
3850
3851 /*************************************************************************/
3852 /* */
3853 /* ROLL[]: ROLL top three elements */
3854 /* Opcode range: 0x8A */
3855 /* Stack: 3 * StkElt --> 3 * StkElt */
3856 /* */
3857 static
3858 void Ins_ROLL( INS_ARG )
3859 {
David Turnerf9b8dec2000-06-16 19:34:52 +00003860 FT_Long A, B, C;
David Turnerd2b1f351999-12-16 23:11:37 +00003861
David Turnerc6a92202000-07-04 18:12:13 +00003862 FT_UNUSED_EXEC;
David Turnerd2b1f351999-12-16 23:11:37 +00003863
Werner Lemberg78575dc2000-06-12 19:36:41 +00003864
David Turnerd2b1f351999-12-16 23:11:37 +00003865 A = args[2];
3866 B = args[1];
3867 C = args[0];
3868
3869 args[2] = C;
3870 args[1] = A;
3871 args[0] = B;
3872 }
3873
3874
3875 /*************************************************************************/
3876 /* */
3877 /* MANAGING THE FLOW OF CONTROL */
3878 /* */
Werner Lemberg5811c7c2000-07-02 13:53:16 +00003879 /* Instructions appear in the specification's order. */
David Turnerd2b1f351999-12-16 23:11:37 +00003880 /* */
3881 /*************************************************************************/
3882
3883
3884 static
David Turnerf9b8dec2000-06-16 19:34:52 +00003885 FT_Bool SkipCode( EXEC_OP )
David Turnerd2b1f351999-12-16 23:11:37 +00003886 {
3887 CUR.IP += CUR.length;
3888
3889 if ( CUR.IP < CUR.codeSize )
3890 {
3891 CUR.opcode = CUR.code[CUR.IP];
3892
3893 CUR.length = opcode_length[CUR.opcode];
3894 if ( CUR.length < 0 )
3895 {
3896 if ( CUR.IP + 1 > CUR.codeSize )
3897 goto Fail_Overflow;
3898 CUR.length = CUR.code[CUR.IP + 1] + 2;
3899 }
3900
3901 if ( CUR.IP + CUR.length <= CUR.codeSize )
3902 return SUCCESS;
3903 }
3904
3905 Fail_Overflow:
3906 CUR.error = TT_Err_Code_Overflow;
3907 return FAILURE;
3908 }
3909
3910
3911 /*************************************************************************/
3912 /* */
3913 /* IF[]: IF test */
3914 /* Opcode range: 0x58 */
3915 /* Stack: StkElt --> */
3916 /* */
3917 static
3918 void Ins_IF( INS_ARG )
3919 {
David Turnerf9b8dec2000-06-16 19:34:52 +00003920 FT_Int nIfs;
3921 FT_Bool Out;
David Turnerd2b1f351999-12-16 23:11:37 +00003922
3923
3924 if ( args[0] != 0 )
3925 return;
3926
3927 nIfs = 1;
3928 Out = 0;
3929
3930 do
3931 {
3932 if ( SKIP_Code() == FAILURE )
3933 return;
3934
3935 switch ( CUR.opcode )
3936 {
3937 case 0x58: /* IF */
3938 nIfs++;
3939 break;
3940
3941 case 0x1B: /* ELSE */
Werner Lemberg78575dc2000-06-12 19:36:41 +00003942 Out = ( nIfs == 1 );
David Turnerd2b1f351999-12-16 23:11:37 +00003943 break;
3944
3945 case 0x59: /* EIF */
3946 nIfs--;
Werner Lemberg78575dc2000-06-12 19:36:41 +00003947 Out = ( nIfs == 0 );
David Turnerd2b1f351999-12-16 23:11:37 +00003948 break;
3949 }
3950 } while ( Out == 0 );
3951 }
3952
3953
3954 /*************************************************************************/
3955 /* */
3956 /* ELSE[]: ELSE */
3957 /* Opcode range: 0x1B */
3958 /* Stack: --> */
3959 /* */
3960 static
3961 void Ins_ELSE( INS_ARG )
3962 {
David Turnerf9b8dec2000-06-16 19:34:52 +00003963 FT_Int nIfs;
David Turnerd2b1f351999-12-16 23:11:37 +00003964
David Turnerc6a92202000-07-04 18:12:13 +00003965 FT_UNUSED_ARG;
David Turnerd2b1f351999-12-16 23:11:37 +00003966
Werner Lemberg78575dc2000-06-12 19:36:41 +00003967
David Turnerd2b1f351999-12-16 23:11:37 +00003968 nIfs = 1;
3969
3970 do
3971 {
3972 if ( SKIP_Code() == FAILURE )
3973 return;
3974
3975 switch ( CUR.opcode )
3976 {
3977 case 0x58: /* IF */
3978 nIfs++;
3979 break;
3980
3981 case 0x59: /* EIF */
3982 nIfs--;
3983 break;
3984 }
3985 } while ( nIfs != 0 );
3986 }
3987
3988
3989 /*************************************************************************/
3990 /* */
3991 /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS */
3992 /* */
Werner Lemberg5811c7c2000-07-02 13:53:16 +00003993 /* Instructions appear in the specification's order. */
David Turnerd2b1f351999-12-16 23:11:37 +00003994 /* */
3995 /*************************************************************************/
3996
3997
3998 /*************************************************************************/
3999 /* */
4000 /* FDEF[]: Function DEFinition */
4001 /* Opcode range: 0x2C */
4002 /* Stack: uint32 --> */
4003 /* */
4004 static
4005 void Ins_FDEF( INS_ARG )
4006 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004007 FT_ULong n;
David Turnerd2b1f351999-12-16 23:11:37 +00004008 TT_DefRecord* rec;
4009 TT_DefRecord* limit;
4010
Werner Lemberg78575dc2000-06-12 19:36:41 +00004011
David Turnerd2b1f351999-12-16 23:11:37 +00004012 /* some font programs are broken enough to redefine functions! */
Werner Lemberg78575dc2000-06-12 19:36:41 +00004013 /* We will then parse the current table. */
4014
David Turnerd2b1f351999-12-16 23:11:37 +00004015 rec = CUR.FDefs;
4016 limit = rec + CUR.numFDefs;
4017 n = args[0];
David Turnere49ab252000-05-16 23:44:38 +00004018
David Turnerd2b1f351999-12-16 23:11:37 +00004019 for ( ; rec < limit; rec++ )
4020 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00004021 if ( rec->opc == n )
David Turnerd2b1f351999-12-16 23:11:37 +00004022 break;
4023 }
David Turnere49ab252000-05-16 23:44:38 +00004024
David Turnerd2b1f351999-12-16 23:11:37 +00004025 if ( rec == limit )
4026 {
4027 /* check that there is enough room for new functions */
4028 if ( CUR.numFDefs >= CUR.maxFDefs )
4029 {
4030 CUR.error = TT_Err_Too_Many_Function_Defs;
4031 return;
4032 }
4033 CUR.numFDefs++;
4034 }
David Turnere49ab252000-05-16 23:44:38 +00004035
David Turnerd2b1f351999-12-16 23:11:37 +00004036 rec->range = CUR.curRange;
4037 rec->opc = n;
Werner Lemberg78575dc2000-06-12 19:36:41 +00004038 rec->start = CUR.IP + 1;
David Turnerd2b1f351999-12-16 23:11:37 +00004039 rec->active = TRUE;
David Turnere49ab252000-05-16 23:44:38 +00004040
David Turnerd2b1f351999-12-16 23:11:37 +00004041 if ( n > CUR.maxFunc )
4042 CUR.maxFunc = n;
David Turnere49ab252000-05-16 23:44:38 +00004043
David Turnerd2b1f351999-12-16 23:11:37 +00004044 /* Now skip the whole function definition. */
4045 /* We don't allow nested IDEFS & FDEFs. */
4046
4047 while ( SKIP_Code() == SUCCESS )
4048 {
4049 switch ( CUR.opcode )
4050 {
4051 case 0x89: /* IDEF */
4052 case 0x2C: /* FDEF */
4053 CUR.error = TT_Err_Nested_DEFS;
4054 return;
4055
4056 case 0x2D: /* ENDF */
4057 return;
4058 }
4059 }
4060 }
4061
4062
4063 /*************************************************************************/
4064 /* */
4065 /* ENDF[]: END Function definition */
4066 /* Opcode range: 0x2D */
4067 /* Stack: --> */
4068 /* */
4069 static
4070 void Ins_ENDF( INS_ARG )
4071 {
4072 TT_CallRec* pRec;
4073
David Turnerc6a92202000-07-04 18:12:13 +00004074 FT_UNUSED_ARG;
David Turnerd2b1f351999-12-16 23:11:37 +00004075
Werner Lemberg78575dc2000-06-12 19:36:41 +00004076
David Turnerd2b1f351999-12-16 23:11:37 +00004077 if ( CUR.callTop <= 0 ) /* We encountered an ENDF without a call */
4078 {
4079 CUR.error = TT_Err_ENDF_In_Exec_Stream;
4080 return;
4081 }
4082
4083 CUR.callTop--;
4084
4085 pRec = &CUR.callStack[CUR.callTop];
4086
4087 pRec->Cur_Count--;
4088
4089 CUR.step_ins = FALSE;
4090
4091 if ( pRec->Cur_Count > 0 )
4092 {
4093 CUR.callTop++;
4094 CUR.IP = pRec->Cur_Restart;
4095 }
4096 else
4097 /* Loop through the current function */
4098 INS_Goto_CodeRange( pRec->Caller_Range,
4099 pRec->Caller_IP );
4100
Werner Lemberg78575dc2000-06-12 19:36:41 +00004101 /* Exit the current call frame. */
David Turnerd2b1f351999-12-16 23:11:37 +00004102
Werner Lemberg78575dc2000-06-12 19:36:41 +00004103 /* NOTE: If the last intruction of a program is a */
4104 /* CALL or LOOPCALL, the return address is */
4105 /* always out of the code range. This is a */
4106 /* valid address, and it is why we do not test */
4107 /* the result of Ins_Goto_CodeRange() here! */
David Turnerd2b1f351999-12-16 23:11:37 +00004108 }
4109
4110
4111 /*************************************************************************/
4112 /* */
4113 /* CALL[]: CALL function */
4114 /* Opcode range: 0x2B */
4115 /* Stack: uint32? --> */
4116 /* */
4117 static
4118 void Ins_CALL( INS_ARG )
4119 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004120 FT_ULong F;
David Turnerd2b1f351999-12-16 23:11:37 +00004121 TT_CallRec* pCrec;
4122 TT_DefRecord* def;
4123
Werner Lemberg78575dc2000-06-12 19:36:41 +00004124
David Turnerd2b1f351999-12-16 23:11:37 +00004125 /* first of all, check the index */
Werner Lemberg78575dc2000-06-12 19:36:41 +00004126
David Turnerd2b1f351999-12-16 23:11:37 +00004127 F = args[0];
Werner Lemberg78575dc2000-06-12 19:36:41 +00004128 if ( BOUNDS( F, CUR.maxFunc + 1 ) )
4129 goto Fail;
David Turnere49ab252000-05-16 23:44:38 +00004130
David Turnerd2b1f351999-12-16 23:11:37 +00004131 /* Except for some old Apple fonts, all functions in a TrueType */
Werner Lemberg78575dc2000-06-12 19:36:41 +00004132 /* font are defined in increasing order, starting from 0. This */
David Turnerd2b1f351999-12-16 23:11:37 +00004133 /* means that we normally have */
4134 /* */
4135 /* CUR.maxFunc+1 == CUR.numFDefs */
4136 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4137 /* */
4138 /* If this isn't true, we need to look up the function table. */
4139
4140 def = CUR.FDefs + F;
Werner Lemberg78575dc2000-06-12 19:36:41 +00004141 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
David Turnerd2b1f351999-12-16 23:11:37 +00004142 {
4143 /* look up the FDefs table */
4144 TT_DefRecord* limit;
David Turnere49ab252000-05-16 23:44:38 +00004145
Werner Lemberg78575dc2000-06-12 19:36:41 +00004146
David Turnerd2b1f351999-12-16 23:11:37 +00004147 def = CUR.FDefs;
4148 limit = def + CUR.numFDefs;
David Turnere49ab252000-05-16 23:44:38 +00004149
Werner Lemberg78575dc2000-06-12 19:36:41 +00004150 while ( def < limit && def->opc != F )
David Turnerd2b1f351999-12-16 23:11:37 +00004151 def++;
David Turnere49ab252000-05-16 23:44:38 +00004152
Werner Lemberg78575dc2000-06-12 19:36:41 +00004153 if ( def == limit )
4154 goto Fail;
David Turnerd2b1f351999-12-16 23:11:37 +00004155 }
David Turnere49ab252000-05-16 23:44:38 +00004156
David Turnerd2b1f351999-12-16 23:11:37 +00004157 /* check that the function is active */
Werner Lemberg78575dc2000-06-12 19:36:41 +00004158 if ( !def->active )
David Turnerd2b1f351999-12-16 23:11:37 +00004159 goto Fail;
David Turnere49ab252000-05-16 23:44:38 +00004160
David Turnerd2b1f351999-12-16 23:11:37 +00004161 /* check the call stack */
4162 if ( CUR.callTop >= CUR.callSize )
4163 {
4164 CUR.error = TT_Err_Stack_Overflow;
4165 return;
4166 }
4167
4168 pCrec = CUR.callStack + CUR.callTop;
4169
4170 pCrec->Caller_Range = CUR.curRange;
4171 pCrec->Caller_IP = CUR.IP + 1;
4172 pCrec->Cur_Count = 1;
4173 pCrec->Cur_Restart = def->start;
4174
4175 CUR.callTop++;
4176
4177 INS_Goto_CodeRange( def->range,
4178 def->start );
David Turnere49ab252000-05-16 23:44:38 +00004179
David Turnerd2b1f351999-12-16 23:11:37 +00004180 CUR.step_ins = FALSE;
4181 return;
David Turnere49ab252000-05-16 23:44:38 +00004182
David Turnerd2b1f351999-12-16 23:11:37 +00004183 Fail:
4184 CUR.error = TT_Err_Invalid_Reference;
4185 }
4186
4187
4188 /*************************************************************************/
4189 /* */
4190 /* LOOPCALL[]: LOOP and CALL function */
4191 /* Opcode range: 0x2A */
4192 /* Stack: uint32? Eint16? --> */
4193 /* */
4194 static
4195 void Ins_LOOPCALL( INS_ARG )
4196 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004197 FT_ULong F;
David Turnerd2b1f351999-12-16 23:11:37 +00004198 TT_CallRec* pCrec;
4199 TT_DefRecord* def;
4200
Werner Lemberg78575dc2000-06-12 19:36:41 +00004201
David Turnerd2b1f351999-12-16 23:11:37 +00004202 /* first of all, check the index */
4203 F = args[1];
Werner Lemberg78575dc2000-06-12 19:36:41 +00004204 if ( BOUNDS( F, CUR.maxFunc + 1 ) )
4205 goto Fail;
David Turnere49ab252000-05-16 23:44:38 +00004206
David Turnerd2b1f351999-12-16 23:11:37 +00004207 /* Except for some old Apple fonts, all functions in a TrueType */
Werner Lemberg78575dc2000-06-12 19:36:41 +00004208 /* font are defined in increasing order, starting from 0. This */
David Turnerd2b1f351999-12-16 23:11:37 +00004209 /* means that we normally have */
4210 /* */
4211 /* CUR.maxFunc+1 == CUR.numFDefs */
4212 /* CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc */
4213 /* */
4214 /* If this isn't true, we need to look up the function table. */
4215
4216 def = CUR.FDefs + F;
Werner Lemberg78575dc2000-06-12 19:36:41 +00004217 if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
David Turnerd2b1f351999-12-16 23:11:37 +00004218 {
4219 /* look up the FDefs table */
4220 TT_DefRecord* limit;
David Turnere49ab252000-05-16 23:44:38 +00004221
Werner Lemberg78575dc2000-06-12 19:36:41 +00004222
David Turnerd2b1f351999-12-16 23:11:37 +00004223 def = CUR.FDefs;
4224 limit = def + CUR.numFDefs;
David Turnere49ab252000-05-16 23:44:38 +00004225
Werner Lemberg78575dc2000-06-12 19:36:41 +00004226 while ( def < limit && def->opc != F )
David Turnerd2b1f351999-12-16 23:11:37 +00004227 def++;
David Turnere49ab252000-05-16 23:44:38 +00004228
Werner Lemberg78575dc2000-06-12 19:36:41 +00004229 if ( def == limit )
4230 goto Fail;
David Turnerd2b1f351999-12-16 23:11:37 +00004231 }
David Turnere49ab252000-05-16 23:44:38 +00004232
David Turnerd2b1f351999-12-16 23:11:37 +00004233 /* check that the function is active */
Werner Lemberg78575dc2000-06-12 19:36:41 +00004234 if ( !def->active )
David Turnerd2b1f351999-12-16 23:11:37 +00004235 goto Fail;
4236
David Turnere49ab252000-05-16 23:44:38 +00004237 /* check stack */
David Turnerd2b1f351999-12-16 23:11:37 +00004238 if ( CUR.callTop >= CUR.callSize )
4239 {
4240 CUR.error = TT_Err_Stack_Overflow;
4241 return;
4242 }
4243
4244 if ( args[0] > 0 )
4245 {
4246 pCrec = CUR.callStack + CUR.callTop;
4247
4248 pCrec->Caller_Range = CUR.curRange;
4249 pCrec->Caller_IP = CUR.IP + 1;
David Turnerf9b8dec2000-06-16 19:34:52 +00004250 pCrec->Cur_Count = (FT_Int)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00004251 pCrec->Cur_Restart = def->start;
4252
4253 CUR.callTop++;
4254
4255 INS_Goto_CodeRange( def->range, def->start );
4256
4257 CUR.step_ins = FALSE;
4258 }
4259 return;
4260
4261 Fail:
4262 CUR.error = TT_Err_Invalid_Reference;
4263 }
4264
4265
4266 /*************************************************************************/
4267 /* */
4268 /* IDEF[]: Instruction DEFinition */
4269 /* Opcode range: 0x89 */
4270 /* Stack: Eint8 --> */
4271 /* */
4272 static
4273 void Ins_IDEF( INS_ARG )
4274 {
4275 TT_DefRecord* def;
4276 TT_DefRecord* limit;
4277
Werner Lemberg78575dc2000-06-12 19:36:41 +00004278
David Turnerd2b1f351999-12-16 23:11:37 +00004279 /* First of all, look for the same function in our table */
Werner Lemberg78575dc2000-06-12 19:36:41 +00004280
David Turnerd2b1f351999-12-16 23:11:37 +00004281 def = CUR.IDefs;
4282 limit = def + CUR.numIDefs;
Werner Lemberg78575dc2000-06-12 19:36:41 +00004283
David Turnerd2b1f351999-12-16 23:11:37 +00004284 for ( ; def < limit; def++ )
David Turnerf9b8dec2000-06-16 19:34:52 +00004285 if ( def->opc == (FT_ULong)args[0] )
David Turnerd2b1f351999-12-16 23:11:37 +00004286 break;
David Turnere49ab252000-05-16 23:44:38 +00004287
David Turnerd2b1f351999-12-16 23:11:37 +00004288 if ( def == limit )
4289 {
4290 /* check that there is enough room for a new instruction */
4291 if ( CUR.numIDefs >= CUR.maxIDefs )
4292 {
4293 CUR.error = TT_Err_Too_Many_Instruction_Defs;
4294 return;
4295 }
4296 CUR.numIDefs++;
4297 }
David Turnere49ab252000-05-16 23:44:38 +00004298
David Turnerd2b1f351999-12-16 23:11:37 +00004299 def->opc = args[0];
4300 def->start = CUR.IP+1;
4301 def->range = CUR.curRange;
4302 def->active = TRUE;
David Turnere49ab252000-05-16 23:44:38 +00004303
David Turnerf9b8dec2000-06-16 19:34:52 +00004304 if ( (FT_ULong)args[0] > CUR.maxIns )
David Turnerd2b1f351999-12-16 23:11:37 +00004305 CUR.maxIns = args[0];
David Turnere49ab252000-05-16 23:44:38 +00004306
David Turnerd2b1f351999-12-16 23:11:37 +00004307 /* Now skip the whole function definition. */
4308 /* We don't allow nested IDEFs & FDEFs. */
4309
4310 while ( SKIP_Code() == SUCCESS )
4311 {
4312 switch ( CUR.opcode )
4313 {
4314 case 0x89: /* IDEF */
4315 case 0x2C: /* FDEF */
4316 CUR.error = TT_Err_Nested_DEFS;
4317 return;
4318 case 0x2D: /* ENDF */
4319 return;
4320 }
4321 }
4322 }
4323
4324
4325 /*************************************************************************/
4326 /* */
4327 /* PUSHING DATA ONTO THE INTERPRETER STACK */
4328 /* */
Werner Lemberg5811c7c2000-07-02 13:53:16 +00004329 /* Instructions appear in the specification's order. */
David Turnerd2b1f351999-12-16 23:11:37 +00004330 /* */
4331 /*************************************************************************/
4332
4333
4334 /*************************************************************************/
4335 /* */
4336 /* NPUSHB[]: PUSH N Bytes */
4337 /* Opcode range: 0x40 */
4338 /* Stack: --> uint32... */
4339 /* */
4340 static
4341 void Ins_NPUSHB( INS_ARG )
4342 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004343 FT_UShort L, K;
David Turnerd2b1f351999-12-16 23:11:37 +00004344
4345
David Turnerf9b8dec2000-06-16 19:34:52 +00004346 L = (FT_UShort)CUR.code[CUR.IP + 1];
David Turnerd2b1f351999-12-16 23:11:37 +00004347
4348 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4349 {
4350 CUR.error = TT_Err_Stack_Overflow;
4351 return;
4352 }
4353
4354 for ( K = 1; K <= L; K++ )
4355 args[K - 1] = CUR.code[CUR.IP + K + 1];
4356
4357 CUR.new_top += L;
4358 }
4359
4360
4361 /*************************************************************************/
4362 /* */
4363 /* NPUSHW[]: PUSH N Words */
4364 /* Opcode range: 0x41 */
4365 /* Stack: --> int32... */
4366 /* */
4367 static
4368 void Ins_NPUSHW( INS_ARG )
4369 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004370 FT_UShort L, K;
David Turnerd2b1f351999-12-16 23:11:37 +00004371
4372
David Turnerf9b8dec2000-06-16 19:34:52 +00004373 L = (FT_UShort)CUR.code[CUR.IP + 1];
David Turnerd2b1f351999-12-16 23:11:37 +00004374
4375 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4376 {
4377 CUR.error = TT_Err_Stack_Overflow;
4378 return;
4379 }
4380
4381 CUR.IP += 2;
4382
4383 for ( K = 0; K < L; K++ )
4384 args[K] = GET_ShortIns();
4385
4386 CUR.step_ins = FALSE;
4387 CUR.new_top += L;
4388 }
4389
4390
4391 /*************************************************************************/
4392 /* */
4393 /* PUSHB[abc]: PUSH Bytes */
4394 /* Opcode range: 0xB0-0xB7 */
4395 /* Stack: --> uint32... */
4396 /* */
4397 static
4398 void Ins_PUSHB( INS_ARG )
4399 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004400 FT_UShort L, K;
David Turnerd2b1f351999-12-16 23:11:37 +00004401
4402
David Turnerf9b8dec2000-06-16 19:34:52 +00004403 L = (FT_UShort)CUR.opcode - 0xB0 + 1;
David Turnerd2b1f351999-12-16 23:11:37 +00004404
4405 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4406 {
4407 CUR.error = TT_Err_Stack_Overflow;
4408 return;
4409 }
4410
4411 for ( K = 1; K <= L; K++ )
4412 args[K - 1] = CUR.code[CUR.IP + K];
4413 }
4414
4415
4416 /*************************************************************************/
4417 /* */
4418 /* PUSHW[abc]: PUSH Words */
4419 /* Opcode range: 0xB8-0xBF */
4420 /* Stack: --> int32... */
4421 /* */
4422 static
4423 void Ins_PUSHW( INS_ARG )
4424 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004425 FT_UShort L, K;
David Turnerd2b1f351999-12-16 23:11:37 +00004426
4427
David Turnerf9b8dec2000-06-16 19:34:52 +00004428 L = (FT_UShort)CUR.opcode - 0xB8 + 1;
David Turnerd2b1f351999-12-16 23:11:37 +00004429
4430 if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
4431 {
4432 CUR.error = TT_Err_Stack_Overflow;
4433 return;
4434 }
4435
4436 CUR.IP++;
4437
4438 for ( K = 0; K < L; K++ )
4439 args[K] = GET_ShortIns();
4440
4441 CUR.step_ins = FALSE;
4442 }
4443
4444
4445 /*************************************************************************/
4446 /* */
4447 /* MANAGING THE GRAPHICS STATE */
4448 /* */
4449 /* Instructions appear in the specs' order. */
4450 /* */
4451 /*************************************************************************/
4452
4453
4454 /*************************************************************************/
4455 /* */
4456 /* GC[a]: Get Coordinate projected onto */
4457 /* Opcode range: 0x46-0x47 */
4458 /* Stack: uint32 --> f26.6 */
4459 /* */
4460 /* BULLSHIT: Measures from the original glyph must be taken along the */
4461 /* dual projection vector! */
4462 /* */
4463 static void Ins_GC( INS_ARG )
4464 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004465 FT_ULong L;
4466 FT_F26Dot6 R;
David Turnerd2b1f351999-12-16 23:11:37 +00004467
4468
David Turnerf9b8dec2000-06-16 19:34:52 +00004469 L = (FT_ULong)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00004470
4471 if ( BOUNDS( L, CUR.zp2.n_points ) )
4472 {
4473 if ( CUR.pedantic_hinting )
4474 {
4475 CUR.error = TT_Err_Invalid_Reference;
4476 return;
4477 }
4478 else
4479 R = 0;
4480 }
4481 else
4482 {
4483 if ( CUR.opcode & 1 )
4484 R = CUR_Func_dualproj( CUR.zp2.org + L, NULL_Vector );
4485 else
4486 R = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
4487 }
4488
4489 args[0] = R;
4490 }
4491
4492
4493 /*************************************************************************/
4494 /* */
4495 /* SCFS[]: Set Coordinate From Stack */
4496 /* Opcode range: 0x48 */
4497 /* Stack: f26.6 uint32 --> */
4498 /* */
4499 /* Formula: */
4500 /* */
4501 /* OA := OA + ( value - OA.p )/( f.p ) * f */
4502 /* */
4503 static
4504 void Ins_SCFS( INS_ARG )
4505 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004506 FT_Long K;
4507 FT_UShort L;
David Turnerd2b1f351999-12-16 23:11:37 +00004508
4509
David Turnerf9b8dec2000-06-16 19:34:52 +00004510 L = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00004511
4512 if ( BOUNDS( L, CUR.zp2.n_points ) )
4513 {
4514 if ( CUR.pedantic_hinting )
4515 CUR.error = TT_Err_Invalid_Reference;
4516 return;
4517 }
4518
4519 K = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
4520
4521 CUR_Func_move( &CUR.zp2, L, args[1] - K );
4522
4523 /* not part of the specs, but here for safety */
4524
4525 if ( CUR.GS.gep2 == 0 )
4526 CUR.zp2.org[L] = CUR.zp2.cur[L];
4527 }
4528
4529
4530 /*************************************************************************/
4531 /* */
4532 /* MD[a]: Measure Distance */
4533 /* Opcode range: 0x49-0x4A */
4534 /* Stack: uint32 uint32 --> f26.6 */
4535 /* */
4536 /* BULLSHIT: Measure taken in the original glyph must be along the dual */
4537 /* projection vector. */
4538 /* */
4539 /* Second BULLSHIT: Flag attributes are inverted! */
4540 /* 0 => measure distance in original outline */
4541 /* 1 => measure distance in grid-fitted outline */
4542 /* */
4543 /* Third one: `zp0 - zp1', and not `zp2 - zp1! */
4544 /* */
4545 static
4546 void Ins_MD( INS_ARG )
4547 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004548 FT_UShort K, L;
4549 FT_F26Dot6 D;
David Turnerd2b1f351999-12-16 23:11:37 +00004550
4551
David Turnerf9b8dec2000-06-16 19:34:52 +00004552 K = (FT_UShort)args[1];
4553 L = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00004554
4555 if( BOUNDS( L, CUR.zp0.n_points ) ||
4556 BOUNDS( K, CUR.zp1.n_points ) )
4557 {
4558 if ( CUR.pedantic_hinting )
4559 {
4560 CUR.error = TT_Err_Invalid_Reference;
4561 return;
4562 }
4563 D = 0;
4564 }
4565 else
4566 {
4567 if ( CUR.opcode & 1 )
4568 D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
4569 else
4570 D = CUR_Func_dualproj( CUR.zp0.org + L, CUR.zp1.org + K );
4571 }
4572
4573 args[0] = D;
4574 }
4575
4576
4577 /*************************************************************************/
4578 /* */
4579 /* SDPVTL[a]: Set Dual PVector to Line */
4580 /* Opcode range: 0x86-0x87 */
4581 /* Stack: uint32 uint32 --> */
4582 /* */
4583 static
4584 void Ins_SDPVTL( INS_ARG )
4585 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004586 FT_Long A, B, C;
4587 FT_UShort p1, p2; /* was FT_Int in pas type ERROR */
David Turnerd2b1f351999-12-16 23:11:37 +00004588
4589
David Turnerf9b8dec2000-06-16 19:34:52 +00004590 p1 = (FT_UShort)args[1];
4591 p2 = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00004592
4593 if ( BOUNDS( p2, CUR.zp1.n_points ) ||
4594 BOUNDS( p1, CUR.zp2.n_points ) )
4595 {
4596 if ( CUR.pedantic_hinting )
4597 CUR.error = TT_Err_Invalid_Reference;
4598 return;
4599 }
4600
4601 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004602 FT_Vector* v1 = CUR.zp1.org + p2;
4603 FT_Vector* v2 = CUR.zp2.org + p1;
David Turnerd2b1f351999-12-16 23:11:37 +00004604
4605
4606 A = v1->x - v2->x;
4607 B = v1->y - v2->y;
4608 }
4609
Werner Lemberg78575dc2000-06-12 19:36:41 +00004610 if ( ( CUR.opcode & 1 ) != 0 )
David Turnerd2b1f351999-12-16 23:11:37 +00004611 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00004612 C = B; /* counter clockwise rotation */
David Turnerd2b1f351999-12-16 23:11:37 +00004613 B = A;
4614 A = -C;
4615 }
4616
4617 NORMalize( A, B, &CUR.GS.dualVector );
4618
4619 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004620 FT_Vector* v1 = CUR.zp1.cur + p2;
4621 FT_Vector* v2 = CUR.zp2.cur + p1;
David Turnerd2b1f351999-12-16 23:11:37 +00004622
4623
4624 A = v1->x - v2->x;
4625 B = v1->y - v2->y;
4626 }
4627
Werner Lemberg78575dc2000-06-12 19:36:41 +00004628 if ( ( CUR.opcode & 1 ) != 0 )
David Turnerd2b1f351999-12-16 23:11:37 +00004629 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00004630 C = B; /* counter clockwise rotation */
David Turnerd2b1f351999-12-16 23:11:37 +00004631 B = A;
4632 A = -C;
4633 }
4634
4635 NORMalize( A, B, &CUR.GS.projVector );
4636
4637 COMPUTE_Funcs();
4638 }
4639
4640
4641 /*************************************************************************/
4642 /* */
4643 /* SZP0[]: Set Zone Pointer 0 */
4644 /* Opcode range: 0x13 */
4645 /* Stack: uint32 --> */
4646 /* */
4647 static
4648 void Ins_SZP0( INS_ARG )
4649 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004650 switch ( (FT_Int)args[0] )
David Turnerd2b1f351999-12-16 23:11:37 +00004651 {
4652 case 0:
4653 CUR.zp0 = CUR.twilight;
4654 break;
4655
4656 case 1:
4657 CUR.zp0 = CUR.pts;
4658 break;
4659
4660 default:
4661 if ( CUR.pedantic_hinting )
4662 CUR.error = TT_Err_Invalid_Reference;
4663 return;
4664 }
4665
David Turnerf9b8dec2000-06-16 19:34:52 +00004666 CUR.GS.gep0 = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00004667 }
4668
4669
4670 /*************************************************************************/
4671 /* */
4672 /* SZP1[]: Set Zone Pointer 1 */
4673 /* Opcode range: 0x14 */
4674 /* Stack: uint32 --> */
4675 /* */
4676 static
4677 void Ins_SZP1( INS_ARG )
4678 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004679 switch ( (FT_Int)args[0] )
David Turnerd2b1f351999-12-16 23:11:37 +00004680 {
4681 case 0:
4682 CUR.zp1 = CUR.twilight;
4683 break;
4684
4685 case 1:
4686 CUR.zp1 = CUR.pts;
4687 break;
4688
4689 default:
4690 if ( CUR.pedantic_hinting )
4691 CUR.error = TT_Err_Invalid_Reference;
4692 return;
4693 }
4694
David Turnerf9b8dec2000-06-16 19:34:52 +00004695 CUR.GS.gep1 = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00004696 }
4697
4698
4699 /*************************************************************************/
4700 /* */
4701 /* SZP2[]: Set Zone Pointer 2 */
4702 /* Opcode range: 0x15 */
4703 /* Stack: uint32 --> */
4704 /* */
4705 static
4706 void Ins_SZP2( INS_ARG )
4707 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004708 switch ( (FT_Int)args[0] )
David Turnerd2b1f351999-12-16 23:11:37 +00004709 {
4710 case 0:
4711 CUR.zp2 = CUR.twilight;
4712 break;
4713
4714 case 1:
4715 CUR.zp2 = CUR.pts;
4716 break;
4717
4718 default:
4719 if ( CUR.pedantic_hinting )
4720 CUR.error = TT_Err_Invalid_Reference;
4721 return;
4722 }
4723
David Turnerf9b8dec2000-06-16 19:34:52 +00004724 CUR.GS.gep2 = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00004725 }
4726
4727
4728 /*************************************************************************/
4729 /* */
4730 /* SZPS[]: Set Zone PointerS */
4731 /* Opcode range: 0x16 */
4732 /* Stack: uint32 --> */
4733 /* */
4734 static
4735 void Ins_SZPS( INS_ARG )
4736 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004737 switch ( (FT_Int)args[0] )
David Turnerd2b1f351999-12-16 23:11:37 +00004738 {
4739 case 0:
4740 CUR.zp0 = CUR.twilight;
4741 break;
4742
4743 case 1:
4744 CUR.zp0 = CUR.pts;
4745 break;
4746
4747 default:
4748 if ( CUR.pedantic_hinting )
4749 CUR.error = TT_Err_Invalid_Reference;
4750 return;
4751 }
4752
4753 CUR.zp1 = CUR.zp0;
4754 CUR.zp2 = CUR.zp0;
4755
David Turnerf9b8dec2000-06-16 19:34:52 +00004756 CUR.GS.gep0 = (FT_UShort)args[0];
4757 CUR.GS.gep1 = (FT_UShort)args[0];
4758 CUR.GS.gep2 = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00004759 }
4760
4761
4762 /*************************************************************************/
4763 /* */
4764 /* INSTCTRL[]: INSTruction ConTRoL */
4765 /* Opcode range: 0x8e */
4766 /* Stack: int32 int32 --> */
4767 /* */
4768 static
4769 void Ins_INSTCTRL( INS_ARG )
4770 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004771 FT_Long K, L;
David Turnerd2b1f351999-12-16 23:11:37 +00004772
4773
4774 K = args[1];
4775 L = args[0];
4776
4777 if ( K < 1 || K > 2 )
4778 {
4779 if ( CUR.pedantic_hinting )
4780 CUR.error = TT_Err_Invalid_Reference;
4781 return;
4782 }
4783
4784 if ( L != 0 )
4785 L = K;
4786
4787 CUR.GS.instruct_control =
David Turnerf9b8dec2000-06-16 19:34:52 +00004788 (FT_Byte)( CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L;
David Turnerd2b1f351999-12-16 23:11:37 +00004789 }
4790
4791
4792 /*************************************************************************/
4793 /* */
4794 /* SCANCTRL[]: SCAN ConTRoL */
4795 /* Opcode range: 0x85 */
4796 /* Stack: uint32? --> */
4797 /* */
4798 static
4799 void Ins_SCANCTRL( INS_ARG )
4800 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004801 FT_Int A;
David Turnerd2b1f351999-12-16 23:11:37 +00004802
4803
4804 /* Get Threshold */
David Turnerf9b8dec2000-06-16 19:34:52 +00004805 A = (FT_Int)( args[0] & 0xFF );
David Turnerd2b1f351999-12-16 23:11:37 +00004806
4807 if ( A == 0xFF )
4808 {
4809 CUR.GS.scan_control = TRUE;
4810 return;
4811 }
4812 else if ( A == 0 )
4813 {
4814 CUR.GS.scan_control = FALSE;
4815 return;
4816 }
4817
4818 A *= 64;
4819
Werner Lemberg78575dc2000-06-12 19:36:41 +00004820#if 0
David Turnerd2b1f351999-12-16 23:11:37 +00004821 if ( (args[0] & 0x100) != 0 && CUR.metrics.pointSize <= A )
4822 CUR.GS.scan_control = TRUE;
Werner Lemberg78575dc2000-06-12 19:36:41 +00004823#endif
David Turnerd2b1f351999-12-16 23:11:37 +00004824
4825 if ( (args[0] & 0x200) != 0 && CUR.tt_metrics.rotated )
4826 CUR.GS.scan_control = TRUE;
4827
4828 if ( (args[0] & 0x400) != 0 && CUR.tt_metrics.stretched )
4829 CUR.GS.scan_control = TRUE;
4830
Werner Lemberg78575dc2000-06-12 19:36:41 +00004831#if 0
David Turnerd2b1f351999-12-16 23:11:37 +00004832 if ( (args[0] & 0x800) != 0 && CUR.metrics.pointSize > A )
4833 CUR.GS.scan_control = FALSE;
Werner Lemberg78575dc2000-06-12 19:36:41 +00004834#endif
David Turnerd2b1f351999-12-16 23:11:37 +00004835
4836 if ( (args[0] & 0x1000) != 0 && CUR.tt_metrics.rotated )
4837 CUR.GS.scan_control = FALSE;
4838
4839 if ( (args[0] & 0x2000) != 0 && CUR.tt_metrics.stretched )
4840 CUR.GS.scan_control = FALSE;
4841}
4842
4843
4844 /*************************************************************************/
4845 /* */
4846 /* SCANTYPE[]: SCAN TYPE */
4847 /* Opcode range: 0x8D */
4848 /* Stack: uint32? --> */
4849 /* */
4850 static
4851 void Ins_SCANTYPE( INS_ARG )
4852 {
Werner Lemberg5811c7c2000-07-02 13:53:16 +00004853 /* for compatibility with future enhancements, */
David Turnerd2b1f351999-12-16 23:11:37 +00004854 /* we must ignore new modes */
4855
4856 if ( args[0] >= 0 && args[0] <= 5 )
4857 {
4858 if ( args[0] == 3 )
4859 args[0] = 2;
4860
David Turnerf9b8dec2000-06-16 19:34:52 +00004861 CUR.GS.scan_type = (FT_Int)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00004862 }
4863 }
4864
4865
4866 /*************************************************************************/
4867 /* */
4868 /* MANAGING OUTLINES */
4869 /* */
Werner Lemberg5811c7c2000-07-02 13:53:16 +00004870 /* Instructions appear in the specification's order. */
David Turnerd2b1f351999-12-16 23:11:37 +00004871 /* */
4872 /*************************************************************************/
4873
4874
4875 /*************************************************************************/
4876 /* */
4877 /* FLIPPT[]: FLIP PoinT */
4878 /* Opcode range: 0x80 */
4879 /* Stack: uint32... --> */
4880 /* */
4881 static
4882 void Ins_FLIPPT( INS_ARG )
4883 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004884 FT_UShort point;
David Turnerd2b1f351999-12-16 23:11:37 +00004885
David Turnerc6a92202000-07-04 18:12:13 +00004886 FT_UNUSED_ARG;
David Turnerd2b1f351999-12-16 23:11:37 +00004887
Werner Lemberg5811c7c2000-07-02 13:53:16 +00004888
David Turnerd2b1f351999-12-16 23:11:37 +00004889 if ( CUR.top < CUR.GS.loop )
4890 {
4891 CUR.error = TT_Err_Too_Few_Arguments;
4892 return;
4893 }
4894
4895 while ( CUR.GS.loop > 0 )
4896 {
4897 CUR.args--;
4898
David Turnerf9b8dec2000-06-16 19:34:52 +00004899 point = (FT_UShort)CUR.stack[CUR.args];
David Turnerd2b1f351999-12-16 23:11:37 +00004900
4901 if ( BOUNDS( point, CUR.pts.n_points ) )
4902 {
4903 if ( CUR.pedantic_hinting )
4904 {
4905 CUR.error = TT_Err_Invalid_Reference;
4906 return;
4907 }
4908 }
4909 else
David Turner41dbcbf2000-03-09 11:46:25 +00004910 CUR.pts.tags[point] ^= FT_Curve_Tag_On;
David Turnerd2b1f351999-12-16 23:11:37 +00004911
4912 CUR.GS.loop--;
4913 }
4914
4915 CUR.GS.loop = 1;
4916 CUR.new_top = CUR.args;
4917 }
4918
4919
4920 /*************************************************************************/
4921 /* */
4922 /* FLIPRGON[]: FLIP RanGe ON */
4923 /* Opcode range: 0x81 */
4924 /* Stack: uint32 uint32 --> */
4925 /* */
4926 static
4927 void Ins_FLIPRGON( INS_ARG )
4928 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004929 FT_UShort I, K, L;
David Turnerd2b1f351999-12-16 23:11:37 +00004930
4931
David Turnerf9b8dec2000-06-16 19:34:52 +00004932 K = (FT_UShort)args[1];
4933 L = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00004934
4935 if ( BOUNDS( K, CUR.pts.n_points ) ||
4936 BOUNDS( L, CUR.pts.n_points ) )
4937 {
4938 if ( CUR.pedantic_hinting )
4939 CUR.error = TT_Err_Invalid_Reference;
4940 return;
4941 }
4942
4943 for ( I = L; I <= K; I++ )
David Turner41dbcbf2000-03-09 11:46:25 +00004944 CUR.pts.tags[I] |= FT_Curve_Tag_On;
David Turnerd2b1f351999-12-16 23:11:37 +00004945 }
4946
4947
4948 /*************************************************************************/
4949 /* */
4950 /* FLIPRGOFF: FLIP RanGe OFF */
4951 /* Opcode range: 0x82 */
4952 /* Stack: uint32 uint32 --> */
4953 /* */
4954 static
4955 void Ins_FLIPRGOFF( INS_ARG )
4956 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004957 FT_UShort I, K, L;
David Turnerd2b1f351999-12-16 23:11:37 +00004958
4959
David Turnerf9b8dec2000-06-16 19:34:52 +00004960 K = (FT_UShort)args[1];
4961 L = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00004962
4963 if ( BOUNDS( K, CUR.pts.n_points ) ||
4964 BOUNDS( L, CUR.pts.n_points ) )
4965 {
4966 if ( CUR.pedantic_hinting )
4967 CUR.error = TT_Err_Invalid_Reference;
4968 return;
4969 }
4970
4971 for ( I = L; I <= K; I++ )
David Turner41dbcbf2000-03-09 11:46:25 +00004972 CUR.pts.tags[I] &= ~FT_Curve_Tag_On;
David Turnerd2b1f351999-12-16 23:11:37 +00004973 }
4974
4975
4976 static
David Turnerf9b8dec2000-06-16 19:34:52 +00004977 FT_Bool Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6* x,
4978 FT_F26Dot6* y,
4979 TT_GlyphZone* zone,
4980 FT_UShort* refp )
David Turnerd2b1f351999-12-16 23:11:37 +00004981 {
David Turnerf9b8dec2000-06-16 19:34:52 +00004982 TT_GlyphZone zp;
4983 FT_UShort p;
4984 FT_F26Dot6 d;
David Turnerd2b1f351999-12-16 23:11:37 +00004985
4986
4987 if ( CUR.opcode & 1 )
4988 {
4989 zp = CUR.zp0;
4990 p = CUR.GS.rp1;
4991 }
4992 else
4993 {
4994 zp = CUR.zp1;
4995 p = CUR.GS.rp2;
4996 }
4997
4998 if ( BOUNDS( p, zp.n_points ) )
4999 {
5000 if ( CUR.pedantic_hinting )
5001 CUR.error = TT_Err_Invalid_Reference;
5002 return FAILURE;
5003 }
5004
5005 *zone = zp;
5006 *refp = p;
5007
5008 d = CUR_Func_project( zp.cur + p, zp.org + p );
5009
David Turnerd42c68e2000-01-27 13:56:02 +00005010#ifdef NO_APPLE_PATENT
Werner Lemberg78575dc2000-06-12 19:36:41 +00005011
David Turnerd42c68e2000-01-27 13:56:02 +00005012 *x = TT_MULDIV( d, CUR.GS.freeVector.x, 0x4000 );
5013 *y = TT_MULDIV( d, CUR.GS.freeVector.y, 0x4000 );
Werner Lemberg78575dc2000-06-12 19:36:41 +00005014
David Turnerd42c68e2000-01-27 13:56:02 +00005015#else
Werner Lemberg78575dc2000-06-12 19:36:41 +00005016
David Turnerd2b1f351999-12-16 23:11:37 +00005017 *x = TT_MULDIV( d,
David Turnerf9b8dec2000-06-16 19:34:52 +00005018 (FT_Long)CUR.GS.freeVector.x * 0x10000L,
David Turnerd2b1f351999-12-16 23:11:37 +00005019 CUR.F_dot_P );
5020 *y = TT_MULDIV( d,
David Turnerf9b8dec2000-06-16 19:34:52 +00005021 (FT_Long)CUR.GS.freeVector.y * 0x10000L,
David Turnerd2b1f351999-12-16 23:11:37 +00005022 CUR.F_dot_P );
Werner Lemberg78575dc2000-06-12 19:36:41 +00005023
5024#endif /* NO_APPLE_PATENT */
5025
David Turnerd2b1f351999-12-16 23:11:37 +00005026 return SUCCESS;
5027 }
5028
5029
5030 static
David Turnerf9b8dec2000-06-16 19:34:52 +00005031 void Move_Zp2_Point( EXEC_OP_ FT_UShort point,
5032 FT_F26Dot6 dx,
5033 FT_F26Dot6 dy,
5034 FT_Bool touch )
David Turnerd2b1f351999-12-16 23:11:37 +00005035 {
5036 if ( CUR.GS.freeVector.x != 0 )
5037 {
5038 CUR.zp2.cur[point].x += dx;
5039 if ( touch )
David Turner41dbcbf2000-03-09 11:46:25 +00005040 CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_X;
David Turnerd2b1f351999-12-16 23:11:37 +00005041 }
5042
5043 if ( CUR.GS.freeVector.y != 0 )
5044 {
5045 CUR.zp2.cur[point].y += dy;
5046 if ( touch )
David Turner41dbcbf2000-03-09 11:46:25 +00005047 CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_Y;
David Turnerd2b1f351999-12-16 23:11:37 +00005048 }
5049 }
5050
5051
5052 /*************************************************************************/
5053 /* */
5054 /* SHP[a]: SHift Point by the last point */
5055 /* Opcode range: 0x32-0x33 */
5056 /* Stack: uint32... --> */
5057 /* */
5058 static
5059 void Ins_SHP( INS_ARG )
5060 {
David Turnerf9b8dec2000-06-16 19:34:52 +00005061 TT_GlyphZone zp;
5062 FT_UShort refp;
David Turnerd2b1f351999-12-16 23:11:37 +00005063
David Turnerf9b8dec2000-06-16 19:34:52 +00005064 FT_F26Dot6 dx,
David Turnerd2b1f351999-12-16 23:11:37 +00005065 dy;
David Turnerf9b8dec2000-06-16 19:34:52 +00005066 FT_UShort point;
David Turnerd2b1f351999-12-16 23:11:37 +00005067
David Turnerc6a92202000-07-04 18:12:13 +00005068 FT_UNUSED_ARG;
David Turnerd2b1f351999-12-16 23:11:37 +00005069
Werner Lemberg78575dc2000-06-12 19:36:41 +00005070
David Turnerd2b1f351999-12-16 23:11:37 +00005071 if ( CUR.top < CUR.GS.loop )
5072 {
5073 CUR.error = TT_Err_Invalid_Reference;
5074 return;
5075 }
5076
5077 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5078 return;
5079
5080 while ( CUR.GS.loop > 0 )
5081 {
5082 CUR.args--;
David Turnerf9b8dec2000-06-16 19:34:52 +00005083 point = (FT_UShort)CUR.stack[CUR.args];
David Turnerd2b1f351999-12-16 23:11:37 +00005084
5085 if ( BOUNDS( point, CUR.zp2.n_points ) )
5086 {
5087 if ( CUR.pedantic_hinting )
5088 {
5089 CUR.error = TT_Err_Invalid_Reference;
5090 return;
5091 }
5092 }
5093 else
5094 /* XXX: UNDOCUMENTED! SHP touches the points */
5095 MOVE_Zp2_Point( point, dx, dy, TRUE );
5096
5097 CUR.GS.loop--;
5098 }
5099
5100 CUR.GS.loop = 1;
5101 CUR.new_top = CUR.args;
5102 }
5103
5104
5105 /*************************************************************************/
5106 /* */
5107 /* SHC[a]: SHift Contour */
5108 /* Opcode range: 0x34-35 */
5109 /* Stack: uint32 --> */
5110 /* */
5111 static
5112 void Ins_SHC( INS_ARG )
5113 {
David Turnerf9b8dec2000-06-16 19:34:52 +00005114 TT_GlyphZone zp;
5115 FT_UShort refp;
5116 FT_F26Dot6 dx,
David Turnerd2b1f351999-12-16 23:11:37 +00005117 dy;
5118
David Turnerf9b8dec2000-06-16 19:34:52 +00005119 FT_Short contour;
5120 FT_UShort first_point, last_point, i;
David Turnerd2b1f351999-12-16 23:11:37 +00005121
5122
David Turnerf9b8dec2000-06-16 19:34:52 +00005123 contour = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00005124
5125 if ( BOUNDS( contour, CUR.pts.n_contours ) )
5126 {
5127 if ( CUR.pedantic_hinting )
5128 CUR.error = TT_Err_Invalid_Reference;
5129 return;
5130 }
5131
5132 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5133 return;
5134
5135 if ( contour == 0 )
5136 first_point = 0;
5137 else
5138 first_point = CUR.pts.contours[contour - 1] + 1;
5139
5140 last_point = CUR.pts.contours[contour];
5141
5142 /* XXX: this is probably wrong... at least it prevents memory */
5143 /* corruption when zp2 is the twilight zone */
5144 if ( last_point > CUR.zp2.n_points )
5145 {
5146 if ( CUR.zp2.n_points > 0 )
5147 last_point = CUR.zp2.n_points - 1;
5148 else
5149 last_point = 0;
5150 }
5151
5152 /* XXX: UNDOCUMENTED! SHC doesn't touch the points */
5153 for ( i = first_point; i <= last_point; i++ )
5154 {
5155 if ( zp.cur != CUR.zp2.cur || refp != i )
5156 MOVE_Zp2_Point( i, dx, dy, FALSE );
5157 }
5158 }
5159
5160
5161 /*************************************************************************/
5162 /* */
5163 /* SHZ[a]: SHift Zone */
5164 /* Opcode range: 0x36-37 */
5165 /* Stack: uint32 --> */
5166 /* */
5167 static
5168 void Ins_SHZ( INS_ARG )
5169 {
David Turnerf9b8dec2000-06-16 19:34:52 +00005170 TT_GlyphZone zp;
5171 FT_UShort refp;
5172 FT_F26Dot6 dx,
David Turnerd2b1f351999-12-16 23:11:37 +00005173 dy;
5174
Werner Lemberg5811c7c2000-07-02 13:53:16 +00005175 FT_UShort last_point, i;
David Turnerd2b1f351999-12-16 23:11:37 +00005176
5177
5178 if ( BOUNDS( args[0], 2 ) )
5179 {
5180 if ( CUR.pedantic_hinting )
5181 CUR.error = TT_Err_Invalid_Reference;
5182 return;
5183 }
5184
5185 if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
5186 return;
5187
5188 if ( CUR.zp2.n_points > 0 )
5189 last_point = CUR.zp2.n_points - 1;
5190 else
5191 last_point = 0;
5192
5193 /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
5194 for ( i = 0; i <= last_point; i++ )
5195 {
5196 if ( zp.cur != CUR.zp2.cur || refp != i )
5197 MOVE_Zp2_Point( i, dx, dy, FALSE );
5198 }
5199 }
5200
5201
5202 /*************************************************************************/
5203 /* */
5204 /* SHPIX[]: SHift points by a PIXel amount */
5205 /* Opcode range: 0x38 */
5206 /* Stack: f26.6 uint32... --> */
5207 /* */
5208 static
5209 void Ins_SHPIX( INS_ARG )
5210 {
David Turnerf9b8dec2000-06-16 19:34:52 +00005211 FT_F26Dot6 dx, dy;
5212 FT_UShort point;
David Turnerd2b1f351999-12-16 23:11:37 +00005213
5214
5215 if ( CUR.top < CUR.GS.loop + 1 )
5216 {
5217 CUR.error = TT_Err_Invalid_Reference;
5218 return;
5219 }
5220
5221 dx = TT_MULDIV( args[0],
David Turnerf9b8dec2000-06-16 19:34:52 +00005222 (FT_Long)CUR.GS.freeVector.x,
David Turnerd2b1f351999-12-16 23:11:37 +00005223 0x4000 );
5224 dy = TT_MULDIV( args[0],
David Turnerf9b8dec2000-06-16 19:34:52 +00005225 (FT_Long)CUR.GS.freeVector.y,
David Turnerd2b1f351999-12-16 23:11:37 +00005226 0x4000 );
5227
5228 while ( CUR.GS.loop > 0 )
5229 {
5230 CUR.args--;
5231
David Turnerf9b8dec2000-06-16 19:34:52 +00005232 point = (FT_UShort)CUR.stack[CUR.args];
David Turnerd2b1f351999-12-16 23:11:37 +00005233
5234 if ( BOUNDS( point, CUR.zp2.n_points ) )
5235 {
5236 if ( CUR.pedantic_hinting )
5237 {
5238 CUR.error = TT_Err_Invalid_Reference;
5239 return;
5240 }
5241 }
5242 else
5243 MOVE_Zp2_Point( point, dx, dy, TRUE );
5244
5245 CUR.GS.loop--;
5246 }
5247
5248 CUR.GS.loop = 1;
5249 CUR.new_top = CUR.args;
5250 }
5251
5252
5253 /*************************************************************************/
5254 /* */
5255 /* MSIRP[a]: Move Stack Indirect Relative Position */
5256 /* Opcode range: 0x3A-0x3B */
5257 /* Stack: f26.6 uint32 --> */
5258 /* */
5259 static
5260 void Ins_MSIRP( INS_ARG )
5261 {
David Turnerf9b8dec2000-06-16 19:34:52 +00005262 FT_UShort point;
5263 FT_F26Dot6 distance;
David Turnerd2b1f351999-12-16 23:11:37 +00005264
5265
David Turnerf9b8dec2000-06-16 19:34:52 +00005266 point = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00005267
5268 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5269 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5270 {
5271 if ( CUR.pedantic_hinting )
5272 CUR.error = TT_Err_Invalid_Reference;
5273 return;
5274 }
5275
5276 /* XXX: UNDOCUMENTED! behaviour */
5277 if ( CUR.GS.gep0 == 0 ) /* if in twilight zone */
5278 {
5279 CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
5280 CUR.zp1.cur[point] = CUR.zp1.org[point];
5281 }
5282
5283 distance = CUR_Func_project( CUR.zp1.cur + point,
5284 CUR.zp0.cur + CUR.GS.rp0 );
5285
5286 CUR_Func_move( &CUR.zp1, point, args[1] - distance );
5287
5288 CUR.GS.rp1 = CUR.GS.rp0;
5289 CUR.GS.rp2 = point;
5290
5291 if ( (CUR.opcode & 1) != 0 )
5292 CUR.GS.rp0 = point;
5293 }
5294
5295
5296 /*************************************************************************/
5297 /* */
5298 /* MDAP[a]: Move Direct Absolute Point */
5299 /* Opcode range: 0x2E-0x2F */
5300 /* Stack: uint32 --> */
5301 /* */
5302 static
5303 void Ins_MDAP( INS_ARG )
5304 {
David Turnerf9b8dec2000-06-16 19:34:52 +00005305 FT_UShort point;
5306 FT_F26Dot6 cur_dist,
David Turnerd2b1f351999-12-16 23:11:37 +00005307 distance;
5308
5309
David Turnerf9b8dec2000-06-16 19:34:52 +00005310 point = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00005311
5312 if ( BOUNDS( point, CUR.zp0.n_points ) )
5313 {
5314 if ( CUR.pedantic_hinting )
5315 CUR.error = TT_Err_Invalid_Reference;
5316 return;
5317 }
5318
5319 /* XXX: Is there some undocumented feature while in the */
5320 /* twilight zone? ? */
Werner Lemberg78575dc2000-06-12 19:36:41 +00005321 if ( ( CUR.opcode & 1 ) != 0 )
David Turnerd2b1f351999-12-16 23:11:37 +00005322 {
5323 cur_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
5324 distance = CUR_Func_round( cur_dist,
5325 CUR.tt_metrics.compensations[0] ) - cur_dist;
5326 }
5327 else
5328 distance = 0;
5329
5330 CUR_Func_move( &CUR.zp0, point, distance );
5331
5332 CUR.GS.rp0 = point;
5333 CUR.GS.rp1 = point;
5334 }
5335
5336
5337 /*************************************************************************/
5338 /* */
5339 /* MIAP[a]: Move Indirect Absolute Point */
5340 /* Opcode range: 0x3E-0x3F */
5341 /* Stack: uint32 uint32 --> */
5342 /* */
5343 static
5344 void Ins_MIAP( INS_ARG )
5345 {
David Turnerf9b8dec2000-06-16 19:34:52 +00005346 FT_ULong cvtEntry;
5347 FT_UShort point;
5348 FT_F26Dot6 distance,
David Turnerd2b1f351999-12-16 23:11:37 +00005349 org_dist;
5350
5351
David Turnerf9b8dec2000-06-16 19:34:52 +00005352 cvtEntry = (FT_ULong)args[1];
5353 point = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00005354
5355 if ( BOUNDS( point, CUR.zp0.n_points ) ||
5356 BOUNDS( cvtEntry, CUR.cvtSize ) )
5357 {
5358 if ( CUR.pedantic_hinting )
5359 CUR.error = TT_Err_Invalid_Reference;
5360 return;
5361 }
5362
5363 /* UNDOCUMENTED! */
5364 /* */
5365 /* The behaviour of an MIAP instruction is quite */
5366 /* different when used in the twilight zone. */
5367 /* */
5368 /* First, no control value cutin test is performed */
5369 /* as it would fail anyway. Second, the original */
5370 /* point, i.e. (org_x,org_y) of zp0.point, is set */
5371 /* to the absolute, unrounded distance found in */
5372 /* the CVT. */
5373 /* */
5374 /* This is used in the CVT programs of the Microsoft */
5375 /* fonts Arial, Times, etc., in order to re-adjust */
5376 /* some key font heights. It allows the use of the */
5377 /* IP instruction in the twilight zone, which */
5378 /* otherwise would be `illegal' according to the */
Werner Lemberg78575dc2000-06-12 19:36:41 +00005379 /* specification. */
David Turnerd2b1f351999-12-16 23:11:37 +00005380 /* */
5381 /* We implement it with a special sequence for the */
5382 /* twilight zone. This is a bad hack, but it seems */
5383 /* to work. */
5384
5385 distance = CUR_Func_read_cvt( cvtEntry );
5386
5387 if ( CUR.GS.gep0 == 0 ) /* If in twilight zone */
5388 {
5389 CUR.zp0.org[point].x = TT_MULDIV( CUR.GS.freeVector.x,
5390 distance, 0x4000 );
5391 CUR.zp0.org[point].y = TT_MULDIV( CUR.GS.freeVector.y,
5392 distance, 0x4000 );
5393 CUR.zp0.cur[point] = CUR.zp0.org[point];
5394 }
5395
5396 org_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
5397
Werner Lemberg78575dc2000-06-12 19:36:41 +00005398 if ( ( CUR.opcode & 1 ) != 0 ) /* rounding and control cutin flag */
David Turnerd2b1f351999-12-16 23:11:37 +00005399 {
5400 if ( ABS( distance - org_dist ) > CUR.GS.control_value_cutin )
5401 distance = org_dist;
5402
5403 distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] );
5404 }
5405
5406 CUR_Func_move( &CUR.zp0, point, distance - org_dist );
5407
5408 CUR.GS.rp0 = point;
5409 CUR.GS.rp1 = point;
5410 }
5411
5412
5413 /*************************************************************************/
5414 /* */
5415 /* MDRP[abcde]: Move Direct Relative Point */
5416 /* Opcode range: 0xC0-0xDF */
5417 /* Stack: uint32 --> */
5418 /* */
5419 static
5420 void Ins_MDRP( INS_ARG )
5421 {
David Turnerf9b8dec2000-06-16 19:34:52 +00005422 FT_UShort point;
5423 FT_F26Dot6 org_dist, distance;
David Turnerd2b1f351999-12-16 23:11:37 +00005424
5425
David Turnerf9b8dec2000-06-16 19:34:52 +00005426 point = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00005427
5428 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5429 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5430 {
5431 if ( CUR.pedantic_hinting )
5432 CUR.error = TT_Err_Invalid_Reference;
5433 return;
5434 }
5435
5436 /* XXX: Is there some undocumented feature while in the */
5437 /* twilight zone? */
5438
5439 org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
5440 CUR.zp0.org + CUR.GS.rp0 );
5441
5442 /* single width cutin test */
5443
5444 if ( ABS( org_dist ) < CUR.GS.single_width_cutin )
5445 {
5446 if ( org_dist >= 0 )
5447 org_dist = CUR.GS.single_width_value;
5448 else
5449 org_dist = -CUR.GS.single_width_value;
5450 }
5451
5452 /* round flag */
5453
Werner Lemberg78575dc2000-06-12 19:36:41 +00005454 if ( ( CUR.opcode & 4 ) != 0 )
5455 distance = CUR_Func_round(
5456 org_dist,
5457 CUR.tt_metrics.compensations[CUR.opcode & 3] );
David Turnerd2b1f351999-12-16 23:11:37 +00005458 else
Werner Lemberg78575dc2000-06-12 19:36:41 +00005459 distance = ROUND_None(
5460 org_dist,
5461 CUR.tt_metrics.compensations[CUR.opcode & 3] );
David Turnerd2b1f351999-12-16 23:11:37 +00005462
5463 /* minimum distance flag */
5464
Werner Lemberg78575dc2000-06-12 19:36:41 +00005465 if ( ( CUR.opcode & 8 ) != 0 )
David Turnerd2b1f351999-12-16 23:11:37 +00005466 {
5467 if ( org_dist >= 0 )
5468 {
5469 if ( distance < CUR.GS.minimum_distance )
5470 distance = CUR.GS.minimum_distance;
5471 }
5472 else
5473 {
5474 if ( distance > -CUR.GS.minimum_distance )
5475 distance = -CUR.GS.minimum_distance;
5476 }
5477 }
5478
5479 /* now move the point */
5480
5481 org_dist = CUR_Func_project( CUR.zp1.cur + point,
5482 CUR.zp0.cur + CUR.GS.rp0 );
5483
5484 CUR_Func_move( &CUR.zp1, point, distance - org_dist );
5485
5486 CUR.GS.rp1 = CUR.GS.rp0;
5487 CUR.GS.rp2 = point;
5488
Werner Lemberg78575dc2000-06-12 19:36:41 +00005489 if ( ( CUR.opcode & 16 ) != 0 )
David Turnerd2b1f351999-12-16 23:11:37 +00005490 CUR.GS.rp0 = point;
5491 }
5492
5493
5494 /*************************************************************************/
5495 /* */
5496 /* MIRP[abcde]: Move Indirect Relative Point */
5497 /* Opcode range: 0xE0-0xFF */
5498 /* Stack: int32? uint32 --> */
5499 /* */
5500 static
5501 void Ins_MIRP( INS_ARG )
5502 {
David Turnerf9b8dec2000-06-16 19:34:52 +00005503 FT_UShort point;
5504 FT_ULong cvtEntry;
David Turnerd2b1f351999-12-16 23:11:37 +00005505
David Turnerf9b8dec2000-06-16 19:34:52 +00005506 FT_F26Dot6 cvt_dist,
David Turnerd2b1f351999-12-16 23:11:37 +00005507 distance,
5508 cur_dist,
5509 org_dist;
5510
5511
David Turnerf9b8dec2000-06-16 19:34:52 +00005512 point = (FT_UShort)args[0];
5513 cvtEntry = (FT_ULong)( args[1] + 1 );
David Turnerd2b1f351999-12-16 23:11:37 +00005514
5515 /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
5516
5517 if ( BOUNDS( point, CUR.zp1.n_points ) ||
5518 BOUNDS( cvtEntry, CUR.cvtSize + 1 ) ||
5519 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5520 {
5521 if ( CUR.pedantic_hinting )
5522 CUR.error = TT_Err_Invalid_Reference;
5523 return;
5524 }
5525
5526 if ( !cvtEntry )
5527 cvt_dist = 0;
5528 else
5529 cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
5530
5531 /* single width test */
5532
5533 if ( ABS( cvt_dist ) < CUR.GS.single_width_cutin )
5534 {
5535 if ( cvt_dist >= 0 )
5536 cvt_dist = CUR.GS.single_width_value;
5537 else
5538 cvt_dist = -CUR.GS.single_width_value;
5539 }
5540
5541 /* XXX: UNDOCUMENTED! -- twilight zone */
5542
5543 if ( CUR.GS.gep1 == 0 )
5544 {
5545 CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +
5546 TT_MULDIV( cvt_dist,
5547 CUR.GS.freeVector.x,
5548 0x4000 );
5549
5550 CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
5551 TT_MULDIV( cvt_dist,
5552 CUR.GS.freeVector.y,
5553 0x4000 );
5554
5555 CUR.zp1.cur[point] = CUR.zp1.org[point];
5556 }
5557
5558 org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
5559 CUR.zp0.org + CUR.GS.rp0 );
5560
5561 cur_dist = CUR_Func_project( CUR.zp1.cur + point,
5562 CUR.zp0.cur + CUR.GS.rp0 );
5563
5564 /* auto-flip test */
5565
5566 if ( CUR.GS.auto_flip )
5567 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00005568 if ( ( org_dist ^ cvt_dist ) < 0 )
David Turnerd2b1f351999-12-16 23:11:37 +00005569 cvt_dist = -cvt_dist;
5570 }
5571
5572 /* control value cutin and round */
5573
Werner Lemberg78575dc2000-06-12 19:36:41 +00005574 if ( ( CUR.opcode & 4 ) != 0 )
David Turnerd2b1f351999-12-16 23:11:37 +00005575 {
5576 /* XXX: UNDOCUMENTED! Only perform cut-in test when both points */
5577 /* refer to the same zone. */
5578
5579 if ( CUR.GS.gep0 == CUR.GS.gep1 )
5580 if ( ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin )
5581 cvt_dist = org_dist;
5582
Werner Lemberg78575dc2000-06-12 19:36:41 +00005583 distance = CUR_Func_round(
5584 cvt_dist,
5585 CUR.tt_metrics.compensations[CUR.opcode & 3] );
David Turnerd2b1f351999-12-16 23:11:37 +00005586 }
5587 else
Werner Lemberg78575dc2000-06-12 19:36:41 +00005588 distance = ROUND_None(
5589 cvt_dist,
5590 CUR.tt_metrics.compensations[CUR.opcode & 3] );
David Turnerd2b1f351999-12-16 23:11:37 +00005591
5592 /* minimum distance test */
5593
Werner Lemberg78575dc2000-06-12 19:36:41 +00005594 if ( ( CUR.opcode & 8 ) != 0 )
David Turnerd2b1f351999-12-16 23:11:37 +00005595 {
5596 if ( org_dist >= 0 )
5597 {
5598 if ( distance < CUR.GS.minimum_distance )
5599 distance = CUR.GS.minimum_distance;
5600 }
5601 else
5602 {
5603 if ( distance > -CUR.GS.minimum_distance )
5604 distance = -CUR.GS.minimum_distance;
5605 }
5606 }
5607
5608 CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
5609
5610 CUR.GS.rp1 = CUR.GS.rp0;
5611
Werner Lemberg78575dc2000-06-12 19:36:41 +00005612 if ( ( CUR.opcode & 16 ) != 0 )
David Turnerd2b1f351999-12-16 23:11:37 +00005613 CUR.GS.rp0 = point;
5614
5615 /* XXX: UNDOCUMENTED! */
5616
5617 CUR.GS.rp2 = point;
5618 }
5619
5620
5621 /*************************************************************************/
5622 /* */
5623 /* ALIGNRP[]: ALIGN Relative Point */
5624 /* Opcode range: 0x3C */
5625 /* Stack: uint32 uint32... --> */
5626 /* */
5627 static
5628 void Ins_ALIGNRP( INS_ARG )
5629 {
David Turnerf9b8dec2000-06-16 19:34:52 +00005630 FT_UShort point;
5631 FT_F26Dot6 distance;
David Turnerd2b1f351999-12-16 23:11:37 +00005632
David Turnerc6a92202000-07-04 18:12:13 +00005633 FT_UNUSED_ARG;
David Turnerd2b1f351999-12-16 23:11:37 +00005634
Werner Lemberg78575dc2000-06-12 19:36:41 +00005635
David Turnerd2b1f351999-12-16 23:11:37 +00005636 if ( CUR.top < CUR.GS.loop ||
5637 BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
5638 {
5639 if ( CUR.pedantic_hinting )
5640 CUR.error = TT_Err_Invalid_Reference;
5641 return;
5642 }
5643
5644 while ( CUR.GS.loop > 0 )
5645 {
5646 CUR.args--;
5647
David Turnerf9b8dec2000-06-16 19:34:52 +00005648 point = (FT_UShort)CUR.stack[CUR.args];
David Turnerd2b1f351999-12-16 23:11:37 +00005649
5650 if ( BOUNDS( point, CUR.zp1.n_points ) )
5651 {
5652 if ( CUR.pedantic_hinting )
5653 {
5654 CUR.error = TT_Err_Invalid_Reference;
5655 return;
5656 }
5657 }
5658 else
5659 {
5660 distance = CUR_Func_project( CUR.zp1.cur + point,
5661 CUR.zp0.cur + CUR.GS.rp0 );
5662
5663 CUR_Func_move( &CUR.zp1, point, -distance );
5664 }
5665
5666 CUR.GS.loop--;
5667 }
5668
5669 CUR.GS.loop = 1;
5670 CUR.new_top = CUR.args;
5671 }
5672
5673
5674 /*************************************************************************/
5675 /* */
5676 /* ISECT[]: moves point to InterSECTion */
5677 /* Opcode range: 0x0F */
5678 /* Stack: 5 * uint32 --> */
5679 /* */
5680 static
5681 void Ins_ISECT( INS_ARG )
5682 {
David Turnerf9b8dec2000-06-16 19:34:52 +00005683 FT_UShort point,
David Turnerd2b1f351999-12-16 23:11:37 +00005684 a0, a1,
5685 b0, b1;
5686
David Turnerf9b8dec2000-06-16 19:34:52 +00005687 FT_F26Dot6 discriminant;
David Turnerd2b1f351999-12-16 23:11:37 +00005688
David Turnerf9b8dec2000-06-16 19:34:52 +00005689 FT_F26Dot6 dx, dy,
David Turnerd2b1f351999-12-16 23:11:37 +00005690 dax, day,
5691 dbx, dby;
5692
David Turnerf9b8dec2000-06-16 19:34:52 +00005693 FT_F26Dot6 val;
David Turnerd2b1f351999-12-16 23:11:37 +00005694
David Turnerf9b8dec2000-06-16 19:34:52 +00005695 FT_Vector R;
David Turnerd2b1f351999-12-16 23:11:37 +00005696
5697
David Turnerf9b8dec2000-06-16 19:34:52 +00005698 point = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00005699
David Turnerf9b8dec2000-06-16 19:34:52 +00005700 a0 = (FT_UShort)args[1];
5701 a1 = (FT_UShort)args[2];
5702 b0 = (FT_UShort)args[3];
5703 b1 = (FT_UShort)args[4];
David Turnerd2b1f351999-12-16 23:11:37 +00005704
5705 if ( BOUNDS( b0, CUR.zp0.n_points ) ||
5706 BOUNDS( b1, CUR.zp0.n_points ) ||
5707 BOUNDS( a0, CUR.zp1.n_points ) ||
5708 BOUNDS( a1, CUR.zp1.n_points ) ||
5709 BOUNDS( point, CUR.zp2.n_points ) )
5710 {
5711 if ( CUR.pedantic_hinting )
5712 CUR.error = TT_Err_Invalid_Reference;
5713 return;
5714 }
5715
5716 dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
5717 dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
5718
5719 dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;
5720 day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;
5721
5722 dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;
5723 dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;
5724
David Turner41dbcbf2000-03-09 11:46:25 +00005725 CUR.zp2.tags[point] |= FT_Curve_Tag_Touch_Both;
David Turnerd2b1f351999-12-16 23:11:37 +00005726
5727 discriminant = TT_MULDIV( dax, -dby, 0x40 ) +
5728 TT_MULDIV( day, dbx, 0x40 );
5729
5730 if ( ABS( discriminant ) >= 0x40 )
5731 {
5732 val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 );
5733
5734 R.x = TT_MULDIV( val, dax, discriminant );
5735 R.y = TT_MULDIV( val, day, discriminant );
5736
5737 CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
5738 CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
5739 }
5740 else
5741 {
5742 /* else, take the middle of the middles of A and B */
5743
5744 CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +
5745 CUR.zp1.cur[a1].x +
5746 CUR.zp0.cur[b0].x +
5747 CUR.zp0.cur[b1].x ) / 4;
5748 CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +
5749 CUR.zp1.cur[a1].y +
5750 CUR.zp0.cur[b0].y +
5751 CUR.zp0.cur[b1].y ) / 4;
5752 }
5753 }
5754
5755
5756 /*************************************************************************/
5757 /* */
5758 /* ALIGNPTS[]: ALIGN PoinTS */
5759 /* Opcode range: 0x27 */
5760 /* Stack: uint32 uint32 --> */
5761 /* */
5762 static
5763 void Ins_ALIGNPTS( INS_ARG )
5764 {
David Turnerf9b8dec2000-06-16 19:34:52 +00005765 FT_UShort p1, p2;
5766 FT_F26Dot6 distance;
David Turnerd2b1f351999-12-16 23:11:37 +00005767
5768
David Turnerf9b8dec2000-06-16 19:34:52 +00005769 p1 = (FT_UShort)args[0];
5770 p2 = (FT_UShort)args[1];
David Turnerd2b1f351999-12-16 23:11:37 +00005771
5772 if ( BOUNDS( args[0], CUR.zp1.n_points ) ||
5773 BOUNDS( args[1], CUR.zp0.n_points ) )
5774 {
5775 if ( CUR.pedantic_hinting )
5776 CUR.error = TT_Err_Invalid_Reference;
5777 return;
5778 }
5779
5780 distance = CUR_Func_project( CUR.zp0.cur + p2,
5781 CUR.zp1.cur + p1 ) / 2;
5782
5783 CUR_Func_move( &CUR.zp1, p1, distance );
5784 CUR_Func_move( &CUR.zp0, p2, -distance );
5785 }
5786
5787
5788 /*************************************************************************/
5789 /* */
5790 /* IP[]: Interpolate Point */
5791 /* Opcode range: 0x39 */
5792 /* Stack: uint32... --> */
5793 /* */
5794 static
5795 void Ins_IP( INS_ARG )
5796 {
David Turnerf9b8dec2000-06-16 19:34:52 +00005797 FT_F26Dot6 org_a, org_b, org_x,
David Turnerd2b1f351999-12-16 23:11:37 +00005798 cur_a, cur_b, cur_x,
5799 distance;
David Turnerf9b8dec2000-06-16 19:34:52 +00005800 FT_UShort point;
David Turnerd2b1f351999-12-16 23:11:37 +00005801
David Turnerc6a92202000-07-04 18:12:13 +00005802 FT_UNUSED_ARG;
David Turnerd2b1f351999-12-16 23:11:37 +00005803
Werner Lemberg78575dc2000-06-12 19:36:41 +00005804
David Turnerd2b1f351999-12-16 23:11:37 +00005805 if ( CUR.top < CUR.GS.loop )
5806 {
5807 CUR.error = TT_Err_Invalid_Reference;
5808 return;
5809 }
5810
Werner Lemberg5811c7c2000-07-02 13:53:16 +00005811 /* XXX: There are some glyphs in some braindead but popular */
David Turnerd2b1f351999-12-16 23:11:37 +00005812 /* fonts out there (e.g. [aeu]grave in monotype.ttf) */
5813 /* calling IP[] with bad values of rp[12]. */
5814 /* Do something sane when this odd thing happens. */
5815
5816 if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
5817 BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
5818 {
5819 org_a = cur_a = 0;
5820 org_b = cur_b = 0;
5821 }
5822 else
5823 {
5824 org_a = CUR_Func_dualproj( CUR.zp0.org + CUR.GS.rp1, NULL_Vector );
5825 org_b = CUR_Func_dualproj( CUR.zp1.org + CUR.GS.rp2, NULL_Vector );
5826
5827 cur_a = CUR_Func_project( CUR.zp0.cur + CUR.GS.rp1, NULL_Vector );
5828 cur_b = CUR_Func_project( CUR.zp1.cur + CUR.GS.rp2, NULL_Vector );
5829 }
5830
5831 while ( CUR.GS.loop > 0 )
5832 {
5833 CUR.args--;
5834
David Turnerf9b8dec2000-06-16 19:34:52 +00005835 point = (FT_UShort)CUR.stack[CUR.args];
David Turnerd2b1f351999-12-16 23:11:37 +00005836 if ( BOUNDS( point, CUR.zp2.n_points ) )
5837 {
5838 if ( CUR.pedantic_hinting )
5839 {
5840 CUR.error = TT_Err_Invalid_Reference;
5841 return;
5842 }
5843 }
5844 else
5845 {
5846 org_x = CUR_Func_dualproj( CUR.zp2.org + point, NULL_Vector );
5847 cur_x = CUR_Func_project ( CUR.zp2.cur + point, NULL_Vector );
5848
5849 if ( ( org_a <= org_b && org_x <= org_a ) ||
5850 ( org_a > org_b && org_x >= org_a ) )
5851
5852 distance = ( cur_a - org_a ) + ( org_x - cur_x );
5853
5854 else if ( ( org_a <= org_b && org_x >= org_b ) ||
5855 ( org_a > org_b && org_x < org_b ) )
5856
5857 distance = ( cur_b - org_b ) + ( org_x - cur_x );
5858
5859 else
5860 /* note: it seems that rounding this value isn't a good */
5861 /* idea (cf. width of capital `S' in Times) */
5862
5863 distance = TT_MULDIV( cur_b - cur_a,
5864 org_x - org_a,
5865 org_b - org_a ) + ( cur_a - cur_x );
5866
5867 CUR_Func_move( &CUR.zp2, point, distance );
5868 }
5869
5870 CUR.GS.loop--;
5871 }
5872
5873 CUR.GS.loop = 1;
5874 CUR.new_top = CUR.args;
5875 }
5876
5877
5878 /*************************************************************************/
5879 /* */
5880 /* UTP[a]: UnTouch Point */
5881 /* Opcode range: 0x29 */
5882 /* Stack: uint32 --> */
5883 /* */
5884 static
5885 void Ins_UTP( INS_ARG )
5886 {
David Turnerf9b8dec2000-06-16 19:34:52 +00005887 FT_UShort point;
5888 FT_Byte mask;
David Turnerd2b1f351999-12-16 23:11:37 +00005889
5890
David Turnerf9b8dec2000-06-16 19:34:52 +00005891 point = (FT_UShort)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00005892
5893 if ( BOUNDS( point, CUR.zp0.n_points ) )
5894 {
5895 if ( CUR.pedantic_hinting )
5896 CUR.error = TT_Err_Invalid_Reference;
5897 return;
5898 }
5899
5900 mask = 0xFF;
5901
5902 if ( CUR.GS.freeVector.x != 0 )
5903 mask &= ~FT_Curve_Tag_Touch_X;
5904
5905 if ( CUR.GS.freeVector.y != 0 )
5906 mask &= ~FT_Curve_Tag_Touch_Y;
5907
David Turner41dbcbf2000-03-09 11:46:25 +00005908 CUR.zp0.tags[point] &= mask;
David Turnerd2b1f351999-12-16 23:11:37 +00005909 }
5910
5911
5912 /* Local variables for Ins_IUP: */
Werner Lemberg5811c7c2000-07-02 13:53:16 +00005913 struct LOC_Ins_IUP
David Turnerd2b1f351999-12-16 23:11:37 +00005914 {
David Turnerf9b8dec2000-06-16 19:34:52 +00005915 FT_Vector* orgs; /* original and current coordinate */
5916 FT_Vector* curs; /* arrays */
David Turnerd2b1f351999-12-16 23:11:37 +00005917 };
5918
5919
Werner Lemberg78575dc2000-06-12 19:36:41 +00005920 static
David Turnerf9b8dec2000-06-16 19:34:52 +00005921 void Shift( FT_UInt p1,
5922 FT_UInt p2,
5923 FT_UInt p,
Werner Lemberg78575dc2000-06-12 19:36:41 +00005924 struct LOC_Ins_IUP* LINK )
David Turnerd2b1f351999-12-16 23:11:37 +00005925 {
David Turnerf9b8dec2000-06-16 19:34:52 +00005926 FT_UInt i;
5927 FT_F26Dot6 x;
David Turnerd2b1f351999-12-16 23:11:37 +00005928
Werner Lemberg78575dc2000-06-12 19:36:41 +00005929
David Turnerd2b1f351999-12-16 23:11:37 +00005930 x = LINK->curs[p].x - LINK->orgs[p].x;
5931
5932 for ( i = p1; i < p; i++ )
5933 LINK->curs[i].x += x;
5934
5935 for ( i = p + 1; i <= p2; i++ )
5936 LINK->curs[i].x += x;
5937 }
5938
5939
Werner Lemberg78575dc2000-06-12 19:36:41 +00005940 static
David Turnerf9b8dec2000-06-16 19:34:52 +00005941 void Interp( FT_UInt p1,
5942 FT_UInt p2,
5943 FT_UInt ref1,
5944 FT_UInt ref2,
Werner Lemberg78575dc2000-06-12 19:36:41 +00005945 struct LOC_Ins_IUP* LINK )
David Turnerd2b1f351999-12-16 23:11:37 +00005946 {
David Turnerf9b8dec2000-06-16 19:34:52 +00005947 FT_UInt i;
5948 FT_F26Dot6 x, x1, x2, d1, d2;
David Turnerd2b1f351999-12-16 23:11:37 +00005949
Werner Lemberg78575dc2000-06-12 19:36:41 +00005950
David Turnerd2b1f351999-12-16 23:11:37 +00005951 if ( p1 > p2 )
5952 return;
5953
5954 x1 = LINK->orgs[ref1].x;
5955 d1 = LINK->curs[ref1].x - LINK->orgs[ref1].x;
5956 x2 = LINK->orgs[ref2].x;
5957 d2 = LINK->curs[ref2].x - LINK->orgs[ref2].x;
5958
5959 if ( x1 == x2 )
5960 {
5961 for ( i = p1; i <= p2; i++ )
5962 {
5963 x = LINK->orgs[i].x;
5964
5965 if ( x <= x1 )
5966 x += d1;
5967 else
5968 x += d2;
5969
5970 LINK->curs[i].x = x;
5971 }
5972 return;
5973 }
5974
5975 if ( x1 < x2 )
5976 {
5977 for ( i = p1; i <= p2; i++ )
5978 {
5979 x = LINK->orgs[i].x;
5980
5981 if ( x <= x1 )
5982 x += d1;
5983 else
5984 {
5985 if ( x >= x2 )
5986 x += d2;
5987 else
5988 x = LINK->curs[ref1].x +
5989 TT_MULDIV( x - x1,
5990 LINK->curs[ref2].x - LINK->curs[ref1].x,
5991 x2 - x1 );
5992 }
5993 LINK->curs[i].x = x;
5994 }
5995 return;
5996 }
5997
5998 /* x2 < x1 */
5999
6000 for ( i = p1; i <= p2; i++ )
6001 {
6002 x = LINK->orgs[i].x;
6003 if ( x <= x2 )
6004 x += d2;
6005 else
6006 {
6007 if ( x >= x1 )
6008 x += d1;
6009 else
6010 x = LINK->curs[ref1].x +
6011 TT_MULDIV( x - x1,
6012 LINK->curs[ref2].x - LINK->curs[ref1].x,
6013 x2 - x1 );
6014 }
6015 LINK->curs[i].x = x;
6016 }
6017 }
6018
6019
6020 /*************************************************************************/
6021 /* */
6022 /* IUP[a]: Interpolate Untouched Points */
6023 /* Opcode range: 0x30-0x31 */
6024 /* Stack: --> */
6025 /* */
6026 static
6027 void Ins_IUP( INS_ARG )
6028 {
6029 struct LOC_Ins_IUP V;
David Turnerf9b8dec2000-06-16 19:34:52 +00006030 FT_Byte mask;
David Turnerd2b1f351999-12-16 23:11:37 +00006031
David Turnerf9b8dec2000-06-16 19:34:52 +00006032 FT_UInt first_point; /* first point of contour */
6033 FT_UInt end_point; /* end point (last+1) of contour */
David Turnerd2b1f351999-12-16 23:11:37 +00006034
David Turnerf9b8dec2000-06-16 19:34:52 +00006035 FT_UInt first_touched; /* first touched point in contour */
6036 FT_UInt cur_touched; /* current touched point in contour */
David Turnerd2b1f351999-12-16 23:11:37 +00006037
David Turnerf9b8dec2000-06-16 19:34:52 +00006038 FT_UInt point; /* current point */
6039 FT_Short contour; /* current contour */
David Turnerd2b1f351999-12-16 23:11:37 +00006040
David Turnerc6a92202000-07-04 18:12:13 +00006041 FT_UNUSED_ARG;
David Turnerd2b1f351999-12-16 23:11:37 +00006042
Werner Lemberg78575dc2000-06-12 19:36:41 +00006043
David Turnerd2b1f351999-12-16 23:11:37 +00006044 if ( CUR.opcode & 1 )
6045 {
6046 mask = FT_Curve_Tag_Touch_X;
6047 V.orgs = CUR.pts.org;
6048 V.curs = CUR.pts.cur;
6049 }
6050 else
6051 {
6052 mask = FT_Curve_Tag_Touch_Y;
David Turner43a2f652000-07-05 18:23:38 +00006053 V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
6054 V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
David Turnerd2b1f351999-12-16 23:11:37 +00006055 }
6056
6057 contour = 0;
6058 point = 0;
6059
6060 do
6061 {
6062 end_point = CUR.pts.contours[contour];
6063 first_point = point;
6064
David Turner41dbcbf2000-03-09 11:46:25 +00006065 while ( point <= end_point && (CUR.pts.tags[point] & mask) == 0 )
David Turnerd2b1f351999-12-16 23:11:37 +00006066 point++;
6067
6068 if ( point <= end_point )
6069 {
6070 first_touched = point;
6071 cur_touched = point;
6072
6073 point++;
6074
6075 while ( point <= end_point )
6076 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00006077 if ( ( CUR.pts.tags[point] & mask ) != 0 )
David Turnerd2b1f351999-12-16 23:11:37 +00006078 {
6079 if ( point > 0 )
6080 Interp( cur_touched + 1,
6081 point - 1,
6082 cur_touched,
6083 point,
6084 &V );
6085 cur_touched = point;
6086 }
6087
6088 point++;
6089 }
6090
6091 if ( cur_touched == first_touched )
6092 Shift( first_point, end_point, cur_touched, &V );
6093 else
6094 {
David Turnerf9b8dec2000-06-16 19:34:52 +00006095 Interp( (FT_UShort)( cur_touched + 1 ),
David Turnerd2b1f351999-12-16 23:11:37 +00006096 end_point,
6097 cur_touched,
6098 first_touched,
6099 &V );
6100
6101 if ( first_touched > 0 )
6102 Interp( first_point,
6103 first_touched - 1,
6104 cur_touched,
6105 first_touched,
6106 &V );
6107 }
6108 }
6109 contour++;
6110 } while ( contour < CUR.pts.n_contours );
6111 }
6112
6113
6114 /*************************************************************************/
6115 /* */
6116 /* DELTAPn[]: DELTA exceptions P1, P2, P3 */
6117 /* Opcode range: 0x5D,0x71,0x72 */
6118 /* Stack: uint32 (2 * uint32)... --> */
6119 /* */
6120 static
6121 void Ins_DELTAP( INS_ARG )
6122 {
David Turnerf9b8dec2000-06-16 19:34:52 +00006123 FT_ULong k, nump;
6124 FT_UShort A;
6125 FT_ULong C;
6126 FT_Long B;
David Turnerd2b1f351999-12-16 23:11:37 +00006127
6128
David Turnerf9b8dec2000-06-16 19:34:52 +00006129 nump = (FT_ULong)args[0]; /* some points theoretically may occur more
David Turnerd2b1f351999-12-16 23:11:37 +00006130 than once, thus UShort isn't enough */
6131
6132 for ( k = 1; k <= nump; k++ )
6133 {
6134 if ( CUR.args < 2 )
6135 {
6136 CUR.error = TT_Err_Too_Few_Arguments;
6137 return;
6138 }
6139
6140 CUR.args -= 2;
6141
David Turnerf9b8dec2000-06-16 19:34:52 +00006142 A = (FT_UShort)CUR.stack[CUR.args + 1];
David Turnerd2b1f351999-12-16 23:11:37 +00006143 B = CUR.stack[CUR.args];
6144
Werner Lemberg78575dc2000-06-12 19:36:41 +00006145 /* XXX: Because some popular fonts contain some invalid DeltaP */
6146 /* instructions, we simply ignore them when the stacked */
6147 /* point reference is off limit, rather than returning an */
6148 /* error. As a delta instruction doesn't change a glyph */
6149 /* in great ways, this shouldn't be a problem. */
David Turnerd2b1f351999-12-16 23:11:37 +00006150
6151 if ( !BOUNDS( A, CUR.zp0.n_points ) )
6152 {
David Turnerf9b8dec2000-06-16 19:34:52 +00006153 C = ( (FT_ULong)B & 0xF0 ) >> 4;
David Turnerd2b1f351999-12-16 23:11:37 +00006154
6155 switch ( CUR.opcode )
6156 {
6157 case 0x5D:
6158 break;
6159
6160 case 0x71:
6161 C += 16;
6162 break;
6163
6164 case 0x72:
6165 C += 32;
6166 break;
6167 }
6168
6169 C += CUR.GS.delta_base;
6170
David Turnerf9b8dec2000-06-16 19:34:52 +00006171 if ( CURRENT_Ppem() == (FT_Long)C )
David Turnerd2b1f351999-12-16 23:11:37 +00006172 {
David Turnerf9b8dec2000-06-16 19:34:52 +00006173 B = ( (FT_ULong)B & 0xF ) - 8;
David Turnerd2b1f351999-12-16 23:11:37 +00006174 if ( B >= 0 )
6175 B++;
Werner Lemberg78575dc2000-06-12 19:36:41 +00006176 B = B * 64 / ( 1L << CUR.GS.delta_shift );
David Turnerd2b1f351999-12-16 23:11:37 +00006177
6178 CUR_Func_move( &CUR.zp0, A, B );
6179 }
6180 }
6181 else
6182 if ( CUR.pedantic_hinting )
6183 CUR.error = TT_Err_Invalid_Reference;
6184 }
6185
6186 CUR.new_top = CUR.args;
6187 }
6188
6189
6190 /*************************************************************************/
6191 /* */
6192 /* DELTACn[]: DELTA exceptions C1, C2, C3 */
6193 /* Opcode range: 0x73,0x74,0x75 */
6194 /* Stack: uint32 (2 * uint32)... --> */
6195 /* */
6196 static
6197 void Ins_DELTAC( INS_ARG )
6198 {
David Turnerf9b8dec2000-06-16 19:34:52 +00006199 FT_ULong nump, k;
6200 FT_ULong A, C;
6201 FT_Long B;
David Turnerd2b1f351999-12-16 23:11:37 +00006202
6203
David Turnerf9b8dec2000-06-16 19:34:52 +00006204 nump = (FT_ULong)args[0];
David Turnerd2b1f351999-12-16 23:11:37 +00006205
6206 for ( k = 1; k <= nump; k++ )
6207 {
6208 if ( CUR.args < 2 )
6209 {
6210 CUR.error = TT_Err_Too_Few_Arguments;
6211 return;
6212 }
6213
6214 CUR.args -= 2;
6215
David Turnerf9b8dec2000-06-16 19:34:52 +00006216 A = (FT_ULong)CUR.stack[CUR.args + 1];
David Turnerd2b1f351999-12-16 23:11:37 +00006217 B = CUR.stack[CUR.args];
6218
6219 if ( BOUNDS( A, CUR.cvtSize ) )
6220 {
Werner Lemberg78575dc2000-06-12 19:36:41 +00006221 if ( CUR.pedantic_hinting )
David Turnerd2b1f351999-12-16 23:11:37 +00006222 {
6223 CUR.error = TT_Err_Invalid_Reference;
6224 return;
6225 }
6226 }
6227 else
6228 {
David Turnerf9b8dec2000-06-16 19:34:52 +00006229 C = ( (FT_ULong)B & 0xF0 ) >> 4;
David Turnerd2b1f351999-12-16 23:11:37 +00006230
6231 switch ( CUR.opcode )
6232 {
6233 case 0x73:
6234 break;
6235
6236 case 0x74:
6237 C += 16;
6238 break;
6239
6240 case 0x75:
6241 C += 32;
6242 break;
6243 }
6244
6245 C += CUR.GS.delta_base;
6246
David Turnerf9b8dec2000-06-16 19:34:52 +00006247 if ( CURRENT_Ppem() == (FT_Long)C )
David Turnerd2b1f351999-12-16 23:11:37 +00006248 {
David Turnerf9b8dec2000-06-16 19:34:52 +00006249 B = ( (FT_ULong)B & 0xF ) - 8;
David Turnerd2b1f351999-12-16 23:11:37 +00006250 if ( B >= 0 )
6251 B++;
Werner Lemberg78575dc2000-06-12 19:36:41 +00006252 B = B * 64 / ( 1L << CUR.GS.delta_shift );
David Turnerd2b1f351999-12-16 23:11:37 +00006253
6254 CUR_Func_move_cvt( A, B );
6255 }
6256 }
6257 }
6258
6259 CUR.new_top = CUR.args;
6260 }
6261
6262
6263 /*************************************************************************/
6264 /* */
6265 /* MISC. INSTRUCTIONS */
6266 /* */
6267 /*************************************************************************/
6268
6269
6270 /*************************************************************************/
6271 /* */
6272 /* GETINFO[]: GET INFOrmation */
6273 /* Opcode range: 0x88 */
6274 /* Stack: uint32 --> uint32 */
6275 /* */
6276 /* XXX: According to Apple specs, bits 1 & 2 of the argument ought to be */
6277 /* consulted before rotated/stretched info is returned. */
6278 static
6279 void Ins_GETINFO( INS_ARG )
6280 {
David Turnerf9b8dec2000-06-16 19:34:52 +00006281 FT_Long K;
David Turnerd2b1f351999-12-16 23:11:37 +00006282
6283
6284 K = 0;
6285
6286 /* We return then Windows 3.1 version number */
6287 /* for the font scaler */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006288 if ( ( args[0] & 1 ) != 0 )
David Turnerd2b1f351999-12-16 23:11:37 +00006289 K = 3;
6290
6291 /* Has the glyph been rotated ? */
6292 if ( CUR.tt_metrics.rotated )
6293 K |= 0x80;
6294
6295 /* Has the glyph been stretched ? */
6296 if ( CUR.tt_metrics.stretched )
6297 K |= 0x100;
6298
6299 args[0] = K;
6300 }
6301
6302
6303 static
6304 void Ins_UNKNOWN( INS_ARG )
6305 {
6306 TT_DefRecord* def = CUR.IDefs;
6307 TT_DefRecord* limit = def + CUR.numIDefs;
David Turnere49ab252000-05-16 23:44:38 +00006308
David Turnerc6a92202000-07-04 18:12:13 +00006309 FT_UNUSED_ARG;
David Turnere49ab252000-05-16 23:44:38 +00006310
Werner Lemberg78575dc2000-06-12 19:36:41 +00006311
David Turnerd2b1f351999-12-16 23:11:37 +00006312 for ( ; def < limit; def++ )
6313 {
David Turnerb1aabf42000-11-30 23:48:22 +00006314 if ( (FT_Byte)def->opc == CUR.opcode && def->active )
David Turnerd2b1f351999-12-16 23:11:37 +00006315 {
6316 TT_CallRec* call;
David Turnere49ab252000-05-16 23:44:38 +00006317
Werner Lemberg78575dc2000-06-12 19:36:41 +00006318
David Turnerd2b1f351999-12-16 23:11:37 +00006319 if ( CUR.callTop >= CUR.callSize )
6320 {
6321 CUR.error = TT_Err_Stack_Overflow;
6322 return;
6323 }
David Turnere49ab252000-05-16 23:44:38 +00006324
David Turnerd2b1f351999-12-16 23:11:37 +00006325 call = CUR.callStack + CUR.callTop++;
6326
6327 call->Caller_Range = CUR.curRange;
6328 call->Caller_IP = CUR.IP+1;
6329 call->Cur_Count = 1;
6330 call->Cur_Restart = def->start;
David Turnere49ab252000-05-16 23:44:38 +00006331
David Turnerd2b1f351999-12-16 23:11:37 +00006332 INS_Goto_CodeRange( def->range, def->start );
David Turnere49ab252000-05-16 23:44:38 +00006333
David Turnerd2b1f351999-12-16 23:11:37 +00006334 CUR.step_ins = FALSE;
6335 return;
6336 }
6337 }
6338
6339 CUR.error = TT_Err_Invalid_Opcode;
6340 }
6341
6342
6343#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
Werner Lemberg78575dc2000-06-12 19:36:41 +00006344
6345
David Turnerd2b1f351999-12-16 23:11:37 +00006346 static
6347 TInstruction_Function Instruct_Dispatch[256] =
6348 {
6349 /* Opcodes are gathered in groups of 16. */
6350 /* Please keep the spaces as they are. */
6351
6352 /* SVTCA y */ Ins_SVTCA,
6353 /* SVTCA x */ Ins_SVTCA,
6354 /* SPvTCA y */ Ins_SPVTCA,
6355 /* SPvTCA x */ Ins_SPVTCA,
6356 /* SFvTCA y */ Ins_SFVTCA,
6357 /* SFvTCA x */ Ins_SFVTCA,
6358 /* SPvTL // */ Ins_SPVTL,
6359 /* SPvTL + */ Ins_SPVTL,
6360 /* SFvTL // */ Ins_SFVTL,
6361 /* SFvTL + */ Ins_SFVTL,
6362 /* SPvFS */ Ins_SPVFS,
6363 /* SFvFS */ Ins_SFVFS,
6364 /* GPV */ Ins_GPV,
6365 /* GFV */ Ins_GFV,
6366 /* SFvTPv */ Ins_SFVTPV,
6367 /* ISECT */ Ins_ISECT,
6368
6369 /* SRP0 */ Ins_SRP0,
6370 /* SRP1 */ Ins_SRP1,
6371 /* SRP2 */ Ins_SRP2,
6372 /* SZP0 */ Ins_SZP0,
6373 /* SZP1 */ Ins_SZP1,
6374 /* SZP2 */ Ins_SZP2,
6375 /* SZPS */ Ins_SZPS,
6376 /* SLOOP */ Ins_SLOOP,
6377 /* RTG */ Ins_RTG,
6378 /* RTHG */ Ins_RTHG,
6379 /* SMD */ Ins_SMD,
6380 /* ELSE */ Ins_ELSE,
6381 /* JMPR */ Ins_JMPR,
6382 /* SCvTCi */ Ins_SCVTCI,
6383 /* SSwCi */ Ins_SSWCI,
6384 /* SSW */ Ins_SSW,
6385
6386 /* DUP */ Ins_DUP,
6387 /* POP */ Ins_POP,
6388 /* CLEAR */ Ins_CLEAR,
6389 /* SWAP */ Ins_SWAP,
6390 /* DEPTH */ Ins_DEPTH,
6391 /* CINDEX */ Ins_CINDEX,
6392 /* MINDEX */ Ins_MINDEX,
6393 /* AlignPTS */ Ins_ALIGNPTS,
6394 /* INS_0x28 */ Ins_UNKNOWN,
6395 /* UTP */ Ins_UTP,
6396 /* LOOPCALL */ Ins_LOOPCALL,
6397 /* CALL */ Ins_CALL,
6398 /* FDEF */ Ins_FDEF,
6399 /* ENDF */ Ins_ENDF,
6400 /* MDAP[0] */ Ins_MDAP,
6401 /* MDAP[1] */ Ins_MDAP,
6402
6403 /* IUP[0] */ Ins_IUP,
6404 /* IUP[1] */ Ins_IUP,
6405 /* SHP[0] */ Ins_SHP,
6406 /* SHP[1] */ Ins_SHP,
6407 /* SHC[0] */ Ins_SHC,
6408 /* SHC[1] */ Ins_SHC,
6409 /* SHZ[0] */ Ins_SHZ,
6410 /* SHZ[1] */ Ins_SHZ,
6411 /* SHPIX */ Ins_SHPIX,
6412 /* IP */ Ins_IP,
6413 /* MSIRP[0] */ Ins_MSIRP,
6414 /* MSIRP[1] */ Ins_MSIRP,
6415 /* AlignRP */ Ins_ALIGNRP,
6416 /* RTDG */ Ins_RTDG,
6417 /* MIAP[0] */ Ins_MIAP,
6418 /* MIAP[1] */ Ins_MIAP,
6419
6420 /* NPushB */ Ins_NPUSHB,
6421 /* NPushW */ Ins_NPUSHW,
6422 /* WS */ Ins_WS,
6423 /* RS */ Ins_RS,
6424 /* WCvtP */ Ins_WCVTP,
6425 /* RCvt */ Ins_RCVT,
6426 /* GC[0] */ Ins_GC,
6427 /* GC[1] */ Ins_GC,
6428 /* SCFS */ Ins_SCFS,
6429 /* MD[0] */ Ins_MD,
6430 /* MD[1] */ Ins_MD,
6431 /* MPPEM */ Ins_MPPEM,
6432 /* MPS */ Ins_MPS,
6433 /* FlipON */ Ins_FLIPON,
6434 /* FlipOFF */ Ins_FLIPOFF,
6435 /* DEBUG */ Ins_DEBUG,
6436
6437 /* LT */ Ins_LT,
6438 /* LTEQ */ Ins_LTEQ,
6439 /* GT */ Ins_GT,
6440 /* GTEQ */ Ins_GTEQ,
6441 /* EQ */ Ins_EQ,
6442 /* NEQ */ Ins_NEQ,
6443 /* ODD */ Ins_ODD,
6444 /* EVEN */ Ins_EVEN,
6445 /* IF */ Ins_IF,
6446 /* EIF */ Ins_EIF,
6447 /* AND */ Ins_AND,
6448 /* OR */ Ins_OR,
6449 /* NOT */ Ins_NOT,
6450 /* DeltaP1 */ Ins_DELTAP,
6451 /* SDB */ Ins_SDB,
6452 /* SDS */ Ins_SDS,
6453
6454 /* ADD */ Ins_ADD,
6455 /* SUB */ Ins_SUB,
6456 /* DIV */ Ins_DIV,
6457 /* MUL */ Ins_MUL,
6458 /* ABS */ Ins_ABS,
6459 /* NEG */ Ins_NEG,
6460 /* FLOOR */ Ins_FLOOR,
6461 /* CEILING */ Ins_CEILING,
6462 /* ROUND[0] */ Ins_ROUND,
6463 /* ROUND[1] */ Ins_ROUND,
6464 /* ROUND[2] */ Ins_ROUND,
6465 /* ROUND[3] */ Ins_ROUND,
6466 /* NROUND[0] */ Ins_NROUND,
6467 /* NROUND[1] */ Ins_NROUND,
6468 /* NROUND[2] */ Ins_NROUND,
6469 /* NROUND[3] */ Ins_NROUND,
6470
6471 /* WCvtF */ Ins_WCVTF,
6472 /* DeltaP2 */ Ins_DELTAP,
6473 /* DeltaP3 */ Ins_DELTAP,
6474 /* DeltaCn[0] */ Ins_DELTAC,
6475 /* DeltaCn[1] */ Ins_DELTAC,
6476 /* DeltaCn[2] */ Ins_DELTAC,
6477 /* SROUND */ Ins_SROUND,
6478 /* S45Round */ Ins_S45ROUND,
6479 /* JROT */ Ins_JROT,
6480 /* JROF */ Ins_JROF,
6481 /* ROFF */ Ins_ROFF,
6482 /* INS_0x7B */ Ins_UNKNOWN,
6483 /* RUTG */ Ins_RUTG,
6484 /* RDTG */ Ins_RDTG,
6485 /* SANGW */ Ins_SANGW,
6486 /* AA */ Ins_AA,
6487
6488 /* FlipPT */ Ins_FLIPPT,
6489 /* FlipRgON */ Ins_FLIPRGON,
6490 /* FlipRgOFF */ Ins_FLIPRGOFF,
6491 /* INS_0x83 */ Ins_UNKNOWN,
6492 /* INS_0x84 */ Ins_UNKNOWN,
6493 /* ScanCTRL */ Ins_SCANCTRL,
6494 /* SDPVTL[0] */ Ins_SDPVTL,
6495 /* SDPVTL[1] */ Ins_SDPVTL,
6496 /* GetINFO */ Ins_GETINFO,
6497 /* IDEF */ Ins_IDEF,
6498 /* ROLL */ Ins_ROLL,
6499 /* MAX */ Ins_MAX,
6500 /* MIN */ Ins_MIN,
6501 /* ScanTYPE */ Ins_SCANTYPE,
6502 /* InstCTRL */ Ins_INSTCTRL,
6503 /* INS_0x8F */ Ins_UNKNOWN,
6504
6505 /* INS_0x90 */ Ins_UNKNOWN,
6506 /* INS_0x91 */ Ins_UNKNOWN,
6507 /* INS_0x92 */ Ins_UNKNOWN,
6508 /* INS_0x93 */ Ins_UNKNOWN,
6509 /* INS_0x94 */ Ins_UNKNOWN,
6510 /* INS_0x95 */ Ins_UNKNOWN,
6511 /* INS_0x96 */ Ins_UNKNOWN,
6512 /* INS_0x97 */ Ins_UNKNOWN,
6513 /* INS_0x98 */ Ins_UNKNOWN,
6514 /* INS_0x99 */ Ins_UNKNOWN,
6515 /* INS_0x9A */ Ins_UNKNOWN,
6516 /* INS_0x9B */ Ins_UNKNOWN,
6517 /* INS_0x9C */ Ins_UNKNOWN,
6518 /* INS_0x9D */ Ins_UNKNOWN,
6519 /* INS_0x9E */ Ins_UNKNOWN,
6520 /* INS_0x9F */ Ins_UNKNOWN,
6521
6522 /* INS_0xA0 */ Ins_UNKNOWN,
6523 /* INS_0xA1 */ Ins_UNKNOWN,
6524 /* INS_0xA2 */ Ins_UNKNOWN,
6525 /* INS_0xA3 */ Ins_UNKNOWN,
6526 /* INS_0xA4 */ Ins_UNKNOWN,
6527 /* INS_0xA5 */ Ins_UNKNOWN,
6528 /* INS_0xA6 */ Ins_UNKNOWN,
6529 /* INS_0xA7 */ Ins_UNKNOWN,
6530 /* INS_0xA8 */ Ins_UNKNOWN,
6531 /* INS_0xA9 */ Ins_UNKNOWN,
6532 /* INS_0xAA */ Ins_UNKNOWN,
6533 /* INS_0xAB */ Ins_UNKNOWN,
6534 /* INS_0xAC */ Ins_UNKNOWN,
6535 /* INS_0xAD */ Ins_UNKNOWN,
6536 /* INS_0xAE */ Ins_UNKNOWN,
6537 /* INS_0xAF */ Ins_UNKNOWN,
6538
6539 /* PushB[0] */ Ins_PUSHB,
6540 /* PushB[1] */ Ins_PUSHB,
6541 /* PushB[2] */ Ins_PUSHB,
6542 /* PushB[3] */ Ins_PUSHB,
6543 /* PushB[4] */ Ins_PUSHB,
6544 /* PushB[5] */ Ins_PUSHB,
6545 /* PushB[6] */ Ins_PUSHB,
6546 /* PushB[7] */ Ins_PUSHB,
6547 /* PushW[0] */ Ins_PUSHW,
6548 /* PushW[1] */ Ins_PUSHW,
6549 /* PushW[2] */ Ins_PUSHW,
6550 /* PushW[3] */ Ins_PUSHW,
6551 /* PushW[4] */ Ins_PUSHW,
6552 /* PushW[5] */ Ins_PUSHW,
6553 /* PushW[6] */ Ins_PUSHW,
6554 /* PushW[7] */ Ins_PUSHW,
6555
6556 /* MDRP[00] */ Ins_MDRP,
6557 /* MDRP[01] */ Ins_MDRP,
6558 /* MDRP[02] */ Ins_MDRP,
6559 /* MDRP[03] */ Ins_MDRP,
6560 /* MDRP[04] */ Ins_MDRP,
6561 /* MDRP[05] */ Ins_MDRP,
6562 /* MDRP[06] */ Ins_MDRP,
6563 /* MDRP[07] */ Ins_MDRP,
6564 /* MDRP[08] */ Ins_MDRP,
6565 /* MDRP[09] */ Ins_MDRP,
6566 /* MDRP[10] */ Ins_MDRP,
6567 /* MDRP[11] */ Ins_MDRP,
6568 /* MDRP[12] */ Ins_MDRP,
6569 /* MDRP[13] */ Ins_MDRP,
6570 /* MDRP[14] */ Ins_MDRP,
6571 /* MDRP[15] */ Ins_MDRP,
6572
6573 /* MDRP[16] */ Ins_MDRP,
6574 /* MDRP[17] */ Ins_MDRP,
6575 /* MDRP[18] */ Ins_MDRP,
6576 /* MDRP[19] */ Ins_MDRP,
6577 /* MDRP[20] */ Ins_MDRP,
6578 /* MDRP[21] */ Ins_MDRP,
6579 /* MDRP[22] */ Ins_MDRP,
6580 /* MDRP[23] */ Ins_MDRP,
6581 /* MDRP[24] */ Ins_MDRP,
6582 /* MDRP[25] */ Ins_MDRP,
6583 /* MDRP[26] */ Ins_MDRP,
6584 /* MDRP[27] */ Ins_MDRP,
6585 /* MDRP[28] */ Ins_MDRP,
6586 /* MDRP[29] */ Ins_MDRP,
6587 /* MDRP[30] */ Ins_MDRP,
6588 /* MDRP[31] */ Ins_MDRP,
6589
6590 /* MIRP[00] */ Ins_MIRP,
6591 /* MIRP[01] */ Ins_MIRP,
6592 /* MIRP[02] */ Ins_MIRP,
6593 /* MIRP[03] */ Ins_MIRP,
6594 /* MIRP[04] */ Ins_MIRP,
6595 /* MIRP[05] */ Ins_MIRP,
6596 /* MIRP[06] */ Ins_MIRP,
6597 /* MIRP[07] */ Ins_MIRP,
6598 /* MIRP[08] */ Ins_MIRP,
6599 /* MIRP[09] */ Ins_MIRP,
6600 /* MIRP[10] */ Ins_MIRP,
6601 /* MIRP[11] */ Ins_MIRP,
6602 /* MIRP[12] */ Ins_MIRP,
6603 /* MIRP[13] */ Ins_MIRP,
6604 /* MIRP[14] */ Ins_MIRP,
6605 /* MIRP[15] */ Ins_MIRP,
6606
6607 /* MIRP[16] */ Ins_MIRP,
6608 /* MIRP[17] */ Ins_MIRP,
6609 /* MIRP[18] */ Ins_MIRP,
6610 /* MIRP[19] */ Ins_MIRP,
6611 /* MIRP[20] */ Ins_MIRP,
6612 /* MIRP[21] */ Ins_MIRP,
6613 /* MIRP[22] */ Ins_MIRP,
6614 /* MIRP[23] */ Ins_MIRP,
6615 /* MIRP[24] */ Ins_MIRP,
6616 /* MIRP[25] */ Ins_MIRP,
6617 /* MIRP[26] */ Ins_MIRP,
6618 /* MIRP[27] */ Ins_MIRP,
6619 /* MIRP[28] */ Ins_MIRP,
6620 /* MIRP[29] */ Ins_MIRP,
6621 /* MIRP[30] */ Ins_MIRP,
6622 /* MIRP[31] */ Ins_MIRP
6623 };
Werner Lemberg78575dc2000-06-12 19:36:41 +00006624
6625
David Turnerd2b1f351999-12-16 23:11:37 +00006626#endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
6627
6628
6629 /*************************************************************************/
6630 /* */
6631 /* RUN */
6632 /* */
6633 /* This function executes a run of opcodes. It will exit in the */
6634 /* following cases: */
6635 /* */
6636 /* - Errors (in which case it returns FALSE). */
6637 /* */
6638 /* - Reaching the end of the main code range (returns TRUE). */
6639 /* Reaching the end of a code range within a function call is an */
6640 /* error. */
6641 /* */
6642 /* - After executing one single opcode, if the flag `Instruction_Trap' */
6643 /* is set to TRUE (returns TRUE). */
6644 /* */
6645 /* On exit whith TRUE, test IP < CodeSize to know wether it comes from */
6646 /* an instruction trap or a normal termination. */
6647 /* */
6648 /* */
6649 /* Note: The documented DEBUG opcode pops a value from the stack. This */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006650 /* behaviour is unsupported; here a DEBUG opcode is always an */
David Turnerd2b1f351999-12-16 23:11:37 +00006651 /* error. */
6652 /* */
6653 /* */
6654 /* THIS IS THE INTERPRETER'S MAIN LOOP. */
6655 /* */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006656 /* Instructions appear in the specification's order. */
David Turnerd2b1f351999-12-16 23:11:37 +00006657 /* */
6658 /*************************************************************************/
6659
6660
Werner Lemberg90a03302000-11-07 17:21:11 +00006661 /* documentation is in ttinterp.h */
6662
David Turner76a5f622000-11-04 01:55:49 +00006663 FT_EXPORT_DEF( FT_Error ) TT_RunIns( TT_ExecContext exc )
David Turnerd2b1f351999-12-16 23:11:37 +00006664 {
David Turnerf9b8dec2000-06-16 19:34:52 +00006665 FT_Long ins_counter = 0; /* executed instructions counter */
David Turnerd2b1f351999-12-16 23:11:37 +00006666
Werner Lemberg78575dc2000-06-12 19:36:41 +00006667
6668#ifdef TT_CONFIG_OPTION_STATIC_RASTER
David Turnerd2b1f351999-12-16 23:11:37 +00006669 cur = *exc;
Werner Lemberg78575dc2000-06-12 19:36:41 +00006670#endif
David Turnerd2b1f351999-12-16 23:11:37 +00006671
6672 /* set CVT functions */
6673 CUR.tt_metrics.ratio = 0;
6674 if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
6675 {
6676 /* non-square pixels, use the stretched routines */
6677 CUR.func_read_cvt = Read_CVT_Stretched;
6678 CUR.func_write_cvt = Write_CVT_Stretched;
6679 CUR.func_move_cvt = Move_CVT_Stretched;
6680 }
6681 else
6682 {
6683 /* square pixels, use normal routines */
6684 CUR.func_read_cvt = Read_CVT;
6685 CUR.func_write_cvt = Write_CVT;
6686 CUR.func_move_cvt = Move_CVT;
6687 }
6688
6689 COMPUTE_Funcs();
David Turnerf9b8dec2000-06-16 19:34:52 +00006690 COMPUTE_Round( (FT_Byte)exc->GS.round_state );
David Turnerd2b1f351999-12-16 23:11:37 +00006691
6692 do
6693 {
6694 CUR.opcode = CUR.code[CUR.IP];
6695
6696 if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )
6697 {
6698 if ( CUR.IP + 1 > CUR.codeSize )
6699 goto LErrorCodeOverflow_;
6700
6701 CUR.length = CUR.code[CUR.IP + 1] + 2;
6702 }
6703
6704 if ( CUR.IP + CUR.length > CUR.codeSize )
6705 goto LErrorCodeOverflow_;
6706
6707 /* First, let's check for empty stack and overflow */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006708 CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 );
David Turnerd2b1f351999-12-16 23:11:37 +00006709
6710 /* `args' is the top of the stack once arguments have been popped. */
6711 /* One can also interpret it as the index of the last argument. */
6712 if ( CUR.args < 0 )
6713 {
6714 CUR.error = TT_Err_Too_Few_Arguments;
6715 goto LErrorLabel_;
6716 }
6717
Werner Lemberg78575dc2000-06-12 19:36:41 +00006718 CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 );
David Turnerd2b1f351999-12-16 23:11:37 +00006719
6720 /* `new_top' is the new top of the stack, after the instruction's */
6721 /* execution. `top' will be set to `new_top' after the `switch' */
6722 /* statement. */
6723 if ( CUR.new_top > CUR.stackSize )
6724 {
6725 CUR.error = TT_Err_Stack_Overflow;
6726 goto LErrorLabel_;
6727 }
6728
6729 CUR.step_ins = TRUE;
6730 CUR.error = TT_Err_Ok;
6731
6732#ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
Werner Lemberg78575dc2000-06-12 19:36:41 +00006733
David Turnerd2b1f351999-12-16 23:11:37 +00006734 {
David Turnerf9b8dec2000-06-16 19:34:52 +00006735 FT_Long* args = CUR.stack + CUR.args;
6736 FT_Byte opcode = CUR.opcode;
David Turnerd2b1f351999-12-16 23:11:37 +00006737
6738
Werner Lemberg63408a12000-12-13 23:44:37 +00006739#undef ARRAY_BOUND_ERROR
6740#define ARRAY_BOUND_ERROR goto Set_Invalid_Ref
David Turnerd2b1f351999-12-16 23:11:37 +00006741
6742
6743 switch ( opcode )
6744 {
6745 case 0x00: /* SVTCA y */
6746 case 0x01: /* SVTCA x */
6747 case 0x02: /* SPvTCA y */
6748 case 0x03: /* SPvTCA x */
6749 case 0x04: /* SFvTCA y */
6750 case 0x05: /* SFvTCA x */
6751 {
David Turnerf9b8dec2000-06-16 19:34:52 +00006752 FT_Short AA, BB;
David Turnerd2b1f351999-12-16 23:11:37 +00006753
6754
David Turnerf9b8dec2000-06-16 19:34:52 +00006755 AA = (FT_Short)( opcode & 1 ) << 14;
6756 BB = AA ^ (FT_Short)0x4000;
David Turnerd2b1f351999-12-16 23:11:37 +00006757
6758 if ( opcode < 4 )
6759 {
6760 CUR.GS.projVector.x = AA;
6761 CUR.GS.projVector.y = BB;
6762
6763 CUR.GS.dualVector.x = AA;
6764 CUR.GS.dualVector.y = BB;
6765 }
6766
Werner Lemberg78575dc2000-06-12 19:36:41 +00006767 if ( ( opcode & 2 ) == 0 )
David Turnerd2b1f351999-12-16 23:11:37 +00006768 {
6769 CUR.GS.freeVector.x = AA;
6770 CUR.GS.freeVector.y = BB;
6771 }
6772
6773 COMPUTE_Funcs();
6774 }
6775 break;
6776
6777 case 0x06: /* SPvTL // */
6778 case 0x07: /* SPvTL + */
6779 DO_SPVTL
6780 break;
6781
6782 case 0x08: /* SFvTL // */
6783 case 0x09: /* SFvTL + */
6784 DO_SFVTL
6785 break;
6786
6787 case 0x0A: /* SPvFS */
6788 DO_SPVFS
6789 break;
6790
6791 case 0x0B: /* SFvFS */
6792 DO_SFVFS
6793 break;
6794
6795 case 0x0C: /* GPV */
6796 DO_GPV
6797 break;
6798
6799 case 0x0D: /* GFV */
6800 DO_GFV
6801 break;
6802
6803 case 0x0E: /* SFvTPv */
6804 DO_SFVTPV
6805 break;
6806
6807 case 0x0F: /* ISECT */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006808 Ins_ISECT( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006809 break;
6810
6811 case 0x10: /* SRP0 */
6812 DO_SRP0
6813 break;
6814
6815 case 0x11: /* SRP1 */
6816 DO_SRP1
6817 break;
6818
6819 case 0x12: /* SRP2 */
6820 DO_SRP2
6821 break;
6822
6823 case 0x13: /* SZP0 */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006824 Ins_SZP0( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006825 break;
6826
6827 case 0x14: /* SZP1 */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006828 Ins_SZP1( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006829 break;
6830
6831 case 0x15: /* SZP2 */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006832 Ins_SZP2( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006833 break;
6834
6835 case 0x16: /* SZPS */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006836 Ins_SZPS( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006837 break;
6838
6839 case 0x17: /* SLOOP */
6840 DO_SLOOP
6841 break;
6842
6843 case 0x18: /* RTG */
6844 DO_RTG
6845 break;
6846
6847 case 0x19: /* RTHG */
6848 DO_RTHG
6849 break;
6850
6851 case 0x1A: /* SMD */
6852 DO_SMD
6853 break;
6854
6855 case 0x1B: /* ELSE */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006856 Ins_ELSE( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006857 break;
6858
6859 case 0x1C: /* JMPR */
6860 DO_JMPR
6861 break;
6862
6863 case 0x1D: /* SCVTCI */
6864 DO_SCVTCI
6865 break;
6866
6867 case 0x1E: /* SSWCI */
6868 DO_SSWCI
6869 break;
6870
6871 case 0x1F: /* SSW */
6872 DO_SSW
6873 break;
6874
6875 case 0x20: /* DUP */
6876 DO_DUP
6877 break;
6878
6879 case 0x21: /* POP */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006880 /* nothing :-) */
David Turnerd2b1f351999-12-16 23:11:37 +00006881 break;
6882
6883 case 0x22: /* CLEAR */
6884 DO_CLEAR
6885 break;
6886
6887 case 0x23: /* SWAP */
6888 DO_SWAP
6889 break;
6890
6891 case 0x24: /* DEPTH */
6892 DO_DEPTH
6893 break;
6894
6895 case 0x25: /* CINDEX */
6896 DO_CINDEX
6897 break;
6898
6899 case 0x26: /* MINDEX */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006900 Ins_MINDEX( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006901 break;
6902
6903 case 0x27: /* ALIGNPTS */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006904 Ins_ALIGNPTS( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006905 break;
6906
6907 case 0x28: /* ???? */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006908 Ins_UNKNOWN( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006909 break;
6910
6911 case 0x29: /* UTP */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006912 Ins_UTP( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006913 break;
6914
6915 case 0x2A: /* LOOPCALL */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006916 Ins_LOOPCALL( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006917 break;
6918
6919 case 0x2B: /* CALL */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006920 Ins_CALL( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006921 break;
6922
6923 case 0x2C: /* FDEF */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006924 Ins_FDEF( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006925 break;
6926
6927 case 0x2D: /* ENDF */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006928 Ins_ENDF( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006929 break;
6930
6931 case 0x2E: /* MDAP */
6932 case 0x2F: /* MDAP */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006933 Ins_MDAP( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006934 break;
6935
6936
6937 case 0x30: /* IUP */
6938 case 0x31: /* IUP */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006939 Ins_IUP( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006940 break;
6941
6942 case 0x32: /* SHP */
6943 case 0x33: /* SHP */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006944 Ins_SHP( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006945 break;
6946
6947 case 0x34: /* SHC */
6948 case 0x35: /* SHC */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006949 Ins_SHC( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006950 break;
6951
6952 case 0x36: /* SHZ */
6953 case 0x37: /* SHZ */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006954 Ins_SHZ( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006955 break;
6956
6957 case 0x38: /* SHPIX */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006958 Ins_SHPIX( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006959 break;
6960
6961 case 0x39: /* IP */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006962 Ins_IP( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006963 break;
6964
6965 case 0x3A: /* MSIRP */
6966 case 0x3B: /* MSIRP */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006967 Ins_MSIRP( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006968 break;
6969
6970 case 0x3C: /* AlignRP */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006971 Ins_ALIGNRP( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006972 break;
6973
6974 case 0x3D: /* RTDG */
6975 DO_RTDG
6976 break;
6977
6978 case 0x3E: /* MIAP */
6979 case 0x3F: /* MIAP */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006980 Ins_MIAP( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006981 break;
6982
6983 case 0x40: /* NPUSHB */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006984 Ins_NPUSHB( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006985 break;
6986
6987 case 0x41: /* NPUSHW */
Werner Lemberg78575dc2000-06-12 19:36:41 +00006988 Ins_NPUSHW( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00006989 break;
6990
6991 case 0x42: /* WS */
6992 DO_WS
6993 break;
6994
Werner Lemberg78575dc2000-06-12 19:36:41 +00006995 Set_Invalid_Ref:
David Turnerd2b1f351999-12-16 23:11:37 +00006996 CUR.error = TT_Err_Invalid_Reference;
6997 break;
6998
6999 case 0x43: /* RS */
7000 DO_RS
7001 break;
7002
7003 case 0x44: /* WCVTP */
7004 DO_WCVTP
7005 break;
7006
7007 case 0x45: /* RCVT */
7008 DO_RCVT
7009 break;
7010
7011 case 0x46: /* GC */
7012 case 0x47: /* GC */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007013 Ins_GC( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007014 break;
7015
7016 case 0x48: /* SCFS */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007017 Ins_SCFS( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007018 break;
7019
7020 case 0x49: /* MD */
7021 case 0x4A: /* MD */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007022 Ins_MD( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007023 break;
7024
7025 case 0x4B: /* MPPEM */
7026 DO_MPPEM
7027 break;
7028
7029 case 0x4C: /* MPS */
7030 DO_MPS
7031 break;
7032
7033 case 0x4D: /* FLIPON */
7034 DO_FLIPON
7035 break;
7036
7037 case 0x4E: /* FLIPOFF */
7038 DO_FLIPOFF
7039 break;
7040
7041 case 0x4F: /* DEBUG */
7042 DO_DEBUG
7043 break;
7044
7045 case 0x50: /* LT */
7046 DO_LT
7047 break;
7048
7049 case 0x51: /* LTEQ */
7050 DO_LTEQ
7051 break;
7052
7053 case 0x52: /* GT */
7054 DO_GT
7055 break;
7056
7057 case 0x53: /* GTEQ */
7058 DO_GTEQ
7059 break;
7060
7061 case 0x54: /* EQ */
7062 DO_EQ
7063 break;
7064
7065 case 0x55: /* NEQ */
7066 DO_NEQ
7067 break;
7068
7069 case 0x56: /* ODD */
7070 DO_ODD
7071 break;
7072
7073 case 0x57: /* EVEN */
7074 DO_EVEN
7075 break;
7076
7077 case 0x58: /* IF */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007078 Ins_IF( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007079 break;
7080
7081 case 0x59: /* EIF */
7082 /* do nothing */
7083 break;
7084
7085 case 0x5A: /* AND */
7086 DO_AND
7087 break;
7088
7089 case 0x5B: /* OR */
7090 DO_OR
7091 break;
7092
7093 case 0x5C: /* NOT */
7094 DO_NOT
7095 break;
7096
7097 case 0x5D: /* DELTAP1 */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007098 Ins_DELTAP( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007099 break;
7100
7101 case 0x5E: /* SDB */
7102 DO_SDB
7103 break;
7104
7105 case 0x5F: /* SDS */
7106 DO_SDS
7107 break;
7108
7109 case 0x60: /* ADD */
7110 DO_ADD
7111 break;
7112
7113 case 0x61: /* SUB */
7114 DO_SUB
7115 break;
7116
7117 case 0x62: /* DIV */
7118 DO_DIV
7119 break;
7120
7121 case 0x63: /* MUL */
7122 DO_MUL
7123 break;
7124
7125 case 0x64: /* ABS */
7126 DO_ABS
7127 break;
7128
7129 case 0x65: /* NEG */
7130 DO_NEG
7131 break;
7132
7133 case 0x66: /* FLOOR */
7134 DO_FLOOR
7135 break;
7136
7137 case 0x67: /* CEILING */
7138 DO_CEILING
7139 break;
7140
7141 case 0x68: /* ROUND */
7142 case 0x69: /* ROUND */
7143 case 0x6A: /* ROUND */
7144 case 0x6B: /* ROUND */
7145 DO_ROUND
7146 break;
7147
7148 case 0x6C: /* NROUND */
7149 case 0x6D: /* NROUND */
7150 case 0x6E: /* NRRUND */
7151 case 0x6F: /* NROUND */
7152 DO_NROUND
7153 break;
7154
7155 case 0x70: /* WCVTF */
7156 DO_WCVTF
7157 break;
7158
7159 case 0x71: /* DELTAP2 */
7160 case 0x72: /* DELTAP3 */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007161 Ins_DELTAP( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007162 break;
7163
7164 case 0x73: /* DELTAC0 */
7165 case 0x74: /* DELTAC1 */
7166 case 0x75: /* DELTAC2 */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007167 Ins_DELTAC( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007168 break;
7169
7170 case 0x76: /* SROUND */
7171 DO_SROUND
7172 break;
7173
7174 case 0x77: /* S45Round */
7175 DO_S45ROUND
7176 break;
7177
7178 case 0x78: /* JROT */
7179 DO_JROT
7180 break;
7181
7182 case 0x79: /* JROF */
7183 DO_JROF
7184 break;
7185
7186 case 0x7A: /* ROFF */
7187 DO_ROFF
7188 break;
7189
7190 case 0x7B: /* ???? */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007191 Ins_UNKNOWN( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007192 break;
7193
7194 case 0x7C: /* RUTG */
7195 DO_RUTG
7196 break;
7197
7198 case 0x7D: /* RDTG */
7199 DO_RDTG
7200 break;
7201
7202 case 0x7E: /* SANGW */
7203 case 0x7F: /* AA */
7204 /* nothing - obsolete */
7205 break;
7206
7207 case 0x80: /* FLIPPT */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007208 Ins_FLIPPT( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007209 break;
7210
7211 case 0x81: /* FLIPRGON */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007212 Ins_FLIPRGON( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007213 break;
7214
7215 case 0x82: /* FLIPRGOFF */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007216 Ins_FLIPRGOFF( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007217 break;
7218
7219 case 0x83: /* UNKNOWN */
7220 case 0x84: /* UNKNOWN */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007221 Ins_UNKNOWN( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007222 break;
7223
7224 case 0x85: /* SCANCTRL */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007225 Ins_SCANCTRL( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007226 break;
7227
7228 case 0x86: /* SDPVTL */
7229 case 0x87: /* SDPVTL */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007230 Ins_SDPVTL( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007231 break;
7232
7233 case 0x88: /* GETINFO */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007234 Ins_GETINFO( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007235 break;
7236
7237 case 0x89: /* IDEF */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007238 Ins_IDEF( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007239 break;
7240
7241 case 0x8A: /* ROLL */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007242 Ins_ROLL( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007243 break;
7244
7245 case 0x8B: /* MAX */
7246 DO_MAX
7247 break;
7248
7249 case 0x8C: /* MIN */
7250 DO_MIN
7251 break;
7252
7253 case 0x8D: /* SCANTYPE */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007254 Ins_SCANTYPE( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007255 break;
7256
7257 case 0x8E: /* INSTCTRL */
Werner Lemberg78575dc2000-06-12 19:36:41 +00007258 Ins_INSTCTRL( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007259 break;
7260
7261 case 0x8F:
Werner Lemberg78575dc2000-06-12 19:36:41 +00007262 Ins_UNKNOWN( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007263 break;
7264
7265 default:
7266 if ( opcode >= 0xE0 )
Werner Lemberg78575dc2000-06-12 19:36:41 +00007267 Ins_MIRP( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007268 else if ( opcode >= 0xC0 )
Werner Lemberg78575dc2000-06-12 19:36:41 +00007269 Ins_MDRP( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007270 else if ( opcode >= 0xB8 )
Werner Lemberg78575dc2000-06-12 19:36:41 +00007271 Ins_PUSHW( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007272 else if ( opcode >= 0xB0 )
Werner Lemberg78575dc2000-06-12 19:36:41 +00007273 Ins_PUSHB( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007274 else
Werner Lemberg78575dc2000-06-12 19:36:41 +00007275 Ins_UNKNOWN( EXEC_ARG_ args );
David Turnerd2b1f351999-12-16 23:11:37 +00007276 }
7277
7278 }
Werner Lemberg78575dc2000-06-12 19:36:41 +00007279
David Turnerd2b1f351999-12-16 23:11:37 +00007280#else
Werner Lemberg78575dc2000-06-12 19:36:41 +00007281
David Turnerd2b1f351999-12-16 23:11:37 +00007282 Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );
Werner Lemberg78575dc2000-06-12 19:36:41 +00007283
7284#endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
7285
Werner Lemberg79860702001-06-08 21:17:29 +00007286 if ( CUR.error != TT_Err_Ok )
David Turnerd2b1f351999-12-16 23:11:37 +00007287 {
7288 switch ( CUR.error )
7289 {
7290 case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
7291 {
7292 TT_DefRecord* def = CUR.IDefs;
7293 TT_DefRecord* limit = def + CUR.numIDefs;
David Turnere49ab252000-05-16 23:44:38 +00007294
Werner Lemberg78575dc2000-06-12 19:36:41 +00007295
David Turnerd2b1f351999-12-16 23:11:37 +00007296 for ( ; def < limit; def++ )
7297 {
David Turnerb1aabf42000-11-30 23:48:22 +00007298 if ( def->active && CUR.opcode == (FT_Byte)def->opc )
David Turnerd2b1f351999-12-16 23:11:37 +00007299 {
7300 TT_CallRec* callrec;
David Turnere49ab252000-05-16 23:44:38 +00007301
Werner Lemberg78575dc2000-06-12 19:36:41 +00007302
David Turnerd2b1f351999-12-16 23:11:37 +00007303 if ( CUR.callTop >= CUR.callSize )
7304 {
7305 CUR.error = TT_Err_Invalid_Reference;
7306 goto LErrorLabel_;
7307 }
David Turnere49ab252000-05-16 23:44:38 +00007308
David Turnerd2b1f351999-12-16 23:11:37 +00007309 callrec = &CUR.callStack[CUR.callTop];
David Turnere49ab252000-05-16 23:44:38 +00007310
David Turnerd2b1f351999-12-16 23:11:37 +00007311 callrec->Caller_Range = CUR.curRange;
7312 callrec->Caller_IP = CUR.IP + 1;
7313 callrec->Cur_Count = 1;
7314 callrec->Cur_Restart = def->start;
David Turnere49ab252000-05-16 23:44:38 +00007315
David Turnerd2b1f351999-12-16 23:11:37 +00007316 if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
7317 goto LErrorLabel_;
David Turnere49ab252000-05-16 23:44:38 +00007318
David Turnerd2b1f351999-12-16 23:11:37 +00007319 goto LSuiteLabel_;
7320 }
7321 }
7322 }
7323
7324 CUR.error = TT_Err_Invalid_Opcode;
7325 goto LErrorLabel_;
Werner Lemberg78575dc2000-06-12 19:36:41 +00007326
7327#if 0
7328 break; /* Unreachable code warning suppression. */
7329 /* Leave to remind in case a later change the editor */
7330 /* to consider break; */
7331#endif
David Turnerd2b1f351999-12-16 23:11:37 +00007332
7333 default:
7334 goto LErrorLabel_;
Werner Lemberg78575dc2000-06-12 19:36:41 +00007335
7336#if 0
7337 break;
7338#endif
David Turnerd2b1f351999-12-16 23:11:37 +00007339 }
7340 }
7341
7342 CUR.top = CUR.new_top;
7343
7344 if ( CUR.step_ins )
7345 CUR.IP += CUR.length;
7346
Werner Lemberg78575dc2000-06-12 19:36:41 +00007347 /* increment instruction counter and check if we didn't */
7348 /* run this program for too long (e.g. infinite loops). */
David Turnerd2b1f351999-12-16 23:11:37 +00007349 if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
7350 return TT_Err_Execution_Too_Long;
7351
Werner Lemberg78575dc2000-06-12 19:36:41 +00007352 LSuiteLabel_:
David Turnerd2b1f351999-12-16 23:11:37 +00007353 if ( CUR.IP >= CUR.codeSize )
7354 {
7355 if ( CUR.callTop > 0 )
7356 {
7357 CUR.error = TT_Err_Code_Overflow;
7358 goto LErrorLabel_;
7359 }
7360 else
7361 goto LNo_Error_;
7362 }
7363 } while ( !CUR.instruction_trap );
7364
7365 LNo_Error_:
Werner Lemberg78575dc2000-06-12 19:36:41 +00007366
7367#ifdef TT_CONFIG_OPTION_STATIC_RASTER
David Turnerd2b1f351999-12-16 23:11:37 +00007368 *exc = cur;
Werner Lemberg78575dc2000-06-12 19:36:41 +00007369#endif
7370
David Turnerd2b1f351999-12-16 23:11:37 +00007371 return TT_Err_Ok;
7372
7373 LErrorCodeOverflow_:
7374 CUR.error = TT_Err_Code_Overflow;
7375
7376 LErrorLabel_:
Werner Lemberg78575dc2000-06-12 19:36:41 +00007377
7378#ifdef TT_CONFIG_OPTION_STATIC_RASTER
David Turnerd2b1f351999-12-16 23:11:37 +00007379 *exc = cur;
Werner Lemberg78575dc2000-06-12 19:36:41 +00007380#endif
7381
David Turnerd2b1f351999-12-16 23:11:37 +00007382 return CUR.error;
7383 }
7384
7385
David Turner1ab77fd2000-02-10 18:08:17 +00007386#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
David Turnerd2b1f351999-12-16 23:11:37 +00007387
Werner Lemberg78575dc2000-06-12 19:36:41 +00007388
David Turnerd2b1f351999-12-16 23:11:37 +00007389/* END */