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;