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 )
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
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 )
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 )
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 )
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
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
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
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
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
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 )
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 )
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 )
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 )
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
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
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
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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 )
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