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'.david-pic-changes
parent
ea1e8d3a53
commit
108fdbbbd3
19 changed files with 2133 additions and 621 deletions
@ -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 */ |
@ -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; |
||||
} |
@ -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 */ |
@ -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; |
||||
} |
@ -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 */ |
@ -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; |
||||
} |
Loading…
Reference in new issue