From 87cb03fdf81733f162fd7b8bc8d239f86ed6a7d3 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Mon, 17 Aug 2026 01:36:16 +0900 Subject: [PATCH] popup: no fallbacks for work areas no desktop has; text setup cannot fail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit popuplayout had two refit stages for a work area shorter than one padded row — 40 pixels — and popupdraw re-checked the layout it had just been handed, against an Imgh that bounded no buffer any more. Pango and Cairo abort rather than return nil, so textinit is void and the layout is never nil; the stride Cairo computes for RGB24 is w*4 by definition; and textdraw set the layout's width and ellipsis twice. --- dat.h | 1 - fn.h | 2 +- font.c | 40 +++++++--------------------------------- popup_layout.c | 25 ++++++------------------- tests/font_test.c | 7 +------ tests/popup_test.c | 28 ++++------------------------ win.c | 6 +----- 7 files changed, 20 insertions(+), 89 deletions(-) diff --git a/dat.h b/dat.h index e267ba3..90efd23 100644 --- a/dat.h +++ b/dat.h @@ -44,7 +44,6 @@ extern int popupscale; #define PopupNumw Fontsz #define PopupTextw (12*Fontsz) #define PopupBasew (2*PopupPad + PopupNumw + PopupTextw) -#define Imgh (2*PopupPad + (Maxdisp + 2)*Fontsz + PopupSep) typedef struct Str Str; struct Str diff --git a/fn.h b/fn.h index f49d523..84cd3c3 100644 --- a/fn.h +++ b/fn.h @@ -48,7 +48,7 @@ int keymeaningful(u32int); void* emalloc(ulong); void* erealloc(void*, ulong); -int textinit(void); +void textinit(void); void textclose(void); int textwidth(Str*); void textdraw(u32int*, int, int, int, int, int, u32int, Str*); diff --git a/font.c b/font.c index 00a1b04..c3486f5 100644 --- a/font.c +++ b/font.c @@ -7,13 +7,6 @@ static PangoFontMap *fontmap; static PangoContext *context; static PangoLayout *layout; -static void -resetlayout(void) -{ - pango_layout_set_width(layout, -1); - pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE); -} - void textclose(void) { @@ -50,28 +43,16 @@ setfont(void) pango_font_description_free(font); } -int +void textinit(void) { - textclose(); FcInit(); fontmap = pango_cairo_font_map_new(); - if(fontmap == nil){ - fprint(2, "strans: popup: can't initialize PangoCairo\n"); - return 0; - } pango_cairo_font_map_set_resolution(PANGO_CAIRO_FONT_MAP(fontmap), 96); context = pango_font_map_create_context(fontmap); - if(context != nil) - layout = pango_layout_new(context); - if(context == nil || layout == nil){ - fprint(2, "strans: popup: can't create text layout\n"); - textclose(); - return 0; - } + layout = pango_layout_new(context); pango_layout_set_single_paragraph_mode(layout, TRUE); setfont(); - return 1; } static int @@ -80,8 +61,6 @@ settext(Str *s) char utf[Maxutf]; int n; - if(layout == nil || s == nil || s->n <= 0) - return 0; n = stoutf(s, utf, sizeof utf); pango_layout_set_text(layout, utf, n); return n > 0; @@ -109,9 +88,8 @@ textwidth(Str *s) { PangoRectangle r; - if(layout == nil) - return 0; - resetlayout(); + pango_layout_set_width(layout, -1); + pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE); if(!settext(s)) return 0; textextents(&r); @@ -130,20 +108,16 @@ textdraw(u32int *buf, int w, int h, int x, int y, int fit, u32int color, PangoRectangle r; cairo_surface_t *surface; cairo_t *cr; - int b, g, red, stride; + int b, g, red; - if(layout == nil || fit <= 0) + if(fit <= 0) return; - resetlayout(); pango_layout_set_width(layout, fit * PANGO_SCALE); pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); if(w <= 0 || h <= 0 || !settext(s)) return; - stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, w); - if(stride < 0 || (vlong)stride != (vlong)w * sizeof buf[0]) - return; surface = cairo_image_surface_create_for_data((uchar*)buf, - CAIRO_FORMAT_RGB24, w, h, stride); + CAIRO_FORMAT_RGB24, w, h, w * sizeof buf[0]); if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS){ cairo_surface_destroy(surface); return; diff --git a/popup_layout.c b/popup_layout.c index c349dfa..ad187a6 100644 --- a/popup_layout.c +++ b/popup_layout.c @@ -119,7 +119,7 @@ void popuplayout(Drawcmd *dc, int areaw, int areah, Popup *p) { char buf[32]; - int first, i, markrow, nall, nmark, npre, pad, total, width, y; + int first, i, markrow, nall, nmark, npre, total, width, y; memset(p, 0, sizeof *p); p->prey = -1; @@ -127,14 +127,12 @@ popuplayout(Drawcmd *dc, int areaw, int areah, Popup *p) p->rowsy = -1; p->marky = -1; p->sely = -1; - pad = PopupPad; nall = min(max(dc->nkouho, 0), Maxdisp); npre = dc->pre.n != 0; if((nall == 0 && !npre) || areaw <= 0 || areah <= 0) return; - /* Rows first; a page marker when they do not all fit; and in a - * sliver of a work area the selected row alone, unpadded. */ + /* As many rows as fit, and a page marker when they do not all. */ total = max(dc->total, dc->first + nall); markrow = dc->first > 0 || nall < total; p->n = fitrows(areah, npre, markrow, nall); @@ -142,15 +140,8 @@ popuplayout(Drawcmd *dc, int areaw, int areah, Popup *p) markrow = 1; p->n = fitrows(areah, npre, markrow, nall); } - if(p->n == 0 && markrow){ - markrow = 0; - p->n = fitrows(areah, npre, markrow, nall); - } - if(p->n == 0 && nall != 0){ - npre = 0; - pad = 0; - p->n = max(min(nall, areah / Fontsz), 1); - } + if(p->n == 0 && !npre) + return; if(p->n != 0 && dc->sel >= p->n) p->row0 = min(dc->sel - p->n + 1, nall - p->n); first = dc->first + p->row0; @@ -171,7 +162,7 @@ popuplayout(Drawcmd *dc, int areaw, int areah, Popup *p) } p->w = min(width, areaw); - y = pad; + y = PopupPad; if(npre){ p->prey = y; y += Fontsz; @@ -188,7 +179,7 @@ popuplayout(Drawcmd *dc, int areaw, int areah, Popup *p) p->marky = y; y += Fontsz; } - p->h = min(y + pad, areah); + p->h = min(y + PopupPad, areah); p->textw = max(p->w - 2*PopupPad - PopupNumw, 0); if(markrow){ p->markw = min(p->markw, max(p->w - 2*PopupPad, 0)); @@ -206,10 +197,6 @@ popupdraw(u32int *img, Drawcmd *dc, Popup *p) u32int color; int i, j, y; - if(img == nil || p->n < 0 || p->n > Maxdisp || - p->row0 < 0 || p->row0 + p->n > dc->nkouho || - p->w <= 0 || p->h <= 0 || p->h > Imgh) - return; fill(img, p->w*p->h, Colbg); if(p->prey >= 0) textdraw(img, p->w, p->h, PopupPad, p->prey, diff --git a/tests/font_test.c b/tests/font_test.c index aaab744..8ca443f 100644 --- a/tests/font_test.c +++ b/tests/font_test.c @@ -189,10 +189,7 @@ font_render(struct ct *t) buf = mem + Guard; fillpixels(buf, Testn, Colbg); a = mkstr("A"); - if(!CT_CHECK(t, textinit())){ - free(mem); - return; - } + textinit(); for(i = 0; i < nelem(plain); i++) checktext(t, buf, plain[i]); @@ -257,6 +254,4 @@ font_render(struct ct *t) checkguards(t, mem); free(mem); textclose(); - textclose(); - CT_EQ_INT(t, 0, textwidth(&a)); } diff --git a/tests/popup_test.c b/tests/popup_test.c index b83b27a..3a7d2fb 100644 --- a/tests/popup_test.c +++ b/tests/popup_test.c @@ -2,6 +2,9 @@ #include "fn.h" #include "test.h" +/* A popup with every section, tall enough for the tests. */ +#define Imgh (2*PopupPad + (Maxdisp + 2)*Fontsz + PopupSep) + enum { Rgbmask = 0xffffff, }; @@ -40,9 +43,6 @@ checkpadding(struct ct *t, u32int *img, Popup *p) void popup_layout(struct ct *t) { - int tinyheight[] = { - 1, PopupPad, 2*PopupPad + Fontsz - 1, - }; static const struct { int first; int shown; @@ -132,8 +132,7 @@ popup_layout(struct ct *t) CT_EQ_INT(t, 100, x); CT_EQ_INT(t, 200, y); - if(!CT_CHECK(t, textinit())) - return; + textinit(); /* Empty sections reserve nothing. */ memset(&dc, 0, sizeof dc); @@ -320,24 +319,5 @@ popup_layout(struct ct *t) CT_CHECK(t, numink > 0); /* full-width 9 */ CT_CHECK(t, markink > 0); /* 9-9/9 */ - /* The selected row wins over preedit and footer in one-row height. */ - dc.pre = mkstr("preedit"); - popuplayout(&dc, PopupBasew, 2*PopupPad + Fontsz, &p); - CT_EQ_INT(t, -1, p.prey); - CT_EQ_INT(t, 1, p.n); - CT_EQ_INT(t, Maxdisp - 1, p.row0); - CT_EQ_INT(t, -1, p.marky); - - /* With less than one padded row, selected content starts at the top. */ - for(i = 0; i < nelem(tinyheight); i++){ - popuplayout(&dc, PopupBasew, tinyheight[i], &p); - CT_EQ_INT(t, min(tinyheight[i], Fontsz), p.h); - CT_EQ_INT(t, 0, p.rowsy); - CT_EQ_INT(t, 0, p.sely); - CT_EQ_INT(t, 1, p.n); - CT_EQ_INT(t, Maxdisp - 1, p.row0); - popupdraw(img, &dc, &p); - CT_EQ_UINT(t, Colsel, pixel(img, &p, p.w - PopupPad - 1, 0)); - } free(img); } diff --git a/win.c b/win.c index 6e16c81..4a52ebb 100644 --- a/win.c +++ b/win.c @@ -250,11 +250,7 @@ wininit(void) win, type, XCB_ATOM_ATOM, 32, 1, &tooltip); gc = xcb_generate_id(conn); xcb_create_gc(conn, gc, win, 0, nil); - if(!textinit()){ - fprint(2, "strans: popup disabled: no usable fonts\n"); - wincleanup(); - return 0; - } + textinit(); return 1; }