135 lines
2.7 KiB
C
135 lines
2.7 KiB
C
#include <vhex/display/font.h>
|
|
|
|
//---
|
|
// Internal
|
|
//---
|
|
|
|
/* dfont_utf8_next(): Read the next UTF-8 code point of a string */
|
|
static uint32_t dfont_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;
|
|
}
|
|
|
|
/* dfont_glyph_index(): Obtain the glyph index of a Unicode code point */
|
|
int dfont_glyph_index(font_t const *f, uint32_t code_point)
|
|
{
|
|
int glyph_start = 0;
|
|
|
|
for(int i = 0; i < f->block_count; i++) {
|
|
int diff = code_point - f->blocks[i].start;
|
|
if(diff >= 0 && diff < f->blocks[i].length) {
|
|
return glyph_start + diff;
|
|
}
|
|
|
|
glyph_start += f->blocks[i].length;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
//---
|
|
// Public API
|
|
//---
|
|
|
|
|
|
/* dfont_get() : get the current font */
|
|
font_t *dfont_get(void)
|
|
{
|
|
extern font_t font8x9;
|
|
return &font8x9;
|
|
}
|
|
|
|
/* dfont_geometry() : get the char geometry */
|
|
int dfont_text_geometry(
|
|
font_t *font,
|
|
char const * const str_char,
|
|
int *size,
|
|
size_t *w,
|
|
size_t *h
|
|
) {
|
|
uint8_t const *str0 = (void *)str_char;
|
|
uint8_t const *str1 = (void *)str_char;
|
|
uint32_t code_point;
|
|
size_t char_width;
|
|
size_t length = 0;
|
|
size_t mx = 0;
|
|
size_t x = 0;
|
|
size_t y = 0;
|
|
int limit;
|
|
int glyph;
|
|
|
|
/* handle special behaviour */
|
|
if (font == NULL)
|
|
font = dfont_get();
|
|
limit = -1;
|
|
if (size != NULL && *size >= 0)
|
|
limit = *size;
|
|
|
|
/* generate geometry information */
|
|
while (1) {
|
|
code_point = dfont_utf8_next(&str0);
|
|
if (code_point == 0 || (limit > 0 && str0 - str1 >= limit))
|
|
break;
|
|
|
|
char_width = font->width;
|
|
if (font->shape.prop == 1) {
|
|
glyph = dfont_glyph_index(font, code_point);
|
|
if (glyph < 0)
|
|
return (-1);
|
|
char_width = font->glyph_width[glyph];
|
|
}
|
|
|
|
/* line discipline */
|
|
x += char_width;
|
|
if (code_point == '\n') {
|
|
y += font->data_height;
|
|
x = 0;
|
|
}
|
|
if (x > mx) mx = x;
|
|
|
|
length++;
|
|
}
|
|
|
|
/* set geometry information */
|
|
if (w != NULL) *w = mx;
|
|
if (h != NULL) *h = y;
|
|
if (size != NULL) *size = length;
|
|
return (0);
|
|
}
|