> On Oct 2, 2017, at 10:06 PM, Gary Allen Vollink <g...@vollink.com> wrote:
> 
> I noticed the following AFTER I sent the initial patch.  I seriously
> doubt that this is new or unexpected behavior since the frc member
> unicodep is used to catch the individual rune that a font was opened
> for (and then eliminate that ONE rune from a new open on the next
> cache search pass).  "break;"
> 
> The problem with this is - outside of the odd Emoji - when dealing
> with Asian languages, if Glyphs can't be found it's because someone is
> looking at a document that expects to have runes in the Asian Extended
> D or E Unicode ranges, and they don't have that font available (in
> monospace).  That means occurrences of repeating, not-found runes are
> going to be much less common than new, unique not-found runes, and
> those font slots QUICKLY run out.
> 
> Maybe ALSO dealing with the ever-growing list of rune-not-found is the
> right way to handle this situation (it will cut down on
> open-then-close), by expanding this patch or in a completely separate
> patch.  The problem is a growing list of not-found makes for code that
> sucks (using ever more memory over time).  wchar_t isn't huge, but
> these Unicode ranges are particularly large.
> 
> Thank you,
> Gary Allen

I revised this looking to improve on what I started.  Presented here for 
discussion.

First, unicodep, was removed.

Second, I introduce a wchar_t array called noglyph of a hard-coded 1024 length 
to take care of the differential between frc[16] and the likelihood of running 
into a high number of unique glyphs.

This deeply expands the advantage of not trying to open a new font for a glyph 
we have already discovered is not found, and includes my original patch of 
re-closing the font (and keeping it out of the frc cache) since that font is 
both already open and isn’t being used to represent a glyph anyway.

In handling the noglyph array, I do a FIFO (instead of a LIFO as the frc does). 
 This seems to give the highest likelihood that anything removed from the array 
will already be off-screen.

Side-note, I’m curious as to objections to switching the frc Font Cache array 
to FIFO as well (with the hope that the earliest fallback is least likely to 
still be on-screen).


Check-in comment:

If fontconfig returns a font that has no matching glyph, close the now opened 
but unused font.  Track glyph-less rune separately.


diff -U 3 a/x.c b/x.c
--- a/x.c       2017-09-30 15:46:51.713848500 -0400
+++ b/x.c       2017-10-04 23:08:23.162156200 -0400
@@ -1,6 +1,7 @@
 /* See LICENSE for license details. */
 #include <errno.h>
 #include <locale.h>
+#include <wchar.h>
 #include <signal.h>
 #include <stdint.h>
 #include <sys/select.h>
@@ -151,9 +152,12 @@
 typedef struct {
        XftFont *font;
        int flags;
-       Rune unicodep;
 } Fontcache;
 
+/* Runes not found array. */
+static wchar_t noglyph[1024];
+static int noglyphlen = 0;
+
 /* Fontcache is an array now. A new font will be appended to the array. */
 static Fontcache frc[16];
 static int frclen = 0;
@@ -997,7 +1001,7 @@
        FcPattern *fcpattern, *fontpattern;
        FcFontSet *fcsets[] = { NULL };
        FcCharSet *fccharset;
-       int i, f, numspecs = 0;
+       int i, f, r, numspecs = 0;
 
        for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
                /* Fetch rune and mode for current glyph. */
@@ -1029,7 +1033,8 @@
 
                /* Lookup character index with default font. */
                glyphidx = XftCharIndex(xw.dpy, font->match, rune);
-               if (glyphidx) {
+               /* OR if already failed to find a glyph for this rune. */
+               if ((glyphidx) || (wmemchr(noglyph, rune, noglyphlen))) {
                        specs[numspecs].font = font->match;
                        specs[numspecs].glyph = glyphidx;
                        specs[numspecs].x = (short)xp;
@@ -1045,11 +1050,6 @@
                        /* Everything correct. */
                        if (glyphidx && frc[f].flags == frcflags)
                                break;
-                       /* We got a default font for a not found glyph. */
-                       if (!glyphidx && frc[f].flags == frcflags
-                                       && frc[f].unicodep == rune) {
-                               break;
-                       }
                }
 
                /* Nothing was found. Use fontconfig to find matching font. */
@@ -1087,7 +1087,6 @@
                        if (frclen >= LEN(frc)) {
                                frclen = LEN(frc) - 1;
                                XftFontClose(xw.dpy, frc[frclen].font);
-                               frc[frclen].unicodep = 0;
                        }
 
                        frc[frclen].font = XftFontOpenPattern(xw.dpy,
@@ -1096,12 +1095,23 @@
                                die("XftFontOpenPattern failed seeking fallback 
font: %s\n",
                                        strerror(errno));
                        frc[frclen].flags = frcflags;
-                       frc[frclen].unicodep = rune;
 
                        glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune);
 
-                       f = frclen;
-                       frclen++;
+                       if (!glyphidx) {
+                               XftFontClose(xw.dpy, frc[frclen].font);
+                               if (noglyphlen >= LEN(noglyph)) {
+                                       /* Get rid of the oldest not found rune 
*/
+                                       for (r=1; r <= LEN(noglyph); r++) {
+                                               noglyph[r-1] = noglyph[r];
+                                       }
+                                       noglyphlen = LEN(noglyph) - 1;
+                               }
+                               noglyph[noglyphlen++] = rune;
+                       } else {
+                               f = frclen;
+                               frclen++;
+                       }
 
                        FcPatternDestroy(fcpattern);
                        FcCharSetDestroy(fccharset);



Reply via email to