Hello,

> This is what I had initially but this caused some bug because it causes
> mismatch between drw_fontset_getwidth() vs the width that actually gets
> rendered. On the first call, drw_fontset_getwidth() will calculate the
> width with invalid_width being 0 but when rendering it will be non-zero
> which messes up some calculation.

I've attached a patch that fixes this.

> I'm also noticing now that if you put an invalid byte at the very end it
> fails to render the ellipsis when truncating the text. To reproduce try
> to put as many 'a' in there to push the invalid byte *just* beyond the
> width of the reigion.
> 
>       $ printf "aaaaa....aaaaa\xff" | ./dmenu
> 
> I've attached a pic where there should be an ellipsis at the end but
> isn't.
> 
> I remember testing this case and fixing it by doing the
> `invalid_width = -1` thing so that it gets initialized even when not
> rendering. But now it happens even after I revert this patch. Weird.
> I'll look into what's going wrong here and fix it.

This bug is not fixed yet. I had a bunch of unexpected things happen
last week and so I wasn't able to work on it. I did figure out the cause
of the bug though, if someone wants to work out a patch before I get to
this, feel free.

Basically, the issue seems to be here:

        if (charexists) {
                drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL);

In the case of error, this sets `tmpw` to 0 instead of `invalid_width`
which is messing up the ellipsis calculation. I tried doing something
like this, which fixes certain cases, but still is buggy on some other
cases:

        if (charexists) {
-               drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL);
+               if (utf8err)
+                       tmpw = invalid_width;
+               else
+                       drw_font_getexts(curfont, text, utf8charlen, &tmpw, 
NULL);

- NRK
>From dfec151bcb3f5d152b59b15418e11da96ee026d6 Mon Sep 17 00:00:00 2001
From: NRK <n...@disroot.org>
Date: Wed, 17 Jul 2024 10:57:39 +0000
Subject: [PATCH] move {ellipsis,invalid}_width initialization to
 drw_fontset_create

currently invalid_width will be 0 on the first getwidth call but
non-zero when rendering. this patch fixes this de-sync which can
cause width calculation issues.

this is also simpler this way since we don't need to worry about
doing weird dance to avoid infinite recursion.
---
 drw.c | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/drw.c b/drw.c
index 344de61..2db2a5d 100644
--- a/drw.c
+++ b/drw.c
@@ -9,6 +9,8 @@
 #include "util.h"
 
 #define UTF_INVALID 0xFFFD
+static int ellipsis_width, invalid_width;
+static const char INVALID[] = "�", ELLIPSIS[] = "...";
 
 static int
 utf8decode(const char *s_in, long *u, int *err)
@@ -139,8 +141,8 @@ xfont_free(Fnt *font)
        free(font);
 }
 
-Fnt*
-drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
+Fnt *
+drw_fontset_create(Drw *drw, const char *fonts[], size_t fontcount)
 {
        Fnt *cur, *ret = NULL;
        size_t i;
@@ -154,7 +156,12 @@ drw_fontset_create(Drw* drw, const char *fonts[], size_t 
fontcount)
                        ret = cur;
                }
        }
-       return (drw->fonts = ret);
+       drw->fonts = ret;
+       if (drw->fonts) {
+               invalid_width = drw_fontset_getwidth(drw, INVALID);
+               ellipsis_width = drw_fontset_getwidth(drw, ELLIPSIS);
+       }
+       return ret;
 }
 
 void
@@ -237,8 +244,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned 
int h, unsigned int lp
        XftResult result;
        int charexists = 0, overflow = 0;
        /* keep track of a couple codepoints for which we have no match. */
-       static unsigned int nomatches[128], ellipsis_width, invalid_width;
-       static const char invalid[] = "�";
+       static unsigned int nomatches[128];
 
        if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts)
                return 0;
@@ -256,10 +262,6 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned 
int h, unsigned int lp
        }
 
        usedfont = drw->fonts;
-       if (!ellipsis_width && render)
-               ellipsis_width = drw_fontset_getwidth(drw, "...");
-       if (!invalid_width && render)
-               invalid_width = drw_fontset_getwidth(drw, invalid);
        while (1) {
                ew = ellipsis_len = utf8err = utf8charlen = utf8strlen = 0;
                utf8str = text;
@@ -314,12 +316,12 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned 
int h, unsigned int lp
                }
                if (utf8err && (!render || invalid_width < w)) {
                        if (render)
-                               drw_text(drw, x, y, w, h, 0, invalid, invert);
+                               drw_text(drw, x, y, w, h, 0, INVALID, invert);
                        x += invalid_width;
                        w -= invalid_width;
                }
                if (render && overflow)
-                       drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", 
invert);
+                       drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, 
ELLIPSIS, invert);
 
                if (!*text || overflow) {
                        break;
-- 
2.42.0

Reply via email to