Move font related data structured to sys/font.c and update vtfontcvt

Prepare support to be able to handle font data in loader, consolidate
data structures to sys/font.h and update vtfontcvt.

vtfontcvt update is about to output set of glyphs in form of C source,
the implementation does allow to output compressed or uncompressed font
bitmaps.

Reviewed by:	bcr
Differential Revision:	https://reviews.freebsd.org/D24189
This commit is contained in:
Toomas Soome 2020-06-14 06:58:58 +00:00
parent e0f7c06de2
commit e7fd9688ea
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=362172
12 changed files with 621 additions and 159 deletions

View File

@ -15,7 +15,7 @@ CLEANFILES+= ${FONTS}
.SUFFIXES: .bdf .fnt .fnt.uu .hex .SUFFIXES: .bdf .fnt .fnt.uu .hex
.bdf.fnt .hex.fnt: .bdf.fnt .hex.fnt:
vtfontcvt ${.IMPSRC} ${.TARGET} vtfontcvt -o ${.TARGET} ${.IMPSRC}
FILESDIR= ${SHAREDIR}/vt/fonts FILESDIR= ${SHAREDIR}/vt/fonts

View File

@ -3006,7 +3006,7 @@ static uint8_t font_bytes[2224 * 16] = {
0x0c, 0x06, 0x03, 0x01, 0x0c, 0x06, 0x03, 0x01,
}; };
static struct vt_font_map font_mapping_normal[308] = { static vfnt_map_t font_mapping_normal[308] = {
{ 0x0020, 0x0001, 0x5e }, { 0x00a0, 0x0001, 0x00 }, { 0x0020, 0x0001, 0x5e }, { 0x00a0, 0x0001, 0x00 },
{ 0x00a1, 0x0060, 0x6e }, { 0x0110, 0x008f, 0x00 }, { 0x00a1, 0x0060, 0x6e }, { 0x0110, 0x008f, 0x00 },
{ 0x0111, 0x00cf, 0x08 }, { 0x011a, 0x00d2, 0x01 }, { 0x0111, 0x00cf, 0x08 }, { 0x011a, 0x00d2, 0x01 },
@ -3163,7 +3163,7 @@ static struct vt_font_map font_mapping_normal[308] = {
{ 0xe0b0, 0x0478, 0x03 }, { 0xf6be, 0x0148, 0x00 }, { 0xe0b0, 0x0478, 0x03 }, { 0xf6be, 0x0148, 0x00 },
}; };
static struct vt_font_map font_mapping_bold[319] = { static vfnt_map_t font_mapping_bold[319] = {
{ 0x0021, 0x047c, 0x0b }, { 0x002d, 0x0220, 0x00 }, { 0x0021, 0x047c, 0x0b }, { 0x002d, 0x0220, 0x00 },
{ 0x002e, 0x0488, 0x50 }, { 0x00a1, 0x04d9, 0x07 }, { 0x002e, 0x0488, 0x50 }, { 0x00a1, 0x04d9, 0x07 },
{ 0x00aa, 0x04e1, 0x03 }, { 0x00af, 0x04e5, 0x07 }, { 0x00aa, 0x04e1, 0x03 }, { 0x00af, 0x04e5, 0x07 },

View File

@ -48,6 +48,7 @@
#include <sys/mouse.h> #include <sys/mouse.h>
#include <sys/terminal.h> #include <sys/terminal.h>
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include <sys/font.h>
#include "opt_syscons.h" #include "opt_syscons.h"
#include "opt_splash.h" #include "opt_splash.h"
@ -400,30 +401,6 @@ void vt_upgrade(struct vt_device *vd);
/* name argument is not used yet. */ /* name argument is not used yet. */
#define VT_DRIVER_DECLARE(name, drv) DATA_SET(vt_drv_set, drv) #define VT_DRIVER_DECLARE(name, drv) DATA_SET(vt_drv_set, drv)
/*
* Fonts.
*
* Remapping tables are used to map Unicode points to glyphs. They need
* to be sorted, because vtfont_lookup() performs a binary search. Each
* font has two remapping tables, for normal and bold. When a character
* is not present in bold, it uses a normal glyph. When no glyph is
* available, it uses glyph 0, which is normally equal to U+FFFD.
*/
struct vt_font_map {
uint32_t vfm_src;
uint16_t vfm_dst;
uint16_t vfm_len;
};
struct vt_font {
struct vt_font_map *vf_map[VFNT_MAPS];
uint8_t *vf_bytes;
unsigned int vf_height, vf_width;
unsigned int vf_map_count[VFNT_MAPS];
unsigned int vf_refcount;
};
#ifndef SC_NO_CUTPASTE #ifndef SC_NO_CUTPASTE
struct vt_mouse_cursor { struct vt_mouse_cursor {
uint8_t map[64 * 64 / 8]; uint8_t map[64 * 64 / 8];

View File

@ -49,7 +49,7 @@ static MALLOC_DEFINE(M_VTFONT, "vtfont", "vt font");
#define VTFONT_MAXDIMENSION 128 #define VTFONT_MAXDIMENSION 128
static uint16_t static uint16_t
vtfont_bisearch(const struct vt_font_map *map, unsigned int len, uint32_t src) vtfont_bisearch(const vfnt_map_t *map, unsigned int len, uint32_t src)
{ {
int min, mid, max; int min, mid, max;
@ -137,7 +137,7 @@ vtfont_unref(struct vt_font *vf)
} }
static int static int
vtfont_validate_map(struct vt_font_map *vfm, unsigned int length, vtfont_validate_map(vfnt_map_t *vfm, unsigned int length,
unsigned int glyph_count) unsigned int glyph_count)
{ {
unsigned int i, last = 0; unsigned int i, last = 0;
@ -198,7 +198,7 @@ vtfont_load(vfnt_t *f, struct vt_font **ret)
vf->vf_map_count[i] = f->map_count[i]; vf->vf_map_count[i] = f->map_count[i];
if (f->map_count[i] == 0) if (f->map_count[i] == 0)
continue; continue;
mapsize = f->map_count[i] * sizeof(struct vt_font_map); mapsize = f->map_count[i] * sizeof(vfnt_map_t);
vf->vf_map[i] = malloc(mapsize, M_VTFONT, M_WAITOK); vf->vf_map[i] = malloc(mapsize, M_VTFONT, M_WAITOK);
error = copyin(f->map[i], vf->vf_map[i], mapsize); error = copyin(f->map[i], vf->vf_map[i], mapsize);
if (error) if (error)

View File

@ -37,6 +37,7 @@
#include <sys/types.h> #include <sys/types.h>
#endif #endif
#include <sys/ioccom.h> #include <sys/ioccom.h>
#include <sys/font.h>
/* /*
* Console ioctl commands. Some commands are named as KDXXXX, GIO_XXX, and * Console ioctl commands. Some commands are named as KDXXXX, GIO_XXX, and
@ -218,18 +219,6 @@ struct fnt16 {
}; };
typedef struct fnt16 fnt16_t; typedef struct fnt16 fnt16_t;
struct vfnt_map {
uint32_t src;
uint16_t dst;
uint16_t len;
};
typedef struct vfnt_map vfnt_map_t;
#define VFNT_MAP_NORMAL 0
#define VFNT_MAP_NORMAL_RIGHT 1
#define VFNT_MAP_BOLD 2
#define VFNT_MAP_BOLD_RIGHT 3
#define VFNT_MAPS 4
struct vfnt { struct vfnt {
vfnt_map_t *map[VFNT_MAPS]; vfnt_map_t *map[VFNT_MAPS];
uint8_t *glyphs; uint8_t *glyphs;

112
sys/sys/font.h Normal file
View File

@ -0,0 +1,112 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2009, 2013 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Ed Schouten under sponsorship from the
* FreeBSD Foundation.
*
* Portions of this software were developed by Oleksandr Rybalko
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _SYS_FONT_H_
#define _SYS_FONT_H_
#include <sys/queue.h>
/*
* Fonts.
*
* Remapping tables are used to map Unicode points to glyphs. They need
* to be sorted, because vtfont_lookup() performs a binary search. Each
* font has two remapping tables, for normal and bold. When a character
* is not present in bold, it uses a normal glyph. When no glyph is
* available, it uses glyph 0, which is normally equal to U+FFFD.
*/
enum vfnt_map_type {
VFNT_MAP_NORMAL = 0, /* Normal font. */
VFNT_MAP_NORMAL_RIGHT, /* Normal font right hand. */
VFNT_MAP_BOLD, /* Bold font. */
VFNT_MAP_BOLD_RIGHT, /* Bold font right hand. */
VFNT_MAPS /* Number of maps. */
};
struct vfnt_map {
uint32_t vfm_src;
uint16_t vfm_dst;
uint16_t vfm_len;
} __packed;
typedef struct vfnt_map vfnt_map_t;
struct vt_font {
vfnt_map_t *vf_map[VFNT_MAPS];
uint8_t *vf_bytes;
uint32_t vf_height;
uint32_t vf_width;
uint32_t vf_map_count[VFNT_MAPS];
uint32_t vf_refcount;
};
typedef struct vt_font_bitmap_data {
uint32_t vfbd_width;
uint32_t vfbd_height;
uint32_t vfbd_compressed_size;
uint32_t vfbd_uncompressed_size;
uint8_t *vfbd_compressed_data;
struct vt_font *vfbd_font;
} vt_font_bitmap_data_t;
typedef enum {
FONT_AUTO,
FONT_MANUAL,
FONT_BOOT
} FONT_FLAGS;
struct fontlist {
char *font_name;
FONT_FLAGS font_flags;
vt_font_bitmap_data_t *font_data;
vt_font_bitmap_data_t *(*font_load)(char *);
STAILQ_ENTRY(fontlist) font_next;
};
#define BORDER_PIXELS 10 /* space from screen border */
typedef STAILQ_HEAD(font_list, fontlist) font_list_t;
#define FONT_HEADER_MAGIC "VFNT0002"
struct font_header {
uint8_t fh_magic[8];
uint8_t fh_width;
uint8_t fh_height;
uint16_t fh_pad;
uint32_t fh_glyph_count;
uint32_t fh_map_count[VFNT_MAPS];
} __packed;
#endif /* !_SYS_FONT_H_ */

View File

@ -92,6 +92,9 @@ DISKINCS+= ${SRCTOP}/sys/sys/disk/bsd.h
SYSINCS+= ${SRCTOP}/sys/sys/nv.h ${SRCTOP}/sys/sys/cnv.h \ SYSINCS+= ${SRCTOP}/sys/sys/nv.h ${SRCTOP}/sys/sys/cnv.h \
${SRCTOP}/sys/sys/dnv.h ${SRCTOP}/sys/sys/dnv.h
# vtfontcvt is using sys/font.h
SYSINCS+= ${SRCTOP}/sys/sys/font.h
# We want to run the build with only ${WORLDTMP} in $PATH to ensure we don't # We want to run the build with only ${WORLDTMP} in $PATH to ensure we don't
# accidentally run tools that are incompatible but happen to be in $PATH. # accidentally run tools that are incompatible but happen to be in $PATH.
# This is especially important when building on Linux/MacOS where many of the # This is especially important when building on Linux/MacOS where many of the

View File

@ -32,35 +32,21 @@ __FBSDID("$FreeBSD$");
#include <sys/endian.h> #include <sys/endian.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/font.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
struct file_mapping {
uint32_t source;
uint16_t destination;
uint16_t length;
} __packed;
struct file_header {
uint8_t magic[8];
uint8_t width;
uint8_t height;
uint16_t pad;
uint32_t glyph_count;
uint32_t map_count[4];
} __packed;
static int static int
print_glyphs(struct file_header *fh) print_glyphs(struct font_header *fh)
{ {
unsigned int gbytes, glyph_count, j, k, total; unsigned int gbytes, glyph_count, j, k, total;
uint8_t *gbuf; uint8_t *gbuf;
gbytes = howmany(fh->width, 8) * fh->height; gbytes = howmany(fh->fh_width, 8) * fh->fh_height;
glyph_count = be32toh(fh->glyph_count); glyph_count = be32toh(fh->fh_glyph_count);
printf("\nstatic uint8_t font_bytes[%u * %u] = {", glyph_count, gbytes); printf("\nstatic uint8_t font_bytes[%u * %u] = {", glyph_count, gbytes);
total = glyph_count * gbytes; total = glyph_count * gbytes;
@ -88,18 +74,18 @@ static const char *map_names[4] = {
"normal", "normal_right", "bold", "bold_right" }; "normal", "normal_right", "bold", "bold_right" };
static int static int
print_mappings(struct file_header *fh, int map_index) print_mappings(struct font_header *fh, int map_index)
{ {
struct file_mapping fm; vfnt_map_t fm;
unsigned int nmappings, i, col = 0; unsigned int nmappings, i, col = 0;
nmappings = be32toh(fh->map_count[map_index]); nmappings = be32toh(fh->fh_map_count[map_index]);
if (nmappings == 0) if (nmappings == 0)
return (0); return (0);
printf("\nstatic struct vt_font_map font_mapping_%s[%u] = {", printf("\nstatic vfnt_map_t font_mapping_%s[%u] = {",
map_names[map_index], nmappings); map_names[map_index], nmappings);
for (i = 0; i < nmappings; i++) { for (i = 0; i < nmappings; i++) {
@ -110,8 +96,8 @@ print_mappings(struct file_header *fh, int map_index)
printf(col == 0 ? "\n\t" : " "); printf(col == 0 ? "\n\t" : " ");
printf("{ 0x%04x, 0x%04x, 0x%02x },", printf("{ 0x%04x, 0x%04x, 0x%02x },",
be32toh(fm.source), be16toh(fm.destination), be32toh(fm.vfm_src), be16toh(fm.vfm_dst),
be16toh(fm.length)); be16toh(fm.vfm_len));
col = (col + 1) % 2; col = (col + 1) % 2;
} }
@ -121,7 +107,7 @@ print_mappings(struct file_header *fh, int map_index)
} }
static int static int
print_info(struct file_header *fh) print_info(struct font_header *fh)
{ {
unsigned int i; unsigned int i;
@ -130,21 +116,21 @@ print_info(struct file_header *fh)
"\t.vf_width\t\t= %u,\n" "\t.vf_width\t\t= %u,\n"
"\t.vf_height\t\t= %u,\n" "\t.vf_height\t\t= %u,\n"
"\t.vf_bytes\t\t= font_bytes,\n", "\t.vf_bytes\t\t= font_bytes,\n",
fh->width, fh->height); fh->fh_width, fh->fh_height);
printf("\t.vf_map\t\t\t= {\n"); printf("\t.vf_map\t\t\t= {\n");
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
if (fh->map_count[i] > 0) if (fh->fh_map_count[i] > 0)
printf("\t\t\t\t font_mapping_%s,\n", map_names[i]); printf("\t\t\t\t font_mapping_%s,\n", map_names[i]);
else else
printf("\t\t\t\t NULL,\n"); printf("\t\t\t\t NULL,\n");
} }
printf("\t\t\t\t },\n"); printf("\t\t\t\t },\n");
printf("\t.vf_map_count\t\t= { %u, %u, %u, %u },\n", printf("\t.vf_map_count\t\t= { %u, %u, %u, %u },\n",
be32toh(fh->map_count[0]), be32toh(fh->fh_map_count[0]),
be32toh(fh->map_count[1]), be32toh(fh->fh_map_count[1]),
be32toh(fh->map_count[2]), be32toh(fh->fh_map_count[2]),
be32toh(fh->map_count[3])); be32toh(fh->fh_map_count[3]));
printf("\t.vf_refcount\t\t= 1,\n};\n"); printf("\t.vf_refcount\t\t= 1,\n};\n");
return (0); return (0);
@ -153,15 +139,15 @@ print_info(struct file_header *fh)
int int
main(int argc __unused, char *argv[] __unused) main(int argc __unused, char *argv[] __unused)
{ {
struct file_header fh; struct font_header fh;
unsigned int i; unsigned int i;
if (fread(&fh, sizeof fh, 1, stdin) != 1) { if (fread(&fh, sizeof fh, 1, stdin) != 1) {
perror("file_header"); perror("font_header");
return (1); return (1);
} }
if (memcmp(fh.magic, "VFNT0002", 8) != 0) { if (memcmp(fh.fh_magic, "VFNT0002", 8) != 0) {
fprintf(stderr, "Bad magic\n"); fprintf(stderr, "Bad magic\n");
return (1); return (1);
} }

View File

@ -1,6 +1,11 @@
# $FreeBSD$ # $FreeBSD$
PROG= vtfontcvt PROG= vtfontcvt
SRCS= vtfontcvt.c lz4.c
MAN8= vtfontcvt.8 MAN8= vtfontcvt.8
# lz4 compression functionality
.PATH: ${SRCTOP}/sys/cddl/contrib/opensolaris/common/lz4
CFLAGS+= -I${SRCTOP}/sys/cddl/contrib/opensolaris/common/lz4
.include <bsd.prog.mk> .include <bsd.prog.mk>

View File

@ -24,7 +24,7 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd June 9, 2014 .Dd Mar 10, 2020
.Dt VTFONTCVT 8 .Dt VTFONTCVT 8
.Os .Os
.Sh NAME .Sh NAME
@ -32,29 +32,44 @@
.Nd "convert font files for use by the video console" .Nd "convert font files for use by the video console"
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl n
.Op Fl f Ar font Ns | Ns Ar source Ns | Ns Ar compressed-source
.Op Fl h Ar height .Op Fl h Ar height
.Fl o Ar output_file
.Op Fl v .Op Fl v
.Op Fl w Ar width .Op Fl w Ar width
.Ar normal_font .Ar normal_font
.Op Ar bold_font .Op Ar bold_font
.Ar output_file
.Sh DESCRIPTION .Sh DESCRIPTION
The The
.Nm .Nm
utility reads source font files in either BDF or Unifont HEX format and utility reads source font files in either BDF or Unifont HEX format and
outputs a binary font file for use by outputs a binary font file, C source, or C source with font data compressed
by using LZ4 compression method.
The output in C source is intended to be used to embed the font into program
binary.
The binary font file is for use by
.Xr vt 4 . .Xr vt 4 .
HEX format files must have the file extension HEX format files must have the file extension
.Pa .hex . .Pa .hex .
.Pp .Pp
The following options are available: The following options are available:
.Bl -tag -width "12345678" .Bl -tag -width "12345678"
.It Fl f Ar font Ns | Ns Ar source Ns | Ns Ar compressed-source
Specify the output format.
The default is binary
.Ar font
file.
.It Fl h Ar height .It Fl h Ar height
Set font height. Set font height.
The default is 16. The default is 16.
Font height is set automatically for HEX files that have a Font height is set automatically for HEX files that have a
.Ql # Height: Ar height .Ql # Height: Ar height
comment before any font data. comment before any font data.
.It Fl n
Do not apply output filtering with C source output.
.It Fl o Ar output_file
Specify the name for the output file.
.It Fl v .It Fl v
Display verbose statistics about the converted font. Display verbose statistics about the converted font.
.It Fl w Ar width .It Fl w Ar width

View File

@ -35,20 +35,18 @@ __FBSDID("$FreeBSD$");
#include <sys/endian.h> #include <sys/endian.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <sys/font.h>
#include <assert.h> #include <assert.h>
#include <err.h> #include <err.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <lz4.h>
#define VFNT_MAPS 4
#define VFNT_MAP_NORMAL 0
#define VFNT_MAP_NORMAL_RH 1
#define VFNT_MAP_BOLD 2
#define VFNT_MAP_BOLD_RH 3
#define VFNT_MAXGLYPHS 131072 #define VFNT_MAXGLYPHS 131072
#define VFNT_MAXDIMENSION 128 #define VFNT_MAXDIMENSION 128
@ -89,12 +87,102 @@ static struct mapping_list maps[VFNT_MAPS] = {
static unsigned int mapping_total, map_count[4], map_folded_count[4], static unsigned int mapping_total, map_count[4], map_folded_count[4],
mapping_unique, mapping_dupe; mapping_unique, mapping_dupe;
enum output_format {
VT_FONT, /* default */
VT_C_SOURCE, /* C source for built in fonts */
VT_C_COMPRESSED /* C source with compressed font data */
};
struct whitelist {
uint32_t c;
uint32_t len;
};
/*
* Compressed font glyph list. To be used with boot loader, we need to have
* ascii set and box drawing chars.
*/
static struct whitelist c_list[] = {
{ .c = 0, .len = 0 }, /* deault char */
{ .c = 0x20, .len = 0x5f },
{ .c = 0x2500, .len = 0 }, /* single frame */
{ .c = 0x2502, .len = 0 },
{ .c = 0x250c, .len = 0 },
{ .c = 0x2510, .len = 0 },
{ .c = 0x2514, .len = 0 },
{ .c = 0x2518, .len = 0 },
{ .c = 0x2550, .len = 1 }, /* double frame */
{ .c = 0x2554, .len = 0 },
{ .c = 0x2557, .len = 0 },
{ .c = 0x255a, .len = 0 },
{ .c = 0x255d, .len = 0 },
};
/*
* Uncompressed source. For x86 we need cp437 so the vga text mode
* can program font into the vga card.
*/
static struct whitelist s_list[] = {
{ .c = 0, .len = 0 }, /* deault char */
{ .c = 0x20, .len = 0x5f }, /* ascii set */
{ .c = 0xA0, .len = 0x5f }, /* latin 1 */
{ .c = 0x0192, .len = 0 },
{ .c = 0x0332, .len = 0 }, /* composing lower line */
{ .c = 0x0393, .len = 0 },
{ .c = 0x0398, .len = 0 },
{ .c = 0x03A3, .len = 0 },
{ .c = 0x03A6, .len = 0 },
{ .c = 0x03A9, .len = 0 },
{ .c = 0x03B1, .len = 1 },
{ .c = 0x03B4, .len = 0 },
{ .c = 0x03C0, .len = 0 },
{ .c = 0x03C3, .len = 0 },
{ .c = 0x03C4, .len = 0 },
{ .c = 0x207F, .len = 0 },
{ .c = 0x20A7, .len = 0 },
{ .c = 0x2205, .len = 0 },
{ .c = 0x220A, .len = 0 },
{ .c = 0x2219, .len = 1 },
{ .c = 0x221E, .len = 0 },
{ .c = 0x2229, .len = 0 },
{ .c = 0x2248, .len = 0 },
{ .c = 0x2261, .len = 0 },
{ .c = 0x2264, .len = 1 },
{ .c = 0x2310, .len = 0 },
{ .c = 0x2320, .len = 1 },
{ .c = 0x2500, .len = 0 },
{ .c = 0x2502, .len = 0 },
{ .c = 0x250C, .len = 0 },
{ .c = 0x2510, .len = 0 },
{ .c = 0x2514, .len = 0 },
{ .c = 0x2518, .len = 0 },
{ .c = 0x251C, .len = 0 },
{ .c = 0x2524, .len = 0 },
{ .c = 0x252C, .len = 0 },
{ .c = 0x2534, .len = 0 },
{ .c = 0x253C, .len = 0 },
{ .c = 0x2550, .len = 0x1c },
{ .c = 0x2580, .len = 0 },
{ .c = 0x2584, .len = 0 },
{ .c = 0x2588, .len = 0 },
{ .c = 0x258C, .len = 0 },
{ .c = 0x2590, .len = 3 },
{ .c = 0x25A0, .len = 0 },
};
static bool filter = true;
static enum output_format format = VT_FONT;
/* Type for write callback. */
typedef size_t (*vt_write)(const void *, size_t, size_t, FILE *);
static uint8_t *uncompressed;
static void static void
usage(void) usage(void)
{ {
(void)fprintf(stderr, (void)fprintf(stderr, "usage: vtfontcvt "
"usage: vtfontcvt [-w width] [-h height] [-v] normal.bdf [bold.bdf] out.fnt\n"); "[-n] [-f font|source|compressed-source] [-w width] "
"[-h height]\n\t[-v] normal.bdf [bold.bdf] out.fnt\n");
exit(1); exit(1);
} }
@ -148,7 +236,7 @@ dedup_mapping(unsigned int map_idx)
struct mapping *mp_bold, *mp_normal, *mp_temp; struct mapping *mp_bold, *mp_normal, *mp_temp;
unsigned normal_map_idx = map_idx - VFNT_MAP_BOLD; unsigned normal_map_idx = map_idx - VFNT_MAP_BOLD;
assert(map_idx == VFNT_MAP_BOLD || map_idx == VFNT_MAP_BOLD_RH); assert(map_idx == VFNT_MAP_BOLD || map_idx == VFNT_MAP_BOLD_RIGHT);
mp_normal = TAILQ_FIRST(&maps[normal_map_idx]); mp_normal = TAILQ_FIRST(&maps[normal_map_idx]);
TAILQ_FOREACH_SAFE(mp_bold, &maps[map_idx], m_list, mp_temp) { TAILQ_FOREACH_SAFE(mp_bold, &maps[map_idx], m_list, mp_temp) {
while (mp_normal->m_char < mp_bold->m_char) while (mp_normal->m_char < mp_bold->m_char)
@ -201,6 +289,32 @@ add_glyph(const uint8_t *bytes, unsigned int map_idx, int fallback)
return (gl); return (gl);
} }
static bool
check_whitelist(unsigned c)
{
struct whitelist *w = NULL;
int i, n = 0;
if (filter == false)
return (true);
if (format == VT_C_SOURCE) {
w = s_list;
n = sizeof (s_list) / sizeof (s_list[0]);
}
if (format == VT_C_COMPRESSED) {
w = c_list;
n = sizeof (c_list) / sizeof (c_list[0]);
}
if (w == NULL)
return (true);
for (i = 0; i < n; i++) {
if (c >= w[i].c && c <= w[i].c + w[i].len)
return (true);
}
return (false);
}
static int static int
add_char(unsigned curchar, unsigned map_idx, uint8_t *bytes, uint8_t *bytes_r) add_char(unsigned curchar, unsigned map_idx, uint8_t *bytes, uint8_t *bytes_r)
{ {
@ -210,7 +324,7 @@ add_char(unsigned curchar, unsigned map_idx, uint8_t *bytes, uint8_t *bytes_r)
if (curchar == 0xFFFD) { if (curchar == 0xFFFD) {
if (map_idx < VFNT_MAP_BOLD) if (map_idx < VFNT_MAP_BOLD)
gl = add_glyph(bytes, 0, 1); gl = add_glyph(bytes, 0, 1);
} else if (curchar >= 0x20) { } else if (filter == false || curchar >= 0x20) {
gl = add_glyph(bytes, map_idx, 0); gl = add_glyph(bytes, map_idx, 0);
if (add_mapping(gl, curchar, map_idx) != 0) if (add_mapping(gl, curchar, map_idx) != 0)
return (1); return (1);
@ -287,9 +401,9 @@ set_width(int w)
static int static int
parse_bdf(FILE *fp, unsigned int map_idx) parse_bdf(FILE *fp, unsigned int map_idx)
{ {
char *line, *ln, *p; char *ln, *p;
size_t length; size_t length;
uint8_t *bytes, *bytes_r; uint8_t *line, *bytes, *bytes_r;
unsigned int curchar = 0, i, j, linenum = 0, bbwbytes; unsigned int curchar = 0, i, j, linenum = 0, bbwbytes;
int bbw, bbh, bbox, bboy; /* Glyph bounding box. */ int bbw, bbh, bbox, bboy; /* Glyph bounding box. */
int fbbw = 0, fbbh, fbbox, fbboy; /* Font bounding box. */ int fbbw = 0, fbbh, fbbox, fbboy; /* Font bounding box. */
@ -414,10 +528,12 @@ parse_bdf(FILE *fp, unsigned int map_idx)
goto out; goto out;
} }
rv = add_char(curchar, map_idx, bytes, if (check_whitelist(curchar) == true) {
dwidth > (int)width ? bytes_r : NULL); rv = add_char(curchar, map_idx, bytes,
if (rv != 0) dwidth > (int)width ? bytes_r : NULL);
goto out; if (rv != 0)
goto out;
}
dwidth = bbw = bbh = 0; dwidth = bbw = bbh = 0;
} }
@ -484,10 +600,12 @@ parse_hex(FILE *fp, unsigned int map_idx)
p += gwbytes * 2; p += gwbytes * 2;
} }
rv = add_char(curchar, map_idx, bytes, if (check_whitelist(curchar) == true) {
gwidth != width ? bytes_r : NULL); rv = add_char(curchar, map_idx, bytes,
if (rv != 0) gwidth != width ? bytes_r : NULL);
goto out; if (rv != 0)
goto out;
}
} }
} }
out: out:
@ -529,15 +647,51 @@ number_glyphs(void)
gl->g_index = idx++; gl->g_index = idx++;
} }
/* Note we only deal with byte stream here. */
static size_t
write_glyph_source(const void *ptr, size_t size, size_t nitems, FILE *stream)
{
const uint8_t *data = ptr;
size_t i;
size *= nitems;
for (i = 0; i < size; i++) {
if ((i % wbytes) == 0) {
if (fprintf(stream, "\n") < 0)
return (0);
}
if (fprintf(stream, "0x%02x, ", data[i]) < 0)
return (0);
}
if (fprintf(stream, "\n") < 0)
nitems = 0;
return (nitems);
}
/* Write to buffer */
static size_t
write_glyph_buf(const void *ptr, size_t size, size_t nitems,
FILE *stream __unused)
{
static size_t index = 0;
size *= nitems;
(void) memmove(uncompressed + index, ptr, size);
index += size;
return (nitems);
}
static int static int
write_glyphs(FILE *fp) write_glyphs(FILE *fp, vt_write cb)
{ {
struct glyph *gl; struct glyph *gl;
unsigned int i; unsigned int i;
for (i = 0; i < VFNT_MAPS; i++) { for (i = 0; i < VFNT_MAPS; i++) {
TAILQ_FOREACH(gl, &glyphs[i], g_list) TAILQ_FOREACH(gl, &glyphs[i], g_list)
if (fwrite(gl->g_data, wbytes * height, 1, fp) != 1) if (cb(gl->g_data, wbytes * height, 1, fp) != 1)
return (1); return (1);
} }
return (0); return (0);
@ -561,27 +715,21 @@ fold_mappings(unsigned int map_idx)
} }
} }
struct file_mapping {
uint32_t source;
uint16_t destination;
uint16_t length;
} __packed;
static int static int
write_mappings(FILE *fp, unsigned int map_idx) write_mappings(FILE *fp, unsigned int map_idx)
{ {
struct mapping_list *ml = &maps[map_idx]; struct mapping_list *ml = &maps[map_idx];
struct mapping *mp; struct mapping *mp;
struct file_mapping fm; vfnt_map_t fm;
unsigned int i = 0, j = 0; unsigned int i = 0, j = 0;
TAILQ_FOREACH(mp, ml, m_list) { TAILQ_FOREACH(mp, ml, m_list) {
j++; j++;
if (mp->m_length > 0) { if (mp->m_length > 0) {
i += mp->m_length; i += mp->m_length;
fm.source = htobe32(mp->m_char); fm.vfm_src = htobe32(mp->m_char);
fm.destination = htobe16(mp->m_glyph->g_index); fm.vfm_dst = htobe16(mp->m_glyph->g_index);
fm.length = htobe16(mp->m_length - 1); fm.vfm_len = htobe16(mp->m_length - 1);
if (fwrite(&fm, sizeof fm, 1, fp) != 1) if (fwrite(&fm, sizeof fm, 1, fp) != 1)
return (1); return (1);
} }
@ -590,21 +738,33 @@ write_mappings(FILE *fp, unsigned int map_idx)
return (0); return (0);
} }
struct file_header { static int
uint8_t magic[8]; write_source_mappings(FILE *fp, unsigned int map_idx)
uint8_t width; {
uint8_t height; struct mapping_list *ml = &maps[map_idx];
uint16_t pad; struct mapping *mp;
uint32_t glyph_count; unsigned int i = 0, j = 0;
uint32_t map_count[4];
} __packed; TAILQ_FOREACH(mp, ml, m_list) {
j++;
if (mp->m_length > 0) {
i += mp->m_length;
if (fprintf(fp, "\t{ 0x%08x, 0x%04x, 0x%04x },\n",
mp->m_char, mp->m_glyph->g_index,
mp->m_length - 1) < 0)
return (1);
}
}
assert(i == j);
return (0);
}
static int static int
write_fnt(const char *filename) write_fnt(const char *filename)
{ {
FILE *fp; FILE *fp;
struct file_header fh = { struct font_header fh = {
.magic = "VFNT0002", .fh_magic = FONT_HEADER_MAGIC,
}; };
fp = fopen(filename, "wb"); fp = fopen(filename, "wb");
@ -613,24 +773,24 @@ write_fnt(const char *filename)
return (1); return (1);
} }
fh.width = width; fh.fh_width = width;
fh.height = height; fh.fh_height = height;
fh.glyph_count = htobe32(glyph_unique); fh.fh_glyph_count = htobe32(glyph_unique);
fh.map_count[0] = htobe32(map_folded_count[0]); fh.fh_map_count[0] = htobe32(map_folded_count[0]);
fh.map_count[1] = htobe32(map_folded_count[1]); fh.fh_map_count[1] = htobe32(map_folded_count[1]);
fh.map_count[2] = htobe32(map_folded_count[2]); fh.fh_map_count[2] = htobe32(map_folded_count[2]);
fh.map_count[3] = htobe32(map_folded_count[3]); fh.fh_map_count[3] = htobe32(map_folded_count[3]);
if (fwrite(&fh, sizeof fh, 1, fp) != 1) { if (fwrite(&fh, sizeof(fh), 1, fp) != 1) {
perror(filename); perror(filename);
fclose(fp); fclose(fp);
return (1); return (1);
} }
if (write_glyphs(fp) != 0 || if (write_glyphs(fp, &fwrite) != 0 ||
write_mappings(fp, VFNT_MAP_NORMAL) != 0 || write_mappings(fp, VFNT_MAP_NORMAL) != 0 ||
write_mappings(fp, VFNT_MAP_NORMAL_RH) != 0 || write_mappings(fp, VFNT_MAP_NORMAL_RIGHT) != 0 ||
write_mappings(fp, VFNT_MAP_BOLD) != 0 || write_mappings(fp, VFNT_MAP_BOLD) != 0 ||
write_mappings(fp, VFNT_MAP_BOLD_RH) != 0) { write_mappings(fp, VFNT_MAP_BOLD_RIGHT) != 0) {
perror(filename); perror(filename);
fclose(fp); fclose(fp);
return (1); return (1);
@ -640,6 +800,198 @@ write_fnt(const char *filename)
return (0); return (0);
} }
static int
write_fnt_source(bool lz4, const char *filename)
{
FILE *fp;
int rv = 1;
size_t uncompressed_size = wbytes * height * glyph_unique;
size_t compressed_size = uncompressed_size;
uint8_t *compressed = NULL;
fp = fopen(filename, "w");
if (fp == NULL) {
perror(filename);
return (1);
}
if (lz4 == true) {
uncompressed = xmalloc(uncompressed_size);
compressed = xmalloc(uncompressed_size);
}
if (fprintf(fp, "/* Generated %ux%u console font source. */\n\n",
width, height) < 0)
goto done;
if (fprintf(fp, "#include <sys/types.h>\n") < 0)
goto done;
if (fprintf(fp, "#include <sys/param.h>\n") < 0)
goto done;
if (fprintf(fp, "#include <sys/font.h>\n\n") < 0)
goto done;
/* Write font bytes. */
if (fprintf(fp, "static uint8_t FONTDATA_%ux%u[] = {\n",
width, height) < 0)
goto done;
if (lz4 == true) {
if (write_glyphs(fp, &write_glyph_buf) != 0)
goto done;
compressed_size = lz4_compress(uncompressed, compressed,
uncompressed_size, compressed_size, 0);
if (write_glyph_source(compressed, compressed_size, 1, fp) != 1)
goto done;
free(uncompressed);
free(compressed);
} else {
if (write_glyphs(fp, &write_glyph_source) != 0)
goto done;
}
if (fprintf(fp, "};\n\n") < 0)
goto done;
/* Write font maps. */
if (!TAILQ_EMPTY(&maps[VFNT_MAP_NORMAL])) {
if (fprintf(fp, "static vfnt_map_t "
"FONTMAP_NORMAL_%ux%u[] = {\n", width, height) < 0)
goto done;
if (write_source_mappings(fp, VFNT_MAP_NORMAL) != 0)
goto done;
if (fprintf(fp, "};\n\n") < 0)
goto done;
}
if (!TAILQ_EMPTY(&maps[VFNT_MAP_NORMAL_RIGHT])) {
if (fprintf(fp, "static vfnt_map_t "
"FONTMAP_NORMAL_RH_%ux%u[] = {\n", width, height) < 0)
goto done;
if (write_source_mappings(fp, VFNT_MAP_NORMAL_RIGHT) != 0)
goto done;
if (fprintf(fp, "};\n\n") < 0)
goto done;
}
if (!TAILQ_EMPTY(&maps[VFNT_MAP_BOLD])) {
if (fprintf(fp, "static vfnt_map_t "
"FONTMAP_BOLD_%ux%u[] = {\n", width, height) < 0)
goto done;
if (write_source_mappings(fp, VFNT_MAP_BOLD) != 0)
goto done;
if (fprintf(fp, "};\n\n") < 0)
goto done;
}
if (!TAILQ_EMPTY(&maps[VFNT_MAP_BOLD_RIGHT])) {
if (fprintf(fp, "static vfnt_map_t "
"FONTMAP_BOLD_RH_%ux%u[] = {\n", width, height) < 0)
goto done;
if (write_source_mappings(fp, VFNT_MAP_BOLD_RIGHT) != 0)
goto done;
if (fprintf(fp, "};\n\n") < 0)
goto done;
}
/* Write struct font. */
if (fprintf(fp, "struct vt_font font_%ux%u = {\n",
width, height) < 0)
goto done;
if (fprintf(fp, "\t.vf_map\t= {\n") < 0)
goto done;
if (TAILQ_EMPTY(&maps[VFNT_MAP_NORMAL])) {
if (fprintf(fp, "\t\t\tNULL,\n") < 0)
goto done;
} else {
if (fprintf(fp, "\t\t\tFONTMAP_NORMAL_%ux%u,\n",
width, height) < 0)
goto done;
}
if (TAILQ_EMPTY(&maps[VFNT_MAP_NORMAL_RIGHT])) {
if (fprintf(fp, "\t\t\tNULL,\n") < 0)
goto done;
} else {
if (fprintf(fp, "\t\t\tFONTMAP_NORMAL_RH_%ux%u,\n",
width, height) < 0)
goto done;
}
if (TAILQ_EMPTY(&maps[VFNT_MAP_BOLD])) {
if (fprintf(fp, "\t\t\tNULL,\n") < 0)
goto done;
} else {
if (fprintf(fp, "\t\t\tFONTMAP_BOLD_%ux%u,\n",
width, height) < 0)
goto done;
}
if (TAILQ_EMPTY(&maps[VFNT_MAP_BOLD_RIGHT])) {
if (fprintf(fp, "\t\t\tNULL\n") < 0)
goto done;
} else {
if (fprintf(fp, "\t\t\tFONTMAP_BOLD_RH_%ux%u\n",
width, height) < 0)
goto done;
}
if (fprintf(fp, "\t\t},\n") < 0)
goto done;
if (lz4 == true) {
if (fprintf(fp, "\t.vf_bytes\t= NULL,\n") < 0)
goto done;
} else {
if (fprintf(fp, "\t.vf_bytes\t= FONTDATA_%ux%u,\n",
width, height) < 0) {
goto done;
}
}
if (fprintf(fp, "\t.vf_width\t= %u,\n", width) < 0)
goto done;
if (fprintf(fp, "\t.vf_height\t= %u,\n", height) < 0)
goto done;
if (fprintf(fp, "\t.vf_map_count\t= { %u, %u, %u, %u }\n",
map_folded_count[0], map_folded_count[1], map_folded_count[2],
map_folded_count[3]) < 0) {
goto done;
}
if (fprintf(fp, "};\n\n") < 0)
goto done;
/* Write bitmap data. */
if (fprintf(fp, "vt_font_bitmap_data_t font_data_%ux%u = {\n",
width, height) < 0)
goto done;
if (fprintf(fp, "\t.vfbd_width\t= %u,\n", width) < 0)
goto done;
if (fprintf(fp, "\t.vfbd_height\t= %u,\n", height) < 0)
goto done;
if (lz4 == true) {
if (fprintf(fp, "\t.vfbd_compressed_size\t= %zu,\n",
compressed_size) < 0) {
goto done;
}
if (fprintf(fp, "\t.vfbd_uncompressed_size\t= %zu,\n",
uncompressed_size) < 0) {
goto done;
}
if (fprintf(fp, "\t.vfbd_compressed_data\t= FONTDATA_%ux%u,\n",
width, height) < 0) {
goto done;
}
} else {
if (fprintf(fp, "\t.vfbd_compressed_size\t= 0,\n") < 0)
goto done;
if (fprintf(fp, "\t.vfbd_uncompressed_size\t= %zu,\n",
uncompressed_size) < 0) {
goto done;
}
if (fprintf(fp, "\t.vfbd_compressed_data\t= NULL,\n") < 0)
goto done;
}
if (fprintf(fp, "\t.vfbd_font = &font_%ux%u\n", width, height) < 0)
goto done;
if (fprintf(fp, "};\n") < 0)
goto done;
rv = 0;
done:
if (rv != 0)
perror(filename);
fclose(fp);
return (0);
}
static void static void
print_font_info(void) print_font_info(void)
{ {
@ -683,16 +1035,33 @@ print_font_info(void)
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int ch, verbose = 0; int ch, verbose = 0, rv = 0;
char *outfile = NULL;
assert(sizeof(struct file_header) == 32); assert(sizeof(struct font_header) == 32);
assert(sizeof(struct file_mapping) == 8); assert(sizeof(vfnt_map_t) == 8);
while ((ch = getopt(argc, argv, "h:vw:")) != -1) { while ((ch = getopt(argc, argv, "nf:h:vw:o:")) != -1) {
switch (ch) { switch (ch) {
case 'f':
if (strcmp(optarg, "font") == 0)
format = VT_FONT;
else if (strcmp(optarg, "source") == 0)
format = VT_C_SOURCE;
else if (strcmp(optarg, "compressed-source") == 0)
format = VT_C_COMPRESSED;
else
errx(1, "Invalid format: %s", optarg);
break;
case 'h': case 'h':
height = atoi(optarg); height = atoi(optarg);
break; break;
case 'n':
filter = false;
break;
case 'o':
outfile = optarg;
break;
case 'v': case 'v':
verbose = 1; verbose = 1;
break; break;
@ -707,9 +1076,14 @@ main(int argc, char *argv[])
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if (argc < 2 || argc > 3) if (outfile == NULL && (argc < 2 || argc > 3))
usage(); usage();
if (outfile == NULL) {
outfile = argv[argc - 1];
argc--;
}
set_width(width); set_width(width);
set_height(height); set_height(height);
@ -717,7 +1091,7 @@ main(int argc, char *argv[])
return (1); return (1);
argc--; argc--;
argv++; argv++;
if (argc == 2) { if (argc == 1) {
if (parse_file(argv[0], VFNT_MAP_BOLD) != 0) if (parse_file(argv[0], VFNT_MAP_BOLD) != 0)
return (1); return (1);
argc--; argc--;
@ -725,16 +1099,26 @@ main(int argc, char *argv[])
} }
number_glyphs(); number_glyphs();
dedup_mapping(VFNT_MAP_BOLD); dedup_mapping(VFNT_MAP_BOLD);
dedup_mapping(VFNT_MAP_BOLD_RH); dedup_mapping(VFNT_MAP_BOLD_RIGHT);
fold_mappings(0); fold_mappings(0);
fold_mappings(1); fold_mappings(1);
fold_mappings(2); fold_mappings(2);
fold_mappings(3); fold_mappings(3);
if (write_fnt(argv[0]) != 0)
return (1); switch (format) {
case VT_FONT:
rv = write_fnt(outfile);
break;
case VT_C_SOURCE:
rv = write_fnt_source(false, outfile);
break;
case VT_C_COMPRESSED:
rv = write_fnt_source(true, outfile);
break;
}
if (verbose) if (verbose)
print_font_info(); print_font_info();
return (0); return (rv);
} }

View File

@ -83,15 +83,6 @@ static struct {
struct video_info video_mode_info; struct video_info video_mode_info;
} cur_info; } cur_info;
struct vt4font_header {
uint8_t magic[8];
uint8_t width;
uint8_t height;
uint16_t pad;
uint32_t glyph_count;
uint32_t map_count[4];
} __packed;
static int hex = 0; static int hex = 0;
static int vesa_cols; static int vesa_cols;
static int vesa_rows; static int vesa_rows;
@ -404,9 +395,9 @@ load_vt4mappingtable(unsigned int nmappings, FILE *f)
} }
for (i = 0; i < nmappings; i++) { for (i = 0; i < nmappings; i++) {
t[i].src = be32toh(t[i].src); t[i].vfm_src = be32toh(t[i].vfm_src);
t[i].dst = be16toh(t[i].dst); t[i].vfm_dst = be16toh(t[i].vfm_dst);
t[i].len = be16toh(t[i].len); t[i].vfm_len = be16toh(t[i].vfm_len);
} }
return (t); return (t);
@ -428,7 +419,7 @@ load_default_vt4font(void)
static void static void
load_vt4font(FILE *f) load_vt4font(FILE *f)
{ {
struct vt4font_header fh; struct font_header fh;
static vfnt_t vfnt; static vfnt_t vfnt;
size_t glyphsize; size_t glyphsize;
unsigned int i; unsigned int i;
@ -438,16 +429,16 @@ load_vt4font(FILE *f)
return; return;
} }
if (memcmp(fh.magic, "VFNT0002", 8) != 0) { if (memcmp(fh.fh_magic, "VFNT0002", 8) != 0) {
warnx("bad magic in font file\n"); warnx("bad magic in font file\n");
return; return;
} }
for (i = 0; i < VFNT_MAPS; i++) for (i = 0; i < VFNT_MAPS; i++)
vfnt.map_count[i] = be32toh(fh.map_count[i]); vfnt.map_count[i] = be32toh(fh.fh_map_count[i]);
vfnt.glyph_count = be32toh(fh.glyph_count); vfnt.glyph_count = be32toh(fh.fh_glyph_count);
vfnt.width = fh.width; vfnt.width = fh.fh_width;
vfnt.height = fh.height; vfnt.height = fh.fh_height;
glyphsize = howmany(vfnt.width, 8) * vfnt.height * vfnt.glyph_count; glyphsize = howmany(vfnt.width, 8) * vfnt.height * vfnt.glyph_count;
if ((vfnt.glyphs = malloc(glyphsize)) == NULL) { if ((vfnt.glyphs = malloc(glyphsize)) == NULL) {