:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / subsys / win32k / freetype / src / cid / cidafm.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  cidafm.c                                                               */
4 /*                                                                         */
5 /*    AFM support for CID-keyed fonts (body).                              */
6 /*                                                                         */
7 /*  Copyright 1996-2000 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 #ifdef FT_FLAT_COMPILE
20
21 #include "cidafm.h"
22
23 #else
24
25 #include <freetype/src/cid/cidafm.h>
26
27 #endif
28
29
30 #include <freetype/internal/ftstream.h>
31 #include <freetype/internal/t1types.h>
32 #include <freetype/internal/t1errors.h>
33
34 #include <stdlib.h>  /* for qsort()   */
35 #include <string.h>  /* for strcmp()  */
36 #include <ctype.h>   /* for isalnum() */
37
38
39   /*************************************************************************/
40   /*                                                                       */
41   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
42   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
43   /* messages during execution.                                            */
44   /*                                                                       */
45 #undef  FT_COMPONENT
46 #define FT_COMPONENT  trace_cidafm
47
48
49   LOCAL_FUNC
50   void  CID_Done_AFM( FT_Memory  memory,
51                       CID_AFM*   afm )
52   {
53     FREE( afm->kern_pairs );
54     afm->num_pairs = 0;
55   }
56
57
58 #undef  IS_KERN_PAIR
59 #define IS_KERN_PAIR( p )  ( p[0] == 'K' && p[1] == 'P' )
60
61 #define IS_ALPHANUM( c )  ( isalnum( c ) || \
62                             c == '_'     || \
63                             c == '.'     )
64
65
66   /* read a glyph name and return the equivalent glyph index */
67   static
68   FT_UInt  afm_atoindex( FT_Byte**  start,
69                          FT_Byte*   limit,
70                          T1_Font*   type1 )
71   {
72     FT_Byte*  p = *start;
73     FT_Int    len;
74     FT_UInt   result = 0;
75     char      temp[64];
76
77
78     /* skip whitespace */
79     while ( ( *p == ' ' || *p == '\t' || *p == ':' || *p == ';' ) &&
80             p < limit                                             )
81       p++;
82     *start = p;
83
84     /* now, read glyph name */
85     while ( IS_ALPHANUM( *p ) && p < limit )
86       p++;
87
88     len = p - *start;
89
90     if ( len > 0 && len < 64 )
91     {
92       FT_Int  n;
93
94
95       /* copy glyph name to intermediate array */
96       MEM_Copy( temp, *start, len );
97       temp[len] = 0;
98
99       /* lookup glyph name in face array */
100       for ( n = 0; n < type1->num_glyphs; n++ )
101       {
102         char*  gname = (char*)type1->glyph_names[n];
103
104
105         if ( gname && gname[0] == temp[0] && strcmp( gname, temp ) == 0 )
106         {
107           result = n;
108           break;
109         }
110       }
111     }
112     *start = p;
113     return result;
114   }
115
116
117   /* read an integer */
118   static
119   int  afm_atoi( FT_Byte**  start,
120                  FT_Byte*   limit )
121   {
122     FT_Byte*  p    = *start;
123     int       sum  = 0;
124     int       sign = 1;
125
126
127     /* skip everything that is not a number */
128     while ( p < limit && !isdigit( *p ) )
129     {
130       sign = 1;
131       if ( *p == '-' )
132         sign = -1;
133
134       p++;
135     }
136
137     while ( p < limit && isdigit( *p ) )
138     {
139       sum = sum * 10 + ( *p - '0' );
140       p++;
141     }
142     *start = p;
143
144     return sum * sign;
145   }
146
147
148 #undef  KERN_INDEX
149 #define KERN_INDEX( g1, g2 )  ( ( (FT_ULong)g1 << 16 ) | g2 )
150
151
152   /* compare two kerning pairs */
153   static
154   int  compare_kern_pairs( const void*  a,
155                            const void*  b )
156   {
157     CID_Kern_Pair*  pair1 = (CID_Kern_Pair*)a;
158     CID_Kern_Pair*  pair2 = (CID_Kern_Pair*)b;
159
160     FT_ULong  index1 = KERN_INDEX( pair1->glyph1, pair1->glyph2 );
161     FT_ULong  index2 = KERN_INDEX( pair2->glyph1, pair2->glyph2 );
162
163
164     return ( index1 - index2 );
165   }
166
167
168   /* parse an AFM file -- for now, only read the kerning pairs */
169   LOCAL_FUNC
170   FT_Error  CID_Read_AFM( FT_Face    cid_face,
171                           FT_Stream  stream )
172   {
173     FT_Error        error;
174     FT_Memory       memory = stream->memory;
175     FT_Byte*        start;
176     FT_Byte*        limit;
177     FT_Byte*        p;
178     FT_Int          count = 0;
179     CID_Kern_Pair*  pair;
180     T1_Font*        type1 = &((T1_Face)t1_face)->type1;
181     CID_AFM*        afm   = 0;
182
183
184     if ( ACCESS_Frame( stream->size ) )
185       return error;
186
187     start = (FT_Byte*)stream->cursor;
188     limit = (FT_Byte*)stream->limit;
189     p     = start;
190
191     /* we are now going to count the occurrences of `KP' or `KPX' in */
192     /* the AFM file.                                                 */
193     count = 0;
194     for ( p = start; p < limit - 3; p++ )
195     {
196       if ( IS_KERN_PAIR( p ) )
197         count++;
198     }
199
200     /* Actually, kerning pairs are simply optional! */
201     if ( count == 0 )
202       goto Exit;
203
204     /* allocate the pairs */
205     if ( ALLOC( afm, sizeof ( *afm ) )                        ||
206          ALLOC_ARRAY( afm->kern_pairs, count, CID_Kern_Pair ) )
207       goto Exit;
208
209     /* now, read each kern pair */
210     pair           = afm->kern_pairs;
211     afm->num_pairs = count;
212
213     /* save in face object */
214     ((T1_Face)t1_face)->afm_data = afm;
215
216     for ( p = start; p < limit - 3; p++ )
217     {
218       if ( IS_KERN_PAIR( p ) )
219       {
220         FT_Byte*  q;
221
222
223         /* skip keyword (`KP' or `KPX') */
224         q = p + 2;
225         if ( *q == 'X' )
226           q++;
227
228         pair->glyph1    = afm_atoindex( &q, limit, type1 );
229         pair->glyph2    = afm_atoindex( &q, limit, type1 );
230         pair->kerning.x = afm_atoi( &q, limit );
231
232         pair->kerning.y = 0;
233         if ( p[2] != 'X' )
234           pair->kerning.y = afm_atoi( &q, limit );
235
236         pair++;
237       }
238     }
239
240     /* now, sort the kern pairs according to their glyph indices */
241     qsort( afm->kern_pairs, count, sizeof ( CID_Kern_Pair ),
242            compare_kern_pairs );
243
244   Exit:
245     if ( error )
246       FREE( afm );
247
248     FORGET_Frame();
249
250     return error;
251   }
252
253
254   /* find the kerning for a given glyph pair */
255   LOCAL_FUNC
256   void  CID_Get_Kerning( CID_AFM*    afm,
257                          FT_UInt     glyph1,
258                          FT_UInt     glyph2,
259                          FT_Vector*  kerning )
260   {
261     CID_Kern_Pair  *min, *mid, *max;
262     FT_ULong       index = KERN_INDEX( glyph1, glyph2 );
263
264
265     /* simple binary search */
266     min = afm->kern_pairs;
267     max = min + afm->num_pairs - 1;
268
269     while ( min <= max )
270     {
271       FT_ULong  midi;
272
273
274       mid = min + ( max - min ) / 2;
275       midi = KERN_INDEX( mid->glyph1, mid->glyph2 );
276       if ( midi == index )
277       {
278         *kerning = mid->kerning;
279         return;
280       }
281
282       if ( midi < index )
283         min = mid + 1;
284       else
285         max = mid - 1;
286     }
287
288     kerning->x = 0;
289     kerning->y = 0;
290   }
291
292
293 /* END */