OLD | NEW |
| (Empty) |
1 /***************************************************************************/ | |
2 /* */ | |
3 /* t1afm.c */ | |
4 /* */ | |
5 /* AFM support for Type 1 fonts (body). */ | |
6 /* */ | |
7 /* Copyright 1996-2011, 2013 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 #include "../../include/ft2build.h" | |
20 #include "t1afm.h" | |
21 #include "../../include/freetype/internal/ftdebug.h" | |
22 #include "../../include/freetype/internal/ftstream.h" | |
23 #include "../../include/freetype/internal/psaux.h" | |
24 #include "t1errors.h" | |
25 | |
26 | |
27 /*************************************************************************/ | |
28 /* */ | |
29 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ | |
30 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ | |
31 /* messages during execution. */ | |
32 /* */ | |
33 #undef FT_COMPONENT | |
34 #define FT_COMPONENT trace_t1afm | |
35 | |
36 | |
37 FT_LOCAL_DEF( void ) | |
38 T1_Done_Metrics( FT_Memory memory, | |
39 AFM_FontInfo fi ) | |
40 { | |
41 FT_FREE( fi->KernPairs ); | |
42 fi->NumKernPair = 0; | |
43 | |
44 FT_FREE( fi->TrackKerns ); | |
45 fi->NumTrackKern = 0; | |
46 | |
47 FT_FREE( fi ); | |
48 } | |
49 | |
50 | |
51 /* read a glyph name and return the equivalent glyph index */ | |
52 static FT_Int | |
53 t1_get_index( const char* name, | |
54 FT_Offset len, | |
55 void* user_data ) | |
56 { | |
57 T1_Font type1 = (T1_Font)user_data; | |
58 FT_Int n; | |
59 | |
60 | |
61 /* PS string/name length must be < 16-bit */ | |
62 if ( len > 0xFFFFU ) | |
63 return 0; | |
64 | |
65 for ( n = 0; n < type1->num_glyphs; n++ ) | |
66 { | |
67 char* gname = (char*)type1->glyph_names[n]; | |
68 | |
69 | |
70 if ( gname && gname[0] == name[0] && | |
71 ft_strlen( gname ) == len && | |
72 ft_strncmp( gname, name, len ) == 0 ) | |
73 return n; | |
74 } | |
75 | |
76 return 0; | |
77 } | |
78 | |
79 | |
80 #undef KERN_INDEX | |
81 #define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) ) | |
82 | |
83 | |
84 /* compare two kerning pairs */ | |
85 FT_CALLBACK_DEF( int ) | |
86 compare_kern_pairs( const void* a, | |
87 const void* b ) | |
88 { | |
89 AFM_KernPair pair1 = (AFM_KernPair)a; | |
90 AFM_KernPair pair2 = (AFM_KernPair)b; | |
91 | |
92 FT_ULong index1 = KERN_INDEX( pair1->index1, pair1->index2 ); | |
93 FT_ULong index2 = KERN_INDEX( pair2->index1, pair2->index2 ); | |
94 | |
95 | |
96 if ( index1 > index2 ) | |
97 return 1; | |
98 else if ( index1 < index2 ) | |
99 return -1; | |
100 else | |
101 return 0; | |
102 } | |
103 | |
104 | |
105 /* parse a PFM file -- for now, only read the kerning pairs */ | |
106 static FT_Error | |
107 T1_Read_PFM( FT_Face t1_face, | |
108 FT_Stream stream, | |
109 AFM_FontInfo fi ) | |
110 { | |
111 FT_Error error = FT_Err_Ok; | |
112 FT_Memory memory = stream->memory; | |
113 FT_Byte* start; | |
114 FT_Byte* limit; | |
115 FT_Byte* p; | |
116 AFM_KernPair kp; | |
117 FT_Int width_table_length; | |
118 FT_CharMap oldcharmap; | |
119 FT_CharMap charmap; | |
120 FT_Int n; | |
121 | |
122 | |
123 start = (FT_Byte*)stream->cursor; | |
124 limit = (FT_Byte*)stream->limit; | |
125 | |
126 /* Figure out how long the width table is. */ | |
127 /* This info is a little-endian short at offset 99. */ | |
128 p = start + 99; | |
129 if ( p + 2 > limit ) | |
130 { | |
131 error = FT_THROW( Unknown_File_Format ); | |
132 goto Exit; | |
133 } | |
134 width_table_length = FT_PEEK_USHORT_LE( p ); | |
135 | |
136 p += 18 + width_table_length; | |
137 if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 ) | |
138 /* extension table is probably optional */ | |
139 goto Exit; | |
140 | |
141 /* Kerning offset is 14 bytes from start of extensions table. */ | |
142 p += 14; | |
143 p = start + FT_PEEK_ULONG_LE( p ); | |
144 | |
145 if ( p == start ) | |
146 /* zero offset means no table */ | |
147 goto Exit; | |
148 | |
149 if ( p + 2 > limit ) | |
150 { | |
151 error = FT_THROW( Unknown_File_Format ); | |
152 goto Exit; | |
153 } | |
154 | |
155 fi->NumKernPair = FT_PEEK_USHORT_LE( p ); | |
156 p += 2; | |
157 if ( p + 4 * fi->NumKernPair > limit ) | |
158 { | |
159 error = FT_THROW( Unknown_File_Format ); | |
160 goto Exit; | |
161 } | |
162 | |
163 /* Actually, kerning pairs are simply optional! */ | |
164 if ( fi->NumKernPair == 0 ) | |
165 goto Exit; | |
166 | |
167 /* allocate the pairs */ | |
168 if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) ) | |
169 goto Exit; | |
170 | |
171 /* now, read each kern pair */ | |
172 kp = fi->KernPairs; | |
173 limit = p + 4 * fi->NumKernPair; | |
174 | |
175 /* PFM kerning data are stored by encoding rather than glyph index, */ | |
176 /* so find the PostScript charmap of this font and install it */ | |
177 /* temporarily. If we find no PostScript charmap, then just use */ | |
178 /* the default and hope it is the right one. */ | |
179 oldcharmap = t1_face->charmap; | |
180 charmap = NULL; | |
181 | |
182 for ( n = 0; n < t1_face->num_charmaps; n++ ) | |
183 { | |
184 charmap = t1_face->charmaps[n]; | |
185 /* check against PostScript pseudo platform */ | |
186 if ( charmap->platform_id == 7 ) | |
187 { | |
188 error = FT_Set_Charmap( t1_face, charmap ); | |
189 if ( error ) | |
190 goto Exit; | |
191 break; | |
192 } | |
193 } | |
194 | |
195 /* Kerning info is stored as: */ | |
196 /* */ | |
197 /* encoding of first glyph (1 byte) */ | |
198 /* encoding of second glyph (1 byte) */ | |
199 /* offset (little-endian short) */ | |
200 for ( ; p < limit ; p += 4 ) | |
201 { | |
202 kp->index1 = FT_Get_Char_Index( t1_face, p[0] ); | |
203 kp->index2 = FT_Get_Char_Index( t1_face, p[1] ); | |
204 | |
205 kp->x = (FT_Int)FT_PEEK_SHORT_LE(p + 2); | |
206 kp->y = 0; | |
207 | |
208 kp++; | |
209 } | |
210 | |
211 if ( oldcharmap != NULL ) | |
212 error = FT_Set_Charmap( t1_face, oldcharmap ); | |
213 if ( error ) | |
214 goto Exit; | |
215 | |
216 /* now, sort the kern pairs according to their glyph indices */ | |
217 ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ), | |
218 compare_kern_pairs ); | |
219 | |
220 Exit: | |
221 if ( error ) | |
222 { | |
223 FT_FREE( fi->KernPairs ); | |
224 fi->NumKernPair = 0; | |
225 } | |
226 | |
227 return error; | |
228 } | |
229 | |
230 | |
231 /* parse a metrics file -- either AFM or PFM depending on what */ | |
232 /* it turns out to be */ | |
233 FT_LOCAL_DEF( FT_Error ) | |
234 T1_Read_Metrics( FT_Face t1_face, | |
235 FT_Stream stream ) | |
236 { | |
237 PSAux_Service psaux; | |
238 FT_Memory memory = stream->memory; | |
239 AFM_ParserRec parser; | |
240 AFM_FontInfo fi = NULL; | |
241 FT_Error error = FT_ERR( Unknown_File_Format ); | |
242 T1_Font t1_font = &( (T1_Face)t1_face )->type1; | |
243 | |
244 | |
245 if ( FT_NEW( fi ) || | |
246 FT_FRAME_ENTER( stream->size ) ) | |
247 goto Exit; | |
248 | |
249 fi->FontBBox = t1_font->font_bbox; | |
250 fi->Ascender = t1_font->font_bbox.yMax; | |
251 fi->Descender = t1_font->font_bbox.yMin; | |
252 | |
253 psaux = (PSAux_Service)( (T1_Face)t1_face )->psaux; | |
254 if ( psaux->afm_parser_funcs ) | |
255 { | |
256 error = psaux->afm_parser_funcs->init( &parser, | |
257 stream->memory, | |
258 stream->cursor, | |
259 stream->limit ); | |
260 | |
261 if ( !error ) | |
262 { | |
263 parser.FontInfo = fi; | |
264 parser.get_index = t1_get_index; | |
265 parser.user_data = t1_font; | |
266 | |
267 error = psaux->afm_parser_funcs->parse( &parser ); | |
268 psaux->afm_parser_funcs->done( &parser ); | |
269 } | |
270 } | |
271 | |
272 if ( FT_ERR_EQ( error, Unknown_File_Format ) ) | |
273 { | |
274 FT_Byte* start = stream->cursor; | |
275 | |
276 | |
277 /* MS Windows allows versions up to 0x3FF without complaining */ | |
278 if ( stream->size > 6 && | |
279 start[1] < 4 && | |
280 FT_PEEK_ULONG_LE( start + 2 ) == stream->size ) | |
281 error = T1_Read_PFM( t1_face, stream, fi ); | |
282 } | |
283 | |
284 if ( !error ) | |
285 { | |
286 t1_font->font_bbox = fi->FontBBox; | |
287 | |
288 t1_face->bbox.xMin = fi->FontBBox.xMin >> 16; | |
289 t1_face->bbox.yMin = fi->FontBBox.yMin >> 16; | |
290 /* no `U' suffix here to 0xFFFF! */ | |
291 t1_face->bbox.xMax = ( fi->FontBBox.xMax + 0xFFFF ) >> 16; | |
292 t1_face->bbox.yMax = ( fi->FontBBox.yMax + 0xFFFF ) >> 16; | |
293 | |
294 /* no `U' suffix here to 0x8000! */ | |
295 t1_face->ascender = (FT_Short)( ( fi->Ascender + 0x8000 ) >> 16 ); | |
296 t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000 ) >> 16 ); | |
297 | |
298 if ( fi->NumKernPair ) | |
299 { | |
300 t1_face->face_flags |= FT_FACE_FLAG_KERNING; | |
301 ( (T1_Face)t1_face )->afm_data = fi; | |
302 fi = NULL; | |
303 } | |
304 } | |
305 | |
306 FT_FRAME_EXIT(); | |
307 | |
308 Exit: | |
309 if ( fi != NULL ) | |
310 T1_Done_Metrics( memory, fi ); | |
311 | |
312 return error; | |
313 } | |
314 | |
315 | |
316 /* find the kerning for a given glyph pair */ | |
317 FT_LOCAL_DEF( void ) | |
318 T1_Get_Kerning( AFM_FontInfo fi, | |
319 FT_UInt glyph1, | |
320 FT_UInt glyph2, | |
321 FT_Vector* kerning ) | |
322 { | |
323 AFM_KernPair min, mid, max; | |
324 FT_ULong idx = KERN_INDEX( glyph1, glyph2 ); | |
325 | |
326 | |
327 /* simple binary search */ | |
328 min = fi->KernPairs; | |
329 max = min + fi->NumKernPair - 1; | |
330 | |
331 while ( min <= max ) | |
332 { | |
333 FT_ULong midi; | |
334 | |
335 | |
336 mid = min + ( max - min ) / 2; | |
337 midi = KERN_INDEX( mid->index1, mid->index2 ); | |
338 | |
339 if ( midi == idx ) | |
340 { | |
341 kerning->x = mid->x; | |
342 kerning->y = mid->y; | |
343 | |
344 return; | |
345 } | |
346 | |
347 if ( midi < idx ) | |
348 min = mid + 1; | |
349 else | |
350 max = mid - 1; | |
351 } | |
352 | |
353 kerning->x = 0; | |
354 kerning->y = 0; | |
355 } | |
356 | |
357 | |
358 FT_LOCAL_DEF( FT_Error ) | |
359 T1_Get_Track_Kerning( FT_Face face, | |
360 FT_Fixed ptsize, | |
361 FT_Int degree, | |
362 FT_Fixed* kerning ) | |
363 { | |
364 AFM_FontInfo fi = (AFM_FontInfo)( (T1_Face)face )->afm_data; | |
365 FT_Int i; | |
366 | |
367 | |
368 if ( !fi ) | |
369 return FT_THROW( Invalid_Argument ); | |
370 | |
371 for ( i = 0; i < fi->NumTrackKern; i++ ) | |
372 { | |
373 AFM_TrackKern tk = fi->TrackKerns + i; | |
374 | |
375 | |
376 if ( tk->degree != degree ) | |
377 continue; | |
378 | |
379 if ( ptsize < tk->min_ptsize ) | |
380 *kerning = tk->min_kern; | |
381 else if ( ptsize > tk->max_ptsize ) | |
382 *kerning = tk->max_kern; | |
383 else | |
384 { | |
385 *kerning = FT_MulDiv( ptsize - tk->min_ptsize, | |
386 tk->max_kern - tk->min_kern, | |
387 tk->max_ptsize - tk->min_ptsize ) + | |
388 tk->min_kern; | |
389 } | |
390 } | |
391 | |
392 return FT_Err_Ok; | |
393 } | |
394 | |
395 | |
396 /* END */ | |
OLD | NEW |