Re: [hackers] [dmenu|libsl][PATCH] optimize drw_text() for large stringsa
> > But I still see the > prompt getting incorrectly cut off and the ellipsis still don't get > rendered in case of font change. I see, you mean in the edge case that there is a font change, but there is not enough space to add a single utf8 character for that font. You can just move the ellipsis rendering if statement outside of the if (utf8strlen) { block. On Tue, Mar 22, 2022 at 6:54 AM NRK wrote: > 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 > @@ -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; > @@ -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; > @@ -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, _w, NULL); > while (1) { > - utf8strlen = 0; > + ew = ellipsis_len = utf8strlen = 0; > utf8str = text; > nextfont = NULL; > while (*text) { > @@ -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, , 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; > } > @@ -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 >
Re: [hackers] [dmenu|libsl][PATCH] optimize drw_text() for large stringsa
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 @@ -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; @@ -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; @@ -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, _w, NULL); while (1) { - utf8strlen = 0; + ew = ellipsis_len = utf8strlen = 0; utf8str = text; nextfont = NULL; while (*text) { @@ -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, , 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; } @@ -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, , NULL); - /* shorten text if necessary */ - for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--) - drw_font_getexts(usedfont, utf8str, len, , NULL); - - if (len) { - memcpy(buf, utf8str, len); - buf[len] = '\0'; - if (len <