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