From 62f234ce3b3fb10633f8bbb1d4159cd5c179345a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 20 Oct 2009 17:33:33 +0000 Subject: [PATCH] UTF-8 combined character fixes. Thai can have treble combinations (1 x width=1 then 2 x width=0) so bump the UTF-8 cell data size to 9 and alter the code to allow this. Also break off the combining code into a separate function, handle any further combining beyond the buffer size by replacing the character with _s, and when redrawing the UTF-8 character don't assume the first part has just been printed, redraw the entire line. --- screen-write.c | 94 +++++++++++++++++++++++++++++++++++--------------- tmux.h | 2 +- tty.c | 13 ++++--- 3 files changed, 73 insertions(+), 36 deletions(-) diff --git a/screen-write.c b/screen-write.c index 9f98153b..9ed8f93b 100644 --- a/screen-write.c +++ b/screen-write.c @@ -24,6 +24,7 @@ void screen_write_initctx(struct screen_write_ctx *, struct tty_ctx *, int); void screen_write_overwrite(struct screen_write_ctx *); +int screen_write_combine(struct screen_write_ctx *, u_char *); /* Initialise writing with a window. */ void @@ -977,8 +978,8 @@ screen_write_cell( struct screen *s = ctx->s; struct grid *gd = s->grid; struct tty_ctx ttyctx; - struct grid_utf8 gu, *tmp_gu; - u_int width, xx, i; + struct grid_utf8 gu; + u_int width, xx; struct grid_cell tmp_gc, *tmp_gcp; int insert = 0; @@ -1003,34 +1004,15 @@ screen_write_cell( (s->cx != screen_size_x(s) && s->cx > screen_size_x(s) - width))) return; - /* If the width is zero, combine onto the previous character. */ + /* + * If the width is zero, combine onto the previous character, if + * there is space. + */ if (width == 0) { - if (s->cx == 0) - return; - tmp_gcp = grid_view_get_cell(gd, s->cx - 1, s->cy); - if (!(tmp_gcp->flags & GRID_FLAG_UTF8)) { - tmp_gcp->flags |= GRID_FLAG_UTF8; - memset(&gu.data, 0xff, sizeof gu.data); - *gu.data = tmp_gcp->data; - gu.width = 1; - grid_view_set_utf8(gd, s->cx - 1, s->cy, &gu); + if (screen_write_combine(ctx, udata) == 0) { + screen_write_initctx(ctx, &ttyctx, 0); + tty_write(tty_cmd_utf8character, &ttyctx); } - tmp_gu = grid_view_get_utf8(gd, s->cx - 1, s->cy); - - for (i = 0; i < UTF8_SIZE; i++) { - if (tmp_gu->data[i] == 0xff) - break; - } - memcpy(tmp_gu->data + i, udata, UTF8_SIZE - i); - - /* - * Assume the previous character has just been input. - * XXX There is no guarantee this is true, need to redraw - * entire line. - */ - screen_write_initctx(ctx, &ttyctx, 0); - ttyctx.ptr = udata; - tty_write(tty_cmd_utf8character, &ttyctx); return; } @@ -1101,6 +1083,62 @@ screen_write_cell( } } +/* Combine a UTF-8 zero-width character onto the previous. */ +int +screen_write_combine(struct screen_write_ctx *ctx, u_char *udata) +{ + struct screen *s = ctx->s; + struct grid *gd = s->grid; + struct grid_cell *gc; + struct grid_utf8 *gu, tmp_gu; + u_int i, old_size, new_size; + + /* Can't combine if at 0. */ + if (s->cx == 0) + return (-1); + + /* Retrieve the previous cell and convert to UTF-8 if not already. */ + gc = grid_view_get_cell(gd, s->cx - 1, s->cy); + if (!(gc->flags & GRID_FLAG_UTF8)) { + memset(&tmp_gu.data, 0xff, sizeof tmp_gu.data); + *tmp_gu.data = gc->data; + tmp_gu.width = 1; + + grid_view_set_utf8(gd, s->cx - 1, s->cy, &tmp_gu); + gc->flags |= GRID_FLAG_UTF8; + } + + /* Get the previous cell's UTF-8 data. */ + gu = grid_view_get_utf8(gd, s->cx - 1, s->cy); + + /* Find the new size. */ + for (new_size = 0; new_size < UTF8_SIZE; new_size++) { + if (udata[new_size] == 0xff) + break; + } + + /* And the old size. */ + for (old_size = 0; old_size < UTF8_SIZE; old_size++) { + if (gu->data[old_size] == 0xff) + break; + } + + /* If there isn't space, scrap this character. */ + if (old_size + new_size > UTF8_SIZE) { + for (i = 0; i < gu->width && i != UTF8_SIZE; i++) + gu->data[i] = '_'; + if (i != UTF8_SIZE) + gu->data[i] = 0xff; + return (0); + } + + /* Otherwise save the character. */ + memcpy(gu->data + old_size, udata, new_size); + if (old_size + new_size != UTF8_SIZE) + gu->data[old_size + new_size] = 0xff; + return (0); +} + /* * UTF-8 wide characters are a bit of an annoyance. They take up more than one * cell on the screen, so following cells must not be drawn by marking them as diff --git a/tmux.h b/tmux.h index 5cd5132b..a61040b6 100644 --- a/tmux.h +++ b/tmux.h @@ -516,7 +516,7 @@ struct grid_cell { } __packed; /* Grid cell UTF-8 data. Used instead of data in grid_cell for UTF-8 cells. */ -#define UTF8_SIZE 8 +#define UTF8_SIZE 9 struct grid_utf8 { u_char width; u_char data[UTF8_SIZE]; diff --git a/tty.c b/tty.c index 93d61c0e..9ddffb95 100644 --- a/tty.c +++ b/tty.c @@ -874,14 +874,13 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_utf8character(struct tty *tty, const struct tty_ctx *ctx) { - u_char *ptr = ctx->ptr; - size_t i; + struct window_pane *wp = ctx->wp; - for (i = 0; i < UTF8_SIZE; i++) { - if (ptr[i] == 0xff) - break; - tty_putc(tty, ptr[i]); - } + /* + * Cannot rely on not being a partial character, so just redraw the + * whole line. + */ + tty_draw_line(tty, wp->screen, ctx->ocy, wp->xoff, wp->yoff); } void