Batch up drawing glyphs
diff --git a/clients/terminal.c b/clients/terminal.c
index 4eb4fab..dda5f9f 100644
--- a/clients/terminal.c
+++ b/clients/terminal.c
@@ -461,16 +461,19 @@
 	return &terminal->data_attr[index * terminal->width];
 }
 
-struct decoded_attr {
-	int foreground;
-	int background;
-	int bold;
-	int underline;
+union decoded_attr {
+	struct {
+		unsigned char foreground;
+		unsigned char background;
+		unsigned char bold;
+		unsigned char underline;
+	};
+	uint32_t key;
 };
 
 static void
 terminal_decode_attr(struct terminal *terminal, int row, int col,
-		     struct decoded_attr *decoded)
+		     union decoded_attr *decoded)
 {
 	struct attr attr;
 	int foreground, background, tmp;
@@ -744,6 +747,69 @@
 			      terminal->color_table[index].a);
 }
 
+struct glyph_run {
+	struct terminal *terminal;
+	cairo_t *cr;
+	int count;
+	union decoded_attr attr;
+	cairo_glyph_t glyphs[256], *g;
+};
+
+static void
+glyph_run_init(struct glyph_run *run, struct terminal *terminal, cairo_t *cr)
+{
+	run->terminal = terminal;
+	run->cr = cr;
+	run->g = run->glyphs;
+	run->count = 0;
+	run->attr.key = 0;
+}
+
+static void
+glyph_run_flush(struct glyph_run *run, union decoded_attr attr)
+{
+	cairo_scaled_font_t *font;
+
+	if (run->count == 0)
+		run->attr = attr;
+	if (run->count > ARRAY_LENGTH(run->glyphs) - 10 ||
+	    (attr.key != run->attr.key)) {
+		if (run->attr.bold)
+			font = run->terminal->font_bold;
+		else
+			font = run->terminal->font_normal;
+		cairo_set_scaled_font(run->cr, font);
+		terminal_set_color(run->terminal, run->cr,
+				   run->attr.foreground);
+
+		cairo_show_glyphs (run->cr, run->glyphs, run->count);
+		run->g = run->glyphs;
+		run->count = 0;
+	}
+}
+
+static void
+glyph_run_add(struct glyph_run *run, int x, int y, union utf8_char *c)
+{
+	int num_glyphs;
+	cairo_scaled_font_t *font;
+
+	num_glyphs = ARRAY_LENGTH(run->glyphs) - run->count;
+
+	if (run->attr.bold)
+		font = run->terminal->font_bold;
+	else
+		font = run->terminal->font_normal;
+
+	cairo_move_to(run->cr, x, y);
+	cairo_scaled_font_text_to_glyphs (font, x, y,
+					  (char *) c->byte, 4,
+					  &run->g, &num_glyphs,
+					  NULL, NULL, NULL);
+	run->g += num_glyphs;
+	run->count += num_glyphs;
+}
+
 static void
 terminal_draw_contents(struct terminal *terminal)
 {
@@ -753,13 +819,11 @@
 	int top_margin, side_margin;
 	int row, col;
 	union utf8_char *p_row;
-	struct decoded_attr attr;
+	union decoded_attr attr;
 	int text_x, text_y;
 	cairo_surface_t *surface;
 	double d;
-	int num_glyphs;
-	cairo_scaled_font_t *font;
-	cairo_glyph_t glyphs[256], *g;
+	struct glyph_run run;
 
 	window_get_child_allocation(terminal->window, &allocation);
 
@@ -801,18 +865,15 @@
 	cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
 
 	/* paint the foreground */
+	glyph_run_init(&run, terminal, cr);
 	for (row = 0; row < terminal->height; row++) {
 		p_row = terminal_get_row(terminal, row);
 		for (col = 0; col < terminal->width; col++) {
 			/* get the attributes for this character cell */
 			terminal_decode_attr(terminal, row, col, &attr);
 
-			if (attr.bold)
-				font = terminal->font_bold;
-			else
-				font = terminal->font_normal;
-			cairo_set_scaled_font(cr, font);
-			terminal_set_color(terminal, cr, attr.foreground);
+			glyph_run_flush(&run, attr);
+
 			text_x = side_margin + col * extents.max_x_advance;
 			text_y = top_margin + extents.ascent + row * extents.height;
 			if (attr.underline) {
@@ -820,18 +881,14 @@
 				cairo_line_to(cr, text_x + extents.max_x_advance, (double) text_y + 1.5);
 				cairo_stroke(cr);
 			}
-			cairo_move_to(cr, text_x, text_y);
 
-			g = glyphs;
-			num_glyphs = ARRAY_LENGTH(glyphs);
-			cairo_scaled_font_text_to_glyphs (font, text_x, text_y,
-							  (char *) p_row[col].byte, 4,
-							  &g, &num_glyphs,
-							  NULL, NULL, NULL);
-			cairo_show_glyphs (cr, g, num_glyphs);
+			glyph_run_add(&run, text_x, text_y, &p_row[col]);
 		}
 	}
 
+	attr.key = ~0;
+	glyph_run_flush(&run, attr);
+
 	if ((terminal->mode & MODE_SHOW_CURSOR) && !terminal->focused) {
 		d = 0.5;