• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * psobjs.c
4  *
5  *   Auxiliary functions for PostScript fonts (body).
6  *
7  * Copyright (C) 1996-2019 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 <ft2build.h>
20 #include FT_INTERNAL_POSTSCRIPT_AUX_H
21 #include FT_INTERNAL_DEBUG_H
22 #include FT_INTERNAL_CALC_H
23 #include FT_DRIVER_H
24 
25 #include "psobjs.h"
26 #include "psconv.h"
27 
28 #include "psauxerr.h"
29 #include "psauxmod.h"
30 
31 
32   /**************************************************************************
33    *
34    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
35    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
36    * messages during execution.
37    */
38 #undef  FT_COMPONENT
39 #define FT_COMPONENT  psobjs
40 
41 
42   /*************************************************************************/
43   /*************************************************************************/
44   /*****                                                               *****/
45   /*****                             PS_TABLE                          *****/
46   /*****                                                               *****/
47   /*************************************************************************/
48   /*************************************************************************/
49 
50   /**************************************************************************
51    *
52    * @Function:
53    *   ps_table_new
54    *
55    * @Description:
56    *   Initializes a PS_Table.
57    *
58    * @InOut:
59    *   table ::
60    *     The address of the target table.
61    *
62    * @Input:
63    *   count ::
64    *     The table size = the maximum number of elements.
65    *
66    *   memory ::
67    *     The memory object to use for all subsequent
68    *     reallocations.
69    *
70    * @Return:
71    *   FreeType error code.  0 means success.
72    */
73   FT_LOCAL_DEF( FT_Error )
ps_table_new(PS_Table table,FT_Int count,FT_Memory memory)74   ps_table_new( PS_Table   table,
75                 FT_Int     count,
76                 FT_Memory  memory )
77   {
78     FT_Error  error;
79 
80 
81     table->memory = memory;
82     if ( FT_NEW_ARRAY( table->elements, count ) ||
83          FT_NEW_ARRAY( table->lengths,  count ) )
84       goto Exit;
85 
86     table->max_elems = count;
87     table->init      = 0xDEADBEEFUL;
88     table->num_elems = 0;
89     table->block     = NULL;
90     table->capacity  = 0;
91     table->cursor    = 0;
92 
93     *(PS_Table_FuncsRec*)&table->funcs = ps_table_funcs;
94 
95   Exit:
96     if ( error )
97       FT_FREE( table->elements );
98 
99     return error;
100   }
101 
102 
103   static void
shift_elements(PS_Table table,FT_Byte * old_base)104   shift_elements( PS_Table  table,
105                   FT_Byte*  old_base )
106   {
107     FT_PtrDist  delta  = table->block - old_base;
108     FT_Byte**   offset = table->elements;
109     FT_Byte**   limit  = offset + table->max_elems;
110 
111 
112     for ( ; offset < limit; offset++ )
113     {
114       if ( offset[0] )
115         offset[0] += delta;
116     }
117   }
118 
119 
120   static FT_Error
reallocate_t1_table(PS_Table table,FT_Offset new_size)121   reallocate_t1_table( PS_Table   table,
122                        FT_Offset  new_size )
123   {
124     FT_Memory  memory   = table->memory;
125     FT_Byte*   old_base = table->block;
126     FT_Error   error;
127 
128 
129     /* allocate new base block */
130     if ( FT_ALLOC( table->block, new_size ) )
131     {
132       table->block = old_base;
133       return error;
134     }
135 
136     /* copy elements and shift offsets */
137     if ( old_base )
138     {
139       FT_MEM_COPY( table->block, old_base, table->capacity );
140       shift_elements( table, old_base );
141       FT_FREE( old_base );
142     }
143 
144     table->capacity = new_size;
145 
146     return FT_Err_Ok;
147   }
148 
149 
150   /**************************************************************************
151    *
152    * @Function:
153    *   ps_table_add
154    *
155    * @Description:
156    *   Adds an object to a PS_Table, possibly growing its memory block.
157    *
158    * @InOut:
159    *   table ::
160    *     The target table.
161    *
162    * @Input:
163    *   idx ::
164    *     The index of the object in the table.
165    *
166    *   object ::
167    *     The address of the object to copy in memory.
168    *
169    *   length ::
170    *     The length in bytes of the source object.
171    *
172    * @Return:
173    *   FreeType error code.  0 means success.  An error is returned if a
174    *   reallocation fails.
175    */
176   FT_LOCAL_DEF( FT_Error )
ps_table_add(PS_Table table,FT_Int idx,const void * object,FT_UInt length)177   ps_table_add( PS_Table     table,
178                 FT_Int       idx,
179                 const void*  object,
180                 FT_UInt      length )
181   {
182     if ( idx < 0 || idx >= table->max_elems )
183     {
184       FT_ERROR(( "ps_table_add: invalid index\n" ));
185       return FT_THROW( Invalid_Argument );
186     }
187 
188     /* grow the base block if needed */
189     if ( table->cursor + length > table->capacity )
190     {
191       FT_Error    error;
192       FT_Offset   new_size = table->capacity;
193       FT_PtrDist  in_offset;
194 
195 
196       in_offset = (FT_Byte*)object - table->block;
197       if ( in_offset < 0 || (FT_Offset)in_offset >= table->capacity )
198         in_offset = -1;
199 
200       while ( new_size < table->cursor + length )
201       {
202         /* increase size by 25% and round up to the nearest multiple
203            of 1024 */
204         new_size += ( new_size >> 2 ) + 1;
205         new_size  = FT_PAD_CEIL( new_size, 1024 );
206       }
207 
208       error = reallocate_t1_table( table, new_size );
209       if ( error )
210         return error;
211 
212       if ( in_offset >= 0 )
213         object = table->block + in_offset;
214     }
215 
216     /* add the object to the base block and adjust offset */
217     table->elements[idx] = table->block + table->cursor;
218     table->lengths [idx] = length;
219     FT_MEM_COPY( table->block + table->cursor, object, length );
220 
221     table->cursor += length;
222     return FT_Err_Ok;
223   }
224 
225 
226   /**************************************************************************
227    *
228    * @Function:
229    *   ps_table_done
230    *
231    * @Description:
232    *   Finalizes a PS_TableRec (i.e., reallocate it to its current
233    *   cursor).
234    *
235    * @InOut:
236    *   table ::
237    *     The target table.
238    *
239    * @Note:
240    *   This function does NOT release the heap's memory block.  It is up
241    *   to the caller to clean it, or reference it in its own structures.
242    */
243   FT_LOCAL_DEF( void )
ps_table_done(PS_Table table)244   ps_table_done( PS_Table  table )
245   {
246     FT_Memory  memory = table->memory;
247     FT_Error   error;
248     FT_Byte*   old_base = table->block;
249 
250 
251     /* should never fail, because rec.cursor <= rec.size */
252     if ( !old_base )
253       return;
254 
255     if ( FT_ALLOC( table->block, table->cursor ) )
256       return;
257     FT_MEM_COPY( table->block, old_base, table->cursor );
258     shift_elements( table, old_base );
259 
260     table->capacity = table->cursor;
261     FT_FREE( old_base );
262 
263     FT_UNUSED( error );
264   }
265 
266 
267   FT_LOCAL_DEF( void )
ps_table_release(PS_Table table)268   ps_table_release( PS_Table  table )
269   {
270     FT_Memory  memory = table->memory;
271 
272 
273     if ( (FT_ULong)table->init == 0xDEADBEEFUL )
274     {
275       FT_FREE( table->block );
276       FT_FREE( table->elements );
277       FT_FREE( table->lengths );
278       table->init = 0;
279     }
280   }
281 
282 
283   /*************************************************************************/
284   /*************************************************************************/
285   /*****                                                               *****/
286   /*****                            T1 PARSER                          *****/
287   /*****                                                               *****/
288   /*************************************************************************/
289   /*************************************************************************/
290 
291 
292   /* first character must be already part of the comment */
293 
294   static void
skip_comment(FT_Byte ** acur,FT_Byte * limit)295   skip_comment( FT_Byte*  *acur,
296                 FT_Byte*   limit )
297   {
298     FT_Byte*  cur = *acur;
299 
300 
301     while ( cur < limit )
302     {
303       if ( IS_PS_NEWLINE( *cur ) )
304         break;
305       cur++;
306     }
307 
308     *acur = cur;
309   }
310 
311 
312   static void
skip_spaces(FT_Byte ** acur,FT_Byte * limit)313   skip_spaces( FT_Byte*  *acur,
314                FT_Byte*   limit )
315   {
316     FT_Byte*  cur = *acur;
317 
318 
319     while ( cur < limit )
320     {
321       if ( !IS_PS_SPACE( *cur ) )
322       {
323         if ( *cur == '%' )
324           /* According to the PLRM, a comment is equal to a space. */
325           skip_comment( &cur, limit );
326         else
327           break;
328       }
329       cur++;
330     }
331 
332     *acur = cur;
333   }
334 
335 
336 #define IS_OCTAL_DIGIT( c ) ( '0' <= (c) && (c) <= '7' )
337 
338 
339   /* first character must be `(';                               */
340   /* *acur is positioned at the character after the closing `)' */
341 
342   static FT_Error
skip_literal_string(FT_Byte ** acur,FT_Byte * limit)343   skip_literal_string( FT_Byte*  *acur,
344                        FT_Byte*   limit )
345   {
346     FT_Byte*      cur   = *acur;
347     FT_Int        embed = 0;
348     FT_Error      error = FT_ERR( Invalid_File_Format );
349     unsigned int  i;
350 
351 
352     while ( cur < limit )
353     {
354       FT_Byte  c = *cur;
355 
356 
357       cur++;
358 
359       if ( c == '\\' )
360       {
361         /* Red Book 3rd ed., section `Literal Text Strings', p. 29:     */
362         /* A backslash can introduce three different types              */
363         /* of escape sequences:                                         */
364         /*   - a special escaped char like \r, \n, etc.                 */
365         /*   - a one-, two-, or three-digit octal number                */
366         /*   - none of the above in which case the backslash is ignored */
367 
368         if ( cur == limit )
369           /* error (or to be ignored?) */
370           break;
371 
372         switch ( *cur )
373         {
374           /* skip `special' escape */
375         case 'n':
376         case 'r':
377         case 't':
378         case 'b':
379         case 'f':
380         case '\\':
381         case '(':
382         case ')':
383           cur++;
384           break;
385 
386         default:
387           /* skip octal escape or ignore backslash */
388           for ( i = 0; i < 3 && cur < limit; i++ )
389           {
390             if ( !IS_OCTAL_DIGIT( *cur ) )
391               break;
392 
393             cur++;
394           }
395         }
396       }
397       else if ( c == '(' )
398         embed++;
399       else if ( c == ')' )
400       {
401         embed--;
402         if ( embed == 0 )
403         {
404           error = FT_Err_Ok;
405           break;
406         }
407       }
408     }
409 
410     *acur = cur;
411 
412     return error;
413   }
414 
415 
416   /* first character must be `<' */
417 
418   static FT_Error
skip_string(FT_Byte ** acur,FT_Byte * limit)419   skip_string( FT_Byte*  *acur,
420                FT_Byte*   limit )
421   {
422     FT_Byte*  cur = *acur;
423     FT_Error  err =  FT_Err_Ok;
424 
425 
426     while ( ++cur < limit )
427     {
428       /* All whitespace characters are ignored. */
429       skip_spaces( &cur, limit );
430       if ( cur >= limit )
431         break;
432 
433       if ( !IS_PS_XDIGIT( *cur ) )
434         break;
435     }
436 
437     if ( cur < limit && *cur != '>' )
438     {
439       FT_ERROR(( "skip_string: missing closing delimiter `>'\n" ));
440       err = FT_THROW( Invalid_File_Format );
441     }
442     else
443       cur++;
444 
445     *acur = cur;
446     return err;
447   }
448 
449 
450   /* first character must be the opening brace that */
451   /* starts the procedure                           */
452 
453   /* NB: [ and ] need not match:                    */
454   /* `/foo {[} def' is a valid PostScript fragment, */
455   /* even within a Type1 font                       */
456 
457   static FT_Error
skip_procedure(FT_Byte ** acur,FT_Byte * limit)458   skip_procedure( FT_Byte*  *acur,
459                   FT_Byte*   limit )
460   {
461     FT_Byte*  cur;
462     FT_Int    embed = 0;
463     FT_Error  error = FT_Err_Ok;
464 
465 
466     FT_ASSERT( **acur == '{' );
467 
468     for ( cur = *acur; cur < limit && error == FT_Err_Ok; cur++ )
469     {
470       switch ( *cur )
471       {
472       case '{':
473         embed++;
474         break;
475 
476       case '}':
477         embed--;
478         if ( embed == 0 )
479         {
480           cur++;
481           goto end;
482         }
483         break;
484 
485       case '(':
486         error = skip_literal_string( &cur, limit );
487         break;
488 
489       case '<':
490         error = skip_string( &cur, limit );
491         break;
492 
493       case '%':
494         skip_comment( &cur, limit );
495         break;
496       }
497     }
498 
499   end:
500     if ( embed != 0 )
501       error = FT_THROW( Invalid_File_Format );
502 
503     *acur = cur;
504 
505     return error;
506   }
507 
508 
509   /************************************************************************
510    *
511    * All exported parsing routines handle leading whitespace and stop at
512    * the first character which isn't part of the just handled token.
513    *
514    */
515 
516 
517   FT_LOCAL_DEF( void )
ps_parser_skip_PS_token(PS_Parser parser)518   ps_parser_skip_PS_token( PS_Parser  parser )
519   {
520     /* Note: PostScript allows any non-delimiting, non-whitespace        */
521     /*       character in a name (PS Ref Manual, 3rd ed, p31).           */
522     /*       PostScript delimiters are (, ), <, >, [, ], {, }, /, and %. */
523 
524     FT_Byte*  cur   = parser->cursor;
525     FT_Byte*  limit = parser->limit;
526     FT_Error  error = FT_Err_Ok;
527 
528 
529     skip_spaces( &cur, limit );             /* this also skips comments */
530     if ( cur >= limit )
531       goto Exit;
532 
533     /* self-delimiting, single-character tokens */
534     if ( *cur == '[' || *cur == ']' )
535     {
536       cur++;
537       goto Exit;
538     }
539 
540     /* skip balanced expressions (procedures and strings) */
541 
542     if ( *cur == '{' )                              /* {...} */
543     {
544       error = skip_procedure( &cur, limit );
545       goto Exit;
546     }
547 
548     if ( *cur == '(' )                              /* (...) */
549     {
550       error = skip_literal_string( &cur, limit );
551       goto Exit;
552     }
553 
554     if ( *cur == '<' )                              /* <...> */
555     {
556       if ( cur + 1 < limit && *(cur + 1) == '<' )   /* << */
557       {
558         cur++;
559         cur++;
560       }
561       else
562         error = skip_string( &cur, limit );
563 
564       goto Exit;
565     }
566 
567     if ( *cur == '>' )
568     {
569       cur++;
570       if ( cur >= limit || *cur != '>' )             /* >> */
571       {
572         FT_ERROR(( "ps_parser_skip_PS_token:"
573                    " unexpected closing delimiter `>'\n" ));
574         error = FT_THROW( Invalid_File_Format );
575         goto Exit;
576       }
577       cur++;
578       goto Exit;
579     }
580 
581     if ( *cur == '/' )
582       cur++;
583 
584     /* anything else */
585     while ( cur < limit )
586     {
587       /* *cur might be invalid (e.g., ')' or '}'), but this   */
588       /* is handled by the test `cur == parser->cursor' below */
589       if ( IS_PS_DELIM( *cur ) )
590         break;
591 
592       cur++;
593     }
594 
595   Exit:
596     if ( cur < limit && cur == parser->cursor )
597     {
598       FT_ERROR(( "ps_parser_skip_PS_token:"
599                  " current token is `%c' which is self-delimiting\n"
600                  "                        "
601                  " but invalid at this point\n",
602                  *cur ));
603 
604       error = FT_THROW( Invalid_File_Format );
605     }
606 
607     if ( cur > limit )
608       cur = limit;
609 
610     parser->error  = error;
611     parser->cursor = cur;
612   }
613 
614 
615   FT_LOCAL_DEF( void )
ps_parser_skip_spaces(PS_Parser parser)616   ps_parser_skip_spaces( PS_Parser  parser )
617   {
618     skip_spaces( &parser->cursor, parser->limit );
619   }
620 
621 
622   /* `token' here means either something between balanced delimiters */
623   /* or the next token; the delimiters are not removed.              */
624 
625   FT_LOCAL_DEF( void )
ps_parser_to_token(PS_Parser parser,T1_Token token)626   ps_parser_to_token( PS_Parser  parser,
627                       T1_Token   token )
628   {
629     FT_Byte*  cur;
630     FT_Byte*  limit;
631     FT_Int    embed;
632 
633 
634     token->type  = T1_TOKEN_TYPE_NONE;
635     token->start = NULL;
636     token->limit = NULL;
637 
638     /* first of all, skip leading whitespace */
639     ps_parser_skip_spaces( parser );
640 
641     cur   = parser->cursor;
642     limit = parser->limit;
643 
644     if ( cur >= limit )
645       return;
646 
647     switch ( *cur )
648     {
649       /************* check for literal string *****************/
650     case '(':
651       token->type  = T1_TOKEN_TYPE_STRING;
652       token->start = cur;
653 
654       if ( skip_literal_string( &cur, limit ) == FT_Err_Ok )
655         token->limit = cur;
656       break;
657 
658       /************* check for programs/array *****************/
659     case '{':
660       token->type  = T1_TOKEN_TYPE_ARRAY;
661       token->start = cur;
662 
663       if ( skip_procedure( &cur, limit ) == FT_Err_Ok )
664         token->limit = cur;
665       break;
666 
667       /************* check for table/array ********************/
668       /* XXX: in theory we should also look for "<<"          */
669       /*      since this is semantically equivalent to "[";   */
670       /*      in practice it doesn't matter (?)               */
671     case '[':
672       token->type  = T1_TOKEN_TYPE_ARRAY;
673       embed        = 1;
674       token->start = cur++;
675 
676       /* we need this to catch `[ ]' */
677       parser->cursor = cur;
678       ps_parser_skip_spaces( parser );
679       cur = parser->cursor;
680 
681       while ( cur < limit && !parser->error )
682       {
683         /* XXX: this is wrong because it does not      */
684         /*      skip comments, procedures, and strings */
685         if ( *cur == '[' )
686           embed++;
687         else if ( *cur == ']' )
688         {
689           embed--;
690           if ( embed <= 0 )
691           {
692             token->limit = ++cur;
693             break;
694           }
695         }
696 
697         parser->cursor = cur;
698         ps_parser_skip_PS_token( parser );
699         /* we need this to catch `[XXX ]' */
700         ps_parser_skip_spaces  ( parser );
701         cur = parser->cursor;
702       }
703       break;
704 
705       /* ************ otherwise, it is any token **************/
706     default:
707       token->start = cur;
708       token->type  = ( *cur == '/' ) ? T1_TOKEN_TYPE_KEY : T1_TOKEN_TYPE_ANY;
709       ps_parser_skip_PS_token( parser );
710       cur = parser->cursor;
711       if ( !parser->error )
712         token->limit = cur;
713     }
714 
715     if ( !token->limit )
716     {
717       token->start = NULL;
718       token->type  = T1_TOKEN_TYPE_NONE;
719     }
720 
721     parser->cursor = cur;
722   }
723 
724 
725   /* NB: `tokens' can be NULL if we only want to count */
726   /* the number of array elements                      */
727 
728   FT_LOCAL_DEF( void )
ps_parser_to_token_array(PS_Parser parser,T1_Token tokens,FT_UInt max_tokens,FT_Int * pnum_tokens)729   ps_parser_to_token_array( PS_Parser  parser,
730                             T1_Token   tokens,
731                             FT_UInt    max_tokens,
732                             FT_Int*    pnum_tokens )
733   {
734     T1_TokenRec  master;
735 
736 
737     *pnum_tokens = -1;
738 
739     /* this also handles leading whitespace */
740     ps_parser_to_token( parser, &master );
741 
742     if ( master.type == T1_TOKEN_TYPE_ARRAY )
743     {
744       FT_Byte*  old_cursor = parser->cursor;
745       FT_Byte*  old_limit  = parser->limit;
746       T1_Token  cur        = tokens;
747       T1_Token  limit      = cur + max_tokens;
748 
749 
750       /* don't include outermost delimiters */
751       parser->cursor = master.start + 1;
752       parser->limit  = master.limit - 1;
753 
754       while ( parser->cursor < parser->limit )
755       {
756         T1_TokenRec  token;
757 
758 
759         ps_parser_to_token( parser, &token );
760         if ( !token.type )
761           break;
762 
763         if ( tokens && cur < limit )
764           *cur = token;
765 
766         cur++;
767       }
768 
769       *pnum_tokens = (FT_Int)( cur - tokens );
770 
771       parser->cursor = old_cursor;
772       parser->limit  = old_limit;
773     }
774   }
775 
776 
777   /* first character must be a delimiter or a part of a number */
778   /* NB: `coords' can be NULL if we just want to skip the      */
779   /*     array; in this case we ignore `max_coords'            */
780 
781   static FT_Int
ps_tocoordarray(FT_Byte ** acur,FT_Byte * limit,FT_Int max_coords,FT_Short * coords)782   ps_tocoordarray( FT_Byte*  *acur,
783                    FT_Byte*   limit,
784                    FT_Int     max_coords,
785                    FT_Short*  coords )
786   {
787     FT_Byte*  cur   = *acur;
788     FT_Int    count = 0;
789     FT_Byte   c, ender;
790 
791 
792     if ( cur >= limit )
793       goto Exit;
794 
795     /* check for the beginning of an array; otherwise, only one number */
796     /* will be read                                                    */
797     c     = *cur;
798     ender = 0;
799 
800     if ( c == '[' )
801       ender = ']';
802     else if ( c == '{' )
803       ender = '}';
804 
805     if ( ender )
806       cur++;
807 
808     /* now, read the coordinates */
809     while ( cur < limit )
810     {
811       FT_Short  dummy;
812       FT_Byte*  old_cur;
813 
814 
815       /* skip whitespace in front of data */
816       skip_spaces( &cur, limit );
817       if ( cur >= limit )
818         goto Exit;
819 
820       if ( *cur == ender )
821       {
822         cur++;
823         break;
824       }
825 
826       old_cur = cur;
827 
828       if ( coords && count >= max_coords )
829         break;
830 
831       /* call PS_Conv_ToFixed() even if coords == NULL */
832       /* to properly parse number at `cur'             */
833       *( coords ? &coords[count] : &dummy ) =
834         (FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 );
835 
836       if ( old_cur == cur )
837       {
838         count = -1;
839         goto Exit;
840       }
841       else
842         count++;
843 
844       if ( !ender )
845         break;
846     }
847 
848   Exit:
849     *acur = cur;
850     return count;
851   }
852 
853 
854   /* first character must be a delimiter or a part of a number */
855   /* NB: `values' can be NULL if we just want to skip the      */
856   /*     array; in this case we ignore `max_values'            */
857   /*                                                           */
858   /* return number of successfully parsed values               */
859 
860   static FT_Int
ps_tofixedarray(FT_Byte ** acur,FT_Byte * limit,FT_Int max_values,FT_Fixed * values,FT_Int power_ten)861   ps_tofixedarray( FT_Byte*  *acur,
862                    FT_Byte*   limit,
863                    FT_Int     max_values,
864                    FT_Fixed*  values,
865                    FT_Int     power_ten )
866   {
867     FT_Byte*  cur   = *acur;
868     FT_Int    count = 0;
869     FT_Byte   c, ender;
870 
871 
872     if ( cur >= limit )
873       goto Exit;
874 
875     /* Check for the beginning of an array.  Otherwise, only one number */
876     /* will be read.                                                    */
877     c     = *cur;
878     ender = 0;
879 
880     if ( c == '[' )
881       ender = ']';
882     else if ( c == '{' )
883       ender = '}';
884 
885     if ( ender )
886       cur++;
887 
888     /* now, read the values */
889     while ( cur < limit )
890     {
891       FT_Fixed  dummy;
892       FT_Byte*  old_cur;
893 
894 
895       /* skip whitespace in front of data */
896       skip_spaces( &cur, limit );
897       if ( cur >= limit )
898         goto Exit;
899 
900       if ( *cur == ender )
901       {
902         cur++;
903         break;
904       }
905 
906       old_cur = cur;
907 
908       if ( values && count >= max_values )
909         break;
910 
911       /* call PS_Conv_ToFixed() even if coords == NULL */
912       /* to properly parse number at `cur'             */
913       *( values ? &values[count] : &dummy ) =
914         PS_Conv_ToFixed( &cur, limit, power_ten );
915 
916       if ( old_cur == cur )
917       {
918         count = -1;
919         goto Exit;
920       }
921       else
922         count++;
923 
924       if ( !ender )
925         break;
926     }
927 
928   Exit:
929     *acur = cur;
930     return count;
931   }
932 
933 
934 #if 0
935 
936   static FT_String*
937   ps_tostring( FT_Byte**  cursor,
938                FT_Byte*   limit,
939                FT_Memory  memory )
940   {
941     FT_Byte*    cur = *cursor;
942     FT_UInt     len = 0;
943     FT_Int      count;
944     FT_String*  result;
945     FT_Error    error;
946 
947 
948     /* XXX: some stupid fonts have a `Notice' or `Copyright' string     */
949     /*      that simply doesn't begin with an opening parenthesis, even */
950     /*      though they have a closing one!  E.g. "amuncial.pfb"        */
951     /*                                                                  */
952     /*      We must deal with these ill-fated cases there.  Note that   */
953     /*      these fonts didn't work with the old Type 1 driver as the   */
954     /*      notice/copyright was not recognized as a valid string token */
955     /*      and made the old token parser commit errors.                */
956 
957     while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) )
958       cur++;
959     if ( cur + 1 >= limit )
960       return 0;
961 
962     if ( *cur == '(' )
963       cur++;  /* skip the opening parenthesis, if there is one */
964 
965     *cursor = cur;
966     count   = 0;
967 
968     /* then, count its length */
969     for ( ; cur < limit; cur++ )
970     {
971       if ( *cur == '(' )
972         count++;
973 
974       else if ( *cur == ')' )
975       {
976         count--;
977         if ( count < 0 )
978           break;
979       }
980     }
981 
982     len = (FT_UInt)( cur - *cursor );
983     if ( cur >= limit || FT_ALLOC( result, len + 1 ) )
984       return 0;
985 
986     /* now copy the string */
987     FT_MEM_COPY( result, *cursor, len );
988     result[len] = '\0';
989     *cursor = cur;
990     return result;
991   }
992 
993 #endif /* 0 */
994 
995 
996   static int
ps_tobool(FT_Byte ** acur,FT_Byte * limit)997   ps_tobool( FT_Byte*  *acur,
998              FT_Byte*   limit )
999   {
1000     FT_Byte*  cur    = *acur;
1001     FT_Bool   result = 0;
1002 
1003 
1004     /* return 1 if we find `true', 0 otherwise */
1005     if ( cur + 3 < limit &&
1006          cur[0] == 't'   &&
1007          cur[1] == 'r'   &&
1008          cur[2] == 'u'   &&
1009          cur[3] == 'e'   )
1010     {
1011       result = 1;
1012       cur   += 5;
1013     }
1014     else if ( cur + 4 < limit &&
1015               cur[0] == 'f'   &&
1016               cur[1] == 'a'   &&
1017               cur[2] == 'l'   &&
1018               cur[3] == 's'   &&
1019               cur[4] == 'e'   )
1020     {
1021       result = 0;
1022       cur   += 6;
1023     }
1024 
1025     *acur = cur;
1026     return result;
1027   }
1028 
1029 
1030   /* load a simple field (i.e. non-table) into the current list of objects */
1031 
1032   FT_LOCAL_DEF( FT_Error )
ps_parser_load_field(PS_Parser parser,const T1_Field field,void ** objects,FT_UInt max_objects,FT_ULong * pflags)1033   ps_parser_load_field( PS_Parser       parser,
1034                         const T1_Field  field,
1035                         void**          objects,
1036                         FT_UInt         max_objects,
1037                         FT_ULong*       pflags )
1038   {
1039     T1_TokenRec   token;
1040     FT_Byte*      cur;
1041     FT_Byte*      limit;
1042     FT_UInt       count;
1043     FT_UInt       idx;
1044     FT_Error      error;
1045     T1_FieldType  type;
1046 
1047 
1048     /* this also skips leading whitespace */
1049     ps_parser_to_token( parser, &token );
1050     if ( !token.type )
1051       goto Fail;
1052 
1053     count = 1;
1054     idx   = 0;
1055     cur   = token.start;
1056     limit = token.limit;
1057 
1058     type = field->type;
1059 
1060     /* we must detect arrays in /FontBBox */
1061     if ( type == T1_FIELD_TYPE_BBOX )
1062     {
1063       T1_TokenRec  token2;
1064       FT_Byte*     old_cur   = parser->cursor;
1065       FT_Byte*     old_limit = parser->limit;
1066 
1067 
1068       /* don't include delimiters */
1069       parser->cursor = token.start + 1;
1070       parser->limit  = token.limit - 1;
1071 
1072       ps_parser_to_token( parser, &token2 );
1073       parser->cursor = old_cur;
1074       parser->limit  = old_limit;
1075 
1076       if ( token2.type == T1_TOKEN_TYPE_ARRAY )
1077       {
1078         type = T1_FIELD_TYPE_MM_BBOX;
1079         goto FieldArray;
1080       }
1081     }
1082     else if ( token.type == T1_TOKEN_TYPE_ARRAY )
1083     {
1084       count = max_objects;
1085 
1086     FieldArray:
1087       /* if this is an array and we have no blend, an error occurs */
1088       if ( max_objects == 0 )
1089         goto Fail;
1090 
1091       idx = 1;
1092 
1093       /* don't include delimiters */
1094       cur++;
1095       limit--;
1096     }
1097 
1098     for ( ; count > 0; count--, idx++ )
1099     {
1100       FT_Byte*    q      = (FT_Byte*)objects[idx] + field->offset;
1101       FT_Long     val;
1102       FT_String*  string = NULL;
1103 
1104 
1105       skip_spaces( &cur, limit );
1106 
1107       switch ( type )
1108       {
1109       case T1_FIELD_TYPE_BOOL:
1110         val = ps_tobool( &cur, limit );
1111         FT_TRACE4(( " %s", val ? "true" : "false" ));
1112         goto Store_Integer;
1113 
1114       case T1_FIELD_TYPE_FIXED:
1115         val = PS_Conv_ToFixed( &cur, limit, 0 );
1116         FT_TRACE4(( " %f", (double)val / 65536 ));
1117         goto Store_Integer;
1118 
1119       case T1_FIELD_TYPE_FIXED_1000:
1120         val = PS_Conv_ToFixed( &cur, limit, 3 );
1121         FT_TRACE4(( " %f", (double)val / 65536 / 1000 ));
1122         goto Store_Integer;
1123 
1124       case T1_FIELD_TYPE_INTEGER:
1125         val = PS_Conv_ToInt( &cur, limit );
1126         FT_TRACE4(( " %ld", val ));
1127         /* fall through */
1128 
1129       Store_Integer:
1130         switch ( field->size )
1131         {
1132         case (8 / FT_CHAR_BIT):
1133           *(FT_Byte*)q = (FT_Byte)val;
1134           break;
1135 
1136         case (16 / FT_CHAR_BIT):
1137           *(FT_UShort*)q = (FT_UShort)val;
1138           break;
1139 
1140         case (32 / FT_CHAR_BIT):
1141           *(FT_UInt32*)q = (FT_UInt32)val;
1142           break;
1143 
1144         default:                /* for 64-bit systems */
1145           *(FT_Long*)q = val;
1146         }
1147         break;
1148 
1149       case T1_FIELD_TYPE_STRING:
1150       case T1_FIELD_TYPE_KEY:
1151         {
1152           FT_Memory  memory = parser->memory;
1153           FT_UInt    len    = (FT_UInt)( limit - cur );
1154 
1155 
1156           if ( cur >= limit )
1157             break;
1158 
1159           /* we allow both a string or a name   */
1160           /* for cases like /FontName (foo) def */
1161           if ( token.type == T1_TOKEN_TYPE_KEY )
1162           {
1163             /* don't include leading `/' */
1164             len--;
1165             cur++;
1166           }
1167           else if ( token.type == T1_TOKEN_TYPE_STRING )
1168           {
1169             /* don't include delimiting parentheses    */
1170             /* XXX we don't handle <<...>> here        */
1171             /* XXX should we convert octal escapes?    */
1172             /*     if so, what encoding should we use? */
1173             cur++;
1174             len -= 2;
1175           }
1176           else
1177           {
1178             FT_ERROR(( "ps_parser_load_field:"
1179                        " expected a name or string\n"
1180                        "                     "
1181                        " but found token of type %d instead\n",
1182                        token.type ));
1183             error = FT_THROW( Invalid_File_Format );
1184             goto Exit;
1185           }
1186 
1187           /* for this to work (FT_String**)q must have been */
1188           /* initialized to NULL                            */
1189           if ( *(FT_String**)q )
1190           {
1191             FT_TRACE0(( "ps_parser_load_field: overwriting field %s\n",
1192                         field->ident ));
1193             FT_FREE( *(FT_String**)q );
1194             *(FT_String**)q = NULL;
1195           }
1196 
1197           if ( FT_ALLOC( string, len + 1 ) )
1198             goto Exit;
1199 
1200           FT_MEM_COPY( string, cur, len );
1201           string[len] = 0;
1202 
1203 #ifdef FT_DEBUG_LEVEL_TRACE
1204           if ( token.type == T1_TOKEN_TYPE_STRING )
1205             FT_TRACE4(( " (%s)", string ));
1206           else
1207             FT_TRACE4(( " /%s", string ));
1208 #endif
1209 
1210           *(FT_String**)q = string;
1211         }
1212         break;
1213 
1214       case T1_FIELD_TYPE_BBOX:
1215         {
1216           FT_Fixed  temp[4];
1217           FT_BBox*  bbox = (FT_BBox*)q;
1218           FT_Int    result;
1219 
1220 
1221           result = ps_tofixedarray( &cur, limit, 4, temp, 0 );
1222 
1223           if ( result < 4 )
1224           {
1225             FT_ERROR(( "ps_parser_load_field:"
1226                        " expected four integers in bounding box\n" ));
1227             error = FT_THROW( Invalid_File_Format );
1228             goto Exit;
1229           }
1230 
1231           bbox->xMin = FT_RoundFix( temp[0] );
1232           bbox->yMin = FT_RoundFix( temp[1] );
1233           bbox->xMax = FT_RoundFix( temp[2] );
1234           bbox->yMax = FT_RoundFix( temp[3] );
1235 
1236           FT_TRACE4(( " [%d %d %d %d]",
1237                       bbox->xMin / 65536,
1238                       bbox->yMin / 65536,
1239                       bbox->xMax / 65536,
1240                       bbox->yMax / 65536 ));
1241         }
1242         break;
1243 
1244       case T1_FIELD_TYPE_MM_BBOX:
1245         {
1246           FT_Memory  memory = parser->memory;
1247           FT_Fixed*  temp   = NULL;
1248           FT_Int     result;
1249           FT_UInt    i;
1250 
1251 
1252           if ( FT_NEW_ARRAY( temp, max_objects * 4 ) )
1253             goto Exit;
1254 
1255           for ( i = 0; i < 4; i++ )
1256           {
1257             result = ps_tofixedarray( &cur, limit, (FT_Int)max_objects,
1258                                       temp + i * max_objects, 0 );
1259             if ( result < 0 || (FT_UInt)result < max_objects )
1260             {
1261               FT_ERROR(( "ps_parser_load_field:"
1262                          " expected %d integer%s in the %s subarray\n"
1263                          "                     "
1264                          " of /FontBBox in the /Blend dictionary\n",
1265                          max_objects, max_objects > 1 ? "s" : "",
1266                          i == 0 ? "first"
1267                                 : ( i == 1 ? "second"
1268                                            : ( i == 2 ? "third"
1269                                                       : "fourth" ) ) ));
1270               error = FT_THROW( Invalid_File_Format );
1271 
1272               FT_FREE( temp );
1273               goto Exit;
1274             }
1275 
1276             skip_spaces( &cur, limit );
1277           }
1278 
1279           FT_TRACE4(( " [" ));
1280           for ( i = 0; i < max_objects; i++ )
1281           {
1282             FT_BBox*  bbox = (FT_BBox*)objects[i];
1283 
1284 
1285             bbox->xMin = FT_RoundFix( temp[i                  ] );
1286             bbox->yMin = FT_RoundFix( temp[i +     max_objects] );
1287             bbox->xMax = FT_RoundFix( temp[i + 2 * max_objects] );
1288             bbox->yMax = FT_RoundFix( temp[i + 3 * max_objects] );
1289 
1290             FT_TRACE4(( " [%d %d %d %d]",
1291                         bbox->xMin / 65536,
1292                         bbox->yMin / 65536,
1293                         bbox->xMax / 65536,
1294                         bbox->yMax / 65536 ));
1295           }
1296           FT_TRACE4(( "]" ));
1297 
1298           FT_FREE( temp );
1299         }
1300         break;
1301 
1302       default:
1303         /* an error occurred */
1304         goto Fail;
1305       }
1306     }
1307 
1308 #if 0  /* obsolete -- keep for reference */
1309     if ( pflags )
1310       *pflags |= 1L << field->flag_bit;
1311 #else
1312     FT_UNUSED( pflags );
1313 #endif
1314 
1315     error = FT_Err_Ok;
1316 
1317   Exit:
1318     return error;
1319 
1320   Fail:
1321     error = FT_THROW( Invalid_File_Format );
1322     goto Exit;
1323   }
1324 
1325 
1326 #define T1_MAX_TABLE_ELEMENTS  32
1327 
1328 
1329   FT_LOCAL_DEF( FT_Error )
ps_parser_load_field_table(PS_Parser parser,const T1_Field field,void ** objects,FT_UInt max_objects,FT_ULong * pflags)1330   ps_parser_load_field_table( PS_Parser       parser,
1331                               const T1_Field  field,
1332                               void**          objects,
1333                               FT_UInt         max_objects,
1334                               FT_ULong*       pflags )
1335   {
1336     T1_TokenRec  elements[T1_MAX_TABLE_ELEMENTS];
1337     T1_Token     token;
1338     FT_Int       num_elements;
1339     FT_Error     error = FT_Err_Ok;
1340     FT_Byte*     old_cursor;
1341     FT_Byte*     old_limit;
1342     T1_FieldRec  fieldrec = *(T1_Field)field;
1343 
1344 
1345     fieldrec.type = T1_FIELD_TYPE_INTEGER;
1346     if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY ||
1347          field->type == T1_FIELD_TYPE_BBOX        )
1348       fieldrec.type = T1_FIELD_TYPE_FIXED;
1349 
1350     ps_parser_to_token_array( parser, elements,
1351                               T1_MAX_TABLE_ELEMENTS, &num_elements );
1352     if ( num_elements < 0 )
1353     {
1354       error = FT_ERR( Ignore );
1355       goto Exit;
1356     }
1357     if ( (FT_UInt)num_elements > field->array_max )
1358       num_elements = (FT_Int)field->array_max;
1359 
1360     old_cursor = parser->cursor;
1361     old_limit  = parser->limit;
1362 
1363     /* we store the elements count if necessary;           */
1364     /* we further assume that `count_offset' can't be zero */
1365     if ( field->type != T1_FIELD_TYPE_BBOX && field->count_offset != 0 )
1366       *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
1367         (FT_Byte)num_elements;
1368 
1369     FT_TRACE4(( " [" ));
1370 
1371     /* we now load each element, adjusting the field.offset on each one */
1372     token = elements;
1373     for ( ; num_elements > 0; num_elements--, token++ )
1374     {
1375       parser->cursor = token->start;
1376       parser->limit  = token->limit;
1377 
1378       error = ps_parser_load_field( parser,
1379                                     &fieldrec,
1380                                     objects,
1381                                     max_objects,
1382                                     0 );
1383       if ( error )
1384         break;
1385 
1386       fieldrec.offset += fieldrec.size;
1387     }
1388 
1389     FT_TRACE4(( "]" ));
1390 
1391 #if 0  /* obsolete -- keep for reference */
1392     if ( pflags )
1393       *pflags |= 1L << field->flag_bit;
1394 #else
1395     FT_UNUSED( pflags );
1396 #endif
1397 
1398     parser->cursor = old_cursor;
1399     parser->limit  = old_limit;
1400 
1401   Exit:
1402     return error;
1403   }
1404 
1405 
1406   FT_LOCAL_DEF( FT_Long )
ps_parser_to_int(PS_Parser parser)1407   ps_parser_to_int( PS_Parser  parser )
1408   {
1409     ps_parser_skip_spaces( parser );
1410     return PS_Conv_ToInt( &parser->cursor, parser->limit );
1411   }
1412 
1413 
1414   /* first character must be `<' if `delimiters' is non-zero */
1415 
1416   FT_LOCAL_DEF( FT_Error )
ps_parser_to_bytes(PS_Parser parser,FT_Byte * bytes,FT_Offset max_bytes,FT_ULong * pnum_bytes,FT_Bool delimiters)1417   ps_parser_to_bytes( PS_Parser  parser,
1418                       FT_Byte*   bytes,
1419                       FT_Offset  max_bytes,
1420                       FT_ULong*  pnum_bytes,
1421                       FT_Bool    delimiters )
1422   {
1423     FT_Error  error = FT_Err_Ok;
1424     FT_Byte*  cur;
1425 
1426 
1427     ps_parser_skip_spaces( parser );
1428     cur = parser->cursor;
1429 
1430     if ( cur >= parser->limit )
1431       goto Exit;
1432 
1433     if ( delimiters )
1434     {
1435       if ( *cur != '<' )
1436       {
1437         FT_ERROR(( "ps_parser_to_bytes: Missing starting delimiter `<'\n" ));
1438         error = FT_THROW( Invalid_File_Format );
1439         goto Exit;
1440       }
1441 
1442       cur++;
1443     }
1444 
1445     *pnum_bytes = PS_Conv_ASCIIHexDecode( &cur,
1446                                           parser->limit,
1447                                           bytes,
1448                                           max_bytes );
1449 
1450     parser->cursor = cur;
1451 
1452     if ( delimiters )
1453     {
1454       if ( cur < parser->limit && *cur != '>' )
1455       {
1456         FT_ERROR(( "ps_parser_to_bytes: Missing closing delimiter `>'\n" ));
1457         error = FT_THROW( Invalid_File_Format );
1458         goto Exit;
1459       }
1460 
1461       parser->cursor++;
1462     }
1463 
1464   Exit:
1465     return error;
1466   }
1467 
1468 
1469   FT_LOCAL_DEF( FT_Fixed )
ps_parser_to_fixed(PS_Parser parser,FT_Int power_ten)1470   ps_parser_to_fixed( PS_Parser  parser,
1471                       FT_Int     power_ten )
1472   {
1473     ps_parser_skip_spaces( parser );
1474     return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten );
1475   }
1476 
1477 
1478   FT_LOCAL_DEF( FT_Int )
ps_parser_to_coord_array(PS_Parser parser,FT_Int max_coords,FT_Short * coords)1479   ps_parser_to_coord_array( PS_Parser  parser,
1480                             FT_Int     max_coords,
1481                             FT_Short*  coords )
1482   {
1483     ps_parser_skip_spaces( parser );
1484     return ps_tocoordarray( &parser->cursor, parser->limit,
1485                             max_coords, coords );
1486   }
1487 
1488 
1489   FT_LOCAL_DEF( FT_Int )
ps_parser_to_fixed_array(PS_Parser parser,FT_Int max_values,FT_Fixed * values,FT_Int power_ten)1490   ps_parser_to_fixed_array( PS_Parser  parser,
1491                             FT_Int     max_values,
1492                             FT_Fixed*  values,
1493                             FT_Int     power_ten )
1494   {
1495     ps_parser_skip_spaces( parser );
1496     return ps_tofixedarray( &parser->cursor, parser->limit,
1497                             max_values, values, power_ten );
1498   }
1499 
1500 
1501 #if 0
1502 
1503   FT_LOCAL_DEF( FT_String* )
1504   T1_ToString( PS_Parser  parser )
1505   {
1506     return ps_tostring( &parser->cursor, parser->limit, parser->memory );
1507   }
1508 
1509 
1510   FT_LOCAL_DEF( FT_Bool )
1511   T1_ToBool( PS_Parser  parser )
1512   {
1513     return ps_tobool( &parser->cursor, parser->limit );
1514   }
1515 
1516 #endif /* 0 */
1517 
1518 
1519   FT_LOCAL_DEF( void )
ps_parser_init(PS_Parser parser,FT_Byte * base,FT_Byte * limit,FT_Memory memory)1520   ps_parser_init( PS_Parser  parser,
1521                   FT_Byte*   base,
1522                   FT_Byte*   limit,
1523                   FT_Memory  memory )
1524   {
1525     parser->error  = FT_Err_Ok;
1526     parser->base   = base;
1527     parser->limit  = limit;
1528     parser->cursor = base;
1529     parser->memory = memory;
1530     parser->funcs  = ps_parser_funcs;
1531   }
1532 
1533 
1534   FT_LOCAL_DEF( void )
ps_parser_done(PS_Parser parser)1535   ps_parser_done( PS_Parser  parser )
1536   {
1537     FT_UNUSED( parser );
1538   }
1539 
1540 
1541   /*************************************************************************/
1542   /*************************************************************************/
1543   /*****                                                               *****/
1544   /*****                            T1 BUILDER                         *****/
1545   /*****                                                               *****/
1546   /*************************************************************************/
1547   /*************************************************************************/
1548 
1549   /**************************************************************************
1550    *
1551    * @Function:
1552    *   t1_builder_init
1553    *
1554    * @Description:
1555    *   Initializes a given glyph builder.
1556    *
1557    * @InOut:
1558    *   builder ::
1559    *     A pointer to the glyph builder to initialize.
1560    *
1561    * @Input:
1562    *   face ::
1563    *     The current face object.
1564    *
1565    *   size ::
1566    *     The current size object.
1567    *
1568    *   glyph ::
1569    *     The current glyph object.
1570    *
1571    *   hinting ::
1572    *     Whether hinting should be applied.
1573    */
1574   FT_LOCAL_DEF( void )
t1_builder_init(T1_Builder builder,FT_Face face,FT_Size size,FT_GlyphSlot glyph,FT_Bool hinting)1575   t1_builder_init( T1_Builder    builder,
1576                    FT_Face       face,
1577                    FT_Size       size,
1578                    FT_GlyphSlot  glyph,
1579                    FT_Bool       hinting )
1580   {
1581     builder->parse_state = T1_Parse_Start;
1582     builder->load_points = 1;
1583 
1584     builder->face   = face;
1585     builder->glyph  = glyph;
1586     builder->memory = face->memory;
1587 
1588     if ( glyph )
1589     {
1590       FT_GlyphLoader  loader = glyph->internal->loader;
1591 
1592 
1593       builder->loader  = loader;
1594       builder->base    = &loader->base.outline;
1595       builder->current = &loader->current.outline;
1596       FT_GlyphLoader_Rewind( loader );
1597 
1598       builder->hints_globals = size->internal->module_data;
1599       builder->hints_funcs   = NULL;
1600 
1601       if ( hinting )
1602         builder->hints_funcs = glyph->internal->glyph_hints;
1603     }
1604 
1605     builder->pos_x = 0;
1606     builder->pos_y = 0;
1607 
1608     builder->left_bearing.x = 0;
1609     builder->left_bearing.y = 0;
1610     builder->advance.x      = 0;
1611     builder->advance.y      = 0;
1612 
1613     builder->funcs = t1_builder_funcs;
1614   }
1615 
1616 
1617   /**************************************************************************
1618    *
1619    * @Function:
1620    *   t1_builder_done
1621    *
1622    * @Description:
1623    *   Finalizes a given glyph builder.  Its contents can still be used
1624    *   after the call, but the function saves important information
1625    *   within the corresponding glyph slot.
1626    *
1627    * @Input:
1628    *   builder ::
1629    *     A pointer to the glyph builder to finalize.
1630    */
1631   FT_LOCAL_DEF( void )
t1_builder_done(T1_Builder builder)1632   t1_builder_done( T1_Builder  builder )
1633   {
1634     FT_GlyphSlot  glyph = builder->glyph;
1635 
1636 
1637     if ( glyph )
1638       glyph->outline = *builder->base;
1639   }
1640 
1641 
1642   /* check that there is enough space for `count' more points */
1643   FT_LOCAL_DEF( FT_Error )
t1_builder_check_points(T1_Builder builder,FT_Int count)1644   t1_builder_check_points( T1_Builder  builder,
1645                            FT_Int      count )
1646   {
1647     return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 );
1648   }
1649 
1650 
1651   /* add a new point, do not check space */
1652   FT_LOCAL_DEF( void )
t1_builder_add_point(T1_Builder builder,FT_Pos x,FT_Pos y,FT_Byte flag)1653   t1_builder_add_point( T1_Builder  builder,
1654                         FT_Pos      x,
1655                         FT_Pos      y,
1656                         FT_Byte     flag )
1657   {
1658     FT_Outline*  outline = builder->current;
1659 
1660 
1661     if ( builder->load_points )
1662     {
1663       FT_Vector*  point   = outline->points + outline->n_points;
1664       FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points;
1665 
1666 
1667       point->x = FIXED_TO_INT( x );
1668       point->y = FIXED_TO_INT( y );
1669       *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
1670     }
1671     outline->n_points++;
1672   }
1673 
1674 
1675   /* check space for a new on-curve point, then add it */
1676   FT_LOCAL_DEF( FT_Error )
t1_builder_add_point1(T1_Builder builder,FT_Pos x,FT_Pos y)1677   t1_builder_add_point1( T1_Builder  builder,
1678                          FT_Pos      x,
1679                          FT_Pos      y )
1680   {
1681     FT_Error  error;
1682 
1683 
1684     error = t1_builder_check_points( builder, 1 );
1685     if ( !error )
1686       t1_builder_add_point( builder, x, y, 1 );
1687 
1688     return error;
1689   }
1690 
1691 
1692   /* check space for a new contour, then add it */
1693   FT_LOCAL_DEF( FT_Error )
t1_builder_add_contour(T1_Builder builder)1694   t1_builder_add_contour( T1_Builder  builder )
1695   {
1696     FT_Outline*  outline = builder->current;
1697     FT_Error     error;
1698 
1699 
1700     /* this might happen in invalid fonts */
1701     if ( !outline )
1702     {
1703       FT_ERROR(( "t1_builder_add_contour: no outline to add points to\n" ));
1704       return FT_THROW( Invalid_File_Format );
1705     }
1706 
1707     if ( !builder->load_points )
1708     {
1709       outline->n_contours++;
1710       return FT_Err_Ok;
1711     }
1712 
1713     error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 );
1714     if ( !error )
1715     {
1716       if ( outline->n_contours > 0 )
1717         outline->contours[outline->n_contours - 1] =
1718           (short)( outline->n_points - 1 );
1719 
1720       outline->n_contours++;
1721     }
1722 
1723     return error;
1724   }
1725 
1726 
1727   /* if a path was begun, add its first on-curve point */
1728   FT_LOCAL_DEF( FT_Error )
t1_builder_start_point(T1_Builder builder,FT_Pos x,FT_Pos y)1729   t1_builder_start_point( T1_Builder  builder,
1730                           FT_Pos      x,
1731                           FT_Pos      y )
1732   {
1733     FT_Error  error = FT_ERR( Invalid_File_Format );
1734 
1735 
1736     /* test whether we are building a new contour */
1737 
1738     if ( builder->parse_state == T1_Parse_Have_Path )
1739       error = FT_Err_Ok;
1740     else
1741     {
1742       builder->parse_state = T1_Parse_Have_Path;
1743       error = t1_builder_add_contour( builder );
1744       if ( !error )
1745         error = t1_builder_add_point1( builder, x, y );
1746     }
1747 
1748     return error;
1749   }
1750 
1751 
1752   /* close the current contour */
1753   FT_LOCAL_DEF( void )
t1_builder_close_contour(T1_Builder builder)1754   t1_builder_close_contour( T1_Builder  builder )
1755   {
1756     FT_Outline*  outline = builder->current;
1757     FT_Int       first;
1758 
1759 
1760     if ( !outline )
1761       return;
1762 
1763     first = outline->n_contours <= 1
1764             ? 0 : outline->contours[outline->n_contours - 2] + 1;
1765 
1766     /* in malformed fonts it can happen that a contour was started */
1767     /* but no points were added                                    */
1768     if ( outline->n_contours && first == outline->n_points )
1769     {
1770       outline->n_contours--;
1771       return;
1772     }
1773 
1774     /* We must not include the last point in the path if it */
1775     /* is located on the first point.                       */
1776     if ( outline->n_points > 1 )
1777     {
1778       FT_Vector*  p1      = outline->points + first;
1779       FT_Vector*  p2      = outline->points + outline->n_points - 1;
1780       FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points - 1;
1781 
1782 
1783       /* `delete' last point only if it coincides with the first */
1784       /* point and it is not a control point (which can happen). */
1785       if ( p1->x == p2->x && p1->y == p2->y )
1786         if ( *control == FT_CURVE_TAG_ON )
1787           outline->n_points--;
1788     }
1789 
1790     if ( outline->n_contours > 0 )
1791     {
1792       /* Don't add contours only consisting of one point, i.e.,  */
1793       /* check whether the first and the last point is the same. */
1794       if ( first == outline->n_points - 1 )
1795       {
1796         outline->n_contours--;
1797         outline->n_points--;
1798       }
1799       else
1800         outline->contours[outline->n_contours - 1] =
1801           (short)( outline->n_points - 1 );
1802     }
1803   }
1804 
1805 
1806   /*************************************************************************/
1807   /*************************************************************************/
1808   /*****                                                               *****/
1809   /*****                           CFF BUILDER                         *****/
1810   /*****                                                               *****/
1811   /*************************************************************************/
1812   /*************************************************************************/
1813 
1814 
1815   /**************************************************************************
1816    *
1817    * @Function:
1818    *   cff_builder_init
1819    *
1820    * @Description:
1821    *   Initializes a given glyph builder.
1822    *
1823    * @InOut:
1824    *   builder ::
1825    *     A pointer to the glyph builder to initialize.
1826    *
1827    * @Input:
1828    *   face ::
1829    *     The current face object.
1830    *
1831    *   size ::
1832    *     The current size object.
1833    *
1834    *   glyph ::
1835    *     The current glyph object.
1836    *
1837    *   hinting ::
1838    *     Whether hinting is active.
1839    */
1840   FT_LOCAL_DEF( void )
cff_builder_init(CFF_Builder * builder,TT_Face face,CFF_Size size,CFF_GlyphSlot glyph,FT_Bool hinting)1841   cff_builder_init( CFF_Builder*   builder,
1842                     TT_Face        face,
1843                     CFF_Size       size,
1844                     CFF_GlyphSlot  glyph,
1845                     FT_Bool        hinting )
1846   {
1847     builder->path_begun  = 0;
1848     builder->load_points = 1;
1849 
1850     builder->face   = face;
1851     builder->glyph  = glyph;
1852     builder->memory = face->root.memory;
1853 
1854     if ( glyph )
1855     {
1856       FT_GlyphLoader  loader = glyph->root.internal->loader;
1857 
1858 
1859       builder->loader  = loader;
1860       builder->base    = &loader->base.outline;
1861       builder->current = &loader->current.outline;
1862       FT_GlyphLoader_Rewind( loader );
1863 
1864       builder->hints_globals = NULL;
1865       builder->hints_funcs   = NULL;
1866 
1867       if ( hinting && size )
1868       {
1869         FT_Size       ftsize   = FT_SIZE( size );
1870         CFF_Internal  internal = (CFF_Internal)ftsize->internal->module_data;
1871 
1872         if ( internal )
1873         {
1874           builder->hints_globals = (void *)internal->topfont;
1875           builder->hints_funcs   = glyph->root.internal->glyph_hints;
1876         }
1877       }
1878     }
1879 
1880     builder->pos_x = 0;
1881     builder->pos_y = 0;
1882 
1883     builder->left_bearing.x = 0;
1884     builder->left_bearing.y = 0;
1885     builder->advance.x      = 0;
1886     builder->advance.y      = 0;
1887 
1888     builder->funcs = cff_builder_funcs;
1889   }
1890 
1891 
1892   /**************************************************************************
1893    *
1894    * @Function:
1895    *   cff_builder_done
1896    *
1897    * @Description:
1898    *   Finalizes a given glyph builder.  Its contents can still be used
1899    *   after the call, but the function saves important information
1900    *   within the corresponding glyph slot.
1901    *
1902    * @Input:
1903    *   builder ::
1904    *     A pointer to the glyph builder to finalize.
1905    */
1906   FT_LOCAL_DEF( void )
cff_builder_done(CFF_Builder * builder)1907   cff_builder_done( CFF_Builder*  builder )
1908   {
1909     CFF_GlyphSlot  glyph = builder->glyph;
1910 
1911 
1912     if ( glyph )
1913       glyph->root.outline = *builder->base;
1914   }
1915 
1916 
1917   /* check that there is enough space for `count' more points */
1918   FT_LOCAL_DEF( FT_Error )
cff_check_points(CFF_Builder * builder,FT_Int count)1919   cff_check_points( CFF_Builder*  builder,
1920                     FT_Int        count )
1921   {
1922     return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 );
1923   }
1924 
1925 
1926   /* add a new point, do not check space */
1927   FT_LOCAL_DEF( void )
cff_builder_add_point(CFF_Builder * builder,FT_Pos x,FT_Pos y,FT_Byte flag)1928   cff_builder_add_point( CFF_Builder*  builder,
1929                          FT_Pos        x,
1930                          FT_Pos        y,
1931                          FT_Byte       flag )
1932   {
1933     FT_Outline*  outline = builder->current;
1934 
1935 
1936     if ( builder->load_points )
1937     {
1938       FT_Vector*  point   = outline->points + outline->n_points;
1939       FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points;
1940 
1941 #ifdef CFF_CONFIG_OPTION_OLD_ENGINE
1942       PS_Driver  driver   = (PS_Driver)FT_FACE_DRIVER( builder->face );
1943 
1944 
1945       if ( driver->hinting_engine == FT_HINTING_FREETYPE )
1946       {
1947         point->x = x >> 16;
1948         point->y = y >> 16;
1949       }
1950       else
1951 #endif
1952       {
1953         /* cf2_decoder_parse_charstrings uses 16.16 coordinates */
1954         point->x = x >> 10;
1955         point->y = y >> 10;
1956       }
1957       *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
1958     }
1959 
1960     outline->n_points++;
1961   }
1962 
1963 
1964   /* check space for a new on-curve point, then add it */
1965   FT_LOCAL_DEF( FT_Error )
cff_builder_add_point1(CFF_Builder * builder,FT_Pos x,FT_Pos y)1966   cff_builder_add_point1( CFF_Builder*  builder,
1967                           FT_Pos        x,
1968                           FT_Pos        y )
1969   {
1970     FT_Error  error;
1971 
1972 
1973     error = cff_check_points( builder, 1 );
1974     if ( !error )
1975       cff_builder_add_point( builder, x, y, 1 );
1976 
1977     return error;
1978   }
1979 
1980 
1981   /* check space for a new contour, then add it */
1982   FT_LOCAL_DEF( FT_Error )
cff_builder_add_contour(CFF_Builder * builder)1983   cff_builder_add_contour( CFF_Builder*  builder )
1984   {
1985     FT_Outline*  outline = builder->current;
1986     FT_Error     error;
1987 
1988 
1989     if ( !builder->load_points )
1990     {
1991       outline->n_contours++;
1992       return FT_Err_Ok;
1993     }
1994 
1995     error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 );
1996     if ( !error )
1997     {
1998       if ( outline->n_contours > 0 )
1999         outline->contours[outline->n_contours - 1] =
2000           (short)( outline->n_points - 1 );
2001 
2002       outline->n_contours++;
2003     }
2004 
2005     return error;
2006   }
2007 
2008 
2009   /* if a path was begun, add its first on-curve point */
2010   FT_LOCAL_DEF( FT_Error )
cff_builder_start_point(CFF_Builder * builder,FT_Pos x,FT_Pos y)2011   cff_builder_start_point( CFF_Builder*  builder,
2012                            FT_Pos        x,
2013                            FT_Pos        y )
2014   {
2015     FT_Error  error = FT_Err_Ok;
2016 
2017 
2018     /* test whether we are building a new contour */
2019     if ( !builder->path_begun )
2020     {
2021       builder->path_begun = 1;
2022       error = cff_builder_add_contour( builder );
2023       if ( !error )
2024         error = cff_builder_add_point1( builder, x, y );
2025     }
2026 
2027     return error;
2028   }
2029 
2030 
2031   /* close the current contour */
2032   FT_LOCAL_DEF( void )
cff_builder_close_contour(CFF_Builder * builder)2033   cff_builder_close_contour( CFF_Builder*  builder )
2034   {
2035     FT_Outline*  outline = builder->current;
2036     FT_Int       first;
2037 
2038 
2039     if ( !outline )
2040       return;
2041 
2042     first = outline->n_contours <= 1
2043             ? 0 : outline->contours[outline->n_contours - 2] + 1;
2044 
2045     /* in malformed fonts it can happen that a contour was started */
2046     /* but no points were added                                    */
2047     if ( outline->n_contours && first == outline->n_points )
2048     {
2049       outline->n_contours--;
2050       return;
2051     }
2052 
2053     /* We must not include the last point in the path if it */
2054     /* is located on the first point.                       */
2055     if ( outline->n_points > 1 )
2056     {
2057       FT_Vector*  p1      = outline->points + first;
2058       FT_Vector*  p2      = outline->points + outline->n_points - 1;
2059       FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points - 1;
2060 
2061 
2062       /* `delete' last point only if it coincides with the first    */
2063       /* point and if it is not a control point (which can happen). */
2064       if ( p1->x == p2->x && p1->y == p2->y )
2065         if ( *control == FT_CURVE_TAG_ON )
2066           outline->n_points--;
2067     }
2068 
2069     if ( outline->n_contours > 0 )
2070     {
2071       /* Don't add contours only consisting of one point, i.e., */
2072       /* check whether begin point and last point are the same. */
2073       if ( first == outline->n_points - 1 )
2074       {
2075         outline->n_contours--;
2076         outline->n_points--;
2077       }
2078       else
2079         outline->contours[outline->n_contours - 1] =
2080           (short)( outline->n_points - 1 );
2081     }
2082   }
2083 
2084 
2085   /*************************************************************************/
2086   /*************************************************************************/
2087   /*****                                                               *****/
2088   /*****                            PS BUILDER                         *****/
2089   /*****                                                               *****/
2090   /*************************************************************************/
2091   /*************************************************************************/
2092 
2093   /**************************************************************************
2094    *
2095    * @Function:
2096    *   ps_builder_init
2097    *
2098    * @Description:
2099    *   Initializes a given glyph builder.
2100    *
2101    * @InOut:
2102    *   builder ::
2103    *     A pointer to the glyph builder to initialize.
2104    *
2105    * @Input:
2106    *   face ::
2107    *     The current face object.
2108    *
2109    *   size ::
2110    *     The current size object.
2111    *
2112    *   glyph ::
2113    *     The current glyph object.
2114    *
2115    *   hinting ::
2116    *     Whether hinting should be applied.
2117    */
2118   FT_LOCAL_DEF( void )
ps_builder_init(PS_Builder * ps_builder,void * builder,FT_Bool is_t1)2119   ps_builder_init( PS_Builder*  ps_builder,
2120                    void*        builder,
2121                    FT_Bool      is_t1 )
2122   {
2123     FT_ZERO( ps_builder );
2124 
2125     if ( is_t1 )
2126     {
2127       T1_Builder  t1builder = (T1_Builder)builder;
2128 
2129 
2130       ps_builder->memory  = t1builder->memory;
2131       ps_builder->face    = (FT_Face)t1builder->face;
2132       ps_builder->glyph   = (CFF_GlyphSlot)t1builder->glyph;
2133       ps_builder->loader  = t1builder->loader;
2134       ps_builder->base    = t1builder->base;
2135       ps_builder->current = t1builder->current;
2136 
2137       ps_builder->pos_x = &t1builder->pos_x;
2138       ps_builder->pos_y = &t1builder->pos_y;
2139 
2140       ps_builder->left_bearing = &t1builder->left_bearing;
2141       ps_builder->advance      = &t1builder->advance;
2142 
2143       ps_builder->bbox        = &t1builder->bbox;
2144       ps_builder->path_begun  = 0;
2145       ps_builder->load_points = t1builder->load_points;
2146       ps_builder->no_recurse  = t1builder->no_recurse;
2147 
2148       ps_builder->metrics_only = t1builder->metrics_only;
2149     }
2150     else
2151     {
2152       CFF_Builder*  cffbuilder = (CFF_Builder*)builder;
2153 
2154 
2155       ps_builder->memory  = cffbuilder->memory;
2156       ps_builder->face    = (FT_Face)cffbuilder->face;
2157       ps_builder->glyph   = cffbuilder->glyph;
2158       ps_builder->loader  = cffbuilder->loader;
2159       ps_builder->base    = cffbuilder->base;
2160       ps_builder->current = cffbuilder->current;
2161 
2162       ps_builder->pos_x = &cffbuilder->pos_x;
2163       ps_builder->pos_y = &cffbuilder->pos_y;
2164 
2165       ps_builder->left_bearing = &cffbuilder->left_bearing;
2166       ps_builder->advance      = &cffbuilder->advance;
2167 
2168       ps_builder->bbox        = &cffbuilder->bbox;
2169       ps_builder->path_begun  = cffbuilder->path_begun;
2170       ps_builder->load_points = cffbuilder->load_points;
2171       ps_builder->no_recurse  = cffbuilder->no_recurse;
2172 
2173       ps_builder->metrics_only = cffbuilder->metrics_only;
2174     }
2175 
2176     ps_builder->is_t1 = is_t1;
2177     ps_builder->funcs = ps_builder_funcs;
2178   }
2179 
2180 
2181   /**************************************************************************
2182    *
2183    * @Function:
2184    *   ps_builder_done
2185    *
2186    * @Description:
2187    *   Finalizes a given glyph builder.  Its contents can still be used
2188    *   after the call, but the function saves important information
2189    *   within the corresponding glyph slot.
2190    *
2191    * @Input:
2192    *   builder ::
2193    *     A pointer to the glyph builder to finalize.
2194    */
2195   FT_LOCAL_DEF( void )
ps_builder_done(PS_Builder * builder)2196   ps_builder_done( PS_Builder*  builder )
2197   {
2198     CFF_GlyphSlot  glyph = builder->glyph;
2199 
2200 
2201     if ( glyph )
2202       glyph->root.outline = *builder->base;
2203   }
2204 
2205 
2206   /* check that there is enough space for `count' more points */
2207   FT_LOCAL_DEF( FT_Error )
ps_builder_check_points(PS_Builder * builder,FT_Int count)2208   ps_builder_check_points( PS_Builder*  builder,
2209                            FT_Int       count )
2210   {
2211     return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 );
2212   }
2213 
2214 
2215   /* add a new point, do not check space */
2216   FT_LOCAL_DEF( void )
ps_builder_add_point(PS_Builder * builder,FT_Pos x,FT_Pos y,FT_Byte flag)2217   ps_builder_add_point( PS_Builder*  builder,
2218                         FT_Pos       x,
2219                         FT_Pos       y,
2220                         FT_Byte      flag )
2221   {
2222     FT_Outline*  outline = builder->current;
2223 
2224 
2225     if ( builder->load_points )
2226     {
2227       FT_Vector*  point   = outline->points + outline->n_points;
2228       FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points;
2229 
2230 #ifdef CFF_CONFIG_OPTION_OLD_ENGINE
2231       PS_Driver  driver   = (PS_Driver)FT_FACE_DRIVER( builder->face );
2232 
2233 
2234       if ( !builder->is_t1 &&
2235            driver->hinting_engine == FT_HINTING_FREETYPE )
2236       {
2237         point->x = x >> 16;
2238         point->y = y >> 16;
2239       }
2240       else
2241 #endif
2242 #ifdef T1_CONFIG_OPTION_OLD_ENGINE
2243 #ifndef CFF_CONFIG_OPTION_OLD_ENGINE
2244       PS_Driver  driver   = (PS_Driver)FT_FACE_DRIVER( builder->face );
2245 #endif
2246       if ( builder->is_t1 &&
2247            driver->hinting_engine == FT_HINTING_FREETYPE )
2248       {
2249         point->x = FIXED_TO_INT( x );
2250         point->y = FIXED_TO_INT( y );
2251       }
2252       else
2253 #endif
2254       {
2255         /* cf2_decoder_parse_charstrings uses 16.16 coordinates */
2256         point->x = x >> 10;
2257         point->y = y >> 10;
2258       }
2259       *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
2260     }
2261     outline->n_points++;
2262   }
2263 
2264 
2265   /* check space for a new on-curve point, then add it */
2266   FT_LOCAL_DEF( FT_Error )
ps_builder_add_point1(PS_Builder * builder,FT_Pos x,FT_Pos y)2267   ps_builder_add_point1( PS_Builder*  builder,
2268                          FT_Pos       x,
2269                          FT_Pos       y )
2270   {
2271     FT_Error  error;
2272 
2273 
2274     error = ps_builder_check_points( builder, 1 );
2275     if ( !error )
2276       ps_builder_add_point( builder, x, y, 1 );
2277 
2278     return error;
2279   }
2280 
2281 
2282   /* check space for a new contour, then add it */
2283   FT_LOCAL_DEF( FT_Error )
ps_builder_add_contour(PS_Builder * builder)2284   ps_builder_add_contour( PS_Builder*  builder )
2285   {
2286     FT_Outline*  outline = builder->current;
2287     FT_Error     error;
2288 
2289 
2290     /* this might happen in invalid fonts */
2291     if ( !outline )
2292     {
2293       FT_ERROR(( "ps_builder_add_contour: no outline to add points to\n" ));
2294       return FT_THROW( Invalid_File_Format );
2295     }
2296 
2297     if ( !builder->load_points )
2298     {
2299       outline->n_contours++;
2300       return FT_Err_Ok;
2301     }
2302 
2303     error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 );
2304     if ( !error )
2305     {
2306       if ( outline->n_contours > 0 )
2307         outline->contours[outline->n_contours - 1] =
2308           (short)( outline->n_points - 1 );
2309 
2310       outline->n_contours++;
2311     }
2312 
2313     return error;
2314   }
2315 
2316 
2317   /* if a path was begun, add its first on-curve point */
2318   FT_LOCAL_DEF( FT_Error )
ps_builder_start_point(PS_Builder * builder,FT_Pos x,FT_Pos y)2319   ps_builder_start_point( PS_Builder*  builder,
2320                           FT_Pos       x,
2321                           FT_Pos       y )
2322   {
2323     FT_Error  error = FT_Err_Ok;
2324 
2325 
2326     /* test whether we are building a new contour */
2327     if ( !builder->path_begun )
2328     {
2329       builder->path_begun = 1;
2330       error = ps_builder_add_contour( builder );
2331       if ( !error )
2332         error = ps_builder_add_point1( builder, x, y );
2333     }
2334 
2335     return error;
2336   }
2337 
2338 
2339   /* close the current contour */
2340   FT_LOCAL_DEF( void )
ps_builder_close_contour(PS_Builder * builder)2341   ps_builder_close_contour( PS_Builder*  builder )
2342   {
2343     FT_Outline*  outline = builder->current;
2344     FT_Int       first;
2345 
2346 
2347     if ( !outline )
2348       return;
2349 
2350     first = outline->n_contours <= 1
2351             ? 0 : outline->contours[outline->n_contours - 2] + 1;
2352 
2353     /* in malformed fonts it can happen that a contour was started */
2354     /* but no points were added                                    */
2355     if ( outline->n_contours && first == outline->n_points )
2356     {
2357       outline->n_contours--;
2358       return;
2359     }
2360 
2361     /* We must not include the last point in the path if it */
2362     /* is located on the first point.                       */
2363     if ( outline->n_points > 1 )
2364     {
2365       FT_Vector*  p1      = outline->points + first;
2366       FT_Vector*  p2      = outline->points + outline->n_points - 1;
2367       FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points - 1;
2368 
2369 
2370       /* `delete' last point only if it coincides with the first */
2371       /* point and it is not a control point (which can happen). */
2372       if ( p1->x == p2->x && p1->y == p2->y )
2373         if ( *control == FT_CURVE_TAG_ON )
2374           outline->n_points--;
2375     }
2376 
2377     if ( outline->n_contours > 0 )
2378     {
2379       /* Don't add contours only consisting of one point, i.e.,  */
2380       /* check whether the first and the last point is the same. */
2381       if ( first == outline->n_points - 1 )
2382       {
2383         outline->n_contours--;
2384         outline->n_points--;
2385       }
2386       else
2387         outline->contours[outline->n_contours - 1] =
2388           (short)( outline->n_points - 1 );
2389     }
2390   }
2391 
2392 
2393   /*************************************************************************/
2394   /*************************************************************************/
2395   /*****                                                               *****/
2396   /*****                            OTHER                              *****/
2397   /*****                                                               *****/
2398   /*************************************************************************/
2399   /*************************************************************************/
2400 
2401 
2402   /**************************************************************************
2403    *
2404    * @Function:
2405    *   ps_decoder_init
2406    *
2407    * @Description:
2408    *   Creates a wrapper decoder for use in the combined
2409    *   Type 1 / CFF interpreter.
2410    *
2411    * @InOut:
2412    *   ps_decoder ::
2413    *     A pointer to the decoder to initialize.
2414    *
2415    * @Input:
2416    *   decoder ::
2417    *     A pointer to the original decoder.
2418    *
2419    *   is_t1 ::
2420    *     Flag indicating Type 1 or CFF
2421    */
2422   FT_LOCAL_DEF( void )
ps_decoder_init(PS_Decoder * ps_decoder,void * decoder,FT_Bool is_t1)2423   ps_decoder_init( PS_Decoder*  ps_decoder,
2424                    void*        decoder,
2425                    FT_Bool      is_t1 )
2426   {
2427     FT_ZERO( ps_decoder );
2428 
2429     if ( is_t1 )
2430     {
2431       T1_Decoder  t1_decoder = (T1_Decoder)decoder;
2432 
2433 
2434       ps_builder_init( &ps_decoder->builder,
2435                        &t1_decoder->builder,
2436                        is_t1 );
2437 
2438       ps_decoder->cf2_instance = &t1_decoder->cf2_instance;
2439       ps_decoder->psnames      = t1_decoder->psnames;
2440 
2441       ps_decoder->num_glyphs  = t1_decoder->num_glyphs;
2442       ps_decoder->glyph_names = t1_decoder->glyph_names;
2443       ps_decoder->hint_mode   = t1_decoder->hint_mode;
2444       ps_decoder->blend       = t1_decoder->blend;
2445 
2446       ps_decoder->num_locals  = (FT_UInt)t1_decoder->num_subrs;
2447       ps_decoder->locals      = t1_decoder->subrs;
2448       ps_decoder->locals_len  = t1_decoder->subrs_len;
2449       ps_decoder->locals_hash = t1_decoder->subrs_hash;
2450 
2451       ps_decoder->buildchar     = t1_decoder->buildchar;
2452       ps_decoder->len_buildchar = t1_decoder->len_buildchar;
2453 
2454       ps_decoder->lenIV = t1_decoder->lenIV;
2455     }
2456     else
2457     {
2458       CFF_Decoder*  cff_decoder = (CFF_Decoder*)decoder;
2459 
2460 
2461       ps_builder_init( &ps_decoder->builder,
2462                        &cff_decoder->builder,
2463                        is_t1 );
2464 
2465       ps_decoder->cff             = cff_decoder->cff;
2466       ps_decoder->cf2_instance    = &cff_decoder->cff->cf2_instance;
2467       ps_decoder->current_subfont = cff_decoder->current_subfont;
2468 
2469       ps_decoder->num_globals  = cff_decoder->num_globals;
2470       ps_decoder->globals      = cff_decoder->globals;
2471       ps_decoder->globals_bias = cff_decoder->globals_bias;
2472       ps_decoder->num_locals   = cff_decoder->num_locals;
2473       ps_decoder->locals       = cff_decoder->locals;
2474       ps_decoder->locals_bias  = cff_decoder->locals_bias;
2475 
2476       ps_decoder->glyph_width   = &cff_decoder->glyph_width;
2477       ps_decoder->width_only    = cff_decoder->width_only;
2478 
2479       ps_decoder->hint_mode = cff_decoder->hint_mode;
2480 
2481       ps_decoder->get_glyph_callback  = cff_decoder->get_glyph_callback;
2482       ps_decoder->free_glyph_callback = cff_decoder->free_glyph_callback;
2483     }
2484   }
2485 
2486 
2487   /* Synthesize a SubFont object for Type 1 fonts, for use in the  */
2488   /* new interpreter to access Private dict data.                  */
2489   FT_LOCAL_DEF( void )
t1_make_subfont(FT_Face face,PS_Private priv,CFF_SubFont subfont)2490   t1_make_subfont( FT_Face      face,
2491                    PS_Private   priv,
2492                    CFF_SubFont  subfont )
2493   {
2494     CFF_Private  cpriv = &subfont->private_dict;
2495     FT_UInt      n, count;
2496 
2497 
2498     FT_ZERO( subfont );
2499     FT_ZERO( cpriv );
2500 
2501     count = cpriv->num_blue_values = priv->num_blue_values;
2502     for ( n = 0; n < count; n++ )
2503       cpriv->blue_values[n] = (FT_Pos)priv->blue_values[n];
2504 
2505     count = cpriv->num_other_blues = priv->num_other_blues;
2506     for ( n = 0; n < count; n++ )
2507       cpriv->other_blues[n] = (FT_Pos)priv->other_blues[n];
2508 
2509     count = cpriv->num_family_blues = priv->num_family_blues;
2510     for ( n = 0; n < count; n++ )
2511       cpriv->family_blues[n] = (FT_Pos)priv->family_blues[n];
2512 
2513     count = cpriv->num_family_other_blues = priv->num_family_other_blues;
2514     for ( n = 0; n < count; n++ )
2515       cpriv->family_other_blues[n] = (FT_Pos)priv->family_other_blues[n];
2516 
2517     cpriv->blue_scale = priv->blue_scale;
2518     cpriv->blue_shift = (FT_Pos)priv->blue_shift;
2519     cpriv->blue_fuzz  = (FT_Pos)priv->blue_fuzz;
2520 
2521     cpriv->standard_width  = (FT_Pos)priv->standard_width[0];
2522     cpriv->standard_height = (FT_Pos)priv->standard_height[0];
2523 
2524     count = cpriv->num_snap_widths = priv->num_snap_widths;
2525     for ( n = 0; n < count; n++ )
2526       cpriv->snap_widths[n] = (FT_Pos)priv->snap_widths[n];
2527 
2528     count = cpriv->num_snap_heights = priv->num_snap_heights;
2529     for ( n = 0; n < count; n++ )
2530       cpriv->snap_heights[n] = (FT_Pos)priv->snap_heights[n];
2531 
2532     cpriv->force_bold       = priv->force_bold;
2533     cpriv->lenIV            = priv->lenIV;
2534     cpriv->language_group   = priv->language_group;
2535     cpriv->expansion_factor = priv->expansion_factor;
2536 
2537     cpriv->subfont = subfont;
2538 
2539 
2540     /* Initialize the random number generator. */
2541     if ( face->internal->random_seed != -1 )
2542     {
2543       /* If we have a face-specific seed, use it.    */
2544       /* If non-zero, update it to a positive value. */
2545       subfont->random = (FT_UInt32)face->internal->random_seed;
2546       if ( face->internal->random_seed )
2547       {
2548         do
2549         {
2550           face->internal->random_seed = (FT_Int32)cff_random(
2551             (FT_UInt32)face->internal->random_seed );
2552 
2553         } while ( face->internal->random_seed < 0 );
2554       }
2555     }
2556     if ( !subfont->random )
2557     {
2558       FT_UInt32  seed;
2559 
2560 
2561       /* compute random seed from some memory addresses */
2562       seed = (FT_UInt32)( (FT_Offset)(char*)&seed    ^
2563                           (FT_Offset)(char*)&face    ^
2564                           (FT_Offset)(char*)&subfont );
2565       seed = seed ^ ( seed >> 10 ) ^ ( seed >> 20 );
2566       if ( seed == 0 )
2567         seed = 0x7384;
2568 
2569       subfont->random = seed;
2570     }
2571   }
2572 
2573 
2574   FT_LOCAL_DEF( void )
t1_decrypt(FT_Byte * buffer,FT_Offset length,FT_UShort seed)2575   t1_decrypt( FT_Byte*   buffer,
2576               FT_Offset  length,
2577               FT_UShort  seed )
2578   {
2579     PS_Conv_EexecDecode( &buffer,
2580                          buffer + length,
2581                          buffer,
2582                          length,
2583                          &seed );
2584   }
2585 
2586 
2587   FT_LOCAL_DEF( FT_UInt32 )
cff_random(FT_UInt32 r)2588   cff_random( FT_UInt32  r )
2589   {
2590     /* a 32bit version of the `xorshift' algorithm */
2591     r ^= r << 13;
2592     r ^= r >> 17;
2593     r ^= r << 5;
2594 
2595     return r;
2596   }
2597 
2598 
2599 /* END */
2600