xref: /inferno-os/libfreetype/t1afm.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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