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