• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 )
cf2_hintmask_init(CF2_HintMask hintmask,FT_Error * error)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 )
cf2_hintmask_isValid(const CF2_HintMask hintmask)78   cf2_hintmask_isValid( const CF2_HintMask  hintmask )
79   {
80     return hintmask->isValid;
81   }
82 
83 
84   FT_LOCAL_DEF( FT_Bool )
cf2_hintmask_isNew(const CF2_HintMask hintmask)85   cf2_hintmask_isNew( const CF2_HintMask  hintmask )
86   {
87     return hintmask->isNew;
88   }
89 
90 
91   FT_LOCAL_DEF( void )
cf2_hintmask_setNew(CF2_HintMask hintmask,FT_Bool val)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* )
cf2_hintmask_getMaskPtr(CF2_HintMask hintmask)103   cf2_hintmask_getMaskPtr( CF2_HintMask  hintmask )
104   {
105     return hintmask->mask;
106   }
107 
108 
109   static size_t
cf2_hintmask_setCounts(CF2_HintMask hintmask,size_t bitCount)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
cf2_hintmask_read(CF2_HintMask hintmask,CF2_Buffer charstring,size_t bitCount)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 )
cf2_hintmask_setAll(CF2_HintMask hintmask,size_t bitCount)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
cf2_doStems(const CF2_Font font,CF2_Stack opStack,CF2_ArrStack stemHintArray,CF2_Fixed * width,FT_Bool * haveWidth,CF2_Fixed hintOffset)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
cf2_doFlex(CF2_Stack opStack,CF2_Fixed * curX,CF2_Fixed * curY,CF2_GlyphPath glyphPath,const FT_Bool * readFromStack,FT_Bool doConditionalLastRead)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 )
cf2_interpT2CharString(CF2_Font font,CF2_Buffer buf,CF2_OutlineCallbacks callbacks,const FT_Vector * translation,FT_Bool doingSeac,CF2_Fixed curX,CF2_Fixed curY,CF2_Fixed * width)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     CF2_GlyphPathRec  glyphPath;
470 
471 
472     FT_ZERO( &storage );
473 
474     /* initialize the remaining objects */
475     cf2_arrstack_init( &subrStack,
476                        memory,
477                        error,
478                        sizeof ( CF2_BufferRec ) );
479     cf2_arrstack_init( &hStemHintArray,
480                        memory,
481                        error,
482                        sizeof ( CF2_StemHintRec ) );
483     cf2_arrstack_init( &vStemHintArray,
484                        memory,
485                        error,
486                        sizeof ( CF2_StemHintRec ) );
487 
488     /* initialize CF2_StemHint arrays */
489     cf2_hintmask_init( &hintMask, error );
490 
491     /* initialize path map to manage drawing operations */
492 
493     /* Note: last 4 params are used to handle `MoveToPermissive', which */
494     /*       may need to call `hintMap.Build'                           */
495     /* TODO: MoveToPermissive is gone; are these still needed?          */
496     cf2_glyphpath_init( &glyphPath,
497                         font,
498                         callbacks,
499                         scaleY,
500                         /* hShift, */
501                         &hStemHintArray,
502                         &vStemHintArray,
503                         &hintMask,
504                         hintOriginY,
505                         &font->blues,
506                         translation );
507 
508     /*
509      * Initialize state for width parsing.  From the CFF Spec:
510      *
511      *   The first stack-clearing operator, which must be one of hstem,
512      *   hstemhm, vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto,
513      *   rmoveto, or endchar, takes an additional argument - the width (as
514      *   described earlier), which may be expressed as zero or one numeric
515      *   argument.
516      *
517      * What we implement here uses the first validly specified width, but
518      * does not detect errors for specifying more than one width.
519      *
520      * If one of the above operators occurs without explicitly specifying
521      * a width, we assume the default width.
522      *
523      */
524     haveWidth = FALSE;
525     *width    = cf2_getDefaultWidthX( decoder );
526 
527     /*
528      * Note: at this point, all pointers to resources must be NULL
529      * and all local objects must be initialized.
530      * There must be no branches to exit: above this point.
531      *
532      */
533 
534     /* allocate an operand stack */
535     opStack = cf2_stack_init( memory, error );
536     if ( !opStack )
537     {
538       lastError = FT_THROW( Out_Of_Memory );
539       goto exit;
540     }
541 
542     /* initialize subroutine stack by placing top level charstring as */
543     /* first element (max depth plus one for the charstring)          */
544     /* Note: Caller owns and must finalize the first charstring.      */
545     /*       Our copy of it does not change that requirement.         */
546     cf2_arrstack_setCount( &subrStack, CF2_MAX_SUBR + 1 );
547 
548     charstring  = (CF2_Buffer)cf2_arrstack_getBuffer( &subrStack );
549     *charstring = *buf;    /* structure copy */
550 
551     charstringIndex = 0;       /* entry is valid now */
552 
553     /* catch errors so far */
554     if ( *error )
555       goto exit;
556 
557     /* main interpreter loop */
558     while ( 1 )
559     {
560       if ( cf2_buf_isEnd( charstring ) )
561       {
562         /* If we've reached the end of the charstring, simulate a */
563         /* cf2_cmdRETURN or cf2_cmdENDCHAR.                       */
564         if ( charstringIndex )
565           op1 = cf2_cmdRETURN;  /* end of buffer for subroutine */
566         else
567           op1 = cf2_cmdENDCHAR; /* end of buffer for top level charstring */
568       }
569       else
570         op1 = (FT_Byte)cf2_buf_readByte( charstring );
571 
572       /* check for errors once per loop */
573       if ( *error )
574         goto exit;
575 
576       instructionLimit--;
577       if ( instructionLimit == 0 )
578       {
579         lastError = FT_THROW( Invalid_Glyph_Format );
580         goto exit;
581       }
582 
583       switch( op1 )
584       {
585       case cf2_cmdRESERVED_0:
586       case cf2_cmdRESERVED_2:
587       case cf2_cmdRESERVED_9:
588       case cf2_cmdRESERVED_13:
589       case cf2_cmdRESERVED_15:
590       case cf2_cmdRESERVED_16:
591       case cf2_cmdRESERVED_17:
592         /* we may get here if we have a prior error */
593         FT_TRACE4(( " unknown op (%d)\n", op1 ));
594         break;
595 
596       case cf2_cmdHSTEMHM:
597       case cf2_cmdHSTEM:
598         FT_TRACE4(( op1 == cf2_cmdHSTEMHM ? " hstemhm\n" : " hstem\n" ));
599 
600         /* never add hints after the mask is computed */
601         if ( cf2_hintmask_isValid( &hintMask ) )
602         {
603           FT_TRACE4(( "cf2_interpT2CharString:"
604                       " invalid horizontal hint mask\n" ));
605           break;
606         }
607 
608         cf2_doStems( font,
609                      opStack,
610                      &hStemHintArray,
611                      width,
612                      &haveWidth,
613                      0 );
614 
615         if ( font->decoder->width_only )
616           goto exit;
617 
618         break;
619 
620       case cf2_cmdVSTEMHM:
621       case cf2_cmdVSTEM:
622         FT_TRACE4(( op1 == cf2_cmdVSTEMHM ? " vstemhm\n" : " vstem\n" ));
623 
624         /* never add hints after the mask is computed */
625         if ( cf2_hintmask_isValid( &hintMask ) )
626         {
627           FT_TRACE4(( "cf2_interpT2CharString:"
628                       " invalid vertical hint mask\n" ));
629           break;
630         }
631 
632         cf2_doStems( font,
633                      opStack,
634                      &vStemHintArray,
635                      width,
636                      &haveWidth,
637                      0 );
638 
639         if ( font->decoder->width_only )
640           goto exit;
641 
642         break;
643 
644       case cf2_cmdVMOVETO:
645         FT_TRACE4(( " vmoveto\n" ));
646 
647         if ( cf2_stack_count( opStack ) > 1 && !haveWidth )
648           *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
649 
650         /* width is defined or default after this */
651         haveWidth = TRUE;
652 
653         if ( font->decoder->width_only )
654           goto exit;
655 
656         curY += cf2_stack_popFixed( opStack );
657 
658         cf2_glyphpath_moveTo( &glyphPath, curX, curY );
659 
660         break;
661 
662       case cf2_cmdRLINETO:
663         {
664           CF2_UInt  index;
665           CF2_UInt  count = cf2_stack_count( opStack );
666 
667 
668           FT_TRACE4(( " rlineto\n" ));
669 
670           for ( index = 0; index < count; index += 2 )
671           {
672             curX += cf2_stack_getReal( opStack, index + 0 );
673             curY += cf2_stack_getReal( opStack, index + 1 );
674 
675             cf2_glyphpath_lineTo( &glyphPath, curX, curY );
676           }
677 
678           cf2_stack_clear( opStack );
679         }
680         continue; /* no need to clear stack again */
681 
682       case cf2_cmdHLINETO:
683       case cf2_cmdVLINETO:
684         {
685           CF2_UInt  index;
686           CF2_UInt  count = cf2_stack_count( opStack );
687 
688           FT_Bool  isX = op1 == cf2_cmdHLINETO;
689 
690 
691           FT_TRACE4(( isX ? " hlineto\n" : " vlineto\n" ));
692 
693           for ( index = 0; index < count; index++ )
694           {
695             CF2_Fixed  v = cf2_stack_getReal( opStack, index );
696 
697 
698             if ( isX )
699               curX += v;
700             else
701               curY += v;
702 
703             isX = !isX;
704 
705             cf2_glyphpath_lineTo( &glyphPath, curX, curY );
706           }
707 
708           cf2_stack_clear( opStack );
709         }
710         continue;
711 
712       case cf2_cmdRCURVELINE:
713       case cf2_cmdRRCURVETO:
714         {
715           CF2_UInt  count = cf2_stack_count( opStack );
716           CF2_UInt  index = 0;
717 
718 
719           FT_TRACE4(( op1 == cf2_cmdRCURVELINE ? " rcurveline\n"
720                                                : " rrcurveto\n" ));
721 
722           while ( index + 6 <= count )
723           {
724             CF2_Fixed  x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
725             CF2_Fixed  y1 = cf2_stack_getReal( opStack, index + 1 ) + curY;
726             CF2_Fixed  x2 = cf2_stack_getReal( opStack, index + 2 ) + x1;
727             CF2_Fixed  y2 = cf2_stack_getReal( opStack, index + 3 ) + y1;
728             CF2_Fixed  x3 = cf2_stack_getReal( opStack, index + 4 ) + x2;
729             CF2_Fixed  y3 = cf2_stack_getReal( opStack, index + 5 ) + y2;
730 
731 
732             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
733 
734             curX   = x3;
735             curY   = y3;
736             index += 6;
737           }
738 
739           if ( op1 == cf2_cmdRCURVELINE )
740           {
741             curX += cf2_stack_getReal( opStack, index + 0 );
742             curY += cf2_stack_getReal( opStack, index + 1 );
743 
744             cf2_glyphpath_lineTo( &glyphPath, curX, curY );
745           }
746 
747           cf2_stack_clear( opStack );
748         }
749         continue; /* no need to clear stack again */
750 
751       case cf2_cmdCALLGSUBR:
752       case cf2_cmdCALLSUBR:
753         {
754           CF2_Int  subrNum;
755 
756 
757           FT_TRACE4(( op1 == cf2_cmdCALLGSUBR ? " callgsubr"
758                                               : " callsubr" ));
759 
760           if ( charstringIndex > CF2_MAX_SUBR )
761           {
762             /* max subr plus one for charstring */
763             lastError = FT_THROW( Invalid_Glyph_Format );
764             goto exit;                      /* overflow of stack */
765           }
766 
767           /* push our current CFF charstring region on subrStack */
768           charstring = (CF2_Buffer)
769                          cf2_arrstack_getPointer(
770                            &subrStack,
771                            (size_t)charstringIndex + 1 );
772 
773           /* set up the new CFF region and pointer */
774           subrNum = cf2_stack_popInt( opStack );
775 
776           switch ( op1 )
777           {
778           case cf2_cmdCALLGSUBR:
779             FT_TRACE4(( " (idx %d, entering level %d)\n",
780                         subrNum + decoder->globals_bias,
781                         charstringIndex + 1 ));
782 
783             if ( cf2_initGlobalRegionBuffer( decoder,
784                                              subrNum,
785                                              charstring ) )
786             {
787               lastError = FT_THROW( Invalid_Glyph_Format );
788               goto exit;  /* subroutine lookup or stream error */
789             }
790             break;
791 
792           default:
793             /* cf2_cmdCALLSUBR */
794             FT_TRACE4(( " (idx %d, entering level %d)\n",
795                         subrNum + decoder->locals_bias,
796                         charstringIndex + 1 ));
797 
798             if ( cf2_initLocalRegionBuffer( decoder,
799                                             subrNum,
800                                             charstring ) )
801             {
802               lastError = FT_THROW( Invalid_Glyph_Format );
803               goto exit;  /* subroutine lookup or stream error */
804             }
805           }
806 
807           charstringIndex += 1;       /* entry is valid now */
808         }
809         continue; /* do not clear the stack */
810 
811       case cf2_cmdRETURN:
812         FT_TRACE4(( " return (leaving level %d)\n", charstringIndex ));
813 
814         if ( charstringIndex < 1 )
815         {
816           /* Note: cannot return from top charstring */
817           lastError = FT_THROW( Invalid_Glyph_Format );
818           goto exit;                      /* underflow of stack */
819         }
820 
821         /* restore position in previous charstring */
822         charstring = (CF2_Buffer)
823                        cf2_arrstack_getPointer(
824                          &subrStack,
825                          (CF2_UInt)--charstringIndex );
826         continue;     /* do not clear the stack */
827 
828       case cf2_cmdESC:
829         {
830           FT_Byte  op2 = (FT_Byte)cf2_buf_readByte( charstring );
831 
832 
833           switch ( op2 )
834           {
835           case cf2_escDOTSECTION:
836             /* something about `flip type of locking' -- ignore it */
837             FT_TRACE4(( " dotsection\n" ));
838 
839             break;
840 
841           case cf2_escAND:
842             {
843               CF2_F16Dot16  arg1;
844               CF2_F16Dot16  arg2;
845 
846 
847               FT_TRACE4(( " and\n" ));
848 
849               arg2 = cf2_stack_popFixed( opStack );
850               arg1 = cf2_stack_popFixed( opStack );
851 
852               cf2_stack_pushInt( opStack, arg1 && arg2 );
853             }
854             continue; /* do not clear the stack */
855 
856           case cf2_escOR:
857             {
858               CF2_F16Dot16  arg1;
859               CF2_F16Dot16  arg2;
860 
861 
862               FT_TRACE4(( " or\n" ));
863 
864               arg2 = cf2_stack_popFixed( opStack );
865               arg1 = cf2_stack_popFixed( opStack );
866 
867               cf2_stack_pushInt( opStack, arg1 || arg2 );
868             }
869             continue; /* do not clear the stack */
870 
871           case cf2_escNOT:
872             {
873               CF2_F16Dot16  arg;
874 
875 
876               FT_TRACE4(( " not\n" ));
877 
878               arg = cf2_stack_popFixed( opStack );
879 
880               cf2_stack_pushInt( opStack, !arg );
881             }
882             continue; /* do not clear the stack */
883 
884           case cf2_escABS:
885             {
886               CF2_F16Dot16  arg;
887 
888 
889               FT_TRACE4(( " abs\n" ));
890 
891               arg = cf2_stack_popFixed( opStack );
892 
893               cf2_stack_pushFixed( opStack, FT_ABS( arg ) );
894             }
895             continue; /* do not clear the stack */
896 
897           case cf2_escADD:
898             {
899               CF2_F16Dot16  summand1;
900               CF2_F16Dot16  summand2;
901 
902 
903               FT_TRACE4(( " add\n" ));
904 
905               summand2 = cf2_stack_popFixed( opStack );
906               summand1 = cf2_stack_popFixed( opStack );
907 
908               cf2_stack_pushFixed( opStack, summand1 + summand2 );
909             }
910             continue; /* do not clear the stack */
911 
912           case cf2_escSUB:
913             {
914               CF2_F16Dot16  minuend;
915               CF2_F16Dot16  subtrahend;
916 
917 
918               FT_TRACE4(( " sub\n" ));
919 
920               subtrahend = cf2_stack_popFixed( opStack );
921               minuend    = cf2_stack_popFixed( opStack );
922 
923               cf2_stack_pushFixed( opStack, minuend - subtrahend );
924             }
925             continue; /* do not clear the stack */
926 
927           case cf2_escDIV:
928             {
929               CF2_F16Dot16  dividend;
930               CF2_F16Dot16  divisor;
931 
932 
933               FT_TRACE4(( " div\n" ));
934 
935               divisor  = cf2_stack_popFixed( opStack );
936               dividend = cf2_stack_popFixed( opStack );
937 
938               cf2_stack_pushFixed( opStack, FT_DivFix( dividend, divisor ) );
939             }
940             continue; /* do not clear the stack */
941 
942           case cf2_escNEG:
943             {
944               CF2_F16Dot16  arg;
945 
946 
947               FT_TRACE4(( " neg\n" ));
948 
949               arg = cf2_stack_popFixed( opStack );
950 
951               cf2_stack_pushFixed( opStack, -arg );
952             }
953             continue; /* do not clear the stack */
954 
955           case cf2_escEQ:
956             {
957               CF2_F16Dot16  arg1;
958               CF2_F16Dot16  arg2;
959 
960 
961               FT_TRACE4(( " eq\n" ));
962 
963               arg2 = cf2_stack_popFixed( opStack );
964               arg1 = cf2_stack_popFixed( opStack );
965 
966               cf2_stack_pushInt( opStack, arg1 == arg2 );
967             }
968             continue; /* do not clear the stack */
969 
970           case cf2_escDROP:
971             FT_TRACE4(( " drop\n" ));
972 
973             (void)cf2_stack_popFixed( opStack );
974             continue; /* do not clear the stack */
975 
976           case cf2_escPUT:
977             {
978               CF2_F16Dot16  val;
979               CF2_Int       idx;
980 
981 
982               FT_TRACE4(( " put\n" ));
983 
984               idx = cf2_stack_popInt( opStack );
985               val = cf2_stack_popFixed( opStack );
986 
987               if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
988                 storage[idx] = val;
989             }
990             continue; /* do not clear the stack */
991 
992           case cf2_escGET:
993             {
994               CF2_Int  idx;
995 
996 
997               FT_TRACE4(( " get\n" ));
998 
999               idx = cf2_stack_popInt( opStack );
1000 
1001               if ( idx >= 0 && idx < CF2_STORAGE_SIZE )
1002                 cf2_stack_pushFixed( opStack, storage[idx] );
1003             }
1004             continue; /* do not clear the stack */
1005 
1006           case cf2_escIFELSE:
1007             {
1008               CF2_F16Dot16  arg1;
1009               CF2_F16Dot16  arg2;
1010               CF2_F16Dot16  cond1;
1011               CF2_F16Dot16  cond2;
1012 
1013 
1014               FT_TRACE4(( " ifelse\n" ));
1015 
1016               cond2 = cf2_stack_popFixed( opStack );
1017               cond1 = cf2_stack_popFixed( opStack );
1018               arg2  = cf2_stack_popFixed( opStack );
1019               arg1  = cf2_stack_popFixed( opStack );
1020 
1021               cf2_stack_pushFixed( opStack, cond1 <= cond2 ? arg1 : arg2 );
1022             }
1023             continue; /* do not clear the stack */
1024 
1025           case cf2_escRANDOM: /* in spec */
1026             FT_TRACE4(( " random\n" ));
1027 
1028             CF2_FIXME;
1029             break;
1030 
1031           case cf2_escMUL:
1032             {
1033               CF2_F16Dot16  factor1;
1034               CF2_F16Dot16  factor2;
1035 
1036 
1037               FT_TRACE4(( " mul\n" ));
1038 
1039               factor2 = cf2_stack_popFixed( opStack );
1040               factor1 = cf2_stack_popFixed( opStack );
1041 
1042               cf2_stack_pushFixed( opStack, FT_MulFix( factor1, factor2 ) );
1043             }
1044             continue; /* do not clear the stack */
1045 
1046           case cf2_escSQRT:
1047             {
1048               CF2_F16Dot16  arg;
1049 
1050 
1051               FT_TRACE4(( " sqrt\n" ));
1052 
1053               arg = cf2_stack_popFixed( opStack );
1054               if ( arg > 0 )
1055               {
1056                 FT_Fixed  root = arg;
1057                 FT_Fixed  new_root;
1058 
1059 
1060                 /* Babylonian method */
1061                 for (;;)
1062                 {
1063                   new_root = ( root + FT_DivFix( arg, root ) + 1 ) >> 1;
1064                   if ( new_root == root )
1065                     break;
1066                   root = new_root;
1067                 }
1068                 arg = new_root;
1069               }
1070               else
1071                 arg = 0;
1072 
1073               cf2_stack_pushFixed( opStack, arg );
1074             }
1075             continue; /* do not clear the stack */
1076 
1077           case cf2_escDUP:
1078             {
1079               CF2_F16Dot16  arg;
1080 
1081 
1082               FT_TRACE4(( " dup\n" ));
1083 
1084               arg = cf2_stack_popFixed( opStack );
1085 
1086               cf2_stack_pushFixed( opStack, arg );
1087               cf2_stack_pushFixed( opStack, arg );
1088             }
1089             continue; /* do not clear the stack */
1090 
1091           case cf2_escEXCH:
1092             {
1093               CF2_F16Dot16  arg1;
1094               CF2_F16Dot16  arg2;
1095 
1096 
1097               FT_TRACE4(( " exch\n" ));
1098 
1099               arg2 = cf2_stack_popFixed( opStack );
1100               arg1 = cf2_stack_popFixed( opStack );
1101 
1102               cf2_stack_pushFixed( opStack, arg2 );
1103               cf2_stack_pushFixed( opStack, arg1 );
1104             }
1105             continue; /* do not clear the stack */
1106 
1107           case cf2_escINDEX:
1108             {
1109               CF2_Int   idx;
1110               CF2_UInt  size;
1111 
1112 
1113               FT_TRACE4(( " index\n" ));
1114 
1115               idx  = cf2_stack_popInt( opStack );
1116               size = cf2_stack_count( opStack );
1117 
1118               if ( size > 0 )
1119               {
1120                 /* for `cf2_stack_getReal', index 0 is bottom of stack */
1121                 CF2_UInt  gr_idx;
1122 
1123 
1124                 if ( idx < 0 )
1125                   gr_idx = size - 1;
1126                 else if ( (CF2_UInt)idx >= size )
1127                   gr_idx = 0;
1128                 else
1129                   gr_idx = size - 1 - (CF2_UInt)idx;
1130 
1131                 cf2_stack_pushFixed( opStack,
1132                                      cf2_stack_getReal( opStack, gr_idx ) );
1133               }
1134             }
1135             continue; /* do not clear the stack */
1136 
1137           case cf2_escROLL:
1138             {
1139               CF2_Int  idx;
1140               CF2_Int  count;
1141 
1142 
1143               FT_TRACE4(( " roll\n" ));
1144 
1145               idx   = cf2_stack_popInt( opStack );
1146               count = cf2_stack_popInt( opStack );
1147 
1148               cf2_stack_roll( opStack, count, idx );
1149             }
1150             continue; /* do not clear the stack */
1151 
1152           case cf2_escHFLEX:
1153             {
1154               static const FT_Bool  readFromStack[12] =
1155               {
1156                 TRUE /* dx1 */, FALSE /* dy1 */,
1157                 TRUE /* dx2 */, TRUE  /* dy2 */,
1158                 TRUE /* dx3 */, FALSE /* dy3 */,
1159                 TRUE /* dx4 */, FALSE /* dy4 */,
1160                 TRUE /* dx5 */, FALSE /* dy5 */,
1161                 TRUE /* dx6 */, FALSE /* dy6 */
1162               };
1163 
1164 
1165               FT_TRACE4(( " hflex\n" ));
1166 
1167               cf2_doFlex( opStack,
1168                           &curX,
1169                           &curY,
1170                           &glyphPath,
1171                           readFromStack,
1172                           FALSE /* doConditionalLastRead */ );
1173             }
1174             continue;
1175 
1176           case cf2_escFLEX:
1177             {
1178               static const FT_Bool  readFromStack[12] =
1179               {
1180                 TRUE /* dx1 */, TRUE /* dy1 */,
1181                 TRUE /* dx2 */, TRUE /* dy2 */,
1182                 TRUE /* dx3 */, TRUE /* dy3 */,
1183                 TRUE /* dx4 */, TRUE /* dy4 */,
1184                 TRUE /* dx5 */, TRUE /* dy5 */,
1185                 TRUE /* dx6 */, TRUE /* dy6 */
1186               };
1187 
1188 
1189               FT_TRACE4(( " flex\n" ));
1190 
1191               cf2_doFlex( opStack,
1192                           &curX,
1193                           &curY,
1194                           &glyphPath,
1195                           readFromStack,
1196                           FALSE /* doConditionalLastRead */ );
1197             }
1198             break;      /* TODO: why is this not a continue? */
1199 
1200           case cf2_escHFLEX1:
1201             {
1202               static const FT_Bool  readFromStack[12] =
1203               {
1204                 TRUE /* dx1 */, TRUE  /* dy1 */,
1205                 TRUE /* dx2 */, TRUE  /* dy2 */,
1206                 TRUE /* dx3 */, FALSE /* dy3 */,
1207                 TRUE /* dx4 */, FALSE /* dy4 */,
1208                 TRUE /* dx5 */, TRUE  /* dy5 */,
1209                 TRUE /* dx6 */, FALSE /* dy6 */
1210               };
1211 
1212 
1213               FT_TRACE4(( " hflex1\n" ));
1214 
1215               cf2_doFlex( opStack,
1216                           &curX,
1217                           &curY,
1218                           &glyphPath,
1219                           readFromStack,
1220                           FALSE /* doConditionalLastRead */ );
1221             }
1222             continue;
1223 
1224           case cf2_escFLEX1:
1225             {
1226               static const FT_Bool  readFromStack[12] =
1227               {
1228                 TRUE  /* dx1 */, TRUE  /* dy1 */,
1229                 TRUE  /* dx2 */, TRUE  /* dy2 */,
1230                 TRUE  /* dx3 */, TRUE  /* dy3 */,
1231                 TRUE  /* dx4 */, TRUE  /* dy4 */,
1232                 TRUE  /* dx5 */, TRUE  /* dy5 */,
1233                 FALSE /* dx6 */, FALSE /* dy6 */
1234               };
1235 
1236 
1237               FT_TRACE4(( " flex1\n" ));
1238 
1239               cf2_doFlex( opStack,
1240                           &curX,
1241                           &curY,
1242                           &glyphPath,
1243                           readFromStack,
1244                           TRUE /* doConditionalLastRead */ );
1245             }
1246             continue;
1247 
1248           case cf2_escRESERVED_1:
1249           case cf2_escRESERVED_2:
1250           case cf2_escRESERVED_6:
1251           case cf2_escRESERVED_7:
1252           case cf2_escRESERVED_8:
1253           case cf2_escRESERVED_13:
1254           case cf2_escRESERVED_16:
1255           case cf2_escRESERVED_17:
1256           case cf2_escRESERVED_19:
1257           case cf2_escRESERVED_25:
1258           case cf2_escRESERVED_31:
1259           case cf2_escRESERVED_32:
1260           case cf2_escRESERVED_33:
1261           default:
1262             FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
1263 
1264           }; /* end of switch statement checking `op2' */
1265 
1266         } /* case cf2_cmdESC */
1267         break;
1268 
1269       case cf2_cmdENDCHAR:
1270         FT_TRACE4(( " endchar\n" ));
1271 
1272         if ( cf2_stack_count( opStack ) == 1 ||
1273              cf2_stack_count( opStack ) == 5 )
1274         {
1275           if ( !haveWidth )
1276             *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
1277         }
1278 
1279         /* width is defined or default after this */
1280         haveWidth = TRUE;
1281 
1282         if ( font->decoder->width_only )
1283           goto exit;
1284 
1285         /* close path if still open */
1286         cf2_glyphpath_closeOpenPath( &glyphPath );
1287 
1288         if ( cf2_stack_count( opStack ) > 1 )
1289         {
1290           /* must be either 4 or 5 --                       */
1291           /* this is a (deprecated) implied `seac' operator */
1292 
1293           CF2_Int        achar;
1294           CF2_Int        bchar;
1295           CF2_BufferRec  component;
1296           CF2_Fixed      dummyWidth;   /* ignore component width */
1297           FT_Error       error2;
1298 
1299 
1300           if ( doingSeac )
1301           {
1302             lastError = FT_THROW( Invalid_Glyph_Format );
1303             goto exit;      /* nested seac */
1304           }
1305 
1306           achar = cf2_stack_popInt( opStack );
1307           bchar = cf2_stack_popInt( opStack );
1308 
1309           curY = cf2_stack_popFixed( opStack );
1310           curX = cf2_stack_popFixed( opStack );
1311 
1312           error2 = cf2_getSeacComponent( decoder, achar, &component );
1313           if ( error2 )
1314           {
1315             lastError = error2;      /* pass FreeType error through */
1316             goto exit;
1317           }
1318           cf2_interpT2CharString( font,
1319                                   &component,
1320                                   callbacks,
1321                                   translation,
1322                                   TRUE,
1323                                   curX,
1324                                   curY,
1325                                   &dummyWidth );
1326           cf2_freeSeacComponent( decoder, &component );
1327 
1328           error2 = cf2_getSeacComponent( decoder, bchar, &component );
1329           if ( error2 )
1330           {
1331             lastError = error2;      /* pass FreeType error through */
1332             goto exit;
1333           }
1334           cf2_interpT2CharString( font,
1335                                   &component,
1336                                   callbacks,
1337                                   translation,
1338                                   TRUE,
1339                                   0,
1340                                   0,
1341                                   &dummyWidth );
1342           cf2_freeSeacComponent( decoder, &component );
1343         }
1344         goto exit;
1345 
1346       case cf2_cmdCNTRMASK:
1347       case cf2_cmdHINTMASK:
1348         /* the final \n in the tracing message gets added in      */
1349         /* `cf2_hintmask_read' (which also traces the mask bytes) */
1350         FT_TRACE4(( op1 == cf2_cmdCNTRMASK ? " cntrmask" : " hintmask" ));
1351 
1352         /* never add hints after the mask is computed */
1353         if ( cf2_stack_count( opStack ) > 1    &&
1354              cf2_hintmask_isValid( &hintMask ) )
1355         {
1356           FT_TRACE4(( "cf2_interpT2CharString: invalid hint mask\n" ));
1357           break;
1358         }
1359 
1360         /* if there are arguments on the stack, there this is an */
1361         /* implied cf2_cmdVSTEMHM                                */
1362         cf2_doStems( font,
1363                      opStack,
1364                      &vStemHintArray,
1365                      width,
1366                      &haveWidth,
1367                      0 );
1368 
1369         if ( font->decoder->width_only )
1370           goto exit;
1371 
1372         if ( op1 == cf2_cmdHINTMASK )
1373         {
1374           /* consume the hint mask bytes which follow the operator */
1375           cf2_hintmask_read( &hintMask,
1376                              charstring,
1377                              cf2_arrstack_size( &hStemHintArray ) +
1378                                cf2_arrstack_size( &vStemHintArray ) );
1379         }
1380         else
1381         {
1382           /*
1383            * Consume the counter mask bytes which follow the operator:
1384            * Build a temporary hint map, just to place and lock those
1385            * stems participating in the counter mask.  These are most
1386            * likely the dominant hstems, and are grouped together in a
1387            * few counter groups, not necessarily in correspondence
1388            * with the hint groups.  This reduces the chances of
1389            * conflicts between hstems that are initially placed in
1390            * separate hint groups and then brought together.  The
1391            * positions are copied back to `hStemHintArray', so we can
1392            * discard `counterMask' and `counterHintMap'.
1393            *
1394            */
1395           CF2_HintMapRec   counterHintMap;
1396           CF2_HintMaskRec  counterMask;
1397 
1398 
1399           cf2_hintmap_init( &counterHintMap,
1400                             font,
1401                             &glyphPath.initialHintMap,
1402                             &glyphPath.hintMoves,
1403                             scaleY );
1404           cf2_hintmask_init( &counterMask, error );
1405 
1406           cf2_hintmask_read( &counterMask,
1407                              charstring,
1408                              cf2_arrstack_size( &hStemHintArray ) +
1409                                cf2_arrstack_size( &vStemHintArray ) );
1410           cf2_hintmap_build( &counterHintMap,
1411                              &hStemHintArray,
1412                              &vStemHintArray,
1413                              &counterMask,
1414                              0,
1415                              FALSE );
1416         }
1417         break;
1418 
1419       case cf2_cmdRMOVETO:
1420         FT_TRACE4(( " rmoveto\n" ));
1421 
1422         if ( cf2_stack_count( opStack ) > 2 && !haveWidth )
1423           *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
1424 
1425         /* width is defined or default after this */
1426         haveWidth = TRUE;
1427 
1428         if ( font->decoder->width_only )
1429           goto exit;
1430 
1431         curY += cf2_stack_popFixed( opStack );
1432         curX += cf2_stack_popFixed( opStack );
1433 
1434         cf2_glyphpath_moveTo( &glyphPath, curX, curY );
1435 
1436         break;
1437 
1438       case cf2_cmdHMOVETO:
1439         FT_TRACE4(( " hmoveto\n" ));
1440 
1441         if ( cf2_stack_count( opStack ) > 1 && !haveWidth )
1442           *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
1443 
1444         /* width is defined or default after this */
1445         haveWidth = TRUE;
1446 
1447         if ( font->decoder->width_only )
1448           goto exit;
1449 
1450         curX += cf2_stack_popFixed( opStack );
1451 
1452         cf2_glyphpath_moveTo( &glyphPath, curX, curY );
1453 
1454         break;
1455 
1456       case cf2_cmdRLINECURVE:
1457         {
1458           CF2_UInt  count = cf2_stack_count( opStack );
1459           CF2_UInt  index = 0;
1460 
1461 
1462           FT_TRACE4(( " rlinecurve\n" ));
1463 
1464           while ( index + 6 < count )
1465           {
1466             curX += cf2_stack_getReal( opStack, index + 0 );
1467             curY += cf2_stack_getReal( opStack, index + 1 );
1468 
1469             cf2_glyphpath_lineTo( &glyphPath, curX, curY );
1470             index += 2;
1471           }
1472 
1473           while ( index < count )
1474           {
1475             CF2_Fixed  x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
1476             CF2_Fixed  y1 = cf2_stack_getReal( opStack, index + 1 ) + curY;
1477             CF2_Fixed  x2 = cf2_stack_getReal( opStack, index + 2 ) + x1;
1478             CF2_Fixed  y2 = cf2_stack_getReal( opStack, index + 3 ) + y1;
1479             CF2_Fixed  x3 = cf2_stack_getReal( opStack, index + 4 ) + x2;
1480             CF2_Fixed  y3 = cf2_stack_getReal( opStack, index + 5 ) + y2;
1481 
1482 
1483             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1484 
1485             curX   = x3;
1486             curY   = y3;
1487             index += 6;
1488           }
1489 
1490           cf2_stack_clear( opStack );
1491         }
1492         continue; /* no need to clear stack again */
1493 
1494       case cf2_cmdVVCURVETO:
1495         {
1496           CF2_UInt  count, count1 = cf2_stack_count( opStack );
1497           CF2_UInt  index = 0;
1498 
1499 
1500           /* if `cf2_stack_count' isn't of the form 4n or 4n+1, */
1501           /* we enforce it by clearing the second bit           */
1502           /* (and sorting the stack indexing to suit)           */
1503           count  = count1 & ~2U;
1504           index += count1 - count;
1505 
1506           FT_TRACE4(( " vvcurveto\n" ));
1507 
1508           while ( index < count )
1509           {
1510             CF2_Fixed  x1, y1, x2, y2, x3, y3;
1511 
1512 
1513             if ( ( count - index ) & 1 )
1514             {
1515               x1 = cf2_stack_getReal( opStack, index ) + curX;
1516 
1517               ++index;
1518             }
1519             else
1520               x1 = curX;
1521 
1522             y1 = cf2_stack_getReal( opStack, index + 0 ) + curY;
1523             x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1524             y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1525             x3 = x2;
1526             y3 = cf2_stack_getReal( opStack, index + 3 ) + y2;
1527 
1528             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1529 
1530             curX   = x3;
1531             curY   = y3;
1532             index += 4;
1533           }
1534 
1535           cf2_stack_clear( opStack );
1536         }
1537         continue; /* no need to clear stack again */
1538 
1539       case cf2_cmdHHCURVETO:
1540         {
1541           CF2_UInt  count, count1 = cf2_stack_count( opStack );
1542           CF2_UInt  index = 0;
1543 
1544 
1545           /* if `cf2_stack_count' isn't of the form 4n or 4n+1, */
1546           /* we enforce it by clearing the second bit           */
1547           /* (and sorting the stack indexing to suit)           */
1548           count  = count1 & ~2U;
1549           index += count1 - count;
1550 
1551           FT_TRACE4(( " hhcurveto\n" ));
1552 
1553           while ( index < count )
1554           {
1555             CF2_Fixed  x1, y1, x2, y2, x3, y3;
1556 
1557 
1558             if ( ( count - index ) & 1 )
1559             {
1560               y1 = cf2_stack_getReal( opStack, index ) + curY;
1561 
1562               ++index;
1563             }
1564             else
1565               y1 = curY;
1566 
1567             x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
1568             x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1569             y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1570             x3 = cf2_stack_getReal( opStack, index + 3 ) + x2;
1571             y3 = y2;
1572 
1573             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1574 
1575             curX   = x3;
1576             curY   = y3;
1577             index += 4;
1578           }
1579 
1580           cf2_stack_clear( opStack );
1581         }
1582         continue; /* no need to clear stack again */
1583 
1584       case cf2_cmdVHCURVETO:
1585       case cf2_cmdHVCURVETO:
1586         {
1587           CF2_UInt  count, count1 = cf2_stack_count( opStack );
1588           CF2_UInt  index = 0;
1589 
1590           FT_Bool  alternate = op1 == cf2_cmdHVCURVETO;
1591 
1592 
1593           /* if `cf2_stack_count' isn't of the form 8n, 8n+1, */
1594           /* 8n+4, or 8n+5, we enforce it by clearing the     */
1595           /* second bit                                       */
1596           /* (and sorting the stack indexing to suit)         */
1597           count  = count1 & ~2U;
1598           index += count1 - count;
1599 
1600           FT_TRACE4(( alternate ? " hvcurveto\n" : " vhcurveto\n" ));
1601 
1602           while ( index < count )
1603           {
1604             CF2_Fixed x1, x2, x3, y1, y2, y3;
1605 
1606 
1607             if ( alternate )
1608             {
1609               x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
1610               y1 = curY;
1611               x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1612               y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1613               y3 = cf2_stack_getReal( opStack, index + 3 ) + y2;
1614 
1615               if ( count - index == 5 )
1616               {
1617                 x3 = cf2_stack_getReal( opStack, index + 4 ) + x2;
1618 
1619                 ++index;
1620               }
1621               else
1622                 x3 = x2;
1623 
1624               alternate = FALSE;
1625             }
1626             else
1627             {
1628               x1 = curX;
1629               y1 = cf2_stack_getReal( opStack, index + 0 ) + curY;
1630               x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1631               y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1632               x3 = cf2_stack_getReal( opStack, index + 3 ) + x2;
1633 
1634               if ( count - index == 5 )
1635               {
1636                 y3 = cf2_stack_getReal( opStack, index + 4 ) + y2;
1637 
1638                 ++index;
1639               }
1640               else
1641                 y3 = y2;
1642 
1643               alternate = TRUE;
1644             }
1645 
1646             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1647 
1648             curX   = x3;
1649             curY   = y3;
1650             index += 4;
1651           }
1652 
1653           cf2_stack_clear( opStack );
1654         }
1655         continue;     /* no need to clear stack again */
1656 
1657       case cf2_cmdEXTENDEDNMBR:
1658         {
1659           CF2_Int  v;
1660 
1661           CF2_Int  byte1 = cf2_buf_readByte( charstring );
1662           CF2_Int  byte2 = cf2_buf_readByte( charstring );
1663 
1664 
1665           v = (FT_Short)( ( byte1 << 8 ) |
1666                             byte2        );
1667 
1668           FT_TRACE4(( " %d", v ));
1669 
1670           cf2_stack_pushInt( opStack, v );
1671         }
1672         continue;
1673 
1674       default:
1675         /* numbers */
1676         {
1677           if ( /* op1 >= 32 && */ op1 <= 246 )
1678           {
1679             CF2_Int  v;
1680 
1681 
1682             v = op1 - 139;
1683 
1684             FT_TRACE4(( " %d", v ));
1685 
1686             /* -107 .. 107 */
1687             cf2_stack_pushInt( opStack, v );
1688           }
1689 
1690           else if ( /* op1 >= 247 && */ op1 <= 250 )
1691           {
1692             CF2_Int  v;
1693 
1694 
1695             v  = op1;
1696             v -= 247;
1697             v *= 256;
1698             v += cf2_buf_readByte( charstring );
1699             v += 108;
1700 
1701             FT_TRACE4(( " %d", v ));
1702 
1703             /* 108 .. 1131 */
1704             cf2_stack_pushInt( opStack, v );
1705           }
1706 
1707           else if ( /* op1 >= 251 && */ op1 <= 254 )
1708           {
1709             CF2_Int  v;
1710 
1711 
1712             v  = op1;
1713             v -= 251;
1714             v *= 256;
1715             v += cf2_buf_readByte( charstring );
1716             v  = -v - 108;
1717 
1718             FT_TRACE4(( " %d", v ));
1719 
1720             /* -1131 .. -108 */
1721             cf2_stack_pushInt( opStack, v );
1722           }
1723 
1724           else /* op1 == 255 */
1725           {
1726             CF2_Fixed  v;
1727 
1728             FT_UInt32  byte1 = (FT_UInt32)cf2_buf_readByte( charstring );
1729             FT_UInt32  byte2 = (FT_UInt32)cf2_buf_readByte( charstring );
1730             FT_UInt32  byte3 = (FT_UInt32)cf2_buf_readByte( charstring );
1731             FT_UInt32  byte4 = (FT_UInt32)cf2_buf_readByte( charstring );
1732 
1733 
1734             v = (CF2_Fixed)( ( byte1 << 24 ) |
1735                              ( byte2 << 16 ) |
1736                              ( byte3 <<  8 ) |
1737                                byte4         );
1738 
1739             FT_TRACE4(( " %.2f", v / 65536.0 ));
1740 
1741             cf2_stack_pushFixed( opStack, v );
1742           }
1743         }
1744         continue;   /* don't clear stack */
1745 
1746       } /* end of switch statement checking `op1' */
1747 
1748       cf2_stack_clear( opStack );
1749 
1750     } /* end of main interpreter loop */
1751 
1752     /* we get here if the charstring ends without cf2_cmdENDCHAR */
1753     FT_TRACE4(( "cf2_interpT2CharString:"
1754                 "  charstring ends without ENDCHAR\n" ));
1755 
1756   exit:
1757     /* check whether last error seen is also the first one */
1758     cf2_setError( error, lastError );
1759 
1760     /* free resources from objects we've used */
1761     cf2_glyphpath_finalize( &glyphPath );
1762     cf2_arrstack_finalize( &vStemHintArray );
1763     cf2_arrstack_finalize( &hStemHintArray );
1764     cf2_arrstack_finalize( &subrStack );
1765     cf2_stack_free( opStack );
1766 
1767     FT_TRACE4(( "\n" ));
1768 
1769     return;
1770   }
1771 
1772 
1773 /* END */
1774