topti: support Unicode in the data structures (WIP)

This change modifies the font_t type to replace the concept of charset
with a more generic list of non-overlapping Unicode blocks defined by a
starting code point and a size.

It also takes advantage of the assembly feature of fxconv, introduced
for libimg long after the first version of topti, to support pointers in
the converted structure rather than having to tediously compute offsets
within a variable-size structure.
This commit is contained in:
Lephe 2020-07-14 12:11:12 +02:00
parent 77de9e7796
commit e3042755d2
Signed by untrusted user: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
5 changed files with 58 additions and 106 deletions

View File

@ -167,25 +167,38 @@ void dvline(int x, int color);
/* font_t: Font data encoded for topti */
typedef struct
{
/* Length of font name (not necessarily NUL-terminated!) */
uint title :5;
/* Font name (NUL-terminated), NULL if no title */
char const *name;
/* Font shape flags */
uint bold :1;
uint italic :1;
uint serif :1;
uint mono :1;
uint bold :1;
uint italic :1;
uint serif :1;
uint mono :1;
uint :3;
/* Whether data is variable-length (proportional font) */
uint prop :1;
/* Reserved for future use */
uint :2;
/* Implemented charcter set */
uint charset :4;
uint prop :1;
/* Line height */
uint8_t line_height;
/* Storage height */
uint8_t data_height;
/* The rest of the data depends on whether the font is proportional */
/* Number of Unicode blocks */
uint8_t block_count;
/* Number of total glyphs */
uint32_t glyph_count;
struct {
/* Unicode point of first character in block */
uint start :20;
/* Length of block */
uint length :12;
} *blocks;
/* Raw glyph data */
uint32_t *data;
union {
/* For monospaced fonts */
struct {
@ -193,23 +206,16 @@ typedef struct
uint16_t width;
/* Storage size, in longwords, of each glyph */
uint16_t storage_size;
/* Raw glyph data */
uint32_t data[];
};
/* For proportional fonts */
struct {
/* Storage index to find glyphs quickly */
uint16_t index[16];
/* Size array (padded to 4 bytes), 1 byte per entry,
followed by glyph data */
uint8_t sized_data[];
uint16_t *glyph_index;
/* Width of each individual glyph */
uint8_t *glyph_width;
};
};
/* The font name is stored after the data. The size is the length set
in the [title] field, padded to 4 bytes with NULs. There might not
be a NUL at the end. */
} GPACKED(4) font_t;
/* dfont(): Set the default font for text rendering

View File

@ -46,15 +46,7 @@ void topti_render(int x, int y, char const *str, size_t size, font_t const *f,
int fg, int bg)
{
/* Raw glyph data */
uint32_t const * data;
if(!f->prop) data = f->data;
else
{
int cs = charset_size(f->charset);
/* 4-align the result */
cs += (4 - cs) & 3;
data = (void *)(f->sized_data + cs);
}
uint32_t const *data = f->data;
/* Storage height, top position within glyph */
int height = f->data_height, top = 0;
@ -76,7 +68,7 @@ void topti_render(int x, int y, char const *str, size_t size, font_t const *f,
{
int c = *str++;
int glyph = charset_decode(f->charset, c);
int glyph = topti_glyph_index(f, c);
if(glyph < 0) continue;
/* Draw the space if background is opaque */
@ -95,7 +87,7 @@ void topti_render(int x, int y, char const *str, size_t size, font_t const *f,
/* Compute horizontal intersection between glyph and screen */
int dataw = f->prop ? f->sized_data[glyph] : f->width;
int dataw = f->prop ? f->glyph_width[glyph] : f->width;
int width = dataw, left = 0;
if(x + dataw <= 0)

View File

@ -88,15 +88,7 @@ void topti_render(int x, int y, char const *str, font_t const *f,
/* Storage height and number of free bits in operators[] */
int height = f->data_height, free;
/* Raw glyph data */
uint32_t const * data;
if(!f->prop) data = f->data;
else
{
int cs = charset_size(f->charset);
/* 4-align the result */
cs += (4 - cs) & 3;
data = (void *)(f->sized_data + cs);
}
uint32_t const *data = f->data;
/* Basic clipping */
if(x > 127 || y > 63 || y + height <= 0) return;
@ -126,13 +118,13 @@ void topti_render(int x, int y, char const *str, font_t const *f,
/* Pull each character into the operator buffer */
while(*str)
{
int glyph = charset_decode(f->charset, *str++);
int glyph = topti_glyph_index(f, *str++);
if(glyph < 0) continue;
int index = topti_offset(f, glyph);
/* Put glyph data into the operators */
int width = f->prop ? f->sized_data[glyph] : f->width;
int width = f->prop ? f->glyph_width[glyph] : f->width;
free = topti_split(data+index, width, height, free, operators);
/* Potential space after the glyph */

View File

@ -26,29 +26,12 @@ extern font_t const *topti_font;
/* Default font */
extern font_t const *gint_default_font;
/* enum topti_charset: Available character set decoders
Each charset is associated with a reduced character table. */
enum topti_charset
{
charset_numeric = 0, /* 10 elements: 0..9 */
charset_upper = 1, /* 26 elements: A..Z */
charset_alpha = 2, /* 52 elements: A..Z, a..z */
charset_alnum = 3, /* 62 elements: A..Z, a..z, 0..9 */
charset_print = 4, /* 95 elements: 0x20..0x7e */
charset_ascii = 5, /* 128 elements: 0x00..0x7f */
};
/* charset_size(): Number of elements in each character set
@set Character set ID
Returns the expected number of glyphs, -1 if charset ID is invalid. */
int charset_size(enum topti_charset set);
/* charset_decode(): Translate ASCII into reduced character sets
Returns the position of [c] in the character table of the given charset, or
-1 if [c] is not part of that set.
@set Any character set
@c Character to decode */
int charset_decode(enum topti_charset set, uint c);
/* 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,
or -1 if code_point is not part of that set.
@f Font object
@code_point Unicode code point to locate the glyph for */
int topti_glyph_index(font_t const *f, uint32_t code_point);
/* topti_offset(): Use a font index to find the location of a glyph
@f Font object

View File

@ -16,41 +16,20 @@ font_t const *dfont(font_t const * font)
return old_font;
}
/* charset_size(): Number of elements in each character set */
int charset_size(enum topti_charset set)
/* 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 size[] = { 10, 26, 52, 62, 95, 128 };
return (uint)set < 6 ? size[set] : -1;
}
int glyph_start = 0;
/* charset_decode(): Translate ASCII into reduced character sets */
int charset_decode(enum topti_charset set, uint c)
{
int x, y;
switch(set)
for(int i = 0; i < f->block_count; i++)
{
case charset_numeric:
x = c - '0';
return (x < 10) ? x : -1;
case charset_upper:
x = (c - 'A') & ~0x20;
return (x < 26) ? x : -1;
case charset_alnum:
x = c - '0';
if(x < 10) return x;
/* Intentional fallthrough */
case charset_alpha:
y = c & 0x20;
x = (c ^ y) - 'A';
/* Turn 32 into 26 and leave 0 as 0 */
y = y - (y >> 3) - (y >> 4);
return (x < 26) ? (x + y) : -1;
case charset_print:
x = c - 0x20;
return (x < 0x5f) ? x : -1;
case charset_ascii:
return c;
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;
@ -62,12 +41,12 @@ 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->sized_data;
uint8_t const *width = f->glyph_width;
/* The index gives us the position of all glyphs whose IDs are mutiples
of 8. Start with a close one and iterate from there. */
/* 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->index[g >> 3];
int offset = f->glyph_index[g >> 3];
/* Traverse the width array (which is in bits) while converting to
longword size */
@ -76,7 +55,7 @@ int topti_offset(font_t const *f, uint glyph)
return offset;
}
/* dsize() - get the width and height of rendered text */
/* dsize(): Get the width and height of rendered text */
void dsize(const char *str, font_t const * f, int *w, int *h)
{
if(!f) f = topti_font;
@ -105,8 +84,8 @@ void dsize(const char *str, font_t const * f, int *w, int *h)
continue;
}
int glyph = charset_decode(f->charset, c);
if(glyph > 0) width += f->sized_data[glyph] + CHAR_SPACING;
int glyph = topti_glyph_index(f, c);
if(glyph >= 0) width += f->glyph_width[glyph] + CHAR_SPACING;
}
*w = width - CHAR_SPACING;
}