Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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