X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=unix%2Fgtkfont.c;h=b152f2bbf8e9436b593841d1326074221a3a67b8;hb=a063e522970946bf7d5dc052079d7773c0dee76d;hp=123731a1d69337693d24be19faf41a14224169f3;hpb=b81b04f9b2fec6d6e7bd71431d0c597ab7f2bab6;p=PuTTY.git diff --git a/unix/gtkfont.c b/unix/gtkfont.c index 123731a1..b152f2bb 100644 --- a/unix/gtkfont.c +++ b/unix/gtkfont.c @@ -191,8 +191,10 @@ static char *x11_guess_derived_font_name(XFontStruct *xfs, int bold, int wide) p++; } - if (nstr < lenof(strings)) + if (nstr < lenof(strings)) { + sfree(dupname); return NULL; /* XLFD was malformed */ + } if (bold) strings[2] = "bold"; @@ -868,6 +870,13 @@ struct pangofont { * Data passed in to unifont_create(). */ 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 = { @@ -984,6 +993,8 @@ static unifont *pangofont_create_internal(GtkWidget *widget, pfont->bold = bold; pfont->shadowoffset = shadowoffset; pfont->shadowalways = shadowalways; + pfont->widthcache = NULL; + pfont->nwidthcache = 0; pango_font_metrics_unref(metrics); @@ -1037,10 +1048,40 @@ static void pangofont_destroy(unifont *font) { struct pangofont *pfont = (struct pangofont *)font; pango_font_description_free(pfont->desc); + sfree(pfont->widthcache); g_object_unref(pfont->fset); 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) { /* Pango implements font fallback, so assume it has everything */ @@ -1123,39 +1164,34 @@ static void pangofont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font, clen++; n = 1; - /* - * If it's a right-to-left character, we must display it on - * its own, to stop Pango helpfully re-reversing our already - * reversed text. - */ - if (!is_rtl(string[0])) { - + if (is_rtl(string[0]) || + pangofont_char_width(layout, pfont, string[n-1], + utfptr, clen) != cellwidth) { /* - * See if that character has the width we expect. + * If this character is a right-to-left one, or has an + * unusual width, then we must display it on its own. */ - pango_layout_set_text(layout, utfptr, 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 < utflen) { - int oldclen = clen; - clen++; /* skip UTF-8 introducer byte */ - while (clen < utflen && - (unsigned char)utfptr[clen] >= 0x80 && - (unsigned char)utfptr[clen] < 0xC0) - clen++; - n++; - pango_layout_set_text(layout, utfptr, clen); - pango_layout_get_pixel_extents(layout, NULL, &rect); - if (rect.width != n * cellwidth) { - clen = oldclen; - n--; - break; - } + } else { + /* + * Try to amalgamate a contiguous string of characters + * with the expected sensible width, for the common case + * in which we're using a monospaced font and everything + * works as expected. + */ + while (clen < utflen) { + int oldclen = clen; + clen++; /* skip UTF-8 introducer byte */ + while (clen < utflen && + (unsigned char)utfptr[clen] >= 0x80 && + (unsigned char)utfptr[clen] < 0xC0) + clen++; + n++; + if (pangofont_char_width(layout, pfont, + string[n-1], utfptr + oldclen, + clen - oldclen) != cellwidth) { + clen = oldclen; + n--; + break; } } } @@ -2288,6 +2324,8 @@ static fontinfo *update_for_intended_size(unifontsel_internal *fs, */ below = findrelpos234(fs->fonts_by_selorder, &info2, NULL, REL234_LE, &pos); + if (!below) + pos = -1; above = index234(fs->fonts_by_selorder, pos+1); /* @@ -2295,7 +2333,7 @@ static fontinfo *update_for_intended_size(unifontsel_internal *fs, * case. If we have, it'll be in `below' and not `above', * because we did a REL234_LE rather than REL234_LT search. */ - if (!fontinfo_selorder_compare(&info2, below)) + if (below && !fontinfo_selorder_compare(&info2, below)) return below; /*