commit aa0b633

uint  ·  2026-05-14 16:29:09 +0000 UTC
parent dd33bbb
add proper utf8 decoding instead of calling raw grapheme_decode_utf8

also rename csi_param->csi_idx
4 files changed,  +66, -16
+5, -5
 1@@ -55,12 +55,11 @@ static Glyph* get_glyph(Fontface* f, uint32_t cp)
 2 	SFT_Image img;
 3 	Glyph* g;
 4 
 5-	if (cp >= GLYPH_CACHE_MAX)
 6-		return NULL;
 7-
 8-	g = &glyphs[cp];
 9-	if (g->valid)
10+	g = &glyphs[cp % GLYPH_CACHE_MAX];
11+	if (g->valid && g->cp == cp)
12 		return g;
13+	free(g->bmp);
14+	memset(g, 0, sizeof(*g));
15 
16 	if (sft_lookup(&f->sft, cp, &glyph) < 0)
17 		return NULL;
18@@ -87,6 +86,7 @@ static Glyph* get_glyph(Fontface* f, uint32_t cp)
19 	g->h = gm.minHeight;
20 	g->lsb = gm.leftSideBearing;
21 	g->yoff = gm.yOffset;
22+	g->cp = cp;
23 	g->valid = true;
24 
25 	return g;
+2, -1
 1@@ -10,6 +10,7 @@
 2 #define Glyph _Glyph /* Xrender defines the same */
 3 typedef struct {
 4 	bool           valid;
 5+	uint32_t       cp;
 6 	int            w;
 7 	int            h;
 8 	int            lsb;
 9@@ -68,7 +69,7 @@ void draw_caret(uint32_t* dst, int w, int h, int cl, int rw, int cw, int ch,
10  * @param h buffer height
11  * @param x x-position to draw at
12  * @param baseline text baseline y-position
13- * @param cp (unicode) codepoint to draw
14+ * @param cp codepoint to draw
15  * @param fg foreground colour
16  */
17 void draw_codepoint(Fontface* face, uint32_t* dst, int w, int h, int x,
+3, -1
 1@@ -42,7 +42,9 @@ typedef struct {
 2 
 3 	enum TState   state;
 4 	int           csi_params[CSI_PARAMS_MAX];
 5-	int           csi_param;
 6+	int           csi_idx;
 7+	char          utf8[4];
 8+	size_t        utf8_len;
 9 } Term;
10 
11 /**
+56, -9
  1@@ -14,6 +14,8 @@ static void erase_display(Term* t, Caret* c);
  2 static void erase_line(Term* t, Caret* c);
  3 static void reset_rune(Term* t, int x, int y);
  4 static void sgr(Term* t);
  5+static void utf8_flush(Term* t, Caret* c);
  6+static void utf8_putc(Term* t, Caret* c, unsigned char ch);
  7 
  8 static const uint32_t ansi_colours[16] = { /* TODO */
  9 	0xff000000, 0xff0000cd, 0xff00cd00, 0xff00cdcd,
 10@@ -26,7 +28,7 @@ static const uint32_t ansi_colours[16] = { /* TODO */
 11  */
 12 static int csi_arg(Term* t, int i, int fallback)
 13 {
 14-	if (i > t->csi_param)
 15+	if (i > t->csi_idx)
 16 		return fallback;
 17 	if (t->csi_params[i] == 0)
 18 		return fallback;
 19@@ -148,7 +150,7 @@ static void csi_reset(Term* t)
 20 {
 21 	for (int i = 0; i < CSI_PARAMS_MAX; i++)
 22 		t->csi_params[i] = 0;
 23-	t->csi_param = 0;
 24+	t->csi_idx = 0;
 25 }
 26 
 27 /** TODO
 28@@ -209,7 +211,7 @@ static void reset_rune(Term* t, int x, int y)
 29  */
 30 static void sgr(Term* t)
 31 {
 32-	for (int i = 0; i <= t->csi_param; i++) {
 33+	for (int i = 0; i <= t->csi_idx; i++) {
 34 		int p = t->csi_params[i];
 35 
 36 		if (p == 0) {
 37@@ -229,7 +231,7 @@ static void sgr(Term* t)
 38 		else if (p == 49)
 39 			t->bg = TERM_DEFAULT_BG;
 40 		else if ((p == 38 || p == 48) &&
 41-		         i + 4 <= t->csi_param && t->csi_params[i + 1] == 2) {
 42+		         i + 4 <= t->csi_idx && t->csi_params[i + 1] == 2) {
 43 			uint32_t col = rgba(
 44 				t->csi_params[i + 2],
 45 				t->csi_params[i + 3],
 46@@ -244,6 +246,50 @@ static void sgr(Term* t)
 47 	}
 48 }
 49 
 50+/** TODO
 51+ */
 52+static void utf8_flush(Term* t, Caret* c)
 53+{
 54+	if (t->utf8_len == 0)
 55+		return;
 56+	term_putc(t, c, GRAPHEME_INVALID_CODEPOINT);
 57+	t->utf8_len = 0;
 58+}
 59+
 60+/** TODO
 61+ */
 62+static void utf8_putc(Term* t, Caret* c, unsigned char ch)
 63+{
 64+	uint_least32_t cp;
 65+	size_t ret;
 66+
 67+	if (ch < 0x80) {
 68+		utf8_flush(t, c);
 69+		term_putc(t, c, ch);
 70+		return;
 71+	}
 72+
 73+	if (t->utf8_len == sizeof(t->utf8))
 74+		utf8_flush(t, c);
 75+
 76+	t->utf8[t->utf8_len++] = (char)ch;
 77+	for (;;) {
 78+		ret = grapheme_decode_utf8(t->utf8, t->utf8_len, &cp);
 79+		if (ret > t->utf8_len)
 80+			return;
 81+		if (ret == 0) {
 82+			t->utf8_len = 0;
 83+			return;
 84+		}
 85+
 86+		term_putc(t, c, (uint32_t)cp);
 87+		t->utf8_len -= ret;
 88+		if (t->utf8_len == 0)
 89+			return;
 90+		memmove(t->utf8, t->utf8 + ret, t->utf8_len);
 91+	}
 92+}
 93+
 94 void term_clear(Term* t, Caret* c)
 95 {
 96 	for (int y = 0; y < t->rows; y++) {
 97@@ -410,10 +456,11 @@ bool term_write(Term* t, Caret* c, const char* s, size_t n)
 98 		switch (t->state) {
 99 		case TSTATE_NORMAL:
100 			if (ch == '\x1B') {
101+				utf8_flush(t, c);
102 				t->state = TSTATE_ESC;
103 			}
104 			else {
105-				term_putc(t, c, ch);
106+				utf8_putc(t, c, ch);
107 			}
108 			break;
109 
110@@ -429,12 +476,12 @@ bool term_write(Term* t, Caret* c, const char* s, size_t n)
111 
112 		case TSTATE_CSI:
113 			if (ch >= '0' && ch <= '9') {
114-				t->csi_params[t->csi_param] *= 10;
115-				t->csi_params[t->csi_param] += ch - '0';
116+				t->csi_params[t->csi_idx] *= 10;
117+				t->csi_params[t->csi_idx] += ch - '0';
118 			}
119 			else if (ch == ';') {
120-				if (t->csi_param + 1 < CSI_PARAMS_MAX)
121-					t->csi_param++;
122+				if (t->csi_idx + 1 < CSI_PARAMS_MAX)
123+					t->csi_idx++;
124 			}
125 			else if (ch == '?' || ch == '>' || ch == '=') {
126 				/* private CSI marker */