/* * Copyright 2008 Department of Mathematical Sciences, New Mexico State University * * 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 * DEPARTMENT OF MATHEMATICAL SCIENCES 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. */ #include "bdfP.h" #ifdef HAVE_HBF #include "hbf.h" #endif #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. * **************************************************************************/ unsigned char bdf_onebpp[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; unsigned char bdf_twobpp[] = { 0xc0, 0x30, 0x0c, 0x03 }; unsigned char bdf_fourbpp[] = { 0xf0, 0x0f }; unsigned char bdf_eightbpp[] = { 0xff }; /************************************************************************** * * Default BDF font options. * **************************************************************************/ static bdf_options_t _bdf_opts = { #ifdef HAVE_FREETYPE FT_LOAD_DEFAULT, /* OTF flags - hinting on. */ #else 0, /* OTF flags */ #endif /* HAVE_FREETYPE */ 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. */ BDF_PSF_ALL, /* PSF font export options. */ 0, /* An X cursor font. */ }; /************************************************************************** * * Builtin BDF font properties. * **************************************************************************/ /* * List of most properties that might appear in a font. Doesn't include the * AXIS_* properties in X11R6 polymorphic fonts. */ static 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}, /* * Throw this in to make it clear. */ {"_XMBDFED_INFO", BDF_ATOM, 1}, }; static unsigned int _num_bdf_properties = sizeof(_bdf_properties) / sizeof(_bdf_properties[0]); /* * User defined properties. */ static bdf_property_t *user_props; static unsigned int nuser_props = 0; /************************************************************************** * * Hash table utilities for the properties. * **************************************************************************/ #define INITIAL_HT_SIZE 241 typedef struct { char *key; void *data; } _hashnode, *hashnode; typedef struct { int limit; int size; int used; hashnode *table; } hashtable; typedef void (*hash_free_func)(hashnode node); static hashnode * hash_bucket(char *key, hashtable *ht) { char *kp = key; unsigned int 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] && strcmp(kp, key) == 0) break; ndp--; if (ndp < bp) ndp = bp + (ht->size - 1); } return ndp; } static void hash_rehash(hashtable *ht) { hashnode *obp = ht->table, *bp, *nbp; int i, sz = ht->size; ht->size <<= 1; ht->limit = ht->size / 3; ht->table = (hashnode *) malloc(sizeof(hashnode) * ht->size); (void) memset((char *) ht->table, 0, sizeof(hashnode) * ht->size); for (i = 0, bp = obp; i < sz; i++, bp++) { if (*bp) { nbp = hash_bucket((*bp)->key, ht); *nbp = *bp; } } free((char *) obp); } static void hash_init(hashtable *ht) { int sz = INITIAL_HT_SIZE; ht->size = sz; ht->limit = sz / 3; ht->used = 0; ht->table = (hashnode *) malloc(sizeof(hashnode) * sz); (void) memset((char *) ht->table, 0, sizeof(hashnode) * sz); } static void hash_free(hashtable *ht) { int i, sz = ht->size; hashnode *bp = ht->table; for (i = 0; i < sz; i++, bp++) { if (*bp) free((char *) *bp); } if (sz > 0) free((char *) ht->table); } static void hash_insert(char *key, void *data, hashtable *ht) { hashnode nn, *bp = hash_bucket(key, ht); nn = *bp; if (!nn) { *bp = nn = (hashnode) malloc(sizeof(_hashnode)); nn->key = key; nn->data = data; if (ht->used >= ht->limit) hash_rehash(ht); ht->used++; } else nn->data = data; } static hashnode hash_lookup(char *key, hashtable *ht) { hashnode *np = hash_bucket(key, ht); return *np; } static void hash_delete(char *name, hashtable *ht) { hashnode *hp; hp = hash_bucket(name, ht); if (*hp) { free((char *) *hp); *hp = 0; } } /* * The builtin property table. */ static hashtable proptbl; /************************************************************************** * * Utility types and functions. * **************************************************************************/ /* * Function type for parsing lines of a BDF font. */ typedef int (*_bdf_line_func_t)( char *line, unsigned int linelen, unsigned int lineno, void *call_data, void *client_data ); /* * List structure for splitting lines into fields. */ typedef struct { char **field; unsigned int size; unsigned int used; char *bfield; unsigned int bsize; unsigned int bused; } _bdf_list_t; /* * Structure used while loading BDF fonts. */ typedef struct { unsigned int flags; unsigned int cnt; unsigned int row; unsigned int bpr; short minlb; short maxlb; short maxrb; short maxas; short maxds; short rbearing; char *glyph_name; int glyph_enc; bdf_font_t *font; bdf_options_t *opts; void *client_data; bdf_callback_t callback; bdf_callback_struct_t cb; unsigned int have[2048]; _bdf_list_t list; } _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 char empty[1] = { 0 }; /* * Assume the line is NULL terminated and that the `list' parameter was * initialized the first time it was used. */ static void _bdf_split(char *separators, char *line, unsigned int linelen, _bdf_list_t *list) { int mult, final_empty; char *sp, *ep, *end; unsigned char seps[32]; /* * Initialize the list. */ list->used = list->bused = 0; /* * If the line is empty, then simply return. */ if (linelen == 0 || line[0] == 0) return; /* * 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) list->bfield = (char *) malloc(linelen); else list->bfield = (char *) realloc(list->bfield, linelen); list->bsize = linelen; } list->bused = linelen; (void) memcpy(list->bfield, line, linelen); return; } /* * Prepare the separator bitmap. */ (void) memset((char *) seps, 0, 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 == '+' && *(sp + 1) == 0) mult = 1; else setsbit(seps, *sp); } /* * Break the line up into fields. */ for (final_empty = 0, sp = ep = line, end = sp + linelen; 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) list->field = (char **) malloc(sizeof(char *) * 5); else list->field = (char **) realloc((char *) list->field, sizeof(char *) * (list->size + 5)); 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) list->field = (char **) malloc(sizeof(char *) * 5); else list->field = (char **) realloc((char *) list->field, sizeof(char *) * (list->size + 5)); list->size += 5; } } if (final_empty) list->field[list->used++] = empty; if (list->used == list->size) { if (list->size == 0) list->field = (char **) malloc(sizeof(char *) * 5); else list->field = (char **) realloc((char *) list->field, sizeof(char *) * (list->size + 5)); list->size += 5; } list->field[list->used] = 0; } static void _bdf_shift(unsigned int n, _bdf_list_t *list) { unsigned int 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 int *len, _bdf_list_t *list) { unsigned int 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. */ static int _bdf_readlines(int fd, _bdf_line_func_t callback, void *client_data, unsigned int *lno) { _bdf_line_func_t cb; unsigned int 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 = read(fd, 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; memmove(buf, pp, n); #if 0 memcpy(buf, pp, n); #endif 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; } unsigned char * _bdf_strdup(unsigned char *s, unsigned int len) { unsigned char *ns; if (s == 0 || len == 0) return 0; ns = (unsigned char *) malloc(len); (void) memcpy((char *) ns, (char *) s, len); return ns; } void _bdf_memmove(char *dest, char *src, unsigned int bytes) { int i, j; i = (int) 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 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 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 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 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 int integer. */ unsigned int _bdf_atoul(char *s, char **end, int base) { unsigned int 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 prefixes of 0[xX] or [Uu][+-]. */ if ((*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) || ((*s == 'U' || *s == 'u') && (*(s + 1) == '+' || *(s + 1) == '-'))) { 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 int integer. */ int _bdf_atol(char *s, char **end, int base) { int 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')) || ((*s == 'U' || *s == 'u') && (*(s + 1) == '+' || *(s + 1) == '-'))) { 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. */ 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; } /************************************************************************** * * 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 %d. Set automatically." #define ACMSG10 "DWIDTH field missing at line %d. Set to glyph width." #define ACMSG11 "SIZE bits per pixel field adjusted to %hd." #define ACMSG12 "Duplicate encoding %d (%s) changed to unencoded." #define ACMSG13 "Glyph %d extra rows removed." #define ACMSG14 "Glyph %d extra columns removed." #define ACMSG15 "Incorrect glyph count: %d indicated but %d found." /* * Error messages. */ #define ERRMSG1 "[line %d] Missing \"%s\" line." #define ERRMSG2 "[line %d] Font header corrupted or missing fields." #define ERRMSG3 "[line %d] Font glyphs corrupted or missing fields." void _bdf_add_acmsg(bdf_font_t *font, char *msg, unsigned int len) { char *cp; if (font->acmsgs_len == 0) font->acmsgs = (char *) malloc(len + 2); else font->acmsgs = (char *) realloc(font->acmsgs, font->acmsgs_len + len + 2); cp = font->acmsgs + font->acmsgs_len; (void) memcpy(cp, msg, len); cp += len; *cp++ = '\n'; *cp = 0; font->acmsgs_len += len + 1; } void _bdf_add_comment(bdf_font_t *font, char *comment, unsigned int len) { char *cp; if (font->comments_len == 0) font->comments = (char *) malloc(len + 2); else font->comments = (char *) realloc(font->comments, font->comments_len + len + 2); cp = font->comments + font->comments_len; (void) memcpy(cp, comment, len); cp += len; *cp++ = '\n'; *cp = 0; font->comments_len += len + 1; } /* * 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 int len; char name[128]; _bdf_list_t list; if (font == 0 || font->name == 0 || font->name[0] == 0) return; font->spacing = opts->font_spacing; len = (unsigned int) (strlen(font->name) + 1); (void) memcpy(name, font->name, len); list.size = list.used = 0; _bdf_split("-", name, len, &list); 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) free((char *) 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 int linelen, char **name, char **value) { 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); /* * 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 void _bdf_add_property(bdf_font_t *font, char *name, char *value) { unsigned int propid; hashnode hn; int len; bdf_property_t *prop, *fp; /* * 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 int) hn->data; switch (fp->format) { case BDF_ATOM: /* * Delete the current atom if it exists. */ if (fp->value.atom != 0) free(fp->value.atom); if (value == 0) len = 1; else len = strlen(value) + 1; if (len > 1) { fp->value.atom = (char *) malloc(len); (void) memcpy(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; } return; } /* * See if this property type exists yet or not. If not, create it. */ hn = hash_lookup(name, &proptbl); if (hn == 0) { bdf_create_property(name, BDF_ATOM); hn = hash_lookup(name, &proptbl); } /* * Allocate another property if this is overflow. */ if (font->props_used == font->props_size) { if (font->props_size == 0) font->props = (bdf_property_t *) malloc(sizeof(bdf_property_t)); else font->props = (bdf_property_t *) realloc((char *) font->props, sizeof(bdf_property_t) * (font->props_size + 1)); fp = font->props + font->props_size; (void) memset((char *) fp, 0, sizeof(bdf_property_t)); font->props_size++; } propid = (unsigned int) hn->data; if (propid >= _num_bdf_properties) prop = 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: if (value == 0) len = 1; else len = strlen(value) + 1; if (len > 1) { fp->value.atom = (char *) malloc(len); (void) memcpy(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; } /* * If the property happens to be a comment, then it doesn't need * to be added to the internal hash table. */ if (memcmp(name, "COMMENT", 7) != 0) /* * Add the property to the font property table. */ hash_insert(fp->name, (void *) font->props_used, (hashtable *) font->internal); 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 (memcmp(name, "DEFAULT_CHAR", 12) == 0) font->default_glyph = fp->value.int32; else if (memcmp(name, "FONT_ASCENT", 11) == 0) font->font_ascent = fp->value.int32; else if (memcmp(name, "FONT_DESCENT", 12) == 0) font->font_descent = fp->value.int32; else if (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; } } /* * Actually parse the glyph info and bitmaps. */ static int _bdf_parse_glyphs(char *line, unsigned int linelen, unsigned int lineno, void *call_data, void *client_data) { int c; char *s; unsigned char *bp; unsigned int i, slen = 0, 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]; next = (_bdf_line_func_t *) call_data; p = (_bdf_parse_t *) client_data; font = p->font; /* * Check for a comment. */ if (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 (memcmp(line, "CHARS", 5) != 0) { sprintf(nbuf, ERRMSG1, lineno, "CHARS"); _bdf_add_acmsg(p->font, nbuf, strlen(nbuf)); return BDF_MISSING_CHARS; } _bdf_split(" +", line, linelen, &p->list); 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; font->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * font->glyphs_size); /* * Make sure the glyph structures are initialized. */ (void) memset((char *) font->glyphs, 0, sizeof(bdf_glyph_t) * font->glyphs_size); /* * 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 (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 (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 (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) free(p->glyph_name); _bdf_split(" +", line, linelen, &p->list); _bdf_shift(1, &p->list); s = _bdf_join(' ', &slen, &p->list); p->glyph_name = (char *) malloc(slen + 1); (void) memcpy(p->glyph_name, s, slen + 1); p->flags |= _BDF_GLYPH; return 0; } /* * Check for the ENCODING field. */ if (memcmp(line, "ENCODING", 8) == 0) { if (!(p->flags & _BDF_GLYPH)) { /* * Missing STARTCHAR field. */ sprintf(nbuf, ERRMSG1, lineno, "STARTCHAR"); _bdf_add_acmsg(font, nbuf, strlen(nbuf)); return BDF_MISSING_STARTCHAR; } _bdf_split(" +", line, linelen, &p->list); 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, 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) { font->glyphs = (bdf_glyph_t *) realloc((char *) font->glyphs, sizeof(bdf_glyph_t) * (font->glyphs_size + 64)); (void) memset((char *) (font->glyphs + font->glyphs_size), 0, sizeof(bdf_glyph_t) << 6); 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) font->unencoded = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) << 2); else font->unencoded = (bdf_glyph_t *) realloc((char *) font->unencoded, sizeof(bdf_glyph_t) * (font->unencoded_size + 4)); 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. */ 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, 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, strlen(nbuf)); p->flags |= _BDF_GLYPH_WIDTH_CHECK; font->modified = 1; } p->row++; return 0; } /* * Expect the SWIDTH (scalable width) field next. */ if (memcmp(line, "SWIDTH", 6) == 0) { if (!(p->flags & _BDF_ENCODING)) { /* * Missing ENCODING field. */ sprintf(nbuf, ERRMSG1, lineno, "ENCODING"); _bdf_add_acmsg(font, nbuf, strlen(nbuf)); return BDF_MISSING_ENCODING; } _bdf_split(" +", line, linelen, &p->list); glyph->swidth = _bdf_atoul(p->list.field[1], 0, 10); p->flags |= _BDF_SWIDTH; return 0; } /* * Expect the DWIDTH (scalable width) field next. */ if (memcmp(line, "DWIDTH", 6) == 0) { _bdf_split(" +", line, linelen, &p->list); 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, 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 (memcmp(line, "BBX", 3) == 0) { _bdf_split(" +", line, linelen, &p->list); 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, 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 (memcmp(line, "BITMAP", 6) == 0) { if (!(p->flags & _BDF_BBX)) { /* * Missing BBX field. */ sprintf(nbuf, ERRMSG1, lineno, "BBX"); _bdf_add_acmsg(font, nbuf, 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; glyph->bitmap = (unsigned char *) malloc(glyph->bytes); 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 int linelen, unsigned int lineno, void *call_data, void *client_data) { unsigned int vlen; _bdf_line_func_t *next; _bdf_parse_t *p; char *name, *value, nbuf[128]; next = (_bdf_line_func_t *) call_data; p = (_bdf_parse_t *) client_data; while (*line == ' ' || *line == '\t') ++line; /* * Check for the end of the properties. */ if (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, 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, strlen(nbuf)); p->font->modified = 1; } p->flags &= ~_BDF_PROPS; *next = _bdf_parse_glyphs; return 0; } /* * Ignore the _XFREE86_GLYPH_RANGES and _XMBDFED_INFO properties. */ if (memcmp(line, "_XFREE86_GLYPH_RANGES", 21) == 0 || memcmp(line, "_XMBDFED_INFO", 13) == 0) return 0; /* * Handle COMMENT fields and properties in a special way to preserve * the spacing. */ if (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)) _bdf_add_property(p->font, name, value); else { _bdf_split(" +", line, linelen, &p->list); 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 int linelen, unsigned int lineno, void *call_data, void *client_data) { unsigned int slen = 0; _bdf_line_func_t *next; _bdf_parse_t *p; bdf_font_t *font; char *s, nbuf[128]; next = (_bdf_line_func_t *) call_data; p = (_bdf_parse_t *) client_data; /* * Check for a comment. This is done to handle those fonts that have * comments before the STARTFONT line for some reason. */ if (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); } return 0; } if (!(p->flags & _BDF_START)) { if (memcmp(line, "STARTFONT", 9) != 0) /* * No STARTFONT field is a good indication of a problem. */ return BDF_MISSING_START; p->flags = _BDF_START; p->font = font = (bdf_font_t *) calloc(1, sizeof(bdf_font_t)); p->font->internal = (void *) malloc(sizeof(hashtable)); hash_init((hashtable *) p->font->internal); p->font->spacing = p->opts->font_spacing; p->font->default_glyph = -1; return 0; } /* * Check for the start of the properties. */ if (memcmp(line, "STARTPROPERTIES", 15) == 0) { _bdf_split(" +", line, linelen, &p->list); p->cnt = p->font->props_size = _bdf_atoul(p->list.field[1], 0, 10); p->font->props = (bdf_property_t *) malloc(sizeof(bdf_property_t) * p->cnt); p->flags |= _BDF_PROPS; *next = _bdf_parse_properties; return 0; } /* * Check for the FONTBOUNDINGBOX field. */ if (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, strlen(nbuf)); return BDF_MISSING_SIZE; } _bdf_split(" +", line, linelen, &p->list); 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 (memcmp(line, "FONT", 4) == 0) { _bdf_split(" +", line, linelen, &p->list); _bdf_shift(1, &p->list); s = _bdf_join(' ', &slen, &p->list); p->font->name = (char *) malloc(slen + 1); (void) 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 (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, strlen(nbuf)); return BDF_MISSING_FONTNAME; } _bdf_split(" +", line, linelen, &p->list); 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, strlen(nbuf)); } } if (p->font->bpp > 4) { sprintf(nbuf, ACMSG11, p->font->bpp); _bdf_add_acmsg(p->font, nbuf, strlen(nbuf)); p->font->bpp = 4; } } else p->font->bpp = 1; p->flags |= _BDF_SIZE; return 0; } return BDF_INVALID_LINE; } /************************************************************************** * * API. * **************************************************************************/ void bdf_setup(void) { unsigned int i; bdf_property_t *prop; hash_init(&proptbl); for (i = 0, prop = _bdf_properties; i < _num_bdf_properties; i++, prop++) hash_insert(prop->name, (void *) i, &proptbl); } void bdf_cleanup(void) { unsigned int i; bdf_property_t *prop; hash_free(&proptbl); /* * Free up the user defined properties. */ for (prop = user_props, i = 0; i < nuser_props; i++, prop++) { free(prop->name); if (prop->format == BDF_ATOM && prop->value.atom != 0) free(prop->value.atom); } if (nuser_props > 0) free((char *) user_props); _bdf_glyph_name_cleanup(); } bdf_font_t * bdf_load_font(FILE *in, bdf_options_t *opts, bdf_callback_t callback, void *data) { int n; unsigned int lineno; char msgbuf[128]; _bdf_parse_t p; (void) 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; n = _bdf_readlines(fileno(in), _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. */ 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, 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, 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, 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, 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, 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, strlen(msgbuf)); } p.font->bbx.height = p.maxas + p.maxds; if (p.flags & _BDF_SWIDTH_ADJ) _bdf_add_acmsg(p.font, ACMSG8, 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, 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) free((char *) p.list.field); if (p.font != 0) { /* * Make sure the comments are NULL terminated if they exist. */ if (p.font->comments_len > 0) { p.font->comments = (char *) realloc(p.font->comments, p.font->comments_len + 1); 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) { p.font->acmsgs = (char *) realloc(p.font->acmsgs, p.font->acmsgs_len + 1); p.font->acmsgs[p.font->acmsgs_len] = 0; } } return p.font; } #ifdef HAVE_HBF static int _bdf_parse_hbf_header(char *line, unsigned int linelen, unsigned int lineno, void *call_data, void *client_data) { unsigned int vlen = 0; char *name, *value; _bdf_parse_t *p; _bdf_line_func_t *next; char nbuf[24]; next = (_bdf_line_func_t *) call_data; p = (_bdf_parse_t *) client_data; /* * Check for comments. */ if (memcmp(line, "COMMENT", 7) == 0) { if (p->opts->keep_comments != 0 && p->font != 0) { name = line; value = name + 7; vlen = linelen - 7; if (*value) { *value++ = 0; vlen--; } /* * If the properties are being parsed, add the comment as a * property. Otherwise, simply add the comment in the normal * fashion. */ if (p->flags & _BDF_PROPS) _bdf_add_property(p->font, name, value); else _bdf_add_comment(p->font, value, vlen); } return 0; } if (!(p->flags & _BDF_START)) { if (memcmp(line, "HBF_START_FONT", 14) != 0) return -1; p->flags = _BDF_START; p->font = (bdf_font_t *) calloc(1, sizeof(bdf_font_t)); /* * HBF fonts are always assumed to be 1 bit per pixel. */ p->font->bpp = 1; p->font->internal = (void *) malloc(sizeof(hashtable)); hash_init((hashtable *) p->font->internal); p->font->hbf = 1; p->font->spacing = p->opts->font_spacing; p->font->default_glyph = -1; return 0; } /* * Check for the HBF_END_FONT field. */ if (memcmp(line, "HBF_END_FONT", 12) == 0) /* * Need to perform some checks here to see whether some fields are * missing or not. */ return 0; /* * Check for HBF keywords which will be added as comments. These should * never occur in the properties list. Assume they won't. */ if (memcmp(line, "HBF_", 4) == 0) { if (p->opts->keep_comments != 0) _bdf_add_comment(p->font, line, linelen); return 0; } if (!(p->flags & _BDF_PROPS)) { /* * Check for the start of the properties. */ if (memcmp(line, "STARTPROPERTIES", 15) == 0) { _bdf_split(" +", line, linelen, &p->list); p->cnt = p->font->props_size = _bdf_atoul(p->list.field[1], 0, 10); p->font->props = (bdf_property_t *) malloc(sizeof(bdf_property_t) * p->cnt); p->flags |= _BDF_PROPS; return 0; } /* * Check for the CHARS field. */ if (memcmp(line, "CHARS", 5) == 0) { _bdf_split(" +", line, linelen, &p->list); p->cnt = p->font->glyphs_size = _bdf_atoul(p->list.field[1], 0, 10); p->font->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * p->cnt); return 0; } /* * Check for the FONTBOUNDINGBOX field. */ if (memcmp(line, "FONTBOUNDINGBOX", 15) == 0) { if (!(p->flags & (_BDF_START|_BDF_FONT_NAME|_BDF_SIZE))) return -1; _bdf_split(" +", line, linelen, &p->list); 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 (memcmp(line, "FONT", 4) == 0) { if (!(p->flags & _BDF_START)) return -1; _bdf_split(" +", line, linelen, &p->list); _bdf_shift(1, &p->list); value = _bdf_join(' ', &vlen, &p->list); p->font->name = (char *) malloc(vlen + 1); (void) memcpy(p->font->name, value, vlen + 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 (memcmp(line, "SIZE", 4) == 0) { if (!(p->flags & (_BDF_START|_BDF_FONT_NAME))) return -1; _bdf_split(" +", line, linelen, &p->list); 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); p->flags |= _BDF_SIZE; return 0; } } else { /* * Check for the end of the properties. */ if (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, 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, strlen(nbuf)); p->font->modified = 1; } p->flags &= ~_BDF_PROPS; return 0; } /* * Handle the next thing in the usual property fashion. */ if (_bdf_is_atom(line, linelen, &name, &value)) _bdf_add_property(p->font, name, value); else { _bdf_split(" +", line, linelen, &p->list); 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; } /* * Anything else is an error. */ return -1; } #define CONST const static void _bdf_add_hbf_glyph(HBF *hbf, unsigned int code, void *callback_data) { CONST unsigned char *bmap; unsigned int n; bdf_glyph_t *gp; bdf_font_t *font; _bdf_parse_t *p; HBF_BBOX *fbbx; double ps, rx, dw; char nbuf[24]; /* * Attempt to get the bitmap. */ if ((bmap = hbfGetBitmap(hbf, code)) == 0) /* * Need some sort of error handling here. */ return; p = (_bdf_parse_t *) callback_data; fbbx = hbfFontBBox(hbf); font = p->font; /* * Check to make sure there is enough space to hold this glyph. If not, * allocate 10 more just in case. */ if (font->glyphs_used == font->glyphs_size) { if (font->glyphs_size == 0) font->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * 16); else font->glyphs = (bdf_glyph_t *) realloc((char *) font->glyphs, sizeof(bdf_glyph_t) * (font->glyphs_used + 16)); gp = font->glyphs + font->glyphs_size; (void) memset((char *) gp, 0, sizeof(bdf_glyph_t) * 16); font->glyphs_size += 16; } gp = font->glyphs + font->glyphs_used++; /* * Set the glyph name. */ sprintf(nbuf, "char%d", code); n = (unsigned int) strlen(nbuf); gp->name = (char *) malloc(n + 1); (void) memcpy(gp->name, nbuf, n + 1); /* * Set encoding. */ gp->encoding = (int) code; /* * Set the device width. */ gp->dwidth = (unsigned short) fbbx->hbf_width; /* * Set the scalable width. */ ps = (double) font->point_size; rx = (double) font->resolution_x; dw = (double) gp->dwidth; gp->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx)); /* * Set the glyph bounding box. */ gp->bbx.width = fbbx->hbf_width; gp->bbx.height = fbbx->hbf_height; gp->bbx.x_offset = fbbx->hbf_xDisplacement; gp->bbx.y_offset = fbbx->hbf_yDisplacement; gp->bbx.ascent = gp->bbx.height + gp->bbx.y_offset; gp->bbx.descent = -gp->bbx.y_offset; /* * Add the bitmap by making a copy. Assumes the font bbx is OK for * determining the number of bytes needed for the glyph bitmap. */ gp->bytes = ((gp->bbx.width + 7) >> 3) * gp->bbx.height; gp->bitmap = (unsigned char *) malloc(gp->bytes); (void) memcpy((char *) gp->bitmap, (char *) bmap, gp->bytes); /* * Call the callback if it was provided. */ 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); } } bdf_font_t * bdf_load_hbf_font(char *filename, bdf_options_t *opts, bdf_callback_t callback, void *data) { int n, diff; unsigned int lineno; FILE *in; HBF *hbf; bdf_property_t *pp; char *name; _bdf_parse_t p; if ((hbf = hbfOpen(filename)) == 0) return 0; if ((in = fopen(hbfFileName(hbf), "r")) == 0) { hbfClose(hbf); return 0; } /* * Parse the HBF header for properties and other things. */ (void) 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; n = _bdf_readlines(fileno(in), _bdf_parse_hbf_header, (void *) &p, &lineno); fclose(in); /* * Determine what spacing the font has so the monowidth field can be set * if necessary. */ if ((pp = bdf_get_font_property(p.font, "SPACING")) != 0) { switch (pp->value.atom[0]) { case 'p': case 'P': p.font->spacing = BDF_PROPORTIONAL; break; case 'm': case 'M': p.font->spacing = BDF_MONOWIDTH; break; case 'c': case 'C': p.font->spacing = BDF_CHARCELL; break; } } /* * Set the monowidth field if necessary. */ if (p.font->spacing != BDF_PROPORTIONAL) p.font->monowidth = p.font->bbx.width; /* * Before loading the glyphs, check to see if any glyph structures have * been added. If not, check the HBF font for the number of characters. * Dynamically increasing glyph storage causes memory fragmentation on * some machines and crashes. This takes care of the cases where the HBF * file does not provide a "CHARS n" line. */ if (p.font->glyphs_size < hbfChars(hbf)) { if (p.font->glyphs_size == 0) p.font->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * hbfChars(hbf)); else p.font->glyphs = (bdf_glyph_t *) realloc((char *) p.font->glyphs, sizeof(bdf_glyph_t) * hbfChars(hbf)); diff = hbfChars(hbf) - p.font->glyphs_size; (void) memset((char *) (p.font->glyphs + p.font->glyphs_size), 0, diff); p.font->glyphs_size = hbfChars(hbf); } /* * Call the callback initially to set things up. */ if (p.callback != 0) { p.cb.reason = BDF_LOAD_START; p.cb.total = p.font->glyphs_size; p.cb.current = 0; (*p.callback)(&p.cb, p.client_data); } /* * Now load the glyphs. */ hbfForEach(hbf, _bdf_add_hbf_glyph, (void *) &p); /* * Close the HBF font. */ hbfClose(hbf); /* * Sort the glyphs by encoding. */ qsort((char *) p.font->glyphs, p.font->glyphs_used, sizeof(bdf_glyph_t), by_encoding); /* * After loading the HBF header, create an XLFD name. If the XLFD name * cannot be made then preserve the name found in the HBF file. */ if ((name = bdf_make_xlfd_name(p.font, "HBF", "Unknown")) != 0) { if (p.font->name != 0) /* * If a name already exists in the font, free it up. */ free(p.font->name); /* * Replace the old name with the XLFD name. */ p.font->name = name; } /* * Mark the font as being modified and generate a message that says * something about the font being converted from HBF format. */ p.font->modified = 1; _bdf_add_acmsg(p.font, "Font converted from HBF to BDF.", 31); return p.font; } #endif /* HAVE_HBF */ /* * Crop the glyph bitmap to the minimum rectangle needed to hold the bits that * are set. Adjust the metrics based on the provided bounding box. */ void _bdf_crop_glyph(bdf_font_t *font, bdf_glyph_t *glyph) { int byte; unsigned short x, y, bpr, nbpr, col, colx, si, di; unsigned short minx, maxx, miny, maxy; unsigned int bytes; unsigned char *bmap, *masks; bdf_bbx_t nbbx; if (glyph == 0) return; (void) memcpy((char *) &nbbx, (char *) &glyph->bbx, sizeof(bdf_bbx_t)); bpr = ((glyph->bbx.width * font->bpp) + 7) >> 3; maxx = maxy = 0; minx = miny = 32767; masks = 0; switch (font->bpp) { case 1: masks = bdf_onebpp; break; case 2: masks = bdf_twobpp; break; case 4: masks = bdf_fourbpp; break; case 8: masks = bdf_eightbpp; break; } for (y = 0; y < glyph->bbx.height; y++) { for (col = x = 0; x < glyph->bbx.width; x++, col += font->bpp) { si = (col & 7) / font->bpp; if (glyph->bitmap[(y * bpr) + (col >> 3)] & masks[si]) { minx = MIN(minx, x); maxx = MAX(maxx, x); miny = MIN(miny, y); maxy = MAX(maxy, y); } } } /* * Handle an empty bitmap as a special case. */ if (minx == 32767) { if (glyph->bytes > 0) free((char *) glyph->bitmap); glyph->bytes = 0; (void) memset((char *) &glyph->bbx, 0, sizeof(bdf_bbx_t)); return; } /* * Increment the max points so width and height calculations won't go * wrong. */ maxx++; maxy++; if (minx > 0) nbbx.x_offset += minx; if (maxx - minx != nbbx.width) nbbx.width = maxx - minx; if (miny > 0) nbbx.ascent -= miny; if (maxy - miny != nbbx.height) nbbx.height = maxy - miny; nbbx.descent = nbbx.height - nbbx.ascent; nbbx.y_offset = -nbbx.descent; nbpr = ((nbbx.width * font->bpp) + 7) >> 3; /* * If nothing changed, then the glyph is already contained in the * minimum rectangle. */ if (memcmp((char *) &nbbx, (char *) &glyph->bbx, sizeof(bdf_bbx_t)) == 0 || (nbpr == bpr && nbbx.height == glyph->bbx.height)) return; /* * The metrics changed, so a new bitmap is needed. */ bytes = nbpr * nbbx.height; bmap = (unsigned char *) malloc(bytes); (void) memset((char *) bmap, 0, bytes); colx = minx * font->bpp; for (y = miny; y < maxy; y++) { for (col = x = minx; x < maxx; x++, col += font->bpp) { si = (col & 7) / font->bpp; byte = glyph->bitmap[(y * bpr) + (col >> 3)] & masks[si]; if (byte) { /* * Position the pixel in the byte if necessary. */ di = ((col - colx) & 7) / font->bpp; if (di < si) byte <<= (si - di) * font->bpp; else if (di > si) byte >>= (di - si) * font->bpp; bmap[((y - miny) * nbpr) + ((col - colx) >> 3)] |= byte; } } } if (glyph->bytes > 0) free((char *) glyph->bitmap); glyph->bytes = bytes; glyph->bitmap = bmap; (void) memcpy((char *) &glyph->bbx, (char *) &nbbx, sizeof(bdf_bbx_t)); } /* * Pad a character-cell font glyph to match the bounds specified in the * provided bounding box. */ void _bdf_pad_cell(bdf_font_t *font, bdf_glyph_t *glyph, bdf_glyph_t *cell) { bdf_bbx_t *bbx; unsigned short si, di, sx, byte; unsigned short x, y, dx, dy, bx, by, bpr, nbpr; unsigned char *bmap, *masks; masks = 0; switch (font->bpp) { case 1: masks = bdf_onebpp; break; case 2: masks = bdf_twobpp; break; case 4: masks = bdf_fourbpp; break; case 8: masks = bdf_eightbpp; break; } bbx = &font->bbx; if (glyph->bbx.width == bbx->width && glyph->bbx.height == bbx->height) { /* * The glyph is already positioned in the cell. Copy the bitmap * and return. */ (void) memcpy((char *) cell->bitmap, (char *) glyph->bitmap, cell->bytes); return; } /* * Determine the X and Y location of the baseline. */ bx = MYABS(bbx->x_offset - glyph->bbx.x_offset); by = (bbx->ascent + bbx->descent) + bbx->y_offset; bpr = ((glyph->bbx.width * font->bpp) + 7) >> 3; nbpr = ((bbx->width * font->bpp) + 7) >> 3; /* * Set various cell values and clear the cell bitmap. */ bmap = cell->bitmap; (void) memset((char *) bmap, 0, cell->bytes); for (dy = by - glyph->bbx.ascent, y = 0; y < glyph->bbx.height; y++, dy++) { for (dx = bx * font->bpp, sx = x = 0; x < glyph->bbx.width; x++, dx += font->bpp, sx += font->bpp) { si = (sx & 7) / font->bpp; byte = glyph->bitmap[(y * bpr) + (sx >> 3)] & masks[si]; if (byte) { di = (dx & 7) / font->bpp; if (di < si) byte <<= (si - di) * font->bpp; else if (di > si) byte >>= (di - si) * font->bpp; bmap[(dy * nbpr) + (dx >> 3)] |= byte; } } } } static char *unix_eol = "\n"; static char *dos_eol = "\r\n"; static char *mac_eol = "\r"; void bdf_save_font(FILE *out, bdf_font_t *font, bdf_options_t *opts, bdf_callback_t callback, void *data) { int len; unsigned int i, j, bpr, pcnt; double dw, ps, rx; char *sp, *ep, *eol; bdf_property_t *p; bdf_glyph_t *c, *cp, cell; bdf_callback_struct_t cb; if (font == 0) return; eol = 0; switch (opts->eol) { case BDF_UNIX_EOL: eol = unix_eol; break; case BDF_DOS_EOL: eol = dos_eol; break; case BDF_MAC_EOL: eol = mac_eol; break; } /* * If the font is a character cell font, allocate some space for the * bitmap. */ if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0) { bpr = ((font->bbx.width * font->bpp) + 7) >> 3; cell.bytes = bpr * font->bbx.height; cell.bitmap = (unsigned char *) malloc(cell.bytes); (void) memcpy((char *) &cell.bbx, (char *) &font->bbx, sizeof(bdf_bbx_t)); } /* * Emit the header. */ fprintf(out, "STARTFONT 2.1%s", eol); /* * Emit the comments. */ if (font->comments_len > 0) { for (sp = font->comments; *sp; sp++) { ep = sp; while (*ep && *ep != '\n') ep++; len = (int) (ep - sp); fprintf(out, "COMMENT %.*s%s", len, sp, eol); sp = ep; } } /* * Emit the font name. */ fprintf(out, "FONT %s%s", font->name, eol); /* * Emit the size info. */ if (font->bpp == 1) fprintf(out, "SIZE %d %d %d%s", font->point_size, font->resolution_x, font->resolution_y, eol); else fprintf(out, "SIZE %d %d %d %hd%s", font->point_size, font->resolution_x, font->resolution_y, font->bpp, eol); /* * Emit the bounding box. */ fprintf(out, "FONTBOUNDINGBOX %hd %hd %hd %hd%s", font->bbx.width, font->bbx.height, font->bbx.x_offset, font->bbx.y_offset, eol); /* * Emit the properties after counting how many are properties and * how many are comments. */ for (i = pcnt = 0, p = font->props; i < font->props_used; i++, p++) { if (memcmp(p->name, "COMMENT", 7) != 0) pcnt++; } fprintf(out, "STARTPROPERTIES %d%s", pcnt, eol); for (i = 0, p = font->props; i < font->props_used; i++, p++) { fprintf(out, "%s ", p->name); if (p->format == BDF_ATOM) { if (p->value.atom == 0) fprintf(out, "\"\"%s", eol); else fprintf(out, "\"%s\"%s", p->value.atom, eol); } else fprintf(out, "%d%s", p->value.int32, eol); } fprintf(out, "ENDPROPERTIES%s", eol); /* * Emit the number of bitmaps in the font. */ fprintf(out, "CHARS %d%s", font->unencoded_used + font->glyphs_used, eol); /* * Call the callback if it was passed to start the save. */ if (callback != 0) { cb.reason = BDF_SAVE_START; cb.total = font->unencoded_used + font->glyphs_used; cb.current = 0; (*callback)(&cb, data); } /* * Emit the unencoded bitmaps. */ for (i = 0, cp = font->unencoded; i < font->unencoded_used; i++, cp++) { /* * If the font has character-cell spacing and the option to pad the * glyphs to the size of the font bbx is set, then pad the glyph. * Otherwise, crop the glyph to the minimum rectangle needed to hold * the bitmap. */ if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0) { /* * Point at the temporary glyph structure and copy the necessary * glyph info into it. */ c = &cell; c->name = cp->name; c->encoding = cp->encoding; c->swidth = cp->swidth; c->dwidth = cp->dwidth; _bdf_pad_cell(font, cp, c); } else { c = cp; _bdf_crop_glyph(font, c); } /* * If the font has monowidth or character-cell spacing, then assign * the font monowidth field to the device width and recalculate the * scalable width. */ if (font->spacing != BDF_PROPORTIONAL) { c->dwidth = font->monowidth; ps = (double) font->point_size; rx = (double) font->resolution_x; dw = (double) c->dwidth; c->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx)); } if (c->name == 0) fprintf(out, "STARTCHAR unencoded%d%sENCODING -1%s", i, eol, eol); else fprintf(out, "STARTCHAR %s%sENCODING -1%s", c->name, eol, eol); fprintf(out, "SWIDTH %hd 0%sDWIDTH %hd 0%s", c->swidth, eol, c->dwidth, eol); fprintf(out, "BBX %hd %hd %hd %hd%s", c->bbx.width, c->bbx.height, c->bbx.x_offset, c->bbx.y_offset, eol); fprintf(out, "BITMAP%s", eol); bpr = ((c->bbx.width * font->bpp) + 7) >> 3; for (j = 0; bpr != 0 && j < c->bytes; j++) { if (j && j % bpr == 0) fprintf(out, eol); fprintf(out, "%02X", c->bitmap[j]); } /* * Handle empty bitmaps like this. */ if (c->bbx.height > 0) fprintf(out, eol); fprintf(out, "ENDCHAR%s", eol); /* * Call the callback if supplied. */ if (callback != 0) { cb.reason = BDF_SAVING; cb.current++; (*callback)(&cb, data); } } /* * Emit the other bitmaps. */ for (i = 0, cp = font->glyphs; i < font->glyphs_used; i++, cp++) { /* * If the font has character-cell spacing and the option to pad the * glyphs to the size of the font bbx is set, then pad the glyph. * Otherwise, crop the glyph to the minimum rectangle needed to hold * the bitmap. */ if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0) { /* * Point at the temporary glyph structure and copy the necessary * glyph info into it. */ c = &cell; c->name = cp->name; c->encoding = cp->encoding; c->swidth = cp->swidth; c->dwidth = cp->dwidth; _bdf_pad_cell(font, cp, c); } else { c = cp; _bdf_crop_glyph(font, c); } /* * If the font has monowidth or character-cell spacing, then assign * the font monowidth field to the device width and recalculate the * scalable width. */ if (font->spacing != BDF_PROPORTIONAL) { c->dwidth = font->monowidth; ps = (double) font->point_size; rx = (double) font->resolution_x; dw = (double) c->dwidth; c->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx)); } if (c->name == 0) fprintf(out, "STARTCHAR char%d%sENCODING %d%s", c->encoding, eol, c->encoding, eol); else fprintf(out, "STARTCHAR %s%sENCODING %d%s", c->name, eol, c->encoding, eol); fprintf(out, "SWIDTH %hd 0%sDWIDTH %hd 0%s", c->swidth, eol, c->dwidth, eol); fprintf(out, "BBX %hd %hd %hd %hd%s", c->bbx.width, c->bbx.height, c->bbx.x_offset, c->bbx.y_offset, eol); fprintf(out, "BITMAP%s", eol); bpr = ((c->bbx.width * font->bpp) + 7) >> 3; for (j = 0; bpr != 0 && j < c->bytes; j++) { if (j && j % bpr == 0) fprintf(out, eol); fprintf(out, "%02X", c->bitmap[j]); } /* * Handle empty bitmaps like this. */ if (c->bbx.height > 0) fprintf(out, eol); fprintf(out, "ENDCHAR%s", eol); /* * Call the callback if supplied. */ if (callback != 0) { cb.reason = BDF_SAVING; cb.current++; (*callback)(&cb, data); } } /* * Emit the trailer. */ fprintf(out, "ENDFONT%s", eol); /* * Always force a final call to the callback to make sure things * get cleaned up. */ if (callback != 0) { cb.reason = BDF_SAVING; cb.current = cb.total; (*callback)(&cb, data); } /* * If the font is a character cell font, clean up the temporary glyph. */ if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0) free((char *) cell.bitmap); } /* * Routine to write a single set of SBIT metrics. */ void bdf_save_sbit_metrics(FILE *out, bdf_font_t *font, bdf_options_t *opts, char *appname) { char *eol; eol = 0; switch (opts->eol) { case BDF_UNIX_EOL: eol = unix_eol; break; case BDF_DOS_EOL: eol = dos_eol; break; case BDF_MAC_EOL: eol = mac_eol; break; } /* * Throw a simple header in. */ if (appname) fprintf(out, ";%s; SBIT metrics file generated by \"%s\".%s;%s%s", eol, appname, eol, eol, eol); /* * Save PPEM. */ fprintf(out, ";%s; Pixels Per Em.%s;%s", eol, eol, eol); fprintf(out, "PPEM %d%s%s", font->point_size, eol, eol); /* * If the font is character cell or monowidth, set this boolean. */ if (font->spacing != BDF_PROPORTIONAL) { fprintf(out, ";%s; Font is not proportional, so use mono advance.%s;%s", eol, eol, eol); fprintf(out, "FORCECONSTANTMETRICS TRUE%s%s", eol, eol); } else { fprintf(out, ";%s; Font is proportional, so do not use mono advance.%s;%s", eol, eol, eol); fprintf(out, "FORCECONSTANTMETRICS FALSE%s%s", eol, eol); } /* * Do the horizontal line metrics only. */ fprintf(out, ";%s; Horizontal line metrics.%s;%s", eol, eol, eol); fprintf(out, "H_ASCENDER %d%sH_DESCENDER %d%s", font->font_ascent, eol, font->font_descent, eol); fprintf(out, "H_WIDTHMAX %hd%s", font->bbx.width, eol); fprintf(out, "H_MINORIGINSB %hd%sH_MINADVANCEBL %hd%s", font->bbx.x_offset, eol, font->bbx.width + font->bbx.x_offset, eol); fprintf(out, "H_MAXBEFOREBL %hd%sH_MINAFTERBL %hd%s%s", font->bbx.ascent, eol, font->bbx.y_offset, eol, eol); /* * Write the default caret info. */ fprintf(out, ";%s; Caret slope and offset info.%s;%s", eol, eol, eol); fprintf(out, "CARETSLOPENUMERATOR 1%sCARETSLOPEDENOMINATOR 0%s", eol, eol); fprintf(out, "CARETOFFSET 0%s%s", eol, eol); /* * Write the bitmap options. */ fprintf(out, ";%s; Bitmap options.%s;%s", eol, eol, eol); fprintf(out, "DIRECTION H%sSTORAGE FAST%s%s", eol, eol, eol); /* * Scaled bitmaps not implemented yet. */ fprintf(out, ";%s; Scaled bitmap info (Not Yet Implemented).%s;%s", eol, eol, eol); } /* * Special routine to dump the font in the Roman Czyborra's hex format. It * only dumps the encoded glyphs and assumes the bitmaps have the correct * sizes. */ void bdf_export_hex(FILE *out, bdf_font_t *font, bdf_options_t *opts, bdf_callback_t callback, void *data) { int bpr, fbpr, j, k; unsigned int i, ng; bdf_glyph_t *gp, cell; bdf_callback_struct_t cb; if (font == 0 || out == 0) return; if (font->glyphs_used == 0) return; /* * Call the callback if it was passed to start the export. */ if (callback != 0) { cb.reason = BDF_EXPORT_START; cb.total = font->glyphs_used; cb.current = 0; (*callback)(&cb, data); } fbpr = ((font->bbx.width * font->bpp) + 7) >> 3; bpr = (((font->bbx.width >> 1) * font->bpp) + 7) >> 3; cell.bytes = fbpr * font->bbx.height; cell.bitmap = (unsigned char *) malloc(cell.bytes); for (i = 0, ng = font->glyphs_used, gp = font->glyphs; i < ng; i++, gp++) { _bdf_pad_cell(font, gp, &cell); fprintf(out, "%04X:", gp->encoding & 0xffff); if (gp->bbx.width <= (font->bbx.width >> 1)) { for (j = 0; j < cell.bytes; j += fbpr) { for (k = 0; k < bpr; k++) fprintf(out, "%02X", cell.bitmap[j + k]); } } else { for (j = 0; j < cell.bytes; j++) fprintf(out, "%02X", cell.bitmap[j]); } if (cell.bytes > 0) putc('\n', out); /* * Call the callback if supplied. */ if (callback != 0) { cb.reason = BDF_EXPORTING; cb.current++; (*callback)(&cb, data); } } /* * Clean up the cell. */ free((char *) cell.bitmap); /* * Always call a final callback to make sure the client gets a chance to * clean things up. */ if (callback != 0) { cb.reason = BDF_EXPORTING; cb.current = cb.total; (*callback)(&cb, data); } } void bdf_free_font(bdf_font_t *font) { unsigned int i; bdf_glyph_t *glyphs; if (font == 0) return; if (font->name != 0) free(font->name); /* * Free up the internal hash table of property names. */ hash_free((hashtable *) font->internal); free((char *) font->internal); /* * Free up the comment info. */ if (font->comments_len > 0) free(font->comments); /* * Free up the auto-correction messages. */ if (font->acmsgs_len > 0) 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) free(font->props[i].value.atom); } if (font->props_size > 0 && font->props != 0) free((char *) font->props); /* * Free up the character info. */ for (i = 0, glyphs = font->glyphs; i < font->glyphs_used; i++, glyphs++) { if (glyphs->name) free(glyphs->name); if (glyphs->bytes > 0 && glyphs->bitmap != 0) free((char *) glyphs->bitmap); } for (i = 0, glyphs = font->unencoded; i < font->unencoded_used; i++, glyphs++) { if (glyphs->name) free(glyphs->name); if (glyphs->bytes > 0) free((char *) glyphs->bitmap); if (glyphs->unicode.map_size > 0) free((char *) glyphs->unicode.map); } if (font->glyphs_size > 0) free((char *) font->glyphs); if (font->unencoded_size > 0) free((char *) 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) free(glyphs->name); if (glyphs->bytes > 0) free((char *) glyphs->bitmap);; if (glyphs->unicode.map_size > 0) free((char *) glyphs->unicode.map); } if (font->overflow.glyphs_size > 0) free((char *) font->overflow.glyphs); free((char *) font); } void bdf_create_property(char *name, int format) { unsigned int n; bdf_property_t *p; /* * First check to see if the property has * already been added or not. If it has, then * simply ignore it. */ if (hash_lookup(name, &proptbl)) return; if (nuser_props == 0) user_props = (bdf_property_t *) malloc(sizeof(bdf_property_t)); else user_props = (bdf_property_t *) realloc((char *) user_props, sizeof(bdf_property_t) * (nuser_props + 1)); p = user_props + nuser_props; (void) memset((char *) p, 0, sizeof(bdf_property_t)); n = (unsigned int) (strlen(name) + 1); p->name = (char *) malloc(n); (void) memcpy(p->name, name, n); p->format = format; p->builtin = 0; n = _num_bdf_properties + nuser_props; hash_insert(p->name, (void *) n, &proptbl); nuser_props++; } bdf_property_t * bdf_get_property(char *name) { hashnode hn; unsigned int propid; if (name == 0 || *name == 0) return 0; if ((hn = hash_lookup(name, &proptbl)) == 0) return 0; propid = (unsigned int) hn->data; if (propid >= _num_bdf_properties) return user_props + (propid - _num_bdf_properties); return _bdf_properties + propid; } /* * Routine to compare two property names. */ static int by_prop_name(const void *a, const void *b) { bdf_property_t *p1, *p2; p1 = (bdf_property_t *) a; p2 = (bdf_property_t *) b; return strcmp(p1->name, p2->name); } unsigned int bdf_property_list(bdf_property_t **props) { unsigned int n; bdf_property_t *p; n = _num_bdf_properties + nuser_props; if (props != 0 && n != 0) { p = (bdf_property_t *) malloc(sizeof(bdf_property_t) * n); (void) memcpy((char *) p, (char *) _bdf_properties, sizeof(bdf_property_t) * _num_bdf_properties); (void) memcpy((char *) (p + _num_bdf_properties), (char *) user_props, sizeof(bdf_property_t) * nuser_props); qsort((char *) p, n, sizeof(bdf_property_t), by_prop_name); *props = p; } return n; } int bdf_replace_comments(bdf_font_t *font, char *comments, unsigned int comments_len) { if (font == 0 || comments_len == 0) return 0; if (font->comments_len > 0) free(font->comments); font->comments = (char *) malloc(comments_len + 1); (void) memcpy(font->comments, comments, comments_len); font->comments[comments_len] = 0; font->comments_len = comments_len; font->modified = 1; return 1; } unsigned int bdf_font_property_list(bdf_font_t *font, bdf_property_t **props) { bdf_property_t *p; if (font == 0 || font->props_used == 0) return 0; if (props != 0) { p = (bdf_property_t *) malloc(sizeof(bdf_property_t) * font->props_used); (void) memcpy((char *) p, (char *) font->props, sizeof(bdf_property_t) * font->props_used); qsort((char *) p, font->props_used, sizeof(bdf_property_t), by_prop_name); *props = p; } return font->props_used; } void bdf_add_font_property(bdf_font_t *font, bdf_property_t *property) { int len; unsigned int propid; hashnode hn; bdf_property_t *p, *ip; if (property == 0 || property->name == 0 || property->name[0] == 0) return; /* * If the font does not have a property hash table yet, make * sure it is allocated. */ if (font->internal == 0) { font->internal = (void *) malloc(sizeof(hashtable)); hash_init((hashtable *) font->internal); } /* * See if the property is in the general property table yet. * If it isn't, then add it. */ if ((hn = hash_lookup(property->name, &proptbl)) == 0) bdf_create_property(property->name, property->format); else { /* * If the property exists and is a user defined property, make sure * its format is updated to match the property being added. */ propid = (unsigned int) hn->data; if (propid >= _num_bdf_properties) { p = user_props + (propid - _num_bdf_properties); if (p->format != property->format) p->format = property->format; } } /* * If the font already has this property, then change the existing one. */ hn = hash_lookup(property->name, (hashtable *) font->internal); if (hn != 0) { /* * Changing an existing property value. */ p = font->props + ((unsigned int) hn->data); /* * If the format changed, then free the atom value if the original * format was an atom. */ if (p->format == BDF_ATOM && property->format != BDF_ATOM && p->value.atom != 0) free((char *) p->value.atom); p->format = property->format; switch (p->format) { case BDF_ATOM: /* * If the property value is the same, then just return. */ if (property->value.atom == p->value.atom || (property->value.atom && p->value.atom && strcmp(property->value.atom, p->value.atom) == 0)) return; if (property->value.atom == 0) len = 1; else len = strlen(property->value.atom) + 1; if (len > 1) { p->value.atom = (char *) malloc(len); (void) memcpy(p->value.atom, property->value.atom, len); } else p->value.atom = 0; break; case BDF_INTEGER: /* * If the property value is the same, then just return. */ if (p->value.int32 == property->value.int32) return; p->value.int32 = property->value.int32; break; case BDF_CARDINAL: /* * If the property value is the same, then just return. */ if (p->value.card32 == property->value.card32) return; p->value.card32 = property->value.card32; break; } } else { /* * New property being added. */ /* * Get the internal table entry for a pointer to the * name of the property. */ hn = hash_lookup(property->name, &proptbl); propid = (unsigned int) hn->data; if (propid >= _num_bdf_properties) ip = user_props + (propid - _num_bdf_properties); else ip = _bdf_properties + propid; /* * Add it to the property list first. */ if (font->props_used == font->props_size) { if (font->props_size == 0) font->props = (bdf_property_t *) malloc(sizeof(bdf_property_t)); else font->props = (bdf_property_t *) realloc((char *) font->props, sizeof(bdf_property_t) * (font->props_size + 1)); font->props_size++; } p = font->props + font->props_used; p->name = ip->name; p->format = ip->format; p->builtin = ip->builtin; switch (p->format) { case BDF_ATOM: if (property->value.atom == 0) len = 1; else len = strlen(property->value.atom) + 1; if (len > 1) { p->value.atom = (char *) malloc(len); (void) memcpy(p->value.atom, property->value.atom, len); } else p->value.atom = 0; break; case BDF_INTEGER: p->value.int32 = property->value.int32; break; case BDF_CARDINAL: p->value.card32 = property->value.card32; break; } /* * Now insert it into the internal hash table. */ hash_insert(p->name, (void *) font->props_used, (hashtable *) font->internal); font->props_used++; } if (memcmp(property->name, "DEFAULT_CHAR", 12) == 0) /* * If the property just added is DEFAULT_CHAR, then make sure the * default_glyph field is set. */ font->default_glyph = p->value.card32; else if (memcmp(property->name, "FONT_ASCENT", 11) == 0) /* * If the property just added is FONT_ASCENT, then adjust the * font_ascent field. */ font->font_ascent = p->value.int32; else if (memcmp(property->name, "FONT_DESCENT", 12) == 0) /* * If the property just added is FONT_DESCENT, then adjust the * font_descent field. */ font->font_descent = p->value.int32; else if (memcmp(property->name, "RESOLUTION_X", 12) == 0) /* * If the property just added is RESOLUTION_X, then adjust the * resolution_x field. */ font->resolution_x = p->value.card32; else if (memcmp(property->name, "RESOLUTION_Y", 12) == 0) /* * If the property just added is RESOLUTION_Y, then adjust the * resolution_y field. */ font->resolution_y = p->value.card32; else if (memcmp(property->name, "POINT_SIZE", 10) == 0) /* * If the property just added is POINT_SIZE, then adjust the * point_size field. */ font->point_size = p->value.int32 / 10; else if (memcmp(property->name, "SPACING", 7) == 0) { /* * Make sure the font spacing is kept in synch if the property * changes. If the spacing changes from proportional to one * of the others, force the monowidth to be set. */ switch (p->value.atom[0]) { case 'C': case 'c': if (font->spacing == BDF_PROPORTIONAL) font->monowidth = font->bbx.width + font->bbx.x_offset; font->spacing = BDF_CHARCELL; break; case 'M': case 'm': if (font->spacing == BDF_PROPORTIONAL) font->monowidth = font->bbx.width + font->bbx.x_offset; font->spacing = BDF_MONOWIDTH; break; case 'P': case 'p': font->spacing = BDF_PROPORTIONAL; break; } } /* * Make sure the font is marked as modified. */ font->modified = 1; } void bdf_delete_font_property(bdf_font_t *font, char *name) { hashnode hn; unsigned int off; bdf_property_t *p; if (font == 0 || name == 0 || *name == 0 || font->props_used == 0) return; if ((hn = hash_lookup(name, (hashtable *) font->internal)) == 0) return; off = (unsigned int) hn->data; p = font->props + off; /* * Delete the ATOM value if appropriate. */ if (p->format == BDF_ATOM && p->value.atom != 0) free(p->value.atom); /* * The property exists. Two things needs to be done: * 1. Remove the property from the hash table. * 2. Remove the property from the font's list of properties. */ hash_delete(name, (hashtable *) font->internal); /* * Locate its offset in the font property list. */ if (off < font->props_used - 1) /* * We have to shift the property list down. */ _bdf_memmove((char *) p, (char *) (p + 1), sizeof(bdf_property_t) * ((font->props_used - 1) - off)); font->props_used--; /* * If the font property happens to be DEFAULT_CHAR, then make sure the * default_glyph field is reset. */ if (strncmp(name, "DEFAULT_CHAR", 12) == 0) font->default_glyph = -1; /* * Update the hash table with the correct indexes. */ for (off = 0, p = font->props; off < font->props_used; off++, p++) hash_insert(p->name, (void *) off, (hashtable *) font->internal); /* * Mark the font as being modified. */ font->modified = 1; } 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 int) hn->data)) : 0; } typedef struct { bdf_options_t *opts; bdf_options_callback_t callback; void *client_data; _bdf_list_t list; } _bdf_opts_parse_t; static int _bdf_get_boolean(char *val) { int ok; ok = 0; if (val == 0 || *val == 0) return ok; switch (val[0]) { case '0': case 'F': case 'f': case 'N': case 'n': ok = 0; break; case '1': case 'T': case 't': case 'Y': case 'y': ok = 1; break; } return ok; } static int _bdf_parse_options(char *line, unsigned int linelen, unsigned int lineno, void *call_data, void *client_data) { _bdf_list_t *lp; _bdf_opts_parse_t *p; int bpp; p = (_bdf_opts_parse_t *) client_data; lp = &p->list; /* * Split the line into fields. */ _bdf_split(" \t+", line, linelen, lp); if (lp->field[0][0] == 'b' && memcmp(lp->field[0], "bits_per_pixel", 14) == 0) { if (lp->used < 2) { fprintf(stderr, "bdf: warning: %d: incorrect number of fields %d.\n", lineno, lp->used); fprintf(stderr, "bdf: warning: %d: bits_per_pixel <1, 2, or 4>.\n", lineno); } else { bpp = _bdf_atol(lp->field[1], 0, 10); if (!(bpp == 1 || bpp == 2 || bpp == 4)) { fprintf(stderr, "bdf: warning: %d: invalid bits per pixel %d.\n", lineno, bpp); fprintf(stderr, "bdf: warning: %d: bits_per_pixel <1, 2, or 4>.\n", lineno); } else p->opts->bits_per_pixel = bpp; } return 0; } if (lp->field[0][0] == 'e' && memcmp(lp->field[0], "eol", 3) == 0) { if (lp->used < 2) { fprintf(stderr, "bdf: warning: %d: incorrect number of fields %d.\n", lineno, lp->used); fprintf(stderr, "bdf: warning: %d: eol .\n", lineno); } else { switch (lp->field[1][0]) { case 'u': case 'U': p->opts->eol = BDF_UNIX_EOL; break; case 'd': case 'D': p->opts->eol = BDF_DOS_EOL; break; case 'm': case 'M': p->opts->eol = BDF_MAC_EOL; break; } } return 0; } if (lp->field[0][0] == 'c' && memcmp(lp->field[0], "correct_metrics", 15) == 0) { if (lp->used < 2) { fprintf(stderr, "bdf: warning: %d: incorrect number of fields %d.\n", lineno, lp->used); fprintf(stderr, "bdf: warning: %d: correct_metrics .\n", lineno); } else p->opts->correct_metrics = _bdf_get_boolean(lp->field[1]); return 0; } if (lp->field[0][0] == 'k' && memcmp(lp->field[0], "keep_unencoded", 14) == 0) { if (lp->used < 2) { fprintf(stderr, "bdf: warning: %d: incorrect number of fields %d.\n", lineno, lp->used); fprintf(stderr, "bdf: warning: %d: keep_unencoded .\n", lineno); } else p->opts->keep_unencoded = _bdf_get_boolean(lp->field[1]); return 0; } if (lp->field[0][0] == 'k' && memcmp(lp->field[0], "keep_comments", 13) == 0) { if (lp->used < 2) { fprintf(stderr, "bdf: warning: %d: incorrect number of fields %d.\n", lineno, lp->used); fprintf(stderr, "bdf: warning: %d: keep_comments .\n", lineno); } else p->opts->keep_comments = _bdf_get_boolean(lp->field[1]); return 0; } if (lp->field[0][0] == 'p' && memcmp(lp->field[0], "pad_character_cells", 19) == 0) { if (lp->used < 2) { fprintf(stderr, "bdf: warning: %d: incorrect number of fields %d.\n", lineno, lp->used); fprintf(stderr, "bdf: warning: %d: pad_character_cells .\n", lineno); } else p->opts->pad_cells = _bdf_get_boolean(lp->field[1]); return 0; } if (lp->field[0][0] == 'p' && memcmp(lp->field[0], "point_size", 10) == 0) { if (lp->used < 2) { fprintf(stderr, "bdf: warning: %d: incorrect number of fields %d.\n", lineno, lp->used); fprintf(stderr, "bdf: warning: %d: point_size .\n", lineno); } else p->opts->point_size = _bdf_atol(lp->field[1], 0, 10); return 0; } if (lp->field[0][0] == 'h' && memcmp(lp->field[0], "horizontal_resolution", 21) == 0) { if (lp->used < 2) { fprintf(stderr, "bdf: warning: %d: incorrect number of fields %d.\n", lineno, lp->used); fprintf(stderr, "bdf: warning: %d: horizontal_resolution .\n", lineno); } else p->opts->resolution_x = _bdf_atoul(lp->field[1], 0, 10); return 0; } if (lp->field[0][0] == 'v' && memcmp(lp->field[0], "vertical_resolution", 19) == 0) { if (lp->used < 2) { fprintf(stderr, "bdf: warning: %d: incorrect number of fields %d.\n", lineno, lp->used); fprintf(stderr, "bdf: warning: %d: vertical_resolution .\n", lineno); } else p->opts->resolution_y = _bdf_atoul(lp->field[1], 0, 10); return 0; } if (lp->field[0][0] == 'f' && memcmp(lp->field[0], "font_spacing", 12) == 0) { if (lp->used < 2) { fprintf(stderr, "bdf: warning: %d: incorrect number of fields %d.\n", lineno, lp->used); fprintf(stderr, "bdf: warning: %d: font_spacing .\n", lineno); } else { switch (lp->field[1][0]) { case 'P': case 'p': p->opts->font_spacing = BDF_PROPORTIONAL; break; case 'M': case 'm': p->opts->font_spacing = BDF_MONOWIDTH; break; case 'C': case 'c': p->opts->font_spacing = BDF_CHARCELL; break; default: fprintf(stderr, "bdf: warning: %d: unknown font spacing '%s'.\n", lineno, lp->field[1]); } } return 0; } if (lp->field[0][0] == 'p' && memcmp(lp->field[0], "property", 8) == 0) { if (lp->used < 3) { fprintf(stderr, "bdf: warning: %d: incorrect number of fields %d.\n", lineno, lp->used); fprintf(stderr, "bdf: warning: %d: property .\n", lineno); } else { switch (lp->field[2][0]) { case 'A': case 'a': bdf_create_property(lp->field[1], BDF_ATOM); break; case 'C': case 'c': bdf_create_property(lp->field[1], BDF_CARDINAL); break; case 'I': case 'i': bdf_create_property(lp->field[1], BDF_INTEGER); break; default: fprintf(stderr, "bdf: warning: %d: unknown property type '%s'.\n", lineno, lp->field[2]); } } return 0; } if (lp->field[0][0] == 'h' && (memcmp(lp->field[0], "hint_truetype_glyphs", 20) == 0 || memcmp(lp->field[0], "hint_opentype_glyphs", 20) == 0)) { if (lp->used < 2) { fprintf(stderr, "bdf: warning: %d: incorrect number of fields %d.\n", lineno, lp->used); fprintf(stderr, "bdf: warning: %d: hint_opentype_glyphs .\n", lineno); } else { #ifdef HAVE_FREETYPE if (_bdf_get_boolean(lp->field[1])) p->opts->otf_flags &= ~FT_LOAD_NO_HINTING; else p->opts->otf_flags |= FT_LOAD_NO_HINTING; #else p->opts->otf_flags = 0; #endif /* HAVE_FREETYPE */ } return 0; } if (lp->field[0][0] == 'g' && memcmp(lp->field[0], "generate_ranges", 15) == 0) /* * Simply ignore the glyph ranges entry in the config file. */ return 0; /* * If the callback returns a non-zero value, the caller has handled the * unknown option found in the file. */ if (p->callback != 0 && (*p->callback)(p->opts, lp->field, lp->used, p->client_data) != 0) return 0; fprintf(stderr, "bdf: warning: %d: unknown configuration option '%s'.\n", lineno, lp->field[0]); return 0; } void bdf_load_options(FILE *in, bdf_options_t *opts, bdf_options_callback_t callback, void *client_data) { unsigned int lineno; _bdf_opts_parse_t p; /* * Don't bother loading the options if the file or options structure * is NULL. */ if (in == 0 || opts == 0) return; (void *) memset((char *) &p, 0, sizeof(_bdf_opts_parse_t)); p.opts = opts; p.callback = callback; p.client_data = client_data; (void) _bdf_readlines(fileno(in), _bdf_parse_options, (void *) &p, &lineno); /* * Free up the list if there is any space allocated. */ if (p.list.size > 0) free((char *) p.list.field); } void bdf_save_options(FILE *out, bdf_options_t *opts) { unsigned int i; if (out == 0 || opts == 0) return; fprintf(out, "#\n# Metrics corrections.\n#\ncorrect_metrics "); if (opts->correct_metrics) fprintf(out, "true\n\n"); else fprintf(out, "false\n\n"); fprintf(out, "#\n# Preserve unencoded glyphs.\n#\nkeep_unencoded "); if (opts->keep_unencoded) fprintf(out, "true\n\n"); else fprintf(out, "false\n\n"); fprintf(out, "#\n# Preserve comments.\n#\nkeep_comments "); if (opts->keep_comments) fprintf(out, "true\n\n"); else fprintf(out, "false\n\n"); fprintf(out, "#\n# Pad character cells.\n#\npad_character_cells "); if (opts->pad_cells) fprintf(out, "true\n\n"); else fprintf(out, "false\n\n"); fprintf(out, "#\n# Font spacing.\n#\nfont_spacing "); switch (opts->font_spacing) { case BDF_PROPORTIONAL: fprintf(out, "proportional\n\n"); break; case BDF_MONOWIDTH: fprintf(out, "monowidth\n\n"); break; case BDF_CHARCELL: fprintf(out, "charactercell\n\n"); break; } fprintf(out, "#\n# Point size.\n#\npoint_size %d\n\n", opts->point_size); fprintf(out, "#\n# Horizontal resolution.\n#\nhorizontal_resolution %d\n\n", opts->resolution_x); fprintf(out, "#\n# Vertical resolution.\n#\nvertical_resolution %d\n\n", opts->resolution_x); fprintf(out, "#\n# Bits per pixel.\n#\nbits_per_pixel %d\n\n", opts->bits_per_pixel); fprintf(out, "#\n# Hint OpenType glyphs.\n#\nhint_opentype_glyphs "); #ifdef HAVE_FREETYPE if (opts->otf_flags & FT_LOAD_NO_HINTING) fprintf(out, "false\n\n"); else fprintf(out, "true\n\n"); #else fprintf(out, "false\n\n"); #endif /* HAVE_FREETYPE */ fprintf(out, "#\n# Set the EOL used when writing BDF fonts.\n#\neol "); switch (opts->eol) { case BDF_UNIX_EOL: fprintf(out, "unix\n\n"); break; case BDF_DOS_EOL: fprintf(out, "dos\n\n"); break; case BDF_MAC_EOL: fprintf(out, "mac\n\n"); break; } /* * Write out the user defined properties if they exist. */ if (nuser_props == 0) return; fprintf(out, "#\n# User defined properties.\n#\n"); for (i = 0; i < nuser_props; i++) { fprintf(out, "property %s ", user_props[i].name); switch (user_props[i].format) { case BDF_ATOM: fprintf(out, "atom\n"); break; case BDF_CARDINAL: fprintf(out, "cardinal\n"); break; case BDF_INTEGER: fprintf(out, "integer\n"); break; } } } void bdf_default_options(bdf_options_t *opts) { if (opts == 0) return; (void) memcpy((char *) opts, (char *) &_bdf_opts, sizeof(bdf_options_t)); } bdf_font_t * bdf_new_font(char *name, int point_size, int resolution_x, int resolution_y, int spacing, int bpp) { int psize; char sp[2]; bdf_font_t *font; double dp, dr; bdf_property_t prop; font = (bdf_font_t *) calloc(1, sizeof(bdf_font_t)); if (name != 0 && *name != 0) { font->name = (char *) malloc(strlen(name) + 1); (void) strcpy(font->name, name); } font->bpp = bpp; font->point_size = point_size; font->resolution_x = resolution_x; font->resolution_y = resolution_y; /* * Determine the pixel size of the new font based on the * point size and resolution. */ dr = (double) resolution_y; dp = (double) (point_size * 10); psize = (int) (((dp * dr) / 722.7) + 0.5); /* * Make the default width about 1.5 smaller than the height. */ font->bbx.height = psize; font->bbx.width = ((double) psize) / 1.5; /* * Now determine the default ascent and descent assuming a * the descent is about 1/4 the ascent. */ font->bbx.descent = psize >> 2; font->bbx.ascent = psize - font->bbx.descent; font->bbx.y_offset = -font->bbx.descent; /* * Allocation the internal hash tables. */ font->internal = (void *) malloc(sizeof(hashtable)); hash_init((hashtable *) font->internal); font->default_glyph = -1; font->spacing = spacing; /* * Add various useful properties. */ prop.name = "POINT_SIZE"; prop.format = BDF_INTEGER; prop.value.int32 = font->point_size * 10; bdf_add_font_property(font, &prop); prop.name = "PIXEL_SIZE"; prop.format = BDF_INTEGER; prop.value.int32 = psize; bdf_add_font_property(font, &prop); prop.name = "RESOLUTION_X"; prop.format = BDF_CARDINAL; prop.value.card32 = (unsigned int) font->resolution_x; bdf_add_font_property(font, &prop); prop.name = "RESOLUTION_Y"; prop.format = BDF_CARDINAL; prop.value.card32 = (unsigned int) font->resolution_y; bdf_add_font_property(font, &prop); prop.name = "FONT_ASCENT"; prop.format = BDF_INTEGER; prop.value.int32 = (int) font->bbx.ascent; bdf_add_font_property(font, &prop); prop.name = "FONT_DESCENT"; prop.format = BDF_INTEGER; prop.value.int32 = (int) font->bbx.descent; bdf_add_font_property(font, &prop); prop.name = "AVERAGE_WIDTH"; prop.format = BDF_INTEGER; prop.value.int32 = font->bbx.width * 10; bdf_add_font_property(font, &prop); sp[0] = 'P'; sp[1] = 0; switch (spacing) { case BDF_PROPORTIONAL: sp[0] = 'P'; break; case BDF_MONOWIDTH: sp[0] = 'M'; break; case BDF_CHARCELL: sp[0] = 'C'; break; } prop.name = "SPACING"; prop.format = BDF_ATOM; prop.value.atom = sp; bdf_add_font_property(font, &prop); /* * Mark the font as unmodified. */ font->modified = 0; return font; } void bdf_set_default_metrics(bdf_font_t *font) { int psize; double dp, dr; bdf_property_t prop; /* * Determine the pixel size of the new font based on the * point size and resolution. */ dr = (double) font->resolution_y; dp = (double) (font->point_size * 10); psize = (int) (((dp * dr) / 722.7) + 0.5); /* * Make the default width about 1.5 smaller than the height. */ font->bbx.height = psize; font->bbx.width = ((double) psize) / 1.5; /* * Now determine the default ascent and descent assuming a * the descent is about 1/4 the ascent. */ font->bbx.descent = psize >> 2; font->bbx.ascent = psize - font->bbx.descent; font->bbx.y_offset = -font->bbx.descent; font->default_glyph = -1; /* * Add various useful properties. */ prop.name = "FONT_ASCENT"; prop.format = BDF_INTEGER; prop.value.int32 = (int) font->bbx.ascent; bdf_add_font_property(font, &prop); prop.name = "FONT_DESCENT"; prop.format = BDF_INTEGER; prop.value.int32 = (int) font->bbx.descent; bdf_add_font_property(font, &prop); prop.name = "AVERAGE_WIDTH"; prop.format = BDF_INTEGER; prop.value.int32 = font->bbx.width * 10; bdf_add_font_property(font, &prop); } int bdf_glyph_modified(bdf_font_t *font, int which, int unencoded) { if (font == 0 || which < 0) return 0; if (unencoded) return _bdf_glyph_modified(font->umod, which); else return _bdf_glyph_modified(font->nmod, which); } void bdf_copy_glyphs(bdf_font_t *font, int start, int end, bdf_glyphlist_t *glyphs, int unencoded) { int tmp, i, nc; bdf_glyph_t *cp, *dp; short maxas, maxds, maxrb, minlb, maxlb, rb; if (start > end) { tmp = end; end = start; start = tmp; } glyphs->bpp = font->bpp; glyphs->start = start; glyphs->end = end; glyphs->glyphs_used = 0; tmp = (end - start) + 1; if (tmp > glyphs->glyphs_size) { if (glyphs->glyphs_size == 0) glyphs->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * tmp); else glyphs->glyphs = (bdf_glyph_t *) realloc((char *) glyphs->glyphs, sizeof(bdf_glyph_t) * tmp); cp = glyphs->glyphs + glyphs->glyphs_size; (void) memset((char *) cp, 0, sizeof(bdf_glyph_t) * (tmp - glyphs->glyphs_size)); glyphs->glyphs_size = tmp; } /* * Clear out bitmaps, names and any PSF Unicode mappings in the existing * entries. */ for (cp = glyphs->glyphs, i = 0; i < glyphs->glyphs_size; i++, cp++) { if (cp->name != 0) free(cp->name); if (cp->bytes > 0) free((char *) cp->bitmap); if (cp->unicode.map_size > 0) free((char *) cp->unicode.map); } /* * Zero out everything. */ (void) memset((char *) &glyphs->bbx, 0, sizeof(bdf_bbx_t)); (void) memset((char *) glyphs->glyphs, 0, sizeof(bdf_glyph_t) * glyphs->glyphs_size); /* * Initialize the bounds used to generate the overall bounding box for the * set of glyphs being copied. */ minlb = font->bbx.width; maxlb = maxrb = maxas = maxds = 0; /* * Do the copy. */ nc = (unencoded == 0) ? font->glyphs_used : font->unencoded_used; cp = (unencoded == 0) ? font->glyphs : font->unencoded; dp = glyphs->glyphs; for (i = 0; i < nc && ((unencoded && i <= end) || cp->encoding <= end); i++, cp++) { if ((unencoded && i >= start) || cp->encoding >= start) { (void) memcpy((char *) dp, (char *) cp, sizeof(bdf_glyph_t)); if (cp->name != 0) { dp->name = (char *) malloc(strlen(cp->name) + 1); (void) strcpy(dp->name, cp->name); } if (cp->bytes > 0) { dp->bytes = cp->bytes; dp->bitmap = (unsigned char *) malloc(cp->bytes); (void) memcpy((char *) dp->bitmap, (char *) cp->bitmap, cp->bytes); } if (cp->unicode.map_used > 0) { dp->unicode.map_used = dp->unicode.map_size = cp->unicode.map_used; dp->unicode.map = (unsigned char *) malloc(dp->unicode.map_used); (void) memcpy((char *) dp->unicode.map, (char *) cp->unicode.map, dp->unicode.map_used); } /* * Determine the overall metrics for the group of characters being * copied. */ maxas = MAX(cp->bbx.ascent, maxas); maxds = MAX(cp->bbx.descent, maxds); rb = cp->bbx.width + cp->bbx.x_offset; maxrb = MAX(rb, maxrb); minlb = MIN(cp->bbx.x_offset, minlb); maxlb = MAX(cp->bbx.x_offset, maxlb); glyphs->glyphs_used++; dp++; } } /* * Set the overall metrics for this set of glyphs. */ glyphs->bbx.width = maxrb - minlb; glyphs->bbx.x_offset = minlb; glyphs->bbx.height = maxas + maxds; glyphs->bbx.ascent = maxas; glyphs->bbx.descent = maxds; glyphs->bbx.y_offset = -maxds; } bdf_glyph_t * _bdf_locate_glyph(bdf_font_t *font, int code, int unencoded) { int l, r, m, nc; bdf_glyph_t *gl; if (code < 0 || font == 0) return 0; if ((unencoded && font->unencoded_used == 0) || font->glyphs_used == 0) return 0; if (unencoded) { gl = font->unencoded; nc = font->unencoded_used; } else { gl = font->glyphs; nc = font->glyphs_used; } for (l = m = 0, r = nc - 1; l < r; ) { m = (l + r) >> 1; if (gl[m].encoding < code) l = m + 1; else if (gl[m].encoding > code) r = m - 1; else break; } /* * Go back until we hit the beginning of the glyphs or until * we find the glyph with a code less than the specified code. */ l = m; while (m > 0 && gl[m].encoding > code) m--; /* * Look forward if necessary. */ m = l; while (m < nc && gl[m].encoding < code) m++; return (m < nc) ? &gl[m] : &gl[nc - 1]; } int bdf_delete_glyphs(bdf_font_t *font, int start, int end, int unencoded) { int i, n, nc, cnt, mod; bdf_glyph_t *cp, *sp, *ep; mod = 0; if (font == 0) return mod; if (start > end) { cnt = end; end = start; start = cnt; } nc = (unencoded == 0) ? font->glyphs_used : font->unencoded_used; cp = (unencoded == 0) ? font->glyphs : font->unencoded; sp = ep = 0; for (i = 0; i < nc && cp->encoding <= end; i++, cp++) { if (cp->encoding >= start && sp == 0) sp = cp; } ep = cp; if (sp == 0) sp = ep; if (ep > sp) { /* * There are some glyphs to delete. * 1. Free the name and bitmap fields of the glyphs being deleted. * 2. Move the end range down if necessary. * 3. Clear the glyphs on the end if a move was done. */ /* * Mark the font as being modified. */ mod = font->modified = 1; cnt = ep - sp; for (cp = sp; cp < ep; cp++) { /* * Mark the glyphs being deleted as also being modified so the * empty cells can be shown correctly by the client programs. */ if (unencoded) _bdf_set_glyph_modified(font->umod, cp->encoding); else _bdf_set_glyph_modified(font->nmod, cp->encoding); if (cp->name != 0) free(cp->name); if (cp->bytes > 0) free((char *) cp->bitmap); } cp = (unencoded == 0) ? font->glyphs : font->unencoded; /* * Check to see if there are some glyphs that need to * be moved down. */ if (ep - cp < nc) { /* * Shift the glyphs down. */ n = nc - (ep - cp); _bdf_memmove((char *) sp, (char *) ep, sizeof(bdf_glyph_t) * n); /* * Set the starting point for the clear. */ ep = sp + n; } else /* * Set the starting point for the clear. */ ep = sp; /* * Clear the glyph space just moved. */ n = nc - (ep - cp); (void) memset((char *) ep, 0, sizeof(bdf_glyph_t) * n); /* * Adjust the number of glyphs used. */ if (unencoded == 0) font->glyphs_used -= cnt; else font->unencoded_used -= cnt; /* * If unencoded glyphs were deleted, re-encode all * of them to cause a shift when everything is redrawn. */ if (unencoded != 0) { for (i = 0, cp = font->unencoded; i < font->unencoded_used; i++, cp++) { if (_bdf_glyph_modified(font->umod, cp->encoding)) { _bdf_clear_glyph_modified(font->umod, cp->encoding); _bdf_set_glyph_modified(font->umod, i); } cp->encoding = i; } } } return mod; } /* * These values are intended to give pixels mapped from 1bpp to nbpp the * darkest available index, which is 1. */ static unsigned char twobpp_ones[] = {0x40, 0x10, 0x04, 0x01}; static unsigned char fourbpp_ones[] = {0x10, 0x01}; static unsigned char eightbpp_ones[] = {0x01}; /* * Routines for quick and dirty dithering. */ static void _bdf_one_to_n(bdf_glyphlist_t *gl, int n) { int i; unsigned short bpr, sbpr, bytes, col, sx, sy; unsigned char *nbmap, *ones = 0; bdf_glyph_t *gp; if (gl == 0 || gl->glyphs_used == 0) return; switch (n) { case 1: ones = bdf_onebpp; break; case 2: ones = twobpp_ones; break; case 4: ones = fourbpp_ones; break; case 8: ones = eightbpp_ones; break; } gl->bpp = n; for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) { if (gp->bbx.width == 0 || gp->bbx.height == 0) continue; sbpr = (gp->bbx.width + 7) >> 3; bpr = ((gp->bbx.width * n) + 7) >> 3; bytes = bpr * gp->bbx.height; nbmap = (unsigned char *) malloc(bytes); (void) memset((char *) nbmap, 0, bytes); for (sy = 0; sy < gp->bbx.height; sy++) { for (col = sx = 0; sx < gp->bbx.width; sx++, col += n) { if (gp->bitmap[(sy * sbpr) + (sx >> 3)] & (0x80 >> (sx & 7))) nbmap[(sy * bpr) + (col >> 3)] |= ones[(col & 7) / n]; } } free((char *) gp->bitmap); gp->bytes = bytes; gp->bitmap = nbmap; } } static void _bdf_n_to_one(bdf_glyphlist_t *gl) { int i; unsigned short bpr, sbpr, bytes, col, sx, sy; unsigned char *nbmap, *masks; bdf_glyph_t *gp; if (gl == 0 || gl->glyphs_used == 0) return; masks = 0; switch (gl->bpp) { case 1: masks = bdf_onebpp; break; case 2: masks = bdf_twobpp; break; case 4: masks = bdf_fourbpp; break; case 8: masks = bdf_eightbpp; break; } for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) { if (gp->bbx.width == 0 || gp->bbx.height == 0) continue; sbpr = ((gp->bbx.width * gl->bpp) + 7) >> 3; bpr = (gp->bbx.width + 7) >> 3; bytes = bpr * gp->bbx.height; nbmap = (unsigned char *) malloc(bytes); (void) memset((char *) nbmap, 0, bytes); for (sy = 0; sy < gp->bbx.height; sy++) { for (col = sx = 0; sx < gp->bbx.width; sx++, col += gl->bpp) { if (gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[(col & 7) / gl->bpp]) nbmap[(sy * bpr) + (sx >> 3)] |= (0x80 >> (sx & 7)); } } free((char *) gp->bitmap); gp->bytes = bytes; gp->bitmap = nbmap; } gl->bpp = 1; } static void _bdf_two_to_four(bdf_glyphlist_t *gl) { int i; unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy; unsigned char *nbmap, *masks; bdf_glyph_t *gp; if (gl == 0 || gl->glyphs_used == 0) return; masks = bdf_twobpp; for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) { if (gp->bbx.width == 0 || gp->bbx.height == 0) continue; sbpr = ((gp->bbx.width << 1) + 7) >> 3; bpr = ((gp->bbx.width << 2) + 7) >> 3; bytes = bpr * gp->bbx.height; nbmap = (unsigned char *) malloc(bytes); (void) memset((char *) nbmap, 0, bytes); for (sy = 0; sy < gp->bbx.height; sy++) { for (col = sx = 0; sx < gp->bbx.width; sx++, col += 2) { si = (col & 7) >> 1; byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si]; if (byte) { if (si < 3) byte >>= (3 - si) << 1; byte <<= 2; if ((sx & 1) == 0) byte <<= 4; nbmap[(sy * bpr) + ((sx << 2) >> 3)] |= byte; } } } free((char *) gp->bitmap); gp->bytes = bytes; gp->bitmap = nbmap; } gl->bpp = 4; } static void _bdf_four_to_two(bdf_glyphlist_t *gl) { int i; unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy; unsigned char *nbmap, *masks; bdf_glyph_t *gp; if (gl == 0 || gl->glyphs_used == 0) return; masks = bdf_fourbpp; gl->bpp = 2; for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) { sbpr = ((gp->bbx.width << 2) + 7) >> 3; bpr = ((gp->bbx.width << 1) + 7) >> 3; bytes = bpr * gp->bbx.height; nbmap = (unsigned char *) malloc(bytes); (void) memset((char *) nbmap, 0, bytes); for (sy = 0; sy < gp->bbx.height; sy++) { for (col = sx = 0; sx < gp->bbx.width; sx++, col += 4) { si = (col & 7) >> 2; byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si]; if (byte) { /* * Shift the byte down to make an index. */ if (si == 0) byte >>= 4; /* * Scale the index to two bits per pixel and shift it into * place if necessary. */ byte >>= 2; /* * Any non-zero byte has to remain non-zero, because index * zero means no bits set. */ if (byte == 0) byte = 1; si = ((sx << 1) & 7) >> 1; if (si < 3) byte <<= (3 - si) << 1; nbmap[(sy * bpr) + ((sx << 1) >> 3)] |= byte; } } } free((char *) gp->bitmap); gp->bytes = bytes; gp->bitmap = nbmap; } } static void _bdf_two_to_eight(bdf_glyphlist_t *gl) { int i; unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy; unsigned char *nbmap, *masks; bdf_glyph_t *gp; if (gl == 0 || gl->glyphs_used == 0) return; masks = bdf_twobpp; for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) { if (gp->bbx.width == 0 || gp->bbx.height == 0) continue; sbpr = ((gp->bbx.width << 1) + 7) >> 3; bpr = gp->bbx.width; bytes = bpr * gp->bbx.height; nbmap = (unsigned char *) malloc(bytes); (void) memset((char *) nbmap, 0, bytes); for (sy = 0; sy < gp->bbx.height; sy++) { for (col = sx = 0; sx < gp->bbx.width; sx++, col += 2) { si = (col & 7) >> 1; byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si]; if (byte) { /* * Shift the byte down to make an index. */ if (si < 3) byte >>= (3 - si) * gl->bpp; /* * Scale the index to four bits per pixel and shift it into * place before adding it. */ byte <<= 6; nbmap[(sy * bpr) + sx] = byte; } } } free((char *) gp->bitmap); gp->bytes = bytes; gp->bitmap = nbmap; } gl->bpp = 8; } static void _bdf_eight_to_two(bdf_glyphlist_t *gl) { int i; unsigned short bpr, sbpr, bytes, si, byte, sx, sy; unsigned char *nbmap, *masks; bdf_glyph_t *gp; if (gl == 0 || gl->glyphs_used == 0) return; masks = bdf_fourbpp; gl->bpp = 2; for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) { sbpr = gp->bbx.width; bpr = ((gp->bbx.width << 1) + 7) >> 3; bytes = bpr * gp->bbx.height; nbmap = (unsigned char *) malloc(bytes); (void) memset((char *) nbmap, 0, bytes); for (sy = 0; sy < gp->bbx.height; sy++) { for (sx = 0; sx < gp->bbx.width; sx++) { byte = gp->bitmap[(sy * sbpr) + sx]; if (byte) { byte >>= 6; if (byte == 0) byte = 1; si = ((sx << 1) & 7) >> 1; if (si < 3) byte <<= (3 - si) << 1; nbmap[(sy * bpr) + ((sx << 1) >> 3)] |= byte; } } } free((char *) gp->bitmap); gp->bytes = bytes; gp->bitmap = nbmap; } } static void _bdf_four_to_eight(bdf_glyphlist_t *gl) { int i; unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy; unsigned char *nbmap, *masks; bdf_glyph_t *gp; if (gl == 0 || gl->glyphs_used == 0) return; masks = bdf_fourbpp; for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) { if (gp->bbx.width == 0 || gp->bbx.height == 0) continue; sbpr = ((gp->bbx.width << 2) + 7) >> 3; bpr = gp->bbx.width; bytes = bpr * gp->bbx.height; nbmap = (unsigned char *) malloc(bytes); (void) memset((char *) nbmap, 0, bytes); for (sy = 0; sy < gp->bbx.height; sy++) { for (col = sx = 0; sx < gp->bbx.width; sx++, col += 4) { si = (col & 7) >> 2; byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si]; if (byte) { if (si == 0) byte >>= 4; byte <<= 4; nbmap[(sy * bpr) + sx] = byte; } } } free((char *) gp->bitmap); gp->bytes = bytes; gp->bitmap = nbmap; } gl->bpp = 8; } static void _bdf_eight_to_four(bdf_glyphlist_t *gl) { int i; unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy; unsigned char *nbmap, *masks; bdf_glyph_t *gp; if (gl == 0 || gl->glyphs_used == 0) return; masks = bdf_twobpp; for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) { if (gp->bbx.width == 0 || gp->bbx.height == 0) continue; sbpr = gp->bbx.width; bpr = ((gp->bbx.width << 2) + 7) >> 3; bytes = bpr * gp->bbx.height; nbmap = (unsigned char *) malloc(bytes); (void) memset((char *) nbmap, 0, bytes); for (sy = 0; sy < gp->bbx.height; sy++) { for (col = sx = 0; sx < gp->bbx.width; sx++, col += 2) { byte = gp->bitmap[(sy * sbpr) + sx]; if (byte) { byte >>= 4; if (byte == 0) byte = 1; /* * Scale the index to four bits per pixel and shift it into * place before adding it. */ si = (col & 7) >> 2; if (si == 0) byte <<= 4; nbmap[(sy * bpr) + ((sx << 2) >> 3)] |= byte; } } } free((char *) gp->bitmap); gp->bytes = bytes; gp->bitmap = nbmap; } gl->bpp = 4; } /* * This only works on glyphs that exist. */ int bdf_replace_mappings(bdf_font_t *font, int encoding, bdf_psf_unimap_t *map, int unencoded) { bdf_glyph_t *gp; if ((gp = _bdf_locate_glyph(font, encoding, unencoded)) == 0 || gp->encoding != encoding) return 0; if (map->map_size > gp->unicode.map_size) { if (gp->unicode.map_size == 0) gp->unicode.map = (unsigned char *) malloc(sizeof(unsigned char) * map->map_size); else gp->unicode.map =(unsigned char *) realloc((char *) gp->unicode.map, sizeof(unsigned char) * map->map_size); gp->unicode.map_size = map->map_size; } gp->unicode.map_used = map->map_used; (void) memcpy((char *) gp->unicode.map, (char *) map->map, sizeof(unsigned char) * map->map_used); /* * Mark the glyph as modified. */ if (unencoded) _bdf_set_glyph_modified(font->umod, gp->encoding); else _bdf_set_glyph_modified(font->nmod, gp->encoding); font->modified = 1; return 1; } int bdf_replace_glyphs(bdf_font_t *font, int start, bdf_glyphlist_t *glyphs, int unencoded) { int resize, appending; int i, n, ng, end, del, remaining, off[2]; bdf_glyph_t *sgp, *gp, *dgp; short maxas, maxds, maxrb, minlb, maxlb, rb; double ps, rx, dw; bdf_bbx_t nbbx; resize = 0; if (font == 0) return resize; /* * Dither the incoming bitmaps so they match the same bits per pixel as * the font. */ if (glyphs->bpp != font->bpp) { if (glyphs->bpp == 1) _bdf_one_to_n(glyphs, font->bpp); else if (font->bpp == 1) _bdf_n_to_one(glyphs); else if (glyphs->bpp == 2) { if (font->bpp == 4) _bdf_two_to_four(glyphs); else _bdf_two_to_eight(glyphs); } else if (glyphs->bpp == 4) { if (font->bpp == 2) _bdf_four_to_two(glyphs); else _bdf_four_to_eight(glyphs); } else if (glyphs->bpp == 8) { if (font->bpp == 2) _bdf_eight_to_two(glyphs); else _bdf_eight_to_four(glyphs); } } /* * Set the point size and horizontal resolution so the scalable width can * be determined. */ ps = (double) font->point_size; rx = (double) font->resolution_x; /* * Determine if a resize is needed. */ /* * Determine the bounding box for the font without the characters being * replaced. */ minlb = 32767; maxlb = maxrb = maxas = maxds = 0; /* * Get the font bounds. */ maxas = MAX(font->bbx.ascent, maxas); maxds = MAX(font->bbx.descent, maxds); rb = font->bbx.width + font->bbx.x_offset; maxrb = MAX(rb, maxrb); minlb = MIN(font->bbx.x_offset, minlb); maxlb = MAX(font->bbx.x_offset, maxlb); /* * Get the bounds of the incoming glyphs. */ maxas = MAX(glyphs->bbx.ascent, maxas); maxds = MAX(glyphs->bbx.descent, maxds); rb = glyphs->bbx.width + glyphs->bbx.x_offset; maxrb = MAX(rb, maxrb); minlb = MIN(glyphs->bbx.x_offset, minlb); maxlb = MAX(glyphs->bbx.x_offset, maxlb); /* * Set up the new font bounding box, minus the characters that are being * removed and with the new characters added. */ nbbx.width = maxrb - minlb; nbbx.x_offset = minlb; nbbx.height = maxas + maxds; nbbx.ascent = maxas; nbbx.descent = maxds; nbbx.y_offset = -maxds; /* * Now determine if the combination of the glyphs removed and the new * glyphs cause the font bounding box to be changed. */ resize = (nbbx.width > font->bbx.width || nbbx.height > font->bbx.height) ? 1 : 0; /* * Set the pointers to the glyphs. */ ng = (unencoded == 0) ? font->glyphs_used : font->unencoded_used; sgp = gp = (unencoded == 0) ? font->glyphs : font->unencoded; /* * Locate the closest glyph on or following `start'. */ for (i = 0; i < ng && gp->encoding < start; i++, gp++) ; appending = (i == ng); /* * Set the starting point for copying the incoming glyphs. */ dgp = gp; n = glyphs->end - glyphs->start; end = start + n; /* * Delete all the glyphs between `start' and `end'. */ for (del = 0, i = start; i <= end; i++) { /* * Mark the character as being modified. */ if (ng > 0 && !appending && gp->encoding == i) { if (unencoded == 0) _bdf_set_glyph_modified(font->nmod, i); else _bdf_set_glyph_modified(font->umod, i); if (gp->name != 0) free(gp->name); if (gp->bytes > 0) free((char *) gp->bitmap); if (gp->unicode.map_size > 0) free((char *) gp->unicode.map); del++; gp++; } } /* * Determine how many glyphs remain following the last one deleted. */ remaining = ng - (gp - sgp); if (glyphs->glyphs_used == 0) { /* * If the glyph list is empty, then shift any remaining glyphs down * to the destination. */ _bdf_memmove((char *) dgp, (char *) gp, sizeof(bdf_glyph_t) * remaining); if (unencoded == 0) font->glyphs_used -= del; else font->unencoded_used -= del; } else { /* * Insert the glyph list after making sure there is enough space to * hold them. Also adjust the encoding and scalable width values * after copying the glyphs. */ if (unencoded == 0) { n = (font->glyphs_used - del) + glyphs->glyphs_used; if (n > font->glyphs_size) { off[0] = gp - sgp; off[1] = dgp - sgp; if (font->glyphs_size == 0) font->glyphs = sgp = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * n); else font->glyphs = sgp = (bdf_glyph_t *) realloc((char *) font->glyphs, sizeof(bdf_glyph_t) * n); gp = sgp + off[0]; dgp = sgp + off[1]; font->glyphs_size = n; } /* * Calculate how many will need to be shifted. */ if ((n = glyphs->glyphs_used - del) >= font->glyphs_used) n = 0; } else { n = (font->unencoded_used - del) + glyphs->glyphs_used; if (n > font->unencoded_size) { off[0] = gp - sgp; off[1] = dgp - sgp; if (font->unencoded_size == 0) font->unencoded = sgp = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * n); else font->unencoded = sgp = (bdf_glyph_t *) realloc((char *) font->unencoded, sizeof(bdf_glyph_t) * n); gp = sgp + off[0]; dgp = sgp + off[1]; font->unencoded_size = n; } /* * Calculate how many will need to be shifted. */ if ((n = glyphs->glyphs_used - del) >= font->unencoded_used) n = 0; } /* * Shift any following glyphs up or down if needed. */ if (n) _bdf_memmove((char *) (gp + n), (char *) gp, sizeof(bdf_glyph_t) * remaining); /* * Copy the incoming glyphs, copy their names and bitmaps, * set their encodings, and set their scalable widths. */ (void) memcpy((char *) dgp, (char *) glyphs->glyphs, sizeof(bdf_glyph_t) * glyphs->glyphs_used); for (i = 0; i < glyphs->glyphs_used; i++, dgp++) { if (dgp->name != 0) dgp->name = (char *) _bdf_strdup((unsigned char *) dgp->name, strlen(dgp->name) + 1); if (dgp->bytes > 0) dgp->bitmap = _bdf_strdup(dgp->bitmap, dgp->bytes); if (dgp->unicode.map_size > 0) dgp->unicode.map = _bdf_strdup(dgp->unicode.map, dgp->unicode.map_size); dgp->encoding = start + (dgp->encoding - glyphs->start); /* * Mark the glyph as being modified in case it fills a cell that * was empty before. */ _bdf_set_glyph_modified(font->nmod, dgp->encoding); dw = (double) dgp->dwidth; dgp->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx)); } /* * Adjust the count of glyphs. */ ng = (ng - del) + glyphs->glyphs_used; if (unencoded == 0) font->glyphs_used = ng; else font->unencoded_used = ng; } /* * Last, if the replacement was done in the unencoded section, * reencode all the glyphs so they show up properly. */ if (unencoded != 0) { for (i = 0; i < ng; i++, sgp++) { if (_bdf_glyph_modified(font->umod, sgp->encoding)) { _bdf_clear_glyph_modified(font->umod, sgp->encoding); _bdf_set_glyph_modified(font->umod, i); } sgp->encoding = i; } } if (resize) (void) memcpy((char *) &font->bbx, (char *) &nbbx, sizeof(bdf_bbx_t)); font->modified = 1; return resize; } int bdf_insert_glyphs(bdf_font_t *font, int start, bdf_glyphlist_t *glyphs) { int resize; unsigned int i, ng, n, which; bdf_glyph_t *gp; resize = 0; if (font == 0) return resize; /* * Dither the incoming bitmaps so they match the same bits per pixel as * the font. */ if (glyphs->bpp != font->bpp) { if (glyphs->bpp == 1) _bdf_one_to_n(glyphs, font->bpp); else if (font->bpp == 1) _bdf_n_to_one(glyphs); else if (glyphs->bpp == 2) _bdf_two_to_four(glyphs); else _bdf_four_to_two(glyphs); } /* * Locate the starting glyph. */ gp = font->glyphs; ng = font->glyphs_used; for (i = 0; i < ng && gp->encoding < start; i++, gp++) ; /* * If there are no glyphs at the starting point, then simply do a replace. */ if (i == ng) return bdf_replace_glyphs(font, start, glyphs, 0); /* * Go through the glyphs that would be shifted due to the insertion and * determine if some of them will overflow the 0xffff boundary. */ n = (glyphs->end - glyphs->start) + 1; for (which = i; i < ng; i++, gp++) { if (gp->encoding + n > 0xffff) break; } if (i < ng) { /* * Some glyphs have to be moved to the unencoded area because they * would overflow the 0xffff boundary if they were moved up. */ bdf_copy_glyphs(font, gp->encoding, font->glyphs[ng - 1].encoding, &font->overflow, 0); bdf_delete_glyphs(font, gp->encoding, font->glyphs[ng - 1].encoding, 0); resize += bdf_replace_glyphs(font, font->unencoded_used, &font->overflow, 1); } /* * Go back to the insertion point and shift the remaining glyph encodings * up by `n'. */ for (gp = font->glyphs + which; which < font->glyphs_used; which++, gp++) { /* * Mark the new glyph locations as being modified. */ gp->encoding += n; _bdf_set_glyph_modified(font->nmod, gp->encoding); } /* * Finally, mark the font as being modified and insert the new glyphs. */ font->modified = 1; return resize + bdf_replace_glyphs(font, start, glyphs, 0); } static void _bdf_combine_glyphs(bdf_font_t *font, bdf_glyph_t *f, bdf_glyph_t *g) { unsigned short x, sx, sy, si, dx, dy, di, byte, dbpr, fbpr, gbpr; short maxas, maxds, maxrb, minlb, maxlb, rb; unsigned char *masks; bdf_bbx_t nbbx; bdf_glyph_t tmp; /* * Determine the max bounding box for the two glyphs. */ minlb = 32767; maxlb = maxrb = maxas = maxds = 0; /* * Get the font glyph bounds. */ maxas = MAX(f->bbx.ascent, maxas); maxds = MAX(f->bbx.descent, maxds); rb = f->bbx.width + f->bbx.x_offset; maxrb = MAX(rb, maxrb); minlb = MIN(f->bbx.x_offset, minlb); maxlb = MAX(f->bbx.x_offset, maxlb); /* * Get the bounds of the incoming glyph. */ maxas = MAX(g->bbx.ascent, maxas); maxds = MAX(g->bbx.descent, maxds); rb = g->bbx.width + g->bbx.x_offset; maxrb = MAX(rb, maxrb); minlb = MIN(g->bbx.x_offset, minlb); maxlb = MAX(g->bbx.x_offset, maxlb); /* * Set up the new glyph bounding box. */ nbbx.width = maxrb - minlb; nbbx.x_offset = minlb; nbbx.height = maxas + maxds; nbbx.ascent = maxas; nbbx.descent = maxds; nbbx.y_offset = -maxds; masks = 0; switch (font->bpp) { case 1: masks = bdf_onebpp; break; case 2: masks = bdf_twobpp; break; case 4: masks = bdf_fourbpp; break; case 8: masks = bdf_eightbpp; break; } fbpr = ((f->bbx.width * font->bpp) + 7) >> 3; gbpr = ((g->bbx.width * font->bpp) + 7) >> 3; dbpr = ((nbbx.width * font->bpp) + 7) >> 3; if (memcmp((char *) &nbbx, (char *) &f->bbx, sizeof(bdf_bbx_t)) == 0) { /* * The largest is the first, so merge the second in with it. */ dy = f->bbx.ascent - g->bbx.ascent; for (sy = 0; sy < g->bbx.height; sy++, dy++) { for (x = sx = 0; x < g->bbx.width; x++, sx += font->bpp) { si = (sx & 7) / font->bpp; if ((byte = g->bitmap[(sy * gbpr) + (sx >> 3)] & masks[si])) /* * No shifting of the byte is needed because the x offset * is the same for both glyphs. */ f->bitmap[(dy * fbpr) + (sx >> 3)] |= byte; } } } else if (memcmp((char *) &nbbx, (char *) &g->bbx, sizeof(bdf_bbx_t)) == 0) { /* * The largest is the incoming glyph, so merge into that one and swap * it with the font glyph. */ dy = g->bbx.ascent - f->bbx.ascent; for (sy = 0; sy < f->bbx.height; sy++, dy++) { for (x = sx = 0; x < f->bbx.width; x++, sx += font->bpp) { si = (sx & 7) / font->bpp; if ((byte = f->bitmap[(sy * gbpr) + (sx >> 3)] & masks[si])) /* * No shifting of the byte is needed because the x offset * is the same for both glyphs. */ g->bitmap[(dy * fbpr) + (sx >> 3)] |= byte; } } /* * Now swap the two glyphs while preserving the name and encoding of * the first glyph. */ tmp.swidth = g->swidth; tmp.dwidth = g->dwidth; tmp.bytes = g->bytes; tmp.bitmap = g->bitmap; (void) memcpy((char *) &tmp.bbx, (char *) &g->bbx, sizeof(bdf_bbx_t)); g->swidth = f->swidth; g->dwidth = f->dwidth; g->bytes = f->bytes; g->bitmap = f->bitmap; (void) memcpy((char *) &g->bbx, (char *) &f->bbx, sizeof(bdf_bbx_t)); f->swidth = tmp.swidth; f->dwidth = tmp.dwidth; f->bytes = tmp.bytes; f->bitmap = tmp.bitmap; (void) memcpy((char *) &f->bbx, (char *) &tmp.bbx, sizeof(bdf_bbx_t)); } else { /* * Need a new bitmap for the combination of the two. */ tmp.bytes = nbbx.height * dbpr; tmp.bitmap = (unsigned char *) malloc(tmp.bytes); (void) memset((char *) tmp.bitmap, 0, tmp.bytes); /* * Merge the first glyph. */ dy = nbbx.ascent - f->bbx.ascent; for (sy = 0; sy < f->bbx.height; sy++, dy++) { dx = MYABS(nbbx.x_offset - f->bbx.x_offset) * font->bpp; for (x = sx = 0; x < f->bbx.width; x++, sx += font->bpp, dx += font->bpp) { si = (sx & 7) / font->bpp; if ((byte = f->bitmap[(sy * fbpr) + (sx >> 3)] & masks[si])) { di = (dx & 7) / font->bpp; if (di < si) byte <<= (si - di) * font->bpp; else if (di > si) byte >>= (di - si) * font->bpp; tmp.bitmap[(dy * dbpr) + (dx >> 3)] |= byte; } } } /* * Merge the second glyph. */ dy = nbbx.ascent - g->bbx.ascent; for (sy = 0; sy < g->bbx.height; sy++, dy++) { dx = MYABS(nbbx.x_offset - g->bbx.x_offset) * font->bpp; for (x = sx = 0; x < g->bbx.width; x++, sx += font->bpp, dx += font->bpp) { si = (sx & 7) / font->bpp; if ((byte = g->bitmap[(sy * gbpr) + (sx >> 3)] & masks[si])) { di = (dx & 7) / font->bpp; if (di < si) byte <<= (si - di) * font->bpp; else if (di > si) byte >>= (di - si) * font->bpp; tmp.bitmap[(dy * dbpr) + (dx >> 3)] |= byte; } } } /* * Now clear the font glyph and copy the temp glyph to it. */ if (f->bytes > 0) free((char *) f->bitmap); f->bytes = tmp.bytes; f->bitmap = tmp.bitmap; (void) memcpy((char *) &f->bbx, (char *) &nbbx, sizeof(bdf_bbx_t)); /* * Set the device width. Pay attention to whether the font is * monowidth or character cell. */ if (font->spacing != BDF_PROPORTIONAL) f->dwidth = font->monowidth; else f->dwidth = MAX(f->dwidth, g->dwidth); } } int bdf_merge_glyphs(bdf_font_t *font, int start, bdf_glyphlist_t *glyphs, int unencoded) { int resize; int i, n, ng, end, add, enc, off; bdf_glyph_t *sgp, *gp, *dgp, *base; short maxas, maxds, maxrb, minlb, maxlb, rb; double ps, rx, dw; bdf_bbx_t nbbx; resize = 0; if (font == 0) return resize; /* * If the glyphs are being merged in the unencoded area, simply append * them. The unencoded area is simply storage. */ if (unencoded) return bdf_replace_glyphs(font, font->unencoded_used, glyphs, unencoded); /* * Dither the incoming bitmaps so they match the same bits per pixel as * the font. */ if (glyphs->bpp != font->bpp) { if (glyphs->bpp == 1) _bdf_one_to_n(glyphs, font->bpp); else if (font->bpp == 1) _bdf_n_to_one(glyphs); else if (glyphs->bpp == 2) _bdf_two_to_four(glyphs); else _bdf_four_to_two(glyphs); } /* * Set the point size and horizontal resolution so the scalable width can * be determined. */ ps = (double) font->point_size; rx = (double) font->resolution_x; /* * Determine if a resize is needed. */ /* * Determine the bounding box for the font without the characters being * replaced. */ minlb = 32767; maxlb = maxrb = maxas = maxds = 0; /* * Get the font bounds. */ maxas = MAX(font->bbx.ascent, maxas); maxds = MAX(font->bbx.descent, maxds); rb = font->bbx.width + font->bbx.x_offset; maxrb = MAX(rb, maxrb); minlb = MIN(font->bbx.x_offset, minlb); maxlb = MAX(font->bbx.x_offset, maxlb); /* * Get the bounds of the incoming glyphs. */ maxas = MAX(glyphs->bbx.ascent, maxas); maxds = MAX(glyphs->bbx.descent, maxds); rb = glyphs->bbx.width + glyphs->bbx.x_offset; maxrb = MAX(rb, maxrb); minlb = MIN(glyphs->bbx.x_offset, minlb); maxlb = MAX(glyphs->bbx.x_offset, maxlb); /* * Set up the new font bounding box, minus the characters that are being * removed and with the new characters added. */ nbbx.width = maxrb - minlb; nbbx.x_offset = minlb; nbbx.height = maxas + maxds; nbbx.ascent = maxas; nbbx.descent = maxds; nbbx.y_offset = -maxds; /* * Now determine if the combination of the glyphs removed and the new * glyphs cause the font bounding box to be changed. */ resize = (nbbx.width > font->bbx.width || nbbx.height > font->bbx.height) ? 1 : 0; /* * Set the pointers to the glyphs. */ ng = (unencoded == 0) ? font->glyphs_used : font->unencoded_used; gp = (unencoded == 0) ? font->glyphs : font->unencoded; /* * Locate the closest glyph on or following `start'. */ for (i = 0; i < ng && gp->encoding < start; i++, gp++) ; if (i == ng) /* * If the gylphs are being added off the end of the list, simply insert * them so any overflows can be handled. */ return bdf_insert_glyphs(font, start, glyphs); /* * Set the starting point for copying the incoming glyphs. */ dgp = gp; n = glyphs->end - glyphs->start; end = start + n; /* * Count the number of glyphs that will be added and mark all the * glyphs that will be modified. */ for (sgp = glyphs->glyphs, add = 0, i = start; i <= end; i++) { enc = (sgp->encoding - glyphs->start) + start; /* * Mark the glyph as being modified. */ if (unencoded == 0) _bdf_set_glyph_modified(font->nmod, enc); else _bdf_set_glyph_modified(font->umod, enc); if (enc == gp->encoding) sgp++; else if (enc < gp->encoding) { add++; sgp++; } if (gp->encoding == i) gp++; } if (add > 0) { ng += add; /* * Need to make room for some glyphs that will be added. */ if (unencoded) { off = dgp - font->unencoded; if (font->unencoded_used == 0) font->unencoded = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * ng); else font->unencoded = (bdf_glyph_t *) realloc((char *) font->unencoded, sizeof(bdf_glyph_t) * ng); dgp = font->unencoded + off; font->unencoded_used = ng; } else { off = dgp - font->glyphs; if (font->glyphs_used == 0) font->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * ng); else font->glyphs = (bdf_glyph_t *) realloc((char *) font->glyphs, sizeof(bdf_glyph_t) * ng); dgp = font->glyphs + off; font->glyphs_used = ng; } } /* * Now go through and do two things: * 1. Insert new incoming glyphs. * 2. Combine two glyphs at the same location. */ base = (!unencoded) ? font->glyphs : font->unencoded; for (gp = dgp, sgp = glyphs->glyphs, i = start; i <= end; i++) { enc = (sgp->encoding - glyphs->start) + start; if (enc < gp->encoding) { /* * Shift the glyphs up by one and add this one. */ if (gp - base < ng) _bdf_memmove((char *) (gp + 1), (char *) gp, sizeof(bdf_glyph_t) * (ng - (gp - base))); (void) memcpy((char *) gp, (char *) sgp, sizeof(bdf_glyph_t)); gp->name = (char *) _bdf_strdup((unsigned char *) gp->name, strlen(gp->name) + 1); if (gp->bytes > 0) gp->bitmap = _bdf_strdup(gp->bitmap, gp->bytes); if (gp->unicode.map_size > 0) gp->unicode.map = _bdf_strdup(gp->unicode.map, gp->unicode.map_size); gp->encoding = i; sgp++; dw = (double) gp->dwidth; gp->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx)); } else if (enc == gp->encoding) { _bdf_combine_glyphs(font, gp, sgp); dw = (double) gp->dwidth; gp->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx)); sgp++; } if (gp->encoding == i) gp++; } if (resize) (void) memcpy((char *) &font->bbx, (char *) &nbbx, sizeof(bdf_bbx_t)); font->modified = 1; return resize; } void bdf_set_modified(bdf_font_t *font, int modified) { if (font == 0 || font->modified == modified) return; if (modified == 0) { /* * Clear out the modified bitmaps. */ (void) memset((char *) font->nmod, 0, sizeof(unsigned int) * 2048); (void) memset((char *) font->umod, 0, sizeof(unsigned int) * 2048); } font->modified = modified; } /************************************************************************** * * XLFD font name functions. * **************************************************************************/ static char *xlfdfields[] = { "FOUNDRY", "FAMILY_NAME", "WEIGHT_NAME", "SLANT", "SETWIDTH_NAME", "ADD_STYLE_NAME", "PIXEL_SIZE", "POINT_SIZE", "RESOLUTION_X", "RESOLUTION_Y", "SPACING", "AVERAGE_WIDTH", "CHARSET_REGISTRY", "CHARSET_ENCODING", }; int bdf_is_xlfd_property(char *name) { int i; for (i = 0; i < 14; i++) { if (strcmp(name, xlfdfields[i]) == 0) return 1; } return 0; } int bdf_has_xlfd_name(bdf_font_t *font) { unsigned int len; char name[256]; _bdf_list_t list; if (font == 0 || font->name == 0 || font->name[0] == 0) return 0; len = (unsigned int) (strlen(font->name) + 1); (void) memcpy(name, font->name, len); list.size = list.used = 0; _bdf_split("-", name, len, &list); if (list.size > 0) free((char *) list.field); return (list.used == 15); } char * bdf_make_xlfd_name(bdf_font_t *font, char *foundry, char *family) { int len; double dp, dr; unsigned int i, width, used; unsigned short awidth, pxsize; bdf_property_t *pp; bdf_glyph_t *gp; char spacing, *name, *val, *np, nbuf[256]; if (font == 0 || bdf_has_xlfd_name(font)) return 0; np = nbuf; /* * Add the FOUNDRY field. */ if ((pp = bdf_get_font_property(font, "FOUNDRY")) != 0) foundry = pp->value.atom; sprintf(np, "-%s", foundry); np += strlen(np); /* * Add the FAMILY_NAME field. */ if ((pp = bdf_get_font_property(font, "FAMILY_NAME")) != 0) family = pp->value.atom; sprintf(np, "-%s", family); np += strlen(np); /* * Add the WEIGHT_NAME field. */ val = ((pp = bdf_get_font_property(font, "WEIGHT_NAME")) != 0) ? pp->value.atom : "Medium"; if (val == 0) val = "Medium"; sprintf(np, "-%s", val); np += strlen(np); /* * Add the SLANT field. */ val = ((pp = bdf_get_font_property(font, "SLANT")) != 0) ? pp->value.atom : "R"; if (val == 0) val = "R"; sprintf(np, "-%s", val); np += strlen(np); /* * Add the SETWIDTH_NAME field. */ val = ((pp = bdf_get_font_property(font, "SETWIDTH_NAME")) != 0) ? pp->value.atom : "Normal"; if (val == 0) val = "Normal"; sprintf(np, "-%s", val); np += strlen(np); /* * Add the ADD_STYLE_NAME field. */ val = ((pp = bdf_get_font_property(font, "ADD_STYLE_NAME")) != 0) ? pp->value.atom : ""; if (val == 0) val = ""; sprintf(np, "-%s", val); np += strlen(np); /* * Add the PIXEL_SIZE field. */ if ((pp = bdf_get_font_property(font, "PIXEL_SIZE")) != 0) sprintf(np, "-%d", pp->value.int32); else { /* * Determine the pixel size. */ dp = (double) (font->point_size * 10); dr = (double) font->resolution_y; pxsize = (unsigned short) (((dp * dr) / 722.7) + 0.5); sprintf(np, "-%hd", pxsize); } np += strlen(np); /* * Add the POINT_SIZE field. */ if ((pp = bdf_get_font_property(font, "POINT_SIZE")) != 0) sprintf(np, "-%d", pp->value.int32); else sprintf(np, "-%d", font->point_size * 10); np += strlen(np); /* * Add the RESOLUTION_X field. */ if ((pp = bdf_get_font_property(font, "RESOLUTION_X")) != 0) sprintf(np, "-%d", pp->value.card32); else sprintf(np, "-%d", font->resolution_x); np += strlen(np); /* * Add the RESOLUTION_Y field. */ if ((pp = bdf_get_font_property(font, "RESOLUTION_Y")) != 0) sprintf(np, "-%d", pp->value.card32); else sprintf(np, "-%d", font->resolution_y); np += strlen(np); /* * Add the SPACING field. */ if ((pp = bdf_get_font_property(font, "SPACING")) != 0) spacing = pp->value.atom[0]; else { spacing = 'P'; switch (font->spacing) { case BDF_PROPORTIONAL: spacing = 'P'; break; case BDF_MONOWIDTH: spacing = 'M'; break; case BDF_CHARCELL: spacing = 'C'; break; } } sprintf(np, "-%c", spacing); np += strlen(np); /* * Add the AVERAGE_WIDTH field. */ if ((pp = bdf_get_font_property(font, "AVERAGE_WIDTH")) != 0) sprintf(np, "-%d", pp->value.int32); else { /* * Determine the average width of all the glyphs in the font. */ width = 0; for (i = 0, gp = font->unencoded; i < font->unencoded_used; i++, gp++) width += gp->dwidth; for (i = 0, gp = font->glyphs; i < font->glyphs_used; i++, gp++) width += gp->dwidth; used = font->unencoded_used + font->glyphs_used; if (used == 0) awidth = font->bbx.width * 10; else awidth = (unsigned short) ((((float) width) / ((float) used)) * 10.0); sprintf(np, "-%hd", awidth); } np += strlen(np); /* * Add the CHARSET_REGISTRY field. */ val = ((pp = bdf_get_font_property(font, "CHARSET_REGISTRY")) != 0) ? pp->value.atom : "FontSpecific"; sprintf(np, "-%s", val); np += strlen(np); /* * Add the CHARSET_ENCODING field. */ val = ((pp = bdf_get_font_property(font, "CHARSET_ENCODING")) != 0) ? pp->value.atom : "0"; sprintf(np, "-%s", val); np += strlen(np); len = (np - nbuf) + 1; name = (char *) malloc(len); (void) memcpy(name, nbuf, len); return name; } void bdf_update_name_from_properties(bdf_font_t *font) { unsigned int i; bdf_property_t *p; _bdf_list_t list; char *np, name[128], nname[128]; if (font == 0 || bdf_has_xlfd_name(font) == 0) return; (void) memset((char *) &list, 0, sizeof(_bdf_list_t)); /* * Split the name into fields and shift out the first empty field. * This assumes that the font has a name. */ i = (unsigned int) strlen(font->name); (void) memcpy(name, font->name, i + 1); _bdf_split("-", name, i, &list); _bdf_shift(1, &list); /* * Initialize the pointer to the new name and add the '-' prefix. */ np = nname; *np++ = '-'; *np = 0; for (i = 0; i < 14; i++) { if ((p = bdf_get_font_property(font, xlfdfields[i])) != 0) { /* * The property exists, so add it to the new font name. */ switch (p->format) { case BDF_ATOM: if (p->value.atom != 0) sprintf(np, "%s", p->value.atom); break; case BDF_CARDINAL: sprintf(np, "%d", p->value.card32); break; case BDF_INTEGER: sprintf(np, "%d", p->value.int32); break; } } else /* * The property does not exist, so add the original value to the * new font name. */ sprintf(np, "%s", list.field[i]); np += strlen(np); if (i + 1 < 14) { *np++ = '-'; *np = 0; } } /* * Replace the existing font name with the new one. */ free(font->name); i = (unsigned int) (strlen(nname) + 1); font->name = (char *) malloc(i); (void) memcpy(font->name, nname, i); /* * Free up the list. */ if (list.size > 0) free((char *) list.field); font->modified = 1; } int bdf_update_properties_from_name(bdf_font_t *font) { unsigned int i; bdf_property_t *p, prop; _bdf_list_t list; char name[128]; if (font == 0 || font->name == 0 || bdf_has_xlfd_name(font) == 0) return 0; (void) memset((char *) &list, 0, sizeof(_bdf_list_t)); /* * Split the name into fields and shift out the first empty field. */ i = (unsigned int) strlen(font->name); (void) memcpy(name, font->name, i + 1); _bdf_split("-", name, i, &list); _bdf_shift(1, &list); for (i = 0; i < 14; i++) { p = bdf_get_property(xlfdfields[i]); prop.name = p->name; prop.format = p->format; switch (prop.format) { case BDF_ATOM: prop.value.atom = list.field[i]; break; case BDF_CARDINAL: prop.value.card32 = _bdf_atoul(list.field[i], 0, 10); break; case BDF_INTEGER: prop.value.int32 = _bdf_atol(list.field[i], 0, 10); break; } bdf_add_font_property(font, &prop); } /* * Free up the list. */ if (list.size > 0) free((char *) list.field); font->modified = 1; return 1; } int bdf_update_average_width(bdf_font_t *font) { int changed; unsigned int i; int oaw, awidth, used; bdf_glyph_t *gp; _bdf_list_t list; bdf_property_t *pp, prop; char *np, num[16], nbuf[128]; changed = 0; used = font->unencoded_used + font->glyphs_used; if (used == 0) awidth = font->bbx.width * 10; else { for (i = 0, awidth = 0, gp = font->unencoded; i < font->unencoded_used; i++, gp++) awidth += gp->dwidth; for (i = 0, gp = font->glyphs; i < font->glyphs_used; i++, gp++) awidth += gp->dwidth; awidth = (int) ((((double) awidth) / ((double) used)) * 10.0); } /* * Check to see if it is different than the average width in the font * name. */ if (bdf_has_xlfd_name(font)) { (void) memset((char *) &list, 0, sizeof(_bdf_list_t)); i = (unsigned int) strlen(font->name); (void) memcpy(nbuf, font->name, i + 1); _bdf_split("-", nbuf, i, &list); oaw = _bdf_atol(list.field[12], 0, 10); if (oaw != awidth) { /* * Construct a new font name with the new average width. */ changed = 1; sprintf(num, "%d", awidth); used = strlen(num) - strlen(list.field[12]); if (used > 0) { /* * Resize the string used for the font name instead of * creating a new one. */ used += i; font->name = (char *) realloc(font->name, used); } /* * Copy the elements of the list back into the new font name. */ np = font->name; *np++ = '-'; for (i = 1; i < list.used; i++) { if (i == 12) strcpy(np, num); else strcpy(np, list.field[i]); np += strlen(np); if (i + 1 < list.used) *np++ = '-'; } } /* * Clear up any space allocated for the list. */ if (list.size > 0) free((char *) list.field); } /* * Now check for the AVERAGE_WIDTH property. */ if ((pp = bdf_get_font_property(font, "AVERAGE_WIDTH")) != 0) { if (pp->value.int32 != awidth) { changed = 1; pp->value.int32 = awidth; } } else { /* * Property doesn't exist yet, so add it. */ changed = 1; prop.name = "AVERAGE_WIDTH"; prop.format = BDF_INTEGER; prop.value.int32 = awidth; bdf_add_font_property(font, &prop); } if (changed) font->modified = 1; return changed; } /* * Change the font bounding box and return a non-zero number if this causes * the font to get larger or smaller. */ int bdf_set_font_bbx(bdf_font_t *font, bdf_metrics_t *metrics) { int resize; resize = 0; if (font == 0 || metrics == 0) return resize; resize = (font->bbx.width != metrics->width || font->bbx.height != metrics->height) ? 1 : 0; font->bbx.width = metrics->width; font->bbx.height = metrics->height; font->bbx.x_offset = metrics->x_offset; font->bbx.y_offset = metrics->y_offset; font->bbx.ascent = metrics->ascent; font->bbx.descent = metrics->descent; /* * If the font is not proportional, then make sure the monowidth field is * set to the font bounding box. */ if (font->spacing != BDF_PROPORTIONAL) font->monowidth = font->bbx.width; return resize; } int bdf_translate_glyphs(bdf_font_t *font, short dx, short dy, int start, int end, bdf_callback_t callback, void *data, int unencoded) { int resize, diff; bdf_glyph_t *gp, *sp, *ep; bdf_callback_struct_t cb; if (font == 0 || (dx == 0 && dy == 0)) return 0; if ((unencoded && font->unencoded_used == 0) || font->glyphs_used == 0) return 0; /* * Call the progress initialization callback. */ if (callback != 0) { cb.reason = BDF_TRANSLATE_START; cb.total = (end - start) + 1; cb.current = 0; (*callback)(&cb, data); } /* * Locate the first and last glyphs to be shifted. */ sp = _bdf_locate_glyph(font, start, unencoded); ep = _bdf_locate_glyph(font, end, unencoded); for (resize = 0, gp = sp; sp <= ep; sp++) { /* * Call the callback if one was provided. */ if (sp != gp && callback != 0) { cb.reason = BDF_TRANSLATING; cb.current = (sp->encoding - start) + 1; (*callback)(&cb, data); } /* * Apply the X translation. */ if (dx != 0) { sp->bbx.x_offset += dx; diff = sp->bbx.x_offset - font->bbx.x_offset; if (sp->bbx.x_offset < font->bbx.x_offset) { font->bbx.x_offset = sp->bbx.x_offset; font->bbx.width += MYABS(diff); resize = 1; } else if (sp->bbx.width + sp->bbx.x_offset > font->bbx.width + font->bbx.x_offset) { font->bbx.width += MYABS(diff); resize = 1; } /* * Mark the glyph as modified appropriately. */ if (unencoded) _bdf_set_glyph_modified(font->umod, sp->encoding); else _bdf_set_glyph_modified(font->nmod, sp->encoding); } /* * Apply the Y translation. */ if (dy != 0) { sp->bbx.y_offset += dy; sp->bbx.descent = -sp->bbx.y_offset; sp->bbx.ascent = sp->bbx.height - sp->bbx.descent; diff = sp->bbx.y_offset - font->bbx.y_offset; if (sp->bbx.y_offset < font->bbx.y_offset) { font->bbx.y_offset = sp->bbx.y_offset; font->bbx.descent = -font->bbx.y_offset; font->bbx.height += MYABS(diff); resize = 1; } else if (sp->bbx.ascent > font->bbx.ascent) { font->bbx.ascent += MYABS(diff); font->bbx.height += MYABS(diff); resize = 1; } /* * Mark the glyph as modified appropriately. */ if (unencoded) _bdf_set_glyph_modified(font->umod, sp->encoding); else _bdf_set_glyph_modified(font->nmod, sp->encoding); } } /* * Call the callback one more time to make sure the client knows * this is done. */ if (callback != 0 && cb.current < cb.total) { cb.reason = BDF_TRANSLATING; cb.current = cb.total; (*callback)(&cb, data); } if (resize) font->modified = 1; return resize; } static void _bdf_resize_rotation(bdf_font_t *font, int mul90, short degrees, bdf_glyph_t *glyph, bdf_bitmap_t *scratch, unsigned short *width, unsigned short *height) { unsigned short w, h, wd, ht, bytes; short cx, cy, x1, y1, x2, y2; double dx1, dy1, dx2, dy2; w = h = 0; cx = glyph->bbx.width >> 1; cy = glyph->bbx.height >> 1; /* * Rotate the lower left and upper right corners and check for a potential * resize. */ x1 = 0; y1 = glyph->bbx.height; x2 = glyph->bbx.width; y2 = 0; dx1 = (double) (x1 - cx); dy1 = (double) (y1 - cy); dx2 = (double) (x2 - cx); dy2 = (double) (y2 - cx); if (mul90) { x1 = cx + (short) ((dx1 * _bdf_cos_tbl[degrees]) - (dy1 * _bdf_sin_tbl[degrees])); y1 = cy + (short) ((dx1 * _bdf_sin_tbl[degrees]) + (dy1 * _bdf_cos_tbl[degrees])); x2 = cx + (short) ((dx2 * _bdf_cos_tbl[degrees]) - (dy2 * _bdf_sin_tbl[degrees])); y2 = cy + (short) ((dx2 * _bdf_sin_tbl[degrees]) + (dy2 * _bdf_cos_tbl[degrees])); } else { x1 = cx + _bdf_ceiling((dx1 * _bdf_cos_tbl[degrees]) - (dy1 * _bdf_sin_tbl[degrees])); y1 = cy + _bdf_ceiling((dx1 * _bdf_sin_tbl[degrees]) + (dy1 * _bdf_cos_tbl[degrees])); x2 = cx + _bdf_ceiling((dx2 * _bdf_cos_tbl[degrees]) - (dy2 * _bdf_sin_tbl[degrees])); y2 = cy + _bdf_ceiling((dx2 * _bdf_sin_tbl[degrees]) + (dy2 * _bdf_cos_tbl[degrees])); } wd = MYABS(x2 - x1); ht = MYABS(y2 - y1); w = MAX(wd, w); h = MAX(ht, h); if (wd > font->bbx.width) font->bbx.width += wd - font->bbx.width; if (ht > font->bbx.height) { font->bbx.ascent += ht - font->bbx.height; font->bbx.height += ht - font->bbx.height; } /* * Rotate the upper left and lower right corners and check for a potential * resize. */ x1 = 0; y1 = 0; x2 = glyph->bbx.width; y2 = glyph->bbx.height; dx1 = (double) (x1 - cx); dy1 = (double) (y1 - cy); dx2 = (double) (x2 - cx); dy2 = (double) (y2 - cx); if (mul90) { x1 = cx + (short) ((dx1 * _bdf_cos_tbl[degrees]) - (dy1 * _bdf_sin_tbl[degrees])); y1 = cy + (short) ((dx1 * _bdf_sin_tbl[degrees]) + (dy1 * _bdf_cos_tbl[degrees])); x2 = cx + (short) ((dx2 * _bdf_cos_tbl[degrees]) - (dy2 * _bdf_sin_tbl[degrees])); y2 = cy + (short) ((dx2 * _bdf_sin_tbl[degrees]) + (dy2 * _bdf_cos_tbl[degrees])); } else { x1 = cx + _bdf_ceiling((dx1 * _bdf_cos_tbl[degrees]) - (dy1 * _bdf_sin_tbl[degrees])); y1 = cy + _bdf_ceiling((dx1 * _bdf_sin_tbl[degrees]) + (dy1 * _bdf_cos_tbl[degrees])); x2 = cx + _bdf_ceiling((dx2 * _bdf_cos_tbl[degrees]) - (dy2 * _bdf_sin_tbl[degrees])); y2 = cy + _bdf_ceiling((dx2 * _bdf_sin_tbl[degrees]) + (dy2 * _bdf_cos_tbl[degrees])); } wd = MYABS(x2 - x1); ht = MYABS(y2 - y1); w = MAX(wd, w); h = MAX(ht, h); if (wd > font->bbx.width) font->bbx.width += wd - font->bbx.width; if (ht > font->bbx.height) { font->bbx.ascent += ht - font->bbx.height; font->bbx.height += ht - font->bbx.height; } if (font->bbx.width > scratch->width || font->bbx.height > scratch->height) { scratch->width = MAX(font->bbx.width, scratch->width); scratch->height = MAX(font->bbx.height, scratch->height); bytes = (((font->bbx.width * font->bpp) + 7) >> 3) * font->bbx.height; if (scratch->bytes == 0) scratch->bitmap = (unsigned char *) malloc(bytes); else scratch->bitmap = (unsigned char *) realloc((char *) scratch->bitmap, bytes); scratch->bytes = bytes; } /* * Clear the bitmap. */ (void) memset((char *) scratch->bitmap, 0, scratch->bytes); /* * Return the new glyph width and height. */ *width = w; *height = h; } int bdf_rotate_glyphs(bdf_font_t *font, short degrees, int start, int end, bdf_callback_t callback, void *data, int unencoded) { int mul90, bpr, sbpr; unsigned short wd, ht, si, di, byte, col; short x, y, cx, cy, nx, ny, ox, oy, shiftx, shifty; bdf_glyph_t *gp, *sp, *ep; unsigned char *masks; double dx, dy; bdf_bitmap_t scratch; bdf_callback_struct_t cb; if (font == 0 || (unencoded && font->unencoded_used == 0) || font->glyphs_used == 0 || degrees == 0) return 0; while (degrees < 0) degrees += 360; while (degrees >= 360) degrees -= 360; mul90 = ((degrees % 90) == 0) ? 1 : 0; masks = 0; switch (font->bpp) { case 1: masks = bdf_onebpp; break; case 2: masks = bdf_twobpp; break; case 4: masks = bdf_fourbpp; break; case 8: masks = bdf_eightbpp; break; } /* * Initialize the scratch bitmap. */ (void) memset((char *) &scratch, 0, sizeof(bdf_bitmap_t)); /* * Call the progress initialization callback. */ if (callback != 0) { cb.reason = BDF_ROTATE_START; cb.total = (end - start) + 1; cb.current = 0; (*callback)(&cb, data); } sp = _bdf_locate_glyph(font, start, unencoded); ep = _bdf_locate_glyph(font, end, unencoded); for (gp = sp; sp <= ep; sp++) { /* * Call the callback if one was provided. */ if (sp != gp && callback != 0) { cb.reason = BDF_ROTATING; cb.current = (sp->encoding - start) + 1; (*callback)(&cb, data); } /* * Resize the bitmap, adjust the font bounding box, and get the new * glyph width and height. */ _bdf_resize_rotation(font, mul90, degrees, sp, &scratch, &wd, &ht); cx = sp->bbx.width >> 1; cy = sp->bbx.height >> 1; shiftx = shifty = 0; sbpr = ((wd * font->bpp) + 7) >> 3; bpr = ((sp->bbx.width * font->bpp) + 7) >> 3; for (y = 0; y < sp->bbx.height; y++) { for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) { si = (col & 7) / font->bpp; byte = sp->bitmap[(y * bpr) + (col >> 3)] & masks[si]; if (byte) { dx = (double) (x - cx); dy = (double) (y - cy); if (mul90) { nx = cx + (short) ((dx * _bdf_cos_tbl[degrees]) - (dy * _bdf_sin_tbl[degrees])); ny = cy + (short) ((dx * _bdf_sin_tbl[degrees]) + (dy * _bdf_cos_tbl[degrees])); } else { nx = cx + _bdf_ceiling((dx * _bdf_cos_tbl[degrees]) - (dy * _bdf_sin_tbl[degrees])); ny = cy + _bdf_ceiling((dx * _bdf_sin_tbl[degrees]) + (dy * _bdf_cos_tbl[degrees])); } if (nx < 0) { shiftx = MIN(shiftx, nx); nx += wd; } else if (nx >= wd) { ox = (nx - wd) + 1; shiftx = MAX(shiftx, ox); nx -= wd; } if (ny < 0) { shifty = MIN(shifty, ny); ny += ht; } else if (ny >= ht) { oy = (ny - ht) + 1; shifty = MAX(shifty, oy); ny -= ht; } nx *= font->bpp; di = (nx & 7) / font->bpp; if (di < si) byte <<= (si - di) * font->bpp; else if (di > si) byte >>= (di - si) * font->bpp; scratch.bitmap[(ny * sbpr) + (nx >> 3)] |= byte; } } } /* * Resize the glyph bitmap if necessary. */ if (wd != sp->bbx.width || ht != sp->bbx.height) { sp->bbx.width = wd; sp->bbx.height = ht; sp->bbx.ascent = ht - sp->bbx.descent; sp->bytes = (((wd * font->bpp) + 7) >> 3) * ht; sp->bitmap = (unsigned char *) realloc((char *) sp->bitmap, sp->bytes); } (void) memset((char *) sp->bitmap, 0, sp->bytes); /* * Copy the glyph from the scratch area to the glyph bitmap, * adjusting for any shift values encountered. */ bpr = ((sp->bbx.width * font->bpp) + 7) >> 3; for (y = 0; y < sp->bbx.height; y++) { for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) { si = (col & 7) / font->bpp; byte = scratch.bitmap[(y * bpr) + (col >> 3)] & masks[si]; if (byte) { nx = x - shiftx; ny = y - shifty; if (nx < 0) nx += sp->bbx.width; else if (nx >= sp->bbx.width) nx -= sp->bbx.width; if (ny < 0) ny += sp->bbx.height; else if (ny >= sp->bbx.height) ny -= sp->bbx.height; nx *= font->bpp; di = (nx & 7) / font->bpp; if (di < si) byte <<= (si - di) * font->bpp; else if (di > si) byte >>= (di - si) * font->bpp; sp->bitmap[(ny * bpr) + (nx >> 3)] |= byte; } } } /* * Mark the glyph as modified. */ if (unencoded) _bdf_set_glyph_modified(font->umod, sp->encoding); else _bdf_set_glyph_modified(font->nmod, sp->encoding); } /* * Call the callback one more time to make sure the client knows * this is done. */ if (callback != 0 && cb.current < cb.total) { cb.reason = BDF_TRANSLATING; cb.current = cb.total; (*callback)(&cb, data); } if (scratch.bytes > 0) free((char *) scratch.bitmap); /* * Rotations always change things, so just return a value indicating this. */ font->modified = 1; return 1; } static void _bdf_resize_shear(bdf_font_t *font, int neg, short degrees, bdf_glyph_t *glyph, bdf_bitmap_t *scratch, unsigned short *width, unsigned short *height) { unsigned short wd, w, bytes; short x1, y1, x2, y2; w = 0; *height = glyph->bbx.height; /* * Shear the lower left and upper right corners and check for a potential * resize. */ x1 = 0; y1 = glyph->bbx.height; x2 = glyph->bbx.width; y2 = 0; if (neg) { x1 += (short) ((double) y1 * _bdf_tan_tbl[degrees]); x2 += (short) ((double) y2 * _bdf_tan_tbl[degrees]); } else { x1 += (short) ((double) (glyph->bbx.height - y1) * _bdf_tan_tbl[degrees]); x2 += (short) ((double) (glyph->bbx.height - y2) * _bdf_tan_tbl[degrees]); } wd = MYABS(x2 - x1); w = MAX(w, wd); if (wd > font->bbx.width) font->bbx.width += wd - font->bbx.width; /* * Shear the upper left and lower right corners and check for a potential * resize. */ x1 = 0; y1 = 0; x2 = glyph->bbx.width; y2 = glyph->bbx.height; if (neg) { x1 += (short) ((double) y1 * _bdf_tan_tbl[degrees]); x2 += (short) ((double) y2 * _bdf_tan_tbl[degrees]); } else { x1 += (short) ((double) (glyph->bbx.height - y1) * _bdf_tan_tbl[degrees]); x2 += (short) ((double) (glyph->bbx.height - y2) * _bdf_tan_tbl[degrees]); } wd = MYABS(x2 - x1); w = MAX(w, wd); if (wd > font->bbx.width) font->bbx.width += wd - font->bbx.width; if (font->bbx.width > scratch->width || font->bbx.height > scratch->height) { scratch->width = MAX(font->bbx.width, scratch->width); scratch->height = MAX(font->bbx.height, scratch->height); bytes = (((font->bbx.width * font->bpp) + 7) >> 3) * font->bbx.height; if (scratch->bytes == 0) scratch->bitmap = (unsigned char *) malloc(bytes); else scratch->bitmap = (unsigned char *) realloc((char *) scratch->bitmap, bytes); scratch->bytes = bytes; } /* * Clear the bitmap. */ (void) memset((char *) scratch->bitmap, 0, scratch->bytes); /* * Return the new glyph width. */ *width = w; } int bdf_shear_glyphs(bdf_font_t *font, short degrees, int start, int end, bdf_callback_t callback, void *data, int unencoded) { int neg, bpr, sbpr; unsigned short wd, ht, si, di, byte, col; short x, y, nx, shiftx, ox; bdf_glyph_t *gp, *sp, *ep; unsigned char *masks; bdf_bitmap_t scratch; bdf_callback_struct_t cb; if (font == 0 || (unencoded && font->unencoded_used == 0) || font->glyphs_used == 0) return 0; if (degrees == 0 || degrees < -45 || degrees > 45) return 0; if ((neg = (degrees < 0))) degrees = -degrees; masks = 0; switch (font->bpp) { case 1: masks = bdf_onebpp; break; case 2: masks = bdf_twobpp; break; case 4: masks = bdf_fourbpp; break; case 8: masks = bdf_eightbpp; break; } /* * Initialize the scratch bitmap. */ (void) memset((char *) &scratch, 0, sizeof(bdf_bitmap_t)); /* * Call the progress initialization callback. */ if (callback != 0) { cb.reason = BDF_SHEAR_START; cb.total = (end - start) + 1; cb.current = 0; (*callback)(&cb, data); } sp = _bdf_locate_glyph(font, start, unencoded); ep = _bdf_locate_glyph(font, end, unencoded); for (gp = sp; sp <= ep; sp++) { /* * Call the callback if one was provided. */ if (sp != gp && callback != 0) { cb.reason = BDF_SHEARING; cb.current = (sp->encoding - start) + 1; (*callback)(&cb, data); } /* * Resize the bitmap, adjust the font bounding box, and get the new * glyph width and height. */ _bdf_resize_shear(font, neg, degrees, sp, &scratch, &wd, &ht); shiftx = 0; sbpr = ((wd * font->bpp) + 7) >> 3; bpr = ((sp->bbx.width * font->bpp) + 7) >> 3; for (y = 0; y < sp->bbx.height; y++) { for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) { si = (col & 7) / font->bpp; byte = sp->bitmap[(y * bpr) + (col >> 3)] & masks[si]; if (byte) { if (neg) nx = x + (short) ((double) y * _bdf_tan_tbl[degrees]); else nx = x + (short) ((double) (sp->bbx.height - y) * _bdf_tan_tbl[degrees]); if (nx < 0) { shiftx = MIN(shiftx, nx); nx += wd; } else if (nx >= wd) { ox = (nx - wd) + 1; shiftx = MAX(shiftx, ox); nx -= wd; } nx *= font->bpp; di = (nx & 7) / font->bpp; if (di < si) byte <<= (si - di) * font->bpp; else if (di > si) byte >>= (di - si) * font->bpp; scratch.bitmap[(y * sbpr) + (nx >> 3)] |= byte; } } } /* * Resize the glyph bitmap if necessary. */ if (wd != sp->bbx.width || ht != sp->bbx.height) { sp->bbx.width = wd; sp->bbx.height = ht; sp->bbx.ascent = ht - sp->bbx.descent; sp->bytes = (((wd * font->bpp) + 7) >> 3) * ht; sp->bitmap = (unsigned char *) realloc((char *) sp->bitmap, sp->bytes); } (void) memset((char *) sp->bitmap, 0, sp->bytes); /* * Copy the glyph from the scratch area to the glyph bitmap, * adjusting for any shift values encountered. */ bpr = ((sp->bbx.width * font->bpp) + 7) >> 3; for (y = 0; y < sp->bbx.height; y++) { for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) { si = (col & 7) / font->bpp; byte = scratch.bitmap[(y * bpr) + (col >> 3)] & masks[si]; if (byte) { nx = x - shiftx; if (nx < 0) nx += sp->bbx.width; else if (nx >= sp->bbx.width) nx -= sp->bbx.width; nx *= font->bpp; di = (nx & 7) / font->bpp; if (di < si) byte <<= (si - di) * font->bpp; else if (di > si) byte >>= (di - si) * font->bpp; sp->bitmap[(y * bpr) + (nx >> 3)] |= byte; } } } /* * Mark the glyph as modified. */ if (unencoded) _bdf_set_glyph_modified(font->umod, sp->encoding); else _bdf_set_glyph_modified(font->nmod, sp->encoding); } /* * Call the callback one more time to make sure the client knows * this is done. */ if (callback != 0 && cb.current < cb.total) { cb.reason = BDF_TRANSLATING; cb.current = cb.total; (*callback)(&cb, data); } if (scratch.bytes > 0) free((char *) scratch.bitmap); /* * Rotations always change things, so just return a value indicating this. */ font->modified = 1; return 1; } static void _bdf_widen_by(bdf_font_t *f, bdf_glyph_t *g, bdf_bitmap_t *s, int n) { int bytes, sbpr, dbpr, col; short x, y, si, di; unsigned char *bmap, *masks; masks = 0; switch (f->bpp) { case 1: masks = bdf_onebpp; break; case 2: masks = bdf_twobpp; break; case 4: masks = bdf_fourbpp; break; case 8: masks = bdf_eightbpp; break; } s->height = g->bbx.height; s->width = g->bbx.width + n; bytes = (((s->width * f->bpp) + 7) >> 3) * s->height; if (s->bytes == 0) s->bitmap = (unsigned char *) malloc(bytes); else s->bitmap = (unsigned char *) realloc((char *) s->bitmap, bytes); s->bytes = bytes; (void) memset((char *) s->bitmap, 0, s->bytes); /* * Copy the glyph bitmap to the scratch area, and then swap the bitmaps. */ sbpr = ((g->bbx.width * f->bpp) + 7) >> 3; dbpr = ((s->width * f->bpp) + 7) >> 3; for (y = 0; y < g->bbx.height; y++) { for (col = x = 0; x < g->bbx.width; x++, col += f->bpp) { si = (col & 7) / f->bpp; bytes = g->bitmap[(y * sbpr) + (col >> 3)] & masks[si]; if (bytes) { di = ((x * f->bpp) & 7) / f->bpp; if (di < si) bytes <<= (si - di) * f->bpp; else if (di > si) bytes >>= (di - si) * f->bpp; s->bitmap[(y * dbpr) + (col >> 3)] |= bytes; } } } g->bbx.width = s->width; /* * Swap the bytes and bitmap fields from the scratch area and the glyph. */ bytes = g->bytes; g->bytes = s->bytes; s->bytes = bytes; bmap = g->bitmap; g->bitmap = s->bitmap; s->bitmap = bmap; } int bdf_embolden_glyphs(bdf_font_t *font, int start, int end, bdf_callback_t callback, void *data, int unencoded, int *resize) { int mod, gmod, bpr; short x, y; unsigned short si, di, b1, b2, col; unsigned char *masks; bdf_glyph_t *gp, *sp, *ep; bdf_bitmap_t scratch; bdf_callback_struct_t cb; if (font == 0 || (unencoded && font->unencoded_used == 0) || font->glyphs_used == 0) return 0; /* * Initialize the scratch bitmap which may be needed. */ (void) memset((char *) &scratch, 0, sizeof(bdf_bitmap_t)); mod = 0; gp = 0; masks = 0; switch (font->bpp) { case 1: masks = bdf_onebpp; break; case 2: masks = bdf_twobpp; break; case 4: masks = bdf_fourbpp; break; case 8: masks = bdf_eightbpp; break; } /* * Call the progress initialization callback. */ if (callback != 0) { cb.reason = BDF_EMBOLDEN_START; cb.total = (end - start) + 1; cb.current = 0; (*callback)(&cb, data); } /* * Initialize the resize flag for the caller. */ *resize = 0; sp = _bdf_locate_glyph(font, start, unencoded); ep = _bdf_locate_glyph(font, end, unencoded); for (; sp <= ep; sp++) { /* * Call the callback if one was provided. */ if (sp != gp && callback != 0) { cb.reason = BDF_EMBOLDENING; cb.current = (sp->encoding - start) + 1; (*callback)(&cb, data); } if (font->spacing == BDF_PROPORTIONAL || (font->spacing == BDF_MONOWIDTH && sp->bbx.width < font->bbx.width)) { /* * Only widen the glyph if it is within reason. */ _bdf_widen_by(font, sp, &scratch, 1); if (sp->bbx.width > font->bbx.width) { /* * Bump the font width up by the difference. */ font->bbx.width += sp->bbx.width - font->bbx.width; *resize = 1; } } gmod = 0; bpr = ((sp->bbx.width * font->bpp) + 7) >> 3; for (y = 0; y < sp->bbx.height; y++) { col = (sp->bbx.width - 1) * font->bpp; for (x = sp->bbx.width - 1; x > 0; x--, col -= font->bpp) { si = (col & 7) / font->bpp; di = ((col - font->bpp) & 7) / font->bpp; b1 = (x == sp->bbx.width) ? 0 : sp->bitmap[(y * bpr) + (col >> 3)] & masks[si]; b2 = sp->bitmap[(y * bpr) + ((col - font->bpp) >> 3)] & masks[di]; if (!b1 && b2) { if (di < si) b2 >>= (si - di) * font->bpp; else if (di > si) b2 <<= (di - si) * font->bpp; sp->bitmap[(y * bpr) + (col >> 3)] |= b2; gmod = mod = 1; } } } /* * Mark the glyph as modified. */ if (gmod) { if (unencoded) _bdf_set_glyph_modified(font->umod, sp->encoding); else _bdf_set_glyph_modified(font->nmod, sp->encoding); } } /* * Call the callback one more time to make sure the client knows * this is done. */ if (callback != 0 && cb.current < cb.total) { cb.reason = BDF_EMBOLDENING; cb.current = cb.total; (*callback)(&cb, data); } /* * Deallocate the scratch bitmap if necessary. */ if (scratch.bytes > 0) free((char *) scratch.bitmap); font->modified = mod; return mod; } static int _endian = 1; static char *little_endian = (char *) &_endian; int bdf_little_endian(void) { return *little_endian; }