[FREETYPE] Update to v2.6.3. CORE-10964
[reactos.git] / reactos / lib / 3rdparty / freetype / src / cff / cf2intrp.c
1 /***************************************************************************/
2 /* */
3 /* cf2intrp.c */
4 /* */
5 /* Adobe's CFF Interpreter (body). */
6 /* */
7 /* Copyright 2007-2014 Adobe Systems Incorporated. */
8 /* */
9 /* This software, and all works of authorship, whether in source or */
10 /* object code form as indicated by the copyright notice(s) included */
11 /* herein (collectively, the "Work") is made available, and may only be */
12 /* used, modified, and distributed under the FreeType Project License, */
13 /* LICENSE.TXT. Additionally, subject to the terms and conditions of the */
14 /* FreeType Project License, each contributor to the Work hereby grants */
15 /* to any individual or legal entity exercising permissions granted by */
16 /* the FreeType Project License and this section (hereafter, "You" or */
17 /* "Your") a perpetual, worldwide, non-exclusive, no-charge, */
18 /* royalty-free, irrevocable (except as stated in this section) patent */
19 /* license to make, have made, use, offer to sell, sell, import, and */
20 /* otherwise transfer the Work, where such license applies only to those */
21 /* patent claims licensable by such contributor that are necessarily */
22 /* infringed by their contribution(s) alone or by combination of their */
23 /* contribution(s) with the Work to which such contribution(s) was */
24 /* submitted. If You institute patent litigation against any entity */
25 /* (including a cross-claim or counterclaim in a lawsuit) alleging that */
26 /* the Work or a contribution incorporated within the Work constitutes */
27 /* direct or contributory patent infringement, then any patent licenses */
28 /* granted to You under this License for that Work shall terminate as of */
29 /* the date such litigation is filed. */
30 /* */
31 /* By using, modifying, or distributing the Work you indicate that you */
32 /* have read and understood the terms and conditions of the */
33 /* FreeType Project License as well as those provided in this section, */
34 /* and you accept them fully. */
35 /* */
36 /***************************************************************************/
37
38
39 #include "cf2ft.h"
40 #include FT_INTERNAL_DEBUG_H
41
42 #include "cf2glue.h"
43 #include "cf2font.h"
44 #include "cf2stack.h"
45 #include "cf2hints.h"
46 #include "cf2intrp.h"
47
48 #include "cf2error.h"
49
50
51 /*************************************************************************/
52 /* */
53 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
54 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
55 /* messages during execution. */
56 /* */
57 #undef FT_COMPONENT
58 #define FT_COMPONENT trace_cf2interp
59
60
61 /* some operators are not implemented yet */
62 #define CF2_FIXME FT_TRACE4(( "cf2_interpT2CharString:" \
63 " operator not implemented yet\n" ))
64
65
66
67 FT_LOCAL_DEF( void )
68 cf2_hintmask_init( CF2_HintMask hintmask,
69 FT_Error* error )
70 {
71 FT_ZERO( hintmask );
72
73 hintmask->error = error;
74 }
75
76
77 FT_LOCAL_DEF( FT_Bool )
78 cf2_hintmask_isValid( const CF2_HintMask hintmask )
79 {
80 return hintmask->isValid;
81 }
82
83
84 FT_LOCAL_DEF( FT_Bool )
85 cf2_hintmask_isNew( const CF2_HintMask hintmask )
86 {
87 return hintmask->isNew;
88 }
89
90
91 FT_LOCAL_DEF( void )
92 cf2_hintmask_setNew( CF2_HintMask hintmask,
93 FT_Bool val )
94 {
95 hintmask->isNew = val;
96 }
97
98
99 /* clients call `getMaskPtr' in order to iterate */
100 /* through hint mask */
101
102 FT_LOCAL_DEF( FT_Byte* )
103 cf2_hintmask_getMaskPtr( CF2_HintMask hintmask )
104 {
105 return hintmask->mask;
106 }
107
108
109 static size_t
110 cf2_hintmask_setCounts( CF2_HintMask hintmask,
111 size_t bitCount )
112 {
113 if ( bitCount > CF2_MAX_HINTS )
114 {
115 /* total of h and v stems must be <= 96 */
116 CF2_SET_ERROR( hintmask->error, Invalid_Glyph_Format );
117 return 0;
118 }
119
120 hintmask->bitCount = bitCount;
121 hintmask->byteCount = ( hintmask->bitCount + 7 ) / 8;
122
123 hintmask->isValid = TRUE;
124 hintmask->isNew = TRUE;
125
126 return bitCount;
127 }
128
129
130 /* consume the hintmask bytes from the charstring, advancing the src */
131 /* pointer */
132 static void
133 cf2_hintmask_read( CF2_HintMask hintmask,
134 CF2_Buffer charstring,
135 size_t bitCount )
136 {
137 size_t i;
138
139 #ifndef CF2_NDEBUG
140 /* these are the bits in the final mask byte that should be zero */
141 /* Note: this variable is only used in an assert expression below */
142 /* and then only if CF2_NDEBUG is not defined */
143 CF2_UInt mask = ( 1 << ( -(CF2_Int)bitCount & 7 ) ) - 1;
144 #endif
145
146
147 /* initialize counts and isValid */
148 if ( cf2_hintmask_setCounts( hintmask, bitCount ) == 0 )
149 return;
150
151 FT_ASSERT( hintmask->byteCount > 0 );
152
153 FT_TRACE4(( " (maskbytes:" ));
154
155 /* set mask and advance interpreter's charstring pointer */
156 for ( i = 0; i < hintmask->byteCount; i++ )
157 {
158 hintmask->mask[i] = (FT_Byte)cf2_buf_readByte( charstring );
159 FT_TRACE4(( " 0x%02X", hintmask->mask[i] ));
160 }
161
162 FT_TRACE4(( ")\n" ));
163
164 /* assert any unused bits in last byte are zero unless there's a prior */
165 /* error */
166 /* bitCount -> mask, 0 -> 0, 1 -> 7f, 2 -> 3f, ... 6 -> 3, 7 -> 1 */
167 #ifndef CF2_NDEBUG
168 FT_ASSERT( ( hintmask->mask[hintmask->byteCount - 1] & mask ) == 0 ||
169 *hintmask->error );
170 #endif
171 }
172
173
174 FT_LOCAL_DEF( void )
175 cf2_hintmask_setAll( CF2_HintMask hintmask,
176 size_t bitCount )
177 {
178 size_t i;
179 CF2_UInt mask = ( 1 << ( -(CF2_Int)bitCount & 7 ) ) - 1;
180
181
182 /* initialize counts and isValid */
183 if ( cf2_hintmask_setCounts( hintmask, bitCount ) == 0 )
184 return;
185
186 FT_ASSERT( hintmask->byteCount > 0 );
187 FT_ASSERT( hintmask->byteCount <=
188 sizeof ( hintmask->mask ) / sizeof ( hintmask->mask[0] ) );
189
190 /* set mask to all ones */
191 for ( i = 0; i < hintmask->byteCount; i++ )
192 hintmask->mask[i] = 0xFF;
193
194 /* clear unused bits */
195 /* bitCount -> mask, 0 -> 0, 1 -> 7f, 2 -> 3f, ... 6 -> 3, 7 -> 1 */
196 hintmask->mask[hintmask->byteCount - 1] &= ~mask;
197 }
198
199
200 /* Type2 charstring opcodes */
201 enum
202 {
203 cf2_cmdRESERVED_0, /* 0 */
204 cf2_cmdHSTEM, /* 1 */
205 cf2_cmdRESERVED_2, /* 2 */
206 cf2_cmdVSTEM, /* 3 */
207 cf2_cmdVMOVETO, /* 4 */
208 cf2_cmdRLINETO, /* 5 */
209 cf2_cmdHLINETO, /* 6 */
210 cf2_cmdVLINETO, /* 7 */
211 cf2_cmdRRCURVETO, /* 8 */
212 cf2_cmdRESERVED_9, /* 9 */
213 cf2_cmdCALLSUBR, /* 10 */
214 cf2_cmdRETURN, /* 11 */
215 cf2_cmdESC, /* 12 */
216 cf2_cmdRESERVED_13, /* 13 */
217 cf2_cmdENDCHAR, /* 14 */
218 cf2_cmdRESERVED_15, /* 15 */
219 cf2_cmdRESERVED_16, /* 16 */
220 cf2_cmdRESERVED_17, /* 17 */
221 cf2_cmdHSTEMHM, /* 18 */
222 cf2_cmdHINTMASK, /* 19 */
223 cf2_cmdCNTRMASK, /* 20 */
224 cf2_cmdRMOVETO, /* 21 */
225 cf2_cmdHMOVETO, /* 22 */
226 cf2_cmdVSTEMHM, /* 23 */
227 cf2_cmdRCURVELINE, /* 24 */
228 cf2_cmdRLINECURVE, /* 25 */
229 cf2_cmdVVCURVETO, /* 26 */
230 cf2_cmdHHCURVETO, /* 27 */
231 cf2_cmdEXTENDEDNMBR, /* 28 */
232 cf2_cmdCALLGSUBR, /* 29 */
233 cf2_cmdVHCURVETO, /* 30 */
234 cf2_cmdHVCURVETO /* 31 */
235 };
236
237 enum
238 {
239 cf2_escDOTSECTION, /* 0 */
240 cf2_escRESERVED_1, /* 1 */
241 cf2_escRESERVED_2, /* 2 */
242 cf2_escAND, /* 3 */
243 cf2_escOR, /* 4 */
244 cf2_escNOT, /* 5 */
245 cf2_escRESERVED_6, /* 6 */
246 cf2_escRESERVED_7, /* 7 */
247 cf2_escRESERVED_8, /* 8 */
248 cf2_escABS, /* 9 */
249 cf2_escADD, /* 10 like otherADD */
250 cf2_escSUB, /* 11 like otherSUB */
251 cf2_escDIV, /* 12 */
252 cf2_escRESERVED_13, /* 13 */
253 cf2_escNEG, /* 14 */
254 cf2_escEQ, /* 15 */
255 cf2_escRESERVED_16, /* 16 */
256 cf2_escRESERVED_17, /* 17 */
257 cf2_escDROP, /* 18 */
258 cf2_escRESERVED_19, /* 19 */
259 cf2_escPUT, /* 20 like otherPUT */
260 cf2_escGET, /* 21 like otherGET */
261 cf2_escIFELSE, /* 22 like otherIFELSE */
262 cf2_escRANDOM, /* 23 like otherRANDOM */
263 cf2_escMUL, /* 24 like otherMUL */
264 cf2_escRESERVED_25, /* 25 */
265 cf2_escSQRT, /* 26 */
266 cf2_escDUP, /* 27 like otherDUP */
267 cf2_escEXCH, /* 28 like otherEXCH */
268 cf2_escINDEX, /* 29 */
269 cf2_escROLL, /* 30 */
270 cf2_escRESERVED_31, /* 31 */
271 cf2_escRESERVED_32, /* 32 */
272 cf2_escRESERVED_33, /* 33 */
273 cf2_escHFLEX, /* 34 */
274 cf2_escFLEX, /* 35 */
275 cf2_escHFLEX1, /* 36 */
276 cf2_escFLEX1 /* 37 */
277 };
278
279
280 /* `stemHintArray' does not change once we start drawing the outline. */
281 static void
282 cf2_doStems( const CF2_Font font,
283 CF2_Stack opStack,
284 CF2_ArrStack stemHintArray,
285 CF2_Fixed* width,
286 FT_Bool* haveWidth,
287 CF2_Fixed hintOffset )
288 {
289 CF2_UInt i;
290 CF2_UInt count = cf2_stack_count( opStack );
291 FT_Bool hasWidthArg = (FT_Bool)( count & 1 );
292
293 /* variable accumulates delta values from operand stack */
294 CF2_Fixed position = hintOffset;
295
296
297 if ( hasWidthArg && !*haveWidth )
298 *width = cf2_stack_getReal( opStack, 0 ) +
299 cf2_getNominalWidthX( font->decoder );
300
301 if ( font->decoder->width_only )
302 goto exit;
303
304 for ( i = hasWidthArg ? 1 : 0; i < count; i += 2 )
305 {
306 /* construct a CF2_StemHint and push it onto the list */
307 CF2_StemHintRec stemhint;
308
309
310 stemhint.min =
311 position += cf2_stack_getReal( opStack, i );
312 stemhint.max =
313 position += cf2_stack_getReal( opStack, i + 1 );
314
315 stemhint.used = FALSE;
316 stemhint.maxDS =
317 stemhint.minDS = 0;
318
319 cf2_arrstack_push( stemHintArray, &stemhint ); /* defer error check */
320 }
321
322 cf2_stack_clear( opStack );
323
324 exit:
325 /* cf2_doStems must define a width (may be default) */
326 *haveWidth = TRUE;
327 }
328
329
330 static void
331 cf2_doFlex( CF2_Stack opStack,
332 CF2_Fixed* curX,
333 CF2_Fixed* curY,
334 CF2_GlyphPath glyphPath,
335 const FT_Bool* readFromStack,
336 FT_Bool doConditionalLastRead )
337 {
338 CF2_Fixed vals[14];
339 CF2_UInt index;
340 FT_Bool isHFlex;
341 CF2_Int top, i, j;
342
343
344 vals[0] = *curX;
345 vals[1] = *curY;
346 index = 0;
347 isHFlex = readFromStack[9] == FALSE;
348 top = isHFlex ? 9 : 10;
349
350 for ( i = 0; i < top; i++ )
351 {
352 vals[i + 2] = vals[i];
353 if ( readFromStack[i] )
354 vals[i + 2] += cf2_stack_getReal( opStack, index++ );
355 }
356
357 if ( isHFlex )
358 vals[9 + 2] = *curY;
359
360 if ( doConditionalLastRead )
361 {
362 FT_Bool lastIsX = (FT_Bool)( cf2_fixedAbs( vals[10] - *curX ) >
363 cf2_fixedAbs( vals[11] - *curY ) );
364 CF2_Fixed lastVal = cf2_stack_getReal( opStack, index );
365
366
367 if ( lastIsX )
368 {
369 vals[12] = vals[10] + lastVal;
370 vals[13] = *curY;
371 }
372 else
373 {
374 vals[12] = *curX;
375 vals[13] = vals[11] + lastVal;
376 }
377 }
378 else
379 {
380 if ( readFromStack[10] )
381 vals[12] = vals[10] + cf2_stack_getReal( opStack, index++ );
382 else
383 vals[12] = *curX;
384
385 if ( readFromStack[11] )
386 vals[13] = vals[11] + cf2_stack_getReal( opStack, index );
387 else
388 vals[13] = *curY;
389 }
390
391 for ( j = 0; j < 2; j++ )
392 cf2_glyphpath_curveTo( glyphPath, vals[j * 6 + 2],
393 vals[j * 6 + 3],
394 vals[j * 6 + 4],
395 vals[j * 6 + 5],
396 vals[j * 6 + 6],
397 vals[j * 6 + 7] );
398
399 cf2_stack_clear( opStack );
400
401 *curX = vals[12];
402 *curY = vals[13];
403 }
404
405
406 /*
407 * `error' is a shared error code used by many objects in this
408 * routine. Before the code continues from an error, it must check and
409 * record the error in `*error'. The idea is that this shared
410 * error code will record the first error encountered. If testing
411 * for an error anyway, the cost of `goto exit' is small, so we do it,
412 * even if continuing would be safe. In this case, `lastError' is
413 * set, so the testing and storing can be done in one place, at `exit'.
414 *
415 * Continuing after an error is intended for objects which do their own
416 * testing of `*error', e.g., array stack functions. This allows us to
417 * avoid an extra test after the call.
418 *
419 * Unimplemented opcodes are ignored.
420 *
421 */
422 FT_LOCAL_DEF( void )
423 cf2_interpT2CharString( CF2_Font font,
424 CF2_Buffer buf,
425 CF2_OutlineCallbacks callbacks,
426 const FT_Vector* translation,
427 FT_Bool doingSeac,
428 CF2_Fixed curX,
429 CF2_Fixed curY,
430 CF2_Fixed* width )
431 {
432 /* lastError is used for errors that are immediately tested */
433 FT_Error lastError = FT_Err_Ok;
434
435 /* pointer to parsed font object */
436 CFF_Decoder* decoder = font->decoder;
437
438 FT_Error* error = &font->error;
439 FT_Memory memory = font->memory;
440
441 CF2_Fixed scaleY = font->innerTransform.d;
442 CF2_Fixed nominalWidthX = cf2_getNominalWidthX( decoder );
443
444 /* save this for hinting seac accents */
445 CF2_Fixed hintOriginY = curY;
446
447 CF2_Stack opStack = NULL;
448 FT_Byte op1; /* first opcode byte */
449
450 CF2_F16Dot16 storage[CF2_STORAGE_SIZE]; /* for `put' and `get' */
451
452 /* instruction limit; 20,000,000 matches Avalon */
453 FT_UInt32 instructionLimit = 20000000UL;
454
455 CF2_ArrStackRec subrStack;
456
457 FT_Bool haveWidth;
458 CF2_Buffer charstring = NULL;
459
460 CF2_Int charstringIndex = -1; /* initialize to empty */
461
462 /* TODO: placeholders for hint structures */
463
464 /* objects used for hinting */
465 CF2_ArrStackRec hStemHintArray;
466 CF2_ArrStackRec vStemHintArray;
467
468 CF2_HintMaskRec hintMask;
469 #ifdef __REACTOS__
470 CF2_GlyphPathRec *glyphPath = malloc(sizeof(CF2_GlyphPathRec));
471 /* Ugly but it allows us to reduce the diff */
472 #define glyphPath (*glyphPath)
473 #else
474 CF2_GlyphPathRec glyphPath;
475 #endif
476
477
478 /* initialize the remaining objects */
479 cf2_arrstack_init( &subrStack,
480 memory,
481 error,
482 sizeof ( CF2_BufferRec ) );
483 cf2_arrstack_init( &hStemHintArray,
484 memory,
485 error,
486 sizeof ( CF2_StemHintRec ) );
487 cf2_arrstack_init( &vStemHintArray,
488 memory,
489 error,
490 sizeof ( CF2_StemHintRec ) );
491
492 /* initialize CF2_StemHint arrays */
493 cf2_hintmask_init( &hintMask, error );
494
495 /* initialize path map to manage drawing operations */
496
497 /* Note: last 4 params are used to handle `MoveToPermissive', which */
498 /* may need to call `hintMap.Build' */
499 /* TODO: MoveToPermissive is gone; are these still needed? */
500 cf2_glyphpath_init( &glyphPath,
501 font,
502 callbacks,
503 scaleY,
504 /* hShift, */
505 &hStemHintArray,
506 &vStemHintArray,
507 &hintMask,
508 hintOriginY,
509 &font->blues,
510 translation );
511
512 /*
513 * Initialize state for width parsing. From the CFF Spec:
514 *
515 * The first stack-clearing operator, which must be one of hstem,
516 * hstemhm, vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto,
517 * rmoveto, or endchar, takes an additional argument - the width (as
518 * described earlier), which may be expressed as zero or one numeric
519 * argument.
520 *
521 * What we implement here uses the first validly specified width, but
522 * does not detect errors for specifying more than one width.
523 *
524 * If one of the above operators occurs without explicitly specifying
525 * a width, we assume the default width.
526 *
527 */
528 haveWidth = FALSE;
529 *width = cf2_getDefaultWidthX( decoder );
530
531 /*
532 * Note: at this point, all pointers to resources must be NULL
533 * and all local objects must be initialized.
534 * There must be no branches to exit: above this point.
535 *
536 */
537
538 /* allocate an operand stack */
539 opStack = cf2_stack_init( memory, error );
540 if ( !opStack )
541 {
542 lastError = FT_THROW( Out_Of_Memory );
543 goto exit;
544 }
545
546 /* initialize subroutine stack by placing top level charstring as */
547 /* first element (max depth plus one for the charstring) */
548 /* Note: Caller owns and must finalize the first charstring. */
549 /* Our copy of it does not change that requirement. */
550 cf2_arrstack_setCount( &subrStack, CF2_MAX_SUBR + 1 );
551
552 charstring = (CF2_Buffer)cf2_arrstack_getBuffer( &subrStack );
553 *charstring = *buf; /* structure copy */
554
555 charstringIndex = 0; /* entry is valid now */
556
557 /* catch errors so far */
558 if ( *error )
559 goto exit;
560
561 /* main interpreter loop */
562 while ( 1 )
563 {
564 if ( cf2_buf_isEnd( charstring ) )
565 {
566 /* If we've reached the end of the charstring, simulate a */
567 /* cf2_cmdRETURN or cf2_cmdENDCHAR. */
568 if ( charstringIndex )
569 op1 = cf2_cmdRETURN; /* end of buffer for subroutine */
570 else
571 op1 = cf2_cmdENDCHAR; /* end of buffer for top level charstring */
572 }
573 else
574 op1 = (FT_Byte)cf2_buf_readByte( charstring );
575
576 /* check for errors once per loop */
577 if ( *error )
578 goto exit;
579
580 instructionLimit--;
581 if ( instructionLimit == 0 )
582 {
583 lastError = FT_THROW( Invalid_Glyph_Format );
584 goto exit;
585 }
586
587 switch( op1 )
588 {
589 case cf2_cmdRESERVED_0:
590 case cf2_cmdRESERVED_2:
591 case cf2_cmdRESERVED_9:
592 case cf2_cmdRESERVED_13:
593 case cf2_cmdRESERVED_15:
594 case cf2_cmdRESERVED_16:
595 case cf2_cmdRESERVED_17:
596 /* we may get here if we have a prior error */
597 FT_TRACE4(( " unknown op (%d)\n", op1 ));
598 break;
599
600 case cf2_cmdHSTEMHM:
601 case cf2_cmdHSTEM:
602 FT_TRACE4(( op1 == cf2_cmdHSTEMHM ? " hstemhm\n" : " hstem\n" ));
603
604 /* never add hints after the mask is computed */
605 if ( cf2_hintmask_isValid( &hintMask ) )
606 {
607 FT_TRACE4(( "cf2_interpT2CharString:"
608 " invalid horizontal hint mask\n" ));
609 break;
610 }
611
612 cf2_doStems( font,
613 opStack,
614 &hStemHintArray,
615 width,
616 &haveWidth,
617 0 );
618
619 if ( font->decoder->width_only )
620 goto exit;
621
622 break;
623
624 case cf2_cmdVSTEMHM:
625 case cf2_cmdVSTEM:
626 FT_TRACE4(( op1 == cf2_cmdVSTEMHM ? " vstemhm\n" : " vstem\n" ));
627
628 /* never add hints after the mask is computed */
629 if ( cf2_hintmask_isValid( &hintMask ) )
630 {
631 FT_TRACE4(( "cf2_interpT2CharString:"
632 " invalid vertical hint mask\n" ));
633 break;
634 }
635
636 cf2_doStems( font,
637 opStack,
638 &vStemHintArray,
639 width,
640 &haveWidth,
641 0 );
642
643 if ( font->decoder->width_only )
644 goto exit;
645
646 break;
647
648 case cf2_cmdVMOVETO:
649 FT_TRACE4(( " vmoveto\n" ));
650
651 if ( cf2_stack_count( opStack ) > 1 && !haveWidth )
652 *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
653
654 /* width is defined or default after this */
655 haveWidth = TRUE;
656
657 if ( font->decoder->width_only )
658 goto exit;
659
660 curY += cf2_stack_popFixed( opStack );
661
662 cf2_glyphpath_moveTo( &glyphPath, curX, curY );
663
664 break;
665
666 case cf2_cmdRLINETO:
667 {
668 CF2_UInt index;
669 CF2_UInt count = cf2_stack_count( opStack );
670
671
672 FT_TRACE4(( " rlineto\n" ));
673
674 for ( index = 0; index < count; index += 2 )
675 {
676 curX += cf2_stack_getReal( opStack, index + 0 );
677 curY += cf2_stack_getReal( opStack, index + 1 );
678
679 cf2_glyphpath_lineTo( &glyphPath, curX, curY );
680 }
681
682 cf2_stack_clear( opStack );
683 }
684 continue; /* no need to clear stack again */
685
686 case cf2_cmdHLINETO:
687 case cf2_cmdVLINETO:
688 {
689 CF2_UInt index;
690 CF2_UInt count = cf2_stack_count( opStack );
691
692 FT_Bool isX = op1 == cf2_cmdHLINETO;
693
694
695 FT_TRACE4(( isX ? " hlineto\n" : " vlineto\n" ));
696
697 for ( index = 0; index < count; index++ )
698 {
699 CF2_Fixed v = cf2_stack_getReal( opStack, index );
700
701
702 if ( isX )
703 curX += v;
704 else
705 curY += v;
706
707 isX = !isX;
708
709 cf2_glyphpath_lineTo( &glyphPath, curX, curY );
710 }
711
712 cf2_stack_clear( opStack );
713 }
714 continue;
715
716 case cf2_cmdRCURVELINE:
717 case cf2_cmdRRCURVETO:
718 {
719 CF2_UInt count = cf2_stack_count( opStack );
720 CF2_UInt index = 0;
721
722
723 FT_TRACE4(( op1 == cf2_cmdRCURVELINE ? " rcurveline\n"
724 : " rrcurveto\n" ));
725
726 while ( index + 6 <= count )
727 {
728 CF2_Fixed x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
729 CF2_Fixed y1 = cf2_stack_getReal( opStack, index + 1 ) + curY;
730 CF2_Fixed x2 = cf2_stack_getReal( opStack, index + 2 ) + x1;
731 CF2_Fixed y2 = cf2_stack_getReal( opStack, index + 3 ) + y1;
732 CF2_Fixed x3 = cf2_stack_getReal( opStack, index + 4 ) + x2;
733 CF2_Fixed y3 = cf2_stack_getReal( opStack, index + 5 ) + y2;
734
735
736 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
737
738 curX = x3;
739 curY = y3;
740 index += 6;
741 }
742
743 if ( op1 == cf2_cmdRCURVELINE )
744 {
745 curX += cf2_stack_getReal( opStack, index + 0 );
746 curY += cf2_stack_getReal( opStack, index + 1 );
747
748 cf2_glyphpath_lineTo( &glyphPath, curX, curY );
749 }
750
751 cf2_stack_clear( opStack );
752 }
753 continue; /* no need to clear stack again */
754
755 case cf2_cmdCALLGSUBR:
756 case cf2_cmdCALLSUBR:
757 {
758 CF2_Int subrNum;
759
760
761 FT_TRACE4(( op1 == cf2_cmdCALLGSUBR ? " callgsubr"
762 : " callsubr" ));
763
764 if ( charstringIndex > CF2_MAX_SUBR )
765 {
766 /* max subr plus one for charstring */
767 lastError = FT_THROW( Invalid_Glyph_Format );
768 goto exit; /* overflow of stack */
769 }
770
771 /* push our current CFF charstring region on subrStack */
772 charstring = (CF2_Buffer)
773 cf2_arrstack_getPointer(
774 &subrStack,
775 (size_t)charstringIndex + 1 );
776
777 /* set up the new CFF region and pointer */
778 subrNum = cf2_stack_popInt( opStack );
779
780 switch ( op1 )
781 {
782 case cf2_cmdCALLGSUBR:
783 FT_TRACE4(( " (idx %d, entering level %d)\n",
784 subrNum + decoder->globals_bias,
785 charstringIndex + 1 ));
786
787 if ( cf2_initGlobalRegionBuffer( decoder,
788 subrNum,
789 charstring ) )
790 {
791 lastError = FT_THROW( Invalid_Glyph_Format );
792 goto exit; /* subroutine lookup or stream error */
793 }
794 break;
795
796 default:
797 /* cf2_cmdCALLSUBR */
798 FT_TRACE4(( " (idx %d, entering level %d)\n",
799 subrNum + decoder->locals_bias,
800 charstringIndex + 1 ));
801
802 if ( cf2_initLocalRegionBuffer( decoder,
803 subrNum,
804 charstring ) )
805 {
806 lastError = FT_THROW( Invalid_Glyph_Format );
807 goto exit; /* subroutine lookup or stream error */
808 }
809 }
810
811 charstringIndex += 1; /* entry is valid now */
812 }
813 continue; /* do not clear the stack */
814
815 case cf2_cmdRETURN:
816 FT_TRACE4(( " return (leaving level %d)\n", charstringIndex ));
817
818 if ( charstringIndex < 1 )
819 {
820 /* Note: cannot return from top charstring */
821 lastError = FT_THROW( Invalid_Glyph_Format );
822 goto exit; /* underflow of stack */
823 }
824
825 /* restore position in previous charstring */
826 charstring = (CF2_Buffer)
827 cf2_arrstack_getPointer(
828 &subrStack,
829 (CF2_UInt)--charstringIndex );
830 continue; /* do not clear the stack */
831
832 case cf2_cmdESC:
833 {
834 FT_Byte op2 = (FT_Byte)cf2_buf_readByte( charstring );
835
836
837 switch ( op2 )
838 {
839 case cf2_escDOTSECTION:
840 /* something about `flip type of locking' -- ignore it */
841 FT_TRACE4(( " dotsection\n" ));
842
843 break;
844
845 case cf2_escAND:
846 {
847 CF2_F16Dot16 arg1;
848 CF2_F16Dot16 arg2;
849
850
851 FT_TRACE4(( " and\n" ));
852
853 arg2 = cf2_stack_popFixed( opStack );
854 arg1 = cf2_stack_popFixed( opStack );
855
856 cf2_stack_pushInt( opStack, arg1 && arg2 );
857 }
858 continue; /* do not clear the stack */
859
860 case cf2_escOR:
861 {
862 CF2_F16Dot16 arg1;
863 CF2_F16Dot16 arg2;
864
865
866 FT_TRACE4(( " or\n" ));
867
868 arg2 = cf2_stack_popFixed( opStack );
869 arg1 = cf2_stack_popFixed( opStack );
870
871 cf2_stack_pushInt( opStack, arg1 || arg2 );
872 }
873 continue; /* do not clear the stack */
874
875 case cf2_escNOT:
876 {
877 CF2_F16Dot16 arg;
878
879
880 FT_TRACE4(( " not\n" ));
881
882 arg = cf2_stack_popFixed( opStack );
883
884 cf2_stack_pushInt( opStack, !arg );
885 }
886 continue; /* do not clear the stack */
887
888 case cf2_escABS:
889 {
890 CF2_F16Dot16 arg;
891
892
893 FT_TRACE4(( " abs\n" ));
894
895 arg = cf2_stack_popFixed( opStack );
896
897 cf2_stack_pushFixed( opStack, FT_ABS( arg ) );
898 }
899 continue; /* do not clear the stack */
900
901 case cf2_escADD:
902 {
903 CF2_F16Dot16 summand1;
904 CF2_F16Dot16 summand2;
905
906
907 FT_TRACE4(( " add\n" ));
908
909 summand2 = cf2_stack_popFixed( opStack );
910 summand1 = cf2_stack_popFixed( opStack );
911
912 cf2_stack_pushFixed( opStack, summand1 + summand2 );
913 }
914 continue; /* do not clear the stack */
915
916 case cf2_escSUB:
917 {
918 CF2_F16Dot16 minuend;
919 CF2_F16Dot16 subtrahend;
920
921
922 FT_TRACE4(( " sub\n" ));
923
924 subtrahend = cf2_stack_popFixed( opStack );
925 minuend = cf2_stack_popFixed( opStack );
926
927 cf2_stack_pushFixed( opStack, minuend - subtrahend );
928 }
929 continue; /* do not clear the stack */
930
931 case cf2_escDIV:
932 {
933 CF2_F16Dot16 dividend;
934 CF2_F16Dot16 divisor;
935
936
937 FT_TRACE4(( " div\n" ));
938
939 divisor = cf2_stack_popFixed( opStack );
940 dividend = cf2_stack_popFixed( opStack );
941
942 cf2_stack_pushFixed( opStack, FT_DivFix( dividend, divisor ) );
943 }
944 continue; /* do not clear the stack */
945
946 case cf2_escNEG:
947 {
948 CF2_F16Dot16 arg;
949
950
951 FT_TRACE4(( " neg\n" ));
952
953 arg = cf2_stack_popFixed( opStack );
954
955 cf2_stack_pushFixed( opStack, -arg );
956 }
957 continue; /* do not clear the stack */
958
959 case cf2_escEQ:
960 {
961 CF2_F16Dot16 arg1;
962 CF2_F16Dot16 arg2;
963
964
965 FT_TRACE4(( " eq\n" ));
966
967 arg2 = cf2_stack_popFixed( opStack );
968 arg1 = cf2_stack_popFixed( opStack );
969
970 cf2_stack_pushInt( opStack, arg1 == arg2 );
971 }
972 continue; /* do not clear the stack */
973
974 case cf2_escDROP:
975 FT_TRACE4(( " drop\n" ));
976
977 (void)cf2_stack_popFixed( opStack );
978 continue; /* do not clear the stack */
979
980 case cf2_escPUT:
981 {
982 CF2_F16Dot16 val;
983 CF2_Int idx;
984
985
986 FT_TRACE4(( " put\n" ));
987
988 idx = cf2_stack_popInt( opStack );
989 val = cf2_stack_popFixed( opStack );
990
991 if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
992 storage[idx] = val;
993 }
994 continue; /* do not clear the stack */
995
996 case cf2_escGET:
997 {
998 CF2_Int idx;
999
1000
1001 FT_TRACE4(( " get\n" ));
1002
1003 idx = cf2_stack_popInt( opStack );
1004
1005 if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
1006 cf2_stack_pushFixed( opStack, storage[idx] );
1007 }
1008 continue; /* do not clear the stack */
1009
1010 case cf2_escIFELSE:
1011 {
1012 CF2_F16Dot16 arg1;
1013 CF2_F16Dot16 arg2;
1014 CF2_F16Dot16 cond1;
1015 CF2_F16Dot16 cond2;
1016
1017
1018 FT_TRACE4(( " ifelse\n" ));
1019
1020 cond2 = cf2_stack_popFixed( opStack );
1021 cond1 = cf2_stack_popFixed( opStack );
1022 arg2 = cf2_stack_popFixed( opStack );
1023 arg1 = cf2_stack_popFixed( opStack );
1024
1025 cf2_stack_pushFixed( opStack, cond1 <= cond2 ? arg1 : arg2 );
1026 }
1027 continue; /* do not clear the stack */
1028
1029 case cf2_escRANDOM: /* in spec */
1030 FT_TRACE4(( " random\n" ));
1031
1032 CF2_FIXME;
1033 break;
1034
1035 case cf2_escMUL:
1036 {
1037 CF2_F16Dot16 factor1;
1038 CF2_F16Dot16 factor2;
1039
1040
1041 FT_TRACE4(( " mul\n" ));
1042
1043 factor2 = cf2_stack_popFixed( opStack );
1044 factor1 = cf2_stack_popFixed( opStack );
1045
1046 cf2_stack_pushFixed( opStack, FT_MulFix( factor1, factor2 ) );
1047 }
1048 continue; /* do not clear the stack */
1049
1050 case cf2_escSQRT:
1051 {
1052 CF2_F16Dot16 arg;
1053
1054
1055 FT_TRACE4(( " sqrt\n" ));
1056
1057 arg = cf2_stack_popFixed( opStack );
1058 if ( arg > 0 )
1059 {
1060 FT_Fixed root = arg;
1061 FT_Fixed new_root;
1062
1063
1064 /* Babylonian method */
1065 for (;;)
1066 {
1067 new_root = ( root + FT_DivFix( arg, root ) + 1 ) >> 1;
1068 if ( new_root == root )
1069 break;
1070 root = new_root;
1071 }
1072 arg = new_root;
1073 }
1074 else
1075 arg = 0;
1076
1077 cf2_stack_pushFixed( opStack, arg );
1078 }
1079 continue; /* do not clear the stack */
1080
1081 case cf2_escDUP:
1082 {
1083 CF2_F16Dot16 arg;
1084
1085
1086 FT_TRACE4(( " dup\n" ));
1087
1088 arg = cf2_stack_popFixed( opStack );
1089
1090 cf2_stack_pushFixed( opStack, arg );
1091 cf2_stack_pushFixed( opStack, arg );
1092 }
1093 continue; /* do not clear the stack */
1094
1095 case cf2_escEXCH:
1096 {
1097 CF2_F16Dot16 arg1;
1098 CF2_F16Dot16 arg2;
1099
1100
1101 FT_TRACE4(( " exch\n" ));
1102
1103 arg2 = cf2_stack_popFixed( opStack );
1104 arg1 = cf2_stack_popFixed( opStack );
1105
1106 cf2_stack_pushFixed( opStack, arg2 );
1107 cf2_stack_pushFixed( opStack, arg1 );
1108 }
1109 continue; /* do not clear the stack */
1110
1111 case cf2_escINDEX:
1112 {
1113 CF2_Int idx;
1114 CF2_UInt size;
1115
1116
1117 FT_TRACE4(( " index\n" ));
1118
1119 idx = cf2_stack_popInt( opStack );
1120 size = cf2_stack_count( opStack );
1121
1122 if ( size > 0 )
1123 {
1124 /* for `cf2_stack_getReal', index 0 is bottom of stack */
1125 CF2_UInt gr_idx;
1126
1127
1128 if ( idx < 0 )
1129 gr_idx = size - 1;
1130 else if ( (CF2_UInt)idx >= size )
1131 gr_idx = 0;
1132 else
1133 gr_idx = size - 1 - (CF2_UInt)idx;
1134
1135 cf2_stack_pushFixed( opStack,
1136 cf2_stack_getReal( opStack, gr_idx ) );
1137 }
1138 }
1139 continue; /* do not clear the stack */
1140
1141 case cf2_escROLL:
1142 {
1143 CF2_Int idx;
1144 CF2_Int count;
1145
1146
1147 FT_TRACE4(( " roll\n" ));
1148
1149 idx = cf2_stack_popInt( opStack );
1150 count = cf2_stack_popInt( opStack );
1151
1152 cf2_stack_roll( opStack, count, idx );
1153 }
1154 continue; /* do not clear the stack */
1155
1156 case cf2_escHFLEX:
1157 {
1158 static const FT_Bool readFromStack[12] =
1159 {
1160 TRUE /* dx1 */, FALSE /* dy1 */,
1161 TRUE /* dx2 */, TRUE /* dy2 */,
1162 TRUE /* dx3 */, FALSE /* dy3 */,
1163 TRUE /* dx4 */, FALSE /* dy4 */,
1164 TRUE /* dx5 */, FALSE /* dy5 */,
1165 TRUE /* dx6 */, FALSE /* dy6 */
1166 };
1167
1168
1169 FT_TRACE4(( " hflex\n" ));
1170
1171 cf2_doFlex( opStack,
1172 &curX,
1173 &curY,
1174 &glyphPath,
1175 readFromStack,
1176 FALSE /* doConditionalLastRead */ );
1177 }
1178 continue;
1179
1180 case cf2_escFLEX:
1181 {
1182 static const FT_Bool readFromStack[12] =
1183 {
1184 TRUE /* dx1 */, TRUE /* dy1 */,
1185 TRUE /* dx2 */, TRUE /* dy2 */,
1186 TRUE /* dx3 */, TRUE /* dy3 */,
1187 TRUE /* dx4 */, TRUE /* dy4 */,
1188 TRUE /* dx5 */, TRUE /* dy5 */,
1189 TRUE /* dx6 */, TRUE /* dy6 */
1190 };
1191
1192
1193 FT_TRACE4(( " flex\n" ));
1194
1195 cf2_doFlex( opStack,
1196 &curX,
1197 &curY,
1198 &glyphPath,
1199 readFromStack,
1200 FALSE /* doConditionalLastRead */ );
1201 }
1202 break; /* TODO: why is this not a continue? */
1203
1204 case cf2_escHFLEX1:
1205 {
1206 static const FT_Bool readFromStack[12] =
1207 {
1208 TRUE /* dx1 */, TRUE /* dy1 */,
1209 TRUE /* dx2 */, TRUE /* dy2 */,
1210 TRUE /* dx3 */, FALSE /* dy3 */,
1211 TRUE /* dx4 */, FALSE /* dy4 */,
1212 TRUE /* dx5 */, TRUE /* dy5 */,
1213 TRUE /* dx6 */, FALSE /* dy6 */
1214 };
1215
1216
1217 FT_TRACE4(( " hflex1\n" ));
1218
1219 cf2_doFlex( opStack,
1220 &curX,
1221 &curY,
1222 &glyphPath,
1223 readFromStack,
1224 FALSE /* doConditionalLastRead */ );
1225 }
1226 continue;
1227
1228 case cf2_escFLEX1:
1229 {
1230 static const FT_Bool readFromStack[12] =
1231 {
1232 TRUE /* dx1 */, TRUE /* dy1 */,
1233 TRUE /* dx2 */, TRUE /* dy2 */,
1234 TRUE /* dx3 */, TRUE /* dy3 */,
1235 TRUE /* dx4 */, TRUE /* dy4 */,
1236 TRUE /* dx5 */, TRUE /* dy5 */,
1237 FALSE /* dx6 */, FALSE /* dy6 */
1238 };
1239
1240
1241 FT_TRACE4(( " flex1\n" ));
1242
1243 cf2_doFlex( opStack,
1244 &curX,
1245 &curY,
1246 &glyphPath,
1247 readFromStack,
1248 TRUE /* doConditionalLastRead */ );
1249 }
1250 continue;
1251
1252 case cf2_escRESERVED_1:
1253 case cf2_escRESERVED_2:
1254 case cf2_escRESERVED_6:
1255 case cf2_escRESERVED_7:
1256 case cf2_escRESERVED_8:
1257 case cf2_escRESERVED_13:
1258 case cf2_escRESERVED_16:
1259 case cf2_escRESERVED_17:
1260 case cf2_escRESERVED_19:
1261 case cf2_escRESERVED_25:
1262 case cf2_escRESERVED_31:
1263 case cf2_escRESERVED_32:
1264 case cf2_escRESERVED_33:
1265 default:
1266 FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
1267
1268 }; /* end of switch statement checking `op2' */
1269
1270 } /* case cf2_cmdESC */
1271 break;
1272
1273 case cf2_cmdENDCHAR:
1274 FT_TRACE4(( " endchar\n" ));
1275
1276 if ( cf2_stack_count( opStack ) == 1 ||
1277 cf2_stack_count( opStack ) == 5 )
1278 {
1279 if ( !haveWidth )
1280 *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
1281 }
1282
1283 /* width is defined or default after this */
1284 haveWidth = TRUE;
1285
1286 if ( font->decoder->width_only )
1287 goto exit;
1288
1289 /* close path if still open */
1290 cf2_glyphpath_closeOpenPath( &glyphPath );
1291
1292 if ( cf2_stack_count( opStack ) > 1 )
1293 {
1294 /* must be either 4 or 5 -- */
1295 /* this is a (deprecated) implied `seac' operator */
1296
1297 CF2_Int achar;
1298 CF2_Int bchar;
1299 CF2_BufferRec component;
1300 CF2_Fixed dummyWidth; /* ignore component width */
1301 FT_Error error2;
1302
1303
1304 if ( doingSeac )
1305 {
1306 lastError = FT_THROW( Invalid_Glyph_Format );
1307 goto exit; /* nested seac */
1308 }
1309
1310 achar = cf2_stack_popInt( opStack );
1311 bchar = cf2_stack_popInt( opStack );
1312
1313 curY = cf2_stack_popFixed( opStack );
1314 curX = cf2_stack_popFixed( opStack );
1315
1316 error2 = cf2_getSeacComponent( decoder, achar, &component );
1317 if ( error2 )
1318 {
1319 lastError = error2; /* pass FreeType error through */
1320 goto exit;
1321 }
1322 cf2_interpT2CharString( font,
1323 &component,
1324 callbacks,
1325 translation,
1326 TRUE,
1327 curX,
1328 curY,
1329 &dummyWidth );
1330 cf2_freeSeacComponent( decoder, &component );
1331
1332 error2 = cf2_getSeacComponent( decoder, bchar, &component );
1333 if ( error2 )
1334 {
1335 lastError = error2; /* pass FreeType error through */
1336 goto exit;
1337 }
1338 cf2_interpT2CharString( font,
1339 &component,
1340 callbacks,
1341 translation,
1342 TRUE,
1343 0,
1344 0,
1345 &dummyWidth );
1346 cf2_freeSeacComponent( decoder, &component );
1347 }
1348 goto exit;
1349
1350 case cf2_cmdCNTRMASK:
1351 case cf2_cmdHINTMASK:
1352 /* the final \n in the tracing message gets added in */
1353 /* `cf2_hintmask_read' (which also traces the mask bytes) */
1354 FT_TRACE4(( op1 == cf2_cmdCNTRMASK ? " cntrmask" : " hintmask" ));
1355
1356 /* never add hints after the mask is computed */
1357 if ( cf2_stack_count( opStack ) > 1 &&
1358 cf2_hintmask_isValid( &hintMask ) )
1359 {
1360 FT_TRACE4(( "cf2_interpT2CharString: invalid hint mask\n" ));
1361 break;
1362 }
1363
1364 /* if there are arguments on the stack, there this is an */
1365 /* implied cf2_cmdVSTEMHM */
1366 cf2_doStems( font,
1367 opStack,
1368 &vStemHintArray,
1369 width,
1370 &haveWidth,
1371 0 );
1372
1373 if ( font->decoder->width_only )
1374 goto exit;
1375
1376 if ( op1 == cf2_cmdHINTMASK )
1377 {
1378 /* consume the hint mask bytes which follow the operator */
1379 cf2_hintmask_read( &hintMask,
1380 charstring,
1381 cf2_arrstack_size( &hStemHintArray ) +
1382 cf2_arrstack_size( &vStemHintArray ) );
1383 }
1384 else
1385 {
1386 /*
1387 * Consume the counter mask bytes which follow the operator:
1388 * Build a temporary hint map, just to place and lock those
1389 * stems participating in the counter mask. These are most
1390 * likely the dominant hstems, and are grouped together in a
1391 * few counter groups, not necessarily in correspondence
1392 * with the hint groups. This reduces the chances of
1393 * conflicts between hstems that are initially placed in
1394 * separate hint groups and then brought together. The
1395 * positions are copied back to `hStemHintArray', so we can
1396 * discard `counterMask' and `counterHintMap'.
1397 *
1398 */
1399 #ifdef __REACTOS__
1400 CF2_HintMapRec *counterHintMap = malloc(sizeof(CF2_HintMapRec));
1401 /* Ugly but it allows us to reduce the diff */
1402 #define counterHintMap (*counterHintMap)
1403 #else
1404 CF2_HintMapRec counterHintMap;
1405 #endif
1406 CF2_HintMaskRec counterMask;
1407
1408
1409 cf2_hintmap_init( &counterHintMap,
1410 font,
1411 &glyphPath.initialHintMap,
1412 &glyphPath.hintMoves,
1413 scaleY );
1414 cf2_hintmask_init( &counterMask, error );
1415
1416 cf2_hintmask_read( &counterMask,
1417 charstring,
1418 cf2_arrstack_size( &hStemHintArray ) +
1419 cf2_arrstack_size( &vStemHintArray ) );
1420 cf2_hintmap_build( &counterHintMap,
1421 &hStemHintArray,
1422 &vStemHintArray,
1423 &counterMask,
1424 0,
1425 FALSE );
1426 #ifdef __REACTOS__
1427 free(&counterHintMap);
1428 #endif
1429 }
1430 break;
1431
1432 case cf2_cmdRMOVETO:
1433 FT_TRACE4(( " rmoveto\n" ));
1434
1435 if ( cf2_stack_count( opStack ) > 2 && !haveWidth )
1436 *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
1437
1438 /* width is defined or default after this */
1439 haveWidth = TRUE;
1440
1441 if ( font->decoder->width_only )
1442 goto exit;
1443
1444 curY += cf2_stack_popFixed( opStack );
1445 curX += cf2_stack_popFixed( opStack );
1446
1447 cf2_glyphpath_moveTo( &glyphPath, curX, curY );
1448
1449 break;
1450
1451 case cf2_cmdHMOVETO:
1452 FT_TRACE4(( " hmoveto\n" ));
1453
1454 if ( cf2_stack_count( opStack ) > 1 && !haveWidth )
1455 *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
1456
1457 /* width is defined or default after this */
1458 haveWidth = TRUE;
1459
1460 if ( font->decoder->width_only )
1461 goto exit;
1462
1463 curX += cf2_stack_popFixed( opStack );
1464
1465 cf2_glyphpath_moveTo( &glyphPath, curX, curY );
1466
1467 break;
1468
1469 case cf2_cmdRLINECURVE:
1470 {
1471 CF2_UInt count = cf2_stack_count( opStack );
1472 CF2_UInt index = 0;
1473
1474
1475 FT_TRACE4(( " rlinecurve\n" ));
1476
1477 while ( index + 6 < count )
1478 {
1479 curX += cf2_stack_getReal( opStack, index + 0 );
1480 curY += cf2_stack_getReal( opStack, index + 1 );
1481
1482 cf2_glyphpath_lineTo( &glyphPath, curX, curY );
1483 index += 2;
1484 }
1485
1486 while ( index < count )
1487 {
1488 CF2_Fixed x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
1489 CF2_Fixed y1 = cf2_stack_getReal( opStack, index + 1 ) + curY;
1490 CF2_Fixed x2 = cf2_stack_getReal( opStack, index + 2 ) + x1;
1491 CF2_Fixed y2 = cf2_stack_getReal( opStack, index + 3 ) + y1;
1492 CF2_Fixed x3 = cf2_stack_getReal( opStack, index + 4 ) + x2;
1493 CF2_Fixed y3 = cf2_stack_getReal( opStack, index + 5 ) + y2;
1494
1495
1496 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1497
1498 curX = x3;
1499 curY = y3;
1500 index += 6;
1501 }
1502
1503 cf2_stack_clear( opStack );
1504 }
1505 continue; /* no need to clear stack again */
1506
1507 case cf2_cmdVVCURVETO:
1508 {
1509 CF2_UInt count, count1 = cf2_stack_count( opStack );
1510 CF2_UInt index = 0;
1511
1512
1513 /* if `cf2_stack_count' isn't of the form 4n or 4n+1, */
1514 /* we enforce it by clearing the second bit */
1515 /* (and sorting the stack indexing to suit) */
1516 count = count1 & ~2U;
1517 index += count1 - count;
1518
1519 FT_TRACE4(( " vvcurveto\n" ));
1520
1521 while ( index < count )
1522 {
1523 CF2_Fixed x1, y1, x2, y2, x3, y3;
1524
1525
1526 if ( ( count - index ) & 1 )
1527 {
1528 x1 = cf2_stack_getReal( opStack, index ) + curX;
1529
1530 ++index;
1531 }
1532 else
1533 x1 = curX;
1534
1535 y1 = cf2_stack_getReal( opStack, index + 0 ) + curY;
1536 x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1537 y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1538 x3 = x2;
1539 y3 = cf2_stack_getReal( opStack, index + 3 ) + y2;
1540
1541 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1542
1543 curX = x3;
1544 curY = y3;
1545 index += 4;
1546 }
1547
1548 cf2_stack_clear( opStack );
1549 }
1550 continue; /* no need to clear stack again */
1551
1552 case cf2_cmdHHCURVETO:
1553 {
1554 CF2_UInt count, count1 = cf2_stack_count( opStack );
1555 CF2_UInt index = 0;
1556
1557
1558 /* if `cf2_stack_count' isn't of the form 4n or 4n+1, */
1559 /* we enforce it by clearing the second bit */
1560 /* (and sorting the stack indexing to suit) */
1561 count = count1 & ~2U;
1562 index += count1 - count;
1563
1564 FT_TRACE4(( " hhcurveto\n" ));
1565
1566 while ( index < count )
1567 {
1568 CF2_Fixed x1, y1, x2, y2, x3, y3;
1569
1570
1571 if ( ( count - index ) & 1 )
1572 {
1573 y1 = cf2_stack_getReal( opStack, index ) + curY;
1574
1575 ++index;
1576 }
1577 else
1578 y1 = curY;
1579
1580 x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
1581 x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1582 y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1583 x3 = cf2_stack_getReal( opStack, index + 3 ) + x2;
1584 y3 = y2;
1585
1586 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1587
1588 curX = x3;
1589 curY = y3;
1590 index += 4;
1591 }
1592
1593 cf2_stack_clear( opStack );
1594 }
1595 continue; /* no need to clear stack again */
1596
1597 case cf2_cmdVHCURVETO:
1598 case cf2_cmdHVCURVETO:
1599 {
1600 CF2_UInt count, count1 = cf2_stack_count( opStack );
1601 CF2_UInt index = 0;
1602
1603 FT_Bool alternate = op1 == cf2_cmdHVCURVETO;
1604
1605
1606 /* if `cf2_stack_count' isn't of the form 8n, 8n+1, */
1607 /* 8n+4, or 8n+5, we enforce it by clearing the */
1608 /* second bit */
1609 /* (and sorting the stack indexing to suit) */
1610 count = count1 & ~2U;
1611 index += count1 - count;
1612
1613 FT_TRACE4(( alternate ? " hvcurveto\n" : " vhcurveto\n" ));
1614
1615 while ( index < count )
1616 {
1617 CF2_Fixed x1, x2, x3, y1, y2, y3;
1618
1619
1620 if ( alternate )
1621 {
1622 x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
1623 y1 = curY;
1624 x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1625 y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1626 y3 = cf2_stack_getReal( opStack, index + 3 ) + y2;
1627
1628 if ( count - index == 5 )
1629 {
1630 x3 = cf2_stack_getReal( opStack, index + 4 ) + x2;
1631
1632 ++index;
1633 }
1634 else
1635 x3 = x2;
1636
1637 alternate = FALSE;
1638 }
1639 else
1640 {
1641 x1 = curX;
1642 y1 = cf2_stack_getReal( opStack, index + 0 ) + curY;
1643 x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1644 y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1645 x3 = cf2_stack_getReal( opStack, index + 3 ) + x2;
1646
1647 if ( count - index == 5 )
1648 {
1649 y3 = cf2_stack_getReal( opStack, index + 4 ) + y2;
1650
1651 ++index;
1652 }
1653 else
1654 y3 = y2;
1655
1656 alternate = TRUE;
1657 }
1658
1659 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1660
1661 curX = x3;
1662 curY = y3;
1663 index += 4;
1664 }
1665
1666 cf2_stack_clear( opStack );
1667 }
1668 continue; /* no need to clear stack again */
1669
1670 case cf2_cmdEXTENDEDNMBR:
1671 {
1672 CF2_Int v;
1673
1674 CF2_Int byte1 = cf2_buf_readByte( charstring );
1675 CF2_Int byte2 = cf2_buf_readByte( charstring );
1676
1677
1678 v = (FT_Short)( ( byte1 << 8 ) |
1679 byte2 );
1680
1681 FT_TRACE4(( " %d", v ));
1682
1683 cf2_stack_pushInt( opStack, v );
1684 }
1685 continue;
1686
1687 default:
1688 /* numbers */
1689 {
1690 if ( /* op1 >= 32 && */ op1 <= 246 )
1691 {
1692 CF2_Int v;
1693
1694
1695 v = op1 - 139;
1696
1697 FT_TRACE4(( " %d", v ));
1698
1699 /* -107 .. 107 */
1700 cf2_stack_pushInt( opStack, v );
1701 }
1702
1703 else if ( /* op1 >= 247 && */ op1 <= 250 )
1704 {
1705 CF2_Int v;
1706
1707
1708 v = op1;
1709 v -= 247;
1710 v *= 256;
1711 v += cf2_buf_readByte( charstring );
1712 v += 108;
1713
1714 FT_TRACE4(( " %d", v ));
1715
1716 /* 108 .. 1131 */
1717 cf2_stack_pushInt( opStack, v );
1718 }
1719
1720 else if ( /* op1 >= 251 && */ op1 <= 254 )
1721 {
1722 CF2_Int v;
1723
1724
1725 v = op1;
1726 v -= 251;
1727 v *= 256;
1728 v += cf2_buf_readByte( charstring );
1729 v = -v - 108;
1730
1731 FT_TRACE4(( " %d", v ));
1732
1733 /* -1131 .. -108 */
1734 cf2_stack_pushInt( opStack, v );
1735 }
1736
1737 else /* op1 == 255 */
1738 {
1739 CF2_Fixed v;
1740
1741 FT_UInt32 byte1 = (FT_UInt32)cf2_buf_readByte( charstring );
1742 FT_UInt32 byte2 = (FT_UInt32)cf2_buf_readByte( charstring );
1743 FT_UInt32 byte3 = (FT_UInt32)cf2_buf_readByte( charstring );
1744 FT_UInt32 byte4 = (FT_UInt32)cf2_buf_readByte( charstring );
1745
1746
1747 v = (CF2_Fixed)( ( byte1 << 24 ) |
1748 ( byte2 << 16 ) |
1749 ( byte3 << 8 ) |
1750 byte4 );
1751
1752 FT_TRACE4(( " %.2f", v / 65536.0 ));
1753
1754 cf2_stack_pushFixed( opStack, v );
1755 }
1756 }
1757 continue; /* don't clear stack */
1758
1759 } /* end of switch statement checking `op1' */
1760
1761 cf2_stack_clear( opStack );
1762
1763 } /* end of main interpreter loop */
1764
1765 /* we get here if the charstring ends without cf2_cmdENDCHAR */
1766 FT_TRACE4(( "cf2_interpT2CharString:"
1767 " charstring ends without ENDCHAR\n" ));
1768
1769 exit:
1770 /* check whether last error seen is also the first one */
1771 cf2_setError( error, lastError );
1772
1773 /* free resources from objects we've used */
1774 cf2_glyphpath_finalize( &glyphPath );
1775 cf2_arrstack_finalize( &vStemHintArray );
1776 cf2_arrstack_finalize( &hStemHintArray );
1777 cf2_arrstack_finalize( &subrStack );
1778 cf2_stack_free( opStack );
1779
1780 FT_TRACE4(( "\n" ));
1781
1782 #ifdef __REACTOS__
1783 free(&glyphPath);
1784 #undef counterHintMap
1785 #undef glyphPath
1786 #endif
1787
1788 return;
1789 }
1790
1791
1792 /* END */