* src/psaux/afmparse.c, src/psaux/afmparse.h: New files which
implement an AFM parser. It is used to parse an AFM file. * src/psaux/psconv.c, src/psaux/psconv.h: New files to provide conversion functions (e.g, PS real number => FT_Fixed) for the PS_Parser and AFM_Parser. Some of the functions are taken, with some modifications, from the psobjs.c * src/psaux/psobjs.c: Use functions from psconv.c. * include/freetype/internal/psaux.h, src/psaux/psauxmod.c:: Add `AFM_Parser' to the `psaux' service. * src/psaux/psaux.c, src/psaux/rules.mk: Include those new files. * src/tools/test_afm.c: A test program for AFM parser. * include/freetype/internal/services/svkern.h, include/freetype/internal/ftserv.h: New service `Kerning'. It is currently only used to get the track kerning information. * src/type1/t1driver.c, src/type1/t1objs.c, src/type1/t1afm.c, src/type1/t1afm.h: Update to use the AFM parser. Provide the `Kerning' service. * include/freetype/freetype.h, src/base/ftobjs.c: New API `FT_Get_Track_Kerning'.
This commit is contained in:
parent
ea1e8d3a53
commit
108fdbbbd3
30
ChangeLog
30
ChangeLog
@ -1,3 +1,33 @@
|
||||
2006-01-16 Chia-I Wu <b90201047@ntu.edu.tw>
|
||||
|
||||
* src/psaux/afmparse.c, src/psaux/afmparse.h: New files which
|
||||
implement an AFM parser. It is used to parse an AFM file.
|
||||
|
||||
* src/psaux/psconv.c, src/psaux/psconv.h: New files to provide
|
||||
conversion functions (e.g, PS real number => FT_Fixed) for the
|
||||
PS_Parser and AFM_Parser. Some of the functions are taken, with some
|
||||
modifications, from the psobjs.c
|
||||
|
||||
* src/psaux/psobjs.c: Use functions from psconv.c.
|
||||
|
||||
* include/freetype/internal/psaux.h, src/psaux/psauxmod.c:: Add
|
||||
`AFM_Parser' to the `psaux' service.
|
||||
|
||||
* src/psaux/psaux.c, src/psaux/rules.mk: Include those new files.
|
||||
|
||||
* src/tools/test_afm.c: A test program for AFM parser.
|
||||
|
||||
* include/freetype/internal/services/svkern.h,
|
||||
include/freetype/internal/ftserv.h: New service `Kerning'. It is
|
||||
currently only used to get the track kerning information.
|
||||
|
||||
* src/type1/t1driver.c, src/type1/t1objs.c, src/type1/t1afm.c,
|
||||
src/type1/t1afm.h: Update to use the AFM parser.
|
||||
Provide the `Kerning' service.
|
||||
|
||||
* include/freetype/freetype.h, src/base/ftobjs.c: New API
|
||||
`FT_Get_Track_Kerning'.
|
||||
|
||||
2006-01-15 Chia-I Wu <b90201047@ntu.edu.tw>
|
||||
|
||||
* include/freetype/internal/ftobjs.h, src/base/ftobjs.c,
|
||||
|
@ -192,6 +192,7 @@ FT_BEGIN_HEADER
|
||||
/* FT_Render_Mode */
|
||||
/* FT_Get_Kerning */
|
||||
/* FT_Kerning_Mode */
|
||||
/* FT_Get_Track_Kerning */
|
||||
/* FT_Get_Glyph_Name */
|
||||
/* FT_Get_Postscript_Name */
|
||||
/* */
|
||||
@ -2711,6 +2712,34 @@ FT_BEGIN_HEADER
|
||||
FT_Vector *akerning );
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Function> */
|
||||
/* FT_Get_Track_Kerning */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* Return the track kerning for a given face object at a given size. */
|
||||
/* */
|
||||
/* <Input> */
|
||||
/* face :: A handle to a source face object. */
|
||||
/* */
|
||||
/* point_size :: The point size in 16.16 fractional points. */
|
||||
/* */
|
||||
/* degree :: The degree of tightness. */
|
||||
/* */
|
||||
/* <Output> */
|
||||
/* akerning :: The kerning in in 16.16 fractional points. */
|
||||
/* */
|
||||
/* <Return> */
|
||||
/* FreeType error code. 0 means success. */
|
||||
/* */
|
||||
FT_EXPORT( FT_Error )
|
||||
FT_Get_Track_Kerning( FT_Face face,
|
||||
FT_Fixed point_size,
|
||||
FT_Int degree,
|
||||
FT_Fixed* akerning );
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Function> */
|
||||
|
@ -313,6 +313,7 @@ FT_BEGIN_HEADER
|
||||
#define FT_SERVICE_TT_CMAP_H <freetype/internal/services/svttcmap.h>
|
||||
#define FT_SERVICE_WINFNT_H <freetype/internal/services/svwinfnt.h>
|
||||
#define FT_SERVICE_XFREE86_NAME_H <freetype/internal/services/svxf86nm.h>
|
||||
#define FT_SERVICE_KERNING_H <freetype/internal/services/svkern.h>
|
||||
|
||||
/* */
|
||||
|
||||
|
@ -685,6 +685,96 @@ FT_BEGIN_HEADER
|
||||
} T1_DecoderRec;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
/***** AFM PARSER *****/
|
||||
/***** *****/
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
typedef struct AFM_ParserRec_* AFM_Parser;
|
||||
|
||||
typedef struct AFM_TrackKernRec_
|
||||
{
|
||||
FT_Int degree;
|
||||
FT_Fixed min_ptsize;
|
||||
FT_Fixed min_kern;
|
||||
FT_Fixed max_ptsize;
|
||||
FT_Fixed max_kern;
|
||||
} AFM_TrackKernRec, *AFM_TrackKern;
|
||||
|
||||
typedef struct AFM_KernPairRec_
|
||||
{
|
||||
FT_Int index1;
|
||||
FT_Int index2;
|
||||
FT_Int x;
|
||||
FT_Int y;
|
||||
} AFM_KernPairRec, *AFM_KernPair;
|
||||
|
||||
typedef struct AFM_FontInfoRec_
|
||||
{
|
||||
FT_Bool IsCIDFont;
|
||||
AFM_TrackKern TrackKerns; /* free if non-NULL */
|
||||
FT_Int NumTrackKern;
|
||||
AFM_KernPair KernPairs; /* free if non-NULL */
|
||||
FT_Int NumKernPair;
|
||||
} AFM_FontInfoRec, *AFM_FontInfo;
|
||||
|
||||
typedef struct AFM_Parser_FuncsRec_
|
||||
{
|
||||
FT_Error
|
||||
(*init)( AFM_Parser parser,
|
||||
FT_Memory memory,
|
||||
FT_Byte* base,
|
||||
FT_Byte* limit );
|
||||
|
||||
void
|
||||
(*done)( AFM_Parser parser );
|
||||
|
||||
FT_Error
|
||||
(*parse)( AFM_Parser parser );
|
||||
|
||||
} AFM_Parser_FuncsRec;
|
||||
|
||||
typedef struct AFM_StreamRec_* AFM_Stream;
|
||||
|
||||
/*************************************************************************/
|
||||
/* */
|
||||
/* <Struct> */
|
||||
/* AFM_ParserRec */
|
||||
/* */
|
||||
/* <Description> */
|
||||
/* An AFM_Parser is a parser for the AFM files. */
|
||||
/* */
|
||||
/* <Fields> */
|
||||
/* memory :: The object used for memory operations */
|
||||
/* (alloc/realloc). */
|
||||
/* */
|
||||
/* stream :: This is an opaque object. */
|
||||
/* */
|
||||
/* FontInfo :: The result will be stored here. */
|
||||
/* */
|
||||
/* get_index :: An user provided function to get glyph index by its */
|
||||
/* name. */
|
||||
/* */
|
||||
typedef struct AFM_ParserRec_
|
||||
{
|
||||
FT_Memory memory;
|
||||
AFM_Stream stream;
|
||||
|
||||
AFM_FontInfo FontInfo;
|
||||
|
||||
FT_Int
|
||||
(*get_index)( const char* name,
|
||||
FT_UInt len,
|
||||
void* user_data );
|
||||
|
||||
void* user_data;
|
||||
|
||||
} AFM_ParserRec;
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
/***** *****/
|
||||
@ -720,6 +810,7 @@ FT_BEGIN_HEADER
|
||||
const PS_Parser_FuncsRec* ps_parser_funcs;
|
||||
const T1_Builder_FuncsRec* t1_builder_funcs;
|
||||
const T1_Decoder_FuncsRec* t1_decoder_funcs;
|
||||
const AFM_Parser_FuncsRec* afm_parser_funcs;
|
||||
|
||||
void
|
||||
(*t1_decrypt)( FT_Byte* buffer,
|
||||
|
51
include/freetype/internal/services/svkern.h
Normal file
51
include/freetype/internal/services/svkern.h
Normal file
@ -0,0 +1,51 @@
|
||||
/***************************************************************************/
|
||||
/* */
|
||||
/* svkern.h */
|
||||
/* */
|
||||
/* The FreeType Kerning service (specification). */
|
||||
/* */
|
||||
/* Copyright 2003, 2004 by */
|
||||
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
|
||||
/* */
|
||||
/* This file is part of the FreeType project, and may only be used, */
|
||||
/* modified, and distributed under the terms of the FreeType project */
|
||||
/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
|
||||
/* this file you indicate that you have read the license and */
|
||||
/* understand and accept it fully. */
|
||||
/* */
|
||||
/***************************************************************************/
|
||||
|
||||
|
||||
#ifndef __SVKERN_H__
|
||||
#define __SVKERN_H__
|
||||
|
||||
#include FT_INTERNAL_SERVICE_H
|
||||
#include FT_TRUETYPE_TABLES_H
|
||||
|
||||
|
||||
FT_BEGIN_HEADER
|
||||
|
||||
#define FT_SERVICE_ID_KERNING "kerning"
|
||||
|
||||
|
||||
typedef FT_Error
|
||||
(*FT_Kerning_TrackGetFunc)( FT_Face face,
|
||||
FT_Fixed point_size,
|
||||
FT_Int degree,
|
||||
FT_Fixed* akerning );
|
||||
|
||||
FT_DEFINE_SERVICE( Kerning )
|
||||
{
|
||||
FT_Kerning_TrackGetFunc get_track;
|
||||
};
|
||||
|
||||
/* */
|
||||
|
||||
|
||||
FT_END_HEADER
|
||||
|
||||
|
||||
#endif /* __SVKERN_H__ */
|
||||
|
||||
|
||||
/* END */
|
@ -33,6 +33,7 @@
|
||||
#include FT_SERVICE_POSTSCRIPT_NAME_H
|
||||
#include FT_SERVICE_GLYPH_DICT_H
|
||||
#include FT_SERVICE_TT_CMAP_H
|
||||
#include FT_SERVICE_KERNING_H
|
||||
|
||||
|
||||
FT_BASE_DEF( FT_Pointer )
|
||||
@ -2376,6 +2377,40 @@
|
||||
}
|
||||
|
||||
|
||||
/* documentation is in freetype.h */
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
FT_Get_Track_Kerning( FT_Face face,
|
||||
FT_Fixed point_size,
|
||||
FT_Int degree,
|
||||
FT_Fixed* akerning )
|
||||
{
|
||||
FT_Service_Kerning service;
|
||||
FT_Error error = FT_Err_Ok;
|
||||
FT_Driver driver;
|
||||
|
||||
|
||||
if ( !face )
|
||||
return FT_Err_Invalid_Face_Handle;
|
||||
|
||||
if ( !akerning )
|
||||
return FT_Err_Invalid_Argument;
|
||||
|
||||
driver = face->driver;
|
||||
|
||||
FT_FACE_FIND_SERVICE( face, service, KERNING );
|
||||
if ( !service )
|
||||
return FT_Err_Unimplemented_Feature;
|
||||
|
||||
error = service->get_track( face,
|
||||
point_size,
|
||||
degree,
|
||||
akerning );
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/* documentation is in freetype.h */
|
||||
|
||||
FT_EXPORT_DEF( FT_Error )
|
||||
|
925
src/psaux/afmparse.c
Normal file
925
src/psaux/afmparse.c
Normal file
@ -0,0 +1,925 @@
|
||||
/***************************************************************************/
|
||||
/* */
|
||||
/* afmparse.c */
|
||||
/* */
|
||||
/* AFM parser (body). */
|
||||
/* */
|
||||
/* Copyright 2006 by */
|
||||
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
|
||||
/* */
|
||||
/* This file is part of the FreeType project, and may only be used, */
|
||||
/* modified, and distributed under the terms of the FreeType project */
|
||||
/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
|
||||
/* this file you indicate that you have read the license and */
|
||||
/* understand and accept it fully. */
|
||||
/* */
|
||||
/***************************************************************************/
|
||||
|
||||
#include FT_INTERNAL_POSTSCRIPT_AUX_H
|
||||
#include FT_INTERNAL_DEBUG_H
|
||||
|
||||
#include "afmparse.h"
|
||||
#include "psconv.h"
|
||||
|
||||
#include "psauxerr.h"
|
||||
|
||||
/***************************************************************************/
|
||||
/* */
|
||||
/* AFM_Stream */
|
||||
/* */
|
||||
/* The use of AFM_Stream is largely inspired by parseAFM.[ch] from t1lib. */
|
||||
/* */
|
||||
/* */
|
||||
|
||||
enum
|
||||
{
|
||||
AFM_STREAM_STATUS_NORMAL,
|
||||
AFM_STREAM_STATUS_EOC,
|
||||
AFM_STREAM_STATUS_EOL,
|
||||
AFM_STREAM_STATUS_EOF
|
||||
};
|
||||
|
||||
|
||||
typedef struct AFM_StreamRec_
|
||||
{
|
||||
FT_Byte* cursor;
|
||||
FT_Byte* base;
|
||||
FT_Byte* limit;
|
||||
|
||||
FT_Int status;
|
||||
|
||||
} AFM_StreamRec;
|
||||
|
||||
|
||||
#ifndef EOF
|
||||
#define EOF -1
|
||||
#endif
|
||||
|
||||
/* this works because empty lines are ignored */
|
||||
#define AFM_IS_NEWLINE( ch ) ( ( ch ) == '\r' || ( ch ) == '\n' )
|
||||
|
||||
#define AFM_IS_EOF( ch ) ( ( ch ) == EOF || ( ch ) == '\x1a' )
|
||||
#define AFM_IS_SPACE( ch ) ( ( ch ) == ' ' || ( ch ) == '\t' )
|
||||
|
||||
/* column separator; there is no `column' in the spec actually */
|
||||
#define AFM_IS_SEP( ch ) ( ( ch ) == ';' )
|
||||
|
||||
#define AFM_GETC() \
|
||||
( ( ( stream )->cursor < ( stream )->limit ) \
|
||||
? *( stream )->cursor++ \
|
||||
: EOF )
|
||||
|
||||
#define AFM_STREAM_KEY_BEGIN( stream ) \
|
||||
(char*)( ( stream )->cursor - 1 )
|
||||
|
||||
#define AFM_STREAM_KEY_LEN( stream, key ) \
|
||||
( (char*)( stream )->cursor - key - 1 )
|
||||
|
||||
#define AFM_STATUS_EOC( stream ) \
|
||||
( ( stream )->status >= AFM_STREAM_STATUS_EOC )
|
||||
|
||||
#define AFM_STATUS_EOL( stream ) \
|
||||
( ( stream )->status >= AFM_STREAM_STATUS_EOL )
|
||||
|
||||
#define AFM_STATUS_EOF( stream ) \
|
||||
( ( stream )->status >= AFM_STREAM_STATUS_EOF )
|
||||
|
||||
static int
|
||||
afm_stream_skip_spaces( AFM_Stream stream )
|
||||
{
|
||||
int ch;
|
||||
|
||||
|
||||
if ( AFM_STATUS_EOC( stream ) )
|
||||
return ';';
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
ch = AFM_GETC();
|
||||
if ( !AFM_IS_SPACE( ch ) )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( AFM_IS_NEWLINE( ch ) )
|
||||
stream->status = AFM_STREAM_STATUS_EOL;
|
||||
else if ( AFM_IS_SEP( ch ) )
|
||||
stream->status = AFM_STREAM_STATUS_EOC;
|
||||
else if ( AFM_IS_EOF( ch ) )
|
||||
stream->status = AFM_STREAM_STATUS_EOF;
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
|
||||
/* read a key or val in current column */
|
||||
static char*
|
||||
afm_stream_read_one( AFM_Stream stream )
|
||||
{
|
||||
char* str;
|
||||
int ch;
|
||||
|
||||
|
||||
afm_stream_skip_spaces( stream );
|
||||
if ( AFM_STATUS_EOC( stream ) )
|
||||
return NULL;
|
||||
|
||||
str = AFM_STREAM_KEY_BEGIN( stream );
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
ch = AFM_GETC();
|
||||
if ( AFM_IS_SPACE( ch ) )
|
||||
break;
|
||||
else if ( AFM_IS_NEWLINE( ch ) )
|
||||
{
|
||||
stream->status = AFM_STREAM_STATUS_EOL;
|
||||
|
||||
break;
|
||||
}
|
||||
else if ( AFM_IS_SEP( ch ) )
|
||||
{
|
||||
stream->status = AFM_STREAM_STATUS_EOC;
|
||||
|
||||
break;
|
||||
}
|
||||
else if ( AFM_IS_EOF( ch ) )
|
||||
{
|
||||
stream->status = AFM_STREAM_STATUS_EOF;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/* read a string (i.e., read to EOL) */
|
||||
static char*
|
||||
afm_stream_read_string( AFM_Stream stream )
|
||||
{
|
||||
char* str;
|
||||
int ch;
|
||||
|
||||
|
||||
afm_stream_skip_spaces( stream );
|
||||
if ( AFM_STATUS_EOL( stream ) )
|
||||
return NULL;
|
||||
|
||||
str = AFM_STREAM_KEY_BEGIN( stream );
|
||||
|
||||
/* scan to eol */
|
||||
while ( 1 )
|
||||
{
|
||||
ch = AFM_GETC();
|
||||
if ( AFM_IS_NEWLINE( ch ) )
|
||||
{
|
||||
stream->status = AFM_STREAM_STATUS_EOL;
|
||||
|
||||
break;
|
||||
}
|
||||
else if ( AFM_IS_EOF( ch ) )
|
||||
{
|
||||
stream->status = AFM_STREAM_STATUS_EOF;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
/* */
|
||||
/* AFM_Parser */
|
||||
/* */
|
||||
/* */
|
||||
|
||||
/* all keys defined in Ch. 7-10 of 5004.AFM_Spec.pdf */
|
||||
typedef enum
|
||||
{
|
||||
AFM_TOKEN_ASCENDER,
|
||||
AFM_TOKEN_AXISLABEL,
|
||||
AFM_TOKEN_AXISTYPE,
|
||||
AFM_TOKEN_B,
|
||||
AFM_TOKEN_BLENDAXISTYPES,
|
||||
AFM_TOKEN_BLENDDESIGNMAP,
|
||||
AFM_TOKEN_BLENDDESIGNPOSITIONS,
|
||||
AFM_TOKEN_C,
|
||||
AFM_TOKEN_CC,
|
||||
AFM_TOKEN_CH,
|
||||
AFM_TOKEN_CAPHEIGHT,
|
||||
AFM_TOKEN_CHARWIDTH,
|
||||
AFM_TOKEN_CHARACTERSET,
|
||||
AFM_TOKEN_CHARACTERS,
|
||||
AFM_TOKEN_DESCENDER,
|
||||
AFM_TOKEN_ENCODINGSCHEME,
|
||||
AFM_TOKEN_ENDAXIS,
|
||||
AFM_TOKEN_ENDCHARMETRICS,
|
||||
AFM_TOKEN_ENDCOMPOSITES,
|
||||
AFM_TOKEN_ENDDIRECTION,
|
||||
AFM_TOKEN_ENDFONTMETRICS,
|
||||
AFM_TOKEN_ENDKERNDATA,
|
||||
AFM_TOKEN_ENDKERNPAIRS,
|
||||
AFM_TOKEN_ENDTRACKKERN,
|
||||
AFM_TOKEN_ESCCHAR,
|
||||
AFM_TOKEN_FAMILYNAME,
|
||||
AFM_TOKEN_FONTBBOX,
|
||||
AFM_TOKEN_FONTNAME,
|
||||
AFM_TOKEN_FULLNAME,
|
||||
AFM_TOKEN_ISBASEFONT,
|
||||
AFM_TOKEN_ISCIDFONT,
|
||||
AFM_TOKEN_ISFIXEDPITCH,
|
||||
AFM_TOKEN_ISFIXEDV,
|
||||
AFM_TOKEN_ITALICANGLE,
|
||||
AFM_TOKEN_KP,
|
||||
AFM_TOKEN_KPH,
|
||||
AFM_TOKEN_KPX,
|
||||
AFM_TOKEN_KPY,
|
||||
AFM_TOKEN_L,
|
||||
AFM_TOKEN_MAPPINGSCHEME,
|
||||
AFM_TOKEN_METRICSSETS,
|
||||
AFM_TOKEN_N,
|
||||
AFM_TOKEN_NOTICE,
|
||||
AFM_TOKEN_PCC,
|
||||
AFM_TOKEN_STARTAXIS,
|
||||
AFM_TOKEN_STARTCHARMETRICS,
|
||||
AFM_TOKEN_STARTCOMPOSITES,
|
||||
AFM_TOKEN_STARTDIRECTION,
|
||||
AFM_TOKEN_STARTFONTMETRICS,
|
||||
AFM_TOKEN_STARTKERNDATA,
|
||||
AFM_TOKEN_STARTKERNPAIRS,
|
||||
AFM_TOKEN_STARTKERNPAIRS0,
|
||||
AFM_TOKEN_STARTKERNPAIRS1,
|
||||
AFM_TOKEN_STARTTRACKKERN,
|
||||
AFM_TOKEN_STDHW,
|
||||
AFM_TOKEN_STDVW,
|
||||
AFM_TOKEN_TRACKKERN,
|
||||
AFM_TOKEN_UNDERLINEPOSITION,
|
||||
AFM_TOKEN_UNDERLINETHICKNESS,
|
||||
AFM_TOKEN_VV,
|
||||
AFM_TOKEN_VVECTOR,
|
||||
AFM_TOKEN_VERSION,
|
||||
AFM_TOKEN_W,
|
||||
AFM_TOKEN_W0,
|
||||
AFM_TOKEN_W0X,
|
||||
AFM_TOKEN_W0Y,
|
||||
AFM_TOKEN_W1,
|
||||
AFM_TOKEN_W1X,
|
||||
AFM_TOKEN_W1Y,
|
||||
AFM_TOKEN_WX,
|
||||
AFM_TOKEN_WY,
|
||||
AFM_TOKEN_WEIGHT,
|
||||
AFM_TOKEN_WEIGHTVECTOR,
|
||||
AFM_TOKEN_XHEIGHT,
|
||||
N_AFM_TOKENS,
|
||||
AFM_TOKEN_UNKNOWN
|
||||
} AFM_Token;
|
||||
|
||||
|
||||
static const char* afm_key_table[N_AFM_TOKENS] =
|
||||
{
|
||||
"Ascender",
|
||||
"AxisLabel",
|
||||
"AxisType",
|
||||
"B",
|
||||
"BlendAxisTypes",
|
||||
"BlendDesignMap",
|
||||
"BlendDesignPositions",
|
||||
"C",
|
||||
"CC",
|
||||
"CH",
|
||||
"CapHeight",
|
||||
"CharWidth",
|
||||
"CharacterSet",
|
||||
"Characters",
|
||||
"Descender",
|
||||
"EncodingScheme",
|
||||
"EndAxis",
|
||||
"EndCharMetrics",
|
||||
"EndComposites",
|
||||
"EndDirection",
|
||||
"EndFontMetrics",
|
||||
"EndKernData",
|
||||
"EndKernPairs",
|
||||
"EndTrackKern",
|
||||
"EscChar",
|
||||
"FamilyName",
|
||||
"FontBBox",
|
||||
"FontName",
|
||||
"FullName",
|
||||
"IsBaseFont",
|
||||
"IsCIDFont",
|
||||
"IsFixedPitch",
|
||||
"IsFixedV",
|
||||
"ItalicAngle",
|
||||
"KP",
|
||||
"KPH",
|
||||
"KPX",
|
||||
"KPY",
|
||||
"L",
|
||||
"MappingScheme",
|
||||
"MetricsSets",
|
||||
"N",
|
||||
"Notice",
|
||||
"PCC",
|
||||
"StartAxis",
|
||||
"StartCharMetrics",
|
||||
"StartComposites",
|
||||
"StartDirection",
|
||||
"StartFontMetrics",
|
||||
"StartKernData",
|
||||
"StartKernPairs",
|
||||
"StartKernPairs0",
|
||||
"StartKernPairs1",
|
||||
"StartTrackKern",
|
||||
"StdHW",
|
||||
"StdVW",
|
||||
"TrackKern",
|
||||
"UnderlinePosition",
|
||||
"UnderlineThickness",
|
||||
"VV",
|
||||
"VVector",
|
||||
"Version",
|
||||
"W",
|
||||
"W0",
|
||||
"W0X",
|
||||
"W0Y",
|
||||
"W1",
|
||||
"W1X",
|
||||
"W1Y",
|
||||
"WX",
|
||||
"WY",
|
||||
"Weight",
|
||||
"WeightVector",
|
||||
"XHeight"
|
||||
};
|
||||
|
||||
|
||||
#define AFM_MAX_ARGUMENTS 5
|
||||
|
||||
static AFM_ValueRec shared_vals[AFM_MAX_ARGUMENTS];
|
||||
|
||||
|
||||
/*
|
||||
* `afm_parser_read_vals' and `afm_parser_next_key' provides
|
||||
* high-level operations to an AFM_Stream. The rest of the
|
||||
* parser functions should use them and should not access
|
||||
* the AFM_Stream directly.
|
||||
*/
|
||||
|
||||
FT_LOCAL_DEF( FT_Int )
|
||||
afm_parser_read_vals( AFM_Parser parser,
|
||||
AFM_Value vals,
|
||||
FT_Int n )
|
||||
{
|
||||
AFM_Stream stream = parser->stream;
|
||||
char* str;
|
||||
FT_Int i;
|
||||
|
||||
|
||||
if ( n > AFM_MAX_ARGUMENTS )
|
||||
return 0;
|
||||
|
||||
for ( i = 0; i < n; i++ )
|
||||
{
|
||||
FT_UInt len;
|
||||
|
||||
|
||||
if ( vals[i].type == AFM_VALUE_TYPE_STRING )
|
||||
str = afm_stream_read_string( stream );
|
||||
else
|
||||
str = afm_stream_read_one( stream );
|
||||
|
||||
if ( !str )
|
||||
break;
|
||||
|
||||
len = AFM_STREAM_KEY_LEN( stream, str );
|
||||
|
||||
switch ( vals[i].type )
|
||||
{
|
||||
case AFM_VALUE_TYPE_STRING:
|
||||
case AFM_VALUE_TYPE_NAME:
|
||||
if ( !FT_QAlloc( parser->memory, len + 1, (void**)&vals[i].u.s ) )
|
||||
{
|
||||
ft_memcpy( vals[i].u.s, str, len );
|
||||
vals[i].u.s[len] = '\0';
|
||||
}
|
||||
break;
|
||||
case AFM_VALUE_TYPE_FIXED:
|
||||
vals[i].u.f = PS_Conv_ToFixed( (FT_Byte**)&str,
|
||||
(FT_Byte*)str + len,
|
||||
0 );
|
||||
break;
|
||||
case AFM_VALUE_TYPE_INTEGER:
|
||||
vals[i].u.i = PS_Conv_ToInt( (FT_Byte**)&str,
|
||||
(FT_Byte*)str + len );
|
||||
break;
|
||||
case AFM_VALUE_TYPE_BOOL:
|
||||
vals[i].u.b = ( len == 4 &&
|
||||
ft_strncmp( str, "true", 4 ) == 0 );
|
||||
break;
|
||||
case AFM_VALUE_TYPE_INDEX:
|
||||
if ( parser->get_index )
|
||||
vals[i].u.i = parser->get_index( str,
|
||||
len,
|
||||
parser->user_data );
|
||||
else
|
||||
vals[i].u.i = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
FT_LOCAL_DEF( char* )
|
||||
afm_parser_next_key( AFM_Parser parser,
|
||||
FT_Bool line,
|
||||
FT_UInt* len )
|
||||
{
|
||||
AFM_Stream stream = parser->stream;
|
||||
char* key;
|
||||
|
||||
|
||||
if ( line )
|
||||
{
|
||||
while ( 1 )
|
||||
{
|
||||
/* skip current line */
|
||||
if ( !AFM_STATUS_EOL( stream ) )
|
||||
afm_stream_read_string( stream );
|
||||
|
||||
stream->status = AFM_STREAM_STATUS_NORMAL;
|
||||
key = afm_stream_read_one( stream );
|
||||
|
||||
/* skip empty line */
|
||||
if ( !key &&
|
||||
!AFM_STATUS_EOF( stream ) &&
|
||||
AFM_STATUS_EOL( stream ) )
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while ( 1 )
|
||||
{
|
||||
/* skip current column */
|
||||
while ( !AFM_STATUS_EOC( stream ) )
|
||||
afm_stream_read_one( stream );
|
||||
|
||||
stream->status = AFM_STREAM_STATUS_NORMAL;
|
||||
key = afm_stream_read_one( stream );
|
||||
|
||||
/* skip empty column */
|
||||
if ( !key &&
|
||||
!AFM_STATUS_EOF( stream ) &&
|
||||
AFM_STATUS_EOC( stream ) )
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( len )
|
||||
*len = ( key ) ? AFM_STREAM_KEY_LEN( stream, key )
|
||||
: 0;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
static AFM_Token
|
||||
afm_tokenize( const char* key,
|
||||
FT_UInt len )
|
||||
{
|
||||
int n;
|
||||
|
||||
|
||||
for ( n = 0; n < N_AFM_TOKENS; n++ )
|
||||
{
|
||||
if ( *( afm_key_table[n] ) == *key )
|
||||
{
|
||||
for ( ; n < N_AFM_TOKENS; n++ )
|
||||
{
|
||||
if ( *( afm_key_table[n] ) != *key )
|
||||
return AFM_TOKEN_UNKNOWN;
|
||||
|
||||
if ( ft_strncmp( afm_key_table[n], key, len ) == 0 )
|
||||
return n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AFM_TOKEN_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
FT_LOCAL_DEF( FT_Error )
|
||||
afm_parser_init( AFM_Parser parser,
|
||||
FT_Memory memory,
|
||||
FT_Byte* base,
|
||||
FT_Byte* limit )
|
||||
{
|
||||
AFM_Stream stream;
|
||||
FT_Error error;
|
||||
|
||||
|
||||
if ( FT_NEW( stream ) )
|
||||
return error;
|
||||
|
||||
stream->cursor = stream->base = base;
|
||||
stream->limit = limit;
|
||||
|
||||
/* so that the first call won't skip the first line */
|
||||
stream->status = AFM_STREAM_STATUS_EOL;
|
||||
|
||||
parser->memory = memory;
|
||||
parser->stream = stream;
|
||||
parser->FontInfo = NULL;
|
||||
parser->get_index = NULL;
|
||||
|
||||
return PSaux_Err_Ok;
|
||||
}
|
||||
|
||||
|
||||
FT_LOCAL( void )
|
||||
afm_parser_done( AFM_Parser parser )
|
||||
{
|
||||
FT_Memory memory = parser->memory;
|
||||
|
||||
|
||||
FT_FREE( parser->stream );
|
||||
}
|
||||
|
||||
|
||||
FT_LOCAL_DEF( FT_Error )
|
||||
afm_parser_read_int( AFM_Parser parser,
|
||||
FT_Int* aint )
|
||||
{
|
||||
AFM_ValueRec val;
|
||||
|
||||
|
||||
val.type = AFM_VALUE_TYPE_INTEGER;
|
||||
|
||||
if ( afm_parser_read_vals( parser, &val, 1 ) == 1 )
|
||||
{
|
||||
*aint = val.u.i;
|
||||
|
||||
return PSaux_Err_Ok;
|
||||
}
|
||||
else
|
||||
return PSaux_Err_Syntax_Error;
|
||||
}
|
||||
|
||||
|
||||
static FT_Error
|
||||
afm_parse_track_kern( AFM_Parser parser )
|
||||
{
|
||||
AFM_FontInfo fi = parser->FontInfo;
|
||||
AFM_TrackKern tk;
|
||||
char* key;
|
||||
FT_UInt len;
|
||||
int n = -1;
|
||||
|
||||
|
||||
if ( afm_parser_read_int( parser, &fi->NumTrackKern ) )
|
||||
goto Fail;
|
||||
|
||||
if ( fi->NumTrackKern )
|
||||
{
|
||||
FT_Memory memory = parser->memory;
|
||||
FT_Error error;
|
||||
|
||||
|
||||
FT_QNEW_ARRAY( fi->TrackKerns, fi->NumTrackKern );
|
||||
if ( error )
|
||||
return error;
|
||||
}
|
||||
|
||||
while ( ( key = afm_parser_next_key( parser, 1, &len ) ) )
|
||||
{
|
||||
switch ( afm_tokenize( key, len ) )
|
||||
{
|
||||
case AFM_TOKEN_TRACKKERN:
|
||||
n++;
|
||||
|
||||
if ( n >= fi->NumTrackKern )
|
||||
goto Fail;
|
||||
|
||||
tk = fi->TrackKerns + n;
|
||||
|
||||
shared_vals[0].type = AFM_VALUE_TYPE_INTEGER;
|
||||
shared_vals[1].type = AFM_VALUE_TYPE_FIXED;
|
||||
shared_vals[2].type = AFM_VALUE_TYPE_FIXED;
|
||||
shared_vals[3].type = AFM_VALUE_TYPE_FIXED;
|
||||
shared_vals[4].type = AFM_VALUE_TYPE_FIXED;
|
||||
if ( afm_parser_read_vals( parser, shared_vals, 5 ) != 5 )
|
||||
goto Fail;
|
||||
|
||||
tk->degree = shared_vals[0].u.i;
|
||||
tk->min_ptsize = shared_vals[1].u.f;
|
||||
tk->min_kern = shared_vals[2].u.f;
|
||||
tk->max_ptsize = shared_vals[3].u.f;
|
||||
tk->max_kern = shared_vals[4].u.f;
|
||||
|
||||
/* is this correct? */
|
||||
if ( tk->degree < 0 && tk->min_kern > 0 )
|
||||
tk->min_kern = -tk->min_kern;
|
||||
break;
|
||||
|
||||
case AFM_TOKEN_ENDTRACKKERN:
|
||||
case AFM_TOKEN_ENDKERNDATA:
|
||||
case AFM_TOKEN_ENDFONTMETRICS:
|
||||
fi->NumTrackKern = n + 1;
|
||||
return PSaux_Err_Ok;
|
||||
break;
|
||||
|
||||
case AFM_TOKEN_UNKNOWN:
|
||||
break;
|
||||
|
||||
default:
|
||||
goto Fail;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Fail:
|
||||
return PSaux_Err_Syntax_Error;
|
||||
}
|
||||
|
||||
|
||||
#undef KERN_INDEX
|
||||
#define KERN_INDEX( g1, g2 ) ( ( (FT_ULong)g1 << 16 ) | g2 )
|
||||
|
||||
/* compare two kerning pairs */
|
||||
FT_CALLBACK_DEF( int )
|
||||
afm_compare_kern_pairs( const void* a,
|
||||
const void* b )
|
||||
{
|
||||
AFM_KernPair kp1 = (AFM_KernPair)a;
|
||||
AFM_KernPair kp2 = (AFM_KernPair)b;
|
||||
|
||||
FT_ULong index1 = KERN_INDEX( kp1->index1, kp1->index2 );
|
||||
FT_ULong index2 = KERN_INDEX( kp2->index1, kp2->index2 );
|
||||
|
||||
|
||||
return (int)( index1 - index2 );
|
||||
}
|
||||
|
||||
|
||||
static FT_Error
|
||||
afm_parse_kern_pairs( AFM_Parser parser )
|
||||
{
|
||||
AFM_FontInfo fi = parser->FontInfo;
|
||||
AFM_KernPair kp;
|
||||
char* key;
|
||||
FT_UInt len;
|
||||
int n = -1;
|
||||
|
||||
|
||||
if ( afm_parser_read_int( parser, &fi->NumKernPair ) )
|
||||
goto Fail;
|
||||
|
||||
if ( fi->NumKernPair )
|
||||
{
|
||||
FT_Memory memory = parser->memory;
|
||||
FT_Error error;
|
||||
|
||||
|
||||
FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair );
|
||||
if ( error )
|
||||
return error;
|
||||
}
|
||||
|
||||
while ( ( key = afm_parser_next_key( parser, 1, &len ) ) )
|
||||
{
|
||||
AFM_Token token = afm_tokenize( key, len );
|
||||
|
||||
|
||||
switch ( token )
|
||||
{
|
||||
case AFM_TOKEN_KP:
|
||||
case AFM_TOKEN_KPX:
|
||||
case AFM_TOKEN_KPY:
|
||||
{
|
||||
FT_Int r;
|
||||
|
||||
|
||||
n++;
|
||||
|
||||
if ( n >= fi->NumKernPair )
|
||||
goto Fail;
|
||||
|
||||
kp = fi->KernPairs + n;
|
||||
|
||||
shared_vals[0].type = AFM_VALUE_TYPE_INDEX;
|
||||
shared_vals[1].type = AFM_VALUE_TYPE_INDEX;
|
||||
shared_vals[2].type = AFM_VALUE_TYPE_INTEGER;
|
||||
shared_vals[3].type = AFM_VALUE_TYPE_INTEGER;
|
||||
r = afm_parser_read_vals( parser, shared_vals, 4 );
|
||||
if ( r < 3 )
|
||||
goto Fail;
|
||||
|
||||
kp->index1 = shared_vals[0].u.i;
|
||||
kp->index2 = shared_vals[1].u.i;
|
||||
if ( token == AFM_TOKEN_KPY )
|
||||
{
|
||||
kp->x = 0;
|
||||
kp->y = shared_vals[2].u.i;
|
||||
}
|
||||
else
|
||||
{
|
||||
kp->x = shared_vals[2].u.i;
|
||||
kp->y = ( token == AFM_TOKEN_KP && r == 4 )
|
||||
? shared_vals[3].u.i : 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AFM_TOKEN_ENDKERNPAIRS:
|
||||
case AFM_TOKEN_ENDKERNDATA:
|
||||
case AFM_TOKEN_ENDFONTMETRICS:
|
||||
fi->NumKernPair = n + 1;
|
||||
ft_qsort( fi->KernPairs, fi->NumKernPair,
|
||||
sizeof( AFM_KernPairRec ),
|
||||
afm_compare_kern_pairs );
|
||||
return PSaux_Err_Ok;
|
||||
break;
|
||||
|
||||
case AFM_TOKEN_UNKNOWN:
|
||||
break;
|
||||
|
||||
default:
|
||||
goto Fail;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Fail:
|
||||
return PSaux_Err_Syntax_Error;
|
||||
}
|
||||
|
||||
|
||||
static FT_Error
|
||||
afm_parse_kern_data( AFM_Parser parser )
|
||||
{
|
||||
FT_Error error;
|
||||
char* key;
|
||||
FT_UInt len;
|
||||
|
||||
|
||||
while ( ( key = afm_parser_next_key( parser, 1, &len ) ) )
|
||||
{
|
||||
switch ( afm_tokenize( key, len ) )
|
||||
{
|
||||
case AFM_TOKEN_STARTTRACKKERN:
|
||||
error = afm_parse_track_kern( parser );
|
||||
if ( error )
|
||||
return error;
|
||||
break;
|
||||
|
||||
case AFM_TOKEN_STARTKERNPAIRS:
|
||||
case AFM_TOKEN_STARTKERNPAIRS0:
|
||||
error = afm_parse_kern_pairs( parser );
|
||||
if ( error )
|
||||
return error;
|
||||
break;
|
||||
|
||||
case AFM_TOKEN_ENDKERNDATA:
|
||||
case AFM_TOKEN_ENDFONTMETRICS:
|
||||
return PSaux_Err_Ok;
|
||||
break;
|
||||
|
||||
case AFM_TOKEN_UNKNOWN:
|
||||
break;
|
||||
|
||||
default:
|
||||
goto Fail;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Fail:
|
||||
return PSaux_Err_Syntax_Error;
|
||||
}
|
||||
|
||||
|
||||
static FT_Error
|
||||
afm_parser_skip_section( AFM_Parser parser,
|
||||
FT_UInt n,
|
||||
AFM_Token end_section )
|
||||
{
|
||||
char* key;
|
||||
FT_UInt len;
|
||||
|
||||
|
||||
while ( n-- > 0 )
|
||||
{
|
||||
key = afm_parser_next_key( parser, 1, NULL );
|
||||
if ( !key )
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
while ( ( key = afm_parser_next_key( parser, 1, &len ) ) )
|
||||
{
|
||||
AFM_Token token = afm_tokenize( key, len );
|
||||
|
||||
|
||||
if ( token == end_section || token == AFM_TOKEN_ENDFONTMETRICS )
|
||||
return PSaux_Err_Ok;
|
||||
}
|
||||
|
||||
Fail:
|
||||
return PSaux_Err_Syntax_Error;
|
||||
}
|
||||
|
||||
|
||||
FT_LOCAL_DEF( FT_Error )
|
||||
afm_parser_parse( AFM_Parser parser )
|
||||
{
|
||||
FT_Memory memory = parser->memory;
|
||||
AFM_FontInfo fi = parser->FontInfo;
|
||||
FT_Error error = PSaux_Err_Syntax_Error;
|
||||
char* key;
|
||||
FT_UInt len;
|
||||
FT_Int metrics_sets = 0;
|
||||
|
||||
|
||||
if ( !fi )
|
||||
return PSaux_Err_Invalid_Argument;
|
||||
|
||||
key = afm_parser_next_key( parser, 1, &len );
|
||||
if ( !key || len != 16 ||
|
||||
ft_strncmp( key, "StartFontMetrics", 16 ) != 0 )
|
||||
return PSaux_Err_Unknown_File_Format;
|
||||
|
||||
while ( ( key = afm_parser_next_key( parser, 1, &len ) ) )
|
||||
{
|
||||
switch ( afm_tokenize( key, len ) )
|
||||
{
|
||||
case AFM_TOKEN_METRICSSETS:
|
||||
if ( afm_parser_read_int( parser, &metrics_sets ) )
|
||||
goto Fail;
|
||||
|
||||
if ( metrics_sets != 0 && metrics_sets != 2 )
|
||||
{
|
||||
error = PSaux_Err_Unimplemented_Feature;
|
||||
|
||||
goto Fail;
|
||||
}
|
||||
break;
|
||||
|
||||
case AFM_TOKEN_ISCIDFONT:
|
||||
shared_vals[0].type = AFM_VALUE_TYPE_BOOL;
|
||||
if ( afm_parser_read_vals( parser, shared_vals, 1 ) != 1 )
|
||||
goto Fail;
|
||||
|
||||
fi->IsCIDFont = shared_vals[0].u.b;
|
||||
break;
|
||||
|
||||
case AFM_TOKEN_STARTCHARMETRICS:
|
||||
{
|
||||
FT_Int n;
|
||||
|
||||
|
||||
if ( afm_parser_read_int( parser, &n ) )
|
||||
goto Fail;
|
||||
|
||||
error = afm_parser_skip_section( parser, n,
|
||||
AFM_TOKEN_ENDCHARMETRICS );
|
||||
if ( error )
|
||||
return error;
|
||||
}
|
||||
break;
|
||||
|
||||
case AFM_TOKEN_STARTKERNDATA:
|
||||
error = afm_parse_kern_data( parser );
|
||||
if ( error )
|
||||
goto Fail;
|
||||
/* no break since we only support kern data */
|
||||
|
||||
case AFM_TOKEN_ENDFONTMETRICS:
|
||||
return PSaux_Err_Ok;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Fail:
|
||||
FT_FREE( fi->TrackKerns );
|
||||
fi->NumTrackKern = 0;
|
||||
|
||||
FT_FREE( fi->KernPairs );
|
||||
fi->NumKernPair = 0;
|
||||
|
||||
fi->IsCIDFont = 0;
|
||||
|
||||
return error;
|
||||
}
|
85
src/psaux/afmparse.h
Normal file
85
src/psaux/afmparse.h
Normal file
@ -0,0 +1,85 @@
|
||||
/***************************************************************************/
|
||||
/* */
|
||||
/* afmparse.h */
|
||||
/* */
|
||||
/* AFM parser (specification). */
|
||||
/* */
|
||||
/* Copyright 2006 by */
|
||||
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
|
||||
/* */
|
||||
/* This file is part of the FreeType project, and may only be used, */
|
||||
/* modified, and distributed under the terms of the FreeType project */
|
||||
/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
|
||||
/* this file you indicate that you have read the license and */
|
||||
/* understand and accept it fully. */
|
||||
/* */
|
||||
/***************************************************************************/
|
||||
|
||||
|
||||
#ifndef __AFMPARSE_H__
|
||||
#define __AFMPARSE_H__
|
||||
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_INTERNAL_POSTSCRIPT_AUX_H
|
||||
|
||||
|
||||
FT_BEGIN_HEADER
|
||||
|
||||
|
||||
FT_LOCAL( FT_Error )
|
||||
afm_parser_init( AFM_Parser parser,
|
||||
FT_Memory memory,
|
||||
FT_Byte* base,
|
||||
FT_Byte* limit );
|
||||
|
||||
|
||||
FT_LOCAL( void )
|
||||
afm_parser_done( AFM_Parser parser );
|
||||
|
||||
|
||||
FT_LOCAL( FT_Error )
|
||||
afm_parser_parse( AFM_Parser parser );
|
||||
|
||||
|
||||
enum AFM_ValueType_
|
||||
{
|
||||
AFM_VALUE_TYPE_STRING,
|
||||
AFM_VALUE_TYPE_NAME,
|
||||
AFM_VALUE_TYPE_FIXED, /* real number */
|
||||
AFM_VALUE_TYPE_INTEGER,
|
||||
AFM_VALUE_TYPE_BOOL,
|
||||
AFM_VALUE_TYPE_INDEX /* glyph index */
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
enum AFM_ValueType_ type;
|
||||
union {
|
||||
char* s;
|
||||
FT_Fixed f;
|
||||
FT_Int i;
|
||||
FT_Bool b;
|
||||
} u;
|
||||
} AFM_ValueRec, *AFM_Value;
|
||||
|
||||
|
||||
FT_LOCAL( FT_Int )
|
||||
afm_parser_read_vals( AFM_Parser parser,
|
||||
AFM_Value vals,
|
||||
FT_Int n );
|
||||
|
||||
|
||||
/* read the next key from the next line or column */
|
||||
FT_LOCAL( char* )
|
||||
afm_parser_next_key( AFM_Parser parser,
|
||||
FT_Bool line,
|
||||
FT_UInt* len );
|
||||
|
||||
FT_END_HEADER
|
||||
|
||||
#endif /* __AFMPARSE_H__ */
|
||||
|
||||
|
||||
/* END */
|
@ -23,6 +23,8 @@
|
||||
#include "psauxmod.c"
|
||||
#include "t1decode.c"
|
||||
#include "t1cmap.c"
|
||||
#include "afmparse.c"
|
||||
#include "psconv.c"
|
||||
|
||||
|
||||
/* END */
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "psobjs.h"
|
||||
#include "t1decode.h"
|
||||
#include "t1cmap.h"
|
||||
#include "afmparse.h"
|
||||
|
||||
|
||||
FT_CALLBACK_TABLE_DEF
|
||||
@ -75,6 +76,15 @@
|
||||
};
|
||||
|
||||
|
||||
FT_CALLBACK_TABLE_DEF
|
||||
const AFM_Parser_FuncsRec afm_parser_funcs =
|
||||
{
|
||||
afm_parser_init,
|
||||
afm_parser_done,
|
||||
afm_parser_parse
|
||||
};
|
||||
|
||||
|
||||
FT_CALLBACK_TABLE_DEF
|
||||
const T1_CMap_ClassesRec t1_cmap_classes =
|
||||
{
|
||||
@ -92,6 +102,7 @@
|
||||
&ps_parser_funcs,
|
||||
&t1_builder_funcs,
|
||||
&t1_decoder_funcs,
|
||||
&afm_parser_funcs,
|
||||
|
||||
t1_decrypt,
|
||||
|
||||
|
394
src/psaux/psconv.c
Normal file
394
src/psaux/psconv.c
Normal file
@ -0,0 +1,394 @@
|
||||
/***************************************************************************/
|
||||
/* */
|
||||
/* psconv.c */
|
||||
/* */
|
||||
/* Some convenient conversions (body). */
|
||||
/* */
|
||||
/* Copyright 2006 by */
|
||||
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
|
||||
/* */
|
||||
/* This file is part of the FreeType project, and may only be used, */
|
||||
/* modified, and distributed under the terms of the FreeType project */
|
||||
/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
|
||||
/* this file you indicate that you have read the license and */
|
||||
/* understand and accept it fully. */
|
||||
/* */
|
||||
/***************************************************************************/
|
||||
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_INTERNAL_POSTSCRIPT_AUX_H
|
||||
#include FT_INTERNAL_DEBUG_H
|
||||
|
||||
#include "psobjs.h"
|
||||
#include "psauxerr.h"
|
||||
|
||||
|
||||
/* The following array is used by various functions to quickly convert */
|
||||
/* digits (both decimal and non-decimal) into numbers. */
|
||||
|
||||
#if 'A' == 65
|
||||
/* ASCII */
|
||||
|
||||
static const char ft_char_table[128] =
|
||||
{
|
||||
/* 0x00 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
|
||||
};
|
||||
|
||||
/* no character >= 0x80 can represent a valid number */
|
||||
#define OP >=
|
||||
|
||||
#endif /* 'A' == 65 */
|
||||
|
||||
#if 'A' == 193
|
||||
/* EBCDIC */
|
||||
|
||||
static const char ft_char_table[128] =
|
||||
{
|
||||
/* 0x80 */
|
||||
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1,
|
||||
-1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1,
|
||||
-1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||
};
|
||||
|
||||
/* no character < 0x80 can represent a valid number */
|
||||
#define OP <
|
||||
|
||||
#endif /* 'A' == 193 */
|
||||
|
||||
FT_LOCAL_DEF( FT_Int )
|
||||
PS_Conv_Strtol( FT_Byte** cursor,
|
||||
FT_Byte* limit,
|
||||
FT_Int base )
|
||||
{
|
||||
FT_Byte* p = *cursor;
|
||||
FT_Int num = 0;
|
||||
FT_Bool sign = 0;
|
||||
|
||||
|
||||
if ( p == limit || base < 2 || base > 36 )
|
||||
return 0;
|
||||
|
||||
if ( *p == '-' || *p == '+' )
|
||||
{
|
||||
sign = ( *p == '-' );
|
||||
|
||||
p++;
|
||||
if ( p == limit )
|
||||
return 0;
|
||||
}
|
||||
|
||||
for ( ; p < limit; p++ )
|
||||
{
|
||||
char c;
|
||||
|
||||
|
||||
if ( IS_PS_SPACE( *p ) || *p OP 0x80 )
|
||||
break;
|
||||
|
||||
c = ft_char_table[*p & 0x7f];
|
||||
|
||||
if ( c < 0 || c >= base )
|
||||
break;
|
||||
|
||||
num = num * base + c;
|
||||
}
|
||||
|
||||
if ( sign )
|
||||
num = -num;
|
||||
|
||||
*cursor = p;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
FT_LOCAL_DEF( FT_Int )
|
||||
PS_Conv_ToInt( FT_Byte** cursor,
|
||||
FT_Byte* limit )
|
||||
|
||||
{
|
||||
FT_Byte* p;
|
||||
FT_Int num;
|
||||
|
||||
|
||||
num = PS_Conv_Strtol( cursor, limit, 10 );
|
||||
p = *cursor;
|
||||
|
||||
if ( p < limit && *p == '#' )
|
||||
{
|
||||
*cursor = p + 1;
|
||||
|
||||
return PS_Conv_Strtol( cursor, limit, num );
|
||||
}
|
||||
else
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
FT_LOCAL_DEF( FT_Fixed )
|
||||
PS_Conv_ToFixed( FT_Byte** cursor,
|
||||
FT_Byte* limit,
|
||||
FT_Int power_ten )
|
||||
{
|
||||
FT_Byte* p = *cursor;
|
||||
FT_Fixed integral;
|
||||
FT_Long decimal = 0, divider = 1;
|
||||
FT_Bool sign = 0;
|
||||
|
||||
|
||||
if ( p == limit )
|
||||
return 0;
|
||||
|
||||
if ( *p == '-' || *p == '+' )
|
||||
{
|
||||
sign = ( *p == '-' );
|
||||
|
||||
p++;
|
||||
if ( p == limit )
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( *p != '.' )
|
||||
{
|
||||
integral = PS_Conv_ToInt( &p, limit ) << 16;
|
||||
|
||||
if ( p == limit )
|
||||
goto Exit;
|
||||
}
|
||||
else
|
||||
integral = 0;
|
||||
|
||||
/* read the decimal part */
|
||||
if ( *p == '.' )
|
||||
{
|
||||
p++;
|
||||
|
||||
for ( ; p < limit; p++ )
|
||||
{
|
||||
char c;
|
||||
|
||||
|
||||
if ( IS_PS_SPACE( *p ) || *p OP 0x80 )
|
||||
break;
|
||||
|
||||
c = ft_char_table[*p & 0x7f];
|
||||
|
||||
if ( c < 0 || c >= 10 )
|
||||
break;
|
||||
|
||||
if ( divider < 10000000L )
|
||||
{
|
||||
decimal = decimal * 10 + c;
|
||||
divider *= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* read exponent, if any */
|
||||
if ( p + 1 < limit && ( *p == 'e' || *p == 'E' ) )
|
||||
{
|
||||
p++;
|
||||
power_ten += PS_Conv_ToInt( &p, limit );
|
||||
}
|
||||
|
||||
Exit:
|
||||
while ( power_ten > 0 )
|
||||
{
|
||||
integral *= 10;
|
||||
decimal *= 10;
|
||||
power_ten--;
|
||||
}
|
||||
|
||||
while ( power_ten < 0 )
|
||||
{
|
||||
integral /= 10;
|
||||
divider *= 10;
|
||||
power_ten++;
|
||||
}
|
||||
|
||||
if ( decimal )
|
||||
integral += FT_DivFix( decimal, divider );
|
||||
|
||||
if ( sign )
|
||||
integral = -integral;
|
||||
|
||||
*cursor = p;
|
||||
|
||||
return integral;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
FT_LOCAL_DEF( FT_UInt )
|
||||
PS_Conv_StringDecode( FT_Byte** cursor,
|
||||
FT_Byte* limit,
|
||||
FT_Byte* buffer,
|
||||
FT_UInt n )
|
||||
{
|
||||
FT_Byte* p;
|
||||
FT_UInt r = 0;
|
||||
|
||||
|
||||
for ( p = *cursor; r < n && p < limit; p++ )
|
||||
{
|
||||
FT_Byte b;
|
||||
|
||||
|
||||
if ( *p != '\\' )
|
||||
{
|
||||
buffer[r++] = *p;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
p++;
|
||||
|
||||
switch ( *p )
|
||||
{
|
||||
case 'n':
|
||||
b = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
b = '\r';
|
||||
break;
|
||||
case 't':
|
||||
b = '\t';
|
||||
break;
|
||||
case 'b':
|
||||
b = '\b';
|
||||
break;
|
||||
case 'f':
|
||||
b = '\f';
|
||||
break;
|
||||
case '\r':
|
||||
p++;
|
||||
if ( *p != '\n' )
|
||||
{
|
||||
b = *p;
|
||||
|
||||
break;
|
||||
}
|
||||
/* no break */
|
||||
case '\n':
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
if ( IS_PS_DIGIT( *p ) )
|
||||
{
|
||||
b = *p - '0';
|
||||
|
||||
p++;
|
||||
|
||||
if ( IS_PS_DIGIT( *p ) )
|
||||
{
|
||||
b = b * 8 + *p - '0';
|
||||
|
||||
p++;
|
||||
|
||||
if ( IS_PS_DIGIT( *p ) )
|
||||
b = b * 8 + *p - '0';
|
||||
else
|
||||
{
|
||||
buffer[r++] = b;
|
||||
b = *p;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[r++] = b;
|
||||
b = *p;
|
||||
}
|
||||
}
|
||||
else
|
||||
b = *p;
|
||||
break;
|
||||
}
|
||||
|
||||
buffer[r++] = b;
|
||||
}
|
||||
|
||||
*cursor = p;
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
FT_LOCAL_DEF( FT_UInt )
|
||||
PS_Conv_ASCIIHexDecode( FT_Byte** cursor,
|
||||
FT_Byte* limit,
|
||||
FT_Byte* buffer,
|
||||
FT_UInt n )
|
||||
{
|
||||
FT_Byte* p;
|
||||
FT_UInt r = 0;
|
||||
|
||||
|
||||
for ( p = *cursor; r < 2 * n && p < limit; p++ )
|
||||
{
|
||||
char c;
|
||||
|
||||
|
||||
if ( IS_PS_SPACE( *p ) )
|
||||
continue;
|
||||
|
||||
if ( *p OP 0x80 )
|
||||
break;
|
||||
|
||||
c = ft_char_table[*p & 0x7f];
|
||||
|
||||
if ( c < 0 || c >= 16 )
|
||||
break;
|
||||
|
||||
if ( r % 2 )
|
||||
*buffer++ += c;
|
||||
else
|
||||
*buffer = c << 4;
|
||||
|
||||
r++;
|
||||
}
|
||||
|
||||
*cursor = p;
|
||||
|
||||
return ( r + 1 ) / 2;
|
||||
}
|
||||
|
||||
|
||||
FT_LOCAL_DEF( FT_UInt )
|
||||
PS_Conv_EexecDecode( FT_Byte** cursor,
|
||||
FT_Byte* limit,
|
||||
FT_Byte* buffer,
|
||||
FT_UInt n,
|
||||
FT_UShort* seed )
|
||||
{
|
||||
FT_Byte* p;
|
||||
FT_UInt r;
|
||||
|
||||
|
||||
for ( r = 0, p = *cursor; r < n && p < limit; r++, p++ )
|
||||
{
|
||||
FT_Byte b = ( *p ^ ( *seed >> 8 ) );
|
||||
|
||||
|
||||
*seed = (FT_UShort)( ( *p + *seed ) * 52845U + 22719 );
|
||||
*buffer++ = b;
|
||||
}
|
||||
|
||||
*cursor = p;
|
||||
|
||||
return r;
|
||||
}
|
106
src/psaux/psconv.h
Normal file
106
src/psaux/psconv.h
Normal file
@ -0,0 +1,106 @@
|
||||
/***************************************************************************/
|
||||
/* */
|
||||
/* psconv.h */
|
||||
/* */
|
||||
/* Some convenient conversions (specification). */
|
||||
/* */
|
||||
/* Copyright 2006 by */
|
||||
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
|
||||
/* */
|
||||
/* This file is part of the FreeType project, and may only be used, */
|
||||
/* modified, and distributed under the terms of the FreeType project */
|
||||
/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
|
||||
/* this file you indicate that you have read the license and */
|
||||
/* understand and accept it fully. */
|
||||
/* */
|
||||
/***************************************************************************/
|
||||
|
||||
|
||||
#ifndef __PSCONV_H__
|
||||
#define __PSCONV_H__
|
||||
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_INTERNAL_POSTSCRIPT_AUX_H
|
||||
|
||||
FT_BEGIN_HEADER
|
||||
|
||||
|
||||
FT_LOCAL_DEF( FT_Int )
|
||||
PS_Conv_Strtol( FT_Byte** cursor,
|
||||
FT_Byte* limit,
|
||||
FT_Int base );
|
||||
|
||||
|
||||
FT_LOCAL( FT_Int )
|
||||
PS_Conv_ToInt( FT_Byte** cursor,
|
||||
FT_Byte* limit );
|
||||
|
||||
FT_LOCAL( FT_Fixed )
|
||||
PS_Conv_ToFixed( FT_Byte** cursor,
|
||||
FT_Byte* limit,
|
||||
FT_Int power_ten );
|
||||
|
||||
#if 0
|
||||
FT_LOCAL( FT_UInt )
|
||||
PS_Conv_StringDecode( FT_Byte** cursor,
|
||||
FT_Byte* limit,
|
||||
FT_Byte* buffer,
|
||||
FT_UInt n );
|
||||
#endif
|
||||
|
||||
FT_LOCAL( FT_UInt )
|
||||
PS_Conv_ASCIIHexDecode( FT_Byte** cursor,
|
||||
FT_Byte* limit,
|
||||
FT_Byte* buffer,
|
||||
FT_UInt n );
|
||||
|
||||
FT_LOCAL( FT_UInt )
|
||||
PS_Conv_EexecDecode( FT_Byte** cursor,
|
||||
FT_Byte* limit,
|
||||
FT_Byte* buffer,
|
||||
FT_UInt n,
|
||||
FT_UShort* seed );
|
||||
|
||||
#define IS_PS_NEWLINE( ch ) \
|
||||
( ( ch ) == '\r' || \
|
||||
( ch ) == '\n' )
|
||||
|
||||
#define IS_PS_SPACE( ch ) \
|
||||
( ( ch ) == ' ' || \
|
||||
IS_PS_NEWLINE( ch ) || \
|
||||
( ch ) == '\t' || \
|
||||
( ch ) == '\f' || \
|
||||
( ch ) == '\0' )
|
||||
|
||||
#define IS_PS_SPECIAL( ch ) \
|
||||
( ( ch ) == '/' || \
|
||||
( ch ) == '(' || \
|
||||
( ch ) == ')' || \
|
||||
( ch ) == '<' || \
|
||||
( ch ) == '>' || \
|
||||
( ch ) == '[' || \
|
||||
( ch ) == ']' || \
|
||||
( ch ) == '{' || \
|
||||
( ch ) == '}' || \
|
||||
( ch ) == '%' )
|
||||
|
||||
#define IS_PS_DELIM( ch ) \
|
||||
( IS_PS_SPACE( ch ) || \
|
||||
IS_PS_SPECIAL( ch ) )
|
||||
|
||||
#define IS_PS_DIGIT( ch ) ( ( ch ) >= '0' && ( ch ) <= '9' )
|
||||
|
||||
#define IS_PS_XDIGIT( ch ) \
|
||||
( IS_PS_DIGIT( ( ch ) ) || \
|
||||
( ( ch ) >= 'A' && ( ch ) <= 'F' ) || \
|
||||
( ( ch ) >= 'a' && ( ch ) <= 'f' ) )
|
||||
|
||||
#define IS_PS_BASE85( ch ) ( ( ch ) >= '!' && ( ch ) <= 'u' )
|
||||
|
||||
FT_END_HEADER
|
||||
|
||||
#endif /* __PSCONV_H__ */
|
||||
|
||||
|
||||
/* END */
|
@ -21,6 +21,7 @@
|
||||
#include FT_INTERNAL_DEBUG_H
|
||||
|
||||
#include "psobjs.h"
|
||||
#include "psconv.h"
|
||||
|
||||
#include "psauxerr.h"
|
||||
|
||||
@ -266,64 +267,6 @@
|
||||
/*************************************************************************/
|
||||
/*************************************************************************/
|
||||
|
||||
/* In the PostScript Language Reference Manual (PLRM) the following */
|
||||
/* characters are called `whitespace characters'. */
|
||||
#define IS_T1_WHITESPACE( c ) ( (c) == ' ' || (c) == '\t' )
|
||||
#define IS_T1_LINESPACE( c ) ( (c) == '\r' || (c) == '\n' || (c) == '\f' )
|
||||
#define IS_T1_NULLSPACE( c ) ( (c) == '\0' )
|
||||
|
||||
/* According to the PLRM all whitespace characters are equivalent, */
|
||||
/* except in comments and strings. */
|
||||
#define IS_T1_SPACE( c ) ( IS_T1_WHITESPACE( c ) || \
|
||||
IS_T1_LINESPACE( c ) || \
|
||||
IS_T1_NULLSPACE( c ) )
|
||||
|
||||
|
||||
/* The following array is used by various functions to quickly convert */
|
||||
/* digits (both decimal and non-decimal) into numbers. */
|
||||
|
||||
#if 'A' == 65
|
||||
/* ASCII */
|
||||
|
||||
static const char ft_char_table[128] =
|
||||
{
|
||||
/* 0x00 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
|
||||
};
|
||||
|
||||
/* no character >= 0x80 can represent a valid number */
|
||||
#define OP >=
|
||||
|
||||
#endif /* 'A' == 65 */
|
||||
|
||||
#if 'A' == 193
|
||||
/* EBCDIC */
|
||||
|
||||
static const char ft_char_table[128] =
|
||||
{
|
||||
/* 0x80 */
|
||||
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1,
|
||||
-1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, -1, -1, -1, -1, -1, -1,
|
||||
-1, 19, 20, 21, 22, 23, 24, 25, 26, 27, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||
}
|
||||
|
||||
/* no character < 0x80 can represent a valid number */
|
||||
#define OP <
|
||||
|
||||
#endif /* 'A' == 193 */
|
||||
|
||||
|
||||
/* first character must be already part of the comment */
|
||||
|
||||
@ -336,7 +279,7 @@
|
||||
|
||||
while ( cur < limit )
|
||||
{
|
||||
if ( IS_T1_LINESPACE( *cur ) )
|
||||
if ( IS_PS_NEWLINE( *cur ) )
|
||||
break;
|
||||
cur++;
|
||||
}
|
||||
@ -354,7 +297,7 @@
|
||||
|
||||
while ( cur < limit )
|
||||
{
|
||||
if ( !IS_T1_SPACE( *cur ) )
|
||||
if ( !IS_PS_SPACE( *cur ) )
|
||||
{
|
||||
if ( *cur == '%' )
|
||||
/* According to the PLRM, a comment is equal to a space. */
|
||||
@ -412,19 +355,12 @@
|
||||
|
||||
while ( ++cur < limit )
|
||||
{
|
||||
int d;
|
||||
|
||||
|
||||
/* All whitespace characters are ignored. */
|
||||
skip_spaces( &cur, limit );
|
||||
if ( cur >= limit )
|
||||
break;
|
||||
|
||||
if ( *cur OP 0x80 )
|
||||
break;
|
||||
|
||||
d = ft_char_table[*cur & 0x7F];
|
||||
if ( d < 0 || d >= 16 )
|
||||
if ( !IS_PS_XDIGIT( *cur ) )
|
||||
break;
|
||||
}
|
||||
|
||||
@ -510,15 +446,6 @@
|
||||
/* anything else */
|
||||
while ( cur < limit )
|
||||
{
|
||||
if ( IS_T1_SPACE( *cur ) ||
|
||||
*cur == '(' ||
|
||||
*cur == '/' ||
|
||||
*cur == '%' ||
|
||||
*cur == '[' || *cur == ']' ||
|
||||
*cur == '{' || *cur == '}' ||
|
||||
*cur == '<' || *cur == '>' )
|
||||
break;
|
||||
|
||||
if ( *cur == ')' )
|
||||
{
|
||||
FT_ERROR(( "ps_parser_skip_PS_token: "
|
||||
@ -526,6 +453,8 @@
|
||||
parser->error = PSaux_Err_Invalid_File_Format;
|
||||
goto Exit;
|
||||
}
|
||||
else if ( IS_PS_DELIM( *cur ) )
|
||||
break;
|
||||
|
||||
cur++;
|
||||
}
|
||||
@ -692,270 +621,6 @@
|
||||
}
|
||||
|
||||
|
||||
/* first character must be already part of the number */
|
||||
|
||||
static FT_Long
|
||||
ps_radix( FT_Long radixBase,
|
||||
FT_Byte* *acur,
|
||||
FT_Byte* limit )
|
||||
{
|
||||
FT_Long result = 0;
|
||||
FT_Byte* cur = *acur;
|
||||
|
||||
|
||||
if ( radixBase < 2 || radixBase > 36 )
|
||||
return 0;
|
||||
|
||||
while ( cur < limit )
|
||||
{
|
||||
int d;
|
||||
|
||||
|
||||
if ( *cur OP 0x80 )
|
||||
break;
|
||||
|
||||
d = ft_char_table[*cur & 0x7F];
|
||||
if ( d < 0 || d >= radixBase )
|
||||
break;
|
||||
|
||||
result = result * radixBase + d;
|
||||
|
||||
cur++;
|
||||
}
|
||||
|
||||
*acur = cur;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* first character must be already part of the number */
|
||||
|
||||
static FT_Long
|
||||
ps_toint( FT_Byte* *acur,
|
||||
FT_Byte* limit )
|
||||
{
|
||||
FT_Long result = 0;
|
||||
FT_Byte* cur = *acur;
|
||||
FT_Byte c;
|
||||
|
||||
|
||||
if ( cur >= limit )
|
||||
goto Exit;
|
||||
|
||||
c = *cur;
|
||||
if ( c == '-' )
|
||||
cur++;
|
||||
|
||||
while ( cur < limit )
|
||||
{
|
||||
int d;
|
||||
|
||||
|
||||
if ( *cur == '#' )
|
||||
{
|
||||
cur++;
|
||||
result = ps_radix( result, &cur, limit );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( *cur OP 0x80 )
|
||||
break;
|
||||
|
||||
d = ft_char_table[*cur & 0x7F];
|
||||
if ( d < 0 || d >= 10 )
|
||||
break;
|
||||
result = result * 10 + d;
|
||||
|
||||
cur++;
|
||||
};
|
||||
|
||||
if ( c == '-' )
|
||||
result = -result;
|
||||
|
||||
Exit:
|
||||
*acur = cur;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* first character must be `<' if `delimiters' is non-zero */
|
||||
|
||||
static FT_Error
|
||||
ps_tobytes( FT_Byte* *acur,
|
||||
FT_Byte* limit,
|
||||
FT_Long max_bytes,
|
||||
FT_Byte* bytes,
|
||||
FT_Long* pnum_bytes,
|
||||
FT_Bool delimiters )
|
||||
{
|
||||
FT_Error error = PSaux_Err_Ok;
|
||||
|
||||
FT_Byte* cur = *acur;
|
||||
FT_Long n = 0;
|
||||
|
||||
|
||||
if ( cur >= limit )
|
||||
goto Exit;
|
||||
|
||||
if ( delimiters )
|
||||
{
|
||||
if ( *cur != '<' )
|
||||
{
|
||||
FT_ERROR(( "ps_tobytes: Missing starting delimiter `<'\n" ));
|
||||
error = PSaux_Err_Invalid_File_Format;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
cur++;
|
||||
}
|
||||
|
||||
max_bytes = max_bytes * 2;
|
||||
|
||||
for ( n = 0; cur < limit; n++, cur++ )
|
||||
{
|
||||
int d;
|
||||
|
||||
|
||||
if ( n >= max_bytes )
|
||||
/* buffer is full */
|
||||
goto Exit;
|
||||
|
||||
/* All whitespace characters are ignored. */
|
||||
skip_spaces( &cur, limit );
|
||||
if ( cur >= limit )
|
||||
break;
|
||||
|
||||
if ( *cur OP 0x80 )
|
||||
break;
|
||||
|
||||
d = ft_char_table[*cur & 0x7F];
|
||||
if ( d < 0 || d >= 16 )
|
||||
break;
|
||||
|
||||
/* <f> == <f0> != <0f> */
|
||||
bytes[n / 2] = (FT_Byte)( ( n % 2 ) ? bytes[n / 2] + d
|
||||
: d * 16 );
|
||||
}
|
||||
|
||||
if ( delimiters )
|
||||
{
|
||||
if ( cur < limit && *cur != '>' )
|
||||
{
|
||||
FT_ERROR(( "ps_tobytes: Missing closing delimiter `>'\n" ));
|
||||
error = PSaux_Err_Invalid_File_Format;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
cur++;
|
||||
}
|
||||
|
||||
*acur = cur;
|
||||
|
||||
Exit:
|
||||
*pnum_bytes = ( n + 1 ) / 2;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/* first character must be already part of the number */
|
||||
|
||||
static FT_Long
|
||||
ps_tofixed( FT_Byte* *acur,
|
||||
FT_Byte* limit,
|
||||
FT_Long power_ten )
|
||||
{
|
||||
FT_Byte* cur = *acur;
|
||||
FT_Long num, divider, result;
|
||||
FT_Int sign = 0;
|
||||
|
||||
|
||||
if ( cur >= limit )
|
||||
return 0;
|
||||
|
||||
/* first of all, check the sign */
|
||||
if ( *cur == '-' && cur + 1 < limit )
|
||||
{
|
||||
sign = 1;
|
||||
cur++;
|
||||
}
|
||||
|
||||
/* then, read the integer part, if any */
|
||||
if ( *cur != '.' )
|
||||
result = ps_toint( &cur, limit ) << 16;
|
||||
else
|
||||
result = 0;
|
||||
|
||||
num = 0;
|
||||
divider = 1;
|
||||
|
||||
if ( cur >= limit )
|
||||
goto Exit;
|
||||
|
||||
/* read decimal part, if any */
|
||||
if ( *cur == '.' && cur + 1 < limit )
|
||||
{
|
||||
cur++;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int d;
|
||||
|
||||
|
||||
if ( *cur OP 0x80 )
|
||||
break;
|
||||
|
||||
d = ft_char_table[*cur & 0x7F];
|
||||
if ( d < 0 || d >= 10 )
|
||||
break;
|
||||
|
||||
if ( divider < 10000000L )
|
||||
{
|
||||
num = num * 10 + d;
|
||||
divider *= 10;
|
||||
}
|
||||
|
||||
cur++;
|
||||
if ( cur >= limit )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* read exponent, if any */
|
||||
if ( cur + 1 < limit && ( *cur == 'e' || *cur == 'E' ) )
|
||||
{
|
||||
cur++;
|
||||
power_ten += ps_toint( &cur, limit );
|
||||
}
|
||||
|
||||
Exit:
|
||||
/* raise to power of ten if needed */
|
||||
while ( power_ten > 0 )
|
||||
{
|
||||
result = result * 10;
|
||||
num = num * 10;
|
||||
power_ten--;
|
||||
}
|
||||
|
||||
while ( power_ten < 0 )
|
||||
{
|
||||
result = result / 10;
|
||||
divider = divider * 10;
|
||||
power_ten++;
|
||||
}
|
||||
|
||||
if ( num )
|
||||
result += FT_DivFix( num, divider );
|
||||
|
||||
if ( sign )
|
||||
result = -result;
|
||||
|
||||
*acur = cur;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* first character must be a delimiter or a part of a number */
|
||||
|
||||
static FT_Int
|
||||
@ -1003,7 +668,8 @@
|
||||
break;
|
||||
}
|
||||
|
||||
coords[count] = (FT_Short)( ps_tofixed( &cur, limit, 0 ) >> 16 );
|
||||
coords[count] =
|
||||
(FT_Short)( PS_Conv_ToFixed( &cur, limit, 0 ) >> 16 );
|
||||
count++;
|
||||
|
||||
if ( !ender )
|
||||
@ -1064,7 +730,7 @@
|
||||
break;
|
||||
}
|
||||
|
||||
values[count] = ps_tofixed( &cur, limit, power_ten );
|
||||
values[count] = PS_Conv_ToFixed( &cur, limit, power_ten );
|
||||
count++;
|
||||
|
||||
if ( !ender )
|
||||
@ -1250,15 +916,15 @@
|
||||
goto Store_Integer;
|
||||
|
||||
case T1_FIELD_TYPE_FIXED:
|
||||
val = ps_tofixed( &cur, limit, 0 );
|
||||
val = PS_Conv_ToFixed( &cur, limit, 0 );
|
||||
goto Store_Integer;
|
||||
|
||||
case T1_FIELD_TYPE_FIXED_1000:
|
||||
val = ps_tofixed( &cur, limit, 3 );
|
||||
val = PS_Conv_ToFixed( &cur, limit, 3 );
|
||||
goto Store_Integer;
|
||||
|
||||
case T1_FIELD_TYPE_INTEGER:
|
||||
val = ps_toint( &cur, limit );
|
||||
val = PS_Conv_ToInt( &cur, limit );
|
||||
/* fall through */
|
||||
|
||||
Store_Integer:
|
||||
@ -1424,10 +1090,12 @@
|
||||
ps_parser_to_int( PS_Parser parser )
|
||||
{
|
||||
ps_parser_skip_spaces( parser );
|
||||
return ps_toint( &parser->cursor, parser->limit );
|
||||
return PS_Conv_ToInt( &parser->cursor, parser->limit );
|
||||
}
|
||||
|
||||
|
||||
/* first character must be `<' if `delimiters' is non-zero */
|
||||
|
||||
FT_LOCAL_DEF( FT_Error )
|
||||
ps_parser_to_bytes( PS_Parser parser,
|
||||
FT_Byte* bytes,
|
||||
@ -1435,13 +1103,49 @@
|
||||
FT_Long* pnum_bytes,
|
||||
FT_Bool delimiters )
|
||||
{
|
||||
FT_Error error = PSaux_Err_Ok;
|
||||
FT_Byte* cur;
|
||||
|
||||
|
||||
ps_parser_skip_spaces( parser );
|
||||
return ps_tobytes( &parser->cursor,
|
||||
parser->limit,
|
||||
max_bytes,
|
||||
bytes,
|
||||
pnum_bytes,
|
||||
delimiters );
|
||||
cur = parser->cursor;
|
||||
|
||||
if ( cur >= parser->limit )
|
||||
goto Exit;
|
||||
|
||||
if ( delimiters )
|
||||
{
|
||||
if ( *cur != '<' )
|
||||
{
|
||||
FT_ERROR(( "ps_tobytes: Missing starting delimiter `<'\n" ));
|
||||
error = PSaux_Err_Invalid_File_Format;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
cur++;
|
||||
}
|
||||
|
||||
*pnum_bytes = PS_Conv_ASCIIHexDecode( &cur,
|
||||
parser->limit,
|
||||
bytes,
|
||||
max_bytes );
|
||||
|
||||
if ( delimiters )
|
||||
{
|
||||
if ( cur < parser->limit && *cur != '>' )
|
||||
{
|
||||
FT_ERROR(( "ps_tobytes: Missing closing delimiter `>'\n" ));
|
||||
error = PSaux_Err_Invalid_File_Format;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
cur++;
|
||||
}
|
||||
|
||||
parser->cursor = cur;
|
||||
|
||||
Exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@ -1450,7 +1154,7 @@
|
||||
FT_Int power_ten )
|
||||
{
|
||||
ps_parser_skip_spaces( parser );
|
||||
return ps_tofixed( &parser->cursor, parser->limit, power_ten );
|
||||
return PS_Conv_ToFixed( &parser->cursor, parser->limit, power_ten );
|
||||
}
|
||||
|
||||
|
||||
@ -1780,16 +1484,11 @@
|
||||
FT_Offset length,
|
||||
FT_UShort seed )
|
||||
{
|
||||
while ( length > 0 )
|
||||
{
|
||||
FT_Byte plain;
|
||||
|
||||
|
||||
plain = (FT_Byte)( *buffer ^ ( seed >> 8 ) );
|
||||
seed = (FT_UShort)( ( *buffer + seed ) * 52845U + 22719 );
|
||||
*buffer++ = plain;
|
||||
length--;
|
||||
}
|
||||
PS_Conv_EexecDecode( &buffer,
|
||||
buffer + length,
|
||||
buffer,
|
||||
length,
|
||||
&seed );
|
||||
}
|
||||
|
||||
|
||||
|
@ -28,6 +28,8 @@ PSAUX_COMPILE := $(FT_COMPILE) $I$(subst /,$(COMPILER_SEP),$(PSAUX_DIR))
|
||||
PSAUX_DRV_SRC := $(PSAUX_DIR)/psobjs.c \
|
||||
$(PSAUX_DIR)/t1decode.c \
|
||||
$(PSAUX_DIR)/t1cmap.c \
|
||||
$(PSAUX_DIR)/afmparse.c \
|
||||
$(PSAUX_DIR)/psconv.c \
|
||||
$(PSAUX_DIR)/psauxmod.c
|
||||
|
||||
# PSAUX driver headers
|
||||
|
146
src/tools/test_afm.c
Normal file
146
src/tools/test_afm.c
Normal file
@ -0,0 +1,146 @@
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_INTERNAL_STREAM_H
|
||||
#include FT_INTERNAL_POSTSCRIPT_AUX_H
|
||||
|
||||
void dump_fontinfo( AFM_FontInfo fi )
|
||||
{
|
||||
FT_Int i;
|
||||
|
||||
|
||||
printf( "This AFM is for %sCID font.\n\n",
|
||||
( fi->IsCIDFont ) ? "" : "non-" );
|
||||
|
||||
if ( fi->NumTrackKern )
|
||||
printf( "There are %d sets of track kernings:\n",
|
||||
fi->NumTrackKern );
|
||||
else
|
||||
printf( "There is no track kerning.\n" );
|
||||
|
||||
for ( i = 0; i < fi->NumTrackKern; i++ )
|
||||
{
|
||||
AFM_TrackKern tk = fi->TrackKerns + i;
|
||||
|
||||
|
||||
printf( "\t%2d: %5.2f %5.2f %5.2f %5.2f\n", tk->degree,
|
||||
tk->min_ptsize / 65536.,
|
||||
tk->min_kern / 65536.,
|
||||
tk->max_ptsize / 65536.,
|
||||
tk->max_kern / 65536. );
|
||||
}
|
||||
|
||||
printf( "\n" );
|
||||
|
||||
if ( fi->NumTrackKern )
|
||||
printf( "There are %d kerning pairs:\n",
|
||||
fi->NumKernPair );
|
||||
else
|
||||
printf( "There is no kerning pair.\n" );
|
||||
|
||||
for ( i = 0; i < fi->NumKernPair; i++ )
|
||||
{
|
||||
AFM_KernPair kp = fi->KernPairs + i;
|
||||
|
||||
|
||||
printf( "\t%3d + %3d => (%4d, %4d)\n", kp->index1,
|
||||
kp->index2,
|
||||
kp->x,
|
||||
kp->y );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
dummy_get_index( const char* name,
|
||||
FT_UInt len,
|
||||
void* user_data )
|
||||
{
|
||||
if ( len )
|
||||
return name[0];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
FT_Error
|
||||
parse_afm( FT_Library library,
|
||||
FT_Stream stream,
|
||||
AFM_FontInfo fi )
|
||||
{
|
||||
PSAux_Service psaux;
|
||||
AFM_ParserRec parser;
|
||||
FT_Error error = FT_Err_Ok;
|
||||
|
||||
|
||||
psaux = (PSAux_Service)FT_Get_Module_Interface( library, "psaux" );
|
||||
if ( !psaux || !psaux->afm_parser_funcs )
|
||||
return -1;
|
||||
|
||||
error = FT_Stream_EnterFrame( stream, stream->size );
|
||||
if ( error )
|
||||
return error;
|
||||
|
||||
error = psaux->afm_parser_funcs->init( &parser,
|
||||
library->memory,
|
||||
stream->cursor,
|
||||
stream->limit );
|
||||
if ( error )
|
||||
return error;
|
||||
|
||||
parser.FontInfo = fi;
|
||||
parser.get_index = dummy_get_index;
|
||||
|
||||
error = psaux->afm_parser_funcs->parse( &parser );
|
||||
|
||||
psaux->afm_parser_funcs->done( &parser );
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int main( int argc,
|
||||
char** argv )
|
||||
{
|
||||
FT_Library library;
|
||||
FT_StreamRec stream;
|
||||
FT_Error error = FT_Err_Ok;
|
||||
AFM_FontInfoRec fi;
|
||||
|
||||
|
||||
if ( argc < 2 )
|
||||
return FT_Err_Invalid_Argument;
|
||||
|
||||
error = FT_Init_FreeType( &library );
|
||||
if ( error )
|
||||
return error;
|
||||
|
||||
FT_ZERO( &stream );
|
||||
error = FT_Stream_Open( &stream, argv[1] );
|
||||
if ( error )
|
||||
goto Exit;
|
||||
stream.memory = library->memory;
|
||||
|
||||
FT_ZERO( &fi );
|
||||
error = parse_afm( library, &stream, &fi );
|
||||
|
||||
if ( !error )
|
||||
{
|
||||
FT_Memory memory = library->memory;
|
||||
|
||||
|
||||
dump_fontinfo( &fi );
|
||||
|
||||
if ( fi.KernPairs )
|
||||
FT_FREE( fi.KernPairs );
|
||||
if ( fi.TrackKerns )
|
||||
FT_FREE( fi.TrackKerns );
|
||||
}
|
||||
else
|
||||
printf( "parse error\n" );
|
||||
|
||||
FT_Stream_Close( &stream );
|
||||
|
||||
Exit:
|
||||
FT_Done_FreeType( library );
|
||||
|
||||
return error;
|
||||
}
|
@ -34,102 +34,41 @@
|
||||
|
||||
|
||||
FT_LOCAL_DEF( void )
|
||||
T1_Done_Metrics( FT_Memory memory,
|
||||
T1_AFM* afm )
|
||||
T1_Done_Metrics( FT_Memory memory,
|
||||
AFM_FontInfo fi )
|
||||
{
|
||||
FT_FREE( afm->kern_pairs );
|
||||
afm->num_pairs = 0;
|
||||
FT_FREE( afm );
|
||||
FT_FREE( fi->KernPairs );
|
||||
fi->NumKernPair = 0;
|
||||
|
||||
FT_FREE( fi->TrackKerns );
|
||||
fi->NumTrackKern = 0;
|
||||
|
||||
FT_FREE( fi );
|
||||
}
|
||||
|
||||
|
||||
#undef IS_KERN_PAIR
|
||||
#define IS_KERN_PAIR( p ) ( p[0] == 'K' && p[1] == 'P' )
|
||||
|
||||
#define IS_ALPHANUM( c ) ( ft_isalnum( c ) || \
|
||||
c == '_' || \
|
||||
c == '.' )
|
||||
|
||||
|
||||
/* read a glyph name and return the equivalent glyph index */
|
||||
static FT_UInt
|
||||
afm_atoindex( FT_Byte** start,
|
||||
FT_Byte* limit,
|
||||
T1_Font type1 )
|
||||
static FT_Int
|
||||
t1_get_index( const char* name,
|
||||
FT_UInt len,
|
||||
void* user_data )
|
||||
{
|
||||
FT_Byte* p = *start;
|
||||
FT_PtrDist len;
|
||||
FT_UInt result = 0;
|
||||
char temp[64];
|
||||
T1_Font type1 = (T1_Font)user_data;
|
||||
FT_Int n;
|
||||
|
||||
|
||||
/* skip whitespace */
|
||||
while ( p < limit &&
|
||||
( *p == ' ' || *p == '\t' || *p == ':' || *p == ';' ) )
|
||||
p++;
|
||||
*start = p;
|
||||
|
||||
/* now, read glyph name */
|
||||
while ( p < limit && IS_ALPHANUM( *p ) )
|
||||
p++;
|
||||
|
||||
len = p - *start;
|
||||
|
||||
if ( len > 0 && len < 64 )
|
||||
for ( n = 0; n < type1->num_glyphs; n++ )
|
||||
{
|
||||
FT_Int n;
|
||||
char* gname = (char*)type1->glyph_names[n];
|
||||
|
||||
|
||||
/* copy glyph name to intermediate array */
|
||||
FT_MEM_COPY( temp, *start, len );
|
||||
temp[len] = 0;
|
||||
|
||||
/* lookup glyph name in face array */
|
||||
for ( n = 0; n < type1->num_glyphs; n++ )
|
||||
{
|
||||
char* gname = (char*)type1->glyph_names[n];
|
||||
|
||||
|
||||
if ( gname && gname[0] == temp[0] && ft_strcmp( gname, temp ) == 0 )
|
||||
{
|
||||
result = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*start = p;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* read an integer */
|
||||
static int
|
||||
afm_atoi( FT_Byte** start,
|
||||
FT_Byte* limit )
|
||||
{
|
||||
FT_Byte* p = *start;
|
||||
int sum = 0;
|
||||
int sign = 1;
|
||||
|
||||
|
||||
/* skip everything that is not a number */
|
||||
while ( p < limit && !isdigit( *p ) )
|
||||
{
|
||||
sign = 1;
|
||||
if ( *p == '-' )
|
||||
sign = -1;
|
||||
|
||||
p++;
|
||||
if ( gname && gname[0] == name[0] &&
|
||||
ft_strlen( gname ) == len &&
|
||||
ft_strncmp( gname, name, len ) == 0 )
|
||||
return n;
|
||||
}
|
||||
|
||||
while ( p < limit && isdigit( *p ) )
|
||||
{
|
||||
sum = sum * 10 + ( *p - '0' );
|
||||
p++;
|
||||
}
|
||||
*start = p;
|
||||
|
||||
return sum * sign;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -142,121 +81,29 @@
|
||||
compare_kern_pairs( const void* a,
|
||||
const void* b )
|
||||
{
|
||||
T1_Kern_Pair* pair1 = (T1_Kern_Pair*)a;
|
||||
T1_Kern_Pair* pair2 = (T1_Kern_Pair*)b;
|
||||
AFM_KernPair pair1 = (AFM_KernPair)a;
|
||||
AFM_KernPair pair2 = (AFM_KernPair)b;
|
||||
|
||||
FT_ULong index1 = KERN_INDEX( pair1->glyph1, pair1->glyph2 );
|
||||
FT_ULong index2 = KERN_INDEX( pair2->glyph1, pair2->glyph2 );
|
||||
FT_ULong index1 = KERN_INDEX( pair1->index1, pair1->index2 );
|
||||
FT_ULong index2 = KERN_INDEX( pair2->index1, pair2->index2 );
|
||||
|
||||
|
||||
return (int)( index1 - index2 );
|
||||
}
|
||||
|
||||
|
||||
/* parse an AFM file -- for now, only read the kerning pairs */
|
||||
static FT_Error
|
||||
T1_Read_AFM( FT_Face t1_face,
|
||||
FT_Stream stream )
|
||||
{
|
||||
FT_Error error = T1_Err_Ok;
|
||||
FT_Memory memory = stream->memory;
|
||||
FT_Byte* start;
|
||||
FT_Byte* limit;
|
||||
FT_Byte* p;
|
||||
FT_Int count = 0;
|
||||
T1_Kern_Pair* pair;
|
||||
T1_Font type1 = &((T1_Face)t1_face)->type1;
|
||||
T1_AFM* afm = 0;
|
||||
|
||||
|
||||
start = (FT_Byte*)stream->cursor;
|
||||
limit = (FT_Byte*)stream->limit;
|
||||
p = start;
|
||||
|
||||
/* we are now going to count the occurences of `KP' or `KPX' in */
|
||||
/* the AFM file */
|
||||
count = 0;
|
||||
for ( p = start; p < limit - 3; p++ )
|
||||
{
|
||||
if ( IS_KERN_PAIR( p ) )
|
||||
count++;
|
||||
}
|
||||
|
||||
/* Actually, kerning pairs are simply optional! */
|
||||
if ( count == 0 )
|
||||
goto Exit;
|
||||
|
||||
/* allocate the pairs */
|
||||
if ( FT_NEW( afm ) || FT_NEW_ARRAY( afm->kern_pairs, count ) )
|
||||
goto Exit;
|
||||
|
||||
/* now, read each kern pair */
|
||||
pair = afm->kern_pairs;
|
||||
afm->num_pairs = count;
|
||||
|
||||
/* save in face object */
|
||||
((T1_Face)t1_face)->afm_data = afm;
|
||||
|
||||
t1_face->face_flags |= FT_FACE_FLAG_KERNING;
|
||||
|
||||
for ( p = start; p < limit - 3; p++ )
|
||||
{
|
||||
if ( IS_KERN_PAIR( p ) )
|
||||
{
|
||||
FT_Byte* q;
|
||||
|
||||
|
||||
/* skip keyword (KP or KPX) */
|
||||
q = p + 2;
|
||||
if ( *q == 'X' )
|
||||
q++;
|
||||
|
||||
pair->glyph1 = afm_atoindex( &q, limit, type1 );
|
||||
pair->glyph2 = afm_atoindex( &q, limit, type1 );
|
||||
pair->kerning.x = afm_atoi( &q, limit );
|
||||
|
||||
pair->kerning.y = 0;
|
||||
if ( p[2] != 'X' )
|
||||
pair->kerning.y = afm_atoi( &q, limit );
|
||||
|
||||
pair++;
|
||||
}
|
||||
}
|
||||
|
||||
/* now, sort the kern pairs according to their glyph indices */
|
||||
ft_qsort( afm->kern_pairs, count, sizeof ( T1_Kern_Pair ),
|
||||
compare_kern_pairs );
|
||||
|
||||
Exit:
|
||||
if ( error )
|
||||
FT_FREE( afm );
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
#define LITTLE_ENDIAN_USHORT( p ) (FT_UShort)( ( (p)[0] ) | \
|
||||
( (p)[1] << 8 ) )
|
||||
|
||||
#define LITTLE_ENDIAN_UINT( p ) (FT_UInt)( ( (p)[0] ) | \
|
||||
( (p)[1] << 8 ) | \
|
||||
( (p)[2] << 16 ) | \
|
||||
( (p)[3] << 24 ) )
|
||||
|
||||
|
||||
/* parse a PFM file -- for now, only read the kerning pairs */
|
||||
static FT_Error
|
||||
T1_Read_PFM( FT_Face t1_face,
|
||||
FT_Stream stream )
|
||||
T1_Read_PFM( FT_Face t1_face,
|
||||
FT_Stream stream,
|
||||
AFM_FontInfo fi )
|
||||
{
|
||||
FT_Error error = T1_Err_Ok;
|
||||
FT_Memory memory = stream->memory;
|
||||
FT_Byte* start;
|
||||
FT_Byte* limit;
|
||||
FT_Byte* p;
|
||||
FT_Int kern_count = 0;
|
||||
T1_Kern_Pair* pair;
|
||||
T1_AFM* afm = 0;
|
||||
AFM_KernPair kp;
|
||||
FT_Int width_table_length;
|
||||
FT_CharMap oldcharmap;
|
||||
FT_CharMap charmap;
|
||||
@ -275,16 +122,16 @@
|
||||
error = T1_Err_Unknown_File_Format;
|
||||
goto Exit;
|
||||
}
|
||||
width_table_length = LITTLE_ENDIAN_USHORT( p );
|
||||
width_table_length = FT_PEEK_USHORT_LE( p );
|
||||
|
||||
p += 18 + width_table_length;
|
||||
if ( p + 0x12 > limit || LITTLE_ENDIAN_USHORT( p ) < 0x12 )
|
||||
if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 )
|
||||
/* extension table is probably optional */
|
||||
goto Exit;
|
||||
|
||||
/* Kerning offset is 14 bytes from start of extensions table. */
|
||||
p += 14;
|
||||
p = start + LITTLE_ENDIAN_UINT( p );
|
||||
p = start + FT_PEEK_ULONG_LE( p );
|
||||
|
||||
if ( p == start )
|
||||
/* zero offset means no table */
|
||||
@ -296,31 +143,25 @@
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
kern_count = LITTLE_ENDIAN_USHORT( p );
|
||||
fi->NumKernPair = FT_PEEK_USHORT_LE( p );
|
||||
p += 2;
|
||||
if ( p + 4 * kern_count > limit )
|
||||
if ( p + 4 * fi->NumKernPair > limit )
|
||||
{
|
||||
error = T1_Err_Unknown_File_Format;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* Actually, kerning pairs are simply optional! */
|
||||
if ( kern_count == 0 )
|
||||
if ( fi->NumKernPair == 0 )
|
||||
goto Exit;
|
||||
|
||||
/* allocate the pairs */
|
||||
if ( FT_NEW( afm ) || FT_NEW_ARRAY( afm->kern_pairs, kern_count ) )
|
||||
if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) )
|
||||
goto Exit;
|
||||
|
||||
/* save in face object */
|
||||
((T1_Face)t1_face)->afm_data = afm;
|
||||
|
||||
t1_face->face_flags |= FT_FACE_FLAG_KERNING;
|
||||
|
||||
/* now, read each kern pair */
|
||||
pair = afm->kern_pairs;
|
||||
afm->num_pairs = kern_count;
|
||||
limit = p + 4 * kern_count;
|
||||
kp = fi->KernPairs;
|
||||
limit = p + 4 * fi->NumKernPair;
|
||||
|
||||
/* PFM kerning data are stored by encoding rather than glyph index, */
|
||||
/* so find the PostScript charmap of this font and install it */
|
||||
@ -347,15 +188,15 @@
|
||||
/* encoding of first glyph (1 byte) */
|
||||
/* encoding of second glyph (1 byte) */
|
||||
/* offset (little-endian short) */
|
||||
for ( ; p < limit ; p+=4 )
|
||||
for ( ; p < limit ; p += 4 )
|
||||
{
|
||||
pair->glyph1 = FT_Get_Char_Index( t1_face, p[0] );
|
||||
pair->glyph2 = FT_Get_Char_Index( t1_face, p[1] );
|
||||
kp->index1 = FT_Get_Char_Index( t1_face, p[0] );
|
||||
kp->index2 = FT_Get_Char_Index( t1_face, p[1] );
|
||||
|
||||
pair->kerning.x = (FT_Short)LITTLE_ENDIAN_USHORT(p + 2);
|
||||
pair->kerning.y = 0;
|
||||
kp->x = (FT_Int)FT_PEEK_USHORT_LE(p + 2);
|
||||
kp->y = 0;
|
||||
|
||||
pair++;
|
||||
kp++;
|
||||
}
|
||||
|
||||
if ( oldcharmap != NULL )
|
||||
@ -364,12 +205,15 @@
|
||||
goto Exit;
|
||||
|
||||
/* now, sort the kern pairs according to their glyph indices */
|
||||
ft_qsort( afm->kern_pairs, kern_count, sizeof ( T1_Kern_Pair ),
|
||||
ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ),
|
||||
compare_kern_pairs );
|
||||
|
||||
Exit:
|
||||
if ( error )
|
||||
FT_FREE( afm );
|
||||
{
|
||||
FT_FREE( fi->KernPairs );
|
||||
fi->NumKernPair = 0;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
@ -381,27 +225,55 @@
|
||||
T1_Read_Metrics( FT_Face t1_face,
|
||||
FT_Stream stream )
|
||||
{
|
||||
FT_Error error;
|
||||
FT_Byte* start;
|
||||
PSAux_Service psaux;
|
||||
FT_Memory memory = stream->memory;
|
||||
AFM_ParserRec parser;
|
||||
AFM_FontInfo fi;
|
||||
FT_Error error = T1_Err_Unknown_File_Format;
|
||||
|
||||
|
||||
if ( FT_FRAME_ENTER( stream->size ) )
|
||||
return error;
|
||||
|
||||
start = (FT_Byte*)stream->cursor;
|
||||
FT_NEW( fi );
|
||||
if ( error )
|
||||
return error;
|
||||
|
||||
if ( stream->size >= ft_strlen( "StartFontMetrics" ) &&
|
||||
ft_strncmp( (const char*)start, "StartFontMetrics",
|
||||
ft_strlen( "StartFontMetrics" ) ) == 0 )
|
||||
error = T1_Read_AFM( t1_face, stream );
|
||||
psaux = (PSAux_Service)( (T1_Face)t1_face )->psaux;
|
||||
if ( psaux && psaux->afm_parser_funcs )
|
||||
{
|
||||
error = psaux->afm_parser_funcs->init( &parser,
|
||||
stream->memory,
|
||||
stream->cursor,
|
||||
stream->limit );
|
||||
|
||||
else if ( stream->size > 6 &&
|
||||
start[0] == 0x00 && start[1] == 0x01 &&
|
||||
LITTLE_ENDIAN_UINT( start + 2 ) == stream->size )
|
||||
error = T1_Read_PFM( t1_face, stream );
|
||||
if ( !error )
|
||||
{
|
||||
parser.FontInfo = fi;
|
||||
parser.get_index = t1_get_index;
|
||||
parser.user_data = &( (T1_Face)t1_face )->type1;
|
||||
|
||||
else
|
||||
error = T1_Err_Unknown_File_Format;
|
||||
error = psaux->afm_parser_funcs->parse( &parser );
|
||||
psaux->afm_parser_funcs->done( &parser );
|
||||
}
|
||||
}
|
||||
|
||||
if ( error == T1_Err_Unknown_File_Format )
|
||||
{
|
||||
FT_Byte* start = stream->cursor;
|
||||
|
||||
|
||||
if ( stream->size > 6 &&
|
||||
start[0] == 0x00 && start[1] == 0x01 &&
|
||||
FT_PEEK_ULONG_LE( start + 2 ) == stream->size )
|
||||
error = T1_Read_PFM( t1_face, stream, fi );
|
||||
}
|
||||
|
||||
if ( !error && fi->NumKernPair )
|
||||
{
|
||||
t1_face->face_flags |= FT_FACE_FLAG_KERNING;
|
||||
( (T1_Face)t1_face )->afm_data = fi;
|
||||
}
|
||||
|
||||
FT_FRAME_EXIT();
|
||||
|
||||
@ -411,18 +283,18 @@
|
||||
|
||||
/* find the kerning for a given glyph pair */
|
||||
FT_LOCAL_DEF( void )
|
||||
T1_Get_Kerning( T1_AFM* afm,
|
||||
FT_UInt glyph1,
|
||||
FT_UInt glyph2,
|
||||
FT_Vector* kerning )
|
||||
T1_Get_Kerning( AFM_FontInfo fi,
|
||||
FT_UInt glyph1,
|
||||
FT_UInt glyph2,
|
||||
FT_Vector* kerning )
|
||||
{
|
||||
T1_Kern_Pair *min, *mid, *max;
|
||||
AFM_KernPair min, mid, max;
|
||||
FT_ULong idx = KERN_INDEX( glyph1, glyph2 );
|
||||
|
||||
|
||||
/* simple binary search */
|
||||
min = afm->kern_pairs;
|
||||
max = min + afm->num_pairs - 1;
|
||||
min = fi->KernPairs;
|
||||
max = min + fi->NumKernPair - 1;
|
||||
|
||||
while ( min <= max )
|
||||
{
|
||||
@ -430,11 +302,13 @@
|
||||
|
||||
|
||||
mid = min + ( max - min ) / 2;
|
||||
midi = KERN_INDEX( mid->glyph1, mid->glyph2 );
|
||||
midi = KERN_INDEX( mid->index1, mid->index2 );
|
||||
|
||||
if ( midi == idx )
|
||||
{
|
||||
*kerning = mid->kerning;
|
||||
kerning->x = mid->x;
|
||||
kerning->y = mid->y;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -449,4 +323,42 @@
|
||||
}
|
||||
|
||||
|
||||
FT_LOCAL_DEF( FT_Error )
|
||||
T1_Get_Track_Kerning( FT_Face face,
|
||||
FT_Fixed ptsize,
|
||||
FT_Int degree,
|
||||
FT_Fixed* kerning )
|
||||
{
|
||||
AFM_FontInfo fi = (AFM_FontInfo)( (T1_Face)face )->afm_data;
|
||||
FT_Int i;
|
||||
|
||||
|
||||
if ( !fi )
|
||||
return T1_Err_Invalid_Argument;
|
||||
|
||||
for ( i = 0; i < fi->NumTrackKern; i++ )
|
||||
{
|
||||
AFM_TrackKern tk = fi->TrackKerns + i;
|
||||
|
||||
|
||||
if ( tk->degree != degree )
|
||||
continue;
|
||||
|
||||
if ( ptsize < tk->min_ptsize )
|
||||
*kerning = tk->min_kern;
|
||||
else if ( ptsize > tk->max_ptsize )
|
||||
*kerning = tk->max_kern;
|
||||
else
|
||||
{
|
||||
*kerning = FT_MulDiv( ptsize - tk->min_ptsize,
|
||||
tk->max_kern - tk->min_kern,
|
||||
tk->max_ptsize - tk->min_ptsize ) +
|
||||
tk->min_kern;
|
||||
}
|
||||
}
|
||||
|
||||
return T1_Err_Ok;
|
||||
}
|
||||
|
||||
|
||||
/* END */
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user