ref: 108fdbbbd3ab7ea18b512762abd01ab4a051ca34
parent: ea1e8d3a53e29d5ba00fff0ca2c468bf4e16e9af
author: Wu, Chia-I (吳佳一) <[email protected]>
date: Mon Jan 16 10:35:56 EST 2006
* 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'.
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,33 @@
+2006-01-16 Chia-I Wu <[email protected]>
+
+ * 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 <[email protected]>
* include/freetype/internal/ftobjs.h, src/base/ftobjs.c,
--- a/include/freetype/freetype.h
+++ b/include/freetype/freetype.h
@@ -192,6 +192,7 @@
/* FT_Render_Mode */
/* FT_Get_Kerning */
/* FT_Kerning_Mode */
+ /* FT_Get_Track_Kerning */
/* FT_Get_Glyph_Name */
/* FT_Get_Postscript_Name */
/* */
@@ -2709,6 +2710,34 @@
FT_UInt right_glyph,
FT_UInt kern_mode,
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 );
/*************************************************************************/
--- a/include/freetype/internal/ftserv.h
+++ b/include/freetype/internal/ftserv.h
@@ -313,6 +313,7 @@
#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>
/* */
--- a/include/freetype/internal/psaux.h
+++ b/include/freetype/internal/psaux.h
@@ -688,6 +688,96 @@
/*************************************************************************/
/*************************************************************************/
/***** *****/
+ /***** 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;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
/***** TYPE1 CHARMAPS *****/
/***** *****/
/*************************************************************************/
@@ -720,6 +810,7 @@
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,
--- /dev/null
+++ b/include/freetype/internal/services/svkern.h
@@ -1,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 */
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -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 )
@@ -2371,6 +2372,40 @@
}
}
}
+
+ return error;
+ }
+
+
+ /* 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;
}
--- /dev/null
+++ b/src/psaux/afmparse.c
@@ -1,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;
+ }
--- /dev/null
+++ b/src/psaux/afmparse.h
@@ -1,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 */
--- a/src/psaux/psaux.c
+++ b/src/psaux/psaux.c
@@ -23,6 +23,8 @@
#include "psauxmod.c"
#include "t1decode.c"
#include "t1cmap.c"
+#include "afmparse.c"
+#include "psconv.c"
/* END */
--- a/src/psaux/psauxmod.c
+++ b/src/psaux/psauxmod.c
@@ -21,6 +21,7 @@
#include "psobjs.h"
#include "t1decode.h"
#include "t1cmap.h"
+#include "afmparse.h"
FT_CALLBACK_TABLE_DEF
@@ -76,6 +77,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 =
{
&t1_cmap_standard_class_rec,
@@ -92,6 +102,7 @@
&ps_parser_funcs,
&t1_builder_funcs,
&t1_decoder_funcs,
+ &afm_parser_funcs,
t1_decrypt,
--- /dev/null
+++ b/src/psaux/psconv.c
@@ -1,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;
+ }
--- /dev/null
+++ b/src/psaux/psconv.h
@@ -1,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 */
--- a/src/psaux/psobjs.c
+++ b/src/psaux/psobjs.c
@@ -21,6 +21,7 @@
#include FT_INTERNAL_DEBUG_H
#include "psobjs.h"
+#include "psconv.h"
#include "psauxerr.h"
@@ -266,65 +267,7 @@
/*************************************************************************/
/*************************************************************************/
- /* 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 */
static void
@@ -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,20 +355,13 @@
while ( ++cur < limit )
{
- int d;
-
-
/* All whitespace characters are ignored. */
skip_spaces( &cur, limit );
if ( cur >= limit )
break;
- if ( *cur OP 0x80 )
+ if ( !IS_PS_XDIGIT( *cur ) )
break;
-
- d = ft_char_table[*cur & 0x7F];
- if ( d < 0 || d >= 16 )
- break;
}
if ( cur < limit && *cur != '>' )
@@ -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 );
}
--- a/src/psaux/rules.mk
+++ b/src/psaux/rules.mk
@@ -28,6 +28,8 @@
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
--- /dev/null
+++ b/src/tools/test_afm.c
@@ -1,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;
+ }
--- a/src/type1/t1afm.c
+++ b/src/type1/t1afm.c
@@ -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;
-#undef IS_KERN_PAIR
-#define IS_KERN_PAIR( p ) ( p[0] == 'K' && p[1] == 'P' )
+ FT_FREE( fi );
+ }
-#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;
- }
- }
+ if ( gname && gname[0] == name[0] &&
+ ft_strlen( gname ) == len &&
+ ft_strncmp( gname, name, len ) == 0 )
+ return n;
}
- *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++;
- }
-
- while ( p < limit && isdigit( *p ) )
- {
- sum = sum * 10 + ( *p - '0' );
- p++;
- }
- *start = p;
-
- return sum * sign;
+ return 0;
}
@@ -142,11 +81,11 @@
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 );
@@ -153,101 +92,11 @@
}
- /* 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;
@@ -254,9 +103,7 @@
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,9 +143,9 @@
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;
@@ -305,22 +152,16 @@
}
/* 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,28 +225,56 @@
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();
return error;
@@ -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;
}
@@ -446,6 +320,44 @@
kerning->x = 0;
kerning->y = 0;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ T1_Get_Track_Kerning( FT_Face face,
+ FT_Fixed ptsize,
+ FT_Int degree,
+ FT_Fixed* kerning )
+ {
+ AFM_FontInfo fi = (AFM_FontInfo)( (T1_Face)face )->afm_data;
+ FT_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;
}
--- a/src/type1/t1afm.h
+++ b/src/type1/t1afm.h
@@ -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
--- a/src/type1/t1driver.c
+++ b/src/type1/t1driver.c
@@ -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;
}
--- a/src/type1/t1objs.c
+++ b/src/type1/t1objs.c
@@ -233,7 +233,7 @@
#ifndef T1_CONFIG_OPTION_NO_AFM
/* release afm data if present */
if ( face->afm_data )
- T1_Done_Metrics( memory, (T1_AFM*)face->afm_data );
+ T1_Done_Metrics( memory, (AFM_FontInfo)face->afm_data );
#endif
/* release unicode map, if any */