* 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 = {
pfont->bold = bold;
pfont->shadowoffset = shadowoffset;
pfont->shadowalways = shadowalways;
+ pfont->widthcache = NULL;
+ pfont->nwidthcache = 0;
pango_font_metrics_unref(metrics);
{
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 */
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;
}
}
}