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