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.
This commit is contained in:
Nicholas Marriott 2009-10-20 17:33:33 +00:00
parent 387f4d42cc
commit 62f234ce3b
3 changed files with 73 additions and 36 deletions

View File

@ -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

2
tmux.h
View File

@ -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];

13
tty.c
View File

@ -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