diff --git a/src/vteft2.c b/src/vteft2.c
index ea04287..f9aa287 100644
--- a/src/vteft2.c
+++ b/src/vteft2.c
@@ -54,13 +54,7 @@ _vte_ft2_check(struct _vte_draw *draw, G
 static void
 _vte_ft2_create(struct _vte_draw *draw, GtkWidget *widget)
 {
-	struct _vte_ft2_data *data;
-	data = g_slice_new0(struct _vte_ft2_data);
-	draw->impl_data = data;
-	data->rgb = NULL;
-	memset(&data->color, 0, sizeof(data->color));
-	data->pixbuf = NULL;
-	data->scrollx = data->scrolly = 0;
+	draw->impl_data = g_slice_new0(struct _vte_ft2_data);
 }
 
 static void
@@ -99,37 +93,32 @@ _vte_ft2_start(struct _vte_draw *draw)
 	guint width, height;
 	data = (struct _vte_ft2_data*) draw->impl_data;
 
-	gdk_window_get_geometry(draw->widget->window,
-				NULL, NULL, &width, &height, NULL);
+	width = draw->widget->allocation.width;
+	height = draw->widget->allocation.height;
 	if (data->rgb == NULL) {
 		data->rgb = _vte_rgb_buffer_new(width, height);
 	} else {
 		_vte_rgb_buffer_resize(data->rgb, width, height);
 	}
-	data->left = data->right = data->top = data->bottom = -1;
+	data->left = data->top = G_MAXINT;
+	data->right = data->bottom = -G_MAXINT;
 }
 
 static void
 _vte_ft2_end(struct _vte_draw *draw)
 {
 	struct _vte_ft2_data *data;
-	guint width, height;
 	GtkWidget *widget;
 	GtkStateType state;
 	data = (struct _vte_ft2_data*) draw->impl_data;
 	widget = draw->widget;
-	gdk_window_get_geometry(widget->window,
-				NULL, NULL, &width, &height, NULL);
-	gtk_widget_ensure_style(widget);
 	state = GTK_WIDGET_STATE(widget);
-	if ((data->left == -1) &&
-	    (data->right == -1) &&
-	    (data->top == -1) &&
-	    (data->bottom == -1)) {
+	if (data->right < data->left) {
 		_vte_rgb_draw_on_drawable(widget->window,
 					  widget->style->fg_gc[state],
 					  0, 0,
-					  width, height,
+						widget->allocation.width,
+						widget->allocation.height,
 					  data->rgb,
 					  0, 0);
 	} else {
@@ -176,17 +165,16 @@ _vte_ft2_set_background_image(struct _vt
 	data->pixbuf = bgpixbuf;
 }
 
-static void
+static inline void
 update_bbox(struct _vte_ft2_data *data, gint x, gint y, gint width, gint height)
 {
-	data->left = (data->left == -1) ?
-		     x : MIN(data->left, x);
-	data->right = (data->right == -1) ?
-		      x + width - 1 : MAX(data->right, x + width - 1);
-	data->top = (data->top == -1) ?
-		    y : MIN(data->top, y);
-	data->bottom = (data->bottom == -1) ?
-		       y + height - 1 : MAX(data->bottom, y + height - 1);
+	if (x < data->left) data->left = x;
+	x += width - 1;
+	if (x > data->right) data->right = x;
+
+	if (y < data->top) data->top = y;
+	y += height - 1;
+	if (y > data->bottom) data->bottom = y;
 }
 
 static void
@@ -220,7 +208,6 @@ _vte_ft2_set_text_font(struct _vte_draw 
 
 	if (data->cache != NULL) {
 		_vte_glyph_cache_free(data->cache);
-		data->cache = NULL;
 	}
 	data->cache = _vte_glyph_cache_new();
 	_vte_glyph_cache_set_font_description(draw->widget, NULL,
@@ -280,11 +267,13 @@ _vte_ft2_draw_text(struct _vte_draw *dra
 		   GdkColor *color, guchar alpha)
 {
 	struct _vte_ft2_data *data;
-	int i;
+	int i, j;
 
 	data = (struct _vte_ft2_data*) draw->impl_data;
 
 	for (i = 0; i < n_requests; i++) {
+		if (requests[i].c == -1 || requests[i].c == 32 /* space */)
+			continue;
 		_vte_glyph_draw(data->cache, requests[i].c, color,
 				requests[i].x, requests[i].y,
 				requests[i].columns,
@@ -293,6 +282,18 @@ _vte_ft2_draw_text(struct _vte_draw *dra
 		update_bbox(data, requests[i].x, requests[i].y,
 			    data->cache->width * requests[i].columns,
 			    data->cache->height);
+		for (j = i + 1; j < n_requests; j++) {
+			if (requests[j].c == requests[i].c) {
+				_vte_rgb_copy(data->rgb,
+						requests[i].x, requests[i].y,
+						requests[i].columns * data->cache->width, data->cache->height,
+						requests[j].x, requests[j].y);
+				update_bbox(data, requests[j].x, requests[j].y,
+						data->cache->width * requests[j].columns,
+						data->cache->height);
+				requests[j].c = -1;
+			}
+		}
 	}
 }
 
diff --git a/src/vtergb.c b/src/vtergb.c
index 03d2ccb..db25ab2 100644
--- a/src/vtergb.c
+++ b/src/vtergb.c
@@ -26,6 +26,8 @@ #include <ft2build.h>
 #include FT_FREETYPE_H
 #include "vtergb.h"
 
+#define ALIGN(x, a) (((x)+((a)-1))&~((a)-1))
+
 struct _vte_rgb_buffer_p {
 	guchar *pixels;
 	gint width, height, stride;
@@ -42,10 +44,11 @@ _vte_rgb_buffer_new(gint width, gint hei
 	width = MAX(width, 1);
 	height = MAX(height, 1);
 
-	ret->width = width;
+	ret->width  = width;
 	ret->height = height;
-	ret->stride = width * 3;
-	ret->length = width * height * 3;
+	/* gdk_rgb prefers a row-alignment of 4 */
+	ret->stride = 3 * ALIGN(width, 4);
+	ret->length = ret->stride * height;
 	ret->pixels = g_malloc(ret->length);
 
 	return (struct _vte_rgb_buffer *) ret;
@@ -66,8 +69,10 @@ _vte_rgb_buffer_resize(struct _vte_rgb_b
 		       gint minimum_height)
 {
 	struct _vte_rgb_buffer_p *buf = (struct _vte_rgb_buffer_p *) buffer;
-	gssize size = minimum_width * minimum_height * 3;
+	gint stride, size;
 
+	stride = 3 * ALIGN(minimum_width, 4);
+	size = stride * minimum_height;
 	if (size > buf->length) {
 		g_free(buf->pixels);
 		buf->length = size;
@@ -76,7 +81,7 @@ _vte_rgb_buffer_resize(struct _vte_rgb_b
 
 	buf->width = minimum_width;
 	buf->height = minimum_height;
-	buf->stride = buf->width * 3;
+	buf->stride = stride;
 }
 
 void
@@ -84,8 +89,8 @@ _vte_rgb_draw_color_rgb(struct _vte_rgb_
 			gint x, gint y, gint width, gint height,
 			guchar r, guchar g, guchar b)
 {
-	gint row, rows, col, cols;
-	gint offset, dest, count;
+	gint i, cols, rows;
+	gint count, stride;
 	guchar *pixels;
 
 	/* Perform a simple clipping check. */
@@ -108,21 +113,24 @@ _vte_rgb_draw_color_rgb(struct _vte_rgb_
 	if (cols <= x) {
 		return;
 	}
+	cols = cols - x;
+	rows = rows - y;
 
+	stride = buffer->stride;
+	pixels += y * stride + x * 3;
+	count = cols * 3;
 	/* Draw the first row by iteration. */
-	dest = y * buffer->stride + x * 3;
-	offset = dest;
-	for (col = x; col < cols; col++) {
-		pixels[dest++] = r;
-		pixels[dest++] = g;
-		pixels[dest++] = b;
+	i = 0;
+	while(cols--) {
+		pixels[i++] = r;
+		pixels[i++] = g;
+		pixels[i++] = b;
 	}
-
 	/* Draw the other rows by copying the data. */
-	count = width * 3;
-	for (row = y + 1; row < rows; row++) {
-		dest = row * buffer->stride + x * 3;
-		memmove(pixels + dest, pixels + offset, count);
+	i = 0;
+	while (--rows) {
+		i += stride;
+		memcpy(pixels + i, pixels, count);
 	}
 }
 
@@ -246,6 +254,30 @@ _vte_rgb_draw_on_drawable(GdkDrawable *d
 }
 
 void
+_vte_rgb_copy(struct _vte_rgb_buffer *buffer,
+		int src_x, int src_y, int width, int height, int dst_x, int dst_y)
+{
+	struct _vte_rgb_buffer_p *buf = (struct _vte_rgb_buffer_p *) buffer;
+	guchar *src, *dst;
+	gint stride;
+
+	g_assert (src_x > 0);
+	g_assert (dst_x >= src_x + width);
+	g_assert (dst_x <= buffer->width);
+
+	stride = buffer->stride;
+	src = buffer->pixels + src_y * stride + 3 * src_x;
+	dst = buffer->pixels + dst_y * stride + 3 * dst_x;
+	width *= 3;
+
+	while (height--) {
+		memcpy (dst, src, width);
+		src += stride;
+		dst += stride;
+	}
+}
+
+void
 _vte_rgb_buffer_clear(struct _vte_rgb_buffer *buffer)
 {
 	struct _vte_rgb_buffer_p *buf = (struct _vte_rgb_buffer_p *) buffer;
diff --git a/src/vtergb.h b/src/vtergb.h
index 49173bf..535bfd9 100644
--- a/src/vtergb.h
+++ b/src/vtergb.h
@@ -47,5 +47,7 @@ void _vte_rgb_draw_on_drawable(GdkDrawab
 			       gint x, gint y, gint width, gint height,
 			       struct _vte_rgb_buffer *buffer,
 			       gint xbias, gint ybias);
+void _vte_rgb_copy(struct _vte_rgb_buffer *buffer,
+		int src_x, int src_y, int width, int height, int dst_x, int dst_y);
 
 #endif
