From 61f950f77ac52779b5fcf34c628df4caee791af4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 6 Sep 2020 19:14:46 +0200 Subject: [PATCH] grid: reflow: calculate width of composed characters correctly Before this patch, reflow called `wcwidth()` on our magic values for composed characters. --- CHANGELOG.md | 1 + grid.c | 24 ++++++++++++++++++++---- grid.h | 4 +++- render.c | 6 ++++-- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2f9b4e8..1728f202 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -103,6 +103,7 @@ (https://codeberg.org/dnkl/foot/issues/101). * Missing DPI values for “some” monitors on Gnome (https://codeberg.org/dnkl/foot/issues/118). +* Handling of multi-column composed characters while reflowing. ### Security diff --git a/grid.c b/grid.c index 24a67903..5f050fc2 100644 --- a/grid.c +++ b/grid.c @@ -57,7 +57,9 @@ void grid_reflow(struct grid *grid, int new_rows, int new_cols, int old_screen_rows, int new_screen_rows, size_t tracking_points_count, - struct coord *const _tracking_points[static tracking_points_count]) + struct coord *const _tracking_points[static tracking_points_count], + size_t compose_count, const struct + composed composed[static compose_count]) { struct row *const *old_grid = grid->rows; const int old_rows = grid->num_rows; @@ -225,19 +227,33 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, if (new_cols_left < cols_needed && new_cols_left >= old_cols_left) empty_count = max(0, empty_count - (cols_needed - new_cols_left)); - int width = max(1, wcwidth(old_row->cells[c].wc)); + wchar_t wc = old_row->cells[c].wc; + if (wc >= CELL_COMB_CHARS_LO && + wc < (CELL_COMB_CHARS_LO + compose_count)) + { + wc = composed[wc - CELL_COMB_CHARS_LO].base; + } + + int width = max(1, wcwidth(wc)); /* Multi-column characters are never cut in half */ assert(c + width <= old_cols); for (int i = 0; i < empty_count + 1; i++) { const struct cell *old_cell = &old_row->cells[c - empty_count + i]; + wc = old_cell->wc; - if (old_cell->wc == CELL_MULT_COL_SPACER) + if (wc == CELL_MULT_COL_SPACER) continue; + if (wc >= CELL_COMB_CHARS_LO && + wc < (CELL_COMB_CHARS_LO + compose_count)) + { + wc = composed[wc - CELL_COMB_CHARS_LO].base; + } + /* Out of columns on current row in new grid? */ - if (new_col_idx + max(1, wcwidth(old_cell->wc)) > new_cols) { + if (new_col_idx + max(1, wcwidth(wc)) > new_cols) { /* Pad to end-of-line with spacers, then line-wrap */ for (;new_col_idx < new_cols; new_col_idx++) print_spacer(); diff --git a/grid.h b/grid.h index b074381e..cbe60536 100644 --- a/grid.h +++ b/grid.h @@ -10,7 +10,9 @@ void grid_reflow( struct grid *grid, int new_rows, int new_cols, int old_screen_rows, int new_screen_rows, size_t tracking_points_count, - struct coord *const tracking_points[static tracking_points_count]); + struct coord *const tracking_points[static tracking_points_count], + size_t compose_count, + const struct composed composed[static compose_count]); static inline int grid_row_absolute(const struct grid *grid, int row_no) diff --git a/render.c b/render.c index ea21b808..8b26c751 100644 --- a/render.c +++ b/render.c @@ -2110,12 +2110,14 @@ maybe_resize(struct terminal *term, int width, int height, bool force) grid_reflow( &term->normal, new_normal_grid_rows, new_cols, old_rows, new_rows, term->grid == &term->normal ? ALEN(tracking_points) : 0, - term->grid == &term->normal ? tracking_points : NULL); + term->grid == &term->normal ? tracking_points : NULL, + term->composed_count, term->composed); grid_reflow( &term->alt, new_alt_grid_rows, new_cols, old_rows, new_rows, term->grid == &term->alt ? ALEN(tracking_points) : 0, - term->grid == &term->alt ? tracking_points : NULL); + term->grid == &term->alt ? tracking_points : NULL, + term->composed_count, term->composed); /* Reset tab stops */ tll_free(term->tab_stops);