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 *
hash_bucket(char * key,hashtable * ht)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
hash_rehash(hashtable * ht)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
hash_init(hashtable * ht)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
hash_free(hashtable * ht)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
hash_insert(char * key,void * data,hashtable * ht)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
hash_lookup(char * key,hashtable * ht)292 hash_lookup(char *key, hashtable *ht)
293 {
294     hashnode *np = hash_bucket(key, ht);
295     return *np;
296 }
297 
298 static void
hash_delete(char * name,hashtable * ht)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
_bdf_split(char * separators,char * line,unsigned int linelen,_bdf_list_t * list)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
_bdf_shift(unsigned int n,_bdf_list_t * list)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 *
_bdf_join(int c,unsigned int * len,_bdf_list_t * list)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
_bdf_readlines(int fd,_bdf_line_func_t callback,void * client_data,unsigned int * lno)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 *
_bdf_strdup(unsigned char * s,unsigned int len)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
_bdf_memmove(char * dest,char * src,unsigned int bytes)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
_bdf_atoul(char * s,char ** end,int base)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
_bdf_atol(char * s,char ** end,int base)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
_bdf_atos(char * s,char ** end,int base)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
by_encoding(const void * a,const void * b)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
_bdf_add_acmsg(bdf_font_t * font,char * msg,unsigned int len)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
_bdf_add_comment(bdf_font_t * font,char * comment,unsigned int len)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
_bdf_set_default_spacing(bdf_font_t * font,bdf_options_t * opts)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
_bdf_is_atom(char * line,unsigned int linelen,char ** name,char ** value)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
_bdf_add_property(bdf_font_t * font,char * name,char * value)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
_bdf_parse_glyphs(char * line,unsigned int linelen,unsigned int lineno,void * call_data,void * client_data)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
_bdf_parse_properties(char * line,unsigned int linelen,unsigned int lineno,void * call_data,void * client_data)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     while (*line == ' ' || *line == '\t')
1658         ++line;
1659 
1660     /*
1661      * Check for the end of the properties.
1662      */
1663     if (memcmp(line, "ENDPROPERTIES", 13) == 0) {
1664         /*
1665          * If the FONT_ASCENT or FONT_DESCENT properties have not been
1666          * encountered yet, then make sure they are added as properties and
1667          * make sure they are set from the font bounding box info.
1668          *
1669          * This is *always* done regardless of the options, because X11
1670          * requires these two fields to compile fonts.
1671          */
1672         if (bdf_get_font_property(p->font, "FONT_ASCENT") == 0) {
1673             p->font->font_ascent = p->font->bbx.ascent;
1674             sprintf(nbuf, "%hd", p->font->bbx.ascent);
1675             _bdf_add_property(p->font, "FONT_ASCENT", nbuf);
1676             sprintf(nbuf, ACMSG1, p->font->bbx.ascent);
1677             _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1678             p->font->modified = 1;
1679         }
1680         if (bdf_get_font_property(p->font, "FONT_DESCENT") == 0) {
1681             p->font->font_descent = p->font->bbx.descent;
1682             sprintf(nbuf, "%hd", p->font->bbx.descent);
1683             _bdf_add_property(p->font, "FONT_DESCENT", nbuf);
1684             sprintf(nbuf, ACMSG2, p->font->bbx.descent);
1685             _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1686             p->font->modified = 1;
1687         }
1688         p->flags &= ~_BDF_PROPS;
1689         *next = _bdf_parse_glyphs;
1690         return 0;
1691     }
1692 
1693     /*
1694      * Ignore the _XFREE86_GLYPH_RANGES and _XMBDFED_INFO properties.
1695      */
1696     if (memcmp(line, "_XFREE86_GLYPH_RANGES", 21) == 0 ||
1697         memcmp(line, "_XMBDFED_INFO", 13) == 0)
1698       return 0;
1699 
1700     /*
1701      * Handle COMMENT fields and properties in a special way to preserve
1702      * the spacing.
1703      */
1704     if (memcmp(line, "COMMENT", 7) == 0) {
1705         name = value = line;
1706         value += 7;
1707         if (*value)
1708           *value++ = 0;
1709         _bdf_add_property(p->font, name, value);
1710     } else if (_bdf_is_atom(line, linelen, &name, &value))
1711       _bdf_add_property(p->font, name, value);
1712     else {
1713         _bdf_split(" +", line, linelen, &p->list);
1714         name = p->list.field[0];
1715         _bdf_shift(1, &p->list);
1716         value = _bdf_join(' ', &vlen, &p->list);
1717         _bdf_add_property(p->font, name, value);
1718     }
1719 
1720     return 0;
1721 }
1722 
1723 /*
1724  * Load the font header.
1725  */
1726 static int
_bdf_parse_start(char * line,unsigned int linelen,unsigned int lineno,void * call_data,void * client_data)1727 _bdf_parse_start(char *line, unsigned int linelen, unsigned int lineno,
1728                  void *call_data, void *client_data)
1729 {
1730     unsigned int slen = 0;
1731     _bdf_line_func_t *next;
1732     _bdf_parse_t *p;
1733     bdf_font_t *font;
1734     char *s, nbuf[128];
1735 
1736     next = (_bdf_line_func_t *) call_data;
1737     p = (_bdf_parse_t *) client_data;
1738 
1739     /*
1740      * Check for a comment.  This is done to handle those fonts that have
1741      * comments before the STARTFONT line for some reason.
1742      */
1743     if (memcmp(line, "COMMENT", 7) == 0) {
1744         if (p->opts->keep_comments != 0 && p->font != 0) {
1745             linelen -= 7;
1746             s = line + 7;
1747             if (*s != 0) {
1748                 s++;
1749                 linelen--;
1750             }
1751             _bdf_add_comment(p->font, s, linelen);
1752         }
1753         return 0;
1754     }
1755 
1756     if (!(p->flags & _BDF_START)) {
1757         if (memcmp(line, "STARTFONT", 9) != 0)
1758           /*
1759            * No STARTFONT field is a good indication of a problem.
1760            */
1761           return BDF_MISSING_START;
1762         p->flags = _BDF_START;
1763         p->font = font = (bdf_font_t *) calloc(1, sizeof(bdf_font_t));
1764         p->font->internal = (void *) malloc(sizeof(hashtable));
1765         hash_init((hashtable *) p->font->internal);
1766         p->font->spacing = p->opts->font_spacing;
1767         p->font->default_glyph = -1;
1768         return 0;
1769     }
1770 
1771     /*
1772      * Check for the start of the properties.
1773      */
1774     if (memcmp(line, "STARTPROPERTIES", 15) == 0) {
1775         _bdf_split(" +", line, linelen, &p->list);
1776         p->cnt = p->font->props_size = _bdf_atoul(p->list.field[1], 0, 10);
1777         p->font->props = (bdf_property_t *)
1778             malloc(sizeof(bdf_property_t) * p->cnt);
1779         p->flags |= _BDF_PROPS;
1780         *next = _bdf_parse_properties;
1781         return 0;
1782     }
1783 
1784     /*
1785      * Check for the FONTBOUNDINGBOX field.
1786      */
1787     if (memcmp(line, "FONTBOUNDINGBOX", 15) == 0) {
1788         if (!(p->flags & _BDF_SIZE)) {
1789             /*
1790              * Missing the SIZE field.
1791              */
1792             sprintf(nbuf, ERRMSG1, lineno, "SIZE");
1793             _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1794             return BDF_MISSING_SIZE;
1795         }
1796         _bdf_split(" +", line, linelen, &p->list);
1797         p->font->bbx.width = _bdf_atos(p->list.field[1], 0, 10);
1798         p->font->bbx.height = _bdf_atos(p->list.field[2], 0, 10);
1799         p->font->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10);
1800         p->font->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10);
1801         p->font->bbx.ascent = p->font->bbx.height + p->font->bbx.y_offset;
1802         p->font->bbx.descent = -p->font->bbx.y_offset;
1803         p->flags |= _BDF_FONT_BBX;
1804         return 0;
1805     }
1806 
1807     /*
1808      * The next thing to check for is the FONT field.
1809      */
1810     if (memcmp(line, "FONT", 4) == 0) {
1811         _bdf_split(" +", line, linelen, &p->list);
1812         _bdf_shift(1, &p->list);
1813         s = _bdf_join(' ', &slen, &p->list);
1814         p->font->name = (char *) malloc(slen + 1);
1815         (void) memcpy(p->font->name, s, slen + 1);
1816         /*
1817          * If the font name is an XLFD name, set the spacing to the one in the
1818          * font name.  If there is no spacing fall back on the default.
1819          */
1820         _bdf_set_default_spacing(p->font, p->opts);
1821         p->flags |= _BDF_FONT_NAME;
1822         return 0;
1823     }
1824 
1825     /*
1826      * Check for the SIZE field.
1827      */
1828     if (memcmp(line, "SIZE", 4) == 0) {
1829         if (!(p->flags & _BDF_FONT_NAME)) {
1830             /*
1831              * Missing the FONT field.
1832              */
1833             sprintf(nbuf, ERRMSG1, lineno, "FONT");
1834             _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1835             return BDF_MISSING_FONTNAME;
1836         }
1837         _bdf_split(" +", line, linelen, &p->list);
1838         p->font->point_size = _bdf_atoul(p->list.field[1], 0, 10);
1839         p->font->resolution_x = _bdf_atoul(p->list.field[2], 0, 10);
1840         p->font->resolution_y = _bdf_atoul(p->list.field[3], 0, 10);
1841 
1842         /*
1843          * Check for the bits per pixel field.
1844          */
1845         if (p->list.used == 5) {
1846             p->font->bpp = _bdf_atos(p->list.field[4], 0, 10);
1847             if (p->font->bpp > 1 && (p->font->bpp & 1)) {
1848                 /*
1849                  * Move up to the next bits per pixel value if an odd number
1850                  * is encountered.
1851                  */
1852                 p->font->bpp++;
1853                 if (p->font->bpp <= 4) {
1854                     sprintf(nbuf, ACMSG11, p->font->bpp);
1855                     _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1856                 }
1857             }
1858             if (p->font->bpp > 4) {
1859                 sprintf(nbuf, ACMSG11, p->font->bpp);
1860                 _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
1861                 p->font->bpp = 4;
1862             }
1863         } else
1864           p->font->bpp = 1;
1865 
1866         p->flags |= _BDF_SIZE;
1867         return 0;
1868     }
1869 
1870     return BDF_INVALID_LINE;
1871 }
1872 
1873 /**************************************************************************
1874  *
1875  * API.
1876  *
1877  **************************************************************************/
1878 
1879 void
bdf_setup(void)1880 bdf_setup(void)
1881 {
1882     unsigned int i;
1883     bdf_property_t *prop;
1884 
1885     hash_init(&proptbl);
1886     for (i = 0, prop = _bdf_properties; i < _num_bdf_properties; i++, prop++)
1887       hash_insert(prop->name, (void *) i, &proptbl);
1888 }
1889 
1890 void
bdf_cleanup(void)1891 bdf_cleanup(void)
1892 {
1893     unsigned int i;
1894     bdf_property_t *prop;
1895 
1896     hash_free(&proptbl);
1897 
1898     /*
1899      * Free up the user defined properties.
1900      */
1901     for (prop = user_props, i = 0; i < nuser_props; i++, prop++) {
1902         free(prop->name);
1903         if (prop->format == BDF_ATOM && prop->value.atom != 0)
1904           free(prop->value.atom);
1905     }
1906     if (nuser_props > 0)
1907       free((char *) user_props);
1908 
1909     _bdf_glyph_name_cleanup();
1910 }
1911 
1912 bdf_font_t *
bdf_load_font(FILE * in,bdf_options_t * opts,bdf_callback_t callback,void * data)1913 bdf_load_font(FILE *in, bdf_options_t *opts, bdf_callback_t callback,
1914               void *data)
1915 {
1916     int n;
1917     unsigned int lineno;
1918     char msgbuf[128];
1919     _bdf_parse_t p;
1920 
1921     (void) memset((char *) &p, 0, sizeof(_bdf_parse_t));
1922     p.opts = (opts != 0) ? opts : &_bdf_opts;
1923     p.minlb = 32767;
1924     p.callback = callback;
1925     p.client_data = data;
1926     n = _bdf_readlines(fileno(in), _bdf_parse_start, (void *) &p, &lineno);
1927 
1928     if (p.font != 0) {
1929         /*
1930          * If the font is not proportional, set the fonts monowidth
1931          * field to the width of the font bounding box.
1932          */
1933         if (p.font->spacing != BDF_PROPORTIONAL)
1934           p.font->monowidth = p.font->bbx.width;
1935 
1936         /*
1937          * If the number of glyphs loaded is not that of the original count,
1938          * indicate the difference.
1939          */
1940         if (p.cnt != p.font->glyphs_used + p.font->unencoded_used) {
1941             sprintf(msgbuf, ACMSG15, p.cnt,
1942                     p.font->glyphs_used + p.font->unencoded_used);
1943             _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1944             p.font->modified = 1;
1945         }
1946 
1947         /*
1948          * Once the font has been loaded, adjust the overall font metrics if
1949          * necessary.
1950          */
1951         if (p.opts->correct_metrics != 0 &&
1952             (p.font->glyphs_used > 0 || p.font->unencoded_used > 0)) {
1953             if (p.maxrb - p.minlb != p.font->bbx.width) {
1954                 sprintf(msgbuf, ACMSG3, p.font->bbx.width, p.maxrb - p.minlb);
1955                 _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1956                 p.font->bbx.width = p.maxrb - p.minlb;
1957                 p.font->modified = 1;
1958             }
1959             if (p.font->bbx.x_offset != p.minlb) {
1960                 sprintf(msgbuf, ACMSG4, p.font->bbx.x_offset, p.minlb);
1961                 _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1962                 p.font->bbx.x_offset = p.minlb;
1963                 p.font->modified = 1;
1964             }
1965             if (p.font->bbx.ascent != p.maxas) {
1966                 sprintf(msgbuf, ACMSG5, p.font->bbx.ascent, p.maxas);
1967                 _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1968                 p.font->bbx.ascent = p.maxas;
1969                 p.font->modified = 1;
1970             }
1971             if (p.font->bbx.descent != p.maxds) {
1972                 sprintf(msgbuf, ACMSG6, p.font->bbx.descent, p.maxds);
1973                 _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1974                 p.font->bbx.descent = p.maxds;
1975                 p.font->bbx.y_offset = -p.maxds;
1976                 p.font->modified = 1;
1977             }
1978             if (p.maxas + p.maxds != p.font->bbx.height) {
1979                 sprintf(msgbuf, ACMSG7, p.font->bbx.height, p.maxas + p.maxds);
1980                 _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
1981             }
1982             p.font->bbx.height = p.maxas + p.maxds;
1983 
1984             if (p.flags & _BDF_SWIDTH_ADJ)
1985               _bdf_add_acmsg(p.font, ACMSG8, strlen(ACMSG8));
1986         }
1987     }
1988 
1989     /*
1990      * Last, if an error happened during loading, handle the messages.
1991      */
1992     if (n < 0 && callback != 0) {
1993         /*
1994          * An error was returned.  Alert the client.
1995          */
1996         p.cb.reason = BDF_ERROR;
1997         p.cb.errlineno = lineno;
1998         (*callback)(&p.cb, data);
1999     } else if (p.flags & _BDF_START) {
2000         if (p.font != 0) {
2001             /*
2002              * The ENDFONT field was never reached or did not exist.
2003              */
2004             if (!(p.flags & _BDF_GLYPHS))
2005               /*
2006                * Error happened while parsing header.
2007                */
2008               sprintf(msgbuf, ERRMSG2, lineno);
2009             else
2010               /*
2011                * Error happened when parsing glyphs.
2012                */
2013               sprintf(msgbuf, ERRMSG3, lineno);
2014 
2015             _bdf_add_acmsg(p.font, msgbuf, strlen(msgbuf));
2016         }
2017 
2018         if (callback != 0) {
2019             p.cb.reason = BDF_ERROR;
2020             p.cb.errlineno = lineno;
2021             (*callback)(&p.cb, data);
2022         }
2023     } else if (callback != 0) {
2024         /*
2025          * This forces the progress bar to always finish.
2026          */
2027         p.cb.current = p.cb.total;
2028         (*p.callback)(&p.cb, p.client_data);
2029     }
2030 
2031     /*
2032      * Free up the list used during the parsing.
2033      */
2034     if (p.list.size > 0)
2035       free((char *) p.list.field);
2036 
2037     if (p.font != 0) {
2038         /*
2039          * Make sure the comments are NULL terminated if they exist.
2040          */
2041         if (p.font->comments_len > 0) {
2042             p.font->comments = (char *) realloc(p.font->comments,
2043                                                 p.font->comments_len + 1);
2044             p.font->comments[p.font->comments_len] = 0;
2045         }
2046 
2047         /*
2048          * Make sure the auto-correct messages are NULL terminated if they
2049          * exist.
2050          */
2051         if (p.font->acmsgs_len > 0) {
2052             p.font->acmsgs = (char *) realloc(p.font->acmsgs,
2053                                               p.font->acmsgs_len + 1);
2054             p.font->acmsgs[p.font->acmsgs_len] = 0;
2055         }
2056     }
2057 
2058     return p.font;
2059 }
2060 
2061 #ifdef HAVE_HBF
2062 
2063 static int
_bdf_parse_hbf_header(char * line,unsigned int linelen,unsigned int lineno,void * call_data,void * client_data)2064 _bdf_parse_hbf_header(char *line, unsigned int linelen, unsigned int lineno,
2065                       void *call_data, void *client_data)
2066 {
2067     unsigned int vlen = 0;
2068     char *name, *value;
2069     _bdf_parse_t *p;
2070     _bdf_line_func_t *next;
2071     char nbuf[24];
2072 
2073     next = (_bdf_line_func_t *) call_data;
2074     p = (_bdf_parse_t *) client_data;
2075 
2076     /*
2077      * Check for comments.
2078      */
2079     if (memcmp(line, "COMMENT", 7) == 0) {
2080         if (p->opts->keep_comments != 0 && p->font != 0) {
2081             name = line;
2082             value = name + 7;
2083             vlen = linelen - 7;
2084             if (*value) {
2085                 *value++ = 0;
2086                 vlen--;
2087             }
2088             /*
2089              * If the properties are being parsed, add the comment as a
2090              * property.  Otherwise, simply add the comment in the normal
2091              * fashion.
2092              */
2093             if (p->flags & _BDF_PROPS)
2094               _bdf_add_property(p->font, name, value);
2095             else
2096               _bdf_add_comment(p->font, value, vlen);
2097         }
2098         return 0;
2099     }
2100 
2101     if (!(p->flags & _BDF_START)) {
2102         if (memcmp(line, "HBF_START_FONT", 14) != 0)
2103           return -1;
2104         p->flags = _BDF_START;
2105         p->font = (bdf_font_t *) calloc(1, sizeof(bdf_font_t));
2106         /*
2107          * HBF fonts are always assumed to be 1 bit per pixel.
2108          */
2109         p->font->bpp = 1;
2110         p->font->internal = (void *) malloc(sizeof(hashtable));
2111         hash_init((hashtable *) p->font->internal);
2112         p->font->hbf = 1;
2113         p->font->spacing = p->opts->font_spacing;
2114         p->font->default_glyph = -1;
2115         return 0;
2116     }
2117 
2118     /*
2119      * Check for the HBF_END_FONT field.
2120      */
2121     if (memcmp(line, "HBF_END_FONT", 12) == 0)
2122       /*
2123        * Need to perform some checks here to see whether some fields are
2124        * missing or not.
2125        */
2126       return 0;
2127 
2128     /*
2129      * Check for HBF keywords which will be added as comments.  These should
2130      * never occur in the properties list.  Assume they won't.
2131      */
2132     if (memcmp(line, "HBF_", 4) == 0) {
2133         if (p->opts->keep_comments != 0)
2134           _bdf_add_comment(p->font, line, linelen);
2135         return 0;
2136     }
2137 
2138     if (!(p->flags & _BDF_PROPS)) {
2139         /*
2140          * Check for the start of the properties.
2141          */
2142         if (memcmp(line, "STARTPROPERTIES", 15) == 0) {
2143             _bdf_split(" +", line, linelen, &p->list);
2144             p->cnt = p->font->props_size = _bdf_atoul(p->list.field[1], 0, 10);
2145             p->font->props = (bdf_property_t *)
2146                 malloc(sizeof(bdf_property_t) * p->cnt);
2147             p->flags |= _BDF_PROPS;
2148             return 0;
2149         }
2150 
2151         /*
2152          * Check for the CHARS field.
2153          */
2154         if (memcmp(line, "CHARS", 5) == 0) {
2155             _bdf_split(" +", line, linelen, &p->list);
2156             p->cnt = p->font->glyphs_size =
2157                 _bdf_atoul(p->list.field[1], 0, 10);
2158             p->font->glyphs = (bdf_glyph_t *)
2159                 malloc(sizeof(bdf_glyph_t) * p->cnt);
2160             return 0;
2161         }
2162 
2163         /*
2164          * Check for the FONTBOUNDINGBOX field.
2165          */
2166         if (memcmp(line, "FONTBOUNDINGBOX", 15) == 0) {
2167             if (!(p->flags & (_BDF_START|_BDF_FONT_NAME|_BDF_SIZE)))
2168               return -1;
2169             _bdf_split(" +", line, linelen, &p->list);
2170             p->font->bbx.width = _bdf_atos(p->list.field[1], 0, 10);
2171             p->font->bbx.height = _bdf_atos(p->list.field[2], 0, 10);
2172             p->font->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10);
2173             p->font->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10);
2174             p->font->bbx.ascent = p->font->bbx.height + p->font->bbx.y_offset;
2175             p->font->bbx.descent = -p->font->bbx.y_offset;
2176             p->flags |= _BDF_FONT_BBX;
2177             return 0;
2178         }
2179 
2180         /*
2181          * The next thing to check for is the FONT field.
2182          */
2183         if (memcmp(line, "FONT", 4) == 0) {
2184             if (!(p->flags & _BDF_START))
2185               return -1;
2186             _bdf_split(" +", line, linelen, &p->list);
2187             _bdf_shift(1, &p->list);
2188             value = _bdf_join(' ', &vlen, &p->list);
2189             p->font->name = (char *) malloc(vlen + 1);
2190             (void) memcpy(p->font->name, value, vlen + 1);
2191             /*
2192              * If the font name is an XLFD name, set the spacing to the one in
2193              * the font name.  If there is no spacing fall back on the
2194              * default.
2195              */
2196             _bdf_set_default_spacing(p->font, p->opts);
2197             p->flags |= _BDF_FONT_NAME;
2198             return 0;
2199         }
2200 
2201         /*
2202          * Check for the SIZE field.
2203          */
2204         if (memcmp(line, "SIZE", 4) == 0) {
2205             if (!(p->flags & (_BDF_START|_BDF_FONT_NAME)))
2206               return -1;
2207             _bdf_split(" +", line, linelen, &p->list);
2208             p->font->point_size = _bdf_atoul(p->list.field[1], 0, 10);
2209             p->font->resolution_x = _bdf_atoul(p->list.field[2], 0, 10);
2210             p->font->resolution_y = _bdf_atoul(p->list.field[3], 0, 10);
2211             p->flags |= _BDF_SIZE;
2212             return 0;
2213         }
2214     } else {
2215         /*
2216          * Check for the end of the properties.
2217          */
2218         if (memcmp(line, "ENDPROPERTIES", 13) == 0) {
2219             /*
2220              * If the FONT_ASCENT or FONT_DESCENT properties have not been
2221              * encountered yet, then make sure they are added as properties and
2222              * make sure they are set from the font bounding box info.
2223              *
2224              * This is *always* done regardless of the options, because X11
2225              * requires these two fields to compile fonts.
2226              */
2227             if (bdf_get_font_property(p->font, "FONT_ASCENT") == 0) {
2228                 p->font->font_ascent = p->font->bbx.ascent;
2229                 sprintf(nbuf, "%hd", p->font->bbx.ascent);
2230                 _bdf_add_property(p->font, "FONT_ASCENT", nbuf);
2231                 sprintf(nbuf, ACMSG1, p->font->bbx.ascent);
2232                 _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
2233                 p->font->modified = 1;
2234             }
2235             if (bdf_get_font_property(p->font, "FONT_DESCENT") == 0) {
2236                 p->font->font_descent = p->font->bbx.descent;
2237                 sprintf(nbuf, "%hd", p->font->bbx.descent);
2238                 _bdf_add_property(p->font, "FONT_DESCENT", nbuf);
2239                 sprintf(nbuf, ACMSG2, p->font->bbx.descent);
2240                 _bdf_add_acmsg(p->font, nbuf, strlen(nbuf));
2241                 p->font->modified = 1;
2242             }
2243             p->flags &= ~_BDF_PROPS;
2244             return 0;
2245         }
2246 
2247         /*
2248          * Handle the next thing in the usual property fashion.
2249          */
2250         if (_bdf_is_atom(line, linelen, &name, &value))
2251           _bdf_add_property(p->font, name, value);
2252         else {
2253             _bdf_split(" +", line, linelen, &p->list);
2254             name = p->list.field[0];
2255             _bdf_shift(1, &p->list);
2256             value = _bdf_join(' ', &vlen, &p->list);
2257             _bdf_add_property(p->font, name, value);
2258         }
2259         return 0;
2260     }
2261 
2262     /*
2263      * Anything else is an error.
2264      */
2265     return -1;
2266 }
2267 
2268 #define CONST const
2269 
2270 static void
_bdf_add_hbf_glyph(HBF * hbf,unsigned int code,void * callback_data)2271 _bdf_add_hbf_glyph(HBF *hbf, unsigned int code, void *callback_data)
2272 {
2273     CONST unsigned char *bmap;
2274     unsigned int n;
2275     bdf_glyph_t *gp;
2276     bdf_font_t *font;
2277     _bdf_parse_t *p;
2278     HBF_BBOX *fbbx;
2279     double ps, rx, dw;
2280     char nbuf[24];
2281 
2282     /*
2283      * Attempt to get the bitmap.
2284      */
2285     if ((bmap = hbfGetBitmap(hbf, code)) == 0)
2286       /*
2287        * Need some sort of error handling here.
2288        */
2289       return;
2290 
2291     p = (_bdf_parse_t *) callback_data;
2292 
2293     fbbx = hbfFontBBox(hbf);
2294 
2295     font = p->font;
2296 
2297     /*
2298      * Check to make sure there is enough space to hold this glyph.  If not,
2299      * allocate 10 more just in case.
2300      */
2301     if (font->glyphs_used == font->glyphs_size) {
2302         if (font->glyphs_size == 0)
2303           font->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * 16);
2304         else
2305           font->glyphs = (bdf_glyph_t *)
2306               realloc((char *) font->glyphs,
2307                       sizeof(bdf_glyph_t) * (font->glyphs_used + 16));
2308         gp = font->glyphs + font->glyphs_size;
2309         (void) memset((char *) gp, 0, sizeof(bdf_glyph_t) * 16);
2310         font->glyphs_size += 16;
2311     }
2312 
2313     gp = font->glyphs + font->glyphs_used++;
2314 
2315     /*
2316      * Set the glyph name.
2317      */
2318     sprintf(nbuf, "char%d", code);
2319     n = (unsigned int) strlen(nbuf);
2320     gp->name = (char *) malloc(n + 1);
2321     (void) memcpy(gp->name, nbuf, n + 1);
2322 
2323     /*
2324      * Set encoding.
2325      */
2326     gp->encoding = (int) code;
2327 
2328     /*
2329      * Set the device width.
2330      */
2331     gp->dwidth = (unsigned short) fbbx->hbf_width;
2332 
2333     /*
2334      * Set the scalable width.
2335      */
2336     ps = (double) font->point_size;
2337     rx = (double) font->resolution_x;
2338     dw = (double) gp->dwidth;
2339     gp->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
2340 
2341     /*
2342      * Set the glyph bounding box.
2343      */
2344     gp->bbx.width = fbbx->hbf_width;
2345     gp->bbx.height = fbbx->hbf_height;
2346     gp->bbx.x_offset = fbbx->hbf_xDisplacement;
2347     gp->bbx.y_offset = fbbx->hbf_yDisplacement;
2348     gp->bbx.ascent = gp->bbx.height + gp->bbx.y_offset;
2349     gp->bbx.descent = -gp->bbx.y_offset;
2350 
2351     /*
2352      * Add the bitmap by making a copy.  Assumes the font bbx is OK for
2353      * determining the number of bytes needed for the glyph bitmap.
2354      */
2355     gp->bytes = ((gp->bbx.width + 7) >> 3) * gp->bbx.height;
2356     gp->bitmap = (unsigned char *) malloc(gp->bytes);
2357     (void) memcpy((char *) gp->bitmap, (char *) bmap, gp->bytes);
2358 
2359     /*
2360      * Call the callback if it was provided.
2361      */
2362     if (p->callback != 0) {
2363         p->cb.reason = BDF_LOADING;
2364         p->cb.total = font->glyphs_size;
2365         p->cb.current = font->glyphs_used;
2366         (*p->callback)(&p->cb, p->client_data);
2367     }
2368 }
2369 
2370 bdf_font_t *
bdf_load_hbf_font(char * filename,bdf_options_t * opts,bdf_callback_t callback,void * data)2371 bdf_load_hbf_font(char *filename, bdf_options_t *opts, bdf_callback_t callback,
2372                   void *data)
2373 {
2374     int n, diff;
2375     unsigned int lineno;
2376     FILE *in;
2377     HBF *hbf;
2378     bdf_property_t *pp;
2379     char *name;
2380     _bdf_parse_t p;
2381 
2382     if ((hbf = hbfOpen(filename)) == 0)
2383       return 0;
2384 
2385     if ((in = fopen(hbfFileName(hbf), "r")) == 0) {
2386         hbfClose(hbf);
2387         return 0;
2388     }
2389 
2390     /*
2391      * Parse the HBF header for properties and other things.
2392      */
2393     (void) memset((char *) &p, 0, sizeof(_bdf_parse_t));
2394     p.opts = (opts != 0) ? opts : &_bdf_opts;
2395     p.minlb = 32767;
2396     p.callback = callback;
2397     p.client_data = data;
2398 
2399     n = _bdf_readlines(fileno(in), _bdf_parse_hbf_header, (void *) &p,
2400                        &lineno);
2401 
2402     fclose(in);
2403 
2404     /*
2405      * Determine what spacing the font has so the monowidth field can be set
2406      * if necessary.
2407      */
2408     if ((pp = bdf_get_font_property(p.font, "SPACING")) != 0) {
2409         switch (pp->value.atom[0]) {
2410           case 'p': case 'P': p.font->spacing = BDF_PROPORTIONAL; break;
2411           case 'm': case 'M': p.font->spacing = BDF_MONOWIDTH; break;
2412           case 'c': case 'C': p.font->spacing = BDF_CHARCELL; break;
2413         }
2414     }
2415 
2416     /*
2417      * Set the monowidth field if necessary.
2418      */
2419     if (p.font->spacing != BDF_PROPORTIONAL)
2420       p.font->monowidth = p.font->bbx.width;
2421 
2422     /*
2423      * Before loading the glyphs, check to see if any glyph structures have
2424      * been added.  If not, check the HBF font for the number of characters.
2425      * Dynamically increasing glyph storage causes memory fragmentation on
2426      * some machines and crashes.  This takes care of the cases where the HBF
2427      * file does not provide a "CHARS n" line.
2428      */
2429     if (p.font->glyphs_size < hbfChars(hbf)) {
2430         if (p.font->glyphs_size == 0)
2431           p.font->glyphs = (bdf_glyph_t *)
2432               malloc(sizeof(bdf_glyph_t) * hbfChars(hbf));
2433         else
2434           p.font->glyphs = (bdf_glyph_t *)
2435               realloc((char *) p.font->glyphs,
2436                       sizeof(bdf_glyph_t) * hbfChars(hbf));
2437         diff = hbfChars(hbf) - p.font->glyphs_size;
2438         (void) memset((char *) (p.font->glyphs + p.font->glyphs_size), 0,
2439                       diff);
2440         p.font->glyphs_size = hbfChars(hbf);
2441     }
2442 
2443     /*
2444      * Call the callback initially to set things up.
2445      */
2446     if (p.callback != 0) {
2447         p.cb.reason = BDF_LOAD_START;
2448         p.cb.total = p.font->glyphs_size;
2449         p.cb.current = 0;
2450         (*p.callback)(&p.cb, p.client_data);
2451     }
2452 
2453     /*
2454      * Now load the glyphs.
2455      */
2456     hbfForEach(hbf, _bdf_add_hbf_glyph, (void *) &p);
2457 
2458     /*
2459      * Close the HBF font.
2460      */
2461     hbfClose(hbf);
2462 
2463     /*
2464      * Sort the glyphs by encoding.
2465      */
2466     qsort((char *) p.font->glyphs, p.font->glyphs_used, sizeof(bdf_glyph_t),
2467           by_encoding);
2468 
2469     /*
2470      * After loading the HBF header, create an XLFD name.  If the XLFD name
2471      * cannot be made then preserve the name found in the HBF file.
2472      */
2473     if ((name = bdf_make_xlfd_name(p.font, "HBF", "Unknown")) != 0) {
2474         if (p.font->name != 0)
2475           /*
2476            * If a name already exists in the font, free it up.
2477            */
2478           free(p.font->name);
2479 
2480         /*
2481          * Replace the old name with the XLFD name.
2482          */
2483         p.font->name = name;
2484     }
2485 
2486     /*
2487      * Mark the font as being modified and generate a message that says
2488      * something about the font being converted from HBF format.
2489      */
2490     p.font->modified = 1;
2491     _bdf_add_acmsg(p.font, "Font converted from HBF to BDF.", 31);
2492 
2493     return p.font;
2494 }
2495 
2496 #endif /* HAVE_HBF */
2497 
2498 /*
2499  * Crop the glyph bitmap to the minimum rectangle needed to hold the bits that
2500  * are set.  Adjust the metrics based on the provided bounding box.
2501  */
2502 void
_bdf_crop_glyph(bdf_font_t * font,bdf_glyph_t * glyph)2503 _bdf_crop_glyph(bdf_font_t *font, bdf_glyph_t *glyph)
2504 {
2505     int byte;
2506     unsigned short x, y, bpr, nbpr, col, colx, si, di;
2507     unsigned short minx, maxx, miny, maxy;
2508     unsigned int bytes;
2509     unsigned char *bmap, *masks;
2510     bdf_bbx_t nbbx;
2511 
2512     if (glyph == 0)
2513       return;
2514 
2515     (void) memcpy((char *) &nbbx, (char *) &glyph->bbx, sizeof(bdf_bbx_t));
2516 
2517     bpr = ((glyph->bbx.width * font->bpp) + 7) >> 3;
2518 
2519     maxx = maxy = 0;
2520     minx = miny = 32767;
2521 
2522     masks = 0;
2523     switch (font->bpp) {
2524       case 1: masks = bdf_onebpp; break;
2525       case 2: masks = bdf_twobpp; break;
2526       case 4: masks = bdf_fourbpp; break;
2527       case 8: masks = bdf_eightbpp; break;
2528     }
2529 
2530     for (y = 0; y < glyph->bbx.height; y++) {
2531         for (col = x = 0; x < glyph->bbx.width; x++, col += font->bpp) {
2532             si = (col & 7) / font->bpp;
2533             if (glyph->bitmap[(y * bpr) + (col >> 3)] & masks[si]) {
2534                 minx = MIN(minx, x);
2535                 maxx = MAX(maxx, x);
2536                 miny = MIN(miny, y);
2537                 maxy = MAX(maxy, y);
2538             }
2539         }
2540     }
2541 
2542     /*
2543      * Handle an empty bitmap as a special case.
2544      */
2545     if (minx == 32767) {
2546         if (glyph->bytes > 0)
2547           free((char *) glyph->bitmap);
2548         glyph->bytes = 0;
2549         (void) memset((char *) &glyph->bbx, 0, sizeof(bdf_bbx_t));
2550         return;
2551     }
2552 
2553     /*
2554      * Increment the max points so width and height calculations won't go
2555      * wrong.
2556      */
2557     maxx++;
2558     maxy++;
2559 
2560     if (minx > 0)
2561       nbbx.x_offset += minx;
2562     if (maxx - minx != nbbx.width)
2563       nbbx.width = maxx - minx;
2564 
2565     if (miny > 0)
2566       nbbx.ascent -= miny;
2567     if (maxy - miny != nbbx.height)
2568       nbbx.height = maxy - miny;
2569     nbbx.descent = nbbx.height - nbbx.ascent;
2570     nbbx.y_offset = -nbbx.descent;
2571 
2572     nbpr = ((nbbx.width * font->bpp) + 7) >> 3;
2573 
2574     /*
2575      * If nothing changed, then the glyph is already contained in the
2576      * minimum rectangle.
2577      */
2578     if (memcmp((char *) &nbbx, (char *) &glyph->bbx,
2579                sizeof(bdf_bbx_t)) == 0 ||
2580         (nbpr == bpr && nbbx.height == glyph->bbx.height))
2581       return;
2582 
2583     /*
2584      * The metrics changed, so a new bitmap is needed.
2585      */
2586     bytes = nbpr * nbbx.height;
2587     bmap = (unsigned char *) malloc(bytes);
2588     (void) memset((char *) bmap, 0, bytes);
2589 
2590     colx = minx * font->bpp;
2591     for (y = miny; y < maxy; y++) {
2592         for (col = x = minx; x < maxx; x++, col += font->bpp) {
2593             si = (col & 7) / font->bpp;
2594             byte = glyph->bitmap[(y * bpr) + (col >> 3)] & masks[si];
2595             if (byte) {
2596                 /*
2597                  * Position the pixel in the byte if necessary.
2598                  */
2599                 di = ((col - colx) & 7) / font->bpp;
2600                 if (di < si)
2601                   byte <<= (si - di) * font->bpp;
2602                 else if (di > si)
2603                   byte >>= (di - si) * font->bpp;
2604                 bmap[((y - miny) * nbpr) + ((col - colx) >> 3)] |= byte;
2605             }
2606         }
2607     }
2608 
2609     if (glyph->bytes > 0)
2610       free((char *) glyph->bitmap);
2611     glyph->bytes = bytes;
2612     glyph->bitmap = bmap;
2613 
2614     (void) memcpy((char *) &glyph->bbx, (char *) &nbbx, sizeof(bdf_bbx_t));
2615 }
2616 
2617 /*
2618  * Pad a character-cell font glyph to match the bounds specified in the
2619  * provided bounding box.
2620  */
2621 void
_bdf_pad_cell(bdf_font_t * font,bdf_glyph_t * glyph,bdf_glyph_t * cell)2622 _bdf_pad_cell(bdf_font_t *font, bdf_glyph_t *glyph, bdf_glyph_t *cell)
2623 {
2624     bdf_bbx_t *bbx;
2625     unsigned short si, di, sx, byte;
2626     unsigned short x, y, dx, dy, bx, by, bpr, nbpr;
2627     unsigned char *bmap, *masks;
2628 
2629     masks = 0;
2630     switch (font->bpp) {
2631       case 1: masks = bdf_onebpp; break;
2632       case 2: masks = bdf_twobpp; break;
2633       case 4: masks = bdf_fourbpp; break;
2634       case 8: masks = bdf_eightbpp; break;
2635     }
2636 
2637     bbx = &font->bbx;
2638 
2639     if (glyph->bbx.width == bbx->width && glyph->bbx.height == bbx->height) {
2640         /*
2641          * The glyph is already positioned in the cell.  Copy the bitmap
2642          * and return.
2643          */
2644         (void) memcpy((char *) cell->bitmap, (char *) glyph->bitmap,
2645                       cell->bytes);
2646         return;
2647     }
2648 
2649     /*
2650      * Determine the X and Y location of the baseline.
2651      */
2652     bx = MYABS(bbx->x_offset - glyph->bbx.x_offset);
2653     by = (bbx->ascent + bbx->descent) + bbx->y_offset;
2654 
2655     bpr = ((glyph->bbx.width * font->bpp) + 7) >> 3;
2656     nbpr = ((bbx->width * font->bpp) + 7) >> 3;
2657 
2658     /*
2659      * Set various cell values and clear the cell bitmap.
2660      */
2661     bmap = cell->bitmap;
2662     (void) memset((char *) bmap, 0, cell->bytes);
2663 
2664     for (dy = by - glyph->bbx.ascent, y = 0; y < glyph->bbx.height;
2665          y++, dy++) {
2666         for (dx = bx * font->bpp, sx = x = 0; x < glyph->bbx.width;
2667              x++, dx += font->bpp, sx += font->bpp) {
2668             si = (sx & 7) / font->bpp;
2669             byte = glyph->bitmap[(y * bpr) + (sx >> 3)] & masks[si];
2670             if (byte) {
2671                 di = (dx & 7) / font->bpp;
2672                 if (di < si)
2673                   byte <<= (si - di) * font->bpp;
2674                 else if (di > si)
2675                   byte >>= (di - si) * font->bpp;
2676                 bmap[(dy * nbpr) + (dx >> 3)] |= byte;
2677             }
2678         }
2679     }
2680 }
2681 
2682 static char *unix_eol = "\n";
2683 static char *dos_eol = "\r\n";
2684 static char *mac_eol = "\r";
2685 
2686 void
bdf_save_font(FILE * out,bdf_font_t * font,bdf_options_t * opts,bdf_callback_t callback,void * data)2687 bdf_save_font(FILE *out, bdf_font_t *font, bdf_options_t *opts,
2688               bdf_callback_t callback, void *data)
2689 {
2690     int len;
2691     unsigned int i, j, bpr, pcnt;
2692     double dw, ps, rx;
2693     char *sp, *ep, *eol;
2694     bdf_property_t *p;
2695     bdf_glyph_t *c, *cp, cell;
2696     bdf_callback_struct_t cb;
2697 
2698     if (font == 0)
2699       return;
2700 
2701     eol = 0;
2702     switch (opts->eol) {
2703       case BDF_UNIX_EOL: eol = unix_eol; break;
2704       case BDF_DOS_EOL: eol = dos_eol; break;
2705       case BDF_MAC_EOL: eol = mac_eol; break;
2706     }
2707 
2708     /*
2709      * If the font is a character cell font, allocate some space for the
2710      * bitmap.
2711      */
2712     if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0) {
2713         bpr = ((font->bbx.width * font->bpp) + 7) >> 3;
2714         cell.bytes = bpr * font->bbx.height;
2715         cell.bitmap = (unsigned char *) malloc(cell.bytes);
2716         (void) memcpy((char *) &cell.bbx, (char *) &font->bbx,
2717                       sizeof(bdf_bbx_t));
2718     }
2719 
2720     /*
2721      * Emit the header.
2722      */
2723     fprintf(out, "STARTFONT 2.1%s", eol);
2724 
2725     /*
2726      * Emit the comments.
2727      */
2728     if (font->comments_len > 0) {
2729         for (sp = font->comments; *sp; sp++) {
2730             ep = sp;
2731             while (*ep && *ep != '\n')
2732               ep++;
2733             len = (int) (ep - sp);
2734             fprintf(out, "COMMENT %.*s%s", len, sp, eol);
2735             sp = ep;
2736         }
2737     }
2738 
2739     /*
2740      * Emit the font name.
2741      */
2742     fprintf(out, "FONT %s%s", font->name, eol);
2743 
2744     /*
2745      * Emit the size info.
2746      */
2747     if (font->bpp == 1)
2748       fprintf(out, "SIZE %d %d %d%s", font->point_size,
2749               font->resolution_x, font->resolution_y, eol);
2750     else
2751       fprintf(out, "SIZE %d %d %d %hd%s", font->point_size,
2752               font->resolution_x, font->resolution_y, font->bpp, eol);
2753 
2754     /*
2755      * Emit the bounding box.
2756      */
2757     fprintf(out, "FONTBOUNDINGBOX %hd %hd %hd %hd%s",
2758             font->bbx.width, font->bbx.height, font->bbx.x_offset,
2759             font->bbx.y_offset, eol);
2760 
2761     /*
2762      * Emit the properties after counting how many are properties and
2763      * how many are comments.
2764      */
2765     for (i = pcnt = 0, p = font->props; i < font->props_used; i++, p++) {
2766         if (memcmp(p->name, "COMMENT", 7) != 0)
2767           pcnt++;
2768     }
2769 
2770     fprintf(out, "STARTPROPERTIES %d%s", pcnt, eol);
2771     for (i = 0, p = font->props; i < font->props_used; i++, p++) {
2772         fprintf(out, "%s ", p->name);
2773         if (p->format == BDF_ATOM) {
2774             if (p->value.atom == 0)
2775               fprintf(out, "\"\"%s", eol);
2776             else
2777               fprintf(out, "\"%s\"%s", p->value.atom, eol);
2778         } else
2779           fprintf(out, "%d%s", p->value.int32, eol);
2780     }
2781 
2782     fprintf(out, "ENDPROPERTIES%s", eol);
2783 
2784     /*
2785      * Emit the number of bitmaps in the font.
2786      */
2787     fprintf(out, "CHARS %d%s", font->unencoded_used + font->glyphs_used, eol);
2788 
2789     /*
2790      * Call the callback if it was passed to start the save.
2791      */
2792     if (callback != 0) {
2793         cb.reason = BDF_SAVE_START;
2794         cb.total = font->unencoded_used + font->glyphs_used;
2795         cb.current = 0;
2796         (*callback)(&cb, data);
2797     }
2798 
2799     /*
2800      * Emit the unencoded bitmaps.
2801      */
2802     for (i = 0, cp = font->unencoded; i < font->unencoded_used; i++, cp++) {
2803         /*
2804          * If the font has character-cell spacing and the option to pad the
2805          * glyphs to the size of the font bbx is set, then pad the glyph.
2806          * Otherwise, crop the glyph to the minimum rectangle needed to hold
2807          * the bitmap.
2808          */
2809         if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0) {
2810             /*
2811              * Point at the temporary glyph structure and copy the necessary
2812              * glyph info into it.
2813              */
2814             c = &cell;
2815             c->name = cp->name;
2816             c->encoding = cp->encoding;
2817             c->swidth = cp->swidth;
2818             c->dwidth = cp->dwidth;
2819             _bdf_pad_cell(font, cp, c);
2820         } else {
2821             c = cp;
2822             _bdf_crop_glyph(font, c);
2823         }
2824 
2825         /*
2826          * If the font has monowidth or character-cell spacing, then assign
2827          * the font monowidth field to the device width and recalculate the
2828          * scalable width.
2829          */
2830         if (font->spacing != BDF_PROPORTIONAL) {
2831             c->dwidth = font->monowidth;
2832             ps = (double) font->point_size;
2833             rx = (double) font->resolution_x;
2834             dw = (double) c->dwidth;
2835             c->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
2836         }
2837         if (c->name == 0)
2838           fprintf(out, "STARTCHAR unencoded%d%sENCODING -1%s", i, eol, eol);
2839         else
2840           fprintf(out, "STARTCHAR %s%sENCODING -1%s", c->name, eol, eol);
2841         fprintf(out, "SWIDTH %hd 0%sDWIDTH %hd 0%s",
2842                 c->swidth, eol, c->dwidth, eol);
2843         fprintf(out, "BBX %hd %hd %hd %hd%s", c->bbx.width, c->bbx.height,
2844                 c->bbx.x_offset, c->bbx.y_offset, eol);
2845         fprintf(out, "BITMAP%s", eol);
2846         bpr = ((c->bbx.width * font->bpp) + 7) >> 3;
2847         for (j = 0; bpr != 0 && j < c->bytes; j++) {
2848             if (j && j % bpr == 0)
2849               fprintf(out, eol);
2850             fprintf(out, "%02X", c->bitmap[j]);
2851         }
2852         /*
2853          * Handle empty bitmaps like this.
2854          */
2855         if (c->bbx.height > 0)
2856           fprintf(out, eol);
2857         fprintf(out, "ENDCHAR%s", eol);
2858 
2859         /*
2860          * Call the callback if supplied.
2861          */
2862         if (callback != 0) {
2863             cb.reason = BDF_SAVING;
2864             cb.current++;
2865             (*callback)(&cb, data);
2866         }
2867     }
2868 
2869     /*
2870      * Emit the other bitmaps.
2871      */
2872     for (i = 0, cp = font->glyphs; i < font->glyphs_used; i++, cp++) {
2873         /*
2874          * If the font has character-cell spacing and the option to pad the
2875          * glyphs to the size of the font bbx is set, then pad the glyph.
2876          * Otherwise, crop the glyph to the minimum rectangle needed to hold
2877          * the bitmap.
2878          */
2879         if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0) {
2880             /*
2881              * Point at the temporary glyph structure and copy the necessary
2882              * glyph info into it.
2883              */
2884             c = &cell;
2885             c->name = cp->name;
2886             c->encoding = cp->encoding;
2887             c->swidth = cp->swidth;
2888             c->dwidth = cp->dwidth;
2889             _bdf_pad_cell(font, cp, c);
2890         } else {
2891             c = cp;
2892             _bdf_crop_glyph(font, c);
2893         }
2894 
2895         /*
2896          * If the font has monowidth or character-cell spacing, then assign
2897          * the font monowidth field to the device width and recalculate the
2898          * scalable width.
2899          */
2900         if (font->spacing != BDF_PROPORTIONAL) {
2901             c->dwidth = font->monowidth;
2902             ps = (double) font->point_size;
2903             rx = (double) font->resolution_x;
2904             dw = (double) c->dwidth;
2905             c->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
2906         }
2907         if (c->name == 0)
2908           fprintf(out, "STARTCHAR char%d%sENCODING %d%s",
2909                   c->encoding, eol, c->encoding, eol);
2910         else
2911           fprintf(out, "STARTCHAR %s%sENCODING %d%s",
2912                   c->name, eol, c->encoding, eol);
2913         fprintf(out, "SWIDTH %hd 0%sDWIDTH %hd 0%s",
2914                 c->swidth, eol, c->dwidth, eol);
2915         fprintf(out, "BBX %hd %hd %hd %hd%s", c->bbx.width, c->bbx.height,
2916                 c->bbx.x_offset, c->bbx.y_offset, eol);
2917         fprintf(out, "BITMAP%s", eol);
2918         bpr = ((c->bbx.width * font->bpp) + 7) >> 3;
2919         for (j = 0; bpr != 0 && j < c->bytes; j++) {
2920             if (j && j % bpr == 0)
2921               fprintf(out, eol);
2922             fprintf(out, "%02X", c->bitmap[j]);
2923         }
2924         /*
2925          * Handle empty bitmaps like this.
2926          */
2927         if (c->bbx.height > 0)
2928           fprintf(out, eol);
2929         fprintf(out, "ENDCHAR%s", eol);
2930 
2931         /*
2932          * Call the callback if supplied.
2933          */
2934         if (callback != 0) {
2935             cb.reason = BDF_SAVING;
2936             cb.current++;
2937             (*callback)(&cb, data);
2938         }
2939     }
2940 
2941     /*
2942      * Emit the trailer.
2943      */
2944     fprintf(out, "ENDFONT%s", eol);
2945 
2946     /*
2947      * Always force a final call to the callback to make sure things
2948      * get cleaned up.
2949      */
2950     if (callback != 0) {
2951         cb.reason = BDF_SAVING;
2952         cb.current = cb.total;
2953         (*callback)(&cb, data);
2954     }
2955 
2956     /*
2957      * If the font is a character cell font, clean up the temporary glyph.
2958      */
2959     if (font->spacing == BDF_CHARCELL && opts->pad_cells != 0)
2960       free((char *) cell.bitmap);
2961 }
2962 
2963 /*
2964  * Routine to write a single set of SBIT metrics.
2965  */
2966 void
bdf_save_sbit_metrics(FILE * out,bdf_font_t * font,bdf_options_t * opts,char * appname)2967 bdf_save_sbit_metrics(FILE *out, bdf_font_t *font, bdf_options_t *opts,
2968                       char *appname)
2969 {
2970     char *eol;
2971 
2972     eol = 0;
2973     switch (opts->eol) {
2974       case BDF_UNIX_EOL: eol = unix_eol; break;
2975       case BDF_DOS_EOL: eol = dos_eol; break;
2976       case BDF_MAC_EOL: eol = mac_eol; break;
2977     }
2978 
2979     /*
2980      * Throw a simple header in.
2981      */
2982     if (appname)
2983       fprintf(out, ";%s; SBIT metrics file generated by \"%s\".%s;%s%s", eol,
2984               appname, eol, eol, eol);
2985 
2986     /*
2987      * Save PPEM.
2988      */
2989     fprintf(out, ";%s; Pixels Per Em.%s;%s", eol, eol, eol);
2990     fprintf(out, "PPEM %d%s%s", font->point_size, eol, eol);
2991 
2992     /*
2993      * If the font is character cell or monowidth, set this boolean.
2994      */
2995     if (font->spacing != BDF_PROPORTIONAL) {
2996         fprintf(out,
2997                 ";%s; Font is not proportional, so use mono advance.%s;%s",
2998                 eol, eol, eol);
2999         fprintf(out, "FORCECONSTANTMETRICS TRUE%s%s", eol, eol);
3000     } else {
3001         fprintf(out,
3002                 ";%s; Font is proportional, so do not use mono advance.%s;%s",
3003                 eol, eol, eol);
3004         fprintf(out, "FORCECONSTANTMETRICS FALSE%s%s", eol, eol);
3005     }
3006 
3007     /*
3008      * Do the horizontal line metrics only.
3009      */
3010     fprintf(out, ";%s; Horizontal line metrics.%s;%s", eol, eol, eol);
3011 
3012     fprintf(out, "H_ASCENDER %d%sH_DESCENDER %d%s", font->font_ascent, eol,
3013             font->font_descent, eol);
3014     fprintf(out, "H_WIDTHMAX %hd%s", font->bbx.width, eol);
3015     fprintf(out, "H_MINORIGINSB %hd%sH_MINADVANCEBL %hd%s",
3016             font->bbx.x_offset, eol,
3017             font->bbx.width + font->bbx.x_offset, eol);
3018     fprintf(out, "H_MAXBEFOREBL %hd%sH_MINAFTERBL %hd%s%s",
3019             font->bbx.ascent, eol, font->bbx.y_offset, eol, eol);
3020 
3021     /*
3022      * Write the default caret info.
3023      */
3024     fprintf(out, ";%s; Caret slope and offset info.%s;%s", eol, eol, eol);
3025     fprintf(out, "CARETSLOPENUMERATOR 1%sCARETSLOPEDENOMINATOR 0%s", eol, eol);
3026     fprintf(out, "CARETOFFSET 0%s%s", eol, eol);
3027 
3028     /*
3029      * Write the bitmap options.
3030      */
3031     fprintf(out, ";%s; Bitmap options.%s;%s", eol, eol, eol);
3032     fprintf(out, "DIRECTION H%sSTORAGE FAST%s%s", eol, eol, eol);
3033 
3034     /*
3035      * Scaled bitmaps not implemented yet.
3036      */
3037     fprintf(out, ";%s; Scaled bitmap info (Not Yet Implemented).%s;%s",
3038             eol, eol, eol);
3039 }
3040 
3041 /*
3042  * Special routine to dump the font in the Roman Czyborra's hex format.  It
3043  * only dumps the encoded glyphs and assumes the bitmaps have the correct
3044  * sizes.
3045  */
3046 void
bdf_export_hex(FILE * out,bdf_font_t * font,bdf_options_t * opts,bdf_callback_t callback,void * data)3047 bdf_export_hex(FILE *out, bdf_font_t *font, bdf_options_t *opts,
3048                bdf_callback_t callback, void *data)
3049 {
3050     int bpr, fbpr, j, k;
3051     unsigned int i, ng;
3052     bdf_glyph_t *gp, cell;
3053     bdf_callback_struct_t cb;
3054 
3055     if (font == 0 || out == 0)
3056       return;
3057 
3058     if (font->glyphs_used == 0)
3059       return;
3060 
3061     /*
3062      * Call the callback if it was passed to start the export.
3063      */
3064     if (callback != 0) {
3065         cb.reason = BDF_EXPORT_START;
3066         cb.total = font->glyphs_used;
3067         cb.current = 0;
3068         (*callback)(&cb, data);
3069     }
3070 
3071     fbpr = ((font->bbx.width * font->bpp) + 7) >> 3;
3072     bpr = (((font->bbx.width >> 1) * font->bpp) + 7) >> 3;
3073     cell.bytes = fbpr * font->bbx.height;
3074     cell.bitmap = (unsigned char *) malloc(cell.bytes);
3075 
3076     for (i = 0, ng = font->glyphs_used, gp = font->glyphs; i < ng; i++, gp++) {
3077         _bdf_pad_cell(font, gp, &cell);
3078         fprintf(out, "%04X:", gp->encoding & 0xffff);
3079         if (gp->bbx.width <= (font->bbx.width >> 1)) {
3080             for (j = 0; j < cell.bytes; j += fbpr) {
3081                 for (k = 0; k < bpr; k++)
3082                   fprintf(out, "%02X", cell.bitmap[j + k]);
3083             }
3084         } else {
3085             for (j = 0; j < cell.bytes; j++)
3086               fprintf(out, "%02X", cell.bitmap[j]);
3087         }
3088         if (cell.bytes > 0)
3089           putc('\n', out);
3090 
3091         /*
3092          * Call the callback if supplied.
3093          */
3094         if (callback != 0) {
3095             cb.reason = BDF_EXPORTING;
3096             cb.current++;
3097             (*callback)(&cb, data);
3098         }
3099     }
3100 
3101     /*
3102      * Clean up the cell.
3103      */
3104     free((char *) cell.bitmap);
3105 
3106     /*
3107      * Always call a final callback to make sure the client gets a chance to
3108      * clean things up.
3109      */
3110     if (callback != 0) {
3111         cb.reason = BDF_EXPORTING;
3112         cb.current = cb.total;
3113         (*callback)(&cb, data);
3114     }
3115 }
3116 
3117 void
bdf_free_font(bdf_font_t * font)3118 bdf_free_font(bdf_font_t *font)
3119 {
3120     unsigned int i;
3121     bdf_glyph_t *glyphs;
3122 
3123     if (font == 0)
3124         return;
3125 
3126     if (font->name != 0)
3127       free(font->name);
3128 
3129     /*
3130      * Free up the internal hash table of property names.
3131      */
3132     hash_free((hashtable *) font->internal);
3133     free((char *) font->internal);
3134 
3135     /*
3136      * Free up the comment info.
3137      */
3138     if (font->comments_len > 0)
3139       free(font->comments);
3140 
3141     /*
3142      * Free up the auto-correction messages.
3143      */
3144     if (font->acmsgs_len > 0)
3145       free(font->acmsgs);
3146 
3147     /*
3148      * Free up the properties.
3149      */
3150     for (i = 0; i < font->props_size; i++) {
3151         if (font->props[i].format == BDF_ATOM && font->props[i].value.atom)
3152           free(font->props[i].value.atom);
3153     }
3154 
3155     if (font->props_size > 0 && font->props != 0)
3156       free((char *) font->props);
3157 
3158     /*
3159      * Free up the character info.
3160      */
3161     for (i = 0, glyphs = font->glyphs; i < font->glyphs_used; i++, glyphs++) {
3162         if (glyphs->name)
3163           free(glyphs->name);
3164         if (glyphs->bytes > 0 && glyphs->bitmap != 0)
3165           free((char *) glyphs->bitmap);
3166     }
3167 
3168     for (i = 0, glyphs = font->unencoded; i < font->unencoded_used;
3169          i++, glyphs++) {
3170         if (glyphs->name)
3171           free(glyphs->name);
3172         if (glyphs->bytes > 0)
3173           free((char *) glyphs->bitmap);
3174         if (glyphs->unicode.map_size > 0)
3175           free((char *) glyphs->unicode.map);
3176     }
3177 
3178     if (font->glyphs_size > 0)
3179       free((char *) font->glyphs);
3180 
3181     if (font->unencoded_size > 0)
3182       free((char *) font->unencoded);
3183 
3184     /*
3185      * Free up the overflow storage if it was used.
3186      */
3187     for (i = 0, glyphs = font->overflow.glyphs; i < font->overflow.glyphs_used;
3188          i++, glyphs++) {
3189         if (glyphs->name != 0)
3190           free(glyphs->name);
3191         if (glyphs->bytes > 0)
3192           free((char *) glyphs->bitmap);;
3193         if (glyphs->unicode.map_size > 0)
3194           free((char *) glyphs->unicode.map);
3195     }
3196     if (font->overflow.glyphs_size > 0)
3197       free((char *) font->overflow.glyphs);
3198 
3199     free((char *) font);
3200 }
3201 
3202 void
bdf_create_property(char * name,int format)3203 bdf_create_property(char *name, int format)
3204 {
3205     unsigned int n;
3206     bdf_property_t *p;
3207 
3208     /*
3209      * First check to see if the property has
3210      * already been added or not.  If it has, then
3211      * simply ignore it.
3212      */
3213 
3214     if (hash_lookup(name, &proptbl))
3215       return;
3216 
3217     if (nuser_props == 0)
3218       user_props = (bdf_property_t *) malloc(sizeof(bdf_property_t));
3219     else
3220       user_props = (bdf_property_t *) realloc((char *) user_props,
3221                                               sizeof(bdf_property_t) *
3222                                               (nuser_props + 1));
3223 
3224     p = user_props + nuser_props;
3225     (void) memset((char *) p, 0, sizeof(bdf_property_t));
3226     n = (unsigned int) (strlen(name) + 1);
3227     p->name = (char *) malloc(n);
3228     (void) memcpy(p->name, name, n);
3229     p->format = format;
3230     p->builtin = 0;
3231 
3232     n = _num_bdf_properties + nuser_props;
3233     hash_insert(p->name, (void *) n, &proptbl);
3234 
3235     nuser_props++;
3236 }
3237 
3238 bdf_property_t *
bdf_get_property(char * name)3239 bdf_get_property(char *name)
3240 {
3241     hashnode hn;
3242     unsigned int propid;
3243 
3244     if (name == 0 || *name == 0)
3245       return 0;
3246 
3247     if ((hn = hash_lookup(name, &proptbl)) == 0)
3248       return 0;
3249 
3250     propid = (unsigned int) hn->data;
3251     if (propid >= _num_bdf_properties)
3252       return user_props + (propid - _num_bdf_properties);
3253     return _bdf_properties + propid;
3254 }
3255 
3256 /*
3257  * Routine to compare two property names.
3258  */
3259 static int
by_prop_name(const void * a,const void * b)3260 by_prop_name(const void *a, const void *b)
3261 {
3262     bdf_property_t *p1, *p2;
3263 
3264     p1 = (bdf_property_t *) a;
3265     p2 = (bdf_property_t *) b;
3266 
3267     return strcmp(p1->name, p2->name);
3268 }
3269 
3270 unsigned int
bdf_property_list(bdf_property_t ** props)3271 bdf_property_list(bdf_property_t **props)
3272 {
3273     unsigned int n;
3274     bdf_property_t *p;
3275 
3276     n = _num_bdf_properties + nuser_props;
3277     if (props != 0 && n != 0) {
3278         p = (bdf_property_t *) malloc(sizeof(bdf_property_t) * n);
3279         (void) memcpy((char *) p, (char *) _bdf_properties,
3280                       sizeof(bdf_property_t) * _num_bdf_properties);
3281         (void) memcpy((char *) (p + _num_bdf_properties), (char *) user_props,
3282                       sizeof(bdf_property_t) * nuser_props);
3283         qsort((char *) p, n, sizeof(bdf_property_t), by_prop_name);
3284         *props = p;
3285     }
3286     return n;
3287 }
3288 
3289 int
bdf_replace_comments(bdf_font_t * font,char * comments,unsigned int comments_len)3290 bdf_replace_comments(bdf_font_t *font, char *comments,
3291                      unsigned int comments_len)
3292 {
3293     if (font == 0 || comments_len == 0)
3294       return 0;
3295 
3296     if (font->comments_len > 0)
3297       free(font->comments);
3298 
3299     font->comments = (char *) malloc(comments_len + 1);
3300     (void) memcpy(font->comments, comments, comments_len);
3301     font->comments[comments_len] = 0;
3302     font->comments_len = comments_len;
3303     font->modified = 1;
3304     return 1;
3305 }
3306 
3307 unsigned int
bdf_font_property_list(bdf_font_t * font,bdf_property_t ** props)3308 bdf_font_property_list(bdf_font_t *font, bdf_property_t **props)
3309 {
3310     bdf_property_t *p;
3311 
3312     if (font == 0 || font->props_used == 0)
3313       return 0;
3314 
3315     if (props != 0) {
3316         p = (bdf_property_t *) malloc(sizeof(bdf_property_t) *
3317                                       font->props_used);
3318         (void) memcpy((char *) p, (char *) font->props,
3319                       sizeof(bdf_property_t) * font->props_used);
3320         qsort((char *) p, font->props_used, sizeof(bdf_property_t),
3321               by_prop_name);
3322         *props = p;
3323     }
3324 
3325     return font->props_used;
3326 }
3327 
3328 void
bdf_add_font_property(bdf_font_t * font,bdf_property_t * property)3329 bdf_add_font_property(bdf_font_t *font, bdf_property_t *property)
3330 {
3331     int len;
3332     unsigned int propid;
3333     hashnode hn;
3334     bdf_property_t *p, *ip;
3335 
3336     if (property == 0 || property->name == 0 || property->name[0] == 0)
3337       return;
3338 
3339     /*
3340      * If the font does not have a property hash table yet, make
3341      * sure it is allocated.
3342      */
3343     if (font->internal == 0) {
3344         font->internal = (void *) malloc(sizeof(hashtable));
3345         hash_init((hashtable *) font->internal);
3346     }
3347 
3348     /*
3349      * See if the property is in the general property table yet.
3350      * If it isn't, then add it.
3351      */
3352     if ((hn = hash_lookup(property->name, &proptbl)) == 0)
3353       bdf_create_property(property->name, property->format);
3354     else {
3355         /*
3356          * If the property exists and is a user defined property, make sure
3357          * its format is updated to match the property being added.
3358          */
3359         propid = (unsigned int) hn->data;
3360         if (propid >= _num_bdf_properties) {
3361             p = user_props + (propid - _num_bdf_properties);
3362             if (p->format != property->format)
3363               p->format = property->format;
3364         }
3365     }
3366 
3367     /*
3368      * If the font already has this property, then change the existing one.
3369      */
3370     hn = hash_lookup(property->name, (hashtable *) font->internal);
3371     if (hn != 0) {
3372         /*
3373          * Changing an existing property value.
3374          */
3375         p = font->props + ((unsigned int) hn->data);
3376 
3377         /*
3378          * If the format changed, then free the atom value if the original
3379          * format was an atom.
3380          */
3381         if (p->format == BDF_ATOM && property->format != BDF_ATOM &&
3382             p->value.atom != 0)
3383           free((char *) p->value.atom);
3384         p->format = property->format;
3385 
3386         switch (p->format) {
3387           case BDF_ATOM:
3388             /*
3389              * If the property value is the same, then just return.
3390              */
3391             if (property->value.atom == p->value.atom ||
3392                 (property->value.atom && p->value.atom &&
3393                  strcmp(property->value.atom, p->value.atom) == 0))
3394               return;
3395             if (property->value.atom == 0)
3396               len = 1;
3397             else
3398               len = strlen(property->value.atom) + 1;
3399             if (len > 1) {
3400                 p->value.atom = (char *) malloc(len);
3401                 (void) memcpy(p->value.atom, property->value.atom, len);
3402             } else
3403               p->value.atom = 0;
3404             break;
3405           case BDF_INTEGER:
3406             /*
3407              * If the property value is the same, then just return.
3408              */
3409             if (p->value.int32 == property->value.int32)
3410               return;
3411             p->value.int32 = property->value.int32;
3412             break;
3413           case BDF_CARDINAL:
3414             /*
3415              * If the property value is the same, then just return.
3416              */
3417             if (p->value.card32 == property->value.card32)
3418               return;
3419             p->value.card32 = property->value.card32;
3420             break;
3421         }
3422     } else {
3423         /*
3424          * New property being added.
3425          */
3426 
3427         /*
3428          * Get the internal table entry for a pointer to the
3429          * name of the property.
3430          */
3431         hn = hash_lookup(property->name, &proptbl);
3432         propid = (unsigned int) hn->data;
3433         if (propid >= _num_bdf_properties)
3434           ip = user_props + (propid - _num_bdf_properties);
3435         else
3436           ip = _bdf_properties + propid;
3437 
3438         /*
3439          * Add it to the property list first.
3440          */
3441         if (font->props_used == font->props_size) {
3442             if (font->props_size == 0)
3443               font->props = (bdf_property_t *) malloc(sizeof(bdf_property_t));
3444             else
3445               font->props = (bdf_property_t *)
3446                 realloc((char *) font->props, sizeof(bdf_property_t) *
3447                         (font->props_size + 1));
3448             font->props_size++;
3449         }
3450         p = font->props + font->props_used;
3451 
3452         p->name = ip->name;
3453         p->format = ip->format;
3454         p->builtin = ip->builtin;
3455 
3456         switch (p->format) {
3457           case BDF_ATOM:
3458             if (property->value.atom == 0)
3459               len = 1;
3460             else
3461               len = strlen(property->value.atom) + 1;
3462             if (len > 1) {
3463                 p->value.atom = (char *) malloc(len);
3464                 (void) memcpy(p->value.atom, property->value.atom, len);
3465             } else
3466               p->value.atom = 0;
3467             break;
3468           case BDF_INTEGER:
3469             p->value.int32 = property->value.int32;
3470             break;
3471           case BDF_CARDINAL:
3472             p->value.card32 = property->value.card32;
3473             break;
3474         }
3475 
3476         /*
3477          * Now insert it into the internal hash table.
3478          */
3479         hash_insert(p->name, (void *) font->props_used,
3480                     (hashtable *) font->internal);
3481         font->props_used++;
3482     }
3483 
3484     if (memcmp(property->name, "DEFAULT_CHAR", 12) == 0)
3485       /*
3486        * If the property just added is DEFAULT_CHAR, then make sure the
3487        * default_glyph field is set.
3488        */
3489       font->default_glyph = p->value.card32;
3490     else if (memcmp(property->name, "FONT_ASCENT", 11) == 0)
3491       /*
3492        * If the property just added is FONT_ASCENT, then adjust the
3493        * font_ascent field.
3494        */
3495       font->font_ascent = p->value.int32;
3496     else if (memcmp(property->name, "FONT_DESCENT", 12) == 0)
3497       /*
3498        * If the property just added is FONT_DESCENT, then adjust the
3499        * font_descent field.
3500        */
3501       font->font_descent = p->value.int32;
3502     else if (memcmp(property->name, "RESOLUTION_X", 12) == 0)
3503       /*
3504        * If the property just added is RESOLUTION_X, then adjust the
3505        * resolution_x field.
3506        */
3507       font->resolution_x = p->value.card32;
3508     else if (memcmp(property->name, "RESOLUTION_Y", 12) == 0)
3509       /*
3510        * If the property just added is RESOLUTION_Y, then adjust the
3511        * resolution_y field.
3512        */
3513       font->resolution_y = p->value.card32;
3514     else if (memcmp(property->name, "POINT_SIZE", 10) == 0)
3515       /*
3516        * If the property just added is POINT_SIZE, then adjust the
3517        * point_size field.
3518        */
3519       font->point_size = p->value.int32 / 10;
3520     else if (memcmp(property->name, "SPACING", 7) == 0) {
3521         /*
3522          * Make sure the font spacing is kept in synch if the property
3523          * changes.  If the spacing changes from proportional to one
3524          * of the others, force the monowidth to be set.
3525          */
3526         switch (p->value.atom[0]) {
3527           case 'C': case 'c':
3528             if (font->spacing == BDF_PROPORTIONAL)
3529               font->monowidth = font->bbx.width + font->bbx.x_offset;
3530             font->spacing = BDF_CHARCELL;
3531             break;
3532           case 'M': case 'm':
3533             if (font->spacing == BDF_PROPORTIONAL)
3534               font->monowidth = font->bbx.width + font->bbx.x_offset;
3535             font->spacing = BDF_MONOWIDTH;
3536             break;
3537           case 'P': case 'p': font->spacing = BDF_PROPORTIONAL; break;
3538         }
3539     }
3540 
3541     /*
3542      * Make sure the font is marked as modified.
3543      */
3544     font->modified = 1;
3545 }
3546 
3547 void
bdf_delete_font_property(bdf_font_t * font,char * name)3548 bdf_delete_font_property(bdf_font_t *font, char *name)
3549 {
3550     hashnode hn;
3551     unsigned int off;
3552     bdf_property_t *p;
3553 
3554     if (font == 0 || name == 0 || *name == 0 || font->props_used == 0)
3555       return;
3556 
3557     if ((hn = hash_lookup(name, (hashtable *) font->internal)) == 0)
3558       return;
3559 
3560     off = (unsigned int) hn->data;
3561     p = font->props + off;
3562 
3563     /*
3564      * Delete the ATOM value if appropriate.
3565      */
3566     if (p->format == BDF_ATOM && p->value.atom != 0)
3567       free(p->value.atom);
3568 
3569     /*
3570      * The property exists.  Two things needs to be done:
3571      * 1. Remove the property from the hash table.
3572      * 2. Remove the property from the font's list of properties.
3573      */
3574     hash_delete(name, (hashtable *) font->internal);
3575 
3576     /*
3577      * Locate its offset in the font property list.
3578      */
3579     if (off < font->props_used - 1)
3580       /*
3581        * We have to shift the property list down.
3582        */
3583       _bdf_memmove((char *) p, (char *) (p + 1),
3584                    sizeof(bdf_property_t) * ((font->props_used - 1) - off));
3585     font->props_used--;
3586 
3587     /*
3588      * If the font property happens to be DEFAULT_CHAR, then make sure the
3589      * default_glyph field is reset.
3590      */
3591     if (strncmp(name, "DEFAULT_CHAR", 12) == 0)
3592       font->default_glyph = -1;
3593 
3594     /*
3595      * Update the hash table with the correct indexes.
3596      */
3597     for (off = 0, p = font->props; off < font->props_used; off++, p++)
3598       hash_insert(p->name, (void *) off, (hashtable *) font->internal);
3599 
3600     /*
3601      * Mark the font as being modified.
3602      */
3603     font->modified = 1;
3604 }
3605 
3606 bdf_property_t *
bdf_get_font_property(bdf_font_t * font,char * name)3607 bdf_get_font_property(bdf_font_t *font, char *name)
3608 {
3609     hashnode hn;
3610 
3611     if (font == 0 || font->props_size == 0 || name == 0 || *name == 0)
3612       return 0;
3613 
3614     hn = hash_lookup(name, (hashtable *) font->internal);
3615     return (hn) ? (font->props + ((unsigned int) hn->data)) : 0;
3616 }
3617 
3618 typedef struct {
3619     bdf_options_t *opts;
3620     bdf_options_callback_t callback;
3621     void *client_data;
3622     _bdf_list_t list;
3623 } _bdf_opts_parse_t;
3624 
3625 static int
_bdf_get_boolean(char * val)3626 _bdf_get_boolean(char *val)
3627 {
3628     int ok;
3629 
3630     ok = 0;
3631     if (val == 0 || *val == 0)
3632       return ok;
3633 
3634     switch (val[0]) {
3635       case '0': case 'F': case 'f': case 'N': case 'n': ok = 0; break;
3636       case '1': case 'T': case 't': case 'Y': case 'y': ok = 1; break;
3637     }
3638     return ok;
3639 }
3640 
3641 static int
_bdf_parse_options(char * line,unsigned int linelen,unsigned int lineno,void * call_data,void * client_data)3642 _bdf_parse_options(char *line, unsigned int linelen, unsigned int lineno,
3643                    void *call_data, void *client_data)
3644 {
3645     _bdf_list_t *lp;
3646     _bdf_opts_parse_t *p;
3647     int bpp;
3648 
3649     p = (_bdf_opts_parse_t *) client_data;
3650     lp = &p->list;
3651 
3652     /*
3653      * Split the line into fields.
3654      */
3655     _bdf_split(" \t+", line, linelen, lp);
3656 
3657     if (lp->field[0][0] == 'b' &&
3658         memcmp(lp->field[0], "bits_per_pixel", 14) == 0) {
3659         if (lp->used < 2) {
3660             fprintf(stderr,
3661                     "bdf: warning: %d: incorrect number of fields %d.\n",
3662                     lineno, lp->used);
3663             fprintf(stderr,
3664                     "bdf: warning: %d: bits_per_pixel <1, 2, or 4>.\n",
3665                     lineno);
3666         } else {
3667             bpp = _bdf_atol(lp->field[1], 0, 10);
3668             if (!(bpp == 1 || bpp == 2 || bpp == 4)) {
3669                 fprintf(stderr,
3670                         "bdf: warning: %d: invalid bits per pixel %d.\n",
3671                         lineno, bpp);
3672                 fprintf(stderr,
3673                         "bdf: warning: %d: bits_per_pixel <1, 2, or 4>.\n",
3674                         lineno);
3675             } else
3676               p->opts->bits_per_pixel = bpp;
3677         }
3678         return 0;
3679     }
3680 
3681     if (lp->field[0][0] == 'e' && memcmp(lp->field[0], "eol", 3) == 0) {
3682         if (lp->used < 2) {
3683             fprintf(stderr,
3684                     "bdf: warning: %d: incorrect number of fields %d.\n",
3685                     lineno, lp->used);
3686             fprintf(stderr,
3687                     "bdf: warning: %d: eol <eolname>.\n", lineno);
3688         } else {
3689             switch (lp->field[1][0]) {
3690               case 'u': case 'U': p->opts->eol = BDF_UNIX_EOL; break;
3691               case 'd': case 'D': p->opts->eol = BDF_DOS_EOL; break;
3692               case 'm': case 'M': p->opts->eol = BDF_MAC_EOL; break;
3693             }
3694         }
3695         return 0;
3696     }
3697 
3698     if (lp->field[0][0] == 'c' &&
3699         memcmp(lp->field[0], "correct_metrics", 15) == 0) {
3700         if (lp->used < 2) {
3701             fprintf(stderr,
3702                     "bdf: warning: %d: incorrect number of fields %d.\n",
3703                     lineno, lp->used);
3704             fprintf(stderr,
3705                     "bdf: warning: %d: correct_metrics <boolean>.\n", lineno);
3706         } else
3707           p->opts->correct_metrics = _bdf_get_boolean(lp->field[1]);
3708 
3709         return 0;
3710     }
3711 
3712     if (lp->field[0][0] == 'k' &&
3713         memcmp(lp->field[0], "keep_unencoded", 14) == 0) {
3714         if (lp->used < 2) {
3715             fprintf(stderr,
3716                     "bdf: warning: %d: incorrect number of fields %d.\n",
3717                     lineno, lp->used);
3718             fprintf(stderr,
3719                     "bdf: warning: %d: keep_unencoded <boolean>.\n", lineno);
3720         } else
3721           p->opts->keep_unencoded = _bdf_get_boolean(lp->field[1]);
3722 
3723         return 0;
3724     }
3725 
3726     if (lp->field[0][0] == 'k' &&
3727         memcmp(lp->field[0], "keep_comments", 13) == 0) {
3728         if (lp->used < 2) {
3729             fprintf(stderr,
3730                     "bdf: warning: %d: incorrect number of fields %d.\n",
3731                     lineno, lp->used);
3732             fprintf(stderr,
3733                     "bdf: warning: %d: keep_comments <boolean>.\n", lineno);
3734         } else
3735           p->opts->keep_comments = _bdf_get_boolean(lp->field[1]);
3736 
3737         return 0;
3738     }
3739 
3740     if (lp->field[0][0] == 'p' &&
3741         memcmp(lp->field[0], "pad_character_cells", 19) == 0) {
3742         if (lp->used < 2) {
3743             fprintf(stderr,
3744                     "bdf: warning: %d: incorrect number of fields %d.\n",
3745                     lineno, lp->used);
3746             fprintf(stderr,
3747                     "bdf: warning: %d: pad_character_cells <boolean>.\n",
3748                     lineno);
3749         } else
3750           p->opts->pad_cells = _bdf_get_boolean(lp->field[1]);
3751 
3752         return 0;
3753     }
3754 
3755     if (lp->field[0][0] == 'p' &&
3756         memcmp(lp->field[0], "point_size", 10) == 0) {
3757         if (lp->used < 2) {
3758             fprintf(stderr,
3759                     "bdf: warning: %d: incorrect number of fields %d.\n",
3760                     lineno, lp->used);
3761             fprintf(stderr,
3762                     "bdf: warning: %d: point_size <integer>.\n", lineno);
3763         } else
3764           p->opts->point_size = _bdf_atol(lp->field[1], 0, 10);
3765         return 0;
3766     }
3767 
3768     if (lp->field[0][0] == 'h' &&
3769         memcmp(lp->field[0], "horizontal_resolution", 21) == 0) {
3770         if (lp->used < 2) {
3771             fprintf(stderr,
3772                     "bdf: warning: %d: incorrect number of fields %d.\n",
3773                     lineno, lp->used);
3774             fprintf(stderr,
3775                     "bdf: warning: %d: horizontal_resolution <cardinal>.\n",
3776                     lineno);
3777         } else
3778           p->opts->resolution_x = _bdf_atoul(lp->field[1], 0, 10);
3779         return 0;
3780     }
3781 
3782     if (lp->field[0][0] == 'v' &&
3783         memcmp(lp->field[0], "vertical_resolution", 19) == 0) {
3784         if (lp->used < 2) {
3785             fprintf(stderr,
3786                     "bdf: warning: %d: incorrect number of fields %d.\n",
3787                     lineno, lp->used);
3788             fprintf(stderr,
3789                     "bdf: warning: %d: vertical_resolution <cardinal>.\n",
3790                     lineno);
3791         } else
3792           p->opts->resolution_y = _bdf_atoul(lp->field[1], 0, 10);
3793         return 0;
3794     }
3795 
3796     if (lp->field[0][0] == 'f' &&
3797         memcmp(lp->field[0], "font_spacing", 12) == 0) {
3798         if (lp->used < 2) {
3799             fprintf(stderr,
3800                     "bdf: warning: %d: incorrect number of fields %d.\n",
3801                     lineno, lp->used);
3802             fprintf(stderr,
3803                     "bdf: warning: %d: font_spacing <spacing name>.\n",
3804                     lineno);
3805         } else {
3806             switch (lp->field[1][0]) {
3807               case 'P': case 'p':
3808                 p->opts->font_spacing = BDF_PROPORTIONAL;
3809                 break;
3810               case 'M': case 'm':
3811                 p->opts->font_spacing = BDF_MONOWIDTH;
3812                 break;
3813               case 'C': case 'c':
3814                 p->opts->font_spacing = BDF_CHARCELL;
3815                 break;
3816               default:
3817                 fprintf(stderr,
3818                         "bdf: warning: %d: unknown font spacing '%s'.\n",
3819                         lineno, lp->field[1]);
3820             }
3821         }
3822         return 0;
3823     }
3824 
3825     if (lp->field[0][0] == 'p' &&
3826         memcmp(lp->field[0], "property", 8) == 0) {
3827         if (lp->used < 3) {
3828             fprintf(stderr,
3829                     "bdf: warning: %d: incorrect number of fields %d.\n",
3830                     lineno, lp->used);
3831             fprintf(stderr,
3832                     "bdf: warning: %d: property <name> <type>.\n",
3833                     lineno);
3834         } else {
3835             switch (lp->field[2][0]) {
3836               case 'A': case 'a':
3837                 bdf_create_property(lp->field[1], BDF_ATOM);
3838                 break;
3839               case 'C': case 'c':
3840                 bdf_create_property(lp->field[1], BDF_CARDINAL);
3841                 break;
3842               case 'I': case 'i':
3843                 bdf_create_property(lp->field[1], BDF_INTEGER);
3844                 break;
3845               default:
3846                 fprintf(stderr,
3847                         "bdf: warning: %d: unknown property type '%s'.\n",
3848                         lineno, lp->field[2]);
3849             }
3850         }
3851         return 0;
3852     }
3853 
3854     if (lp->field[0][0] == 'h' &&
3855         (memcmp(lp->field[0], "hint_truetype_glyphs", 20) == 0 ||
3856          memcmp(lp->field[0], "hint_opentype_glyphs", 20) == 0)) {
3857         if (lp->used < 2) {
3858             fprintf(stderr,
3859                     "bdf: warning: %d: incorrect number of fields %d.\n",
3860                     lineno, lp->used);
3861             fprintf(stderr,
3862                     "bdf: warning: %d: hint_opentype_glyphs <boolean>.\n",
3863                     lineno);
3864         } else {
3865 #ifdef HAVE_FREETYPE
3866             if (_bdf_get_boolean(lp->field[1]))
3867               p->opts->otf_flags &= ~FT_LOAD_NO_HINTING;
3868             else
3869               p->opts->otf_flags |= FT_LOAD_NO_HINTING;
3870 #else
3871             p->opts->otf_flags = 0;
3872 #endif /* HAVE_FREETYPE */
3873         }
3874 
3875         return 0;
3876     }
3877 
3878     if (lp->field[0][0] == 'g' &&
3879         memcmp(lp->field[0], "generate_ranges", 15) == 0)
3880       /*
3881        * Simply ignore the glyph ranges entry in the config file.
3882        */
3883       return 0;
3884 
3885     /*
3886      * If the callback returns a non-zero value, the caller has handled the
3887      * unknown option found in the file.
3888      */
3889     if (p->callback != 0 &&
3890         (*p->callback)(p->opts, lp->field, lp->used, p->client_data) != 0)
3891       return 0;
3892 
3893     fprintf(stderr, "bdf: warning: %d: unknown configuration option '%s'.\n",
3894             lineno, lp->field[0]);
3895     return 0;
3896 }
3897 
3898 void
bdf_load_options(FILE * in,bdf_options_t * opts,bdf_options_callback_t callback,void * client_data)3899 bdf_load_options(FILE *in, bdf_options_t *opts,
3900                  bdf_options_callback_t callback, void *client_data)
3901 {
3902     unsigned int lineno;
3903     _bdf_opts_parse_t p;
3904 
3905     /*
3906      * Don't bother loading the options if the file or options structure
3907      * is NULL.
3908      */
3909     if (in == 0 || opts == 0)
3910       return;
3911 
3912     (void *) memset((char *) &p, 0, sizeof(_bdf_opts_parse_t));
3913     p.opts = opts;
3914     p.callback = callback;
3915     p.client_data = client_data;
3916     (void) _bdf_readlines(fileno(in), _bdf_parse_options, (void *) &p,
3917                           &lineno);
3918 
3919     /*
3920      * Free up the list if there is any space allocated.
3921      */
3922     if (p.list.size > 0)
3923       free((char *) p.list.field);
3924 }
3925 
3926 void
bdf_save_options(FILE * out,bdf_options_t * opts)3927 bdf_save_options(FILE *out, bdf_options_t *opts)
3928 {
3929     unsigned int i;
3930 
3931     if (out == 0 || opts == 0)
3932       return;
3933 
3934     fprintf(out, "#\n# Metrics corrections.\n#\ncorrect_metrics ");
3935     if (opts->correct_metrics)
3936       fprintf(out, "true\n\n");
3937     else
3938       fprintf(out, "false\n\n");
3939 
3940     fprintf(out, "#\n# Preserve unencoded glyphs.\n#\nkeep_unencoded ");
3941     if (opts->keep_unencoded)
3942       fprintf(out, "true\n\n");
3943     else
3944       fprintf(out, "false\n\n");
3945 
3946     fprintf(out, "#\n# Preserve comments.\n#\nkeep_comments ");
3947     if (opts->keep_comments)
3948       fprintf(out, "true\n\n");
3949     else
3950       fprintf(out, "false\n\n");
3951 
3952     fprintf(out, "#\n# Pad character cells.\n#\npad_character_cells ");
3953     if (opts->pad_cells)
3954       fprintf(out, "true\n\n");
3955     else
3956       fprintf(out, "false\n\n");
3957 
3958     fprintf(out, "#\n# Font spacing.\n#\nfont_spacing ");
3959     switch (opts->font_spacing) {
3960       case BDF_PROPORTIONAL: fprintf(out, "proportional\n\n"); break;
3961       case BDF_MONOWIDTH: fprintf(out, "monowidth\n\n"); break;
3962       case BDF_CHARCELL: fprintf(out, "charactercell\n\n"); break;
3963     }
3964 
3965     fprintf(out, "#\n# Point size.\n#\npoint_size %d\n\n", opts->point_size);
3966 
3967     fprintf(out,
3968             "#\n# Horizontal resolution.\n#\nhorizontal_resolution %d\n\n",
3969             opts->resolution_x);
3970 
3971     fprintf(out,
3972             "#\n# Vertical resolution.\n#\nvertical_resolution %d\n\n",
3973             opts->resolution_x);
3974 
3975     fprintf(out,
3976             "#\n# Bits per pixel.\n#\nbits_per_pixel %d\n\n",
3977             opts->bits_per_pixel);
3978 
3979     fprintf(out, "#\n# Hint OpenType glyphs.\n#\nhint_opentype_glyphs ");
3980 #ifdef HAVE_FREETYPE
3981     if (opts->otf_flags & FT_LOAD_NO_HINTING)
3982       fprintf(out, "false\n\n");
3983     else
3984       fprintf(out, "true\n\n");
3985 #else
3986     fprintf(out, "false\n\n");
3987 #endif /* HAVE_FREETYPE */
3988 
3989     fprintf(out, "#\n# Set the EOL used when writing BDF fonts.\n#\neol ");
3990     switch (opts->eol) {
3991       case BDF_UNIX_EOL: fprintf(out, "unix\n\n"); break;
3992       case BDF_DOS_EOL: fprintf(out, "dos\n\n"); break;
3993       case BDF_MAC_EOL: fprintf(out, "mac\n\n"); break;
3994     }
3995 
3996     /*
3997      * Write out the user defined properties if they exist.
3998      */
3999     if (nuser_props == 0)
4000       return;
4001 
4002     fprintf(out, "#\n# User defined properties.\n#\n");
4003 
4004     for (i = 0; i < nuser_props; i++) {
4005         fprintf(out, "property %s ", user_props[i].name);
4006         switch (user_props[i].format) {
4007           case BDF_ATOM: fprintf(out, "atom\n"); break;
4008           case BDF_CARDINAL: fprintf(out, "cardinal\n"); break;
4009           case BDF_INTEGER: fprintf(out, "integer\n"); break;
4010         }
4011     }
4012 }
4013 
4014 void
bdf_default_options(bdf_options_t * opts)4015 bdf_default_options(bdf_options_t *opts)
4016 {
4017     if (opts == 0)
4018       return;
4019 
4020     (void) memcpy((char *) opts, (char *) &_bdf_opts, sizeof(bdf_options_t));
4021 }
4022 
4023 bdf_font_t *
bdf_new_font(char * name,int point_size,int resolution_x,int resolution_y,int spacing,int bpp)4024 bdf_new_font(char *name, int point_size, int resolution_x, int resolution_y,
4025              int spacing, int bpp)
4026 {
4027     int psize;
4028     char sp[2];
4029     bdf_font_t *font;
4030     double dp, dr;
4031     bdf_property_t prop;
4032 
4033     font = (bdf_font_t *) calloc(1, sizeof(bdf_font_t));
4034     if (name != 0 && *name != 0) {
4035         font->name = (char *) malloc(strlen(name) + 1);
4036         (void) strcpy(font->name, name);
4037     }
4038 
4039     font->bpp = bpp;
4040     font->point_size = point_size;
4041     font->resolution_x = resolution_x;
4042     font->resolution_y = resolution_y;
4043 
4044     /*
4045      * Determine the pixel size of the new font based on the
4046      * point size and resolution.
4047      */
4048     dr = (double) resolution_y;
4049     dp = (double) (point_size * 10);
4050     psize = (int) (((dp * dr) / 722.7) + 0.5);
4051 
4052     /*
4053      * Make the default width about 1.5 smaller than the height.
4054      */
4055     font->bbx.height = psize;
4056     font->bbx.width = ((double) psize) / 1.5;
4057 
4058     /*
4059      * Now determine the default ascent and descent assuming a
4060      * the descent is about 1/4 the ascent.
4061      */
4062     font->bbx.descent = psize >> 2;
4063     font->bbx.ascent = psize - font->bbx.descent;
4064 
4065     font->bbx.y_offset = -font->bbx.descent;
4066 
4067     /*
4068      * Allocation the internal hash tables.
4069      */
4070     font->internal = (void *) malloc(sizeof(hashtable));
4071     hash_init((hashtable *) font->internal);
4072 
4073     font->default_glyph = -1;
4074     font->spacing = spacing;
4075 
4076     /*
4077      * Add various useful properties.
4078      */
4079     prop.name = "POINT_SIZE";
4080     prop.format = BDF_INTEGER;
4081     prop.value.int32 = font->point_size * 10;
4082     bdf_add_font_property(font, &prop);
4083 
4084     prop.name = "PIXEL_SIZE";
4085     prop.format = BDF_INTEGER;
4086     prop.value.int32 = psize;
4087     bdf_add_font_property(font, &prop);
4088 
4089     prop.name = "RESOLUTION_X";
4090     prop.format = BDF_CARDINAL;
4091     prop.value.card32 = (unsigned int) font->resolution_x;
4092     bdf_add_font_property(font, &prop);
4093 
4094     prop.name = "RESOLUTION_Y";
4095     prop.format = BDF_CARDINAL;
4096     prop.value.card32 = (unsigned int) font->resolution_y;
4097     bdf_add_font_property(font, &prop);
4098 
4099     prop.name = "FONT_ASCENT";
4100     prop.format = BDF_INTEGER;
4101     prop.value.int32 = (int) font->bbx.ascent;
4102     bdf_add_font_property(font, &prop);
4103 
4104     prop.name = "FONT_DESCENT";
4105     prop.format = BDF_INTEGER;
4106     prop.value.int32 = (int) font->bbx.descent;
4107     bdf_add_font_property(font, &prop);
4108 
4109     prop.name = "AVERAGE_WIDTH";
4110     prop.format = BDF_INTEGER;
4111     prop.value.int32 = font->bbx.width * 10;
4112     bdf_add_font_property(font, &prop);
4113 
4114     sp[0] = 'P';
4115     sp[1] = 0;
4116     switch (spacing) {
4117       case BDF_PROPORTIONAL: sp[0] = 'P'; break;
4118       case BDF_MONOWIDTH: sp[0] = 'M'; break;
4119       case BDF_CHARCELL: sp[0] = 'C'; break;
4120     }
4121     prop.name = "SPACING";
4122     prop.format = BDF_ATOM;
4123     prop.value.atom = sp;
4124     bdf_add_font_property(font, &prop);
4125 
4126     /*
4127      * Mark the font as unmodified.
4128      */
4129     font->modified = 0;
4130 
4131     return font;
4132 }
4133 
4134 void
bdf_set_default_metrics(bdf_font_t * font)4135 bdf_set_default_metrics(bdf_font_t *font)
4136 {
4137     int psize;
4138     double dp, dr;
4139     bdf_property_t prop;
4140 
4141     /*
4142      * Determine the pixel size of the new font based on the
4143      * point size and resolution.
4144      */
4145     dr = (double) font->resolution_y;
4146     dp = (double) (font->point_size * 10);
4147     psize = (int) (((dp * dr) / 722.7) + 0.5);
4148 
4149     /*
4150      * Make the default width about 1.5 smaller than the height.
4151      */
4152     font->bbx.height = psize;
4153     font->bbx.width = ((double) psize) / 1.5;
4154 
4155     /*
4156      * Now determine the default ascent and descent assuming a
4157      * the descent is about 1/4 the ascent.
4158      */
4159     font->bbx.descent = psize >> 2;
4160     font->bbx.ascent = psize - font->bbx.descent;
4161 
4162     font->bbx.y_offset = -font->bbx.descent;
4163 
4164     font->default_glyph = -1;
4165 
4166     /*
4167      * Add various useful properties.
4168      */
4169     prop.name = "FONT_ASCENT";
4170     prop.format = BDF_INTEGER;
4171     prop.value.int32 = (int) font->bbx.ascent;
4172     bdf_add_font_property(font, &prop);
4173 
4174     prop.name = "FONT_DESCENT";
4175     prop.format = BDF_INTEGER;
4176     prop.value.int32 = (int) font->bbx.descent;
4177     bdf_add_font_property(font, &prop);
4178 
4179     prop.name = "AVERAGE_WIDTH";
4180     prop.format = BDF_INTEGER;
4181     prop.value.int32 = font->bbx.width * 10;
4182     bdf_add_font_property(font, &prop);
4183 }
4184 
4185 int
bdf_glyph_modified(bdf_font_t * font,int which,int unencoded)4186 bdf_glyph_modified(bdf_font_t *font, int which, int unencoded)
4187 {
4188     if (font == 0 || which < 0)
4189       return 0;
4190 
4191     if (unencoded)
4192       return _bdf_glyph_modified(font->umod, which);
4193     else
4194       return _bdf_glyph_modified(font->nmod, which);
4195 }
4196 
4197 void
bdf_copy_glyphs(bdf_font_t * font,int start,int end,bdf_glyphlist_t * glyphs,int unencoded)4198 bdf_copy_glyphs(bdf_font_t *font, int start, int end,
4199                 bdf_glyphlist_t *glyphs, int unencoded)
4200 {
4201     int tmp, i, nc;
4202     bdf_glyph_t *cp, *dp;
4203     short maxas, maxds, maxrb, minlb, maxlb, rb;
4204 
4205     if (start > end) {
4206         tmp = end;
4207         end = start;
4208         start = tmp;
4209     }
4210 
4211     glyphs->bpp = font->bpp;
4212     glyphs->start = start;
4213     glyphs->end = end;
4214     glyphs->glyphs_used = 0;
4215 
4216     tmp = (end - start) + 1;
4217     if (tmp > glyphs->glyphs_size) {
4218         if (glyphs->glyphs_size == 0)
4219           glyphs->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * tmp);
4220         else
4221           glyphs->glyphs = (bdf_glyph_t *) realloc((char *) glyphs->glyphs,
4222                                                    sizeof(bdf_glyph_t) * tmp);
4223         cp = glyphs->glyphs + glyphs->glyphs_size;
4224         (void) memset((char *) cp, 0,
4225                       sizeof(bdf_glyph_t) * (tmp - glyphs->glyphs_size));
4226         glyphs->glyphs_size = tmp;
4227     }
4228 
4229     /*
4230      * Clear out bitmaps, names and any PSF Unicode mappings in the existing
4231      * entries.
4232      */
4233     for (cp = glyphs->glyphs, i = 0; i < glyphs->glyphs_size; i++, cp++) {
4234         if (cp->name != 0)
4235           free(cp->name);
4236         if (cp->bytes > 0)
4237           free((char *) cp->bitmap);
4238         if (cp->unicode.map_size > 0)
4239           free((char *) cp->unicode.map);
4240     }
4241 
4242     /*
4243      * Zero out everything.
4244      */
4245     (void) memset((char *) &glyphs->bbx, 0, sizeof(bdf_bbx_t));
4246     (void) memset((char *) glyphs->glyphs, 0,
4247                   sizeof(bdf_glyph_t) * glyphs->glyphs_size);
4248 
4249     /*
4250      * Initialize the bounds used to generate the overall bounding box for the
4251      * set of glyphs being copied.
4252      */
4253     minlb = font->bbx.width;
4254     maxlb = maxrb = maxas = maxds = 0;
4255 
4256     /*
4257      * Do the copy.
4258      */
4259     nc = (unencoded == 0) ? font->glyphs_used : font->unencoded_used;
4260     cp = (unencoded == 0) ? font->glyphs : font->unencoded;
4261     dp = glyphs->glyphs;
4262 
4263     for (i = 0;
4264          i < nc && ((unencoded && i <= end) || cp->encoding <= end);
4265          i++, cp++) {
4266         if ((unencoded && i >= start) || cp->encoding >= start) {
4267             (void) memcpy((char *) dp, (char *) cp, sizeof(bdf_glyph_t));
4268             if (cp->name != 0) {
4269                 dp->name = (char *) malloc(strlen(cp->name) + 1);
4270                 (void) strcpy(dp->name, cp->name);
4271             }
4272             if (cp->bytes > 0) {
4273                 dp->bytes = cp->bytes;
4274                 dp->bitmap = (unsigned char *) malloc(cp->bytes);
4275                 (void) memcpy((char *) dp->bitmap, (char *) cp->bitmap,
4276                               cp->bytes);
4277             }
4278             if (cp->unicode.map_used > 0) {
4279                 dp->unicode.map_used = dp->unicode.map_size =
4280                     cp->unicode.map_used;
4281                 dp->unicode.map =
4282                     (unsigned char *) malloc(dp->unicode.map_used);
4283                 (void) memcpy((char *) dp->unicode.map,
4284                               (char *) cp->unicode.map,
4285                               dp->unicode.map_used);
4286             }
4287 
4288             /*
4289              * Determine the overall metrics for the group of characters being
4290              * copied.
4291              */
4292             maxas = MAX(cp->bbx.ascent, maxas);
4293             maxds = MAX(cp->bbx.descent, maxds);
4294             rb = cp->bbx.width + cp->bbx.x_offset;
4295             maxrb = MAX(rb, maxrb);
4296             minlb = MIN(cp->bbx.x_offset, minlb);
4297             maxlb = MAX(cp->bbx.x_offset, maxlb);
4298 
4299             glyphs->glyphs_used++;
4300             dp++;
4301         }
4302     }
4303 
4304     /*
4305      * Set the overall metrics for this set of glyphs.
4306      */
4307     glyphs->bbx.width = maxrb - minlb;
4308     glyphs->bbx.x_offset = minlb;
4309 
4310     glyphs->bbx.height = maxas + maxds;
4311     glyphs->bbx.ascent = maxas;
4312     glyphs->bbx.descent = maxds;
4313     glyphs->bbx.y_offset = -maxds;
4314 }
4315 
4316 bdf_glyph_t *
_bdf_locate_glyph(bdf_font_t * font,int code,int unencoded)4317 _bdf_locate_glyph(bdf_font_t *font, int code, int unencoded)
4318 {
4319     int l, r, m, nc;
4320     bdf_glyph_t *gl;
4321 
4322     if (code < 0 || font == 0)
4323       return 0;
4324 
4325     if ((unencoded && font->unencoded_used == 0) ||
4326         font->glyphs_used == 0)
4327       return 0;
4328 
4329     if (unencoded) {
4330         gl = font->unencoded;
4331         nc = font->unencoded_used;
4332     } else {
4333         gl = font->glyphs;
4334         nc = font->glyphs_used;
4335     }
4336     for (l = m = 0, r = nc - 1; l < r; ) {
4337         m = (l + r) >> 1;
4338         if (gl[m].encoding < code)
4339           l = m + 1;
4340         else if (gl[m].encoding > code)
4341           r = m - 1;
4342         else
4343           break;
4344     }
4345 
4346     /*
4347      * Go back until we hit the beginning of the glyphs or until
4348      * we find the glyph with a code less than the specified code.
4349      */
4350     l = m;
4351     while (m > 0 && gl[m].encoding > code)
4352       m--;
4353 
4354     /*
4355      * Look forward if necessary.
4356      */
4357     m = l;
4358     while (m < nc && gl[m].encoding < code)
4359       m++;
4360 
4361     return (m < nc) ? &gl[m] : &gl[nc - 1];
4362 }
4363 
4364 int
bdf_delete_glyphs(bdf_font_t * font,int start,int end,int unencoded)4365 bdf_delete_glyphs(bdf_font_t *font, int start, int end, int unencoded)
4366 {
4367     int i, n, nc, cnt, mod;
4368     bdf_glyph_t *cp, *sp, *ep;
4369 
4370     mod = 0;
4371 
4372     if (font == 0)
4373       return mod;
4374 
4375     if (start > end) {
4376         cnt = end;
4377         end = start;
4378         start = cnt;
4379     }
4380 
4381     nc = (unencoded == 0) ? font->glyphs_used : font->unencoded_used;
4382     cp = (unencoded == 0) ? font->glyphs : font->unencoded;
4383     sp = ep = 0;
4384 
4385     for (i = 0; i < nc && cp->encoding <= end; i++, cp++) {
4386         if (cp->encoding >= start && sp == 0)
4387           sp = cp;
4388     }
4389     ep = cp;
4390     if (sp == 0)
4391       sp = ep;
4392 
4393     if (ep > sp) {
4394         /*
4395          * There are some glyphs to delete.
4396          * 1. Free the name and bitmap fields of the glyphs being deleted.
4397          * 2. Move the end range down if necessary.
4398          * 3. Clear the glyphs on the end if a move was done.
4399          */
4400 
4401         /*
4402          * Mark the font as being modified.
4403          */
4404         mod = font->modified = 1;
4405 
4406         cnt = ep - sp;
4407 
4408         for (cp = sp; cp < ep; cp++) {
4409             /*
4410              * Mark the glyphs being deleted as also being modified so the
4411              * empty cells can be shown correctly by the client programs.
4412              */
4413             if (unencoded)
4414               _bdf_set_glyph_modified(font->umod, cp->encoding);
4415             else
4416               _bdf_set_glyph_modified(font->nmod, cp->encoding);
4417 
4418             if (cp->name != 0)
4419               free(cp->name);
4420             if (cp->bytes > 0)
4421               free((char *) cp->bitmap);
4422         }
4423 
4424         cp = (unencoded == 0) ? font->glyphs : font->unencoded;
4425 
4426         /*
4427          * Check to see if there are some glyphs that need to
4428          * be moved down.
4429          */
4430         if (ep - cp < nc) {
4431             /*
4432              * Shift the glyphs down.
4433              */
4434             n = nc - (ep - cp);
4435             _bdf_memmove((char *) sp, (char *) ep, sizeof(bdf_glyph_t) * n);
4436 
4437             /*
4438              * Set the starting point for the clear.
4439              */
4440             ep = sp + n;
4441         } else
4442           /*
4443            * Set the starting point for the clear.
4444            */
4445           ep = sp;
4446 
4447         /*
4448          * Clear the glyph space just moved.
4449          */
4450         n = nc - (ep - cp);
4451         (void) memset((char *) ep, 0, sizeof(bdf_glyph_t) * n);
4452 
4453         /*
4454          * Adjust the number of glyphs used.
4455          */
4456         if (unencoded == 0)
4457           font->glyphs_used -= cnt;
4458         else
4459           font->unencoded_used -= cnt;
4460 
4461         /*
4462          * If unencoded glyphs were deleted, re-encode all
4463          * of them to cause a shift when everything is redrawn.
4464          */
4465         if (unencoded != 0) {
4466             for (i = 0, cp = font->unencoded; i < font->unencoded_used;
4467                  i++, cp++) {
4468                 if (_bdf_glyph_modified(font->umod, cp->encoding)) {
4469                     _bdf_clear_glyph_modified(font->umod, cp->encoding);
4470                     _bdf_set_glyph_modified(font->umod, i);
4471                 }
4472                 cp->encoding = i;
4473             }
4474         }
4475     }
4476     return mod;
4477 }
4478 
4479 /*
4480  * These values are intended to give pixels mapped from 1bpp to nbpp the
4481  * darkest available index, which is 1.
4482  */
4483 static unsigned char twobpp_ones[] = {0x40, 0x10, 0x04, 0x01};
4484 static unsigned char fourbpp_ones[] = {0x10, 0x01};
4485 static unsigned char eightbpp_ones[] = {0x01};
4486 
4487 /*
4488  * Routines for quick and dirty dithering.
4489  */
4490 static void
_bdf_one_to_n(bdf_glyphlist_t * gl,int n)4491 _bdf_one_to_n(bdf_glyphlist_t *gl, int n)
4492 {
4493     int i;
4494     unsigned short bpr, sbpr, bytes, col, sx, sy;
4495     unsigned char *nbmap, *ones = 0;
4496     bdf_glyph_t *gp;
4497 
4498     if (gl == 0 || gl->glyphs_used == 0)
4499       return;
4500 
4501     switch (n) {
4502       case 1: ones = bdf_onebpp; break;
4503       case 2: ones = twobpp_ones; break;
4504       case 4: ones = fourbpp_ones; break;
4505       case 8: ones = eightbpp_ones; break;
4506     }
4507 
4508     gl->bpp = n;
4509     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4510         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4511           continue;
4512         sbpr = (gp->bbx.width + 7) >> 3;
4513         bpr = ((gp->bbx.width * n) + 7) >> 3;
4514         bytes = bpr * gp->bbx.height;
4515         nbmap = (unsigned char *) malloc(bytes);
4516         (void) memset((char *) nbmap, 0, bytes);
4517 
4518         for (sy = 0; sy < gp->bbx.height; sy++) {
4519             for (col = sx = 0; sx < gp->bbx.width; sx++, col += n) {
4520                 if (gp->bitmap[(sy * sbpr) + (sx >> 3)] & (0x80 >> (sx & 7)))
4521                   nbmap[(sy * bpr) + (col >> 3)] |= ones[(col & 7) / n];
4522             }
4523         }
4524         free((char *) gp->bitmap);
4525         gp->bytes = bytes;
4526         gp->bitmap = nbmap;
4527     }
4528 }
4529 
4530 static void
_bdf_n_to_one(bdf_glyphlist_t * gl)4531 _bdf_n_to_one(bdf_glyphlist_t *gl)
4532 {
4533     int i;
4534     unsigned short bpr, sbpr, bytes, col, sx, sy;
4535     unsigned char *nbmap, *masks;
4536     bdf_glyph_t *gp;
4537 
4538     if (gl == 0 || gl->glyphs_used == 0)
4539       return;
4540 
4541     masks = 0;
4542     switch (gl->bpp) {
4543       case 1: masks = bdf_onebpp; break;
4544       case 2: masks = bdf_twobpp; break;
4545       case 4: masks = bdf_fourbpp; break;
4546       case 8: masks = bdf_eightbpp; break;
4547     }
4548 
4549     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4550         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4551           continue;
4552         sbpr = ((gp->bbx.width * gl->bpp) + 7) >> 3;
4553         bpr = (gp->bbx.width + 7) >> 3;
4554         bytes = bpr * gp->bbx.height;
4555         nbmap = (unsigned char *) malloc(bytes);
4556         (void) memset((char *) nbmap, 0, bytes);
4557 
4558         for (sy = 0; sy < gp->bbx.height; sy++) {
4559             for (col = sx = 0; sx < gp->bbx.width; sx++, col += gl->bpp) {
4560                 if (gp->bitmap[(sy * sbpr) + (col >> 3)] &
4561                     masks[(col & 7) / gl->bpp])
4562                   nbmap[(sy * bpr) + (sx >> 3)] |= (0x80 >> (sx & 7));
4563             }
4564         }
4565         free((char *) gp->bitmap);
4566         gp->bytes = bytes;
4567         gp->bitmap = nbmap;
4568     }
4569     gl->bpp = 1;
4570 }
4571 
4572 static void
_bdf_two_to_four(bdf_glyphlist_t * gl)4573 _bdf_two_to_four(bdf_glyphlist_t *gl)
4574 {
4575     int i;
4576     unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy;
4577     unsigned char *nbmap, *masks;
4578     bdf_glyph_t *gp;
4579 
4580     if (gl == 0 || gl->glyphs_used == 0)
4581       return;
4582 
4583     masks = bdf_twobpp;
4584 
4585     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4586         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4587           continue;
4588         sbpr = ((gp->bbx.width << 1) + 7) >> 3;
4589         bpr = ((gp->bbx.width << 2) + 7) >> 3;
4590         bytes = bpr * gp->bbx.height;
4591         nbmap = (unsigned char *) malloc(bytes);
4592         (void) memset((char *) nbmap, 0, bytes);
4593 
4594         for (sy = 0; sy < gp->bbx.height; sy++) {
4595             for (col = sx = 0; sx < gp->bbx.width; sx++, col += 2) {
4596                 si = (col & 7) >> 1;
4597                 byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si];
4598                 if (byte) {
4599                     if (si < 3)
4600                       byte >>= (3 - si) << 1;
4601                     byte <<= 2;
4602                     if ((sx & 1) == 0)
4603                       byte <<= 4;
4604                     nbmap[(sy * bpr) + ((sx << 2) >> 3)] |= byte;
4605                 }
4606             }
4607         }
4608         free((char *) gp->bitmap);
4609         gp->bytes = bytes;
4610         gp->bitmap = nbmap;
4611     }
4612     gl->bpp = 4;
4613 }
4614 
4615 static void
_bdf_four_to_two(bdf_glyphlist_t * gl)4616 _bdf_four_to_two(bdf_glyphlist_t *gl)
4617 {
4618     int i;
4619     unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy;
4620     unsigned char *nbmap, *masks;
4621     bdf_glyph_t *gp;
4622 
4623     if (gl == 0 || gl->glyphs_used == 0)
4624       return;
4625 
4626     masks = bdf_fourbpp;
4627 
4628     gl->bpp = 2;
4629     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4630         sbpr = ((gp->bbx.width << 2) + 7) >> 3;
4631         bpr = ((gp->bbx.width << 1) + 7) >> 3;
4632         bytes = bpr * gp->bbx.height;
4633         nbmap = (unsigned char *) malloc(bytes);
4634         (void) memset((char *) nbmap, 0, bytes);
4635 
4636         for (sy = 0; sy < gp->bbx.height; sy++) {
4637             for (col = sx = 0; sx < gp->bbx.width; sx++, col += 4) {
4638                 si = (col & 7) >> 2;
4639                 byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si];
4640                 if (byte) {
4641                     /*
4642                      * Shift the byte down to make an index.
4643                      */
4644                     if (si == 0)
4645                       byte >>= 4;
4646 
4647                     /*
4648                      * Scale the index to two bits per pixel and shift it into
4649                      * place if necessary.
4650                      */
4651                     byte >>= 2;
4652                     /*
4653                      * Any non-zero byte has to remain non-zero, because index
4654                      * zero means no bits set.
4655                      */
4656                     if (byte == 0)
4657                       byte = 1;
4658 
4659                     si = ((sx << 1) & 7) >> 1;
4660                     if (si < 3)
4661                       byte <<= (3 - si) << 1;
4662 
4663                     nbmap[(sy * bpr) + ((sx << 1) >> 3)] |= byte;
4664                 }
4665             }
4666         }
4667         free((char *) gp->bitmap);
4668         gp->bytes = bytes;
4669         gp->bitmap = nbmap;
4670     }
4671 }
4672 
4673 static void
_bdf_two_to_eight(bdf_glyphlist_t * gl)4674 _bdf_two_to_eight(bdf_glyphlist_t *gl)
4675 {
4676     int i;
4677     unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy;
4678     unsigned char *nbmap, *masks;
4679     bdf_glyph_t *gp;
4680 
4681     if (gl == 0 || gl->glyphs_used == 0)
4682       return;
4683 
4684     masks = bdf_twobpp;
4685 
4686     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4687         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4688           continue;
4689         sbpr = ((gp->bbx.width << 1) + 7) >> 3;
4690         bpr = gp->bbx.width;
4691         bytes = bpr * gp->bbx.height;
4692         nbmap = (unsigned char *) malloc(bytes);
4693         (void) memset((char *) nbmap, 0, bytes);
4694 
4695         for (sy = 0; sy < gp->bbx.height; sy++) {
4696             for (col = sx = 0; sx < gp->bbx.width; sx++, col += 2) {
4697                 si = (col & 7) >> 1;
4698                 byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si];
4699                 if (byte) {
4700                     /*
4701                      * Shift the byte down to make an index.
4702                      */
4703                     if (si < 3)
4704                       byte >>= (3 - si) * gl->bpp;
4705 
4706                     /*
4707                      * Scale the index to four bits per pixel and shift it into
4708                      * place before adding it.
4709                      */
4710                     byte <<= 6;
4711                     nbmap[(sy * bpr) + sx] = byte;
4712                 }
4713             }
4714         }
4715         free((char *) gp->bitmap);
4716         gp->bytes = bytes;
4717         gp->bitmap = nbmap;
4718     }
4719     gl->bpp = 8;
4720 }
4721 
4722 static void
_bdf_eight_to_two(bdf_glyphlist_t * gl)4723 _bdf_eight_to_two(bdf_glyphlist_t *gl)
4724 {
4725     int i;
4726     unsigned short bpr, sbpr, bytes, si, byte, sx, sy;
4727     unsigned char *nbmap, *masks;
4728     bdf_glyph_t *gp;
4729 
4730     if (gl == 0 || gl->glyphs_used == 0)
4731       return;
4732 
4733     masks = bdf_fourbpp;
4734 
4735     gl->bpp = 2;
4736     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4737         sbpr = gp->bbx.width;
4738         bpr = ((gp->bbx.width << 1) + 7) >> 3;
4739         bytes = bpr * gp->bbx.height;
4740         nbmap = (unsigned char *) malloc(bytes);
4741         (void) memset((char *) nbmap, 0, bytes);
4742 
4743         for (sy = 0; sy < gp->bbx.height; sy++) {
4744             for (sx = 0; sx < gp->bbx.width; sx++) {
4745                 byte = gp->bitmap[(sy * sbpr) + sx];
4746                 if (byte) {
4747                     byte >>= 6;
4748                     if (byte == 0)
4749                       byte = 1;
4750 
4751                     si = ((sx << 1) & 7) >> 1;
4752                     if (si < 3)
4753                       byte <<= (3 - si) << 1;
4754 
4755                     nbmap[(sy * bpr) + ((sx << 1) >> 3)] |= byte;
4756                 }
4757             }
4758         }
4759         free((char *) gp->bitmap);
4760         gp->bytes = bytes;
4761         gp->bitmap = nbmap;
4762     }
4763 }
4764 
4765 static void
_bdf_four_to_eight(bdf_glyphlist_t * gl)4766 _bdf_four_to_eight(bdf_glyphlist_t *gl)
4767 {
4768     int i;
4769     unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy;
4770     unsigned char *nbmap, *masks;
4771     bdf_glyph_t *gp;
4772 
4773     if (gl == 0 || gl->glyphs_used == 0)
4774       return;
4775 
4776     masks = bdf_fourbpp;
4777 
4778     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4779         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4780           continue;
4781         sbpr = ((gp->bbx.width << 2) + 7) >> 3;
4782         bpr = gp->bbx.width;
4783         bytes = bpr * gp->bbx.height;
4784         nbmap = (unsigned char *) malloc(bytes);
4785         (void) memset((char *) nbmap, 0, bytes);
4786 
4787         for (sy = 0; sy < gp->bbx.height; sy++) {
4788             for (col = sx = 0; sx < gp->bbx.width; sx++, col += 4) {
4789                 si = (col & 7) >> 2;
4790                 byte = gp->bitmap[(sy * sbpr) + (col >> 3)] & masks[si];
4791                 if (byte) {
4792                     if (si == 0)
4793                       byte >>= 4;
4794 
4795                     byte <<= 4;
4796                     nbmap[(sy * bpr) + sx] = byte;
4797                 }
4798             }
4799         }
4800         free((char *) gp->bitmap);
4801         gp->bytes = bytes;
4802         gp->bitmap = nbmap;
4803     }
4804     gl->bpp = 8;
4805 }
4806 
4807 static void
_bdf_eight_to_four(bdf_glyphlist_t * gl)4808 _bdf_eight_to_four(bdf_glyphlist_t *gl)
4809 {
4810     int i;
4811     unsigned short bpr, sbpr, bytes, col, si, byte, sx, sy;
4812     unsigned char *nbmap, *masks;
4813     bdf_glyph_t *gp;
4814 
4815     if (gl == 0 || gl->glyphs_used == 0)
4816       return;
4817 
4818     masks = bdf_twobpp;
4819 
4820     for (gp = gl->glyphs, i = 0; i < gl->glyphs_used; i++, gp++) {
4821         if (gp->bbx.width == 0 || gp->bbx.height == 0)
4822           continue;
4823         sbpr = gp->bbx.width;
4824         bpr = ((gp->bbx.width << 2) + 7) >> 3;
4825         bytes = bpr * gp->bbx.height;
4826         nbmap = (unsigned char *) malloc(bytes);
4827         (void) memset((char *) nbmap, 0, bytes);
4828 
4829         for (sy = 0; sy < gp->bbx.height; sy++) {
4830             for (col = sx = 0; sx < gp->bbx.width; sx++, col += 2) {
4831                 byte = gp->bitmap[(sy * sbpr) + sx];
4832                 if (byte) {
4833                     byte >>= 4;
4834                     if (byte == 0)
4835                       byte = 1;
4836 
4837                     /*
4838                      * Scale the index to four bits per pixel and shift it into
4839                      * place before adding it.
4840                      */
4841                     si = (col & 7) >> 2;
4842                     if (si == 0)
4843                       byte <<= 4;
4844                     nbmap[(sy * bpr) + ((sx << 2) >> 3)] |= byte;
4845                 }
4846             }
4847         }
4848         free((char *) gp->bitmap);
4849         gp->bytes = bytes;
4850         gp->bitmap = nbmap;
4851     }
4852     gl->bpp = 4;
4853 }
4854 
4855 /*
4856  * This only works on glyphs that exist.
4857  */
4858 int
bdf_replace_mappings(bdf_font_t * font,int encoding,bdf_psf_unimap_t * map,int unencoded)4859 bdf_replace_mappings(bdf_font_t *font, int encoding, bdf_psf_unimap_t *map,
4860                      int unencoded)
4861 {
4862     bdf_glyph_t *gp;
4863 
4864     if ((gp = _bdf_locate_glyph(font, encoding, unencoded)) == 0 ||
4865         gp->encoding != encoding)
4866       return 0;
4867 
4868     if (map->map_size > gp->unicode.map_size) {
4869         if (gp->unicode.map_size == 0)
4870           gp->unicode.map = (unsigned char *)
4871               malloc(sizeof(unsigned char) * map->map_size);
4872         else
4873           gp->unicode.map =(unsigned char *)
4874               realloc((char *) gp->unicode.map,
4875                       sizeof(unsigned char) * map->map_size);
4876         gp->unicode.map_size = map->map_size;
4877     }
4878     gp->unicode.map_used = map->map_used;
4879     (void) memcpy((char *) gp->unicode.map, (char *) map->map,
4880                   sizeof(unsigned char) * map->map_used);
4881 
4882     /*
4883      * Mark the glyph as modified.
4884      */
4885     if (unencoded)
4886       _bdf_set_glyph_modified(font->umod, gp->encoding);
4887     else
4888       _bdf_set_glyph_modified(font->nmod, gp->encoding);
4889 
4890     font->modified = 1;
4891 
4892     return 1;
4893 }
4894 
4895 int
bdf_replace_glyphs(bdf_font_t * font,int start,bdf_glyphlist_t * glyphs,int unencoded)4896 bdf_replace_glyphs(bdf_font_t *font, int start, bdf_glyphlist_t *glyphs,
4897                    int unencoded)
4898 {
4899     int resize, appending;
4900     int i, n, ng, end, del, remaining, off[2];
4901     bdf_glyph_t *sgp, *gp, *dgp;
4902     short maxas, maxds, maxrb, minlb, maxlb, rb;
4903     double ps, rx, dw;
4904     bdf_bbx_t nbbx;
4905 
4906     resize = 0;
4907 
4908     if (font == 0)
4909       return resize;
4910 
4911     /*
4912      * Dither the incoming bitmaps so they match the same bits per pixel as
4913      * the font.
4914      */
4915     if (glyphs->bpp != font->bpp) {
4916         if (glyphs->bpp == 1)
4917           _bdf_one_to_n(glyphs, font->bpp);
4918         else if (font->bpp == 1)
4919           _bdf_n_to_one(glyphs);
4920         else if (glyphs->bpp == 2) {
4921             if (font->bpp == 4)
4922               _bdf_two_to_four(glyphs);
4923             else
4924               _bdf_two_to_eight(glyphs);
4925         } else if (glyphs->bpp == 4) {
4926             if (font->bpp == 2)
4927               _bdf_four_to_two(glyphs);
4928             else
4929               _bdf_four_to_eight(glyphs);
4930         } else if (glyphs->bpp == 8) {
4931             if (font->bpp == 2)
4932               _bdf_eight_to_two(glyphs);
4933             else
4934               _bdf_eight_to_four(glyphs);
4935         }
4936     }
4937 
4938     /*
4939      * Set the point size and horizontal resolution so the scalable width can
4940      * be determined.
4941      */
4942     ps = (double) font->point_size;
4943     rx = (double) font->resolution_x;
4944 
4945     /*
4946      * Determine if a resize is needed.
4947      */
4948 
4949     /*
4950      * Determine the bounding box for the font without the characters being
4951      * replaced.
4952      */
4953     minlb = 32767;
4954     maxlb = maxrb = maxas = maxds = 0;
4955 
4956     /*
4957      * Get the font bounds.
4958      */
4959     maxas = MAX(font->bbx.ascent, maxas);
4960     maxds = MAX(font->bbx.descent, maxds);
4961     rb = font->bbx.width + font->bbx.x_offset;
4962     maxrb = MAX(rb, maxrb);
4963     minlb = MIN(font->bbx.x_offset, minlb);
4964     maxlb = MAX(font->bbx.x_offset, maxlb);
4965 
4966     /*
4967      * Get the bounds of the incoming glyphs.
4968      */
4969     maxas = MAX(glyphs->bbx.ascent, maxas);
4970     maxds = MAX(glyphs->bbx.descent, maxds);
4971     rb = glyphs->bbx.width + glyphs->bbx.x_offset;
4972     maxrb = MAX(rb, maxrb);
4973     minlb = MIN(glyphs->bbx.x_offset, minlb);
4974     maxlb = MAX(glyphs->bbx.x_offset, maxlb);
4975 
4976     /*
4977      * Set up the new font bounding box, minus the characters that are being
4978      * removed and with the new characters added.
4979      */
4980     nbbx.width = maxrb - minlb;
4981     nbbx.x_offset = minlb;
4982 
4983     nbbx.height = maxas + maxds;
4984     nbbx.ascent = maxas;
4985     nbbx.descent = maxds;
4986     nbbx.y_offset = -maxds;
4987 
4988     /*
4989      * Now determine if the combination of the glyphs removed and the new
4990      * glyphs cause the font bounding box to be changed.
4991      */
4992     resize = (nbbx.width > font->bbx.width ||
4993               nbbx.height > font->bbx.height) ? 1 : 0;
4994 
4995     /*
4996      * Set the pointers to the glyphs.
4997      */
4998     ng = (unencoded == 0) ? font->glyphs_used : font->unencoded_used;
4999     sgp = gp = (unencoded == 0) ? font->glyphs : font->unencoded;
5000 
5001     /*
5002      * Locate the closest glyph on or following `start'.
5003      */
5004     for (i = 0; i < ng && gp->encoding < start; i++, gp++) ;
5005 
5006     appending = (i == ng);
5007 
5008     /*
5009      * Set the starting point for copying the incoming glyphs.
5010      */
5011     dgp = gp;
5012 
5013     n = glyphs->end - glyphs->start;
5014     end = start + n;
5015 
5016     /*
5017      * Delete all the glyphs between `start' and `end'.
5018      */
5019     for (del = 0, i = start; i <= end; i++) {
5020         /*
5021          * Mark the character as being modified.
5022          */
5023         if (ng > 0 && !appending && gp->encoding == i) {
5024             if (unencoded == 0)
5025               _bdf_set_glyph_modified(font->nmod, i);
5026             else
5027               _bdf_set_glyph_modified(font->umod, i);
5028 
5029             if (gp->name != 0)
5030               free(gp->name);
5031             if (gp->bytes > 0)
5032               free((char *) gp->bitmap);
5033             if (gp->unicode.map_size > 0)
5034               free((char *) gp->unicode.map);
5035             del++;
5036             gp++;
5037         }
5038     }
5039 
5040     /*
5041      * Determine how many glyphs remain following the last one deleted.
5042      */
5043     remaining = ng - (gp - sgp);
5044 
5045     if (glyphs->glyphs_used == 0) {
5046         /*
5047          * If the glyph list is empty, then shift any remaining glyphs down
5048          * to the destination.
5049          */
5050         _bdf_memmove((char *) dgp, (char *) gp,
5051                      sizeof(bdf_glyph_t) * remaining);
5052         if (unencoded == 0)
5053           font->glyphs_used -= del;
5054         else
5055           font->unencoded_used -= del;
5056     } else {
5057         /*
5058          * Insert the glyph list after making sure there is enough space to
5059          * hold them.  Also adjust the encoding and scalable width values
5060          * after copying the glyphs.
5061          */
5062         if (unencoded == 0) {
5063             n = (font->glyphs_used - del) + glyphs->glyphs_used;
5064             if (n > font->glyphs_size) {
5065                 off[0] = gp - sgp;
5066                 off[1] = dgp - sgp;
5067                 if (font->glyphs_size == 0)
5068                   font->glyphs = sgp =
5069                       (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * n);
5070                 else
5071                   font->glyphs = sgp =
5072                       (bdf_glyph_t *) realloc((char *) font->glyphs,
5073                                               sizeof(bdf_glyph_t) * n);
5074                 gp = sgp + off[0];
5075                 dgp = sgp + off[1];
5076                 font->glyphs_size = n;
5077             }
5078 
5079             /*
5080              * Calculate how many will need to be shifted.
5081              */
5082             if ((n = glyphs->glyphs_used - del) >= font->glyphs_used)
5083               n = 0;
5084         } else {
5085             n = (font->unencoded_used - del) + glyphs->glyphs_used;
5086             if (n > font->unencoded_size) {
5087                 off[0] = gp - sgp;
5088                 off[1] = dgp - sgp;
5089                 if (font->unencoded_size == 0)
5090                   font->unencoded = sgp =
5091                       (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * n);
5092                 else
5093                   font->unencoded = sgp =
5094                       (bdf_glyph_t *) realloc((char *) font->unencoded,
5095                                               sizeof(bdf_glyph_t) * n);
5096                 gp = sgp + off[0];
5097                 dgp = sgp + off[1];
5098                 font->unencoded_size = n;
5099             }
5100 
5101             /*
5102              * Calculate how many will need to be shifted.
5103              */
5104             if ((n = glyphs->glyphs_used - del) >= font->unencoded_used)
5105               n = 0;
5106         }
5107 
5108         /*
5109          * Shift any following glyphs up or down if needed.
5110          */
5111         if (n)
5112           _bdf_memmove((char *) (gp + n), (char *) gp,
5113                        sizeof(bdf_glyph_t) * remaining);
5114 
5115         /*
5116          * Copy the incoming glyphs, copy their names and bitmaps,
5117          * set their encodings, and set their scalable widths.
5118          */
5119         (void) memcpy((char *) dgp, (char *) glyphs->glyphs,
5120                       sizeof(bdf_glyph_t) * glyphs->glyphs_used);
5121         for (i = 0; i < glyphs->glyphs_used; i++, dgp++) {
5122             if (dgp->name != 0)
5123               dgp->name = (char *) _bdf_strdup((unsigned char *) dgp->name,
5124                                                strlen(dgp->name) + 1);
5125 
5126             if (dgp->bytes > 0)
5127               dgp->bitmap = _bdf_strdup(dgp->bitmap, dgp->bytes);
5128 
5129             if (dgp->unicode.map_size > 0)
5130               dgp->unicode.map = _bdf_strdup(dgp->unicode.map,
5131                                              dgp->unicode.map_size);
5132 
5133             dgp->encoding = start + (dgp->encoding - glyphs->start);
5134 
5135             /*
5136              * Mark the glyph as being modified in case it fills a cell that
5137              * was empty before.
5138              */
5139             _bdf_set_glyph_modified(font->nmod, dgp->encoding);
5140 
5141             dw = (double) dgp->dwidth;
5142             dgp->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
5143         }
5144 
5145         /*
5146          * Adjust the count of glyphs.
5147          */
5148         ng = (ng - del) + glyphs->glyphs_used;
5149         if (unencoded == 0)
5150           font->glyphs_used = ng;
5151         else
5152           font->unencoded_used = ng;
5153     }
5154 
5155     /*
5156      * Last, if the replacement was done in the unencoded section,
5157      * reencode all the glyphs so they show up properly.
5158      */
5159     if (unencoded != 0) {
5160         for (i = 0; i < ng; i++, sgp++) {
5161             if (_bdf_glyph_modified(font->umod, sgp->encoding)) {
5162                 _bdf_clear_glyph_modified(font->umod, sgp->encoding);
5163                 _bdf_set_glyph_modified(font->umod, i);
5164             }
5165             sgp->encoding = i;
5166         }
5167     }
5168 
5169     if (resize)
5170       (void) memcpy((char *) &font->bbx, (char *) &nbbx, sizeof(bdf_bbx_t));
5171 
5172     font->modified = 1;
5173 
5174     return resize;
5175 }
5176 
5177 int
bdf_insert_glyphs(bdf_font_t * font,int start,bdf_glyphlist_t * glyphs)5178 bdf_insert_glyphs(bdf_font_t *font, int start, bdf_glyphlist_t *glyphs)
5179 {
5180     int resize;
5181     unsigned int i, ng, n, which;
5182     bdf_glyph_t *gp;
5183 
5184     resize = 0;
5185 
5186     if (font == 0)
5187       return resize;
5188 
5189     /*
5190      * Dither the incoming bitmaps so they match the same bits per pixel as
5191      * the font.
5192      */
5193     if (glyphs->bpp != font->bpp) {
5194         if (glyphs->bpp == 1)
5195           _bdf_one_to_n(glyphs, font->bpp);
5196         else if (font->bpp == 1)
5197           _bdf_n_to_one(glyphs);
5198         else if (glyphs->bpp == 2)
5199           _bdf_two_to_four(glyphs);
5200         else
5201           _bdf_four_to_two(glyphs);
5202     }
5203 
5204     /*
5205      * Locate the starting glyph.
5206      */
5207     gp = font->glyphs;
5208     ng = font->glyphs_used;
5209     for (i = 0; i < ng && gp->encoding < start; i++, gp++) ;
5210 
5211     /*
5212      * If there are no glyphs at the starting point, then simply do a replace.
5213      */
5214     if (i == ng)
5215       return bdf_replace_glyphs(font, start, glyphs, 0);
5216 
5217     /*
5218      * Go through the glyphs that would be shifted due to the insertion and
5219      * determine if some of them will overflow the 0xffff boundary.
5220      */
5221     n = (glyphs->end - glyphs->start) + 1;
5222     for (which = i; i < ng; i++, gp++) {
5223         if (gp->encoding + n > 0xffff)
5224           break;
5225     }
5226 
5227     if (i < ng) {
5228         /*
5229          * Some glyphs have to be moved to the unencoded area because they
5230          * would overflow the 0xffff boundary if they were moved up.
5231          */
5232         bdf_copy_glyphs(font, gp->encoding, font->glyphs[ng - 1].encoding,
5233                         &font->overflow, 0);
5234         bdf_delete_glyphs(font,  gp->encoding, font->glyphs[ng - 1].encoding,
5235                           0);
5236         resize += bdf_replace_glyphs(font, font->unencoded_used,
5237                                      &font->overflow, 1);
5238     }
5239 
5240     /*
5241      * Go back to the insertion point and shift the remaining glyph encodings
5242      * up by `n'.
5243      */
5244     for (gp = font->glyphs + which; which < font->glyphs_used; which++, gp++) {
5245         /*
5246          * Mark the new glyph locations as being modified.
5247          */
5248         gp->encoding += n;
5249         _bdf_set_glyph_modified(font->nmod, gp->encoding);
5250     }
5251 
5252     /*
5253      * Finally, mark the font as being modified and insert the new glyphs.
5254      */
5255     font->modified = 1;
5256 
5257     return resize + bdf_replace_glyphs(font, start, glyphs, 0);
5258 }
5259 
5260 static void
_bdf_combine_glyphs(bdf_font_t * font,bdf_glyph_t * f,bdf_glyph_t * g)5261 _bdf_combine_glyphs(bdf_font_t *font, bdf_glyph_t *f, bdf_glyph_t *g)
5262 {
5263     unsigned short x, sx, sy, si, dx, dy, di, byte, dbpr, fbpr, gbpr;
5264     short maxas, maxds, maxrb, minlb, maxlb, rb;
5265     unsigned char *masks;
5266     bdf_bbx_t nbbx;
5267     bdf_glyph_t tmp;
5268 
5269     /*
5270      * Determine the max bounding box for the two glyphs.
5271      */
5272     minlb = 32767;
5273     maxlb = maxrb = maxas = maxds = 0;
5274 
5275     /*
5276      * Get the font glyph bounds.
5277      */
5278     maxas = MAX(f->bbx.ascent, maxas);
5279     maxds = MAX(f->bbx.descent, maxds);
5280     rb = f->bbx.width + f->bbx.x_offset;
5281     maxrb = MAX(rb, maxrb);
5282     minlb = MIN(f->bbx.x_offset, minlb);
5283     maxlb = MAX(f->bbx.x_offset, maxlb);
5284 
5285     /*
5286      * Get the bounds of the incoming glyph.
5287      */
5288     maxas = MAX(g->bbx.ascent, maxas);
5289     maxds = MAX(g->bbx.descent, maxds);
5290     rb = g->bbx.width + g->bbx.x_offset;
5291     maxrb = MAX(rb, maxrb);
5292     minlb = MIN(g->bbx.x_offset, minlb);
5293     maxlb = MAX(g->bbx.x_offset, maxlb);
5294 
5295     /*
5296      * Set up the new glyph bounding box.
5297      */
5298     nbbx.width = maxrb - minlb;
5299     nbbx.x_offset = minlb;
5300     nbbx.height = maxas + maxds;
5301     nbbx.ascent = maxas;
5302     nbbx.descent = maxds;
5303     nbbx.y_offset = -maxds;
5304 
5305     masks = 0;
5306     switch (font->bpp) {
5307       case 1: masks = bdf_onebpp; break;
5308       case 2: masks = bdf_twobpp; break;
5309       case 4: masks = bdf_fourbpp; break;
5310       case 8: masks = bdf_eightbpp; break;
5311     }
5312 
5313     fbpr = ((f->bbx.width * font->bpp) + 7) >> 3;
5314     gbpr = ((g->bbx.width * font->bpp) + 7) >> 3;
5315     dbpr = ((nbbx.width * font->bpp) + 7) >> 3;
5316 
5317     if (memcmp((char *) &nbbx, (char *) &f->bbx, sizeof(bdf_bbx_t)) == 0) {
5318         /*
5319          * The largest is the first, so merge the second in with it.
5320          */
5321         dy = f->bbx.ascent - g->bbx.ascent;
5322         for (sy = 0; sy < g->bbx.height; sy++, dy++) {
5323             for (x = sx = 0; x < g->bbx.width; x++, sx += font->bpp) {
5324                 si = (sx & 7) / font->bpp;
5325                 if ((byte = g->bitmap[(sy * gbpr) + (sx >> 3)] & masks[si]))
5326                   /*
5327                    * No shifting of the byte is needed because the x offset
5328                    * is the same for both glyphs.
5329                    */
5330                   f->bitmap[(dy * fbpr) + (sx >> 3)] |= byte;
5331             }
5332         }
5333     } else if (memcmp((char *) &nbbx, (char *) &g->bbx,
5334                       sizeof(bdf_bbx_t)) == 0) {
5335         /*
5336          * The largest is the incoming glyph, so merge into that one and swap
5337          * it with the font glyph.
5338          */
5339         dy = g->bbx.ascent - f->bbx.ascent;
5340         for (sy = 0; sy < f->bbx.height; sy++, dy++) {
5341             for (x = sx = 0; x < f->bbx.width; x++, sx += font->bpp) {
5342                 si = (sx & 7) / font->bpp;
5343                 if ((byte = f->bitmap[(sy * gbpr) + (sx >> 3)] & masks[si]))
5344                   /*
5345                    * No shifting of the byte is needed because the x offset
5346                    * is the same for both glyphs.
5347                    */
5348                   g->bitmap[(dy * fbpr) + (sx >> 3)] |= byte;
5349             }
5350         }
5351 
5352         /*
5353          * Now swap the two glyphs while preserving the name and encoding of
5354          * the first glyph.
5355          */
5356         tmp.swidth = g->swidth;
5357         tmp.dwidth = g->dwidth;
5358         tmp.bytes = g->bytes;
5359         tmp.bitmap = g->bitmap;
5360         (void) memcpy((char *) &tmp.bbx, (char *) &g->bbx, sizeof(bdf_bbx_t));
5361 
5362         g->swidth = f->swidth;
5363         g->dwidth = f->dwidth;
5364         g->bytes = f->bytes;
5365         g->bitmap = f->bitmap;
5366         (void) memcpy((char *) &g->bbx, (char *) &f->bbx, sizeof(bdf_bbx_t));
5367 
5368         f->swidth = tmp.swidth;
5369         f->dwidth = tmp.dwidth;
5370         f->bytes = tmp.bytes;
5371         f->bitmap = tmp.bitmap;
5372         (void) memcpy((char *) &f->bbx, (char *) &tmp.bbx, sizeof(bdf_bbx_t));
5373     } else {
5374         /*
5375          * Need a new bitmap for the combination of the two.
5376          */
5377         tmp.bytes = nbbx.height * dbpr;
5378         tmp.bitmap = (unsigned char *) malloc(tmp.bytes);
5379         (void) memset((char *) tmp.bitmap, 0, tmp.bytes);
5380 
5381         /*
5382          * Merge the first glyph.
5383          */
5384         dy = nbbx.ascent - f->bbx.ascent;
5385         for (sy = 0; sy < f->bbx.height; sy++, dy++) {
5386             dx = MYABS(nbbx.x_offset - f->bbx.x_offset) * font->bpp;
5387             for (x = sx = 0; x < f->bbx.width; x++,
5388                      sx += font->bpp, dx += font->bpp) {
5389                 si = (sx & 7) / font->bpp;
5390                 if ((byte = f->bitmap[(sy * fbpr) + (sx >> 3)] & masks[si])) {
5391                     di = (dx & 7) / font->bpp;
5392                     if (di < si)
5393                       byte <<= (si - di) * font->bpp;
5394                     else if (di > si)
5395                       byte >>= (di - si) * font->bpp;
5396                     tmp.bitmap[(dy * dbpr) + (dx >> 3)] |= byte;
5397                 }
5398             }
5399         }
5400 
5401         /*
5402          * Merge the second glyph.
5403          */
5404         dy = nbbx.ascent - g->bbx.ascent;
5405         for (sy = 0; sy < g->bbx.height; sy++, dy++) {
5406             dx = MYABS(nbbx.x_offset - g->bbx.x_offset) * font->bpp;
5407             for (x = sx = 0; x < g->bbx.width; x++,
5408                      sx += font->bpp, dx += font->bpp) {
5409                 si = (sx & 7) / font->bpp;
5410                 if ((byte = g->bitmap[(sy * gbpr) + (sx >> 3)] & masks[si])) {
5411                     di = (dx & 7) / font->bpp;
5412                     if (di < si)
5413                       byte <<= (si - di) * font->bpp;
5414                     else if (di > si)
5415                       byte >>= (di - si) * font->bpp;
5416                     tmp.bitmap[(dy * dbpr) + (dx >> 3)] |= byte;
5417                 }
5418             }
5419         }
5420 
5421         /*
5422          * Now clear the font glyph and copy the temp glyph to it.
5423          */
5424         if (f->bytes > 0)
5425           free((char *) f->bitmap);
5426         f->bytes = tmp.bytes;
5427         f->bitmap = tmp.bitmap;
5428         (void) memcpy((char *) &f->bbx, (char *) &nbbx, sizeof(bdf_bbx_t));
5429 
5430         /*
5431          * Set the device width.  Pay attention to whether the font is
5432          * monowidth or character cell.
5433          */
5434         if (font->spacing != BDF_PROPORTIONAL)
5435           f->dwidth = font->monowidth;
5436         else
5437           f->dwidth = MAX(f->dwidth, g->dwidth);
5438     }
5439 }
5440 
5441 int
bdf_merge_glyphs(bdf_font_t * font,int start,bdf_glyphlist_t * glyphs,int unencoded)5442 bdf_merge_glyphs(bdf_font_t *font, int start, bdf_glyphlist_t *glyphs,
5443                  int unencoded)
5444 {
5445     int resize;
5446     int i, n, ng, end, add, enc, off;
5447     bdf_glyph_t *sgp, *gp, *dgp, *base;
5448     short maxas, maxds, maxrb, minlb, maxlb, rb;
5449     double ps, rx, dw;
5450     bdf_bbx_t nbbx;
5451 
5452     resize = 0;
5453 
5454     if (font == 0)
5455       return resize;
5456 
5457     /*
5458      * If the glyphs are being merged in the unencoded area, simply append
5459      * them.  The unencoded area is simply storage.
5460      */
5461     if (unencoded)
5462       return bdf_replace_glyphs(font, font->unencoded_used, glyphs, unencoded);
5463 
5464     /*
5465      * Dither the incoming bitmaps so they match the same bits per pixel as
5466      * the font.
5467      */
5468     if (glyphs->bpp != font->bpp) {
5469         if (glyphs->bpp == 1)
5470           _bdf_one_to_n(glyphs, font->bpp);
5471         else if (font->bpp == 1)
5472           _bdf_n_to_one(glyphs);
5473         else if (glyphs->bpp == 2)
5474           _bdf_two_to_four(glyphs);
5475         else
5476           _bdf_four_to_two(glyphs);
5477     }
5478 
5479     /*
5480      * Set the point size and horizontal resolution so the scalable width can
5481      * be determined.
5482      */
5483     ps = (double) font->point_size;
5484     rx = (double) font->resolution_x;
5485 
5486     /*
5487      * Determine if a resize is needed.
5488      */
5489 
5490     /*
5491      * Determine the bounding box for the font without the characters being
5492      * replaced.
5493      */
5494     minlb = 32767;
5495     maxlb = maxrb = maxas = maxds = 0;
5496 
5497     /*
5498      * Get the font bounds.
5499      */
5500     maxas = MAX(font->bbx.ascent, maxas);
5501     maxds = MAX(font->bbx.descent, maxds);
5502     rb = font->bbx.width + font->bbx.x_offset;
5503     maxrb = MAX(rb, maxrb);
5504     minlb = MIN(font->bbx.x_offset, minlb);
5505     maxlb = MAX(font->bbx.x_offset, maxlb);
5506 
5507     /*
5508      * Get the bounds of the incoming glyphs.
5509      */
5510     maxas = MAX(glyphs->bbx.ascent, maxas);
5511     maxds = MAX(glyphs->bbx.descent, maxds);
5512     rb = glyphs->bbx.width + glyphs->bbx.x_offset;
5513     maxrb = MAX(rb, maxrb);
5514     minlb = MIN(glyphs->bbx.x_offset, minlb);
5515     maxlb = MAX(glyphs->bbx.x_offset, maxlb);
5516 
5517     /*
5518      * Set up the new font bounding box, minus the characters that are being
5519      * removed and with the new characters added.
5520      */
5521     nbbx.width = maxrb - minlb;
5522     nbbx.x_offset = minlb;
5523 
5524     nbbx.height = maxas + maxds;
5525     nbbx.ascent = maxas;
5526     nbbx.descent = maxds;
5527     nbbx.y_offset = -maxds;
5528 
5529     /*
5530      * Now determine if the combination of the glyphs removed and the new
5531      * glyphs cause the font bounding box to be changed.
5532      */
5533     resize = (nbbx.width > font->bbx.width ||
5534               nbbx.height > font->bbx.height) ? 1 : 0;
5535 
5536     /*
5537      * Set the pointers to the glyphs.
5538      */
5539     ng = (unencoded == 0) ? font->glyphs_used : font->unencoded_used;
5540     gp = (unencoded == 0) ? font->glyphs : font->unencoded;
5541 
5542     /*
5543      * Locate the closest glyph on or following `start'.
5544      */
5545     for (i = 0; i < ng && gp->encoding < start; i++, gp++) ;
5546 
5547     if (i == ng)
5548       /*
5549        * If the gylphs are being added off the end of the list, simply insert
5550        * them so any overflows can be handled.
5551        */
5552       return bdf_insert_glyphs(font, start, glyphs);
5553 
5554     /*
5555      * Set the starting point for copying the incoming glyphs.
5556      */
5557     dgp = gp;
5558 
5559     n = glyphs->end - glyphs->start;
5560     end = start + n;
5561 
5562     /*
5563      * Count the number of glyphs that will be added and mark all the
5564      * glyphs that will be modified.
5565      */
5566     for (sgp = glyphs->glyphs, add = 0, i = start; i <= end; i++) {
5567         enc = (sgp->encoding - glyphs->start) + start;
5568 
5569         /*
5570          * Mark the glyph as being modified.
5571          */
5572         if (unencoded == 0)
5573           _bdf_set_glyph_modified(font->nmod, enc);
5574         else
5575           _bdf_set_glyph_modified(font->umod, enc);
5576 
5577         if (enc == gp->encoding)
5578           sgp++;
5579         else if (enc < gp->encoding) {
5580             add++;
5581             sgp++;
5582         }
5583 
5584         if (gp->encoding == i)
5585           gp++;
5586     }
5587 
5588     if (add > 0) {
5589         ng += add;
5590 
5591         /*
5592          * Need to make room for some glyphs that will be added.
5593          */
5594         if (unencoded) {
5595             off = dgp - font->unencoded;
5596             if (font->unencoded_used == 0)
5597               font->unencoded =
5598                   (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * ng);
5599             else
5600               font->unencoded =
5601                   (bdf_glyph_t *) realloc((char *) font->unencoded,
5602                                           sizeof(bdf_glyph_t) * ng);
5603             dgp = font->unencoded + off;
5604             font->unencoded_used = ng;
5605         } else {
5606             off = dgp - font->glyphs;
5607             if (font->glyphs_used == 0)
5608               font->glyphs =
5609                   (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * ng);
5610             else
5611               font->glyphs =
5612                   (bdf_glyph_t *) realloc((char *) font->glyphs,
5613                                           sizeof(bdf_glyph_t) * ng);
5614             dgp = font->glyphs + off;
5615             font->glyphs_used = ng;
5616         }
5617     }
5618 
5619     /*
5620      * Now go through and do two things:
5621      * 1. Insert new incoming glyphs.
5622      * 2. Combine two glyphs at the same location.
5623      */
5624     base = (!unencoded) ? font->glyphs : font->unencoded;
5625     for (gp = dgp, sgp = glyphs->glyphs, i = start; i <= end; i++) {
5626         enc = (sgp->encoding - glyphs->start) + start;
5627         if (enc < gp->encoding) {
5628             /*
5629              * Shift the glyphs up by one and add this one.
5630              */
5631             if (gp - base < ng)
5632               _bdf_memmove((char *) (gp + 1), (char *) gp,
5633                            sizeof(bdf_glyph_t) * (ng - (gp - base)));
5634             (void) memcpy((char *) gp, (char *) sgp, sizeof(bdf_glyph_t));
5635             gp->name = (char *) _bdf_strdup((unsigned char *) gp->name,
5636                                             strlen(gp->name) + 1);
5637             if (gp->bytes > 0)
5638               gp->bitmap = _bdf_strdup(gp->bitmap, gp->bytes);
5639             if (gp->unicode.map_size > 0)
5640               gp->unicode.map = _bdf_strdup(gp->unicode.map,
5641                                             gp->unicode.map_size);
5642             gp->encoding = i;
5643             sgp++;
5644             dw = (double) gp->dwidth;
5645             gp->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
5646         } else if (enc == gp->encoding) {
5647             _bdf_combine_glyphs(font, gp, sgp);
5648             dw = (double) gp->dwidth;
5649             gp->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
5650             sgp++;
5651         }
5652         if (gp->encoding == i)
5653           gp++;
5654     }
5655 
5656     if (resize)
5657       (void) memcpy((char *) &font->bbx, (char *) &nbbx, sizeof(bdf_bbx_t));
5658 
5659     font->modified = 1;
5660 
5661     return resize;
5662 }
5663 
5664 void
bdf_set_modified(bdf_font_t * font,int modified)5665 bdf_set_modified(bdf_font_t *font, int modified)
5666 {
5667     if (font == 0 || font->modified == modified)
5668       return;
5669 
5670     if (modified == 0) {
5671         /*
5672          * Clear out the modified bitmaps.
5673          */
5674         (void) memset((char *) font->nmod, 0, sizeof(unsigned int) * 2048);
5675         (void) memset((char *) font->umod, 0, sizeof(unsigned int) * 2048);
5676     }
5677     font->modified = modified;
5678 }
5679 
5680 /**************************************************************************
5681  *
5682  * XLFD font name functions.
5683  *
5684  **************************************************************************/
5685 
5686 static char *xlfdfields[] = {
5687     "FOUNDRY",
5688     "FAMILY_NAME",
5689     "WEIGHT_NAME",
5690     "SLANT",
5691     "SETWIDTH_NAME",
5692     "ADD_STYLE_NAME",
5693     "PIXEL_SIZE",
5694     "POINT_SIZE",
5695     "RESOLUTION_X",
5696     "RESOLUTION_Y",
5697     "SPACING",
5698     "AVERAGE_WIDTH",
5699     "CHARSET_REGISTRY",
5700     "CHARSET_ENCODING",
5701 };
5702 
5703 int
bdf_is_xlfd_property(char * name)5704 bdf_is_xlfd_property(char *name)
5705 {
5706     int i;
5707 
5708     for (i = 0; i < 14; i++) {
5709         if (strcmp(name, xlfdfields[i]) == 0)
5710           return 1;
5711     }
5712     return 0;
5713 }
5714 
5715 int
bdf_has_xlfd_name(bdf_font_t * font)5716 bdf_has_xlfd_name(bdf_font_t *font)
5717 {
5718     unsigned int len;
5719     char name[256];
5720     _bdf_list_t list;
5721 
5722     if (font == 0 || font->name == 0 || font->name[0] == 0)
5723       return 0;
5724 
5725     len = (unsigned int) (strlen(font->name) + 1);
5726     (void) memcpy(name, font->name, len);
5727     list.size = list.used = 0;
5728     _bdf_split("-", name, len, &list);
5729     if (list.size > 0)
5730       free((char *) list.field);
5731 
5732     return (list.used == 15);
5733 }
5734 
5735 char *
bdf_make_xlfd_name(bdf_font_t * font,char * foundry,char * family)5736 bdf_make_xlfd_name(bdf_font_t *font, char *foundry, char *family)
5737 {
5738     int len;
5739     double dp, dr;
5740     unsigned int i, width, used;
5741     unsigned short awidth, pxsize;
5742     bdf_property_t *pp;
5743     bdf_glyph_t *gp;
5744     char spacing, *name, *val, *np, nbuf[256];
5745 
5746     if (font == 0 || bdf_has_xlfd_name(font))
5747       return 0;
5748 
5749     np = nbuf;
5750 
5751     /*
5752      * Add the FOUNDRY field.
5753      */
5754     if ((pp = bdf_get_font_property(font, "FOUNDRY")) != 0)
5755       foundry = pp->value.atom;
5756     sprintf(np, "-%s", foundry);
5757     np += strlen(np);
5758 
5759     /*
5760      * Add the FAMILY_NAME field.
5761      */
5762     if ((pp = bdf_get_font_property(font, "FAMILY_NAME")) != 0)
5763       family = pp->value.atom;
5764     sprintf(np, "-%s", family);
5765     np += strlen(np);
5766 
5767     /*
5768      * Add the WEIGHT_NAME field.
5769      */
5770     val = ((pp = bdf_get_font_property(font, "WEIGHT_NAME")) != 0) ?
5771         pp->value.atom : "Medium";
5772     if (val == 0)
5773       val = "Medium";
5774     sprintf(np, "-%s", val);
5775     np += strlen(np);
5776 
5777     /*
5778      * Add the SLANT field.
5779      */
5780     val = ((pp = bdf_get_font_property(font, "SLANT")) != 0) ?
5781         pp->value.atom : "R";
5782     if (val == 0)
5783       val = "R";
5784     sprintf(np, "-%s", val);
5785     np += strlen(np);
5786 
5787     /*
5788      * Add the SETWIDTH_NAME field.
5789      */
5790     val = ((pp = bdf_get_font_property(font, "SETWIDTH_NAME")) != 0) ?
5791         pp->value.atom : "Normal";
5792     if (val == 0)
5793       val = "Normal";
5794     sprintf(np, "-%s", val);
5795     np += strlen(np);
5796 
5797     /*
5798      * Add the ADD_STYLE_NAME field.
5799      */
5800     val = ((pp = bdf_get_font_property(font, "ADD_STYLE_NAME")) != 0) ?
5801         pp->value.atom : "";
5802     if (val == 0)
5803       val = "";
5804     sprintf(np, "-%s", val);
5805     np += strlen(np);
5806 
5807     /*
5808      * Add the PIXEL_SIZE field.
5809      */
5810     if ((pp = bdf_get_font_property(font, "PIXEL_SIZE")) != 0)
5811       sprintf(np, "-%d", pp->value.int32);
5812     else {
5813         /*
5814          * Determine the pixel size.
5815          */
5816         dp = (double) (font->point_size * 10);
5817         dr = (double) font->resolution_y;
5818         pxsize = (unsigned short) (((dp * dr) / 722.7) + 0.5);
5819         sprintf(np, "-%hd", pxsize);
5820     }
5821     np += strlen(np);
5822 
5823     /*
5824      * Add the POINT_SIZE field.
5825      */
5826     if ((pp = bdf_get_font_property(font, "POINT_SIZE")) != 0)
5827       sprintf(np, "-%d", pp->value.int32);
5828     else
5829       sprintf(np, "-%d", font->point_size * 10);
5830     np += strlen(np);
5831 
5832     /*
5833      * Add the RESOLUTION_X field.
5834      */
5835     if ((pp = bdf_get_font_property(font, "RESOLUTION_X")) != 0)
5836       sprintf(np, "-%d", pp->value.card32);
5837     else
5838       sprintf(np, "-%d", font->resolution_x);
5839     np += strlen(np);
5840 
5841     /*
5842      * Add the RESOLUTION_Y field.
5843      */
5844     if ((pp = bdf_get_font_property(font, "RESOLUTION_Y")) != 0)
5845       sprintf(np, "-%d", pp->value.card32);
5846     else
5847       sprintf(np, "-%d", font->resolution_y);
5848     np += strlen(np);
5849 
5850     /*
5851      * Add the SPACING field.
5852      */
5853     if ((pp = bdf_get_font_property(font, "SPACING")) != 0)
5854       spacing = pp->value.atom[0];
5855     else {
5856         spacing = 'P';
5857         switch (font->spacing) {
5858           case BDF_PROPORTIONAL: spacing = 'P'; break;
5859           case BDF_MONOWIDTH: spacing = 'M'; break;
5860           case BDF_CHARCELL: spacing = 'C'; break;
5861         }
5862     }
5863     sprintf(np, "-%c", spacing);
5864     np += strlen(np);
5865 
5866     /*
5867      * Add the AVERAGE_WIDTH field.
5868      */
5869     if ((pp = bdf_get_font_property(font, "AVERAGE_WIDTH")) != 0)
5870       sprintf(np, "-%d", pp->value.int32);
5871     else {
5872         /*
5873          * Determine the average width of all the glyphs in the font.
5874          */
5875         width = 0;
5876         for (i = 0, gp = font->unencoded; i < font->unencoded_used; i++, gp++)
5877           width += gp->dwidth;
5878         for (i = 0, gp = font->glyphs; i < font->glyphs_used; i++, gp++)
5879           width += gp->dwidth;
5880 
5881         used = font->unencoded_used + font->glyphs_used;
5882         if (used == 0)
5883           awidth = font->bbx.width * 10;
5884         else
5885           awidth = (unsigned short) ((((float) width) /
5886                                       ((float) used)) * 10.0);
5887         sprintf(np, "-%hd", awidth);
5888     }
5889     np += strlen(np);
5890 
5891     /*
5892      * Add the CHARSET_REGISTRY field.
5893      */
5894     val = ((pp = bdf_get_font_property(font, "CHARSET_REGISTRY")) != 0) ?
5895         pp->value.atom : "FontSpecific";
5896     sprintf(np, "-%s", val);
5897     np += strlen(np);
5898 
5899     /*
5900      * Add the CHARSET_ENCODING field.
5901      */
5902     val = ((pp = bdf_get_font_property(font, "CHARSET_ENCODING")) != 0) ?
5903         pp->value.atom : "0";
5904     sprintf(np, "-%s", val);
5905     np += strlen(np);
5906 
5907     len = (np - nbuf) + 1;
5908     name = (char *) malloc(len);
5909     (void) memcpy(name, nbuf, len);
5910     return name;
5911 }
5912 
5913 void
bdf_update_name_from_properties(bdf_font_t * font)5914 bdf_update_name_from_properties(bdf_font_t *font)
5915 {
5916     unsigned int i;
5917     bdf_property_t *p;
5918     _bdf_list_t list;
5919     char *np, name[128], nname[128];
5920 
5921     if (font == 0 || bdf_has_xlfd_name(font) == 0)
5922       return;
5923 
5924     (void) memset((char *) &list, 0, sizeof(_bdf_list_t));
5925 
5926     /*
5927      * Split the name into fields and shift out the first empty field.
5928      * This assumes that the font has a name.
5929      */
5930     i = (unsigned int) strlen(font->name);
5931     (void) memcpy(name, font->name, i + 1);
5932     _bdf_split("-", name, i, &list);
5933     _bdf_shift(1, &list);
5934 
5935     /*
5936      * Initialize the pointer to the new name and add the '-' prefix.
5937      */
5938     np = nname;
5939     *np++ = '-';
5940     *np = 0;
5941 
5942     for (i = 0; i < 14; i++) {
5943         if ((p = bdf_get_font_property(font, xlfdfields[i])) != 0) {
5944             /*
5945              * The property exists, so add it to the new font name.
5946              */
5947             switch (p->format) {
5948               case BDF_ATOM:
5949                 if (p->value.atom != 0)
5950                   sprintf(np, "%s", p->value.atom);
5951                 break;
5952               case BDF_CARDINAL:
5953                 sprintf(np, "%d", p->value.card32);
5954                 break;
5955               case BDF_INTEGER:
5956                 sprintf(np, "%d", p->value.int32);
5957                 break;
5958             }
5959         } else
5960           /*
5961            * The property does not exist, so add the original value to the
5962            * new font name.
5963            */
5964           sprintf(np, "%s", list.field[i]);
5965         np += strlen(np);
5966         if (i + 1 < 14) {
5967             *np++ = '-';
5968             *np = 0;
5969         }
5970     }
5971 
5972     /*
5973      * Replace the existing font name with the new one.
5974      */
5975     free(font->name);
5976     i = (unsigned int) (strlen(nname) + 1);
5977     font->name = (char *) malloc(i);
5978     (void) memcpy(font->name, nname, i);
5979 
5980     /*
5981      * Free up the list.
5982      */
5983     if (list.size > 0)
5984       free((char *) list.field);
5985 
5986     font->modified = 1;
5987 }
5988 
5989 int
bdf_update_properties_from_name(bdf_font_t * font)5990 bdf_update_properties_from_name(bdf_font_t *font)
5991 {
5992     unsigned int i;
5993     bdf_property_t *p, prop;
5994     _bdf_list_t list;
5995     char name[128];
5996 
5997     if (font == 0 || font->name == 0 || bdf_has_xlfd_name(font) == 0)
5998       return 0;
5999 
6000     (void) memset((char *) &list, 0, sizeof(_bdf_list_t));
6001 
6002     /*
6003      * Split the name into fields and shift out the first empty field.
6004      */
6005     i = (unsigned int) strlen(font->name);
6006     (void) memcpy(name, font->name, i + 1);
6007     _bdf_split("-", name, i, &list);
6008     _bdf_shift(1, &list);
6009 
6010     for (i = 0; i < 14; i++) {
6011         p = bdf_get_property(xlfdfields[i]);
6012         prop.name = p->name;
6013         prop.format = p->format;
6014         switch (prop.format) {
6015           case BDF_ATOM:
6016             prop.value.atom = list.field[i];
6017             break;
6018           case BDF_CARDINAL:
6019             prop.value.card32 = _bdf_atoul(list.field[i], 0, 10);
6020             break;
6021           case BDF_INTEGER:
6022             prop.value.int32 = _bdf_atol(list.field[i], 0, 10);
6023             break;
6024         }
6025         bdf_add_font_property(font, &prop);
6026     }
6027 
6028     /*
6029      * Free up the list.
6030      */
6031     if (list.size > 0)
6032       free((char *) list.field);
6033 
6034     font->modified = 1;
6035 
6036     return 1;
6037 }
6038 
6039 int
bdf_update_average_width(bdf_font_t * font)6040 bdf_update_average_width(bdf_font_t *font)
6041 {
6042     int changed;
6043     unsigned int i;
6044     int oaw, awidth, used;
6045     bdf_glyph_t *gp;
6046     _bdf_list_t list;
6047     bdf_property_t *pp, prop;
6048     char *np, num[16], nbuf[128];
6049 
6050     changed = 0;
6051 
6052     used = font->unencoded_used + font->glyphs_used;
6053     if (used == 0)
6054       awidth = font->bbx.width * 10;
6055     else {
6056         for (i = 0, awidth = 0, gp = font->unencoded; i < font->unencoded_used;
6057              i++, gp++)
6058           awidth += gp->dwidth;
6059         for (i = 0, gp = font->glyphs; i < font->glyphs_used; i++, gp++)
6060           awidth += gp->dwidth;
6061         awidth = (int) ((((double) awidth) / ((double) used)) * 10.0);
6062     }
6063 
6064     /*
6065      * Check to see if it is different than the average width in the font
6066      * name.
6067      */
6068     if (bdf_has_xlfd_name(font)) {
6069         (void) memset((char *) &list, 0, sizeof(_bdf_list_t));
6070         i = (unsigned int) strlen(font->name);
6071         (void) memcpy(nbuf, font->name, i + 1);
6072         _bdf_split("-", nbuf, i, &list);
6073         oaw = _bdf_atol(list.field[12], 0, 10);
6074         if (oaw != awidth) {
6075             /*
6076              * Construct a new font name with the new average width.
6077              */
6078             changed = 1;
6079             sprintf(num, "%d", awidth);
6080             used = strlen(num) - strlen(list.field[12]);
6081             if (used > 0) {
6082                 /*
6083                  * Resize the string used for the font name instead of
6084                  * creating a new one.
6085                  */
6086                 used += i;
6087                 font->name = (char *) realloc(font->name, used);
6088             }
6089 
6090             /*
6091              * Copy the elements of the list back into the new font name.
6092              */
6093             np = font->name;
6094             *np++ = '-';
6095             for (i = 1; i < list.used; i++) {
6096                 if (i == 12)
6097                   strcpy(np, num);
6098                 else
6099                   strcpy(np, list.field[i]);
6100                 np += strlen(np);
6101                 if (i + 1 < list.used)
6102                   *np++ = '-';
6103             }
6104         }
6105 
6106         /*
6107          * Clear up any space allocated for the list.
6108          */
6109         if (list.size > 0)
6110           free((char *) list.field);
6111     }
6112 
6113     /*
6114      * Now check for the AVERAGE_WIDTH property.
6115      */
6116     if ((pp = bdf_get_font_property(font, "AVERAGE_WIDTH")) != 0) {
6117         if (pp->value.int32 != awidth) {
6118             changed = 1;
6119             pp->value.int32 = awidth;
6120         }
6121     } else {
6122         /*
6123          * Property doesn't exist yet, so add it.
6124          */
6125         changed = 1;
6126         prop.name = "AVERAGE_WIDTH";
6127         prop.format = BDF_INTEGER;
6128         prop.value.int32 = awidth;
6129         bdf_add_font_property(font, &prop);
6130     }
6131 
6132     if (changed)
6133       font->modified = 1;
6134 
6135     return changed;
6136 }
6137 
6138 /*
6139  * Change the font bounding box and return a non-zero number if this causes
6140  * the font to get larger or smaller.
6141  */
6142 int
bdf_set_font_bbx(bdf_font_t * font,bdf_metrics_t * metrics)6143 bdf_set_font_bbx(bdf_font_t *font, bdf_metrics_t *metrics)
6144 {
6145     int resize;
6146 
6147     resize = 0;
6148 
6149     if (font == 0 || metrics == 0)
6150       return resize;
6151 
6152     resize = (font->bbx.width != metrics->width ||
6153               font->bbx.height != metrics->height) ? 1 : 0;
6154 
6155     font->bbx.width = metrics->width;
6156     font->bbx.height = metrics->height;
6157     font->bbx.x_offset = metrics->x_offset;
6158     font->bbx.y_offset = metrics->y_offset;
6159     font->bbx.ascent = metrics->ascent;
6160     font->bbx.descent = metrics->descent;
6161 
6162     /*
6163      * If the font is not proportional, then make sure the monowidth field is
6164      * set to the font bounding box.
6165      */
6166     if (font->spacing != BDF_PROPORTIONAL)
6167       font->monowidth = font->bbx.width;
6168 
6169     return resize;
6170 }
6171 
6172 int
bdf_translate_glyphs(bdf_font_t * font,short dx,short dy,int start,int end,bdf_callback_t callback,void * data,int unencoded)6173 bdf_translate_glyphs(bdf_font_t *font, short dx, short dy, int start,
6174                      int end, bdf_callback_t callback, void *data,
6175                      int unencoded)
6176 {
6177     int resize, diff;
6178     bdf_glyph_t *gp, *sp, *ep;
6179     bdf_callback_struct_t cb;
6180 
6181     if (font == 0 || (dx == 0 && dy == 0))
6182       return 0;
6183 
6184     if ((unencoded && font->unencoded_used == 0) || font->glyphs_used == 0)
6185       return 0;
6186 
6187     /*
6188      * Call the progress initialization callback.
6189      */
6190     if (callback != 0) {
6191         cb.reason = BDF_TRANSLATE_START;
6192         cb.total = (end - start) + 1;
6193         cb.current = 0;
6194         (*callback)(&cb, data);
6195     }
6196 
6197     /*
6198      * Locate the first and last glyphs to be shifted.
6199      */
6200     sp = _bdf_locate_glyph(font, start, unencoded);
6201     ep = _bdf_locate_glyph(font, end, unencoded);
6202     for (resize = 0, gp = sp; sp <= ep; sp++) {
6203         /*
6204          * Call the callback if one was provided.
6205          */
6206         if (sp != gp && callback != 0) {
6207             cb.reason = BDF_TRANSLATING;
6208             cb.current = (sp->encoding - start) + 1;
6209             (*callback)(&cb, data);
6210         }
6211 
6212         /*
6213          * Apply the X translation.
6214          */
6215         if (dx != 0) {
6216             sp->bbx.x_offset += dx;
6217             diff = sp->bbx.x_offset - font->bbx.x_offset;
6218             if (sp->bbx.x_offset < font->bbx.x_offset) {
6219                 font->bbx.x_offset = sp->bbx.x_offset;
6220                 font->bbx.width += MYABS(diff);
6221                 resize = 1;
6222             } else if (sp->bbx.width + sp->bbx.x_offset >
6223                        font->bbx.width + font->bbx.x_offset) {
6224                 font->bbx.width += MYABS(diff);
6225                 resize = 1;
6226             }
6227 
6228             /*
6229              * Mark the glyph as modified appropriately.
6230              */
6231             if (unencoded)
6232               _bdf_set_glyph_modified(font->umod, sp->encoding);
6233             else
6234               _bdf_set_glyph_modified(font->nmod, sp->encoding);
6235         }
6236 
6237         /*
6238          * Apply the Y translation.
6239          */
6240         if (dy != 0) {
6241             sp->bbx.y_offset += dy;
6242             sp->bbx.descent = -sp->bbx.y_offset;
6243             sp->bbx.ascent = sp->bbx.height - sp->bbx.descent;
6244             diff = sp->bbx.y_offset - font->bbx.y_offset;
6245             if (sp->bbx.y_offset < font->bbx.y_offset) {
6246                 font->bbx.y_offset = sp->bbx.y_offset;
6247                 font->bbx.descent = -font->bbx.y_offset;
6248                 font->bbx.height += MYABS(diff);
6249                 resize = 1;
6250             } else if (sp->bbx.ascent > font->bbx.ascent) {
6251                 font->bbx.ascent += MYABS(diff);
6252                 font->bbx.height += MYABS(diff);
6253                 resize = 1;
6254             }
6255 
6256             /*
6257              * Mark the glyph as modified appropriately.
6258              */
6259             if (unencoded)
6260               _bdf_set_glyph_modified(font->umod, sp->encoding);
6261             else
6262               _bdf_set_glyph_modified(font->nmod, sp->encoding);
6263         }
6264     }
6265 
6266     /*
6267      * Call the callback one more time to make sure the client knows
6268      * this is done.
6269      */
6270     if (callback != 0 && cb.current < cb.total) {
6271         cb.reason = BDF_TRANSLATING;
6272         cb.current = cb.total;
6273         (*callback)(&cb, data);
6274     }
6275 
6276     if (resize)
6277       font->modified = 1;
6278 
6279     return resize;
6280 }
6281 
6282 static void
_bdf_resize_rotation(bdf_font_t * font,int mul90,short degrees,bdf_glyph_t * glyph,bdf_bitmap_t * scratch,unsigned short * width,unsigned short * height)6283 _bdf_resize_rotation(bdf_font_t *font, int mul90, short degrees,
6284                      bdf_glyph_t *glyph, bdf_bitmap_t *scratch,
6285                      unsigned short *width, unsigned short *height)
6286 {
6287     unsigned short w, h, wd, ht, bytes;
6288     short cx, cy, x1, y1, x2, y2;
6289     double dx1, dy1, dx2, dy2;
6290 
6291     w = h = 0;
6292 
6293     cx = glyph->bbx.width >> 1;
6294     cy = glyph->bbx.height >> 1;
6295 
6296     /*
6297      * Rotate the lower left and upper right corners and check for a potential
6298      * resize.
6299      */
6300     x1 = 0;
6301     y1 = glyph->bbx.height;
6302     x2 = glyph->bbx.width;
6303     y2 = 0;
6304 
6305     dx1 = (double) (x1 - cx);
6306     dy1 = (double) (y1 - cy);
6307     dx2 = (double) (x2 - cx);
6308     dy2 = (double) (y2 - cx);
6309 
6310     if (mul90) {
6311         x1 = cx + (short) ((dx1 * _bdf_cos_tbl[degrees]) -
6312                            (dy1 * _bdf_sin_tbl[degrees]));
6313         y1 = cy + (short) ((dx1 * _bdf_sin_tbl[degrees]) +
6314                            (dy1 * _bdf_cos_tbl[degrees]));
6315         x2 = cx + (short) ((dx2 * _bdf_cos_tbl[degrees]) -
6316                            (dy2 * _bdf_sin_tbl[degrees]));
6317         y2 = cy + (short) ((dx2 * _bdf_sin_tbl[degrees]) +
6318                            (dy2 * _bdf_cos_tbl[degrees]));
6319     } else {
6320         x1 = cx + _bdf_ceiling((dx1 * _bdf_cos_tbl[degrees]) -
6321                                (dy1 * _bdf_sin_tbl[degrees]));
6322         y1 = cy + _bdf_ceiling((dx1 * _bdf_sin_tbl[degrees]) +
6323                                (dy1 * _bdf_cos_tbl[degrees]));
6324         x2 = cx + _bdf_ceiling((dx2 * _bdf_cos_tbl[degrees]) -
6325                                (dy2 * _bdf_sin_tbl[degrees]));
6326         y2 = cy + _bdf_ceiling((dx2 * _bdf_sin_tbl[degrees]) +
6327                                (dy2 * _bdf_cos_tbl[degrees]));
6328     }
6329 
6330     wd = MYABS(x2 - x1);
6331     ht = MYABS(y2 - y1);
6332 
6333     w = MAX(wd, w);
6334     h = MAX(ht, h);
6335 
6336     if (wd > font->bbx.width)
6337       font->bbx.width += wd - font->bbx.width;
6338     if (ht > font->bbx.height) {
6339         font->bbx.ascent += ht - font->bbx.height;
6340         font->bbx.height += ht - font->bbx.height;
6341     }
6342 
6343     /*
6344      * Rotate the upper left and lower right corners and check for a potential
6345      * resize.
6346      */
6347     x1 = 0;
6348     y1 = 0;
6349     x2 = glyph->bbx.width;
6350     y2 = glyph->bbx.height;
6351 
6352     dx1 = (double) (x1 - cx);
6353     dy1 = (double) (y1 - cy);
6354     dx2 = (double) (x2 - cx);
6355     dy2 = (double) (y2 - cx);
6356 
6357     if (mul90) {
6358         x1 = cx + (short) ((dx1 * _bdf_cos_tbl[degrees]) -
6359                            (dy1 * _bdf_sin_tbl[degrees]));
6360         y1 = cy + (short) ((dx1 * _bdf_sin_tbl[degrees]) +
6361                            (dy1 * _bdf_cos_tbl[degrees]));
6362         x2 = cx + (short) ((dx2 * _bdf_cos_tbl[degrees]) -
6363                            (dy2 * _bdf_sin_tbl[degrees]));
6364         y2 = cy + (short) ((dx2 * _bdf_sin_tbl[degrees]) +
6365                            (dy2 * _bdf_cos_tbl[degrees]));
6366     } else {
6367         x1 = cx + _bdf_ceiling((dx1 * _bdf_cos_tbl[degrees]) -
6368                                (dy1 * _bdf_sin_tbl[degrees]));
6369         y1 = cy + _bdf_ceiling((dx1 * _bdf_sin_tbl[degrees]) +
6370                                (dy1 * _bdf_cos_tbl[degrees]));
6371         x2 = cx + _bdf_ceiling((dx2 * _bdf_cos_tbl[degrees]) -
6372                                (dy2 * _bdf_sin_tbl[degrees]));
6373         y2 = cy + _bdf_ceiling((dx2 * _bdf_sin_tbl[degrees]) +
6374                                (dy2 * _bdf_cos_tbl[degrees]));
6375     }
6376 
6377     wd = MYABS(x2 - x1);
6378     ht = MYABS(y2 - y1);
6379 
6380     w = MAX(wd, w);
6381     h = MAX(ht, h);
6382 
6383     if (wd > font->bbx.width)
6384       font->bbx.width += wd - font->bbx.width;
6385     if (ht > font->bbx.height) {
6386         font->bbx.ascent += ht - font->bbx.height;
6387         font->bbx.height += ht - font->bbx.height;
6388     }
6389 
6390     if (font->bbx.width > scratch->width ||
6391         font->bbx.height > scratch->height) {
6392         scratch->width = MAX(font->bbx.width, scratch->width);
6393         scratch->height = MAX(font->bbx.height, scratch->height);
6394         bytes = (((font->bbx.width * font->bpp) + 7) >> 3) * font->bbx.height;
6395         if (scratch->bytes == 0)
6396           scratch->bitmap = (unsigned char *) malloc(bytes);
6397         else
6398           scratch->bitmap = (unsigned char *)
6399               realloc((char *) scratch->bitmap, bytes);
6400         scratch->bytes = bytes;
6401     }
6402 
6403     /*
6404      * Clear the bitmap.
6405      */
6406     (void) memset((char *) scratch->bitmap, 0, scratch->bytes);
6407 
6408     /*
6409      * Return the new glyph width and height.
6410      */
6411     *width = w;
6412     *height = h;
6413 }
6414 
6415 int
bdf_rotate_glyphs(bdf_font_t * font,short degrees,int start,int end,bdf_callback_t callback,void * data,int unencoded)6416 bdf_rotate_glyphs(bdf_font_t *font, short degrees, int start,
6417                   int end, bdf_callback_t callback, void *data,
6418                   int unencoded)
6419 {
6420     int mul90, bpr, sbpr;
6421     unsigned short wd, ht, si, di, byte, col;
6422     short x, y, cx, cy, nx, ny, ox, oy, shiftx, shifty;
6423     bdf_glyph_t *gp, *sp, *ep;
6424     unsigned char *masks;
6425     double dx, dy;
6426     bdf_bitmap_t scratch;
6427     bdf_callback_struct_t cb;
6428 
6429     if (font == 0 ||
6430         (unencoded && font->unencoded_used == 0) ||
6431         font->glyphs_used == 0 ||
6432         degrees == 0)
6433       return 0;
6434 
6435     while (degrees < 0)
6436       degrees += 360;
6437     while (degrees >= 360)
6438       degrees -= 360;
6439 
6440     mul90 = ((degrees % 90) == 0) ? 1 : 0;
6441 
6442     masks = 0;
6443     switch (font->bpp) {
6444       case 1: masks = bdf_onebpp; break;
6445       case 2: masks = bdf_twobpp; break;
6446       case 4: masks = bdf_fourbpp; break;
6447       case 8: masks = bdf_eightbpp; break;
6448     }
6449 
6450     /*
6451      * Initialize the scratch bitmap.
6452      */
6453     (void) memset((char *) &scratch, 0, sizeof(bdf_bitmap_t));
6454 
6455     /*
6456      * Call the progress initialization callback.
6457      */
6458     if (callback != 0) {
6459         cb.reason = BDF_ROTATE_START;
6460         cb.total = (end - start) + 1;
6461         cb.current = 0;
6462         (*callback)(&cb, data);
6463     }
6464 
6465     sp = _bdf_locate_glyph(font, start, unencoded);
6466     ep = _bdf_locate_glyph(font, end, unencoded);
6467     for (gp = sp; sp <= ep; sp++) {
6468         /*
6469          * Call the callback if one was provided.
6470          */
6471         if (sp != gp && callback != 0) {
6472             cb.reason = BDF_ROTATING;
6473             cb.current = (sp->encoding - start) + 1;
6474             (*callback)(&cb, data);
6475         }
6476 
6477         /*
6478          * Resize the bitmap, adjust the font bounding box, and get the new
6479          * glyph width and height.
6480          */
6481         _bdf_resize_rotation(font, mul90, degrees, sp, &scratch, &wd, &ht);
6482 
6483         cx = sp->bbx.width >> 1;
6484         cy = sp->bbx.height >> 1;
6485 
6486         shiftx = shifty = 0;
6487         sbpr = ((wd * font->bpp) + 7) >> 3;
6488         bpr = ((sp->bbx.width * font->bpp) + 7) >> 3;
6489         for (y = 0; y < sp->bbx.height; y++) {
6490             for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) {
6491                 si = (col & 7) / font->bpp;
6492                 byte = sp->bitmap[(y * bpr) + (col >> 3)] & masks[si];
6493                 if (byte) {
6494                     dx = (double) (x - cx);
6495                     dy = (double) (y - cy);
6496                     if (mul90) {
6497                         nx = cx + (short) ((dx * _bdf_cos_tbl[degrees]) -
6498                                            (dy * _bdf_sin_tbl[degrees]));
6499                         ny = cy + (short) ((dx * _bdf_sin_tbl[degrees]) +
6500                                            (dy * _bdf_cos_tbl[degrees]));
6501                     } else {
6502                         nx = cx + _bdf_ceiling((dx * _bdf_cos_tbl[degrees]) -
6503                                                (dy * _bdf_sin_tbl[degrees]));
6504                         ny = cy + _bdf_ceiling((dx * _bdf_sin_tbl[degrees]) +
6505                                                (dy * _bdf_cos_tbl[degrees]));
6506                     }
6507                     if (nx < 0) {
6508                         shiftx = MIN(shiftx, nx);
6509                         nx += wd;
6510                     } else if (nx >= wd) {
6511                         ox = (nx - wd) + 1;
6512                         shiftx = MAX(shiftx, ox);
6513                         nx -= wd;
6514                     }
6515                     if (ny < 0) {
6516                         shifty = MIN(shifty, ny);
6517                         ny += ht;
6518                     } else if (ny >= ht) {
6519                         oy = (ny - ht) + 1;
6520                         shifty = MAX(shifty, oy);
6521                         ny -= ht;
6522                     }
6523                     nx *= font->bpp;
6524                     di = (nx & 7) / font->bpp;
6525                     if (di < si)
6526                       byte <<= (si - di) * font->bpp;
6527                     else if (di > si)
6528                       byte >>= (di - si) * font->bpp;
6529                     scratch.bitmap[(ny * sbpr) + (nx >> 3)] |= byte;
6530                 }
6531             }
6532         }
6533         /*
6534          * Resize the glyph bitmap if necessary.
6535          */
6536         if (wd != sp->bbx.width || ht != sp->bbx.height) {
6537             sp->bbx.width = wd;
6538             sp->bbx.height = ht;
6539             sp->bbx.ascent = ht - sp->bbx.descent;
6540             sp->bytes = (((wd * font->bpp) + 7) >> 3) * ht;
6541             sp->bitmap = (unsigned char *)
6542                 realloc((char *) sp->bitmap, sp->bytes);
6543         }
6544         (void) memset((char *) sp->bitmap, 0, sp->bytes);
6545 
6546         /*
6547          * Copy the glyph from the scratch area to the glyph bitmap,
6548          * adjusting for any shift values encountered.
6549          */
6550         bpr = ((sp->bbx.width * font->bpp) + 7) >> 3;
6551         for (y = 0; y < sp->bbx.height; y++) {
6552             for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) {
6553                 si = (col & 7) / font->bpp;
6554                 byte = scratch.bitmap[(y * bpr) + (col >> 3)] & masks[si];
6555                 if (byte) {
6556                     nx = x - shiftx;
6557                     ny = y - shifty;
6558                     if (nx < 0)
6559                       nx += sp->bbx.width;
6560                     else if (nx >= sp->bbx.width)
6561                       nx -= sp->bbx.width;
6562                     if (ny < 0)
6563                       ny += sp->bbx.height;
6564                     else if (ny >= sp->bbx.height)
6565                       ny -= sp->bbx.height;
6566                     nx *= font->bpp;
6567                     di = (nx & 7) / font->bpp;
6568                     if (di < si)
6569                       byte <<= (si - di) * font->bpp;
6570                     else if (di > si)
6571                       byte >>= (di - si) * font->bpp;
6572                     sp->bitmap[(ny * bpr) + (nx >> 3)] |= byte;
6573                 }
6574             }
6575         }
6576         /*
6577          * Mark the glyph as modified.
6578          */
6579         if (unencoded)
6580           _bdf_set_glyph_modified(font->umod, sp->encoding);
6581         else
6582           _bdf_set_glyph_modified(font->nmod, sp->encoding);
6583     }
6584 
6585     /*
6586      * Call the callback one more time to make sure the client knows
6587      * this is done.
6588      */
6589     if (callback != 0 && cb.current < cb.total) {
6590         cb.reason = BDF_TRANSLATING;
6591         cb.current = cb.total;
6592         (*callback)(&cb, data);
6593     }
6594 
6595     if (scratch.bytes > 0)
6596       free((char *) scratch.bitmap);
6597 
6598     /*
6599      * Rotations always change things, so just return a value indicating this.
6600      */
6601     font->modified = 1;
6602     return 1;
6603 }
6604 
6605 static void
_bdf_resize_shear(bdf_font_t * font,int neg,short degrees,bdf_glyph_t * glyph,bdf_bitmap_t * scratch,unsigned short * width,unsigned short * height)6606 _bdf_resize_shear(bdf_font_t *font, int neg, short degrees,
6607                   bdf_glyph_t *glyph, bdf_bitmap_t *scratch,
6608                   unsigned short *width, unsigned short *height)
6609 {
6610     unsigned short wd, w, bytes;
6611     short x1, y1, x2, y2;
6612 
6613     w = 0;
6614     *height = glyph->bbx.height;
6615 
6616     /*
6617      * Shear the lower left and upper right corners and check for a potential
6618      * resize.
6619      */
6620     x1 = 0;
6621     y1 = glyph->bbx.height;
6622     x2 = glyph->bbx.width;
6623     y2 = 0;
6624 
6625     if (neg) {
6626         x1 += (short) ((double) y1 * _bdf_tan_tbl[degrees]);
6627         x2 += (short) ((double) y2 * _bdf_tan_tbl[degrees]);
6628     } else {
6629         x1 += (short) ((double) (glyph->bbx.height - y1) *
6630                        _bdf_tan_tbl[degrees]);
6631         x2 += (short) ((double) (glyph->bbx.height - y2) *
6632                        _bdf_tan_tbl[degrees]);
6633     }
6634 
6635     wd = MYABS(x2 - x1);
6636     w = MAX(w, wd);
6637 
6638     if (wd > font->bbx.width)
6639       font->bbx.width += wd - font->bbx.width;
6640 
6641     /*
6642      * Shear the upper left and lower right corners and check for a potential
6643      * resize.
6644      */
6645     x1 = 0;
6646     y1 = 0;
6647     x2 = glyph->bbx.width;
6648     y2 = glyph->bbx.height;
6649 
6650     if (neg) {
6651         x1 += (short) ((double) y1 * _bdf_tan_tbl[degrees]);
6652         x2 += (short) ((double) y2 * _bdf_tan_tbl[degrees]);
6653     } else {
6654         x1 += (short) ((double) (glyph->bbx.height - y1) *
6655                        _bdf_tan_tbl[degrees]);
6656         x2 += (short) ((double) (glyph->bbx.height - y2) *
6657                        _bdf_tan_tbl[degrees]);
6658     }
6659 
6660     wd = MYABS(x2 - x1);
6661     w = MAX(w, wd);
6662 
6663     if (wd > font->bbx.width)
6664       font->bbx.width += wd - font->bbx.width;
6665 
6666     if (font->bbx.width > scratch->width ||
6667         font->bbx.height > scratch->height) {
6668         scratch->width = MAX(font->bbx.width, scratch->width);
6669         scratch->height = MAX(font->bbx.height, scratch->height);
6670         bytes = (((font->bbx.width * font->bpp) + 7) >> 3) * font->bbx.height;
6671         if (scratch->bytes == 0)
6672           scratch->bitmap = (unsigned char *) malloc(bytes);
6673         else
6674           scratch->bitmap = (unsigned char *)
6675               realloc((char *) scratch->bitmap, bytes);
6676         scratch->bytes = bytes;
6677     }
6678 
6679     /*
6680      * Clear the bitmap.
6681      */
6682     (void) memset((char *) scratch->bitmap, 0, scratch->bytes);
6683 
6684     /*
6685      * Return the new glyph width.
6686      */
6687     *width = w;
6688 }
6689 
6690 int
bdf_shear_glyphs(bdf_font_t * font,short degrees,int start,int end,bdf_callback_t callback,void * data,int unencoded)6691 bdf_shear_glyphs(bdf_font_t *font, short degrees, int start,
6692                  int end, bdf_callback_t callback, void *data,
6693                  int unencoded)
6694 {
6695     int neg, bpr, sbpr;
6696     unsigned short wd, ht, si, di, byte, col;
6697     short x, y, nx, shiftx, ox;
6698     bdf_glyph_t *gp, *sp, *ep;
6699     unsigned char *masks;
6700     bdf_bitmap_t scratch;
6701     bdf_callback_struct_t cb;
6702 
6703     if (font == 0 || (unencoded && font->unencoded_used == 0) ||
6704         font->glyphs_used == 0)
6705       return 0;
6706 
6707     if (degrees == 0 || degrees < -45 || degrees > 45)
6708       return 0;
6709 
6710     if ((neg = (degrees < 0)))
6711       degrees = -degrees;
6712 
6713     masks = 0;
6714     switch (font->bpp) {
6715       case 1: masks = bdf_onebpp; break;
6716       case 2: masks = bdf_twobpp; break;
6717       case 4: masks = bdf_fourbpp; break;
6718       case 8: masks = bdf_eightbpp; break;
6719     }
6720 
6721     /*
6722      * Initialize the scratch bitmap.
6723      */
6724     (void) memset((char *) &scratch, 0, sizeof(bdf_bitmap_t));
6725 
6726     /*
6727      * Call the progress initialization callback.
6728      */
6729     if (callback != 0) {
6730         cb.reason = BDF_SHEAR_START;
6731         cb.total = (end - start) + 1;
6732         cb.current = 0;
6733         (*callback)(&cb, data);
6734     }
6735 
6736     sp = _bdf_locate_glyph(font, start, unencoded);
6737     ep = _bdf_locate_glyph(font, end, unencoded);
6738     for (gp = sp; sp <= ep; sp++) {
6739         /*
6740          * Call the callback if one was provided.
6741          */
6742         if (sp != gp && callback != 0) {
6743             cb.reason = BDF_SHEARING;
6744             cb.current = (sp->encoding - start) + 1;
6745             (*callback)(&cb, data);
6746         }
6747 
6748         /*
6749          * Resize the bitmap, adjust the font bounding box, and get the new
6750          * glyph width and height.
6751          */
6752         _bdf_resize_shear(font, neg, degrees, sp, &scratch, &wd, &ht);
6753 
6754         shiftx = 0;
6755         sbpr = ((wd * font->bpp) + 7) >> 3;
6756         bpr = ((sp->bbx.width * font->bpp) + 7) >> 3;
6757         for (y = 0; y < sp->bbx.height; y++) {
6758             for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) {
6759                 si = (col & 7) / font->bpp;
6760                 byte = sp->bitmap[(y * bpr) + (col >> 3)] & masks[si];
6761                 if (byte) {
6762                     if (neg)
6763                       nx = x + (short) ((double) y * _bdf_tan_tbl[degrees]);
6764                     else
6765                       nx = x + (short) ((double) (sp->bbx.height - y) *
6766                                         _bdf_tan_tbl[degrees]);
6767 
6768                     if (nx < 0) {
6769                         shiftx = MIN(shiftx, nx);
6770                         nx += wd;
6771                     } else if (nx >= wd) {
6772                         ox = (nx - wd) + 1;
6773                         shiftx = MAX(shiftx, ox);
6774                         nx -= wd;
6775                     }
6776                     nx *= font->bpp;
6777                     di = (nx & 7) / font->bpp;
6778                     if (di < si)
6779                       byte <<= (si - di) * font->bpp;
6780                     else if (di > si)
6781                       byte >>= (di - si) * font->bpp;
6782                     scratch.bitmap[(y * sbpr) + (nx >> 3)] |= byte;
6783                 }
6784             }
6785         }
6786         /*
6787          * Resize the glyph bitmap if necessary.
6788          */
6789         if (wd != sp->bbx.width || ht != sp->bbx.height) {
6790             sp->bbx.width = wd;
6791             sp->bbx.height = ht;
6792             sp->bbx.ascent = ht - sp->bbx.descent;
6793             sp->bytes = (((wd * font->bpp) + 7) >> 3) * ht;
6794             sp->bitmap = (unsigned char *)
6795                 realloc((char *) sp->bitmap, sp->bytes);
6796         }
6797         (void) memset((char *) sp->bitmap, 0, sp->bytes);
6798 
6799         /*
6800          * Copy the glyph from the scratch area to the glyph bitmap,
6801          * adjusting for any shift values encountered.
6802          */
6803         bpr = ((sp->bbx.width * font->bpp) + 7) >> 3;
6804         for (y = 0; y < sp->bbx.height; y++) {
6805             for (col = x = 0; x < sp->bbx.width; x++, col += font->bpp) {
6806                 si = (col & 7) / font->bpp;
6807                 byte = scratch.bitmap[(y * bpr) + (col >> 3)] & masks[si];
6808                 if (byte) {
6809                     nx = x - shiftx;
6810                     if (nx < 0)
6811                       nx += sp->bbx.width;
6812                     else if (nx >= sp->bbx.width)
6813                       nx -= sp->bbx.width;
6814                     nx *= font->bpp;
6815                     di = (nx & 7) / font->bpp;
6816                     if (di < si)
6817                       byte <<= (si - di) * font->bpp;
6818                     else if (di > si)
6819                       byte >>= (di - si) * font->bpp;
6820                     sp->bitmap[(y * bpr) + (nx >> 3)] |= byte;
6821                 }
6822             }
6823         }
6824         /*
6825          * Mark the glyph as modified.
6826          */
6827         if (unencoded)
6828           _bdf_set_glyph_modified(font->umod, sp->encoding);
6829         else
6830           _bdf_set_glyph_modified(font->nmod, sp->encoding);
6831     }
6832 
6833     /*
6834      * Call the callback one more time to make sure the client knows
6835      * this is done.
6836      */
6837     if (callback != 0 && cb.current < cb.total) {
6838         cb.reason = BDF_TRANSLATING;
6839         cb.current = cb.total;
6840         (*callback)(&cb, data);
6841     }
6842 
6843     if (scratch.bytes > 0)
6844       free((char *) scratch.bitmap);
6845 
6846     /*
6847      * Rotations always change things, so just return a value indicating this.
6848      */
6849     font->modified = 1;
6850     return 1;
6851 }
6852 
6853 static void
_bdf_widen_by(bdf_font_t * f,bdf_glyph_t * g,bdf_bitmap_t * s,int n)6854 _bdf_widen_by(bdf_font_t *f, bdf_glyph_t *g, bdf_bitmap_t *s, int n)
6855 {
6856     int bytes, sbpr, dbpr, col;
6857     short x, y, si, di;
6858     unsigned char *bmap, *masks;
6859 
6860     masks = 0;
6861     switch (f->bpp) {
6862       case 1: masks = bdf_onebpp; break;
6863       case 2: masks = bdf_twobpp; break;
6864       case 4: masks = bdf_fourbpp; break;
6865       case 8: masks = bdf_eightbpp; break;
6866     }
6867 
6868     s->height = g->bbx.height;
6869     s->width = g->bbx.width + n;
6870 
6871     bytes = (((s->width * f->bpp) + 7) >> 3) * s->height;
6872 
6873     if (s->bytes == 0)
6874       s->bitmap = (unsigned char *) malloc(bytes);
6875     else
6876       s->bitmap = (unsigned char *)
6877           realloc((char *) s->bitmap, bytes);
6878     s->bytes = bytes;
6879 
6880     (void) memset((char *) s->bitmap, 0, s->bytes);
6881 
6882     /*
6883      * Copy the glyph bitmap to the scratch area, and then swap the bitmaps.
6884      */
6885     sbpr = ((g->bbx.width * f->bpp) + 7) >> 3;
6886     dbpr = ((s->width * f->bpp) + 7) >> 3;
6887     for (y = 0; y < g->bbx.height; y++) {
6888         for (col = x = 0; x < g->bbx.width; x++, col += f->bpp) {
6889             si = (col & 7) / f->bpp;
6890             bytes = g->bitmap[(y * sbpr) + (col >> 3)] & masks[si];
6891             if (bytes) {
6892                 di = ((x * f->bpp) & 7) / f->bpp;
6893                 if (di < si)
6894                   bytes <<= (si - di) * f->bpp;
6895                 else if (di > si)
6896                   bytes >>= (di - si) * f->bpp;
6897                 s->bitmap[(y * dbpr) + (col >> 3)] |= bytes;
6898             }
6899         }
6900     }
6901     g->bbx.width = s->width;
6902 
6903     /*
6904      * Swap the bytes and bitmap fields from the scratch area and the glyph.
6905      */
6906     bytes = g->bytes;
6907     g->bytes = s->bytes;
6908     s->bytes = bytes;
6909 
6910     bmap = g->bitmap;
6911     g->bitmap = s->bitmap;
6912     s->bitmap = bmap;
6913 }
6914 
6915 int
bdf_embolden_glyphs(bdf_font_t * font,int start,int end,bdf_callback_t callback,void * data,int unencoded,int * resize)6916 bdf_embolden_glyphs(bdf_font_t *font, int start, int end,
6917                     bdf_callback_t callback, void *data, int unencoded,
6918                     int *resize)
6919 {
6920     int mod, gmod, bpr;
6921     short x, y;
6922     unsigned short si, di, b1, b2, col;
6923     unsigned char *masks;
6924     bdf_glyph_t *gp, *sp, *ep;
6925     bdf_bitmap_t scratch;
6926     bdf_callback_struct_t cb;
6927 
6928     if (font == 0 || (unencoded && font->unencoded_used == 0) ||
6929         font->glyphs_used == 0)
6930       return 0;
6931 
6932     /*
6933      * Initialize the scratch bitmap which may be needed.
6934      */
6935     (void) memset((char *) &scratch, 0, sizeof(bdf_bitmap_t));
6936 
6937     mod = 0;
6938     gp = 0;
6939 
6940     masks = 0;
6941     switch (font->bpp) {
6942       case 1: masks = bdf_onebpp; break;
6943       case 2: masks = bdf_twobpp; break;
6944       case 4: masks = bdf_fourbpp; break;
6945       case 8: masks = bdf_eightbpp; break;
6946     }
6947 
6948     /*
6949      * Call the progress initialization callback.
6950      */
6951     if (callback != 0) {
6952         cb.reason = BDF_EMBOLDEN_START;
6953         cb.total = (end - start) + 1;
6954         cb.current = 0;
6955         (*callback)(&cb, data);
6956     }
6957 
6958     /*
6959      * Initialize the resize flag for the caller.
6960      */
6961     *resize = 0;
6962 
6963     sp = _bdf_locate_glyph(font, start, unencoded);
6964     ep = _bdf_locate_glyph(font, end, unencoded);
6965     for (; sp <= ep; sp++) {
6966         /*
6967          * Call the callback if one was provided.
6968          */
6969         if (sp != gp && callback != 0) {
6970             cb.reason = BDF_EMBOLDENING;
6971             cb.current = (sp->encoding - start) + 1;
6972             (*callback)(&cb, data);
6973         }
6974 
6975         if (font->spacing == BDF_PROPORTIONAL ||
6976             (font->spacing == BDF_MONOWIDTH &&
6977              sp->bbx.width < font->bbx.width)) {
6978             /*
6979              * Only widen the glyph if it is within reason.
6980              */
6981             _bdf_widen_by(font, sp, &scratch, 1);
6982 
6983             if (sp->bbx.width > font->bbx.width) {
6984                 /*
6985                  * Bump the font width up by the difference.
6986                  */
6987                 font->bbx.width += sp->bbx.width - font->bbx.width;
6988                 *resize = 1;
6989             }
6990         }
6991 
6992         gmod = 0;
6993         bpr = ((sp->bbx.width * font->bpp) + 7) >> 3;
6994         for (y = 0; y < sp->bbx.height; y++) {
6995             col = (sp->bbx.width - 1) * font->bpp;
6996             for (x = sp->bbx.width - 1; x > 0; x--, col -= font->bpp) {
6997                 si = (col & 7) / font->bpp;
6998                 di = ((col - font->bpp) & 7) / font->bpp;
6999                 b1 = (x == sp->bbx.width) ? 0 :
7000                     sp->bitmap[(y * bpr) + (col >> 3)] & masks[si];
7001                 b2 = sp->bitmap[(y * bpr) + ((col - font->bpp) >> 3)] &
7002                     masks[di];
7003                 if (!b1 && b2) {
7004                     if (di < si)
7005                       b2 >>= (si - di) * font->bpp;
7006                     else if (di > si)
7007                       b2 <<= (di - si) * font->bpp;
7008                     sp->bitmap[(y * bpr) + (col >> 3)] |= b2;
7009                     gmod = mod = 1;
7010                 }
7011             }
7012         }
7013         /*
7014          * Mark the glyph as modified.
7015          */
7016         if (gmod) {
7017             if (unencoded)
7018               _bdf_set_glyph_modified(font->umod, sp->encoding);
7019             else
7020               _bdf_set_glyph_modified(font->nmod, sp->encoding);
7021         }
7022     }
7023 
7024     /*
7025      * Call the callback one more time to make sure the client knows
7026      * this is done.
7027      */
7028     if (callback != 0 && cb.current < cb.total) {
7029         cb.reason = BDF_EMBOLDENING;
7030         cb.current = cb.total;
7031         (*callback)(&cb, data);
7032     }
7033 
7034     /*
7035      * Deallocate the scratch bitmap if necessary.
7036      */
7037     if (scratch.bytes > 0)
7038       free((char *) scratch.bitmap);
7039 
7040     font->modified = mod;
7041 
7042     return mod;
7043 }
7044 
7045 static int _endian = 1;
7046 static char *little_endian = (char *) &_endian;
7047 
7048 int
bdf_little_endian(void)7049 bdf_little_endian(void)
7050 {
7051     return *little_endian;
7052 }
7053