Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3918 Serge 1
/***************************************************************************/
2
/*                                                                         */
3
/*  psobjs.c                                                               */
4
/*                                                                         */
5
/*    Auxiliary functions for PostScript fonts (body).                     */
6
/*                                                                         */
7
/*  Copyright 1996-2013 by                                                 */
8
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9
/*                                                                         */
10
/*  This file is part of the FreeType project, and may only be used,       */
11
/*  modified, and distributed under the terms of the FreeType project      */
12
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13
/*  this file you indicate that you have read the license and              */
14
/*  understand and accept it fully.                                        */
15
/*                                                                         */
16
/***************************************************************************/
17
 
18
 
19
#include 
20
#include FT_INTERNAL_POSTSCRIPT_AUX_H
21
#include FT_INTERNAL_DEBUG_H
22
#include FT_INTERNAL_CALC_H
23
 
24
#include "psobjs.h"
25
#include "psconv.h"
26
 
27
#include "psauxerr.h"
28
 
29
 
30
  /*************************************************************************/
31
  /*                                                                       */
32
  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
33
  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
34
  /* messages during execution.                                            */
35
  /*                                                                       */
36
#undef  FT_COMPONENT
37
#define FT_COMPONENT  trace_psobjs
38
 
39
 
40
  /*************************************************************************/
41
  /*************************************************************************/
42
  /*****                                                               *****/
43
  /*****                             PS_TABLE                          *****/
44
  /*****                                                               *****/
45
  /*************************************************************************/
46
  /*************************************************************************/
47
 
48
  /*************************************************************************/
49
  /*                                                                       */
50
  /*                                                             */
51
  /*    ps_table_new                                                       */
52
  /*                                                                       */
53
  /*                                                          */
54
  /*    Initializes a PS_Table.                                            */
55
  /*                                                                       */
56
  /*                                                                */
57
  /*    table  :: The address of the target table.                         */
58
  /*                                                                       */
59
  /*                                                                */
60
  /*    count  :: The table size = the maximum number of elements.         */
61
  /*                                                                       */
62
  /*    memory :: The memory object to use for all subsequent              */
63
  /*              reallocations.                                           */
64
  /*                                                                       */
65
  /*                                                               */
66
  /*    FreeType error code.  0 means success.                             */
67
  /*                                                                       */
68
  FT_LOCAL_DEF( FT_Error )
69
  ps_table_new( PS_Table   table,
70
                FT_Int     count,
71
                FT_Memory  memory )
72
  {
73
    FT_Error  error;
74
 
75
 
76
    table->memory = memory;
77
    if ( FT_NEW_ARRAY( table->elements, count ) ||
78
         FT_NEW_ARRAY( table->lengths,  count ) )
79
      goto Exit;
80
 
81
    table->max_elems = count;
82
    table->init      = 0xDEADBEEFUL;
83
    table->num_elems = 0;
84
    table->block     = 0;
85
    table->capacity  = 0;
86
    table->cursor    = 0;
87
 
88
    *(PS_Table_FuncsRec*)&table->funcs = ps_table_funcs;
89
 
90
  Exit:
91
    if ( error )
92
      FT_FREE( table->elements );
93
 
94
    return error;
95
  }
96
 
97
 
98
  static void
99
  shift_elements( PS_Table  table,
100
                  FT_Byte*  old_base )
101
  {
102
    FT_PtrDist  delta  = table->block - old_base;
103
    FT_Byte**   offset = table->elements;
104
    FT_Byte**   limit  = offset + table->max_elems;
105
 
106
 
107
    for ( ; offset < limit; offset++ )
108
    {
109
      if ( offset[0] )
110
        offset[0] += delta;
111
    }
112
  }
113
 
114
 
115
  static FT_Error
116
  reallocate_t1_table( PS_Table   table,
117
                       FT_Offset  new_size )
118
  {
119
    FT_Memory  memory   = table->memory;
120
    FT_Byte*   old_base = table->block;
121
    FT_Error   error;
122
 
123
 
124
    /* allocate new base block */
125
    if ( FT_ALLOC( table->block, new_size ) )
126
    {
127
      table->block = old_base;
128
      return error;
129
    }
130
 
131
    /* copy elements and shift offsets */
132
    if ( old_base )
133
    {
134
      FT_MEM_COPY( table->block, old_base, table->capacity );
135
      shift_elements( table, old_base );
136
      FT_FREE( old_base );
137
    }
138
 
139
    table->capacity = new_size;
140
 
141
    return FT_Err_Ok;
142
  }
143
 
144
 
145
  /*************************************************************************/
146
  /*                                                                       */
147
  /*                                                             */
148
  /*    ps_table_add                                                       */
149
  /*                                                                       */
150
  /*                                                          */
151
  /*    Adds an object to a PS_Table, possibly growing its memory block.   */
152
  /*                                                                       */
153
  /*                                                                */
154
  /*    table  :: The target table.                                        */
155
  /*                                                                       */
156
  /*                                                                */
157
  /*    idx    :: The index of the object in the table.                    */
158
  /*                                                                       */
159
  /*    object :: The address of the object to copy in memory.             */
160
  /*                                                                       */
161
  /*    length :: The length in bytes of the source object.                */
162
  /*                                                                       */
163
  /*                                                               */
164
  /*    FreeType error code.  0 means success.  An error is returned if a  */
165
  /*    reallocation fails.                                                */
166
  /*                                                                       */
167
  FT_LOCAL_DEF( FT_Error )
168
  ps_table_add( PS_Table    table,
169
                FT_Int      idx,
170
                void*       object,
171
                FT_PtrDist  length )
172
  {
173
    if ( idx < 0 || idx >= table->max_elems )
174
    {
175
      FT_ERROR(( "ps_table_add: invalid index\n" ));
176
      return FT_THROW( Invalid_Argument );
177
    }
178
 
179
    if ( length < 0 )
180
    {
181
      FT_ERROR(( "ps_table_add: invalid length\n" ));
182
      return FT_THROW( Invalid_Argument );
183
    }
184
 
185
    /* grow the base block if needed */
186
    if ( table->cursor + length > table->capacity )
187
    {
188
      FT_Error    error;
189
      FT_Offset   new_size = table->capacity;
190
      FT_PtrDist  in_offset;
191
 
192
 
193
      in_offset = (FT_Byte*)object - table->block;
194
      if ( in_offset < 0 || (FT_Offset)in_offset >= table->capacity )
195
        in_offset = -1;
196
 
197
      while ( new_size < table->cursor + length )
198
      {
199
        /* increase size by 25% and round up to the nearest multiple
200
           of 1024 */
201
        new_size += ( new_size >> 2 ) + 1;
202
        new_size  = FT_PAD_CEIL( new_size, 1024 );
203
      }
204
 
205
      error = reallocate_t1_table( table, new_size );
206
      if ( error )
207
        return error;
208
 
209
      if ( in_offset >= 0 )
210
        object = table->block + in_offset;
211
    }
212
 
213
    /* add the object to the base block and adjust offset */
214
    table->elements[idx] = table->block + table->cursor;
215
    table->lengths [idx] = length;
216
    FT_MEM_COPY( table->block + table->cursor, object, length );
217
 
218
    table->cursor += length;
219
    return FT_Err_Ok;
220
  }
221
 
222
 
223
  /*************************************************************************/
224
  /*                                                                       */
225
  /*                                                             */
226
  /*    ps_table_done                                                      */
227
  /*                                                                       */
228
  /*                                                          */
229
  /*    Finalizes a PS_TableRec (i.e., reallocate it to its current        */
230
  /*    cursor).                                                           */
231
  /*                                                                       */
232
  /*                                                                */
233
  /*    table :: The target table.                                         */
234
  /*                                                                       */
235
  /*                                                                 */
236
  /*    This function does NOT release the heap's memory block.  It is up  */
237
  /*    to the caller to clean it, or reference it in its own structures.  */
238
  /*                                                                       */
239
  FT_LOCAL_DEF( void )
240
  ps_table_done( PS_Table  table )
241
  {
242
    FT_Memory  memory = table->memory;
243
    FT_Error   error;
244
    FT_Byte*   old_base = table->block;
245
 
246
 
247
    /* should never fail, because rec.cursor <= rec.size */
248
    if ( !old_base )
249
      return;
250
 
251
    if ( FT_ALLOC( table->block, table->cursor ) )
252
      return;
253
    FT_MEM_COPY( table->block, old_base, table->cursor );
254
    shift_elements( table, old_base );
255
 
256
    table->capacity = table->cursor;
257
    FT_FREE( old_base );
258
 
259
    FT_UNUSED( error );
260
  }
261
 
262
 
263
  FT_LOCAL_DEF( void )
264
  ps_table_release( PS_Table  table )
265
  {
266
    FT_Memory  memory = table->memory;
267
 
268
 
269
    if ( (FT_ULong)table->init == 0xDEADBEEFUL )
270
    {
271
      FT_FREE( table->block );
272
      FT_FREE( table->elements );
273
      FT_FREE( table->lengths );
274
      table->init = 0;
275
    }
276
  }
277
 
278
 
279
  /*************************************************************************/
280
  /*************************************************************************/
281
  /*****                                                               *****/
282
  /*****                            T1 PARSER                          *****/
283
  /*****                                                               *****/
284
  /*************************************************************************/
285
  /*************************************************************************/
286
 
287
 
288
  /* first character must be already part of the comment */
289
 
290
  static void
291
  skip_comment( FT_Byte*  *acur,
292
                FT_Byte*   limit )
293
  {
294
    FT_Byte*  cur = *acur;
295
 
296
 
297
    while ( cur < limit )
298
    {
299
      if ( IS_PS_NEWLINE( *cur ) )
300
        break;
301
      cur++;
302
    }
303
 
304
    *acur = cur;
305
  }
306
 
307
 
308
  static void
309
  skip_spaces( FT_Byte*  *acur,
310
               FT_Byte*   limit )
311
  {
312
    FT_Byte*  cur = *acur;
313
 
314
 
315
    while ( cur < limit )
316
    {
317
      if ( !IS_PS_SPACE( *cur ) )
318
      {
319
        if ( *cur == '%' )
320
          /* According to the PLRM, a comment is equal to a space. */
321
          skip_comment( &cur, limit );
322
        else
323
          break;
324
      }
325
      cur++;
326
    }
327
 
328
    *acur = cur;
329
  }
330
 
331
 
332
#define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' )
333
 
334
 
335
  /* first character must be `(';                               */
336
  /* *acur is positioned at the character after the closing `)' */
337
 
338
  static FT_Error
339
  skip_literal_string( FT_Byte*  *acur,
340
                       FT_Byte*   limit )
341
  {
342
    FT_Byte*      cur   = *acur;
343
    FT_Int        embed = 0;
344
    FT_Error      error = FT_ERR( Invalid_File_Format );
345
    unsigned int  i;
346
 
347
 
348
    while ( cur < limit )
349
    {
350
      FT_Byte  c = *cur;
351
 
352
 
353
      ++cur;
354
 
355
      if ( c == '\\' )
356
      {
357
        /* Red Book 3rd ed., section `Literal Text Strings', p. 29:     */
358
        /* A backslash can introduce three different types              */
359
        /* of escape sequences:                                         */
360
        /*   - a special escaped char like \r, \n, etc.                 */
361
        /*   - a one-, two-, or three-digit octal number                */
362
        /*   - none of the above in which case the backslash is ignored */
363
 
364
        if ( cur == limit )
365
          /* error (or to be ignored?) */
366
          break;
367
 
368
        switch ( *cur )
369
        {
370
          /* skip `special' escape */
371
        case 'n':
372
        case 'r':
373
        case 't':
374
        case 'b':
375
        case 'f':
376
        case '\\':
377
        case '(':
378
        case ')':
379
          ++cur;
380
          break;
381
 
382
        default:
383
          /* skip octal escape or ignore backslash */
384
          for ( i = 0; i < 3 && cur < limit; ++i )
385
          {
386
            if ( !IS_OCTAL_DIGIT( *cur ) )
387
              break;
388
 
389
            ++cur;
390
          }
391
        }
392
      }
393
      else if ( c == '(' )
394
        embed++;
395
      else if ( c == ')' )
396
      {
397
        embed--;
398
        if ( embed == 0 )
399
        {
400
          error = FT_Err_Ok;
401
          break;
402
        }
403
      }
404
    }
405
 
406
    *acur = cur;
407
 
408
    return error;
409
  }
410
 
411
 
412
  /* first character must be `<' */
413
 
414
  static FT_Error
415
  skip_string( FT_Byte*  *acur,
416
               FT_Byte*   limit )
417
  {
418
    FT_Byte*  cur = *acur;
419
    FT_Error  err =  FT_Err_Ok;
420
 
421
 
422
    while ( ++cur < limit )
423
    {
424
      /* All whitespace characters are ignored. */
425
      skip_spaces( &cur, limit );
426
      if ( cur >= limit )
427
        break;
428
 
429
      if ( !IS_PS_XDIGIT( *cur ) )
430
        break;
431
    }
432
 
433
    if ( cur < limit && *cur != '>' )
434
    {
435
      FT_ERROR(( "skip_string: missing closing delimiter `>'\n" ));
436
      err = FT_THROW( Invalid_File_Format );
437
    }
438
    else
439
      cur++;
440
 
441
    *acur = cur;
442
    return err;
443
  }
444
 
445
 
446
  /* first character must be the opening brace that */
447
  /* starts the procedure                           */
448
 
449
  /* NB: [ and ] need not match:                    */
450
  /* `/foo {[} def' is a valid PostScript fragment, */
451
  /* even within a Type1 font                       */
452
 
453
  static FT_Error
454
  skip_procedure( FT_Byte*  *acur,
455
                  FT_Byte*   limit )
456
  {
457
    FT_Byte*  cur;
458
    FT_Int    embed = 0;
459
    FT_Error  error = FT_Err_Ok;
460
 
461
 
462
    FT_ASSERT( **acur == '{' );
463
 
464
    for ( cur = *acur; cur < limit && error == FT_Err_Ok; ++cur )
465
    {
466
      switch ( *cur )
467
      {
468
      case '{':
469
        ++embed;
470
        break;
471
 
472
      case '}':
473
        --embed;
474
        if ( embed == 0 )
475
        {
476
          ++cur;
477
          goto end;
478
        }
479
        break;
480
 
481
      case '(':
482
        error = skip_literal_string( &cur, limit );
483
        break;
484
 
485
      case '<':
486
        error = skip_string( &cur, limit );
487
        break;
488
 
489
      case '%':
490
        skip_comment( &cur, limit );
491
        break;
492
      }
493
    }
494
 
495
  end:
496
    if ( embed != 0 )
497
      error = FT_THROW( Invalid_File_Format );
498
 
499
    *acur = cur;
500
 
501
    return error;
502
  }
503
 
504
 
505
  /***********************************************************************/
506
  /*                                                                     */
507
  /* All exported parsing routines handle leading whitespace and stop at */
508
  /* the first character which isn't part of the just handled token.     */
509
  /*                                                                     */
510
  /***********************************************************************/
511
 
512
 
513
  FT_LOCAL_DEF( void )
514
  ps_parser_skip_PS_token( PS_Parser  parser )
515
  {
516
    /* Note: PostScript allows any non-delimiting, non-whitespace        */
517
    /*       character in a name (PS Ref Manual, 3rd ed, p31).           */
518
    /*       PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */
519
 
520
    FT_Byte*  cur   = parser->cursor;
521
    FT_Byte*  limit = parser->limit;
522
    FT_Error  error = FT_Err_Ok;
523
 
524
 
525
    skip_spaces( &cur, limit );             /* this also skips comments */
526
    if ( cur >= limit )
527
      goto Exit;
528
 
529
    /* self-delimiting, single-character tokens */
530
    if ( *cur == '[' || *cur == ']' )
531
    {
532
      cur++;
533
      goto Exit;
534
    }
535
 
536
    /* skip balanced expressions (procedures and strings) */
537
 
538
    if ( *cur == '{' )                              /* {...} */
539
    {
540
      error = skip_procedure( &cur, limit );
541
      goto Exit;
542
    }
543
 
544
    if ( *cur == '(' )                              /* (...) */
545
    {
546
      error = skip_literal_string( &cur, limit );
547
      goto Exit;
548
    }
549
 
550
    if ( *cur == '<' )                              /* <...> */
551
    {
552
      if ( cur + 1 < limit && *(cur + 1) == '<' )   /* << */
553
      {
554
        cur++;
555
        cur++;
556
      }
557
      else
558
        error = skip_string( &cur, limit );
559
 
560
      goto Exit;
561
    }
562
 
563
    if ( *cur == '>' )
564
    {
565
      cur++;
566
      if ( cur >= limit || *cur != '>' )             /* >> */
567
      {
568
        FT_ERROR(( "ps_parser_skip_PS_token:"
569
                   " unexpected closing delimiter `>'\n" ));
570
        error = FT_THROW( Invalid_File_Format );
571
        goto Exit;
572
      }
573
      cur++;
574
      goto Exit;
575
    }
576
 
577
    if ( *cur == '/' )
578
      cur++;
579
 
580
    /* anything else */
581
    while ( cur < limit )
582
    {
583
      /* *cur might be invalid (e.g., ')' or '}'), but this   */
584
      /* is handled by the test `cur == parser->cursor' below */
585
      if ( IS_PS_DELIM( *cur ) )
586
        break;
587
 
588
      cur++;
589
    }
590
 
591
  Exit:
592
    if ( cur < limit && cur == parser->cursor )
593
    {
594
      FT_ERROR(( "ps_parser_skip_PS_token:"
595
                 " current token is `%c' which is self-delimiting\n"
596
                 "                        "
597
                 " but invalid at this point\n",
598
                 *cur ));
599
 
600
      error = FT_THROW( Invalid_File_Format );
601
    }
602
 
603
    parser->error  = error;
604
    parser->cursor = cur;
605
  }
606
 
607
 
608
  FT_LOCAL_DEF( void )
609
  ps_parser_skip_spaces( PS_Parser  parser )
610
  {
611
    skip_spaces( &parser->cursor, parser->limit );
612
  }
613
 
614
 
615
  /* `token' here means either something between balanced delimiters */
616
  /* or the next token; the delimiters are not removed.              */
617
 
618
  FT_LOCAL_DEF( void )
619
  ps_parser_to_token( PS_Parser  parser,
620
                      T1_Token   token )
621
  {
622
    FT_Byte*  cur;
623
    FT_Byte*  limit;
624
    FT_Int    embed;
625
 
626
 
627
    token->type  = T1_TOKEN_TYPE_NONE;
628
    token->start = 0;
629
    token->limit = 0;
630
 
631
    /* first of all, skip leading whitespace */
632
    ps_parser_skip_spaces( parser );
633
 
634
    cur   = parser->cursor;
635
    limit = parser->limit;
636
 
637
    if ( cur >= limit )
638
      return;
639
 
640
    switch ( *cur )
641
    {
642
      /************* check for literal string *****************/
643
    case '(':
644
      token->type  = T1_TOKEN_TYPE_STRING;
645
      token->start = cur;
646
 
647
      if ( skip_literal_string( &cur, limit ) == FT_Err_Ok )
648
        token->limit = cur;
649
      break;
650
 
651
      /************* check for programs/array *****************/
652
    case '{':
653
      token->type  = T1_TOKEN_TYPE_ARRAY;
654
      token->start = cur;
655
 
656
      if ( skip_procedure( &cur, limit ) == FT_Err_Ok )
657
        token->limit = cur;
658
      break;
659
 
660
      /************* check for table/array ********************/
661
      /* XXX: in theory we should also look for "<<"          */
662
      /*      since this is semantically equivalent to "[";   */
663
      /*      in practice it doesn't matter (?)               */
664
    case '[':
665
      token->type  = T1_TOKEN_TYPE_ARRAY;
666
      embed        = 1;
667
      token->start = cur++;
668
 
669
      /* we need this to catch `[ ]' */
670
      parser->cursor = cur;
671
      ps_parser_skip_spaces( parser );
672
      cur = parser->cursor;
673
 
674
      while ( cur < limit && !parser->error )
675
      {
676
        /* XXX: this is wrong because it does not      */
677
        /*      skip comments, procedures, and strings */
678
        if ( *cur == '[' )
679
          embed++;
680
        else if ( *cur == ']' )
681
        {
682
          embed--;
683
          if ( embed <= 0 )
684
          {
685
            token->limit = ++cur;
686
            break;
687
          }
688
        }
689
 
690
        parser->cursor = cur;
691
        ps_parser_skip_PS_token( parser );
692
        /* we need this to catch `[XXX ]' */
693
        ps_parser_skip_spaces  ( parser );
694
        cur = parser->cursor;
695
      }
696
      break;
697
 
698
      /* ************ otherwise, it is any token **************/
699
    default:
700
      token->start = cur;
701
      token->type  = ( *cur == '/' ? T1_TOKEN_TYPE_KEY : T1_TOKEN_TYPE_ANY );
702
      ps_parser_skip_PS_token( parser );
703
      cur = parser->cursor;
704
      if ( !parser->error )
705
        token->limit = cur;
706
    }
707
 
708
    if ( !token->limit )
709
    {
710
      token->start = 0;
711
      token->type  = T1_TOKEN_TYPE_NONE;
712
    }
713
 
714
    parser->cursor = cur;
715
  }
716
 
717
 
718
  /* NB: `tokens' can be NULL if we only want to count */
719
  /* the number of array elements                      */
720
 
721
  FT_LOCAL_DEF( void )
722
  ps_parser_to_token_array( PS_Parser  parser,
723
                            T1_Token   tokens,
724
                            FT_UInt    max_tokens,
725
                            FT_Int*    pnum_tokens )
726
  {
727
    T1_TokenRec  master;
728
 
729
 
730
    *pnum_tokens = -1;
731
 
732
    /* this also handles leading whitespace */
733
    ps_parser_to_token( parser, &master );
734
 
735
    if ( master.type == T1_TOKEN_TYPE_ARRAY )
736
    {
737
      FT_Byte*  old_cursor = parser->cursor;
738
      FT_Byte*  old_limit  = parser->limit;
739
      T1_Token  cur        = tokens;
740
      T1_Token  limit      = cur + max_tokens;
741
 
742
 
743
      /* don't include outermost delimiters */
744
      parser->cursor = master.start + 1;
745
      parser->limit  = master.limit - 1;
746
 
747
      while ( parser->cursor < parser->limit )
748
      {
749
        T1_TokenRec  token;
750
 
751
 
752
        ps_parser_to_token( parser, &token );
753
        if ( !token.type )
754
          break;
755
 
756
        if ( tokens != NULL && cur < limit )
757
          *cur = token;
758
 
759
        cur++;
760
      }
761
 
762
      *pnum_tokens = (FT_Int)( cur - tokens );
763
 
764
      parser->cursor = old_cursor;
765
      parser->limit  = old_limit;
766
    }
767
  }
768
 
769
 
770
  /* first character must be a delimiter or a part of a number */
771
  /* NB: `coords' can be NULL if we just want to skip the      */
772
  /*     array; in this case we ignore `max_coords'            */
773
 
774
  static FT_Int
775
  ps_tocoordarray( FT_Byte*  *acur,
776
                   FT_Byte*   limit,
777
                   FT_Int     max_coords,
778
                   FT_Short*  coords )
779
  {
780
    FT_Byte*  cur   = *acur;
781
    FT_Int    count = 0;
782
    FT_Byte   c, ender;
783
 
784
 
785
    if ( cur >= limit )
786
      goto Exit;
787
 
788
    /* check for the beginning of an array; otherwise, only one number */
789
    /* will be read                                                    */
790
    c     = *cur;
791
    ender = 0;
792
 
793
    if ( c == '[' )
794
      ender = ']';
795
    else if ( c == '{' )
796
      ender = '}';
797
 
798
    if ( ender )
799
      cur++;
800
 
801
    /* now, read the coordinates */
802
    while ( cur < limit )
803
    {
804
      FT_Short  dummy;
805
      FT_Byte*  old_cur;
806
 
807
 
808
      /* skip whitespace in front of data */
809
      skip_spaces( &cur, limit );
810
      if ( cur >= limit )
811
        goto Exit;
812
 
813
      if ( *cur == ender )
814
      {
815
        cur++;
816
        break;
817
      }
818
 
819
      old_cur = cur;
820
 
821
      if ( coords != NULL && count >= max_coords )
822
        break;
823
 
824
      /* call PS_Conv_ToFixed() even if coords == NULL */
825
      /* to properly parse number at `cur'             */
826
      *( coords != NULL ? &coords[count] : &dummy ) =
827
        (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 );
828
 
829
      if ( old_cur == cur )
830
      {
831
        count = -1;
832
        goto Exit;
833
      }
834
      else
835
        count++;
836
 
837
      if ( !ender )
838
        break;
839
    }
840
 
841
  Exit:
842
    *acur = cur;
843
    return count;
844
  }
845
 
846
 
847
  /* first character must be a delimiter or a part of a number */
848
  /* NB: `values' can be NULL if we just want to skip the      */
849
  /*     array; in this case we ignore `max_values'            */
850
 
851
  static FT_Int
852
  ps_tofixedarray( FT_Byte*  *acur,
853
                   FT_Byte*   limit,
854
                   FT_Int     max_values,
855
                   FT_Fixed*  values,
856
                   FT_Int     power_ten )
857
  {
858
    FT_Byte*  cur   = *acur;
859
    FT_Int    count = 0;
860
    FT_Byte   c, ender;
861
 
862
 
863
    if ( cur >= limit )
864
      goto Exit;
865
 
866
    /* Check for the beginning of an array.  Otherwise, only one number */
867
    /* will be read.                                                    */
868
    c     = *cur;
869
    ender = 0;
870
 
871
    if ( c == '[' )
872
      ender = ']';
873
    else if ( c == '{' )
874
      ender = '}';
875
 
876
    if ( ender )
877
      cur++;
878
 
879
    /* now, read the values */
880
    while ( cur < limit )
881
    {
882
      FT_Fixed  dummy;
883
      FT_Byte*  old_cur;
884
 
885
 
886
      /* skip whitespace in front of data */
887
      skip_spaces( &cur, limit );
888
      if ( cur >= limit )
889
        goto Exit;
890
 
891
      if ( *cur == ender )
892
      {
893
        cur++;
894
        break;
895
      }
896
 
897
      old_cur = cur;
898
 
899
      if ( values != NULL && count >= max_values )
900
        break;
901
 
902
      /* call PS_Conv_ToFixed() even if coords == NULL */
903
      /* to properly parse number at `cur'             */
904
      *( values != NULL ? &values[count] : &dummy ) =
905
        PS_Conv_ToFixed( &cur, limit, power_ten );
906
 
907
      if ( old_cur == cur )
908
      {
909
        count = -1;
910
        goto Exit;
911
      }
912
      else
913
        count++;
914
 
915
      if ( !ender )
916
        break;
917
    }
918
 
919
  Exit:
920
    *acur = cur;
921
    return count;
922
  }
923
 
924
 
925
#if 0
926
 
927
  static FT_String*
928
  ps_tostring( FT_Byte**  cursor,
929
               FT_Byte*   limit,
930
               FT_Memory  memory )
931
  {
932
    FT_Byte*    cur = *cursor;
933
    FT_PtrDist  len = 0;
934
    FT_Int      count;
935
    FT_String*  result;
936
    FT_Error    error;
937
 
938
 
939
    /* XXX: some stupid fonts have a `Notice' or `Copyright' string     */
940
    /*      that simply doesn't begin with an opening parenthesis, even */
941
    /*      though they have a closing one!  E.g. "amuncial.pfb"        */
942
    /*                                                                  */
943
    /*      We must deal with these ill-fated cases there.  Note that   */
944
    /*      these fonts didn't work with the old Type 1 driver as the   */
945
    /*      notice/copyright was not recognized as a valid string token */
946
    /*      and made the old token parser commit errors.                */
947
 
948
    while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) )
949
      cur++;
950
    if ( cur + 1 >= limit )
951
      return 0;
952
 
953
    if ( *cur == '(' )
954
      cur++;  /* skip the opening parenthesis, if there is one */
955
 
956
    *cursor = cur;
957
    count   = 0;
958
 
959
    /* then, count its length */
960
    for ( ; cur < limit; cur++ )
961
    {
962
      if ( *cur == '(' )
963
        count++;
964
 
965
      else if ( *cur == ')' )
966
      {
967
        count--;
968
        if ( count < 0 )
969
          break;
970
      }
971
    }
972
 
973
    len = cur - *cursor;
974
    if ( cur >= limit || FT_ALLOC( result, len + 1 ) )
975
      return 0;
976
 
977
    /* now copy the string */
978
    FT_MEM_COPY( result, *cursor, len );
979
    result[len] = '\0';
980
    *cursor = cur;
981
    return result;
982
  }
983
 
984
#endif /* 0 */
985
 
986
 
987
  static int
988
  ps_tobool( FT_Byte*  *acur,
989
             FT_Byte*   limit )
990
  {
991
    FT_Byte*  cur    = *acur;
992
    FT_Bool   result = 0;
993
 
994
 
995
    /* return 1 if we find `true', 0 otherwise */
996
    if ( cur + 3 < limit &&
997
         cur[0] == 't'   &&
998
         cur[1] == 'r'   &&
999
         cur[2] == 'u'   &&
1000
         cur[3] == 'e'   )
1001
    {
1002
      result = 1;
1003
      cur   += 5;
1004
    }
1005
    else if ( cur + 4 < limit &&
1006
              cur[0] == 'f'   &&
1007
              cur[1] == 'a'   &&
1008
              cur[2] == 'l'   &&
1009
              cur[3] == 's'   &&
1010
              cur[4] == 'e'   )
1011
    {
1012
      result = 0;
1013
      cur   += 6;
1014
    }
1015
 
1016
    *acur = cur;
1017
    return result;
1018
  }
1019
 
1020
 
1021
  /* load a simple field (i.e. non-table) into the current list of objects */
1022
 
1023
  FT_LOCAL_DEF( FT_Error )
1024
  ps_parser_load_field( PS_Parser       parser,
1025
                        const T1_Field  field,
1026
                        void**          objects,
1027
                        FT_UInt         max_objects,
1028
                        FT_ULong*       pflags )
1029
  {
1030
    T1_TokenRec   token;
1031
    FT_Byte*      cur;
1032
    FT_Byte*      limit;
1033
    FT_UInt       count;
1034
    FT_UInt       idx;
1035
    FT_Error      error;
1036
    T1_FieldType  type;
1037
 
1038
 
1039
    /* this also skips leading whitespace */
1040
    ps_parser_to_token( parser, &token );
1041
    if ( !token.type )
1042
      goto Fail;
1043
 
1044
    count = 1;
1045
    idx   = 0;
1046
    cur   = token.start;
1047
    limit = token.limit;
1048
 
1049
    type = field->type;
1050
 
1051
    /* we must detect arrays in /FontBBox */
1052
    if ( type == T1_FIELD_TYPE_BBOX )
1053
    {
1054
      T1_TokenRec  token2;
1055
      FT_Byte*     old_cur   = parser->cursor;
1056
      FT_Byte*     old_limit = parser->limit;
1057
 
1058
 
1059
      /* don't include delimiters */
1060
      parser->cursor = token.start + 1;
1061
      parser->limit  = token.limit - 1;
1062
 
1063
      ps_parser_to_token( parser, &token2 );
1064
      parser->cursor = old_cur;
1065
      parser->limit  = old_limit;
1066
 
1067
      if ( token2.type == T1_TOKEN_TYPE_ARRAY )
1068
      {
1069
        type = T1_FIELD_TYPE_MM_BBOX;
1070
        goto FieldArray;
1071
      }
1072
    }
1073
    else if ( token.type == T1_TOKEN_TYPE_ARRAY )
1074
    {
1075
      count = max_objects;
1076
 
1077
    FieldArray:
1078
      /* if this is an array and we have no blend, an error occurs */
1079
      if ( max_objects == 0 )
1080
        goto Fail;
1081
 
1082
      idx = 1;
1083
 
1084
      /* don't include delimiters */
1085
      cur++;
1086
      limit--;
1087
    }
1088
 
1089
    for ( ; count > 0; count--, idx++ )
1090
    {
1091
      FT_Byte*    q = (FT_Byte*)objects[idx] + field->offset;
1092
      FT_Long     val;
1093
      FT_String*  string;
1094
 
1095
 
1096
      skip_spaces( &cur, limit );
1097
 
1098
      switch ( type )
1099
      {
1100
      case T1_FIELD_TYPE_BOOL:
1101
        val = ps_tobool( &cur, limit );
1102
        goto Store_Integer;
1103
 
1104
      case T1_FIELD_TYPE_FIXED:
1105
        val = PS_Conv_ToFixed( &cur, limit, 0 );
1106
        goto Store_Integer;
1107
 
1108
      case T1_FIELD_TYPE_FIXED_1000:
1109
        val = PS_Conv_ToFixed( &cur, limit, 3 );
1110
        goto Store_Integer;
1111
 
1112
      case T1_FIELD_TYPE_INTEGER:
1113
        val = PS_Conv_ToInt( &cur, limit );
1114
        /* fall through */
1115
 
1116
      Store_Integer:
1117
        switch ( field->size )
1118
        {
1119
        case (8 / FT_CHAR_BIT):
1120
          *(FT_Byte*)q = (FT_Byte)val;
1121
          break;
1122
 
1123
        case (16 / FT_CHAR_BIT):
1124
          *(FT_UShort*)q = (FT_UShort)val;
1125
          break;
1126
 
1127
        case (32 / FT_CHAR_BIT):
1128
          *(FT_UInt32*)q = (FT_UInt32)val;
1129
          break;
1130
 
1131
        default:                /* for 64-bit systems */
1132
          *(FT_Long*)q = val;
1133
        }
1134
        break;
1135
 
1136
      case T1_FIELD_TYPE_STRING:
1137
      case T1_FIELD_TYPE_KEY:
1138
        {
1139
          FT_Memory  memory = parser->memory;
1140
          FT_UInt    len    = (FT_UInt)( limit - cur );
1141
 
1142
 
1143
          if ( cur >= limit )
1144
            break;
1145
 
1146
          /* we allow both a string or a name   */
1147
          /* for cases like /FontName (foo) def */
1148
          if ( token.type == T1_TOKEN_TYPE_KEY )
1149
          {
1150
            /* don't include leading `/' */
1151
            len--;
1152
            cur++;
1153
          }
1154
          else if ( token.type == T1_TOKEN_TYPE_STRING )
1155
          {
1156
            /* don't include delimiting parentheses    */
1157
            /* XXX we don't handle <<...>> here        */
1158
            /* XXX should we convert octal escapes?    */
1159
            /*     if so, what encoding should we use? */
1160
            cur++;
1161
            len -= 2;
1162
          }
1163
          else
1164
          {
1165
            FT_ERROR(( "ps_parser_load_field:"
1166
                       " expected a name or string\n"
1167
                       "                     "
1168
                       " but found token of type %d instead\n",
1169
                       token.type ));
1170
            error = FT_THROW( Invalid_File_Format );
1171
            goto Exit;
1172
          }
1173
 
1174
          /* for this to work (FT_String**)q must have been */
1175
          /* initialized to NULL                            */
1176
          if ( *(FT_String**)q != NULL )
1177
          {
1178
            FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n",
1179
                        field->ident ));
1180
            FT_FREE( *(FT_String**)q );
1181
            *(FT_String**)q = NULL;
1182
          }
1183
 
1184
          if ( FT_ALLOC( string, len + 1 ) )
1185
            goto Exit;
1186
 
1187
          FT_MEM_COPY( string, cur, len );
1188
          string[len] = 0;
1189
 
1190
          *(FT_String**)q = string;
1191
        }
1192
        break;
1193
 
1194
      case T1_FIELD_TYPE_BBOX:
1195
        {
1196
          FT_Fixed  temp[4];
1197
          FT_BBox*  bbox = (FT_BBox*)q;
1198
          FT_Int    result;
1199
 
1200
 
1201
          result = ps_tofixedarray( &cur, limit, 4, temp, 0 );
1202
 
1203
          if ( result < 0 )
1204
          {
1205
            FT_ERROR(( "ps_parser_load_field:"
1206
                       " expected four integers in bounding box\n" ));
1207
            error = FT_THROW( Invalid_File_Format );
1208
            goto Exit;
1209
          }
1210
 
1211
          bbox->xMin = FT_RoundFix( temp[0] );
1212
          bbox->yMin = FT_RoundFix( temp[1] );
1213
          bbox->xMax = FT_RoundFix( temp[2] );
1214
          bbox->yMax = FT_RoundFix( temp[3] );
1215
        }
1216
        break;
1217
 
1218
      case T1_FIELD_TYPE_MM_BBOX:
1219
        {
1220
          FT_Memory  memory = parser->memory;
1221
          FT_Fixed*  temp;
1222
          FT_Int     result;
1223
          FT_UInt    i;
1224
 
1225
 
1226
          if ( FT_NEW_ARRAY( temp, max_objects * 4 ) )
1227
            goto Exit;
1228
 
1229
          for ( i = 0; i < 4; i++ )
1230
          {
1231
            result = ps_tofixedarray( &cur, limit, max_objects,
1232
                                      temp + i * max_objects, 0 );
1233
            if ( result < 0 )
1234
            {
1235
              FT_ERROR(( "ps_parser_load_field:"
1236
                         " expected %d integers in the %s subarray\n"
1237
                         "                     "
1238
                         " of /FontBBox in the /Blend dictionary\n",
1239
                         max_objects,
1240
                         i == 0 ? "first"
1241
                                : ( i == 1 ? "second"
1242
                                           : ( i == 2 ? "third"
1243
                                                      : "fourth" ) ) ));
1244
              error = FT_THROW( Invalid_File_Format );
1245
              goto Exit;
1246
            }
1247
 
1248
            skip_spaces( &cur, limit );
1249
          }
1250
 
1251
          for ( i = 0; i < max_objects; i++ )
1252
          {
1253
            FT_BBox*  bbox = (FT_BBox*)objects[i];
1254
 
1255
 
1256
            bbox->xMin = FT_RoundFix( temp[i                  ] );
1257
            bbox->yMin = FT_RoundFix( temp[i +     max_objects] );
1258
            bbox->xMax = FT_RoundFix( temp[i + 2 * max_objects] );
1259
            bbox->yMax = FT_RoundFix( temp[i + 3 * max_objects] );
1260
          }
1261
 
1262
          FT_FREE( temp );
1263
        }
1264
        break;
1265
 
1266
      default:
1267
        /* an error occurred */
1268
        goto Fail;
1269
      }
1270
    }
1271
 
1272
#if 0  /* obsolete -- keep for reference */
1273
    if ( pflags )
1274
      *pflags |= 1L << field->flag_bit;
1275
#else
1276
    FT_UNUSED( pflags );
1277
#endif
1278
 
1279
    error = FT_Err_Ok;
1280
 
1281
  Exit:
1282
    return error;
1283
 
1284
  Fail:
1285
    error = FT_THROW( Invalid_File_Format );
1286
    goto Exit;
1287
  }
1288
 
1289
 
1290
#define T1_MAX_TABLE_ELEMENTS  32
1291
 
1292
 
1293
  FT_LOCAL_DEF( FT_Error )
1294
  ps_parser_load_field_table( PS_Parser       parser,
1295
                              const T1_Field  field,
1296
                              void**          objects,
1297
                              FT_UInt         max_objects,
1298
                              FT_ULong*       pflags )
1299
  {
1300
    T1_TokenRec  elements[T1_MAX_TABLE_ELEMENTS];
1301
    T1_Token     token;
1302
    FT_Int       num_elements;
1303
    FT_Error     error = FT_Err_Ok;
1304
    FT_Byte*     old_cursor;
1305
    FT_Byte*     old_limit;
1306
    T1_FieldRec  fieldrec = *(T1_Field)field;
1307
 
1308
 
1309
    fieldrec.type = T1_FIELD_TYPE_INTEGER;
1310
    if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY ||
1311
         field->type == T1_FIELD_TYPE_BBOX        )
1312
      fieldrec.type = T1_FIELD_TYPE_FIXED;
1313
 
1314
    ps_parser_to_token_array( parser, elements,
1315
                              T1_MAX_TABLE_ELEMENTS, &num_elements );
1316
    if ( num_elements < 0 )
1317
    {
1318
      error = FT_ERR( Ignore );
1319
      goto Exit;
1320
    }
1321
    if ( (FT_UInt)num_elements > field->array_max )
1322
      num_elements = field->array_max;
1323
 
1324
    old_cursor = parser->cursor;
1325
    old_limit  = parser->limit;
1326
 
1327
    /* we store the elements count if necessary;           */
1328
    /* we further assume that `count_offset' can't be zero */
1329
    if ( field->type != T1_FIELD_TYPE_BBOX && field->count_offset != 0 )
1330
      *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
1331
        (FT_Byte)num_elements;
1332
 
1333
    /* we now load each element, adjusting the field.offset on each one */
1334
    token = elements;
1335
    for ( ; num_elements > 0; num_elements--, token++ )
1336
    {
1337
      parser->cursor = token->start;
1338
      parser->limit  = token->limit;
1339
      ps_parser_load_field( parser, &fieldrec, objects, max_objects, 0 );
1340
      fieldrec.offset += fieldrec.size;
1341
    }
1342
 
1343
#if 0  /* obsolete -- keep for reference */
1344
    if ( pflags )
1345
      *pflags |= 1L << field->flag_bit;
1346
#else
1347
    FT_UNUSED( pflags );
1348
#endif
1349
 
1350
    parser->cursor = old_cursor;
1351
    parser->limit  = old_limit;
1352
 
1353
  Exit:
1354
    return error;
1355
  }
1356
 
1357
 
1358
  FT_LOCAL_DEF( FT_Long )
1359
  ps_parser_to_int( PS_Parser  parser )
1360
  {
1361
    ps_parser_skip_spaces( parser );
1362
    return PS_Conv_ToInt( &parser->cursor, parser->limit );
1363
  }
1364
 
1365
 
1366
  /* first character must be `<' if `delimiters' is non-zero */
1367
 
1368
  FT_LOCAL_DEF( FT_Error )
1369
  ps_parser_to_bytes( PS_Parser  parser,
1370
                      FT_Byte*   bytes,
1371
                      FT_Offset  max_bytes,
1372
                      FT_Long*   pnum_bytes,
1373
                      FT_Bool    delimiters )
1374
  {
1375
    FT_Error  error = FT_Err_Ok;
1376
    FT_Byte*  cur;
1377
 
1378
 
1379
    ps_parser_skip_spaces( parser );
1380
    cur = parser->cursor;
1381
 
1382
    if ( cur >= parser->limit )
1383
      goto Exit;
1384
 
1385
    if ( delimiters )
1386
    {
1387
      if ( *cur != '<' )
1388
      {
1389
        FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" ));
1390
        error = FT_THROW( Invalid_File_Format );
1391
        goto Exit;
1392
      }
1393
 
1394
      cur++;
1395
    }
1396
 
1397
    *pnum_bytes = PS_Conv_ASCIIHexDecode( &cur,
1398
                                          parser->limit,
1399
                                          bytes,
1400
                                          max_bytes );
1401
 
1402
    if ( delimiters )
1403
    {
1404
      if ( cur < parser->limit && *cur != '>' )
1405
      {
1406
        FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" ));
1407
        error = FT_THROW( Invalid_File_Format );
1408
        goto Exit;
1409
      }
1410
 
1411
      cur++;
1412
    }
1413
 
1414
    parser->cursor = cur;
1415
 
1416
  Exit:
1417
    return error;
1418
  }
1419
 
1420
 
1421
  FT_LOCAL_DEF( FT_Fixed )
1422
  ps_parser_to_fixed( PS_Parser  parser,
1423
                      FT_Int     power_ten )
1424
  {
1425
    ps_parser_skip_spaces( parser );
1426
    return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten );
1427
  }
1428
 
1429
 
1430
  FT_LOCAL_DEF( FT_Int )
1431
  ps_parser_to_coord_array( PS_Parser  parser,
1432
                            FT_Int     max_coords,
1433
                            FT_Short*  coords )
1434
  {
1435
    ps_parser_skip_spaces( parser );
1436
    return ps_tocoordarray( &parser->cursor, parser->limit,
1437
                            max_coords, coords );
1438
  }
1439
 
1440
 
1441
  FT_LOCAL_DEF( FT_Int )
1442
  ps_parser_to_fixed_array( PS_Parser  parser,
1443
                            FT_Int     max_values,
1444
                            FT_Fixed*  values,
1445
                            FT_Int     power_ten )
1446
  {
1447
    ps_parser_skip_spaces( parser );
1448
    return ps_tofixedarray( &parser->cursor, parser->limit,
1449
                            max_values, values, power_ten );
1450
  }
1451
 
1452
 
1453
#if 0
1454
 
1455
  FT_LOCAL_DEF( FT_String* )
1456
  T1_ToString( PS_Parser  parser )
1457
  {
1458
    return ps_tostring( &parser->cursor, parser->limit, parser->memory );
1459
  }
1460
 
1461
 
1462
  FT_LOCAL_DEF( FT_Bool )
1463
  T1_ToBool( PS_Parser  parser )
1464
  {
1465
    return ps_tobool( &parser->cursor, parser->limit );
1466
  }
1467
 
1468
#endif /* 0 */
1469
 
1470
 
1471
  FT_LOCAL_DEF( void )
1472
  ps_parser_init( PS_Parser  parser,
1473
                  FT_Byte*   base,
1474
                  FT_Byte*   limit,
1475
                  FT_Memory  memory )
1476
  {
1477
    parser->error  = FT_Err_Ok;
1478
    parser->base   = base;
1479
    parser->limit  = limit;
1480
    parser->cursor = base;
1481
    parser->memory = memory;
1482
    parser->funcs  = ps_parser_funcs;
1483
  }
1484
 
1485
 
1486
  FT_LOCAL_DEF( void )
1487
  ps_parser_done( PS_Parser  parser )
1488
  {
1489
    FT_UNUSED( parser );
1490
  }
1491
 
1492
 
1493
  /*************************************************************************/
1494
  /*************************************************************************/
1495
  /*****                                                               *****/
1496
  /*****                            T1 BUILDER                         *****/
1497
  /*****                                                               *****/
1498
  /*************************************************************************/
1499
  /*************************************************************************/
1500
 
1501
  /*************************************************************************/
1502
  /*                                                                       */
1503
  /*                                                             */
1504
  /*    t1_builder_init                                                    */
1505
  /*                                                                       */
1506
  /*                                                          */
1507
  /*    Initializes a given glyph builder.                                 */
1508
  /*                                                                       */
1509
  /*                                                                */
1510
  /*    builder :: A pointer to the glyph builder to initialize.           */
1511
  /*                                                                       */
1512
  /*                                                                */
1513
  /*    face    :: The current face object.                                */
1514
  /*                                                                       */
1515
  /*    size    :: The current size object.                                */
1516
  /*                                                                       */
1517
  /*    glyph   :: The current glyph object.                               */
1518
  /*                                                                       */
1519
  /*    hinting :: Whether hinting should be applied.                      */
1520
  /*                                                                       */
1521
  FT_LOCAL_DEF( void )
1522
  t1_builder_init( T1_Builder    builder,
1523
                   FT_Face       face,
1524
                   FT_Size       size,
1525
                   FT_GlyphSlot  glyph,
1526
                   FT_Bool       hinting )
1527
  {
1528
    builder->parse_state = T1_Parse_Start;
1529
    builder->load_points = 1;
1530
 
1531
    builder->face   = face;
1532
    builder->glyph  = glyph;
1533
    builder->memory = face->memory;
1534
 
1535
    if ( glyph )
1536
    {
1537
      FT_GlyphLoader  loader = glyph->internal->loader;
1538
 
1539
 
1540
      builder->loader  = loader;
1541
      builder->base    = &loader->base.outline;
1542
      builder->current = &loader->current.outline;
1543
      FT_GlyphLoader_Rewind( loader );
1544
 
1545
      builder->hints_globals = size->internal;
1546
      builder->hints_funcs   = 0;
1547
 
1548
      if ( hinting )
1549
        builder->hints_funcs = glyph->internal->glyph_hints;
1550
    }
1551
 
1552
    builder->pos_x = 0;
1553
    builder->pos_y = 0;
1554
 
1555
    builder->left_bearing.x = 0;
1556
    builder->left_bearing.y = 0;
1557
    builder->advance.x      = 0;
1558
    builder->advance.y      = 0;
1559
 
1560
    builder->funcs = t1_builder_funcs;
1561
  }
1562
 
1563
 
1564
  /*************************************************************************/
1565
  /*                                                                       */
1566
  /*                                                             */
1567
  /*    t1_builder_done                                                    */
1568
  /*                                                                       */
1569
  /*                                                          */
1570
  /*    Finalizes a given glyph builder.  Its contents can still be used   */
1571
  /*    after the call, but the function saves important information       */
1572
  /*    within the corresponding glyph slot.                               */
1573
  /*                                                                       */
1574
  /*                                                                */
1575
  /*    builder :: A pointer to the glyph builder to finalize.             */
1576
  /*                                                                       */
1577
  FT_LOCAL_DEF( void )
1578
  t1_builder_done( T1_Builder  builder )
1579
  {
1580
    FT_GlyphSlot  glyph = builder->glyph;
1581
 
1582
 
1583
    if ( glyph )
1584
      glyph->outline = *builder->base;
1585
  }
1586
 
1587
 
1588
  /* check that there is enough space for `count' more points */
1589
  FT_LOCAL_DEF( FT_Error )
1590
  t1_builder_check_points( T1_Builder  builder,
1591
                           FT_Int      count )
1592
  {
1593
    return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 );
1594
  }
1595
 
1596
 
1597
  /* add a new point, do not check space */
1598
  FT_LOCAL_DEF( void )
1599
  t1_builder_add_point( T1_Builder  builder,
1600
                        FT_Pos      x,
1601
                        FT_Pos      y,
1602
                        FT_Byte     flag )
1603
  {
1604
    FT_Outline*  outline = builder->current;
1605
 
1606
 
1607
    if ( builder->load_points )
1608
    {
1609
      FT_Vector*  point   = outline->points + outline->n_points;
1610
      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points;
1611
 
1612
 
1613
      point->x = FIXED_TO_INT( x );
1614
      point->y = FIXED_TO_INT( y );
1615
      *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
1616
    }
1617
    outline->n_points++;
1618
  }
1619
 
1620
 
1621
  /* check space for a new on-curve point, then add it */
1622
  FT_LOCAL_DEF( FT_Error )
1623
  t1_builder_add_point1( T1_Builder  builder,
1624
                         FT_Pos      x,
1625
                         FT_Pos      y )
1626
  {
1627
    FT_Error  error;
1628
 
1629
 
1630
    error = t1_builder_check_points( builder, 1 );
1631
    if ( !error )
1632
      t1_builder_add_point( builder, x, y, 1 );
1633
 
1634
    return error;
1635
  }
1636
 
1637
 
1638
  /* check space for a new contour, then add it */
1639
  FT_LOCAL_DEF( FT_Error )
1640
  t1_builder_add_contour( T1_Builder  builder )
1641
  {
1642
    FT_Outline*  outline = builder->current;
1643
    FT_Error     error;
1644
 
1645
 
1646
    /* this might happen in invalid fonts */
1647
    if ( !outline )
1648
    {
1649
      FT_ERROR(( "t1_builder_add_contour: no outline to add points to\n" ));
1650
      return FT_THROW( Invalid_File_Format );
1651
    }
1652
 
1653
    if ( !builder->load_points )
1654
    {
1655
      outline->n_contours++;
1656
      return FT_Err_Ok;
1657
    }
1658
 
1659
    error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 );
1660
    if ( !error )
1661
    {
1662
      if ( outline->n_contours > 0 )
1663
        outline->contours[outline->n_contours - 1] =
1664
          (short)( outline->n_points - 1 );
1665
 
1666
      outline->n_contours++;
1667
    }
1668
 
1669
    return error;
1670
  }
1671
 
1672
 
1673
  /* if a path was begun, add its first on-curve point */
1674
  FT_LOCAL_DEF( FT_Error )
1675
  t1_builder_start_point( T1_Builder  builder,
1676
                          FT_Pos      x,
1677
                          FT_Pos      y )
1678
  {
1679
    FT_Error  error = FT_ERR( Invalid_File_Format );
1680
 
1681
 
1682
    /* test whether we are building a new contour */
1683
 
1684
    if ( builder->parse_state == T1_Parse_Have_Path )
1685
      error = FT_Err_Ok;
1686
    else
1687
    {
1688
      builder->parse_state = T1_Parse_Have_Path;
1689
      error = t1_builder_add_contour( builder );
1690
      if ( !error )
1691
        error = t1_builder_add_point1( builder, x, y );
1692
    }
1693
 
1694
    return error;
1695
  }
1696
 
1697
 
1698
  /* close the current contour */
1699
  FT_LOCAL_DEF( void )
1700
  t1_builder_close_contour( T1_Builder  builder )
1701
  {
1702
    FT_Outline*  outline = builder->current;
1703
    FT_Int       first;
1704
 
1705
 
1706
    if ( !outline )
1707
      return;
1708
 
1709
    first = outline->n_contours <= 1
1710
            ? 0 : outline->contours[outline->n_contours - 2] + 1;
1711
 
1712
    /* We must not include the last point in the path if it */
1713
    /* is located on the first point.                       */
1714
    if ( outline->n_points > 1 )
1715
    {
1716
      FT_Vector*  p1      = outline->points + first;
1717
      FT_Vector*  p2      = outline->points + outline->n_points - 1;
1718
      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points - 1;
1719
 
1720
 
1721
      /* `delete' last point only if it coincides with the first */
1722
      /* point and it is not a control point (which can happen). */
1723
      if ( p1->x == p2->x && p1->y == p2->y )
1724
        if ( *control == FT_CURVE_TAG_ON )
1725
          outline->n_points--;
1726
    }
1727
 
1728
    if ( outline->n_contours > 0 )
1729
    {
1730
      /* Don't add contours only consisting of one point, i.e.,  */
1731
      /* check whether the first and the last point is the same. */
1732
      if ( first == outline->n_points - 1 )
1733
      {
1734
        outline->n_contours--;
1735
        outline->n_points--;
1736
      }
1737
      else
1738
        outline->contours[outline->n_contours - 1] =
1739
          (short)( outline->n_points - 1 );
1740
    }
1741
  }
1742
 
1743
 
1744
  /*************************************************************************/
1745
  /*************************************************************************/
1746
  /*****                                                               *****/
1747
  /*****                            OTHER                              *****/
1748
  /*****                                                               *****/
1749
  /*************************************************************************/
1750
  /*************************************************************************/
1751
 
1752
  FT_LOCAL_DEF( void )
1753
  t1_decrypt( FT_Byte*   buffer,
1754
              FT_Offset  length,
1755
              FT_UShort  seed )
1756
  {
1757
    PS_Conv_EexecDecode( &buffer,
1758
                         buffer + length,
1759
                         buffer,
1760
                         length,
1761
                         &seed );
1762
  }
1763
 
1764
 
1765
/* END */