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