* src/psaux/afmparse.c, src/psaux/afmparse.h: New files which

implement an AFM parser.  It is used to parse an AFM file.

* src/psaux/psconv.c, src/psaux/psconv.h: New files to provide
conversion functions (e.g, PS real number => FT_Fixed) for the
PS_Parser and AFM_Parser.  Some of the functions are taken, with some
modifications, from the psobjs.c

* src/psaux/psobjs.c: Use functions from psconv.c.

* include/freetype/internal/psaux.h, src/psaux/psauxmod.c:: Add
`AFM_Parser' to the `psaux' service.

* src/psaux/psaux.c, src/psaux/rules.mk: Include those new files.

* src/tools/test_afm.c: A test program for AFM parser.

* include/freetype/internal/services/svkern.h,
include/freetype/internal/ftserv.h: New service `Kerning'.  It is
currently only used to get the track kerning information.

* src/type1/t1driver.c, src/type1/t1objs.c, src/type1/t1afm.c,
src/type1/t1afm.h: Update to use the AFM parser.
Provide the `Kerning' service.

* include/freetype/freetype.h, src/base/ftobjs.c: New API
`FT_Get_Track_Kerning'.
This commit is contained in:
Wu, Chia-I (吳佳一) 2006-01-16 15:35:56 +00:00
parent ea1e8d3a53
commit 108fdbbbd3
19 changed files with 2134 additions and 622 deletions

View File

@ -1,3 +1,33 @@
2006-01-16 Chia-I Wu <b90201047@ntu.edu.tw>
* src/psaux/afmparse.c, src/psaux/afmparse.h: New files which
implement an AFM parser. It is used to parse an AFM file.
* src/psaux/psconv.c, src/psaux/psconv.h: New files to provide
conversion functions (e.g, PS real number => FT_Fixed) for the
PS_Parser and AFM_Parser. Some of the functions are taken, with some
modifications, from the psobjs.c
* src/psaux/psobjs.c: Use functions from psconv.c.
* include/freetype/internal/psaux.h, src/psaux/psauxmod.c:: Add
`AFM_Parser' to the `psaux' service.
* src/psaux/psaux.c, src/psaux/rules.mk: Include those new files.
* src/tools/test_afm.c: A test program for AFM parser.
* include/freetype/internal/services/svkern.h,
include/freetype/internal/ftserv.h: New service `Kerning'. It is
currently only used to get the track kerning information.
* src/type1/t1driver.c, src/type1/t1objs.c, src/type1/t1afm.c,
src/type1/t1afm.h: Update to use the AFM parser.
Provide the `Kerning' service.
* include/freetype/freetype.h, src/base/ftobjs.c: New API
`FT_Get_Track_Kerning'.
2006-01-15 Chia-I Wu <b90201047@ntu.edu.tw>
* include/freetype/internal/ftobjs.h, src/base/ftobjs.c,

View File

@ -192,6 +192,7 @@ FT_BEGIN_HEADER
/* FT_Render_Mode */
/* FT_Get_Kerning */
/* FT_Kerning_Mode */
/* FT_Get_Track_Kerning */
/* FT_Get_Glyph_Name */
/* FT_Get_Postscript_Name */
/* */
@ -2711,6 +2712,34 @@ FT_BEGIN_HEADER
FT_Vector *akerning );
/*************************************************************************/
/* */
/* <Function> */
/* FT_Get_Track_Kerning */
/* */
/* <Description> */
/* Return the track kerning for a given face object at a given size. */
/* */
/* <Input> */
/* face :: A handle to a source face object. */
/* */
/* point_size :: The point size in 16.16 fractional points. */
/* */
/* degree :: The degree of tightness. */
/* */
/* <Output> */
/* akerning :: The kerning in in 16.16 fractional points. */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
/* */
FT_EXPORT( FT_Error )
FT_Get_Track_Kerning( FT_Face face,
FT_Fixed point_size,
FT_Int degree,
FT_Fixed* akerning );
/*************************************************************************/
/* */
/* <Function> */

View File

@ -313,6 +313,7 @@ FT_BEGIN_HEADER
#define FT_SERVICE_TT_CMAP_H <freetype/internal/services/svttcmap.h>
#define FT_SERVICE_WINFNT_H <freetype/internal/services/svwinfnt.h>
#define FT_SERVICE_XFREE86_NAME_H <freetype/internal/services/svxf86nm.h>
#define FT_SERVICE_KERNING_H <freetype/internal/services/svkern.h>
/* */

View File

@ -685,6 +685,96 @@ FT_BEGIN_HEADER
} T1_DecoderRec;
/*************************************************************************/
/*************************************************************************/
/***** *****/
/***** AFM PARSER *****/
/***** *****/
/*************************************************************************/
/*************************************************************************/
typedef struct AFM_ParserRec_* AFM_Parser;
typedef struct AFM_TrackKernRec_
{
FT_Int degree;
FT_Fixed min_ptsize;
FT_Fixed min_kern;
FT_Fixed max_ptsize;
FT_Fixed max_kern;
} AFM_TrackKernRec, *AFM_TrackKern;
typedef struct AFM_KernPairRec_
{
FT_Int index1;
FT_Int index2;
FT_Int x;
FT_Int y;
} AFM_KernPairRec, *AFM_KernPair;
typedef struct AFM_FontInfoRec_
{
FT_Bool IsCIDFont;
AFM_TrackKern TrackKerns; /* free if non-NULL */
FT_Int NumTrackKern;
AFM_KernPair KernPairs; /* free if non-NULL */
FT_Int NumKernPair;
} AFM_FontInfoRec, *AFM_FontInfo;
typedef struct AFM_Parser_FuncsRec_
{
FT_Error
(*init)( AFM_Parser parser,
FT_Memory memory,
FT_Byte* base,
FT_Byte* limit );
void
(*done)( AFM_Parser parser );
FT_Error
(*parse)( AFM_Parser parser );
} AFM_Parser_FuncsRec;
typedef struct AFM_StreamRec_* AFM_Stream;
/*************************************************************************/
/* */
/* <Struct> */
/* AFM_ParserRec */
/* */
/* <Description> */
/* An AFM_Parser is a parser for the AFM files. */
/* */
/* <Fields> */
/* memory :: The object used for memory operations */
/* (alloc/realloc). */
/* */
/* stream :: This is an opaque object. */
/* */
/* FontInfo :: The result will be stored here. */
/* */
/* get_index :: An user provided function to get glyph index by its */
/* name. */
/* */
typedef struct AFM_ParserRec_
{
FT_Memory memory;
AFM_Stream stream;
AFM_FontInfo FontInfo;
FT_Int
(*get_index)( const char* name,
FT_UInt len,
void* user_data );
void* user_data;
} AFM_ParserRec;
/*************************************************************************/
/*************************************************************************/
/***** *****/
@ -720,6 +810,7 @@ FT_BEGIN_HEADER
const PS_Parser_FuncsRec* ps_parser_funcs;
const T1_Builder_FuncsRec* t1_builder_funcs;
const T1_Decoder_FuncsRec* t1_decoder_funcs;
const AFM_Parser_FuncsRec* afm_parser_funcs;
void
(*t1_decrypt)( FT_Byte* buffer,

View File

@ -0,0 +1,51 @@
/***************************************************************************/
/* */
/* svkern.h */
/* */
/* The FreeType Kerning service (specification). */
/* */
/* Copyright 2003, 2004 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. */
/* */
/***************************************************************************/
#ifndef __SVKERN_H__
#define __SVKERN_H__
#include FT_INTERNAL_SERVICE_H
#include FT_TRUETYPE_TABLES_H
FT_BEGIN_HEADER
#define FT_SERVICE_ID_KERNING "kerning"
typedef FT_Error
(*FT_Kerning_TrackGetFunc)( FT_Face face,
FT_Fixed point_size,
FT_Int degree,
FT_Fixed* akerning );
FT_DEFINE_SERVICE( Kerning )
{
FT_Kerning_TrackGetFunc get_track;
};
/* */
FT_END_HEADER
#endif /* __SVKERN_H__ */
/* END */

View File

@ -33,6 +33,7 @@
#include FT_SERVICE_POSTSCRIPT_NAME_H
#include FT_SERVICE_GLYPH_DICT_H
#include FT_SERVICE_TT_CMAP_H
#include FT_SERVICE_KERNING_H
FT_BASE_DEF( FT_Pointer )
@ -2376,6 +2377,40 @@
}
/* documentation is in freetype.h */
FT_EXPORT_DEF( FT_Error )
FT_Get_Track_Kerning( FT_Face face,
FT_Fixed point_size,
FT_Int degree,
FT_Fixed* akerning )
{
FT_Service_Kerning service;
FT_Error error = FT_Err_Ok;
FT_Driver driver;
if ( !face )
return FT_Err_Invalid_Face_Handle;
if ( !akerning )
return FT_Err_Invalid_Argument;
driver = face->driver;
FT_FACE_FIND_SERVICE( face, service, KERNING );
if ( !service )
return FT_Err_Unimplemented_Feature;
error = service->get_track( face,
point_size,
degree,
akerning );
return error;
}
/* documentation is in freetype.h */
FT_EXPORT_DEF( FT_Error )

925
src/psaux/afmparse.c Normal file
View File

@ -0,0 +1,925 @@
/***************************************************************************/
/* */
/* afmparse.c */
/* */
/* AFM parser (body). */
/* */
/* Copyright 2006 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. */
/* */
/***************************************************************************/
#include FT_INTERNAL_POSTSCRIPT_AUX_H
#include FT_INTERNAL_DEBUG_H
#include "afmparse.h"
#include "psconv.h"
#include "psauxerr.h"
/***************************************************************************/
/* */
/* AFM_Stream */
/* */
/* The use of AFM_Stream is largely inspired by parseAFM.[ch] from t1lib. */
/* */
/* */
enum
{
AFM_STREAM_STATUS_NORMAL,
AFM_STREAM_STATUS_EOC,
AFM_STREAM_STATUS_EOL,
AFM_STREAM_STATUS_EOF
};
typedef struct AFM_StreamRec_
{
FT_Byte* cursor;
FT_Byte* base;
FT_Byte* limit;
FT_Int status;
} AFM_StreamRec;
#ifndef EOF
#define EOF -1
#endif
/* this works because empty lines are ignored */
#define AFM_IS_NEWLINE( ch ) ( ( ch ) == '\r' || ( ch ) == '\n' )
#define AFM_IS_EOF( ch ) ( ( ch ) == EOF || ( ch ) == '\x1a' )
#define AFM_IS_SPACE( ch ) ( ( ch ) == ' ' || ( ch ) == '\t' )
/* column separator; there is no `column' in the spec actually */
#define AFM_IS_SEP( ch ) ( ( ch ) == ';' )
#define AFM_GETC() \
( ( ( stream )->cursor < ( stream )->limit ) \
? *( stream )->cursor++ \
: EOF )
#define AFM_STREAM_KEY_BEGIN( stream ) \
(char*)( ( stream )->cursor - 1 )
#define AFM_STREAM_KEY_LEN( stream, key ) \
( (char*)( stream )->cursor - key - 1 )
#define AFM_STATUS_EOC( stream ) \
( ( stream )->status >= AFM_STREAM_STATUS_EOC )
#define AFM_STATUS_EOL( stream ) \
( ( stream )->status >= AFM_STREAM_STATUS_EOL )
#define AFM_STATUS_EOF( stream ) \
( ( stream )->status >= AFM_STREAM_STATUS_EOF )
static int
afm_stream_skip_spaces( AFM_Stream stream )
{
int ch;
if ( AFM_STATUS_EOC( stream ) )
return ';';
while ( 1 )
{
ch = AFM_GETC();
if ( !AFM_IS_SPACE( ch ) )
break;
}
if ( AFM_IS_NEWLINE( ch ) )
stream->status = AFM_STREAM_STATUS_EOL;
else if ( AFM_IS_SEP( ch ) )
stream->status = AFM_STREAM_STATUS_EOC;
else if ( AFM_IS_EOF( ch ) )
stream->status = AFM_STREAM_STATUS_EOF;
return ch;
}
/* read a key or val in current column */
static char*
afm_stream_read_one( AFM_Stream stream )
{
char* str;
int ch;
afm_stream_skip_spaces( stream );
if ( AFM_STATUS_EOC( stream ) )
return NULL;
str = AFM_STREAM_KEY_BEGIN( stream );
while ( 1 )
{
ch = AFM_GETC();
if ( AFM_IS_SPACE( ch ) )
break;
else if ( AFM_IS_NEWLINE( ch ) )
{
stream->status = AFM_STREAM_STATUS_EOL;
break;
}
else if ( AFM_IS_SEP( ch ) )
{
stream->status = AFM_STREAM_STATUS_EOC;
break;
}
else if ( AFM_IS_EOF( ch ) )
{
stream->status = AFM_STREAM_STATUS_EOF;
break;
}
}
return str;
}
/* read a string (i.e., read to EOL) */
static char*
afm_stream_read_string( AFM_Stream stream )
{
char* str;
int ch;
afm_stream_skip_spaces( stream );
if ( AFM_STATUS_EOL( stream ) )
return NULL;
str = AFM_STREAM_KEY_BEGIN( stream );
/* scan to eol */
while ( 1 )
{
ch = AFM_GETC();
if ( AFM_IS_NEWLINE( ch ) )
{
stream->status = AFM_STREAM_STATUS_EOL;
break;
}
else if ( AFM_IS_EOF( ch ) )
{
stream->status = AFM_STREAM_STATUS_EOF;
break;
}
}
return str;
}
/***************************************************************************/
/* */
/* AFM_Parser */
/* */
/* */
/* all keys defined in Ch. 7-10 of 5004.AFM_Spec.pdf */
typedef enum
{
AFM_TOKEN_ASCENDER,
AFM_TOKEN_AXISLABEL,
AFM_TOKEN_AXISTYPE,
AFM_TOKEN_B,
AFM_TOKEN_BLENDAXISTYPES,
AFM_TOKEN_BLENDDESIGNMAP,
AFM_TOKEN_BLENDDESIGNPOSITIONS,
AFM_TOKEN_C,
AFM_TOKEN_CC,
AFM_TOKEN_CH,
AFM_TOKEN_CAPHEIGHT,
AFM_TOKEN_CHARWIDTH,
AFM_TOKEN_CHARACTERSET,
AFM_TOKEN_CHARACTERS,
AFM_TOKEN_DESCENDER,
AFM_TOKEN_ENCODINGSCHEME,
AFM_TOKEN_ENDAXIS,
AFM_TOKEN_ENDCHARMETRICS,
AFM_TOKEN_ENDCOMPOSITES,
AFM_TOKEN_ENDDIRECTION,
AFM_TOKEN_ENDFONTMETRICS,
AFM_TOKEN_ENDKERNDATA,
AFM_TOKEN_ENDKERNPAIRS,
AFM_TOKEN_ENDTRACKKERN,
AFM_TOKEN_ESCCHAR,
AFM_TOKEN_FAMILYNAME,
AFM_TOKEN_FONTBBOX,
AFM_TOKEN_FONTNAME,
AFM_TOKEN_FULLNAME,
AFM_TOKEN_ISBASEFONT,
AFM_TOKEN_ISCIDFONT,
AFM_TOKEN_ISFIXEDPITCH,
AFM_TOKEN_ISFIXEDV,
AFM_TOKEN_ITALICANGLE,
AFM_TOKEN_KP,
AFM_TOKEN_KPH,
AFM_TOKEN_KPX,
AFM_TOKEN_KPY,
AFM_TOKEN_L,
AFM_TOKEN_MAPPINGSCHEME,
AFM_TOKEN_METRICSSETS,
AFM_TOKEN_N,
AFM_TOKEN_NOTICE,
AFM_TOKEN_PCC,
AFM_TOKEN_STARTAXIS,
AFM_TOKEN_STARTCHARMETRICS,
AFM_TOKEN_STARTCOMPOSITES,
AFM_TOKEN_STARTDIRECTION,
AFM_TOKEN_STARTFONTMETRICS,
AFM_TOKEN_STARTKERNDATA,
AFM_TOKEN_STARTKERNPAIRS,
AFM_TOKEN_STARTKERNPAIRS0,
AFM_TOKEN_STARTKERNPAIRS1,
AFM_TOKEN_STARTTRACKKERN,
AFM_TOKEN_STDHW,
AFM_TOKEN_STDVW,
AFM_TOKEN_TRACKKERN,
AFM_TOKEN_UNDERLINEPOSITION,
AFM_TOKEN_UNDERLINETHICKNESS,
AFM_TOKEN_VV,
AFM_TOKEN_VVECTOR,
AFM_TOKEN_VERSION,
AFM_TOKEN_W,
AFM_TOKEN_W0,
AFM_TOKEN_W0X,
AFM_TOKEN_W0Y,
AFM_TOKEN_W1,
AFM_TOKEN_W1X,
AFM_TOKEN_W1Y,
AFM_TOKEN_WX,
AFM_TOKEN_WY,
AFM_TOKEN_WEIGHT,
AFM_TOKEN_WEIGHTVECTOR,
AFM_TOKEN_XHEIGHT,
N_AFM_TOKENS,
AFM_TOKEN_UNKNOWN
} AFM_Token;
static const char* afm_key_table[N_AFM_TOKENS] =
{
"Ascender",
"AxisLabel",
"AxisType",
"B",
"BlendAxisTypes",
"BlendDesignMap",
"BlendDesignPositions",
"C",
"CC",
"CH",
"CapHeight",
"CharWidth",
"CharacterSet",
"Characters",
"Descender",
"EncodingScheme",
"EndAxis",
"EndCharMetrics",
"EndComposites",
"EndDirection",
"EndFontMetrics",
"EndKernData",
"EndKernPairs",
"EndTrackKern",
"EscChar",
"FamilyName",
"FontBBox",
"FontName",
"FullName",
"IsBaseFont",
"IsCIDFont",
"IsFixedPitch",
"IsFixedV",
"ItalicAngle",
"KP",
"KPH",
"KPX",
"KPY",
"L",
"MappingScheme",
"MetricsSets",
"N",
"Notice",
"PCC",
"StartAxis",
"StartCharMetrics",
"StartComposites",
"StartDirection",
"StartFontMetrics",
"StartKernData",
"StartKernPairs",
"StartKernPairs0",
"StartKernPairs1",
"StartTrackKern",
"StdHW",
"StdVW",
"TrackKern",
"UnderlinePosition",
"UnderlineThickness",
"VV",
"VVector",
"Version",
"W",
"W0",
"W0X",
"W0Y",
"W1",
"W1X",
"W1Y",
"WX",
"WY",
"Weight",
"WeightVector",
"XHeight"
};
#define AFM_MAX_ARGUMENTS 5
static AFM_ValueRec shared_vals[AFM_MAX_ARGUMENTS];
/*
* `afm_parser_read_vals' and `afm_parser_next_key' provides
* high-level operations to an AFM_Stream. The rest of the
* parser functions should use them and should not access
* the AFM_Stream directly.
*/
FT_LOCAL_DEF( FT_Int )
afm_parser_read_vals( AFM_Parser parser,
AFM_Value vals,
FT_Int n )
{
AFM_Stream stream = parser->stream;
char* str;
FT_Int i;
if ( n > AFM_MAX_ARGUMENTS )
return 0;
for ( i = 0; i < n; i++ )
{
FT_UInt len;
if ( vals[i].type == AFM_VALUE_TYPE_STRING )
str = afm_stream_read_string( stream );
else
str = afm_stream_read_one( stream );
if ( !str )
break;
len = AFM_STREAM_KEY_LEN( stream, str );
switch ( vals[i].type )
{
case AFM_VALUE_TYPE_STRING:
case AFM_VALUE_TYPE_NAME:
if ( !FT_QAlloc( parser->memory, len + 1, (void**)&vals[i].u.s ) )
{
ft_memcpy( vals[i].u.s, str, len );
vals[i].u.s[len] = '\0';
}
break;
case AFM_VALUE_TYPE_FIXED:
vals[i].u.f = PS_Conv_ToFixed( (FT_Byte**)&str,
(FT_Byte*)str + len,
0 );
break;
case AFM_VALUE_TYPE_INTEGER:
vals[i].u.i = PS_Conv_ToInt( (FT_Byte**)&str,
(FT_Byte*)str + len );
break;
case AFM_VALUE_TYPE_BOOL:
vals[i].u.b = ( len == 4 &&
ft_strncmp( str, "true", 4 ) == 0 );
break;
case AFM_VALUE_TYPE_INDEX:
if ( parser->get_index )
vals[i].u.i = parser->get_index( str,
len,
parser->user_data );
else
vals[i].u.i = 0;
break;
}
}
return i;
}
FT_LOCAL_DEF( char* )
afm_parser_next_key( AFM_Parser parser,
FT_Bool line,
FT_UInt* len )
{
AFM_Stream stream = parser->stream;
char* key;
if ( line )
{
while ( 1 )
{
/* skip current line */
if ( !AFM_STATUS_EOL( stream ) )
afm_stream_read_string( stream );
stream->status = AFM_STREAM_STATUS_NORMAL;
key = afm_stream_read_one( stream );
/* skip empty line */
if ( !key &&
!AFM_STATUS_EOF( stream ) &&
AFM_STATUS_EOL( stream ) )
continue;
break;
}
}
else
{
while ( 1 )
{
/* skip current column */
while ( !AFM_STATUS_EOC( stream ) )
afm_stream_read_one( stream );
stream->status = AFM_STREAM_STATUS_NORMAL;
key = afm_stream_read_one( stream );
/* skip empty column */
if ( !key &&
!AFM_STATUS_EOF( stream ) &&
AFM_STATUS_EOC( stream ) )
continue;
break;
}
}
if ( len )
*len = ( key ) ? AFM_STREAM_KEY_LEN( stream, key )
: 0;
return key;
}
static AFM_Token
afm_tokenize( const char* key,
FT_UInt len )
{
int n;
for ( n = 0; n < N_AFM_TOKENS; n++ )
{
if ( *( afm_key_table[n] ) == *key )
{
for ( ; n < N_AFM_TOKENS; n++ )
{
if ( *( afm_key_table[n] ) != *key )
return AFM_TOKEN_UNKNOWN;
if ( ft_strncmp( afm_key_table[n], key, len ) == 0 )
return n;
}
}
}
return AFM_TOKEN_UNKNOWN;
}
FT_LOCAL_DEF( FT_Error )
afm_parser_init( AFM_Parser parser,
FT_Memory memory,
FT_Byte* base,
FT_Byte* limit )
{
AFM_Stream stream;
FT_Error error;
if ( FT_NEW( stream ) )
return error;
stream->cursor = stream->base = base;
stream->limit = limit;
/* so that the first call won't skip the first line */
stream->status = AFM_STREAM_STATUS_EOL;
parser->memory = memory;
parser->stream = stream;
parser->FontInfo = NULL;
parser->get_index = NULL;
return PSaux_Err_Ok;
}
FT_LOCAL( void )
afm_parser_done( AFM_Parser parser )
{
FT_Memory memory = parser->memory;
FT_FREE( parser->stream );
}
FT_LOCAL_DEF( FT_Error )
afm_parser_read_int( AFM_Parser parser,
FT_Int* aint )
{
AFM_ValueRec val;
val.type = AFM_VALUE_TYPE_INTEGER;
if ( afm_parser_read_vals( parser, &val, 1 ) == 1 )
{
*aint = val.u.i;
return PSaux_Err_Ok;
}
else
return PSaux_Err_Syntax_Error;
}
static FT_Error
afm_parse_track_kern( AFM_Parser parser )
{
AFM_FontInfo fi = parser->FontInfo;
AFM_TrackKern tk;
char* key;
FT_UInt len;
int n = -1;
if ( afm_parser_read_int( parser, &fi->NumTrackKern ) )
goto Fail;
if ( fi->NumTrackKern )
{
FT_Memory memory = parser->memory;
FT_Error error;
FT_QNEW_ARRAY( fi->TrackKerns, fi->NumTrackKern );
if ( error )
return error;
}
while ( ( key = afm_parser_next_key( parser, 1, &len ) ) )
{
switch ( afm_tokenize( key, len ) )
{
case AFM_TOKEN_TRACKKERN:
n++;
if ( n >= fi->NumTrackKern )
goto Fail;
tk = fi->TrackKerns + n;
shared_vals[0].type = AFM_VALUE_TYPE_INTEGER;
shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
shared_vals[4].type = AFM_VALUE_TYPE_FIXED;
if ( afm_parser_read_vals( parser, shared_vals, 5 ) != 5 )
goto Fail;
tk->degree = shared_vals[0].u.i;
tk->min_ptsize = shared_vals[1].u.f;
tk->min_kern = shared_vals[2].u.f;
tk->max_ptsize = shared_vals[3].u.f;
tk->max_kern = shared_vals[4].u.f;
/* is this correct? */
if ( tk->degree < 0 && tk->min_kern > 0 )
tk->min_kern = -tk->min_kern;
break;
case AFM_TOKEN_ENDTRACKKERN:
case AFM_TOKEN_ENDKERNDATA:
case AFM_TOKEN_ENDFONTMETRICS:
fi->NumTrackKern = n + 1;
return PSaux_Err_Ok;
break;
case AFM_TOKEN_UNKNOWN:
break;
default:
goto Fail;
break;
}
}
Fail:
return PSaux_Err_Syntax_Error;
}
#undef KERN_INDEX
#define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 )
/* compare two kerning pairs */
FT_CALLBACK_DEF( int )
afm_compare_kern_pairs( const void* a,
const void* b )
{
AFM_KernPair kp1 = (AFM_KernPair)a;
AFM_KernPair kp2 = (AFM_KernPair)b;
FT_ULong index1 = KERN_INDEX( kp1->index1, kp1->index2 );
FT_ULong index2 = KERN_INDEX( kp2->index1, kp2->index2 );
return (int)( index1 - index2 );
}
static FT_Error
afm_parse_kern_pairs( AFM_Parser parser )
{
AFM_FontInfo fi = parser->FontInfo;
AFM_KernPair kp;
char* key;
FT_UInt len;
int n = -1;
if ( afm_parser_read_int( parser, &fi->NumKernPair ) )
goto Fail;
if ( fi->NumKernPair )
{
FT_Memory memory = parser->memory;
FT_Error error;
FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair );
if ( error )
return error;
}
while ( ( key = afm_parser_next_key( parser, 1, &len ) ) )
{
AFM_Token token = afm_tokenize( key, len );
switch ( token )
{
case AFM_TOKEN_KP:
case AFM_TOKEN_KPX:
case AFM_TOKEN_KPY:
{
FT_Int r;
n++;
if ( n >= fi->NumKernPair )
goto Fail;
kp = fi->KernPairs + n;
shared_vals[0].type = AFM_VALUE_TYPE_INDEX;
shared_vals[1].type = AFM_VALUE_TYPE_INDEX;
shared_vals[2].type = AFM_VALUE_TYPE_INTEGER;
shared_vals[3].type = AFM_VALUE_TYPE_INTEGER;
r = afm_parser_read_vals( parser, shared_vals, 4 );
if ( r < 3 )
goto Fail;
kp->index1 = shared_vals[0].u.i;
kp->index2 = shared_vals[1].u.i;
if ( token == AFM_TOKEN_KPY )
{
kp->x = 0;
kp->y = shared_vals[2].u.i;
}
else
{
kp->x = shared_vals[2].u.i;
kp->y = ( token == AFM_TOKEN_KP && r == 4 )
? shared_vals[3].u.i : 0;
}
}
break;
case AFM_TOKEN_ENDKERNPAIRS:
case AFM_TOKEN_ENDKERNDATA:
case AFM_TOKEN_ENDFONTMETRICS:
fi->NumKernPair = n + 1;
ft_qsort( fi->KernPairs, fi->NumKernPair,
sizeof( AFM_KernPairRec ),
afm_compare_kern_pairs );
return PSaux_Err_Ok;
break;
case AFM_TOKEN_UNKNOWN:
break;
default:
goto Fail;
break;
}
}
Fail:
return PSaux_Err_Syntax_Error;
}
static FT_Error
afm_parse_kern_data( AFM_Parser parser )
{
FT_Error error;
char* key;
FT_UInt len;
while ( ( key = afm_parser_next_key( parser, 1, &len ) ) )
{
switch ( afm_tokenize( key, len ) )
{
case AFM_TOKEN_STARTTRACKKERN:
error = afm_parse_track_kern( parser );
if ( error )
return error;
break;
case AFM_TOKEN_STARTKERNPAIRS:
case AFM_TOKEN_STARTKERNPAIRS0:
error = afm_parse_kern_pairs( parser );
if ( error )
return error;
break;
case AFM_TOKEN_ENDKERNDATA:
case AFM_TOKEN_ENDFONTMETRICS:
return PSaux_Err_Ok;
break;
case AFM_TOKEN_UNKNOWN:
break;
default:
goto Fail;
break;
}
}
Fail:
return PSaux_Err_Syntax_Error;
}
static FT_Error
afm_parser_skip_section( AFM_Parser parser,
FT_UInt n,
AFM_Token end_section )
{
char* key;
FT_UInt len;
while ( n-- > 0 )
{
key = afm_parser_next_key( parser, 1, NULL );
if ( !key )
goto Fail;
}
while ( ( key = afm_parser_next_key( parser, 1, &len ) ) )
{
AFM_Token token = afm_tokenize( key, len );
if ( token == end_section || token == AFM_TOKEN_ENDFONTMETRICS )
return PSaux_Err_Ok;
}
Fail:
return PSaux_Err_Syntax_Error;
}
FT_LOCAL_DEF( FT_Error )
afm_parser_parse( AFM_Parser parser )
{
FT_Memory memory = parser->memory;
AFM_FontInfo fi = parser->FontInfo;
FT_Error error = PSaux_Err_Syntax_Error;
char* key;
FT_UInt len;
FT_Int metrics_sets = 0;
if ( !fi )
return PSaux_Err_Invalid_Argument;
key = afm_parser_next_key( parser, 1, &len );
if ( !key || len != 16 ||
ft_strncmp( key, "StartFontMetrics", 16 ) != 0 )
return PSaux_Err_Unknown_File_Format;
while ( ( key = afm_parser_next_key( parser, 1, &len ) ) )
{
switch ( afm_tokenize( key, len ) )
{
case AFM_TOKEN_METRICSSETS:
if ( afm_parser_read_int( parser, &metrics_sets ) )
goto Fail;
if ( metrics_sets != 0 && metrics_sets != 2 )
{
error = PSaux_Err_Unimplemented_Feature;
goto Fail;
}
break;
case AFM_TOKEN_ISCIDFONT:
shared_vals[0].type = AFM_VALUE_TYPE_BOOL;
if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
goto Fail;
fi->IsCIDFont = shared_vals[0].u.b;
break;
case AFM_TOKEN_STARTCHARMETRICS:
{
FT_Int n;
if ( afm_parser_read_int( parser, &n ) )
goto Fail;
error = afm_parser_skip_section( parser, n,
AFM_TOKEN_ENDCHARMETRICS );
if ( error )
return error;
}
break;
case AFM_TOKEN_STARTKERNDATA:
error = afm_parse_kern_data( parser );
if ( error )
goto Fail;
/* no break since we only support kern data */
case AFM_TOKEN_ENDFONTMETRICS:
return PSaux_Err_Ok;
break;
default:
break;
}
}
Fail:
FT_FREE( fi->TrackKerns );
fi->NumTrackKern = 0;
FT_FREE( fi->KernPairs );
fi->NumKernPair = 0;
fi->IsCIDFont = 0;
return error;
}

85
src/psaux/afmparse.h Normal file
View File

@ -0,0 +1,85 @@
/***************************************************************************/
/* */
/* afmparse.h */
/* */
/* AFM parser (specification). */
/* */
/* Copyright 2006 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. */
/* */
/***************************************************************************/
#ifndef __AFMPARSE_H__
#define __AFMPARSE_H__
#include <ft2build.h>
#include FT_INTERNAL_POSTSCRIPT_AUX_H
FT_BEGIN_HEADER
FT_LOCAL( FT_Error )
afm_parser_init( AFM_Parser parser,
FT_Memory memory,
FT_Byte* base,
FT_Byte* limit );
FT_LOCAL( void )
afm_parser_done( AFM_Parser parser );
FT_LOCAL( FT_Error )
afm_parser_parse( AFM_Parser parser );
enum AFM_ValueType_
{
AFM_VALUE_TYPE_STRING,
AFM_VALUE_TYPE_NAME,
AFM_VALUE_TYPE_FIXED, /* real number */
AFM_VALUE_TYPE_INTEGER,
AFM_VALUE_TYPE_BOOL,
AFM_VALUE_TYPE_INDEX /* glyph index */
};
typedef struct
{
enum AFM_ValueType_ type;
union {
char* s;
FT_Fixed f;
FT_Int i;
FT_Bool b;
} u;
} AFM_ValueRec, *AFM_Value;
FT_LOCAL( FT_Int )
afm_parser_read_vals( AFM_Parser parser,
AFM_Value vals,
FT_Int n );
/* read the next key from the next line or column */
FT_LOCAL( char* )
afm_parser_next_key( AFM_Parser parser,
FT_Bool line,
FT_UInt* len );
FT_END_HEADER
#endif /* __AFMPARSE_H__ */
/* END */

View File

@ -23,6 +23,8 @@
#include "psauxmod.c"
#include "t1decode.c"
#include "t1cmap.c"
#include "afmparse.c"
#include "psconv.c"
/* END */

View File

@ -21,6 +21,7 @@
#include "psobjs.h"
#include "t1decode.h"
#include "t1cmap.h"
#include "afmparse.h"
FT_CALLBACK_TABLE_DEF
@ -75,6 +76,15 @@
};
FT_CALLBACK_TABLE_DEF
const AFM_Parser_FuncsRec afm_parser_funcs =
{
afm_parser_init,
afm_parser_done,
afm_parser_parse
};
FT_CALLBACK_TABLE_DEF
const T1_CMap_ClassesRec t1_cmap_classes =
{
@ -92,6 +102,7 @@
&ps_parser_funcs,
&t1_builder_funcs,
&t1_decoder_funcs,
&afm_parser_funcs,
t1_decrypt,

394
src/psaux/psconv.c Normal file
View File

@ -0,0 +1,394 @@
/***************************************************************************/
/* */
/* psconv.c */
/* */
/* Some convenient conversions (body). */
/* */
/* Copyright 2006 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. */
/* */
/***************************************************************************/
#include <ft2build.h>
#include FT_INTERNAL_POSTSCRIPT_AUX_H
#include FT_INTERNAL_DEBUG_H
#include "psobjs.h"
#include "psauxerr.h"
/* The following array is used by various functions to quickly convert */
/* digits (both decimal and non-decimal) into numbers. */
#if 'A' == 65
/* ASCII */
static const char ft_char_table[128] =
{
/* 0x00 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
};
/* no character >= 0x80 can represent a valid number */
#define OP >=
#endif /* 'A' == 65 */
#if 'A' == 193
/* EBCDIC */
static const char ft_char_table[128] =
{
/* 0x80 */
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1,
-1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1,
-1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1,
-1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1,
-1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
};
/* no character < 0x80 can represent a valid number */
#define OP <
#endif /* 'A' == 193 */
FT_LOCAL_DEF( FT_Int )
PS_Conv_Strtol( FT_Byte** cursor,
FT_Byte* limit,
FT_Int base )
{
FT_Byte* p = *cursor;
FT_Int num = 0;
FT_Bool sign = 0;
if ( p == limit || base < 2 || base > 36 )
return 0;
if ( *p == '-' || *p == '+' )
{
sign = ( *p == '-' );
p++;
if ( p == limit )
return 0;
}
for ( ; p < limit; p++ )
{
char c;
if ( IS_PS_SPACE( *p ) || *p OP 0x80 )
break;
c = ft_char_table[*p & 0x7f];
if ( c < 0 || c >= base )
break;
num = num * base + c;
}
if ( sign )
num = -num;
*cursor = p;
return num;
}
FT_LOCAL_DEF( FT_Int )
PS_Conv_ToInt( FT_Byte** cursor,
FT_Byte* limit )
{
FT_Byte* p;
FT_Int num;
num = PS_Conv_Strtol( cursor, limit, 10 );
p = *cursor;
if ( p < limit && *p == '#' )
{
*cursor = p + 1;
return PS_Conv_Strtol( cursor, limit, num );
}
else
return num;
}
FT_LOCAL_DEF( FT_Fixed )
PS_Conv_ToFixed( FT_Byte** cursor,
FT_Byte* limit,
FT_Int power_ten )
{
FT_Byte* p = *cursor;
FT_Fixed integral;
FT_Long decimal = 0, divider = 1;
FT_Bool sign = 0;
if ( p == limit )
return 0;
if ( *p == '-' || *p == '+' )
{
sign = ( *p == '-' );
p++;
if ( p == limit )
return 0;
}
if ( *p != '.' )
{
integral = PS_Conv_ToInt( &p, limit ) << 16;
if ( p == limit )
goto Exit;
}
else
integral = 0;
/* read the decimal part */
if ( *p == '.' )
{
p++;
for ( ; p < limit; p++ )
{
char c;
if ( IS_PS_SPACE( *p ) || *p OP 0x80 )
break;
c = ft_char_table[*p & 0x7f];
if ( c < 0 || c >= 10 )
break;
if ( divider < 10000000L )
{
decimal = decimal * 10 + c;
divider *= 10;
}
}
}
/* read exponent, if any */
if ( p + 1 < limit && ( *p == 'e' || *p == 'E' ) )
{
p++;
power_ten += PS_Conv_ToInt( &p, limit );
}
Exit:
while ( power_ten > 0 )
{
integral *= 10;
decimal *= 10;
power_ten--;
}
while ( power_ten < 0 )
{
integral /= 10;
divider *= 10;
power_ten++;
}
if ( decimal )
integral += FT_DivFix( decimal, divider );
if ( sign )
integral = -integral;
*cursor = p;
return integral;
}
#if 0
FT_LOCAL_DEF( FT_UInt )
PS_Conv_StringDecode( FT_Byte** cursor,
FT_Byte* limit,
FT_Byte* buffer,
FT_UInt n )
{
FT_Byte* p;
FT_UInt r = 0;
for ( p = *cursor; r < n && p < limit; p++ )
{
FT_Byte b;
if ( *p != '\\' )
{
buffer[r++] = *p;
continue;
}
p++;
switch ( *p )
{
case 'n':
b = '\n';
break;
case 'r':
b = '\r';
break;
case 't':
b = '\t';
break;
case 'b':
b = '\b';
break;
case 'f':
b = '\f';
break;
case '\r':
p++;
if ( *p != '\n' )
{
b = *p;
break;
}
/* no break */
case '\n':
continue;
break;
default:
if ( IS_PS_DIGIT( *p ) )
{
b = *p - '0';
p++;
if ( IS_PS_DIGIT( *p ) )
{
b = b * 8 + *p - '0';
p++;
if ( IS_PS_DIGIT( *p ) )
b = b * 8 + *p - '0';
else
{
buffer[r++] = b;
b = *p;
}
}
else
{
buffer[r++] = b;
b = *p;
}
}
else
b = *p;
break;
}
buffer[r++] = b;
}
*cursor = p;
return r;
}
#endif
FT_LOCAL_DEF( FT_UInt )
PS_Conv_ASCIIHexDecode( FT_Byte** cursor,
FT_Byte* limit,
FT_Byte* buffer,
FT_UInt n )
{
FT_Byte* p;
FT_UInt r = 0;
for ( p = *cursor; r < 2 * n && p < limit; p++ )
{
char c;
if ( IS_PS_SPACE( *p ) )
continue;
if ( *p OP 0x80 )
break;
c = ft_char_table[*p & 0x7f];
if ( c < 0 || c >= 16 )
break;
if ( r % 2 )
*buffer++ += c;
else
*buffer = c << 4;
r++;
}
*cursor = p;
return ( r + 1 ) / 2;
}
FT_LOCAL_DEF( FT_UInt )
PS_Conv_EexecDecode( FT_Byte** cursor,
FT_Byte* limit,
FT_Byte* buffer,
FT_UInt n,
FT_UShort* seed )
{
FT_Byte* p;
FT_UInt r;
for ( r = 0, p = *cursor; r < n && p < limit; r++, p++ )
{
FT_Byte b = ( *p ^ ( *seed >> 8 ) );
*seed = (FT_UShort)( ( *p + *seed ) * 52845U + 22719 );
*buffer++ = b;
}
*cursor = p;
return r;
}

106
src/psaux/psconv.h Normal file
View File

@ -0,0 +1,106 @@
/***************************************************************************/
/* */
/* psconv.h */
/* */
/* Some convenient conversions (specification). */
/* */
/* Copyright 2006 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. */
/* */
/***************************************************************************/
#ifndef __PSCONV_H__
#define __PSCONV_H__
#include <ft2build.h>
#include FT_INTERNAL_POSTSCRIPT_AUX_H
FT_BEGIN_HEADER
FT_LOCAL_DEF( FT_Int )
PS_Conv_Strtol( FT_Byte** cursor,
FT_Byte* limit,
FT_Int base );
FT_LOCAL( FT_Int )
PS_Conv_ToInt( FT_Byte** cursor,
FT_Byte* limit );
FT_LOCAL( FT_Fixed )
PS_Conv_ToFixed( FT_Byte** cursor,
FT_Byte* limit,
FT_Int power_ten );
#if 0
FT_LOCAL( FT_UInt )
PS_Conv_StringDecode( FT_Byte** cursor,
FT_Byte* limit,
FT_Byte* buffer,
FT_UInt n );
#endif
FT_LOCAL( FT_UInt )
PS_Conv_ASCIIHexDecode( FT_Byte** cursor,
FT_Byte* limit,
FT_Byte* buffer,
FT_UInt n );
FT_LOCAL( FT_UInt )
PS_Conv_EexecDecode( FT_Byte** cursor,
FT_Byte* limit,
FT_Byte* buffer,
FT_UInt n,
FT_UShort* seed );
#define IS_PS_NEWLINE( ch ) \
( ( ch ) == '\r' || \
( ch ) == '\n' )
#define IS_PS_SPACE( ch ) \
( ( ch ) == ' ' || \
IS_PS_NEWLINE( ch ) || \
( ch ) == '\t' || \
( ch ) == '\f' || \
( ch ) == '\0' )
#define IS_PS_SPECIAL( ch ) \
( ( ch ) == '/' || \
( ch ) == '(' || \
( ch ) == ')' || \
( ch ) == '<' || \
( ch ) == '>' || \
( ch ) == '[' || \
( ch ) == ']' || \
( ch ) == '{' || \
( ch ) == '}' || \
( ch ) == '%' )
#define IS_PS_DELIM( ch ) \
( IS_PS_SPACE( ch ) || \
IS_PS_SPECIAL( ch ) )
#define IS_PS_DIGIT( ch ) ( ( ch ) >= '0' && ( ch ) <= '9' )
#define IS_PS_XDIGIT( ch ) \
( IS_PS_DIGIT( ( ch ) ) || \
( ( ch ) >= 'A' && ( ch ) <= 'F' ) || \
( ( ch ) >= 'a' && ( ch ) <= 'f' ) )
#define IS_PS_BASE85( ch ) ( ( ch ) >= '!' && ( ch ) <= 'u' )
FT_END_HEADER
#endif /* __PSCONV_H__ */
/* END */

View File

@ -21,6 +21,7 @@
#include FT_INTERNAL_DEBUG_H
#include "psobjs.h"
#include "psconv.h"
#include "psauxerr.h"
@ -266,64 +267,6 @@
/*************************************************************************/
/*************************************************************************/
/* In the PostScript Language Reference Manual (PLRM) the following */
/* characters are called `whitespace characters'. */
#define IS_T1_WHITESPACE( c ) ( (c) == ' ' || (c) == '\t' )
#define IS_T1_LINESPACE( c ) ( (c) == '\r' || (c) == '\n' || (c) == '\f' )
#define IS_T1_NULLSPACE( c ) ( (c) == '\0' )
/* According to the PLRM all whitespace characters are equivalent, */
/* except in comments and strings. */
#define IS_T1_SPACE( c ) ( IS_T1_WHITESPACE( c ) || \
IS_T1_LINESPACE( c ) || \
IS_T1_NULLSPACE( c ) )
/* The following array is used by various functions to quickly convert */
/* digits (both decimal and non-decimal) into numbers. */
#if 'A' == 65
/* ASCII */
static const char ft_char_table[128] =
{
/* 0x00 */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
};
/* no character >= 0x80 can represent a valid number */
#define OP >=
#endif /* 'A' == 65 */
#if 'A' == 193
/* EBCDIC */
static const char ft_char_table[128] =
{
/* 0x80 */
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1,
-1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1,
-1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1,
-1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1,
-1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
}
/* no character < 0x80 can represent a valid number */
#define OP <
#endif /* 'A' == 193 */
/* first character must be already part of the comment */
@ -336,7 +279,7 @@
while ( cur < limit )
{
if ( IS_T1_LINESPACE( *cur ) )
if ( IS_PS_NEWLINE( *cur ) )
break;
cur++;
}
@ -354,7 +297,7 @@
while ( cur < limit )
{
if ( !IS_T1_SPACE( *cur ) )
if ( !IS_PS_SPACE( *cur ) )
{
if ( *cur == '%' )
/* According to the PLRM, a comment is equal to a space. */
@ -412,19 +355,12 @@
while ( ++cur < limit )
{
int d;
/* All whitespace characters are ignored. */
skip_spaces( &cur, limit );
if ( cur >= limit )
break;
if ( *cur OP 0x80 )
break;
d = ft_char_table[*cur & 0x7F];
if ( d < 0 || d >= 16 )
if ( !IS_PS_XDIGIT( *cur ) )
break;
}
@ -510,15 +446,6 @@
/* anything else */
while ( cur < limit )
{
if ( IS_T1_SPACE( *cur ) ||
*cur == '(' ||
*cur == '/' ||
*cur == '%' ||
*cur == '[' || *cur == ']' ||
*cur == '{' || *cur == '}' ||
*cur == '<' || *cur == '>' )
break;
if ( *cur == ')' )
{
FT_ERROR(( "ps_parser_skip_PS_token: "
@ -526,6 +453,8 @@
parser->error = PSaux_Err_Invalid_File_Format;
goto Exit;
}
else if ( IS_PS_DELIM( *cur ) )
break;
cur++;
}
@ -692,270 +621,6 @@
}
/* first character must be already part of the number */
static FT_Long
ps_radix( FT_Long radixBase,
FT_Byte* *acur,
FT_Byte* limit )
{
FT_Long result = 0;
FT_Byte* cur = *acur;
if ( radixBase < 2 || radixBase > 36 )
return 0;
while ( cur < limit )
{
int d;
if ( *cur OP 0x80 )
break;
d = ft_char_table[*cur & 0x7F];
if ( d < 0 || d >= radixBase )
break;
result = result * radixBase + d;
cur++;
}
*acur = cur;
return result;
}
/* first character must be already part of the number */
static FT_Long
ps_toint( FT_Byte* *acur,
FT_Byte* limit )
{
FT_Long result = 0;
FT_Byte* cur = *acur;
FT_Byte c;
if ( cur >= limit )
goto Exit;
c = *cur;
if ( c == '-' )
cur++;
while ( cur < limit )
{
int d;
if ( *cur == '#' )
{
cur++;
result = ps_radix( result, &cur, limit );
break;
}
if ( *cur OP 0x80 )
break;
d = ft_char_table[*cur & 0x7F];
if ( d < 0 || d >= 10 )
break;
result = result * 10 + d;
cur++;
};
if ( c == '-' )
result = -result;
Exit:
*acur = cur;
return result;
}
/* first character must be `<' if `delimiters' is non-zero */
static FT_Error
ps_tobytes( FT_Byte* *acur,
FT_Byte* limit,
FT_Long max_bytes,
FT_Byte* bytes,
FT_Long* pnum_bytes,
FT_Bool delimiters )
{
FT_Error error = PSaux_Err_Ok;
FT_Byte* cur = *acur;
FT_Long n = 0;
if ( cur >= limit )
goto Exit;
if ( delimiters )
{
if ( *cur != '<' )
{
FT_ERROR(( "ps_tobytes: Missing starting delimiter `<'\n" ));
error = PSaux_Err_Invalid_File_Format;
goto Exit;
}
cur++;
}
max_bytes = max_bytes * 2;
for ( n = 0; cur < limit; n++, cur++ )
{
int d;
if ( n >= max_bytes )
/* buffer is full */
goto Exit;
/* All whitespace characters are ignored. */
skip_spaces( &cur, limit );
if ( cur >= limit )
break;
if ( *cur OP 0x80 )
break;
d = ft_char_table[*cur & 0x7F];
if ( d < 0 || d >= 16 )
break;
/* <f> == <f0> != <0f> */
bytes[n / 2] = (FT_Byte)( ( n % 2 ) ? bytes[n / 2] + d
: d * 16 );
}
if ( delimiters )
{
if ( cur < limit && *cur != '>' )
{
FT_ERROR(( "ps_tobytes: Missing closing delimiter `>'\n" ));
error = PSaux_Err_Invalid_File_Format;
goto Exit;
}
cur++;
}
*acur = cur;
Exit:
*pnum_bytes = ( n + 1 ) / 2;
return error;
}
/* first character must be already part of the number */
static FT_Long
ps_tofixed( FT_Byte* *acur,
FT_Byte* limit,
FT_Long power_ten )
{
FT_Byte* cur = *acur;
FT_Long num, divider, result;
FT_Int sign = 0;
if ( cur >= limit )
return 0;
/* first of all, check the sign */
if ( *cur == '-' && cur + 1 < limit )
{
sign = 1;
cur++;
}
/* then, read the integer part, if any */
if ( *cur != '.' )
result = ps_toint( &cur, limit ) << 16;
else
result = 0;
num = 0;
divider = 1;
if ( cur >= limit )
goto Exit;
/* read decimal part, if any */
if ( *cur == '.' && cur + 1 < limit )
{
cur++;
for (;;)
{
int d;
if ( *cur OP 0x80 )
break;
d = ft_char_table[*cur & 0x7F];
if ( d < 0 || d >= 10 )
break;
if ( divider < 10000000L )
{
num = num * 10 + d;
divider *= 10;
}
cur++;
if ( cur >= limit )
break;
}
}
/* read exponent, if any */
if ( cur + 1 < limit && ( *cur == 'e' || *cur == 'E' ) )
{
cur++;
power_ten += ps_toint( &cur, limit );
}
Exit:
/* raise to power of ten if needed */
while ( power_ten > 0 )
{
result = result * 10;
num = num * 10;
power_ten--;
}
while ( power_ten < 0 )
{
result = result / 10;
divider = divider * 10;
power_ten++;
}
if ( num )
result += FT_DivFix( num, divider );
if ( sign )
result = -result;
*acur = cur;
return result;
}
/* first character must be a delimiter or a part of a number */
static FT_Int
@ -1003,7 +668,8 @@
break;
}
coords[count] = (FT_Short)( ps_tofixed( &cur, limit, 0 ) >> 16 );
coords[count] =
(FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 );
count++;
if ( !ender )
@ -1064,7 +730,7 @@
break;
}
values[count] = ps_tofixed( &cur, limit, power_ten );
values[count] = PS_Conv_ToFixed( &cur, limit, power_ten );
count++;
if ( !ender )
@ -1250,15 +916,15 @@
goto Store_Integer;
case T1_FIELD_TYPE_FIXED:
val = ps_tofixed( &cur, limit, 0 );
val = PS_Conv_ToFixed( &cur, limit, 0 );
goto Store_Integer;
case T1_FIELD_TYPE_FIXED_1000:
val = ps_tofixed( &cur, limit, 3 );
val = PS_Conv_ToFixed( &cur, limit, 3 );
goto Store_Integer;
case T1_FIELD_TYPE_INTEGER:
val = ps_toint( &cur, limit );
val = PS_Conv_ToInt( &cur, limit );
/* fall through */
Store_Integer:
@ -1424,10 +1090,12 @@
ps_parser_to_int( PS_Parser parser )
{
ps_parser_skip_spaces( parser );
return ps_toint( &parser->cursor, parser->limit );
return PS_Conv_ToInt( &parser->cursor, parser->limit );
}
/* first character must be `<' if `delimiters' is non-zero */
FT_LOCAL_DEF( FT_Error )
ps_parser_to_bytes( PS_Parser parser,
FT_Byte* bytes,
@ -1435,13 +1103,49 @@
FT_Long* pnum_bytes,
FT_Bool delimiters )
{
FT_Error error = PSaux_Err_Ok;
FT_Byte* cur;
ps_parser_skip_spaces( parser );
return ps_tobytes( &parser->cursor,
parser->limit,
max_bytes,
bytes,
pnum_bytes,
delimiters );
cur = parser->cursor;
if ( cur >= parser->limit )
goto Exit;
if ( delimiters )
{
if ( *cur != '<' )
{
FT_ERROR(( "ps_tobytes: Missing starting delimiter `<'\n" ));
error = PSaux_Err_Invalid_File_Format;
goto Exit;
}
cur++;
}
*pnum_bytes = PS_Conv_ASCIIHexDecode( &cur,
parser->limit,
bytes,
max_bytes );
if ( delimiters )
{
if ( cur < parser->limit && *cur != '>' )
{
FT_ERROR(( "ps_tobytes: Missing closing delimiter `>'\n" ));
error = PSaux_Err_Invalid_File_Format;
goto Exit;
}
cur++;
}
parser->cursor = cur;
Exit:
return error;
}
@ -1450,7 +1154,7 @@
FT_Int power_ten )
{
ps_parser_skip_spaces( parser );
return ps_tofixed( &parser->cursor, parser->limit, power_ten );
return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten );
}
@ -1780,16 +1484,11 @@
FT_Offset length,
FT_UShort seed )
{
while ( length > 0 )
{
FT_Byte plain;
plain = (FT_Byte)( *buffer ^ ( seed >> 8 ) );
seed = (FT_UShort)( ( *buffer + seed ) * 52845U + 22719 );
*buffer++ = plain;
length--;
}
PS_Conv_EexecDecode( &buffer,
buffer + length,
buffer,
length,
&seed );
}

View File

@ -28,6 +28,8 @@ PSAUX_COMPILE := $(FT_COMPILE) $I$(subst /,$(COMPILER_SEP),$(PSAUX_DIR))
PSAUX_DRV_SRC := $(PSAUX_DIR)/psobjs.c \
$(PSAUX_DIR)/t1decode.c \
$(PSAUX_DIR)/t1cmap.c \
$(PSAUX_DIR)/afmparse.c \
$(PSAUX_DIR)/psconv.c \
$(PSAUX_DIR)/psauxmod.c
# PSAUX driver headers

146
src/tools/test_afm.c Normal file
View File

@ -0,0 +1,146 @@
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_INTERNAL_STREAM_H
#include FT_INTERNAL_POSTSCRIPT_AUX_H
void dump_fontinfo( AFM_FontInfo fi )
{
FT_Int i;
printf( "This AFM is for %sCID font.\n\n",
( fi->IsCIDFont ) ? "" : "non-" );
if ( fi->NumTrackKern )
printf( "There are %d sets of track kernings:\n",
fi->NumTrackKern );
else
printf( "There is no track kerning.\n" );
for ( i = 0; i < fi->NumTrackKern; i++ )
{
AFM_TrackKern tk = fi->TrackKerns + i;
printf( "\t%2d: %5.2f %5.2f %5.2f %5.2f\n", tk->degree,
tk->min_ptsize / 65536.,
tk->min_kern / 65536.,
tk->max_ptsize / 65536.,
tk->max_kern / 65536. );
}
printf( "\n" );
if ( fi->NumTrackKern )
printf( "There are %d kerning pairs:\n",
fi->NumKernPair );
else
printf( "There is no kerning pair.\n" );
for ( i = 0; i < fi->NumKernPair; i++ )
{
AFM_KernPair kp = fi->KernPairs + i;
printf( "\t%3d + %3d => (%4d, %4d)\n", kp->index1,
kp->index2,
kp->x,
kp->y );
}
}
int
dummy_get_index( const char* name,
FT_UInt len,
void* user_data )
{
if ( len )
return name[0];
else
return 0;
}
FT_Error
parse_afm( FT_Library library,
FT_Stream stream,
AFM_FontInfo fi )
{
PSAux_Service psaux;
AFM_ParserRec parser;
FT_Error error = FT_Err_Ok;
psaux = (PSAux_Service)FT_Get_Module_Interface( library, "psaux" );
if ( !psaux || !psaux->afm_parser_funcs )
return -1;
error = FT_Stream_EnterFrame( stream, stream->size );
if ( error )
return error;
error = psaux->afm_parser_funcs->init( &parser,
library->memory,
stream->cursor,
stream->limit );
if ( error )
return error;
parser.FontInfo = fi;
parser.get_index = dummy_get_index;
error = psaux->afm_parser_funcs->parse( &parser );
psaux->afm_parser_funcs->done( &parser );
return error;
}
int main( int argc,
char** argv )
{
FT_Library library;
FT_StreamRec stream;
FT_Error error = FT_Err_Ok;
AFM_FontInfoRec fi;
if ( argc < 2 )
return FT_Err_Invalid_Argument;
error = FT_Init_FreeType( &library );
if ( error )
return error;
FT_ZERO( &stream );
error = FT_Stream_Open( &stream, argv[1] );
if ( error )
goto Exit;
stream.memory = library->memory;
FT_ZERO( &fi );
error = parse_afm( library, &stream, &fi );
if ( !error )
{
FT_Memory memory = library->memory;
dump_fontinfo( &fi );
if ( fi.KernPairs )
FT_FREE( fi.KernPairs );
if ( fi.TrackKerns )
FT_FREE( fi.TrackKerns );
}
else
printf( "parse error\n" );
FT_Stream_Close( &stream );
Exit:
FT_Done_FreeType( library );
return error;
}

View File

@ -34,102 +34,41 @@
FT_LOCAL_DEF( void )
T1_Done_Metrics( FT_Memory memory,
T1_AFM* afm )
T1_Done_Metrics( FT_Memory memory,
AFM_FontInfo fi )
{
FT_FREE( afm->kern_pairs );
afm->num_pairs = 0;
FT_FREE( afm );
FT_FREE( fi->KernPairs );
fi->NumKernPair = 0;
FT_FREE( fi->TrackKerns );
fi->NumTrackKern = 0;
FT_FREE( fi );
}
#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 */
static FT_UInt
afm_atoindex( FT_Byte** start,
FT_Byte* limit,
T1_Font type1 )
static FT_Int
t1_get_index( const char* name,
FT_UInt len,
void* user_data )
{
FT_Byte* p = *start;
FT_PtrDist len;
FT_UInt result = 0;
char temp[64];
T1_Font type1 = (T1_Font)user_data;
FT_Int n;
/* skip whitespace */
while ( p < limit &&
( *p == ' ' || *p == '\t' || *p == ':' || *p == ';' ) )
p++;
*start = p;
/* now, read glyph name */
while ( p < limit && IS_ALPHANUM( *p ) )
p++;
len = p - *start;
if ( len > 0 && len < 64 )
for ( n = 0; n < type1->num_glyphs; n++ )
{
FT_Int n;
char* gname = (char*)type1->glyph_names[n];
/* copy glyph name to intermediate array */
FT_MEM_COPY( temp, *start, len );
temp[len] = 0;
/* lookup glyph name in face array */
for ( n = 0; n < type1->num_glyphs; n++ )
{
char* gname = (char*)type1->glyph_names[n];
if ( gname && gname[0] == temp[0] && ft_strcmp( gname, temp ) == 0 )
{
result = n;
break;
}
}
}
*start = p;
return result;
}
/* read an integer */
static int
afm_atoi( FT_Byte** start,
FT_Byte* limit )
{
FT_Byte* p = *start;
int sum = 0;
int sign = 1;
/* skip everything that is not a number */
while ( p < limit && !isdigit( *p ) )
{
sign = 1;
if ( *p == '-' )
sign = -1;
p++;
if ( gname && gname[0] == name[0] &&
ft_strlen( gname ) == len &&
ft_strncmp( gname, name, len ) == 0 )
return n;
}
while ( p < limit && isdigit( *p ) )
{
sum = sum * 10 + ( *p - '0' );
p++;
}
*start = p;
return sum * sign;
return 0;
}
@ -142,121 +81,29 @@
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;
AFM_KernPair pair1 = (AFM_KernPair)a;
AFM_KernPair pair2 = (AFM_KernPair)b;
FT_ULong index1 = KERN_INDEX( pair1->glyph1, pair1->glyph2 );
FT_ULong index2 = KERN_INDEX( pair2->glyph1, pair2->glyph2 );
FT_ULong index1 = KERN_INDEX( pair1->index1, pair1->index2 );
FT_ULong index2 = KERN_INDEX( pair2->index1, pair2->index2 );
return (int)( index1 - index2 );
}
/* parse an AFM file -- for now, only read the kerning pairs */
static FT_Error
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;
start = (FT_Byte*)stream->cursor;
limit = (FT_Byte*)stream->limit;
p = start;
/* 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;
/* allocate the pairs */
if ( FT_NEW( afm ) || FT_NEW_ARRAY( afm->kern_pairs, count ) )
goto Exit;
/* now, read each kern pair */
pair = afm->kern_pairs;
afm->num_pairs = count;
/* 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;
/* skip keyword (KP or KPX) */
q = p + 2;
if ( *q == 'X' )
q++;
pair->glyph1 = afm_atoindex( &q, limit, type1 );
pair->glyph2 = afm_atoindex( &q, limit, type1 );
pair->kerning.x = afm_atoi( &q, limit );
pair->kerning.y = 0;
if ( p[2] != 'X' )
pair->kerning.y = afm_atoi( &q, limit );
pair++;
}
}
/* now, sort the kern pairs according to their glyph indices */
ft_qsort( afm->kern_pairs, count, sizeof ( T1_Kern_Pair ),
compare_kern_pairs );
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 )
T1_Read_PFM( FT_Face t1_face,
FT_Stream stream,
AFM_FontInfo fi )
{
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;
AFM_KernPair kp;
FT_Int width_table_length;
FT_CharMap oldcharmap;
FT_CharMap charmap;
@ -275,16 +122,16 @@
error = T1_Err_Unknown_File_Format;
goto Exit;
}
width_table_length = LITTLE_ENDIAN_USHORT( p );
width_table_length = FT_PEEK_USHORT_LE( p );
p += 18 + width_table_length;
if ( p + 0x12 > limit || LITTLE_ENDIAN_USHORT( p ) < 0x12 )
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 + LITTLE_ENDIAN_UINT( p );
p = start + FT_PEEK_ULONG_LE( p );
if ( p == start )
/* zero offset means no table */
@ -296,31 +143,25 @@
goto Exit;
}
kern_count = LITTLE_ENDIAN_USHORT( p );
fi->NumKernPair = FT_PEEK_USHORT_LE( p );
p += 2;
if ( p + 4 * kern_count > limit )
if ( p + 4 * fi->NumKernPair > limit )
{
error = T1_Err_Unknown_File_Format;
goto Exit;
}
/* Actually, kerning pairs are simply optional! */
if ( kern_count == 0 )
if ( fi->NumKernPair == 0 )
goto Exit;
/* allocate the pairs */
if ( FT_NEW( afm ) || FT_NEW_ARRAY( afm->kern_pairs, kern_count ) )
if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
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;
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 */
@ -347,15 +188,15 @@
/* encoding of first glyph (1 byte) */
/* encoding of second glyph (1 byte) */
/* offset (little-endian short) */
for ( ; p < limit ; p+=4 )
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] );
kp->index1 = FT_Get_Char_Index( t1_face, p[0] );
kp->index2 = FT_Get_Char_Index( t1_face, p[1] );
pair->kerning.x = (FT_Short)LITTLE_ENDIAN_USHORT(p + 2);
pair->kerning.y = 0;
kp->x = (FT_Int)FT_PEEK_USHORT_LE(p + 2);
kp->y = 0;
pair++;
kp++;
}
if ( oldcharmap != NULL )
@ -364,12 +205,15 @@
goto Exit;
/* now, sort the kern pairs according to their glyph indices */
ft_qsort( afm->kern_pairs, kern_count, sizeof ( T1_Kern_Pair ),
ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ),
compare_kern_pairs );
Exit:
if ( error )
FT_FREE( afm );
{
FT_FREE( fi->KernPairs );
fi->NumKernPair = 0;
}
return error;
}
@ -381,27 +225,55 @@
T1_Read_Metrics( FT_Face t1_face,
FT_Stream stream )
{
FT_Error error;
FT_Byte* start;
PSAux_Service psaux;
FT_Memory memory = stream->memory;
AFM_ParserRec parser;
AFM_FontInfo fi;
FT_Error error = T1_Err_Unknown_File_Format;
if ( FT_FRAME_ENTER( stream->size ) )
return error;
start = (FT_Byte*)stream->cursor;
FT_NEW( fi );
if ( error )
return error;
if ( stream->size >= ft_strlen( "StartFontMetrics" ) &&
ft_strncmp( (const char*)start, "StartFontMetrics",
ft_strlen( "StartFontMetrics" ) ) == 0 )
error = T1_Read_AFM( t1_face, stream );
psaux = (PSAux_Service)( (T1_Face)t1_face )->psaux;
if ( psaux && psaux->afm_parser_funcs )
{
error = psaux->afm_parser_funcs->init( &parser,
stream->memory,
stream->cursor,
stream->limit );
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 );
if ( !error )
{
parser.FontInfo = fi;
parser.get_index = t1_get_index;
parser.user_data = &( (T1_Face)t1_face )->type1;
else
error = T1_Err_Unknown_File_Format;
error = psaux->afm_parser_funcs->parse( &parser );
psaux->afm_parser_funcs->done( &parser );
}
}
if ( error == T1_Err_Unknown_File_Format )
{
FT_Byte* start = stream->cursor;
if ( stream->size > 6 &&
start[0] == 0x00 && start[1] == 0x01 &&
FT_PEEK_ULONG_LE( start + 2 ) == stream->size )
error = T1_Read_PFM( t1_face, stream, fi );
}
if ( !error && fi->NumKernPair )
{
t1_face->face_flags |= FT_FACE_FLAG_KERNING;
( (T1_Face)t1_face )->afm_data = fi;
}
FT_FRAME_EXIT();
@ -411,18 +283,18 @@
/* find the kerning for a given glyph pair */
FT_LOCAL_DEF( void )
T1_Get_Kerning( T1_AFM* afm,
FT_UInt glyph1,
FT_UInt glyph2,
FT_Vector* kerning )
T1_Get_Kerning( AFM_FontInfo fi,
FT_UInt glyph1,
FT_UInt glyph2,
FT_Vector* kerning )
{
T1_Kern_Pair *min, *mid, *max;
AFM_KernPair min, mid, max;
FT_ULong idx = KERN_INDEX( glyph1, glyph2 );
/* simple binary search */
min = afm->kern_pairs;
max = min + afm->num_pairs - 1;
min = fi->KernPairs;
max = min + fi->NumKernPair - 1;
while ( min <= max )
{
@ -430,11 +302,13 @@
mid = min + ( max - min ) / 2;
midi = KERN_INDEX( mid->glyph1, mid->glyph2 );
midi = KERN_INDEX( mid->index1, mid->index2 );
if ( midi == idx )
{
*kerning = mid->kerning;
kerning->x = mid->x;
kerning->y = mid->y;
return;
}
@ -449,4 +323,42 @@
}
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_Int i;
if ( !fi )
return T1_Err_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 T1_Err_Ok;
}
/* END */

View File

@ -26,37 +26,25 @@
FT_BEGIN_HEADER
typedef struct T1_Kern_Pair_
{
FT_UInt glyph1;
FT_UInt glyph2;
FT_Vector kerning;
} T1_Kern_Pair;
typedef struct T1_AFM_
{
FT_Int num_pairs;
T1_Kern_Pair* kern_pairs;
} T1_AFM;
FT_LOCAL( FT_Error )
T1_Read_Metrics( FT_Face face,
FT_Stream stream );
FT_LOCAL( void )
T1_Done_Metrics( FT_Memory memory,
T1_AFM* afm );
T1_Done_Metrics( FT_Memory memory,
AFM_FontInfo fi );
FT_LOCAL( void )
T1_Get_Kerning( T1_AFM* afm,
FT_UInt glyph1,
FT_UInt glyph2,
FT_Vector* kerning );
T1_Get_Kerning( AFM_FontInfo fi,
FT_UInt glyph1,
FT_UInt glyph2,
FT_Vector* kerning );
FT_LOCAL( FT_Error )
T1_Get_Track_Kerning( FT_Face face,
FT_Fixed ptsize,
FT_Int degree,
FT_Fixed* kerning );
FT_END_HEADER

View File

@ -36,6 +36,7 @@
#include FT_SERVICE_POSTSCRIPT_NAME_H
#include FT_SERVICE_POSTSCRIPT_CMAPS_H
#include FT_SERVICE_POSTSCRIPT_INFO_H
#include FT_SERVICE_KERNING_H
/*************************************************************************/
/* */
@ -176,6 +177,10 @@
(PS_GetFontPrivateFunc)t1_ps_get_font_private,
};
static const FT_Service_KerningRec t1_service_kerning =
{
T1_Get_Track_Kerning,
};
/*
* SERVICE LIST
@ -188,6 +193,7 @@
{ FT_SERVICE_ID_GLYPH_DICT, &t1_service_glyph_dict },
{ FT_SERVICE_ID_XF86_NAME, FT_XF86_FORMAT_TYPE_1 },
{ FT_SERVICE_ID_POSTSCRIPT_INFO, &t1_service_ps_info },
{ FT_SERVICE_ID_KERNING, &t1_service_kerning },
#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
{ FT_SERVICE_ID_MULTI_MASTERS, &t1_service_multi_masters },
@ -246,15 +252,14 @@
FT_UInt right_glyph,
FT_Vector* kerning )
{
T1_AFM* afm;
kerning->x = 0;
kerning->y = 0;
afm = (T1_AFM*)face->afm_data;
if ( afm )
T1_Get_Kerning( afm, left_glyph, right_glyph, kerning );
if ( face->afm_data )
T1_Get_Kerning( (AFM_FontInfo)face->afm_data,
left_glyph,
right_glyph,
kerning );
return T1_Err_Ok;
}

View File

@ -233,7 +233,7 @@
#ifndef T1_CONFIG_OPTION_NO_AFM
/* release afm data if present */
if ( face->afm_data )
T1_Done_Metrics( memory, (T1_AFM*)face->afm_data );
T1_Done_Metrics( memory, (AFM_FontInfo)face->afm_data );
#endif
/* release unicode map, if any */