freetype2/src/type1/t1afm.c

453 lines
12 KiB
C
Raw Normal View History

/***************************************************************************/
/* */
/* t1afm.c */
/* */
/* AFM support for Type 1 fonts (body). */
/* */
/* Copyright 1996-2001, 2002, 2003, 2004, 2005 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
/* modified, and distributed under the terms of the FreeType project */
/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
/* this file you indicate that you have read the license and */
/* understand and accept it fully. */
/* */
/***************************************************************************/
2000-12-08 17:17:16 +01:00
#include <ft2build.h>
#include "t1afm.h"
#include "t1errors.h"
#include FT_INTERNAL_STREAM_H
#include FT_INTERNAL_TYPE1_TYPES_H
/*************************************************************************/
/* */
/* The macro FT_COMPONENT is used in trace mode. It is an implicit */
/* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
/* messages during execution. */
/* */
#undef FT_COMPONENT
#define FT_COMPONENT trace_t1afm
FT_LOCAL_DEF( void )
T1_Done_Metrics( FT_Memory memory,
T1_AFM* afm )
{
FT_FREE( afm->kern_pairs );
afm->num_pairs = 0;
FT_FREE( afm );
}
#undef IS_KERN_PAIR
#define IS_KERN_PAIR( p ) ( p[0] == 'K' && p[1] == 'P' )
#define IS_ALPHANUM( c ) ( ft_isalnum( c ) || \
c == '_' || \
c == '.' )
/* read a glyph name and return the equivalent glyph index */
2001-06-28 09:17:51 +02:00
static FT_UInt
afm_atoindex( FT_Byte** start,
FT_Byte* limit,
T1_Font type1 )
{
FT_Byte* p = *start;
FT_PtrDist len;
FT_UInt result = 0;
char temp[64];
2000-05-17 01:44:38 +02:00
/* skip whitespace */
while ( p < limit &&
( *p == ' ' || *p == '\t' || *p == ':' || *p == ';' ) )
p++;
*start = p;
2000-05-17 01:44:38 +02:00
/* now, read glyph name */
while ( p < limit && IS_ALPHANUM( *p ) )
p++;
len = p - *start;
if ( len > 0 && len < 64 )
{
FT_Int n;
2000-05-17 01:44:38 +02:00
/* copy glyph name to intermediate array */
FT_MEM_COPY( temp, *start, len );
temp[len] = 0;
2000-05-17 01:44:38 +02:00
/* lookup glyph name in face array */
for ( n = 0; n < type1->num_glyphs; n++ )
{
2000-02-28 12:32:54 +01:00
char* gname = (char*)type1->glyph_names[n];
2000-05-17 01:44:38 +02:00
if ( gname && gname[0] == temp[0] && ft_strcmp( gname, temp ) == 0 )
{
result = n;
break;
}
}
}
*start = p;
return result;
}
/* read an integer */
2001-06-28 09:17:51 +02:00
static int
afm_atoi( FT_Byte** start,
FT_Byte* limit )
{
2000-02-28 12:32:54 +01:00
FT_Byte* p = *start;
int sum = 0;
2000-02-29 18:14:02 +01:00
int sign = 1;
2000-05-17 01:44:38 +02:00
/* skip everything that is not a number */
while ( p < limit && !isdigit( *p ) )
2000-02-28 12:32:54 +01:00
{
sign = 1;
if ( *p == '-' )
2000-02-28 12:32:54 +01:00
sign = -1;
2000-05-17 01:44:38 +02:00
p++;
2000-02-28 12:32:54 +01:00
}
2000-05-17 01:44:38 +02:00
while ( p < limit && isdigit( *p ) )
{
sum = sum * 10 + ( *p - '0' );
p++;
}
*start = p;
return sum * sign;
}
#undef KERN_INDEX
#define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 )
/* compare two kerning pairs */
2001-06-28 09:17:51 +02:00
FT_CALLBACK_DEF( int )
compare_kern_pairs( const void* a,
const void* b )
{
T1_Kern_Pair* pair1 = (T1_Kern_Pair*)a;
T1_Kern_Pair* pair2 = (T1_Kern_Pair*)b;
2000-05-17 01:44:38 +02:00
FT_ULong index1 = KERN_INDEX( pair1->glyph1, pair1->glyph2 );
FT_ULong index2 = KERN_INDEX( pair2->glyph1, pair2->glyph2 );
2000-05-17 01:44:38 +02:00
return (int)( index1 - index2 );
}
/* parse an AFM file -- for now, only read the kerning pairs */
static FT_Error
2001-06-28 09:17:51 +02:00
T1_Read_AFM( 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 count = 0;
T1_Kern_Pair* pair;
T1_Font type1 = &((T1_Face)t1_face)->type1;
T1_AFM* afm = 0;
2000-05-17 01:44:38 +02:00
start = (FT_Byte*)stream->cursor;
limit = (FT_Byte*)stream->limit;
p = start;
2000-05-17 01:44:38 +02:00
/* we are now going to count the occurences of `KP' or `KPX' in */
/* the AFM file */
count = 0;
for ( p = start; p < limit - 3; p++ )
{
if ( IS_KERN_PAIR( p ) )
count++;
}
/* Actually, kerning pairs are simply optional! */
if ( count == 0 )
goto Exit;
2000-05-17 01:44:38 +02:00
/* allocate the pairs */
if ( FT_NEW( afm ) || FT_NEW_ARRAY( afm->kern_pairs, count ) )
goto Exit;
2000-05-17 01:44:38 +02:00
/* now, read each kern pair */
pair = afm->kern_pairs;
afm->num_pairs = count;
2000-05-17 01:44:38 +02:00
/* save in face object */
((T1_Face)t1_face)->afm_data = afm;
t1_face->face_flags |= FT_FACE_FLAG_KERNING;
for ( p = start; p < limit - 3; p++ )
{
if ( IS_KERN_PAIR( p ) )
{
FT_Byte* q;
2000-05-17 01:44:38 +02:00
/* skip keyword (KP or KPX) */
q = p + 2;
if ( *q == 'X' )
q++;
2000-05-17 01:44:38 +02:00
pair->glyph1 = afm_atoindex( &q, limit, type1 );
pair->glyph2 = afm_atoindex( &q, limit, type1 );
pair->kerning.x = afm_atoi( &q, limit );
2000-05-17 01:44:38 +02:00
pair->kerning.y = 0;
if ( p[2] != 'X' )
pair->kerning.y = afm_atoi( &q, limit );
2000-05-17 01:44:38 +02:00
pair++;
}
}
2000-05-17 01:44:38 +02:00
/* now, sort the kern pairs according to their glyph indices */
ft_qsort( afm->kern_pairs, count, sizeof ( T1_Kern_Pair ),
compare_kern_pairs );
2000-05-17 01:44:38 +02:00
Exit:
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 == start )
/* zero offset means no table */
goto Exit;
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;
}
/* find the kerning for a given glyph pair */
FT_LOCAL_DEF( void )
2001-06-28 09:17:51 +02:00
T1_Get_Kerning( T1_AFM* afm,
FT_UInt glyph1,
FT_UInt glyph2,
FT_Vector* kerning )
{
T1_Kern_Pair *min, *mid, *max;
* src/base/ftdbgmem.c (ft_mem_table_resize, ft_mem_table_new, ft_mem_table_set, ft_mem_debug_alloc, ft_mem_debug_free, ft_mem_debug_realloc, ft_mem_debug_done, FT_Alloc_Debug, FT_Realloc_Debug, FT_Free_Debug): Fix compiler warnings. * src/base/ftcalc.c (FT_MulFix): Ditto. * src/cff/cffdrivr.c (cff_get_name_index): Ditto. * src/cff/cffobjs.c (CFF_Size_Get_Global_Funcs, CFF_Size_Init, CFF_GlyphSlot_Init): Ditto. * src/cid/cidobjs.c (CID_GlyphSlot_Init, CID_Size_Get_Globals_Funcs): Ditto. * src/type1/t1objs.c (T1_Size_Get_Globals_Funcs, T1_GlyphSlot_Init): Ditto. * src/pshinter/pshmod.c (pshinter_interface): Use `static const'. * src/winfonts/winfnt.c (FNT_Get_Next_Char): Remove unused variables. * include/freetype/internal/psaux.h (T1_Builder_Funcs): Renamed to... (T1_Builder_FuncsRec): This. (T1_Builder_Funcs): New typedef. (PSAux_Interface): Remove compiler warnings. * src/psaux/psauxmod.c (t1_builder_funcs), src/psaux/psobjs.h (t1_builder_funcs): Updated. * src/pshinter/pshglob.h (PSH_Blue_Align): Replaced with ... (PSH_BLUE_ALIGN_{NONE,TOP,BOT}): New defines. (PSH_AlignmentRec): Updated. * include/freetype/internal/ftstream.h (GET_Char, GET_Byte): Fix typo. * include/freetype/internal/ftgloadr.h (FT_SubGlyph): Ditto. * src/base/ftstream (FT_Get_Char): Rename to... (FT_Stream_Get_Char): This. * src/base/ftnames.c (FT_Get_Sfnt_Name): s/index/idx/ -- `index' is a built-in function in gcc, causing warning messages with gcc 3.0. * src/autohint/ahglyph.c (ah_outline_load): Ditto. * src/autohint/ahglobal.c (ah_hinter_compute_blues): Ditto. * src/cache/ftcmanag.c (ftc_family_table_alloc, ftc_family_table_free, FTC_Manager_Done, FTC_Manager_Register_Cache): Ditto. * src/cff/cffload.c (cff_new_index, cff_done_index, cff_explicit_index, CFF_Access_Element, CFF_Forget_Element, CFF_Get_Name, CFF_Get_String, CFF_Load_SubFont, CFF_Load_Font, CFF_Done_Font): Ditto. * src/psaux/psobjs.c (PS_Table_Add, PS_Parser_LoadField): Ditto. * src/psaux/t1decode.c (T1_Decoder_Parse_Charstrings): Ditto. * src/pshinter/pshrec.c (ps_mask_test_bit, ps_mask_clear_bit, ps_mask_set_bit, ps_dimension_add_t1stem, ps_hints_t1stem3, * src/pshinter/pshalgo1.c (psh1_hint_table_record, psh1_hint_table_record_mask, psh1_hint_table_activate_mask): Ditto. * src/pshinter/pshalgo2.c (psh2_hint_table_record, psh2_hint_table_record_mask, psh2_hint_table_activate_mask): Ditto. * src/sfnt/ttpost.c (Load_Format_20, Load_Format_25, TT_Get_PS_Name): Ditto. * src/truetype/ttgload.c (TT_Get_Metrics, Get_HMetrics, load_truetype_glyph): Ditto. * src/type1/t1load.c (parse_subrs, T1_Open_Face): Ditto. * src/type1/t1afm.c (T1_Get_Kerning): Ditto. * include/freetype/cache/ftcmanag.h (ftc_family_table_free): Ditto.
2002-03-07 22:59:59 +01:00
FT_ULong idx = KERN_INDEX( glyph1, glyph2 );
2000-05-17 01:44:38 +02:00
/* simple binary search */
min = afm->kern_pairs;
max = min + afm->num_pairs - 1;
2000-05-17 01:44:38 +02:00
while ( min <= max )
{
FT_ULong midi;
2000-05-17 01:44:38 +02:00
mid = min + ( max - min ) / 2;
midi = KERN_INDEX( mid->glyph1, mid->glyph2 );
* src/base/ftdbgmem.c (ft_mem_table_resize, ft_mem_table_new, ft_mem_table_set, ft_mem_debug_alloc, ft_mem_debug_free, ft_mem_debug_realloc, ft_mem_debug_done, FT_Alloc_Debug, FT_Realloc_Debug, FT_Free_Debug): Fix compiler warnings. * src/base/ftcalc.c (FT_MulFix): Ditto. * src/cff/cffdrivr.c (cff_get_name_index): Ditto. * src/cff/cffobjs.c (CFF_Size_Get_Global_Funcs, CFF_Size_Init, CFF_GlyphSlot_Init): Ditto. * src/cid/cidobjs.c (CID_GlyphSlot_Init, CID_Size_Get_Globals_Funcs): Ditto. * src/type1/t1objs.c (T1_Size_Get_Globals_Funcs, T1_GlyphSlot_Init): Ditto. * src/pshinter/pshmod.c (pshinter_interface): Use `static const'. * src/winfonts/winfnt.c (FNT_Get_Next_Char): Remove unused variables. * include/freetype/internal/psaux.h (T1_Builder_Funcs): Renamed to... (T1_Builder_FuncsRec): This. (T1_Builder_Funcs): New typedef. (PSAux_Interface): Remove compiler warnings. * src/psaux/psauxmod.c (t1_builder_funcs), src/psaux/psobjs.h (t1_builder_funcs): Updated. * src/pshinter/pshglob.h (PSH_Blue_Align): Replaced with ... (PSH_BLUE_ALIGN_{NONE,TOP,BOT}): New defines. (PSH_AlignmentRec): Updated. * include/freetype/internal/ftstream.h (GET_Char, GET_Byte): Fix typo. * include/freetype/internal/ftgloadr.h (FT_SubGlyph): Ditto. * src/base/ftstream (FT_Get_Char): Rename to... (FT_Stream_Get_Char): This. * src/base/ftnames.c (FT_Get_Sfnt_Name): s/index/idx/ -- `index' is a built-in function in gcc, causing warning messages with gcc 3.0. * src/autohint/ahglyph.c (ah_outline_load): Ditto. * src/autohint/ahglobal.c (ah_hinter_compute_blues): Ditto. * src/cache/ftcmanag.c (ftc_family_table_alloc, ftc_family_table_free, FTC_Manager_Done, FTC_Manager_Register_Cache): Ditto. * src/cff/cffload.c (cff_new_index, cff_done_index, cff_explicit_index, CFF_Access_Element, CFF_Forget_Element, CFF_Get_Name, CFF_Get_String, CFF_Load_SubFont, CFF_Load_Font, CFF_Done_Font): Ditto. * src/psaux/psobjs.c (PS_Table_Add, PS_Parser_LoadField): Ditto. * src/psaux/t1decode.c (T1_Decoder_Parse_Charstrings): Ditto. * src/pshinter/pshrec.c (ps_mask_test_bit, ps_mask_clear_bit, ps_mask_set_bit, ps_dimension_add_t1stem, ps_hints_t1stem3, * src/pshinter/pshalgo1.c (psh1_hint_table_record, psh1_hint_table_record_mask, psh1_hint_table_activate_mask): Ditto. * src/pshinter/pshalgo2.c (psh2_hint_table_record, psh2_hint_table_record_mask, psh2_hint_table_activate_mask): Ditto. * src/sfnt/ttpost.c (Load_Format_20, Load_Format_25, TT_Get_PS_Name): Ditto. * src/truetype/ttgload.c (TT_Get_Metrics, Get_HMetrics, load_truetype_glyph): Ditto. * src/type1/t1load.c (parse_subrs, T1_Open_Face): Ditto. * src/type1/t1afm.c (T1_Get_Kerning): Ditto. * include/freetype/cache/ftcmanag.h (ftc_family_table_free): Ditto.
2002-03-07 22:59:59 +01:00
if ( midi == idx )
{
*kerning = mid->kerning;
return;
}
2000-05-17 01:44:38 +02:00
* src/base/ftdbgmem.c (ft_mem_table_resize, ft_mem_table_new, ft_mem_table_set, ft_mem_debug_alloc, ft_mem_debug_free, ft_mem_debug_realloc, ft_mem_debug_done, FT_Alloc_Debug, FT_Realloc_Debug, FT_Free_Debug): Fix compiler warnings. * src/base/ftcalc.c (FT_MulFix): Ditto. * src/cff/cffdrivr.c (cff_get_name_index): Ditto. * src/cff/cffobjs.c (CFF_Size_Get_Global_Funcs, CFF_Size_Init, CFF_GlyphSlot_Init): Ditto. * src/cid/cidobjs.c (CID_GlyphSlot_Init, CID_Size_Get_Globals_Funcs): Ditto. * src/type1/t1objs.c (T1_Size_Get_Globals_Funcs, T1_GlyphSlot_Init): Ditto. * src/pshinter/pshmod.c (pshinter_interface): Use `static const'. * src/winfonts/winfnt.c (FNT_Get_Next_Char): Remove unused variables. * include/freetype/internal/psaux.h (T1_Builder_Funcs): Renamed to... (T1_Builder_FuncsRec): This. (T1_Builder_Funcs): New typedef. (PSAux_Interface): Remove compiler warnings. * src/psaux/psauxmod.c (t1_builder_funcs), src/psaux/psobjs.h (t1_builder_funcs): Updated. * src/pshinter/pshglob.h (PSH_Blue_Align): Replaced with ... (PSH_BLUE_ALIGN_{NONE,TOP,BOT}): New defines. (PSH_AlignmentRec): Updated. * include/freetype/internal/ftstream.h (GET_Char, GET_Byte): Fix typo. * include/freetype/internal/ftgloadr.h (FT_SubGlyph): Ditto. * src/base/ftstream (FT_Get_Char): Rename to... (FT_Stream_Get_Char): This. * src/base/ftnames.c (FT_Get_Sfnt_Name): s/index/idx/ -- `index' is a built-in function in gcc, causing warning messages with gcc 3.0. * src/autohint/ahglyph.c (ah_outline_load): Ditto. * src/autohint/ahglobal.c (ah_hinter_compute_blues): Ditto. * src/cache/ftcmanag.c (ftc_family_table_alloc, ftc_family_table_free, FTC_Manager_Done, FTC_Manager_Register_Cache): Ditto. * src/cff/cffload.c (cff_new_index, cff_done_index, cff_explicit_index, CFF_Access_Element, CFF_Forget_Element, CFF_Get_Name, CFF_Get_String, CFF_Load_SubFont, CFF_Load_Font, CFF_Done_Font): Ditto. * src/psaux/psobjs.c (PS_Table_Add, PS_Parser_LoadField): Ditto. * src/psaux/t1decode.c (T1_Decoder_Parse_Charstrings): Ditto. * src/pshinter/pshrec.c (ps_mask_test_bit, ps_mask_clear_bit, ps_mask_set_bit, ps_dimension_add_t1stem, ps_hints_t1stem3, * src/pshinter/pshalgo1.c (psh1_hint_table_record, psh1_hint_table_record_mask, psh1_hint_table_activate_mask): Ditto. * src/pshinter/pshalgo2.c (psh2_hint_table_record, psh2_hint_table_record_mask, psh2_hint_table_activate_mask): Ditto. * src/sfnt/ttpost.c (Load_Format_20, Load_Format_25, TT_Get_PS_Name): Ditto. * src/truetype/ttgload.c (TT_Get_Metrics, Get_HMetrics, load_truetype_glyph): Ditto. * src/type1/t1load.c (parse_subrs, T1_Open_Face): Ditto. * src/type1/t1afm.c (T1_Get_Kerning): Ditto. * include/freetype/cache/ftcmanag.h (ftc_family_table_free): Ditto.
2002-03-07 22:59:59 +01:00
if ( midi < idx )
min = mid + 1;
else
max = mid - 1;
}
kerning->x = 0;
kerning->y = 0;
}
/* END */