1 /***************************************************************************/
5 /* AFM support for Type 1 fonts (body). */
7 /* Copyright 1996-2001 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 /***************************************************************************/
21 #include FT_INTERNAL_STREAM_H
22 #include FT_INTERNAL_TYPE1_TYPES_H
23 #include <stdlib.h> /* for qsort() */
24 #include <string.h> /* for strcmp() */
25 #include <ctype.h> /* for isalnum() */
28 /*************************************************************************/
30 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
31 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
32 /* messages during execution. */
35 #define FT_COMPONENT trace_t1afm
39 T1_Done_AFM( FT_Memory memory,
42 FREE( afm->kern_pairs );
49 #define IS_KERN_PAIR( p ) ( p[0] == 'K' && p[1] == 'P' )
51 #define IS_ALPHANUM( c ) ( isalnum( c ) || \
56 /* read a glyph name and return the equivalent glyph index */
58 afm_atoindex( FT_Byte** start,
69 while ( ( *p == ' ' || *p == '\t' || *p == ':' || *p == ';' ) &&
74 /* now, read glyph name */
75 while ( IS_ALPHANUM( *p ) && p < limit )
78 len = (FT_Int)( p - *start );
80 if ( len > 0 && len < 64 )
85 /* copy glyph name to intermediate array */
86 MEM_Copy( temp, *start, len );
89 /* lookup glyph name in face array */
90 for ( n = 0; n < type1->num_glyphs; n++ )
92 char* gname = (char*)type1->glyph_names[n];
95 if ( gname && gname[0] == temp[0] && strcmp( gname, temp ) == 0 )
107 /* read an integer */
109 afm_atoi( FT_Byte** start,
117 /* skip everything that is not a number */
118 while ( p < limit && !isdigit( *p ) )
127 while ( p < limit && isdigit( *p ) )
129 sum = sum * 10 + ( *p - '0' );
139 #define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 )
142 /* compare two kerning pairs */
143 FT_CALLBACK_DEF( int )
144 compare_kern_pairs( const void* a,
147 T1_Kern_Pair* pair1 = (T1_Kern_Pair*)a;
148 T1_Kern_Pair* pair2 = (T1_Kern_Pair*)b;
150 FT_ULong index1 = KERN_INDEX( pair1->glyph1, pair1->glyph2 );
151 FT_ULong index2 = KERN_INDEX( pair2->glyph1, pair2->glyph2 );
154 return ( index1 - index2 );
158 /* parse an AFM file -- for now, only read the kerning pairs */
159 FT_LOCAL_DEF FT_Error
160 T1_Read_AFM( FT_Face t1_face,
164 FT_Memory memory = stream->memory;
170 T1_Font* type1 = &((T1_Face)t1_face)->type1;
174 if ( ACCESS_Frame( stream->size ) )
177 start = (FT_Byte*)stream->cursor;
178 limit = (FT_Byte*)stream->limit;
181 /* we are now going to count the occurences of `KP' or `KPX' in */
184 for ( p = start; p < limit - 3; p++ )
186 if ( IS_KERN_PAIR( p ) )
190 /* Actually, kerning pairs are simply optional! */
194 /* allocate the pairs */
195 if ( ALLOC( afm, sizeof ( *afm ) ) ||
196 ALLOC_ARRAY( afm->kern_pairs, count, T1_Kern_Pair ) )
199 /* now, read each kern pair */
200 pair = afm->kern_pairs;
201 afm->num_pairs = count;
203 /* save in face object */
204 ((T1_Face)t1_face)->afm_data = afm;
206 t1_face->face_flags |= FT_FACE_FLAG_KERNING;
208 for ( p = start; p < limit - 3; p++ )
210 if ( IS_KERN_PAIR( p ) )
215 /* skip keyword (KP or KPX) */
220 pair->glyph1 = afm_atoindex( &q, limit, type1 );
221 pair->glyph2 = afm_atoindex( &q, limit, type1 );
222 pair->kerning.x = afm_atoi( &q, limit );
226 pair->kerning.y = afm_atoi( &q, limit );
232 /* now, sort the kern pairs according to their glyph indices */
233 qsort( afm->kern_pairs, count, sizeof ( T1_Kern_Pair ),
234 compare_kern_pairs );
246 /* find the kerning for a given glyph pair */
248 T1_Get_Kerning( T1_AFM* afm,
253 T1_Kern_Pair *min, *mid, *max;
254 FT_ULong index = KERN_INDEX( glyph1, glyph2 );
257 /* simple binary search */
258 min = afm->kern_pairs;
259 max = min + afm->num_pairs - 1;
266 mid = min + ( max - min ) / 2;
267 midi = KERN_INDEX( mid->glyph1, mid->glyph2 );
271 *kerning = mid->kerning;