[PATCH 1/2] As some CJK fonts are dual-width, use the average width of ASCII glyphs instead of the max_x_advance of the font, just like the vte project.

Bill Spitzak spitzak at gmail.com
Mon Jul 8 14:37:39 PDT 2013


This average will result in a value that does not match any of the 
characters. Using the width of '2' probably works better. This means 
that at least digits will line up (it is very common for all digits 
except perhaps '1' to have the same width). In theory you can use 'n' 
but I have gotten better proportional width columns by using '2' in the 
(rare) font where '2' and 'n' are different widths. Do not use the width 
of space as it is much too small.

Kristian Høgsberg wrote:
> On Thu, Jun 06, 2013 at 03:32:41PM +0800, Peng Wu wrote:
>> ---
>>  clients/terminal.c | 55 ++++++++++++++++++++++++++++++++++++++++--------------
>>  1 file changed, 41 insertions(+), 14 deletions(-)
> 
> Thanks, that makes sense, committed.  Sorry for the delay.
> 
> Kristian
> 
>> diff --git a/clients/terminal.c b/clients/terminal.c
>> index 2985726..0d4f726 100644
>> --- a/clients/terminal.c
>> +++ b/clients/terminal.c
>> @@ -54,6 +54,16 @@ terminal_destroy(struct terminal *terminal);
>>  static int
>>  terminal_run(struct terminal *terminal, const char *path);
>>  
>> +#define TERMINAL_DRAW_SINGLE_WIDE_CHARACTERS    \
>> +    " !\"#$%&'()*+,-./"                         \
>> +    "0123456789"                                \
>> +    ":;<=>?@"                                   \
>> +    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"                \
>> +    "[\\]^_`"                                   \
>> +    "abcdefghijklmnopqrstuvwxyz"                \
>> +    "{|}~"                                      \
>> +    ""
>> +
>>  #define MOD_SHIFT	0x01
>>  #define MOD_ALT		0x02
>>  #define MOD_CTRL	0x04
>> @@ -407,6 +417,7 @@ struct terminal {
>>  	struct color_scheme *color_scheme;
>>  	struct terminal_color color_table[256];
>>  	cairo_font_extents_t extents;
>> +	double average_width;
>>  	cairo_scaled_font_t *font_normal, *font_bold;
>>  	uint32_t hide_cursor_serial;
>>  
>> @@ -760,12 +771,12 @@ resize_handler(struct widget *widget,
>>  	int32_t columns, rows, m;
>>  
>>  	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;
>>  
>>  	if (!window_is_fullscreen(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;
>>  		widget_set_size(terminal->widget, width, height);
>>  	}
>> @@ -783,7 +794,7 @@ terminal_resize(struct terminal *terminal, int columns, int rows)
>>  		return;
>>  
>>  	m = 2 * terminal->margin;
>> -	width = columns * terminal->extents.max_x_advance + m;
>> +	width = columns * terminal->average_width + m;
>>  	height = rows * terminal->extents.height + m;
>>  
>>  	frame_set_child_size(terminal->widget, width, height);
>> @@ -930,6 +941,7 @@ redraw_handler(struct widget *widget, void *data)
>>  	double d;
>>  	struct glyph_run run;
>>  	cairo_font_extents_t extents;
>> +	double average_width;
>>  
>>  	surface = window_get_surface(terminal->window);
>>  	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);
>>  
>>  	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;
>>  
>>  	cairo_set_line_width(cr, 1.0);
>> @@ -962,11 +975,11 @@ redraw_handler(struct widget *widget, void *data)
>>  				continue;
>>  
>>  			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);
>> -			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, -extents.max_x_advance, 0);
>> +			cairo_rel_line_to(cr, -average_width, 0);
>>  			cairo_close_path(cr);
>>  			cairo_fill(cr);
>>  		}
>> @@ -984,12 +997,12 @@ redraw_handler(struct widget *widget, void *data)
>>  
>>  			glyph_run_flush(&run, attr);
>>  
>> -			text_x = col * extents.max_x_advance;
>> +			text_x = col * average_width;
>>  			text_y = extents.ascent + row * extents.height;
>>  			if (attr.attr.a & ATTRMASK_UNDERLINE) {
>>  				terminal_set_color(terminal, cr, attr.attr.fg);
>>  				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);
>>  			}
>>  
>> @@ -1005,11 +1018,11 @@ redraw_handler(struct widget *widget, void *data)
>>  		d = 0.5;
>>  
>>  		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);
>> -		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, -extents.max_x_advance + 2 * d, 0);
>> +		cairo_rel_line_to(cr, -average_width + 2 * d, 0);
>>  		cairo_close_path(cr);
>>  
>>  		cairo_stroke(cr);
>> @@ -1022,7 +1035,7 @@ redraw_handler(struct widget *widget, void *data)
>>  
>>  	if (terminal->send_cursor_position) {
>>  		cursor_x = side_margin + allocation.x +
>> -				terminal->column * extents.max_x_advance;
>> +				terminal->column * average_width;
>>  		cursor_y = top_margin + allocation.y +
>>  				terminal->row * extents.height;
>>  		window_set_text_cursor_position(terminal->window,
>> @@ -2371,7 +2384,7 @@ recompute_selection(struct terminal *terminal)
>>  	int cw, ch;
>>  	union utf8_char *data;
>>  
>> -	cw = terminal->extents.max_x_advance;
>> +	cw = terminal->average_width;
>>  	ch = terminal->extents.height;
>>  	widget_get_allocation(terminal->widget, &allocation);
>>  	width = terminal->width * cw;
>> @@ -2527,12 +2540,17 @@ output_handler(struct window *window, struct output *output, int enter,
>>  	window_schedule_redraw(window);
>>  }
>>  
>> +#ifndef howmany
>> +#define howmany(x, y) (((x) + ((y) - 1)) / (y))
>> +#endif
>> +
>>  static struct terminal *
>>  terminal_create(struct display *display)
>>  {
>>  	struct terminal *terminal;
>>  	cairo_surface_t *surface;
>>  	cairo_t *cr;
>> +	cairo_text_extents_t text_extents;
>>  
>>  	terminal = malloc(sizeof *terminal);
>>  	if (terminal == NULL)
>> @@ -2584,6 +2602,15 @@ terminal_create(struct display *display)
>>  	cairo_scaled_font_reference(terminal->font_normal);
>>  
>>  	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_surface_destroy(surface);
>>  
>> -- 
>> 1.8.1.4
>>
>> _______________________________________________
>> wayland-devel mailing list
>> wayland-devel at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel


More information about the wayland-devel mailing list