unicode-combining: store seen combining chains "globally" in the term struct

Instead of storing combining data per cell, realize that most
combinations are re-occurring and that there's lots of available space
left in the unicode range, and store seen base+combining combinations
chains in a per-terminal array.

When we encounter a combining character, we first try to pre-compose,
like before. If that fails, we then search for the current
base+combining combo in the list of previously seen combinations. If
not found there either, we allocate a new combo and add it to the
list. Regardless, the result is an index into this array. We store
this index, offsetted by COMB_CHARS_LO=0x40000000ul in the cell.

When rendering, we need to check if the cell character is a plain
character, or if it's a composed character (identified by checking if
the cell character is >= COMB_CHARS_LO).

Then we render the grapheme pretty much like before.
This commit is contained in:
Daniel Eklöf 2020-05-03 11:03:22 +02:00
parent ae7383189a
commit 62e0774319
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
8 changed files with 97 additions and 92 deletions

View file

@ -142,12 +142,7 @@ min_bufsize_for_extraction(const struct terminal *term)
{
const struct coord *start = &term->selection.start;
const struct coord *end = &term->selection.end;
const size_t chars_per_cell =
#if FOOT_UNICODE_MAX_COMBINING_CHARS > 0
1 + ALEN(term->grid->cur_row->comb_chars[0].chars);
#else
1;
#endif
const size_t chars_per_cell = 1 + ALEN(term->composed[0].combining);
switch (term->selection.kind) {
case SELECTION_NONE:
@ -239,16 +234,17 @@ extract_one(struct terminal *term, struct row *row, struct cell *cell,
ctx->empty_count = 0;
assert(ctx->idx + 1 <= ctx->size);
ctx->buf[ctx->idx++] = cell->wc;
#if FOOT_UNICODE_MAX_COMBINING_CHARS > 0
const struct combining_chars *comb_chars = &row->comb_chars[col];
if (cell->wc >= COMB_CHARS_LO && cell->wc < (COMB_CHARS_LO + term->composed_count)) {
const struct composed *composed = &term->composed[cell->wc - COMB_CHARS_LO];
assert(cell->wc != 0);
assert(ctx->idx + comb_chars->count <= ctx->size);
for (size_t i = 0; i < comb_chars->count; i++)
ctx->buf[ctx->idx++] = comb_chars->chars[i];
#endif
ctx->buf[ctx->idx++] = composed->base;
assert(ctx->idx + composed->count <= ctx->size);
for (size_t i = 0; i < composed->count; i++)
ctx->buf[ctx->idx++] = composed->combining[i];
} else
ctx->buf[ctx->idx++] = cell->wc;
ctx->last_row = row;
ctx->last_cell = cell;