1 /***************************************************************************/
2 /* */
3 /* psobjs.c */
4 /* */
5 /* Auxiliary functions for PostScript fonts (body). */
6 /* */
7 /* Copyright 1996-2001 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 /***************************************************************************/
19 #include <ft2build.h>
20 #include FT_INTERNAL_POSTSCRIPT_AUX_H
21 #include FT_INTERNAL_DEBUG_H
23 #include "psobjs.h"
25 #include "psauxerr.h"
28 /*************************************************************************/
29 /*************************************************************************/
30 /***** *****/
31 /***** PS_TABLE *****/
32 /***** *****/
33 /*************************************************************************/
34 /*************************************************************************/
36 /*************************************************************************/
37 /* */
38 /* <Function> */
39 /* PS_Table_New */
40 /* */
41 /* <Description> */
42 /* Initializes a PS_Table. */
43 /* */
44 /* <InOut> */
45 /* table :: The address of the target table. */
46 /* */
47 /* <Input> */
48 /* count :: The table size = the maximum number of elements. */
49 /* */
50 /* memory :: The memory object to use for all subsequent */
51 /* reallocations. */
52 /* */
53 /* <Return> */
54 /* FreeType error code. 0 means success. */
55 /* */
56 FT_LOCAL_DEF FT_Error
57 PS_Table_New( PS_Table* table,
58 FT_Int count,
59 FT_Memory memory )
60 {
61 FT_Error error;
64 table->memory = memory;
65 if ( ALLOC_ARRAY( table->elements, count, FT_Byte* ) ||
66 ALLOC_ARRAY( table->lengths, count, FT_Byte* ) )
67 goto Exit;
69 table->max_elems = count;
70 table->init = 0xDEADBEEFUL;
71 table->num_elems = 0;
72 table->block = 0;
73 table->capacity = 0;
74 table->cursor = 0;
75 table->funcs = ps_table_funcs;
77 Exit:
78 if ( error )
79 FREE( table->elements );
81 return error;
82 }
85 static void
86 shift_elements( PS_Table* table,
87 FT_Byte* old_base )
88 {
89 FT_Long delta = (FT_Long)( table->block - old_base );
90 FT_Byte** offset = table->elements;
91 FT_Byte** limit = offset + table->max_elems;
94 for ( ; offset < limit; offset++ )
95 {
96 if ( offset[0] )
97 offset[0] += delta;
98 }
99 }
102 static FT_Error
103 reallocate_t1_table( PS_Table* table,
104 FT_Long new_size )
105 {
106 FT_Memory memory = table->memory;
107 FT_Byte* old_base = table->block;
108 FT_Error error;
111 /* allocate new base block */
112 if ( ALLOC( table->block, new_size ) )
113 return error;
115 /* copy elements and shift offsets */
116 if (old_base )
117 {
118 MEM_Copy( table->block, old_base, table->capacity );
119 shift_elements( table, old_base );
120 FREE( old_base );
121 }
123 table->capacity = new_size;
125 return PSaux_Err_Ok;
126 }
129 /*************************************************************************/
130 /* */
131 /* <Function> */
132 /* PS_Table_Add */
133 /* */
134 /* <Description> */
135 /* Adds an object to a PS_Table, possibly growing its memory block. */
136 /* */
137 /* <InOut> */
138 /* table :: The target table. */
139 /* */
140 /* <Input> */
141 /* index :: The index of the object in the table. */
142 /* */
143 /* object :: The address of the object to copy in memory. */
144 /* */
145 /* length :: The length in bytes of the source object. */
146 /* */
147 /* <Return> */
148 /* FreeType error code. 0 means success. An error is returned if a */
149 /* reallocation fails. */
150 /* */
151 FT_LOCAL_DEF FT_Error
152 PS_Table_Add( PS_Table* table,
153 FT_Int index,
154 void* object,
155 FT_Int length )
156 {
157 if ( index < 0 || index > table->max_elems )
158 {
159 FT_ERROR(( "PS_Table_Add: invalid index\n" ));
160 return PSaux_Err_Invalid_Argument;
161 }
163 /* grow the base block if needed */
164 if ( table->cursor + length > table->capacity )
165 {
166 FT_Error error;
167 FT_Offset new_size = table->capacity;
168 FT_Long in_offset;
171 in_offset = (FT_Long)((FT_Byte*)object - table->block);
172 if ( (FT_ULong)in_offset >= table->capacity )
173 in_offset = -1;
175 while ( new_size < table->cursor + length )
176 new_size += 1024;
178 error = reallocate_t1_table( table, new_size );
179 if ( error )
180 return error;
182 if ( in_offset >= 0 )
183 object = table->block + in_offset;
184 }
186 /* add the object to the base block and adjust offset */
187 table->elements[index] = table->block + table->cursor;
188 table->lengths [index] = length;
189 MEM_Copy( table->block + table->cursor, object, length );
191 table->cursor += length;
192 return PSaux_Err_Ok;
193 }
196 /*************************************************************************/
197 /* */
198 /* <Function> */
199 /* PS_Table_Done */
200 /* */
201 /* <Description> */
202 /* Finalizes a PS_Table (i.e., reallocate it to its current cursor). */
203 /* */
204 /* <InOut> */
205 /* table :: The target table. */
206 /* */
207 /* <Note> */
208 /* This function does NOT release the heap's memory block. It is up */
209 /* to the caller to clean it, or reference it in its own structures. */
210 /* */
211 FT_LOCAL_DEF void
212 PS_Table_Done( PS_Table* table )
213 {
214 FT_Memory memory = table->memory;
215 FT_Error error;
216 FT_Byte* old_base = table->block;
219 /* should never fail, because rec.cursor <= rec.size */
220 if ( !old_base )
221 return;
223 if ( ALLOC( table->block, table->cursor ) )
224 return;
225 MEM_Copy( table->block, old_base, table->cursor );
226 shift_elements( table, old_base );
228 table->capacity = table->cursor;
229 FREE( old_base );
230 }
233 FT_LOCAL_DEF void
234 PS_Table_Release( PS_Table* table )
235 {
236 FT_Memory memory = table->memory;
239 if ( (FT_ULong)table->init == 0xDEADBEEFUL )
240 {
241 FREE( table->block );
242 FREE( table->elements );
243 FREE( table->lengths );
244 table->init = 0;
245 }
246 }
249 /*************************************************************************/
250 /*************************************************************************/
251 /***** *****/
252 /***** T1 PARSER *****/
253 /***** *****/
254 /*************************************************************************/
255 /*************************************************************************/
258 #define IS_T1_WHITESPACE( c ) ( (c) == ' ' || (c) == '\t' )
259 #define IS_T1_LINESPACE( c ) ( (c) == '\r' || (c) == '\n' )
261 #define IS_T1_SPACE( c ) ( IS_T1_WHITESPACE( c ) || IS_T1_LINESPACE( c ) )
264 FT_LOCAL_DEF void
265 T1_Skip_Spaces( T1_Parser* parser )
266 {
267 FT_Byte* cur = parser->cursor;
268 FT_Byte* limit = parser->limit;
271 while ( cur < limit )
272 {
273 FT_Byte c = *cur;
276 if ( !IS_T1_SPACE( c ) )
277 break;
278 cur++;
279 }
280 parser->cursor = cur;
281 }
284 FT_LOCAL_DEF void
285 T1_Skip_Alpha( T1_Parser* parser )
286 {
287 FT_Byte* cur = parser->cursor;
288 FT_Byte* limit = parser->limit;
291 while ( cur < limit )
292 {
293 FT_Byte c = *cur;
296 if ( IS_T1_SPACE( c ) )
297 break;
298 cur++;
299 }
300 parser->cursor = cur;
301 }
304 FT_LOCAL_DEF void
305 T1_ToToken( T1_Parser* parser,
306 T1_Token* token )
307 {
308 FT_Byte* cur;
309 FT_Byte* limit;
310 FT_Byte starter, ender;
311 FT_Int embed;
314 token->type = t1_token_none;
315 token->start = 0;
316 token->limit = 0;
318 /* first of all, skip space */
319 T1_Skip_Spaces( parser );
321 cur = parser->cursor;
322 limit = parser->limit;
324 if ( cur < limit )
325 {
326 switch ( *cur )
327 {
328 /************* check for strings ***********************/
329 case '(':
330 token->type = t1_token_string;
331 ender = ')';
332 goto Lookup_Ender;
334 /************* check for programs/array ****************/
335 case '{':
336 token->type = t1_token_array;
337 ender = '}';
338 goto Lookup_Ender;
340 /************* check for table/array ******************/
341 case '[':
342 token->type = t1_token_array;
343 ender = ']';
345 Lookup_Ender:
346 embed = 1;
347 starter = *cur++;
348 token->start = cur;
349 while ( cur < limit )
350 {
351 if ( *cur == starter )
352 embed++;
353 else if ( *cur == ender )
354 {
355 embed--;
356 if ( embed <= 0 )
357 {
358 token->limit = cur++;
359 break;
360 }
361 }
362 cur++;
363 }
364 break;
366 /* **************** otherwise, it's any token **********/
367 default:
368 token->start = cur++;
369 token->type = t1_token_any;
370 while ( cur < limit && !IS_T1_SPACE( *cur ) )
371 cur++;
373 token->limit = cur;
374 }
376 if ( !token->limit )
377 {
378 token->start = 0;
379 token->type = t1_token_none;
380 }
382 parser->cursor = cur;
383 }
384 }
387 FT_LOCAL_DEF void
388 T1_ToTokenArray( T1_Parser* parser,
389 T1_Token* tokens,
390 FT_UInt max_tokens,
391 FT_Int* pnum_tokens )
392 {
393 T1_Token master;
396 *pnum_tokens = -1;
398 T1_ToToken( parser, &master );
399 if ( master.type == t1_token_array )
400 {
401 FT_Byte* old_cursor = parser->cursor;
402 FT_Byte* old_limit = parser->limit;
403 T1_Token* cur = tokens;
404 T1_Token* limit = cur + max_tokens;
407 parser->cursor = master.start;
408 parser->limit = master.limit;
410 while ( parser->cursor < parser->limit )
411 {
412 T1_Token token;
415 T1_ToToken( parser, &token );
416 if ( !token.type )
417 break;
419 if ( cur < limit )
420 *cur = token;
422 cur++;
423 }
425 *pnum_tokens = (FT_Int)( cur - tokens );
427 parser->cursor = old_cursor;
428 parser->limit = old_limit;
429 }
430 }
433 static FT_Long
434 t1_toint( FT_Byte** cursor,
435 FT_Byte* limit )
436 {
437 FT_Long result = 0;
438 FT_Byte* cur = *cursor;
439 FT_Byte c = '\0', d;
442 for ( ; cur < limit; cur++ )
443 {
444 c = *cur;
445 d = (FT_Byte)( c - '0' );
446 if ( d < 10 )
447 break;
449 if ( c == '-' )
450 {
451 cur++;
452 break;
453 }
454 }
456 if ( cur < limit )
457 {
458 do
459 {
460 d = (FT_Byte)( cur[0] - '0' );
461 if ( d >= 10 )
462 break;
464 result = result * 10 + d;
465 cur++;
467 } while ( cur < limit );
469 if ( c == '-' )
470 result = -result;
471 }
473 *cursor = cur;
474 return result;
475 }
478 static FT_Long
479 t1_tofixed( FT_Byte** cursor,
480 FT_Byte* limit,
481 FT_Long power_ten )
482 {
483 FT_Byte* cur = *cursor;
484 FT_Long num, divider, result;
485 FT_Int sign = 0;
486 FT_Byte d;
489 if ( cur >= limit )
490 return 0;
492 /* first of all, check the sign */
493 if ( *cur == '-' )
494 {
495 sign = 1;
496 cur++;
497 }
499 /* then, read the integer part, if any */
500 if ( *cur != '.' )
501 result = t1_toint( &cur, limit ) << 16;
502 else
503 result = 0;
505 num = 0;
506 divider = 1;
508 if ( cur >= limit )
509 goto Exit;
511 /* read decimal part, if any */
512 if ( *cur == '.' && cur + 1 < limit )
513 {
514 cur++;
516 for (;;)
517 {
518 d = (FT_Byte)( *cur - '0' );
519 if ( d >= 10 )
520 break;
522 if ( divider < 10000000L )
523 {
524 num = num * 10 + d;
525 divider *= 10;
526 }
528 cur++;
529 if ( cur >= limit )
530 break;
531 }
532 }
534 /* read exponent, if any */
535 if ( cur + 1 < limit && ( *cur == 'e' || *cur == 'E' ) )
536 {
537 cur++;
538 power_ten += t1_toint( &cur, limit );
539 }
541 Exit:
542 /* raise to power of ten if needed */
543 while ( power_ten > 0 )
544 {
545 result = result * 10;
546 num = num * 10;
547 power_ten--;
548 }
550 while ( power_ten < 0 )
551 {
552 result = result / 10;
553 divider = divider * 10;
554 power_ten++;
555 }
557 if ( num )
558 result += FT_DivFix( num, divider );
560 if ( sign )
561 result = -result;
563 *cursor = cur;
564 return result;
565 }
568 static FT_Int
569 t1_tocoordarray( FT_Byte** cursor,
570 FT_Byte* limit,
571 FT_Int max_coords,
572 FT_Short* coords )
573 {
574 FT_Byte* cur = *cursor;
575 FT_Int count = 0;
576 FT_Byte c, ender;
579 if ( cur >= limit )
580 goto Exit;
582 /* check for the beginning of an array; if not, only one number will */
583 /* be read */
584 c = *cur;
585 ender = 0;
587 if ( c == '[' )
588 ender = ']';
590 if ( c == '{' )
591 ender = '}';
593 if ( ender )
594 cur++;
596 /* now, read the coordinates */
597 for ( ; cur < limit; )
598 {
599 /* skip whitespace in front of data */
600 for (;;)
601 {
602 c = *cur;
603 if ( c != ' ' && c != '\t' )
604 break;
606 cur++;
607 if ( cur >= limit )
608 goto Exit;
609 }
611 if ( count >= max_coords || c == ender )
612 break;
614 coords[count] = (FT_Short)( t1_tofixed( &cur, limit, 0 ) >> 16 );
615 count++;
617 if ( !ender )
618 break;
619 }
621 Exit:
622 *cursor = cur;
623 return count;
624 }
627 static FT_Int
628 t1_tofixedarray( FT_Byte** cursor,
629 FT_Byte* limit,
630 FT_Int max_values,
631 FT_Fixed* values,
632 FT_Int power_ten )
633 {
634 FT_Byte* cur = *cursor;
635 FT_Int count = 0;
636 FT_Byte c, ender;
639 if ( cur >= limit ) goto Exit;
641 /* check for the beginning of an array. If not, only one number will */
642 /* be read */
643 c = *cur;
644 ender = 0;
646 if ( c == '[' )
647 ender = ']';
649 if ( c == '{' )
650 ender = '}';
652 if ( ender )
653 cur++;
655 /* now, read the values */
656 for ( ; cur < limit; )
657 {
658 /* skip whitespace in front of data */
659 for (;;)
660 {
661 c = *cur;
662 if ( c != ' ' && c != '\t' )
663 break;
665 cur++;
666 if ( cur >= limit )
667 goto Exit;
668 }
670 if ( count >= max_values || c == ender )
671 break;
673 values[count] = t1_tofixed( &cur, limit, power_ten );
674 count++;
676 if ( !ender )
677 break;
678 }
680 Exit:
681 *cursor = cur;
682 return count;
683 }
686 #if 0
688 static FT_String*
689 t1_tostring( FT_Byte** cursor,
690 FT_Byte* limit,
691 FT_Memory memory )
692 {
693 FT_Byte* cur = *cursor;
694 FT_Int len = 0;
695 FT_Int count;
696 FT_String* result;
697 FT_Error error;
700 /* XXX: some stupid fonts have a `Notice' or `Copyright' string */
701 /* that simply doesn't begin with an opening parenthesis, even */
702 /* though they have a closing one! E.g. "amuncial.pfb" */
703 /* */
704 /* We must deal with these ill-fated cases there. Note that */
705 /* these fonts didn't work with the old Type 1 driver as the */
706 /* notice/copyright was not recognized as a valid string token */
707 /* and made the old token parser commit errors. */
709 while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) )
710 cur++;
711 if ( cur + 1 >= limit )
712 return 0;
714 if ( *cur == '(' )
715 cur++; /* skip the opening parenthesis, if there is one */
717 *cursor = cur;
718 count = 0;
720 /* then, count its length */
721 for ( ; cur < limit; cur++ )
722 {
723 if ( *cur == '(' )
724 count++;
726 else if ( *cur == ')' )
727 {
728 count--;
729 if ( count < 0 )
730 break;
731 }
732 }
734 len = cur - *cursor;
735 if ( cur >= limit || ALLOC( result, len + 1 ) )
736 return 0;
738 /* now copy the string */
739 MEM_Copy( result, *cursor, len );
740 result[len] = '\0';
741 *cursor = cur;
742 return result;
743 }
745 #endif /* 0 */
748 static int
749 t1_tobool( FT_Byte** cursor,
750 FT_Byte* limit )
751 {
752 FT_Byte* cur = *cursor;
753 FT_Bool result = 0;
756 /* return 1 if we find `true', 0 otherwise */
757 if ( cur + 3 < limit &&
758 cur[0] == 't' &&
759 cur[1] == 'r' &&
760 cur[2] == 'u' &&
761 cur[3] == 'e' )
762 {
763 result = 1;
764 cur += 5;
765 }
766 else if ( cur + 4 < limit &&
767 cur[0] == 'f' &&
768 cur[1] == 'a' &&
769 cur[2] == 'l' &&
770 cur[3] == 's' &&
771 cur[4] == 'e' )
772 {
773 result = 0;
774 cur += 6;
775 }
777 *cursor = cur;
778 return result;
779 }
782 /* Load a simple field (i.e. non-table) into the current list of objects */
783 FT_LOCAL_DEF FT_Error
784 T1_Load_Field( T1_Parser* parser,
785 const T1_Field* field,
786 void** objects,
787 FT_UInt max_objects,
788 FT_ULong* pflags )
789 {
790 T1_Token token;
791 FT_Byte* cur;
792 FT_Byte* limit;
793 FT_UInt count;
794 FT_UInt index;
795 FT_Error error;
798 T1_ToToken( parser, &token );
799 if ( !token.type )
800 goto Fail;
802 count = 1;
803 index = 0;
804 cur = token.start;
805 limit = token.limit;
807 if ( token.type == t1_token_array )
808 {
809 /* if this is an array, and we have no blend, an error occurs */
810 if ( max_objects == 0 )
811 goto Fail;
813 count = max_objects;
814 index = 1;
815 }
817 for ( ; count > 0; count--, index++ )
818 {
819 FT_Byte* q = (FT_Byte*)objects[index] + field->offset;
820 FT_Long val;
821 FT_String* string;
824 switch ( field->type )
825 {
826 case t1_field_bool:
827 val = t1_tobool( &cur, limit );
828 goto Store_Integer;
830 case t1_field_fixed:
831 val = t1_tofixed( &cur, limit, 3 );
832 goto Store_Integer;
834 case t1_field_integer:
835 val = t1_toint( &cur, limit );
837 Store_Integer:
838 switch ( field->size )
839 {
840 case 1:
841 *(FT_Byte*)q = (FT_Byte)val;
842 break;
844 case 2:
845 *(FT_UShort*)q = (FT_UShort)val;
846 break;
848 case 4:
849 *(FT_UInt32*)q = (FT_UInt32)val;
850 break;
852 default: /* for 64-bit systems */
853 *(FT_Long*)q = val;
854 }
855 break;
857 case t1_field_string:
858 {
859 FT_Memory memory = parser->memory;
860 FT_UInt len = (FT_UInt)( limit - cur );
863 if ( *(FT_String**)q )
864 /* with synthetic fonts, it's possible to find a field twice */
865 break;
867 if ( ALLOC( string, len + 1 ) )
868 goto Exit;
870 MEM_Copy( string, cur, len );
871 string[len] = 0;
873 *(FT_String**)q = string;
874 }
875 break;
877 default:
878 /* an error occured */
879 goto Fail;
880 }
881 }
883 #if 0 /* obsolete - keep for reference */
884 if ( pflags )
885 *pflags |= 1L << field->flag_bit;
886 #else
887 FT_UNUSED( pflags );
888 #endif
890 error = PSaux_Err_Ok;
892 Exit:
893 return error;
895 Fail:
896 error = PSaux_Err_Invalid_File_Format;
897 goto Exit;
898 }
901 #define T1_MAX_TABLE_ELEMENTS 32
904 FT_LOCAL_DEF FT_Error
905 T1_Load_Field_Table( T1_Parser* parser,
906 const T1_Field* field,
907 void** objects,
908 FT_UInt max_objects,
909 FT_ULong* pflags )
910 {
911 T1_Token elements[T1_MAX_TABLE_ELEMENTS];
912 T1_Token* token;
913 FT_Int num_elements;
914 FT_Error error = 0;
915 FT_Byte* old_cursor;
916 FT_Byte* old_limit;
917 T1_Field fieldrec = *(T1_Field*)field;
919 #if 1
920 fieldrec.type = t1_field_integer;
921 if ( field->type == t1_field_fixed_array )
922 fieldrec.type = t1_field_fixed;
923 #endif
925 T1_ToTokenArray( parser, elements, 32, &num_elements );
926 if ( num_elements < 0 )
927 goto Fail;
929 if ( num_elements > T1_MAX_TABLE_ELEMENTS )
930 num_elements = T1_MAX_TABLE_ELEMENTS;
932 old_cursor = parser->cursor;
933 old_limit = parser->limit;
935 /* we store the elements count */
936 *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
937 (FT_Byte)num_elements;
939 /* we now load each element, adjusting the field.offset on each one */
940 token = elements;
941 for ( ; num_elements > 0; num_elements--, token++ )
942 {
943 parser->cursor = token->start;
944 parser->limit = token->limit;
945 T1_Load_Field( parser, &fieldrec, objects, max_objects, 0 );
946 fieldrec.offset += fieldrec.size;
947 }
949 #if 0 /* obsolete -- keep for reference */
950 if ( pflags )
951 *pflags |= 1L << field->flag_bit;
952 #else
953 FT_UNUSED( pflags );
954 #endif
956 parser->cursor = old_cursor;
957 parser->limit = old_limit;
959 Exit:
960 return error;
962 Fail:
963 error = PSaux_Err_Invalid_File_Format;
964 goto Exit;
965 }
968 FT_LOCAL_DEF FT_Long
969 T1_ToInt( T1_Parser* parser )
970 {
971 return t1_toint( &parser->cursor, parser->limit );
972 }
975 FT_LOCAL_DEF FT_Fixed
976 T1_ToFixed( T1_Parser* parser,
977 FT_Int power_ten )
978 {
979 return t1_tofixed( &parser->cursor, parser->limit, power_ten );
980 }
983 FT_LOCAL_DEF FT_Int
984 T1_ToCoordArray( T1_Parser* parser,
985 FT_Int max_coords,
986 FT_Short* coords )
987 {
988 return t1_tocoordarray( &parser->cursor, parser->limit,
989 max_coords, coords );
990 }
993 FT_LOCAL_DEF FT_Int
994 T1_ToFixedArray( T1_Parser* parser,
995 FT_Int max_values,
996 FT_Fixed* values,
997 FT_Int power_ten )
998 {
999 return t1_tofixedarray( &parser->cursor, parser->limit,
1000 max_values, values, power_ten );
1001 }
1004 #if 0
1006 FT_LOCAL_DEF FT_String*
1007 T1_ToString( T1_Parser* parser )
1008 {
1009 return t1_tostring( &parser->cursor, parser->limit, parser->memory );
1010 }
1013 FT_LOCAL_DEF FT_Bool
1014 T1_ToBool( T1_Parser* parser )
1015 {
1016 return t1_tobool( &parser->cursor, parser->limit );
1017 }
1019 #endif /* 0 */
1022 FT_LOCAL_DEF void
1023 T1_Init_Parser( T1_Parser* parser,
1024 FT_Byte* base,
1025 FT_Byte* limit,
1026 FT_Memory memory )
1027 {
1028 parser->error = 0;
1029 parser->base = base;
1030 parser->limit = limit;
1031 parser->cursor = base;
1032 parser->memory = memory;
1033 parser->funcs = t1_parser_funcs;
1034 }
1037 FT_LOCAL_DEF void
1038 T1_Done_Parser( T1_Parser* parser )
1039 {
1040 FT_UNUSED( parser );
1041 }
1044 /*************************************************************************/
1045 /*************************************************************************/
1046 /***** *****/
1047 /***** T1 BUILDER *****/
1048 /***** *****/
1049 /*************************************************************************/
1050 /*************************************************************************/
1052 /*************************************************************************/
1053 /* */
1054 /* <Function> */
1055 /* T1_Builder_Init */
1056 /* */
1057 /* <Description> */
1058 /* Initializes a given glyph builder. */
1059 /* */
1060 /* <InOut> */
1061 /* builder :: A pointer to the glyph builder to initialize. */
1062 /* */
1063 /* <Input> */
1064 /* face :: The current face object. */
1065 /* */
1066 /* size :: The current size object. */
1067 /* */
1068 /* glyph :: The current glyph object. */
1069 /* */
1070 FT_LOCAL_DEF void
1071 T1_Builder_Init( T1_Builder* builder,
1072 FT_Face face,
1073 FT_Size size,
1074 FT_GlyphSlot glyph )
1075 {
1076 builder->path_begun = 0;
1077 builder->load_points = 1;
1079 builder->face = face;
1080 builder->glyph = glyph;
1081 builder->memory = face->memory;
1083 if ( glyph )
1084 {
1085 FT_GlyphLoader* loader = glyph->internal->loader;
1088 builder->loader = loader;
1089 builder->base = &loader->base.outline;
1090 builder->current = &loader->current.outline;
1091 FT_GlyphLoader_Rewind( loader );
1092 }
1094 if ( size )
1095 {
1096 builder->scale_x = size->metrics.x_scale;
1097 builder->scale_y = size->metrics.y_scale;
1098 }
1100 builder->pos_x = 0;
1101 builder->pos_y = 0;
1103 builder->left_bearing.x = 0;
1104 builder->left_bearing.y = 0;
1105 builder->advance.x = 0;
1106 builder->advance.y = 0;
1108 builder->funcs = t1_builder_funcs;
1109 }
1112 /*************************************************************************/
1113 /* */
1114 /* <Function> */
1115 /* T1_Builder_Done */
1116 /* */
1117 /* <Description> */
1118 /* Finalizes a given glyph builder. Its contents can still be used */
1119 /* after the call, but the function saves important information */
1120 /* within the corresponding glyph slot. */
1121 /* */
1122 /* <Input> */
1123 /* builder :: A pointer to the glyph builder to finalize. */
1124 /* */
1125 FT_LOCAL_DEF void
1126 T1_Builder_Done( T1_Builder* builder )
1127 {
1128 FT_GlyphSlot glyph = builder->glyph;
1131 if ( glyph )
1132 glyph->outline = *builder->base;
1133 }
1136 /* check that there is enough room for `count' more points */
1137 FT_LOCAL_DEF FT_Error
1138 T1_Builder_Check_Points( T1_Builder* builder,
1139 FT_Int count )
1140 {
1141 return FT_GlyphLoader_Check_Points( builder->loader, count, 0 );
1142 }
1145 /* add a new point, do not check space */
1146 FT_LOCAL_DEF void
1147 T1_Builder_Add_Point( T1_Builder* builder,
1148 FT_Pos x,
1149 FT_Pos y,
1150 FT_Byte flag )
1151 {
1152 FT_Outline* outline = builder->current;
1155 if ( builder->load_points )
1156 {
1157 FT_Vector* point = outline->points + outline->n_points;
1158 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points;
1161 if ( builder->shift )
1162 {
1163 x >>= 16;
1164 y >>= 16;
1165 }
1166 point->x = x;
1167 point->y = y;
1168 *control = (FT_Byte)( flag ? FT_Curve_Tag_On : FT_Curve_Tag_Cubic );
1170 builder->last = *point;
1171 }
1172 outline->n_points++;
1173 }
1176 /* check space for a new on-curve point, then add it */
1177 FT_LOCAL_DEF FT_Error
1178 T1_Builder_Add_Point1( T1_Builder* builder,
1179 FT_Pos x,
1180 FT_Pos y )
1181 {
1182 FT_Error error;
1185 error = T1_Builder_Check_Points( builder, 1 );
1186 if ( !error )
1187 T1_Builder_Add_Point( builder, x, y, 1 );
1189 return error;
1190 }
1193 /* check room for a new contour, then add it */
1194 FT_LOCAL_DEF FT_Error
1195 T1_Builder_Add_Contour( T1_Builder* builder )
1196 {
1197 FT_Outline* outline = builder->current;
1198 FT_Error error;
1201 if ( !builder->load_points )
1202 {
1203 outline->n_contours++;
1204 return PSaux_Err_Ok;
1205 }
1207 error = FT_GlyphLoader_Check_Points( builder->loader, 0, 1 );
1208 if ( !error )
1209 {
1210 if ( outline->n_contours > 0 )
1211 outline->contours[outline->n_contours - 1] =
1212 (short)( outline->n_points - 1 );
1214 outline->n_contours++;
1215 }
1217 return error;
1218 }
1221 /* if a path was begun, add its first on-curve point */
1222 FT_LOCAL_DEF FT_Error
1223 T1_Builder_Start_Point( T1_Builder* builder,
1224 FT_Pos x,
1225 FT_Pos y )
1226 {
1227 FT_Error error = 0;
1230 /* test whether we are building a new contour */
1231 if ( !builder->path_begun )
1232 {
1233 builder->path_begun = 1;
1234 error = T1_Builder_Add_Contour( builder );
1235 if ( !error )
1236 error = T1_Builder_Add_Point1( builder, x, y );
1237 }
1238 return error;
1239 }
1242 /* close the current contour */
1243 FT_LOCAL_DEF void
1244 T1_Builder_Close_Contour( T1_Builder* builder )
1245 {
1246 FT_Outline* outline = builder->current;
1249 /* XXXX: We must not include the last point in the path if it */
1250 /* is located on the first point. */
1251 if ( outline->n_points > 1 )
1252 {
1253 FT_Int first = 0;
1254 FT_Vector* p1 = outline->points + first;
1255 FT_Vector* p2 = outline->points + outline->n_points - 1;
1256 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1;
1259 if ( outline->n_contours > 1 )
1260 {
1261 first = outline->contours[outline->n_contours - 2] + 1;
1262 p1 = outline->points + first;
1263 }
1265 /* `delete' last point only if it coincides with the first */
1266 /* point and it is not a control point (which can happen). */
1267 if ( p1->x == p2->x && p1->y == p2->y )
1268 if ( *control == FT_Curve_Tag_On )
1269 outline->n_points--;
1270 }
1272 if ( outline->n_contours > 0 )
1273 outline->contours[outline->n_contours - 1] =
1274 (short)( outline->n_points - 1 );
1275 }
1278 /*************************************************************************/
1279 /*************************************************************************/
1280 /***** *****/
1281 /***** OTHER *****/
1282 /***** *****/
1283 /*************************************************************************/
1284 /*************************************************************************/
1286 FT_LOCAL_DEF void
1287 T1_Decrypt( FT_Byte* buffer,
1288 FT_Offset length,
1289 FT_UShort seed )
1290 {
1291 while ( length > 0 )
1292 {
1293 FT_Byte plain;
1296 plain = (FT_Byte)( *buffer ^ ( seed >> 8 ) );
1297 seed = (FT_UShort)( ( *buffer + seed ) * 52845U + 22719 );
1298 *buffer++ = plain;
1299 length--;
1300 }
1301 }
1304 /* END */