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