1 /***************************************************************************/
5 /* AFM parser (body). */
7 /* Copyright 2006, 2007, 2008, 2009 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
19 #include FT_FREETYPE_H
20 #include FT_INTERNAL_POSTSCRIPT_AUX_H
28 /***************************************************************************/
32 /* The use of AFM_Stream is largely inspired by parseAFM.[ch] from t1lib. */
38 AFM_STREAM_STATUS_NORMAL
,
39 AFM_STREAM_STATUS_EOC
,
40 AFM_STREAM_STATUS_EOL
,
45 typedef struct AFM_StreamRec_
61 /* this works because empty lines are ignored */
62 #define AFM_IS_NEWLINE( ch ) ( (ch) == '\r' || (ch) == '\n' )
64 #define AFM_IS_EOF( ch ) ( (ch) == EOF || (ch) == '\x1a' )
65 #define AFM_IS_SPACE( ch ) ( (ch) == ' ' || (ch) == '\t' )
67 /* column separator; there is no `column' in the spec actually */
68 #define AFM_IS_SEP( ch ) ( (ch) == ';' )
71 ( ( (stream)->cursor < (stream)->limit ) ? *(stream)->cursor++ \
74 #define AFM_STREAM_KEY_BEGIN( stream ) \
75 (char*)( (stream)->cursor - 1 )
77 #define AFM_STREAM_KEY_LEN( stream, key ) \
78 ( (char*)(stream)->cursor - key - 1 )
80 #define AFM_STATUS_EOC( stream ) \
81 ( (stream)->status >= AFM_STREAM_STATUS_EOC )
83 #define AFM_STATUS_EOL( stream ) \
84 ( (stream)->status >= AFM_STREAM_STATUS_EOL )
86 #define AFM_STATUS_EOF( stream ) \
87 ( (stream)->status >= AFM_STREAM_STATUS_EOF )
91 afm_stream_skip_spaces( AFM_Stream stream
)
93 int ch
= 0; /* make stupid compiler happy */
96 if ( AFM_STATUS_EOC( stream
) )
102 if ( !AFM_IS_SPACE( ch
) )
106 if ( AFM_IS_NEWLINE( ch
) )
107 stream
->status
= AFM_STREAM_STATUS_EOL
;
108 else if ( AFM_IS_SEP( ch
) )
109 stream
->status
= AFM_STREAM_STATUS_EOC
;
110 else if ( AFM_IS_EOF( ch
) )
111 stream
->status
= AFM_STREAM_STATUS_EOF
;
117 /* read a key or value in current column */
119 afm_stream_read_one( AFM_Stream stream
)
125 afm_stream_skip_spaces( stream
);
126 if ( AFM_STATUS_EOC( stream
) )
129 str
= AFM_STREAM_KEY_BEGIN( stream
);
134 if ( AFM_IS_SPACE( ch
) )
136 else if ( AFM_IS_NEWLINE( ch
) )
138 stream
->status
= AFM_STREAM_STATUS_EOL
;
141 else if ( AFM_IS_SEP( ch
) )
143 stream
->status
= AFM_STREAM_STATUS_EOC
;
146 else if ( AFM_IS_EOF( ch
) )
148 stream
->status
= AFM_STREAM_STATUS_EOF
;
157 /* read a string (i.e., read to EOL) */
159 afm_stream_read_string( AFM_Stream stream
)
165 afm_stream_skip_spaces( stream
);
166 if ( AFM_STATUS_EOL( stream
) )
169 str
= AFM_STREAM_KEY_BEGIN( stream
);
175 if ( AFM_IS_NEWLINE( ch
) )
177 stream
->status
= AFM_STREAM_STATUS_EOL
;
180 else if ( AFM_IS_EOF( ch
) )
182 stream
->status
= AFM_STREAM_STATUS_EOF
;
191 /*************************************************************************/
197 /* all keys defined in Ch. 7-10 of 5004.AFM_Spec.pdf */
198 typedef enum AFM_Token_
204 AFM_TOKEN_BLENDAXISTYPES
,
205 AFM_TOKEN_BLENDDESIGNMAP
,
206 AFM_TOKEN_BLENDDESIGNPOSITIONS
,
212 AFM_TOKEN_CHARACTERSET
,
213 AFM_TOKEN_CHARACTERS
,
215 AFM_TOKEN_ENCODINGSCHEME
,
217 AFM_TOKEN_ENDCHARMETRICS
,
218 AFM_TOKEN_ENDCOMPOSITES
,
219 AFM_TOKEN_ENDDIRECTION
,
220 AFM_TOKEN_ENDFONTMETRICS
,
221 AFM_TOKEN_ENDKERNDATA
,
222 AFM_TOKEN_ENDKERNPAIRS
,
223 AFM_TOKEN_ENDTRACKKERN
,
225 AFM_TOKEN_FAMILYNAME
,
229 AFM_TOKEN_ISBASEFONT
,
231 AFM_TOKEN_ISFIXEDPITCH
,
233 AFM_TOKEN_ITALICANGLE
,
239 AFM_TOKEN_MAPPINGSCHEME
,
240 AFM_TOKEN_METRICSSETS
,
245 AFM_TOKEN_STARTCHARMETRICS
,
246 AFM_TOKEN_STARTCOMPOSITES
,
247 AFM_TOKEN_STARTDIRECTION
,
248 AFM_TOKEN_STARTFONTMETRICS
,
249 AFM_TOKEN_STARTKERNDATA
,
250 AFM_TOKEN_STARTKERNPAIRS
,
251 AFM_TOKEN_STARTKERNPAIRS0
,
252 AFM_TOKEN_STARTKERNPAIRS1
,
253 AFM_TOKEN_STARTTRACKKERN
,
257 AFM_TOKEN_UNDERLINEPOSITION
,
258 AFM_TOKEN_UNDERLINETHICKNESS
,
272 AFM_TOKEN_WEIGHTVECTOR
,
280 static const char* const afm_key_table
[N_AFM_TOKENS
] =
288 "BlendDesignPositions",
340 "UnderlineThickness",
360 * `afm_parser_read_vals' and `afm_parser_next_key' provide
361 * high-level operations to an AFM_Stream. The rest of the
362 * parser functions should use them without accessing the
363 * AFM_Stream directly.
366 FT_LOCAL_DEF( FT_Int
)
367 afm_parser_read_vals( AFM_Parser parser
,
371 AFM_Stream stream
= parser
->stream
;
376 if ( n
> AFM_MAX_ARGUMENTS
)
379 for ( i
= 0; i
< n
; i
++ )
382 AFM_Value val
= vals
+ i
;
385 if ( val
->type
== AFM_VALUE_TYPE_STRING
)
386 str
= afm_stream_read_string( stream
);
388 str
= afm_stream_read_one( stream
);
393 len
= AFM_STREAM_KEY_LEN( stream
, str
);
397 case AFM_VALUE_TYPE_STRING
:
398 case AFM_VALUE_TYPE_NAME
:
400 FT_Memory memory
= parser
->memory
;
404 if ( !FT_QALLOC( val
->u
.s
, len
+ 1 ) )
406 ft_memcpy( val
->u
.s
, str
, len
);
407 val
->u
.s
[len
] = '\0';
412 case AFM_VALUE_TYPE_FIXED
:
413 val
->u
.f
= PS_Conv_ToFixed( (FT_Byte
**)(void*)&str
,
414 (FT_Byte
*)str
+ len
, 0 );
417 case AFM_VALUE_TYPE_INTEGER
:
418 val
->u
.i
= PS_Conv_ToInt( (FT_Byte
**)(void*)&str
,
419 (FT_Byte
*)str
+ len
);
422 case AFM_VALUE_TYPE_BOOL
:
423 val
->u
.b
= FT_BOOL( len
== 4 &&
424 !ft_strncmp( str
, "true", 4 ) );
427 case AFM_VALUE_TYPE_INDEX
:
428 if ( parser
->get_index
)
429 val
->u
.i
= parser
->get_index( str
, len
, parser
->user_data
);
440 FT_LOCAL_DEF( char* )
441 afm_parser_next_key( AFM_Parser parser
,
445 AFM_Stream stream
= parser
->stream
;
446 char* key
= 0; /* make stupid compiler happy */
453 /* skip current line */
454 if ( !AFM_STATUS_EOL( stream
) )
455 afm_stream_read_string( stream
);
457 stream
->status
= AFM_STREAM_STATUS_NORMAL
;
458 key
= afm_stream_read_one( stream
);
460 /* skip empty line */
462 !AFM_STATUS_EOF( stream
) &&
463 AFM_STATUS_EOL( stream
) )
473 /* skip current column */
474 while ( !AFM_STATUS_EOC( stream
) )
475 afm_stream_read_one( stream
);
477 stream
->status
= AFM_STREAM_STATUS_NORMAL
;
478 key
= afm_stream_read_one( stream
);
480 /* skip empty column */
482 !AFM_STATUS_EOF( stream
) &&
483 AFM_STATUS_EOC( stream
) )
491 *len
= ( key
) ? (FT_Offset
)AFM_STREAM_KEY_LEN( stream
, key
)
499 afm_tokenize( const char* key
,
505 for ( n
= 0; n
< N_AFM_TOKENS
; n
++ )
507 if ( *( afm_key_table
[n
] ) == *key
)
509 for ( ; n
< N_AFM_TOKENS
; n
++ )
511 if ( *( afm_key_table
[n
] ) != *key
)
512 return AFM_TOKEN_UNKNOWN
;
514 if ( ft_strncmp( afm_key_table
[n
], key
, len
) == 0 )
515 return (AFM_Token
) n
;
520 return AFM_TOKEN_UNKNOWN
;
524 FT_LOCAL_DEF( FT_Error
)
525 afm_parser_init( AFM_Parser parser
,
534 if ( FT_NEW( stream
) )
537 stream
->cursor
= stream
->base
= base
;
538 stream
->limit
= limit
;
540 /* don't skip the first line during the first call */
541 stream
->status
= AFM_STREAM_STATUS_EOL
;
543 parser
->memory
= memory
;
544 parser
->stream
= stream
;
545 parser
->FontInfo
= NULL
;
546 parser
->get_index
= NULL
;
553 afm_parser_done( AFM_Parser parser
)
555 FT_Memory memory
= parser
->memory
;
558 FT_FREE( parser
->stream
);
562 FT_LOCAL_DEF( FT_Error
)
563 afm_parser_read_int( AFM_Parser parser
,
569 val
.type
= AFM_VALUE_TYPE_INTEGER
;
571 if ( afm_parser_read_vals( parser
, &val
, 1 ) == 1 )
578 return PSaux_Err_Syntax_Error
;
583 afm_parse_track_kern( AFM_Parser parser
)
585 AFM_FontInfo fi
= parser
->FontInfo
;
592 if ( afm_parser_read_int( parser
, &fi
->NumTrackKern
) )
595 if ( fi
->NumTrackKern
)
597 FT_Memory memory
= parser
->memory
;
601 if ( FT_QNEW_ARRAY( fi
->TrackKerns
, fi
->NumTrackKern
) )
605 while ( ( key
= afm_parser_next_key( parser
, 1, &len
) ) != 0 )
607 AFM_ValueRec shared_vals
[5];
610 switch ( afm_tokenize( key
, len
) )
612 case AFM_TOKEN_TRACKKERN
:
615 if ( n
>= fi
->NumTrackKern
)
618 tk
= fi
->TrackKerns
+ n
;
620 shared_vals
[0].type
= AFM_VALUE_TYPE_INTEGER
;
621 shared_vals
[1].type
= AFM_VALUE_TYPE_FIXED
;
622 shared_vals
[2].type
= AFM_VALUE_TYPE_FIXED
;
623 shared_vals
[3].type
= AFM_VALUE_TYPE_FIXED
;
624 shared_vals
[4].type
= AFM_VALUE_TYPE_FIXED
;
625 if ( afm_parser_read_vals( parser
, shared_vals
, 5 ) != 5 )
628 tk
->degree
= shared_vals
[0].u
.i
;
629 tk
->min_ptsize
= shared_vals
[1].u
.f
;
630 tk
->min_kern
= shared_vals
[2].u
.f
;
631 tk
->max_ptsize
= shared_vals
[3].u
.f
;
632 tk
->max_kern
= shared_vals
[4].u
.f
;
634 /* is this correct? */
635 if ( tk
->degree
< 0 && tk
->min_kern
> 0 )
636 tk
->min_kern
= -tk
->min_kern
;
639 case AFM_TOKEN_ENDTRACKKERN
:
640 case AFM_TOKEN_ENDKERNDATA
:
641 case AFM_TOKEN_ENDFONTMETRICS
:
642 fi
->NumTrackKern
= n
+ 1;
645 case AFM_TOKEN_UNKNOWN
:
654 return PSaux_Err_Syntax_Error
;
659 #define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 )
662 /* compare two kerning pairs */
663 FT_CALLBACK_DEF( int )
664 afm_compare_kern_pairs( const void* a
,
667 AFM_KernPair kp1
= (AFM_KernPair
)a
;
668 AFM_KernPair kp2
= (AFM_KernPair
)b
;
670 FT_ULong index1
= KERN_INDEX( kp1
->index1
, kp1
->index2
);
671 FT_ULong index2
= KERN_INDEX( kp2
->index1
, kp2
->index2
);
674 if ( index1
> index2
)
676 else if ( index1
< index2
)
684 afm_parse_kern_pairs( AFM_Parser parser
)
686 AFM_FontInfo fi
= parser
->FontInfo
;
693 if ( afm_parser_read_int( parser
, &fi
->NumKernPair
) )
696 if ( fi
->NumKernPair
)
698 FT_Memory memory
= parser
->memory
;
702 if ( FT_QNEW_ARRAY( fi
->KernPairs
, fi
->NumKernPair
) )
706 while ( ( key
= afm_parser_next_key( parser
, 1, &len
) ) != 0 )
708 AFM_Token token
= afm_tokenize( key
, len
);
718 AFM_ValueRec shared_vals
[4];
723 if ( n
>= fi
->NumKernPair
)
726 kp
= fi
->KernPairs
+ n
;
728 shared_vals
[0].type
= AFM_VALUE_TYPE_INDEX
;
729 shared_vals
[1].type
= AFM_VALUE_TYPE_INDEX
;
730 shared_vals
[2].type
= AFM_VALUE_TYPE_INTEGER
;
731 shared_vals
[3].type
= AFM_VALUE_TYPE_INTEGER
;
732 r
= afm_parser_read_vals( parser
, shared_vals
, 4 );
736 kp
->index1
= shared_vals
[0].u
.i
;
737 kp
->index2
= shared_vals
[1].u
.i
;
738 if ( token
== AFM_TOKEN_KPY
)
741 kp
->y
= shared_vals
[2].u
.i
;
745 kp
->x
= shared_vals
[2].u
.i
;
746 kp
->y
= ( token
== AFM_TOKEN_KP
&& r
== 4 )
747 ? shared_vals
[3].u
.i
: 0;
752 case AFM_TOKEN_ENDKERNPAIRS
:
753 case AFM_TOKEN_ENDKERNDATA
:
754 case AFM_TOKEN_ENDFONTMETRICS
:
755 fi
->NumKernPair
= n
+ 1;
756 ft_qsort( fi
->KernPairs
, fi
->NumKernPair
,
757 sizeof( AFM_KernPairRec
),
758 afm_compare_kern_pairs
);
761 case AFM_TOKEN_UNKNOWN
:
770 return PSaux_Err_Syntax_Error
;
775 afm_parse_kern_data( AFM_Parser parser
)
782 while ( ( key
= afm_parser_next_key( parser
, 1, &len
) ) != 0 )
784 switch ( afm_tokenize( key
, len
) )
786 case AFM_TOKEN_STARTTRACKKERN
:
787 error
= afm_parse_track_kern( parser
);
792 case AFM_TOKEN_STARTKERNPAIRS
:
793 case AFM_TOKEN_STARTKERNPAIRS0
:
794 error
= afm_parse_kern_pairs( parser
);
799 case AFM_TOKEN_ENDKERNDATA
:
800 case AFM_TOKEN_ENDFONTMETRICS
:
803 case AFM_TOKEN_UNKNOWN
:
812 return PSaux_Err_Syntax_Error
;
817 afm_parser_skip_section( AFM_Parser parser
,
819 AFM_Token end_section
)
827 key
= afm_parser_next_key( parser
, 1, NULL
);
832 while ( ( key
= afm_parser_next_key( parser
, 1, &len
) ) != 0 )
834 AFM_Token token
= afm_tokenize( key
, len
);
837 if ( token
== end_section
|| token
== AFM_TOKEN_ENDFONTMETRICS
)
842 return PSaux_Err_Syntax_Error
;
846 FT_LOCAL_DEF( FT_Error
)
847 afm_parser_parse( AFM_Parser parser
)
849 FT_Memory memory
= parser
->memory
;
850 AFM_FontInfo fi
= parser
->FontInfo
;
851 FT_Error error
= PSaux_Err_Syntax_Error
;
854 FT_Int metrics_sets
= 0;
858 return PSaux_Err_Invalid_Argument
;
860 key
= afm_parser_next_key( parser
, 1, &len
);
861 if ( !key
|| len
!= 16 ||
862 ft_strncmp( key
, "StartFontMetrics", 16 ) != 0 )
863 return PSaux_Err_Unknown_File_Format
;
865 while ( ( key
= afm_parser_next_key( parser
, 1, &len
) ) != 0 )
867 AFM_ValueRec shared_vals
[4];
870 switch ( afm_tokenize( key
, len
) )
872 case AFM_TOKEN_METRICSSETS
:
873 if ( afm_parser_read_int( parser
, &metrics_sets
) )
876 if ( metrics_sets
!= 0 && metrics_sets
!= 2 )
878 error
= PSaux_Err_Unimplemented_Feature
;
884 case AFM_TOKEN_ISCIDFONT
:
885 shared_vals
[0].type
= AFM_VALUE_TYPE_BOOL
;
886 if ( afm_parser_read_vals( parser
, shared_vals
, 1 ) != 1 )
889 fi
->IsCIDFont
= shared_vals
[0].u
.b
;
892 case AFM_TOKEN_FONTBBOX
:
893 shared_vals
[0].type
= AFM_VALUE_TYPE_FIXED
;
894 shared_vals
[1].type
= AFM_VALUE_TYPE_FIXED
;
895 shared_vals
[2].type
= AFM_VALUE_TYPE_FIXED
;
896 shared_vals
[3].type
= AFM_VALUE_TYPE_FIXED
;
897 if ( afm_parser_read_vals( parser
, shared_vals
, 4 ) != 4 )
900 fi
->FontBBox
.xMin
= shared_vals
[0].u
.f
;
901 fi
->FontBBox
.yMin
= shared_vals
[1].u
.f
;
902 fi
->FontBBox
.xMax
= shared_vals
[2].u
.f
;
903 fi
->FontBBox
.yMax
= shared_vals
[3].u
.f
;
906 case AFM_TOKEN_ASCENDER
:
907 shared_vals
[0].type
= AFM_VALUE_TYPE_FIXED
;
908 if ( afm_parser_read_vals( parser
, shared_vals
, 1 ) != 1 )
911 fi
->Ascender
= shared_vals
[0].u
.f
;
914 case AFM_TOKEN_DESCENDER
:
915 shared_vals
[0].type
= AFM_VALUE_TYPE_FIXED
;
916 if ( afm_parser_read_vals( parser
, shared_vals
, 1 ) != 1 )
919 fi
->Descender
= shared_vals
[0].u
.f
;
922 case AFM_TOKEN_STARTCHARMETRICS
:
927 if ( afm_parser_read_int( parser
, &n
) )
930 error
= afm_parser_skip_section( parser
, n
,
931 AFM_TOKEN_ENDCHARMETRICS
);
937 case AFM_TOKEN_STARTKERNDATA
:
938 error
= afm_parse_kern_data( parser
);
941 /* fall through since we only support kern data */
943 case AFM_TOKEN_ENDFONTMETRICS
:
952 FT_FREE( fi
->TrackKerns
);
953 fi
->NumTrackKern
= 0;
955 FT_FREE( fi
->KernPairs
);