1 /***************************************************************************/
5 /* AFM support for Type 1 fonts (body). */
7 /* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 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 /* PS string/name length must be < 16-bit */
64 for ( n
= 0; n
< type1
->num_glyphs
; n
++ )
66 char* gname
= (char*)type1
->glyph_names
[n
];
69 if ( gname
&& gname
[0] == name
[0] &&
70 ft_strlen( gname
) == len
&&
71 ft_strncmp( gname
, name
, len
) == 0 )
80 #define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) )
83 /* compare two kerning pairs */
84 FT_CALLBACK_DEF( int )
85 compare_kern_pairs( const void* a
,
88 AFM_KernPair pair1
= (AFM_KernPair
)a
;
89 AFM_KernPair pair2
= (AFM_KernPair
)b
;
91 FT_ULong index1
= KERN_INDEX( pair1
->index1
, pair1
->index2
);
92 FT_ULong index2
= KERN_INDEX( pair2
->index1
, pair2
->index2
);
95 if ( index1
> index2
)
97 else if ( index1
< index2
)
104 /* parse a PFM file -- for now, only read the kerning pairs */
106 T1_Read_PFM( FT_Face t1_face
,
110 FT_Error error
= T1_Err_Ok
;
111 FT_Memory memory
= stream
->memory
;
116 FT_Int width_table_length
;
117 FT_CharMap oldcharmap
;
122 start
= (FT_Byte
*)stream
->cursor
;
123 limit
= (FT_Byte
*)stream
->limit
;
126 /* Figure out how long the width table is. */
127 /* This info is a little-endian short at offset 99. */
131 error
= T1_Err_Unknown_File_Format
;
134 width_table_length
= FT_PEEK_USHORT_LE( p
);
136 p
+= 18 + width_table_length
;
137 if ( p
+ 0x12 > limit
|| FT_PEEK_USHORT_LE( p
) < 0x12 )
138 /* extension table is probably optional */
141 /* Kerning offset is 14 bytes from start of extensions table. */
143 p
= start
+ FT_PEEK_ULONG_LE( p
);
146 /* zero offset means no table */
151 error
= T1_Err_Unknown_File_Format
;
155 fi
->NumKernPair
= FT_PEEK_USHORT_LE( p
);
157 if ( p
+ 4 * fi
->NumKernPair
> limit
)
159 error
= T1_Err_Unknown_File_Format
;
163 /* Actually, kerning pairs are simply optional! */
164 if ( fi
->NumKernPair
== 0 )
167 /* allocate the pairs */
168 if ( FT_QNEW_ARRAY( fi
->KernPairs
, fi
->NumKernPair
) )
171 /* now, read each kern pair */
173 limit
= p
+ 4 * fi
->NumKernPair
;
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
;
182 for ( n
= 0; n
< t1_face
->num_charmaps
; n
++ )
184 charmap
= t1_face
->charmaps
[n
];
185 /* check against PostScript pseudo platform */
186 if ( charmap
->platform_id
== 7 )
188 error
= FT_Set_Charmap( t1_face
, charmap
);
195 /* Kerning info is stored as: */
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 )
202 kp
->index1
= FT_Get_Char_Index( t1_face
, p
[0] );
203 kp
->index2
= FT_Get_Char_Index( t1_face
, p
[1] );
205 kp
->x
= (FT_Int
)FT_PEEK_SHORT_LE(p
+ 2);
211 if ( oldcharmap
!= NULL
)
212 error
= FT_Set_Charmap( t1_face
, oldcharmap
);
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
);
223 FT_FREE( fi
->KernPairs
);
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
,
238 FT_Memory memory
= stream
->memory
;
239 AFM_ParserRec parser
;
241 FT_Error error
= T1_Err_Unknown_File_Format
;
242 T1_Font t1_font
= &( (T1_Face
)t1_face
)->type1
;
246 FT_FRAME_ENTER( stream
->size
) )
249 fi
->FontBBox
= t1_font
->font_bbox
;
250 fi
->Ascender
= t1_font
->font_bbox
.yMax
;
251 fi
->Descender
= t1_font
->font_bbox
.yMin
;
253 psaux
= (PSAux_Service
)( (T1_Face
)t1_face
)->psaux
;
254 if ( psaux
&& psaux
->afm_parser_funcs
)
256 error
= psaux
->afm_parser_funcs
->init( &parser
,
263 parser
.FontInfo
= fi
;
264 parser
.get_index
= t1_get_index
;
265 parser
.user_data
= t1_font
;
267 error
= psaux
->afm_parser_funcs
->parse( &parser
);
268 psaux
->afm_parser_funcs
->done( &parser
);
272 if ( error
== T1_Err_Unknown_File_Format
)
274 FT_Byte
* start
= stream
->cursor
;
277 /* MS Windows allows versions up to 0x3FF without complaining */
278 if ( stream
->size
> 6 &&
280 FT_PEEK_ULONG_LE( start
+ 2 ) == stream
->size
)
281 error
= T1_Read_PFM( t1_face
, stream
, fi
);
286 t1_font
->font_bbox
= fi
->FontBBox
;
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;
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 );
298 if ( fi
->NumKernPair
)
300 t1_face
->face_flags
|= FT_FACE_FLAG_KERNING
;
301 ( (T1_Face
)t1_face
)->afm_data
= fi
;
310 T1_Done_Metrics( memory
, fi
);
316 /* find the kerning for a given glyph pair */
318 T1_Get_Kerning( AFM_FontInfo fi
,
323 AFM_KernPair min
, mid
, max
;
324 FT_ULong idx
= KERN_INDEX( glyph1
, glyph2
);
327 /* simple binary search */
329 max
= min
+ fi
->NumKernPair
- 1;
336 mid
= min
+ ( max
- min
) / 2;
337 midi
= KERN_INDEX( mid
->index1
, mid
->index2
);
358 FT_LOCAL_DEF( FT_Error
)
359 T1_Get_Track_Kerning( FT_Face face
,
364 AFM_FontInfo fi
= (AFM_FontInfo
)( (T1_Face
)face
)->afm_data
;
369 return T1_Err_Invalid_Argument
;
371 for ( i
= 0; i
< fi
->NumTrackKern
; i
++ )
373 AFM_TrackKern tk
= fi
->TrackKerns
+ i
;
376 if ( tk
->degree
!= degree
)
379 if ( ptsize
< tk
->min_ptsize
)
380 *kerning
= tk
->min_kern
;
381 else if ( ptsize
> tk
->max_ptsize
)
382 *kerning
= tk
->max_kern
;
385 *kerning
= FT_MulDiv( ptsize
- tk
->min_ptsize
,
386 tk
->max_kern
- tk
->min_kern
,
387 tk
->max_ptsize
- tk
->min_ptsize
) +