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