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