#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#define array_size(a) (sizeof(a) / sizeof((a)[0]))
#define FONT "FiraMonoOT-Regular.otf"
static FT_Library freetype;
static FT_Face font_face;
static _Noreturn void
die(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
fprintf(stderr, "Error: ");
vfprintf(stderr, fmt, args);
va_end(args);
fputc('\n', stderr);
exit(1);
}
enum {
MODE_C,
MODE_84,
};
static uint16_t interval_starts[128];
static uint8_t interval_sizes[128];
static int num_intervals;
static uint16_t charcodes[1024];
static uint32_t bitmap_offsets[1024];
static int num_glyphs;
static uint8_t bitmap_bytes[1024 * 1024];
static int num_bitmap_bytes;
void
write_c(void)
{
int fds[2];
pipe(fds);
if (fork() == 0) {
close(fds[1]);
dup2(fds[0], 0);
close(fds[0]);
execlp("fmt", "fmt", "--prefix= ", (char *)NULL);
}
close(fds[0]);
dup2(fds[1], 1);
close(fds[1]);
printf("static const uint16_t interval_starts[%d] = {\n\n ", num_intervals);
for (int i = 0; i < num_intervals; i++) {
printf("%u, ", (unsigned)interval_starts[i]);
}
printf("\n\n};\n\n");
printf("static const uint8_t interval_sizes[%d] = {\n\n ", num_intervals);
for (int i = 0; i < num_intervals; i++) {
printf("%u, ", (unsigned)interval_sizes[i]);
}
printf("\n\n};\n\n");
printf("static const uint16_t bitmap_offsets[%d] = {\n\n ", num_glyphs);
for (int i = 0; i < num_glyphs; i++) {
printf("%u, ", (unsigned)bitmap_offsets[i]);
}
printf("\n\n};\n\n");
printf("static const uint8_t bitmap_bytes[%d] = {\n\n ", num_bitmap_bytes);
for (int i = 0; i < num_bitmap_bytes; i++) {
printf("%u, ", (unsigned)bitmap_bytes[i]);
}
printf("\n\n};\n");
fflush(stdout);
close(1);
wait(NULL);
}
void
write_84(void)
{
for (int i = 0; i < num_intervals;) {
int begin = i;
printf(" (load 0 %5d \"", begin * 2);
for (; i < num_intervals && i - begin < 16; i++) {
printf("%02x", (unsigned)(interval_starts[i] & 0xff));
printf("%02x", (unsigned)(interval_starts[i] >> 8));
}
printf("\")\n");
}
printf("\n");
for (int i = 0; i < num_intervals;) {
int begin = i;
printf(" (load 1 %5d \"", begin);
for (; i < num_intervals && i - begin < 32; i++) {
printf("%02x", (unsigned)interval_sizes[i]);
}
printf("\")\n");
}
printf("\n");
for (int i = 0; i < num_glyphs;) {
int begin = i;
printf(" (load 2 %5d \"", begin * 2);
for (; i < num_glyphs && i - begin < 16; i++) {
printf("%02x", (unsigned)(bitmap_offsets[i] & 0xff));
printf("%02x", (unsigned)(bitmap_offsets[i] >> 8));
}
printf("\")\n");
}
printf("\n");
for (int i = 0; i < num_bitmap_bytes;) {
int begin = i;
printf(" (load 3 %5d \"", begin);
for (; i < num_bitmap_bytes && i - begin < 32; i++) {
printf("%02x", (unsigned)bitmap_bytes[i]);
}
printf("\")\n");
}
printf("\n");
}
int
main(int argc, const char *argv[])
{
int err;
const char *usage = "usage: build_fira_mono_table <mode>";
if (argc != 2)
die(usage);
int mode;
if (strcmp(argv[1], "c") == 0)
mode = MODE_C;
else if (strcmp(argv[1], "84") == 0)
mode = MODE_84;
else
die(usage);
err = FT_Init_FreeType(&freetype);
if (err)
die("Failed to initialize freetype.");
err = FT_New_Face(freetype, FONT, 0, &font_face);
if (err)
die("Failed to open font.");
err = FT_Set_Pixel_Sizes(font_face, 16, 16);
if (err)
die("Failed to set font size.");
FT_ULong charcode;
FT_UInt index;
FT_GlyphSlot slot = font_face->glyph;
charcode = FT_Get_First_Char(font_face, &index);
while (index != 0) {
bool choose =
(charcode == 0) ||
(32 <= charcode && charcode <= 126) ||
(0x80 <= charcode && charcode <= 0xff) ||
(0x2000 <= charcode && charcode <= 0x206f) ||
(0x2500 <= charcode && charcode <= 0x257f) ||
(charcode == 0x25c9);
if (choose) {
charcodes[num_glyphs] = charcode;
err = FT_Load_Glyph(font_face, index, FT_LOAD_RENDER);
if (err)
die("Failed to load glyph.");
bitmap_offsets[num_glyphs] = num_bitmap_bytes;
num_glyphs++;
bitmap_bytes[num_bitmap_bytes++] = (uint8_t)slot->bitmap_top;
bitmap_bytes[num_bitmap_bytes++] = (uint8_t)slot->bitmap_left;
bitmap_bytes[num_bitmap_bytes++] = (uint8_t)slot->bitmap.rows;
bitmap_bytes[num_bitmap_bytes++] = (uint8_t)slot->bitmap.width;
int num_pixels = slot->bitmap.rows * slot->bitmap.width;
for (int i = 0; i < num_pixels; i++)
bitmap_bytes[num_bitmap_bytes++] = slot->bitmap.buffer[i];
}
charcode = FT_Get_Next_Char(font_face, charcode, &index);
}
if (num_glyphs > 0) {
interval_starts[0] = charcodes[0];
interval_sizes[0] = 1;
for (int i = 1; i < num_glyphs; i++) {
if (charcodes[i - 1] + 1 != charcodes[i]) {
num_intervals++;
interval_starts[num_intervals] = charcodes[i];
}
interval_sizes[num_intervals]++;
}
num_intervals++;
}
if (mode == MODE_C)
write_c();
else if (mode == MODE_84)
write_84();
return 0;
}