popup: no fallbacks for work areas no desktop has; text setup cannot fail
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.
This commit is contained in:
1
dat.h
1
dat.h
@@ -44,7 +44,6 @@ extern int popupscale;
|
|||||||
#define PopupNumw Fontsz
|
#define PopupNumw Fontsz
|
||||||
#define PopupTextw (12*Fontsz)
|
#define PopupTextw (12*Fontsz)
|
||||||
#define PopupBasew (2*PopupPad + PopupNumw + PopupTextw)
|
#define PopupBasew (2*PopupPad + PopupNumw + PopupTextw)
|
||||||
#define Imgh (2*PopupPad + (Maxdisp + 2)*Fontsz + PopupSep)
|
|
||||||
|
|
||||||
typedef struct Str Str;
|
typedef struct Str Str;
|
||||||
struct Str
|
struct Str
|
||||||
|
|||||||
2
fn.h
2
fn.h
@@ -48,7 +48,7 @@ int keymeaningful(u32int);
|
|||||||
void* emalloc(ulong);
|
void* emalloc(ulong);
|
||||||
void* erealloc(void*, ulong);
|
void* erealloc(void*, ulong);
|
||||||
|
|
||||||
int textinit(void);
|
void textinit(void);
|
||||||
void textclose(void);
|
void textclose(void);
|
||||||
int textwidth(Str*);
|
int textwidth(Str*);
|
||||||
void textdraw(u32int*, int, int, int, int, int, u32int, Str*);
|
void textdraw(u32int*, int, int, int, int, int, u32int, Str*);
|
||||||
|
|||||||
38
font.c
38
font.c
@@ -7,13 +7,6 @@ static PangoFontMap *fontmap;
|
|||||||
static PangoContext *context;
|
static PangoContext *context;
|
||||||
static PangoLayout *layout;
|
static PangoLayout *layout;
|
||||||
|
|
||||||
static void
|
|
||||||
resetlayout(void)
|
|
||||||
{
|
|
||||||
pango_layout_set_width(layout, -1);
|
|
||||||
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
textclose(void)
|
textclose(void)
|
||||||
{
|
{
|
||||||
@@ -50,28 +43,16 @@ setfont(void)
|
|||||||
pango_font_description_free(font);
|
pango_font_description_free(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
textinit(void)
|
textinit(void)
|
||||||
{
|
{
|
||||||
textclose();
|
|
||||||
FcInit();
|
FcInit();
|
||||||
fontmap = pango_cairo_font_map_new();
|
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);
|
pango_cairo_font_map_set_resolution(PANGO_CAIRO_FONT_MAP(fontmap), 96);
|
||||||
context = pango_font_map_create_context(fontmap);
|
context = pango_font_map_create_context(fontmap);
|
||||||
if(context != nil)
|
|
||||||
layout = pango_layout_new(context);
|
layout = pango_layout_new(context);
|
||||||
if(context == nil || layout == nil){
|
|
||||||
fprint(2, "strans: popup: can't create text layout\n");
|
|
||||||
textclose();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
pango_layout_set_single_paragraph_mode(layout, TRUE);
|
pango_layout_set_single_paragraph_mode(layout, TRUE);
|
||||||
setfont();
|
setfont();
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -80,8 +61,6 @@ settext(Str *s)
|
|||||||
char utf[Maxutf];
|
char utf[Maxutf];
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if(layout == nil || s == nil || s->n <= 0)
|
|
||||||
return 0;
|
|
||||||
n = stoutf(s, utf, sizeof utf);
|
n = stoutf(s, utf, sizeof utf);
|
||||||
pango_layout_set_text(layout, utf, n);
|
pango_layout_set_text(layout, utf, n);
|
||||||
return n > 0;
|
return n > 0;
|
||||||
@@ -109,9 +88,8 @@ textwidth(Str *s)
|
|||||||
{
|
{
|
||||||
PangoRectangle r;
|
PangoRectangle r;
|
||||||
|
|
||||||
if(layout == nil)
|
pango_layout_set_width(layout, -1);
|
||||||
return 0;
|
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
|
||||||
resetlayout();
|
|
||||||
if(!settext(s))
|
if(!settext(s))
|
||||||
return 0;
|
return 0;
|
||||||
textextents(&r);
|
textextents(&r);
|
||||||
@@ -130,20 +108,16 @@ textdraw(u32int *buf, int w, int h, int x, int y, int fit, u32int color,
|
|||||||
PangoRectangle r;
|
PangoRectangle r;
|
||||||
cairo_surface_t *surface;
|
cairo_surface_t *surface;
|
||||||
cairo_t *cr;
|
cairo_t *cr;
|
||||||
int b, g, red, stride;
|
int b, g, red;
|
||||||
|
|
||||||
if(layout == nil || fit <= 0)
|
if(fit <= 0)
|
||||||
return;
|
return;
|
||||||
resetlayout();
|
|
||||||
pango_layout_set_width(layout, fit * PANGO_SCALE);
|
pango_layout_set_width(layout, fit * PANGO_SCALE);
|
||||||
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
|
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
|
||||||
if(w <= 0 || h <= 0 || !settext(s))
|
if(w <= 0 || h <= 0 || !settext(s))
|
||||||
return;
|
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,
|
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){
|
if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS){
|
||||||
cairo_surface_destroy(surface);
|
cairo_surface_destroy(surface);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ void
|
|||||||
popuplayout(Drawcmd *dc, int areaw, int areah, Popup *p)
|
popuplayout(Drawcmd *dc, int areaw, int areah, Popup *p)
|
||||||
{
|
{
|
||||||
char buf[32];
|
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);
|
memset(p, 0, sizeof *p);
|
||||||
p->prey = -1;
|
p->prey = -1;
|
||||||
@@ -127,14 +127,12 @@ popuplayout(Drawcmd *dc, int areaw, int areah, Popup *p)
|
|||||||
p->rowsy = -1;
|
p->rowsy = -1;
|
||||||
p->marky = -1;
|
p->marky = -1;
|
||||||
p->sely = -1;
|
p->sely = -1;
|
||||||
pad = PopupPad;
|
|
||||||
nall = min(max(dc->nkouho, 0), Maxdisp);
|
nall = min(max(dc->nkouho, 0), Maxdisp);
|
||||||
npre = dc->pre.n != 0;
|
npre = dc->pre.n != 0;
|
||||||
if((nall == 0 && !npre) || areaw <= 0 || areah <= 0)
|
if((nall == 0 && !npre) || areaw <= 0 || areah <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Rows first; a page marker when they do not all fit; and in a
|
/* As many rows as fit, and a page marker when they do not all. */
|
||||||
* sliver of a work area the selected row alone, unpadded. */
|
|
||||||
total = max(dc->total, dc->first + nall);
|
total = max(dc->total, dc->first + nall);
|
||||||
markrow = dc->first > 0 || nall < total;
|
markrow = dc->first > 0 || nall < total;
|
||||||
p->n = fitrows(areah, npre, markrow, nall);
|
p->n = fitrows(areah, npre, markrow, nall);
|
||||||
@@ -142,15 +140,8 @@ popuplayout(Drawcmd *dc, int areaw, int areah, Popup *p)
|
|||||||
markrow = 1;
|
markrow = 1;
|
||||||
p->n = fitrows(areah, npre, markrow, nall);
|
p->n = fitrows(areah, npre, markrow, nall);
|
||||||
}
|
}
|
||||||
if(p->n == 0 && markrow){
|
if(p->n == 0 && !npre)
|
||||||
markrow = 0;
|
return;
|
||||||
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 && dc->sel >= p->n)
|
if(p->n != 0 && dc->sel >= p->n)
|
||||||
p->row0 = min(dc->sel - p->n + 1, nall - p->n);
|
p->row0 = min(dc->sel - p->n + 1, nall - p->n);
|
||||||
first = dc->first + p->row0;
|
first = dc->first + p->row0;
|
||||||
@@ -171,7 +162,7 @@ popuplayout(Drawcmd *dc, int areaw, int areah, Popup *p)
|
|||||||
}
|
}
|
||||||
p->w = min(width, areaw);
|
p->w = min(width, areaw);
|
||||||
|
|
||||||
y = pad;
|
y = PopupPad;
|
||||||
if(npre){
|
if(npre){
|
||||||
p->prey = y;
|
p->prey = y;
|
||||||
y += Fontsz;
|
y += Fontsz;
|
||||||
@@ -188,7 +179,7 @@ popuplayout(Drawcmd *dc, int areaw, int areah, Popup *p)
|
|||||||
p->marky = y;
|
p->marky = y;
|
||||||
y += Fontsz;
|
y += Fontsz;
|
||||||
}
|
}
|
||||||
p->h = min(y + pad, areah);
|
p->h = min(y + PopupPad, areah);
|
||||||
p->textw = max(p->w - 2*PopupPad - PopupNumw, 0);
|
p->textw = max(p->w - 2*PopupPad - PopupNumw, 0);
|
||||||
if(markrow){
|
if(markrow){
|
||||||
p->markw = min(p->markw, max(p->w - 2*PopupPad, 0));
|
p->markw = min(p->markw, max(p->w - 2*PopupPad, 0));
|
||||||
@@ -206,10 +197,6 @@ popupdraw(u32int *img, Drawcmd *dc, Popup *p)
|
|||||||
u32int color;
|
u32int color;
|
||||||
int i, j, y;
|
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);
|
fill(img, p->w*p->h, Colbg);
|
||||||
if(p->prey >= 0)
|
if(p->prey >= 0)
|
||||||
textdraw(img, p->w, p->h, PopupPad, p->prey,
|
textdraw(img, p->w, p->h, PopupPad, p->prey,
|
||||||
|
|||||||
@@ -189,10 +189,7 @@ font_render(struct ct *t)
|
|||||||
buf = mem + Guard;
|
buf = mem + Guard;
|
||||||
fillpixels(buf, Testn, Colbg);
|
fillpixels(buf, Testn, Colbg);
|
||||||
a = mkstr("A");
|
a = mkstr("A");
|
||||||
if(!CT_CHECK(t, textinit())){
|
textinit();
|
||||||
free(mem);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for(i = 0; i < nelem(plain); i++)
|
for(i = 0; i < nelem(plain); i++)
|
||||||
checktext(t, buf, plain[i]);
|
checktext(t, buf, plain[i]);
|
||||||
|
|
||||||
@@ -257,6 +254,4 @@ font_render(struct ct *t)
|
|||||||
checkguards(t, mem);
|
checkguards(t, mem);
|
||||||
free(mem);
|
free(mem);
|
||||||
textclose();
|
textclose();
|
||||||
textclose();
|
|
||||||
CT_EQ_INT(t, 0, textwidth(&a));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
#include "fn.h"
|
#include "fn.h"
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
|
||||||
|
/* A popup with every section, tall enough for the tests. */
|
||||||
|
#define Imgh (2*PopupPad + (Maxdisp + 2)*Fontsz + PopupSep)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
Rgbmask = 0xffffff,
|
Rgbmask = 0xffffff,
|
||||||
};
|
};
|
||||||
@@ -40,9 +43,6 @@ checkpadding(struct ct *t, u32int *img, Popup *p)
|
|||||||
void
|
void
|
||||||
popup_layout(struct ct *t)
|
popup_layout(struct ct *t)
|
||||||
{
|
{
|
||||||
int tinyheight[] = {
|
|
||||||
1, PopupPad, 2*PopupPad + Fontsz - 1,
|
|
||||||
};
|
|
||||||
static const struct {
|
static const struct {
|
||||||
int first;
|
int first;
|
||||||
int shown;
|
int shown;
|
||||||
@@ -132,8 +132,7 @@ popup_layout(struct ct *t)
|
|||||||
CT_EQ_INT(t, 100, x);
|
CT_EQ_INT(t, 100, x);
|
||||||
CT_EQ_INT(t, 200, y);
|
CT_EQ_INT(t, 200, y);
|
||||||
|
|
||||||
if(!CT_CHECK(t, textinit()))
|
textinit();
|
||||||
return;
|
|
||||||
|
|
||||||
/* Empty sections reserve nothing. */
|
/* Empty sections reserve nothing. */
|
||||||
memset(&dc, 0, sizeof dc);
|
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, numink > 0); /* full-width 9 */
|
||||||
CT_CHECK(t, markink > 0); /* 9-9/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);
|
free(img);
|
||||||
}
|
}
|
||||||
|
|||||||
6
win.c
6
win.c
@@ -250,11 +250,7 @@ wininit(void)
|
|||||||
win, type, XCB_ATOM_ATOM, 32, 1, &tooltip);
|
win, type, XCB_ATOM_ATOM, 32, 1, &tooltip);
|
||||||
gc = xcb_generate_id(conn);
|
gc = xcb_generate_id(conn);
|
||||||
xcb_create_gc(conn, gc, win, 0, nil);
|
xcb_create_gc(conn, gc, win, 0, nil);
|
||||||
if(!textinit()){
|
textinit();
|
||||||
fprint(2, "strans: popup disabled: no usable fonts\n");
|
|
||||||
wincleanup();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user