From: simon Date: Mon, 11 May 2009 08:46:17 +0000 (+0000) Subject: Pango-based font handling: combine display of adjacent characters X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/commitdiff_plain/8412ec80fffa6d4e3422a7240409a9d775b29c44 Pango-based font handling: combine display of adjacent characters into a single gdk_draw_layout() where conveniently feasible, after some work with xtrace revealed this as a major source of pterm's slow display updates when using client-side fonts. Ideally we ought to be able to do better. I know exactly what sequence of X protocol operations I want to see on the wire, but I don't know how to persuade Pango to generate them. git-svn-id: svn://svn.tartarus.org/sgt/putty@8558 cda61777-01e9-0310-a592-d414129be87e --- diff --git a/unix/gtkfont.c b/unix/gtkfont.c index fb756309..0db5ba29 100644 --- a/unix/gtkfont.c +++ b/unix/gtkfont.c @@ -892,28 +892,83 @@ static void pangofont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, } while (len > 0) { - int clen; + int clen, n; /* - * Extract a single UTF-8 character from the string. + * We want to display every character from this string in + * the centre of its own character cell. In the worst case, + * this requires a separate text-drawing call for each + * character; but in the common case where the font is + * properly fixed-width, we can draw many characters in one + * go which is much faster. + * + * This still isn't really ideal. If you look at what + * happens in the X protocol as a result of all of this, you + * find - naturally enough - that each call to + * gdk_draw_layout() generates a separate set of X RENDER + * operations involving creating a picture, setting a clip + * rectangle, doing some drawing and undoing the whole lot. + * In an ideal world, we should _always_ be able to turn the + * contents of this loop into a single RenderCompositeGlyphs + * operation which internally specifies inter-character + * deltas to get the spacing right, which would give us full + * speed _even_ in the worst case of a non-fixed-width font. + * However, Pango's architecture and documentation are so + * unhelpful that I have no idea how if at all to persuade + * them to do that. + */ + + /* + * Start by extracting a single UTF-8 character from the + * string. */ clen = 1; while (clen < len && (unsigned char)string[clen] >= 0x80 && (unsigned char)string[clen] < 0xC0) clen++; + n = 1; + + /* + * See if that character has the width we expect. + */ + pango_layout_set_text(layout, string, clen); + pango_layout_get_pixel_extents(layout, NULL, &rect); + + if (rect.width == cellwidth) { + /* + * Try extracting more characters, for as long as they + * stay well-behaved. + */ + while (clen < len) { + int oldclen = clen; + clen++; /* skip UTF-8 introducer byte */ + while (clen < len && + (unsigned char)string[clen] >= 0x80 && + (unsigned char)string[clen] < 0xC0) + clen++; + n++; + pango_layout_set_text(layout, string, clen); + pango_layout_get_pixel_extents(layout, NULL, &rect); + if (rect.width != n * cellwidth) { + clen = oldclen; + n--; + break; + } + } + } pango_layout_set_text(layout, string, clen); pango_layout_get_pixel_extents(layout, NULL, &rect); - gdk_draw_layout(target, gc, x + (cellwidth - rect.width)/2, + gdk_draw_layout(target, gc, x + (n*cellwidth - rect.width)/2, y + (pfont->u.height - rect.height)/2, layout); if (shadowbold) - gdk_draw_layout(target, gc, x + (cellwidth - rect.width)/2 + pfont->shadowoffset, + gdk_draw_layout(target, gc, x + (n*cellwidth - rect.width)/2 + pfont->shadowoffset, y + (pfont->u.height - rect.height)/2, layout); len -= clen; string += clen; - x += cellwidth; + x += n * cellwidth; } g_object_unref(layout);