URI: 
       drw_text: improve performance when there's no match - dmenu - dynamic menu
  HTML git clone git://git.suckless.org/dmenu
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 22511c41d55a38a770541ae617a09383d5e6ad1c
   DIR parent 77526f756e23e362081ac807521f901f2e5cd5e6
  HTML Author: NRK <nrk@disroot.org>
       Date:   Thu, 24 Mar 2022 00:37:55 +0600
       
       drw_text: improve performance when there's no match
       
       this was the last piece of the puzzle, the case where we can't find any
       font to draw the codepoint.
       
       in such cases, we use XftFontMatch() which is INSANELY slow. but that's
       not the real problem. the real problem was we were continuously trying
       to match the same thing over and over again.
       
       this patch introduces a small cache, which keeps track a couple
       codepoints for which we know we won't find any matches.
       
       with this, i can dump lots of emojies into dmenu where some of them
       don't have any matching font, and still not have dmenu lag insanely or
       FREEZE completely when scrolling up and down.
       
       this also improves startup time, which will of course depend on the
       system and all installed fonts; but on my system and test case i see the
       following startup time drop:
       
       before -> after
       60ms   -> 34ms
       
       Diffstat:
         M drw.c                               |      13 ++++++++++++-
       
       1 file changed, 12 insertions(+), 1 deletion(-)
       ---
   DIR diff --git a/drw.c b/drw.c
       @@ -251,7 +251,7 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int
        int
        drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
        {
       -        int ty, ellipsis_x = 0;
       +        int i, ty, ellipsis_x = 0;
                unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len, ellipsis_width;
                XftDraw *d = NULL;
                Fnt *usedfont, *curfont, *nextfont;
       @@ -263,6 +263,9 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
                FcPattern *match;
                XftResult result;
                int charexists = 0, overflow = 0;
       +        /* keep track of a couple codepoints for which we have no match. */
       +        enum { nomatches_len = 64 };
       +        static struct { long codepoint[nomatches_len]; unsigned int idx; } nomatches;
        
                if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
                        return 0;
       @@ -346,6 +349,12 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
                                 * character must be drawn. */
                                charexists = 1;
        
       +                        for (i = 0; i < nomatches_len; ++i) {
       +                                /* avoid calling XftFontMatch if we know we won't find a match */
       +                                if (utf8codepoint == nomatches.codepoint[i])
       +                                        goto no_match;
       +                        }
       +
                                fccharset = FcCharSetCreate();
                                FcCharSetAddChar(fccharset, utf8codepoint);
        
       @@ -374,6 +383,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
                                                curfont->next = usedfont;
                                        } else {
                                                xfont_free(usedfont);
       +                                        nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint;
       +no_match:
                                                usedfont = drw->fonts;
                                        }
                                }