freetype2/src/type1/t1afm.c

409 lines
10 KiB
C
Raw Normal View History

/****************************************************************************
*
* t1afm.c
*
* AFM support for Type 1 fonts (body).
*
2022-01-11 10:54:10 +01:00
* Copyright (C) 1996-2022 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 "t1afm.h"
#include <freetype/internal/ftdebug.h>
#include <freetype/internal/ftstream.h>
#include <freetype/internal/psaux.h>
#include "t1errors.h"
#ifndef T1_CONFIG_OPTION_NO_AFM
/**************************************************************************
*
* 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 t1afm
FT_LOCAL_DEF( void )
T1_Done_Metrics( FT_Memory memory,
AFM_FontInfo fi )
{
FT_FREE( fi->KernPairs );
fi->NumKernPair = 0;
2000-05-17 01:44:38 +02:00
FT_FREE( fi->TrackKerns );
fi->NumTrackKern = 0;
FT_FREE( fi );
}
/* read a glyph name and return the equivalent glyph index */
static FT_Int
t1_get_index( const char* name,
FT_Offset len,
void* user_data )
{
T1_Font type1 = (T1_Font)user_data;
FT_Int n;
2000-05-17 01:44:38 +02:00
/* PS string/name length must be < 16-bit */
if ( len > 0xFFFFU )
return 0;
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] == name[0] &&
ft_strlen( gname ) == len &&
ft_strncmp( gname, name, len ) == 0 )
return n;
}
return 0;
}
#undef KERN_INDEX
#define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) )
/* compare two kerning pairs */
FT_COMPARE_DEF( int )
compare_kern_pairs( const void* a,
const void* b )
{
AFM_KernPair pair1 = (AFM_KernPair)a;
AFM_KernPair pair2 = (AFM_KernPair)b;
2000-05-17 01:44:38 +02:00
FT_ULong index1 = KERN_INDEX( pair1->index1, pair1->index2 );
FT_ULong index2 = KERN_INDEX( pair2->index1, pair2->index2 );
2000-05-17 01:44:38 +02:00
if ( index1 > index2 )
return 1;
else if ( index1 < index2 )
return -1;
else
return 0;
}
/* parse a PFM file -- for now, only read the kerning pairs */
static FT_Error
T1_Read_PFM( FT_Face t1_face,
FT_Stream stream,
AFM_FontInfo fi )
{
FT_Error error = FT_Err_Ok;
2006-01-16 23:35:33 +01:00
FT_Memory memory = stream->memory;
FT_Byte* start;
FT_Byte* limit;
FT_Byte* p;
AFM_KernPair kp;
FT_Int width_table_length;
FT_CharMap oldcharmap;
FT_CharMap charmap;
FT_Int n;
start = (FT_Byte*)stream->cursor;
limit = (FT_Byte*)stream->limit;
/* 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 = FT_THROW( Unknown_File_Format );
goto Exit;
}
width_table_length = FT_PEEK_USHORT_LE( p );
p += 18 + width_table_length;
if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 )
/* extension table is probably optional */
goto Exit;
/* Kerning offset is 14 bytes from start of extensions table. */
p += 14;
p = start + FT_PEEK_ULONG_LE( p );
if ( p == start )
/* zero offset means no table */
goto Exit;
if ( p + 2 > limit )
{
error = FT_THROW( Unknown_File_Format );
goto Exit;
}
fi->NumKernPair = FT_PEEK_USHORT_LE( p );
p += 2;
if ( p + 4 * fi->NumKernPair > limit )
{
error = FT_THROW( Unknown_File_Format );
goto Exit;
}
/* Actually, kerning pairs are simply optional! */
if ( fi->NumKernPair == 0 )
goto Exit;
/* allocate the pairs */
if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
goto Exit;
/* now, read each kern pair */
kp = fi->KernPairs;
limit = p + 4 * fi->NumKernPair;
/* 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;
for ( n = 0; n < t1_face->num_charmaps; n++ )
{
charmap = t1_face->charmaps[n];
/* check against PostScript pseudo platform */
if ( charmap->platform_id == 7 )
{
t1_face->charmap = charmap;
break;
}
}
/* Kerning info is stored as: */
/* */
/* encoding of first glyph (1 byte) */
/* encoding of second glyph (1 byte) */
/* offset (little-endian short) */
2016-02-15 12:54:40 +01:00
for ( ; p < limit; p += 4 )
{
kp->index1 = FT_Get_Char_Index( t1_face, p[0] );
kp->index2 = FT_Get_Char_Index( t1_face, p[1] );
2022-04-01 08:50:33 +02:00
kp->x = (FT_Int)FT_PEEK_SHORT_LE( p + 2 );
kp->y = 0;
kp++;
}
t1_face->charmap = oldcharmap;
/* now, sort the kern pairs according to their glyph indices */
ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ),
compare_kern_pairs );
Exit:
if ( error )
{
FT_FREE( fi->KernPairs );
fi->NumKernPair = 0;
}
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 )
{
2006-01-16 23:35:33 +01:00
PSAux_Service psaux;
FT_Memory memory = stream->memory;
2006-01-16 23:35:33 +01:00
AFM_ParserRec parser;
AFM_FontInfo fi = NULL;
FT_Error error = FT_ERR( Unknown_File_Format );
T1_Face face = (T1_Face)t1_face;
T1_Font t1_font = &face->type1;
if ( face->afm_data )
{
FT_TRACE1(( "T1_Read_Metrics:"
" Freeing previously attached metrics data.\n" ));
T1_Done_Metrics( memory, (AFM_FontInfo)face->afm_data );
face->afm_data = NULL;
}
if ( FT_NEW( fi ) ||
FT_FRAME_ENTER( stream->size ) )
goto Exit;
fi->FontBBox = t1_font->font_bbox;
fi->Ascender = t1_font->font_bbox.yMax;
fi->Descender = t1_font->font_bbox.yMin;
psaux = (PSAux_Service)face->psaux;
if ( psaux->afm_parser_funcs )
{
error = psaux->afm_parser_funcs->init( &parser,
stream->memory,
stream->cursor,
stream->limit );
if ( !error )
{
parser.FontInfo = fi;
parser.get_index = t1_get_index;
parser.user_data = t1_font;
error = psaux->afm_parser_funcs->parse( &parser );
psaux->afm_parser_funcs->done( &parser );
}
}
if ( FT_ERR_EQ( error, Unknown_File_Format ) )
{
FT_Byte* start = stream->cursor;
/* MS Windows allows versions up to 0x3FF without complaining */
if ( stream->size > 6 &&
start[1] < 4 &&
FT_PEEK_ULONG_LE( start + 2 ) == stream->size )
error = T1_Read_PFM( t1_face, stream, fi );
}
if ( !error )
{
t1_font->font_bbox = fi->FontBBox;
t1_face->bbox.xMin = fi->FontBBox.xMin >> 16;
t1_face->bbox.yMin = fi->FontBBox.yMin >> 16;
/* no `U' suffix here to 0xFFFF! */
t1_face->bbox.xMax = ( fi->FontBBox.xMax + 0xFFFF ) >> 16;
t1_face->bbox.yMax = ( fi->FontBBox.yMax + 0xFFFF ) >> 16;
/* no `U' suffix here to 0x8000! */
t1_face->ascender = (FT_Short)( ( fi->Ascender + 0x8000 ) >> 16 );
t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000 ) >> 16 );
if ( fi->NumKernPair )
{
t1_face->face_flags |= FT_FACE_FLAG_KERNING;
face->afm_data = fi;
fi = NULL;
}
}
FT_FRAME_EXIT();
Exit:
if ( fi )
T1_Done_Metrics( memory, fi );
return error;
}
/* find the kerning for a given glyph pair */
FT_LOCAL_DEF( void )
T1_Get_Kerning( AFM_FontInfo fi,
FT_UInt glyph1,
FT_UInt glyph2,
FT_Vector* kerning )
{
AFM_KernPair 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 = fi->KernPairs;
max = min + fi->NumKernPair - 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->index1, mid->index2 );
* 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->x = mid->x;
kerning->y = mid->y;
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;
}
FT_LOCAL_DEF( FT_Error )
T1_Get_Track_Kerning( FT_Face face,
FT_Fixed ptsize,
FT_Int degree,
FT_Fixed* kerning )
{
AFM_FontInfo fi = (AFM_FontInfo)( (T1_Face)face )->afm_data;
FT_UInt i;
if ( !fi )
return FT_THROW( Invalid_Argument );
for ( i = 0; i < fi->NumTrackKern; i++ )
{
AFM_TrackKern tk = fi->TrackKerns + i;
if ( tk->degree != degree )
continue;
if ( ptsize < tk->min_ptsize )
*kerning = tk->min_kern;
else if ( ptsize > tk->max_ptsize )
*kerning = tk->max_kern;
else
{
*kerning = FT_MulDiv( ptsize - tk->min_ptsize,
tk->max_kern - tk->min_kern,
tk->max_ptsize - tk->min_ptsize ) +
tk->min_kern;
}
}
return FT_Err_Ok;
}
#else /* T1_CONFIG_OPTION_NO_AFM */
/* ANSI C doesn't like empty source files */
typedef int _t1_afm_dummy;
#endif /* T1_CONFIG_OPTION_NO_AFM */
/* END */