mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2025-04-16 16:06:53 +02:00
This would work if the string has double NUL, which is common enough that this bug never came up before. x)
189 lines
4.2 KiB
C
189 lines
4.2 KiB
C
#include <gint/defs/types.h>
|
|
#include <gint/display.h>
|
|
|
|
#include "../render/render.h"
|
|
|
|
/* dfont(): Set the default font for text rendering */
|
|
font_t const *dfont(font_t const * font)
|
|
{
|
|
font_t const *old_font = topti_font;
|
|
|
|
topti_font = font ? font : gint_default_font;
|
|
return old_font;
|
|
}
|
|
|
|
/* dfont_default(): Get gint's default font */
|
|
font_t const *dfont_default(void)
|
|
{
|
|
return gint_default_font;
|
|
}
|
|
|
|
/* topti_glyph_index(): Obtain the glyph index of a Unicode code point */
|
|
int topti_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;
|
|
}
|
|
|
|
/* topti_offset(): Use a font index to find the location of a glyph */
|
|
int topti_offset(font_t const *f, uint glyph)
|
|
{
|
|
/* Non-proportional fonts don't need an index */
|
|
if(!f->prop) return glyph * f->storage_size;
|
|
|
|
uint8_t const *width = f->glyph_width;
|
|
|
|
/* The index gives us the position of all glyphs whose IDs are
|
|
multiples of 8. Start with a close one and iterate from there. */
|
|
uint g = glyph & ~0x7;
|
|
int offset = f->glyph_index[g >> 3];
|
|
|
|
/* Traverse the width array (which is in bits) while converting to
|
|
longword size */
|
|
while(g < glyph) offset += (width[g++] * f->data_height + 31) >> 5;
|
|
|
|
return offset;
|
|
}
|
|
|
|
/* topti_utf8_next(): Read the next UTF-8 code point of a string */
|
|
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;
|
|
}
|
|
|
|
/* dnsize(): Get the width and height of rendered text, with character limit */
|
|
void dnsize(char const *str_char, int size, font_t const *f, int *w, int *h)
|
|
{
|
|
uint8_t const *str = (void *)str_char;
|
|
uint8_t const *str0 = str;
|
|
uint32_t code_point;
|
|
|
|
if(!f) f = topti_font;
|
|
if(h) *h = f->line_height;
|
|
if(!w) return;
|
|
|
|
/* Width for monospaced fonts is easy, unfortunately we still need to
|
|
compute the length and group bytes into Unicode code points. */
|
|
if(!f->prop)
|
|
{
|
|
int length = 0;
|
|
while(1)
|
|
{
|
|
code_point = topti_utf8_next(&str);
|
|
if(!code_point || (size >= 0 && str - str0 > size))
|
|
break;
|
|
length++;
|
|
}
|
|
|
|
*w = (f->width + f->char_spacing) * length - f->char_spacing;
|
|
return;
|
|
}
|
|
|
|
/* For proportional fonts, fetch the width of each individual glyphs */
|
|
int width = 0;
|
|
|
|
while(1)
|
|
{
|
|
code_point = topti_utf8_next(&str);
|
|
if(!code_point || (size >= 0 && str - str0 > size)) break;
|
|
|
|
int glyph = topti_glyph_index(f, code_point);
|
|
if(glyph >= 0)
|
|
width += f->glyph_width[glyph] + f->char_spacing;
|
|
}
|
|
*w = width - f->char_spacing;
|
|
}
|
|
|
|
/* dsize(): Get the width and height of rendered text */
|
|
void dsize(char const *str_char, font_t const *f, int *w, int *h)
|
|
{
|
|
return dnsize(str_char, -1, f, w, h);
|
|
}
|
|
|
|
/* drsize(): Get width of rendered text with reverse size limit */
|
|
char const *drsize(char const *str_char, font_t const *f, int width, int *w)
|
|
{
|
|
uint8_t const *str = (void *)str_char;
|
|
uint32_t code_point;
|
|
|
|
int used_width = 0;
|
|
if(!f) f = topti_font;
|
|
|
|
while(used_width < width)
|
|
{
|
|
/* Record that last glyph considered fits */
|
|
str_char = (void *)str;
|
|
|
|
code_point = topti_utf8_next(&str);
|
|
if(!code_point)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(used_width > 0) used_width += f->char_spacing;
|
|
if(!f->prop)
|
|
{
|
|
used_width += f->width;
|
|
}
|
|
else
|
|
{
|
|
int glyph = topti_glyph_index(f, code_point);
|
|
if(glyph >= 0) used_width += f->glyph_width[glyph];
|
|
}
|
|
}
|
|
|
|
if(w) *w = used_width;
|
|
return str_char;
|
|
}
|