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