1 /***************************************************************************/ 2 /* */ 3 /* t1afm.c */ 4 /* */ 5 /* AFM support for Type 1 fonts (body). */ 6 /* */ 7 /* Copyright 1996-2001, 2002 by */ 8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 9 /* */ 10 /* This file is part of the FreeType project, and may only be used, */ 11 /* modified, and distributed under the terms of the FreeType project */ 12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 13 /* this file you indicate that you have read the license and */ 14 /* understand and accept it fully. */ 15 /* */ 16 /***************************************************************************/ 17 18 19 #include <ft2build.h> 20 #include "t1afm.h" 21 #include FT_INTERNAL_STREAM_H 22 #include FT_INTERNAL_TYPE1_TYPES_H 23 24 25 /*************************************************************************/ 26 /* */ 27 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 28 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 29 /* messages during execution. */ 30 /* */ 31 #undef FT_COMPONENT 32 #define FT_COMPONENT trace_t1afm 33 34 35 FT_LOCAL_DEF( void ) T1_Done_AFM(FT_Memory memory,T1_AFM * afm)36 T1_Done_AFM( FT_Memory memory, 37 T1_AFM* afm ) 38 { 39 FT_FREE( afm->kern_pairs ); 40 afm->num_pairs = 0; 41 FT_FREE( afm ); 42 } 43 44 45 #undef IS_KERN_PAIR 46 #define IS_KERN_PAIR( p ) ( p[0] == 'K' && p[1] == 'P' ) 47 48 #define IS_ALPHANUM( c ) ( ft_isalnum( c ) || \ 49 c == '_' || \ 50 c == '.' ) 51 52 53 /* read a glyph name and return the equivalent glyph index */ 54 static FT_UInt afm_atoindex(FT_Byte ** start,FT_Byte * limit,T1_Font type1)55 afm_atoindex( FT_Byte** start, 56 FT_Byte* limit, 57 T1_Font type1 ) 58 { 59 FT_Byte* p = *start; 60 FT_PtrDist len; 61 FT_UInt result = 0; 62 char temp[64]; 63 64 65 /* skip whitespace */ 66 while ( ( *p == ' ' || *p == '\t' || *p == ':' || *p == ';' ) && 67 p < limit ) 68 p++; 69 *start = p; 70 71 /* now, read glyph name */ 72 while ( IS_ALPHANUM( *p ) && p < limit ) 73 p++; 74 75 len = p - *start; 76 77 if ( len > 0 && len < 64 ) 78 { 79 FT_Int n; 80 81 82 /* copy glyph name to intermediate array */ 83 FT_MEM_COPY( temp, *start, len ); 84 temp[len] = 0; 85 86 /* lookup glyph name in face array */ 87 for ( n = 0; n < type1->num_glyphs; n++ ) 88 { 89 char* gname = (char*)type1->glyph_names[n]; 90 91 92 if ( gname && gname[0] == temp[0] && ft_strcmp( gname, temp ) == 0 ) 93 { 94 result = n; 95 break; 96 } 97 } 98 } 99 *start = p; 100 return result; 101 } 102 103 104 /* read an integer */ 105 static int afm_atoi(FT_Byte ** start,FT_Byte * limit)106 afm_atoi( FT_Byte** start, 107 FT_Byte* limit ) 108 { 109 FT_Byte* p = *start; 110 int sum = 0; 111 int sign = 1; 112 113 114 /* skip everything that is not a number */ 115 while ( p < limit && !isdigit( *p ) ) 116 { 117 sign = 1; 118 if ( *p == '-' ) 119 sign = -1; 120 121 p++; 122 } 123 124 while ( p < limit && isdigit( *p ) ) 125 { 126 sum = sum * 10 + ( *p - '0' ); 127 p++; 128 } 129 *start = p; 130 131 return sum * sign; 132 } 133 134 135 #undef KERN_INDEX 136 #define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 ) 137 138 139 /* compare two kerning pairs */ 140 FT_CALLBACK_DEF( int ) compare_kern_pairs(const void * a,const void * b)141 compare_kern_pairs( const void* a, 142 const void* b ) 143 { 144 T1_Kern_Pair* pair1 = (T1_Kern_Pair*)a; 145 T1_Kern_Pair* pair2 = (T1_Kern_Pair*)b; 146 147 FT_ULong index1 = KERN_INDEX( pair1->glyph1, pair1->glyph2 ); 148 FT_ULong index2 = KERN_INDEX( pair2->glyph1, pair2->glyph2 ); 149 150 151 return ( index1 - index2 ); 152 } 153 154 155 /* parse an AFM file -- for now, only read the kerning pairs */ 156 FT_LOCAL_DEF( FT_Error ) T1_Read_AFM(FT_Face t1_face,FT_Stream stream)157 T1_Read_AFM( FT_Face t1_face, 158 FT_Stream stream ) 159 { 160 FT_Error error; 161 FT_Memory memory = stream->memory; 162 FT_Byte* start; 163 FT_Byte* limit; 164 FT_Byte* p; 165 FT_Int count = 0; 166 T1_Kern_Pair* pair; 167 T1_Font type1 = &((T1_Face)t1_face)->type1; 168 T1_AFM* afm = 0; 169 170 171 if ( FT_FRAME_ENTER( stream->size ) ) 172 return error; 173 174 start = (FT_Byte*)stream->cursor; 175 limit = (FT_Byte*)stream->limit; 176 p = start; 177 178 /* we are now going to count the occurences of `KP' or `KPX' in */ 179 /* the AFM file */ 180 count = 0; 181 for ( p = start; p < limit - 3; p++ ) 182 { 183 if ( IS_KERN_PAIR( p ) ) 184 count++; 185 } 186 187 /* Actually, kerning pairs are simply optional! */ 188 if ( count == 0 ) 189 goto Exit; 190 191 /* allocate the pairs */ 192 if ( FT_NEW( afm ) || FT_NEW_ARRAY( afm->kern_pairs, count ) ) 193 goto Exit; 194 195 /* now, read each kern pair */ 196 pair = afm->kern_pairs; 197 afm->num_pairs = count; 198 199 /* save in face object */ 200 ((T1_Face)t1_face)->afm_data = afm; 201 202 t1_face->face_flags |= FT_FACE_FLAG_KERNING; 203 204 for ( p = start; p < limit - 3; p++ ) 205 { 206 if ( IS_KERN_PAIR( p ) ) 207 { 208 FT_Byte* q; 209 210 211 /* skip keyword (KP or KPX) */ 212 q = p + 2; 213 if ( *q == 'X' ) 214 q++; 215 216 pair->glyph1 = afm_atoindex( &q, limit, type1 ); 217 pair->glyph2 = afm_atoindex( &q, limit, type1 ); 218 pair->kerning.x = afm_atoi( &q, limit ); 219 220 pair->kerning.y = 0; 221 if ( p[2] != 'X' ) 222 pair->kerning.y = afm_atoi( &q, limit ); 223 224 pair++; 225 } 226 } 227 228 /* now, sort the kern pairs according to their glyph indices */ 229 ft_qsort( afm->kern_pairs, count, sizeof ( T1_Kern_Pair ), 230 compare_kern_pairs ); 231 232 Exit: 233 if ( error ) 234 FT_FREE( afm ); 235 236 FT_FRAME_EXIT(); 237 238 return error; 239 } 240 241 242 /* find the kerning for a given glyph pair */ 243 FT_LOCAL_DEF( void ) T1_Get_Kerning(T1_AFM * afm,FT_UInt glyph1,FT_UInt glyph2,FT_Vector * kerning)244 T1_Get_Kerning( T1_AFM* afm, 245 FT_UInt glyph1, 246 FT_UInt glyph2, 247 FT_Vector* kerning ) 248 { 249 T1_Kern_Pair *min, *mid, *max; 250 FT_ULong idx = KERN_INDEX( glyph1, glyph2 ); 251 252 253 /* simple binary search */ 254 min = afm->kern_pairs; 255 max = min + afm->num_pairs - 1; 256 257 while ( min <= max ) 258 { 259 FT_ULong midi; 260 261 262 mid = min + ( max - min ) / 2; 263 midi = KERN_INDEX( mid->glyph1, mid->glyph2 ); 264 265 if ( midi == idx ) 266 { 267 *kerning = mid->kerning; 268 return; 269 } 270 271 if ( midi < idx ) 272 min = mid + 1; 273 else 274 max = mid - 1; 275 } 276 277 kerning->x = 0; 278 kerning->y = 0; 279 } 280 281 282 /* END */ 283