comparison nuklear_ui/font.c @ 2480:369a52e302e2

Try multiple results from fc-match on Linux rather than assuming the first choice font will be suitable
author Michael Pavone <pavone@retrodev.com>
date Sat, 30 Mar 2024 14:26:48 -0700
parents 3dd9c68472fb
children 48ab1e3e5df5
comparison
equal deleted inserted replaced
2479:29baf8d5a579 2480:369a52e302e2
3 #include <stdint.h> 3 #include <stdint.h>
4 #include <string.h> 4 #include <string.h>
5 #include "../util.h" 5 #include "../util.h"
6 #include "sfnt.h" 6 #include "sfnt.h"
7 7
8 char *default_font_path(void) 8 char **preferred_font_paths(uint32_t *num_out)
9 { 9 {
10 char ** ret;
10 #ifdef FONT_PATH 11 #ifdef FONT_PATH
11 FILE *f = fopen(FONT_PATH, "rb"); 12 FILE *f = fopen(FONT_PATH, "rb");
12 if (f) { 13 if (f) {
13 fclose(f); 14 fclose(f);
14 return strdup(FONT_PATH); 15 ret = calloc(1, sizeof(char*));
16 ret[0] = strdup(FONT_PATH);
17 *num_out = 1;
18 return ret;
15 } 19 }
16 #endif 20 #endif
17 //TODO: specify language dynamically once BlastEm is localized 21 //TODO: specify language dynamically once BlastEm is localized
18 FILE *fc_pipe = popen("fc-match :lang=en -f '%{file}'", "r"); 22 FILE *fc_pipe = popen("fc-match -s -f '%{file}\n' :lang=en", "r");
19 if (!fc_pipe) { 23 if (!fc_pipe) {
20 return NULL; 24 return NULL;
21 } 25 }
22 size_t buf_size = 128; 26 size_t buf_size = 4096;
23 char *buffer = NULL; 27 char *buffer = NULL;
24 size_t total = 0, read = 0; 28 size_t total = 0, read = 0;
25 do { 29 do {
26 total += read; 30 total += read;
27 buf_size *= 2; 31 buf_size *= 2;
31 } 35 }
32 read = fread(buffer, 1, buf_size - total, fc_pipe); 36 read = fread(buffer, 1, buf_size - total, fc_pipe);
33 } while (read == (buf_size - total)); 37 } while (read == (buf_size - total));
34 total += read; 38 total += read;
35 buffer[total] = 0; 39 buffer[total] = 0;
36 40 *num_out = 0;
37 return buffer; 41 for (size_t i = 0; i < total; i++)
42 {
43 if (buffer[i] == '\n') {
44 buffer[i] = 0;
45 if (i + 1 != total) {
46 (*num_out)++;
47 }
48 }
49 }
50 ret = calloc(*num_out, sizeof(char*));
51 size_t entry = 0;
52 ret[entry++] = buffer;
53 for (size_t i = 0; i < total - 1 && entry < *num_out; i++)
54 {
55 if (!buffer[i]) {
56 ret[entry++] = buffer + i + 1;
57 }
58 }
59 return ret;
38 } 60 }
39 61
40 uint8_t *default_font(uint32_t *size_out) 62 uint8_t *default_font(uint32_t *size_out)
41 { 63 {
42 char *path = default_font_path(); 64 uint8_t *ret = NULL;
43 if (!path) { 65 uint32_t num_fonts;
66 char **paths = preferred_font_paths(&num_fonts);
67 if (!paths) {
44 goto error; 68 goto error;
45 } 69 }
46 FILE *f = fopen(path, "rb"); 70 for (uint32_t i = 0; i < num_fonts && !ret; i++)
47 free(path); 71 {
48 if (!f) { 72 FILE *f = fopen(paths[i], "rb");
49 goto error; 73 if (!f) {
74 fprintf(stderr, "Failed to open font file %s\n", paths[i]);
75 continue;
76 }
77 long size = file_size(f);
78 uint8_t *buffer = malloc(size);
79 if (size != fread(buffer, 1, size, f)) {
80 fprintf(stderr, "Failed to read font file %s\n", paths[i]);
81 fclose(f);
82 continue;
83 }
84 fclose(f);
85 sfnt_container *sfnt = load_sfnt(buffer, size);
86 if (!sfnt) {
87 fprintf(stderr, "File %s does not contain SFNT resources\n", paths[i]);
88 free(buffer);
89 continue;
90 }
91 for (uint8_t j = 0; j < sfnt->num_fonts; j++)
92 {
93 if (sfnt_has_truetype_glyphs(sfnt->tables + j)) {
94 ret = sfnt_flatten(sfnt->tables + j, size_out);
95 sfnt = NULL;
96 break;
97 }
98 fprintf(stderr, "Font %s in file %s doesn't have TrueType glyphs\n", sfnt_name(sfnt->tables + j, SFNT_POSTSCRIPT), paths[i]);
99 }
100 if (sfnt) {
101 sfnt_free(sfnt);
102 }
50 } 103 }
51 long size = file_size(f); 104 free(paths[0]);
52 uint8_t *buffer = malloc(size); 105 free(paths);
53 if (size != fread(buffer, 1, size, f)) {
54 fclose(f);
55 goto error;
56 }
57 fclose(f);
58 sfnt_container *sfnt = load_sfnt(buffer, size);
59 if (!sfnt) {
60 free(buffer);
61 goto error;
62 }
63 return sfnt_flatten(sfnt->tables, size_out);
64 error: 106 error:
65 //TODO: try to find a suitable font in /usr/share/fonts as a fallback 107 //TODO: try to find a suitable font in /usr/share/fonts as a fallback
66 return NULL; 108 return ret;
67 } 109 }