topti: support Unicode fonts

This change adds UTF-8 decoding to dtext() to fully use Unicode fonts
provided by fxconv.
This commit is contained in:
Lephe 2020-07-14 15:28:46 +02:00
parent e3042755d2
commit e16f3acfa1
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
4 changed files with 80 additions and 15 deletions

View file

@ -42,9 +42,11 @@ static void topti_glyph(uint16_t *vram, uint32_t const * data, int left,
dataw - width, index); dataw - width, index);
} }
void topti_render(int x, int y, char const *str, size_t size, font_t const *f, static void topti_render(int x, int y, char const *str_char, font_t const *f,
int fg, int bg) int fg, int bg)
{ {
uint8_t const *str = (void *)str_char;
/* Raw glyph data */ /* Raw glyph data */
uint32_t const *data = f->data; uint32_t const *data = f->data;
@ -64,15 +66,16 @@ void topti_render(int x, int y, char const *str, size_t size, font_t const *f,
int active_space = 0; int active_space = 0;
/* Read each character from the input string */ /* Read each character from the input string */
while(size--) while(1)
{ {
int c = *str++; uint32_t code_point = topti_utf8_next(&str);
if(!code_point) break;
int glyph = topti_glyph_index(f, c); int glyph = topti_glyph_index(f, code_point);
if(glyph < 0) continue; if(glyph < 0) continue;
/* Draw the space if background is opaque */ /* Draw the space if background is opaque */
int prop_space = (c == ' ' && f->prop) ? 5 : 0; int prop_space = (code_point == ' ' && f->prop) ? 5 : 0;
if(active_space || prop_space) if(active_space || prop_space)
{ {
active_space += prop_space; active_space += prop_space;
@ -124,5 +127,5 @@ void dtext_opt(int x, int y, int fg, int bg, int halign, int valign,
if(valign == DTEXT_MIDDLE) y -= ((h+1) >> 1); if(valign == DTEXT_MIDDLE) y -= ((h+1) >> 1);
} }
topti_render(x, y, str, strlen(str), topti_font, fg, bg); topti_render(x, y, str, topti_font, fg, bg);
} }

View file

@ -82,9 +82,11 @@ static int topti_split(uint32_t const * glyph, int width, int height, int free,
} }
/* topti_render(): Render a string on the VRAM */ /* topti_render(): Render a string on the VRAM */
void topti_render(int x, int y, char const *str, font_t const *f, void topti_render(int x, int y, char const *str_char, font_t const *f,
asm_text_t *asm_fg, asm_text_t *asm_bg, uint32_t *v1, uint32_t *v2) asm_text_t *asm_fg, asm_text_t *asm_bg, uint32_t *v1, uint32_t *v2)
{ {
uint8_t const *str = (void *)str_char;
/* Storage height and number of free bits in operators[] */ /* Storage height and number of free bits in operators[] */
int height = f->data_height, free; int height = f->data_height, free;
/* Raw glyph data */ /* Raw glyph data */
@ -116,9 +118,12 @@ void topti_render(int x, int y, char const *str, font_t const *f,
v2 += (y << 2) + x; v2 += (y << 2) + x;
/* Pull each character into the operator buffer */ /* Pull each character into the operator buffer */
while(*str) while(1)
{ {
int glyph = topti_glyph_index(f, *str++); uint32_t code_point = topti_utf8_next(&str);
if(!code_point) break;
int glyph = topti_glyph_index(f, code_point);
if(glyph < 0) continue; if(glyph < 0) continue;
int index = topti_offset(f, glyph); int index = topti_offset(f, glyph);

View file

@ -26,6 +26,11 @@ extern font_t const *topti_font;
/* Default font */ /* Default font */
extern font_t const *gint_default_font; extern font_t const *gint_default_font;
/* topti_utf8_next(): Read the next UTF-8 code point of a string
Returns the next code point and advances the string. Returns 0 (NUL) at the
end of the string. */
uint32_t topti_utf8_next(uint8_t const **str_pointer);
/* topti_glyph_index(): Obtain the glyph index of a Unicode code point /* topti_glyph_index(): Obtain the glyph index of a Unicode code point
Returns the position of code_point in the character table of the given font, Returns the position of code_point in the character table of the given font,
or -1 if code_point is not part of that set. or -1 if code_point is not part of that set.

View file

@ -55,9 +55,57 @@ int topti_offset(font_t const *f, uint glyph)
return offset; return offset;
} }
/* dsize(): Get the width and height of rendered text */ /* topti_utf8_next(): Read the next UTF-8 code point of a string */
void dsize(const char *str, font_t const * f, int *w, int *h) uint32_t topti_utf8_next(uint8_t const **str_pointer)
{ {
uint8_t const *str = *str_pointer;
uint8_t lead = *str++;
/* Skip non-leaders which are invalid as starting bytes */
while((lead >= 0x80 && lead <= 0xbf) ||
lead == 0xc0 || lead == 0xc1 || lead == 0xfe || lead == 0xff)
{
lead = *str++;
}
/* This base case will handle the NUL terminator */
if(lead <= 0x7f)
{
*str_pointer = str;
return lead;
}
uint8_t n2 = (*str++ & 0x3f);
if(lead <= 0xdf)
{
*str_pointer = str;
return ((lead & 0x1f) << 6) | n2;
}
uint8_t n3 = (*str++ & 0x3f);
if(lead <= 0xef)
{
*str_pointer = str;
return ((lead & 0x0f) << 12) | (n2 << 6) | n3;
}
uint8_t n4 = (*str++ & 0x3f);
if(lead <= 0xf7)
{
*str_pointer = str;
return ((lead & 0x07) << 18) | (n2 << 12) | (n3 << 6) | n4;
}
/* It the string is too invalid, force a space and try to continue */
*str_pointer = str;
return 0x20;
}
/* dsize(): Get the width and height of rendered text */
void dsize(char const *str_char, font_t const * f, int *w, int *h)
{
uint8_t const *str = (void *)str_char;
if(!f) f = topti_font; if(!f) f = topti_font;
if(h) *h = f->line_height; if(h) *h = f->line_height;
if(!w) return; if(!w) return;
@ -74,17 +122,21 @@ void dsize(const char *str, font_t const * f, int *w, int *h)
} }
/* For proportional fonts, fetch the width of each individual glyphs */ /* For proportional fonts, fetch the width of each individual glyphs */
int width = 0, c; int width = 0;
uint32_t code_point;
while((c = *str++)) while(1)
{ {
if(c == ' ') code_point = topti_utf8_next(&str);
if(!code_point) break;
if(code_point == ' ')
{ {
width += PROP_SPACING + CHAR_SPACING; width += PROP_SPACING + CHAR_SPACING;
continue; continue;
} }
int glyph = topti_glyph_index(f, c); int glyph = topti_glyph_index(f, code_point);
if(glyph >= 0) width += f->glyph_width[glyph] + CHAR_SPACING; if(glyph >= 0) width += f->glyph_width[glyph] + CHAR_SPACING;
} }
*w = width - CHAR_SPACING; *w = width - CHAR_SPACING;