Skip to content

Commit 7a894dc

Browse files
ihaanahoGadgetoid
authored andcommitted
PicoVector: Add support for utf-8 characters.
1 parent a2e8127 commit 7a894dc

File tree

1 file changed

+54
-9
lines changed

1 file changed

+54
-9
lines changed

libraries/pico_vector/alright-fonts.h

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ typedef struct {
7676
} af_path_t;
7777

7878
typedef struct {
79-
char codepoint;
79+
uint16_t codepoint;
8080
int8_t x, y, w, h;
8181
int8_t advance;
8282
uint8_t path_count;
@@ -106,7 +106,7 @@ typedef struct {
106106
} af_text_metrics_t;
107107

108108
bool af_load_font_file(AF_FILE file, af_face_t *face);
109-
void af_render_character(af_face_t *face, const char codepoint, af_text_metrics_t *tm);
109+
void af_render_character(af_face_t *face, uint16_t codepoint, af_text_metrics_t *tm);
110110
void af_render(af_face_t *face, const char *text, size_t tlen, float max_line_width, float max_height, af_text_metrics_t *tm);
111111
pp_rect_t af_measure(af_face_t *face, const char *text, size_t tlen, float max_line_width, af_text_metrics_t *tm);
112112

@@ -210,6 +210,33 @@ bool af_load_font_file(AF_FILE file, af_face_t *face) {
210210
return true;
211211
}
212212

213+
uint16_t get_utf8_char(const char *text, const char *end) {
214+
uint16_t codepoint;
215+
if((*text & 0x80) == 0x00) {
216+
codepoint = *text; // ASCII, codepoints U+0000...U007F
217+
}
218+
else if( ((*text & 0xE0) == 0xC0) && (text+1 <= end) && ((*(text+1) & 0xC0) == 0x80) ) {
219+
codepoint = ((uint16_t)(*text & 0x1F) << 6) + (*(text+1) & 0x3F); //codepoints U+0080...U+07FF
220+
}
221+
else if( ((*text & 0xF0) == 0xE0) && (text+2 <= end) && ((*(text+1) & 0xC0) == 0x80) && ((*(text+2) & 0xC0) == 0x80) ) {
222+
codepoint = ((uint16_t)(*text & 0x0F) << 12) + ((uint16_t)(*(text+1) & 0x3F) << 6) + (*(text+2) & 0x3F); // codepoints U+0800...U+FFFF
223+
}
224+
else {
225+
codepoint = 0xFFFF; // malformed UTF-8 sequences or unsupported codepoints starting at U+10000
226+
}
227+
return codepoint;
228+
}
229+
230+
uint8_t num_of_utf8_continuation_bytes(const char *text, const char *end) {
231+
uint8_t cont = 0;
232+
for(char c = *text; text < end; text++, c = *text) {
233+
if((c & 0xC0) == 0x80) {
234+
cont++;
235+
}
236+
}
237+
return cont;
238+
}
239+
213240
af_glyph_t *find_glyph(af_face_t *face, char c) {
214241
for(int i = 0; i < face->glyph_count; i++) {
215242
if(face->glyphs[i].codepoint == c) {
@@ -238,7 +265,7 @@ void af_render_glyph(af_glyph_t* glyph, af_text_metrics_t *tm) {
238265
pp_poly_free(poly);
239266
}
240267

241-
void af_render_character(af_face_t *face, const char c, af_text_metrics_t *tm) {
268+
void af_render_character(af_face_t *face, uint16_t c, af_text_metrics_t *tm) {
242269
af_glyph_t *glyph = find_glyph(face, c);
243270
if(!glyph) {
244271
return;
@@ -251,14 +278,23 @@ float get_line_width(af_face_t *face, const char *text, size_t *tlen, float max_
251278
const char *start = text;
252279
const char *end = text + *tlen;
253280
const char *last_space = nullptr;
254-
for(char c = *text; text < end; text++, c = *text) {
255-
af_glyph_t *glyph = find_glyph(face, c);
281+
uint16_t utf8_char;
282+
while(text < end) {
283+
utf8_char = get_utf8_char(text, end);
284+
text++;
285+
if(utf8_char > 0x7F) {
286+
text++;
287+
}
288+
if(utf8_char > 0x7FF) {
289+
text++;
290+
}
291+
af_glyph_t *glyph = find_glyph(face, utf8_char);
256292
if(!glyph) {
257293
continue;
258294
}
259295

260296
float char_width;
261-
if(c == L' ') {
297+
if(utf8_char == L' ') {
262298
char_width = (glyph->advance * tm->word_spacing) / 100.0f;
263299
last_space = text;
264300
} else {
@@ -311,6 +347,7 @@ void af_render(af_face_t *face, const char *text, size_t tlen, float max_line_wi
311347

312348
float line_height = (tm->line_height * 128.0f) / 100.0f;
313349
float scale = tm->size / 128.0f;
350+
uint16_t utf8_char;
314351

315352
struct {
316353
float x, y;
@@ -337,8 +374,16 @@ void af_render(af_face_t *face, const char *text, size_t tlen, float max_line_wi
337374
int line_width = get_line_width(face, line, &line_len, max_line_width, tm);
338375
char *end = line + line_len;
339376

340-
for(char c = *line; line < end; line++, c = *line) {
341-
af_glyph_t *glyph = find_glyph(face, c);
377+
while(line < end) {
378+
utf8_char = get_utf8_char(line, end);
379+
line++;
380+
if(utf8_char > 0x7F) {
381+
line++;
382+
}
383+
if(utf8_char > 0x7FF) {
384+
line++;
385+
}
386+
af_glyph_t *glyph = find_glyph(face, utf8_char);
342387
if(!glyph) {
343388
continue;
344389
}
@@ -361,7 +406,7 @@ void af_render(af_face_t *face, const char *text, size_t tlen, float max_line_wi
361406

362407
af_render_glyph(glyph, tm);
363408

364-
if(c == L' ') {
409+
if(utf8_char == L' ') {
365410
caret.x += (glyph->advance * tm->word_spacing) / 100.0f;
366411
} else {
367412
caret.x += (glyph->advance * tm->letter_spacing) / 100.0f;

0 commit comments

Comments
 (0)