2 * Copyright 2008 Department of Mathematical Sciences, New Mexico State University
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
27 #include <sys/types.h>
34 #define MAX(h,i) ((h) > (i) ? (h) : (i))
35 #define MIN(l,o) ((l) < (o) ? (l) : (o))
38 * Header for Sun VF fonts.
42 unsigned short total_bytes;
43 unsigned short max_width;
44 unsigned short max_height;
49 * Character metrics data for Sun VF fonts.
52 unsigned short offset;
58 unsigned short dwidth;
61 /**************************************************************************
65 **************************************************************************/
68 _bdf_load_vfont(FILE *in, vfhdr_t *hdr, bdf_callback_t callback, void *data,
75 bdf_callback_struct_t cb;
76 vfmetrics_t met, metrics[256];
79 * Convert the header values to little endian if necessary.
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);
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.
94 fp = bdf_new_font(0, (int) hdr->max_height, 72, 72, BDF_PROPORTIONAL, 1);
97 * Force the bits per pixel to 1.
102 * Load the glyph metrics and set a marker to the beginning of the glyph
105 fread((char *) metrics, sizeof(vfmetrics_t), 256, in);
111 * Count the number of glyphs that actually exist and determine the font
112 * bounding box in the process.
114 (void) memset((char *) &met, 0, sizeof(vfmetrics_t));
117 for (first = -1, ismono = 1, i = 0; i < 256; i++) {
118 if (metrics[i].bytes == 0)
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.
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))
138 * If this is a little endian machine, convert the 16-bit values from
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);
151 * Update the value used for average width calculation.
153 *awidth = *awidth + (metrics[i].rbearing - metrics[i].lbearing);
156 * Increment the count of characters.
161 * Determine the font bounding box.
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);
170 * Adjust the font bounding box accordingly.
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;
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
185 fp->spacing = BDF_MONOWIDTH;
188 * Set up to load the glyphs.
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);
195 * Set the callback up.
198 cb.reason = BDF_LOAD_START;
200 cb.total = fp->glyphs_size;
201 (*callback)(&cb, data);
207 for (i = 0; i < 256; i++) {
208 if (metrics[i].bytes == 0)
212 * Put the file pointer back at the beginning of the bitmaps.
216 gp = fp->glyphs + fp->glyphs_used++;
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);
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);
233 fseek(in, (int) metrics[i].offset, 1L);
234 fread((char *) gp->bitmap, gp->bytes, 1, in);
237 * Call the callback if indicated.
240 cb.reason = BDF_LOADING;
241 cb.total = fp->glyphs_size;
242 cb.current = fp->glyphs_used;
243 (*callback)(&cb, data);
248 * Add a message indicating the font was converted.
250 _bdf_add_comment(fp, "Font converted from VF to BDF.", 30);
251 _bdf_add_acmsg(fp, "Font converted from VF to BDF.", 30);
260 * Load a simple binary font.
263 _bdf_load_simple(FILE *in, int height, bdf_callback_t callback, void *data,
264 int type, int *awidth)
267 unsigned short dwidth, swidth;
270 bdf_callback_struct_t cb;
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.
276 fp = bdf_new_font(0, (int) height, 72, 72, BDF_CHARCELL, 1);
279 * Force the bits per pixel to be one.
284 * Make sure the width is always set to 8 no matter what. This may
285 * change in the future, but not anytime soon.
287 *awidth = fp->bbx.width = 8;
290 * Adjust the ascent and descent by hand for the 14pt and 8pt fonts.
298 * Default the font ascent and descent to that of the bounding box.
300 fp->font_ascent = fp->bbx.ascent;
301 fp->font_descent = fp->bbx.descent;
304 * Simple fonts will have at most 256 glyphs.
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);
312 * Determine the default scalable and device width for each character.
314 dwidth = fp->bbx.width;
315 swidth = (unsigned short)
316 (((double) dwidth) * 72000.0) /
317 ((double) fp->point_size * fp->resolution_x);
320 * Set up to call the callback.
323 cb.reason = BDF_LOAD_START;
325 cb.total = fp->glyphs_size;
326 (*callback)(&cb, data);
330 * Now load the glyphs, assigning a default encoding.
332 for (i = 0, gp = fp->glyphs; i < fp->glyphs_size; i++, gp++) {
336 (void) memcpy((char *) &gp->bbx, (char *) &fp->bbx, sizeof(bdf_bbx_t));
339 gp->bitmap = (unsigned char *) malloc(height);
340 fread((char *) gp->bitmap, height, 1, in);
344 * Call the callback if indicated.
347 cb.reason = BDF_LOADING;
348 cb.total = fp->glyphs_size;
349 cb.current = fp->glyphs_used;
350 (*callback)(&cb, data);
355 * Add a message indicating the font was converted.
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);
366 * Return the new font.
372 * A structure to pass around in update callbacks.
378 bdf_callback_t cback;
383 * A routine to report the progress of loading a codepage font over all
387 _bdf_codepage_progress(bdf_callback_struct_t *cb, void *data)
389 _bdf_update_rec_t *up;
390 bdf_callback_struct_t ncb;
392 up = (_bdf_update_rec_t *) data;
397 if (up->curr != 0 && cb->current == 0) {
402 up->curr += cb->current - up->lcurr;
403 up->lcurr = cb->current;
405 ncb.reason = cb->reason;
406 ncb.total = up->total;
407 ncb.current = up->curr;
410 (*up->cback)(&ncb, up->data);
414 * Load a codepage font which actually contains three fonts. This makes
415 * use of the routine that loads the simple fonts.
418 _bdf_load_codepage(FILE *in, bdf_callback_t callback, void *data,
419 bdf_font_t *fonts[3], int awidth[3])
421 _bdf_update_rec_t up;
424 * Initialize an override callback structure.
429 up.curr = up.lcurr = 0;
432 * Load the 16pt font.
434 if (fseek(in, 40, 0L))
435 return BDF_NOT_CONSOLE_FONT;
437 fonts[0] = _bdf_load_simple(in, 16, _bdf_codepage_progress, (void *) &up,
441 * Load the 14pt font.
443 if (fseek(in, 4142, 0L)) {
445 bdf_free_font(fonts[0]);
447 return BDF_NOT_CONSOLE_FONT;
449 fonts[1] = _bdf_load_simple(in, 14, _bdf_codepage_progress, (void *) &up,
455 if (fseek(in, 7732, 0L)) {
457 bdf_free_font(fonts[0]);
459 bdf_free_font(fonts[1]);
460 fonts[0] = fonts[1] = 0;
461 return BDF_NOT_CONSOLE_FONT;
463 fonts[2] = _bdf_load_simple(in, 8, _bdf_codepage_progress, (void *) &up,
467 * All the fonts loaded OK.
472 /**************************************************************************
476 **************************************************************************/
478 static unsigned char vfmagic[] = {0x01, 0x1e};
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)
484 unsigned char hdr[4];
491 (void) fstat(fileno(in), &st);
494 awidth[0] = awidth[1] = awidth[2] = 0;
495 (void) memset((char *) fonts, 0, sizeof(bdf_font_t *) * 3);
497 fread((char *) hdr, sizeof(unsigned char), 4, in);
499 if (memcmp((char *) hdr, _bdf_psfcombined, 4) == 0)
500 return BDF_PSF_UNSUPPORTED;
502 if (memcmp((char *) hdr, (char *) _bdf_psf1magic, 2) == 0 ||
503 memcmp((char *) hdr, (char *) _bdf_psf2magic, 4) == 0)
505 * Have a PSF font that may contain a mapping table.
507 fonts[0] = bdf_load_psf(in, hdr, opts, callback, data, awidth);
510 * Reset to the beginning of the file.
513 if (memcmp((char *) hdr, (char *) vfmagic, 2) == 0) {
515 * Have a Sun vfont. Need to reload the header.
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) {
521 * Have a CP font with three sizes. Create all three fonts and
525 if ((res = _bdf_load_codepage(in, callback, data, fonts, awidth)))
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
533 if (st.st_size & 0xff)
534 return BDF_NOT_CONSOLE_FONT;
536 fonts[0] = _bdf_load_simple(in, st.st_size >> 8, callback, data,
542 * Add all the default properties.
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);
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);
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);
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);
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);
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);
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);
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;
590 bdf_add_font_property(fonts[res], &prop);