boxdraw.c (5369B)
1 /* 2 * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih 3 * MIT/X Consortium License 4 */ 5 6 #include <X11/Xft/Xft.h> 7 #include "st.h" 8 #include "boxdraw_data.h" 9 #include "boxdraw.h" 10 11 /* Rounded non-negative integers division of n / d */ 12 #define DIV(n, d) (((n) + (d) / 2) / (d)) 13 14 #ifndef BOXDRAW_H 15 #define BOXDRAW_H 16 17 extern int boxdraw; 18 extern int boxdraw_braille; 19 extern int boxdraw_bold; 20 21 #endif 22 23 24 int boxdraw = 1; // Enables box drawing 25 int boxdraw_braille = 1; // Enables braille support 26 int boxdraw_bold = 1; // Enables bold support 27 28 static Display *xdpy; 29 static Colormap xcmap; 30 static XftDraw *xd; 31 static Visual *xvis; 32 33 static void drawbox(int, int, int, int, XftColor *, XftColor *, ushort); 34 static void drawboxlines(int, int, int, int, XftColor *, ushort); 35 36 /* public API */ 37 38 void 39 boxdraw_xinit(Display *dpy, Colormap cmap, XftDraw *draw, Visual *vis) 40 { 41 xdpy = dpy; xcmap = cmap; xd = draw, xvis = vis; 42 } 43 44 int 45 isboxdraw(Rune u) 46 { 47 Rune block = u & ~0xff; 48 return (boxdraw && block == 0x2500 && boxdata[(uint8_t)u]) || 49 (boxdraw_braille && block == 0x2800); 50 } 51 52 /* the "index" is actually the entire shape data encoded as ushort */ 53 ushort 54 boxdrawindex(const Glyph *g) 55 { 56 if (boxdraw_braille && (g->u & ~0xff) == 0x2800) 57 return BRL | (uint8_t)g->u; 58 if (boxdraw_bold && (g->mode & ATTR_BOLD)) 59 return BDB | boxdata[(uint8_t)g->u]; 60 return boxdata[(uint8_t)g->u]; 61 } 62 63 void 64 drawboxes(int x, int y, int cw, int ch, XftColor *fg, XftColor *bg, 65 const XftGlyphFontSpec *specs, int len) 66 { 67 for ( ; len-- > 0; x += cw, specs++) 68 drawbox(x, y, cw, ch, fg, bg, (ushort)specs->glyph); 69 } 70 71 /* implementation */ 72 73 void 74 drawbox(int x, int y, int w, int h, XftColor *fg, XftColor *bg, ushort bd) 75 { 76 ushort cat = bd & ~(BDB | 0xff); /* mask out bold and data */ 77 if (bd & (BDL | BDA)) { 78 /* lines (light/double/heavy/arcs) */ 79 drawboxlines(x, y, w, h, fg, bd); 80 81 } else if (cat == BBD) { 82 /* lower (8-X)/8 block */ 83 int d = DIV((uint8_t)bd * h, 8); 84 XftDrawRect(xd, fg, x, y + d, w, h - d); 85 86 } else if (cat == BBU) { 87 /* upper X/8 block */ 88 XftDrawRect(xd, fg, x, y, w, DIV((uint8_t)bd * h, 8)); 89 90 } else if (cat == BBL) { 91 /* left X/8 block */ 92 XftDrawRect(xd, fg, x, y, DIV((uint8_t)bd * w, 8), h); 93 94 } else if (cat == BBR) { 95 /* right (8-X)/8 block */ 96 int d = DIV((uint8_t)bd * w, 8); 97 XftDrawRect(xd, fg, x + d, y, w - d, h); 98 99 } else if (cat == BBQ) { 100 /* Quadrants */ 101 int w2 = DIV(w, 2), h2 = DIV(h, 2); 102 if (bd & TL) 103 XftDrawRect(xd, fg, x, y, w2, h2); 104 if (bd & TR) 105 XftDrawRect(xd, fg, x + w2, y, w - w2, h2); 106 if (bd & BL) 107 XftDrawRect(xd, fg, x, y + h2, w2, h - h2); 108 if (bd & BR) 109 XftDrawRect(xd, fg, x + w2, y + h2, w - w2, h - h2); 110 111 } else if (bd & BBS) { 112 /* Shades - data is 1/2/3 for 25%/50%/75% alpha, respectively */ 113 int d = (uint8_t)bd; 114 XftColor xfc; 115 XRenderColor xrc = { .alpha = 0xffff }; 116 117 xrc.red = DIV(fg->color.red * d + bg->color.red * (4 - d), 4); 118 xrc.green = DIV(fg->color.green * d + bg->color.green * (4 - d), 4); 119 xrc.blue = DIV(fg->color.blue * d + bg->color.blue * (4 - d), 4); 120 121 XftColorAllocValue(xdpy, xvis, xcmap, &xrc, &xfc); 122 XftDrawRect(xd, &xfc, x, y, w, h); 123 XftColorFree(xdpy, xvis, xcmap, &xfc); 124 125 } else if (cat == BRL) { 126 /* braille, each data bit corresponds to one dot at 2x4 grid */ 127 int w1 = DIV(w, 2); 128 int h1 = DIV(h, 4), h2 = DIV(h, 2), h3 = DIV(3 * h, 4); 129 130 if (bd & 1) XftDrawRect(xd, fg, x, y, w1, h1); 131 if (bd & 2) XftDrawRect(xd, fg, x, y + h1, w1, h2 - h1); 132 if (bd & 4) XftDrawRect(xd, fg, x, y + h2, w1, h3 - h2); 133 if (bd & 8) XftDrawRect(xd, fg, x + w1, y, w - w1, h1); 134 if (bd & 16) XftDrawRect(xd, fg, x + w1, y + h1, w - w1, h2 - h1); 135 if (bd & 32) XftDrawRect(xd, fg, x + w1, y + h2, w - w1, h3 - h2); 136 if (bd & 64) XftDrawRect(xd, fg, x, y + h3, w1, h - h3); 137 if (bd & 128) XftDrawRect(xd, fg, x + w1, y + h3, w - w1, h - h3); 138 139 } 140 } 141 142 void 143 drawboxlines(int x, int y, int w, int h, XftColor *fg, ushort bd) 144 { 145 /* s: stem thickness. width/8 roughly matches underscore thickness. */ 146 /* We draw bold as 1.5 * normal-stem and at least 1px thicker. */ 147 /* doubles draw at least 3px, even when w or h < 3. bold needs 6px. */ 148 int mwh = MIN(w, h); 149 int base_s = MAX(1, DIV(mwh, 8)); 150 int bold = (bd & BDB) && mwh >= 6; /* possibly ignore boldness */ 151 int s = bold ? MAX(base_s + 1, DIV(3 * base_s, 2)) : base_s; 152 int w2 = DIV(w - s, 2), h2 = DIV(h - s, 2); 153 /* the s-by-s square (x + w2, y + h2, s, s) is the center texel. */ 154 /* The base length (per direction till edge) includes this square. */ 155 156 int light = bd & (LL | LU | LR | LD); 157 int double_ = bd & (DL | DU | DR | DD); 158 159 if (light) { 160 /* d: additional (negative) length to not-draw the center */ 161 /* texel - at arcs and avoid drawing inside (some) doubles */ 162 /* light crosses double only at DH+LV, DV+LH (ref. shapes) */ 163 int arc = bd & BDA; 164 int multi_light = light & (light - 1); 165 int multi_double = double_ & (double_ - 1); 166 /* light crosses double only at DH+LV, DV+LH (ref. shapes) */ 167 int d = arc || (multi_double && !multi_light) ? -s : 0; 168 169 if (bd & LL) 170 XftDrawRect(xd, fg, x, y + h2, w2 + s + d, s); 171 if (bd & LU) 172 XftDrawRect(xd, fg, x + w2, y, s, h2 + s + d); 173 if (bd & LR) 174 XftDrawRect(xd, fg, x + w2 - d, y + h2, w - w2 + d, s); 175 if (bd & LD) 176 XftDrawRect(xd, fg, x + w2, y + h2, s, h - h2); 177 } 178 } 179