HTTPS
https://git.nageyqma.icu/nageyqma/st.git
SSH
git@git.nageyqma.icu:nageyqma/st.git
HTTPS 链接可直接 git clone;推送代码请使用 SSH。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
/*
* Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih
* MIT/X Consortium License
*/
#include "st.h"
#include "render.h"
#include "boxdraw_data.h"
/* Rounded non-negative integers division of n / d */
#define DIV(n, d) (((n) + (d) / 2) / (d))
static void drawbox(int, int, int, int, uint32_t, uint32_t, ushort);
static void drawboxlines(int, int, int, int, uint32_t, ushort);
/* public API */
int
isboxdraw(Rune u)
{
Rune block = u & ~0xff;
return (boxdraw && block == 0x2500 && boxdata[(uint8_t)u]) ||
(boxdraw_braille && block == 0x2800);
}
/* the "index" is actually the entire shape data encoded as ushort */
ushort
boxdrawindex(const Glyph *g)
{
if (boxdraw_braille && (g->u & ~0xff) == 0x2800)
return BRL | (uint8_t)g->u;
if (boxdraw_bold && (g->mode & ATTR_BOLD))
return BDB | boxdata[(uint8_t)g->u];
return boxdata[(uint8_t)g->u];
}
void
drawboxes(int x, int y, int cw, int ch, uint32_t fg, uint32_t bg,
const GlyphSpec *specs, int len)
{
for ( ; len-- > 0; x += cw, specs++)
drawbox(x, y, cw, ch, fg, bg, (ushort)specs->glyph);
}
/* implementation */
void
drawbox(int x, int y, int w, int h, uint32_t fg, uint32_t bg, ushort bd)
{
ushort cat = bd & ~(BDB | 0xff); /* mask out bold and data */
if (bd & (BDL | BDA)) {
/* lines (light/double/heavy/arcs) */
drawboxlines(x, y, w, h, fg, bd);
} else if (cat == BBD) {
/* lower (8-X)/8 block */
int d = DIV((uint8_t)bd * h, 8);
blendrect(x, y + d, w, h - d, fg);
} else if (cat == BBU) {
/* upper X/8 block */
blendrect(x, y, w, DIV((uint8_t)bd * h, 8), fg);
} else if (cat == BBL) {
/* left X/8 block */
blendrect(x, y, DIV((uint8_t)bd * w, 8), h, fg);
} else if (cat == BBR) {
/* right (8-X)/8 block */
int d = DIV((uint8_t)bd * w, 8);
blendrect(x + d, y, w - d, h, fg);
} else if (cat == BBQ) {
/* Quadrants */
int w2 = DIV(w, 2), h2 = DIV(h, 2);
if (bd & TL)
blendrect(x, y, w2, h2, fg);
if (bd & TR)
blendrect(x + w2, y, w - w2, h2, fg);
if (bd & BL)
blendrect(x, y + h2, w2, h - h2, fg);
if (bd & BR)
blendrect(x + w2, y + h2, w - w2, h - h2, fg);
} else if (bd & BBS) {
/* Shades - data is 1/2/3 for 25%/50%/75% alpha, respectively */
int d = (uint8_t)bd;
uint32_t r = DIV(((fg >> 16) & 0xff) * d + ((bg >> 16) & 0xff) * (4 - d), 4);
uint32_t g = DIV(((fg >> 8) & 0xff) * d + ((bg >> 8) & 0xff) * (4 - d), 4);
uint32_t b = DIV((fg & 0xff) * d + (bg & 0xff) * (4 - d), 4);
blendrect(x, y, w, h, 0xff000000 | r << 16 | g << 8 | b);
} else if (cat == BRL) {
/* braille, each data bit corresponds to one dot at 2x4 grid */
int w1 = DIV(w, 2);
int h1 = DIV(h, 4), h2 = DIV(h, 2), h3 = DIV(3 * h, 4);
if (bd & 1) blendrect(x, y, w1, h1, fg);
if (bd & 2) blendrect(x, y + h1, w1, h2 - h1, fg);
if (bd & 4) blendrect(x, y + h2, w1, h3 - h2, fg);
if (bd & 8) blendrect(x + w1, y, w - w1, h1, fg);
if (bd & 16) blendrect(x + w1, y + h1, w - w1, h2 - h1, fg);
if (bd & 32) blendrect(x + w1, y + h2, w - w1, h3 - h2, fg);
if (bd & 64) blendrect(x, y + h3, w1, h - h3, fg);
if (bd & 128) blendrect(x + w1, y + h3, w - w1, h - h3, fg);
}
}
void
drawboxlines(int x, int y, int w, int h, uint32_t fg, ushort bd)
{
/* s: stem thickness. width/8 roughly matches underscore thickness. */
/* We draw bold as 1.5 * normal-stem and at least 1px thicker. */
/* doubles draw at least 3px, even when w or h < 3. bold needs 6px. */
int mwh = MIN(w, h);
int base_s = MAX(1, DIV(mwh, 8));
int bold = (bd & BDB) && mwh >= 6; /* possibly ignore boldness */
int s = bold ? MAX(base_s + 1, DIV(3 * base_s, 2)) : base_s;
int w2 = DIV(w - s, 2), h2 = DIV(h - s, 2);
/* the s-by-s square (x + w2, y + h2, s, s) is the center texel. */
/* The base length (per direction till edge) includes this square. */
int light = bd & (LL | LU | LR | LD);
int double_ = bd & (DL | DU | DR | DD);
if (light) {
/* d: additional (negative) length to not-draw the center */
/* texel - at arcs and avoid drawing inside (some) doubles */
int arc = bd & BDA;
int multi_light = light & (light - 1);
int multi_double = double_ & (double_ - 1);
/* light crosses double only at DH+LV, DV+LH (ref. shapes) */
int d = arc || (multi_double && !multi_light) ? -s : 0;
if (bd & LL)
blendrect(x, y + h2, w2 + s + d, s, fg);
if (bd & LU)
blendrect(x + w2, y, s, h2 + s + d, fg);
if (bd & LR)
blendrect(x + w2 - d, y + h2, w - w2 + d, s, fg);
if (bd & LD)
blendrect(x + w2, y + h2 - d, s, h - h2 + d, fg);
}
/* double lines - also align with light to form heavy when combined */
if (double_) {
/*
* going clockwise, for each double-ray: p is additional length
* to the single-ray nearer to the previous direction, and n to
* the next. p and n adjust from the base length to lengths
* which consider other doubles - shorter to avoid intersections
* (p, n), or longer to draw the far-corner texel (n).
*/
int dl = bd & DL, du = bd & DU, dr = bd & DR, dd = bd & DD;
if (dl) {
int p = dd ? -s : 0, n = du ? -s : dd ? s : 0;
blendrect(x, y + h2 + s, w2 + s + p, s, fg);
blendrect(x, y + h2 - s, w2 + s + n, s, fg);
}
if (du) {
int p = dl ? -s : 0, n = dr ? -s : dl ? s : 0;
blendrect(x + w2 - s, y, s, h2 + s + p, fg);
blendrect(x + w2 + s, y, s, h2 + s + n, fg);
}
if (dr) {
int p = du ? -s : 0, n = dd ? -s : du ? s : 0;
blendrect(x + w2 - p, y + h2 - s, w - w2 + p, s, fg);
blendrect(x + w2 - n, y + h2 + s, w - w2 + n, s, fg);
}
if (dd) {
int p = dr ? -s : 0, n = dl ? -s : dr ? s : 0;
blendrect(x + w2 + s, y + h2 - p, s, h - h2 + p, fg);
blendrect(x + w2 - s, y + h2 - n, s, h - h2 + n, fg);
}
}
}