Fix warnings in android build, fix font rendering issue, fix issue 357588: wrong...
[pdfium.git] / core / src / fxge / fx_freetype / fxft2.5.01 / src / cff / cf2intrp.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  cf2intrp.c                                                             */
4 /*                                                                         */
5 /*    Adobe's CFF Interpreter (body).                                      */
6 /*                                                                         */
7 /*  Copyright 2007-2013 Adobe Systems Incorporated.                        */
8 /*                                                                         */
9 /*  This software, and all works of authorship, whether in source or       */
10 /*  object code form as indicated by the copyright notice(s) included      */
11 /*  herein (collectively, the "Work") is made available, and may only be   */
12 /*  used, modified, and distributed under the FreeType Project License,    */
13 /*  LICENSE.TXT.  Additionally, subject to the terms and conditions of the */
14 /*  FreeType Project License, each contributor to the Work hereby grants   */
15 /*  to any individual or legal entity exercising permissions granted by    */
16 /*  the FreeType Project License and this section (hereafter, "You" or     */
17 /*  "Your") a perpetual, worldwide, non-exclusive, no-charge,              */
18 /*  royalty-free, irrevocable (except as stated in this section) patent    */
19 /*  license to make, have made, use, offer to sell, sell, import, and      */
20 /*  otherwise transfer the Work, where such license applies only to those  */
21 /*  patent claims licensable by such contributor that are necessarily      */
22 /*  infringed by their contribution(s) alone or by combination of their    */
23 /*  contribution(s) with the Work to which such contribution(s) was        */
24 /*  submitted.  If You institute patent litigation against any entity      */
25 /*  (including a cross-claim or counterclaim in a lawsuit) alleging that   */
26 /*  the Work or a contribution incorporated within the Work constitutes    */
27 /*  direct or contributory patent infringement, then any patent licenses   */
28 /*  granted to You under this License for that Work shall terminate as of  */
29 /*  the date such litigation is filed.                                     */
30 /*                                                                         */
31 /*  By using, modifying, or distributing the Work you indicate that you    */
32 /*  have read and understood the terms and conditions of the               */
33 /*  FreeType Project License as well as those provided in this section,    */
34 /*  and you accept them fully.                                             */
35 /*                                                                         */
36 /***************************************************************************/
37
38
39 #include "cf2ft.h"
40 #include "../../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     /* initialize the remaining objects */
468     cf2_arrstack_init( &subrStack,
469                        memory,
470                        error,
471                        sizeof ( CF2_BufferRec ) );
472     cf2_arrstack_init( &hStemHintArray,
473                        memory,
474                        error,
475                        sizeof ( CF2_StemHintRec ) );
476     cf2_arrstack_init( &vStemHintArray,
477                        memory,
478                        error,
479                        sizeof ( CF2_StemHintRec ) );
480
481     /* initialize CF2_StemHint arrays */
482     cf2_hintmask_init( &hintMask, error );
483
484     /* initialize path map to manage drawing operations */
485
486     /* Note: last 4 params are used to handle `MoveToPermissive', which */
487     /*       may need to call `hintMap.Build'                           */
488     /* TODO: MoveToPermissive is gone; are these still needed?          */
489     cf2_glyphpath_init( &glyphPath,
490                         font,
491                         callbacks,
492                         scaleY,
493                         /* hShift, */
494                         &hStemHintArray,
495                         &vStemHintArray,
496                         &hintMask,
497                         hintOriginY,
498                         &font->blues,
499                         translation );
500
501     /*
502      * Initialize state for width parsing.  From the CFF Spec:
503      *
504      *   The first stack-clearing operator, which must be one of hstem,
505      *   hstemhm, vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto,
506      *   rmoveto, or endchar, takes an additional argument - the width (as
507      *   described earlier), which may be expressed as zero or one numeric
508      *   argument.
509      *
510      * What we implement here uses the first validly specified width, but
511      * does not detect errors for specifying more than one width.
512      *
513      * If one of the above operators occurs without explicitly specifying
514      * a width, we assume the default width.
515      *
516      */
517     haveWidth = FALSE;
518     *width    = cf2_getDefaultWidthX( decoder );
519
520     /*
521      * Note: at this point, all pointers to resources must be NULL
522      * and all local objects must be initialized.
523      * There must be no branches to exit: above this point.
524      *
525      */
526
527     /* allocate an operand stack */
528     opStack = cf2_stack_init( memory, error );
529     if ( !opStack )
530     {
531       lastError = FT_THROW( Out_Of_Memory );
532       goto exit;
533     }
534
535     /* initialize subroutine stack by placing top level charstring as */
536     /* first element (max depth plus one for the charstring)          */
537     /* Note: Caller owns and must finalize the first charstring.      */
538     /*       Our copy of it does not change that requirement.         */
539     cf2_arrstack_setCount( &subrStack, CF2_MAX_SUBR + 1 );
540
541     charstring  = (CF2_Buffer)cf2_arrstack_getBuffer( &subrStack );
542     *charstring = *buf;    /* structure copy */
543
544     charstringIndex = 0;       /* entry is valid now */
545
546     /* catch errors so far */
547     if ( *error )
548       goto exit;
549
550     /* main interpreter loop */
551     while ( 1 )
552     {
553       if ( cf2_buf_isEnd( charstring ) )
554       {
555         /* If we've reached the end of the charstring, simulate a */
556         /* cf2_cmdRETURN or cf2_cmdENDCHAR.                       */
557         if ( charstringIndex )
558           op1 = cf2_cmdRETURN;  /* end of buffer for subroutine */
559         else
560           op1 = cf2_cmdENDCHAR; /* end of buffer for top level charstring */
561       }
562       else
563         op1 = (FT_Byte)cf2_buf_readByte( charstring );
564
565       /* check for errors once per loop */
566       if ( *error )
567         goto exit;
568
569       instructionLimit--;
570       if ( instructionLimit == 0 )
571       {
572         lastError = FT_THROW( Invalid_Glyph_Format );
573         goto exit;
574       }
575
576       switch( op1 )
577       {
578       case cf2_cmdRESERVED_0:
579       case cf2_cmdRESERVED_2:
580       case cf2_cmdRESERVED_9:
581       case cf2_cmdRESERVED_13:
582       case cf2_cmdRESERVED_15:
583       case cf2_cmdRESERVED_16:
584       case cf2_cmdRESERVED_17:
585         /* we may get here if we have a prior error */
586         FT_TRACE4(( " unknown op (%d)\n", op1 ));
587         break;
588
589       case cf2_cmdHSTEMHM:
590       case cf2_cmdHSTEM:
591         FT_TRACE4(( op1 == cf2_cmdHSTEMHM ? " hstemhm\n" : " hstem\n" ));
592
593         /* never add hints after the mask is computed */
594         if ( cf2_hintmask_isValid( &hintMask ) )
595           FT_TRACE4(( "cf2_interpT2CharString:"
596                       " invalid horizontal hint mask\n" ));
597
598         cf2_doStems( font,
599                      opStack,
600                      &hStemHintArray,
601                      width,
602                      &haveWidth,
603                      0 );
604
605         if ( font->decoder->width_only )
606             goto exit;
607
608         break;
609
610       case cf2_cmdVSTEMHM:
611       case cf2_cmdVSTEM:
612         FT_TRACE4(( op1 == cf2_cmdVSTEMHM ? " vstemhm\n" : " vstem\n" ));
613
614         /* never add hints after the mask is computed */
615         if ( cf2_hintmask_isValid( &hintMask ) )
616           FT_TRACE4(( "cf2_interpT2CharString:"
617                       " invalid vertical hint mask\n" ));
618
619         cf2_doStems( font,
620                      opStack,
621                      &vStemHintArray,
622                      width,
623                      &haveWidth,
624                      0 );
625
626         if ( font->decoder->width_only )
627             goto exit;
628
629         break;
630
631       case cf2_cmdVMOVETO:
632         FT_TRACE4(( " vmoveto\n" ));
633
634         if ( cf2_stack_count( opStack ) > 1 && !haveWidth )
635           *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
636
637         /* width is defined or default after this */
638         haveWidth = TRUE;
639
640         if ( font->decoder->width_only )
641             goto exit;
642
643         curY += cf2_stack_popFixed( opStack );
644
645         cf2_glyphpath_moveTo( &glyphPath, curX, curY );
646                 if (glyphPath.callbacks && glyphPath.callbacks->error && *glyphPath.callbacks->error) goto exit;
647
648         break;
649
650       case cf2_cmdRLINETO:
651         {
652           CF2_UInt  index;
653           CF2_UInt  count = cf2_stack_count( opStack );
654
655
656           FT_TRACE4(( " rlineto\n" ));
657
658           for ( index = 0; index < count; index += 2 )
659           {
660             curX += cf2_stack_getReal( opStack, index + 0 );
661             curY += cf2_stack_getReal( opStack, index + 1 );
662
663             cf2_glyphpath_lineTo( &glyphPath, curX, curY );
664                         if (glyphPath.callbacks && glyphPath.callbacks->error && *glyphPath.callbacks->error) goto exit;
665           }
666
667           cf2_stack_clear( opStack );
668         }
669         continue; /* no need to clear stack again */
670
671       case cf2_cmdHLINETO:
672       case cf2_cmdVLINETO:
673         {
674           CF2_UInt  index;
675           CF2_UInt  count = cf2_stack_count( opStack );
676
677           FT_Bool  isX = op1 == cf2_cmdHLINETO;
678
679
680           FT_TRACE4(( isX ? " hlineto\n" : " vlineto\n" ));
681
682           for ( index = 0; index < count; index++ )
683           {
684             CF2_Fixed  v = cf2_stack_getReal( opStack, index );
685
686
687             if ( isX )
688               curX += v;
689             else
690               curY += v;
691
692             isX = !isX;
693
694             cf2_glyphpath_lineTo( &glyphPath, curX, curY );
695                         if (glyphPath.callbacks && glyphPath.callbacks->error && *glyphPath.callbacks->error) goto exit;
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                         if (glyphPath.callbacks && glyphPath.callbacks->error && *glyphPath.callbacks->error) goto exit;
724
725             curX   = x3;
726             curY   = y3;
727             index += 6;
728           }
729
730           if ( op1 == cf2_cmdRCURVELINE )
731           {
732             curX += cf2_stack_getReal( opStack, index + 0 );
733             curY += cf2_stack_getReal( opStack, index + 1 );
734
735             cf2_glyphpath_lineTo( &glyphPath, curX, curY );
736                         if (glyphPath.callbacks && glyphPath.callbacks->error && *glyphPath.callbacks->error) goto exit;
737           }
738
739           cf2_stack_clear( opStack );
740         }
741         continue; /* no need to clear stack again */
742
743       case cf2_cmdCALLGSUBR:
744       case cf2_cmdCALLSUBR:
745         {
746           CF2_UInt  subrIndex;
747
748
749           FT_TRACE4(( op1 == cf2_cmdCALLGSUBR ? " callgsubr"
750                                               : " callsubr" ));
751
752           if ( charstringIndex > CF2_MAX_SUBR )
753           {
754             /* max subr plus one for charstring */
755             lastError = FT_THROW( Invalid_Glyph_Format );
756             goto exit;                      /* overflow of stack */
757           }
758
759           /* push our current CFF charstring region on subrStack */
760           charstring = (CF2_Buffer)
761                          cf2_arrstack_getPointer( &subrStack,
762                                                   charstringIndex + 1 );
763
764           /* set up the new CFF region and pointer */
765           subrIndex = cf2_stack_popInt( opStack );
766
767           switch ( op1 )
768           {
769           case cf2_cmdCALLGSUBR:
770             FT_TRACE4(( "(%d)\n", subrIndex + decoder->globals_bias ));
771
772             if ( cf2_initGlobalRegionBuffer( decoder,
773                                              subrIndex,
774                                              charstring ) )
775             {
776               lastError = FT_THROW( Invalid_Glyph_Format );
777               goto exit;  /* subroutine lookup or stream error */
778             }
779             break;
780
781           default:
782             /* cf2_cmdCALLSUBR */
783             FT_TRACE4(( "(%d)\n", subrIndex + decoder->locals_bias ));
784
785             if ( cf2_initLocalRegionBuffer( decoder,
786                                             subrIndex,
787                                             charstring ) )
788             {
789               lastError = FT_THROW( Invalid_Glyph_Format );
790               goto exit;  /* subroutine lookup or stream error */
791             }
792           }
793
794           charstringIndex += 1;       /* entry is valid now */
795         }
796         continue; /* do not clear the stack */
797
798       case cf2_cmdRETURN:
799         FT_TRACE4(( " return\n" ));
800
801         if ( charstringIndex < 1 )
802         {
803           /* Note: cannot return from top charstring */
804           lastError = FT_THROW( Invalid_Glyph_Format );
805           goto exit;                      /* underflow of stack */
806         }
807
808         /* restore position in previous charstring */
809         charstring = (CF2_Buffer)
810                        cf2_arrstack_getPointer( &subrStack,
811                                                 --charstringIndex );
812         continue;     /* do not clear the stack */
813
814       case cf2_cmdESC:
815         {
816           FT_Byte  op2 = (FT_Byte)cf2_buf_readByte( charstring );
817
818
819           switch ( op2 )
820           {
821           case cf2_escDOTSECTION:
822             /* something about `flip type of locking' -- ignore it */
823             FT_TRACE4(( " dotsection\n" ));
824
825             break;
826
827           /* TODO: should these operators be supported? */
828           case cf2_escAND: /* in spec */
829             FT_TRACE4(( " and\n" ));
830
831             CF2_FIXME;
832             break;
833
834           case cf2_escOR: /* in spec */
835             FT_TRACE4(( " or\n" ));
836
837             CF2_FIXME;
838             break;
839
840           case cf2_escNOT: /* in spec */
841             FT_TRACE4(( " not\n" ));
842
843             CF2_FIXME;
844             break;
845
846           case cf2_escABS: /* in spec */
847             FT_TRACE4(( " abs\n" ));
848
849             CF2_FIXME;
850             break;
851
852           case cf2_escADD: /* in spec */
853             FT_TRACE4(( " add\n" ));
854
855             CF2_FIXME;
856             break;
857
858           case cf2_escSUB: /* in spec */
859             FT_TRACE4(( " sub\n" ));
860
861             CF2_FIXME;
862             break;
863
864           case cf2_escDIV: /* in spec */
865             FT_TRACE4(( " div\n" ));
866
867             CF2_FIXME;
868             break;
869
870           case cf2_escNEG: /* in spec */
871             FT_TRACE4(( " neg\n" ));
872
873             CF2_FIXME;
874             break;
875
876           case cf2_escEQ: /* in spec */
877             FT_TRACE4(( " eq\n" ));
878
879             CF2_FIXME;
880             break;
881
882           case cf2_escDROP: /* in spec */
883             FT_TRACE4(( " drop\n" ));
884
885             CF2_FIXME;
886             break;
887
888           case cf2_escPUT: /* in spec */
889             FT_TRACE4(( " put\n" ));
890
891             CF2_FIXME;
892             break;
893
894           case cf2_escGET: /* in spec */
895             FT_TRACE4(( " get\n" ));
896
897             CF2_FIXME;
898             break;
899
900           case cf2_escIFELSE: /* in spec */
901             FT_TRACE4(( " ifelse\n" ));
902
903             CF2_FIXME;
904             break;
905
906           case cf2_escRANDOM: /* in spec */
907             FT_TRACE4(( " random\n" ));
908
909             CF2_FIXME;
910             break;
911
912           case cf2_escMUL: /* in spec */
913             FT_TRACE4(( " mul\n" ));
914
915             CF2_FIXME;
916             break;
917
918           case cf2_escSQRT: /* in spec */
919             FT_TRACE4(( " sqrt\n" ));
920
921             CF2_FIXME;
922             break;
923
924           case cf2_escDUP: /* in spec */
925             FT_TRACE4(( " dup\n" ));
926
927             CF2_FIXME;
928             break;
929
930           case cf2_escEXCH: /* in spec */
931             FT_TRACE4(( " exch\n" ));
932
933             CF2_FIXME;
934             break;
935
936           case cf2_escINDEX: /* in spec */
937             FT_TRACE4(( " index\n" ));
938
939             CF2_FIXME;
940             break;
941
942           case cf2_escROLL: /* in spec */
943             FT_TRACE4(( " roll\n" ));
944
945             CF2_FIXME;
946             break;
947
948           case cf2_escHFLEX:
949             {
950               static const FT_Bool  readFromStack[12] =
951               {
952                 TRUE /* dx1 */, FALSE /* dy1 */,
953                 TRUE /* dx2 */, TRUE  /* dy2 */,
954                 TRUE /* dx3 */, FALSE /* dy3 */,
955                 TRUE /* dx4 */, FALSE /* dy4 */,
956                 TRUE /* dx5 */, FALSE /* dy5 */,
957                 TRUE /* dx6 */, FALSE /* dy6 */
958               };
959
960
961               FT_TRACE4(( " hflex\n" ));
962
963               cf2_doFlex( opStack,
964                           &curX,
965                           &curY,
966                           &glyphPath,
967                           readFromStack,
968                           FALSE /* doConditionalLastRead */ );
969             }
970             continue;
971
972           case cf2_escFLEX:
973             {
974               static const FT_Bool  readFromStack[12] =
975               {
976                 TRUE /* dx1 */, TRUE /* dy1 */,
977                 TRUE /* dx2 */, TRUE /* dy2 */,
978                 TRUE /* dx3 */, TRUE /* dy3 */,
979                 TRUE /* dx4 */, TRUE /* dy4 */,
980                 TRUE /* dx5 */, TRUE /* dy5 */,
981                 TRUE /* dx6 */, TRUE /* dy6 */
982               };
983
984
985               FT_TRACE4(( " flex\n" ));
986
987               cf2_doFlex( opStack,
988                           &curX,
989                           &curY,
990                           &glyphPath,
991                           readFromStack,
992                           FALSE /* doConditionalLastRead */ );
993             }
994             break;      /* TODO: why is this not a continue? */
995
996           case cf2_escHFLEX1:
997             {
998               static const FT_Bool  readFromStack[12] =
999               {
1000                 TRUE /* dx1 */, TRUE  /* dy1 */,
1001                 TRUE /* dx2 */, TRUE  /* dy2 */,
1002                 TRUE /* dx3 */, FALSE /* dy3 */,
1003                 TRUE /* dx4 */, FALSE /* dy4 */,
1004                 TRUE /* dx5 */, TRUE  /* dy5 */,
1005                 TRUE /* dx6 */, FALSE /* dy6 */
1006               };
1007
1008
1009               FT_TRACE4(( " hflex1\n" ));
1010
1011               cf2_doFlex( opStack,
1012                           &curX,
1013                           &curY,
1014                           &glyphPath,
1015                           readFromStack,
1016                           FALSE /* doConditionalLastRead */ );
1017             }
1018             continue;
1019
1020           case cf2_escFLEX1:
1021             {
1022               static const FT_Bool  readFromStack[12] =
1023               {
1024                 TRUE  /* dx1 */, TRUE  /* dy1 */,
1025                 TRUE  /* dx2 */, TRUE  /* dy2 */,
1026                 TRUE  /* dx3 */, TRUE  /* dy3 */,
1027                 TRUE  /* dx4 */, TRUE  /* dy4 */,
1028                 TRUE  /* dx5 */, TRUE  /* dy5 */,
1029                 FALSE /* dx6 */, FALSE /* dy6 */
1030               };
1031
1032
1033               FT_TRACE4(( " flex1\n" ));
1034
1035               cf2_doFlex( opStack,
1036                           &curX,
1037                           &curY,
1038                           &glyphPath,
1039                           readFromStack,
1040                           TRUE /* doConditionalLastRead */ );
1041             }
1042             continue;
1043
1044           case cf2_escRESERVED_1:
1045           case cf2_escRESERVED_2:
1046           case cf2_escRESERVED_6:
1047           case cf2_escRESERVED_7:
1048           case cf2_escRESERVED_8:
1049           case cf2_escRESERVED_13:
1050           case cf2_escRESERVED_16:
1051           case cf2_escRESERVED_17:
1052           case cf2_escRESERVED_19:
1053           case cf2_escRESERVED_25:
1054           case cf2_escRESERVED_31:
1055           case cf2_escRESERVED_32:
1056           case cf2_escRESERVED_33:
1057           default:
1058             FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
1059
1060           }; /* end of switch statement checking `op2' */
1061
1062         } /* case cf2_cmdESC */
1063         break;
1064
1065       case cf2_cmdENDCHAR:
1066         FT_TRACE4(( " endchar\n" ));
1067
1068         if ( cf2_stack_count( opStack ) == 1 ||
1069              cf2_stack_count( opStack ) == 5 )
1070         {
1071           if ( !haveWidth )
1072             *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
1073         }
1074
1075         /* width is defined or default after this */
1076         haveWidth = TRUE;
1077
1078         if ( font->decoder->width_only )
1079             goto exit;
1080
1081         /* close path if still open */
1082         cf2_glyphpath_closeOpenPath( &glyphPath );
1083
1084         if ( cf2_stack_count( opStack ) > 1 )
1085         {
1086           /* must be either 4 or 5 --                       */
1087           /* this is a (deprecated) implied `seac' operator */
1088
1089           CF2_UInt       achar;
1090           CF2_UInt       bchar;
1091           CF2_BufferRec  component;
1092           CF2_Fixed      dummyWidth;   /* ignore component width */
1093           FT_Error       error2;
1094
1095
1096           if ( doingSeac )
1097           {
1098             lastError = FT_THROW( Invalid_Glyph_Format );
1099             goto exit;      /* nested seac */
1100           }
1101
1102           achar = cf2_stack_popInt( opStack );
1103           bchar = cf2_stack_popInt( opStack );
1104
1105           curY = cf2_stack_popFixed( opStack );
1106           curX = cf2_stack_popFixed( opStack );
1107
1108           error2 = cf2_getSeacComponent( decoder, achar, &component );
1109           if ( error2 )
1110           {
1111              lastError = error2;      /* pass FreeType error through */
1112              goto exit;
1113           }
1114           cf2_interpT2CharString( font,
1115                                   &component,
1116                                   callbacks,
1117                                   translation,
1118                                   TRUE,
1119                                   curX,
1120                                   curY,
1121                                   &dummyWidth );
1122           cf2_freeSeacComponent( decoder, &component );
1123
1124           error2 = cf2_getSeacComponent( decoder, bchar, &component );
1125           if ( error2 )
1126           {
1127             lastError = error2;      /* pass FreeType error through */
1128             goto exit;
1129           }
1130           cf2_interpT2CharString( font,
1131                                   &component,
1132                                   callbacks,
1133                                   translation,
1134                                   TRUE,
1135                                   0,
1136                                   0,
1137                                   &dummyWidth );
1138           cf2_freeSeacComponent( decoder, &component );
1139         }
1140         goto exit;
1141
1142       case cf2_cmdCNTRMASK:
1143       case cf2_cmdHINTMASK:
1144         /* the final \n in the tracing message gets added in      */
1145         /* `cf2_hintmask_read' (which also traces the mask bytes) */
1146         FT_TRACE4(( op1 == cf2_cmdCNTRMASK ? " cntrmask" : " hintmask" ));
1147
1148         /* if there are arguments on the stack, there this is an */
1149         /* implied cf2_cmdVSTEMHM                                */
1150         if ( cf2_stack_count( opStack ) != 0 )
1151         {
1152           /* never add hints after the mask is computed */
1153           if ( cf2_hintmask_isValid( &hintMask ) )
1154             FT_TRACE4(( "cf2_interpT2CharString: invalid hint mask\n" ));
1155         }
1156
1157         cf2_doStems( font,
1158                      opStack,
1159                      &vStemHintArray,
1160                      width,
1161                      &haveWidth,
1162                      0 );
1163
1164         if ( font->decoder->width_only )
1165             goto exit;
1166
1167         if ( op1 == cf2_cmdHINTMASK )
1168         {
1169           /* consume the hint mask bytes which follow the operator */
1170           cf2_hintmask_read( &hintMask,
1171                              charstring,
1172                              cf2_arrstack_size( &hStemHintArray ) +
1173                                cf2_arrstack_size( &vStemHintArray ) );
1174         }
1175         else
1176         {
1177           /*
1178            * Consume the counter mask bytes which follow the operator:
1179            * Build a temporary hint map, just to place and lock those
1180            * stems participating in the counter mask.  These are most
1181            * likely the dominant hstems, and are grouped together in a
1182            * few counter groups, not necessarily in correspondence
1183            * with the hint groups.  This reduces the chances of
1184            * conflicts between hstems that are initially placed in
1185            * separate hint groups and then brought together.  The
1186            * positions are copied back to `hStemHintArray', so we can
1187            * discard `counterMask' and `counterHintMap'.
1188            *
1189            */
1190           CF2_HintMapRec   counterHintMap;
1191           CF2_HintMaskRec  counterMask;
1192
1193
1194           cf2_hintmap_init( &counterHintMap,
1195                             font,
1196                             &glyphPath.initialHintMap,
1197                             &glyphPath.hintMoves,
1198                             scaleY );
1199           cf2_hintmask_init( &counterMask, error );
1200
1201           cf2_hintmask_read( &counterMask,
1202                              charstring,
1203                              cf2_arrstack_size( &hStemHintArray ) +
1204                                cf2_arrstack_size( &vStemHintArray ) );
1205           cf2_hintmap_build( &counterHintMap,
1206                              &hStemHintArray,
1207                              &vStemHintArray,
1208                              &counterMask,
1209                              0,
1210                              FALSE );
1211         }
1212         break;
1213
1214       case cf2_cmdRMOVETO:
1215         FT_TRACE4(( " rmoveto\n" ));
1216
1217         if ( cf2_stack_count( opStack ) > 2 && !haveWidth )
1218           *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
1219
1220         /* width is defined or default after this */
1221         haveWidth = TRUE;
1222
1223         if ( font->decoder->width_only )
1224             goto exit;
1225
1226         curY += cf2_stack_popFixed( opStack );
1227         curX += cf2_stack_popFixed( opStack );
1228
1229         cf2_glyphpath_moveTo( &glyphPath, curX, curY );
1230                 if (glyphPath.callbacks && glyphPath.callbacks->error && *glyphPath.callbacks->error) goto exit;
1231
1232         break;
1233
1234       case cf2_cmdHMOVETO:
1235         FT_TRACE4(( " hmoveto\n" ));
1236
1237         if ( cf2_stack_count( opStack ) > 1 && !haveWidth )
1238           *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
1239
1240         /* width is defined or default after this */
1241         haveWidth = TRUE;
1242
1243         if ( font->decoder->width_only )
1244             goto exit;
1245
1246         curX += cf2_stack_popFixed( opStack );
1247
1248         cf2_glyphpath_moveTo( &glyphPath, curX, curY );
1249                 if (glyphPath.callbacks && glyphPath.callbacks->error && *glyphPath.callbacks->error) goto exit;
1250
1251         break;
1252
1253       case cf2_cmdRLINECURVE:
1254         {
1255           CF2_UInt  count = cf2_stack_count( opStack );
1256           CF2_UInt  index = 0;
1257
1258
1259           FT_TRACE4(( " rlinecurve\n" ));
1260
1261           while ( index + 6 < count )
1262           {
1263             curX += cf2_stack_getReal( opStack, index + 0 );
1264             curY += cf2_stack_getReal( opStack, index + 1 );
1265
1266             cf2_glyphpath_lineTo( &glyphPath, curX, curY );
1267                         if (glyphPath.callbacks && glyphPath.callbacks->error && *glyphPath.callbacks->error) goto exit;
1268             index += 2;
1269           }
1270
1271           while ( index < count )
1272           {
1273             CF2_Fixed  x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
1274             CF2_Fixed  y1 = cf2_stack_getReal( opStack, index + 1 ) + curY;
1275             CF2_Fixed  x2 = cf2_stack_getReal( opStack, index + 2 ) + x1;
1276             CF2_Fixed  y2 = cf2_stack_getReal( opStack, index + 3 ) + y1;
1277             CF2_Fixed  x3 = cf2_stack_getReal( opStack, index + 4 ) + x2;
1278             CF2_Fixed  y3 = cf2_stack_getReal( opStack, index + 5 ) + y2;
1279
1280
1281             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1282                         if (glyphPath.callbacks && glyphPath.callbacks->error && *glyphPath.callbacks->error) goto exit;
1283
1284             curX   = x3;
1285             curY   = y3;
1286             index += 6;
1287           }
1288
1289           cf2_stack_clear( opStack );
1290         }
1291         continue; /* no need to clear stack again */
1292
1293       case cf2_cmdVVCURVETO:
1294         {
1295           CF2_UInt  count = cf2_stack_count( opStack );
1296           CF2_UInt  index = 0;
1297
1298
1299           FT_TRACE4(( " vvcurveto\n" ));
1300
1301           while ( index < count )
1302           {
1303             CF2_Fixed  x1, y1, x2, y2, x3, y3;
1304
1305
1306             if ( ( count - index ) & 1 )
1307             {
1308               x1 = cf2_stack_getReal( opStack, index ) + curX;
1309
1310               ++index;
1311             }
1312             else
1313               x1 = curX;
1314
1315             y1 = cf2_stack_getReal( opStack, index + 0 ) + curY;
1316             x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1317             y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1318             x3 = x2;
1319             y3 = cf2_stack_getReal( opStack, index + 3 ) + y2;
1320
1321             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1322                         if (glyphPath.callbacks && glyphPath.callbacks->error && *glyphPath.callbacks->error) goto exit;
1323
1324             curX   = x3;
1325             curY   = y3;
1326             index += 4;
1327           }
1328
1329           cf2_stack_clear( opStack );
1330         }
1331         continue; /* no need to clear stack again */
1332
1333       case cf2_cmdHHCURVETO:
1334         {
1335           CF2_UInt  count = cf2_stack_count( opStack );
1336           CF2_UInt  index = 0;
1337
1338
1339           FT_TRACE4(( " hhcurveto\n" ));
1340
1341           while ( index < count )
1342           {
1343             CF2_Fixed  x1, y1, x2, y2, x3, y3;
1344
1345
1346             if ( ( count - index ) & 1 )
1347             {
1348               y1 = cf2_stack_getReal( opStack, index ) + curY;
1349
1350               ++index;
1351             }
1352             else
1353               y1 = curY;
1354
1355             x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
1356             x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1357             y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1358             x3 = cf2_stack_getReal( opStack, index + 3 ) + x2;
1359             y3 = y2;
1360
1361             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1362                         if (glyphPath.callbacks && glyphPath.callbacks->error && *glyphPath.callbacks->error) goto exit;
1363
1364             curX   = x3;
1365             curY   = y3;
1366             index += 4;
1367           }
1368
1369           cf2_stack_clear( opStack );
1370         }
1371         continue; /* no need to clear stack again */
1372
1373       case cf2_cmdVHCURVETO:
1374       case cf2_cmdHVCURVETO:
1375         {
1376           CF2_UInt  count = cf2_stack_count( opStack );
1377           CF2_UInt  index = 0;
1378
1379           FT_Bool  alternate = op1 == cf2_cmdHVCURVETO;
1380
1381
1382           FT_TRACE4(( alternate ? " hvcurveto\n" : " vhcurveto\n" ));
1383
1384           while ( index < count )
1385           {
1386             CF2_Fixed x1, x2, x3, y1, y2, y3;
1387
1388
1389             if ( alternate )
1390             {
1391               x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
1392               y1 = curY;
1393               x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1394               y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1395               y3 = cf2_stack_getReal( opStack, index + 3 ) + y2;
1396
1397               if ( count - index == 5 )
1398               {
1399                 x3 = cf2_stack_getReal( opStack, index + 4 ) + x2;
1400
1401                 ++index;
1402               }
1403               else
1404                 x3 = x2;
1405
1406               alternate = FALSE;
1407             }
1408             else
1409             {
1410               x1 = curX;
1411               y1 = cf2_stack_getReal( opStack, index + 0 ) + curY;
1412               x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1413               y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1414               x3 = cf2_stack_getReal( opStack, index + 3 ) + x2;
1415
1416               if ( count - index == 5 )
1417               {
1418                 y3 = cf2_stack_getReal( opStack, index + 4 ) + y2;
1419
1420                 ++index;
1421               }
1422               else
1423                 y3 = y2;
1424
1425               alternate = TRUE;
1426             }
1427
1428             cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1429                         if (glyphPath.callbacks && glyphPath.callbacks->error && *glyphPath.callbacks->error) goto exit;
1430
1431             curX   = x3;
1432             curY   = y3;
1433             index += 4;
1434           }
1435
1436           cf2_stack_clear( opStack );
1437         }
1438         continue;     /* no need to clear stack again */
1439
1440       case cf2_cmdEXTENDEDNMBR:
1441         {
1442           CF2_Int  v;
1443
1444
1445           v = (FT_Short)( ( cf2_buf_readByte( charstring ) << 8 ) |
1446                             cf2_buf_readByte( charstring )        );
1447
1448           FT_TRACE4(( " %d", v ));
1449
1450           cf2_stack_pushInt( opStack, v );
1451         }
1452         continue;
1453
1454       default:
1455         /* numbers */
1456         {
1457           if ( /* op1 >= 32 && */ op1 <= 246 )
1458           {
1459             CF2_Int  v;
1460
1461
1462             v = op1 - 139;
1463
1464             FT_TRACE4(( " %d", v ));
1465
1466             /* -107 .. 107 */
1467             cf2_stack_pushInt( opStack, v );
1468           }
1469
1470           else if ( /* op1 >= 247 && */ op1 <= 250 )
1471           {
1472             CF2_Int  v;
1473
1474
1475             v  = op1;
1476             v -= 247;
1477             v *= 256;
1478             v += cf2_buf_readByte( charstring );
1479             v += 108;
1480
1481             FT_TRACE4(( " %d", v ));
1482
1483             /* 108 .. 1131 */
1484             cf2_stack_pushInt( opStack, v );
1485           }
1486
1487           else if ( /* op1 >= 251 && */ op1 <= 254 )
1488           {
1489             CF2_Int  v;
1490
1491
1492             v  = op1;
1493             v -= 251;
1494             v *= 256;
1495             v += cf2_buf_readByte( charstring );
1496             v  = -v - 108;
1497
1498             FT_TRACE4(( " %d", v ));
1499
1500             /* -1131 .. -108 */
1501             cf2_stack_pushInt( opStack, v );
1502           }
1503
1504           else /* op1 == 255 */
1505           {
1506             CF2_Fixed  v;
1507
1508
1509             v = (CF2_Fixed)
1510                   ( ( (FT_UInt32)cf2_buf_readByte( charstring ) << 24 ) |
1511                     ( (FT_UInt32)cf2_buf_readByte( charstring ) << 16 ) |
1512                     ( (FT_UInt32)cf2_buf_readByte( charstring ) <<  8 ) |
1513                       (FT_UInt32)cf2_buf_readByte( charstring )         );
1514
1515             FT_TRACE4(( " %.2f", v / 65536.0 ));
1516
1517             cf2_stack_pushFixed( opStack, v );
1518           }
1519         }
1520         continue;   /* don't clear stack */
1521
1522       } /* end of switch statement checking `op1' */
1523
1524       cf2_stack_clear( opStack );
1525
1526     } /* end of main interpreter loop */
1527
1528     /* we get here if the charstring ends without cf2_cmdENDCHAR */
1529     FT_TRACE4(( "cf2_interpT2CharString:"
1530                 "  charstring ends without ENDCHAR\n" ));
1531
1532   exit:
1533     /* check whether last error seen is also the first one */
1534     cf2_setError( error, lastError );
1535
1536     /* free resources from objects we've used */
1537     cf2_glyphpath_finalize( &glyphPath );
1538     cf2_arrstack_finalize( &vStemHintArray );
1539     cf2_arrstack_finalize( &hStemHintArray );
1540     cf2_arrstack_finalize( &subrStack );
1541     cf2_stack_free( opStack );
1542
1543     FT_TRACE4(( "\n" ));
1544
1545     return;
1546   }
1547
1548
1549 /* END */