Use the average width of ASCII glyphs for cell width
As some CJK fonts are dual-width, calculate the average width of ASCII glyphs and use that instead of the max_x_advance of the font. This is what VTE does too. https://bugs.freedesktop.org/show_bug.cgi?id=63796
This commit is contained in:
committed by
Kristian Høgsberg
parent
aaadc774a7
commit
f291f20553
+41
-14
@@ -54,6 +54,16 @@ terminal_destroy(struct terminal *terminal);
|
|||||||
static int
|
static int
|
||||||
terminal_run(struct terminal *terminal, const char *path);
|
terminal_run(struct terminal *terminal, const char *path);
|
||||||
|
|
||||||
|
#define TERMINAL_DRAW_SINGLE_WIDE_CHARACTERS \
|
||||||
|
" !\"#$%&'()*+,-./" \
|
||||||
|
"0123456789" \
|
||||||
|
":;<=>?@" \
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
|
||||||
|
"[\\]^_`" \
|
||||||
|
"abcdefghijklmnopqrstuvwxyz" \
|
||||||
|
"{|}~" \
|
||||||
|
""
|
||||||
|
|
||||||
#define MOD_SHIFT 0x01
|
#define MOD_SHIFT 0x01
|
||||||
#define MOD_ALT 0x02
|
#define MOD_ALT 0x02
|
||||||
#define MOD_CTRL 0x04
|
#define MOD_CTRL 0x04
|
||||||
@@ -407,6 +417,7 @@ struct terminal {
|
|||||||
struct color_scheme *color_scheme;
|
struct color_scheme *color_scheme;
|
||||||
struct terminal_color color_table[256];
|
struct terminal_color color_table[256];
|
||||||
cairo_font_extents_t extents;
|
cairo_font_extents_t extents;
|
||||||
|
double average_width;
|
||||||
cairo_scaled_font_t *font_normal, *font_bold;
|
cairo_scaled_font_t *font_normal, *font_bold;
|
||||||
uint32_t hide_cursor_serial;
|
uint32_t hide_cursor_serial;
|
||||||
|
|
||||||
@@ -760,12 +771,12 @@ resize_handler(struct widget *widget,
|
|||||||
int32_t columns, rows, m;
|
int32_t columns, rows, m;
|
||||||
|
|
||||||
m = 2 * terminal->margin;
|
m = 2 * terminal->margin;
|
||||||
columns = (width - m) / (int32_t) terminal->extents.max_x_advance;
|
columns = (width - m) / (int32_t) terminal->average_width;
|
||||||
rows = (height - m) / (int32_t) terminal->extents.height;
|
rows = (height - m) / (int32_t) terminal->extents.height;
|
||||||
|
|
||||||
if (!window_is_fullscreen(terminal->window) &&
|
if (!window_is_fullscreen(terminal->window) &&
|
||||||
!window_is_maximized(terminal->window)) {
|
!window_is_maximized(terminal->window)) {
|
||||||
width = columns * terminal->extents.max_x_advance + m;
|
width = columns * terminal->average_width + m;
|
||||||
height = rows * terminal->extents.height + m;
|
height = rows * terminal->extents.height + m;
|
||||||
widget_set_size(terminal->widget, width, height);
|
widget_set_size(terminal->widget, width, height);
|
||||||
}
|
}
|
||||||
@@ -783,7 +794,7 @@ terminal_resize(struct terminal *terminal, int columns, int rows)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
m = 2 * terminal->margin;
|
m = 2 * terminal->margin;
|
||||||
width = columns * terminal->extents.max_x_advance + m;
|
width = columns * terminal->average_width + m;
|
||||||
height = rows * terminal->extents.height + m;
|
height = rows * terminal->extents.height + m;
|
||||||
|
|
||||||
frame_set_child_size(terminal->widget, width, height);
|
frame_set_child_size(terminal->widget, width, height);
|
||||||
@@ -930,6 +941,7 @@ redraw_handler(struct widget *widget, void *data)
|
|||||||
double d;
|
double d;
|
||||||
struct glyph_run run;
|
struct glyph_run run;
|
||||||
cairo_font_extents_t extents;
|
cairo_font_extents_t extents;
|
||||||
|
double average_width;
|
||||||
|
|
||||||
surface = window_get_surface(terminal->window);
|
surface = window_get_surface(terminal->window);
|
||||||
widget_get_allocation(terminal->widget, &allocation);
|
widget_get_allocation(terminal->widget, &allocation);
|
||||||
@@ -946,7 +958,8 @@ redraw_handler(struct widget *widget, void *data)
|
|||||||
cairo_set_scaled_font(cr, terminal->font_normal);
|
cairo_set_scaled_font(cr, terminal->font_normal);
|
||||||
|
|
||||||
extents = terminal->extents;
|
extents = terminal->extents;
|
||||||
side_margin = (allocation.width - terminal->width * extents.max_x_advance) / 2;
|
average_width = terminal->average_width;
|
||||||
|
side_margin = (allocation.width - terminal->width * average_width) / 2;
|
||||||
top_margin = (allocation.height - terminal->height * extents.height) / 2;
|
top_margin = (allocation.height - terminal->height * extents.height) / 2;
|
||||||
|
|
||||||
cairo_set_line_width(cr, 1.0);
|
cairo_set_line_width(cr, 1.0);
|
||||||
@@ -962,11 +975,11 @@ redraw_handler(struct widget *widget, void *data)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
terminal_set_color(terminal, cr, attr.attr.bg);
|
terminal_set_color(terminal, cr, attr.attr.bg);
|
||||||
cairo_move_to(cr, col * extents.max_x_advance,
|
cairo_move_to(cr, col * average_width,
|
||||||
row * extents.height);
|
row * extents.height);
|
||||||
cairo_rel_line_to(cr, extents.max_x_advance, 0);
|
cairo_rel_line_to(cr, average_width, 0);
|
||||||
cairo_rel_line_to(cr, 0, extents.height);
|
cairo_rel_line_to(cr, 0, extents.height);
|
||||||
cairo_rel_line_to(cr, -extents.max_x_advance, 0);
|
cairo_rel_line_to(cr, -average_width, 0);
|
||||||
cairo_close_path(cr);
|
cairo_close_path(cr);
|
||||||
cairo_fill(cr);
|
cairo_fill(cr);
|
||||||
}
|
}
|
||||||
@@ -984,12 +997,12 @@ redraw_handler(struct widget *widget, void *data)
|
|||||||
|
|
||||||
glyph_run_flush(&run, attr);
|
glyph_run_flush(&run, attr);
|
||||||
|
|
||||||
text_x = col * extents.max_x_advance;
|
text_x = col * average_width;
|
||||||
text_y = extents.ascent + row * extents.height;
|
text_y = extents.ascent + row * extents.height;
|
||||||
if (attr.attr.a & ATTRMASK_UNDERLINE) {
|
if (attr.attr.a & ATTRMASK_UNDERLINE) {
|
||||||
terminal_set_color(terminal, cr, attr.attr.fg);
|
terminal_set_color(terminal, cr, attr.attr.fg);
|
||||||
cairo_move_to(cr, text_x, (double)text_y + 1.5);
|
cairo_move_to(cr, text_x, (double)text_y + 1.5);
|
||||||
cairo_line_to(cr, text_x + extents.max_x_advance, (double) text_y + 1.5);
|
cairo_line_to(cr, text_x + average_width, (double) text_y + 1.5);
|
||||||
cairo_stroke(cr);
|
cairo_stroke(cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1005,11 +1018,11 @@ redraw_handler(struct widget *widget, void *data)
|
|||||||
d = 0.5;
|
d = 0.5;
|
||||||
|
|
||||||
cairo_set_line_width(cr, 1);
|
cairo_set_line_width(cr, 1);
|
||||||
cairo_move_to(cr, terminal->column * extents.max_x_advance + d,
|
cairo_move_to(cr, terminal->column * average_width + d,
|
||||||
terminal->row * extents.height + d);
|
terminal->row * extents.height + d);
|
||||||
cairo_rel_line_to(cr, extents.max_x_advance - 2 * d, 0);
|
cairo_rel_line_to(cr, average_width - 2 * d, 0);
|
||||||
cairo_rel_line_to(cr, 0, extents.height - 2 * d);
|
cairo_rel_line_to(cr, 0, extents.height - 2 * d);
|
||||||
cairo_rel_line_to(cr, -extents.max_x_advance + 2 * d, 0);
|
cairo_rel_line_to(cr, -average_width + 2 * d, 0);
|
||||||
cairo_close_path(cr);
|
cairo_close_path(cr);
|
||||||
|
|
||||||
cairo_stroke(cr);
|
cairo_stroke(cr);
|
||||||
@@ -1022,7 +1035,7 @@ redraw_handler(struct widget *widget, void *data)
|
|||||||
|
|
||||||
if (terminal->send_cursor_position) {
|
if (terminal->send_cursor_position) {
|
||||||
cursor_x = side_margin + allocation.x +
|
cursor_x = side_margin + allocation.x +
|
||||||
terminal->column * extents.max_x_advance;
|
terminal->column * average_width;
|
||||||
cursor_y = top_margin + allocation.y +
|
cursor_y = top_margin + allocation.y +
|
||||||
terminal->row * extents.height;
|
terminal->row * extents.height;
|
||||||
window_set_text_cursor_position(terminal->window,
|
window_set_text_cursor_position(terminal->window,
|
||||||
@@ -2371,7 +2384,7 @@ recompute_selection(struct terminal *terminal)
|
|||||||
int cw, ch;
|
int cw, ch;
|
||||||
union utf8_char *data;
|
union utf8_char *data;
|
||||||
|
|
||||||
cw = terminal->extents.max_x_advance;
|
cw = terminal->average_width;
|
||||||
ch = terminal->extents.height;
|
ch = terminal->extents.height;
|
||||||
widget_get_allocation(terminal->widget, &allocation);
|
widget_get_allocation(terminal->widget, &allocation);
|
||||||
width = terminal->width * cw;
|
width = terminal->width * cw;
|
||||||
@@ -2527,12 +2540,17 @@ output_handler(struct window *window, struct output *output, int enter,
|
|||||||
window_schedule_redraw(window);
|
window_schedule_redraw(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef howmany
|
||||||
|
#define howmany(x, y) (((x) + ((y) - 1)) / (y))
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct terminal *
|
static struct terminal *
|
||||||
terminal_create(struct display *display)
|
terminal_create(struct display *display)
|
||||||
{
|
{
|
||||||
struct terminal *terminal;
|
struct terminal *terminal;
|
||||||
cairo_surface_t *surface;
|
cairo_surface_t *surface;
|
||||||
cairo_t *cr;
|
cairo_t *cr;
|
||||||
|
cairo_text_extents_t text_extents;
|
||||||
|
|
||||||
terminal = malloc(sizeof *terminal);
|
terminal = malloc(sizeof *terminal);
|
||||||
if (terminal == NULL)
|
if (terminal == NULL)
|
||||||
@@ -2584,6 +2602,15 @@ terminal_create(struct display *display)
|
|||||||
cairo_scaled_font_reference(terminal->font_normal);
|
cairo_scaled_font_reference(terminal->font_normal);
|
||||||
|
|
||||||
cairo_font_extents(cr, &terminal->extents);
|
cairo_font_extents(cr, &terminal->extents);
|
||||||
|
|
||||||
|
/* Compute the average ascii glyph width */
|
||||||
|
cairo_text_extents(cr, TERMINAL_DRAW_SINGLE_WIDE_CHARACTERS,
|
||||||
|
&text_extents);
|
||||||
|
terminal->average_width = howmany
|
||||||
|
(text_extents.width,
|
||||||
|
strlen(TERMINAL_DRAW_SINGLE_WIDE_CHARACTERS));
|
||||||
|
terminal->average_width = ceil(terminal->average_width);
|
||||||
|
|
||||||
cairo_destroy(cr);
|
cairo_destroy(cr);
|
||||||
cairo_surface_destroy(surface);
|
cairo_surface_destroy(surface);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user