2466 lines
65 KiB
C
2466 lines
65 KiB
C
|
/*
|
||
|
* Copyright 2000 Computing Research Labs, New Mexico State University
|
||
|
* Copyright 2001 Francesco Zappa Nardelli
|
||
|
*
|
||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||
|
* copy of this software and associated documentation files (the "Software"),
|
||
|
* to deal in the Software without restriction, including without limitation
|
||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||
|
* Software is furnished to do so, subject to the following conditions:
|
||
|
*
|
||
|
* The above copyright notice and this permission notice shall be included in
|
||
|
* all copies or substantial portions of the Software.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
|
* THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
|
||
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
||
|
* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
||
|
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
static char rcsid[] = "$Id$";
|
||
|
*/
|
||
|
|
||
|
#include <ft2build.h>
|
||
|
|
||
|
#include FT_INTERNAL_DEBUG_H
|
||
|
#include FT_INTERNAL_STREAM_H
|
||
|
#include FT_INTERNAL_OBJECTS_H
|
||
|
|
||
|
#include "bdf.h"
|
||
|
|
||
|
#include "bdferror.h"
|
||
|
|
||
|
#undef MAX
|
||
|
#define MAX(h, i) ((h) > (i) ? (h) : (i))
|
||
|
|
||
|
#undef MIN
|
||
|
#define MIN(l, o) ((l) < (o) ? (l) : (o))
|
||
|
|
||
|
/**************************************************************************
|
||
|
*
|
||
|
* Masks used for checking different bits per pixel cases.
|
||
|
*
|
||
|
**************************************************************************/
|
||
|
|
||
|
static const unsigned char onebpp[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
|
||
|
static const unsigned char twobpp[] = { 0xc0, 0x30, 0x0c, 0x03 };
|
||
|
static const unsigned char fourbpp[] = { 0xf0, 0x0f };
|
||
|
static const unsigned char eightbpp[] = { 0xff };
|
||
|
|
||
|
/**************************************************************************
|
||
|
*
|
||
|
* Default BDF font options.
|
||
|
*
|
||
|
**************************************************************************/
|
||
|
|
||
|
static const bdf_options_t _bdf_opts =
|
||
|
{
|
||
|
1, /* Hint TTF glyphs. */
|
||
|
1, /* Correct metrics. */
|
||
|
1, /* Preserve unencoded glyphs. */
|
||
|
1, /* Preserve comments. */
|
||
|
1, /* Pad character-cells. */
|
||
|
BDF_PROPORTIONAL, /* Default spacing. */
|
||
|
12, /* Default point size. */
|
||
|
0, /* Default horizontal resolution. */
|
||
|
0, /* Default vertical resolution. */
|
||
|
1, /* Bits per pixel. */
|
||
|
BDF_UNIX_EOL, /* Line separator. */
|
||
|
};
|
||
|
|
||
|
/**************************************************************************
|
||
|
*
|
||
|
* Builtin BDF font properties.
|
||
|
*
|
||
|
**************************************************************************/
|
||
|
|
||
|
/*
|
||
|
* List of most properties that might appear in a font. Doesn't include the
|
||
|
* RAW_* and AXIS_* properties in X11R6 polymorphic fonts.
|
||
|
*/
|
||
|
static const bdf_property_t _bdf_properties[] =
|
||
|
{
|
||
|
{"ADD_STYLE_NAME", BDF_ATOM, 1},
|
||
|
{"AVERAGE_WIDTH", BDF_INTEGER, 1},
|
||
|
{"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1},
|
||
|
{"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1},
|
||
|
{"CAP_HEIGHT", BDF_INTEGER, 1},
|
||
|
{"CHARSET_COLLECTIONS", BDF_ATOM, 1},
|
||
|
{"CHARSET_ENCODING", BDF_ATOM, 1},
|
||
|
{"CHARSET_REGISTRY", BDF_ATOM, 1},
|
||
|
{"COMMENT", BDF_ATOM, 1},
|
||
|
{"COPYRIGHT", BDF_ATOM, 1},
|
||
|
{"DEFAULT_CHAR", BDF_CARDINAL, 1},
|
||
|
{"DESTINATION", BDF_CARDINAL, 1},
|
||
|
{"DEVICE_FONT_NAME", BDF_ATOM, 1},
|
||
|
{"END_SPACE", BDF_INTEGER, 1},
|
||
|
{"FACE_NAME", BDF_ATOM, 1},
|
||
|
{"FAMILY_NAME", BDF_ATOM, 1},
|
||
|
{"FIGURE_WIDTH", BDF_INTEGER, 1},
|
||
|
{"FONT", BDF_ATOM, 1},
|
||
|
{"FONTNAME_REGISTRY", BDF_ATOM, 1},
|
||
|
{"FONT_ASCENT", BDF_INTEGER, 1},
|
||
|
{"FONT_DESCENT", BDF_INTEGER, 1},
|
||
|
{"FOUNDRY", BDF_ATOM, 1},
|
||
|
{"FULL_NAME", BDF_ATOM, 1},
|
||
|
{"ITALIC_ANGLE", BDF_INTEGER, 1},
|
||
|
{"MAX_SPACE", BDF_INTEGER, 1},
|
||
|
{"MIN_SPACE", BDF_INTEGER, 1},
|
||
|
{"NORM_SPACE", BDF_INTEGER, 1},
|
||
|
{"NOTICE", BDF_ATOM, 1},
|
||
|
{"PIXEL_SIZE", BDF_INTEGER, 1},
|
||
|
{"POINT_SIZE", BDF_INTEGER, 1},
|
||
|
{"QUAD_WIDTH", BDF_INTEGER, 1},
|
||
|
{"RAW_ASCENT", BDF_INTEGER, 1},
|
||
|
{"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1},
|
||
|
{"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1},
|
||
|
{"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1},
|
||
|
{"RAW_CAP_HEIGHT", BDF_INTEGER, 1},
|
||
|
{"RAW_DESCENT", BDF_INTEGER, 1},
|
||
|
{"RAW_END_SPACE", BDF_INTEGER, 1},
|
||
|
{"RAW_FIGURE_WIDTH", BDF_INTEGER, 1},
|
||
|
{"RAW_MAX_SPACE", BDF_INTEGER, 1},
|
||
|
{"RAW_MIN_SPACE", BDF_INTEGER, 1},
|
||
|
{"RAW_NORM_SPACE", BDF_INTEGER, 1},
|
||
|
{"RAW_PIXEL_SIZE", BDF_INTEGER, 1},
|
||
|
{"RAW_POINT_SIZE", BDF_INTEGER, 1},
|
||
|
{"RAW_PIXELSIZE", BDF_INTEGER, 1},
|
||
|
{"RAW_POINTSIZE", BDF_INTEGER, 1},
|
||
|
{"RAW_QUAD_WIDTH", BDF_INTEGER, 1},
|
||
|
{"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1},
|
||
|
{"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1},
|
||
|
{"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1},
|
||
|
{"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1},
|
||
|
{"RAW_SUBSCRIPT_X", BDF_INTEGER, 1},
|
||
|
{"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1},
|
||
|
{"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1},
|
||
|
{"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1},
|
||
|
{"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1},
|
||
|
{"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1},
|
||
|
{"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1},
|
||
|
{"RAW_X_HEIGHT", BDF_INTEGER, 1},
|
||
|
{"RELATIVE_SETWIDTH", BDF_CARDINAL, 1},
|
||
|
{"RELATIVE_WEIGHT", BDF_CARDINAL, 1},
|
||
|
{"RESOLUTION", BDF_INTEGER, 1},
|
||
|
{"RESOLUTION_X", BDF_CARDINAL, 1},
|
||
|
{"RESOLUTION_Y", BDF_CARDINAL, 1},
|
||
|
{"SETWIDTH_NAME", BDF_ATOM, 1},
|
||
|
{"SLANT", BDF_ATOM, 1},
|
||
|
{"SMALL_CAP_SIZE", BDF_INTEGER, 1},
|
||
|
{"SPACING", BDF_ATOM, 1},
|
||
|
{"STRIKEOUT_ASCENT", BDF_INTEGER, 1},
|
||
|
{"STRIKEOUT_DESCENT", BDF_INTEGER, 1},
|
||
|
{"SUBSCRIPT_SIZE", BDF_INTEGER, 1},
|
||
|
{"SUBSCRIPT_X", BDF_INTEGER, 1},
|
||
|
{"SUBSCRIPT_Y", BDF_INTEGER, 1},
|
||
|
{"SUPERSCRIPT_SIZE", BDF_INTEGER, 1},
|
||
|
{"SUPERSCRIPT_X", BDF_INTEGER, 1},
|
||
|
{"SUPERSCRIPT_Y", BDF_INTEGER, 1},
|
||
|
{"UNDERLINE_POSITION", BDF_INTEGER, 1},
|
||
|
{"UNDERLINE_THICKNESS", BDF_INTEGER, 1},
|
||
|
{"WEIGHT", BDF_CARDINAL, 1},
|
||
|
{"WEIGHT_NAME", BDF_ATOM, 1},
|
||
|
{"X_HEIGHT", BDF_INTEGER, 1},
|
||
|
{"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1},
|
||
|
{"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1},
|
||
|
};
|
||
|
|
||
|
static const FT_ULong _num_bdf_properties = FT_NUM_ELEMENT(_bdf_properties);
|
||
|
|
||
|
/*
|
||
|
* User defined properties.
|
||
|
*/
|
||
|
/*static bdf_property_t *user_props;
|
||
|
static unsigned long nuser_props = 0;*/
|
||
|
|
||
|
/**************************************************************************
|
||
|
*
|
||
|
* Hash table utilities for the properties.
|
||
|
*
|
||
|
**************************************************************************/
|
||
|
|
||
|
#define INITIAL_HT_SIZE 241
|
||
|
|
||
|
typedef void (*hash_free_func)(hashnode node);
|
||
|
|
||
|
static hashnode*
|
||
|
hash_bucket(char *key, hashtable *ht)
|
||
|
{
|
||
|
char* kp = key;
|
||
|
unsigned long res = 0;
|
||
|
hashnode* bp = ht->table, *ndp;
|
||
|
|
||
|
/*
|
||
|
* Mocklisp hash function.
|
||
|
*/
|
||
|
while (*kp)
|
||
|
res = (res << 5) - res + *kp++;
|
||
|
|
||
|
ndp = bp + (res % ht->size);
|
||
|
while (*ndp)
|
||
|
{
|
||
|
kp = (*ndp)->key;
|
||
|
|
||
|
if (kp[0] == key[0] && ft_strcmp(kp, key) == 0)
|
||
|
break;
|
||
|
|
||
|
ndp--;
|
||
|
if (ndp < bp)
|
||
|
ndp = bp + (ht->size - 1);
|
||
|
}
|
||
|
return ndp;
|
||
|
}
|
||
|
|
||
|
|
||
|
static FT_Error
|
||
|
hash_rehash ( hashtable* ht,
|
||
|
FT_Memory memory )
|
||
|
{
|
||
|
hashnode *obp = ht->table, *bp, *nbp;
|
||
|
int i, sz = ht->size;
|
||
|
FT_Error error;
|
||
|
|
||
|
ht->size <<= 1;
|
||
|
ht->limit = ht->size / 3;
|
||
|
|
||
|
if ( FT_NEW_ARRAY( ht->table , ht->size ) )
|
||
|
return error;
|
||
|
|
||
|
for (i = 0, bp = obp; i < sz; i++, bp++)
|
||
|
{
|
||
|
if (*bp)
|
||
|
{
|
||
|
nbp = hash_bucket((*bp)->key, ht);
|
||
|
*nbp = *bp;
|
||
|
}
|
||
|
}
|
||
|
FT_FREE(obp);
|
||
|
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
static FT_Error
|
||
|
hash_init ( hashtable* ht,
|
||
|
FT_Memory memory )
|
||
|
{
|
||
|
int sz = INITIAL_HT_SIZE;
|
||
|
FT_Error error;
|
||
|
|
||
|
ht->size = sz;
|
||
|
ht->limit = sz / 3;
|
||
|
ht->used = 0;
|
||
|
|
||
|
if ( FT_NEW_ARRAY( ht->table, size ) )
|
||
|
return error;
|
||
|
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
hash_free( hashtable* ht,
|
||
|
FT_Memory memory )
|
||
|
{
|
||
|
/* FT_Error error; */
|
||
|
|
||
|
if ( ht != 0 )
|
||
|
{
|
||
|
int i, sz = ht->size;
|
||
|
hashnode* bp = ht->table;
|
||
|
|
||
|
for (i = 0; i < sz; i++, bp++)
|
||
|
{
|
||
|
if (*bp)
|
||
|
FT_FREE(*bp);
|
||
|
}
|
||
|
if (sz > 0)
|
||
|
FT_FREE(ht->table);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static FT_Error
|
||
|
hash_insert ( char* key,
|
||
|
void* data,
|
||
|
hashtable* ht,
|
||
|
FT_Memory memory )
|
||
|
{
|
||
|
FT_Error error = FT_Err_Ok;
|
||
|
hashnode nn, *bp = hash_bucket(key, ht);
|
||
|
|
||
|
nn = *bp;
|
||
|
if (!nn)
|
||
|
{
|
||
|
if ( FT_NEW( nn ) )
|
||
|
return error;
|
||
|
|
||
|
*bp = nn;
|
||
|
nn->key = key;
|
||
|
nn->data = data;
|
||
|
|
||
|
if (ht->used >= ht->limit)
|
||
|
error = hash_rehash(ht, memory);
|
||
|
|
||
|
ht->used++;
|
||
|
}
|
||
|
else
|
||
|
nn->data = data;
|
||
|
|
||
|
return error;
|
||
|
}
|
||
|
|
||
|
|
||
|
static hashnode
|
||
|
hash_lookup(char *key, hashtable *ht)
|
||
|
{
|
||
|
hashnode *np = hash_bucket(key, ht);
|
||
|
return *np;
|
||
|
}
|
||
|
|
||
|
#ifdef 0
|
||
|
static void
|
||
|
hash_delete(char *name, hashtable *ht , FT_Memory memory)
|
||
|
{
|
||
|
hashnode *hp;
|
||
|
/* FT_Error error; */
|
||
|
|
||
|
hp = hash_bucket(name, ht);
|
||
|
FT_FREE( *hp );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* The builtin property table.
|
||
|
*/
|
||
|
/*static hashtable proptbl; */ /* XXX eliminate this */
|
||
|
|
||
|
|
||
|
|
||
|
/**************************************************************************
|
||
|
*
|
||
|
* Utility types and functions.
|
||
|
*
|
||
|
**************************************************************************/
|
||
|
|
||
|
/*
|
||
|
* Function type for parsing lines of a BDF font.
|
||
|
*/
|
||
|
typedef int (*_bdf_line_func_t)( char* line,
|
||
|
unsigned long linelen,
|
||
|
unsigned long lineno,
|
||
|
void* call_data,
|
||
|
void* client_data );
|
||
|
|
||
|
/*
|
||
|
* List structure for splitting lines into fields.
|
||
|
*/
|
||
|
typedef struct
|
||
|
{
|
||
|
char** field;
|
||
|
unsigned long size;
|
||
|
unsigned long used;
|
||
|
char* bfield;
|
||
|
unsigned long bsize;
|
||
|
unsigned long bused;
|
||
|
|
||
|
} _bdf_list_t;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Structure used while loading BDF fonts.
|
||
|
*/
|
||
|
typedef struct
|
||
|
{
|
||
|
unsigned long flags;
|
||
|
unsigned long cnt;
|
||
|
unsigned long row;
|
||
|
unsigned long bpr;
|
||
|
short minlb;
|
||
|
short maxlb;
|
||
|
short maxrb;
|
||
|
short maxas;
|
||
|
short maxds;
|
||
|
short rbearing;
|
||
|
char* glyph_name;
|
||
|
long glyph_enc;
|
||
|
bdf_font_t* font;
|
||
|
bdf_options_t* opts;
|
||
|
void* client_data;
|
||
|
bdf_callback_t callback;
|
||
|
bdf_callback_struct_t cb;
|
||
|
unsigned long have[2048];
|
||
|
_bdf_list_t list;
|
||
|
|
||
|
FT_Memory memory;
|
||
|
|
||
|
} _bdf_parse_t;
|
||
|
|
||
|
#define setsbit(m, cc) (m[(cc) >> 3] |= (1 << ((cc) & 7)))
|
||
|
#define sbitset(m, cc) (m[(cc) >> 3] & (1 << ((cc) & 7)))
|
||
|
|
||
|
/*
|
||
|
* An empty string for empty fields.
|
||
|
*/
|
||
|
static const char empty[1] = { 0 }; /* XXX eliminate this */
|
||
|
|
||
|
/*
|
||
|
* Assume the line is NULL terminated and that the `list' parameter was
|
||
|
* initialized the first time it was used.
|
||
|
*/
|
||
|
static FT_Error
|
||
|
_bdf_split ( char* separators,
|
||
|
char* line,
|
||
|
unsigned long linelen,
|
||
|
_bdf_list_t* list,
|
||
|
FT_Memory memory )
|
||
|
{
|
||
|
int mult, final_empty;
|
||
|
char *sp, *ep, *end;
|
||
|
unsigned char seps[32];
|
||
|
FT_Error error;
|
||
|
|
||
|
/*
|
||
|
* Initialize the list.
|
||
|
*/
|
||
|
list->used = list->bused = 0;
|
||
|
|
||
|
/*
|
||
|
* If the line is empty, then simply return.
|
||
|
*/
|
||
|
if ( linelen == 0 || line[0] == 0 )
|
||
|
return FT_Err_Ok;
|
||
|
|
||
|
/*
|
||
|
* If the `separators' parameter is NULL or empty, split the list into
|
||
|
* individual bytes.
|
||
|
*/
|
||
|
if ( separators == 0 || *separators == 0 )
|
||
|
{
|
||
|
if ( linelen > list->bsize )
|
||
|
{
|
||
|
if ( list->bsize )
|
||
|
{
|
||
|
if ( FT_ALLOC ( list->bfield , linelen) )
|
||
|
return error;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( FT_REALLOC ( list->bfield , list->bsize, linelen) )
|
||
|
return error;
|
||
|
}
|
||
|
list->bsize = linelen;
|
||
|
}
|
||
|
list->bused = linelen;
|
||
|
|
||
|
FT_MEM_COPY (list->bfield, line, linelen);
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Prepare the separator bitmap.
|
||
|
*/
|
||
|
FT_MEM_ZERO( seps, 32 );
|
||
|
|
||
|
/*
|
||
|
* If the very last character of the separator string is a plus, then set
|
||
|
* the `mult' flag to indicate that multiple separators should be
|
||
|
* collapsed into one.
|
||
|
*/
|
||
|
for ( mult = 0, sp = separators; sp && *sp; sp++ )
|
||
|
{
|
||
|
if ( sp[0] == '+' && sp[1] == 0)
|
||
|
mult = 1;
|
||
|
else
|
||
|
setsbit( seps, sp[0] );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Break the line up into fields.
|
||
|
*/
|
||
|
final_empty = 0;
|
||
|
sp = ep = line;
|
||
|
end = sp + linelen;
|
||
|
for ( ; sp < end && *sp;)
|
||
|
{
|
||
|
/*
|
||
|
* Collect everything that is not a separator.
|
||
|
*/
|
||
|
for ( ; *ep && !sbitset( seps, *ep ); ep++ ) ;
|
||
|
|
||
|
/*
|
||
|
* Resize the list if necessary.
|
||
|
*/
|
||
|
if ( list->used == list->size )
|
||
|
{
|
||
|
if ( list->size == 0 )
|
||
|
{
|
||
|
if ( FT_NEW_ARRAY( list->field , 5) )
|
||
|
return error;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( FT_RENEW_ARRAY( list->field , list->size, list->size+5 )
|
||
|
return error;
|
||
|
}
|
||
|
list->size += 5;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Assign the field appropriately.
|
||
|
*/
|
||
|
list->field[ list->used++ ] = (ep > sp) ? sp : empty;
|
||
|
|
||
|
sp = ep;
|
||
|
if (mult)
|
||
|
{
|
||
|
/*
|
||
|
* If multiple separators should be collapsed, do it now by
|
||
|
* setting all the separator characters to 0.
|
||
|
*/
|
||
|
for ( ; *ep && sbitset(seps, *ep); ep++ )
|
||
|
*ep = 0;
|
||
|
|
||
|
}
|
||
|
else if (*ep != 0)
|
||
|
{
|
||
|
/*
|
||
|
* Don't collapse multiple separators by making them 0, so just
|
||
|
* make the one encountered 0.
|
||
|
*/
|
||
|
*ep++ = 0;
|
||
|
}
|
||
|
|
||
|
final_empty = ( ep > sp && *ep == 0 );
|
||
|
sp = ep;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Finally, NULL terminate the list.
|
||
|
*/
|
||
|
if ( list->used + final_empty + 1 >= list->size )
|
||
|
{
|
||
|
if ( list->used == list->size )
|
||
|
{
|
||
|
if ( list->size == 0 )
|
||
|
{
|
||
|
if ( FT_NEW_ARRAY( list->field, 5 ) )
|
||
|
return error;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( FT_RENEW_ARRAY( list->field , list->size, list->size+5 ) )
|
||
|
return error;
|
||
|
}
|
||
|
list->size += 5;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (final_empty)
|
||
|
list->field[ list->used++ ] = empty;
|
||
|
|
||
|
if ( list->used == list->size )
|
||
|
{
|
||
|
if ( list->size == 0 )
|
||
|
{
|
||
|
if ( FT_NEW_ARRAY( list->field , 5 ) )
|
||
|
return error;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( FT_NEW_ARRAY( list->field, list->size, list->size + 5 ) )
|
||
|
return error;
|
||
|
}
|
||
|
list->size += 5;
|
||
|
}
|
||
|
list->field[ list->used ] = 0;
|
||
|
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
_bdf_shift( unsigned long n,
|
||
|
_bdf_list_t* list)
|
||
|
{
|
||
|
unsigned long i, u;
|
||
|
|
||
|
if ( list == 0 || list->used == 0 || n == 0 )
|
||
|
return;
|
||
|
|
||
|
if ( n >= list->used )
|
||
|
{
|
||
|
list->used = 0;
|
||
|
return;
|
||
|
}
|
||
|
for ( u = n, i = 0; u < list->used; i++, u++ )
|
||
|
list->field[i] = list->field[u];
|
||
|
|
||
|
list->used -= n;
|
||
|
}
|
||
|
|
||
|
|
||
|
static char*
|
||
|
_bdf_join( int c,
|
||
|
unsigned long* len,
|
||
|
_bdf_list_t* list)
|
||
|
{
|
||
|
unsigned long i, j;
|
||
|
char *fp, *dp;
|
||
|
|
||
|
if ( list == 0 || list->used == 0 )
|
||
|
return 0;
|
||
|
|
||
|
*len = 0;
|
||
|
|
||
|
dp = list->field[0];
|
||
|
|
||
|
for ( i = j = 0; i < list->used; i++ )
|
||
|
{
|
||
|
fp = list->field[i];
|
||
|
while (*fp)
|
||
|
dp[j++] = *fp++;
|
||
|
|
||
|
if (i + 1 < list->used)
|
||
|
dp[j++] = c;
|
||
|
}
|
||
|
dp[j] = 0;
|
||
|
|
||
|
*len = j;
|
||
|
return dp;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* High speed file reader that passes each line to a callback.
|
||
|
*/
|
||
|
int ftreadstream( FT_Stream stream,
|
||
|
char* buffer,
|
||
|
int count )
|
||
|
{
|
||
|
int read_bytes;
|
||
|
int pos = stream->pos;
|
||
|
|
||
|
if ( pos >= stream->size )
|
||
|
{
|
||
|
FT_ERROR(( "FT_Read_Stream_At:" ));
|
||
|
FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
|
||
|
pos, stream->size ));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if ( stream->read )
|
||
|
read_bytes = stream->read( stream, pos, buffer, count );
|
||
|
else
|
||
|
{
|
||
|
read_bytes = stream->size - pos;
|
||
|
if ( read_bytes > count )
|
||
|
read_bytes = count;
|
||
|
|
||
|
ft_memcpy( buffer, stream->base + pos, read_bytes );
|
||
|
}
|
||
|
|
||
|
stream->pos = pos + read_bytes;
|
||
|
|
||
|
return read_bytes;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
_bdf_readstream( FT_Stream stream,
|
||
|
_bdf_line_func_t callback,
|
||
|
void* client_data,
|
||
|
unsigned long* lno)
|
||
|
{
|
||
|
_bdf_line_func_t cb;
|
||
|
unsigned long lineno;
|
||
|
int n, res, done, refill, bytes, hold;
|
||
|
char *ls, *le, *pp, *pe, *hp;
|
||
|
char buf[65536];
|
||
|
|
||
|
if (callback == 0)
|
||
|
return -1;
|
||
|
|
||
|
cb = callback;
|
||
|
lineno = 1;
|
||
|
buf[0] = 0;
|
||
|
res = done = 0;
|
||
|
pp = ls = le = buf;
|
||
|
bytes = 65536;
|
||
|
|
||
|
while ( !done && (n = ftreadstream(stream, pp, bytes)) > 0 )
|
||
|
{
|
||
|
/*
|
||
|
* Determine the new end of the buffer pages.
|
||
|
*/
|
||
|
pe = pp + n;
|
||
|
|
||
|
for (refill = 0; done == 0 && refill == 0; )
|
||
|
{
|
||
|
while (le < pe && *le != '\n' && *le != '\r')
|
||
|
le++;
|
||
|
|
||
|
if (le == pe)
|
||
|
{
|
||
|
/*
|
||
|
* Hit the end of the last page in the buffer. Need to find
|
||
|
* out how many pages to shift and how many pages need to be
|
||
|
* read in. Adjust the line start and end pointers down to
|
||
|
* point to the right places in the pages.
|
||
|
*/
|
||
|
pp = buf + (((ls - buf) >> 13) << 13);
|
||
|
n = pp - buf;
|
||
|
ls -= n;
|
||
|
le -= n;
|
||
|
n = pe - pp;
|
||
|
(void) ft_memcpy(buf, pp, n);
|
||
|
pp = buf + n;
|
||
|
bytes = 65536 - n;
|
||
|
refill = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/*
|
||
|
* Temporarily NULL terminate the line.
|
||
|
*/
|
||
|
hp = le;
|
||
|
hold = *le;
|
||
|
*le = 0;
|
||
|
|
||
|
if (callback && *ls != '#' && *ls != 0x1a && le > ls &&
|
||
|
(res = (*cb)(ls, le - ls, lineno, (void *) &cb,
|
||
|
client_data)) != 0)
|
||
|
done = 1;
|
||
|
else {
|
||
|
ls = ++le;
|
||
|
/*
|
||
|
* Handle the case of DOS crlf sequences.
|
||
|
*/
|
||
|
if (le < pe && hold == '\n' && *le =='\r')
|
||
|
ls = ++le;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Increment the line number.
|
||
|
*/
|
||
|
lineno++;
|
||
|
|
||
|
/*
|
||
|
* Restore the character at the end of the line.
|
||
|
*/
|
||
|
*hp = hold;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
*lno = lineno;
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
|
||
|
FT_LOCAL_DEF( void )
|
||
|
_bdf_memmove(char *dest, char *src, unsigned long bytes)
|
||
|
{
|
||
|
long i, j;
|
||
|
|
||
|
i = (long) bytes;
|
||
|
j = i & 7;
|
||
|
i = (i + 7) >> 3;
|
||
|
|
||
|
/*
|
||
|
* Do a memmove using Ye Olde Duff's Device for efficiency.
|
||
|
*/
|
||
|
if (src < dest) {
|
||
|
src += bytes;
|
||
|
dest += bytes;
|
||
|
|
||
|
switch (j) {
|
||
|
case 0: do {
|
||
|
*--dest = *--src;
|
||
|
case 7: *--dest = *--src;
|
||
|
case 6: *--dest = *--src;
|
||
|
case 5: *--dest = *--src;
|
||
|
case 4: *--dest = *--src;
|
||
|
case 3: *--dest = *--src;
|
||
|
case 2: *--dest = *--src;
|
||
|
case 1: *--dest = *--src;
|
||
|
} while (--i > 0);
|
||
|
}
|
||
|
} else if (src > dest) {
|
||
|
switch (j) {
|
||
|
case 0: do {
|
||
|
*dest++ = *src++;
|
||
|
case 7: *dest++ = *src++;
|
||
|
case 6: *dest++ = *src++;
|
||
|
case 5: *dest++ = *src++;
|
||
|
case 4: *dest++ = *src++;
|
||
|
case 3: *dest++ = *src++;
|
||
|
case 2: *dest++ = *src++;
|
||
|
case 1: *dest++ = *src++;
|
||
|
} while (--i > 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static const unsigned char a2i[128] = {
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||
|
};
|
||
|
|
||
|
static const unsigned char odigits[32] = {
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
};
|
||
|
|
||
|
static const unsigned char ddigits[32] = {
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
};
|
||
|
|
||
|
static const unsigned char hdigits[32] = {
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
|
||
|
0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
};
|
||
|
|
||
|
#define isdigok(m, d) (m[(d) >> 3] & (1 << ((d) & 7)))
|
||
|
|
||
|
/*
|
||
|
* Routine to convert an ASCII string into an unsigned long integer.
|
||
|
*/
|
||
|
static unsigned long
|
||
|
_bdf_atoul(char *s, char **end, int base)
|
||
|
{
|
||
|
unsigned long v;
|
||
|
unsigned char *dmap;
|
||
|
|
||
|
if (s == 0 || *s == 0)
|
||
|
return 0;
|
||
|
|
||
|
/*
|
||
|
* Make sure the radix is something recognizable. Default to 10.
|
||
|
*/
|
||
|
switch (base)
|
||
|
{
|
||
|
case 8: dmap = odigits; break;
|
||
|
case 16: dmap = hdigits; break;
|
||
|
default: base = 10; dmap = ddigits; break;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check for the special hex prefix.
|
||
|
*/
|
||
|
if ( s[0] == '0' && ( s[1] == 'x' || s[1] == 'X'))
|
||
|
{
|
||
|
base = 16;
|
||
|
dmap = hdigits;
|
||
|
s += 2;
|
||
|
}
|
||
|
|
||
|
for ( v = 0; isdigok(dmap, *s); s++ )
|
||
|
v = (v * base) + a2i[(int) *s];
|
||
|
|
||
|
if (end != 0)
|
||
|
*end = s;
|
||
|
|
||
|
return v;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Routine to convert an ASCII string into an signed long integer.
|
||
|
*/
|
||
|
static long
|
||
|
_bdf_atol(char *s, char **end, int base)
|
||
|
{
|
||
|
long v, neg;
|
||
|
unsigned char *dmap;
|
||
|
|
||
|
if (s == 0 || *s == 0)
|
||
|
return 0;
|
||
|
|
||
|
/*
|
||
|
* Make sure the radix is something recognizable. Default to 10.
|
||
|
*/
|
||
|
switch (base) {
|
||
|
case 8: dmap = odigits; break;
|
||
|
case 16: dmap = hdigits; break;
|
||
|
default: base = 10; dmap = ddigits; break;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check for a minus sign.
|
||
|
*/
|
||
|
neg = 0;
|
||
|
if (*s == '-') {
|
||
|
s++;
|
||
|
neg = 1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check for the special hex prefix.
|
||
|
*/
|
||
|
if (*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) {
|
||
|
base = 16;
|
||
|
dmap = hdigits;
|
||
|
s += 2;
|
||
|
}
|
||
|
|
||
|
for (v = 0; isdigok(dmap, *s); s++)
|
||
|
v = (v * base) + a2i[(int) *s];
|
||
|
|
||
|
if (end != 0)
|
||
|
*end = s;
|
||
|
|
||
|
return (!neg) ? v : -v;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Routine to convert an ASCII string into an signed short integer.
|
||
|
*/
|
||
|
static short
|
||
|
_bdf_atos(char *s, char **end, int base)
|
||
|
{
|
||
|
short v, neg;
|
||
|
unsigned char *dmap;
|
||
|
|
||
|
if (s == 0 || *s == 0)
|
||
|
return 0;
|
||
|
|
||
|
/*
|
||
|
* Make sure the radix is something recognizable. Default to 10.
|
||
|
*/
|
||
|
switch (base) {
|
||
|
case 8: dmap = odigits; break;
|
||
|
case 16: dmap = hdigits; break;
|
||
|
default: base = 10; dmap = ddigits; break;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check for a minus.
|
||
|
*/
|
||
|
neg = 0;
|
||
|
if (*s == '-') {
|
||
|
s++;
|
||
|
neg = 1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check for the special hex prefix.
|
||
|
*/
|
||
|
if (*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) {
|
||
|
base = 16;
|
||
|
dmap = hdigits;
|
||
|
s += 2;
|
||
|
}
|
||
|
|
||
|
for (v = 0; isdigok(dmap, *s); s++)
|
||
|
v = (v * base) + a2i[(int) *s];
|
||
|
|
||
|
if (end != 0)
|
||
|
*end = s;
|
||
|
|
||
|
return (!neg) ? v : -v;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Routine to compare two glyphs by encoding so they can be sorted.
|
||
|
*/
|
||
|
static int
|
||
|
by_encoding(const void *a, const void *b)
|
||
|
{
|
||
|
bdf_glyph_t *c1, *c2;
|
||
|
|
||
|
c1 = (bdf_glyph_t *) a;
|
||
|
c2 = (bdf_glyph_t *) b;
|
||
|
if (c1->encoding < c2->encoding)
|
||
|
return -1;
|
||
|
else if (c1->encoding > c2->encoding)
|
||
|
return 1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
static FT_Error
|
||
|
bdf_create_property( char* name,
|
||
|
int format,
|
||
|
bdf_font_t* font )
|
||
|
{
|
||
|
unsigned long n;
|
||
|
bdf_property_t* p;
|
||
|
FT_Memory memory = font->memory;
|
||
|
FT_Error error;
|
||
|
|
||
|
/*
|
||
|
* First check to see if the property has
|
||
|
* already been added or not. If it has, then
|
||
|
* simply ignore it.
|
||
|
*/
|
||
|
if ( hash_lookup( name, &(font->proptbl)) )
|
||
|
return FT_Err_Ok;
|
||
|
|
||
|
if (font->nuser_props == 0)
|
||
|
{
|
||
|
if ( FT_NEW( font->user_props ) )
|
||
|
return error;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( FT_RENEW_ARRAY( font->user_props, font->nuser_props,
|
||
|
(font->nuser_props + 1) ) )
|
||
|
return error;
|
||
|
}
|
||
|
|
||
|
p = font->user_props + font->nuser_props;
|
||
|
|
||
|
FT_ZERO( p );
|
||
|
|
||
|
n = (unsigned long) (ft_strlen(name) + 1);
|
||
|
|
||
|
if ( FT_ALLOC ( p->name , n) )
|
||
|
return error;
|
||
|
|
||
|
FT_MEM_COPY(p->name, name, n);
|
||
|
p->format = format;
|
||
|
p->builtin = 0;
|
||
|
|
||
|
n = _num_bdf_properties + font->nuser_props;
|
||
|
|
||
|
error = hash_insert(p->name, (void *) n, &(font->proptbl) , memory);
|
||
|
if (error) return error;
|
||
|
|
||
|
font->nuser_props++;
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
FT_LOCAL_DEF( bdf_property_t* )
|
||
|
bdf_get_property(char *name, bdf_font_t *font)
|
||
|
{
|
||
|
hashnode hn;
|
||
|
unsigned long propid;
|
||
|
|
||
|
if (name == 0 || *name == 0)
|
||
|
return 0;
|
||
|
|
||
|
if ((hn = hash_lookup(name, &(font->proptbl))) == 0)
|
||
|
return 0;
|
||
|
|
||
|
propid = (unsigned long) hn->data;
|
||
|
if (propid >= _num_bdf_properties)
|
||
|
return font->user_props + (propid - _num_bdf_properties);
|
||
|
|
||
|
return _bdf_properties + propid;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**************************************************************************
|
||
|
*
|
||
|
* BDF font file parsing flags and functions.
|
||
|
*
|
||
|
**************************************************************************/
|
||
|
|
||
|
/*
|
||
|
* Parse flags.
|
||
|
*/
|
||
|
#define _BDF_START 0x0001
|
||
|
#define _BDF_FONT_NAME 0x0002
|
||
|
#define _BDF_SIZE 0x0004
|
||
|
#define _BDF_FONT_BBX 0x0008
|
||
|
#define _BDF_PROPS 0x0010
|
||
|
#define _BDF_GLYPHS 0x0020
|
||
|
#define _BDF_GLYPH 0x0040
|
||
|
#define _BDF_ENCODING 0x0080
|
||
|
#define _BDF_SWIDTH 0x0100
|
||
|
#define _BDF_DWIDTH 0x0200
|
||
|
#define _BDF_BBX 0x0400
|
||
|
#define _BDF_BITMAP 0x0800
|
||
|
|
||
|
#define _BDF_SWIDTH_ADJ 0x1000
|
||
|
|
||
|
#define _BDF_GLYPH_BITS (_BDF_GLYPH|_BDF_ENCODING|_BDF_SWIDTH|\
|
||
|
_BDF_DWIDTH|_BDF_BBX|_BDF_BITMAP)
|
||
|
|
||
|
#define _BDF_GLYPH_WIDTH_CHECK 0x40000000
|
||
|
#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000
|
||
|
|
||
|
/*
|
||
|
* Auto correction messages.
|
||
|
*/
|
||
|
#define ACMSG1 "FONT_ASCENT property missing. Added \"FONT_ASCENT %hd\"."
|
||
|
#define ACMSG2 "FONT_DESCENT property missing. Added \"FONT_DESCENT %hd\"."
|
||
|
#define ACMSG3 "Font width != actual width. Old: %hd New: %hd."
|
||
|
#define ACMSG4 "Font left bearing != actual left bearing. Old: %hd New: %hd."
|
||
|
#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd."
|
||
|
#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd."
|
||
|
#define ACMSG7 "Font height != actual height. Old: %hd New: %hd."
|
||
|
#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made."
|
||
|
#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically."
|
||
|
#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width."
|
||
|
#define ACMSG11 "SIZE bits per pixel field adjusted to %hd."
|
||
|
#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded."
|
||
|
#define ACMSG13 "Glyph %ld extra rows removed."
|
||
|
#define ACMSG14 "Glyph %ld extra columns removed."
|
||
|
#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found."
|
||
|
|
||
|
/*
|
||
|
* Error messages.
|
||
|
*/
|
||
|
#define ERRMSG1 "[line %ld] Missing \"%s\" line."
|
||
|
#define ERRMSG2 "[line %ld] Font header corrupted or missing fields."
|
||
|
#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields."
|
||
|
|
||
|
static FT_Error
|
||
|
_bdf_add_acmsg ( bdf_font_t* font,
|
||
|
char* msg,
|
||
|
unsigned long len )
|
||
|
{
|
||
|
char* cp;
|
||
|
FT_Memory memory = font->memory;
|
||
|
FT_Error error;
|
||
|
|
||
|
if ( font->acmsgs_len == 0 )
|
||
|
{
|
||
|
if ( FT_ALLOC ( font->acmsgs , len + 1 ) )
|
||
|
return error;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( FT_REALLOC ( font->acmsgs , font->acmsgs_len ,
|
||
|
font->acmsgs_len + len + 1 ) )
|
||
|
return error;
|
||
|
}
|
||
|
|
||
|
cp = font->acmsgs + font->acmsgs_len;
|
||
|
FT_MEM_COPY(cp, msg, len);
|
||
|
cp += len;
|
||
|
*cp++ = '\n';
|
||
|
font->acmsgs_len += len + 1;
|
||
|
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
static FT_Error
|
||
|
_bdf_add_comment ( bdf_font_t* font,
|
||
|
char* comment,
|
||
|
unsigned long len )
|
||
|
{
|
||
|
char *cp;
|
||
|
FT_Memory memory = font->memory;
|
||
|
FT_Error error;
|
||
|
|
||
|
if (font->comments_len == 0) {
|
||
|
if ( FT_ALLOC ( font->comments , len + 1 ) )
|
||
|
return error;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( FT_REALLOC ( font->comments , font->comments_len,
|
||
|
font->comments_len + len + 1) )
|
||
|
return error;
|
||
|
}
|
||
|
|
||
|
cp = font->comments + font->comments_len;
|
||
|
FT_MEM_COPY(cp, comment, len);
|
||
|
cp += len;
|
||
|
*cp++ = '\n';
|
||
|
font->comments_len += len + 1;
|
||
|
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Set the spacing from the font name if it exists, or set it to the default
|
||
|
* specified in the options.
|
||
|
*/
|
||
|
static void
|
||
|
_bdf_set_default_spacing( bdf_font_t* font,
|
||
|
bdf_options_t* opts)
|
||
|
{
|
||
|
unsigned long len;
|
||
|
char name[128];
|
||
|
_bdf_list_t list;
|
||
|
FT_Memory memory;
|
||
|
/* FT_Error error; */
|
||
|
|
||
|
if ( font == 0 || font->name == 0 || font->name[0] == 0 )
|
||
|
return;
|
||
|
|
||
|
memory = font->memory;
|
||
|
|
||
|
font->spacing = opts->font_spacing;
|
||
|
|
||
|
len = (unsigned long) ( ft_strlen(font->name) + 1 );
|
||
|
(void) ft_memcpy(name, font->name, len);
|
||
|
|
||
|
list.size = list.used = 0;
|
||
|
_bdf_split("-", name, len, &list, memory);
|
||
|
|
||
|
if (list.used == 15) {
|
||
|
switch (list.field[11][0]) {
|
||
|
case 'C': case 'c': font->spacing = BDF_CHARCELL; break;
|
||
|
case 'M': case 'm': font->spacing = BDF_MONOWIDTH; break;
|
||
|
case 'P': case 'p': font->spacing = BDF_PROPORTIONAL; break;
|
||
|
}
|
||
|
}
|
||
|
if (list.size > 0)
|
||
|
FT_FREE(list.field);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Determine if the property is an atom or not. If it is, then clean it up so
|
||
|
* the double quotes are removed if they exist.
|
||
|
*/
|
||
|
static int
|
||
|
_bdf_is_atom( char* line,
|
||
|
unsigned long linelen,
|
||
|
char* *name,
|
||
|
char* *value,
|
||
|
bdf_font_t* font)
|
||
|
{
|
||
|
int hold;
|
||
|
char *sp, *ep;
|
||
|
bdf_property_t *p;
|
||
|
|
||
|
*name = sp = ep = line;
|
||
|
while (*ep && *ep != ' ' && *ep != '\t')
|
||
|
ep++;
|
||
|
|
||
|
hold = -1;
|
||
|
if (*ep)
|
||
|
{
|
||
|
hold = *ep;
|
||
|
*ep = 0;
|
||
|
}
|
||
|
|
||
|
p = bdf_get_property(sp, font);
|
||
|
|
||
|
/*
|
||
|
* Restore the character that was saved before any return can happen.
|
||
|
*/
|
||
|
if (hold != -1)
|
||
|
*ep = hold;
|
||
|
|
||
|
/*
|
||
|
* If the propert exists and is not an atom, just return here.
|
||
|
*/
|
||
|
if (p && p->format != BDF_ATOM)
|
||
|
return 0;
|
||
|
|
||
|
/*
|
||
|
* The property is an atom. Trim all leading and trailing whitespace and
|
||
|
* double quotes for the atom value.
|
||
|
*/
|
||
|
sp = ep;
|
||
|
ep = line + linelen;
|
||
|
|
||
|
/*
|
||
|
* Trim the leading whitespace if it exists.
|
||
|
*/
|
||
|
*sp++ = 0;
|
||
|
while (*sp && (*sp == ' ' || *sp == '\t'))
|
||
|
sp++;
|
||
|
|
||
|
/*
|
||
|
* Trim the leading double quote if it exists.
|
||
|
*/
|
||
|
if (*sp == '"')
|
||
|
sp++;
|
||
|
*value = sp;
|
||
|
|
||
|
/*
|
||
|
* Trim the trailing whitespace if it exists.
|
||
|
*/
|
||
|
while (ep > sp && (*(ep - 1) == ' ' || *(ep - 1) == '\t'))
|
||
|
*--ep = 0;
|
||
|
|
||
|
/*
|
||
|
* Trim the trailing double quote if it exists.
|
||
|
*/
|
||
|
if (ep > sp && *(ep - 1) == '"')
|
||
|
*--ep = 0;
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
static FT_Error
|
||
|
_bdf_add_property ( bdf_font_t* font,
|
||
|
char* name,
|
||
|
char* value)
|
||
|
{
|
||
|
unsigned long propid;
|
||
|
hashnode hn;
|
||
|
int len;
|
||
|
bdf_property_t *prop, *fp;
|
||
|
FT_Memory memory = font->memory;
|
||
|
FT_Error error;
|
||
|
/* hashtable proptbl = font->proptbl;
|
||
|
bdf_property_t *user_props = font->user_props;
|
||
|
unsigned long nuser_props = font->nuser_props;
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* First, check to see if the property already exists in the font.
|
||
|
*/
|
||
|
if ((hn = hash_lookup(name, (hashtable *) font->internal)) != 0) {
|
||
|
/*
|
||
|
* The property already exists in the font, so simply replace
|
||
|
* the value of the property with the current value.
|
||
|
*/
|
||
|
fp = font->props + (unsigned long) hn->data;
|
||
|
|
||
|
switch (prop->format)
|
||
|
{
|
||
|
case BDF_ATOM:
|
||
|
{
|
||
|
/*
|
||
|
* Delete the current atom if it exists.
|
||
|
*/
|
||
|
FT_FREE ( fp->value.atom );
|
||
|
|
||
|
if (value == 0)
|
||
|
len = 1;
|
||
|
else
|
||
|
len = ft_strlen(value) + 1;
|
||
|
if (len > 1)
|
||
|
{
|
||
|
if ( FT_ALLOC ( fp->value.atom , len ) )
|
||
|
return error;
|
||
|
|
||
|
FT_MEM_COPY(fp->value.atom, value, len);
|
||
|
}
|
||
|
else
|
||
|
fp->value.atom = 0;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case BDF_INTEGER:
|
||
|
fp->value.int32 = _bdf_atol(value, 0, 10);
|
||
|
break;
|
||
|
|
||
|
case BDF_CARDINAL:
|
||
|
fp->value.card32 = _bdf_atoul(value, 0, 10);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
;
|
||
|
}
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* See if this property type exists yet or not. If not, create it.
|
||
|
*/
|
||
|
hn = hash_lookup(name, &(font->proptbl));
|
||
|
if (hn == 0) {
|
||
|
bdf_create_property(name, BDF_ATOM, font);
|
||
|
hn = hash_lookup(name, &(font->proptbl));
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Allocate another property if this is overflow.
|
||
|
*/
|
||
|
if (font->props_used == font->props_size)
|
||
|
{
|
||
|
if (font->props_size == 0)
|
||
|
{
|
||
|
if ( FT_NEW( font->props ) )
|
||
|
return error;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( FT_RENEW_ARRAY( font->props, font->props_size,
|
||
|
(font->props_size + 1) ) )
|
||
|
return error;
|
||
|
}
|
||
|
fp = font->props + font->props_size;
|
||
|
FT_ZERO( fp );
|
||
|
font->props_size++;
|
||
|
}
|
||
|
|
||
|
propid = (unsigned long) hn->data;
|
||
|
if (propid >= _num_bdf_properties)
|
||
|
prop = font->user_props + (propid - _num_bdf_properties);
|
||
|
else
|
||
|
prop = _bdf_properties + propid;
|
||
|
|
||
|
fp = font->props + font->props_used;
|
||
|
|
||
|
fp->name = prop->name;
|
||
|
fp->format = prop->format;
|
||
|
fp->builtin = prop->builtin;
|
||
|
|
||
|
switch (prop->format)
|
||
|
{
|
||
|
case BDF_ATOM:
|
||
|
{
|
||
|
fp->value.atom = NULL;
|
||
|
|
||
|
if ( value && value[0] != 0 )
|
||
|
{
|
||
|
len = ft_strlen(value) + 1;
|
||
|
|
||
|
if ( FT_ALLOC ( fp->value.atom , len ) )
|
||
|
return error;
|
||
|
|
||
|
FT_MEM_COPY (fp->value.atom, value, len);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case BDF_INTEGER:
|
||
|
fp->value.int32 = _bdf_atol(value, 0, 10);
|
||
|
break;
|
||
|
|
||
|
case BDF_CARDINAL:
|
||
|
fp->value.card32 = _bdf_atoul(value, 0, 10);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If the property happens to be a comment, then it doesn't need
|
||
|
* to be added to the internal hash table.
|
||
|
*/
|
||
|
if ( ft_memcmp(name, "COMMENT", 7) != 0 )
|
||
|
/*
|
||
|
* Add the property to the font property table.
|
||
|
*/
|
||
|
hash_insert( fp->name, (void *) font->props_used,
|
||
|
(hashtable *) font->internal, memory);
|
||
|
|
||
|
font->props_used++;
|
||
|
|
||
|
/*
|
||
|
* Some special cases need to be handled here. The DEFAULT_CHAR property
|
||
|
* needs to be located if it exists in the property list, the FONT_ASCENT
|
||
|
* and FONT_DESCENT need to be assigned if they are present, and the
|
||
|
* SPACING property should override the default spacing.
|
||
|
*/
|
||
|
if ( ft_memcmp(name, "DEFAULT_CHAR", 12) == 0 )
|
||
|
font->default_glyph = fp->value.int32;
|
||
|
|
||
|
else if ( ft_memcmp(name, "FONT_ASCENT", 11) == 0 )
|
||
|
font->font_ascent = fp->value.int32;
|
||
|
|
||
|
else if ( ft_memcmp(name, "FONT_DESCENT", 12) == 0 )
|
||
|
font->font_descent = fp->value.int32;
|
||
|
|
||
|
else if ( ft_memcmp(name, "SPACING", 7) == 0 )
|
||
|
{
|
||
|
if (fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P')
|
||
|
font->spacing = BDF_PROPORTIONAL;
|
||
|
|
||
|
else if (fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M')
|
||
|
font->spacing = BDF_MONOWIDTH;
|
||
|
|
||
|
else if (fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C')
|
||
|
font->spacing = BDF_CHARCELL;
|
||
|
}
|
||
|
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Actually parse the glyph info and bitmaps.
|
||
|
*/
|
||
|
static int
|
||
|
_bdf_parse_glyphs( char* line,
|
||
|
unsigned long linelen,
|
||
|
unsigned long lineno,
|
||
|
void* call_data,
|
||
|
void* client_data)
|
||
|
{
|
||
|
int c;
|
||
|
char *s;
|
||
|
unsigned char *bp;
|
||
|
unsigned long i, slen, nibbles;
|
||
|
double ps, rx, dw, sw;
|
||
|
_bdf_line_func_t *next;
|
||
|
_bdf_parse_t *p;
|
||
|
bdf_glyph_t *glyph;
|
||
|
bdf_font_t *font;
|
||
|
char nbuf[128];
|
||
|
FT_Memory memory;
|
||
|
FT_Error error;
|
||
|
|
||
|
next = (_bdf_line_func_t *) call_data;
|
||
|
p = (_bdf_parse_t *) client_data;
|
||
|
|
||
|
font = p->font;
|
||
|
memory = font->memory;
|
||
|
|
||
|
/*
|
||
|
* Check for a comment.
|
||
|
*/
|
||
|
if (ft_memcmp(line, "COMMENT", 7) == 0) {
|
||
|
linelen -= 7;
|
||
|
s = line + 7;
|
||
|
if (*s != 0) {
|
||
|
s++;
|
||
|
linelen--;
|
||
|
}
|
||
|
_bdf_add_comment(p->font, s, linelen);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* The very first thing expected is the number of glyphs.
|
||
|
*/
|
||
|
if (!(p->flags & _BDF_GLYPHS)) {
|
||
|
if (ft_memcmp(line, "CHARS", 5) != 0) {
|
||
|
sprintf(nbuf, ERRMSG1, lineno, "CHARS");
|
||
|
_bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
|
||
|
return BDF_MISSING_CHARS;
|
||
|
}
|
||
|
_bdf_split(" +", line, linelen, &p->list, memory);
|
||
|
p->cnt = font->glyphs_size = _bdf_atoul(p->list.field[1], 0, 10);
|
||
|
|
||
|
/*
|
||
|
* Make sure the number of glyphs is non-zero.
|
||
|
*/
|
||
|
if (p->cnt == 0)
|
||
|
font->glyphs_size = 64;
|
||
|
|
||
|
if ( FT_ALLOC ( font->glyphs , sizeof(bdf_glyph_t) *
|
||
|
font->glyphs_size ) )
|
||
|
return FT_Err_Out_Of_Memory;
|
||
|
|
||
|
/*
|
||
|
* Set up the callback to indicate the glyph loading is about to
|
||
|
* begin.
|
||
|
*/
|
||
|
if (p->callback != 0) {
|
||
|
p->cb.reason = BDF_LOAD_START;
|
||
|
p->cb.total = p->cnt;
|
||
|
p->cb.current = 0;
|
||
|
(*p->callback)(&p->cb, p->client_data);
|
||
|
}
|
||
|
p->flags |= _BDF_GLYPHS;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check for the ENDFONT field.
|
||
|
*/
|
||
|
if (ft_memcmp(line, "ENDFONT", 7) == 0) {
|
||
|
/*
|
||
|
* Sort the glyphs by encoding.
|
||
|
*/
|
||
|
qsort((char *) font->glyphs, font->glyphs_used, sizeof(bdf_glyph_t),
|
||
|
by_encoding);
|
||
|
|
||
|
p->flags &= ~_BDF_START;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check for the ENDCHAR field.
|
||
|
*/
|
||
|
if (ft_memcmp(line, "ENDCHAR", 7) == 0) {
|
||
|
/*
|
||
|
* Set up and call the callback if it was passed.
|
||
|
*/
|
||
|
if (p->callback != 0) {
|
||
|
p->cb.reason = BDF_LOADING;
|
||
|
p->cb.total = font->glyphs_size;
|
||
|
p->cb.current = font->glyphs_used;
|
||
|
(*p->callback)(&p->cb, p->client_data);
|
||
|
}
|
||
|
p->glyph_enc = 0;
|
||
|
p->flags &= ~_BDF_GLYPH_BITS;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check to see if a glyph is being scanned but should be ignored
|
||
|
* because it is an unencoded glyph.
|
||
|
*/
|
||
|
if ((p->flags & _BDF_GLYPH) &&
|
||
|
p->glyph_enc == -1 && p->opts->keep_unencoded == 0)
|
||
|
return 0;
|
||
|
|
||
|
/*
|
||
|
* Check for the STARTCHAR field.
|
||
|
*/
|
||
|
if (ft_memcmp(line, "STARTCHAR", 9) == 0) {
|
||
|
/*
|
||
|
* Set the character name in the parse info first until the
|
||
|
* encoding can be checked for an unencoded character.
|
||
|
*/
|
||
|
if (p->glyph_name != 0)
|
||
|
FT_FREE(p->glyph_name);
|
||
|
_bdf_split(" +", line, linelen, &p->list,memory);
|
||
|
_bdf_shift(1, &p->list);
|
||
|
s = _bdf_join(' ', &slen, &p->list);
|
||
|
if ( FT_ALLOC ( p->glyph_name , (slen + 1) ) )
|
||
|
return BDF_OUT_OF_MEMORY;
|
||
|
FT_MEM_COPY(p->glyph_name, s, slen + 1);
|
||
|
p->flags |= _BDF_GLYPH;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check for the ENCODING field.
|
||
|
*/
|
||
|
if (ft_memcmp(line, "ENCODING", 8) == 0) {
|
||
|
if (!(p->flags & _BDF_GLYPH)) {
|
||
|
/*
|
||
|
* Missing STARTCHAR field.
|
||
|
*/
|
||
|
sprintf(nbuf, ERRMSG1, lineno, "STARTCHAR");
|
||
|
_bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
|
||
|
return BDF_MISSING_STARTCHAR;
|
||
|
}
|
||
|
_bdf_split(" +", line, linelen, &p->list, memory);
|
||
|
p->glyph_enc = _bdf_atol(p->list.field[1], 0, 10);
|
||
|
|
||
|
/*
|
||
|
* Check to see if this encoding has already been encountered. If it
|
||
|
* has then change it to unencoded so it gets added if indicated.
|
||
|
*/
|
||
|
if (p->glyph_enc >= 0) {
|
||
|
if (_bdf_glyph_modified(p->have, p->glyph_enc)) {
|
||
|
/*
|
||
|
* Add a message saying a glyph has been moved to the
|
||
|
* unencoded area.
|
||
|
*/
|
||
|
sprintf(nbuf, ACMSG12, p->glyph_enc, p->glyph_name);
|
||
|
_bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
|
||
|
p->glyph_enc = -1;
|
||
|
font->modified = 1;
|
||
|
} else
|
||
|
_bdf_set_glyph_modified(p->have, p->glyph_enc);
|
||
|
}
|
||
|
|
||
|
if (p->glyph_enc >= 0) {
|
||
|
/*
|
||
|
* Make sure there are enough glyphs allocated in case the
|
||
|
* number of characters happen to be wrong.
|
||
|
*/
|
||
|
if (font->glyphs_used == font->glyphs_size) {
|
||
|
if ( FT_REALLOC ( font->glyphs,
|
||
|
sizeof(bdf_glyph_t) * font->glyphs_size,
|
||
|
sizeof(bdf_glyph_t) * (font->glyphs_size + 64) ) )
|
||
|
return BDF_OUT_OF_MEMORY;
|
||
|
FT_MEM_SET ((char *) (font->glyphs + font->glyphs_size),
|
||
|
0, sizeof(bdf_glyph_t) << 6); /* FZ inutile */
|
||
|
font->glyphs_size += 64;
|
||
|
}
|
||
|
|
||
|
glyph = font->glyphs + font->glyphs_used++;
|
||
|
glyph->name = p->glyph_name;
|
||
|
glyph->encoding = p->glyph_enc;
|
||
|
|
||
|
/*
|
||
|
* Reset the initial glyph info.
|
||
|
*/
|
||
|
p->glyph_name = 0;
|
||
|
} else {
|
||
|
/*
|
||
|
* Unencoded glyph. Check to see if it should be added or not.
|
||
|
*/
|
||
|
if (p->opts->keep_unencoded != 0) {
|
||
|
/*
|
||
|
* Allocate the next unencoded glyph.
|
||
|
*/
|
||
|
if (font->unencoded_used == font->unencoded_size) {
|
||
|
if (font->unencoded_size == 0) {
|
||
|
if ( FT_ALLOC ( font->unencoded , sizeof(bdf_glyph_t) << 2 ) )
|
||
|
return BDF_OUT_OF_MEMORY;
|
||
|
}
|
||
|
else {
|
||
|
if ( FT_REALLOC ( font->unencoded ,
|
||
|
sizeof(bdf_glyph_t) * font->unencoded_size,
|
||
|
sizeof(bdf_glyph_t) *
|
||
|
(font->unencoded_size + 4) ) )
|
||
|
return BDF_OUT_OF_MEMORY;
|
||
|
}
|
||
|
font->unencoded_size += 4;
|
||
|
}
|
||
|
|
||
|
glyph = font->unencoded + font->unencoded_used;
|
||
|
glyph->name = p->glyph_name;
|
||
|
glyph->encoding = font->unencoded_used++;
|
||
|
} else
|
||
|
/*
|
||
|
* Free up the glyph name if the unencoded shouldn't be
|
||
|
* kept.
|
||
|
*/
|
||
|
FT_FREE( p->glyph_name );
|
||
|
|
||
|
p->glyph_name = 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Clear the flags that might be added when width and height are
|
||
|
* checked for consistency.
|
||
|
*/
|
||
|
p->flags &= ~(_BDF_GLYPH_WIDTH_CHECK|_BDF_GLYPH_HEIGHT_CHECK);
|
||
|
|
||
|
p->flags |= _BDF_ENCODING;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Point at the glyph being constructed.
|
||
|
*/
|
||
|
if (p->glyph_enc == -1)
|
||
|
glyph = font->unencoded + (font->unencoded_used - 1);
|
||
|
else
|
||
|
glyph = font->glyphs + (font->glyphs_used - 1);
|
||
|
|
||
|
/*
|
||
|
* Check to see if a bitmap is being constructed.
|
||
|
*/
|
||
|
if (p->flags & _BDF_BITMAP) {
|
||
|
/*
|
||
|
* If there are more rows than are specified in the glyph metrics,
|
||
|
* ignore the remaining lines.
|
||
|
*/
|
||
|
if (p->row >= glyph->bbx.height) {
|
||
|
if (!(p->flags & _BDF_GLYPH_HEIGHT_CHECK)) {
|
||
|
sprintf(nbuf, ACMSG13, glyph->encoding);
|
||
|
_bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
|
||
|
p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
|
||
|
font->modified = 1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Only collect the number of nibbles indicated by the glyph metrics.
|
||
|
* If there are more columns, they are simply ignored.
|
||
|
*/
|
||
|
nibbles = p->bpr << 1;
|
||
|
bp = glyph->bitmap + (p->row * p->bpr);
|
||
|
for (i = 0, *bp = 0; i < nibbles; i++) {
|
||
|
c = line[i];
|
||
|
*bp = (*bp << 4) + a2i[c];
|
||
|
if (i + 1 < nibbles && (i & 1))
|
||
|
*++bp = 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If any line has extra columns, indicate they have been removed.
|
||
|
*/
|
||
|
if ((line[nibbles] == '0' || a2i[(int) line[nibbles]] != 0) &&
|
||
|
!(p->flags & _BDF_GLYPH_WIDTH_CHECK)) {
|
||
|
sprintf(nbuf, ACMSG14, glyph->encoding);
|
||
|
_bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
|
||
|
p->flags |= _BDF_GLYPH_WIDTH_CHECK;
|
||
|
font->modified = 1;
|
||
|
}
|
||
|
|
||
|
p->row++;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Expect the SWIDTH (scalable width) field next.
|
||
|
*/
|
||
|
if (ft_memcmp(line, "SWIDTH", 6) == 0) {
|
||
|
if (!(p->flags & _BDF_ENCODING)) {
|
||
|
/*
|
||
|
* Missing ENCODING field.
|
||
|
*/
|
||
|
sprintf(nbuf, ERRMSG1, lineno, "ENCODING");
|
||
|
_bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
|
||
|
return BDF_MISSING_ENCODING;
|
||
|
}
|
||
|
_bdf_split(" +", line, linelen, &p->list, memory);
|
||
|
glyph->swidth = _bdf_atoul(p->list.field[1], 0, 10);
|
||
|
p->flags |= _BDF_SWIDTH;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Expect the DWIDTH (scalable width) field next.
|
||
|
*/
|
||
|
if (ft_memcmp(line, "DWIDTH", 6) == 0) {
|
||
|
_bdf_split(" +", line, linelen, &p->list,memory);
|
||
|
glyph->dwidth = _bdf_atoul(p->list.field[1], 0, 10);
|
||
|
|
||
|
if (!(p->flags & _BDF_SWIDTH)) {
|
||
|
/*
|
||
|
* Missing SWIDTH field. Add an auto correction message and set
|
||
|
* the scalable width from the device width.
|
||
|
*/
|
||
|
sprintf(nbuf, ACMSG9, lineno);
|
||
|
_bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
|
||
|
ps = (double) font->point_size;
|
||
|
rx = (double) font->resolution_x;
|
||
|
dw = (double) glyph->dwidth;
|
||
|
glyph->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
|
||
|
}
|
||
|
|
||
|
p->flags |= _BDF_DWIDTH;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Expect the BBX field next.
|
||
|
*/
|
||
|
if (ft_memcmp(line, "BBX", 3) == 0) {
|
||
|
_bdf_split(" +", line, linelen, &p->list, memory);
|
||
|
glyph->bbx.width = _bdf_atos(p->list.field[1], 0, 10);
|
||
|
glyph->bbx.height = _bdf_atos(p->list.field[2], 0, 10);
|
||
|
glyph->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10);
|
||
|
glyph->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10);
|
||
|
|
||
|
/*
|
||
|
* Generate the ascent and descent of the character.
|
||
|
*/
|
||
|
glyph->bbx.ascent = glyph->bbx.height + glyph->bbx.y_offset;
|
||
|
glyph->bbx.descent = -glyph->bbx.y_offset;
|
||
|
|
||
|
/*
|
||
|
* Determine the overall font bounding box as the characters are
|
||
|
* loaded so corrections can be done later if indicated.
|
||
|
*/
|
||
|
p->maxas = MAX(glyph->bbx.ascent, p->maxas);
|
||
|
p->maxds = MAX(glyph->bbx.descent, p->maxds);
|
||
|
p->rbearing = glyph->bbx.width + glyph->bbx.x_offset;
|
||
|
p->maxrb = MAX(p->rbearing, p->maxrb);
|
||
|
p->minlb = MIN(glyph->bbx.x_offset, p->minlb);
|
||
|
p->maxlb = MAX(glyph->bbx.x_offset, p->maxlb);
|
||
|
|
||
|
if (!(p->flags & _BDF_DWIDTH)) {
|
||
|
/*
|
||
|
* Missing DWIDTH field. Add an auto correction message and set
|
||
|
* the device width to the glyph width.
|
||
|
*/
|
||
|
sprintf(nbuf, ACMSG10, lineno);
|
||
|
_bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
|
||
|
glyph->dwidth = glyph->bbx.width;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH
|
||
|
* value if necessary.
|
||
|
*/
|
||
|
if (p->opts->correct_metrics != 0) {
|
||
|
/*
|
||
|
* Determine the point size of the glyph.
|
||
|
*/
|
||
|
ps = (double) font->point_size;
|
||
|
rx = (double) font->resolution_x;
|
||
|
dw = (double) glyph->dwidth;
|
||
|
sw = (unsigned short) ((dw * 72000.0) / (ps * rx));
|
||
|
|
||
|
if (sw != glyph->swidth) {
|
||
|
glyph->swidth = sw;
|
||
|
if (p->glyph_enc == -1)
|
||
|
_bdf_set_glyph_modified(font->umod,
|
||
|
font->unencoded_used - 1);
|
||
|
else
|
||
|
_bdf_set_glyph_modified(font->nmod, glyph->encoding);
|
||
|
p->flags |= _BDF_SWIDTH_ADJ;
|
||
|
font->modified = 1;
|
||
|
}
|
||
|
}
|
||
|
p->flags |= _BDF_BBX;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* And finally, gather up the bitmap.
|
||
|
*/
|
||
|
if (ft_memcmp(line, "BITMAP", 6) == 0) {
|
||
|
if (!(p->flags & _BDF_BBX)) {
|
||
|
/*
|
||
|
* Missing BBX field.
|
||
|
*/
|
||
|
sprintf(nbuf, ERRMSG1, lineno, "BBX");
|
||
|
_bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
|
||
|
return BDF_MISSING_BBX;
|
||
|
}
|
||
|
/*
|
||
|
* Allocate enough space for the bitmap.
|
||
|
*/
|
||
|
p->bpr = ((glyph->bbx.width * p->font->bpp) + 7) >> 3;
|
||
|
glyph->bytes = p->bpr * glyph->bbx.height;
|
||
|
if ( FT_ALLOC ( glyph->bitmap , glyph->bytes ) )
|
||
|
return BDF_OUT_OF_MEMORY;
|
||
|
p->row = 0;
|
||
|
p->flags |= _BDF_BITMAP;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return BDF_INVALID_LINE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Load the font properties.
|
||
|
*/
|
||
|
static int
|
||
|
_bdf_parse_properties(char *line, unsigned long linelen, unsigned long lineno,
|
||
|
void *call_data, void *client_data)
|
||
|
{
|
||
|
unsigned long vlen;
|
||
|
_bdf_line_func_t *next;
|
||
|
_bdf_parse_t *p;
|
||
|
char *name, *value, nbuf[128];
|
||
|
FT_Memory memory;
|
||
|
|
||
|
next = (_bdf_line_func_t *) call_data;
|
||
|
p = (_bdf_parse_t *) client_data;
|
||
|
|
||
|
memory = p->font->memory;
|
||
|
/*
|
||
|
* Check for the end of the properties.
|
||
|
*/
|
||
|
if (ft_memcmp(line, "ENDPROPERTIES", 13) == 0) {
|
||
|
/*
|
||
|
* If the FONT_ASCENT or FONT_DESCENT properties have not been
|
||
|
* encountered yet, then make sure they are added as properties and
|
||
|
* make sure they are set from the font bounding box info.
|
||
|
*
|
||
|
* This is *always* done regardless of the options, because X11
|
||
|
* requires these two fields to compile fonts.
|
||
|
*/
|
||
|
if (bdf_get_font_property(p->font, "FONT_ASCENT") == 0) {
|
||
|
p->font->font_ascent = p->font->bbx.ascent;
|
||
|
sprintf(nbuf, "%hd", p->font->bbx.ascent);
|
||
|
_bdf_add_property(p->font, "FONT_ASCENT", nbuf);
|
||
|
sprintf(nbuf, ACMSG1, p->font->bbx.ascent);
|
||
|
_bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
|
||
|
p->font->modified = 1;
|
||
|
}
|
||
|
if (bdf_get_font_property(p->font, "FONT_DESCENT") == 0) {
|
||
|
p->font->font_descent = p->font->bbx.descent;
|
||
|
sprintf(nbuf, "%hd", p->font->bbx.descent);
|
||
|
_bdf_add_property(p->font, "FONT_DESCENT", nbuf);
|
||
|
sprintf(nbuf, ACMSG2, p->font->bbx.descent);
|
||
|
_bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
|
||
|
p->font->modified = 1;
|
||
|
}
|
||
|
p->flags &= ~_BDF_PROPS;
|
||
|
*next = _bdf_parse_glyphs;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Ignore the _XFREE86_GLYPH_RANGES properties.
|
||
|
*/
|
||
|
if (ft_memcmp(line, "_XFREE86_GLYPH_RANGES", 21) == 0)
|
||
|
return 0;
|
||
|
|
||
|
/*
|
||
|
* Handle COMMENT fields and properties in a special way to preserve
|
||
|
* the spacing.
|
||
|
*/
|
||
|
if (ft_memcmp(line, "COMMENT", 7) == 0) {
|
||
|
name = value = line;
|
||
|
value += 7;
|
||
|
if (*value)
|
||
|
*value++ = 0;
|
||
|
_bdf_add_property(p->font, name, value);
|
||
|
} else if (_bdf_is_atom(line, linelen, &name, &value, p->font))
|
||
|
_bdf_add_property(p->font, name, value);
|
||
|
else {
|
||
|
_bdf_split(" +", line, linelen, &p->list, memory);
|
||
|
name = p->list.field[0];
|
||
|
_bdf_shift(1, &p->list);
|
||
|
value = _bdf_join(' ', &vlen, &p->list);
|
||
|
_bdf_add_property(p->font, name, value);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Load the font header.
|
||
|
*/
|
||
|
static int
|
||
|
_bdf_parse_start(char *line, unsigned long linelen, unsigned long lineno,
|
||
|
void *call_data, void *client_data)
|
||
|
{
|
||
|
unsigned long slen;
|
||
|
_bdf_line_func_t *next;
|
||
|
_bdf_parse_t *p;
|
||
|
bdf_font_t *font;
|
||
|
char *s, nbuf[128];
|
||
|
/* int test; */
|
||
|
FT_Memory memory;
|
||
|
FT_Error error;
|
||
|
|
||
|
next = (_bdf_line_func_t *) call_data;
|
||
|
p = (_bdf_parse_t *) client_data;
|
||
|
if (p->font)
|
||
|
memory = p->font->memory;
|
||
|
|
||
|
/*
|
||
|
* Check for a comment. This is done to handle those fonts that have
|
||
|
* comments before the STARTFONT line for some reason.
|
||
|
*/
|
||
|
if (ft_memcmp(line, "COMMENT", 7) == 0) {
|
||
|
if (p->opts->keep_comments != 0 && p->font != 0) {
|
||
|
linelen -= 7;
|
||
|
s = line + 7;
|
||
|
if (*s != 0) {
|
||
|
s++;
|
||
|
linelen--;
|
||
|
}
|
||
|
_bdf_add_comment(p->font, s, linelen);
|
||
|
/* here font is not defined ! */
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (!(p->flags & _BDF_START)) {
|
||
|
|
||
|
memory = p->memory;
|
||
|
|
||
|
if (ft_memcmp(line, "STARTFONT", 9) != 0)
|
||
|
/*
|
||
|
* No STARTFONT field is a good indication of a problem.
|
||
|
*/
|
||
|
return BDF_MISSING_START;
|
||
|
p->flags = _BDF_START;
|
||
|
font = p->font = 0;
|
||
|
|
||
|
if ( FT_ALLOC ( font, sizeof(bdf_font_t) ) )
|
||
|
return BDF_OUT_OF_MEMORY;
|
||
|
p->font = font;
|
||
|
|
||
|
font->memory = p->memory;
|
||
|
p->memory = 0;
|
||
|
|
||
|
/* if (font == 0) {
|
||
|
fprintf(stderr,"failed font\n");
|
||
|
}*/ /* XXX */
|
||
|
|
||
|
{ /* setup */
|
||
|
unsigned long i;
|
||
|
bdf_property_t *prop;
|
||
|
|
||
|
hash_init(&(font->proptbl), memory);
|
||
|
for (i = 0, prop = _bdf_properties;
|
||
|
i < _num_bdf_properties; i++, prop++)
|
||
|
hash_insert(prop->name, (void *) i, &(font->proptbl) , memory);
|
||
|
}
|
||
|
|
||
|
if ( FT_ALLOC ( p->font->internal , sizeof(hashtable) ) )
|
||
|
return BDF_OUT_OF_MEMORY;
|
||
|
hash_init((hashtable *) p->font->internal,memory);
|
||
|
p->font->spacing = p->opts->font_spacing;
|
||
|
p->font->default_glyph = -1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check for the start of the properties.
|
||
|
*/
|
||
|
if (ft_memcmp(line, "STARTPROPERTIES", 15) == 0) {
|
||
|
_bdf_split(" +", line, linelen, &p->list, memory);
|
||
|
p->cnt = p->font->props_size = _bdf_atoul(p->list.field[1], 0, 10);
|
||
|
|
||
|
if ( FT_ALLOC ( p->font->props , (sizeof(bdf_property_t) * p->cnt) ) )
|
||
|
return BDF_OUT_OF_MEMORY;
|
||
|
p->flags |= _BDF_PROPS;
|
||
|
*next = _bdf_parse_properties;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check for the FONTBOUNDINGBOX field.
|
||
|
*/
|
||
|
if (ft_memcmp(line, "FONTBOUNDINGBOX", 15) == 0) {
|
||
|
if (!(p->flags & _BDF_SIZE)) {
|
||
|
/*
|
||
|
* Missing the SIZE field.
|
||
|
*/
|
||
|
sprintf(nbuf, ERRMSG1, lineno, "SIZE");
|
||
|
_bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
|
||
|
return BDF_MISSING_SIZE;
|
||
|
}
|
||
|
_bdf_split(" +", line, linelen, &p->list , memory);
|
||
|
p->font->bbx.width = _bdf_atos(p->list.field[1], 0, 10);
|
||
|
p->font->bbx.height = _bdf_atos(p->list.field[2], 0, 10);
|
||
|
p->font->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10);
|
||
|
p->font->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10);
|
||
|
p->font->bbx.ascent = p->font->bbx.height + p->font->bbx.y_offset;
|
||
|
p->font->bbx.descent = -p->font->bbx.y_offset;
|
||
|
p->flags |= _BDF_FONT_BBX;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* The next thing to check for is the FONT field.
|
||
|
*/
|
||
|
if (ft_memcmp(line, "FONT", 4) == 0) {
|
||
|
_bdf_split(" +", line, linelen, &p->list , memory);
|
||
|
_bdf_shift(1, &p->list);
|
||
|
s = _bdf_join(' ', &slen, &p->list);
|
||
|
if ( FT_ALLOC ( p->font->name , slen + 1 ) )
|
||
|
return BDF_OUT_OF_MEMORY;
|
||
|
(void) ft_memcpy(p->font->name, s, slen + 1);
|
||
|
/*
|
||
|
* If the font name is an XLFD name, set the spacing to the one in the
|
||
|
* font name. If there is no spacing fall back on the default.
|
||
|
*/
|
||
|
_bdf_set_default_spacing(p->font, p->opts);
|
||
|
p->flags |= _BDF_FONT_NAME;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Check for the SIZE field.
|
||
|
*/
|
||
|
if (ft_memcmp(line, "SIZE", 4) == 0) {
|
||
|
if (!(p->flags & _BDF_FONT_NAME)) {
|
||
|
/*
|
||
|
* Missing the FONT field.
|
||
|
*/
|
||
|
sprintf(nbuf, ERRMSG1, lineno, "FONT");
|
||
|
_bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
|
||
|
return BDF_MISSING_FONTNAME;
|
||
|
}
|
||
|
_bdf_split(" +", line, linelen, &p->list, memory);
|
||
|
p->font->point_size = _bdf_atoul(p->list.field[1], 0, 10);
|
||
|
p->font->resolution_x = _bdf_atoul(p->list.field[2], 0, 10);
|
||
|
p->font->resolution_y = _bdf_atoul(p->list.field[3], 0, 10);
|
||
|
|
||
|
/*
|
||
|
* Check for the bits per pixel field.
|
||
|
*/
|
||
|
if (p->list.used == 5) {
|
||
|
p->font->bpp = _bdf_atos(p->list.field[4], 0, 10);
|
||
|
if (p->font->bpp > 1 && (p->font->bpp & 1)) {
|
||
|
/*
|
||
|
* Move up to the next bits per pixel value if an odd number
|
||
|
* is encountered.
|
||
|
*/
|
||
|
p->font->bpp++;
|
||
|
if (p->font->bpp <= 4) {
|
||
|
sprintf(nbuf, ACMSG11, p->font->bpp);
|
||
|
_bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
|
||
|
}
|
||
|
}
|
||
|
if (p->font->bpp > 4) {
|
||
|
sprintf(nbuf, ACMSG11, p->font->bpp);
|
||
|
_bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
|
||
|
p->font->bpp = 4;
|
||
|
}
|
||
|
} else
|
||
|
p->font->bpp = 1;
|
||
|
|
||
|
p->flags |= _BDF_SIZE;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return BDF_INVALID_LINE;
|
||
|
}
|
||
|
|
||
|
/**************************************************************************
|
||
|
*
|
||
|
* API.
|
||
|
*
|
||
|
**************************************************************************/
|
||
|
|
||
|
|
||
|
FT_LOCAL_DEF( bdf_font_t* )
|
||
|
bdf_load_font( FT_Stream stream,
|
||
|
FT_Memory extmemory,
|
||
|
bdf_options_t* opts,
|
||
|
bdf_callback_t callback,
|
||
|
void* data)
|
||
|
{
|
||
|
int n;
|
||
|
unsigned long lineno;
|
||
|
char msgbuf[128];
|
||
|
_bdf_parse_t p;
|
||
|
FT_Memory memory;
|
||
|
FT_Error error;
|
||
|
|
||
|
(void) ft_memset((char *) &p, 0, sizeof(_bdf_parse_t));
|
||
|
p.opts = (opts != 0) ? opts : &_bdf_opts;
|
||
|
p.minlb = 32767;
|
||
|
p.callback = callback;
|
||
|
p.client_data = data;
|
||
|
|
||
|
p.memory = extmemory; /* only during font creation */
|
||
|
|
||
|
n = _bdf_readstream(stream, _bdf_parse_start, (void *) &p, &lineno);
|
||
|
|
||
|
if (p.font != 0) {
|
||
|
/*
|
||
|
* If the font is not proportional, set the fonts monowidth
|
||
|
* field to the width of the font bounding box.
|
||
|
*/
|
||
|
memory = p.font->memory;
|
||
|
|
||
|
if (p.font->spacing != BDF_PROPORTIONAL)
|
||
|
p.font->monowidth = p.font->bbx.width;
|
||
|
|
||
|
/*
|
||
|
* If the number of glyphs loaded is not that of the original count,
|
||
|
* indicate the difference.
|
||
|
*/
|
||
|
if (p.cnt != p.font->glyphs_used + p.font->unencoded_used) {
|
||
|
sprintf(msgbuf, ACMSG15, p.cnt,
|
||
|
p.font->glyphs_used + p.font->unencoded_used);
|
||
|
_bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
|
||
|
p.font->modified = 1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Once the font has been loaded, adjust the overall font metrics if
|
||
|
* necessary.
|
||
|
*/
|
||
|
if (p.opts->correct_metrics != 0 &&
|
||
|
(p.font->glyphs_used > 0 || p.font->unencoded_used > 0)) {
|
||
|
if (p.maxrb - p.minlb != p.font->bbx.width) {
|
||
|
sprintf(msgbuf, ACMSG3, p.font->bbx.width, p.maxrb - p.minlb);
|
||
|
_bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
|
||
|
p.font->bbx.width = p.maxrb - p.minlb;
|
||
|
p.font->modified = 1;
|
||
|
}
|
||
|
if (p.font->bbx.x_offset != p.minlb) {
|
||
|
sprintf(msgbuf, ACMSG4, p.font->bbx.x_offset, p.minlb);
|
||
|
_bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
|
||
|
p.font->bbx.x_offset = p.minlb;
|
||
|
p.font->modified = 1;
|
||
|
}
|
||
|
if (p.font->bbx.ascent != p.maxas) {
|
||
|
sprintf(msgbuf, ACMSG5, p.font->bbx.ascent, p.maxas);
|
||
|
_bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
|
||
|
p.font->bbx.ascent = p.maxas;
|
||
|
p.font->modified = 1;
|
||
|
}
|
||
|
if (p.font->bbx.descent != p.maxds) {
|
||
|
sprintf(msgbuf, ACMSG6, p.font->bbx.descent, p.maxds);
|
||
|
_bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
|
||
|
p.font->bbx.descent = p.maxds;
|
||
|
p.font->bbx.y_offset = -p.maxds;
|
||
|
p.font->modified = 1;
|
||
|
}
|
||
|
if (p.maxas + p.maxds != p.font->bbx.height) {
|
||
|
sprintf(msgbuf, ACMSG7, p.font->bbx.height, p.maxas + p.maxds);
|
||
|
_bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
|
||
|
}
|
||
|
p.font->bbx.height = p.maxas + p.maxds;
|
||
|
|
||
|
if (p.flags & _BDF_SWIDTH_ADJ)
|
||
|
_bdf_add_acmsg(p.font, ACMSG8, ft_strlen(ACMSG8));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Last, if an error happened during loading, handle the messages.
|
||
|
*/
|
||
|
if (n < 0 && callback != 0) {
|
||
|
/*
|
||
|
* An error was returned. Alert the client.
|
||
|
*/
|
||
|
p.cb.reason = BDF_ERROR;
|
||
|
p.cb.errlineno = lineno;
|
||
|
(*callback)(&p.cb, data);
|
||
|
} else if (p.flags & _BDF_START) {
|
||
|
if (p.font != 0) {
|
||
|
/*
|
||
|
* The ENDFONT field was never reached or did not exist.
|
||
|
*/
|
||
|
if (!(p.flags & _BDF_GLYPHS))
|
||
|
/*
|
||
|
* Error happened while parsing header.
|
||
|
*/
|
||
|
sprintf(msgbuf, ERRMSG2, lineno);
|
||
|
else
|
||
|
/*
|
||
|
* Error happened when parsing glyphs.
|
||
|
*/
|
||
|
sprintf(msgbuf, ERRMSG3, lineno);
|
||
|
|
||
|
_bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
|
||
|
}
|
||
|
|
||
|
if (callback != 0) {
|
||
|
p.cb.reason = BDF_ERROR;
|
||
|
p.cb.errlineno = lineno;
|
||
|
(*callback)(&p.cb, data);
|
||
|
}
|
||
|
} else if (callback != 0) {
|
||
|
/*
|
||
|
* This forces the progress bar to always finish.
|
||
|
*/
|
||
|
p.cb.current = p.cb.total;
|
||
|
(*p.callback)(&p.cb, p.client_data);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Free up the list used during the parsing.
|
||
|
*/
|
||
|
if (p.list.size > 0)
|
||
|
FT_FREE( p.list.field );
|
||
|
|
||
|
if (p.font != 0) {
|
||
|
/*
|
||
|
* Make sure the comments are NULL terminated if they exist.
|
||
|
*/
|
||
|
memory = p.font->memory;
|
||
|
|
||
|
if (p.font->comments_len > 0) {
|
||
|
if ( FT_REALLOC ( p.font->comments , p.font->comments_len ,
|
||
|
p.font->comments_len + 1 ) )
|
||
|
return 0;
|
||
|
p.font->comments[p.font->comments_len] = 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Make sure the auto-correct messages are NULL terminated if they
|
||
|
* exist.
|
||
|
*/
|
||
|
if (p.font->acmsgs_len > 0) {
|
||
|
memory = p.font->memory;
|
||
|
|
||
|
if ( FT_REALLOC ( p.font->acmsgs , p.font->acmsgs_len ,
|
||
|
p.font->acmsgs_len + 1 ) )
|
||
|
return 0;
|
||
|
p.font->acmsgs[p.font->acmsgs_len] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return p.font;
|
||
|
}
|
||
|
|
||
|
|
||
|
FT_LOCAL_DEF( void )
|
||
|
bdf_free_font( bdf_font_t *font )
|
||
|
{
|
||
|
bdf_property_t *prop;
|
||
|
unsigned long i;
|
||
|
bdf_glyph_t *glyphs;
|
||
|
FT_Memory memory;
|
||
|
|
||
|
if (font == 0)
|
||
|
return;
|
||
|
|
||
|
memory = font->memory;
|
||
|
|
||
|
if (font->name != 0)
|
||
|
FT_FREE(font->name);
|
||
|
|
||
|
/*
|
||
|
* Free up the internal hash table of property names.
|
||
|
*/
|
||
|
if (font->internal) {
|
||
|
hash_free((hashtable *) font->internal, memory);
|
||
|
FT_FREE(font->internal);
|
||
|
}
|
||
|
/*
|
||
|
* Free up the comment info.
|
||
|
*/
|
||
|
if (font->comments_len > 0)
|
||
|
FT_FREE(font->comments);
|
||
|
|
||
|
/*
|
||
|
* Free up the auto-correction messages.
|
||
|
*/
|
||
|
if (font->acmsgs_len > 0)
|
||
|
FT_FREE(font->acmsgs);
|
||
|
|
||
|
/*
|
||
|
* Free up the properties.
|
||
|
*/
|
||
|
for (i = 0; i < font->props_size; i++) {
|
||
|
if (font->props[i].format == BDF_ATOM && font->props[i].value.atom)
|
||
|
FT_FREE(font->props[i].value.atom);
|
||
|
}
|
||
|
|
||
|
if (font->props_size > 0 && font->props != 0)
|
||
|
FT_FREE(font->props);
|
||
|
|
||
|
/*
|
||
|
* Free up the character info.
|
||
|
*/
|
||
|
for (i = 0, glyphs = font->glyphs; i < font->glyphs_used; i++, glyphs++) {
|
||
|
if (glyphs->name)
|
||
|
FT_FREE(glyphs->name);
|
||
|
if (glyphs->bytes > 0 && glyphs->bitmap != 0)
|
||
|
FT_FREE(glyphs->bitmap);
|
||
|
}
|
||
|
|
||
|
for (i = 0, glyphs = font->unencoded; i < font->unencoded_used;
|
||
|
i++, glyphs++) {
|
||
|
if (glyphs->name)
|
||
|
FT_FREE(glyphs->name);
|
||
|
if (glyphs->bytes > 0)
|
||
|
FT_FREE(glyphs->bitmap);
|
||
|
}
|
||
|
|
||
|
if (font->glyphs_size > 0)
|
||
|
FT_FREE( font->glyphs);
|
||
|
|
||
|
if (font->unencoded_size > 0)
|
||
|
FT_FREE( font->unencoded);
|
||
|
|
||
|
/*
|
||
|
* Free up the overflow storage if it was used.
|
||
|
*/
|
||
|
for (i = 0, glyphs = font->overflow.glyphs; i < font->overflow.glyphs_used;
|
||
|
i++, glyphs++) {
|
||
|
if (glyphs->name != 0)
|
||
|
FT_FREE(glyphs->name);
|
||
|
if (glyphs->bytes > 0)
|
||
|
FT_FREE( glyphs->bitmap);;
|
||
|
}
|
||
|
if (font->overflow.glyphs_size > 0)
|
||
|
FT_FREE(font->overflow.glyphs);
|
||
|
|
||
|
/* bdf_cleanup */
|
||
|
hash_free(&(font->proptbl),memory);
|
||
|
|
||
|
/*
|
||
|
* Free up the user defined properties.
|
||
|
*/
|
||
|
for (prop = font->user_props, i = 0; i < font->nuser_props; i++, prop++) {
|
||
|
FT_FREE(prop->name);
|
||
|
if (prop->format == BDF_ATOM && prop->value.atom != 0)
|
||
|
FT_FREE(prop->value.atom);
|
||
|
}
|
||
|
if (font->nuser_props > 0)
|
||
|
FT_FREE(font->user_props);
|
||
|
|
||
|
/*FREE( font);*/ /* XXX Fixme */
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
FT_LOCAL_DEF( bdf_property_t* )
|
||
|
bdf_get_font_property( bdf_font_t* font,
|
||
|
char* name)
|
||
|
{
|
||
|
hashnode hn;
|
||
|
|
||
|
if (font == 0 || font->props_size == 0 || name == 0 || *name == 0)
|
||
|
return 0;
|
||
|
|
||
|
hn = hash_lookup(name, (hashtable *) font->internal);
|
||
|
return (hn) ? (font->props + ((unsigned long) hn->data)) : 0;
|
||
|
}
|