From a50afc6500f398454da10a19b9204736f6e8b7da Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Tue, 26 Sep 2023 10:08:44 +0100 Subject: [PATCH] Update xrdp font handling to use new UTF-8 calls --- xrdp/funcs.c | 93 ---------------------- xrdp/lang.c | 4 +- xrdp/xrdp.h | 24 ++++-- xrdp/xrdp_bitmap.c | 53 ++++++------- xrdp/xrdp_login_wnd.c | 6 +- xrdp/xrdp_painter.c | 178 ++++++++++++++++++++++++++++++------------ xrdp/xrdp_types.h | 4 +- xrdp/xrdp_wm.c | 4 +- 8 files changed, 178 insertions(+), 188 deletions(-) diff --git a/xrdp/funcs.c b/xrdp/funcs.c index 02b10e84..da030c7c 100644 --- a/xrdp/funcs.c +++ b/xrdp/funcs.c @@ -166,80 +166,6 @@ check_bounds(struct xrdp_bitmap *b, int *x, int *y, int *cx, int *cy) return 1; } -/*****************************************************************************/ -/* add a ch at index position in text, index starts at 0 */ -/* if index = -1 add it to the end */ -int -add_char_at(char *text, int text_size, twchar ch, int index) -{ - int len; - int i; - twchar *wstr; - - len = g_mbstowcs(0, text, 0); - wstr = (twchar *)g_malloc((len + 16) * sizeof(twchar), 0); - g_mbstowcs(wstr, text, len + 1); - - if ((index >= len) || (index < 0)) - { - wstr[len] = ch; - wstr[len + 1] = 0; - g_wcstombs(text, wstr, text_size); - g_free(wstr); - return 0; - } - - for (i = (len - 1); i >= index; i--) - { - wstr[i + 1] = wstr[i]; - } - - wstr[i + 1] = ch; - wstr[len + 1] = 0; - g_wcstombs(text, wstr, text_size); - g_free(wstr); - return 0; -} - -/*****************************************************************************/ -/* remove a ch at index position in text, index starts at 0 */ -/* if index = -1 remove it from the end */ -int -remove_char_at(char *text, int text_size, int index) -{ - int len; - int i; - twchar *wstr; - - len = g_mbstowcs(0, text, 0); - - if (len <= 0) - { - return 0; - } - - wstr = (twchar *)g_malloc((len + 16) * sizeof(twchar), 0); - g_mbstowcs(wstr, text, len + 1); - - if ((index >= (len - 1)) || (index < 0)) - { - wstr[len - 1] = 0; - g_wcstombs(text, wstr, text_size); - g_free(wstr); - return 0; - } - - for (i = index; i < (len - 1); i++) - { - wstr[i] = wstr[i + 1]; - } - - wstr[len - 1] = 0; - g_wcstombs(text, wstr, text_size); - g_free(wstr); - return 0; -} - /*****************************************************************************/ int set_string(char **in_str, const char *in) @@ -253,22 +179,3 @@ set_string(char **in_str, const char *in) *in_str = g_strdup(in); return 0; } - -/*****************************************************************************/ -int -wchar_repeat(twchar *dest, int dest_size_in_wchars, twchar ch, int repeat) -{ - int index; - - for (index = 0; index < repeat; index++) - { - if (index >= dest_size_in_wchars) - { - break; - } - - dest[index] = ch; - } - - return 0; -} diff --git a/xrdp/lang.c b/xrdp/lang.c index ba4e9c84..ad81e360 100644 --- a/xrdp/lang.c +++ b/xrdp/lang.c @@ -153,7 +153,7 @@ get_keysym_from_scan_code(int device_flags, int scan_code, int *keys, } /*****************************************************************************/ -twchar +char32_t get_char_from_scan_code(int device_flags, int scan_code, int *keys, int caps_lock, int num_lock, int scroll_lock, struct xrdp_keymap *keymap) @@ -169,7 +169,7 @@ get_char_from_scan_code(int device_flags, int scan_code, int *keys, return 0; } - return (twchar)(ki->chr); + return ki->chr; } /*****************************************************************************/ diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 43e096f9..0db9f35b 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -333,6 +333,17 @@ xrdp_painter_draw_bitmap(struct xrdp_painter *self, int x, int y, int cx, int cy); int xrdp_painter_text_width(struct xrdp_painter *self, const char *text); + +/* As above, but have a maximum Unicode character count for the string */ +int +xrdp_painter_text_width_count(struct xrdp_painter *self, + const char *text, unsigned int c32_count); + +/* Size of a string composed of a repeated number of Unicode characters */ +int +xrdp_painter_repeated_char_width(struct xrdp_painter *self, + char32_t c32, unsigned int repeat_count); + unsigned int xrdp_painter_font_body_height(const struct xrdp_painter *self); int @@ -349,6 +360,11 @@ xrdp_painter_draw_text2(struct xrdp_painter *self, int box_right, int box_bottom, int x, int y, char *data, int data_len); int +xrdp_painter_draw_char(struct xrdp_painter *self, + struct xrdp_bitmap *bitmap, + int x, int y, char32_t chr, + unsigned int repeat_count); +int xrdp_painter_copy(struct xrdp_painter *self, struct xrdp_bitmap *src, struct xrdp_bitmap *dst, @@ -403,13 +419,7 @@ rect_contained_by(struct xrdp_rect *in1, int left, int top, int check_bounds(struct xrdp_bitmap *b, int *x, int *y, int *cx, int *cy); int -add_char_at(char *text, int text_size, twchar ch, int index); -int -remove_char_at(char *text, int text_size, int index); -int set_string(char **in_str, const char *in); -int -wchar_repeat(twchar *dest, int dest_size_in_wchars, twchar ch, int repeat); /* in lang.c */ struct xrdp_key_info * @@ -420,7 +430,7 @@ int get_keysym_from_scan_code(int device_flags, int scan_code, int *keys, int caps_lock, int num_lock, int scroll_lock, struct xrdp_keymap *keymap); -twchar +char32_t get_char_from_scan_code(int device_flags, int scan_code, int *keys, int caps_lock, int num_lock, int scroll_lock, struct xrdp_keymap *keymap); diff --git a/xrdp/xrdp_bitmap.c b/xrdp/xrdp_bitmap.c index 39affa8f..572464ce 100644 --- a/xrdp/xrdp_bitmap.c +++ b/xrdp/xrdp_bitmap.c @@ -621,8 +621,6 @@ xrdp_bitmap_invalidate(struct xrdp_bitmap *self, struct xrdp_rect *rect) struct xrdp_rect r2; struct xrdp_painter *painter; unsigned int font_height; - twchar wtext[256]; - char text[256]; char *p; if (self == 0) /* if no bitmap */ @@ -821,10 +819,9 @@ xrdp_bitmap_invalidate(struct xrdp_bitmap *self, struct xrdp_rect *rect) if (self->password_char != 0) { - i = g_mbstowcs(0, self->caption1, 0); - g_memset(text, self->password_char, i); - text[i] = 0; - xrdp_painter_draw_text(painter, self, 4, 2, text); + unsigned int repeat_count = utf8_char_count(self->caption1); + xrdp_painter_draw_char(painter, self, 4, 2, self->password_char, + repeat_count); } else { @@ -838,18 +835,16 @@ xrdp_bitmap_invalidate(struct xrdp_bitmap *self, struct xrdp_rect *rect) { if (self->password_char != 0) { - wchar_repeat(wtext, 255, self->password_char, self->edit_pos); - wtext[self->edit_pos] = 0; - g_wcstombs(text, wtext, 255); + w = xrdp_painter_repeated_char_width(painter, + self->password_char, + self->edit_pos); } else { - g_mbstowcs(wtext, self->caption1, 255); - wtext[self->edit_pos] = 0; - g_wcstombs(text, wtext, 255); + w = xrdp_painter_text_width_count(painter, self->caption1, + self->edit_pos); } - w = xrdp_painter_text_width(painter, text); painter->fg_color = self->wm->white; painter->rop = 0x5a; xrdp_painter_fill_rect(painter, self, 4 + w, 3, 2, self->height - 6); @@ -1027,14 +1022,11 @@ int xrdp_bitmap_def_proc(struct xrdp_bitmap *self, int msg, int param1, int param2) { - twchar c; int n; int i; int shift; int ext; int scan_code; - int num_bytes; - int num_chars; struct xrdp_bitmap *b; struct xrdp_bitmap *focus_out_control; @@ -1174,7 +1166,7 @@ xrdp_bitmap_def_proc(struct xrdp_bitmap *self, int msg, else if ((scan_code == 77 || scan_code == 80) && (ext || self->wm->num_lock == 0)) { - if (self->edit_pos < g_mbstowcs(0, self->caption1, 0)) + if (self->edit_pos < (int)utf8_char_count(self->caption1)) { self->edit_pos++; xrdp_bitmap_invalidate(self, 0); @@ -1183,14 +1175,14 @@ xrdp_bitmap_def_proc(struct xrdp_bitmap *self, int msg, /* backspace */ else if (scan_code == 14) { - n = g_mbstowcs(0, self->caption1, 0); + n = utf8_char_count(self->caption1); if (n > 0) { if (self->edit_pos > 0) { self->edit_pos--; - remove_char_at(self->caption1, 255, self->edit_pos); + utf8_remove_char_at(self->caption1, self->edit_pos); xrdp_bitmap_invalidate(self, 0); } } @@ -1199,13 +1191,13 @@ xrdp_bitmap_def_proc(struct xrdp_bitmap *self, int msg, else if (scan_code == 83 && (ext || self->wm->num_lock == 0)) { - n = g_mbstowcs(0, self->caption1, 0); + n = utf8_char_count(self->caption1); if (n > 0) { if (self->edit_pos < n) { - remove_char_at(self->caption1, 255, self->edit_pos); + utf8_remove_char_at(self->caption1, self->edit_pos); xrdp_bitmap_invalidate(self, 0); } } @@ -1214,7 +1206,7 @@ xrdp_bitmap_def_proc(struct xrdp_bitmap *self, int msg, else if (scan_code == 79 && (ext || self->wm->num_lock == 0)) { - n = g_mbstowcs(0, self->caption1, 0); + n = utf8_char_count(self->caption1); if (self->edit_pos < n) { @@ -1234,16 +1226,15 @@ xrdp_bitmap_def_proc(struct xrdp_bitmap *self, int msg, } else { - c = get_char_from_scan_code - (param2, scan_code, self->wm->keys, self->wm->caps_lock, - self->wm->num_lock, self->wm->scroll_lock, - &(self->wm->keymap)); - num_chars = g_mbstowcs(0, self->caption1, 0); - num_bytes = g_strlen(self->caption1); - - if ((c >= 32) && (num_chars < 127) && (num_bytes < 250)) + char32_t c = get_char_from_scan_code + (param2, scan_code, self->wm->keys, self->wm->caps_lock, + self->wm->num_lock, self->wm->scroll_lock, + &(self->wm->keymap)); + // Add a printing character to the string. If successful, + // bump the edit position and re-display the string + if (c >= ' ' && + utf8_add_char_at(self->caption1, 256, c, self->edit_pos)) { - add_char_at(self->caption1, 255, c, self->edit_pos); self->edit_pos++; xrdp_bitmap_invalidate(self, 0); } diff --git a/xrdp/xrdp_login_wnd.c b/xrdp/xrdp_login_wnd.c index 6c31868a..9ec7245a 100644 --- a/xrdp/xrdp_login_wnd.c +++ b/xrdp/xrdp_login_wnd.c @@ -467,7 +467,7 @@ xrdp_wm_show_edits(struct xrdp_wm *self, struct xrdp_bitmap *combo) { g_strncpy(b->caption1, value + ASK_LEN, 255); } - b->edit_pos = g_mbstowcs(0, b->caption1, 0); + b->edit_pos = utf8_char_count(b->caption1); if (self->login_window->focused_control == 0) { @@ -486,7 +486,7 @@ xrdp_wm_show_edits(struct xrdp_wm *self, struct xrdp_bitmap *combo) self->session->client_info->domain, combo->data_list->count, 0, resultIP); g_strncpy(b->caption1, resultIP, 255); - b->edit_pos = g_mbstowcs(0, b->caption1, 0); + b->edit_pos = utf8_char_count(b->caption1); } } @@ -495,7 +495,7 @@ xrdp_wm_show_edits(struct xrdp_wm *self, struct xrdp_bitmap *combo) self->session->client_info->username[0]) { g_strncpy(b->caption1, self->session->client_info->username, 255); - b->edit_pos = g_mbstowcs(0, b->caption1, 0); + b->edit_pos = utf8_char_count(b->caption1); if (b->edit_pos > 0) { diff --git a/xrdp/xrdp_painter.c b/xrdp/xrdp_painter.c index 3f92c6d2..50ab371a 100644 --- a/xrdp/xrdp_painter.c +++ b/xrdp/xrdp_painter.c @@ -22,6 +22,8 @@ #include #endif +#include + #include "xrdp.h" #include "string_calls.h" @@ -428,37 +430,54 @@ xrdp_painter_rop(int rop, int src, int dst) int xrdp_painter_text_width(struct xrdp_painter *self, const char *text) { - int index; - int rv; - int len; - struct xrdp_font_char *font_item; - twchar *wstr; + return xrdp_painter_text_width_count(self, text, UINT_MAX); +} - LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_painter_text_width:"); +/*****************************************************************************/ +int +xrdp_painter_text_width_count(struct xrdp_painter *self, const char *text, + unsigned int c32_count) +{ + int rv = 0; + + LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_painter_text_width_count:"); xrdp_painter_font_needed(self); - if (self->font == 0) + if (self->font != NULL && text != NULL) { - return 0; + unsigned int index; + for (index = 0 ; index < c32_count; ++index) + { + struct xrdp_font_char *font_item; + char32_t c32 = utf8_get_next_char(&text, NULL); + if (c32 == 0) + { + break; // Terminator + } + font_item = XRDP_FONT_GET_CHAR(self->font, c32); + rv += font_item->incby; + } } - if (text == 0) + return rv; +} + +/*****************************************************************************/ +int +xrdp_painter_repeated_char_width(struct xrdp_painter *self, + char32_t chr, unsigned int repeat_count) +{ + int rv = 0; + + LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_painter_repeated_char_width:"); + xrdp_painter_font_needed(self); + + if (self->font != NULL) { - return 0; + struct xrdp_font_char *font_item = XRDP_FONT_GET_CHAR(self->font, chr); + rv = font_item->incby * repeat_count; } - rv = 0; - len = g_mbstowcs(0, text, 0); - wstr = (twchar *)g_malloc((len + 2) * sizeof(twchar), 0); - g_mbstowcs(wstr, text, len + 1); - - for (index = 0; index < len; index++) - { - font_item = XRDP_FONT_GET_CHAR(self->font, wstr[index]); - rv = rv + font_item->incby; - } - - g_free(wstr); return rv; } @@ -764,10 +783,11 @@ xrdp_painter_fill_rect(struct xrdp_painter *self, } /*****************************************************************************/ -int -xrdp_painter_draw_text(struct xrdp_painter *self, - struct xrdp_bitmap *dst, - int x, int y, const char *text) +static int +xrdp_painter_draw_utf32(struct xrdp_painter *self, + struct xrdp_bitmap *dst, + int x, int y, + char32_t utf32[], unsigned int utf32len) { int i; int f; @@ -776,8 +796,7 @@ xrdp_painter_draw_text(struct xrdp_painter *self, int x1; int y1; int flags; - int len; - int index; + unsigned int index; int total_width; int total_height; int dx; @@ -789,7 +808,6 @@ xrdp_painter_draw_text(struct xrdp_painter *self, struct xrdp_rect draw_rect; struct xrdp_font *font; struct xrdp_font_char *font_item; - twchar *wstr; LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_painter_draw_text:"); @@ -798,9 +816,7 @@ xrdp_painter_draw_text(struct xrdp_painter *self, return 0; } - len = g_mbstowcs(0, text, 0); - - if (len < 1) + if (utf32len < 1) { return 0; } @@ -829,15 +845,15 @@ xrdp_painter_draw_text(struct xrdp_painter *self, if (dst->type != WND_TYPE_OFFSCREEN) { ldst = self->wm->screen; - /* convert to wide char */ - wstr = (twchar *)g_malloc((len + 2) * sizeof(twchar), 0); - g_mbstowcs(wstr, text, len + 1); font = self->font; + + // Calculate total width and height fields total_width = 0; total_height = 0; - for (index = 0; index < len; index++) + + for (index = 0 ; index < utf32len; ++index) { - font_item = XRDP_FONT_GET_CHAR(font, wstr[index]); + font_item = XRDP_FONT_GET_CHAR(font, utf32[index]); k = font_item->incby; total_width += k; /* Use the nominal height of the font to work out the @@ -846,6 +862,7 @@ xrdp_painter_draw_text(struct xrdp_painter *self, font->body_height + font_item->baseline + font_item->height; total_height = MAX(total_height, glyph_height); } + xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); xrdp_wm_get_vis_region(self->wm, dst, x, y, @@ -873,9 +890,9 @@ xrdp_painter_draw_text(struct xrdp_painter *self, draw_rect.left, draw_rect.top, draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top); - for (index = 0; index < len; index++) + for (index = 0 ; index < utf32len; ++index) { - font_item = XRDP_FONT_GET_CHAR(font, wstr[index]); + font_item = XRDP_FONT_GET_CHAR(font, utf32[index]); g_memset(&pat, 0, sizeof(pat)); pat.format = PT_FORMAT_c1; pat.width = font_item->width; @@ -899,25 +916,22 @@ xrdp_painter_draw_text(struct xrdp_painter *self, } painter_clear_clip(self->painter); xrdp_region_delete(region); - g_free(wstr); } return 0; #endif } - /* convert to wide char */ - wstr = (twchar *)g_malloc((len + 2) * sizeof(twchar), 0); - g_mbstowcs(wstr, text, len + 1); font = self->font; f = 0; k = 0; total_width = 0; total_height = 0; - data = (char *)g_malloc(len * 4, 1); + index = 0; + data = (char *)g_malloc(utf32len * 2, 1); - for (index = 0; index < len; index++) + for (index = 0 ; index < utf32len; ++index) { - font_item = XRDP_FONT_GET_CHAR(font, wstr[index]); + font_item = XRDP_FONT_GET_CHAR(font, utf32[index]); i = xrdp_cache_add_char(self->wm->cache, font_item); f = HIWORD(i); c = LOWORD(i); @@ -960,7 +974,7 @@ xrdp_painter_draw_text(struct xrdp_painter *self, self->fg_color, 0, x - 1, y - 1, x + total_width, y + total_height, 0, 0, 0, 0, - x1, y1, data, len * 2, &draw_rect); + x1, y1, data, utf32len * 2, &draw_rect); } k++; @@ -968,10 +982,44 @@ xrdp_painter_draw_text(struct xrdp_painter *self, xrdp_region_delete(region); g_free(data); - g_free(wstr); return 0; } + +/*****************************************************************************/ +int +xrdp_painter_draw_text(struct xrdp_painter *self, + struct xrdp_bitmap *dst, + int x, int y, const char *text) +{ + int rv = 0; + unsigned int c32_count = utf8_char_count(text); + + if (c32_count > 0) + { + char32_t *utf32 = (char32_t *)malloc(c32_count * sizeof(char32_t)); + if (utf32 == NULL) + { + rv = 1; + } + else + { + unsigned int i = 0; + char32_t c32; + + while ((c32 = utf8_get_next_char(&text, NULL)) != 0) + { + utf32[i++] = c32; + } + + rv = xrdp_painter_draw_utf32(self, dst, x, y, utf32, c32_count); + free (utf32); + } + } + + return rv; +} + /*****************************************************************************/ int xrdp_painter_draw_text2(struct xrdp_painter *self, @@ -1063,6 +1111,40 @@ xrdp_painter_draw_text2(struct xrdp_painter *self, return 0; } +/*****************************************************************************/ +int +xrdp_painter_draw_char(struct xrdp_painter *self, + struct xrdp_bitmap *dst, + int x, int y, char32_t chr, + unsigned int repeat_count) +{ + int rv = 0; + + if (repeat_count > 0) + { + char32_t *utf32 = + (char32_t *)malloc(repeat_count * sizeof(char32_t)); + + if (utf32 == NULL) + { + rv = 1; + } + else + { + unsigned int i = 0; + for (i = 0; i < repeat_count; ++i) + { + utf32[i] = chr; + } + + rv = xrdp_painter_draw_utf32(self, dst, x, y, utf32, repeat_count); + free (utf32); + } + } + + return rv; +} + /*****************************************************************************/ int xrdp_painter_copy(struct xrdp_painter *self, diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index e379ff50..ffdf4549 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -419,7 +419,7 @@ struct xrdp_mm struct xrdp_key_info { int sym; - int chr; + char32_t chr; }; struct xrdp_keymap @@ -632,7 +632,7 @@ struct xrdp_bitmap struct list *child_list; /* for edit */ int edit_pos; - twchar password_char; + char32_t password_char; /* for button or combo */ int state; /* for button 0 = normal 1 = down */ /* for combo */ diff --git a/xrdp/xrdp_wm.c b/xrdp/xrdp_wm.c index 1bf0ca78..879f1165 100644 --- a/xrdp/xrdp_wm.c +++ b/xrdp/xrdp_wm.c @@ -1645,8 +1645,8 @@ xrdp_wm_key_sync(struct xrdp_wm *self, int device_flags, int key_flags) } /*****************************************************************************/ -int -xrdp_wm_key_unicode(struct xrdp_wm *self, int device_flags, int unicode) +static int +xrdp_wm_key_unicode(struct xrdp_wm *self, int device_flags, char32_t unicode) { int index;