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