parent
cda32b71ba
commit
a8635cc626
2 changed files with 269 additions and 0 deletions
@ -0,0 +1,222 @@ |
||||
/***************************************************************************
|
||||
* |
||||
* t1afm.c - support for reading Type 1 AFM files |
||||
* |
||||
* |
||||
***************************************************************************/ |
||||
|
||||
#include <t1afm.h> |
||||
#include <ftstream.h> |
||||
#include <t1types.h> |
||||
#include <stdlib.h> /* for qsort */ |
||||
|
||||
LOCAL_FUNC |
||||
void T1_Done_AFM( FT_Memory memory, T1_AFM* afm ) |
||||
{ |
||||
FREE( afm->kern_pairs ); |
||||
afm->num_pairs = 0; |
||||
} |
||||
|
||||
#undef IS_KERN_PAIR |
||||
#define IS_KERN_PAIR(p) ( p[0] == 'K' && p[1] == 'P' ) |
||||
|
||||
#define IS_ALPHANUM(c) ( (c >= 'A' && c <= 'Z') || \ |
||||
(c >= 'a' && c <= 'z') || \
|
||||
(c >= '0' && c <= '9') || \
|
||||
(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 ) |
||||
{ |
||||
FT_Byte* p = *start; |
||||
FT_Int len; |
||||
FT_UInt result = 0; |
||||
char temp[64]; |
||||
|
||||
/* skip whitespace */
|
||||
while ( (*p == ' ' || *p == '\t' || *p == ':' || *p == ';') && p < limit ) |
||||
p++; |
||||
*start = p; |
||||
|
||||
/* now, read glyph name */ |
||||
while ( IS_ALPHANUM(*p) && p < limit ) p++; |
||||
len = p - *start; |
||||
if (len > 0 && len < 64) |
||||
{ |
||||
FT_UInt n; |
||||
|
||||
/* copy glyph name to intermediate array */ |
||||
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; |
||||
|
||||
if ( gname && gname[0] == temp[0] && 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; |
||||
|
||||
/* skip everything that is not a number */ |
||||
while ( p < limit && (*p < '0' || *p > '9') ) |
||||
p++; |
||||
|
||||
while ( p < limit && (*p >= '0' || *p < '9') ) |
||||
{ |
||||
sum = sum*10 + (*p - '0'); |
||||
p++; |
||||
} |
||||
*start = p; |
||||
return sum; |
||||
} |
||||
|
||||
|
||||
#undef KERN_INDEX |
||||
#define KERN_INDEX(g1,g2) (((T1_ULong)g1 << 16) | g2) |
||||
|
||||
/* compare two kerning pairs */ |
||||
static |
||||
int 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; |
||||
|
||||
T1_ULong index1 = KERN_INDEX(pair1->glyph1,pair1->glyph2); |
||||
T1_ULong index2 = KERN_INDEX(pair2->glyph1,pair2->glyph2); |
||||
|
||||
return ( index1 < index2 ? -1 : |
||||
( index1 > index2 ? 1 : 0 )); |
||||
} |
||||
|
||||
|
||||
/* parse an AFM file - for now, only read the kerning pairs */ |
||||
LOCAL_FUNC |
||||
FT_Error T1_Read_AFM( FT_Stream stream, |
||||
FT_Face t1_face ) |
||||
{ |
||||
FT_Error error; |
||||
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; |
||||
|
||||
if ( !ACCESS_Frame(stream->size) ) |
||||
return error; |
||||
|
||||
start = stream->cursor; |
||||
limit = 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 ( ALLOC( afm, sizeof(*afm ) || |
||||
ALLOC_ARRAY( afm->kern_pairs, count, T1_Kern_Pair ) ) |
||||
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; |
||||
|
||||
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 */ |
||||
qsort( afm->kern_pairs, count, sizeof(T1_Kern_Pair), compare_kern_pairs ); |
||||
|
||||
Exit: |
||||
if (error) |
||||
FREE( afm ); |
||||
|
||||
FORGET_Frame(); |
||||
return error; |
||||
} |
||||
|
||||
|
||||
/* find the kerning for a given glyph pair */
|
||||
LOCAL_FUNC |
||||
void T1_Get_Kerning( T1_AFM* afm, |
||||
FT_UInt glyph1, |
||||
FT_UInt glyph2, |
||||
FT_Vector* kerning ) |
||||
{ |
||||
T1_Kern_Pair *min, *mid, *max; |
||||
T1_ULong index = KERN_INDEX(glyph1,glyph2); |
||||
|
||||
/* simple binary search */ |
||||
min = afm->kern_pairs; |
||||
max = min + afm->num_pairs-1; |
||||
|
||||
while (min <= max) |
||||
{ |
||||
T1_ULong midi; |
||||
|
||||
mid = min + (max-min)/2; |
||||
midi = KERN_INDEX(mid->glyph1,mid->glyph2);
|
||||
if ( midi == index ) |
||||
{ |
||||
*kerning = mid->kerning; |
||||
return; |
||||
} |
||||
|
||||
if ( midi < index ) min = mid+1; |
||||
else max = mid-1; |
||||
} |
||||
kerning->x = 0; |
||||
kerning->y = 0; |
||||
} |
||||
|
@ -0,0 +1,47 @@ |
||||
/***************************************************************************
|
||||
* |
||||
* t1afm.h - support for reading Type 1 AFM files |
||||
* |
||||
* |
||||
***************************************************************************/ |
||||
|
||||
#ifndef T1AFM_H |
||||
#define T1AFM_H |
||||
|
||||
#include <ftobjs.h> |
||||
|
||||
/* In this version, we only read the kerning table from the */ |
||||
/* AFM file. We may add support for ligatures a bit later.. */ |
||||
|
||||
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; |
||||
|
||||
|
||||
LOCAL_DEF |
||||
FT_Error T1_Read_AFM( FT_Stream stream, |
||||
FT_Face face ); |
||||
|
||||
LOCAL_DEF |
||||
void T1_Done_AFM( FT_Memory memory, |
||||
T1_AFM* afm ); |
||||
|
||||
LOCAL_DEF |
||||
void T1_Get_Kerning( T1_AFM* afm, |
||||
FT_UInt glyph1, |
||||
FT_UInt glyph2, |
||||
FT_Vector* kerning ); |
||||
|
||||
#endif /* T1AFM_H */ |
Loading…
Reference in new issue