[dev] [st] [patch] If no Glyph Found, Do Not Keep a Font Loaded

From: Gary Allen Vollink <gary_AT_vollink.com>
Date: Wed, 21 Mar 2018 14:18:53 -0400

This patch is over my previous simplification patch
(https://lists.suckless.org/dev/1803/32601.html), though it could be
reworked to go in without it.

Problem: When working with text from many languages, it does not take
long to run out of font slots for Runes that do not exist within any
given fontconfig.  Currently, each rune that is not part of a default
set takes up another font slot (whether or not that rune is even
found).I have found that runes in text (not emoji) have a tendency of
showing up in sets, for instance a whole block of text may be in
Cyrillic, which quickly takes up the 16 slots available for loaded
fonts.  This is fine until another rune IS found and put on screen. 
Whenever that happens, the next time a rune isn't found that font is
closed and a new one inserted (whether or not that font includes the
required glyph). Unloading an on-screen font at the next not-found rune
will crash st.


What I have is a partial Fix. This patch makes it take longer for this
problem to manifest by making sure the limited font slots are not kept
open when a glyph cannot be found.  Note that this does not really help
the issue on MacOS where the noglyph font will always claim a glyph
(even though it's nothing but a binarybox).  I haven't found a way to
fix it completely (on MacOS and/or over long periods of usage on Linux)
without writing something that even I think sucks.  I personally got
over this by /also/ adjusting the size of the frc[] array on my own
build.  Either way, this is what I have to offer...



Patch:

Track runes that are not found separately from the Fontcache, frc[],
forget not-found runes in fifo, not lifo.  Close an opened font if it
doesn't include the required glyph (not taking up an frc[] slot).


diff -U 3 -p a/x.c b/x.c
--- a/x.c       2018-03-21 13:22:53.549236600 -0400
+++ b/x.c       2018-03-21 13:32:00.894134500 -0400
_AT_@ -3,6 +3,7 @@
  #include <math.h>
  #include <limits.h>
  #include <locale.h>
+#include <wchar.h>
  #include <signal.h>
  #include <sys/select.h>
  #include <time.h>
_AT_@ -219,9 +220,12 @@ enum {
  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;
_AT_@ -1145,7 +1149,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *sp
         float runewidth = win.cw;
         Rune rune;
         FT_UInt glyphidx;
-       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. */
_AT_@ -1177,7 +1181,8 @@ xmakeglyphfontspecs(XftGlyphFontSpec *sp

                 /* 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;
_AT_@ -1193,11 +1198,6 @@ xmakeglyphfontspecs(XftGlyphFontSpec *sp
                         /* 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. */
_AT_@ -1208,7 +1208,6 @@ xmakeglyphfontspecs(XftGlyphFontSpec *sp
                         if (frclen >= LEN(frc)) {
                                 frclen = LEN(frc) - 1;
                                 XftFontClose(xw.dpy, frc[frclen].font);
-                               frc[frclen].unicodep = 0;
                         }

                         /*
_AT_@ -1224,12 +1223,23 @@ xmakeglyphfontspecs(XftGlyphFontSpec *sp
                         }
                         frc[frclen].font = newFont.match;
                         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++;
+                       }
                 }

                 specs[numspecs].font = frc[f].font;
Received on Wed Mar 21 2018 - 19:18:53 CET

This archive was generated by hypermail 2.3.0 : Wed Mar 21 2018 - 19:24:20 CET