From d232f593832f55b6101b6cda1c688a4c5f6add07 Mon Sep 17 00:00:00 2001 From: Werner Lemberg Date: Mon, 2 Aug 2004 05:38:33 +0000 Subject: [PATCH] * docs/CHANGES: Updated. FreeType now can read kerning values from PFM files. * src/type1/t1afm.c (T1_Done_AFM): Renamed to... (T1_Done_Metrics): This. Update all callers. (T1_Read_AFM): Make it static. Don't enter and leave a frame. (LITTLE_ENDIAN_USHORT, LITTLE_ENDIAN_UINT): New macros. (T1_Read_PFM): New function. (T1_Read_Metrics): New higher-level function to be used instead of T1Read_AFM. Update all callers. --- ChangeLog | 19 +++++ docs/CHANGES | 22 ++++++ src/type1/t1afm.c | 178 +++++++++++++++++++++++++++++++++++++++++-- src/type1/t1afm.h | 8 +- src/type1/t1driver.c | 2 +- src/type1/t1objs.c | 2 +- 6 files changed, 218 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index 455e186ee..49bf148f0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2004-08-01 Werner Lemberg + + * docs/CHANGES: Updated. + +2004-08-01 George Williams + + FreeType now can read kerning values from PFM files. + + * src/type1/t1afm.c (T1_Done_AFM): Renamed to... + (T1_Done_Metrics): This. + Update all callers. + (T1_Read_AFM): Make it static. + Don't enter and leave a frame. + (LITTLE_ENDIAN_USHORT, LITTLE_ENDIAN_UINT): New macros. + (T1_Read_PFM): New function. + (T1_Read_Metrics): New higher-level function to be used instead of + T1Read_AFM. + Update all callers. + 2004-07-31 Werner Lemberg * src/pcf/pcfread (pcf_load_font), src/bdf/bdfdrivr.c diff --git a/docs/CHANGES b/docs/CHANGES index 55164a336..5b11097c1 100644 --- a/docs/CHANGES +++ b/docs/CHANGES @@ -1,3 +1,25 @@ +LATEST CHANGES BETWEEN 2.1.10 and 2.1.9 + + I. IMPORTANT BUG FIXES + + - The size comparison for BDF and PCF files could fail sometimes. + + - Some CFF files were still not loaded correctly. Patch from + Derek Noonburg. + + - The stroker still had some serious bugs. + + + II. IMPORTANT CHANGES + + - George Williams contributed code to read kerning data from PFM + files. + + - FreeType now uses the TT_NAME_ID_PREFERRED_FAMILY and + TT_NAME_ID_PREFERRED_SUBFAMILY strings (if available) for + setting family and style in SFNT fonts (patch from Kornfeld + Eliyahu Peter). + LATEST CHANGES BETWEEN 2.1.9 and 2.1.8 diff --git a/src/type1/t1afm.c b/src/type1/t1afm.c index 65d86fab3..c56ba653b 100644 --- a/src/type1/t1afm.c +++ b/src/type1/t1afm.c @@ -33,8 +33,8 @@ FT_LOCAL_DEF( void ) - T1_Done_AFM( FT_Memory memory, - T1_AFM* afm ) + T1_Done_Metrics( FT_Memory memory, + T1_AFM* afm ) { FT_FREE( afm->kern_pairs ); afm->num_pairs = 0; @@ -153,11 +153,11 @@ /* parse an AFM file -- for now, only read the kerning pairs */ - FT_LOCAL_DEF( FT_Error ) + static FT_Error T1_Read_AFM( FT_Face t1_face, FT_Stream stream ) { - FT_Error error; + FT_Error error = T1_Err_Ok; FT_Memory memory = stream->memory; FT_Byte* start; FT_Byte* limit; @@ -168,9 +168,6 @@ T1_AFM* afm = 0; - if ( FT_FRAME_ENTER( stream->size ) ) - return error; - start = (FT_Byte*)stream->cursor; limit = (FT_Byte*)stream->limit; p = start; @@ -233,6 +230,173 @@ if ( error ) FT_FREE( afm ); + return error; + } + + +#define LITTLE_ENDIAN_USHORT( p ) (FT_UShort)( ( (p)[0] ) | \ + ( (p)[1] << 8 ) ) + +#define LITTLE_ENDIAN_UINT( p ) (FT_UInt)( ( (p)[0] ) | \ + ( (p)[1] << 8 ) | \ + ( (p)[2] << 16 ) | \ + ( (p)[3] << 24 ) ) + + + /* parse a PFM file -- for now, only read the kerning pairs */ + static FT_Error + T1_Read_PFM( FT_Face t1_face, + FT_Stream stream ) + { + FT_Error error = T1_Err_Ok; + FT_Memory memory = stream->memory; + FT_Byte* start; + FT_Byte* limit; + FT_Byte* p; + FT_Int kern_count = 0; + T1_Kern_Pair* pair; + T1_AFM* afm = 0; + FT_Int width_table_length; + FT_CharMap oldcharmap; + FT_CharMap charmap; + FT_Int n; + + + start = (FT_Byte*)stream->cursor; + limit = (FT_Byte*)stream->limit; + p = start; + + /* Figure out how long the width table is. */ + /* This info is a little-endian short at offset 99. */ + p = start + 99; + if ( p + 2 > limit ) + { + error = T1_Err_Unknown_File_Format; + goto Exit; + } + width_table_length = LITTLE_ENDIAN_USHORT( p ); + + p += 18 + width_table_length; + if ( p + 0x12 > limit || LITTLE_ENDIAN_USHORT( p ) < 0x12 ) + /* extension table is probably optional */ + goto Exit; + + /* Kerning offset is 14 bytes from start of extensions table. */ + p += 14; + p = start + LITTLE_ENDIAN_UINT( p ); + if ( p + 2 > limit ) + { + error = T1_Err_Unknown_File_Format; + goto Exit; + } + + kern_count = LITTLE_ENDIAN_USHORT( p ); + p += 2; + if ( p + 4 * kern_count > limit ) + { + error = T1_Err_Unknown_File_Format; + goto Exit; + } + + /* Actually, kerning pairs are simply optional! */ + if ( kern_count == 0 ) + goto Exit; + + /* allocate the pairs */ + if ( FT_NEW( afm ) || FT_NEW_ARRAY( afm->kern_pairs, kern_count ) ) + goto Exit; + + /* save in face object */ + ((T1_Face)t1_face)->afm_data = afm; + + t1_face->face_flags |= FT_FACE_FLAG_KERNING; + + /* now, read each kern pair */ + pair = afm->kern_pairs; + afm->num_pairs = kern_count; + limit = p + 4 * kern_count; + + /* PFM kerning data are stored by encoding rather than glyph index, */ + /* so find the PostScript charmap of this font and install it */ + /* temporarily. If we find no PostScript charmap, then just use */ + /* the default and hope it is the right one. */ + oldcharmap = t1_face->charmap; + charmap = NULL; + + for ( n = 0; n < t1_face->num_charmaps; n++ ) + { + charmap = t1_face->charmaps[n]; + /* check against PostScript pseudo platform */ + if ( charmap->platform_id == 7 ) + { + error = FT_Set_Charmap( t1_face, charmap ); + if ( error ) + goto Exit; + break; + } + } + + /* Kerning info is stored as: */ + /* */ + /* encoding of first glyph (1 byte) */ + /* encoding of second glyph (1 byte) */ + /* offset (little-endian short) */ + for ( ; p < limit ; p+=4 ) + { + pair->glyph1 = FT_Get_Char_Index( t1_face, p[0] ); + pair->glyph2 = FT_Get_Char_Index( t1_face, p[1] ); + + pair->kerning.x = (FT_Short)LITTLE_ENDIAN_USHORT(p + 2); + pair->kerning.y = 0; + + pair++; + } + + if ( oldcharmap != NULL ) + error = FT_Set_Charmap( t1_face, oldcharmap ); + if ( error ) + goto Exit; + + /* now, sort the kern pairs according to their glyph indices */ + ft_qsort( afm->kern_pairs, kern_count, sizeof ( T1_Kern_Pair ), + compare_kern_pairs ); + + Exit: + if ( error ) + FT_FREE( afm ); + + return error; + } + + + /* parse a metrics file -- either AFM or PFM depending on what */ + /* it turns out to be */ + FT_LOCAL_DEF( FT_Error ) + T1_Read_Metrics( FT_Face t1_face, + FT_Stream stream ) + { + FT_Error error; + FT_Byte* start; + + + if ( FT_FRAME_ENTER( stream->size ) ) + return error; + + start = (FT_Byte*)stream->cursor; + + if ( stream->size >= ft_strlen( "StartFontMetrics" ) && + ft_strncmp( (const char*)start, "StartFontMetrics", + ft_strlen( "StartFontMetrics" ) ) == 0 ) + error = T1_Read_AFM( t1_face, stream ); + + else if ( stream->size > 6 && + start[0] == 0x00 && start[1] == 0x01 && + LITTLE_ENDIAN_UINT( start + 2 ) == stream->size ) + error = T1_Read_PFM( t1_face, stream ); + + else + error = T1_Err_Unknown_File_Format; + FT_FRAME_EXIT(); return error; diff --git a/src/type1/t1afm.h b/src/type1/t1afm.h index 77cc6a6e9..5aaeb67a7 100644 --- a/src/type1/t1afm.h +++ b/src/type1/t1afm.h @@ -44,12 +44,12 @@ FT_BEGIN_HEADER FT_LOCAL( FT_Error ) - T1_Read_AFM( FT_Face face, - FT_Stream stream ); + T1_Read_Metrics( FT_Face face, + FT_Stream stream ); FT_LOCAL( void ) - T1_Done_AFM( FT_Memory memory, - T1_AFM* afm ); + T1_Done_Metrics( FT_Memory memory, + T1_AFM* afm ); FT_LOCAL( void ) T1_Get_Kerning( T1_AFM* afm, diff --git a/src/type1/t1driver.c b/src/type1/t1driver.c index b37ae77c5..652eebc18 100644 --- a/src/type1/t1driver.c +++ b/src/type1/t1driver.c @@ -294,7 +294,7 @@ (FT_Face_AttachFunc) 0, #else (FT_Face_GetKerningFunc) Get_Kerning, - (FT_Face_AttachFunc) T1_Read_AFM, + (FT_Face_AttachFunc) T1_Read_Metrics, #endif (FT_Face_GetAdvancesFunc) 0 }; diff --git a/src/type1/t1objs.c b/src/type1/t1objs.c index a832ee000..519fa08d9 100644 --- a/src/type1/t1objs.c +++ b/src/type1/t1objs.c @@ -233,7 +233,7 @@ #ifndef T1_CONFIG_OPTION_NO_AFM /* release afm data if present */ if ( face->afm_data ) - T1_Done_AFM( memory, (T1_AFM*)face->afm_data ); + T1_Done_Metrics( memory, (T1_AFM*)face->afm_data ); #endif /* release unicode map, if any */