mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 18:07:59 +00:00
Performance: cache character widths returned from Pango.
Profiling reveals that pterm in Pango rendering mode uses an absurd
amount of CPU when it's not even actually _drawing_ the text, because
of all the calls to pango_layout_get_pixel_extents() while
pangofont_draw_text tries to work out which characters it can safely
draw as part of a long string. Caching the results speeds things up
greatly.
(cherry picked from commit c3ef30c883
)
This commit is contained in:
parent
0eb3bf07fc
commit
14464764da
@ -870,6 +870,13 @@ struct pangofont {
|
|||||||
* Data passed in to unifont_create().
|
* Data passed in to unifont_create().
|
||||||
*/
|
*/
|
||||||
int bold, shadowoffset, shadowalways;
|
int bold, shadowoffset, shadowalways;
|
||||||
|
/*
|
||||||
|
* Cache of character widths, indexed by Unicode code point. In
|
||||||
|
* pixels; -1 means we haven't asked Pango about this character
|
||||||
|
* before.
|
||||||
|
*/
|
||||||
|
int *widthcache;
|
||||||
|
unsigned nwidthcache;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct unifont_vtable pangofont_vtable = {
|
static const struct unifont_vtable pangofont_vtable = {
|
||||||
@ -986,6 +993,8 @@ static unifont *pangofont_create_internal(GtkWidget *widget,
|
|||||||
pfont->bold = bold;
|
pfont->bold = bold;
|
||||||
pfont->shadowoffset = shadowoffset;
|
pfont->shadowoffset = shadowoffset;
|
||||||
pfont->shadowalways = shadowalways;
|
pfont->shadowalways = shadowalways;
|
||||||
|
pfont->widthcache = NULL;
|
||||||
|
pfont->nwidthcache = 0;
|
||||||
|
|
||||||
pango_font_metrics_unref(metrics);
|
pango_font_metrics_unref(metrics);
|
||||||
|
|
||||||
@ -1039,10 +1048,40 @@ static void pangofont_destroy(unifont *font)
|
|||||||
{
|
{
|
||||||
struct pangofont *pfont = (struct pangofont *)font;
|
struct pangofont *pfont = (struct pangofont *)font;
|
||||||
pango_font_description_free(pfont->desc);
|
pango_font_description_free(pfont->desc);
|
||||||
|
sfree(pfont->widthcache);
|
||||||
g_object_unref(pfont->fset);
|
g_object_unref(pfont->fset);
|
||||||
sfree(font);
|
sfree(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int pangofont_char_width(PangoLayout *layout, struct pangofont *pfont,
|
||||||
|
wchar_t uchr, const char *utfchr, int utflen)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Here we check whether a character has the same width as the
|
||||||
|
* character cell it'll be drawn in. Because profiling showed that
|
||||||
|
* pango_layout_get_pixel_extents() was a huge bottleneck when we
|
||||||
|
* were calling it every time we needed to know this, we instead
|
||||||
|
* call it only on characters we don't already know about, and
|
||||||
|
* cache the results.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((unsigned)uchr >= pfont->nwidthcache) {
|
||||||
|
unsigned newsize = ((int)uchr + 0x100) & ~0xFF;
|
||||||
|
pfont->widthcache = sresize(pfont->widthcache, newsize, int);
|
||||||
|
while (pfont->nwidthcache < newsize)
|
||||||
|
pfont->widthcache[pfont->nwidthcache++] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pfont->widthcache[uchr] < 0) {
|
||||||
|
PangoRectangle rect;
|
||||||
|
pango_layout_set_text(layout, utfchr, utflen);
|
||||||
|
pango_layout_get_pixel_extents(layout, NULL, &rect);
|
||||||
|
pfont->widthcache[uchr] = rect.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pfont->widthcache[uchr];
|
||||||
|
}
|
||||||
|
|
||||||
static int pangofont_has_glyph(unifont *font, wchar_t glyph)
|
static int pangofont_has_glyph(unifont *font, wchar_t glyph)
|
||||||
{
|
{
|
||||||
/* Pango implements font fallback, so assume it has everything */
|
/* Pango implements font fallback, so assume it has everything */
|
||||||
@ -1125,23 +1164,19 @@ static void pangofont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
|
|||||||
clen++;
|
clen++;
|
||||||
n = 1;
|
n = 1;
|
||||||
|
|
||||||
|
if (is_rtl(string[0]) ||
|
||||||
|
pangofont_char_width(layout, pfont, string[n-1],
|
||||||
|
utfptr, clen) != cellwidth) {
|
||||||
/*
|
/*
|
||||||
* If it's a right-to-left character, we must display it on
|
* If this character is a right-to-left one, or has an
|
||||||
* its own, to stop Pango helpfully re-reversing our already
|
* unusual width, then we must display it on its own.
|
||||||
* reversed text.
|
|
||||||
*/
|
*/
|
||||||
if (!is_rtl(string[0])) {
|
} else {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See if that character has the width we expect.
|
* Try to amalgamate a contiguous string of characters
|
||||||
*/
|
* with the expected sensible width, for the common case
|
||||||
pango_layout_set_text(layout, utfptr, clen);
|
* in which we're using a monospaced font and everything
|
||||||
pango_layout_get_pixel_extents(layout, NULL, &rect);
|
* works as expected.
|
||||||
|
|
||||||
if (rect.width == cellwidth) {
|
|
||||||
/*
|
|
||||||
* Try extracting more characters, for as long as they
|
|
||||||
* stay well-behaved.
|
|
||||||
*/
|
*/
|
||||||
while (clen < utflen) {
|
while (clen < utflen) {
|
||||||
int oldclen = clen;
|
int oldclen = clen;
|
||||||
@ -1151,16 +1186,15 @@ static void pangofont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
|
|||||||
(unsigned char)utfptr[clen] < 0xC0)
|
(unsigned char)utfptr[clen] < 0xC0)
|
||||||
clen++;
|
clen++;
|
||||||
n++;
|
n++;
|
||||||
pango_layout_set_text(layout, utfptr, clen);
|
if (pangofont_char_width(layout, pfont,
|
||||||
pango_layout_get_pixel_extents(layout, NULL, &rect);
|
string[n-1], utfptr + oldclen,
|
||||||
if (rect.width != n * cellwidth) {
|
clen - oldclen) != cellwidth) {
|
||||||
clen = oldclen;
|
clen = oldclen;
|
||||||
n--;
|
n--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pango_layout_set_text(layout, utfptr, clen);
|
pango_layout_set_text(layout, utfptr, clen);
|
||||||
pango_layout_get_pixel_extents(layout, NULL, &rect);
|
pango_layout_get_pixel_extents(layout, NULL, &rect);
|
||||||
|
Loading…
Reference in New Issue
Block a user