1 /***************************************************************************/
5 /* AFM support for Type 1 fonts (body). */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, */
9 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
11 /* This file is part of the FreeType project, and may only be used, */
12 /* modified, and distributed under the terms of the FreeType project */
13 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */
14 /* this file you indicate that you have read the license and */
15 /* understand and accept it fully. */
17 /***************************************************************************/
23 #include FT_INTERNAL_STREAM_H
24 #include FT_INTERNAL_POSTSCRIPT_AUX_H
27 /*************************************************************************/
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. */
34 #define FT_COMPONENT trace_t1afm
38 T1_Done_Metrics( FT_Memory memory,
41 FT_FREE( fi->KernPairs );
44 FT_FREE( fi->TrackKerns );
51 /* read a glyph name and return the equivalent glyph index */
53 t1_get_index( const char* name,
57 T1_Font type1 = (T1_Font)user_data;
61 /* PS string/name length must be < 16-bit */
65 for ( n = 0; n < type1->num_glyphs; n++ )
67 char* gname = (char*)type1->glyph_names[n];
70 if ( gname && gname[0] == name[0] &&
71 ft_strlen( gname ) == len &&
72 ft_strncmp( gname, name, len ) == 0 )
81 #define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) )
84 /* compare two kerning pairs */
85 FT_CALLBACK_DEF( int )
86 compare_kern_pairs( const void* a,
89 AFM_KernPair pair1 = (AFM_KernPair)a;
90 AFM_KernPair pair2 = (AFM_KernPair)b;
92 FT_ULong index1 = KERN_INDEX( pair1->index1, pair1->index2 );
93 FT_ULong index2 = KERN_INDEX( pair2->index1, pair2->index2 );
96 if ( index1 > index2 )
98 else if ( index1 < index2 )
105 /* parse a PFM file -- for now, only read the kerning pairs */
107 T1_Read_PFM( FT_Face t1_face,
111 FT_Error error = T1_Err_Ok;
112 FT_Memory memory = stream->memory;
117 FT_Int width_table_length;
118 FT_CharMap oldcharmap;
123 start = (FT_Byte*)stream->cursor;
124 limit = (FT_Byte*)stream->limit;
127 /* Figure out how long the width table is. */
128 /* This info is a little-endian short at offset 99. */
132 error = T1_Err_Unknown_File_Format;
135 width_table_length = FT_PEEK_USHORT_LE( p );
137 p += 18 + width_table_length;
138 if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 )
139 /* extension table is probably optional */
142 /* Kerning offset is 14 bytes from start of extensions table. */
144 p = start + FT_PEEK_ULONG_LE( p );
147 /* zero offset means no table */
152 error = T1_Err_Unknown_File_Format;
156 fi->NumKernPair = FT_PEEK_USHORT_LE( p );
158 if ( p + 4 * fi->NumKernPair > limit )
160 error = T1_Err_Unknown_File_Format;
164 /* Actually, kerning pairs are simply optional! */
165 if ( fi->NumKernPair == 0 )
168 /* allocate the pairs */
169 if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
172 /* now, read each kern pair */
174 limit = p + 4 * fi->NumKernPair;
176 /* PFM kerning data are stored by encoding rather than glyph index, */
177 /* so find the PostScript charmap of this font and install it */
178 /* temporarily. If we find no PostScript charmap, then just use */
179 /* the default and hope it is the right one. */
180 oldcharmap = t1_face->charmap;
183 for ( n = 0; n < t1_face->num_charmaps; n++ )
185 charmap = t1_face->charmaps[n];
186 /* check against PostScript pseudo platform */
187 if ( charmap->platform_id == 7 )
189 error = FT_Set_Charmap( t1_face, charmap );
196 /* Kerning info is stored as: */
198 /* encoding of first glyph (1 byte) */
199 /* encoding of second glyph (1 byte) */
200 /* offset (little-endian short) */
201 for ( ; p < limit ; p += 4 )
203 kp->index1 = FT_Get_Char_Index( t1_face, p[0] );
204 kp->index2 = FT_Get_Char_Index( t1_face, p[1] );
206 kp->x = (FT_Int)FT_PEEK_SHORT_LE(p + 2);
212 if ( oldcharmap != NULL )
213 error = FT_Set_Charmap( t1_face, oldcharmap );
217 /* now, sort the kern pairs according to their glyph indices */
218 ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ),
219 compare_kern_pairs );
224 FT_FREE( fi->KernPairs );
232 /* parse a metrics file -- either AFM or PFM depending on what */
233 /* it turns out to be */
234 FT_LOCAL_DEF( FT_Error )
235 T1_Read_Metrics( FT_Face t1_face,
239 FT_Memory memory = stream->memory;
240 AFM_ParserRec parser;
241 AFM_FontInfo fi = NULL;
242 FT_Error error = T1_Err_Unknown_File_Format;
243 T1_Font t1_font = &( (T1_Face)t1_face )->type1;
247 FT_FRAME_ENTER( stream->size ) )
250 fi->FontBBox = t1_font->font_bbox;
251 fi->Ascender = t1_font->font_bbox.yMax;
252 fi->Descender = t1_font->font_bbox.yMin;
254 psaux = (PSAux_Service)( (T1_Face)t1_face )->psaux;
255 if ( psaux && psaux->afm_parser_funcs )
257 error = psaux->afm_parser_funcs->init( &parser,
264 parser.FontInfo = fi;
265 parser.get_index = t1_get_index;
266 parser.user_data = t1_font;
268 error = psaux->afm_parser_funcs->parse( &parser );
269 psaux->afm_parser_funcs->done( &parser );
273 if ( error == T1_Err_Unknown_File_Format )
275 FT_Byte* start = stream->cursor;
278 /* MS Windows allows versions up to 0x3FF without complaining */
279 if ( stream->size > 6 &&
281 FT_PEEK_ULONG_LE( start + 2 ) == stream->size )
282 error = T1_Read_PFM( t1_face, stream, fi );
287 t1_font->font_bbox = fi->FontBBox;
289 t1_face->bbox.xMin = fi->FontBBox.xMin >> 16;
290 t1_face->bbox.yMin = fi->FontBBox.yMin >> 16;
291 /* no `U' suffix here to 0xFFFF! */
292 t1_face->bbox.xMax = ( fi->FontBBox.xMax + 0xFFFF ) >> 16;
293 t1_face->bbox.yMax = ( fi->FontBBox.yMax + 0xFFFF ) >> 16;
295 /* no `U' suffix here to 0x8000! */
296 t1_face->ascender = (FT_Short)( ( fi->Ascender + 0x8000 ) >> 16 );
297 t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000 ) >> 16 );
299 if ( fi->NumKernPair )
301 t1_face->face_flags |= FT_FACE_FLAG_KERNING;
302 ( (T1_Face)t1_face )->afm_data = fi;
311 T1_Done_Metrics( memory, fi );
317 /* find the kerning for a given glyph pair */
319 T1_Get_Kerning( AFM_FontInfo fi,
324 AFM_KernPair min, mid, max;
325 FT_ULong idx = KERN_INDEX( glyph1, glyph2 );
328 /* simple binary search */
330 max = min + fi->NumKernPair - 1;
337 mid = min + ( max - min ) / 2;
338 midi = KERN_INDEX( mid->index1, mid->index2 );
359 FT_LOCAL_DEF( FT_Error )
360 T1_Get_Track_Kerning( FT_Face face,
365 AFM_FontInfo fi = (AFM_FontInfo)( (T1_Face)face )->afm_data;
370 return T1_Err_Invalid_Argument;
372 for ( i = 0; i < fi->NumTrackKern; i++ )
374 AFM_TrackKern tk = fi->TrackKerns + i;
377 if ( tk->degree != degree )
380 if ( ptsize < tk->min_ptsize )
381 *kerning = tk->min_kern;
382 else if ( ptsize > tk->max_ptsize )
383 *kerning = tk->max_kern;
386 *kerning = FT_MulDiv( ptsize - tk->min_ptsize,
387 tk->max_kern - tk->min_kern,
388 tk->max_ptsize - tk->min_ptsize ) +