commit 22511c41d55a38a770541ae617a09383d5e6ad1c
Author:     NRK <[email protected]>
AuthorDate: Thu Mar 24 00:37:55 2022 +0600
Commit:     Hiltjo Posthuma <[email protected]>
CommitDate: Fri Mar 25 22:49:07 2022 +0100

    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

diff --git a/drw.c b/drw.c
index 7d985b1..a50c9ee 100644
--- 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;
                                }
                        }

Reply via email to