commit 1f68875
seiko
·
2026-05-29 15:11:15 +0000 UTC
parent 549d0d5
complete bdf parser
2 files changed,
+164,
-16
+161,
-16
1@@ -1,5 +1,6 @@
2 #include <ctype.h>
3 #include <math.h>
4+#include <stdint.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8@@ -18,34 +19,183 @@ static int type(const char* path);
9 * @param f fontface to load font into
10 * @param path path to load font from
11 *
12- * @return -1=failed to load font
13+ * @return -1=fail, 0=success
14 */
15 static int load_bdf(Fontface* f, const char* path)
16 {
17- /* stub */
18- return -1;
19+ f->kind = FONT_BDF;
20+
21+ FILE* fp;
22+ fp = fopen(path, "r");
23+ if (!fp)
24+ return -1;
25+
26+ char line[1024];
27+ int asc = -1;
28+ int dsc = -1;
29+ int encoding = -1;
30+ int advance = 0;
31+ int bw = 0; /* bmp width */
32+ int bh = 0; /* bmp height */
33+ int xoff = 0;
34+ int yoff = 0;
35+ int seen_any_glyph = 0;
36+
37+ while (fgets(line, sizeof(line), fp)) {
38+ if (sscanf(line, "FONT_ASCENT %d", &asc) == 1)
39+ continue;
40+ if (sscanf(line, "FONT_DESCENT %d", &dsc) == 1)
41+ continue;
42+
43+ /* ignore everything until glyphs start */
44+ if (strncmp(line, "STARTCHAR", 9) != 0)
45+ continue;
46+
47+ /* reset vaules for new glyph */
48+ encoding = -1;
49+ advance = 0;
50+ bw = 0;
51+ bh = 0;
52+ xoff = 0;
53+ yoff = 0;
54+
55+ while (fgets(line, sizeof(line), fp)) {
56+ if (sscanf(line, "ENCODING %d", &encoding) == 1)
57+ continue;
58+ if (sscanf(line, "DWIDTH %d", &advance) == 1)
59+ continue;
60+ if (sscanf(line, "BBX %d %d %d %d",
61+ &bw, &bh, &xoff, &yoff) == 4)
62+ continue;
63+
64+ if (strncmp(line, "BITMAP", 6) == 0) {
65+ BdfGlyph* g;
66+ int rowbits;
67+
68+ /* invalid character code
69+ TODO: just skip it
70+ */
71+ if (encoding < 0 || encoding >= BDF_GLYPHS_MAX)
72+ break;
73+
74+ /* empty/invalid size */
75+ if (bw <= 0 || bh <= 0)
76+ break;
77+
78+ g = &f->bdf[encoding];
79+ free(g->bmp); /* prevent leak on reset */
80+ memset(g, 0, sizeof(*g));
81+
82+ g->w = bw;
83+ g->h = bh;
84+ g->xoff = xoff;
85+ g->yoff = yoff;
86+ g->adv = advance;
87+
88+ g->bmp = calloc((size_t)bw * bh, 1);
89+ if (!g->bmp) {
90+ fclose(fp);
91+ font_free(f);
92+ return -1;
93+ }
94+
95+ /* each bmp row in BDF is padded as a multiple
96+ of 8 bits. this rounds width up to the next
97+ multiple of 8
98+ */
99+ rowbits = (bw + 7) & ~7;
100+
101+ for (int y = 0; y < bh; y++) {
102+ uint64_t bits;
103+
104+ /* missing row */
105+ if (!fgets(line, sizeof(line), fp)) {
106+ fclose(fp);
107+ font_free(f);
108+ return -1;
109+ }
110+
111+ bits = strtoull(line, NULL, 16); /* hex to bits */
112+ for (int x = 0; x < bw; x++) {
113+ int bit = rowbits - 1 - x;
114+
115+ if ((bits >> bit) & 1)
116+ g->bmp[y * bw + x] = 255; /* solid */
117+ }
118+ }
119+
120+ g->valid = 1;
121+ if (advance > f->cellw)
122+ f->cellw = advance;
123+ seen_any_glyph = 1;
124+
125+ continue;
126+ }
127+
128+ if (strncmp(line, "ENDCHAR", 7) == 0)
129+ break;
130+ }
131+ }
132+
133+ fclose(fp);
134+
135+ if (!seen_any_glyph)
136+ return -1;
137+
138+ /* estimate asc/dsc if they werent provided */
139+ if (asc < 0 || dsc < 0) {
140+ asc = 0;
141+ dsc = 0;
142+
143+ for (int i = 0; i < BDF_GLYPHS_MAX; i++) {
144+ BdfGlyph* g = &f->bdf[i];
145+
146+ /* unloaded glpyh */
147+ if (!g->valid)
148+ continue;
149+
150+ /* highest point above baseline */
151+ if (g->h + g->yoff > asc)
152+ asc = g->h + g->yoff;
153+
154+ /* lowest point below baseline */
155+ if (-g->yoff > dsc)
156+ dsc = -g->yoff;
157+ }
158+ }
159+
160+ f->asc = asc;
161+ f->dsc = -dsc;
162+ f->cellh = asc + dsc;
163+ f->size = f->cellh;
164+
165+ if (f->cellw <= 0 || f->cellh <= 0) {
166+ font_free(f);
167+ return -1;
168+ }
169+
170+ return 0;
171 }
172
173 /*
174- * @brief load a bdf font
175+ * @brief load an sft font
176 *
177 * @param f fontface to load font into
178 * @param path path to load font from
179 * @param size size to load font as
180 *
181- * @return -1=failed to load font, 1=success
182+ * @return -1=failed to load font, 0=success
183 */
184 static int load_sft(Fontface* f, const char* path, double size)
185 {
186+ f->kind = FONT_SFT;
187+
188 SFT_LMetrics lm;
189 SFT_Glyph glyph;
190 SFT_GMetrics gm;
191
192- f->kind = FONT_SFT;
193-
194 if (!f || !path || size <= 0)
195 return -1;
196- memset(f, 0, sizeof(*f));
197
198 f->font = sft_loadfile(path);
199 if (!f->font)
200@@ -81,7 +231,7 @@ static int load_sft(Fontface* f, const char* path, double size)
201 if (f->cellw <= 0 || f->cellh <= 0)
202 goto fail;
203
204- return 1;
205+ return 0;
206
207 fail:
208 font_free(f);
209@@ -128,13 +278,8 @@ static int type(const char* path)
210 if (pl < 4)
211 return -1;
212
213- char ext[4];
214- memcpy(ext, path + pl - 4, 4);
215- ext[3] = '\0';
216-
217- if (strcicmp(ext, "bdf") == 0)
218+ if (strcicmp(path + pl - 4, ".bdf") == 0)
219 return FONT_BDF;
220-
221 return FONT_SFT;
222 }
223
224@@ -151,7 +296,7 @@ int font_load(Fontface* f, const char* path, double size)
225 if (t < 0)
226 return -1;
227
228- if (t == 0)
229+ if (t == FONT_BDF)
230 return load_bdf(f, path);
231
232 if (size <= 0)
+3,
-0
1@@ -18,7 +18,10 @@ typedef struct {
2 int adv; /* advance */
3 int w;
4 int h;
5+ int xoff;
6+ int yoff;
7 } BdfFont;
8+typedef BdfFont BdfGlyph;
9
10 typedef struct {
11 FontKind kind;