From: Jan Arne Petersen Date: Mon, 5 Nov 2012 02:26:39 +0000 (+0100) Subject: editor: Fix handling of UTF-8 text X-Git-Tag: 1.0.90~360 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6345faa39a29915a4146c988d7f095369bb80074;p=platform%2Fupstream%2Fweston.git editor: Fix handling of UTF-8 text Fix display, cursor movement and text deletion for UTF-8 text. Signed-off-by: Jan Arne Petersen --- diff --git a/clients/editor.c b/clients/editor.c index d185137..cbc7218 100644 --- a/clients/editor.c +++ b/clients/editor.c @@ -66,6 +66,40 @@ struct editor { struct text_entry *editor; }; +static const char * +utf8_start_char(const char *text, const char *p) +{ + for (; p >= text; --p) { + if ((*p & 0xc0) != 0x80) + return p; + } + return NULL; +} + +static const char * +utf8_prev_char(const char *text, const char *p) +{ + if (p > text) + return utf8_start_char(text, --p); + return NULL; +} + +static const char * +utf8_end_char(const char *p) +{ + while ((*p & 0xc0) == 0x80) + p++; + return p; +} + +static const char * +utf8_next_char(const char *p) +{ + if (*p != 0) + return utf8_end_char(++p); + return NULL; +} + static struct text_layout * text_layout_create(void) { @@ -148,6 +182,34 @@ text_layout_extents(struct text_layout *layout, cairo_text_extents_t *extents) extents); } +static uint32_t +bytes_from_glyphs(struct text_layout *layout, uint32_t index) +{ + int i; + uint32_t glyphs = 0, bytes = 0; + + for (i = 0; i < layout->num_clusters && glyphs < index; i++) { + bytes += layout->clusters[i].num_bytes; + glyphs += layout->clusters[i].num_glyphs; + } + + return bytes; +} + +static uint32_t +glyphs_from_bytes(struct text_layout *layout, uint32_t index) +{ + int i; + uint32_t glyphs = 0, bytes = 0; + + for (i = 0; i < layout->num_clusters && bytes < index; i++) { + bytes += layout->clusters[i].num_bytes; + glyphs += layout->clusters[i].num_glyphs; + } + + return glyphs; +} + static int text_layout_xy_to_index(struct text_layout *layout, double x, double y) { @@ -168,20 +230,21 @@ text_layout_xy_to_index(struct text_layout *layout, double x, double y) for (i = 0; i < layout->num_glyphs - 1; ++i) { d = layout->glyphs[i + 1].x - layout->glyphs[i].x; if (x < layout->glyphs[i].x + d/2) - return i; + return bytes_from_glyphs(layout, i); } d = extents.width - layout->glyphs[layout->num_glyphs - 1].x; if (x < layout->glyphs[layout->num_glyphs - 1].x + d/2) - return layout->num_glyphs - 1; + return bytes_from_glyphs(layout, layout->num_glyphs - 1); - return layout->num_glyphs; + return bytes_from_glyphs(layout, layout->num_glyphs); } static void text_layout_index_to_pos(struct text_layout *layout, uint32_t index, cairo_rectangle_t *pos) { cairo_text_extents_t extents; + int glyph_index = glyphs_from_bytes(layout, index); if (!pos) return; @@ -190,7 +253,7 @@ text_layout_index_to_pos(struct text_layout *layout, uint32_t index, cairo_recta layout->glyphs, layout->num_glyphs, &extents); - if ((int)index >= layout->num_glyphs) { + if (glyph_index >= layout->num_glyphs) { pos->x = extents.x_advance; pos->y = layout->num_glyphs ? layout->glyphs[layout->num_glyphs - 1].y : 0; pos->width = 1; @@ -198,9 +261,9 @@ text_layout_index_to_pos(struct text_layout *layout, uint32_t index, cairo_recta return; } - pos->x = layout->glyphs[index].x; - pos->y = layout->glyphs[index].y; - pos->width = (int)index < layout->num_glyphs - 1 ? layout->glyphs[index + 1].x : extents.x_advance - pos->x; + pos->x = layout->glyphs[glyph_index].x; + pos->y = layout->glyphs[glyph_index].y; + pos->width = glyph_index < layout->num_glyphs - 1 ? layout->glyphs[glyph_index + 1].x : extents.x_advance - pos->x; pos->height = extents.height; } @@ -268,6 +331,7 @@ text_model_delete_surrounding_text(void *data, { struct text_entry *entry = data; uint32_t cursor_index = index + entry->cursor; + const char *start, *end; if (cursor_index > strlen(entry->text)) { fprintf(stderr, "Invalid cursor index %d\n", index); @@ -282,7 +346,12 @@ text_model_delete_surrounding_text(void *data, if (length == 0) return; - text_entry_delete_text(entry, cursor_index, length); + start = utf8_start_char(entry->text, entry->text + cursor_index); + end = utf8_end_char(entry->text + cursor_index + length); + + text_entry_delete_text(entry, + start - entry->text, + end - start); } static void @@ -300,6 +369,7 @@ text_model_key(void *data, struct text_entry *entry = data; const char *state_label; const char *key_label = "released"; + const char *new_char; if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { state_label = "pressed"; @@ -313,15 +383,17 @@ text_model_key(void *data, key_label = "Enter"; break; case XKB_KEY_Left: - if (entry->cursor > 0) { - entry->cursor--; + new_char = utf8_prev_char(entry->text, entry->text + entry->cursor); + if (new_char != NULL) { + entry->cursor = new_char - entry->text; entry->anchor = entry->cursor; widget_schedule_redraw(entry->widget); } break; case XKB_KEY_Right: - if (entry->cursor < strlen(entry->text)) { - entry->cursor++; + new_char = utf8_next_char(entry->text + entry->cursor); + if (new_char != NULL) { + entry->cursor = new_char - entry->text; entry->anchor = entry->cursor; widget_schedule_redraw(entry->widget); }