Introduction
Introduction Statistics Contact Development Disclaimer Help
st-boxdraw-20181101-30ec9a3.diff - sites - public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log
Files
Refs
---
st-boxdraw-20181101-30ec9a3.diff (15872B)
---
1 From 1630b7016d26c266d004f38ecfef2c4b708aa9a6 Mon Sep 17 00:00:00 2001
2 From: "Avi Halachmi (:avih)" <[email protected]>
3 Date: Fri, 26 Oct 2018 13:11:20 +0300
4 Subject: [PATCH] boxdraw: custom-draw U+25XX lines/blocks to align seaml…
5
6 It seems impossible to ensure that blocks and line drawing glyphs
7 align without visible gaps for all combinations of arbitrary font,
8 size and width/height scale factor.
9
10 This commit adds an option to custom-draw (without using the font)
11 most of the lines/blocks codepoints such that they're rendered
12 identically (per size) and align perfectly regardless of font, size
13 or chscale/cwscale configuration values.
14
15 138 shapes are supported (U+2500 - U+259F except dashes, diagonals
16 and shades), composited as 16-bit values at boxdraw_data.h .
17
18 See links and references at boxdraw_data.h
19 ---
20 Makefile | 3 +-
21 boxdraw.c | 141 ++++++++++++++++++++++++++++++++++
22 boxdraw_data.h | 202 +++++++++++++++++++++++++++++++++++++++++++++++++
23 config.def.h | 8 ++
24 st.c | 3 +
25 st.h | 9 +++
26 x.c | 19 +++--
27 7 files changed, 379 insertions(+), 6 deletions(-)
28 create mode 100644 boxdraw.c
29 create mode 100644 boxdraw_data.h
30
31 diff --git a/Makefile b/Makefile
32 index 0b3cecd..8d3af33 100644
33 --- a/Makefile
34 +++ b/Makefile
35 @@ -4,7 +4,7 @@
36
37 include config.mk
38
39 -SRC = st.c x.c
40 +SRC = st.c x.c boxdraw.c
41 OBJ = $(SRC:.c=.o)
42
43 all: options st
44 @@ -23,6 +23,7 @@ config.h:
45
46 st.o: config.h st.h win.h
47 x.o: arg.h st.h win.h
48 +boxdraw.o: config.h st.h boxdraw_data.h
49
50 $(OBJ): config.h config.mk
51
52 diff --git a/boxdraw.c b/boxdraw.c
53 new file mode 100644
54 index 0000000..357250f
55 --- /dev/null
56 +++ b/boxdraw.c
57 @@ -0,0 +1,141 @@
58 +#include <X11/Xft/Xft.h>
59 +#include "st.h"
60 +#include "boxdraw_data.h"
61 +
62 +static void drawbox(XftDraw *, int, int, int, int, XftColor *, ushort);
63 +static void drawboxlines(XftDraw *, int, int, int, int, XftColor *, ush…
64 +
65 +/* public API */
66 +
67 +int
68 +isboxdraw(const Glyph *g)
69 +{
70 + return (g->u & ~0xff) == 0x2500 &&
71 + boxdata[(uint8_t)g->u] != 0 &&
72 + (g->mode & ATTR_ITALIC) == 0;
73 +}
74 +
75 +/* the "index" is actually the entire shape data encoded as ushort */
76 +ushort
77 +boxdrawindex(const Glyph *g)
78 +{
79 + return boxdata[(uint8_t)g->u] | ((g->mode & ATTR_BOLD) ? BDB : …
80 +}
81 +
82 +void
83 +drawboxes(XftDraw *xd, int x, int y, int cw, int ch, XftColor *fg,
84 + const XftGlyphFontSpec *specs, int len)
85 +{
86 + for ( ; len-- > 0; x += cw, specs++)
87 + drawbox(xd, x, y, cw, ch, fg, (ushort)specs->glyph);
88 +}
89 +
90 +/* implementation */
91 +
92 +void
93 +drawbox(XftDraw *xd, int x, int y, int w, int h, XftColor *fg, ushort b…
94 +{
95 + if (bd & (BDL | BDA)) {
96 + /* lines (light/double/heavy/arcs) */
97 + drawboxlines(xd, x, y, w, h, fg, bd);
98 +
99 + } else if (bd & BBD) {
100 + /* lower (8-X)/8 block */
101 + int d = ((uint8_t)bd * h + 4) / 8;
102 + XftDrawRect(xd, fg, x, y + d, w, h - d);
103 +
104 + } else if (bd & BBU) {
105 + /* upper X/8 block */
106 + XftDrawRect(xd, fg, x, y, w, ((uint8_t)bd * h + 4) / 8);
107 +
108 + } else if (bd & BBL) {
109 + /* left X/8 block */
110 + XftDrawRect(xd, fg, x, y, ((uint8_t)bd * w + 4) / 8, h);
111 +
112 + } else if (bd & BBR) {
113 + /* right (8-X)/8 block */
114 + int d = ((uint8_t)bd * w + 4) / 8;
115 + XftDrawRect(xd, fg, x + d, y, w - d, h);
116 +
117 + } else if (bd & BBQ) {
118 + /* Quadrants */
119 + int w2 = (w + 1) / 2, h2 = (h + 1) / 2;
120 + if (bd & TL)
121 + XftDrawRect(xd, fg, x, y, w2, h2);
122 + if (bd & TR)
123 + XftDrawRect(xd, fg, x + w2, y, w - w2, h2);
124 + if (bd & BL)
125 + XftDrawRect(xd, fg, x, y + h2, w2, h - h2);
126 + if (bd & BR)
127 + XftDrawRect(xd, fg, x + w2, y + h2, w - w2, h -…
128 + }
129 +}
130 +
131 +void
132 +drawboxlines(XftDraw *xd, int x, int y, int w, int h, XftColor *fg, ush…
133 +{
134 + /* s: stem thickness. width/8 roughly matches underscore thickn…
135 + /* We draw bold as 1.5 * normal-stem and at least 1px thicker. …
136 + /* doubles draw at least 3px, even when w or h < 3. bold needs …
137 + int mwh = MIN(w, h);
138 + int base_s = MAX(1, (mwh + 4) / 8);
139 + int bold = (bd & BDB) && mwh >= 6; /* possibly ignore boldness…
140 + int s = bold ? MAX(base_s + 1, (3 * base_s + 1) / 2) : base_s;
141 + int w2 = (w - s + 1) / 2, h2 = (h - s + 1) / 2;
142 + /* the s-by-s square (x + w2, y + h2, s, s) is the center texel…
143 + /* The base length (per direction till edge) includes this squa…
144 +
145 + int light = bd & (LL | LU | LR | LD);
146 + int double_ = bd & (DL | DU | DR | DD);
147 +
148 + if (light) {
149 + /* d: additional (negative) length to not-draw the cent…
150 + /* texel - at arcs and avoid drawing inside (some) doub…
151 + int arc = bd & BDA;
152 + int multi_light = light & (light - 1);
153 + int multi_double = double_ & (double_ - 1);
154 + /* light crosses double only at DH+LV, DV+LH (ref. shap…
155 + int d = arc || (multi_double && !multi_light) ? -s : 0;
156 +
157 + if (bd & LL)
158 + XftDrawRect(xd, fg, x, y + h2, w2 + s + d, s);
159 + if (bd & LU)
160 + XftDrawRect(xd, fg, x + w2, y, s, h2 + s + d);
161 + if (bd & LR)
162 + XftDrawRect(xd, fg, x + w2 - d, y + h2, w - w2 …
163 + if (bd & LD)
164 + XftDrawRect(xd, fg, x + w2, y + h2 - d, s, h - …
165 + }
166 +
167 + /* double lines - also align with light to form heavy when comb…
168 + if (double_) {
169 + /*
170 + * going clockwise, for each double-ray: p is additional…
171 + * to the single-ray nearer to the previous direction, a…
172 + * the next. p and n adjust from the base length to leng…
173 + * which consider other doubles - shorter to avoid inter…
174 + * (p, n), or longer to draw the far-corner texel (n).
175 + */
176 + int dl = bd & DL, du = bd & DU, dr = bd & DR, dd = bd &…
177 + if (dl) {
178 + int p = dd ? -s : 0, n = du ? -s : dd ? s : 0;
179 + XftDrawRect(xd, fg, x, y + h2 + s, w2 + s + p, …
180 + XftDrawRect(xd, fg, x, y + h2 - s, w2 + s + n, …
181 + }
182 + if (du) {
183 + int p = dl ? -s : 0, n = dr ? -s : dl ? s : 0;
184 + XftDrawRect(xd, fg, x + w2 - s, y, s, h2 + s + …
185 + XftDrawRect(xd, fg, x + w2 + s, y, s, h2 + s + …
186 + }
187 + if (dr) {
188 + int p = du ? -s : 0, n = dd ? -s : du ? s : 0;
189 + XftDrawRect(xd, fg, x + w2 - p, y + h2 - s, w -…
190 + XftDrawRect(xd, fg, x + w2 - n, y + h2 + s, w -…
191 + }
192 + if (dd) {
193 + int p = dr ? -s : 0, n = dl ? -s : dr ? s : 0;
194 + XftDrawRect(xd, fg, x + w2 + s, y + h2 - p, s, …
195 + XftDrawRect(xd, fg, x + w2 - s, y + h2 - n, s, …
196 + }
197 + }
198 +}
199 diff --git a/boxdraw_data.h b/boxdraw_data.h
200 new file mode 100644
201 index 0000000..ee78cdc
202 --- /dev/null
203 +++ b/boxdraw_data.h
204 @@ -0,0 +1,202 @@
205 +/*
206 + * U+25XX codepoints data
207 + *
208 + * References:
209 + * http://www.unicode.org/charts/PDF/U2500.pdf
210 + * http://www.unicode.org/charts/PDF/U2580.pdf
211 + *
212 + * Test page:
213 + * https://github.com/GNOME/vte/blob/master/doc/boxes.txt
214 + */
215 +
216 +/* Each shape is encoded as 16-bits. Higher bits are category, lower ar…
217 +/* Categories (mutually exclusive except BDB): */
218 +#define BDL (1<<8) /* Box Draw Lines (light/double/heavy) */
219 +#define BDA (1<<9) /* Box Draw Arc (light) */
220 +#define BBD (1<<10) /* Box Block Down (lower) X/8 */
221 +#define BBL (1<<11) /* Box Block Left X/8 */
222 +#define BBU (1<<12) /* Box Block Upper X/8 */
223 +#define BBR (1<<13) /* Box Block Right X/8 */
224 +#define BBQ (1<<14) /* Box Block Quadrants */
225 +#define BDB (1<<15) /* Box Draw is Bold */
226 +
227 +/* (BDL/BDA) Light/Double/Heavy x Left/Up/Right/Down/Horizontal/Vertica…
228 +/* Heavy is light+double (literally drawing light+double align to form …
229 +#define LL (1<<0)
230 +#define LU (1<<1)
231 +#define LR (1<<2)
232 +#define LD (1<<3)
233 +#define LH (LL+LR)
234 +#define LV (LU+LD)
235 +
236 +#define DL (1<<4)
237 +#define DU (1<<5)
238 +#define DR (1<<6)
239 +#define DD (1<<7)
240 +#define DH (DL+DR)
241 +#define DV (DU+DD)
242 +
243 +#define HL (LL+DL)
244 +#define HU (LU+DU)
245 +#define HR (LR+DR)
246 +#define HD (LD+DD)
247 +#define HH (HL+HR)
248 +#define HV (HU+HD)
249 +
250 +/* (BBQ) Quadrants Top/Bottom x Left/Right */
251 +#define TL (1<<0)
252 +#define TR (1<<1)
253 +#define BL (1<<2)
254 +#define BR (1<<3)
255 +
256 +/* 138 shapes are supported: U+2500 - U+259F except dashes/diagonals/sh…
257 +static const unsigned short boxdata[256] = {
258 + /* light lines */
259 + [0x00] = BDL + LH, /* light horizontal */
260 + [0x02] = BDL + LV, /* light vertical */
261 + [0x0c] = BDL + LD + LR, /* light down and right */
262 + [0x10] = BDL + LD + LL, /* light down and left */
263 + [0x14] = BDL + LU + LR, /* light up and right */
264 + [0x18] = BDL + LU + LL, /* light up and left */
265 + [0x1c] = BDL + LV + LR, /* light vertical and right */
266 + [0x24] = BDL + LV + LL, /* light vertical and left */
267 + [0x2c] = BDL + LH + LD, /* light horizontal and down */
268 + [0x34] = BDL + LH + LU, /* light horizontal and up */
269 + [0x3c] = BDL + LV + LH, /* light vertical and horizontal */
270 + [0x74] = BDL + LL, /* light left */
271 + [0x75] = BDL + LU, /* light up */
272 + [0x76] = BDL + LR, /* light right */
273 + [0x77] = BDL + LD, /* light down */
274 +
275 + /* heavy [+light] lines */
276 + [0x01] = BDL + HH,
277 + [0x03] = BDL + HV,
278 + [0x0d] = BDL + HR + LD,
279 + [0x0e] = BDL + HD + LR,
280 + [0x0f] = BDL + HD + HR,
281 + [0x11] = BDL + HL + LD,
282 + [0x12] = BDL + HD + LL,
283 + [0x13] = BDL + HD + HL,
284 + [0x15] = BDL + HR + LU,
285 + [0x16] = BDL + HU + LR,
286 + [0x17] = BDL + HU + HR,
287 + [0x19] = BDL + HL + LU,
288 + [0x1a] = BDL + HU + LL,
289 + [0x1b] = BDL + HU + HL,
290 + [0x1d] = BDL + HR + LV,
291 + [0x1e] = BDL + HU + LD + LR,
292 + [0x1f] = BDL + HD + LR + LU,
293 + [0x20] = BDL + HV + LR,
294 + [0x21] = BDL + HU + HR + LD,
295 + [0x22] = BDL + HD + HR + LU,
296 + [0x23] = BDL + HV + HR,
297 + [0x25] = BDL + HL + LV,
298 + [0x26] = BDL + HU + LD + LL,
299 + [0x27] = BDL + HD + LU + LL,
300 + [0x28] = BDL + HV + LL,
301 + [0x29] = BDL + HU + HL + LD,
302 + [0x2a] = BDL + HD + HL + LU,
303 + [0x2b] = BDL + HV + HL,
304 + [0x2d] = BDL + HL + LD + LR,
305 + [0x2e] = BDL + HR + LL + LD,
306 + [0x2f] = BDL + HH + LD,
307 + [0x30] = BDL + HD + LH,
308 + [0x31] = BDL + HD + HL + LR,
309 + [0x32] = BDL + HR + HD + LL,
310 + [0x33] = BDL + HH + HD,
311 + [0x35] = BDL + HL + LU + LR,
312 + [0x36] = BDL + HR + LU + LL,
313 + [0x37] = BDL + HH + LU,
314 + [0x38] = BDL + HU + LH,
315 + [0x39] = BDL + HU + HL + LR,
316 + [0x3a] = BDL + HU + HR + LL,
317 + [0x3b] = BDL + HH + HU,
318 + [0x3d] = BDL + HL + LV + LR,
319 + [0x3e] = BDL + HR + LV + LL,
320 + [0x3f] = BDL + HH + LV,
321 + [0x40] = BDL + HU + LH + LD,
322 + [0x41] = BDL + HD + LH + LU,
323 + [0x42] = BDL + HV + LH,
324 + [0x43] = BDL + HU + HL + LD + LR,
325 + [0x44] = BDL + HU + HR + LD + LL,
326 + [0x45] = BDL + HD + HL + LU + LR,
327 + [0x46] = BDL + HD + HR + LU + LL,
328 + [0x47] = BDL + HH + HU + LD,
329 + [0x48] = BDL + HH + HD + LU,
330 + [0x49] = BDL + HV + HL + LR,
331 + [0x4a] = BDL + HV + HR + LL,
332 + [0x4b] = BDL + HV + HH,
333 + [0x78] = BDL + HL,
334 + [0x79] = BDL + HU,
335 + [0x7a] = BDL + HR,
336 + [0x7b] = BDL + HD,
337 + [0x7c] = BDL + HR + LL,
338 + [0x7d] = BDL + HD + LU,
339 + [0x7e] = BDL + HL + LR,
340 + [0x7f] = BDL + HU + LD,
341 +
342 + /* double [+light] lines */
343 + [0x50] = BDL + DH,
344 + [0x51] = BDL + DV,
345 + [0x52] = BDL + DR + LD,
346 + [0x53] = BDL + DD + LR,
347 + [0x54] = BDL + DR + DD,
348 + [0x55] = BDL + DL + LD,
349 + [0x56] = BDL + DD + LL,
350 + [0x57] = BDL + DL + DD,
351 + [0x58] = BDL + DR + LU,
352 + [0x59] = BDL + DU + LR,
353 + [0x5a] = BDL + DU + DR,
354 + [0x5b] = BDL + DL + LU,
355 + [0x5c] = BDL + DU + LL,
356 + [0x5d] = BDL + DL + DU,
357 + [0x5e] = BDL + DR + LV,
358 + [0x5f] = BDL + DV + LR,
359 + [0x60] = BDL + DV + DR,
360 + [0x61] = BDL + DL + LV,
361 + [0x62] = BDL + DV + LL,
362 + [0x63] = BDL + DV + DL,
363 + [0x64] = BDL + DH + LD,
364 + [0x65] = BDL + DD + LH,
365 + [0x66] = BDL + DD + DH,
366 + [0x67] = BDL + DH + LU,
367 + [0x68] = BDL + DU + LH,
368 + [0x69] = BDL + DH + DU,
369 + [0x6a] = BDL + DH + LV,
370 + [0x6b] = BDL + DV + LH,
371 + [0x6c] = BDL + DH + DV,
372 +
373 + /* (light) arcs */
374 + [0x6d] = BDA + LD + LR,
375 + [0x6e] = BDA + LD + LL,
376 + [0x6f] = BDA + LU + LL,
377 + [0x70] = BDA + LU + LR,
378 +
379 + /* Lower (Down) X/8 block (data is 8 - X) */
380 + [0x81] = BBD + 7, [0x82] = BBD + 6, [0x83] = BBD + 5, [0x84] = …
381 + [0x85] = BBD + 3, [0x86] = BBD + 2, [0x87] = BBD + 1, [0x88] = …
382 +
383 + /* Left X/8 block (data is X) */
384 + [0x89] = BBL + 7, [0x8a] = BBL + 6, [0x8b] = BBL + 5, [0x8c] = …
385 + [0x8d] = BBL + 3, [0x8e] = BBL + 2, [0x8f] = BBL + 1,
386 +
387 + /* upper 1/2 (4/8), 1/8 block (X), right 1/2, 1/8 block (8-X) */
388 + [0x80] = BBU + 4, [0x94] = BBU + 1,
389 + [0x90] = BBR + 4, [0x95] = BBR + 7,
390 +
391 + /* Quadrants */
392 + [0x96] = BBQ + BL,
393 + [0x97] = BBQ + BR,
394 + [0x98] = BBQ + TL,
395 + [0x99] = BBQ + TL + BL + BR,
396 + [0x9a] = BBQ + TL + BR,
397 + [0x9b] = BBQ + TL + TR + BL,
398 + [0x9c] = BBQ + TL + TR + BR,
399 + [0x9d] = BBQ + TR,
400 + [0x9e] = BBQ + BL + TR,
401 + [0x9f] = BBQ + BL + TR + BR,
402 +
403 + /* U+2504 - U+250B, U+254C - U+254F: unsupported (dashes) */
404 + /* U+2571 - U+2573: unsupported (diagonals) */
405 + /* U+2591 - U+2593: unsupported (shades) */
406 +};
407 diff --git a/config.def.h b/config.def.h
408 index 823e79f..018cbe4 100644
409 --- a/config.def.h
410 +++ b/config.def.h
411 @@ -56,6 +56,14 @@ static unsigned int blinktimeout = 800;
412 */
413 static unsigned int cursorthickness = 2;
414
415 +/*
416 + * 1: custom-draw (without using the font) most of the lines/blocks cha…
417 + * for gapless alignment between cells. This includes all the codepo…
418 + * U+2500 - U+259F except dashes, diagonals and shades.
419 + * 0: disable (render all glyphs normally from the font).
420 + */
421 +const int boxdraw = 0;
422 +
423 /*
424 * bell volume. It must be a value between -100 and 100. Use 0 for disa…
425 * it
426 diff --git a/st.c b/st.c
427 index 46cf2da..7ee136a 100644
428 --- a/st.c
429 +++ b/st.c
430 @@ -1228,6 +1228,9 @@ tsetchar(Rune u, Glyph *attr, int x, int y)
431 term.dirty[y] = 1;
432 term.line[y][x] = *attr;
433 term.line[y][x].u = u;
434 +
435 + if (boxdraw && isboxdraw(&term.line[y][x]))
436 + term.line[y][x].mode |= ATTR_BOXDRAW;
437 }
438
439 void
440 diff --git a/st.h b/st.h
441 index 38c61c4..fc68c3b 100644
442 --- a/st.h
443 +++ b/st.h
444 @@ -33,6 +33,7 @@ enum glyph_attribute {
445 ATTR_WRAP = 1 << 8,
446 ATTR_WIDE = 1 << 9,
447 ATTR_WDUMMY = 1 << 10,
448 + ATTR_BOXDRAW = 1 << 11,
449 ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
450 };
451
452 @@ -110,6 +111,13 @@ void *xmalloc(size_t);
453 void *xrealloc(void *, size_t);
454 char *xstrdup(char *);
455
456 +int isboxdraw(const Glyph *);
457 +ushort boxdrawindex(const Glyph *);
458 +#ifdef XFT_VERSION
459 +/* only exposed to x.c, otherwise we'll need Xft.h for the types */
460 +void drawboxes(XftDraw *, int, int, int, int, XftColor *, const XftGlyp…
461 +#endif
462 +
463 /* config.h globals */
464 extern char *utmp;
465 extern char *stty_args;
466 @@ -120,3 +128,4 @@ extern char *termname;
467 extern unsigned int tabspaces;
468 extern unsigned int defaultfg;
469 extern unsigned int defaultbg;
470 +extern const int boxdraw;
471 diff --git a/x.c b/x.c
472 index 00cb6b1..730f525 100644
473 --- a/x.c
474 +++ b/x.c
475 @@ -1164,8 +1164,13 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, cons…
476 yp = winy + font->ascent;
477 }
478
479 - /* Lookup character index with default font. */
480 - glyphidx = XftCharIndex(xw.dpy, font->match, rune);
481 + if (mode & ATTR_BOXDRAW) {
482 + /* minor shoehorning: boxdraw uses only this us…
483 + glyphidx = boxdrawindex(&glyphs[i]);
484 + } else {
485 + /* Lookup character index with default font. */
486 + glyphidx = XftCharIndex(xw.dpy, font->match, ru…
487 + }
488 if (glyphidx) {
489 specs[numspecs].font = font->match;
490 specs[numspecs].glyph = glyphidx;
491 @@ -1372,8 +1377,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs…
492 r.width = width;
493 XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
494
495 - /* Render the glyphs. */
496 - XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
497 + if (base.mode & ATTR_BOXDRAW) {
498 + drawboxes(xw.draw, winx, winy, width / len, win.ch, fg,…
499 + } else {
500 + /* Render the glyphs. */
501 + XftDrawGlyphFontSpec(xw.draw, fg, specs, len);
502 + }
503
504 /* Render underline and strikethrough. */
505 if (base.mode & ATTR_UNDERLINE) {
506 @@ -1416,7 +1425,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int o…
507 /*
508 * Select the right color for the right mode.
509 */
510 - g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR…
511 + g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR…
512
513 if (IS_SET(MODE_REVERSE)) {
514 g.mode |= ATTR_REVERSE;
515 --
516 2.19.1
517
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.