]> git.karo-electronics.de Git - gbdfed.git/blob - bdf.c
Initial import of upstream V1.6 from
[gbdfed.git] / bdf.c
1 /*
2  * Copyright 2008 Department of Mathematical Sciences, New Mexico State University
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * DEPARTMENT OF MATHEMATICAL SCIENCES OR NEW MEXICO STATE UNIVERSITY BE
18  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 #include "bdfP.h"
23
24 #ifdef HAVE_HBF
25 #include "hbf.h"
26 #endif
27
28 #undef MAX
29 #define MAX(h, i) ((h) > (i) ? (h) : (i))
30
31 #undef MIN
32 #define MIN(l, o) ((l) < (o) ? (l) : (o))
33
34 /**************************************************************************
35  *
36  * Masks used for checking different bits per pixel cases.
37  *
38  **************************************************************************/
39
40 unsigned char bdf_onebpp[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
41 unsigned char bdf_twobpp[] = { 0xc0, 0x30, 0x0c, 0x03 };
42 unsigned char bdf_fourbpp[] = { 0xf0, 0x0f };
43 unsigned char bdf_eightbpp[] = { 0xff };
44
45 /**************************************************************************
46  *
47  * Default BDF font options.
48  *
49  **************************************************************************/
50
51 static bdf_options_t _bdf_opts = {
52 #ifdef HAVE_FREETYPE
53     FT_LOAD_DEFAULT,     /* OTF flags - hinting on.        */
54 #else
55     0,                   /* OTF flags                      */
56 #endif /* HAVE_FREETYPE */
57     1,                   /* Correct metrics.               */
58     1,                   /* Preserve unencoded glyphs.     */
59     1,                   /* Preserve comments.             */
60     1,                   /* Pad character-cells.           */
61     BDF_PROPORTIONAL,    /* Default spacing.               */
62     12,                  /* Default point size.            */
63     0,                   /* Default horizontal resolution. */
64     0,                   /* Default vertical resolution.   */
65     1,                   /* Bits per pixel.                */
66     BDF_UNIX_EOL,        /* Line separator.                */
67     BDF_PSF_ALL,         /* PSF font export options.       */
68     0,                   /* An X cursor font.              */
69 };
70
71 /**************************************************************************
72  *
73  * Builtin BDF font properties.
74  *
75  **************************************************************************/
76
77 /*
78  * List of most properties that might appear in a font.  Doesn't include the
79  * AXIS_* properties in X11R6 polymorphic fonts.
80  */
81 static bdf_property_t _bdf_properties[] = {
82     {"ADD_STYLE_NAME",          BDF_ATOM,     1},
83     {"AVERAGE_WIDTH",           BDF_INTEGER,  1},
84     {"AVG_CAPITAL_WIDTH",       BDF_INTEGER,  1},
85     {"AVG_LOWERCASE_WIDTH",     BDF_INTEGER,  1},
86     {"CAP_HEIGHT",              BDF_INTEGER,  1},
87     {"CHARSET_COLLECTIONS",     BDF_ATOM,     1},
88     {"CHARSET_ENCODING",        BDF_ATOM,     1},
89     {"CHARSET_REGISTRY",        BDF_ATOM,     1},
90     {"COMMENT",                 BDF_ATOM,     1},
91     {"COPYRIGHT",               BDF_ATOM,     1},
92     {"DEFAULT_CHAR",            BDF_CARDINAL, 1},
93     {"DESTINATION",             BDF_CARDINAL, 1},
94     {"DEVICE_FONT_NAME",        BDF_ATOM,     1},
95     {"END_SPACE",               BDF_INTEGER,  1},
96     {"FACE_NAME",               BDF_ATOM,     1},
97     {"FAMILY_NAME",             BDF_ATOM,     1},
98     {"FIGURE_WIDTH",            BDF_INTEGER,  1},
99     {"FONT",                    BDF_ATOM,     1},
100     {"FONTNAME_REGISTRY",       BDF_ATOM,     1},
101     {"FONT_ASCENT",             BDF_INTEGER,  1},
102     {"FONT_DESCENT",            BDF_INTEGER,  1},
103     {"FOUNDRY",                 BDF_ATOM,     1},
104     {"FULL_NAME",               BDF_ATOM,     1},
105     {"ITALIC_ANGLE",            BDF_INTEGER,  1},
106     {"MAX_SPACE",               BDF_INTEGER,  1},
107     {"MIN_SPACE",               BDF_INTEGER,  1},
108     {"NORM_SPACE",              BDF_INTEGER,  1},
109     {"NOTICE",                  BDF_ATOM,     1},
110     {"PIXEL_SIZE",              BDF_INTEGER,  1},
111     {"POINT_SIZE",              BDF_INTEGER,  1},
112     {"QUAD_WIDTH",              BDF_INTEGER,  1},
113     {"RAW_ASCENT",              BDF_INTEGER,  1},
114     {"RAW_AVERAGE_WIDTH",       BDF_INTEGER,  1},
115     {"RAW_AVG_CAPITAL_WIDTH",   BDF_INTEGER,  1},
116     {"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER,  1},
117     {"RAW_CAP_HEIGHT",          BDF_INTEGER,  1},
118     {"RAW_DESCENT",             BDF_INTEGER,  1},
119     {"RAW_END_SPACE",           BDF_INTEGER,  1},
120     {"RAW_FIGURE_WIDTH",        BDF_INTEGER,  1},
121     {"RAW_MAX_SPACE",           BDF_INTEGER,  1},
122     {"RAW_MIN_SPACE",           BDF_INTEGER,  1},
123     {"RAW_NORM_SPACE",          BDF_INTEGER,  1},
124     {"RAW_PIXEL_SIZE",          BDF_INTEGER,  1},
125     {"RAW_POINT_SIZE",          BDF_INTEGER,  1},
126     {"RAW_PIXELSIZE",           BDF_INTEGER,  1},
127     {"RAW_POINTSIZE",           BDF_INTEGER,  1},
128     {"RAW_QUAD_WIDTH",          BDF_INTEGER,  1},
129     {"RAW_SMALL_CAP_SIZE",      BDF_INTEGER,  1},
130     {"RAW_STRIKEOUT_ASCENT",    BDF_INTEGER,  1},
131     {"RAW_STRIKEOUT_DESCENT",   BDF_INTEGER,  1},
132     {"RAW_SUBSCRIPT_SIZE",      BDF_INTEGER,  1},
133     {"RAW_SUBSCRIPT_X",         BDF_INTEGER,  1},
134     {"RAW_SUBSCRIPT_Y",         BDF_INTEGER,  1},
135     {"RAW_SUPERSCRIPT_SIZE",    BDF_INTEGER,  1},
136     {"RAW_SUPERSCRIPT_X",       BDF_INTEGER,  1},
137     {"RAW_SUPERSCRIPT_Y",       BDF_INTEGER,  1},
138     {"RAW_UNDERLINE_POSITION",  BDF_INTEGER,  1},
139     {"RAW_UNDERLINE_THICKNESS", BDF_INTEGER,  1},
140     {"RAW_X_HEIGHT",            BDF_INTEGER,  1},
141     {"RELATIVE_SETWIDTH",       BDF_CARDINAL, 1},
142     {"RELATIVE_WEIGHT",         BDF_CARDINAL, 1},
143     {"RESOLUTION",              BDF_INTEGER,  1},
144     {"RESOLUTION_X",            BDF_CARDINAL, 1},
145     {"RESOLUTION_Y",            BDF_CARDINAL, 1},
146     {"SETWIDTH_NAME",           BDF_ATOM,     1},
147     {"SLANT",                   BDF_ATOM,     1},
148     {"SMALL_CAP_SIZE",          BDF_INTEGER,  1},
149     {"SPACING",                 BDF_ATOM,     1},
150     {"STRIKEOUT_ASCENT",        BDF_INTEGER,  1},
151     {"STRIKEOUT_DESCENT",       BDF_INTEGER,  1},
152     {"SUBSCRIPT_SIZE",          BDF_INTEGER,  1},
153     {"SUBSCRIPT_X",             BDF_INTEGER,  1},
154     {"SUBSCRIPT_Y",             BDF_INTEGER,  1},
155     {"SUPERSCRIPT_SIZE",        BDF_INTEGER,  1},
156     {"SUPERSCRIPT_X",           BDF_INTEGER,  1},
157     {"SUPERSCRIPT_Y",           BDF_INTEGER,  1},
158     {"UNDERLINE_POSITION",      BDF_INTEGER,  1},
159     {"UNDERLINE_THICKNESS",     BDF_INTEGER,  1},
160     {"WEIGHT",                  BDF_CARDINAL, 1},
161     {"WEIGHT_NAME",             BDF_ATOM,     1},
162     {"X_HEIGHT",                BDF_INTEGER,  1},
163     {"_MULE_BASELINE_OFFSET",   BDF_INTEGER,  1},
164     {"_MULE_RELATIVE_COMPOSE",  BDF_INTEGER,  1},
165     /*
166      * Throw this in to make it clear.
167      */
168     {"_XMBDFED_INFO",           BDF_ATOM,     1},
169 };
170
171 static unsigned int _num_bdf_properties =
172 sizeof(_bdf_properties) / sizeof(_bdf_properties[0]);
173
174 /*
175  * User defined properties.
176  */
177 static bdf_property_t *user_props;
178 static unsigned int nuser_props = 0;
179
180 /**************************************************************************
181  *
182  * Hash table utilities for the properties.
183  *
184  **************************************************************************/
185
186 #define INITIAL_HT_SIZE 241
187
188 typedef struct {
189     char *key;
190     void *data;
191 } _hashnode, *hashnode;
192
193 typedef struct {
194     int limit;
195     int size;
196     int used;
197     hashnode *table;
198 } hashtable;
199
200 typedef void (*hash_free_func)(hashnode node);
201
202 static hashnode *
203 hash_bucket(char *key, hashtable *ht)
204 {
205     char *kp = key;
206     unsigned int res = 0;
207     hashnode *bp = ht->table, *ndp;
208
209     /*
210      * Mocklisp hash function.
211      */
212     while (*kp)
213       res = (res << 5) - res + *kp++;
214
215     ndp = bp + (res % ht->size);
216     while (*ndp) {
217         kp = (*ndp)->key;
218         if (kp[0] == key[0] && strcmp(kp, key) == 0)
219           break;
220         ndp--;
221         if (ndp < bp)
222           ndp = bp + (ht->size - 1);
223     }
224     return ndp;
225 }
226
227 static void
228 hash_rehash(hashtable *ht)
229 {
230     hashnode *obp = ht->table, *bp, *nbp;
231     int i, sz = ht->size;
232
233     ht->size <<= 1;
234     ht->limit = ht->size / 3;
235     ht->table = (hashnode *) malloc(sizeof(hashnode) * ht->size);
236     (void) memset((char *) ht->table, 0, sizeof(hashnode) * ht->size);
237
238     for (i = 0, bp = obp; i < sz; i++, bp++) {
239         if (*bp) {
240             nbp = hash_bucket((*bp)->key, ht);
241             *nbp = *bp;
242         }
243     }
244     free((char *) obp);
245 }
246
247 static void
248 hash_init(hashtable *ht)
249 {
250     int sz = INITIAL_HT_SIZE;
251
252     ht->size = sz;
253     ht->limit = sz / 3;
254     ht->used = 0;
255     ht->table = (hashnode *) malloc(sizeof(hashnode) * sz);
256     (void) memset((char *) ht->table, 0, sizeof(hashnode) * sz);
257 }
258
259 static void
260 hash_free(hashtable *ht)
261 {
262     int i, sz = ht->size;
263     hashnode *bp = ht->table;
264
265     for (i = 0; i < sz; i++, bp++) {
266         if (*bp)
267           free((char *) *bp);
268     }
269     if (sz > 0)
270       free((char *) ht->table);
271 }
272
273 static void
274 hash_insert(char *key, void *data, hashtable *ht)
275 {
276     hashnode nn, *bp = hash_bucket(key, ht);
277
278     nn = *bp;
279     if (!nn) {
280         *bp = nn = (hashnode) malloc(sizeof(_hashnode));
281         nn->key = key;
282         nn->data = data;
283
284         if (ht->used >= ht->limit)
285           hash_rehash(ht);
286         ht->used++;
287     } else
288       nn->data = data;
289 }
290
291 static hashnode
292 hash_lookup(char *key, hashtable *ht)
293 {
294     hashnode *np = hash_bucket(key, ht);
295     return *np;
296 }
297
298 static void
299 hash_delete(char *name, hashtable *ht)
300 {
301     hashnode *hp;
302
303     hp = hash_bucket(name, ht);
304     if (*hp) {
305         free((char *) *hp);
306         *hp = 0;
307     }
308 }
309
310 /*
311  * The builtin property table.
312  */
313 static hashtable proptbl;
314
315 /**************************************************************************
316  *
317  * Utility types and functions.
318  *
319  **************************************************************************/
320
321 /*
322  * Function type for parsing lines of a BDF font.
323  */
324 typedef int (*_bdf_line_func_t)(
325     char *line,
326     unsigned int linelen,
327     unsigned int lineno,
328     void *call_data,
329     void *client_data
330 );
331
332 /*
333  * List structure for splitting lines into fields.
334  */
335 typedef struct {
336     char **field;
337     unsigned int size;
338     unsigned int used;
339     char *bfield;
340     unsigned int bsize;
341     unsigned int bused;
342 } _bdf_list_t;
343
344 /*
345  * Structure used while loading BDF fonts.
346  */
347 typedef struct {
348     unsigned int flags;
349     unsigned int cnt;
350     unsigned int row;
351     unsigned int bpr;
352     short minlb;
353     short maxlb;
354     short maxrb;
355     short maxas;
356     short maxds;
357     short rbearing;
358     char *glyph_name;
359     int glyph_enc;
360     bdf_font_t *font;
361     bdf_options_t *opts;
362     void *client_data;
363     bdf_callback_t callback;
364     bdf_callback_struct_t cb;
365     unsigned int have[2048];
366     _bdf_list_t list;
367 } _bdf_parse_t;
368
369 #define setsbit(m, cc) (m[(cc) >> 3] |= (1 << ((cc) & 7)))
370 #define sbitset(m, cc) (m[(cc) >> 3] & (1 << ((cc) & 7)))
371
372 /*
373  * An empty string for empty fields.
374  */
375 static char empty[1] = { 0 };
376
377 /*
378  * Assume the line is NULL terminated and that the `list' parameter was
379  * initialized the first time it was used.
380  */
381 static void
382 _bdf_split(char *separators, char *line, unsigned int linelen,
383            _bdf_list_t *list)
384 {
385     int mult, final_empty;
386     char *sp, *ep, *end;
387     unsigned char seps[32];
388
389     /*
390      * Initialize the list.
391      */
392     list->used = list->bused = 0;
393
394     /*
395      * If the line is empty, then simply return.
396      */
397     if (linelen == 0 || line[0] == 0)
398       return;
399
400     /*
401      * If the `separators' parameter is NULL or empty, split the list into
402      * individual bytes.
403      */
404     if (separators == 0 || *separators == 0) {
405         if (linelen > list->bsize) {
406             if (list->bsize)
407               list->bfield = (char *) malloc(linelen);
408             else
409               list->bfield = (char *) realloc(list->bfield, linelen);
410             list->bsize = linelen;
411         }
412         list->bused = linelen;
413         (void) memcpy(list->bfield, line, linelen);
414         return;
415     }
416
417     /*
418      * Prepare the separator bitmap.
419      */
420     (void) memset((char *) seps, 0, 32);
421
422     /*
423      * If the very last character of the separator string is a plus, then set
424      * the `mult' flag to indicate that multiple separators should be
425      * collapsed into one.
426      */
427     for (mult = 0, sp = separators; sp && *sp; sp++) {
428         if (*sp == '+' && *(sp + 1) == 0)
429           mult = 1;
430         else
431           setsbit(seps, *sp);
432     }
433
434     /*
435      * Break the line up into fields.
436      */
437     for (final_empty = 0, sp = ep = line, end = sp + linelen;
438          sp < end && *sp;) {
439         /*
440          * Collect everything that is not a separator.
441          */
442         for (; *ep && !sbitset(seps, *ep); ep++) ;
443
444         /*
445          * Resize the list if necessary.
446          */
447         if (list->used == list->size) {
448             if (list->size == 0)
449               list->field = (char **) malloc(sizeof(char *) * 5);
450             else
451               list->field = (char **)
452                   realloc((char *) list->field,
453                           sizeof(char *) * (list->size + 5));
454
455             list->size += 5;
456         }
457
458         /*
459          * Assign the field appropriately.
460          */
461         list->field[list->used++] = (ep > sp) ? sp : empty;
462
463         sp = ep;
464         if (mult) {
465             /*
466              * If multiple separators should be collapsed, do it now by
467              * setting all the separator characters to 0.
468              */
469             for (; *ep && sbitset(seps, *ep); ep++)
470               *ep = 0;
471         } else if (*ep != 0)
472           /*
473            * Don't collapse multiple separators by making them 0, so just
474            * make the one encountered 0.
475            */
476           *ep++ = 0;
477         final_empty = (ep > sp && *ep == 0);
478         sp = ep;
479     }
480
481     /*
482      * Finally, NULL terminate the list.
483      */
484     if (list->used + final_empty + 1 >= list->size) {
485         if (list->used == list->size) {
486             if (list->size == 0)
487               list->field = (char **) malloc(sizeof(char *) * 5);
488             else
489               list->field = (char **)
490                   realloc((char *) list->field,
491                           sizeof(char *) * (list->size + 5));
492             list->size += 5;
493         }
494     }
495     if (final_empty)
496       list->field[list->used++] = empty;
497
498     if (list->used == list->size) {
499         if (list->size == 0)
500           list->field = (char **) malloc(sizeof(char *) * 5);
501         else
502           list->field = (char **)
503               realloc((char *) list->field,
504                       sizeof(char *) * (list->size + 5));
505         list->size += 5;
506     }
507     list->field[list->used] = 0;
508 }
509
510 static void
511 _bdf_shift(unsigned int n, _bdf_list_t *list)
512 {
513     unsigned int i, u;
514
515     if (list == 0 || list->used == 0 || n == 0)
516       return;
517
518     if (n >= list->used) {
519         list->used = 0;
520         return;
521     }
522     for (u = n, i = 0; u < list->used; i++, u++)
523       list->field[i] = list->field[u];
524     list->used -= n;
525 }
526
527 static char *
528 _bdf_join(int c, unsigned int *len, _bdf_list_t *list)
529 {
530     unsigned int i, j;
531     char *fp, *dp;
532
533     if (list == 0 || list->used == 0)
534       return 0;
535
536     *len = 0;
537
538     dp = list->field[0];
539     for (i = j = 0; i < list->used; i++) {
540         fp = list->field[i];
541         while (*fp)
542           dp[j++] = *fp++;
543         if (i + 1 < list->used)
544           dp[j++] = c;
545     }
546     dp[j] = 0;
547
548     *len = j;
549     return dp;
550 }
551
552 /*
553  * High speed file reader that passes each line to a callback.
554  */
555 static int
556 _bdf_readlines(int fd, _bdf_line_func_t callback, void *client_data,
557                unsigned int *lno)
558 {
559     _bdf_line_func_t cb;
560     unsigned int lineno;
561     int n, res, done, refill, bytes, hold;
562     char *ls, *le, *pp, *pe, *hp;
563     char buf[65536];
564
565     if (callback == 0)
566       return -1;
567
568     cb = callback;
569     lineno = 1;
570     buf[0] = 0;
571     res = done = 0;
572     pp = ls = le = buf;
573     bytes = 65536;
574     while (!done && (n = read(fd, pp, bytes)) > 0) {
575         /*
576          * Determine the new end of the buffer pages.
577          */
578         pe = pp + n;
579
580         for (refill = 0; done == 0 && refill == 0; ) {
581             while (le < pe && *le != '\n' && *le != '\r')
582               le++;
583
584             if (le == pe) {
585                 /*
586                  * Hit the end of the last page in the buffer.  Need to find
587                  * out how many pages to shift and how many pages need to be
588                  * read in.  Adjust the line start and end pointers down to
589                  * point to the right places in the pages.
590                  */
591                 pp = buf + (((ls - buf) >> 13) << 13);
592                 n = pp - buf;
593                 ls -= n;
594                 le -= n;
595                 n = pe - pp;
596                 memmove(buf, pp, n);
597 #if 0
598                 memcpy(buf, pp, n);
599 #endif
600                 pp = buf + n;
601                 bytes = 65536 - n;
602                 refill = 1;
603             } else {
604                 /*
605                  * Temporarily NULL terminate the line.
606                  */
607                 hp = le;
608                 hold = *le;
609                 *le = 0;
610
611                 if (callback && *ls != '#' && *ls != 0x1a && le > ls &&
612                     (res = (*cb)(ls, le - ls, lineno, (void *) &cb,
613                                  client_data)) != 0)
614                   done = 1;
615                 else {
616                     ls = ++le;
617                     /*
618                      * Handle the case of DOS crlf sequences.
619                      */
620                     if (le < pe && hold == '\n' && *le =='\r')
621                       ls = ++le;
622                 }
623
624                 /*
625                  * Increment the line number.
626                  */
627                 lineno++;
628
629                 /*
630                  * Restore the character at the end of the line.
631                  */
632                 *hp = hold;
633             }
634         }
635     }
636     *lno = lineno;
637     return res;
638 }
639
640 unsigned char *
641 _bdf_strdup(unsigned char *s, unsigned int len)
642 {
643     unsigned char *ns;
644
645     if (s == 0 || len == 0)
646       return 0;
647
648     ns = (unsigned char *) malloc(len);
649     (void) memcpy((char *) ns, (char *) s, len);
650     return ns;
651 }
652
653 void
654 _bdf_memmove(char *dest, char *src, unsigned int bytes)
655 {
656     int i, j;
657
658     i = (int) bytes;
659     j = i & 7;
660     i = (i + 7) >> 3;
661
662     /*
663      * Do a memmove using Ye Olde Duff's Device for efficiency.
664      */
665     if (src < dest) {
666         src += bytes;
667         dest += bytes;
668
669         switch (j) {
670           case 0: do {
671               *--dest = *--src;
672             case 7: *--dest = *--src;
673             case 6: *--dest = *--src;
674             case 5: *--dest = *--src;
675             case 4: *--dest = *--src;
676             case 3: *--dest = *--src;
677             case 2: *--dest = *--src;
678             case 1: *--dest = *--src;
679           } while (--i > 0);
680         }
681     } else if (src > dest) {
682         switch (j) {
683           case 0: do {
684               *dest++ = *src++;
685             case 7: *dest++ = *src++;
686             case 6: *dest++ = *src++;
687             case 5: *dest++ = *src++;
688             case 4: *dest++ = *src++;
689             case 3: *dest++ = *src++;
690             case 2: *dest++ = *src++;
691             case 1: *dest++ = *src++;
692           } while (--i > 0);
693         }
694     }
695 }
696
697 static unsigned char a2i[128] = {
698     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
699     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
700     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
701     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
702     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
703     0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
704     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
705     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
706     0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
707     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
708     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
709 };
710
711 static unsigned char odigits[32] = {
712     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
713     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
714     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
715     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
716 };
717
718 static unsigned char ddigits[32] = {
719     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
720     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
721     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
722     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
723 };
724
725 static unsigned char hdigits[32] = {
726     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
727     0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
728     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
729     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
730 };
731
732 #define isdigok(m, d) (m[(d) >> 3] & (1 << ((d) & 7)))
733
734 /*
735  * Routine to convert an ASCII string into an unsigned int integer.
736  */
737 unsigned int
738 _bdf_atoul(char *s, char **end, int base)
739 {
740     unsigned int v;
741     unsigned char *dmap;
742
743     if (s == 0 || *s == 0)
744       return 0;
745
746     /*
747      * Make sure the radix is something recognizable.  Default to 10.
748      */
749     switch (base) {
750       case 8: dmap = odigits; break;
751       case 16: dmap = hdigits; break;
752       default: base = 10; dmap = ddigits; break;
753     }
754
755     /*
756      * Check for the special hex prefixes of 0[xX] or [Uu][+-].
757      */
758     if ((*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) ||
759         ((*s == 'U' || *s == 'u') && (*(s + 1) == '+' || *(s + 1) == '-'))) {
760         base = 16;
761         dmap = hdigits;
762         s += 2;
763     }
764
765     for (v = 0; isdigok(dmap, *s); s++)
766       v = (v * base) + a2i[(int) *s];
767
768     if (end != 0)
769       *end = s;
770
771     return v;
772 }
773
774 /*
775  * Routine to convert an ASCII string into an signed int integer.
776  */
777 int
778 _bdf_atol(char *s, char **end, int base)
779 {
780     int v, neg;
781     unsigned char *dmap;
782
783     if (s == 0 || *s == 0)
784       return 0;
785
786     /*
787      * Make sure the radix is something recognizable.  Default to 10.
788      */
789     switch (base) {
790       case 8: dmap = odigits; break;
791       case 16: dmap = hdigits; break;
792       default: base = 10; dmap = ddigits; break;
793     }
794
795     /*
796      * Check for a minus sign.
797      */
798     neg = 0;
799     if (*s == '-') {
800         s++;
801         neg = 1;
802     }
803
804     /*
805      * Check for the special hex prefix.
806      */
807     if ((*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) ||
808         ((*s == 'U' || *s == 'u') && (*(s + 1) == '+' || *(s + 1) == '-'))) {
809         base = 16;
810         dmap = hdigits;
811         s += 2;
812     }
813
814     for (v = 0; isdigok(dmap, *s); s++)
815       v = (v * base) + a2i[(int) *s];
816
817     if (end != 0)
818       *end = s;
819
820     return (!neg) ? v : -v;
821 }
822
823 /*
824  * Routine to convert an ASCII string into an signed short integer.
825  */
826 short
827 _bdf_atos(char *s, char **end, int base)
828 {
829     short v, neg;
830     unsigned char *dmap;
831
832     if (s == 0 || *s == 0)
833       return 0;
834
835     /*
836      * Make sure the radix is something recognizable.  Default to 10.
837      */
838     switch (base) {
839       case 8: dmap = odigits; break;
840       case 16: dmap = hdigits; break;
841       default: base = 10; dmap = ddigits; break;
842     }
843
844     /*
845      * Check for a minus.
846      */
847     neg = 0;
848     if (*s == '-') {
849         s++;
850         neg = 1;
851     }
852
853     /*
854      * Check for the special hex prefix.
855      */
856     if (*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) {
857         base = 16;
858         dmap = hdigits;
859         s += 2;
860     }
861
862     for (v = 0; isdigok(dmap, *s); s++)
863       v = (v * base) + a2i[(int) *s];
864
865     if (end != 0)
866       *end = s;
867
868     return (!neg) ? v : -v;
869 }
870
871 /*
872  * Routine to compare two glyphs by encoding so they can be sorted.
873  */
874 static int
875 by_encoding(const void *a, const void *b)
876 {
877     bdf_glyph_t *c1, *c2;
878
879     c1 = (bdf_glyph_t *) a;
880     c2 = (bdf_glyph_t *) b;
881     if (c1->encoding < c2->encoding)
882       return -1;
883     else if (c1->encoding > c2->encoding)
884       return 1;
885     return 0;
886 }
887
888 /**************************************************************************
889  *
890  * BDF font file parsing flags and functions.
891  *
892  **************************************************************************/
893
894 /*
895  * Parse flags.
896  */
897 #define _BDF_START     0x0001
898 #define _BDF_FONT_NAME 0x0002
899 #define _BDF_SIZE      0x0004
900 #define _BDF_FONT_BBX  0x0008
901 #define _BDF_PROPS     0x0010
902 #define _BDF_GLYPHS    0x0020
903 #define _BDF_GLYPH     0x0040
904 #define _BDF_ENCODING  0x0080
905 #define _BDF_SWIDTH    0x0100
906 #define _BDF_DWIDTH    0x0200
907 #define _BDF_BBX       0x0400
908 #define _BDF_BITMAP    0x0800
909
910 #define _BDF_SWIDTH_ADJ 0x1000
911
912 #define _BDF_GLYPH_BITS (_BDF_GLYPH|_BDF_ENCODING|_BDF_SWIDTH|\
913                          _BDF_DWIDTH|_BDF_BBX|_BDF_BITMAP)
914
915 #define _BDF_GLYPH_WIDTH_CHECK 0x40000000
916 #define _BDF_GLYPH_HEIGHT_CHECK 0x80000000
917
918 /*
919  * Auto correction messages.
920  */
921 #define ACMSG1 "FONT_ASCENT property missing.  Added \"FONT_ASCENT %hd\"."
922 #define ACMSG2 "FONT_DESCENT property missing.  Added \"FONT_DESCENT %hd\"."
923 #define ACMSG3 "Font width != actual width.  Old: %hd New: %hd."
924 #define ACMSG4 "Font left bearing != actual left bearing.  Old: %hd New: %hd."
925 #define ACMSG5 "Font ascent != actual ascent.  Old: %hd New: %hd."
926 #define ACMSG6 "Font descent != actual descent.  Old: %hd New: %hd."
927 #define ACMSG7 "Font height != actual height. Old: %hd New: %hd."
928 #define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made."
929 #define ACMSG9 "SWIDTH field missing at line %d.  Set automatically."
930 #define ACMSG10 "DWIDTH field missing at line %d.  Set to glyph width."
931 #define ACMSG11 "SIZE bits per pixel field adjusted to %hd."
932 #define ACMSG12 "Duplicate encoding %d (%s) changed to unencoded."
933 #define ACMSG13 "Glyph %d extra rows removed."
934 #define ACMSG14 "Glyph %d extra columns removed."
935 #define ACMSG15 "Incorrect glyph count: %d indicated but %d found."
936
937 /*
938  * Error messages.
939  */
940 #define ERRMSG1 "[line %d] Missing \"%s\" line."
941 #define ERRMSG2 "[line %d] Font header corrupted or missing fields."
942 #define ERRMSG3 "[line %d] Font glyphs corrupted or missing fields."
943
944 void
945 _bdf_add_acmsg(bdf_font_t *font, char *msg, unsigned int len)
946 {
947     char *cp;
948
949     if (font->acmsgs_len == 0)
950       font->acmsgs = (char *) malloc(len + 2);
951     else
952       font->acmsgs = (char *) realloc(font->acmsgs,
953                                       font->acmsgs_len + len + 2);
954
955     cp = font->acmsgs + font->acmsgs_len;
956     (void) memcpy(cp, msg, len);
957     cp += len;
958     *cp++ = '\n';
959     *cp = 0;
960     font->acmsgs_len += len + 1;
961 }
962
963 void
964 _bdf_add_comment(bdf_font_t *font, char *comment, unsigned int len)
965 {
966     char *cp;
967
968     if (font->comments_len == 0)
969       font->comments = (char *) malloc(len + 2);
970     else
971       font->comments = (char *) realloc(font->comments,
972                                         font->comments_len + len + 2);
973
974     cp = font->comments + font->comments_len;
975     (void) memcpy(cp, comment, len);
976     cp += len;
977     *cp++ = '\n';
978     *cp = 0;
979     font->comments_len += len + 1;
980 }
981
982 /*
983  * Set the spacing from the font name if it exists, or set it to the default
984  * specified in the options.
985  */
986 static void
987 _bdf_set_default_spacing(bdf_font_t *font, bdf_options_t *opts)
988 {
989     unsigned int len;
990     char name[128];
991     _bdf_list_t list;
992
993     if (font == 0 || font->name == 0 || font->name[0] == 0)
994       return;
995
996     font->spacing = opts->font_spacing;
997
998     len = (unsigned int) (strlen(font->name) + 1);
999     (void) memcpy(name, font->name, len);
1000     list.size = list.used = 0;
1001     _bdf_split("-", name, len, &list);
1002     if (list.used == 15) {
1003         switch (list.field[11][0]) {
1004           case 'C': case 'c': font->spacing = BDF_CHARCELL; break;
1005           case 'M': case 'm': font->spacing = BDF_MONOWIDTH; break;
1006           case 'P': case 'p': font->spacing = BDF_PROPORTIONAL; break;
1007         }
1008     }
1009     if (list.size > 0)
1010       free((char *) list.field);
1011 }
1012
1013 /*
1014  * Determine if the property is an atom or not.  If it is, then clean it up so
1015  * the double quotes are removed if they exist.
1016  */
1017 static int
1018 _bdf_is_atom(char *line, unsigned int linelen, char **name, char **value)
1019 {
1020     int hold;
1021     char *sp, *ep;
1022     bdf_property_t *p;
1023
1024     *name = sp = ep = line;
1025     while (*ep && *ep != ' ' && *ep != '\t')
1026       ep++;
1027
1028     hold = -1;
1029     if (*ep) {
1030         hold = *ep;
1031         *ep = 0;
1032     }
1033
1034     p = bdf_get_property(sp);
1035
1036     /*
1037      * Restore the character that was saved before any return can happen.
1038      */
1039     if (hold != -1)
1040       *ep = hold;
1041
1042     /*
1043      * If the propert exists and is not an atom, just return here.
1044      */
1045     if (p && p->format != BDF_ATOM)
1046       return 0;
1047
1048     /*
1049      * The property is an atom.  Trim all leading and trailing whitespace and
1050      * double quotes for the atom value.
1051      */
1052     sp = ep;
1053     ep = line + linelen;
1054
1055     /*
1056      * Trim the leading whitespace if it exists.
1057      */
1058     *sp++ = 0;
1059     while (*sp && (*sp == ' ' || *sp == '\t'))
1060       sp++;
1061
1062     /*
1063      * Trim the leading double quote if it exists.
1064      */
1065     if (*sp == '"')
1066       sp++;
1067     *value = sp;
1068
1069     /*
1070      * Trim the trailing whitespace if it exists.
1071      */
1072     while (ep > sp && (*(ep - 1) == ' ' || *(ep - 1) == '\t'))
1073       *--ep = 0;
1074
1075     /*
1076      * Trim the trailing double quote if it exists.
1077      */
1078     if (ep > sp && *(ep - 1) == '"')
1079       *--ep = 0;
1080
1081     return 1;
1082 }
1083
1084 static void
1085 _bdf_add_property(bdf_font_t *font, char *name, char *value)
1086 {
1087     unsigned int propid;
1088     hashnode hn;
1089     int len;
1090     bdf_property_t *prop, *fp;
1091
1092     /*
1093      * First, check to see if the property already exists in the font.
1094      */
1095     if ((hn = hash_lookup(name, (hashtable *) font->internal)) != 0) {
1096         /*
1097          * The property already exists in the font, so simply replace
1098          * the value of the property with the current value.
1099          */
1100         fp = font->props + (unsigned int) hn->data;
1101
1102         switch (fp->format) {
1103           case BDF_ATOM:
1104             /*
1105              * Delete the current atom if it exists.
1106              */
1107             if (fp->value.atom != 0)
1108               free(fp->value.atom);
1109
1110             if (value == 0)
1111               len = 1;
1112             else
1113               len = strlen(value) + 1;
1114             if (len > 1) {
1115                 fp->value.atom = (char *) malloc(len);
1116                 (void) memcpy(fp->value.atom, value, len);
1117             } else
1118               fp->value.atom = 0;
1119             break;
1120           case BDF_INTEGER:
1121             fp->value.int32 = _bdf_atol(value, 0, 10);
1122             break;
1123           case BDF_CARDINAL:
1124             fp->value.card32 = _bdf_atoul(value, 0, 10);
1125             break;
1126         }
1127         return;
1128     }
1129
1130     /*
1131      * See if this property type exists yet or not.  If not, create it.
1132      */
1133     hn = hash_lookup(name, &proptbl);
1134     if (hn == 0) {
1135         bdf_create_property(name, BDF_ATOM);
1136         hn = hash_lookup(name, &proptbl);
1137     }
1138
1139     /*
1140      * Allocate another property if this is overflow.
1141      */
1142     if (font->props_used == font->props_size) {
1143         if (font->props_size == 0)
1144           font->props = (bdf_property_t *) malloc(sizeof(bdf_property_t));
1145         else
1146           font->props = (bdf_property_t *)
1147               realloc((char *) font->props, sizeof(bdf_property_t) *
1148                       (font->props_size + 1));
1149         fp = font->props + font->props_size;
1150         (void) memset((char *) fp, 0, sizeof(bdf_property_t));
1151         font->props_size++;
1152     }
1153
1154     propid = (unsigned int) hn->data;
1155     if (propid >= _num_bdf_properties)
1156       prop = user_props + (propid - _num_bdf_properties);
1157     else
1158       prop = _bdf_properties + propid;
1159
1160     fp = font->props + font->props_used;
1161
1162     fp->name = prop->name;
1163     fp->format = prop->format;
1164     fp->builtin = prop->builtin;
1165
1166     switch (prop->format) {
1167       case BDF_ATOM:
1168         if (value == 0)
1169           len = 1;
1170         else
1171           len = strlen(value) + 1;
1172         if (len > 1) {
1173             fp->value.atom = (char *) malloc(len);
1174             (void) memcpy(fp->value.atom, value, len);
1175         } else
1176           fp->value.atom = 0;
1177         break;
1178       case BDF_INTEGER:
1179         fp->value.int32 = _bdf_atol(value, 0, 10);
1180         break;
1181       case BDF_CARDINAL:
1182         fp->value.card32 = _bdf_atoul(value, 0, 10);
1183         break;
1184     }
1185
1186     /*
1187      * If the property happens to be a comment, then it doesn't need
1188      * to be added to the internal hash table.
1189      */
1190     if (memcmp(name, "COMMENT", 7) != 0)
1191       /*
1192        * Add the property to the font property table.
1193        */
1194       hash_insert(fp->name, (void *) font->props_used,
1195                   (hashtable *) font->internal);
1196
1197     font->props_used++;
1198
1199     /*
1200      * Some special cases need to be handled here.  The DEFAULT_CHAR property
1201      * needs to be located if it exists in the property list, the FONT_ASCENT
1202      * and FONT_DESCENT need to be assigned if they are present, and the
1203      * SPACING property should override the default spacing.
1204      */
1205     if (memcmp(name, "DEFAULT_CHAR", 12) == 0)
1206       font->default_glyph = fp->value.int32;
1207     else if (memcmp(name, "FONT_ASCENT", 11) == 0)
1208       font->font_ascent = fp->value.int32;
1209     else if (memcmp(name, "FONT_DESCENT", 12) == 0)
1210       font->font_descent = fp->value.int32;
1211     else if (memcmp(name, "SPACING", 7) == 0) {
1212         if (fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P')
1213           font->spacing = BDF_PROPORTIONAL;
1214         else if (fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M')
1215           font->spacing = BDF_MONOWIDTH;
1216         else if (fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C')
1217           font->spacing = BDF_CHARCELL;
1218     }
1219 }
1220
1221 /*
1222  * Actually parse the glyph info and bitmaps.
1223  */
1224 static int
1225 _bdf_parse_glyphs(char *line, unsigned int linelen, unsigned int lineno,
1226                   void *call_data, void *client_data)
1227 {
1228     int c;
1229     char *s;
1230     unsigned char *bp;
1231     unsigned int i, slen = 0, nibbles;
1232     double ps, rx, dw, sw;
1233     _bdf_line_func_t *next;
1234     _bdf_parse_t *p;
1235     bdf_glyph_t *glyph;
1236     bdf_font_t *font;
1237     char nbuf[128];
1238
1239     next = (_bdf_line_func_t *) call_data;
1240     p = (_bdf_parse_t *) client_data;
1241
1242     font = p->font;
1243
1244     /*
1245      * Check for a comment.
1246      */
1247     if (memcmp(line, "COMMENT", 7) == 0) {
1248         linelen -= 7;
1249         s = line + 7;
1250         if (*s != 0) {
1251             s++;
1252             linelen--;
1253         }
1254         _bdf_add_comment(p->font, s, linelen);
1255         return 0;
1256     }
1257
1258     /*
1259      * The very first thing expected is the number of glyphs.
1260      */
1261     if (!(p->flags & _BDF_GLYPHS)) {
1262         if (memcmp(line, "CHARS", 5) != 0) {
1263             sprintf(nbuf, ERRMSG1, lineno, "CHARS");
1264             _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1265             return BDF_MISSING_CHARS;
1266         }
1267         _bdf_split(" +", line, linelen, &p->list);
1268         p->cnt = font->glyphs_size = _bdf_atoul(p->list.field[1], 0, 10);
1269
1270         /*
1271          * Make sure the number of glyphs is non-zero.
1272          */
1273         if (p->cnt == 0)
1274           font->glyphs_size = 64;
1275
1276         font->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) *
1277                                               font->glyphs_size);
1278         /*
1279          * Make sure the glyph structures are initialized.
1280          */
1281         (void) memset((char *) font->glyphs, 0,
1282                       sizeof(bdf_glyph_t) * font->glyphs_size);
1283
1284         /*
1285          * Set up the callback to indicate the glyph loading is about to
1286          * begin.
1287          */
1288         if (p->callback != 0) {
1289             p->cb.reason = BDF_LOAD_START;
1290             p->cb.total = p->cnt;
1291             p->cb.current = 0;
1292             (*p->callback)(&p->cb, p->client_data);
1293         }
1294         p->flags |= _BDF_GLYPHS;
1295         return 0;
1296     }
1297
1298     /*
1299      * Check for the ENDFONT field.
1300      */
1301     if (memcmp(line, "ENDFONT", 7) == 0) {
1302         /*
1303          * Sort the glyphs by encoding.
1304          */
1305         qsort((char *) font->glyphs, font->glyphs_used, sizeof(bdf_glyph_t),
1306               by_encoding);
1307
1308         p->flags &= ~_BDF_START;
1309         return 0;
1310     }
1311
1312     /*
1313      * Check for the ENDCHAR field.
1314      */
1315     if (memcmp(line, "ENDCHAR", 7) == 0) {
1316         /*
1317          * Set up and call the callback if it was passed.
1318          */
1319         if (p->callback != 0) {
1320             p->cb.reason = BDF_LOADING;
1321             p->cb.total = font->glyphs_size;
1322             p->cb.current = font->glyphs_used;
1323             (*p->callback)(&p->cb, p->client_data);
1324         }
1325         p->glyph_enc = 0;
1326         p->flags &= ~_BDF_GLYPH_BITS;
1327         return 0;
1328     }
1329
1330     /*
1331      * Check to see if a glyph is being scanned but should be ignored
1332      * because it is an unencoded glyph.
1333      */
1334     if ((p->flags & _BDF_GLYPH) &&
1335         p->glyph_enc == -1 && p->opts->keep_unencoded == 0)
1336       return 0;
1337
1338     /*
1339      * Check for the STARTCHAR field.
1340      */
1341     if (memcmp(line, "STARTCHAR", 9) == 0) {
1342         /*
1343          * Set the character name in the parse info first until the
1344          * encoding can be checked for an unencoded character.
1345          */
1346         if (p->glyph_name != 0)
1347           free(p->glyph_name);
1348         _bdf_split(" +", line, linelen, &p->list);
1349         _bdf_shift(1, &p->list);
1350         s = _bdf_join(' ', &slen, &p->list);
1351         p->glyph_name = (char *) malloc(slen + 1);
1352         (void) memcpy(p->glyph_name, s, slen + 1);
1353         p->flags |= _BDF_GLYPH;
1354         return 0;
1355     }
1356
1357     /*
1358      * Check for the ENCODING field.
1359      */
1360     if (memcmp(line, "ENCODING", 8) == 0) {
1361         if (!(p->flags & _BDF_GLYPH)) {
1362             /*
1363              * Missing STARTCHAR field.
1364              */
1365             sprintf(nbuf, ERRMSG1, lineno, "STARTCHAR");
1366             _bdf_add_acmsg(font, nbuf, strlen(nbuf));
1367             return BDF_MISSING_STARTCHAR;
1368         }
1369         _bdf_split(" +", line, linelen, &p->list);
1370         p->glyph_enc = _bdf_atol(p->list.field[1], 0, 10);
1371
1372         /*
1373          * Check to see if this encoding has already been encountered.  If it
1374          * has then change it to unencoded so it gets added if indicated.
1375          */
1376         if (p->glyph_enc >= 0) {
1377             if (_bdf_glyph_modified(p->have, p->glyph_enc)) {
1378                 /*
1379                  * Add a message saying a glyph has been moved to the
1380                  * unencoded area.
1381                  */
1382                 sprintf(nbuf, ACMSG12, p->glyph_enc, p->glyph_name);
1383                 _bdf_add_acmsg(font, nbuf, strlen(nbuf));
1384                 p->glyph_enc = -1;
1385                 font->modified = 1;
1386             } else
1387               _bdf_set_glyph_modified(p->have, p->glyph_enc);
1388         }
1389
1390         if (p->glyph_enc >= 0) {
1391             /*
1392              * Make sure there are enough glyphs allocated in case the
1393              * number of characters happen to be wrong.
1394              */
1395             if (font->glyphs_used == font->glyphs_size) {
1396                 font->glyphs = (bdf_glyph_t *)
1397                     realloc((char *) font->glyphs,
1398                             sizeof(bdf_glyph_t) * (font->glyphs_size + 64));
1399                 (void) memset((char *) (font->glyphs + font->glyphs_size),
1400                               0, sizeof(bdf_glyph_t) << 6);
1401                 font->glyphs_size += 64;
1402             }
1403
1404             glyph = font->glyphs + font->glyphs_used++;
1405             glyph->name = p->glyph_name;
1406             glyph->encoding = p->glyph_enc;
1407
1408             /*
1409              * Reset the initial glyph info.
1410              */
1411             p->glyph_name = 0;
1412         } else {
1413             /*
1414              * Unencoded glyph.  Check to see if it should be added or not.
1415              */
1416             if (p->opts->keep_unencoded != 0) {
1417                 /*
1418                  * Allocate the next unencoded glyph.
1419                  */
1420                 if (font->unencoded_used == font->unencoded_size) {
1421                     if (font->unencoded_size == 0)
1422                       font->unencoded = (bdf_glyph_t *)
1423                           malloc(sizeof(bdf_glyph_t) << 2);
1424                     else
1425                       font->unencoded = (bdf_glyph_t *)
1426                           realloc((char *) font->unencoded,
1427                                   sizeof(bdf_glyph_t) *
1428                                   (font->unencoded_size + 4));
1429                     font->unencoded_size += 4;
1430                 }
1431
1432                 glyph = font->unencoded + font->unencoded_used;
1433                 glyph->name = p->glyph_name;
1434                 glyph->encoding = font->unencoded_used++;
1435             } else
1436               /*
1437                * Free up the glyph name if the unencoded shouldn't be
1438                * kept.
1439                */
1440               free(p->glyph_name);
1441
1442             p->glyph_name = 0;
1443         }
1444
1445         /*
1446          * Clear the flags that might be added when width and height are
1447          * checked for consistency.
1448          */
1449         p->flags &= ~(_BDF_GLYPH_WIDTH_CHECK|_BDF_GLYPH_HEIGHT_CHECK);
1450
1451         p->flags |= _BDF_ENCODING;
1452         return 0;
1453     }
1454
1455     /*
1456      * Point at the glyph being constructed.
1457      */
1458     if (p->glyph_enc == -1)
1459       glyph = font->unencoded + (font->unencoded_used - 1);
1460     else
1461       glyph = font->glyphs + (font->glyphs_used - 1);
1462
1463     /*
1464      * Check to see if a bitmap is being constructed.
1465      */
1466     if (p->flags & _BDF_BITMAP) {
1467         /*
1468          * If there are more rows than are specified in the glyph metrics,
1469          * ignore the remaining lines.
1470          */
1471         if (p->row >= glyph->bbx.height) {
1472             if (!(p->flags & _BDF_GLYPH_HEIGHT_CHECK)) {
1473                 sprintf(nbuf, ACMSG13, glyph->encoding);
1474                 _bdf_add_acmsg(font, nbuf, strlen(nbuf));
1475                 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
1476                 font->modified = 1;
1477             }
1478             return 0;
1479         }
1480
1481         /*
1482          * Only collect the number of nibbles indicated by the glyph metrics.
1483          * If there are more columns, they are simply ignored.
1484          */
1485         nibbles = p->bpr << 1;
1486         bp = glyph->bitmap + (p->row * p->bpr);
1487         for (i = 0, *bp = 0; i < nibbles; i++) {
1488             c = line[i];
1489             *bp = (*bp << 4) + a2i[c];
1490             if (i + 1 < nibbles && (i & 1))
1491               *++bp = 0;
1492         }
1493
1494         /*
1495          * If any line has extra columns, indicate they have been removed.
1496          */
1497         if ((line[nibbles] == '0' || a2i[(int) line[nibbles]] != 0) &&
1498             !(p->flags & _BDF_GLYPH_WIDTH_CHECK)) {
1499             sprintf(nbuf, ACMSG14, glyph->encoding);
1500             _bdf_add_acmsg(font, nbuf, strlen(nbuf));
1501             p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1502             font->modified = 1;
1503         }
1504
1505         p->row++;
1506         return 0;
1507     }
1508
1509     /*
1510      * Expect the SWIDTH (scalable width) field next.
1511      */
1512     if (memcmp(line, "SWIDTH", 6) == 0) {
1513         if (!(p->flags & _BDF_ENCODING)) {
1514             /*
1515              * Missing ENCODING field.
1516              */
1517             sprintf(nbuf, ERRMSG1, lineno, "ENCODING");
1518             _bdf_add_acmsg(font, nbuf, strlen(nbuf));
1519             return BDF_MISSING_ENCODING;
1520         }
1521         _bdf_split(" +", line, linelen, &p->list);
1522         glyph->swidth = _bdf_atoul(p->list.field[1], 0, 10);
1523         p->flags |= _BDF_SWIDTH;
1524         return 0;
1525     }
1526
1527     /*
1528      * Expect the DWIDTH (scalable width) field next.
1529      */
1530     if (memcmp(line, "DWIDTH", 6) == 0) {
1531         _bdf_split(" +", line, linelen, &p->list);
1532         glyph->dwidth = _bdf_atoul(p->list.field[1], 0, 10);
1533
1534         if (!(p->flags & _BDF_SWIDTH)) {
1535             /*
1536              * Missing SWIDTH field.  Add an auto correction message and set
1537              * the scalable width from the device width.
1538              */
1539             sprintf(nbuf, ACMSG9, lineno);
1540             _bdf_add_acmsg(font, nbuf, strlen(nbuf));
1541             ps = (double) font->point_size;
1542             rx = (double) font->resolution_x;
1543             dw = (double) glyph->dwidth;
1544             glyph->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
1545         }
1546
1547         p->flags |= _BDF_DWIDTH;
1548         return 0;
1549     }
1550
1551     /*
1552      * Expect the BBX field next.
1553      */
1554     if (memcmp(line, "BBX", 3) == 0) {
1555         _bdf_split(" +", line, linelen, &p->list);
1556         glyph->bbx.width = _bdf_atos(p->list.field[1], 0, 10);
1557         glyph->bbx.height = _bdf_atos(p->list.field[2], 0, 10);
1558         glyph->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10);
1559         glyph->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10);
1560
1561         /*
1562          * Generate the ascent and descent of the character.
1563          */
1564         glyph->bbx.ascent = glyph->bbx.height + glyph->bbx.y_offset;
1565         glyph->bbx.descent = -glyph->bbx.y_offset;
1566
1567         /*
1568          * Determine the overall font bounding box as the characters are
1569          * loaded so corrections can be done later if indicated.
1570          */
1571         p->maxas = MAX(glyph->bbx.ascent, p->maxas);
1572         p->maxds = MAX(glyph->bbx.descent, p->maxds);
1573         p->rbearing = glyph->bbx.width + glyph->bbx.x_offset;
1574         p->maxrb = MAX(p->rbearing, p->maxrb);
1575         p->minlb = MIN(glyph->bbx.x_offset, p->minlb);
1576         p->maxlb = MAX(glyph->bbx.x_offset, p->maxlb);
1577
1578         if (!(p->flags & _BDF_DWIDTH)) {
1579             /*
1580              * Missing DWIDTH field.  Add an auto correction message and set
1581              * the device width to the glyph width.
1582              */
1583             sprintf(nbuf, ACMSG10, lineno);
1584             _bdf_add_acmsg(font, nbuf, strlen(nbuf));
1585             glyph->dwidth = glyph->bbx.width;
1586         }
1587
1588         /*
1589          * If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH
1590          * value if necessary.
1591          */
1592         if (p->opts->correct_metrics != 0) {
1593             /*
1594              * Determine the point size of the glyph.
1595              */
1596             ps = (double) font->point_size;
1597             rx = (double) font->resolution_x;
1598             dw = (double) glyph->dwidth;
1599             sw = (unsigned short) ((dw * 72000.0) / (ps * rx));
1600
1601             if (sw != glyph->swidth) {
1602                 glyph->swidth = sw;
1603                 if (p->glyph_enc == -1)
1604                   _bdf_set_glyph_modified(font->umod,
1605                                           font->unencoded_used - 1);
1606                 else
1607                   _bdf_set_glyph_modified(font->nmod, glyph->encoding);
1608                 p->flags |= _BDF_SWIDTH_ADJ;
1609                 font->modified = 1;
1610             }
1611         }
1612         p->flags |= _BDF_BBX;
1613         return 0;
1614     }
1615
1616     /*
1617      * And finally, gather up the bitmap.
1618      */
1619     if (memcmp(line, "BITMAP", 6) == 0) {
1620         if (!(p->flags & _BDF_BBX)) {
1621             /*
1622              * Missing BBX field.
1623              */
1624             sprintf(nbuf, ERRMSG1, lineno, "BBX");
1625             _bdf_add_acmsg(font, nbuf, strlen(nbuf));
1626             return BDF_MISSING_BBX;
1627         }
1628         /*
1629          * Allocate enough space for the bitmap.
1630          */
1631         p->bpr = ((glyph->bbx.width * p->font->bpp) + 7) >> 3;
1632         glyph->bytes = p->bpr * glyph->bbx.height;
1633         glyph->bitmap = (unsigned char *) malloc(glyph->bytes);
1634         p->row = 0;
1635         p->flags |= _BDF_BITMAP;
1636         return 0;
1637     }
1638
1639     return BDF_INVALID_LINE;
1640 }
1641
1642 /*
1643  * Load the font properties.
1644  */
1645 static int
1646 _bdf_parse_properties(char *line, unsigned int linelen, unsigned int lineno,
1647                       void *call_data, void *client_data)
1648 {
1649     unsigned int vlen;
1650     _bdf_line_func_t *next;
1651     _bdf_parse_t *p;
1652     char *name, *value, nbuf[128];
1653
1654     next = (_bdf_line_func_t *) call_data;
1655     p = (_bdf_parse_t *) client_data;
1656
1657     /*
1658      * Check for the end of the properties.
1659      */
1660     if (memcmp(line, "ENDPROPERTIES", 13) == 0) {
1661         /*
1662          * If the FONT_ASCENT or FONT_DESCENT properties have not been
1663          * encountered yet, then make sure they are added as properties and
1664          * make sure they are set from the font bounding box info.
1665          *
1666          * This is *always* done regardless of the options, because X11
1667          * requires these two fields to compile fonts.
1668          */
1669         if (bdf_get_font_property(p->font, "FONT_ASCENT") == 0) {
1670             p->font->font_ascent = p->font->bbx.ascent;
1671             sprintf(nbuf, "%hd", p->font->bbx.ascent);
1672             _bdf_add_property(p->font, "FONT_ASCENT", nbuf);
1673             sprintf(nbuf, ACMSG1, p->font->bbx.ascent);
1674             _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1675             p->font->modified = 1;
1676         }
1677         if (bdf_get_font_property(p->font, "FONT_DESCENT") == 0) {
1678             p->font->font_descent = p->font->bbx.descent;
1679             sprintf(nbuf, "%hd", p->font->bbx.descent);
1680             _bdf_add_property(p->font, "FONT_DESCENT", nbuf);
1681             sprintf(nbuf, ACMSG2, p->font->bbx.descent);
1682             _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1683             p->font->modified = 1;
1684         }
1685         p->flags &= ~_BDF_PROPS;
1686         *next = _bdf_parse_glyphs;
1687         return 0;
1688     }
1689
1690     /*
1691      * Ignore the _XFREE86_GLYPH_RANGES and _XMBDFED_INFO properties.
1692      */
1693     if (memcmp(line, "_XFREE86_GLYPH_RANGES", 21) == 0 ||
1694         memcmp(line, "_XMBDFED_INFO", 13) == 0)
1695       return 0;
1696
1697     /*
1698      * Handle COMMENT fields and properties in a special way to preserve
1699      * the spacing.
1700      */
1701     if (memcmp(line, "COMMENT", 7) == 0) {
1702         name = value = line;
1703         value += 7;
1704         if (*value)
1705           *value++ = 0;
1706         _bdf_add_property(p->font, name, value);
1707     } else if (_bdf_is_atom(line, linelen, &name, &value))
1708       _bdf_add_property(p->font, name, value);
1709     else {
1710         _bdf_split(" +", line, linelen, &p->list);
1711         name = p->list.field[0];
1712         _bdf_shift(1, &p->list);
1713         value = _bdf_join(' ', &vlen, &p->list);
1714         _bdf_add_property(p->font, name, value);
1715     }
1716
1717     return 0;
1718 }
1719
1720 /*
1721  * Load the font header.
1722  */
1723 static int
1724 _bdf_parse_start(char *line, unsigned int linelen, unsigned int lineno,
1725                  void *call_data, void *client_data)
1726 {
1727     unsigned int slen = 0;
1728     _bdf_line_func_t *next;
1729     _bdf_parse_t *p;
1730     bdf_font_t *font;
1731     char *s, nbuf[128];
1732
1733     next = (_bdf_line_func_t *) call_data;
1734     p = (_bdf_parse_t *) client_data;
1735
1736     /*
1737      * Check for a comment.  This is done to handle those fonts that have
1738      * comments before the STARTFONT line for some reason.
1739      */
1740     if (memcmp(line, "COMMENT", 7) == 0) {
1741         if (p->opts->keep_comments != 0 && p->font != 0) {
1742             linelen -= 7;
1743             s = line + 7;
1744             if (*s != 0) {
1745                 s++;
1746                 linelen--;
1747             }
1748             _bdf_add_comment(p->font, s, linelen);
1749         }
1750         return 0;
1751     }
1752
1753     if (!(p->flags & _BDF_START)) {
1754         if (memcmp(line, "STARTFONT", 9) != 0)
1755           /*
1756            * No STARTFONT field is a good indication of a problem.
1757            */
1758           return BDF_MISSING_START;
1759         p->flags = _BDF_START;
1760         p->font = font = (bdf_font_t *) calloc(1, sizeof(bdf_font_t));
1761         p->font->internal = (void *) malloc(sizeof(hashtable));
1762         hash_init((hashtable *) p->font->internal);
1763         p->font->spacing = p->opts->font_spacing;
1764         p->font->default_glyph = -1;
1765         return 0;
1766     }
1767
1768     /*
1769      * Check for the start of the properties.
1770      */
1771     if (memcmp(line, "STARTPROPERTIES", 15) == 0) {
1772         _bdf_split(" +", line, linelen, &p->list);
1773         p->cnt = p->font->props_size = _bdf_atoul(p->list.field[1], 0, 10);
1774         p->font->props = (bdf_property_t *)
1775             malloc(sizeof(bdf_property_t) * p->cnt);
1776         p->flags |= _BDF_PROPS;
1777         *next = _bdf_parse_properties;
1778         return 0;
1779     }
1780
1781     /*
1782      * Check for the FONTBOUNDINGBOX field.
1783      */
1784     if (memcmp(line, "FONTBOUNDINGBOX", 15) == 0) {
1785         if (!(p->flags & _BDF_SIZE)) {
1786             /*
1787              * Missing the SIZE field.
1788              */
1789             sprintf(nbuf, ERRMSG1, lineno, "SIZE");
1790             _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1791             return BDF_MISSING_SIZE;
1792         }
1793         _bdf_split(" +", line, linelen, &p->list);
1794         p->font->bbx.width = _bdf_atos(p->list.field[1], 0, 10);
1795         p->font->bbx.height = _bdf_atos(p->list.field[2], 0, 10);
1796         p->font->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10);
1797         p->font->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10);
1798         p->font->bbx.ascent = p->font->bbx.height + p->font->bbx.y_offset;
1799         p->font->bbx.descent = -p->font->bbx.y_offset;
1800         p->flags |= _BDF_FONT_BBX;
1801         return 0;
1802     }
1803
1804     /*
1805      * The next thing to check for is the FONT field.
1806      */
1807     if (memcmp(line, "FONT", 4) == 0) {
1808         _bdf_split(" +", line, linelen, &p->list);
1809         _bdf_shift(1, &p->list);
1810         s = _bdf_join(' ', &slen, &p->list);
1811         p->font->name = (char *) malloc(slen + 1);
1812         (void) memcpy(p->font->name, s, slen + 1);
1813         /*
1814          * If the font name is an XLFD name, set the spacing to the one in the
1815          * font name.  If there is no spacing fall back on the default.
1816          */
1817         _bdf_set_default_spacing(p->font, p->opts);
1818         p->flags |= _BDF_FONT_NAME;
1819         return 0;
1820     }
1821
1822     /*
1823      * Check for the SIZE field.
1824      */
1825     if (memcmp(line, "SIZE", 4) == 0) {
1826         if (!(p->flags & _BDF_FONT_NAME)) {
1827             /*
1828              * Missing the FONT field.
1829              */
1830             sprintf(nbuf, ERRMSG1, lineno, "FONT");
1831             _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1832             return BDF_MISSING_FONTNAME;
1833         }
1834         _bdf_split(" +", line, linelen, &p->list);
1835         p->font->point_size = _bdf_atoul(p->list.field[1], 0, 10);
1836         p->font->resolution_x = _bdf_atoul(p->list.field[2], 0, 10);
1837         p->font->resolution_y = _bdf_atoul(p->list.field[3], 0, 10);
1838
1839         /*
1840          * Check for the bits per pixel field.
1841          */
1842         if (p->list.used == 5) {
1843             p->font->bpp = _bdf_atos(p->list.field[4], 0, 10);
1844             if (p->font->bpp > 1 && (p->font->bpp & 1)) {
1845                 /*
1846                  * Move up to the next bits per pixel value if an odd number
1847                  * is encountered.
1848                  */
1849                 p->font->bpp++;
1850                 if (p->font->bpp <= 4) {
1851                     sprintf(nbuf, ACMSG11, p->font->bpp);
1852                     _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1853                 }
1854             }
1855             if (p->font->bpp > 4) {
1856                 sprintf(nbuf, ACMSG11, p->font->bpp);
1857                 _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1858                 p->font->bpp = 4;
1859             }
1860         } else
1861           p->font->bpp = 1;
1862
1863         p->flags |= _BDF_SIZE;
1864         return 0;
1865     }
1866
1867     return BDF_INVALID_LINE;
1868 }
1869
1870 /**************************************************************************
1871  *
1872  * API.
1873  *
1874  **************************************************************************/
1875
1876 void
1877 bdf_setup(void)
1878 {
1879     unsigned int i;
1880     bdf_property_t *prop;
1881
1882     hash_init(&proptbl);
1883     for (i = 0, prop = _bdf_properties; i < _num_bdf_properties; i++, prop++)
1884       hash_insert(prop->name, (void *) i, &proptbl);
1885 }
1886
1887 void
1888 bdf_cleanup(void)
1889 {
1890     unsigned int i;
1891     bdf_property_t *prop;
1892
1893     hash_free(&proptbl);
1894
1895     /*
1896      * Free up the user defined properties.
1897      */
1898     for (prop = user_props, i = 0; i < nuser_props; i++, prop++) {
1899         free(prop->name);
1900         if (prop->format == BDF_ATOM && prop->value.atom != 0)
1901           free(prop->value.atom);
1902     }
1903     if (nuser_props > 0)
1904       free((char *) user_props);
1905
1906     _bdf_glyph_name_cleanup();
1907 }
1908
1909 bdf_font_t *
1910 bdf_load_font(FILE *in, bdf_options_t *opts, bdf_callback_t callback,
1911               void *data)
1912 {
1913     int n;
1914     unsigned int lineno;
1915     char msgbuf[128];
1916     _bdf_parse_t p;
1917
1918     (void) memset((char *) &p, 0, sizeof(_bdf_parse_t));
1919     p.opts = (opts != 0) ? opts : &_bdf_opts;
1920     p.minlb = 32767;
1921     p.callback = callback;
1922     p.client_data = data;
1923     n = _bdf_readlines(fileno(in), _bdf_parse_start, (void *) &p, &lineno);
1924
1925     if (p.font != 0) {
1926         /*
1927          * If the font is not proportional, set the fonts monowidth
1928          * field to the width of the font bounding box.
1929          */
1930         if (p.font->spacing != BDF_PROPORTIONAL)
1931           p.font->monowidth = p.font->bbx.width;
1932
1933         /*
1934          * If the number of glyphs loaded is not that of the original count,
1935          * indicate the difference.
1936          */
1937         if (p.cnt != p.font->glyphs_used + p.font->unencoded_used) {
1938             sprintf(msgbuf, ACMSG15, p.cnt,
1939                     p.font->glyphs_used + p.font->unencoded_used);
1940             _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1941             p.font->modified = 1;
1942         }
1943
1944         /*
1945          * Once the font has been loaded, adjust the overall font metrics if
1946          * necessary.
1947          */
1948         if (p.opts->correct_metrics != 0 &&
1949             (p.font->glyphs_used > 0 || p.font->unencoded_used > 0)) {
1950             if (p.maxrb - p.minlb != p.font->bbx.width) {
1951                 sprintf(msgbuf, ACMSG3, p.font->bbx.width, p.maxrb - p.minlb);
1952                 _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1953                 p.font->bbx.width = p.maxrb - p.minlb;
1954                 p.font->modified = 1;
1955             }
1956             if (p.font->bbx.x_offset != p.minlb) {
1957                 sprintf(msgbuf, ACMSG4, p.font->bbx.x_offset, p.minlb);
1958                 _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1959                 p.font->bbx.x_offset = p.minlb;
1960                 p.font->modified = 1;
1961             }
1962             if (p.font->bbx.ascent != p.maxas) {
1963                 sprintf(msgbuf, ACMSG5, p.font->bbx.ascent, p.maxas);
1964                 _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1965                 p.font->bbx.ascent = p.maxas;
1966                 p.font->modified = 1;
1967             }
1968             if (p.font->bbx.descent != p.maxds) {
1969                 sprintf(msgbuf, ACMSG6, p.font->bbx.descent, p.maxds);
1970                 _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1971                 p.font->bbx.descent = p.maxds;
1972                 p.font->bbx.y_offset = -p.maxds;
1973                 p.font->modified = 1;
1974             }
1975             if (p.maxas + p.maxds != p.font->bbx.height) {
1976                 sprintf(msgbuf, ACMSG7, p.font->bbx.height, p.maxas + p.maxds);
1977                 _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1978             }
1979             p.font->bbx.height = p.maxas + p.maxds;
1980
1981             if (p.flags & _BDF_SWIDTH_ADJ)
1982               _bdf_add_acmsg(p.font, ACMSG8, strlen(ACMSG8));
1983         }
1984     }
1985
1986     /*
1987      * Last, if an error happened during loading, handle the messages.
1988      */
1989     if (n < 0 && callback != 0) {
1990         /*
1991          * An error was returned.  Alert the client.
1992          */
1993         p.cb.reason = BDF_ERROR;
1994         p.cb.errlineno = lineno;
1995         (*callback)(&p.cb, data);
1996     } else if (p.flags & _BDF_START) {
1997         if (p.font != 0) {
1998             /*
1999              * The ENDFONT field was never reached or did not exist.
2000              */
2001             if (!(p.flags & _BDF_GLYPHS))
2002               /*
2003                * Error happened while parsing header.
2004                */
2005               sprintf(msgbuf, ERRMSG2, lineno);
2006             else
2007               /*
2008                * Error happened when parsing glyphs.
2009                */
2010               sprintf(msgbuf, ERRMSG3, lineno);
2011
2012             _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
2013         }
2014
2015         if (callback != 0) {
2016             p.cb.reason = BDF_ERROR;
2017             p.cb.errlineno = lineno;
2018             (*callback)(&p.cb, data);
2019         }
2020     } else if (callback != 0) {
2021         /*
2022          * This forces the progress bar to always finish.
2023          */
2024         p.cb.current = p.cb.total;
2025         (*p.callback)(&p.cb, p.client_data);
2026     }
2027
2028     /*
2029      * Free up the list used during the parsing.
2030      */
2031     if (p.list.size > 0)
2032       free((char *) p.list.field);
2033
2034     if (p.font != 0) {
2035         /*
2036          * Make sure the comments are NULL terminated if they exist.
2037          */
2038         if (p.font->comments_len > 0) {
2039             p.font->comments = (char *) realloc(p.font->comments,
2040                                                 p.font->comments_len + 1);
2041             p.font->comments[p.font->comments_len] = 0;
2042         }
2043
2044         /*
2045          * Make sure the auto-correct messages are NULL terminated if they
2046          * exist.
2047          */
2048         if (p.font->acmsgs_len > 0) {
2049             p.font->acmsgs = (char *) realloc(p.font->acmsgs,
2050                                               p.font->acmsgs_len + 1);
2051             p.font->acmsgs[p.font->acmsgs_len] = 0;
2052         }
2053     }
2054
2055     return p.font;
2056 }
2057
2058 #ifdef HAVE_HBF
2059
2060 static int
2061 _bdf_parse_hbf_header(char *line, unsigned int linelen, unsigned int lineno,
2062                       void *call_data, void *client_data)
2063 {
2064     unsigned int vlen = 0;
2065     char *name, *value;
2066     _bdf_parse_t *p;
2067     _bdf_line_func_t *next;
2068     char nbuf[24];
2069
2070     next = (_bdf_line_func_t *) call_data;
2071     p = (_bdf_parse_t *) client_data;
2072
2073     /*
2074      * Check for comments.
2075      */
2076     if (memcmp(line, "COMMENT", 7) == 0) {
2077         if (p->opts->keep_comments != 0 && p->font != 0) {
2078             name = line;
2079             value = name + 7;
2080             vlen = linelen - 7;
2081             if (*value) {
2082                 *value++ = 0;
2083                 vlen--;
2084             }
2085             /*
2086              * If the properties are being parsed, add the comment as a
2087              * property.  Otherwise, simply add the comment in the normal
2088              * fashion.
2089              */
2090             if (p->flags & _BDF_PROPS)
2091               _bdf_add_property(p->font, name, value);
2092             else
2093               _bdf_add_comment(p->font, value, vlen);
2094         }
2095         return 0;
2096     }
2097
2098     if (!(p->flags & _BDF_START)) {
2099         if (memcmp(line, "HBF_START_FONT", 14) != 0)
2100           return -1;
2101         p->flags = _BDF_START;
2102         p->font = (bdf_font_t *) calloc(1, sizeof(bdf_font_t));
2103         /*
2104          * HBF fonts are always assumed to be 1 bit per pixel.
2105          */
2106         p->font->bpp = 1;
2107         p->font->internal = (void *) malloc(sizeof(hashtable));
2108         hash_init((hashtable *) p->font->internal);
2109         p->font->hbf = 1;
2110         p->font->spacing = p->opts->font_spacing;
2111         p->font->default_glyph = -1;
2112         return 0;
2113     }
2114
2115     /*
2116      * Check for the HBF_END_FONT field.
2117      */
2118     if (memcmp(line, "HBF_END_FONT", 12) == 0)
2119       /*
2120        * Need to perform some checks here to see whether some fields are
2121        * missing or not.
2122        */
2123       return 0;
2124
2125     /*
2126      * Check for HBF keywords which will be added as comments.  These should
2127      * never occur in the properties list.  Assume they won't.
2128      */
2129     if (memcmp(line, "HBF_", 4) == 0) {
2130         if (p->opts->keep_comments != 0)
2131           _bdf_add_comment(p->font, line, linelen);
2132         return 0;
2133     }
2134
2135     if (!(p->flags & _BDF_PROPS)) {
2136         /*
2137          * Check for the start of the properties.
2138          */
2139         if (memcmp(line, "STARTPROPERTIES", 15) == 0) {
2140             _bdf_split(" +", line, linelen, &p->list);
2141             p->cnt = p->font->props_size = _bdf_atoul(p->list.field[1], 0, 10);
2142             p->font->props = (bdf_property_t *)
2143                 malloc(sizeof(bdf_property_t) * p->cnt);
2144             p->flags |= _BDF_PROPS;
2145             return 0;
2146         }
2147
2148         /*
2149          * Check for the CHARS field.
2150          */
2151         if (memcmp(line, "CHARS", 5) == 0) {
2152             _bdf_split(" +", line, linelen, &p->list);
2153             p->cnt = p->font->glyphs_size =
2154                 _bdf_atoul(p->list.field[1], 0, 10);
2155             p->font->glyphs = (bdf_glyph_t *)
2156                 malloc(sizeof(bdf_glyph_t) * p->cnt);
2157             return 0;
2158         }
2159
2160         /*
2161          * Check for the FONTBOUNDINGBOX field.
2162          */
2163         if (memcmp(line, "FONTBOUNDINGBOX", 15) == 0) {
2164             if (!(p->flags & (_BDF_START|_BDF_FONT_NAME|_BDF_SIZE)))
2165               return -1;
2166             _bdf_split(" +", line, linelen, &p->list);
2167             p->font->bbx.width = _bdf_atos(p->list.field[1], 0, 10);
2168             p->font->bbx.height = _bdf_atos(p->list.field[2], 0, 10);
2169             p->font->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10);
2170             p->font->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10);
2171             p->font->bbx.ascent = p->font->bbx.height + p->font->bbx.y_offset;
2172             p->font->bbx.descent = -p->font->bbx.y_offset;
2173             p->flags |= _BDF_FONT_BBX;
2174             return 0;
2175         }
2176
2177         /*
2178          * The next thing to check for is the FONT field.
2179          */
2180         if (memcmp(line, "FONT", 4) == 0) {
2181             if (!(p->flags & _BDF_START))
2182               return -1;
2183             _bdf_split(" +", line, linelen, &p->list);
2184             _bdf_shift(1, &p->list);
2185             value = _bdf_join(' ', &vlen, &p->list);
2186             p->font->name = (char *) malloc(vlen + 1);
2187             (void) memcpy(p->font->name, value, vlen + 1);
2188             /*
2189              * If the font name is an XLFD name, set the spacing to the one in
2190              * the font name.  If there is no spacing fall back on the
2191              * default.
2192              */
2193             _bdf_set_default_spacing(p->font, p->opts);
2194             p->flags |= _BDF_FONT_NAME;
2195             return 0;
2196         }
2197
2198         /*
2199          * Check for the SIZE field.
2200          */
2201         if (memcmp(line, "SIZE", 4) == 0) {
2202             if (!(p->flags & (_BDF_START|_BDF_FONT_NAME)))
2203               return -1;
2204             _bdf_split(" +", line, linelen, &p->list);
2205             p->font->point_size = _bdf_atoul(p->list.field[1], 0, 10);
2206             p->font->resolution_x = _bdf_atoul(p->list.field[2], 0, 10);
2207             p->font->resolution_y = _bdf_atoul(p->list.field[3], 0, 10);
2208             p->flags |= _BDF_SIZE;
2209             return 0;
2210         }
2211     } else {
2212         /*
2213          * Check for the end of the properties.
2214          */
2215         if (memcmp(line, "ENDPROPERTIES", 13) == 0) {
2216             /*
2217              * If the FONT_ASCENT or FONT_DESCENT properties have not been
2218              * encountered yet, then make sure they are added as properties and
2219              * make sure they are set from the font bounding box info.
2220              *
2221              * This is *always* done regardless of the options, because X11
2222              * requires these two fields to compile fonts.
2223              */
2224             if (bdf_get_font_property(p->font, "FONT_ASCENT") == 0) {
2225                 p->font->font_ascent = p->font->bbx.ascent;
2226                 sprintf(nbuf, "%hd", p->font->bbx.ascent);
2227                 _bdf_add_property(p->font, "FONT_ASCENT", nbuf);
2228                 sprintf(nbuf, ACMSG1, p->font->bbx.ascent);
2229                 _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
2230                 p->font->modified = 1;
2231             }
2232             if (bdf_get_font_property(p->font, "FONT_DESCENT") == 0) {
2233                 p->font->font_descent = p->font->bbx.descent;
2234                 sprintf(nbuf, "%hd", p->font->bbx.descent);
2235                 _bdf_add_property(p->font, "FONT_DESCENT", nbuf);
2236                 sprintf(nbuf, ACMSG2, p->font->bbx.descent);
2237                 _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
2238                 p->font->modified = 1;
2239             }
2240             p->flags &= ~_BDF_PROPS;
2241             return 0;
2242         }
2243
2244         /*
2245          * Handle the next thing in the usual property fashion.
2246          */
2247         if (_bdf_is_atom(line, linelen, &name, &value))
2248           _bdf_add_property(p->font, name, value);
2249         else {
2250             _bdf_split(" +", line, linelen, &p->list);
2251             name = p->list.field[0];
2252             _bdf_shift(1, &p->list);
2253             value = _bdf_join(' ', &vlen, &p->list);
2254             _bdf_add_property(p->font, name, value);
2255         }
2256         return 0;
2257     }
2258
2259     /*
2260      * Anything else is an error.
2261      */
2262     return -1;
2263 }
2264
2265 #define CONST const
2266
2267 static void
2268 _bdf_add_hbf_glyph(HBF *hbf, unsigned int code, void *callback_data)
2269 {
2270     CONST unsigned char *bmap;
2271     unsigned int n;
2272     bdf_glyph_t *gp;
2273     bdf_font_t *font;
2274     _bdf_parse_t *p;
2275     HBF_BBOX *fbbx;
2276     double ps, rx, dw;
2277     char nbuf[24];
2278
2279     /*
2280      * Attempt to get the bitmap.
2281      */
2282     if ((bmap = hbfGetBitmap(hbf, code)) == 0)
2283       /*
2284        * Need some sort of error handling here.
2285        */
2286       return;
2287
2288     p = (_bdf_parse_t *) callback_data;
2289
2290     fbbx = hbfFontBBox(hbf);
2291
2292     font = p->font;
2293
2294     /*
2295      * Check to make sure there is enough space to hold this glyph.  If not,
2296      * allocate 10 more just in case.
2297      */
2298     if (font->glyphs_used == font->glyphs_size) {
2299         if (font->glyphs_size == 0)
2300           font->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * 16);
2301         else
2302           font->glyphs = (bdf_glyph_t *)
2303               realloc((char *) font->glyphs,
2304                       sizeof(bdf_glyph_t) * (font->glyphs_used + 16));
2305         gp = font->glyphs + font->glyphs_size;
2306         (void) memset((char *) gp, 0, sizeof(bdf_glyph_t) * 16);
2307         font->glyphs_size += 16;
2308     }
2309
2310     gp = font->glyphs + font->glyphs_used++;
2311
2312     /*
2313      * Set the glyph name.
2314      */
2315     sprintf(nbuf, "char%d", code);
2316     n = (unsigned int) strlen(nbuf);
2317     gp->name = (char *) malloc(n + 1);
2318     (void) memcpy(gp->name, nbuf, n + 1);
2319
2320     /*
2321      * Set encoding.
2322      */
2323     gp->encoding = (int) code;
2324
2325     /*
2326      * Set the device width.
2327      */
2328     gp->dwidth = (unsigned short) fbbx->hbf_width;
2329
2330     /*
2331      * Set the scalable width.
2332      */
2333     ps = (double) font->point_size;
2334     rx = (double) font->resolution_x;
2335     dw = (double) gp->dwidth;
2336     gp->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
2337
2338     /*
2339      * Set the glyph bounding box.
2340      */
2341     gp->bbx.width = fbbx->hbf_width;
2342     gp->bbx.height = fbbx->hbf_height;
2343     gp->bbx.x_offset = fbbx->hbf_xDisplacement;
2344     gp->bbx.y_offset = fbbx->hbf_yDisplacement;
2345     gp->bbx.ascent = gp->bbx.height + gp->bbx.y_offset;
2346     gp->bbx.descent = -gp->bbx.y_offset;
2347
2348     /*
2349      * Add the bitmap by making a copy.  Assumes the font bbx is OK for
2350      * determining the number of bytes needed for the glyph bitmap.
2351      */
2352     gp->bytes = ((gp->bbx.width + 7) >> 3) * gp->bbx.height;
2353     gp->bitmap = (unsigned char *) malloc(gp->bytes);
2354     (void) memcpy((char *) gp->bitmap, (char *) bmap, gp->bytes);
2355
2356     /*
2357      * Call the callback if it was provided.
2358      */
2359     if (p->callback != 0) {
2360         p->cb.reason = BDF_LOADING;
2361         p->cb.total = font->glyphs_size;
2362         p->cb.current = font->glyphs_used;
2363         (*p->callback)(&p->cb, p->client_data);
2364     }
2365 }
2366
2367 bdf_font_t *
2368 bdf_load_hbf_font(char *filename, bdf_options_t *opts, bdf_callback_t callback,
2369                   void *data)
2370 {
2371     int n, diff;
2372     unsigned int lineno;
2373     FILE *in;
2374     HBF *hbf;
2375     bdf_property_t *pp;
2376     char *name;
2377     _bdf_parse_t p;
2378
2379     if ((hbf = hbfOpen(filename)) == 0)
2380       return 0;
2381
2382     if ((in = fopen(hbfFileName(hbf), "r")) == 0) {
2383         hbfClose(hbf);
2384         return 0;
2385     }
2386
2387     /*
2388      * Parse the HBF header for properties and other things.
2389      */
2390     (void) memset((char *) &p, 0, sizeof(_bdf_parse_t));
2391     p.opts = (opts != 0) ? opts : &_bdf_opts;
2392     p.minlb = 32767;
2393     p.callback = callback;
2394     p.client_data = data;
2395
2396     n = _bdf_readlines(fileno(in), _bdf_parse_hbf_header, (void *) &p,
2397                        &lineno);
2398
2399     fclose(in);
2400
2401     /*
2402      * Determine what spacing the font has so the monowidth field can be set
2403      * if necessary.
2404      */
2405     if ((pp = bdf_get_font_property(p.font, "SPACING")) != 0) {
2406         switch (pp->value.atom[0]) {
2407           case 'p': case 'P': p.font->spacing = BDF_PROPORTIONAL; break;
2408           case 'm': case 'M': p.font->spacing = BDF_MONOWIDTH; break;
2409           case 'c': case 'C': p.font->spacing = BDF_CHARCELL; break;
2410         }
2411     }
2412
2413     /*
2414      * Set the monowidth field if necessary.
2415      */
2416     if (p.font->spacing != BDF_PROPORTIONAL)
2417       p.font->monowidth = p.font->bbx.width;
2418
2419     /*
2420      * Before loading the glyphs, check to see if any glyph structures have
2421      * been added.  If not, check the HBF font for the number of characters.
2422      * Dynamically increasing glyph storage causes memory fragmentation on
2423      * some machines and crashes.  This takes care of the cases where the HBF
2424      * file does not provide a "CHARS n" line.
2425      */
2426     if (p.font->glyphs_size < hbfChars(hbf)) {
2427         if (p.font->glyphs_size == 0)
2428           p.font->glyphs = (bdf_glyph_t *)
2429               malloc(sizeof(bdf_glyph_t) * hbfChars(hbf));
2430         else
2431           p.font->glyphs = (bdf_glyph_t *)
2432               realloc((char *) p.font->glyphs,
2433                       sizeof(bdf_glyph_t) * hbfChars(hbf));
2434         diff = hbfChars(hbf) - p.font->glyphs_size;
2435         (void) memset((char *) (p.font->glyphs + p.font->glyphs_size), 0,
2436                       diff);
2437         p.font->glyphs_size = hbfChars(hbf);
2438     }
2439
2440     /*
2441      * Call the callback initially to set things up.
2442      */
2443     if (p.callback != 0) {
2444         p.cb.reason = BDF_LOAD_START;
2445         p.cb.total = p.font->glyphs_size;
2446         p.cb.current = 0;
2447         (*p.callback)(&p.cb, p.client_data);
2448     }
2449
2450     /*
2451      * Now load the glyphs.
2452      */
2453     hbfForEach(hbf, _bdf_add_hbf_glyph, (void *) &p);
2454
2455     /*
2456      * Close the HBF font.
2457      */
2458     hbfClose(hbf);
2459
2460     /*
2461      * Sort the glyphs by encoding.
2462      */
2463     qsort((char *) p.font->glyphs, p.font->glyphs_used, sizeof(bdf_glyph_t),
2464           by_encoding);
2465
2466     /*
2467      * After loading the HBF header, create an XLFD name.  If the XLFD name
2468      * cannot be made then preserve the name found in the HBF file.
2469      */
2470     if ((name = bdf_make_xlfd_name(p.font, "HBF", "Unknown")) != 0) {
2471         if (p.font->name != 0)
2472           /*
2473            * If a name already exists in the font, free it up.
2474            */
2475           free(p.font->name);
2476
2477         /*
2478          * Replace the old name with the XLFD name.
2479          */
2480         p.font->name = name;
2481     }
2482
2483     /*
2484      * Mark the font as being modified and generate a message that says
2485      * something about the font being converted from HBF format.
2486      */
2487     p.font->modified = 1;
2488     _bdf_add_acmsg(p.font, "Font converted from HBF to BDF.", 31);
2489
2490     return p.font;
2491 }
2492
2493 #endif /* HAVE_HBF */
2494
2495 /*
2496  * Crop the glyph bitmap to the minimum rectangle needed to hold the bits that
2497  * are set.  Adjust the metrics based on the provided bounding box.
2498  */
2499 void
2500 _bdf_crop_glyph(bdf_font_t *font, bdf_glyph_t *glyph)
2501 {
2502     int byte;
2503     unsigned short x, y, bpr, nbpr, col, colx, si, di;
2504     unsigned short minx, maxx, miny, maxy;
2505     unsigned int bytes;
2506     unsigned char *bmap, *masks;
2507     bdf_bbx_t nbbx;
2508
2509     if (glyph == 0)
2510       return;
2511
2512     (void) memcpy((char *) &nbbx, (char *) &glyph->bbx, sizeof(bdf_bbx_t));
2513
2514     bpr = ((glyph->bbx.width * font->bpp) + 7) >> 3;
2515
2516     maxx = maxy = 0;
2517     minx = miny = 32767;
2518
2519     masks = 0;
2520     switch (font->bpp) {
2521       case 1: masks = bdf_onebpp; break;
2522       case 2: masks = bdf_twobpp; break;
2523       case 4: masks = bdf_fourbpp; break;
2524       case 8: masks = bdf_eightbpp; break;
2525     }
2526
2527     for (y = 0; y < glyph->bbx.height; y++) {
2528         for (col = x = 0; x < glyph->bbx.width; x++, col += font->bpp) {
2529             si = (col & 7) / font->bpp;
2530             if (glyph->bitmap[(y * bpr) + (col >> 3)] & masks[si]) {
2531                 minx = MIN(minx, x);
2532                 maxx = MAX(maxx, x);
2533                 miny = MIN(miny, y);
2534                 maxy = MAX(maxy, y);
2535             }
2536         }
2537     }
2538
2539     /*
2540      * Handle an empty bitmap as a special case.
2541      */
2542     if (minx == 32767) {
2543         if (glyph->bytes > 0)
2544           free((char *) glyph->bitmap);
2545         glyph->bytes = 0;
2546         (void) memset((char *) &glyph->bbx, 0, sizeof(bdf_bbx_t));
2547         return;
2548     }
2549
2550     /*
2551      * Increment the max points so width and height calculations won't go
2552      * wrong.
2553      */
2554     maxx++;
2555     maxy++;
2556
2557     if (minx > 0)
2558       nbbx.x_offset += minx;
2559     if (maxx - minx != nbbx.width)
2560       nbbx.width = maxx - minx;
2561
2562     if (miny > 0)
2563       nbbx.ascent -= miny;
2564     if (maxy - miny != nbbx.height)
2565       nbbx.height = maxy - miny;
2566     nbbx.descent = nbbx.height - nbbx.ascent;
2567     nbbx.y_offset = -nbbx.descent;
2568
2569     nbpr = ((nbbx.width * font->bpp) + 7) >> 3;
2570
2571     /*
2572      * If nothing changed, then the glyph is already contained in the
2573      * minimum rectangle.
2574      */
2575     if (memcmp((char *) &nbbx, (char *) &glyph->bbx,
2576                sizeof(bdf_bbx_t)) == 0 ||
2577         (nbpr == bpr && nbbx.height == glyph->bbx.height))
2578       return;
2579
2580     /*
2581      * The metrics changed, so a new bitmap is needed.
2582      */
2583     bytes = nbpr * nbbx.height;
2584     bmap = (unsigned char *) malloc(bytes);
2585     (void) memset((char *) bmap, 0, bytes);
2586
2587     colx = minx * font->bpp;
2588     for (y = miny; y < maxy; y++) {
2589         for (col = x = minx; x < maxx; x++, col += font->bpp) {
2590             si = (col & 7) / font->bpp;
2591             byte = glyph->bitmap[(y * bpr) + (col >> 3)] & masks[si];
2592             if (byte) {
2593                 /*
2594                  * Position the pixel in the byte if necessary.
2595                  */
2596                 di = ((col - colx) & 7) / font->bpp;
2597                 if (di < si)
2598                   byte <<= (si - di) * font->bpp;
2599                 else if (di > si)
2600                   byte >>= (di - si) * font->bpp;
2601                 bmap[((y - miny) * nbpr) + ((col - colx) >> 3)] |= byte;
2602             }
2603         }
2604     }
2605
2606     if (glyph->bytes > 0)
2607       free((char *) glyph->bitmap);
2608     glyph->bytes = bytes;
2609     glyph->bitmap = bmap;
2610
2611     (void) memcpy((char *) &glyph->bbx, (char *) &nbbx, sizeof(bdf_bbx_t));
2612 }
2613
2614 /*
2615  * Pad a character-cell font glyph to match the bounds specified in the
2616  * provided bounding box.
2617  */
2618 void
2619 _bdf_pad_cell(bdf_font_t *font, bdf_glyph_t *glyph, bdf_glyph_t *cell)
2620 {
2621     bdf_bbx_t *bbx;
2622     unsigned short si, di, sx, byte;
2623     unsigned short x, y, dx, dy, bx, by, bpr, nbpr;
2624     unsigned char *bmap, *masks;
2625
2626     masks = 0;
2627     switch (font->bpp) {
2628       case 1: masks = bdf_onebpp; break;
2629       case 2: masks = bdf_twobpp; break;
2630       case 4: masks = bdf_fourbpp; break;
2631       case 8: masks = bdf_eightbpp; break;
2632     }
2633
2634     bbx = &font->bbx;
2635
2636     if (glyph->bbx.width == bbx->width && glyph->bbx.height == bbx->height) {
2637         /*
2638          * The glyph is already positioned in the cell.  Copy the bitmap
2639          * and return.
2640          */
2641         (void) memcpy((char *) cell->bitmap, (char *) glyph->bitmap,
2642                       cell->bytes);
2643         return;
2644     }
2645
2646     /*
2647      * Determine the X and Y location of the baseline.
2648      */
2649     bx = MYABS(bbx->x_offset - glyph->bbx.x_offset);
2650     by = (bbx->ascent + bbx->descent) + bbx->y_offset;
2651
2652     bpr = ((glyph->bbx.width * font->bpp) + 7) >> 3;
2653     nbpr = ((bbx->width * font->bpp) + 7) >> 3;
2654
2655     /*
2656      * Set various cell values and clear the cell bitmap.
2657      */
2658     bmap = cell->bitmap;
2659     (void) memset((char *) bmap, 0, cell->bytes);
2660
2661     for (dy = by - glyph->bbx.ascent, y = 0; y < glyph->bbx.height;
2662          y++, dy++) {
2663         for (dx = bx * font->bpp, sx = x = 0; x < glyph->bbx.width;
2664              x++, dx += font->bpp, sx += font->bpp) {
2665             si = (sx & 7) / font->bpp;
2666             byte = glyph->bitmap[(y * bpr) + (sx >> 3)] & masks[si];
2667             if (byte) {
2668                 di = (dx & 7) / font->bpp;
2669                 if (di < si)
2670                   byte <<= (si - di) * font->bpp;
2671                 else if (di > si)
2672                   byte >>= (di - si) * font->bpp;
2673                 bmap[(dy * nbpr) + (dx >> 3)] |= byte;
2674             }
2675         }
2676     }
2677 }
2678
2679 static char *unix_eol = "\n";
2680 static char *dos_eol = "\r\n";
2681 static char *mac_eol = "\r";
2682
2683 void
2684 bdf_save_font(FILE *out, bdf_font_t *font, bdf_options_t *opts,
2685               bdf_callback_t callback, void *data)
2686 {
2687     int len;
2688     unsigned int i, j, bpr, pcnt;
2689     double dw, ps, rx;
2690     char *sp, *ep, *eol;
2691     bdf_property_t *p;
2692     bdf_glyph_t *c, *cp, cell;
2693     bdf_callback_struct_t cb;
2694
2695     if (font == 0)
2696       return;
2697
2698     eol = 0;
2699     switch (opts->eol) {
2700       case BDF_UNIX_EOL: eol = unix_eol; break;
2701       case BDF_DOS_EOL: eol = dos_eol; break;
2702       case BDF_MAC_EOL: eol = mac_eol; break;
2703     }
2704
2705     /*
2706      * If the font is a character cell font, allocate some space for the
2707      * bitmap.
2708      */
2709     if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0) {
2710         bpr = ((font->bbx.width * font->bpp) + 7) >> 3;
2711         cell.bytes = bpr * font->bbx.height;
2712         cell.bitmap = (unsigned char *) malloc(cell.bytes);
2713         (void) memcpy((char *) &cell.bbx, (char *) &font->bbx,
2714                       sizeof(bdf_bbx_t));
2715     }
2716
2717     /*
2718      * Emit the header.
2719      */
2720     fprintf(out, "STARTFONT 2.1%s", eol);
2721
2722     /*
2723      * Emit the comments.
2724      */
2725     if (font->comments_len > 0) {
2726         for (sp = font->comments; *sp; sp++) {
2727             ep = sp;
2728             while (*ep && *ep != '\n')
2729               ep++;
2730             len = (int) (ep - sp);
2731             fprintf(out, "COMMENT %.*s%s", len, sp, eol);
2732             sp = ep;
2733         }
2734     }
2735
2736     /*
2737      * Emit the font name.
2738      */
2739     fprintf(out, "FONT %s%s", font->name, eol);
2740
2741     /*
2742      * Emit the size info.
2743      */
2744     if (font->bpp == 1)
2745       fprintf(out, "SIZE %d %d %d%s", font->point_size,
2746               font->resolution_x, font->resolution_y, eol);
2747     else
2748       fprintf(out, "SIZE %d %d %d %hd%s", font->point_size,
2749               font->resolution_x, font->resolution_y, font->bpp, eol);
2750
2751     /*
2752      * Emit the bounding box.
2753      */
2754     fprintf(out, "FONTBOUNDINGBOX %hd %hd %hd %hd%s",
2755             font->bbx.width, font->bbx.height, font->bbx.x_offset,
2756             font->bbx.y_offset, eol);
2757
2758     /*
2759      * Emit the properties after counting how many are properties and
2760      * how many are comments.
2761      */
2762     for (i = pcnt = 0, p = font->props; i < font->props_used; i++, p++) {
2763         if (memcmp(p->name, "COMMENT", 7) != 0)
2764           pcnt++;
2765     }
2766
2767     fprintf(out, "STARTPROPERTIES %d%s", pcnt, eol);
2768     for (i = 0, p = font->props; i < font->props_used; i++, p++) {
2769         fprintf(out, "%s ", p->name);
2770         if (p->format == BDF_ATOM) {
2771             if (p->value.atom == 0)
2772               fprintf(out, "\"\"%s", eol);
2773             else
2774               fprintf(out, "\"%s\"%s", p->value.atom, eol);
2775         } else
2776           fprintf(out, "%d%s", p->value.int32, eol);
2777     }
2778
2779     fprintf(out, "ENDPROPERTIES%s", eol);
2780
2781     /*
2782      * Emit the number of bitmaps in the font.
2783      */
2784     fprintf(out, "CHARS %d%s", font->unencoded_used + font->glyphs_used, eol);
2785
2786     /*
2787      * Call the callback if it was passed to start the save.
2788      */
2789     if (callback != 0) {
2790         cb.reason = BDF_SAVE_START;
2791         cb.total = font->unencoded_used + font->glyphs_used;
2792         cb.current = 0;
2793         (*callback)(&cb, data);
2794     }
2795
2796     /*
2797      * Emit the unencoded bitmaps.
2798      */
2799     for (i = 0, cp = font->unencoded; i < font->unencoded_used; i++, cp++) {
2800         /*
2801          * If the font has character-cell spacing and the option to pad the
2802          * glyphs to the size of the font bbx is set, then pad the glyph.
2803          * Otherwise, crop the glyph to the minimum rectangle needed to hold
2804          * the bitmap.
2805          */
2806         if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0) {
2807             /*
2808              * Point at the temporary glyph structure and copy the necessary
2809              * glyph info into it.
2810              */
2811             c = &cell;
2812             c->name = cp->name;
2813             c->encoding = cp->encoding;
2814             c->swidth = cp->swidth;
2815             c->dwidth = cp->dwidth;
2816             _bdf_pad_cell(font, cp, c);
2817         } else {
2818             c = cp;
2819             _bdf_crop_glyph(font, c);
2820         }
2821
2822         /*
2823          * If the font has monowidth or character-cell spacing, then assign
2824          * the font monowidth field to the device width and recalculate the
2825          * scalable width.
2826          */
2827         if (font->spacing != BDF_PROPORTIONAL) {
2828             c->dwidth = font->monowidth;
2829             ps = (double) font->point_size;
2830             rx = (double) font->resolution_x;
2831             dw = (double) c->dwidth;
2832             c->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
2833         }
2834         if (c->name == 0)
2835           fprintf(out, "STARTCHAR unencoded%d%sENCODING -1%s", i, eol, eol);
2836         else
2837           fprintf(out, "STARTCHAR %s%sENCODING -1%s", c->name, eol, eol);
2838         fprintf(out, "SWIDTH %hd 0%sDWIDTH %hd 0%s",
2839                 c->swidth, eol, c->dwidth, eol);
2840         fprintf(out, "BBX %hd %hd %hd %hd%s", c->bbx.width, c->bbx.height,
2841                 c->bbx.x_offset, c->bbx.y_offset, eol);
2842         fprintf(out, "BITMAP%s", eol);
2843         bpr = ((c->bbx.width * font->bpp) + 7) >> 3;
2844         for (j = 0; bpr != 0 && j < c->bytes; j++) {
2845             if (j && j % bpr == 0)
2846               fprintf(out, eol);
2847             fprintf(out, "%02X", c->bitmap[j]);
2848         }
2849         /*
2850          * Handle empty bitmaps like this.
2851          */
2852         if (c->bbx.height > 0)
2853           fprintf(out, eol);
2854         fprintf(out, "ENDCHAR%s", eol);
2855
2856         /*
2857          * Call the callback if supplied.
2858          */
2859         if (callback != 0) {
2860             cb.reason = BDF_SAVING;
2861             cb.current++;
2862             (*callback)(&cb, data);
2863         }
2864     }
2865
2866     /*
2867      * Emit the other bitmaps.
2868      */
2869     for (i = 0, cp = font->glyphs; i < font->glyphs_used; i++, cp++) {
2870         /*
2871          * If the font has character-cell spacing and the option to pad the
2872          * glyphs to the size of the font bbx is set, then pad the glyph.
2873          * Otherwise, crop the glyph to the minimum rectangle needed to hold
2874          * the bitmap.
2875          */
2876         if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0) {
2877             /*
2878              * Point at the temporary glyph structure and copy the necessary
2879              * glyph info into it.
2880              */
2881             c = &cell;
2882             c->name = cp->name;
2883             c->encoding = cp->encoding;
2884             c->swidth = cp->swidth;
2885             c->dwidth = cp->dwidth;
2886             _bdf_pad_cell(font, cp, c);
2887         } else {
2888             c = cp;
2889             _bdf_crop_glyph(font, c);
2890         }
2891
2892         /*
2893          * If the font has monowidth or character-cell spacing, then assign
2894          * the font monowidth field to the device width and recalculate the
2895          * scalable width.
2896          */
2897         if (font->spacing != BDF_PROPORTIONAL) {
2898             c->dwidth = font->monowidth;
2899             ps = (double) font->point_size;
2900             rx = (double) font->resolution_x;
2901             dw = (double) c->dwidth;
2902             c->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
2903         }
2904         if (c->name == 0)
2905           fprintf(out, "STARTCHAR char%d%sENCODING %d%s",
2906                   c->encoding, eol, c->encoding, eol);
2907         else
2908           fprintf(out, "STARTCHAR %s%sENCODING %d%s",
2909                   c->name, eol, c->encoding, eol);
2910         fprintf(out, "SWIDTH %hd 0%sDWIDTH %hd 0%s",
2911                 c->swidth, eol, c->dwidth, eol);
2912         fprintf(out, "BBX %hd %hd %hd %hd%s", c->bbx.width, c->bbx.height,
2913                 c->bbx.x_offset, c->bbx.y_offset, eol);
2914         fprintf(out, "BITMAP%s", eol);
2915         bpr = ((c->bbx.width * font->bpp) + 7) >> 3;
2916         for (j = 0; bpr != 0 && j < c->bytes; j++) {
2917             if (j && j % bpr == 0)
2918               fprintf(out, eol);
2919             fprintf(out, "%02X", c->bitmap[j]);
2920         }
2921         /*
2922          * Handle empty bitmaps like this.
2923          */
2924         if (c->bbx.height > 0)
2925           fprintf(out, eol);
2926         fprintf(out, "ENDCHAR%s", eol);
2927
2928         /*
2929          * Call the callback if supplied.
2930          */
2931         if (callback != 0) {
2932             cb.reason = BDF_SAVING;
2933             cb.current++;
2934             (*callback)(&cb, data);
2935         }
2936     }
2937
2938     /*
2939      * Emit the trailer.
2940      */
2941     fprintf(out, "ENDFONT%s", eol);
2942
2943     /*
2944      * Always force a final call to the callback to make sure things
2945      * get cleaned up.
2946      */
2947     if (callback != 0) {
2948         cb.reason = BDF_SAVING;
2949         cb.current = cb.total;
2950         (*callback)(&cb, data);
2951     }
2952
2953     /*
2954      * If the font is a character cell font, clean up the temporary glyph.
2955      */
2956     if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0)
2957       free((char *) cell.bitmap);
2958 }
2959
2960 /*
2961  * Routine to write a single set of SBIT metrics.
2962  */
2963 void
2964 bdf_save_sbit_metrics(FILE *out, bdf_font_t *font, bdf_options_t *opts,
2965                       char *appname)
2966 {
2967     char *eol;
2968
2969     eol = 0;
2970     switch (opts->eol) {
2971       case BDF_UNIX_EOL: eol = unix_eol; break;
2972       case BDF_DOS_EOL: eol = dos_eol; break;
2973       case BDF_MAC_EOL: eol = mac_eol; break;
2974     }
2975
2976     /*
2977      * Throw a simple header in.
2978      */
2979     if (appname)
2980       fprintf(out, ";%s; SBIT metrics file generated by \"%s\".%s;%s%s", eol,
2981               appname, eol, eol, eol);
2982
2983     /*
2984      * Save PPEM.
2985      */
2986     fprintf(out, ";%s; Pixels Per Em.%s;%s", eol, eol, eol);
2987     fprintf(out, "PPEM %d%s%s", font->point_size, eol, eol);
2988
2989     /*
2990      * If the font is character cell or monowidth, set this boolean.
2991      */
2992     if (font->spacing != BDF_PROPORTIONAL) {
2993         fprintf(out,
2994                 ";%s; Font is not proportional, so use mono advance.%s;%s",
2995                 eol, eol, eol);
2996         fprintf(out, "FORCECONSTANTMETRICS TRUE%s%s", eol, eol);
2997     } else {
2998         fprintf(out,
2999                 ";%s; Font is proportional, so do not use mono advance.%s;%s",
3000                 eol, eol, eol);
3001         fprintf(out, "FORCECONSTANTMETRICS FALSE%s%s", eol, eol);
3002     }
3003
3004     /*
3005      * Do the horizontal line metrics only.
3006      */
3007     fprintf(out, ";%s; Horizontal line metrics.%s;%s", eol, eol, eol);
3008
3009     fprintf(out, "H_ASCENDER %d%sH_DESCENDER %d%s", font->font_ascent, eol,
3010             font->font_descent, eol);
3011     fprintf(out, "H_WIDTHMAX %hd%s", font->bbx.width, eol);
3012     fprintf(out, "H_MINORIGINSB %hd%sH_MINADVANCEBL %hd%s",
3013             font->bbx.x_offset, eol,
3014             font->bbx.width + font->bbx.x_offset, eol);
3015     fprintf(out, "H_MAXBEFOREBL %hd%sH_MINAFTERBL %hd%s%s",
3016             font->bbx.ascent, eol, font->bbx.y_offset, eol, eol);
3017
3018     /*
3019      * Write the default caret info.
3020      */
3021     fprintf(out, ";%s; Caret slope and offset info.%s;%s", eol, eol, eol);
3022     fprintf(out, "CARETSLOPENUMERATOR 1%sCARETSLOPEDENOMINATOR 0%s", eol, eol);
3023     fprintf(out, "CARETOFFSET 0%s%s", eol, eol);
3024
3025     /*
3026      * Write the bitmap options.
3027      */
3028     fprintf(out, ";%s; Bitmap options.%s;%s", eol, eol, eol);
3029     fprintf(out, "DIRECTION H%sSTORAGE FAST%s%s", eol, eol, eol);
3030
3031     /*
3032      * Scaled bitmaps not implemented yet.
3033      */
3034     fprintf(out, ";%s; Scaled bitmap info (Not Yet Implemented).%s;%s",
3035             eol, eol, eol);
3036 }
3037
3038 /*
3039  * Special routine to dump the font in the Roman Czyborra's hex format.  It
3040  * only dumps the encoded glyphs and assumes the bitmaps have the correct
3041  * sizes.
3042  */
3043 void
3044 bdf_export_hex(FILE *out, bdf_font_t *font, bdf_options_t *opts,
3045                bdf_callback_t callback, void *data)
3046 {
3047     int bpr, fbpr, j, k;
3048     unsigned int i, ng;
3049     bdf_glyph_t *gp, cell;
3050     bdf_callback_struct_t cb;
3051
3052     if (font == 0 || out == 0)
3053       return;
3054
3055     if (font->glyphs_used == 0)
3056       return;
3057
3058     /*
3059      * Call the callback if it was passed to start the export.
3060      */
3061     if (callback != 0) {
3062         cb.reason = BDF_EXPORT_START;
3063         cb.total = font->glyphs_used;
3064         cb.current = 0;
3065         (*callback)(&cb, data);
3066     }
3067
3068     fbpr = ((font->bbx.width * font->bpp) + 7) >> 3;
3069     bpr = (((font->bbx.width >> 1) * font->bpp) + 7) >> 3;
3070     cell.bytes = fbpr * font->bbx.height;
3071     cell.bitmap = (unsigned char *) malloc(cell.bytes);
3072
3073     for (i = 0, ng = font->glyphs_used, gp = font->glyphs; i < ng; i++, gp++) {
3074         _bdf_pad_cell(font, gp, &cell);
3075         fprintf(out, "%04X:", gp->encoding & 0xffff);
3076         if (gp->bbx.width <= (font->bbx.width >> 1)) {
3077             for (j = 0; j < cell.bytes; j += fbpr) {
3078                 for (k = 0; k < bpr; k++)
3079                   fprintf(out, "%02X", cell.bitmap[j + k]);
3080             }
3081         } else {
3082             for (j = 0; j < cell.bytes; j++)
3083               fprintf(out, "%02X", cell.bitmap[j]);
3084         }
3085         if (cell.bytes > 0)
3086           putc('\n', out);
3087
3088         /*
3089          * Call the callback if supplied.
3090          */
3091         if (callback != 0) {
3092             cb.reason = BDF_EXPORTING;
3093             cb.current++;
3094             (*callback)(&cb, data);
3095         }
3096     }
3097
3098     /*
3099      * Clean up the cell.
3100      */
3101     free((char *) cell.bitmap);
3102
3103     /*
3104      * Always call a final callback to make sure the client gets a chance to
3105      * clean things up.
3106      */
3107     if (callback != 0) {
3108         cb.reason = BDF_EXPORTING;
3109         cb.current = cb.total;
3110         (*callback)(&cb, data);
3111     }
3112 }
3113
3114 void
3115 bdf_free_font(bdf_font_t *font)
3116 {
3117     unsigned int i;
3118     bdf_glyph_t *glyphs;
3119
3120     if (font == 0)
3121         return;
3122
3123     if (font->name != 0)
3124       free(font->name);
3125
3126     /*
3127      * Free up the internal hash table of property names.
3128      */
3129     hash_free((hashtable *) font->internal);
3130     free((char *) font->internal);
3131
3132     /*
3133      * Free up the comment info.
3134      */
3135     if (font->comments_len > 0)
3136       free(font->comments);
3137
3138     /*
3139      * Free up the auto-correction messages.
3140      */
3141     if (font->acmsgs_len > 0)
3142       free(font->acmsgs);
3143
3144     /*
3145      * Free up the properties.
3146      */
3147     for (i = 0; i < font->props_size; i++) {
3148         if (font->props[i].format == BDF_ATOM && font->props[i].value.atom)
3149           free(font->props[i].value.atom);
3150     }
3151
3152     if (font->props_size > 0 && font->props != 0)
3153       free((char *) font->props);
3154
3155     /*
3156      * Free up the character info.
3157      */
3158     for (i = 0, glyphs = font->glyphs; i < font->glyphs_used; i++, glyphs++) {
3159         if (glyphs->name)
3160           free(glyphs->name);
3161         if (glyphs->bytes > 0 && glyphs->bitmap != 0)
3162           free((char *) glyphs->bitmap);
3163     }
3164
3165     for (i = 0, glyphs = font->unencoded; i < font->unencoded_used;
3166          i++, glyphs++) {
3167         if (glyphs->name)
3168           free(glyphs->name);
3169         if (glyphs->bytes > 0)
3170           free((char *) glyphs->bitmap);
3171         if (glyphs->unicode.map_size > 0)
3172           free((char *) glyphs->unicode.map);
3173     }
3174
3175     if (font->glyphs_size > 0)
3176       free((char *) font->glyphs);
3177
3178     if (font->unencoded_size > 0)
3179       free((char *) font->unencoded);
3180
3181     /*
3182      * Free up the overflow storage if it was used.
3183      */
3184     for (i = 0, glyphs = font->overflow.glyphs; i < font->overflow.glyphs_used;
3185          i++, glyphs++) {
3186         if (glyphs->name != 0)
3187           free(glyphs->name);
3188         if (glyphs->bytes > 0)
3189           free((char *) glyphs->bitmap);;
3190         if (glyphs->unicode.map_size > 0)
3191           free((char *) glyphs->unicode.map);
3192     }
3193     if (font->overflow.glyphs_size > 0)
3194       free((char *) font->overflow.glyphs);
3195
3196     free((char *) font);
3197 }
3198
3199 void
3200 bdf_create_property(char *name, int format)
3201 {
3202     unsigned int n;
3203     bdf_property_t *p;
3204
3205     /*
3206      * First check to see if the property has
3207      * already been added or not.  If it has, then
3208      * simply ignore it.
3209      */
3210
3211     if (hash_lookup(name, &proptbl))
3212       return;
3213
3214     if (nuser_props == 0)
3215       user_props = (bdf_property_t *) malloc(sizeof(bdf_property_t));
3216     else
3217       user_props = (bdf_property_t *) realloc((char *) user_props,
3218                                               sizeof(bdf_property_t) *
3219                                               (nuser_props + 1));
3220
3221     p = user_props + nuser_props;
3222     (void) memset((char *) p, 0, sizeof(bdf_property_t));
3223     n = (unsigned int) (strlen(name) + 1);
3224     p->name = (char *) malloc(n);
3225     (void) memcpy(p->name, name, n);
3226     p->format = format;
3227     p->builtin = 0;
3228
3229     n = _num_bdf_properties + nuser_props;
3230     hash_insert(p->name, (void *) n, &proptbl);
3231
3232     nuser_props++;
3233 }
3234
3235 bdf_property_t *
3236 bdf_get_property(char *name)
3237 {
3238     hashnode hn;
3239     unsigned int propid;
3240
3241     if (name == 0 || *name == 0)
3242       return 0;
3243
3244     if ((hn = hash_lookup(name, &proptbl)) == 0)
3245       return 0;
3246
3247     propid = (unsigned int) hn->data;
3248     if (propid >= _num_bdf_properties)
3249       return user_props + (propid - _num_bdf_properties);
3250     return _bdf_properties + propid;
3251 }
3252
3253 /*
3254  * Routine to compare two property names.
3255  */
3256 static int
3257 by_prop_name(const void *a, const void *b)
3258 {
3259     bdf_property_t *p1, *p2;
3260
3261     p1 = (bdf_property_t *) a;
3262     p2 = (bdf_property_t *) b;
3263
3264     return strcmp(p1->name, p2->name);
3265 }
3266
3267 unsigned int
3268 bdf_property_list(bdf_property_t **props)
3269 {
3270     unsigned int n;
3271     bdf_property_t *p;
3272
3273     n = _num_bdf_properties + nuser_props;
3274     if (props != 0 && n != 0) {
3275         p = (bdf_property_t *) malloc(sizeof(bdf_property_t) * n);
3276         (void) memcpy((char *) p, (char *) _bdf_properties,
3277                       sizeof(bdf_property_t) * _num_bdf_properties);
3278         (void) memcpy((char *) (p + _num_bdf_properties), (char *) user_props,
3279                       sizeof(bdf_property_t) * nuser_props);
3280         qsort((char *) p, n, sizeof(bdf_property_t), by_prop_name);
3281         *props = p;
3282     }
3283     return n;
3284 }
3285
3286 int
3287 bdf_replace_comments(bdf_font_t *font, char *comments,
3288                      unsigned int comments_len)
3289 {
3290     if (font == 0 || comments_len == 0)
3291       return 0;
3292
3293     if (font->comments_len > 0)
3294       free(font->comments);
3295
3296     font->comments = (char *) malloc(comments_len + 1);
3297     (void) memcpy(font->comments, comments, comments_len);
3298     font->comments[comments_len] = 0;
3299     font->comments_len = comments_len;
3300     font->modified = 1;
3301     return 1;
3302 }
3303
3304 unsigned int
3305 bdf_font_property_list(bdf_font_t *font, bdf_property_t **props)
3306 {
3307     bdf_property_t *p;
3308
3309     if (font == 0 || font->props_used == 0)
3310       return 0;
3311
3312     if (props != 0) {
3313         p = (bdf_property_t *) malloc(sizeof(bdf_property_t) *
3314                                       font->props_used);
3315         (void) memcpy((char *) p, (char *) font->props,
3316                       sizeof(bdf_property_t) * font->props_used);
3317         qsort((char *) p, font->props_used, sizeof(bdf_property_t),
3318               by_prop_name);
3319         *props = p;
3320     }
3321
3322     return font->props_used;
3323 }
3324
3325 void
3326 bdf_add_font_property(bdf_font_t *font, bdf_property_t *property)
3327 {
3328     int len;
3329     unsigned int propid;
3330     hashnode hn;
3331     bdf_property_t *p, *ip;
3332
3333     if (property == 0 || property->name == 0 || property->name[0] == 0)
3334       return;
3335
3336     /*
3337      * If the font does not have a property hash table yet, make
3338      * sure it is allocated.
3339      */
3340     if (font->internal == 0) {
3341         font->internal = (void *) malloc(sizeof(hashtable));
3342         hash_init((hashtable *) font->internal);
3343     }
3344
3345     /*
3346      * See if the property is in the general property table yet.
3347      * If it isn't, then add it.
3348      */
3349     if ((hn = hash_lookup(property->name, &proptbl)) == 0)
3350       bdf_create_property(property->name, property->format);
3351     else {
3352         /*
3353          * If the property exists and is a user defined property, make sure
3354          * its format is updated to match the property being added.
3355          */
3356         propid = (unsigned int) hn->data;
3357         if (propid >= _num_bdf_properties) {
3358             p = user_props + (propid - _num_bdf_properties);
3359             if (p->format != property->format)
3360               p->format = property->format;
3361         }
3362     }
3363
3364     /*
3365      * If the font already has this property, then change the existing one.
3366      */
3367     hn = hash_lookup(property->name, (hashtable *) font->internal);
3368     if (hn != 0) {
3369         /*
3370          * Changing an existing property value.
3371          */
3372         p = font->props + ((unsigned int) hn->data);
3373
3374         /*
3375          * If the format changed, then free the atom value if the original
3376          * format was an atom.
3377          */
3378         if (p->format == BDF_ATOM && property->format != BDF_ATOM &&
3379             p->value.atom != 0)
3380           free((char *) p->value.atom);
3381         p->format = property->format;
3382
3383         switch (p->format) {
3384           case BDF_ATOM:
3385             /*
3386              * If the property value is the same, then just return.
3387              */
3388             if (property->value.atom == p->value.atom ||
3389                 (property->value.atom && p->value.atom &&
3390                  strcmp(property->value.atom, p->value.atom) == 0))
3391               return;
3392             if (property->value.atom == 0)
3393               len = 1;
3394             else
3395               len = strlen(property->value.atom) + 1;
3396             if (len > 1) {
3397                 p->value.atom = (char *) malloc(len);
3398                 (void) memcpy(p->value.atom, property->value.atom, len);
3399             } else
3400               p->value.atom = 0;
3401             break;
3402           case BDF_INTEGER:
3403             /*
3404              * If the property value is the same, then just return.
3405              */
3406             if (p->value.int32 == property->value.int32)
3407               return;
3408             p->value.int32 = property->value.int32;
3409             break;
3410           case BDF_CARDINAL:
3411             /*
3412              * If the property value is the same, then just return.
3413              */
3414             if (p->value.card32 == property->value.card32)
3415               return;
3416             p->value.card32 = property->value.card32;
3417             break;
3418         }
3419     } else {
3420         /*
3421          * New property being added.
3422          */
3423
3424         /*
3425          * Get the internal table entry for a pointer to the
3426          * name of the property.
3427          */
3428         hn = hash_lookup(property->name, &proptbl);
3429         propid = (unsigned int) hn->data;
3430         if (propid >= _num_bdf_properties)
3431           ip = user_props + (propid - _num_bdf_properties);
3432         else
3433           ip = _bdf_properties + propid;
3434
3435         /*
3436          * Add it to the property list first.
3437          */
3438         if (font->props_used == font->props_size) {
3439             if (font->props_size == 0)
3440               font->props = (bdf_property_t *) malloc(sizeof(bdf_property_t));
3441             else
3442               font->props = (bdf_property_t *)
3443                 realloc((char *) font->props, sizeof(bdf_property_t) *
3444                         (font->props_size + 1));
3445             font->props_size++;
3446         }
3447         p = font->props + font->props_used;
3448
3449         p->name = ip->name;
3450         p->format = ip->format;
3451         p->builtin = ip->builtin;
3452
3453         switch (p->format) {
3454           case BDF_ATOM:
3455             if (property->value.atom == 0)
3456               len = 1;
3457             else
3458               len = strlen(property->value.atom) + 1;
3459             if (len > 1) {
3460                 p->value.atom = (char *) malloc(len);
3461                 (void) memcpy(p->value.atom, property->value.atom, len);
3462             } else
3463               p->value.atom = 0;
3464             break;
3465           case BDF_INTEGER:
3466             p->value.int32 = property->value.int32;
3467             break;
3468           case BDF_CARDINAL:
3469             p->value.card32 = property->value.card32;
3470             break;
3471         }
3472
3473         /*
3474          * Now insert it into the internal hash table.
3475          */
3476         hash_insert(p->name, (void *) font->props_used,
3477                     (hashtable *) font->internal);
3478         font->props_used++;
3479     }
3480
3481     if (memcmp(property->name, "DEFAULT_CHAR", 12) == 0)
3482       /*
3483        * If the property just added is DEFAULT_CHAR, then make sure the
3484        * default_glyph field is set.
3485        */
3486       font->default_glyph = p->value.card32;
3487     else if (memcmp(property->name, "FONT_ASCENT", 11) == 0)
3488       /*
3489        * If the property just added is FONT_ASCENT, then adjust the
3490        * font_ascent field.
3491        */
3492       font->font_ascent = p->value.int32;
3493     else if (memcmp(property->name, "FONT_DESCENT", 12) == 0)
3494       /*
3495        * If the property just added is FONT_DESCENT, then adjust the
3496        * font_descent field.
3497        */
3498       font->font_descent = p->value.int32;
3499     else if (memcmp(property->name, "RESOLUTION_X", 12) == 0)
3500       /*
3501        * If the property just added is RESOLUTION_X, then adjust the
3502        * resolution_x field.
3503        */
3504       font->resolution_x = p->value.card32;
3505     else if (memcmp(property->name, "RESOLUTION_Y", 12) == 0)
3506       /*
3507        * If the property just added is RESOLUTION_Y, then adjust the
3508        * resolution_y field.
3509        */
3510       font->resolution_y = p->value.card32;
3511     else if (memcmp(property->name, "POINT_SIZE", 10) == 0)
3512       /*
3513        * If the property just added is POINT_SIZE, then adjust the
3514        * point_size field.
3515        */
3516       font->point_size = p->value.int32 / 10;
3517     else if (memcmp(property->name, "SPACING", 7) == 0) {
3518         /*
3519          * Make sure the font spacing is kept in synch if the property
3520          * changes.  If the spacing changes from proportional to one
3521          * of the others, force the monowidth to be set.
3522          */
3523         switch (p->value.atom[0]) {
3524           case 'C': case 'c':
3525             if (font->spacing == BDF_PROPORTIONAL)
3526               font->monowidth = font->bbx.width + font->bbx.x_offset;
3527             font->spacing = BDF_CHARCELL;
3528             break;
3529           case 'M': case 'm':
3530             if (font->spacing == BDF_PROPORTIONAL)
3531               font->monowidth = font->bbx.width + font->bbx.x_offset;
3532             font->spacing = BDF_MONOWIDTH;
3533             break;
3534           case 'P': case 'p': font->spacing = BDF_PROPORTIONAL; break;
3535         }
3536     }
3537
3538     /*
3539      * Make sure the font is marked as modified.
3540      */
3541     font->modified = 1;
3542 }
3543
3544 void
3545 bdf_delete_font_property(bdf_font_t *font, char *name)
3546 {
3547     hashnode hn;
3548     unsigned int off;
3549     bdf_property_t *p;
3550
3551     if (font == 0 || name == 0 || *name == 0 || font->props_used == 0)
3552       return;
3553
3554     if ((hn = hash_lookup(name, (hashtable *) font->internal)) == 0)
3555       return;
3556
3557     off = (unsigned int) hn->data;
3558     p = font->props + off;
3559
3560     /*
3561      * Delete the ATOM value if appropriate.
3562      */
3563     if (p->format == BDF_ATOM && p->value.atom != 0)
3564       free(p->value.atom);
3565
3566     /*
3567      * The property exists.  Two things needs to be done:
3568      * 1. Remove the property from the hash table.
3569      * 2. Remove the property from the font's list of properties.
3570      */
3571     hash_delete(name, (hashtable *) font->internal);
3572
3573     /*
3574      * Locate its offset in the font property list.
3575      */
3576     if (off < font->props_used - 1)
3577       /*
3578        * We have to shift the property list down.
3579        */
3580       _bdf_memmove((char *) p, (char *) (p + 1),
3581                    sizeof(bdf_property_t) * ((font->props_used - 1) - off));
3582     font->props_used--;
3583
3584     /*
3585      * If the font property happens to be DEFAULT_CHAR, then make sure the
3586      * default_glyph field is reset.
3587      */
3588     if (strncmp(name, "DEFAULT_CHAR", 12) == 0)
3589       font->default_glyph = -1;
3590
3591     /*
3592      * Update the hash table with the correct indexes.
3593      */
3594     for (off = 0, p = font->props; off < font->props_used; off++, p++)
3595       hash_insert(p->name, (void *) off, (hashtable *) font->internal);
3596
3597     /*
3598      * Mark the font as being modified.
3599      */
3600     font->modified = 1;
3601 }
3602
3603 bdf_property_t *
3604 bdf_get_font_property(bdf_font_t *font, char *name)
3605 {
3606     hashnode hn;
3607
3608     if (font == 0 || font->props_size == 0 || name == 0 || *name == 0)
3609       return 0;
3610
3611     hn = hash_lookup(name, (hashtable *) font->internal);
3612     return (hn) ? (font->props + ((unsigned int) hn->data)) : 0;
3613 }
3614
3615 typedef struct {
3616     bdf_options_t *opts;
3617     bdf_options_callback_t callback;
3618     void *client_data;
3619     _bdf_list_t list;
3620 } _bdf_opts_parse_t;
3621
3622 static int
3623 _bdf_get_boolean(char *val)
3624 {
3625     int ok;
3626
3627     ok = 0;
3628     if (val == 0 || *val == 0)
3629       return ok;
3630
3631     switch (val[0]) {
3632       case '0': case 'F': case 'f': case 'N': case 'n': ok = 0; break;
3633       case '1': case 'T': case 't': case 'Y': case 'y': ok = 1; break;
3634     }
3635     return ok;
3636 }
3637
3638 static int
3639 _bdf_parse_options(char *line, unsigned int linelen, unsigned int lineno,
3640                    void *call_data, void *client_data)
3641 {
3642     _bdf_list_t *lp;
3643     _bdf_opts_parse_t *p;
3644     int bpp;
3645
3646     p = (_bdf_opts_parse_t *) client_data;
3647     lp = &p->list;
3648
3649     /*
3650      * Split the line into fields.
3651      */
3652     _bdf_split(" \t+", line, linelen, lp);
3653
3654     if (lp->field[0][0] == 'b' &&
3655         memcmp(lp->field[0], "bits_per_pixel", 14) == 0) {
3656         if (lp->used < 2) {
3657             fprintf(stderr,
3658                     "bdf: warning: %d: incorrect number of fields %d.\n",
3659                     lineno, lp->used);
3660             fprintf(stderr,
3661                     "bdf: warning: %d: bits_per_pixel <1, 2, or 4>.\n",
3662                     lineno);
3663         } else {
3664             bpp = _bdf_atol(lp->field[1], 0, 10);
3665             if (!(bpp == 1 || bpp == 2 || bpp == 4)) {
3666                 fprintf(stderr,
3667                         "bdf: warning: %d: invalid bits per pixel %d.\n",
3668                         lineno, bpp);
3669                 fprintf(stderr,
3670                         "bdf: warning: %d: bits_per_pixel <1, 2, or 4>.\n",
3671                         lineno);
3672             } else
3673               p->opts->bits_per_pixel = bpp;
3674         }
3675         return 0;
3676     }
3677
3678     if (lp->field[0][0] == 'e' && memcmp(lp->field[0], "eol", 3) == 0) {
3679         if (lp->used < 2) {
3680             fprintf(stderr,
3681                     "bdf: warning: %d: incorrect number of fields %d.\n",
3682                     lineno, lp->used);
3683             fprintf(stderr,
3684                     "bdf: warning: %d: eol <eolname>.\n", lineno);
3685         } else {
3686             switch (lp->field[1][0]) {
3687               case 'u': case 'U': p->opts->eol = BDF_UNIX_EOL; break;
3688               case 'd': case 'D': p->opts->eol = BDF_DOS_EOL; break;
3689               case 'm': case 'M': p->opts->eol = BDF_MAC_EOL; break;
3690             }
3691         }
3692         return 0;
3693     }
3694
3695     if (lp->field[0][0] == 'c' &&
3696         memcmp(lp->field[0], "correct_metrics", 15) == 0) {
3697         if (lp->used < 2) {
3698             fprintf(stderr,
3699                     "bdf: warning: %d: incorrect number of fields %d.\n",
3700                     lineno, lp->used);
3701             fprintf(stderr,
3702                     "bdf: warning: %d: correct_metrics <boolean>.\n", lineno);
3703         } else
3704           p->opts->correct_metrics = _bdf_get_boolean(lp->field[1]);
3705
3706         return 0;
3707     }
3708
3709     if (lp->field[0][0] == 'k' &&
3710         memcmp(lp->field[0], "keep_unencoded", 14) == 0) {
3711         if (lp->used < 2) {
3712             fprintf(stderr,
3713                     "bdf: warning: %d: incorrect number of fields %d.\n",
3714                     lineno, lp->used);
3715             fprintf(stderr,
3716                     "bdf: warning: %d: keep_unencoded <boolean>.\n", lineno);
3717         } else
3718           p->opts->keep_unencoded = _bdf_get_boolean(lp->field[1]);
3719
3720         return 0;
3721     }
3722
3723     if (lp->field[0][0] == 'k' &&
3724         memcmp(lp->field[0], "keep_comments", 13) == 0) {
3725         if (lp->used < 2) {
3726             fprintf(stderr,
3727                     "bdf: warning: %d: incorrect number of fields %d.\n",
3728                     lineno, lp->used);
3729             fprintf(stderr,
3730                     "bdf: warning: %d: keep_comments <boolean>.\n", lineno);
3731         } else
3732           p->opts->keep_comments = _bdf_get_boolean(lp->field[1]);
3733
3734         return 0;
3735     }
3736
3737     if (lp->field[0][0] == 'p' &&
3738         memcmp(lp->field[0], "pad_character_cells", 19) == 0) {
3739         if (lp->used < 2) {
3740             fprintf(stderr,
3741                     "bdf: warning: %d: incorrect number of fields %d.\n",
3742                     lineno, lp->used);
3743             fprintf(stderr,
3744                     "bdf: warning: %d: pad_character_cells <boolean>.\n",
3745                     lineno);
3746         } else
3747           p->opts->pad_cells = _bdf_get_boolean(lp->field[1]);
3748
3749         return 0;
3750     }
3751
3752     if (lp->field[0][0] == 'p' &&
3753         memcmp(lp->field[0], "point_size", 10) == 0) {
3754         if (lp->used < 2) {
3755             fprintf(stderr,
3756                     "bdf: warning: %d: incorrect number of fields %d.\n",
3757                     lineno, lp->used);
3758             fprintf(stderr,
3759                     "bdf: warning: %d: point_size <integer>.\n", lineno);
3760         } else
3761           p->opts->point_size = _bdf_atol(lp->field[1], 0, 10);
3762         return 0;
3763     }
3764
3765     if (lp->field[0][0] == 'h' &&
3766         memcmp(lp->field[0], "horizontal_resolution", 21) == 0) {
3767         if (lp->used < 2) {
3768             fprintf(stderr,
3769                     "bdf: warning: %d: incorrect number of fields %d.\n",
3770                     lineno, lp->used);
3771             fprintf(stderr,
3772                     "bdf: warning: %d: horizontal_resolution <cardinal>.\n",
3773                     lineno);
3774         } else
3775           p->opts->resolution_x = _bdf_atoul(lp->field[1], 0, 10);
3776         return 0;
3777     }
3778
3779     if (lp->field[0][0] == 'v' &&
3780         memcmp(lp->field[0], "vertical_resolution", 19) == 0) {
3781         if (lp->used < 2) {
3782             fprintf(stderr,
3783                     "bdf: warning: %d: incorrect number of fields %d.\n",
3784                     lineno, lp->used);
3785             fprintf(stderr,
3786                     "bdf: warning: %d: vertical_resolution <cardinal>.\n",
3787                     lineno);
3788         } else
3789           p->opts->resolution_y = _bdf_atoul(lp->field[1], 0, 10);
3790         return 0;
3791     }
3792
3793     if (lp->field[0][0] == 'f' &&
3794         memcmp(lp->field[0], "font_spacing", 12) == 0) {
3795         if (lp->used < 2) {
3796             fprintf(stderr,
3797                     "bdf: warning: %d: incorrect number of fields %d.\n",
3798                     lineno, lp->used);
3799             fprintf(stderr,
3800                     "bdf: warning: %d: font_spacing <spacing name>.\n",
3801                     lineno);
3802         } else {
3803             switch (lp->field[1][0]) {
3804               case 'P': case 'p':
3805                 p->opts->font_spacing = BDF_PROPORTIONAL;
3806                 break;
3807               case 'M': case 'm':
3808                 p->opts->font_spacing = BDF_MONOWIDTH;
3809                 break;
3810               case 'C': case 'c':
3811                 p->opts->font_spacing = BDF_CHARCELL;
3812                 break;
3813               default:
3814                 fprintf(stderr,
3815                         "bdf: warning: %d: unknown font spacing '%s'.\n",
3816                         lineno, lp->field[1]);
3817             }
3818         }
3819         return 0;
3820     }
3821
3822     if (lp->field[0][0] == 'p' &&
3823         memcmp(lp->field[0], "property", 8) == 0) {
3824         if (lp->used < 3) {
3825             fprintf(stderr,
3826                     "bdf: warning: %d: incorrect number of fields %d.\n",
3827                     lineno, lp->used);
3828             fprintf(stderr,
3829                     "bdf: warning: %d: property <name> <type>.\n",
3830                     lineno);
3831         } else {
3832             switch (lp->field[2][0]) {
3833               case 'A': case 'a':
3834                 bdf_create_property(lp->field[1], BDF_ATOM);
3835                 break;
3836               case 'C': case 'c':
3837                 bdf_create_property(lp->field[1], BDF_CARDINAL);
3838                 break;
3839               case 'I': case 'i':
3840                 bdf_create_property(lp->field[1], BDF_INTEGER);
3841                 break;
3842               default:
3843                 fprintf(stderr,
3844                         "bdf: warning: %d: unknown property type '%s'.\n",
3845                         lineno, lp->field[2]);
3846             }
3847         }
3848         return 0;
3849     }
3850
3851     if (lp->field[0][0] == 'h' &&
3852         (memcmp(lp->field[0], "hint_truetype_glyphs", 20) == 0 ||
3853          memcmp(lp->field[0], "hint_opentype_glyphs", 20) == 0)) {
3854         if (lp->used < 2) {
3855             fprintf(stderr,
3856                     "bdf: warning: %d: incorrect number of fields %d.\n",
3857                     lineno, lp->used);
3858             fprintf(stderr,
3859                     "bdf: warning: %d: hint_opentype_glyphs <boolean>.\n",
3860                     lineno);
3861         } else {
3862 #ifdef HAVE_FREETYPE
3863             if (_bdf_get_boolean(lp->field[1]))
3864               p->opts->otf_flags &= ~FT_LOAD_NO_HINTING;
3865             else
3866               p->opts->otf_flags |= FT_LOAD_NO_HINTING;
3867 #else
3868             p->opts->otf_flags = 0;
3869 #endif /* HAVE_FREETYPE */
3870         }
3871
3872         return 0;
3873     }
3874
3875     if (lp->field[0][0] == 'g' &&
3876         memcmp(lp->field[0], "generate_ranges", 15) == 0)
3877       /*
3878        * Simply ignore the glyph ranges entry in the config file.
3879        */
3880       return 0;
3881
3882     /*
3883      * If the callback returns a non-zero value, the caller has handled the
3884      * unknown option found in the file.
3885      */
3886     if (p->callback != 0 &&
3887         (*p->callback)(p->opts, lp->field, lp->used, p->client_data) != 0)
3888       return 0;
3889
3890     fprintf(stderr, "bdf: warning: %d: unknown configuration option '%s'.\n",
3891             lineno, lp->field[0]);
3892     return 0;
3893 }
3894
3895 void
3896 bdf_load_options(FILE *in, bdf_options_t *opts,
3897                  bdf_options_callback_t callback, void *client_data)
3898 {
3899     unsigned int lineno;
3900     _bdf_opts_parse_t p;
3901
3902     /*
3903      * Don't bother loading the options if the file or options structure
3904      * is NULL.
3905      */
3906     if (in == 0 || opts == 0)
3907       return;
3908
3909     (void *) memset((char *) &p, 0, sizeof(_bdf_opts_parse_t));
3910     p.opts = opts;
3911     p.callback = callback;
3912     p.client_data = client_data;
3913     (void) _bdf_readlines(fileno(in), _bdf_parse_options, (void *) &p,
3914                           &lineno);
3915
3916     /*
3917      * Free up the list if there is any space allocated.
3918      */
3919     if (p.list.size > 0)
3920       free((char *) p.list.field);
3921 }
3922
3923 void
3924 bdf_save_options(FILE *out, bdf_options_t *opts)
3925 {
3926     unsigned int i;
3927
3928     if (out == 0 || opts == 0)
3929       return;
3930
3931     fprintf(out, "#\n# Metrics corrections.\n#\ncorrect_metrics ");
3932     if (opts->correct_metrics)
3933       fprintf(out, "true\n\n");
3934     else
3935       fprintf(out, "false\n\n");
3936
3937     fprintf(out, "#\n# Preserve unencoded glyphs.\n#\nkeep_unencoded ");
3938     if (opts->keep_unencoded)
3939       fprintf(out, "true\n\n");
3940     else
3941       fprintf(out, "false\n\n");
3942
3943     fprintf(out, "#\n# Preserve comments.\n#\nkeep_comments ");
3944     if (opts->keep_comments)
3945       fprintf(out, "true\n\n");
3946     else
3947       fprintf(out, "false\n\n");
3948
3949     fprintf(out, "#\n# Pad character cells.\n#\npad_character_cells ");
3950     if (opts->pad_cells)
3951       fprintf(out, "true\n\n");
3952     else
3953       fprintf(out, "false\n\n");
3954
3955     fprintf(out, "#\n# Font spacing.\n#\nfont_spacing ");
3956     switch (opts->font_spacing) {
3957       case BDF_PROPORTIONAL: fprintf(out, "proportional\n\n"); break;
3958       case BDF_MONOWIDTH: fprintf(out, "monowidth\n\n"); break;
3959       case BDF_CHARCELL: fprintf(out, "charactercell\n\n"); break;
3960     }
3961
3962     fprintf(out, "#\n# Point size.\n#\npoint_size %d\n\n", opts->point_size);
3963
3964     fprintf(out,
3965             "#\n# Horizontal resolution.\n#\nhorizontal_resolution %d\n\n",
3966             opts->resolution_x);
3967
3968     fprintf(out,
3969             "#\n# Vertical resolution.\n#\nvertical_resolution %d\n\n",
3970             opts->resolution_x);
3971
3972     fprintf(out,
3973             "#\n# Bits per pixel.\n#\nbits_per_pixel %d\n\n",
3974             opts->bits_per_pixel);
3975
3976     fprintf(out, "#\n# Hint OpenType glyphs.\n#\nhint_opentype_glyphs ");
3977 #ifdef HAVE_FREETYPE
3978     if (opts->otf_flags & FT_LOAD_NO_HINTING)
3979       fprintf(out, "false\n\n");
3980     else
3981       fprintf(out, "true\n\n");
3982 #else
3983     fprintf(out, "false\n\n");
3984 #endif /* HAVE_FREETYPE */
3985
3986     fprintf(out, "#\n# Set the EOL used when writing BDF fonts.\n#\neol ");
3987     switch (opts->eol) {
3988       case BDF_UNIX_EOL: fprintf(out, "unix\n\n"); break;
3989       case BDF_DOS_EOL: fprintf(out, "dos\n\n"); break;
3990       case BDF_MAC_EOL: fprintf(out, "mac\n\n"); break;
3991     }
3992
3993     /*
3994      * Write out the user defined properties if they exist.
3995      */
3996     if (nuser_props == 0)
3997       return;
3998
3999     fprintf(out, "#\n# User defined properties.\n#\n");
4000
4001     for (i = 0; i < nuser_props; i++) {
4002         fprintf(out, "property %s ", user_props[i].name);
4003         switch (user_props[i].format) {
4004           case BDF_ATOM: fprintf(out, "atom\n"); break;
4005           case BDF_CARDINAL: fprintf(out, "cardinal\n"); break;
4006           case BDF_INTEGER: fprintf(out, "integer\n"); break;
4007         }
4008     }
4009 }
4010
4011 void
4012 bdf_default_options(bdf_options_t *opts)
4013 {
4014     if (opts == 0)
4015       return;
4016
4017     (void) memcpy((char *) opts, (char *) &_bdf_opts, sizeof(bdf_options_t));
4018 }
4019
4020 bdf_font_t *
4021 bdf_new_font(char *name, int point_size, int resolution_x, int resolution_y,
4022              int spacing, int bpp)
4023 {
4024     int psize;
4025     char sp[2];
4026     bdf_font_t *font;
4027     double dp, dr;
4028     bdf_property_t prop;
4029
4030     font = (bdf_font_t *) calloc(1, sizeof(bdf_font_t));
4031     if (name != 0 && *name != 0) {
4032         font->name = (char *) malloc(strlen(name) + 1);
4033         (void) strcpy(font->name, name);
4034     }
4035
4036     font->bpp = bpp;
4037     font->point_size = point_size;
4038     font->resolution_x = resolution_x;
4039     font->resolution_y = resolution_y;
4040
4041     /*
4042      * Determine the pixel size of the new font based on the
4043      * point size and resolution.
4044      */
4045     dr = (double) resolution_y;
4046     dp = (double) (point_size * 10);
4047     psize = (int) (((dp * dr) / 722.7) + 0.5);
4048
4049     /*
4050      * Make the default width about 1.5 smaller than the height.
4051      */
4052     font->bbx.height = psize;
4053     font->bbx.width = ((double) psize) / 1.5;
4054
4055     /*
4056      * Now determine the default ascent and descent assuming a
4057      * the descent is about 1/4 the ascent.
4058      */
4059     font->bbx.descent = psize >> 2;
4060     font->bbx.ascent = psize - font->bbx.descent;
4061
4062     font->bbx.y_offset = -font->bbx.descent;
4063
4064     /*
4065      * Allocation the internal hash tables.
4066      */
4067     font->internal = (void *) malloc(sizeof(hashtable));
4068     hash_init((hashtable *) font->internal);
4069
4070     font->default_glyph = -1;
4071     font->spacing = spacing;
4072
4073     /*
4074      * Add various useful properties.
4075      */
4076     prop.name = "POINT_SIZE";
4077     prop.format = BDF_INTEGER;
4078     prop.value.int32 = font->point_size * 10;
4079     bdf_add_font_property(font, &prop);
4080
4081     prop.name = "PIXEL_SIZE";
4082     prop.format = BDF_INTEGER;
4083     prop.value.int32 = psize;
4084     bdf_add_font_property(font, &prop);
4085
4086     prop.name = "RESOLUTION_X";
4087     prop.format = BDF_CARDINAL;
4088     prop.value.card32 = (unsigned int) font->resolution_x;
4089     bdf_add_font_property(font, &prop);
4090
4091     prop.name = "RESOLUTION_Y";
4092     prop.format = BDF_CARDINAL;
4093     prop.value.card32 = (unsigned int) font->resolution_y;
4094     bdf_add_font_property(font, &prop);
4095
4096     prop.name = "FONT_ASCENT";
4097     prop.format = BDF_INTEGER;
4098     prop.value.int32 = (int) font->bbx.ascent;
4099     bdf_add_font_property(font, &prop);
4100
4101     prop.name = "FONT_DESCENT";
4102     prop.format = BDF_INTEGER;
4103     prop.value.int32 = (int) font->bbx.descent;
4104     bdf_add_font_property(font, &prop);
4105
4106     prop.name = "AVERAGE_WIDTH";
4107     prop.format = BDF_INTEGER;
4108     prop.value.int32 = font->bbx.width * 10;
4109     bdf_add_font_property(font, &prop);
4110
4111     sp[0] = 'P';
4112     sp[1] = 0;
4113     switch (spacing) {
4114       case BDF_PROPORTIONAL: sp[0] = 'P'; break;
4115       case BDF_MONOWIDTH: sp[0] = 'M'; break;
4116       case BDF_CHARCELL: sp[0] = 'C'; break;
4117     }
4118     prop.name = "SPACING";
4119     prop.format = BDF_ATOM;
4120     prop.value.atom = sp;
4121     bdf_add_font_property(font, &prop);
4122
4123     /*
4124      * Mark the font as unmodified.
4125      */
4126     font->modified = 0;
4127
4128     return font;
4129 }
4130
4131 void
4132 bdf_set_default_metrics(bdf_font_t *font)
4133 {
4134     int psize;
4135     double dp, dr;
4136     bdf_property_t prop;
4137
4138     /*
4139      * Determine the pixel size of the new font based on the
4140      * point size and resolution.
4141      */
4142     dr = (double) font->resolution_y;
4143     dp = (double) (font->point_size * 10);
4144     psize = (int) (((dp * dr) / 722.7) + 0.5);
4145
4146     /*
4147      * Make the default width about 1.5 smaller than the height.
4148      */
4149     font->bbx.height = psize;
4150     font->bbx.width = ((double) psize) / 1.5;
4151
4152     /*
4153      * Now determine the default ascent and descent assuming a
4154      * the descent is about 1/4 the ascent.
4155      */
4156     font->bbx.descent = psize >> 2;
4157     font->bbx.ascent = psize - font->bbx.descent;
4158
4159     font->bbx.y_offset = -font->bbx.descent;
4160
4161     font->default_glyph = -1;
4162
4163     /*
4164      * Add various useful properties.
4165      */
4166     prop.name = "FONT_ASCENT";
4167     prop.format = BDF_INTEGER;
4168     prop.value.int32 = (int) font->bbx.ascent;
4169     bdf_add_font_property(font, &prop);
4170
4171     prop.name = "FONT_DESCENT";
4172     prop.format = BDF_INTEGER;
4173     prop.value.int32 = (int) font->bbx.descent;
4174     bdf_add_font_property(font, &prop);
4175
4176     prop.name = "AVERAGE_WIDTH";
4177     prop.format = BDF_INTEGER;
4178     prop.value.int32 = font->bbx.width * 10;
4179     bdf_add_font_property(font, &prop);
4180 }
4181
4182 int
4183 bdf_glyph_modified(bdf_font_t *font, int which, int unencoded)
4184 {
4185     if (font == 0 || which < 0)
4186       return 0;
4187
4188     if (unencoded)
4189       return _bdf_glyph_modified(font->umod, which);
4190     else
4191       return _bdf_glyph_modified(font->nmod, which);
4192 }
4193
4194 void
4195 bdf_copy_glyphs(bdf_font_t *font, int start, int end,
4196                 bdf_glyphlist_t *glyphs, int unencoded)
4197 {
4198     int tmp, i, nc;
4199     bdf_glyph_t *cp, *dp;
4200     short maxas, maxds, maxrb, minlb, maxlb, rb;
4201
4202     if (start > end) {
4203         tmp = end;
4204         end = start;
4205         start = tmp;
4206     }
4207
4208     glyphs->bpp = font->bpp;
4209     glyphs->start = start;
4210     glyphs->end = end;
4211     glyphs->glyphs_used = 0;
4212
4213     tmp = (end - start) + 1;
4214     if (tmp > glyphs->glyphs_size) {
4215         if (glyphs->glyphs_size == 0)
4216           glyphs->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * tmp);
4217         else
4218           glyphs->glyphs = (bdf_glyph_t *) realloc((char *) glyphs->glyphs,
4219                                                    sizeof(bdf_glyph_t) * tmp);
4220         cp = glyphs->glyphs + glyphs->glyphs_size;
4221         (void) memset((char *) cp, 0,
4222                       sizeof(bdf_glyph_t) * (tmp - glyphs->glyphs_size));
4223         glyphs->glyphs_size = tmp;
4224     }
4225
4226     /*
4227      * Clear out bitmaps, names and any PSF Unicode mappings in the existing
4228      * entries.
4229      */
4230     for (cp = glyphs->glyphs, i = 0; i < glyphs->glyphs_size; i++, cp++) {
4231         if (cp->name != 0)
4232           free(cp->name);
4233         if (cp->bytes > 0)
4234           free((char *) cp->bitmap);
4235         if (cp->unicode.map_size > 0)
4236           free((char *) cp->unicode.map);
4237     }
4238
4239     /*
4240      * Zero out everything.
4241      */
4242     (void) memset((char *) &glyphs->bbx, 0, sizeof(bdf_bbx_t));
4243     (void) memset((char *) glyphs->glyphs, 0,
4244                   sizeof(bdf_glyph_t) * glyphs->glyphs_size);
4245
4246     /*
4247      * Initialize the bounds used to generate the overall bounding box for the
4248      * set of glyphs being copied.
4249      */
4250     minlb = font->bbx.width;
4251     maxlb = maxrb = maxas = maxds = 0;
4252
4253     /*
4254      * Do the copy.
4255      */
4256     nc = (unencoded == 0) ? font->glyphs_used : font->unencoded_used;
4257     cp = (unencoded == 0) ? font->glyphs : font->unencoded;
4258     dp = glyphs->glyphs;
4259
4260     for (i = 0;
4261          i < nc && ((unencoded && i <= end) || cp->encoding <= end);
4262          i++, cp++) {
4263         if ((unencoded && i >= start) || cp->encoding >= start) {
4264             (void) memcpy((char *) dp, (char *) cp, sizeof(bdf_glyph_t));
4265             if (cp->name != 0) {
4266                 dp->name = (char *) malloc(strlen(cp->name) + 1);
4267                 (void) strcpy(dp->name, cp->name);
4268             }
4269             if (cp->bytes > 0) {
4270                 dp->bytes = cp->bytes;
4271                 dp->bitmap = (unsigned char *) malloc(cp->bytes);
4272                 (void) memcpy((char *) dp->bitmap, (char *) cp->bitmap,
4273                               cp->bytes);
4274             }
4275             if (cp->unicode.map_used > 0) {
4276                 dp->unicode.map_used = dp->unicode.map_size =
4277                     cp->unicode.map_used;
4278                 dp->unicode.map =
4279                     (unsigned char *) malloc(dp->unicode.map_used);
4280                 (void) memcpy((char *) dp->unicode.map,
4281                               (char *) cp->unicode.map,
4282                               dp->unicode.map_used);
4283             }
4284
4285             /*
4286              * Determine the overall metrics for the group of characters being
4287              * copied.
4288              */
4289             maxas = MAX(cp->bbx.ascent, maxas);
4290             maxds = MAX(cp->bbx.descent, maxds);
4291             rb = cp->bbx.width + cp->bbx.x_offset;
4292             maxrb = MAX(rb, maxrb);
4293             minlb = MIN(cp->bbx.x_offset, minlb);
4294             maxlb = MAX(cp->bbx.x_offset, maxlb);
4295
4296             glyphs->glyphs_used++;
4297             dp++;
4298         }
4299     }
4300
4301     /*
4302      * Set the overall metrics for this set of glyphs.
4303      */
4304     glyphs->bbx.width = maxrb - minlb;
4305     glyphs->bbx.x_offset = minlb;
4306
4307     glyphs->bbx.height = maxas + maxds;
4308     glyphs->bbx.ascent = maxas;
4309     glyphs->bbx.descent = maxds;
4310     glyphs->bbx.y_offset = -maxds;
4311 }
4312
4313 bdf_glyph_t *
4314 _bdf_locate_glyph(bdf_font_t *font, int code, int unencoded)
4315 {
4316     int l, r, m, nc;
4317     bdf_glyph_t *gl;
4318
4319     if (code < 0 || font == 0)
4320       return 0;
4321
4322     if ((unencoded && font->unencoded_used == 0) ||
4323         font->glyphs_used == 0)
4324       return 0;
4325
4326     if (unencoded) {
4327         gl = font->unencoded;
4328         nc = font->unencoded_used;
4329     } else {
4330         gl = font->glyphs;
4331         nc = font->glyphs_used;
4332     }
4333     for (l = m = 0, r = nc - 1; l < r; ) {
4334         m = (l + r) >> 1;
4335         if (gl[m].encoding < code)
4336           l = m + 1;
4337         else if (gl[m].encoding > code)
4338           r = m - 1;
4339         else
4340           break;
4341     }
4342
4343     /*
4344      * Go back until we hit the beginning of the glyphs or until
4345      * we find the glyph with a code less than the specified code.
4346      */
4347     l = m;
4348     while (m > 0 && gl[m].encoding > code)
4349       m--;
4350
4351     /*
4352      * Look forward if necessary.
4353      */
4354     m = l;
4355     while (m < nc && gl[m].encoding < code)
4356       m++;
4357
4358     return (m < nc) ? &gl[m] : &gl[nc - 1];
4359 }
4360
4361 int
4362 bdf_delete_glyphs(bdf_font_t *font, int start, int end, int unencoded)
4363 {
4364     int i, n, nc, cnt, mod;
4365     bdf_glyph_t *cp, *sp, *ep;
4366
4367     mod = 0;
4368
4369     if (font == 0)
4370       return mod;
4371
4372     if (start > end) {
4373         cnt = end;
4374         end = start;
4375         start = cnt;
4376     }
4377
4378     nc = (unencoded == 0) ? font->glyphs_used : font->unencoded_used;
4379     cp = (unencoded == 0) ? font->glyphs : font->unencoded;
4380     sp = ep = 0;
4381
4382     for (i = 0; i < nc && cp->encoding <= end; i++, cp++) {
4383         if (cp->encoding >= start && sp == 0)
4384           sp = cp;
4385     }
4386     ep = cp;
4387     if (sp == 0)
4388       sp = ep;
4389
4390     if (ep > sp) {
4391         /*
4392          * There are some glyphs to delete.
4393          * 1. Free the name and bitmap fields of the glyphs being deleted.
4394          * 2. Move the end range down if necessary.
4395          * 3. Clear the glyphs on the end if a move was done.
4396          */
4397
4398         /*
4399          * Mark the font as being modified.
4400          */
4401         mod = font->modified = 1;
4402
4403         cnt = ep - sp;
4404
4405         for (cp = sp; cp < ep; cp++) {
4406             /*
4407              * Mark the glyphs being deleted as also being modified so the
4408              * empty cells can be shown correctly by the client programs.
4409              */
4410             if (unencoded)
4411               _bdf_set_glyph_modified(font->umod, cp->encoding);
4412             else
4413               _bdf_set_glyph_modified(font->nmod, cp->encoding);
4414
4415             if (cp->name != 0)
4416               free(cp->name);
4417             if (cp->bytes > 0)
4418               free((char *) cp->bitmap);
4419         }
4420
4421         cp = (unencoded == 0) ? font->glyphs : font->unencoded;
4422
4423         /*
4424          * Check to see if there are some glyphs that need to
4425          * be moved down.
4426          */
4427         if (ep - cp < nc) {
4428             /*
4429              * Shift the glyphs down.
4430              */
4431             n = nc - (ep - cp);
4432             _bdf_memmove((char *) sp, (char *) ep, sizeof(bdf_glyph_t) * n);
4433
4434             /*
4435              * Set the starting point for the clear.
4436              */
4437             ep = sp + n;
4438         } else
4439           /*
4440            * Set the starting point for the clear.
4441            */
4442           ep = sp;
4443
4444         /*
4445          * Clear the glyph space just moved.
4446          */
4447         n = nc - (ep - cp);
4448         (void) memset((char *) ep, 0, sizeof(bdf_glyph_t) * n);
4449
4450         /*
4451          * Adjust the number of glyphs used.
4452          */
4453         if (unencoded == 0)
4454           font->glyphs_used -= cnt;
4455         else
4456           font->unencoded_used -= cnt;
4457
4458         /*
4459          * If unencoded glyphs were deleted, re-encode all
4460          * of them to cause a shift when everything is redrawn.
4461          */
4462         if (unencoded != 0) {
4463             for (i = 0, cp = font->unencoded; i < font->unencoded_used;
4464                  i++, cp++) {
4465                 if (_bdf_glyph_modified(font->umod, cp->encoding)) {
4466                     _bdf_clear_glyph_modified(font->umod, cp->encoding);
4467                     _bdf_set_glyph_modified(font->umod, i);
4468                 }
4469                 cp->encoding = i;
4470             }
4471         }
4472     }
4473     return mod;
4474 }
4475
4476 /*
4477  * These values are intended to give pixels mapped from 1bpp to nbpp the
4478  * darkest available index, which is 1.
4479  */
4480 static unsigned char twobpp_ones[] = {0x40, 0x10, 0x04, 0x01};
4481 static unsigned char fourbpp_ones[] = {0x10, 0x01};
4482 static unsigned char eightbpp_ones[] = {0x01};
4483
4484 /*
4485  * Routines for quick and dirty dithering.
4486  */
4487 static void
4488 _bdf_one_to_n(bdf_glyphlist_t *gl, int n)
4489 {
4490     int i;
4491     unsigned short bpr, sbpr, bytes, col, sx, sy;
4492     unsigned char *nbmap, *ones = 0;
4493     bdf_glyph_t *gp;
4494
4495     if (gl == 0 || gl->glyphs_used == 0)
4496       return;
4497
4498     switch (n) {
4499       case 1: ones = bdf_onebpp; break;
4500       case 2: ones = twobpp_ones; break;
4501       case 4: ones = fourbpp_ones; break;
4502       case 8: ones = eightbpp_ones; break;
4503     }
4504
4505     gl->bpp = n;
4506     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4507         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4508           continue;
4509         sbpr = (gp->bbx.width + 7) >> 3;
4510         bpr = ((gp->bbx.width * n) + 7) >> 3;
4511         bytes = bpr * gp->bbx.height;
4512         nbmap = (unsigned char *) malloc(bytes);
4513         (void) memset((char *) nbmap, 0, bytes);
4514
4515         for (sy = 0; sy < gp->bbx.height; sy++) {
4516             for (col = sx = 0; sx < gp->bbx.width; sx++, col += n) {
4517                 if (gp->bitmap[(sy * sbpr) + (sx >> 3)] & (0x80 >> (sx & 7)))
4518                   nbmap[(sy * bpr) + (col >> 3)] |= ones[(col & 7) / n];
4519             }
4520         }
4521         free((char *) gp->bitmap);
4522         gp->bytes = bytes;
4523         gp->bitmap = nbmap;
4524     }
4525 }
4526
4527 static void
4528 _bdf_n_to_one(bdf_glyphlist_t *gl)
4529 {
4530     int i;
4531     unsigned short bpr, sbpr, bytes, col, sx, sy;
4532     unsigned char *nbmap, *masks;
4533     bdf_glyph_t *gp;
4534
4535     if (gl == 0 || gl->glyphs_used == 0)
4536       return;
4537
4538     masks = 0;
4539     switch (gl->bpp) {
4540       case 1: masks = bdf_onebpp; break;
4541       case 2: masks = bdf_twobpp; break;
4542       case 4: masks = bdf_fourbpp; break;
4543       case 8: masks = bdf_eightbpp; break;
4544     }
4545
4546     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4547         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4548           continue;
4549         sbpr = ((gp->bbx.width * gl->bpp) + 7) >> 3;
4550         bpr = (gp->bbx.width + 7) >> 3;
4551         bytes = bpr * gp->bbx.height;
4552         nbmap = (unsigned char *) malloc(bytes);
4553         (void) memset((char *) nbmap, 0, bytes);
4554
4555         for (sy = 0; sy < gp->bbx.height; sy++) {
4556             for (col = sx = 0; sx < gp->bbx.width; sx++, col += gl->bpp) {
4557                 if (gp->bitmap[(sy * sbpr) + (col >> 3)] &
4558                     masks[(col & 7) / gl->bpp])
4559                   nbmap[(sy * bpr) + (sx >> 3)] |= (0x80 >> (sx & 7));
4560             }
4561         }
4562         free((char *) gp->bitmap);
4563         gp->bytes = bytes;
4564         gp->bitmap = nbmap;
4565     }
4566     gl->bpp = 1;
4567 }
4568
4569 static void
4570 _bdf_two_to_four(bdf_glyphlist_t *gl)
4571 {
4572     int i;
4573     unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy;
4574     unsigned char *nbmap, *masks;
4575     bdf_glyph_t *gp;
4576
4577     if (gl == 0 || gl->glyphs_used == 0)
4578       return;
4579
4580     masks = bdf_twobpp;
4581
4582     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4583         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4584           continue;
4585         sbpr = ((gp->bbx.width << 1) + 7) >> 3;
4586         bpr = ((gp->bbx.width << 2) + 7) >> 3;
4587         bytes = bpr * gp->bbx.height;
4588         nbmap = (unsigned char *) malloc(bytes);
4589         (void) memset((char *) nbmap, 0, bytes);
4590
4591         for (sy = 0; sy < gp->bbx.height; sy++) {
4592             for (col = sx = 0; sx < gp->bbx.width; sx++, col += 2) {
4593                 si = (col & 7) >> 1;
4594                 byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si];
4595                 if (byte) {
4596                     if (si < 3)
4597                       byte >>= (3 - si) << 1;
4598                     byte <<= 2;
4599                     if ((sx & 1) == 0)
4600                       byte <<= 4;
4601                     nbmap[(sy * bpr) + ((sx << 2) >> 3)] |= byte;
4602                 }
4603             }
4604         }
4605         free((char *) gp->bitmap);
4606         gp->bytes = bytes;
4607         gp->bitmap = nbmap;
4608     }
4609     gl->bpp = 4;
4610 }
4611
4612 static void
4613 _bdf_four_to_two(bdf_glyphlist_t *gl)
4614 {
4615     int i;
4616     unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy;
4617     unsigned char *nbmap, *masks;
4618     bdf_glyph_t *gp;
4619
4620     if (gl == 0 || gl->glyphs_used == 0)
4621       return;
4622
4623     masks = bdf_fourbpp;
4624
4625     gl->bpp = 2;
4626     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4627         sbpr = ((gp->bbx.width << 2) + 7) >> 3;
4628         bpr = ((gp->bbx.width << 1) + 7) >> 3;
4629         bytes = bpr * gp->bbx.height;
4630         nbmap = (unsigned char *) malloc(bytes);
4631         (void) memset((char *) nbmap, 0, bytes);
4632
4633         for (sy = 0; sy < gp->bbx.height; sy++) {
4634             for (col = sx = 0; sx < gp->bbx.width; sx++, col += 4) {
4635                 si = (col & 7) >> 2;
4636                 byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si];
4637                 if (byte) {
4638                     /*
4639                      * Shift the byte down to make an index.
4640                      */
4641                     if (si == 0)
4642                       byte >>= 4;
4643
4644                     /*
4645                      * Scale the index to two bits per pixel and shift it into
4646                      * place if necessary.
4647                      */
4648                     byte >>= 2;
4649                     /*
4650                      * Any non-zero byte has to remain non-zero, because index
4651                      * zero means no bits set.
4652                      */
4653                     if (byte == 0)
4654                       byte = 1;
4655
4656                     si = ((sx << 1) & 7) >> 1;
4657                     if (si < 3)
4658                       byte <<= (3 - si) << 1;
4659
4660                     nbmap[(sy * bpr) + ((sx << 1) >> 3)] |= byte;
4661                 }
4662             }
4663         }
4664         free((char *) gp->bitmap);
4665         gp->bytes = bytes;
4666         gp->bitmap = nbmap;
4667     }
4668 }
4669
4670 static void
4671 _bdf_two_to_eight(bdf_glyphlist_t *gl)
4672 {
4673     int i;
4674     unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy;
4675     unsigned char *nbmap, *masks;
4676     bdf_glyph_t *gp;
4677
4678     if (gl == 0 || gl->glyphs_used == 0)
4679       return;
4680
4681     masks = bdf_twobpp;
4682
4683     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4684         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4685           continue;
4686         sbpr = ((gp->bbx.width << 1) + 7) >> 3;
4687         bpr = gp->bbx.width;
4688         bytes = bpr * gp->bbx.height;
4689         nbmap = (unsigned char *) malloc(bytes);
4690         (void) memset((char *) nbmap, 0, bytes);
4691
4692         for (sy = 0; sy < gp->bbx.height; sy++) {
4693             for (col = sx = 0; sx < gp->bbx.width; sx++, col += 2) {
4694                 si = (col & 7) >> 1;
4695                 byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si];
4696                 if (byte) {
4697                     /*
4698                      * Shift the byte down to make an index.
4699                      */
4700                     if (si < 3)
4701                       byte >>= (3 - si) * gl->bpp;
4702
4703                     /*
4704                      * Scale the index to four bits per pixel and shift it into
4705                      * place before adding it.
4706                      */
4707                     byte <<= 6;
4708                     nbmap[(sy * bpr) + sx] = byte;
4709                 }
4710             }
4711         }
4712         free((char *) gp->bitmap);
4713         gp->bytes = bytes;
4714         gp->bitmap = nbmap;
4715     }
4716     gl->bpp = 8;
4717 }
4718
4719 static void
4720 _bdf_eight_to_two(bdf_glyphlist_t *gl)
4721 {
4722     int i;
4723     unsigned short bpr, sbpr, bytes, si, byte, sx, sy;
4724     unsigned char *nbmap, *masks;
4725     bdf_glyph_t *gp;
4726
4727     if (gl == 0 || gl->glyphs_used == 0)
4728       return;
4729
4730     masks = bdf_fourbpp;
4731
4732     gl->bpp = 2;
4733     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4734         sbpr = gp->bbx.width;
4735         bpr = ((gp->bbx.width << 1) + 7) >> 3;
4736         bytes = bpr * gp->bbx.height;
4737         nbmap = (unsigned char *) malloc(bytes);
4738         (void) memset((char *) nbmap, 0, bytes);
4739
4740         for (sy = 0; sy < gp->bbx.height; sy++) {
4741             for (sx = 0; sx < gp->bbx.width; sx++) {
4742                 byte = gp->bitmap[(sy * sbpr) + sx];
4743                 if (byte) {
4744                     byte >>= 6;
4745                     if (byte == 0)
4746                       byte = 1;
4747
4748                     si = ((sx << 1) & 7) >> 1;
4749                     if (si < 3)
4750                       byte <<= (3 - si) << 1;
4751
4752                     nbmap[(sy * bpr) + ((sx << 1) >> 3)] |= byte;
4753                 }
4754             }
4755         }
4756         free((char *) gp->bitmap);
4757         gp->bytes = bytes;
4758         gp->bitmap = nbmap;
4759     }
4760 }
4761
4762 static void
4763 _bdf_four_to_eight(bdf_glyphlist_t *gl)
4764 {
4765     int i;
4766     unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy;
4767     unsigned char *nbmap, *masks;
4768     bdf_glyph_t *gp;
4769
4770     if (gl == 0 || gl->glyphs_used == 0)
4771       return;
4772
4773     masks = bdf_fourbpp;
4774
4775     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4776         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4777           continue;
4778         sbpr = ((gp->bbx.width << 2) + 7) >> 3;
4779         bpr = gp->bbx.width;
4780         bytes = bpr * gp->bbx.height;
4781         nbmap = (unsigned char *) malloc(bytes);
4782         (void) memset((char *) nbmap, 0, bytes);
4783
4784         for (sy = 0; sy < gp->bbx.height; sy++) {
4785             for (col = sx = 0; sx < gp->bbx.width; sx++, col += 4) {
4786                 si = (col & 7) >> 2;
4787                 byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si];
4788                 if (byte) {
4789                     if (si == 0)
4790                       byte >>= 4;
4791
4792                     byte <<= 4;
4793                     nbmap[(sy * bpr) + sx] = byte;
4794                 }
4795             }
4796         }
4797         free((char *) gp->bitmap);
4798         gp->bytes = bytes;
4799         gp->bitmap = nbmap;
4800     }
4801     gl->bpp = 8;
4802 }
4803
4804 static void
4805 _bdf_eight_to_four(bdf_glyphlist_t *gl)
4806 {
4807     int i;
4808     unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy;
4809     unsigned char *nbmap, *masks;
4810     bdf_glyph_t *gp;
4811
4812     if (gl == 0 || gl->glyphs_used == 0)
4813       return;
4814
4815     masks = bdf_twobpp;
4816
4817     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4818         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4819           continue;
4820         sbpr = gp->bbx.width;
4821         bpr = ((gp->bbx.width << 2) + 7) >> 3;
4822         bytes = bpr * gp->bbx.height;
4823         nbmap = (unsigned char *) malloc(bytes);
4824         (void) memset((char *) nbmap, 0, bytes);
4825
4826         for (sy = 0; sy < gp->bbx.height; sy++) {
4827             for (col = sx = 0; sx < gp->bbx.width; sx++, col += 2) {
4828                 byte = gp->bitmap[(sy * sbpr) + sx];
4829                 if (byte) {
4830                     byte >>= 4;
4831                     if (byte == 0)
4832                       byte = 1;
4833
4834                     /*
4835                      * Scale the index to four bits per pixel and shift it into
4836                      * place before adding it.
4837                      */
4838                     si = (col & 7) >> 2;
4839                     if (si == 0)
4840                       byte <<= 4;
4841                     nbmap[(sy * bpr) + ((sx << 2) >> 3)] |= byte;
4842                 }
4843             }
4844         }
4845         free((char *) gp->bitmap);
4846         gp->bytes = bytes;
4847         gp->bitmap = nbmap;
4848     }
4849     gl->bpp = 4;
4850 }
4851
4852 /*
4853  * This only works on glyphs that exist.
4854  */
4855 int
4856 bdf_replace_mappings(bdf_font_t *font, int encoding, bdf_psf_unimap_t *map,
4857                      int unencoded)
4858 {
4859     bdf_glyph_t *gp;
4860
4861     if ((gp = _bdf_locate_glyph(font, encoding, unencoded)) == 0 ||
4862         gp->encoding != encoding)
4863       return 0;
4864
4865     if (map->map_size > gp->unicode.map_size) {
4866         if (gp->unicode.map_size == 0)
4867           gp->unicode.map = (unsigned char *)
4868               malloc(sizeof(unsigned char) * map->map_size);
4869         else
4870           gp->unicode.map =(unsigned char *)
4871               realloc((char *) gp->unicode.map,
4872                       sizeof(unsigned char) * map->map_size);
4873         gp->unicode.map_size = map->map_size;
4874     }
4875     gp->unicode.map_used = map->map_used;
4876     (void) memcpy((char *) gp->unicode.map, (char *) map->map,
4877                   sizeof(unsigned char) * map->map_used);
4878
4879     /*
4880      * Mark the glyph as modified.
4881      */
4882     if (unencoded)
4883       _bdf_set_glyph_modified(font->umod, gp->encoding);
4884     else
4885       _bdf_set_glyph_modified(font->nmod, gp->encoding);
4886
4887     font->modified = 1;
4888
4889     return 1;
4890 }
4891
4892 int
4893 bdf_replace_glyphs(bdf_font_t *font, int start, bdf_glyphlist_t *glyphs,
4894                    int unencoded)
4895 {
4896     int resize, appending;
4897     int i, n, ng, end, del, remaining, off[2];
4898     bdf_glyph_t *sgp, *gp, *dgp;
4899     short maxas, maxds, maxrb, minlb, maxlb, rb;
4900     double ps, rx, dw;
4901     bdf_bbx_t nbbx;
4902
4903     resize = 0;
4904
4905     if (font == 0)
4906       return resize;
4907
4908     /*
4909      * Dither the incoming bitmaps so they match the same bits per pixel as
4910      * the font.
4911      */
4912     if (glyphs->bpp != font->bpp) {
4913         if (glyphs->bpp == 1)
4914           _bdf_one_to_n(glyphs, font->bpp);
4915         else if (font->bpp == 1)
4916           _bdf_n_to_one(glyphs);
4917         else if (glyphs->bpp == 2) {
4918             if (font->bpp == 4)
4919               _bdf_two_to_four(glyphs);
4920             else
4921               _bdf_two_to_eight(glyphs);
4922         } else if (glyphs->bpp == 4) {
4923             if (font->bpp == 2)
4924               _bdf_four_to_two(glyphs);
4925             else
4926               _bdf_four_to_eight(glyphs);
4927         } else if (glyphs->bpp == 8) {
4928             if (font->bpp == 2)
4929               _bdf_eight_to_two(glyphs);
4930             else
4931               _bdf_eight_to_four(glyphs);
4932         }
4933     }
4934
4935     /*
4936      * Set the point size and horizontal resolution so the scalable width can
4937      * be determined.
4938      */
4939     ps = (double) font->point_size;
4940     rx = (double) font->resolution_x;
4941
4942     /*
4943      * Determine if a resize is needed.
4944      */
4945
4946     /*
4947      * Determine the bounding box for the font without the characters being
4948      * replaced.
4949      */
4950     minlb = 32767;
4951     maxlb = maxrb = maxas = maxds = 0;
4952
4953     /*
4954      * Get the font bounds.
4955      */
4956     maxas = MAX(font->bbx.ascent, maxas);
4957     maxds = MAX(font->bbx.descent, maxds);
4958     rb = font->bbx.width + font->bbx.x_offset;
4959     maxrb = MAX(rb, maxrb);
4960     minlb = MIN(font->bbx.x_offset, minlb);
4961     maxlb = MAX(font->bbx.x_offset, maxlb);
4962
4963     /*
4964      * Get the bounds of the incoming glyphs.
4965      */
4966     maxas = MAX(glyphs->bbx.ascent, maxas);
4967     maxds = MAX(glyphs->bbx.descent, maxds);
4968     rb = glyphs->bbx.width + glyphs->bbx.x_offset;
4969     maxrb = MAX(rb, maxrb);
4970     minlb = MIN(glyphs->bbx.x_offset, minlb);
4971     maxlb = MAX(glyphs->bbx.x_offset, maxlb);
4972
4973     /*
4974      * Set up the new font bounding box, minus the characters that are being
4975      * removed and with the new characters added.
4976      */
4977     nbbx.width = maxrb - minlb;
4978     nbbx.x_offset = minlb;
4979
4980     nbbx.height = maxas + maxds;
4981     nbbx.ascent = maxas;
4982     nbbx.descent = maxds;
4983     nbbx.y_offset = -maxds;
4984
4985     /*
4986      * Now determine if the combination of the glyphs removed and the new
4987      * glyphs cause the font bounding box to be changed.
4988      */
4989     resize = (nbbx.width > font->bbx.width ||
4990               nbbx.height > font->bbx.height) ? 1 : 0;
4991
4992     /*
4993      * Set the pointers to the glyphs.
4994      */
4995     ng = (unencoded == 0) ? font->glyphs_used : font->unencoded_used;
4996     sgp = gp = (unencoded == 0) ? font->glyphs : font->unencoded;
4997
4998     /*
4999      * Locate the closest glyph on or following `start'.
5000      */
5001     for (i = 0; i < ng && gp->encoding < start; i++, gp++) ;
5002
5003     appending = (i == ng);
5004
5005     /*
5006      * Set the starting point for copying the incoming glyphs.
5007      */
5008     dgp = gp;
5009
5010     n = glyphs->end - glyphs->start;
5011     end = start + n;
5012
5013     /*
5014      * Delete all the glyphs between `start' and `end'.
5015      */
5016     for (del = 0, i = start; i <= end; i++) {
5017         /*
5018          * Mark the character as being modified.
5019          */
5020         if (ng > 0 && !appending && gp->encoding == i) {
5021             if (unencoded == 0)
5022               _bdf_set_glyph_modified(font->nmod, i);
5023             else
5024               _bdf_set_glyph_modified(font->umod, i);
5025
5026             if (gp->name != 0)
5027               free(gp->name);
5028             if (gp->bytes > 0)
5029               free((char *) gp->bitmap);
5030             if (gp->unicode.map_size > 0)
5031               free((char *) gp->unicode.map);
5032             del++;
5033             gp++;
5034         }
5035     }
5036
5037     /*
5038      * Determine how many glyphs remain following the last one deleted.
5039      */
5040     remaining = ng - (gp - sgp);
5041
5042     if (glyphs->glyphs_used == 0) {
5043         /*
5044          * If the glyph list is empty, then shift any remaining glyphs down
5045          * to the destination.
5046          */
5047         _bdf_memmove((char *) dgp, (char *) gp,
5048                      sizeof(bdf_glyph_t) * remaining);
5049         if (unencoded == 0)
5050           font->glyphs_used -= del;
5051         else
5052           font->unencoded_used -= del;
5053     } else {
5054         /*
5055          * Insert the glyph list after making sure there is enough space to
5056          * hold them.  Also adjust the encoding and scalable width values
5057          * after copying the glyphs.
5058          */
5059         if (unencoded == 0) {
5060             n = (font->glyphs_used - del) + glyphs->glyphs_used;
5061             if (n > font->glyphs_size) {
5062                 off[0] = gp - sgp;
5063                 off[1] = dgp - sgp;
5064                 if (font->glyphs_size == 0)
5065                   font->glyphs = sgp =
5066                       (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * n);
5067                 else
5068                   font->glyphs = sgp =
5069                       (bdf_glyph_t *) realloc((char *) font->glyphs,
5070                                               sizeof(bdf_glyph_t) * n);
5071                 gp = sgp + off[0];
5072                 dgp = sgp + off[1];
5073                 font->glyphs_size = n;
5074             }
5075
5076             /*
5077              * Calculate how many will need to be shifted.
5078              */
5079             if ((n = glyphs->glyphs_used - del) >= font->glyphs_used)
5080               n = 0;
5081         } else {
5082             n = (font->unencoded_used - del) + glyphs->glyphs_used;
5083             if (n > font->unencoded_size) {
5084                 off[0] = gp - sgp;
5085                 off[1] = dgp - sgp;
5086                 if (font->unencoded_size == 0)
5087                   font->unencoded = sgp =
5088                       (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * n);
5089                 else
5090                   font->unencoded = sgp =
5091                       (bdf_glyph_t *) realloc((char *) font->unencoded,
5092                                               sizeof(bdf_glyph_t) * n);
5093                 gp = sgp + off[0];
5094                 dgp = sgp + off[1];
5095                 font->unencoded_size = n;
5096             }
5097
5098             /*
5099              * Calculate how many will need to be shifted.
5100              */
5101             if ((n = glyphs->glyphs_used - del) >= font->unencoded_used)
5102               n = 0;
5103         }
5104
5105         /*
5106          * Shift any following glyphs up or down if needed.
5107          */
5108         if (n)
5109           _bdf_memmove((char *) (gp + n), (char *) gp,
5110                        sizeof(bdf_glyph_t) * remaining);
5111
5112         /*
5113          * Copy the incoming glyphs, copy their names and bitmaps,
5114          * set their encodings, and set their scalable widths.
5115          */
5116         (void) memcpy((char *) dgp, (char *) glyphs->glyphs,
5117                       sizeof(bdf_glyph_t) * glyphs->glyphs_used);
5118         for (i = 0; i < glyphs->glyphs_used; i++, dgp++) {
5119             if (dgp->name != 0)
5120               dgp->name = (char *) _bdf_strdup((unsigned char *) dgp->name,
5121                                                strlen(dgp->name) + 1);
5122
5123             if (dgp->bytes > 0)
5124               dgp->bitmap = _bdf_strdup(dgp->bitmap, dgp->bytes);
5125
5126             if (dgp->unicode.map_size > 0)
5127               dgp->unicode.map = _bdf_strdup(dgp->unicode.map,
5128                                              dgp->unicode.map_size);
5129
5130             dgp->encoding = start + (dgp->encoding - glyphs->start);
5131
5132             /*
5133              * Mark the glyph as being modified in case it fills a cell that
5134              * was empty before.
5135              */
5136             _bdf_set_glyph_modified(font->nmod, dgp->encoding);
5137
5138             dw = (double) dgp->dwidth;
5139             dgp->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
5140         }
5141
5142         /*
5143          * Adjust the count of glyphs.
5144          */
5145         ng = (ng - del) + glyphs->glyphs_used;
5146         if (unencoded == 0)
5147           font->glyphs_used = ng;
5148         else
5149           font->unencoded_used = ng;
5150     }
5151
5152     /*
5153      * Last, if the replacement was done in the unencoded section,
5154      * reencode all the glyphs so they show up properly.
5155      */
5156     if (unencoded != 0) {
5157         for (i = 0; i < ng; i++, sgp++) {
5158             if (_bdf_glyph_modified(font->umod, sgp->encoding)) {
5159                 _bdf_clear_glyph_modified(font->umod, sgp->encoding);
5160                 _bdf_set_glyph_modified(font->umod, i);
5161             }
5162             sgp->encoding = i;
5163         }
5164     }
5165
5166     if (resize)
5167       (void) memcpy((char *) &font->bbx, (char *) &nbbx, sizeof(bdf_bbx_t));
5168
5169     font->modified = 1;
5170
5171     return resize;
5172 }
5173
5174 int
5175 bdf_insert_glyphs(bdf_font_t *font, int start, bdf_glyphlist_t *glyphs)
5176 {
5177     int resize;
5178     unsigned int i, ng, n, which;
5179     bdf_glyph_t *gp;
5180
5181     resize = 0;
5182
5183     if (font == 0)
5184       return resize;
5185
5186     /*
5187      * Dither the incoming bitmaps so they match the same bits per pixel as
5188      * the font.
5189      */
5190     if (glyphs->bpp != font->bpp) {
5191         if (glyphs->bpp == 1)
5192           _bdf_one_to_n(glyphs, font->bpp);
5193         else if (font->bpp == 1)
5194           _bdf_n_to_one(glyphs);
5195         else if (glyphs->bpp == 2)
5196           _bdf_two_to_four(glyphs);
5197         else
5198           _bdf_four_to_two(glyphs);
5199     }
5200
5201     /*
5202      * Locate the starting glyph.
5203      */
5204     gp = font->glyphs;
5205     ng = font->glyphs_used;
5206     for (i = 0; i < ng && gp->encoding < start; i++, gp++) ;
5207
5208     /*
5209      * If there are no glyphs at the starting point, then simply do a replace.
5210      */
5211     if (i == ng)
5212       return bdf_replace_glyphs(font, start, glyphs, 0);
5213
5214     /*
5215      * Go through the glyphs that would be shifted due to the insertion and
5216      * determine if some of them will overflow the 0xffff boundary.
5217      */
5218     n = (glyphs->end - glyphs->start) + 1;
5219     for (which = i; i < ng; i++, gp++) {
5220         if (gp->encoding + n > 0xffff)
5221           break;
5222     }
5223
5224     if (i < ng) {
5225         /*
5226          * Some glyphs have to be moved to the unencoded area because they
5227          * would overflow the 0xffff boundary if they were moved up.
5228          */
5229         bdf_copy_glyphs(font, gp->encoding, font->glyphs[ng - 1].encoding,
5230                         &font->overflow, 0);
5231         bdf_delete_glyphs(font,  gp->encoding, font->glyphs[ng - 1].encoding,
5232                           0);
5233         resize += bdf_replace_glyphs(font, font->unencoded_used,
5234                                      &font->overflow, 1);
5235     }
5236
5237     /*
5238      * Go back to the insertion point and shift the remaining glyph encodings
5239      * up by `n'.
5240      */
5241     for (gp = font->glyphs + which; which < font->glyphs_used; which++, gp++) {
5242         /*
5243          * Mark the new glyph locations as being modified.
5244          */
5245         gp->encoding += n;
5246         _bdf_set_glyph_modified(font->nmod, gp->encoding);
5247     }
5248
5249     /*
5250      * Finally, mark the font as being modified and insert the new glyphs.
5251      */
5252     font->modified = 1;
5253
5254     return resize + bdf_replace_glyphs(font, start, glyphs, 0);
5255 }
5256
5257 static void
5258 _bdf_combine_glyphs(bdf_font_t *font, bdf_glyph_t *f, bdf_glyph_t *g)
5259 {
5260     unsigned short x, sx, sy, si, dx, dy, di, byte, dbpr, fbpr, gbpr;
5261     short maxas, maxds, maxrb, minlb, maxlb, rb;
5262     unsigned char *masks;
5263     bdf_bbx_t nbbx;
5264     bdf_glyph_t tmp;
5265
5266     /*
5267      * Determine the max bounding box for the two glyphs.
5268      */
5269     minlb = 32767;
5270     maxlb = maxrb = maxas = maxds = 0;
5271
5272     /*
5273      * Get the font glyph bounds.
5274      */
5275     maxas = MAX(f->bbx.ascent, maxas);
5276     maxds = MAX(f->bbx.descent, maxds);
5277     rb = f->bbx.width + f->bbx.x_offset;
5278     maxrb = MAX(rb, maxrb);
5279     minlb = MIN(f->bbx.x_offset, minlb);
5280     maxlb = MAX(f->bbx.x_offset, maxlb);
5281
5282     /*
5283      * Get the bounds of the incoming glyph.
5284      */
5285     maxas = MAX(g->bbx.ascent, maxas);
5286     maxds = MAX(g->bbx.descent, maxds);
5287     rb = g->bbx.width + g->bbx.x_offset;
5288     maxrb = MAX(rb, maxrb);
5289     minlb = MIN(g->bbx.x_offset, minlb);
5290     maxlb = MAX(g->bbx.x_offset, maxlb);
5291
5292     /*
5293      * Set up the new glyph bounding box.
5294      */
5295     nbbx.width = maxrb - minlb;
5296     nbbx.x_offset = minlb;
5297     nbbx.height = maxas + maxds;
5298     nbbx.ascent = maxas;
5299     nbbx.descent = maxds;
5300     nbbx.y_offset = -maxds;
5301
5302     masks = 0;
5303     switch (font->bpp) {
5304       case 1: masks = bdf_onebpp; break;
5305       case 2: masks = bdf_twobpp; break;
5306       case 4: masks = bdf_fourbpp; break;
5307       case 8: masks = bdf_eightbpp; break;
5308     }
5309
5310     fbpr = ((f->bbx.width * font->bpp) + 7) >> 3;
5311     gbpr = ((g->bbx.width * font->bpp) + 7) >> 3;
5312     dbpr = ((nbbx.width * font->bpp) + 7) >> 3;
5313
5314     if (memcmp((char *) &nbbx, (char *) &f->bbx, sizeof(bdf_bbx_t)) == 0) {
5315         /*
5316          * The largest is the first, so merge the second in with it.
5317          */
5318         dy = f->bbx.ascent - g->bbx.ascent;
5319         for (sy = 0; sy < g->bbx.height; sy++, dy++) {
5320             for (x = sx = 0; x < g->bbx.width; x++, sx += font->bpp) {
5321                 si = (sx & 7) / font->bpp;
5322                 if ((byte = g->bitmap[(sy * gbpr) + (sx >> 3)] & masks[si]))
5323                   /*
5324                    * No shifting of the byte is needed because the x offset
5325                    * is the same for both glyphs.
5326                    */
5327                   f->bitmap[(dy * fbpr) + (sx >> 3)] |= byte;
5328             }
5329         }
5330     } else if (memcmp((char *) &nbbx, (char *) &g->bbx,
5331                       sizeof(bdf_bbx_t)) == 0) {
5332         /*
5333          * The largest is the incoming glyph, so merge into that one and swap
5334          * it with the font glyph.
5335          */
5336         dy = g->bbx.ascent - f->bbx.ascent;
5337         for (sy = 0; sy < f->bbx.height; sy++, dy++) {
5338             for (x = sx = 0; x < f->bbx.width; x++, sx += font->bpp) {
5339                 si = (sx & 7) / font->bpp;
5340                 if ((byte = f->bitmap[(sy * gbpr) + (sx >> 3)] & masks[si]))
5341                   /*
5342                    * No shifting of the byte is needed because the x offset
5343                    * is the same for both glyphs.
5344                    */
5345                   g->bitmap[(dy * fbpr) + (sx >> 3)] |= byte;
5346             }
5347         }
5348
5349         /*
5350          * Now swap the two glyphs while preserving the name and encoding of
5351          * the first glyph.
5352          */
5353         tmp.swidth = g->swidth;
5354         tmp.dwidth = g->dwidth;
5355         tmp.bytes = g->bytes;
5356         tmp.bitmap = g->bitmap;
5357         (void) memcpy((char *) &tmp.bbx, (char *) &g->bbx, sizeof(bdf_bbx_t));
5358
5359         g->swidth = f->swidth;
5360         g->dwidth = f->dwidth;
5361         g->bytes = f->bytes;
5362         g->bitmap = f->bitmap;
5363         (void) memcpy((char *) &g->bbx, (char *) &f->bbx, sizeof(bdf_bbx_t));
5364
5365         f->swidth = tmp.swidth;
5366         f->dwidth = tmp.dwidth;
5367         f->bytes = tmp.bytes;
5368         f->bitmap = tmp.bitmap;
5369         (void) memcpy((char *) &f->bbx, (char *) &tmp.bbx, sizeof(bdf_bbx_t));
5370     } else {
5371         /*
5372          * Need a new bitmap for the combination of the two.
5373          */
5374         tmp.bytes = nbbx.height * dbpr;
5375         tmp.bitmap = (unsigned char *) malloc(tmp.bytes);
5376         (void) memset((char *) tmp.bitmap, 0, tmp.bytes);
5377
5378         /*
5379          * Merge the first glyph.
5380          */
5381         dy = nbbx.ascent - f->bbx.ascent;
5382         for (sy = 0; sy < f->bbx.height; sy++, dy++) {
5383             dx = MYABS(nbbx.x_offset - f->bbx.x_offset) * font->bpp;
5384             for (x = sx = 0; x < f->bbx.width; x++,
5385                      sx += font->bpp, dx += font->bpp) {
5386                 si = (sx & 7) / font->bpp;
5387                 if ((byte = f->bitmap[(sy * fbpr) + (sx >> 3)] & masks[si])) {
5388                     di = (dx & 7) / font->bpp;
5389                     if (di < si)
5390                       byte <<= (si - di) * font->bpp;
5391                     else if (di > si)
5392                       byte >>= (di - si) * font->bpp;
5393                     tmp.bitmap[(dy * dbpr) + (dx >> 3)] |= byte;
5394                 }
5395             }
5396         }
5397
5398         /*
5399          * Merge the second glyph.
5400          */
5401         dy = nbbx.ascent - g->bbx.ascent;
5402         for (sy = 0; sy < g->bbx.height; sy++, dy++) {
5403             dx = MYABS(nbbx.x_offset - g->bbx.x_offset) * font->bpp;
5404             for (x = sx = 0; x < g->bbx.width; x++,
5405                      sx += font->bpp, dx += font->bpp) {
5406                 si = (sx & 7) / font->bpp;
5407                 if ((byte = g->bitmap[(sy * gbpr) + (sx >> 3)] & masks[si])) {
5408                     di = (dx & 7) / font->bpp;
5409                     if (di < si)
5410                       byte <<= (si - di) * font->bpp;
5411                     else if (di > si)
5412                       byte >>= (di - si) * font->bpp;
5413                     tmp.bitmap[(dy * dbpr) + (dx >> 3)] |= byte;
5414                 }
5415             }
5416         }
5417
5418         /*
5419          * Now clear the font glyph and copy the temp glyph to it.
5420          */
5421         if (f->bytes > 0)
5422           free((char *) f->bitmap);
5423         f->bytes = tmp.bytes;
5424         f->bitmap = tmp.bitmap;
5425         (void) memcpy((char *) &f->bbx, (char *) &nbbx, sizeof(bdf_bbx_t));
5426
5427         /*
5428          * Set the device width.  Pay attention to whether the font is
5429          * monowidth or character cell.
5430          */
5431         if (font->spacing != BDF_PROPORTIONAL)
5432           f->dwidth = font->monowidth;
5433         else
5434           f->dwidth = MAX(f->dwidth, g->dwidth);
5435     }
5436 }
5437
5438 int
5439 bdf_merge_glyphs(bdf_font_t *font, int start, bdf_glyphlist_t *glyphs,
5440                  int unencoded)
5441 {
5442     int resize;
5443     int i, n, ng, end, add, enc, off;
5444     bdf_glyph_t *sgp, *gp, *dgp, *base;
5445     short maxas, maxds, maxrb, minlb, maxlb, rb;
5446     double ps, rx, dw;
5447     bdf_bbx_t nbbx;
5448
5449     resize = 0;
5450
5451     if (font == 0)
5452       return resize;
5453
5454     /*
5455      * If the glyphs are being merged in the unencoded area, simply append
5456      * them.  The unencoded area is simply storage.
5457      */
5458     if (unencoded)
5459       return bdf_replace_glyphs(font, font->unencoded_used, glyphs, unencoded);
5460
5461     /*
5462      * Dither the incoming bitmaps so they match the same bits per pixel as
5463      * the font.
5464      */
5465     if (glyphs->bpp != font->bpp) {
5466         if (glyphs->bpp == 1)
5467           _bdf_one_to_n(glyphs, font->bpp);
5468         else if (font->bpp == 1)
5469           _bdf_n_to_one(glyphs);
5470         else if (glyphs->bpp == 2)
5471           _bdf_two_to_four(glyphs);
5472         else
5473           _bdf_four_to_two(glyphs);
5474     }
5475
5476     /*
5477      * Set the point size and horizontal resolution so the scalable width can
5478      * be determined.
5479      */
5480     ps = (double) font->point_size;
5481     rx = (double) font->resolution_x;
5482
5483     /*
5484      * Determine if a resize is needed.
5485      */
5486
5487     /*
5488      * Determine the bounding box for the font without the characters being
5489      * replaced.
5490      */
5491     minlb = 32767;
5492     maxlb = maxrb = maxas = maxds = 0;
5493
5494     /*
5495      * Get the font bounds.
5496      */
5497     maxas = MAX(font->bbx.ascent, maxas);
5498     maxds = MAX(font->bbx.descent, maxds);
5499     rb = font->bbx.width + font->bbx.x_offset;
5500     maxrb = MAX(rb, maxrb);
5501     minlb = MIN(font->bbx.x_offset, minlb);
5502     maxlb = MAX(font->bbx.x_offset, maxlb);
5503
5504     /*
5505      * Get the bounds of the incoming glyphs.
5506      */
5507     maxas = MAX(glyphs->bbx.ascent, maxas);
5508     maxds = MAX(glyphs->bbx.descent, maxds);
5509     rb = glyphs->bbx.width + glyphs->bbx.x_offset;
5510     maxrb = MAX(rb, maxrb);
5511     minlb = MIN(glyphs->bbx.x_offset, minlb);
5512     maxlb = MAX(glyphs->bbx.x_offset, maxlb);
5513
5514     /*
5515      * Set up the new font bounding box, minus the characters that are being
5516      * removed and with the new characters added.
5517      */
5518     nbbx.width = maxrb - minlb;
5519     nbbx.x_offset = minlb;
5520
5521     nbbx.height = maxas + maxds;
5522     nbbx.ascent = maxas;
5523     nbbx.descent = maxds;
5524     nbbx.y_offset = -maxds;
5525
5526     /*
5527      * Now determine if the combination of the glyphs removed and the new
5528      * glyphs cause the font bounding box to be changed.
5529      */
5530     resize = (nbbx.width > font->bbx.width ||
5531               nbbx.height > font->bbx.height) ? 1 : 0;
5532
5533     /*
5534      * Set the pointers to the glyphs.
5535      */
5536     ng = (unencoded == 0) ? font->glyphs_used : font->unencoded_used;
5537     gp = (unencoded == 0) ? font->glyphs : font->unencoded;
5538
5539     /*
5540      * Locate the closest glyph on or following `start'.
5541      */
5542     for (i = 0; i < ng && gp->encoding < start; i++, gp++) ;
5543
5544     if (i == ng)
5545       /*
5546        * If the gylphs are being added off the end of the list, simply insert
5547        * them so any overflows can be handled.
5548        */
5549       return bdf_insert_glyphs(font, start, glyphs);
5550
5551     /*
5552      * Set the starting point for copying the incoming glyphs.
5553      */
5554     dgp = gp;
5555
5556     n = glyphs->end - glyphs->start;
5557     end = start + n;
5558
5559     /*
5560      * Count the number of glyphs that will be added and mark all the
5561      * glyphs that will be modified.
5562      */
5563     for (sgp = glyphs->glyphs, add = 0, i = start; i <= end; i++) {
5564         enc = (sgp->encoding - glyphs->start) + start;
5565
5566         /*
5567          * Mark the glyph as being modified.
5568          */
5569         if (unencoded == 0)
5570           _bdf_set_glyph_modified(font->nmod, enc);
5571         else
5572           _bdf_set_glyph_modified(font->umod, enc);
5573
5574         if (enc == gp->encoding)
5575           sgp++;
5576         else if (enc < gp->encoding) {
5577             add++;
5578             sgp++;
5579         }
5580
5581         if (gp->encoding == i)
5582           gp++;
5583     }
5584
5585     if (add > 0) {
5586         ng += add;
5587
5588         /*
5589          * Need to make room for some glyphs that will be added.
5590          */
5591         if (unencoded) {
5592             off = dgp - font->unencoded;
5593             if (font->unencoded_used == 0)
5594               font->unencoded =
5595                   (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * ng);
5596             else
5597               font->unencoded =
5598                   (bdf_glyph_t *) realloc((char *) font->unencoded,
5599                                           sizeof(bdf_glyph_t) * ng);
5600             dgp = font->unencoded + off;
5601             font->unencoded_used = ng;
5602         } else {
5603             off = dgp - font->glyphs;
5604             if (font->glyphs_used == 0)
5605               font->glyphs =
5606                   (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * ng);
5607             else
5608               font->glyphs =
5609                   (bdf_glyph_t *) realloc((char *) font->glyphs,
5610                                           sizeof(bdf_glyph_t) * ng);
5611             dgp = font->glyphs + off;
5612             font->glyphs_used = ng;
5613         }
5614     }
5615
5616     /*
5617      * Now go through and do two things:
5618      * 1. Insert new incoming glyphs.
5619      * 2. Combine two glyphs at the same location.
5620      */
5621     base = (!unencoded) ? font->glyphs : font->unencoded;
5622     for (gp = dgp, sgp = glyphs->glyphs, i = start; i <= end; i++) {
5623         enc = (sgp->encoding - glyphs->start) + start;
5624         if (enc < gp->encoding) {
5625             /*
5626              * Shift the glyphs up by one and add this one.
5627              */
5628             if (gp - base < ng)
5629               _bdf_memmove((char *) (gp + 1), (char *) gp,
5630                            sizeof(bdf_glyph_t) * (ng - (gp - base)));
5631             (void) memcpy((char *) gp, (char *) sgp, sizeof(bdf_glyph_t));
5632             gp->name = (char *) _bdf_strdup((unsigned char *) gp->name,
5633                                             strlen(gp->name) + 1);
5634             if (gp->bytes > 0)
5635               gp->bitmap = _bdf_strdup(gp->bitmap, gp->bytes);
5636             if (gp->unicode.map_size > 0)
5637               gp->unicode.map = _bdf_strdup(gp->unicode.map,
5638                                             gp->unicode.map_size);
5639             gp->encoding = i;
5640             sgp++;
5641             dw = (double) gp->dwidth;
5642             gp->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
5643         } else if (enc == gp->encoding) {
5644             _bdf_combine_glyphs(font, gp, sgp);
5645             dw = (double) gp->dwidth;
5646             gp->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
5647             sgp++;
5648         }
5649         if (gp->encoding == i)
5650           gp++;
5651     }
5652
5653     if (resize)
5654       (void) memcpy((char *) &font->bbx, (char *) &nbbx, sizeof(bdf_bbx_t));
5655
5656     font->modified = 1;
5657
5658     return resize;
5659 }
5660
5661 void
5662 bdf_set_modified(bdf_font_t *font, int modified)
5663 {
5664     if (font == 0 || font->modified == modified)
5665       return;
5666
5667     if (modified == 0) {
5668         /*
5669          * Clear out the modified bitmaps.
5670          */
5671         (void) memset((char *) font->nmod, 0, sizeof(unsigned int) * 2048);
5672         (void) memset((char *) font->umod, 0, sizeof(unsigned int) * 2048);
5673     }
5674     font->modified = modified;
5675 }
5676
5677 /**************************************************************************
5678  *
5679  * XLFD font name functions.
5680  *
5681  **************************************************************************/
5682
5683 static char *xlfdfields[] = {
5684     "FOUNDRY",
5685     "FAMILY_NAME",
5686     "WEIGHT_NAME",
5687     "SLANT",
5688     "SETWIDTH_NAME",
5689     "ADD_STYLE_NAME",
5690     "PIXEL_SIZE",
5691     "POINT_SIZE",
5692     "RESOLUTION_X",
5693     "RESOLUTION_Y",
5694     "SPACING",
5695     "AVERAGE_WIDTH",
5696     "CHARSET_REGISTRY",
5697     "CHARSET_ENCODING",
5698 };
5699
5700 int
5701 bdf_is_xlfd_property(char *name)
5702 {
5703     int i;
5704
5705     for (i = 0; i < 14; i++) {
5706         if (strcmp(name, xlfdfields[i]) == 0)
5707           return 1;
5708     }
5709     return 0;
5710 }
5711
5712 int
5713 bdf_has_xlfd_name(bdf_font_t *font)
5714 {
5715     unsigned int len;
5716     char name[256];
5717     _bdf_list_t list;
5718
5719     if (font == 0 || font->name == 0 || font->name[0] == 0)
5720       return 0;
5721
5722     len = (unsigned int) (strlen(font->name) + 1);
5723     (void) memcpy(name, font->name, len);
5724     list.size = list.used = 0;
5725     _bdf_split("-", name, len, &list);
5726     if (list.size > 0)
5727       free((char *) list.field);
5728
5729     return (list.used == 15);
5730 }
5731
5732 char *
5733 bdf_make_xlfd_name(bdf_font_t *font, char *foundry, char *family)
5734 {
5735     int len;
5736     double dp, dr;
5737     unsigned int i, width, used;
5738     unsigned short awidth, pxsize;
5739     bdf_property_t *pp;
5740     bdf_glyph_t *gp;
5741     char spacing, *name, *val, *np, nbuf[256];
5742
5743     if (font == 0 || bdf_has_xlfd_name(font))
5744       return 0;
5745
5746     np = nbuf;
5747
5748     /*
5749      * Add the FOUNDRY field.
5750      */
5751     if ((pp = bdf_get_font_property(font, "FOUNDRY")) != 0)
5752       foundry = pp->value.atom;
5753     sprintf(np, "-%s", foundry);
5754     np += strlen(np);
5755
5756     /*
5757      * Add the FAMILY_NAME field.
5758      */
5759     if ((pp = bdf_get_font_property(font, "FAMILY_NAME")) != 0)
5760       family = pp->value.atom;
5761     sprintf(np, "-%s", family);
5762     np += strlen(np);
5763
5764     /*
5765      * Add the WEIGHT_NAME field.
5766      */
5767     val = ((pp = bdf_get_font_property(font, "WEIGHT_NAME")) != 0) ?
5768         pp->value.atom : "Medium";
5769     if (val == 0)
5770       val = "Medium";
5771     sprintf(np, "-%s", val);
5772     np += strlen(np);
5773
5774     /*
5775      * Add the SLANT field.
5776      */
5777     val = ((pp = bdf_get_font_property(font, "SLANT")) != 0) ?
5778         pp->value.atom : "R";
5779     if (val == 0)
5780       val = "R";
5781     sprintf(np, "-%s", val);
5782     np += strlen(np);
5783
5784     /*
5785      * Add the SETWIDTH_NAME field.
5786      */
5787     val = ((pp = bdf_get_font_property(font, "SETWIDTH_NAME")) != 0) ?
5788         pp->value.atom : "Normal";
5789     if (val == 0)
5790       val = "Normal";
5791     sprintf(np, "-%s", val);
5792     np += strlen(np);
5793
5794     /*
5795      * Add the ADD_STYLE_NAME field.
5796      */
5797     val = ((pp = bdf_get_font_property(font, "ADD_STYLE_NAME")) != 0) ?
5798         pp->value.atom : "";
5799     if (val == 0)
5800       val = "";
5801     sprintf(np, "-%s", val);
5802     np += strlen(np);
5803
5804     /*
5805      * Add the PIXEL_SIZE field.
5806      */
5807     if ((pp = bdf_get_font_property(font, "PIXEL_SIZE")) != 0)
5808       sprintf(np, "-%d", pp->value.int32);
5809     else {
5810         /*
5811          * Determine the pixel size.
5812          */
5813         dp = (double) (font->point_size * 10);
5814         dr = (double) font->resolution_y;
5815         pxsize = (unsigned short) (((dp * dr) / 722.7) + 0.5);
5816         sprintf(np, "-%hd", pxsize);
5817     }
5818     np += strlen(np);
5819
5820     /*
5821      * Add the POINT_SIZE field.
5822      */
5823     if ((pp = bdf_get_font_property(font, "POINT_SIZE")) != 0)
5824       sprintf(np, "-%d", pp->value.int32);
5825     else
5826       sprintf(np, "-%d", font->point_size * 10);
5827     np += strlen(np);
5828
5829     /*
5830      * Add the RESOLUTION_X field.
5831      */
5832     if ((pp = bdf_get_font_property(font, "RESOLUTION_X")) != 0)
5833       sprintf(np, "-%d", pp->value.card32);
5834     else
5835       sprintf(np, "-%d", font->resolution_x);
5836     np += strlen(np);
5837
5838     /*
5839      * Add the RESOLUTION_Y field.
5840      */
5841     if ((pp = bdf_get_font_property(font, "RESOLUTION_Y")) != 0)
5842       sprintf(np, "-%d", pp->value.card32);
5843     else
5844       sprintf(np, "-%d", font->resolution_y);
5845     np += strlen(np);
5846
5847     /*
5848      * Add the SPACING field.
5849      */
5850     if ((pp = bdf_get_font_property(font, "SPACING")) != 0)
5851       spacing = pp->value.atom[0];
5852     else {
5853         spacing = 'P';
5854         switch (font->spacing) {
5855           case BDF_PROPORTIONAL: spacing = 'P'; break;
5856           case BDF_MONOWIDTH: spacing = 'M'; break;
5857           case BDF_CHARCELL: spacing = 'C'; break;
5858         }
5859     }
5860     sprintf(np, "-%c", spacing);
5861     np += strlen(np);
5862
5863     /*
5864      * Add the AVERAGE_WIDTH field.
5865      */
5866     if ((pp = bdf_get_font_property(font, "AVERAGE_WIDTH")) != 0)
5867       sprintf(np, "-%d", pp->value.int32);
5868     else {
5869         /*
5870          * Determine the average width of all the glyphs in the font.
5871          */
5872         width = 0;
5873         for (i = 0, gp = font->unencoded; i < font->unencoded_used; i++, gp++)
5874           width += gp->dwidth;
5875         for (i = 0, gp = font->glyphs; i < font->glyphs_used; i++, gp++)
5876           width += gp->dwidth;
5877
5878         used = font->unencoded_used + font->glyphs_used;
5879         if (used == 0)
5880           awidth = font->bbx.width * 10;
5881         else
5882           awidth = (unsigned short) ((((float) width) /
5883                                       ((float) used)) * 10.0);
5884         sprintf(np, "-%hd", awidth);
5885     }
5886     np += strlen(np);
5887
5888     /*
5889      * Add the CHARSET_REGISTRY field.
5890      */
5891     val = ((pp = bdf_get_font_property(font, "CHARSET_REGISTRY")) != 0) ?
5892         pp->value.atom : "FontSpecific";
5893     sprintf(np, "-%s", val);
5894     np += strlen(np);
5895
5896     /*
5897      * Add the CHARSET_ENCODING field.
5898      */
5899     val = ((pp = bdf_get_font_property(font, "CHARSET_ENCODING")) != 0) ?
5900         pp->value.atom : "0";
5901     sprintf(np, "-%s", val);
5902     np += strlen(np);
5903
5904     len = (np - nbuf) + 1;
5905     name = (char *) malloc(len);
5906     (void) memcpy(name, nbuf, len);
5907     return name;
5908 }
5909
5910 void
5911 bdf_update_name_from_properties(bdf_font_t *font)
5912 {
5913     unsigned int i;
5914     bdf_property_t *p;
5915     _bdf_list_t list;
5916     char *np, name[128], nname[128];
5917
5918     if (font == 0 || bdf_has_xlfd_name(font) == 0)
5919       return;
5920
5921     (void) memset((char *) &list, 0, sizeof(_bdf_list_t));
5922
5923     /*
5924      * Split the name into fields and shift out the first empty field.
5925      * This assumes that the font has a name.
5926      */
5927     i = (unsigned int) strlen(font->name);
5928     (void) memcpy(name, font->name, i + 1);
5929     _bdf_split("-", name, i, &list);
5930     _bdf_shift(1, &list);
5931
5932     /*
5933      * Initialize the pointer to the new name and add the '-' prefix.
5934      */
5935     np = nname;
5936     *np++ = '-';
5937     *np = 0;
5938
5939     for (i = 0; i < 14; i++) {
5940         if ((p = bdf_get_font_property(font, xlfdfields[i])) != 0) {
5941             /*
5942              * The property exists, so add it to the new font name.
5943              */
5944             switch (p->format) {
5945               case BDF_ATOM:
5946                 if (p->value.atom != 0)
5947                   sprintf(np, "%s", p->value.atom);
5948                 break;
5949               case BDF_CARDINAL:
5950                 sprintf(np, "%d", p->value.card32);
5951                 break;
5952               case BDF_INTEGER:
5953                 sprintf(np, "%d", p->value.int32);
5954                 break;
5955             }
5956         } else
5957           /*
5958            * The property does not exist, so add the original value to the
5959            * new font name.
5960            */
5961           sprintf(np, "%s", list.field[i]);
5962         np += strlen(np);
5963         if (i + 1 < 14) {
5964             *np++ = '-';
5965             *np = 0;
5966         }
5967     }
5968
5969     /*
5970      * Replace the existing font name with the new one.
5971      */
5972     free(font->name);
5973     i = (unsigned int) (strlen(nname) + 1);
5974     font->name = (char *) malloc(i);
5975     (void) memcpy(font->name, nname, i);
5976
5977     /*
5978      * Free up the list.
5979      */
5980     if (list.size > 0)
5981       free((char *) list.field);
5982
5983     font->modified = 1;
5984 }
5985
5986 int
5987 bdf_update_properties_from_name(bdf_font_t *font)
5988 {
5989     unsigned int i;
5990     bdf_property_t *p, prop;
5991     _bdf_list_t list;
5992     char name[128];
5993
5994     if (font == 0 || font->name == 0 || bdf_has_xlfd_name(font) == 0)
5995       return 0;
5996
5997     (void) memset((char *) &list, 0, sizeof(_bdf_list_t));
5998
5999     /*
6000      * Split the name into fields and shift out the first empty field.
6001      */
6002     i = (unsigned int) strlen(font->name);
6003     (void) memcpy(name, font->name, i + 1);
6004     _bdf_split("-", name, i, &list);
6005     _bdf_shift(1, &list);
6006
6007     for (i = 0; i < 14; i++) {
6008         p = bdf_get_property(xlfdfields[i]);
6009         prop.name = p->name;
6010         prop.format = p->format;
6011         switch (prop.format) {
6012           case BDF_ATOM:
6013             prop.value.atom = list.field[i];
6014             break;
6015           case BDF_CARDINAL:
6016             prop.value.card32 = _bdf_atoul(list.field[i], 0, 10);
6017             break;
6018           case BDF_INTEGER:
6019             prop.value.int32 = _bdf_atol(list.field[i], 0, 10);
6020             break;
6021         }
6022         bdf_add_font_property(font, &prop);
6023     }
6024
6025     /*
6026      * Free up the list.
6027      */
6028     if (list.size > 0)
6029       free((char *) list.field);
6030
6031     font->modified = 1;
6032
6033     return 1;
6034 }
6035
6036 int
6037 bdf_update_average_width(bdf_font_t *font)
6038 {
6039     int changed;
6040     unsigned int i;
6041     int oaw, awidth, used;
6042     bdf_glyph_t *gp;
6043     _bdf_list_t list;
6044     bdf_property_t *pp, prop;
6045     char *np, num[16], nbuf[128];
6046
6047     changed = 0;
6048
6049     used = font->unencoded_used + font->glyphs_used;
6050     if (used == 0)
6051       awidth = font->bbx.width * 10;
6052     else {
6053         for (i = 0, awidth = 0, gp = font->unencoded; i < font->unencoded_used;
6054              i++, gp++)
6055           awidth += gp->dwidth;
6056         for (i = 0, gp = font->glyphs; i < font->glyphs_used; i++, gp++)
6057           awidth += gp->dwidth;
6058         awidth = (int) ((((double) awidth) / ((double) used)) * 10.0);
6059     }
6060
6061     /*
6062      * Check to see if it is different than the average width in the font
6063      * name.
6064      */
6065     if (bdf_has_xlfd_name(font)) {
6066         (void) memset((char *) &list, 0, sizeof(_bdf_list_t));
6067         i = (unsigned int) strlen(font->name);
6068         (void) memcpy(nbuf, font->name, i + 1);
6069         _bdf_split("-", nbuf, i, &list);
6070         oaw = _bdf_atol(list.field[12], 0, 10);
6071         if (oaw != awidth) {
6072             /*
6073              * Construct a new font name with the new average width.
6074              */
6075             changed = 1;
6076             sprintf(num, "%d", awidth);
6077             used = strlen(num) - strlen(list.field[12]);
6078             if (used > 0) {
6079                 /*
6080                  * Resize the string used for the font name instead of
6081                  * creating a new one.
6082                  */
6083                 used += i;
6084                 font->name = (char *) realloc(font->name, used);
6085             }
6086
6087             /*
6088              * Copy the elements of the list back into the new font name.
6089              */
6090             np = font->name;
6091             *np++ = '-';
6092             for (i = 1; i < list.used; i++) {
6093                 if (i == 12)
6094                   strcpy(np, num);
6095                 else
6096                   strcpy(np, list.field[i]);
6097                 np += strlen(np);
6098                 if (i + 1 < list.used)
6099                   *np++ = '-';
6100             }
6101         }
6102
6103         /*
6104          * Clear up any space allocated for the list.
6105          */
6106         if (list.size > 0)
6107           free((char *) list.field);
6108     }
6109
6110     /*
6111      * Now check for the AVERAGE_WIDTH property.
6112      */
6113     if ((pp = bdf_get_font_property(font, "AVERAGE_WIDTH")) != 0) {
6114         if (pp->value.int32 != awidth) {
6115             changed = 1;
6116             pp->value.int32 = awidth;
6117         }
6118     } else {
6119         /*
6120          * Property doesn't exist yet, so add it.
6121          */
6122         changed = 1;
6123         prop.name = "AVERAGE_WIDTH";
6124         prop.format = BDF_INTEGER;
6125         prop.value.int32 = awidth;
6126         bdf_add_font_property(font, &prop);
6127     }
6128
6129     if (changed)
6130       font->modified = 1;
6131
6132     return changed;
6133 }
6134
6135 /*
6136  * Change the font bounding box and return a non-zero number if this causes
6137  * the font to get larger or smaller.
6138  */
6139 int
6140 bdf_set_font_bbx(bdf_font_t *font, bdf_metrics_t *metrics)
6141 {
6142     int resize;
6143
6144     resize = 0;
6145
6146     if (font == 0 || metrics == 0)
6147       return resize;
6148
6149     resize = (font->bbx.width != metrics->width ||
6150               font->bbx.height != metrics->height) ? 1 : 0;
6151
6152     font->bbx.width = metrics->width;
6153     font->bbx.height = metrics->height;
6154     font->bbx.x_offset = metrics->x_offset;
6155     font->bbx.y_offset = metrics->y_offset;
6156     font->bbx.ascent = metrics->ascent;
6157     font->bbx.descent = metrics->descent;
6158
6159     /*
6160      * If the font is not proportional, then make sure the monowidth field is
6161      * set to the font bounding box.
6162      */
6163     if (font->spacing != BDF_PROPORTIONAL)
6164       font->monowidth = font->bbx.width;
6165
6166     return resize;
6167 }
6168
6169 int
6170 bdf_translate_glyphs(bdf_font_t *font, short dx, short dy, int start,
6171                      int end, bdf_callback_t callback, void *data,
6172                      int unencoded)
6173 {
6174     int resize, diff;
6175     bdf_glyph_t *gp, *sp, *ep;
6176     bdf_callback_struct_t cb;
6177
6178     if (font == 0 || (dx == 0 && dy == 0))
6179       return 0;
6180
6181     if ((unencoded && font->unencoded_used == 0) || font->glyphs_used == 0)
6182       return 0;
6183
6184     /*
6185      * Call the progress initialization callback.
6186      */
6187     if (callback != 0) {
6188         cb.reason = BDF_TRANSLATE_START;
6189         cb.total = (end - start) + 1;
6190         cb.current = 0;
6191         (*callback)(&cb, data);
6192     }
6193
6194     /*
6195      * Locate the first and last glyphs to be shifted.
6196      */
6197     sp = _bdf_locate_glyph(font, start, unencoded);
6198     ep = _bdf_locate_glyph(font, end, unencoded);
6199     for (resize = 0, gp = sp; sp <= ep; sp++) {
6200         /*
6201          * Call the callback if one was provided.
6202          */
6203         if (sp != gp && callback != 0) {
6204             cb.reason = BDF_TRANSLATING;
6205             cb.current = (sp->encoding - start) + 1;
6206             (*callback)(&cb, data);
6207         }
6208
6209         /*
6210          * Apply the X translation.
6211          */
6212         if (dx != 0) {
6213             sp->bbx.x_offset += dx;
6214             diff = sp->bbx.x_offset - font->bbx.x_offset;
6215             if (sp->bbx.x_offset < font->bbx.x_offset) {
6216                 font->bbx.x_offset = sp->bbx.x_offset;
6217                 font->bbx.width += MYABS(diff);
6218                 resize = 1;
6219             } else if (sp->bbx.width + sp->bbx.x_offset >
6220                        font->bbx.width + font->bbx.x_offset) {
6221                 font->bbx.width += MYABS(diff);
6222                 resize = 1;
6223             }
6224
6225             /*
6226              * Mark the glyph as modified appropriately.
6227              */
6228             if (unencoded)
6229               _bdf_set_glyph_modified(font->umod, sp->encoding);
6230             else
6231               _bdf_set_glyph_modified(font->nmod, sp->encoding);
6232         }
6233
6234         /*
6235          * Apply the Y translation.
6236          */
6237         if (dy != 0) {
6238             sp->bbx.y_offset += dy;
6239             sp->bbx.descent = -sp->bbx.y_offset;
6240             sp->bbx.ascent = sp->bbx.height - sp->bbx.descent;
6241             diff = sp->bbx.y_offset - font->bbx.y_offset;
6242             if (sp->bbx.y_offset < font->bbx.y_offset) {
6243                 font->bbx.y_offset = sp->bbx.y_offset;
6244                 font->bbx.descent = -font->bbx.y_offset;
6245                 font->bbx.height += MYABS(diff);
6246                 resize = 1;
6247             } else if (sp->bbx.ascent > font->bbx.ascent) {
6248                 font->bbx.ascent += MYABS(diff);
6249                 font->bbx.height += MYABS(diff);
6250                 resize = 1;
6251             }
6252
6253             /*
6254              * Mark the glyph as modified appropriately.
6255              */
6256             if (unencoded)
6257               _bdf_set_glyph_modified(font->umod, sp->encoding);
6258             else
6259               _bdf_set_glyph_modified(font->nmod, sp->encoding);
6260         }
6261     }
6262
6263     /*
6264      * Call the callback one more time to make sure the client knows
6265      * this is done.
6266      */
6267     if (callback != 0 && cb.current < cb.total) {
6268         cb.reason = BDF_TRANSLATING;
6269         cb.current = cb.total;
6270         (*callback)(&cb, data);
6271     }
6272
6273     if (resize)
6274       font->modified = 1;
6275
6276     return resize;
6277 }
6278
6279 static void
6280 _bdf_resize_rotation(bdf_font_t *font, int mul90, short degrees,
6281                      bdf_glyph_t *glyph, bdf_bitmap_t *scratch,
6282                      unsigned short *width, unsigned short *height)
6283 {
6284     unsigned short w, h, wd, ht, bytes;
6285     short cx, cy, x1, y1, x2, y2;
6286     double dx1, dy1, dx2, dy2;
6287
6288     w = h = 0;
6289
6290     cx = glyph->bbx.width >> 1;
6291     cy = glyph->bbx.height >> 1;
6292
6293     /*
6294      * Rotate the lower left and upper right corners and check for a potential
6295      * resize.
6296      */
6297     x1 = 0;
6298     y1 = glyph->bbx.height;
6299     x2 = glyph->bbx.width;
6300     y2 = 0;
6301
6302     dx1 = (double) (x1 - cx);
6303     dy1 = (double) (y1 - cy);
6304     dx2 = (double) (x2 - cx);
6305     dy2 = (double) (y2 - cx);
6306
6307     if (mul90) {
6308         x1 = cx + (short) ((dx1 * _bdf_cos_tbl[degrees]) -
6309                            (dy1 * _bdf_sin_tbl[degrees]));
6310         y1 = cy + (short) ((dx1 * _bdf_sin_tbl[degrees]) +
6311                            (dy1 * _bdf_cos_tbl[degrees]));
6312         x2 = cx + (short) ((dx2 * _bdf_cos_tbl[degrees]) -
6313                            (dy2 * _bdf_sin_tbl[degrees]));
6314         y2 = cy + (short) ((dx2 * _bdf_sin_tbl[degrees]) +
6315                            (dy2 * _bdf_cos_tbl[degrees]));
6316     } else {
6317         x1 = cx + _bdf_ceiling((dx1 * _bdf_cos_tbl[degrees]) -
6318                                (dy1 * _bdf_sin_tbl[degrees]));
6319         y1 = cy + _bdf_ceiling((dx1 * _bdf_sin_tbl[degrees]) +
6320                                (dy1 * _bdf_cos_tbl[degrees]));
6321         x2 = cx + _bdf_ceiling((dx2 * _bdf_cos_tbl[degrees]) -
6322                                (dy2 * _bdf_sin_tbl[degrees]));
6323         y2 = cy + _bdf_ceiling((dx2 * _bdf_sin_tbl[degrees]) +
6324                                (dy2 * _bdf_cos_tbl[degrees]));
6325     }
6326
6327     wd = MYABS(x2 - x1);
6328     ht = MYABS(y2 - y1);
6329
6330     w = MAX(wd, w);
6331     h = MAX(ht, h);
6332
6333     if (wd > font->bbx.width)
6334       font->bbx.width += wd - font->bbx.width;
6335     if (ht > font->bbx.height) {
6336         font->bbx.ascent += ht - font->bbx.height;
6337         font->bbx.height += ht - font->bbx.height;
6338     }
6339
6340     /*
6341      * Rotate the upper left and lower right corners and check for a potential
6342      * resize.
6343      */
6344     x1 = 0;
6345     y1 = 0;
6346     x2 = glyph->bbx.width;
6347     y2 = glyph->bbx.height;
6348
6349     dx1 = (double) (x1 - cx);
6350     dy1 = (double) (y1 - cy);
6351     dx2 = (double) (x2 - cx);
6352     dy2 = (double) (y2 - cx);
6353
6354     if (mul90) {
6355         x1 = cx + (short) ((dx1 * _bdf_cos_tbl[degrees]) -
6356                            (dy1 * _bdf_sin_tbl[degrees]));
6357         y1 = cy + (short) ((dx1 * _bdf_sin_tbl[degrees]) +
6358                            (dy1 * _bdf_cos_tbl[degrees]));
6359         x2 = cx + (short) ((dx2 * _bdf_cos_tbl[degrees]) -
6360                            (dy2 * _bdf_sin_tbl[degrees]));
6361         y2 = cy + (short) ((dx2 * _bdf_sin_tbl[degrees]) +
6362                            (dy2 * _bdf_cos_tbl[degrees]));
6363     } else {
6364         x1 = cx + _bdf_ceiling((dx1 * _bdf_cos_tbl[degrees]) -
6365                                (dy1 * _bdf_sin_tbl[degrees]));
6366         y1 = cy + _bdf_ceiling((dx1 * _bdf_sin_tbl[degrees]) +
6367                                (dy1 * _bdf_cos_tbl[degrees]));
6368         x2 = cx + _bdf_ceiling((dx2 * _bdf_cos_tbl[degrees]) -
6369                                (dy2 * _bdf_sin_tbl[degrees]));
6370         y2 = cy + _bdf_ceiling((dx2 * _bdf_sin_tbl[degrees]) +
6371                                (dy2 * _bdf_cos_tbl[degrees]));
6372     }
6373
6374     wd = MYABS(x2 - x1);
6375     ht = MYABS(y2 - y1);
6376
6377     w = MAX(wd, w);
6378     h = MAX(ht, h);
6379
6380     if (wd > font->bbx.width)
6381       font->bbx.width += wd - font->bbx.width;
6382     if (ht > font->bbx.height) {
6383         font->bbx.ascent += ht - font->bbx.height;
6384         font->bbx.height += ht - font->bbx.height;
6385     }
6386
6387     if (font->bbx.width > scratch->width ||
6388         font->bbx.height > scratch->height) {
6389         scratch->width = MAX(font->bbx.width, scratch->width);
6390         scratch->height = MAX(font->bbx.height, scratch->height);
6391         bytes = (((font->bbx.width * font->bpp) + 7) >> 3) * font->bbx.height;
6392         if (scratch->bytes == 0)
6393           scratch->bitmap = (unsigned char *) malloc(bytes);
6394         else
6395           scratch->bitmap = (unsigned char *)
6396               realloc((char *) scratch->bitmap, bytes);
6397         scratch->bytes = bytes;
6398     }
6399
6400     /*
6401      * Clear the bitmap.
6402      */
6403     (void) memset((char *) scratch->bitmap, 0, scratch->bytes);
6404
6405     /*
6406      * Return the new glyph width and height.
6407      */
6408     *width = w;
6409     *height = h;
6410 }
6411
6412 int
6413 bdf_rotate_glyphs(bdf_font_t *font, short degrees, int start,
6414                   int end, bdf_callback_t callback, void *data,
6415                   int unencoded)
6416 {
6417     int mul90, bpr, sbpr;
6418     unsigned short wd, ht, si, di, byte, col;
6419     short x, y, cx, cy, nx, ny, ox, oy, shiftx, shifty;
6420     bdf_glyph_t *gp, *sp, *ep;
6421     unsigned char *masks;
6422     double dx, dy;
6423     bdf_bitmap_t scratch;
6424     bdf_callback_struct_t cb;
6425
6426     if (font == 0 ||
6427         (unencoded && font->unencoded_used == 0) ||
6428         font->glyphs_used == 0 ||
6429         degrees == 0)
6430       return 0;
6431
6432     while (degrees < 0)
6433       degrees += 360;
6434     while (degrees >= 360)
6435       degrees -= 360;
6436
6437     mul90 = ((degrees % 90) == 0) ? 1 : 0;
6438
6439     masks = 0;
6440     switch (font->bpp) {
6441       case 1: masks = bdf_onebpp; break;
6442       case 2: masks = bdf_twobpp; break;
6443       case 4: masks = bdf_fourbpp; break;
6444       case 8: masks = bdf_eightbpp; break;
6445     }
6446
6447     /*
6448      * Initialize the scratch bitmap.
6449      */
6450     (void) memset((char *) &scratch, 0, sizeof(bdf_bitmap_t));
6451
6452     /*
6453      * Call the progress initialization callback.
6454      */
6455     if (callback != 0) {
6456         cb.reason = BDF_ROTATE_START;
6457         cb.total = (end - start) + 1;
6458         cb.current = 0;
6459         (*callback)(&cb, data);
6460     }
6461
6462     sp = _bdf_locate_glyph(font, start, unencoded);
6463     ep = _bdf_locate_glyph(font, end, unencoded);
6464     for (gp = sp; sp <= ep; sp++) {
6465         /*
6466          * Call the callback if one was provided.
6467          */
6468         if (sp != gp && callback != 0) {
6469             cb.reason = BDF_ROTATING;
6470             cb.current = (sp->encoding - start) + 1;
6471             (*callback)(&cb, data);
6472         }
6473
6474         /*
6475          * Resize the bitmap, adjust the font bounding box, and get the new
6476          * glyph width and height.
6477          */
6478         _bdf_resize_rotation(font, mul90, degrees, sp, &scratch, &wd, &ht);
6479
6480         cx = sp->bbx.width >> 1;
6481         cy = sp->bbx.height >> 1;
6482
6483         shiftx = shifty = 0;
6484         sbpr = ((wd * font->bpp) + 7) >> 3;
6485         bpr = ((sp->bbx.width * font->bpp) + 7) >> 3;
6486         for (y = 0; y < sp->bbx.height; y++) {
6487             for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) {
6488                 si = (col & 7) / font->bpp;
6489                 byte = sp->bitmap[(y * bpr) + (col >> 3)] & masks[si];
6490                 if (byte) {
6491                     dx = (double) (x - cx);
6492                     dy = (double) (y - cy);
6493                     if (mul90) {
6494                         nx = cx + (short) ((dx * _bdf_cos_tbl[degrees]) -
6495                                            (dy * _bdf_sin_tbl[degrees]));
6496                         ny = cy + (short) ((dx * _bdf_sin_tbl[degrees]) +
6497                                            (dy * _bdf_cos_tbl[degrees]));
6498                     } else {
6499                         nx = cx + _bdf_ceiling((dx * _bdf_cos_tbl[degrees]) -
6500                                                (dy * _bdf_sin_tbl[degrees]));
6501                         ny = cy + _bdf_ceiling((dx * _bdf_sin_tbl[degrees]) +
6502                                                (dy * _bdf_cos_tbl[degrees]));
6503                     }
6504                     if (nx < 0) {
6505                         shiftx = MIN(shiftx, nx);
6506                         nx += wd;
6507                     } else if (nx >= wd) {
6508                         ox = (nx - wd) + 1;
6509                         shiftx = MAX(shiftx, ox);
6510                         nx -= wd;
6511                     }
6512                     if (ny < 0) {
6513                         shifty = MIN(shifty, ny);
6514                         ny += ht;
6515                     } else if (ny >= ht) {
6516                         oy = (ny - ht) + 1;
6517                         shifty = MAX(shifty, oy);
6518                         ny -= ht;
6519                     }
6520                     nx *= font->bpp;
6521                     di = (nx & 7) / font->bpp;
6522                     if (di < si)
6523                       byte <<= (si - di) * font->bpp;
6524                     else if (di > si)
6525                       byte >>= (di - si) * font->bpp;
6526                     scratch.bitmap[(ny * sbpr) + (nx >> 3)] |= byte;
6527                 }
6528             }
6529         }
6530         /*
6531          * Resize the glyph bitmap if necessary.
6532          */
6533         if (wd != sp->bbx.width || ht != sp->bbx.height) {
6534             sp->bbx.width = wd;
6535             sp->bbx.height = ht;
6536             sp->bbx.ascent = ht - sp->bbx.descent;
6537             sp->bytes = (((wd * font->bpp) + 7) >> 3) * ht;
6538             sp->bitmap = (unsigned char *)
6539                 realloc((char *) sp->bitmap, sp->bytes);
6540         }
6541         (void) memset((char *) sp->bitmap, 0, sp->bytes);
6542
6543         /*
6544          * Copy the glyph from the scratch area to the glyph bitmap,
6545          * adjusting for any shift values encountered.
6546          */
6547         bpr = ((sp->bbx.width * font->bpp) + 7) >> 3;
6548         for (y = 0; y < sp->bbx.height; y++) {
6549             for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) {
6550                 si = (col & 7) / font->bpp;
6551                 byte = scratch.bitmap[(y * bpr) + (col >> 3)] & masks[si];
6552                 if (byte) {
6553                     nx = x - shiftx;
6554                     ny = y - shifty;
6555                     if (nx < 0)
6556                       nx += sp->bbx.width;
6557                     else if (nx >= sp->bbx.width)
6558                       nx -= sp->bbx.width;
6559                     if (ny < 0)
6560                       ny += sp->bbx.height;
6561                     else if (ny >= sp->bbx.height)
6562                       ny -= sp->bbx.height;
6563                     nx *= font->bpp;
6564                     di = (nx & 7) / font->bpp;
6565                     if (di < si)
6566                       byte <<= (si - di) * font->bpp;
6567                     else if (di > si)
6568                       byte >>= (di - si) * font->bpp;
6569                     sp->bitmap[(ny * bpr) + (nx >> 3)] |= byte;
6570                 }
6571             }
6572         }
6573         /*
6574          * Mark the glyph as modified.
6575          */
6576         if (unencoded)
6577           _bdf_set_glyph_modified(font->umod, sp->encoding);
6578         else
6579           _bdf_set_glyph_modified(font->nmod, sp->encoding);
6580     }
6581
6582     /*
6583      * Call the callback one more time to make sure the client knows
6584      * this is done.
6585      */
6586     if (callback != 0 && cb.current < cb.total) {
6587         cb.reason = BDF_TRANSLATING;
6588         cb.current = cb.total;
6589         (*callback)(&cb, data);
6590     }
6591
6592     if (scratch.bytes > 0)
6593       free((char *) scratch.bitmap);
6594
6595     /*
6596      * Rotations always change things, so just return a value indicating this.
6597      */
6598     font->modified = 1;
6599     return 1;
6600 }
6601
6602 static void
6603 _bdf_resize_shear(bdf_font_t *font, int neg, short degrees,
6604                   bdf_glyph_t *glyph, bdf_bitmap_t *scratch,
6605                   unsigned short *width, unsigned short *height)
6606 {
6607     unsigned short wd, w, bytes;
6608     short x1, y1, x2, y2;
6609
6610     w = 0;
6611     *height = glyph->bbx.height;
6612
6613     /*
6614      * Shear the lower left and upper right corners and check for a potential
6615      * resize.
6616      */
6617     x1 = 0;
6618     y1 = glyph->bbx.height;
6619     x2 = glyph->bbx.width;
6620     y2 = 0;
6621
6622     if (neg) {
6623         x1 += (short) ((double) y1 * _bdf_tan_tbl[degrees]);
6624         x2 += (short) ((double) y2 * _bdf_tan_tbl[degrees]);
6625     } else {
6626         x1 += (short) ((double) (glyph->bbx.height - y1) *
6627                        _bdf_tan_tbl[degrees]);
6628         x2 += (short) ((double) (glyph->bbx.height - y2) *
6629                        _bdf_tan_tbl[degrees]);
6630     }
6631
6632     wd = MYABS(x2 - x1);
6633     w = MAX(w, wd);
6634
6635     if (wd > font->bbx.width)
6636       font->bbx.width += wd - font->bbx.width;
6637
6638     /*
6639      * Shear the upper left and lower right corners and check for a potential
6640      * resize.
6641      */
6642     x1 = 0;
6643     y1 = 0;
6644     x2 = glyph->bbx.width;
6645     y2 = glyph->bbx.height;
6646
6647     if (neg) {
6648         x1 += (short) ((double) y1 * _bdf_tan_tbl[degrees]);
6649         x2 += (short) ((double) y2 * _bdf_tan_tbl[degrees]);
6650     } else {
6651         x1 += (short) ((double) (glyph->bbx.height - y1) *
6652                        _bdf_tan_tbl[degrees]);
6653         x2 += (short) ((double) (glyph->bbx.height - y2) *
6654                        _bdf_tan_tbl[degrees]);
6655     }
6656
6657     wd = MYABS(x2 - x1);
6658     w = MAX(w, wd);
6659
6660     if (wd > font->bbx.width)
6661       font->bbx.width += wd - font->bbx.width;
6662
6663     if (font->bbx.width > scratch->width ||
6664         font->bbx.height > scratch->height) {
6665         scratch->width = MAX(font->bbx.width, scratch->width);
6666         scratch->height = MAX(font->bbx.height, scratch->height);
6667         bytes = (((font->bbx.width * font->bpp) + 7) >> 3) * font->bbx.height;
6668         if (scratch->bytes == 0)
6669           scratch->bitmap = (unsigned char *) malloc(bytes);
6670         else
6671           scratch->bitmap = (unsigned char *)
6672               realloc((char *) scratch->bitmap, bytes);
6673         scratch->bytes = bytes;
6674     }
6675
6676     /*
6677      * Clear the bitmap.
6678      */
6679     (void) memset((char *) scratch->bitmap, 0, scratch->bytes);
6680
6681     /*
6682      * Return the new glyph width.
6683      */
6684     *width = w;
6685 }
6686
6687 int
6688 bdf_shear_glyphs(bdf_font_t *font, short degrees, int start,
6689                  int end, bdf_callback_t callback, void *data,
6690                  int unencoded)
6691 {
6692     int neg, bpr, sbpr;
6693     unsigned short wd, ht, si, di, byte, col;
6694     short x, y, nx, shiftx, ox;
6695     bdf_glyph_t *gp, *sp, *ep;
6696     unsigned char *masks;
6697     bdf_bitmap_t scratch;
6698     bdf_callback_struct_t cb;
6699
6700     if (font == 0 || (unencoded && font->unencoded_used == 0) ||
6701         font->glyphs_used == 0)
6702       return 0;
6703
6704     if (degrees == 0 || degrees < -45 || degrees > 45)
6705       return 0;
6706
6707     if ((neg = (degrees < 0)))
6708       degrees = -degrees;
6709
6710     masks = 0;
6711     switch (font->bpp) {
6712       case 1: masks = bdf_onebpp; break;
6713       case 2: masks = bdf_twobpp; break;
6714       case 4: masks = bdf_fourbpp; break;
6715       case 8: masks = bdf_eightbpp; break;
6716     }
6717
6718     /*
6719      * Initialize the scratch bitmap.
6720      */
6721     (void) memset((char *) &scratch, 0, sizeof(bdf_bitmap_t));
6722
6723     /*
6724      * Call the progress initialization callback.
6725      */
6726     if (callback != 0) {
6727         cb.reason = BDF_SHEAR_START;
6728         cb.total = (end - start) + 1;
6729         cb.current = 0;
6730         (*callback)(&cb, data);
6731     }
6732
6733     sp = _bdf_locate_glyph(font, start, unencoded);
6734     ep = _bdf_locate_glyph(font, end, unencoded);
6735     for (gp = sp; sp <= ep; sp++) {
6736         /*
6737          * Call the callback if one was provided.
6738          */
6739         if (sp != gp && callback != 0) {
6740             cb.reason = BDF_SHEARING;
6741             cb.current = (sp->encoding - start) + 1;
6742             (*callback)(&cb, data);
6743         }
6744
6745         /*
6746          * Resize the bitmap, adjust the font bounding box, and get the new
6747          * glyph width and height.
6748          */
6749         _bdf_resize_shear(font, neg, degrees, sp, &scratch, &wd, &ht);
6750
6751         shiftx = 0;
6752         sbpr = ((wd * font->bpp) + 7) >> 3;
6753         bpr = ((sp->bbx.width * font->bpp) + 7) >> 3;
6754         for (y = 0; y < sp->bbx.height; y++) {
6755             for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) {
6756                 si = (col & 7) / font->bpp;
6757                 byte = sp->bitmap[(y * bpr) + (col >> 3)] & masks[si];
6758                 if (byte) {
6759                     if (neg)
6760                       nx = x + (short) ((double) y * _bdf_tan_tbl[degrees]);
6761                     else
6762                       nx = x + (short) ((double) (sp->bbx.height - y) *
6763                                         _bdf_tan_tbl[degrees]);
6764
6765                     if (nx < 0) {
6766                         shiftx = MIN(shiftx, nx);
6767                         nx += wd;
6768                     } else if (nx >= wd) {
6769                         ox = (nx - wd) + 1;
6770                         shiftx = MAX(shiftx, ox);
6771                         nx -= wd;
6772                     }
6773                     nx *= font->bpp;
6774                     di = (nx & 7) / font->bpp;
6775                     if (di < si)
6776                       byte <<= (si - di) * font->bpp;
6777                     else if (di > si)
6778                       byte >>= (di - si) * font->bpp;
6779                     scratch.bitmap[(y * sbpr) + (nx >> 3)] |= byte;
6780                 }
6781             }
6782         }
6783         /*
6784          * Resize the glyph bitmap if necessary.
6785          */
6786         if (wd != sp->bbx.width || ht != sp->bbx.height) {
6787             sp->bbx.width = wd;
6788             sp->bbx.height = ht;
6789             sp->bbx.ascent = ht - sp->bbx.descent;
6790             sp->bytes = (((wd * font->bpp) + 7) >> 3) * ht;
6791             sp->bitmap = (unsigned char *)
6792                 realloc((char *) sp->bitmap, sp->bytes);
6793         }
6794         (void) memset((char *) sp->bitmap, 0, sp->bytes);
6795
6796         /*
6797          * Copy the glyph from the scratch area to the glyph bitmap,
6798          * adjusting for any shift values encountered.
6799          */
6800         bpr = ((sp->bbx.width * font->bpp) + 7) >> 3;
6801         for (y = 0; y < sp->bbx.height; y++) {
6802             for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) {
6803                 si = (col & 7) / font->bpp;
6804                 byte = scratch.bitmap[(y * bpr) + (col >> 3)] & masks[si];
6805                 if (byte) {
6806                     nx = x - shiftx;
6807                     if (nx < 0)
6808                       nx += sp->bbx.width;
6809                     else if (nx >= sp->bbx.width)
6810                       nx -= sp->bbx.width;
6811                     nx *= font->bpp;
6812                     di = (nx & 7) / font->bpp;
6813                     if (di < si)
6814                       byte <<= (si - di) * font->bpp;
6815                     else if (di > si)
6816                       byte >>= (di - si) * font->bpp;
6817                     sp->bitmap[(y * bpr) + (nx >> 3)] |= byte;
6818                 }
6819             }
6820         }
6821         /*
6822          * Mark the glyph as modified.
6823          */
6824         if (unencoded)
6825           _bdf_set_glyph_modified(font->umod, sp->encoding);
6826         else
6827           _bdf_set_glyph_modified(font->nmod, sp->encoding);
6828     }
6829
6830     /*
6831      * Call the callback one more time to make sure the client knows
6832      * this is done.
6833      */
6834     if (callback != 0 && cb.current < cb.total) {
6835         cb.reason = BDF_TRANSLATING;
6836         cb.current = cb.total;
6837         (*callback)(&cb, data);
6838     }
6839
6840     if (scratch.bytes > 0)
6841       free((char *) scratch.bitmap);
6842
6843     /*
6844      * Rotations always change things, so just return a value indicating this.
6845      */
6846     font->modified = 1;
6847     return 1;
6848 }
6849
6850 static void
6851 _bdf_widen_by(bdf_font_t *f, bdf_glyph_t *g, bdf_bitmap_t *s, int n)
6852 {
6853     int bytes, sbpr, dbpr, col;
6854     short x, y, si, di;
6855     unsigned char *bmap, *masks;
6856
6857     masks = 0;
6858     switch (f->bpp) {
6859       case 1: masks = bdf_onebpp; break;
6860       case 2: masks = bdf_twobpp; break;
6861       case 4: masks = bdf_fourbpp; break;
6862       case 8: masks = bdf_eightbpp; break;
6863     }
6864
6865     s->height = g->bbx.height;
6866     s->width = g->bbx.width + n;
6867
6868     bytes = (((s->width * f->bpp) + 7) >> 3) * s->height;
6869
6870     if (s->bytes == 0)
6871       s->bitmap = (unsigned char *) malloc(bytes);
6872     else
6873       s->bitmap = (unsigned char *)
6874           realloc((char *) s->bitmap, bytes);
6875     s->bytes = bytes;
6876
6877     (void) memset((char *) s->bitmap, 0, s->bytes);
6878
6879     /*
6880      * Copy the glyph bitmap to the scratch area, and then swap the bitmaps.
6881      */
6882     sbpr = ((g->bbx.width * f->bpp) + 7) >> 3;
6883     dbpr = ((s->width * f->bpp) + 7) >> 3;
6884     for (y = 0; y < g->bbx.height; y++) {
6885         for (col = x = 0; x < g->bbx.width; x++, col += f->bpp) {
6886             si = (col & 7) / f->bpp;
6887             bytes = g->bitmap[(y * sbpr) + (col >> 3)] & masks[si];
6888             if (bytes) {
6889                 di = ((x * f->bpp) & 7) / f->bpp;
6890                 if (di < si)
6891                   bytes <<= (si - di) * f->bpp;
6892                 else if (di > si)
6893                   bytes >>= (di - si) * f->bpp;
6894                 s->bitmap[(y * dbpr) + (col >> 3)] |= bytes;
6895             }
6896         }
6897     }
6898     g->bbx.width = s->width;
6899
6900     /*
6901      * Swap the bytes and bitmap fields from the scratch area and the glyph.
6902      */
6903     bytes = g->bytes;
6904     g->bytes = s->bytes;
6905     s->bytes = bytes;
6906
6907     bmap = g->bitmap;
6908     g->bitmap = s->bitmap;
6909     s->bitmap = bmap;
6910 }
6911
6912 int
6913 bdf_embolden_glyphs(bdf_font_t *font, int start, int end,
6914                     bdf_callback_t callback, void *data, int unencoded,
6915                     int *resize)
6916 {
6917     int mod, gmod, bpr;
6918     short x, y;
6919     unsigned short si, di, b1, b2, col;
6920     unsigned char *masks;
6921     bdf_glyph_t *gp, *sp, *ep;
6922     bdf_bitmap_t scratch;
6923     bdf_callback_struct_t cb;
6924
6925     if (font == 0 || (unencoded && font->unencoded_used == 0) ||
6926         font->glyphs_used == 0)
6927       return 0;
6928
6929     /*
6930      * Initialize the scratch bitmap which may be needed.
6931      */
6932     (void) memset((char *) &scratch, 0, sizeof(bdf_bitmap_t));
6933
6934     mod = 0;
6935     gp = 0;
6936
6937     masks = 0;
6938     switch (font->bpp) {
6939       case 1: masks = bdf_onebpp; break;
6940       case 2: masks = bdf_twobpp; break;
6941       case 4: masks = bdf_fourbpp; break;
6942       case 8: masks = bdf_eightbpp; break;
6943     }
6944
6945     /*
6946      * Call the progress initialization callback.
6947      */
6948     if (callback != 0) {
6949         cb.reason = BDF_EMBOLDEN_START;
6950         cb.total = (end - start) + 1;
6951         cb.current = 0;
6952         (*callback)(&cb, data);
6953     }
6954
6955     /*
6956      * Initialize the resize flag for the caller.
6957      */
6958     *resize = 0;
6959
6960     sp = _bdf_locate_glyph(font, start, unencoded);
6961     ep = _bdf_locate_glyph(font, end, unencoded);
6962     for (; sp <= ep; sp++) {
6963         /*
6964          * Call the callback if one was provided.
6965          */
6966         if (sp != gp && callback != 0) {
6967             cb.reason = BDF_EMBOLDENING;
6968             cb.current = (sp->encoding - start) + 1;
6969             (*callback)(&cb, data);
6970         }
6971
6972         if (font->spacing == BDF_PROPORTIONAL ||
6973             (font->spacing == BDF_MONOWIDTH &&
6974              sp->bbx.width < font->bbx.width)) {
6975             /*
6976              * Only widen the glyph if it is within reason.
6977              */
6978             _bdf_widen_by(font, sp, &scratch, 1);
6979
6980             if (sp->bbx.width > font->bbx.width) {
6981                 /*
6982                  * Bump the font width up by the difference.
6983                  */
6984                 font->bbx.width += sp->bbx.width - font->bbx.width;
6985                 *resize = 1;
6986             }
6987         }
6988
6989         gmod = 0;
6990         bpr = ((sp->bbx.width * font->bpp) + 7) >> 3;
6991         for (y = 0; y < sp->bbx.height; y++) {
6992             col = (sp->bbx.width - 1) * font->bpp;
6993             for (x = sp->bbx.width - 1; x > 0; x--, col -= font->bpp) {
6994                 si = (col & 7) / font->bpp;
6995                 di = ((col - font->bpp) & 7) / font->bpp;
6996                 b1 = (x == sp->bbx.width) ? 0 :
6997                     sp->bitmap[(y * bpr) + (col >> 3)] & masks[si];
6998                 b2 = sp->bitmap[(y * bpr) + ((col - font->bpp) >> 3)] &
6999                     masks[di];
7000                 if (!b1 && b2) {
7001                     if (di < si)
7002                       b2 >>= (si - di) * font->bpp;
7003                     else if (di > si)
7004                       b2 <<= (di - si) * font->bpp;
7005                     sp->bitmap[(y * bpr) + (col >> 3)] |= b2;
7006                     gmod = mod = 1;
7007                 }
7008             }
7009         }
7010         /*
7011          * Mark the glyph as modified.
7012          */
7013         if (gmod) {
7014             if (unencoded)
7015               _bdf_set_glyph_modified(font->umod, sp->encoding);
7016             else
7017               _bdf_set_glyph_modified(font->nmod, sp->encoding);
7018         }
7019     }
7020
7021     /*
7022      * Call the callback one more time to make sure the client knows
7023      * this is done.
7024      */
7025     if (callback != 0 && cb.current < cb.total) {
7026         cb.reason = BDF_EMBOLDENING;
7027         cb.current = cb.total;
7028         (*callback)(&cb, data);
7029     }
7030
7031     /*
7032      * Deallocate the scratch bitmap if necessary.
7033      */
7034     if (scratch.bytes > 0)
7035       free((char *) scratch.bitmap);
7036
7037     font->modified = mod;
7038
7039     return mod;
7040 }
7041
7042 static int _endian = 1;
7043 static char *little_endian = (char *) &_endian;
7044
7045 int
7046 bdf_little_endian(void)
7047 {
7048     return *little_endian;
7049 }