Re: [hackers] [dmenu|libsl][PATCH] optimize drw_text() for large stringsa

From: NRK <nrk_AT_disroot.org>
Date: Tue, 22 Mar 2022 11:54:32 +0600

On Mon, Mar 21, 2022 at 10:35:21PM +0100, Stein Gunnar Bakkeby wrote:
> you make some interesting points. I am curious as to what your queueing
> approach would look like.
>
> I played around some more simplifying the ellipsis drawing and removing buf
> as you suggested.
> This would solve all of the aforementioned problems as far as I can tell,
> but it can result in a partly drawn
> emoji for example when the ellipsis cuts it off (which I think is a fair
> tradeoff).

Hi,

Tried out your last patch, it's simpler indeed. But I still see the
prompt getting incorrectly cut off and the ellipsis still don't get
rendered in case of font change.

The queue patch solves the above problems, but as I've said it's quite
messy. I was planning to move everything over to the queue so that we
won't need to special case anything during string drawing.

But after looking at your current patch, I've scraped that idea. It's
simpler to just draw on top of the problem cases, overwriting them
instead.

The following diff fixes pretty much every problem for me. The
performance is better and I don't notice any problems with truncating.
Let me know if there's still some edge case unhandled.

- NRK

diff --git a/drw.c b/drw.c
index 4cdbcbe..8595a69 100644
--- a/drw.c
+++ b/drw.c
_AT_@ -251,12 +251,10 @@ 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)
 {
- char buf[1024];
- int ty;
- unsigned int ew;
+ int ty, ellipsis_x = 0;
+ unsigned int tmpw, ew, ellipsis_w, ellipsis_len;
         XftDraw *d = NULL;
         Fnt *usedfont, *curfont, *nextfont;
- size_t i, len;
         int utf8strlen, utf8charlen, render = x || y || w || h;
         long utf8codepoint = 0;
         const char *utf8str;
_AT_@ -264,7 +262,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
         FcPattern *fcpattern;
         FcPattern *match;
         XftResult result;
- int charexists = 0;
+ int charexists = 0, overflow = 0;
 
         if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
                 return 0;
_AT_@ -282,8 +280,9 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
         }
 
         usedfont = drw->fonts;
+ drw_font_getexts(usedfont, "...", 3, &ellipsis_w, NULL);
         while (1) {
- utf8strlen = 0;
+ ew = ellipsis_len = utf8strlen = 0;
                 utf8str = text;
                 nextfont = NULL;
                 while (*text) {
_AT_@ -291,9 +290,19 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
                         for (curfont = drw->fonts; curfont; curfont = curfont->next) {
                                 charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
                                 if (charexists) {
- if (curfont == usedfont) {
+ drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL);
+ if (ew + ellipsis_w <= w) {
+ ellipsis_x = x + ew;
+ ellipsis_len = utf8strlen;
+ }
+
+ if (ew > w) {
+ overflow = 1;
+ utf8strlen = ellipsis_len;
+ } else if (curfont == usedfont) {
                                                 utf8strlen += utf8charlen;
                                                 text += utf8charlen;
+ ew += tmpw;
                                         } else {
                                                 nextfont = curfont;
                                         }
_AT_@ -301,36 +310,25 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
                                 }
                         }
 
- if (!charexists || nextfont)
+ if (overflow || !charexists || nextfont)
                                 break;
                         else
                                 charexists = 0;
                 }
 
                 if (utf8strlen) {
- drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
- /* shorten text if necessary */
- for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--)
- drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
-
- if (len) {
- memcpy(buf, utf8str, len);
- buf[len] = '\0';
- if (len < utf8strlen)
- for (i = len; i && i > len - 3; buf[--i] = '.')
- ; /* NOP */
-
- if (render) {
- ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
- XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
- usedfont->xfont, x, ty, (XftChar8 *)buf, len);
- }
- x += ew;
- w -= ew;
+ if (render) {
+ ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
+ XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
+ usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen);
                         }
+ x += ew;
+ w -= ew;
                 }
+ if (render && overflow)
+ drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert);
 
- if (!*text) {
+ if (overflow || !*text) {
                         break;
                 } else if (nextfont) {
                         charexists = 0;
Received on Tue Mar 22 2022 - 06:54:32 CET

This archive was generated by hypermail 2.3.0 : Tue Mar 22 2022 - 07:00:38 CET