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