1 /***************************************************************************/
5 /* AFM support for Type 1 fonts (body). */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
22 #include FT_INTERNAL_STREAM_H
23 #include FT_INTERNAL_POSTSCRIPT_AUX_H
26 /*************************************************************************/
28 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
29 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
30 /* messages during execution. */
33 #define FT_COMPONENT trace_t1afm
37 T1_Done_Metrics( FT_Memory memory
,
40 FT_FREE( fi
->KernPairs
);
43 FT_FREE( fi
->TrackKerns
);
50 /* read a glyph name and return the equivalent glyph index */
52 t1_get_index( const char* name
,
56 T1_Font type1
= (T1_Font
)user_data
;
60 for ( n
= 0; n
< type1
->num_glyphs
; n
++ )
62 char* gname
= (char*)type1
->glyph_names
[n
];
65 if ( gname
&& gname
[0] == name
[0] &&
66 ft_strlen( gname
) == len
&&
67 ft_strncmp( gname
, name
, len
) == 0 )
76 #define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) )
79 /* compare two kerning pairs */
80 FT_CALLBACK_DEF( int )
81 compare_kern_pairs( const void* a
,
84 AFM_KernPair pair1
= (AFM_KernPair
)a
;
85 AFM_KernPair pair2
= (AFM_KernPair
)b
;
87 FT_ULong index1
= KERN_INDEX( pair1
->index1
, pair1
->index2
);
88 FT_ULong index2
= KERN_INDEX( pair2
->index1
, pair2
->index2
);
91 return (int)( index1
- index2
);
95 /* parse a PFM file -- for now, only read the kerning pairs */
97 T1_Read_PFM( FT_Face t1_face
,
101 FT_Error error
= T1_Err_Ok
;
102 FT_Memory memory
= stream
->memory
;
107 FT_Int width_table_length
;
108 FT_CharMap oldcharmap
;
113 start
= (FT_Byte
*)stream
->cursor
;
114 limit
= (FT_Byte
*)stream
->limit
;
117 /* Figure out how long the width table is. */
118 /* This info is a little-endian short at offset 99. */
122 error
= T1_Err_Unknown_File_Format
;
125 width_table_length
= FT_PEEK_USHORT_LE( p
);
127 p
+= 18 + width_table_length
;
128 if ( p
+ 0x12 > limit
|| FT_PEEK_USHORT_LE( p
) < 0x12 )
129 /* extension table is probably optional */
132 /* Kerning offset is 14 bytes from start of extensions table. */
134 p
= start
+ FT_PEEK_ULONG_LE( p
);
137 /* zero offset means no table */
142 error
= T1_Err_Unknown_File_Format
;
146 fi
->NumKernPair
= FT_PEEK_USHORT_LE( p
);
148 if ( p
+ 4 * fi
->NumKernPair
> limit
)
150 error
= T1_Err_Unknown_File_Format
;
154 /* Actually, kerning pairs are simply optional! */
155 if ( fi
->NumKernPair
== 0 )
158 /* allocate the pairs */
159 if ( FT_QNEW_ARRAY( fi
->KernPairs
, fi
->NumKernPair
) )
162 /* now, read each kern pair */
164 limit
= p
+ 4 * fi
->NumKernPair
;
166 /* PFM kerning data are stored by encoding rather than glyph index, */
167 /* so find the PostScript charmap of this font and install it */
168 /* temporarily. If we find no PostScript charmap, then just use */
169 /* the default and hope it is the right one. */
170 oldcharmap
= t1_face
->charmap
;
173 for ( n
= 0; n
< t1_face
->num_charmaps
; n
++ )
175 charmap
= t1_face
->charmaps
[n
];
176 /* check against PostScript pseudo platform */
177 if ( charmap
->platform_id
== 7 )
179 error
= FT_Set_Charmap( t1_face
, charmap
);
186 /* Kerning info is stored as: */
188 /* encoding of first glyph (1 byte) */
189 /* encoding of second glyph (1 byte) */
190 /* offset (little-endian short) */
191 for ( ; p
< limit
; p
+= 4 )
193 kp
->index1
= FT_Get_Char_Index( t1_face
, p
[0] );
194 kp
->index2
= FT_Get_Char_Index( t1_face
, p
[1] );
196 kp
->x
= (FT_Int
)FT_PEEK_SHORT_LE(p
+ 2);
202 if ( oldcharmap
!= NULL
)
203 error
= FT_Set_Charmap( t1_face
, oldcharmap
);
207 /* now, sort the kern pairs according to their glyph indices */
208 ft_qsort( fi
->KernPairs
, fi
->NumKernPair
, sizeof ( AFM_KernPairRec
),
209 compare_kern_pairs
);
214 FT_FREE( fi
->KernPairs
);
222 /* parse a metrics file -- either AFM or PFM depending on what */
223 /* it turns out to be */
224 FT_LOCAL_DEF( FT_Error
)
225 T1_Read_Metrics( FT_Face t1_face
,
229 FT_Memory memory
= stream
->memory
;
230 AFM_ParserRec parser
;
232 FT_Error error
= T1_Err_Unknown_File_Format
;
233 T1_Font t1_font
= &( (T1_Face
)t1_face
)->type1
;
237 FT_FRAME_ENTER( stream
->size
) )
240 fi
->FontBBox
= t1_font
->font_bbox
;
241 fi
->Ascender
= t1_font
->font_bbox
.yMax
;
242 fi
->Descender
= t1_font
->font_bbox
.yMin
;
244 psaux
= (PSAux_Service
)( (T1_Face
)t1_face
)->psaux
;
245 if ( psaux
&& psaux
->afm_parser_funcs
)
247 error
= psaux
->afm_parser_funcs
->init( &parser
,
254 parser
.FontInfo
= fi
;
255 parser
.get_index
= t1_get_index
;
256 parser
.user_data
= t1_font
;
258 error
= psaux
->afm_parser_funcs
->parse( &parser
);
259 psaux
->afm_parser_funcs
->done( &parser
);
263 if ( error
== T1_Err_Unknown_File_Format
)
265 FT_Byte
* start
= stream
->cursor
;
268 /* MS Windows allows versions up to 0x3FF without complaining */
269 if ( stream
->size
> 6 &&
271 FT_PEEK_ULONG_LE( start
+ 2 ) == stream
->size
)
272 error
= T1_Read_PFM( t1_face
, stream
, fi
);
277 t1_font
->font_bbox
= fi
->FontBBox
;
279 t1_face
->bbox
.xMin
= fi
->FontBBox
.xMin
>> 16;
280 t1_face
->bbox
.yMin
= fi
->FontBBox
.yMin
>> 16;
281 t1_face
->bbox
.xMax
= ( fi
->FontBBox
.xMax
+ 0xFFFFU
) >> 16;
282 t1_face
->bbox
.yMax
= ( fi
->FontBBox
.yMax
+ 0xFFFFU
) >> 16;
284 t1_face
->ascender
= (FT_Short
)( ( fi
->Ascender
+ 0x8000U
) >> 16 );
285 t1_face
->descender
= (FT_Short
)( ( fi
->Descender
+ 0x8000U
) >> 16 );
287 if ( fi
->NumKernPair
)
289 t1_face
->face_flags
|= FT_FACE_FLAG_KERNING
;
290 ( (T1_Face
)t1_face
)->afm_data
= fi
;
299 T1_Done_Metrics( memory
, fi
);
305 /* find the kerning for a given glyph pair */
307 T1_Get_Kerning( AFM_FontInfo fi
,
312 AFM_KernPair min
, mid
, max
;
313 FT_ULong idx
= KERN_INDEX( glyph1
, glyph2
);
316 /* simple binary search */
318 max
= min
+ fi
->NumKernPair
- 1;
325 mid
= min
+ ( max
- min
) / 2;
326 midi
= KERN_INDEX( mid
->index1
, mid
->index2
);
347 FT_LOCAL_DEF( FT_Error
)
348 T1_Get_Track_Kerning( FT_Face face
,
353 AFM_FontInfo fi
= (AFM_FontInfo
)( (T1_Face
)face
)->afm_data
;
358 return T1_Err_Invalid_Argument
;
360 for ( i
= 0; i
< fi
->NumTrackKern
; i
++ )
362 AFM_TrackKern tk
= fi
->TrackKerns
+ i
;
365 if ( tk
->degree
!= degree
)
368 if ( ptsize
< tk
->min_ptsize
)
369 *kerning
= tk
->min_kern
;
370 else if ( ptsize
> tk
->max_ptsize
)
371 *kerning
= tk
->max_kern
;
374 *kerning
= FT_MulDiv( ptsize
- tk
->min_ptsize
,
375 tk
->max_kern
- tk
->min_kern
,
376 tk
->max_ptsize
- tk
->min_ptsize
) +