]> git.kernelconcepts.de Git - gbdfed.git/blob - bdfcons.c
Fixup several compile faults due to changes in recent distributions,
[gbdfed.git] / bdfcons.c
1 /*
2  * Copyright 2008 Department of Mathematical Sciences, New Mexico State University
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * DEPARTMENT OF MATHEMATICAL SCIENCES OR NEW MEXICO STATE UNIVERSITY BE
18  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29
30 #include "bdfP.h"
31
32 #undef MAX
33 #undef MIN
34 #define MAX(h,i) ((h) > (i) ? (h) : (i))
35 #define MIN(l,o) ((l) < (o) ? (l) : (o))
36
37 /*
38  * Header for Sun VF fonts.
39  */
40 typedef struct {
41     unsigned short mag;
42     unsigned short total_bytes;
43     unsigned short max_width;
44     unsigned short max_height;
45     unsigned short pad;
46 } vfhdr_t;
47
48 /*
49  * Character metrics data for Sun VF fonts.
50  */
51 typedef struct {
52     unsigned short offset;
53     unsigned short bytes;
54     char ascent;
55     char descent;
56     char lbearing;
57     char rbearing;
58     unsigned short dwidth;
59 } vfmetrics_t;
60
61 /**************************************************************************
62  *
63  * Support functions.
64  *
65  **************************************************************************/
66
67 static bdf_font_t *
68 _bdf_load_vfont(FILE *in, vfhdr_t *hdr, bdf_callback_t callback, void *data,
69                 int *awidth)
70 {
71     int first, ismono;
72     int i, pos;
73     bdf_font_t *fp;
74     bdf_glyph_t *gp;
75     bdf_callback_struct_t cb;
76     vfmetrics_t met, metrics[256];
77
78     /*
79      * Convert the header values to little endian if necessary.
80      */
81     if (bdf_little_endian()) {
82         hdr->total_bytes = ((hdr->total_bytes & 0xff) << 8) |
83             ((hdr->total_bytes >> 8) & 0xff);
84         hdr->max_width = ((hdr->max_width & 0xff) << 8) |
85             ((hdr->max_width >> 8) & 0xff);
86         hdr->max_height = ((hdr->max_height & 0xff) << 8) |
87             ((hdr->max_height >> 8) & 0xff);
88     }
89
90     /*
91      * The point size of the font will be the height, the resolution will
92      * default to 72dpi, and the spacing will default to proportional.
93      */
94     fp = bdf_new_font(0, (int) hdr->max_height, 72, 72, BDF_PROPORTIONAL, 1);
95
96     /*
97      * Force the bits per pixel to 1.
98      */
99     fp->bpp = 1;
100
101     /*
102      * Load the glyph metrics and set a marker to the beginning of the glyph
103      * bitmaps.
104      */
105     fread((char *) metrics, sizeof(vfmetrics_t), 256, in);
106     pos = ftell(in);
107
108     *awidth = 0;
109
110     /*
111      * Count the number of glyphs that actually exist and determine the font
112      * bounding box in the process.
113      */
114     (void) memset((char *) &met, 0, sizeof(vfmetrics_t));
115     met.lbearing = 127;
116     fp->glyphs_size = 0;
117     for (first = -1, ismono = 1, i = 0; i < 256; i++) {
118         if (metrics[i].bytes == 0)
119           continue;
120
121         if (first == -1)
122           first = i;
123
124         /*
125          * Start out by assuming the font is monowidth, but if any glyph
126          * encountered has metrics different than the first glyph defined,
127          * change that flag.  If the font is still flagged as monowidth when
128          * this loop is done, then change the font to a monowidth font.
129          */
130         if (i != first && ismono &&
131             (metrics[i].ascent != metrics[first].ascent ||
132              metrics[i].descent != metrics[first].descent ||
133              metrics[i].lbearing != metrics[first].lbearing ||
134              metrics[i].rbearing != metrics[first].rbearing))
135           ismono = 0;
136
137         /*
138          * If this is a little endian machine, convert the 16-bit values from
139          * big endian.
140          */
141         if (bdf_little_endian()) {
142             metrics[i].offset = ((metrics[i].offset & 0xff) << 8) |
143                 ((metrics[i].offset >> 8) & 0xff);
144             metrics[i].bytes = ((metrics[i].bytes & 0xff) << 8) |
145                 ((metrics[i].bytes >> 8) & 0xff);
146             metrics[i].dwidth = ((metrics[i].dwidth & 0xff) << 8) |
147                 ((metrics[i].dwidth >> 8) & 0xff);
148         }
149
150         /*
151          * Update the value used for average width calculation.
152          */
153         *awidth = *awidth + (metrics[i].rbearing - metrics[i].lbearing);
154
155         /*
156          * Increment the count of characters.
157          */
158         fp->glyphs_size++;
159
160         /*
161          * Determine the font bounding box.
162          */
163         met.ascent = MAX(met.ascent, metrics[i].ascent);
164         met.descent = MAX(met.descent, metrics[i].descent);
165         met.lbearing = MIN(met.lbearing, metrics[i].lbearing);
166         met.rbearing = MAX(met.rbearing, metrics[i].rbearing);
167     }
168
169     /*
170      * Adjust the font bounding box accordingly.
171      */
172     fp->bbx.ascent = met.ascent;
173     fp->bbx.descent = met.descent;
174     fp->bbx.width = met.rbearing + met.lbearing;
175     fp->bbx.height = met.ascent + met.descent;
176     fp->bbx.x_offset = met.lbearing;
177     fp->bbx.y_offset = -met.descent;
178
179     /*
180      * If the font is still flagged as a monowidth font, change the font
181      * spacing.  The actual SPACING property will be adjusted once this
182      * routine returns.
183      */
184     if (ismono)
185       fp->spacing = BDF_MONOWIDTH;
186
187     /*
188      * Set up to load the glyphs.
189      */
190     fp->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * fp->glyphs_size);
191     (void) memset((char *) fp->glyphs, 0,
192                   sizeof(bdf_glyph_t) * fp->glyphs_size);
193
194     /*
195      * Set the callback up.
196      */
197     if (callback != 0) {
198         cb.reason = BDF_LOAD_START;
199         cb.current = 0;
200         cb.total = fp->glyphs_size;
201         (*callback)(&cb, data);
202     }
203
204     /*
205      * Get the glyphs.
206      */
207     for (i = 0; i < 256; i++) {
208         if (metrics[i].bytes == 0)
209           continue;
210
211         /*
212          * Put the file pointer back at the beginning of the bitmaps.
213          */
214         fseek(in, pos, 0L);
215
216         gp = fp->glyphs + fp->glyphs_used++;
217
218         gp->encoding = i;
219         gp->dwidth = metrics[i].dwidth;
220         gp->swidth = (unsigned short)
221             (((double) gp->dwidth) * 72000.0) /
222             ((double) fp->point_size * fp->resolution_x);
223
224         gp->bbx.ascent = metrics[i].ascent;
225         gp->bbx.descent = metrics[i].descent;
226         gp->bbx.width = metrics[i].rbearing + metrics[i].lbearing;
227         gp->bbx.height = metrics[i].ascent + metrics[i].descent;
228         gp->bbx.x_offset = metrics[i].lbearing;
229         gp->bbx.y_offset = -metrics[i].descent;
230         gp->bytes = metrics[i].bytes;
231         gp->bitmap = (unsigned char *) malloc(gp->bytes);
232
233         fseek(in, (int) metrics[i].offset, 1L);
234         fread((char *) gp->bitmap, gp->bytes, 1, in);
235
236         /*
237          * Call the callback if indicated.
238          */
239         if (callback != 0) {
240             cb.reason = BDF_LOADING;
241             cb.total = fp->glyphs_size;
242             cb.current = fp->glyphs_used;
243             (*callback)(&cb, data);
244         }
245     }
246
247     /*
248      * Add a message indicating the font was converted.
249      */
250     _bdf_add_comment(fp, "Font converted from VF to BDF.", 30);
251     _bdf_add_acmsg(fp, "Font converted from VF to BDF.", 30);
252
253     /*
254      * Return the font.
255      */
256     return fp;
257 }
258
259 /*
260  * Load a simple binary font.
261  */
262 static bdf_font_t *
263 _bdf_load_simple(FILE *in, int height, bdf_callback_t callback, void *data,
264                  int type, int *awidth)
265 {
266     int i;
267     unsigned short dwidth, swidth;
268     bdf_font_t *fp;
269     bdf_glyph_t *gp;
270     bdf_callback_struct_t cb;
271
272     /*
273      * The point size of the font will be the height, the resolution will
274      * default to 72dpi, and the spacing will default to character cell.
275      */
276     fp = bdf_new_font(0, (int) height, 72, 72, BDF_CHARCELL, 1);
277
278     /*
279      * Force the bits per pixel to be one.
280      */
281     fp->bpp = 1;
282
283     /*
284      * Make sure the width is always set to 8 no matter what.  This may
285      * change in the future, but not anytime soon.
286      */
287     *awidth = fp->bbx.width = 8;
288
289     /*
290      * Adjust the ascent and descent by hand for the 14pt and 8pt fonts.
291      */
292     if (height != 16) {
293         fp->bbx.ascent++;
294         fp->bbx.descent--;
295     }
296
297     /*
298      * Default the font ascent and descent to that of the bounding box.
299      */
300     fp->font_ascent = fp->bbx.ascent;
301     fp->font_descent = fp->bbx.descent;
302
303     /*
304      * Simple fonts will have at most 256 glyphs.
305      */
306     fp->glyphs_size = 256;
307     fp->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * fp->glyphs_size);
308     (void) memset((char *) fp->glyphs, 0,
309                   sizeof(bdf_glyph_t) * fp->glyphs_size);
310
311     /*
312      * Determine the default scalable and device width for each character.
313      */
314     dwidth = fp->bbx.width;
315     swidth = (unsigned short)
316         (((double) dwidth) * 72000.0) /
317         ((double) fp->point_size * fp->resolution_x);
318
319     /*
320      * Set up to call the callback.
321      */
322     if (callback != 0) {
323         cb.reason = BDF_LOAD_START;
324         cb.current = 0;
325         cb.total = fp->glyphs_size;
326         (*callback)(&cb, data);
327     }
328
329     /*
330      * Now load the glyphs, assigning a default encoding.
331      */
332     for (i = 0, gp = fp->glyphs; i < fp->glyphs_size; i++, gp++) {
333         gp->encoding = i;
334         gp->dwidth = dwidth;
335         gp->swidth = swidth;
336         (void) memcpy((char *) &gp->bbx, (char *) &fp->bbx, sizeof(bdf_bbx_t));
337
338         gp->bytes = height;
339         gp->bitmap = (unsigned char *) malloc(height);
340         fread((char *) gp->bitmap, height, 1, in);
341         fp->glyphs_used++;
342
343         /*
344          * Call the callback if indicated.
345          */
346         if (callback != 0) {
347             cb.reason = BDF_LOADING;
348             cb.total = fp->glyphs_size;
349             cb.current = fp->glyphs_used;
350             (*callback)(&cb, data);
351         }
352     }
353
354     /*
355      * Add a message indicating the font was converted.
356      */
357     if (type == 1) {
358         _bdf_add_comment(fp, "Font converted from VGA/EGA to BDF.", 35);
359         _bdf_add_acmsg(fp, "Font converted from VGA/EGA to BDF.", 35);
360     } else if (type == 2) {
361         _bdf_add_comment(fp, "Fonts converted from CP to BDF.", 31);
362         _bdf_add_acmsg(fp, "Fonts converted from CP to BDF.", 31);
363     }
364
365     /*
366      * Return the new font.
367      */
368     return fp;
369 }
370
371 /*
372  * A structure to pass around in update callbacks.
373  */
374 typedef struct {
375     unsigned int total;
376     unsigned int curr;
377     unsigned int lcurr;
378     bdf_callback_t cback;
379     void *data;
380 } _bdf_update_rec_t;
381
382 /*
383  * A routine to report the progress of loading a codepage font over all
384  * three fonts.
385  */
386 static void
387 _bdf_codepage_progress(bdf_callback_struct_t *cb, void *data)
388 {
389     _bdf_update_rec_t *up;
390     bdf_callback_struct_t ncb;
391
392     up = (_bdf_update_rec_t *) data;
393
394     if (up->cback == 0)
395       return;
396
397     if (up->curr != 0 && cb->current == 0) {
398         up->lcurr = 0;
399         return;
400     }
401
402     up->curr += cb->current - up->lcurr;
403     up->lcurr = cb->current;
404
405     ncb.reason = cb->reason;
406     ncb.total = up->total;
407     ncb.current = up->curr;
408
409     if (up->cback != 0)
410       (*up->cback)(&ncb, up->data);
411 }
412
413 /*
414  * Load a codepage font which actually contains three fonts.  This makes
415  * use of the routine that loads the simple fonts.
416  */
417 static int
418 _bdf_load_codepage(FILE *in, bdf_callback_t callback, void *data,
419                    bdf_font_t *fonts[3], int awidth[3])
420 {
421     _bdf_update_rec_t up;
422
423     /*
424      * Initialize an override callback structure.
425      */
426     up.cback = callback;
427     up.data = data;
428     up.total = 768;
429     up.curr = up.lcurr = 0;
430
431     /*
432      * Load the 16pt font.
433      */
434     if (fseek(in, 40, 0L))
435       return BDF_NOT_CONSOLE_FONT;
436
437     fonts[0] = _bdf_load_simple(in, 16, _bdf_codepage_progress, (void *) &up,
438                                 0, &awidth[0]);
439
440     /*
441      * Load the 14pt font.
442      */
443     if (fseek(in, 4142, 0L)) {
444         if (fonts[0] != 0)
445           bdf_free_font(fonts[0]);
446         fonts[0] = 0;
447         return BDF_NOT_CONSOLE_FONT;
448     }
449     fonts[1] = _bdf_load_simple(in, 14, _bdf_codepage_progress, (void *) &up,
450                                 0, &awidth[1]);
451
452     /*
453      * Load the 8pt font.
454      */
455     if (fseek(in, 7732, 0L)) {
456         if (fonts[0] != 0)
457           bdf_free_font(fonts[0]);
458         if (fonts[1] != 0)
459           bdf_free_font(fonts[1]);
460         fonts[0] = fonts[1] = 0;
461         return BDF_NOT_CONSOLE_FONT;
462     }
463     fonts[2] = _bdf_load_simple(in, 8, _bdf_codepage_progress, (void *) &up,
464                                 2, &awidth[2]);
465
466     /*
467      * All the fonts loaded OK.
468      */
469     return BDF_OK;
470 }
471
472 /**************************************************************************
473  *
474  * API.
475  *
476  **************************************************************************/
477
478 static unsigned char vfmagic[] = {0x01, 0x1e};
479
480 int
481 bdf_load_console_font(FILE *in, bdf_options_t *opts, bdf_callback_t callback,
482                       void *data, bdf_font_t *fonts[3], int *nfonts)
483 {
484     unsigned char hdr[4];
485     int res, awidth[3];
486     double dp, dr;
487     bdf_property_t prop;
488     vfhdr_t vhdr;
489     struct stat st;
490
491     (void) fstat(fileno(in), &st);
492
493     *nfonts = 1;
494     awidth[0] = awidth[1] = awidth[2] = 0;
495     (void) memset((char *) fonts, 0, sizeof(bdf_font_t *) * 3);
496
497     fread((char *) hdr, sizeof(unsigned char), 4, in);
498
499     if (memcmp((char *) hdr, _bdf_psfcombined, 4) == 0)
500       return BDF_PSF_UNSUPPORTED;
501
502     if (memcmp((char *) hdr, (char *) _bdf_psf1magic, 2) == 0 ||
503         memcmp((char *) hdr, (char *) _bdf_psf2magic, 4) == 0)
504       /*
505        * Have a PSF font that may contain a mapping table.
506        */
507       fonts[0] = bdf_load_psf(in, hdr, opts, callback, data, awidth);
508     else {
509         /*
510          * Reset to the beginning of the file.
511          */
512         fseek(in, 0, 0L);
513         if (memcmp((char *) hdr, (char *) vfmagic, 2) == 0) {
514             /*
515              * Have a Sun vfont.  Need to reload the header.
516              */
517             (void) fread((char *) &vhdr, sizeof(vfhdr_t), 1, in);
518             fonts[0] = _bdf_load_vfont(in, &vhdr, callback, data, awidth);
519         } else if (st.st_size == 9780) {
520             /*
521              * Have a CP font with three sizes.  Create all three fonts and
522              * return them.
523              */
524             *nfonts = 3;
525             if ((res = _bdf_load_codepage(in, callback, data, fonts, awidth)))
526               return res;
527         } else {
528             /*
529              * Have a plain font with 256 characters.  If the file size is not
530              * evenly divisible by 256, then the file is probably corrupt or
531              * is not a font.
532              */
533             if (st.st_size & 0xff)
534               return BDF_NOT_CONSOLE_FONT;
535
536             fonts[0] = _bdf_load_simple(in, st.st_size >> 8, callback, data,
537                                         1, awidth);
538         }
539     }
540
541     /*
542      * Add all the default properties.
543      */
544     for (res = 0; res < *nfonts; res++) {
545         prop.name = "POINT_SIZE";
546         prop.format = BDF_INTEGER;
547         prop.value.int32 = fonts[res]->point_size * 10;
548         bdf_add_font_property(fonts[res], &prop);
549
550         dr = (double) fonts[res]->resolution_y;
551         dp = (double) (fonts[res]->point_size * 10);
552         prop.name = "PIXEL_SIZE";
553         prop.format = BDF_INTEGER;
554         prop.value.int32 = (int) (((dp * dr) / 722.7) + 0.5);
555         bdf_add_font_property(fonts[res], &prop);
556
557         prop.name = "RESOLUTION_X";
558         prop.format = BDF_CARDINAL;
559         prop.value.card32 = (unsigned int) fonts[res]->resolution_x;
560         bdf_add_font_property(fonts[res], &prop);
561
562         prop.name = "RESOLUTION_Y";
563         prop.format = BDF_CARDINAL;
564         prop.value.card32 = (unsigned int) fonts[res]->resolution_y;
565         bdf_add_font_property(fonts[res], &prop);
566
567         prop.name = "FONT_ASCENT";
568         prop.format = BDF_INTEGER;
569         prop.value.int32 = (int) fonts[res]->bbx.ascent;
570         bdf_add_font_property(fonts[res], &prop);
571
572         prop.name = "FONT_DESCENT";
573         prop.format = BDF_INTEGER;
574         prop.value.int32 = (int) fonts[res]->bbx.descent;
575         bdf_add_font_property(fonts[res], &prop);
576
577         prop.name = "AVERAGE_WIDTH";
578         prop.format = BDF_INTEGER;
579         prop.value.int32 = (awidth[res] / fonts[res]->glyphs_used) * 10;
580         bdf_add_font_property(fonts[res], &prop);
581
582         prop.name = "SPACING";
583         prop.format = BDF_ATOM;
584         prop.value.atom = "P";
585         switch (fonts[res]->spacing) {
586           case BDF_PROPORTIONAL: prop.value.atom = "P"; break;
587           case BDF_MONOWIDTH: prop.value.atom = "M"; break;
588           case BDF_CHARCELL: prop.value.atom = "C"; break;
589         }
590         bdf_add_font_property(fonts[res], &prop);
591     }
592
593     return BDF_OK;
594 }