From e3042755d2d4f579f1fa3d8ab8af7228791688c4 Mon Sep 17 00:00:00 2001 From: Lephe Date: Tue, 14 Jul 2020 12:11:12 +0200 Subject: [PATCH] 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. --- include/gint/display.h | 50 ++++++++++++++++++++---------------- src/render-cg/topti.c | 14 +++-------- src/render-fx/topti.c | 14 +++-------- src/render/render.h | 29 +++++---------------- src/render/topti.c | 57 +++++++++++++----------------------------- 5 files changed, 58 insertions(+), 106 deletions(-) diff --git a/include/gint/display.h b/include/gint/display.h index 2bdf74a..b43830c 100644 --- a/include/gint/display.h +++ b/include/gint/display.h @@ -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 diff --git a/src/render-cg/topti.c b/src/render-cg/topti.c index 6c04039..2d34d2c 100644 --- a/src/render-cg/topti.c +++ b/src/render-cg/topti.c @@ -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) diff --git a/src/render-fx/topti.c b/src/render-fx/topti.c index e53c0b3..f3da78e 100644 --- a/src/render-fx/topti.c +++ b/src/render-fx/topti.c @@ -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 */ diff --git a/src/render/render.h b/src/render/render.h index 95522c0..23c963e 100644 --- a/src/render/render.h +++ b/src/render/render.h @@ -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 diff --git a/src/render/topti.c b/src/render/topti.c index 0788beb..25fe0d9 100644 --- a/src/render/topti.c +++ b/src/render/topti.c @@ -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; }