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