]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/freetype/cid/cidafm.c
support for multiple images in one file
[wxWidgets.git] / src / freetype / cid / cidafm.c
... / ...
CommitLineData
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 <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 */