forked from dnkl/foot
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2911 lines
81 KiB
2911 lines
81 KiB
#include "box-drawing.h" |
|
|
|
#include <stdio.h> |
|
#include <errno.h> |
|
|
|
#define LOG_MODULE "box-drawing" |
|
#define LOG_ENABLE_DBG 0 |
|
#include "log.h" |
|
#include "config.h" |
|
#include "macros.h" |
|
#include "stride.h" |
|
#include "terminal.h" |
|
#include "util.h" |
|
#include "xmalloc.h" |
|
|
|
enum thickness { |
|
LIGHT, |
|
HEAVY, |
|
}; |
|
|
|
struct buf { |
|
uint8_t *data; |
|
pixman_image_t *pix; |
|
pixman_format_code_t format; |
|
int width; |
|
int height; |
|
int stride; |
|
bool solid_shades; |
|
|
|
int thickness[2]; |
|
|
|
/* For sextants and wedges */ |
|
int x_halfs[2]; |
|
int y_thirds[2]; |
|
}; |
|
|
|
static const pixman_color_t white = {0xffff, 0xffff, 0xffff, 0xffff}; |
|
|
|
static void |
|
change_buffer_format(struct buf *buf, pixman_format_code_t new_format) |
|
{ |
|
int stride = stride_for_format_and_width(new_format, buf->width); |
|
uint8_t *new_data = xcalloc(buf->height * stride, 1); |
|
pixman_image_t *new_pix = pixman_image_create_bits_no_clear( |
|
new_format, buf->width, buf->height, (uint32_t *)new_data, stride); |
|
|
|
if (new_pix == NULL) { |
|
errno = ENOMEM; |
|
perror(__func__); |
|
abort(); |
|
} |
|
|
|
pixman_image_unref(buf->pix); |
|
free(buf->data); |
|
|
|
buf->data = new_data; |
|
buf->pix = new_pix; |
|
buf->format = new_format; |
|
buf->stride = stride; |
|
} |
|
|
|
static int NOINLINE |
|
_thickness(int base_thickness, enum thickness thick) |
|
{ |
|
int multiplier = thick * 2 + 1; |
|
|
|
xassert(base_thickness >= 1); |
|
xassert((thick == LIGHT && multiplier == 1) || |
|
(thick == HEAVY && multiplier == 3)); |
|
|
|
return base_thickness * multiplier; |
|
} |
|
#define thickness(thick) buf->thickness[thick] |
|
|
|
static void NOINLINE |
|
_hline(struct buf *buf, int x1, int x2, int y, int thick) |
|
{ |
|
pixman_box32_t box = { |
|
.x1 = min(max(x1, 0), buf->width), |
|
.x2 = min(max(x2, 0), buf->width), |
|
.y1 = min(max(y, 0), buf->height), |
|
.y2 = min(max(y + thick, 0), buf->height), |
|
}; |
|
pixman_image_fill_boxes(PIXMAN_OP_SRC, buf->pix, &white, 1, &box); |
|
} |
|
|
|
#define hline(x1, x2, y, thick) _hline(buf, x1, x2, y, thick) |
|
|
|
static void NOINLINE |
|
_vline(struct buf *buf, int y1, int y2, int x, int thick) |
|
{ |
|
pixman_box32_t box = { |
|
.x1 = min(max(x, 0), buf->width), |
|
.x2 = min(max(x + thick, 0), buf->width), |
|
.y1 = min(max(y1, 0), buf->height), |
|
.y2 = min(max(y2, 0), buf->height), |
|
}; |
|
pixman_image_fill_boxes(PIXMAN_OP_SRC, buf->pix, &white, 1, &box); |
|
} |
|
|
|
#define vline(y1, y2, x, thick) _vline(buf, y1, y2, x, thick) |
|
|
|
static void NOINLINE |
|
_rect(struct buf *buf, int x1, int y1, int x2, int y2) |
|
{ |
|
pixman_box32_t box = { |
|
.x1 = min(max(x1, 0), buf->width), |
|
.y1 = min(max(y1, 0), buf->height), |
|
.x2 = min(max(x2, 0), buf->width), |
|
.y2 = min(max(y2, 0), buf->height), |
|
}; |
|
pixman_image_fill_boxes(PIXMAN_OP_SRC, buf->pix, &white, 1, &box); |
|
} |
|
|
|
#define rect(x1, y1, x2, y2) _rect(buf, x1, y1, x2, y2) |
|
|
|
static void NOINLINE |
|
_hline_middle(struct buf *buf, enum thickness _thick) |
|
{ |
|
int thick = thickness(_thick); |
|
hline(0, buf->width, (buf->height - thick) / 2, thick); |
|
} |
|
|
|
static void NOINLINE |
|
_hline_middle_left(struct buf *buf, enum thickness _vthick, enum thickness _hthick) |
|
{ |
|
int vthick = thickness(_vthick); |
|
int hthick = thickness(_hthick); |
|
_hline(buf, 0, (buf->width + vthick) / 2, (buf->height - hthick) / 2, hthick); |
|
} |
|
|
|
static void NOINLINE |
|
_hline_middle_right(struct buf *buf, enum thickness _vthick, enum thickness _hthick) |
|
{ |
|
int vthick = thickness(_vthick); |
|
int hthick = thickness(_hthick); |
|
hline((buf->width - vthick) / 2, buf->width, (buf->height - hthick) / 2, hthick); |
|
} |
|
|
|
static void NOINLINE |
|
_vline_middle(struct buf *buf, enum thickness _thick) |
|
{ |
|
int thick = thickness(_thick); |
|
vline(0, buf->height, (buf->width - thick) / 2, thick); |
|
} |
|
|
|
static void NOINLINE |
|
_vline_middle_up(struct buf *buf, enum thickness _vthick, enum thickness _hthick) |
|
{ |
|
int vthick = thickness(_vthick); |
|
int hthick = thickness(_hthick); |
|
vline(0, (buf->height + hthick) / 2, (buf->width - vthick) / 2, vthick); |
|
} |
|
|
|
static void NOINLINE |
|
_vline_middle_down(struct buf *buf, enum thickness _vthick, enum thickness _hthick) |
|
{ |
|
int vthick = thickness(_vthick); |
|
int hthick = thickness(_hthick); |
|
vline((buf->height - hthick) / 2, buf->height, (buf->width - vthick) / 2, vthick); |
|
} |
|
|
|
#define hline_middle(thick) _hline_middle(buf, thick) |
|
#define hline_middle_left(thick) _hline_middle_left(buf, thick, thick) |
|
#define hline_middle_right(thick) _hline_middle_right(buf, thick, thick) |
|
#define hline_middle_left_mixed(vthick, hthick) _hline_middle_left(buf, vthick, hthick) |
|
#define hline_middle_right_mixed(vthick, hthick) _hline_middle_right(buf, vthick, hthick) |
|
#define vline_middle(thick) _vline_middle(buf, thick) |
|
#define vline_middle_up(thick) _vline_middle_up(buf, thick, thick) |
|
#define vline_middle_down(thick) _vline_middle_down(buf, thick, thick) |
|
#define vline_middle_up_mixed(vthick, hthick) _vline_middle_up(buf, vthick, hthick) |
|
#define vline_middle_down_mixed(vthick, hthick) _vline_middle_down(buf, vthick, hthick) |
|
|
|
static void |
|
draw_box_drawings_light_horizontal(struct buf *buf) |
|
{ |
|
hline_middle(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_horizontal(struct buf *buf) |
|
{ |
|
hline_middle(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_vertical(struct buf *buf) |
|
{ |
|
vline_middle(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_vertical(struct buf *buf) |
|
{ |
|
vline_middle(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_dash_horizontal(struct buf *buf, int count, int thick, int gap) |
|
{ |
|
int width = buf->width; |
|
int height = buf->height; |
|
|
|
xassert(count >= 2 && count <= 4); |
|
const int gap_count = count - 1; |
|
|
|
int dash_width = (width - (gap_count * gap)) / count; |
|
while (dash_width <= 0 && gap > 1) { |
|
gap--; |
|
dash_width = (width - (gap_count * gap)) / count; |
|
} |
|
|
|
if (dash_width <= 0) { |
|
hline_middle(LIGHT); |
|
return; |
|
} |
|
|
|
xassert(count * dash_width + gap_count * gap <= width); |
|
|
|
int remaining = width - count * dash_width - gap_count * gap; |
|
|
|
int x[4] = {0}; |
|
int w[4] = {dash_width, dash_width, dash_width, dash_width}; |
|
|
|
x[0] = 0; |
|
|
|
x[1] = x[0] + w[0] + gap; |
|
if (count == 2) |
|
w[1] = width - x[1]; |
|
else if (count == 3) |
|
w[1] += remaining; |
|
else |
|
w[1] += remaining / 2; |
|
|
|
if (count >= 3) { |
|
x[2] = x[1] + w[1] + gap; |
|
if (count == 3) |
|
w[2] = width - x[2]; |
|
else |
|
w[2] += remaining - remaining / 2; |
|
} |
|
|
|
if (count >= 4) { |
|
x[3] = x[2] + w[2] + gap; |
|
w[3] = width - x[3]; |
|
} |
|
|
|
hline(x[0], x[0] + w[0], (height - thick) / 2, thick); |
|
hline(x[1], x[1] + w[1], (height - thick) / 2, thick); |
|
if (count >= 3) |
|
hline(x[2], x[2] + w[2], (height - thick) / 2, thick); |
|
if (count >= 4) |
|
hline(x[3], x[3] + w[3], (height - thick) / 2, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_dash_vertical(struct buf *buf, int count, int thick, int gap) |
|
{ |
|
int width = buf->width; |
|
int height = buf->height; |
|
|
|
xassert(count >= 2 && count <= 4); |
|
const int gap_count = count - 1; |
|
|
|
int dash_height = (height - (gap_count * gap)) / count; |
|
while (dash_height <= 0 && gap > 1) { |
|
gap--; |
|
dash_height = (height - (gap_count * gap)) / count; |
|
} |
|
|
|
if (dash_height <= 0) { |
|
vline_middle(LIGHT); |
|
return; |
|
} |
|
|
|
xassert(count * dash_height + gap_count * gap <= height); |
|
|
|
int remaining = height - count * dash_height - gap_count * gap; |
|
|
|
int y[4] = {0}; |
|
int h[4] = {dash_height, dash_height, dash_height, dash_height}; |
|
|
|
y[0] = 0; |
|
|
|
y[1] = y[0] + h[0] + gap; |
|
if (count == 2) |
|
h[1] = height - y[1]; |
|
else if (count == 3) |
|
h[1] += remaining; |
|
else |
|
h[1] += remaining / 2; |
|
|
|
if (count >= 3) { |
|
y[2] = y[1] + h[1] + gap; |
|
if (count == 3) |
|
h[2] = height - y[2]; |
|
else |
|
h[2] += remaining - remaining / 2; |
|
} |
|
|
|
if (count >= 4) { |
|
y[3] = y[2] + h[2] + gap; |
|
h[3] = height - y[3]; |
|
} |
|
|
|
vline(y[0], y[0] + h[0], (width - thick) / 2, thick); |
|
vline(y[1], y[1] + h[1], (width - thick) / 2, thick); |
|
if (count >= 3) |
|
vline(y[2], y[2] + h[2], (width - thick) / 2, thick); |
|
if (count >= 4) |
|
vline(y[3], y[3] + h[3], (width - thick) / 2, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_triple_dash_horizontal(struct buf *buf) |
|
{ |
|
draw_box_drawings_dash_horizontal(buf, 3, thickness(LIGHT), thickness(LIGHT)); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_triple_dash_horizontal(struct buf *buf) |
|
{ |
|
draw_box_drawings_dash_horizontal(buf, 3, thickness(HEAVY), thickness(LIGHT)); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_triple_dash_vertical(struct buf *buf) |
|
{ |
|
draw_box_drawings_dash_vertical(buf, 3, thickness(LIGHT), thickness(HEAVY)); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_triple_dash_vertical(struct buf *buf) |
|
{ |
|
draw_box_drawings_dash_vertical(buf, 3, thickness(HEAVY), thickness(HEAVY)); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_quadruple_dash_horizontal(struct buf *buf) |
|
{ |
|
draw_box_drawings_dash_horizontal(buf, 4, thickness(LIGHT), thickness(LIGHT)); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_quadruple_dash_horizontal(struct buf *buf) |
|
{ |
|
draw_box_drawings_dash_horizontal(buf, 4, thickness(HEAVY), thickness(LIGHT)); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_quadruple_dash_vertical(struct buf *buf) |
|
{ |
|
draw_box_drawings_dash_vertical(buf, 4, thickness(LIGHT), thickness(LIGHT)); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_quadruple_dash_vertical(struct buf *buf) |
|
{ |
|
draw_box_drawings_dash_vertical(buf, 4, thickness(HEAVY), thickness(LIGHT)); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_down_and_right(struct buf *buf) |
|
{ |
|
hline_middle_right(LIGHT); |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_light_and_right_heavy(struct buf *buf) |
|
{ |
|
hline_middle_right_mixed(LIGHT, HEAVY); |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_heavy_and_right_light(struct buf *buf) |
|
{ |
|
hline_middle_right(LIGHT); |
|
vline_middle_down_mixed(HEAVY, LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_down_and_right(struct buf *buf) |
|
{ |
|
hline_middle_right(HEAVY); |
|
vline_middle_down(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_down_and_left(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_light_and_left_heavy(struct buf *buf) |
|
{ |
|
hline_middle_left_mixed(LIGHT, HEAVY); |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_heavy_and_left_light(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
vline_middle_down_mixed(HEAVY, LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_down_and_left(struct buf *buf) |
|
{ |
|
hline_middle_left(HEAVY); |
|
vline_middle_down(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_up_and_right(struct buf *buf) |
|
{ |
|
hline_middle_right(LIGHT); |
|
vline_middle_up(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_light_and_right_heavy(struct buf *buf) |
|
{ |
|
hline_middle_right_mixed(LIGHT, HEAVY); |
|
vline_middle_up(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_heavy_and_right_light(struct buf *buf) |
|
{ |
|
hline_middle_right(LIGHT); |
|
vline_middle_up_mixed(HEAVY, LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_up_and_right(struct buf *buf) |
|
{ |
|
hline_middle_right(HEAVY); |
|
vline_middle_up(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_up_and_left(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
vline_middle_up(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_light_and_left_heavy(struct buf *buf) |
|
{ |
|
hline_middle_left_mixed(LIGHT, HEAVY); |
|
vline_middle_up(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_heavy_and_left_light(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
vline_middle_up_mixed(HEAVY, LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_up_and_left(struct buf *buf) |
|
{ |
|
hline_middle_left(HEAVY); |
|
vline_middle_up(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_vertical_and_right(struct buf *buf) |
|
{ |
|
hline_middle_right(LIGHT); |
|
vline_middle(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_vertical_light_and_right_heavy(struct buf *buf) |
|
{ |
|
hline_middle_right_mixed(LIGHT, HEAVY); |
|
vline_middle(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_heavy_and_right_down_light(struct buf *buf) |
|
{ |
|
hline_middle_right(LIGHT); |
|
vline_middle_up_mixed(HEAVY, LIGHT); |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_heavy_and_right_up_light(struct buf *buf) |
|
{ |
|
hline_middle_right(LIGHT); |
|
vline_middle_up(LIGHT); |
|
vline_middle_down_mixed(HEAVY, LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_vertical_heavy_and_right_light(struct buf *buf) |
|
{ |
|
hline_middle_right(LIGHT); |
|
vline_middle(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_light_and_right_up_heavy(struct buf *buf) |
|
{ |
|
hline_middle_right(HEAVY); |
|
vline_middle_up(HEAVY); |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_light_and_right_down_heavy(struct buf *buf) |
|
{ |
|
hline_middle_right(HEAVY); |
|
vline_middle_up(LIGHT); |
|
vline_middle_down(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_vertical_and_right(struct buf *buf) |
|
{ |
|
hline_middle_right(HEAVY); |
|
vline_middle(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_vertical_and_left(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
vline_middle(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_vertical_light_and_left_heavy(struct buf *buf) |
|
{ |
|
hline_middle_left_mixed(LIGHT, HEAVY); |
|
vline_middle(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_heavy_and_left_down_light(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
vline_middle_up_mixed(HEAVY, LIGHT); |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_heavy_and_left_up_light(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
vline_middle_up(LIGHT); |
|
vline_middle_down_mixed(HEAVY, LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_vertical_heavy_and_left_light(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
vline_middle(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_light_and_left_up_heavy(struct buf *buf) |
|
{ |
|
hline_middle_left(HEAVY); |
|
vline_middle_up(HEAVY); |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_light_and_left_down_heavy(struct buf *buf) |
|
{ |
|
hline_middle_left(HEAVY); |
|
vline_middle_up(LIGHT); |
|
vline_middle_down(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_vertical_and_left(struct buf *buf) |
|
{ |
|
hline_middle_left(HEAVY); |
|
vline_middle(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_down_and_horizontal(struct buf *buf) |
|
{ |
|
hline_middle(LIGHT); |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_left_heavy_and_right_down_light(struct buf *buf) |
|
{ |
|
hline_middle_left_mixed(LIGHT, HEAVY); |
|
hline_middle_right(LIGHT); |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_right_heavy_and_left_down_light(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
hline_middle_right_mixed(LIGHT, HEAVY); |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_light_and_horizontal_heavy(struct buf *buf) |
|
{ |
|
hline_middle(HEAVY); |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_heavy_and_horizontal_light(struct buf *buf) |
|
{ |
|
hline_middle(LIGHT); |
|
vline_middle_down_mixed(HEAVY, LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_right_light_and_left_down_heavy(struct buf *buf) |
|
{ |
|
hline_middle_left(HEAVY); |
|
hline_middle_right(LIGHT); |
|
vline_middle_down(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_left_light_and_right_down_heavy(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
hline_middle_right(HEAVY); |
|
vline_middle_down(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_down_and_horizontal(struct buf *buf) |
|
{ |
|
hline_middle(HEAVY); |
|
vline_middle_down(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_up_and_horizontal(struct buf *buf) |
|
{ |
|
hline_middle(LIGHT); |
|
vline_middle_up(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_left_heavy_and_right_up_light(struct buf *buf) |
|
{ |
|
hline_middle_left_mixed(LIGHT, HEAVY); |
|
hline_middle_right(LIGHT); |
|
vline_middle_up(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_right_heavy_and_left_up_light(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
hline_middle_right_mixed(LIGHT, HEAVY); |
|
vline_middle_up(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_light_and_horizontal_heavy(struct buf *buf) |
|
{ |
|
hline_middle(HEAVY); |
|
vline_middle_up(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_heavy_and_horizontal_light(struct buf *buf) |
|
{ |
|
hline_middle(LIGHT); |
|
vline_middle_up_mixed(HEAVY, LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_right_light_and_left_up_heavy(struct buf *buf) |
|
{ |
|
hline_middle_left(HEAVY); |
|
hline_middle_right(LIGHT); |
|
vline_middle_up(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_left_light_and_right_up_heavy(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
hline_middle_right(HEAVY); |
|
vline_middle_up(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_up_and_horizontal(struct buf *buf) |
|
{ |
|
hline_middle(HEAVY); |
|
vline_middle_up(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_vertical_and_horizontal(struct buf *buf) |
|
{ |
|
hline_middle(LIGHT); |
|
vline_middle(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_left_heavy_and_right_vertical_light(struct buf *buf) |
|
{ |
|
hline_middle_left_mixed(LIGHT, HEAVY); |
|
hline_middle_right(LIGHT); |
|
vline_middle(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_right_heavy_and_left_vertical_light(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
hline_middle_right_mixed(LIGHT, HEAVY); |
|
vline_middle(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_vertical_light_and_horizontal_heavy(struct buf *buf) |
|
{ |
|
hline_middle(HEAVY); |
|
vline_middle(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_heavy_and_down_horizontal_light(struct buf *buf) |
|
{ |
|
hline_middle(LIGHT); |
|
vline_middle_up_mixed(HEAVY, LIGHT); |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_heavy_and_up_horizontal_light(struct buf *buf) |
|
{ |
|
hline_middle(LIGHT); |
|
vline_middle_up(LIGHT); |
|
vline_middle_down_mixed(HEAVY, LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_vertical_heavy_and_horizontal_light(struct buf *buf) |
|
{ |
|
hline_middle(LIGHT); |
|
vline_middle(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_left_up_heavy_and_right_down_light(struct buf *buf) |
|
{ |
|
hline_middle_left(HEAVY); |
|
hline_middle_right(LIGHT); |
|
vline_middle_up(HEAVY); |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_right_up_heavy_and_left_down_light(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
hline_middle_right(HEAVY); |
|
vline_middle_up(HEAVY); |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_left_down_heavy_and_right_up_light(struct buf *buf) |
|
{ |
|
hline_middle_left(HEAVY); |
|
hline_middle_right(LIGHT); |
|
vline_middle_up(LIGHT); |
|
vline_middle_down(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_right_down_heavy_and_left_up_light(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
hline_middle_right(HEAVY); |
|
vline_middle_up(LIGHT); |
|
vline_middle_down(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_light_and_up_horizontal_heavy(struct buf *buf) |
|
{ |
|
hline_middle(HEAVY); |
|
vline_middle_up(HEAVY); |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_light_and_down_horizontal_heavy(struct buf *buf) |
|
{ |
|
hline_middle(HEAVY); |
|
vline_middle_up(LIGHT); |
|
vline_middle_down(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_right_light_and_left_vertical_heavy(struct buf *buf) |
|
{ |
|
hline_middle_left(HEAVY); |
|
hline_middle_right(LIGHT); |
|
vline_middle(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_left_light_and_right_vertical_heavy(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
hline_middle_right(HEAVY); |
|
vline_middle(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_vertical_and_horizontal(struct buf *buf) |
|
{ |
|
hline_middle(HEAVY); |
|
vline_middle(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_double_dash_horizontal(struct buf *buf) |
|
{ |
|
draw_box_drawings_dash_horizontal(buf, 2, thickness(LIGHT), thickness(LIGHT)); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_double_dash_horizontal(struct buf *buf) |
|
{ |
|
draw_box_drawings_dash_horizontal(buf, 2, thickness(HEAVY), thickness(LIGHT)); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_double_dash_vertical(struct buf *buf) |
|
{ |
|
draw_box_drawings_dash_vertical(buf, 2, thickness(LIGHT), thickness(HEAVY)); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_double_dash_vertical(struct buf *buf) |
|
{ |
|
draw_box_drawings_dash_vertical(buf, 2, thickness(HEAVY), thickness(HEAVY)); |
|
} |
|
|
|
static void |
|
draw_box_drawings_double_horizontal(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int mid = (buf->height - thick * 3) / 2; |
|
|
|
hline(0, buf->width, mid, thick); |
|
hline(0, buf->width, mid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_double_vertical(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int mid = (buf->width - thick * 3) / 2; |
|
|
|
vline(0, buf->height, mid, thick); |
|
vline(0, buf->height, mid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_single_and_right_double(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
int vmid = (buf->width - thick) / 2; |
|
|
|
vline_middle_down(LIGHT); |
|
|
|
hline(vmid, buf->width, hmid, thick); |
|
hline(vmid, buf->width, hmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_double_and_right_single(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick) / 2; |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
hline_middle_right(LIGHT); |
|
|
|
vline(hmid, buf->height, vmid, thick); |
|
vline(hmid, buf->height, vmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_double_down_and_right(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
vline(hmid, buf->height, vmid, thick); |
|
vline(hmid + 2 * thick, buf->height, vmid + 2 * thick, thick); |
|
|
|
hline(vmid, buf->width, hmid, thick); |
|
hline(vmid + 2 * thick, buf->width, hmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_single_and_left_double(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
int vmid = (buf->width + thick) / 2; |
|
|
|
vline_middle_down(LIGHT); |
|
|
|
hline(0, vmid, hmid, thick); |
|
hline(0, vmid, hmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_double_and_left_single(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick) / 2; |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
hline_middle_left(LIGHT); |
|
|
|
vline(hmid, buf->height, vmid, thick); |
|
vline(hmid, buf->height, vmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_double_down_and_left(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
vline(hmid + 2 * thick, buf->height, vmid, thick); |
|
vline(hmid, buf->height, vmid + 2 * thick, thick); |
|
|
|
hline(0, vmid + 2 * thick, hmid, thick); |
|
hline(0, vmid, hmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_single_and_right_double(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
int vmid = (buf->width - thick) / 2; |
|
|
|
vline_middle_up(LIGHT); |
|
|
|
hline(vmid, buf->width, hmid, thick); |
|
hline(vmid, buf->width, hmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_double_and_right_single(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height + thick) / 2; |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
hline_middle_right(LIGHT); |
|
|
|
vline(0, hmid, vmid, thick); |
|
vline(0, hmid, vmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_double_up_and_right(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
vline(0, hmid + 2 * thick, vmid, thick); |
|
vline(0, hmid, vmid + 2 * thick, thick); |
|
|
|
hline(vmid + 2 * thick, buf->width, hmid, thick); |
|
hline(vmid, buf->width, hmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_single_and_left_double(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
int vmid = (buf->width + thick) / 2; |
|
|
|
vline_middle_up(LIGHT); |
|
|
|
hline(0, vmid, hmid, thick); |
|
hline(0, vmid, hmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_double_and_left_single(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height + thick) / 2; |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
hline_middle_left(LIGHT); |
|
|
|
vline(0, hmid, vmid, thick); |
|
vline(0, hmid, vmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_double_up_and_left(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
vline(0, hmid + 0 * thick + thick, vmid, thick); |
|
vline(0, hmid + 2 * thick + thick, vmid + 2 * thick, thick); |
|
|
|
hline(0, vmid, hmid, thick); |
|
hline(0, vmid + 2 * thick, hmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_vertical_single_and_right_double(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
int vmid = (buf->width - thick) / 2; |
|
|
|
vline_middle(LIGHT); |
|
|
|
hline(vmid, buf->width, hmid, thick); |
|
hline(vmid, buf->width, hmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_vertical_double_and_right_single(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
hline(vmid + 2 * thick, buf->width, (buf->height - thick) / 2, thick); |
|
|
|
vline(0, buf->height, vmid, thick); |
|
vline(0, buf->height, vmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_double_vertical_and_right(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
vline(0, buf->height, vmid, thick); |
|
vline(0, hmid, vmid + 2 * thick, thick); |
|
vline(hmid + 2 * thick, buf->height, vmid + 2 * thick, thick); |
|
|
|
hline(vmid + 2 * thick, buf->width, hmid, thick); |
|
hline(vmid + 2 * thick, buf->width, hmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_vertical_single_and_left_double(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
int vmid = (buf->width + thick) / 2; |
|
|
|
vline_middle(LIGHT); |
|
|
|
hline(0, vmid, hmid, thick); |
|
hline(0, vmid, hmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_vertical_double_and_left_single(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
hline(0, vmid, (buf->height - thick) / 2, thick); |
|
|
|
vline(0, buf->height, vmid, thick); |
|
vline(0, buf->height, vmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_double_vertical_and_left(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
vline(0, buf->height, vmid + 2 * thick, thick); |
|
vline(0, hmid, vmid, thick); |
|
vline(hmid + 2 * thick, buf->height, vmid, thick); |
|
|
|
hline(0, vmid + thick, hmid, thick); |
|
hline(0, vmid, hmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_single_and_horizontal_double(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
|
|
vline(hmid + 2 * thick, buf->height, (buf->width - thick) / 2, thick); |
|
|
|
hline(0, buf->width, hmid, thick); |
|
hline(0, buf->width, hmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_down_double_and_horizontal_single(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick) / 2; |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
hline_middle(LIGHT); |
|
|
|
vline(hmid, buf->height, vmid, thick); |
|
vline(hmid, buf->height, vmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_double_down_and_horizontal(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
hline(0, buf->width, hmid, thick); |
|
hline(0, vmid, hmid + 2 * thick, thick); |
|
hline(vmid + 2 * thick, buf->width, hmid + 2 * thick, thick); |
|
|
|
vline(hmid + 2 * thick, buf->height, vmid, thick); |
|
vline(hmid + 2 * thick, buf->height, vmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_single_and_horizontal_double(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
int vmid = (buf->width - thick) / 2; |
|
|
|
vline(0, hmid, vmid, thick); |
|
|
|
hline(0, buf->width, hmid, thick); |
|
hline(0, buf->width, hmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_up_double_and_horizontal_single(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick) / 2; |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
hline_middle(LIGHT); |
|
|
|
vline(0, hmid, vmid, thick); |
|
vline(0, hmid, vmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_double_up_and_horizontal(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
vline(0, hmid, vmid, thick); |
|
vline(0, hmid, vmid + 2 * thick, thick); |
|
|
|
hline(0, vmid + thick, hmid, thick); |
|
hline(vmid + 2 * thick, buf->width, hmid, thick); |
|
hline(0, buf->width, hmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_vertical_single_and_horizontal_double(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
|
|
vline_middle(LIGHT); |
|
|
|
hline(0, buf->width, hmid, thick); |
|
hline(0, buf->width, hmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_vertical_double_and_horizontal_single(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
hline_middle(LIGHT); |
|
|
|
vline(0, buf->height, vmid, thick); |
|
vline(0, buf->height, vmid + 2 * thick, thick); |
|
} |
|
|
|
static void |
|
draw_box_drawings_double_vertical_and_horizontal(struct buf *buf) |
|
{ |
|
int thick = thickness(LIGHT); |
|
int hmid = (buf->height - thick * 3) / 2; |
|
int vmid = (buf->width - thick * 3) / 2; |
|
|
|
hline(0, vmid, hmid, thick); |
|
hline(vmid + 2 * thick, buf->width, hmid, thick); |
|
hline(0, vmid, hmid + 2 * thick, thick); |
|
hline(vmid + 2 * thick, buf->width, hmid + 2 * thick, thick); |
|
|
|
vline(0, hmid + thick, vmid, thick); |
|
vline(0, hmid, vmid + 2 * thick, thick); |
|
vline(hmid + 2 * thick, buf->height, vmid, thick); |
|
vline(hmid + 2 * thick, buf->height, vmid + 2 * thick, thick); |
|
} |
|
|
|
static inline void |
|
set_a1_bit(uint8_t *data, size_t ofs, size_t bit_no) |
|
{ |
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
|
data[ofs] |= 1 << bit_no; |
|
#else |
|
data[ofs] |= 1 << (7 - bit_no); |
|
#endif |
|
} |
|
|
|
static void NOINLINE |
|
draw_box_drawings_light_arc(struct buf *buf, wchar_t wc) |
|
{ |
|
const pixman_format_code_t fmt = buf->format; |
|
const int supersample = fmt == PIXMAN_a8 ? 4 : 1; |
|
const int height = buf->height * supersample; |
|
const int width = buf->width * supersample; |
|
const int stride = fmt == PIXMAN_a8 |
|
? stride_for_format_and_width(PIXMAN_a8, width) : buf->stride; |
|
uint8_t *data = supersample > 1 ? xcalloc(height * stride, 1) : buf->data; |
|
|
|
const int thick = thickness(LIGHT) * supersample; |
|
|
|
const bool thick_is_odd = (thick / supersample) % 2; |
|
const bool height_is_odd = buf->height % 2; |
|
const bool width_is_odd = buf->width % 2; |
|
|
|
const double a = (width - thick) / 2; |
|
const double b = (height - thick) / 2; |
|
|
|
const double a2 = a * a; |
|
const double b2 = b * b; |
|
|
|
const int num_samples = height * 16; |
|
|
|
for (int i = 0; i < num_samples; i++) { |
|
double y = i / 16.; |
|
double x = sqrt(a2 * (1. - y * y / b2)); |
|
|
|
const int row = round(y); |
|
const int col = round(x); |
|
|
|
if (col < 0) |
|
continue; |
|
|
|
int row_start = 0; |
|
int row_end = 0; |
|
int col_start = 0; |
|
int col_end = 0; |
|
|
|
/* |
|
* At this point, row/col is only correct for ╯. For the other |
|
* arcs, we need to mirror the arc around either the x-, y- or |
|
* both axis. |
|
* |
|
* When doing so, we need to adjust for asymmetrical cell |
|
* dimensions. |
|
* |
|
* The amazing box drawing art below represents the lower part |
|
* of a cell, with the beginning of a vertical line in the |
|
* middle. Each column represents one pixel. |
|
* |
|
* |
|
* Even cell Odd cell |
|
* |
|
* │ │ │ │ |
|
* Even line │ ┆ ┆ │ │ ┆ ┆ │ |
|
* │ ┆ ┆ │ │ ┆ ┆ │ |
|
* └─┴─┴─┴─┘ └─┴─┴─┴─┴─┘ |
|
* |
|
* |
|
* │ │ │ │ |
|
* Odd line │ ┆ ┆ │ │ ┆ ┆ │ |
|
* │ ┆ ┆ │ │ ┆ ┆ │ |
|
* └─┴─┴─┴─┘ └─┴─┴─┴─┴─┘ |
|
* |
|
* As can be seen(?), the resulting line is asymmetrical when |
|
* *either* the cell is odd sized, *or* the line is odd |
|
* sized. But not when both are. |
|
* |
|
* Hence the ‘thick % 2 ^ width % 2’ in the expressions below. |
|
*/ |
|
switch (wc) { |
|
case L'╭': |
|
row_end = height - row - (thick_is_odd ^ height_is_odd); |
|
row_start = row_end - thick; |
|
col_end = width - col - (thick_is_odd ^ width_is_odd); |
|
col_start = col_end - thick; |
|
break; |
|
|
|
case L'╮': |
|
row_end = height - row - (thick_is_odd ^ height_is_odd); |
|
row_start = row_end - thick; |
|
col_start = col - ((thick_is_odd ^ width_is_odd) ? supersample / 2 : 0); |
|
col_end = col_start + thick; |
|
break; |
|
|
|
case L'╰': |
|
row_start = row - ((thick_is_odd ^ height_is_odd) ? supersample / 2 : 0); |
|
row_end = row_start + thick; |
|
col_end = width - col - (thick_is_odd ^ width_is_odd); |
|
col_start = col_end - thick; |
|
break; |
|
|
|
case L'╯': |
|
row_start = row - ((thick_is_odd ^ height_is_odd) ? supersample / 2 : 0); |
|
row_end = row_start + thick; |
|
col_start = col - ((thick_is_odd ^ width_is_odd) ? supersample / 2 : 0); |
|
col_end = col_start + thick; |
|
break; |
|
} |
|
|
|
xassert(row_end > row_start); |
|
xassert(col_end > col_start); |
|
|
|
for (int r = max(row_start, 0); r < max(min(row_end, height), 0); r++) { |
|
for (int c = max(col_start, 0); c < max(min(col_end, width), 0); c++) { |
|
if (fmt == PIXMAN_a1) { |
|
size_t idx = c / 8; |
|
size_t bit_no = c % 8; |
|
set_a1_bit(data, r * stride + idx, bit_no); |
|
} else |
|
data[r * stride + c] = 0xff; |
|
} |
|
} |
|
} |
|
|
|
/* |
|
* Since a cell may not be completely symmetrical around its y- |
|
* and x-axis, the mirroring done above may result in the last |
|
* col/row of the arc not being filled in. This code ensures they |
|
* are. |
|
*/ |
|
|
|
if (wc == L'╭' || wc == L'╰') { |
|
for (int y = 0; y < thick; y++) { |
|
int row = (height - thick) / 2 + y - ((thick_is_odd ^ height_is_odd) ? supersample / 2 : 0); |
|
for (int col = width - supersample; col < width; col++) { |
|
if (row >= 0 && row < height && col >= 0) { |
|
if (fmt == PIXMAN_a1) { |
|
size_t ofs = col / 8; |
|
size_t bit_no = col % 8; |
|
set_a1_bit(data, row * stride + ofs, bit_no); |
|
} else |
|
data[row * stride + col] = 0xff; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (wc == L'╭' || wc == L'╮') { |
|
for (int x = 0; x < thick; x++) { |
|
int col = (width - thick) / 2 + x - ((thick_is_odd ^ width_is_odd) ? supersample / 2 : 0); |
|
for (int row = height - supersample; row < height; row++) { |
|
if (row >= 0 && col >= 0 && col < width) { |
|
if (fmt == PIXMAN_a1) { |
|
size_t ofs = col / 8; |
|
size_t bit_no = col % 8; |
|
set_a1_bit(data, row * stride + ofs, bit_no); |
|
} else |
|
data[row * stride + col] = 0xff; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (fmt == PIXMAN_a8) { |
|
xassert(data != buf->data); |
|
|
|
/* Downsample */ |
|
for (size_t r = 0; r < buf->height; r++) { |
|
for (size_t c = 0; c < buf->width; c++) { |
|
uint32_t total = 0; |
|
for (size_t i = 0; i < supersample; i++) { |
|
for (size_t j = 0; j < supersample; j++) |
|
total += data[(r * supersample + i) * stride + c * supersample + j]; |
|
} |
|
uint8_t average = min(total / (supersample * supersample), 0xff); |
|
buf->data[r * buf->stride + c] = average; |
|
} |
|
} |
|
|
|
free(data); |
|
} |
|
} |
|
|
|
static void NOINLINE |
|
draw_box_drawings_light_diagonal_upper_right_to_lower_left(struct buf *buf) |
|
{ |
|
pixman_trapezoid_t trap = { |
|
.top = pixman_int_to_fixed(0), |
|
.bottom = pixman_int_to_fixed(buf->height), |
|
.left = { |
|
.p1 = { |
|
.x = pixman_double_to_fixed(buf->width - thickness(LIGHT) / 2.), |
|
.y = pixman_int_to_fixed(0), |
|
}, |
|
.p2 = { |
|
.x = pixman_double_to_fixed(0 - thickness(LIGHT) / 2.), |
|
.y = pixman_int_to_fixed(buf->height), |
|
}, |
|
}, |
|
.right = { |
|
.p1 = { |
|
.x = pixman_double_to_fixed(buf->width + thickness(LIGHT) / 2.), |
|
.y = pixman_int_to_fixed(0), |
|
}, |
|
.p2 = { |
|
.x = pixman_double_to_fixed(0 + thickness(LIGHT) / 2.), |
|
.y = pixman_int_to_fixed(buf->height), |
|
}, |
|
}, |
|
}; |
|
|
|
pixman_rasterize_trapezoid(buf->pix, &trap, 0, 0); |
|
} |
|
|
|
static void NOINLINE |
|
draw_box_drawings_light_diagonal_upper_left_to_lower_right(struct buf *buf) |
|
{ |
|
pixman_trapezoid_t trap = { |
|
.top = pixman_int_to_fixed(0), |
|
.bottom = pixman_int_to_fixed(buf->height), |
|
.left = { |
|
.p1 = { |
|
.x = pixman_double_to_fixed(0 - thickness(LIGHT) / 2.), |
|
.y = pixman_int_to_fixed(0), |
|
}, |
|
.p2 = { |
|
.x = pixman_double_to_fixed(buf->width - thickness(LIGHT) / 2.), |
|
.y = pixman_int_to_fixed(buf->height), |
|
}, |
|
}, |
|
.right = { |
|
.p1 = { |
|
.x = pixman_double_to_fixed(0 + thickness(LIGHT) / 2.), |
|
.y = pixman_int_to_fixed(0), |
|
}, |
|
.p2 = { |
|
.x = pixman_double_to_fixed(buf->width + thickness(LIGHT) / 2.), |
|
.y = pixman_int_to_fixed(buf->height), |
|
}, |
|
}, |
|
}; |
|
|
|
pixman_rasterize_trapezoid(buf->pix, &trap, 0, 0); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_diagonal_cross(struct buf *buf) |
|
{ |
|
draw_box_drawings_light_diagonal_upper_right_to_lower_left(buf); |
|
draw_box_drawings_light_diagonal_upper_left_to_lower_right(buf); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_left(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_up(struct buf *buf) |
|
{ |
|
vline_middle_up(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_right(struct buf *buf) |
|
{ |
|
hline_middle_right(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_down(struct buf *buf) |
|
{ |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_left(struct buf *buf) |
|
{ |
|
hline_middle_left(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_up(struct buf *buf) |
|
{ |
|
vline_middle_up(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_right(struct buf *buf) |
|
{ |
|
hline_middle_right(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_down(struct buf *buf) |
|
{ |
|
vline_middle_down(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_left_and_heavy_right(struct buf *buf) |
|
{ |
|
hline_middle_left(LIGHT); |
|
hline_middle_right(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_light_up_and_heavy_down(struct buf *buf) |
|
{ |
|
vline_middle_up(LIGHT); |
|
vline_middle_down(HEAVY); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_left_and_light_right(struct buf *buf) |
|
{ |
|
hline_middle_left(HEAVY); |
|
hline_middle_right(LIGHT); |
|
} |
|
|
|
static void |
|
draw_box_drawings_heavy_up_and_light_down(struct buf *buf) |
|
{ |
|
vline_middle_up(HEAVY); |
|
vline_middle_down(LIGHT); |
|
} |
|
|
|
static void |
|
draw_upper_half_block(struct buf *buf) |
|
{ |
|
rect(0, 0, buf->width, round(buf->height / 2.)); |
|
} |
|
|
|
static void |
|
draw_lower_one_eighth_block(struct buf *buf) |
|
{ |
|
rect(0, buf->height - round(buf->height / 8.), buf->width, buf->height); |
|
} |
|
|
|
static void |
|
draw_lower_one_quarter_block(struct buf *buf) |
|
{ |
|
rect(0, buf->height - round(buf->height / 4.), buf->width, buf->height); |
|
} |
|
|
|
static void |
|
draw_lower_three_eighths_block(struct buf *buf) |
|
{ |
|
rect(0, buf->height - round(3. * buf->height / 8.), buf->width, buf->height); |
|
} |
|
|
|
static void |
|
draw_lower_half_block(struct buf *buf) |
|
{ |
|
rect(0, buf->height - round(buf->height / 2.), buf->width, buf->height); |
|
} |
|
|
|
static void |
|
draw_lower_five_eighths_block(struct buf *buf) |
|
{ |
|
rect(0, buf->height - round(5. * buf->height / 8.), buf->width, buf->height); |
|
} |
|
|
|
static void |
|
draw_lower_three_quarters_block(struct buf *buf) |
|
{ |
|
rect(0, buf->height - round(3. * buf->height / 4.), buf->width, buf->height); |
|
} |
|
|
|
static void |
|
draw_lower_seven_eighths_block(struct buf *buf) |
|
{ |
|
rect(0, buf->height - round(7. * buf->height / 8.), buf->width, buf->height); |
|
} |
|
|
|
static void |
|
draw_upper_one_quarter_block(struct buf *buf) |
|
{ |
|
rect(0, 0, buf->width, round(buf->height / 4.)); |
|
} |
|
|
|
static void |
|
draw_upper_three_eighths_block(struct buf *buf) |
|
{ |
|
rect(0, 0, buf->width, round(3. * buf->height / 8.)); |
|
} |
|
|
|
static void |
|
draw_upper_five_eighths_block(struct buf *buf) |
|
{ |
|
rect(0, 0, buf->width, round(5. * buf->height / 8.)); |
|
} |
|
|
|
static void |
|
draw_upper_three_quarters_block(struct buf *buf) |
|
{ |
|
rect(0, 0, buf->width, round(3. * buf->height / 4.)); |
|
} |
|
|
|
static void |
|
draw_upper_seven_eighths_block(struct buf *buf) |
|
{ |
|
rect(0, 0, buf->width, round(7. * buf->height / 8.)); |
|
} |
|
|
|
static void |
|
draw_full_block(struct buf *buf) |
|
{ |
|
rect(0, 0, buf->width, buf->height); |
|
} |
|
|
|
static void |
|
draw_left_seven_eighths_block(struct buf *buf) |
|
{ |
|
rect(0, 0, round(7. * buf->width / 8.), buf->height); |
|
} |
|
|
|
static void |
|
draw_left_three_quarters_block(struct buf *buf) |
|
{ |
|
rect(0, 0, round(3. * buf->width / 4.), buf->height); |
|
} |
|
|
|
static void |
|
draw_left_five_eighths_block(struct buf *buf) |
|
{ |
|
rect(0, 0, round(5. * buf->width / 8.), buf->height); |
|
} |
|
|
|
static void |
|
draw_left_half_block(struct buf *buf) |
|
{ |
|
rect(0, 0, round(buf->width / 2.), buf->height); |
|
} |
|
|
|
static void |
|
draw_left_three_eighths_block(struct buf *buf) |
|
{ |
|
rect(0, 0, round(3. * buf->width / 8.), buf->height); |
|
} |
|
|
|
static void |
|
draw_left_one_quarter_block(struct buf *buf) |
|
{ |
|
rect(0, 0, round(buf->width / 4.), buf->height); |
|
} |
|
|
|
static void |
|
draw_vertical_one_eighth_block_n(struct buf *buf, int n) |
|
{ |
|
double x = round((double)n * buf->width / 8.); |
|
double w = round(buf->width / 8.); |
|
rect(x, 0, x + w, buf->height); |
|
} |
|
|
|
static void |
|
draw_left_one_eighth_block(struct buf *buf) |
|
{ |
|
draw_vertical_one_eighth_block_n(buf, 0); |
|
} |
|
|
|
static void |
|
draw_vertical_one_eighth_block_2(struct buf *buf) |
|
{ |
|
draw_vertical_one_eighth_block_n(buf, 1); |
|
} |
|
|
|
static void |
|
draw_vertical_one_eighth_block_3(struct buf *buf) |
|
{ |
|
draw_vertical_one_eighth_block_n(buf, 2); |
|
} |
|
|
|
static void |
|
draw_vertical_one_eighth_block_4(struct buf *buf) |
|
{ |
|
draw_vertical_one_eighth_block_n(buf, 3); |
|
} |
|
|
|
static void |
|
draw_vertical_one_eighth_block_5(struct buf *buf) |
|
{ |
|
draw_vertical_one_eighth_block_n(buf, 4); |
|
} |
|
|
|
static void |
|
draw_vertical_one_eighth_block_6(struct buf *buf) |
|
{ |
|
draw_vertical_one_eighth_block_n(buf, 5); |
|
} |
|
|
|
static void |
|
draw_vertical_one_eighth_block_7(struct buf *buf) |
|
{ |
|
draw_vertical_one_eighth_block_n(buf, 6); |
|
} |
|
|
|
static void |
|
draw_right_half_block(struct buf *buf) |
|
{ |
|
rect(round(buf->width / 2.), 0, buf->width, buf->height); |
|
} |
|
|
|
static void NOINLINE |
|
draw_pixman_shade(struct buf *buf, uint16_t v) |
|
{ |
|
pixman_color_t shade = {.red = 0, .green = 0, .blue = 0, .alpha = v}; |
|
pixman_image_fill_rectangles( |
|
PIXMAN_OP_SRC, buf->pix, &shade, 1, |
|
(pixman_rectangle16_t []){{0, 0, buf->width, buf->height}}); |
|
} |
|
|
|
static void |
|
draw_light_shade(struct buf *buf) |
|
{ |
|
pixman_format_code_t fmt = buf->format; |
|
|
|
if (buf->solid_shades && fmt == PIXMAN_a1) |
|
change_buffer_format(buf, PIXMAN_a8); |
|
else if (!buf->solid_shades && fmt == PIXMAN_a8) |
|
change_buffer_format(buf, PIXMAN_a1); |
|
|
|
if (buf->solid_shades) |
|
draw_pixman_shade(buf, 0x4000); |
|
else { |
|
for (size_t row = 0; row < buf->height; row += 2) { |
|
for (size_t col = 0; col < buf->width; col += 2) { |
|
size_t idx = col / 8; |
|
size_t bit_no = col % 8; |
|
set_a1_bit(buf->data, row * buf->stride + idx, bit_no); |
|
} |
|
} |
|
} |
|
} |
|
|
|
static void |
|
draw_medium_shade(struct buf *buf) |
|
{ |
|
pixman_format_code_t fmt = buf->format; |
|
|
|
if (buf->solid_shades && fmt == PIXMAN_a1) |
|
change_buffer_format(buf, PIXMAN_a8); |
|
else if (!buf->solid_shades && fmt == PIXMAN_a8) |
|
change_buffer_format(buf, PIXMAN_a1); |
|
|
|
if (buf->solid_shades) |
|
draw_pixman_shade(buf, 0x8000); |
|
else { |
|
for (size_t row = 0; row < buf->height; row++) { |
|
for (size_t col = row % 2; col < buf->width; col += 2) { |
|
size_t idx = col / 8; |
|
size_t bit_no = col % 8; |
|
set_a1_bit(buf->data, row * buf->stride + idx, bit_no); |
|
} |
|
} |
|
} |
|
} |
|
|
|
static void |
|
draw_dark_shade(struct buf *buf) |
|
{ |
|
pixman_format_code_t fmt = buf->format; |
|
|
|
if (buf->solid_shades && fmt == PIXMAN_a1) |
|
change_buffer_format(buf, PIXMAN_a8); |
|
else if (!buf->solid_shades && fmt == PIXMAN_a8) |
|
change_buffer_format(buf, PIXMAN_a1); |
|
|
|
if (buf->solid_shades) |
|
draw_pixman_shade(buf, 0xc000); |
|
else { |
|
for (size_t row = 0; row < buf->height; row++) { |
|
for (size_t col = 0; col < buf->width; col += 1 + row % 2) { |
|
size_t idx = col / 8; |
|
size_t bit_no = col % 8; |
|
set_a1_bit(buf->data, row * buf->stride + idx, bit_no); |
|
} |
|
} |
|
} |
|
} |
|
|
|
static void NOINLINE |
|
draw_horizontal_one_eighth_block_n(struct buf *buf, int n) |
|
{ |
|
double y = round((double)n * buf->height / 8.); |
|
double h = round(buf->height / 8.); |
|
rect(0, y, buf->width, y + h); |
|
} |
|
|
|
static void |
|
draw_upper_one_eighth_block(struct buf *buf) |
|
{ |
|
draw_horizontal_one_eighth_block_n(buf, 0); |
|
} |
|
|
|
static void |
|
draw_horizontal_one_eighth_block_2(struct buf *buf) |
|
{ |
|
draw_horizontal_one_eighth_block_n(buf, 1); |
|
} |
|
|
|
static void |
|
draw_horizontal_one_eighth_block_3(struct buf *buf) |
|
{ |
|
draw_horizontal_one_eighth_block_n(buf, 2); |
|
} |
|
|
|
static void |
|
draw_horizontal_one_eighth_block_4(struct buf *buf) |
|
{ |
|
draw_horizontal_one_eighth_block_n(buf, 3); |
|
} |
|
|
|
static void |
|
draw_horizontal_one_eighth_block_5(struct buf *buf) |
|
{ |
|
draw_horizontal_one_eighth_block_n(buf, 4); |
|
} |
|
|
|
static void |
|
draw_horizontal_one_eighth_block_6(struct buf *buf) |
|
{ |
|
draw_horizontal_one_eighth_block_n(buf, 5); |
|
} |
|
|
|
static void |
|
draw_horizontal_one_eighth_block_7(struct buf *buf) |
|
{ |
|
draw_horizontal_one_eighth_block_n(buf, 6); |
|
} |
|
|
|
static void |
|
draw_right_one_eighth_block(struct buf *buf) |
|
{ |
|
rect(buf->width - round(buf->width / 8.), 0, buf->width, buf->height); |
|
} |
|
|
|
static void |
|
quad_upper_left(struct buf *buf) |
|
{ |
|
rect(0, 0, ceil(buf->width / 2.), ceil(buf->height / 2.)); |
|
} |
|
|
|
static void |
|
quad_upper_right(struct buf *buf) |
|
{ |
|
rect(floor(buf->width / 2.), 0, buf->width, ceil(buf->height / 2.)); |
|
} |
|
|
|
static void |
|
quad_lower_left(struct buf *buf) |
|
{ |
|
rect(0, floor(buf->height / 2.), ceil(buf->width / 2.), buf->height); |
|
} |
|
|
|
static void |
|
quad_lower_right(struct buf *buf) |
|
{ |
|
rect(floor(buf->width / 2.), floor(buf->height / 2.), buf->width, buf->height); |
|
} |
|
|
|
static void NOINLINE |
|
draw_quadrant(struct buf *buf, wchar_t wc) |
|
{ |
|
enum { |
|
UPPER_LEFT = 1 << 0, |
|
UPPER_RIGHT = 1 << 1, |
|
LOWER_LEFT = 1 << 2, |
|
LOWER_RIGHT = 1 << 3, |
|
}; |
|
|
|
static const uint8_t matrix[10] = { |
|
LOWER_LEFT, |
|
LOWER_RIGHT, |
|
UPPER_LEFT, |
|
UPPER_LEFT | LOWER_LEFT | LOWER_RIGHT, |
|
UPPER_LEFT | LOWER_RIGHT, |
|
UPPER_LEFT | UPPER_RIGHT | LOWER_LEFT, |
|
UPPER_LEFT | UPPER_RIGHT | LOWER_RIGHT, |
|
UPPER_RIGHT, |
|
UPPER_RIGHT | LOWER_LEFT, |
|
UPPER_RIGHT | LOWER_LEFT | LOWER_RIGHT, |
|
}; |
|
|
|
xassert(wc >= 0x2596 && wc <= 0x259f); |
|
const size_t idx = wc - 0x2596; |
|
|
|
xassert(idx < ALEN(matrix)); |
|
uint8_t encoded = matrix[idx]; |
|
|
|
if (encoded & UPPER_LEFT) |
|
quad_upper_left(buf); |
|
|
|
if (encoded & UPPER_RIGHT) |
|
quad_upper_right(buf); |
|
|
|
if (encoded & LOWER_LEFT) |
|
quad_lower_left(buf); |
|
|
|
if (encoded & LOWER_RIGHT) |
|
quad_lower_right(buf); |
|
} |
|
|
|
static void NOINLINE |
|
draw_braille(struct buf *buf, wchar_t wc) |
|
{ |
|
int w = min(buf->width / 4, buf->height / 8); |
|
int x_spacing = buf->width / 4; |
|
int y_spacing = buf->height / 8; |
|
int x_margin = x_spacing / 2; |
|
int y_margin = y_spacing / 2; |
|
|
|
int x_px_left = buf->width - 2 * x_margin - x_spacing - 2 * w; |
|
int y_px_left = buf->height - 2 * y_margin - 3 * y_spacing - 4 * w; |
|
|
|
LOG_DBG( |
|
"braille: before adjusting: " |
|
"cell: %dx%d, margin=%dx%d, spacing=%dx%d, width=%d, left=%dx%d", |
|
buf->width, buf->height, x_margin, y_margin, x_spacing, y_spacing, |
|
w, x_px_left, y_px_left); |
|
|
|
/* First, try hard to ensure the DOT width is non-zero */ |
|
if (x_px_left >= 2 && y_px_left >= 4 && w == 0) { |
|
w++; |
|
x_px_left -= 2; |
|
y_px_left -= 4; |
|
} |
|
|
|
/* Second, prefer a non-zero margin */ |
|
if (x_px_left >= 2 && x_margin == 0) { x_margin = 1; x_px_left -= 2; } |
|
if (y_px_left >= 2 && y_margin == 0) { y_margin = 1; y_px_left -= 2; } |
|
|
|
/* Third, increase spacing */ |
|
if (x_px_left >= 1) { x_spacing++; x_px_left--; } |
|
if (y_px_left >= 3) { y_spacing++; y_px_left -= 3; } |
|
|
|
/* Fourth, margins (“spacing”, but on the sides) */ |
|
if (x_px_left >= 2) { x_margin++; x_px_left -= 2; } |
|
if (y_px_left >= 2) { y_margin++; y_px_left -= 2; } |
|
|
|
/* Last - increase dot width */ |
|
if (x_px_left >= 2 && y_px_left >= 4) { |
|
w++; |
|
x_px_left -= 2; |
|
y_px_left -= 4; |
|
} |
|
|
|
LOG_DBG( |
|
"braille: after adjusting: " |
|
"cell: %dx%d, margin=%dx%d, spacing=%dx%d, width=%d, left=%dx%d", |
|
buf->width, buf->height, x_margin, y_margin, x_spacing, y_spacing, |
|
w, x_px_left, y_px_left); |
|
|
|
xassert(x_px_left <= 1 || y_px_left <= 1); |
|
xassert(2 * x_margin + 2 * w + x_spacing <= buf->width); |
|
xassert(2 * y_margin + 4 * w + 3 * y_spacing <= buf->height); |
|
|
|
int x[2], y[4]; |
|
x[0] = x_margin; |
|
x[1] = x_margin + w + x_spacing; |
|
y[0] = y_margin; |
|
y[1] = y[0] + w + y_spacing; |
|
y[2] = y[1] + w + y_spacing; |
|
y[3] = y[2] + w + y_spacing; |
|
|
|
assert(wc >= 0x2800); |
|
assert(wc <= 0x28ff); |
|
uint8_t sym = wc - 0x2800; |
|
|
|
/* Left side */ |
|
if (sym & 1) |
|
rect(x[0], y[0], x[0] + w, y[0] + w); |
|
if (sym & 2) |
|
rect(x[0], y[1], x[0] + w, y[1] + w); |
|
if (sym & 4) |
|
rect(x[0], y[2], x[0] + w, y[2] + w); |
|
|
|
/* Right side */ |
|
if (sym & 8) |
|
rect(x[1], y[0], x[1] + w, y[0] + w); |
|
if (sym & 16) |
|
rect(x[1], y[1], x[1] + w, y[1] + w); |
|
if (sym & 32) |
|
rect(x[1], y[2], x[1] + w, y[2] + w); |
|
|
|
/* 8-dot patterns */ |
|
if (sym & 64) |
|
rect(x[0], y[3], x[0] + w, y[3] + w); |
|
if (sym & 128) |
|
rect(x[1], y[3], x[1] + w, y[3] + w); |
|
} |
|
|
|
static void |
|
sextant_upper_left(struct buf *buf) |
|
{ |
|
rect(0, 0, buf->x_halfs[0], buf->y_thirds[0]); |
|
} |
|
|
|
static void |
|
sextant_middle_left(struct buf *buf) |
|
{ |
|
rect(0, buf->y_thirds[0], buf->x_halfs[0], buf->y_thirds[1]); |
|
} |
|
|
|
static void |
|
sextant_lower_left(struct buf *buf) |
|
{ |
|
rect(0, buf->y_thirds[1], buf->x_halfs[0], buf->height); |
|
} |
|
|
|
static void |
|
sextant_upper_right(struct buf *buf) |
|
{ |
|
rect(buf->x_halfs[1], 0, buf->width, buf->y_thirds[0]); |
|
} |
|
|
|
static void |
|
sextant_middle_right(struct buf *buf) |
|
{ |
|
rect(buf->x_halfs[1], buf->y_thirds[0], buf->width, buf->y_thirds[1]); |
|
} |
|
|
|
static void |
|
sextant_lower_right(struct buf *buf) |
|
{ |
|
rect(buf->x_halfs[1], buf->y_thirds[1], buf->width, buf->height); |
|
} |
|
|
|
static void NOINLINE |
|
draw_sextant(struct buf *buf, wchar_t wc) |
|
{ |
|
/* |
|
* Each byte encodes one sextant: |
|
* |
|
* Bit sextant |
|
* 0 upper left |
|
* 1 middle left |
|
* 2 lower left |
|
* 3 upper right |
|
* 4 middle right |
|
* 5 lower right |
|
*/ |
|
enum { |
|
UPPER_LEFT = 1 << 0, |
|
MIDDLE_LEFT = 1 << 1, |
|
LOWER_LEFT = 1 << 2, |
|
UPPER_RIGHT = 1 << 3, |
|
MIDDLE_RIGHT = 1 << 4, |
|
LOWER_RIGHT = 1 << 5, |
|
}; |
|
|
|
static const uint8_t matrix[60] = { |
|
/* U+1fb00 - U+1fb0f */ |
|
UPPER_LEFT, |
|
UPPER_RIGHT, |
|
UPPER_LEFT | UPPER_RIGHT, |
|
MIDDLE_LEFT, |
|
UPPER_LEFT | MIDDLE_LEFT, |
|
UPPER_RIGHT | MIDDLE_LEFT, |
|
UPPER_LEFT | UPPER_RIGHT | MIDDLE_LEFT, |
|
MIDDLE_RIGHT, |
|
UPPER_LEFT | MIDDLE_RIGHT, |
|
UPPER_RIGHT | MIDDLE_RIGHT, |
|
UPPER_LEFT | UPPER_RIGHT | MIDDLE_RIGHT, |
|
MIDDLE_LEFT | MIDDLE_RIGHT, |
|
UPPER_LEFT | MIDDLE_LEFT | MIDDLE_RIGHT, |
|
UPPER_RIGHT | MIDDLE_LEFT | MIDDLE_RIGHT, |
|
UPPER_LEFT | UPPER_RIGHT | MIDDLE_LEFT | MIDDLE_RIGHT, |
|
LOWER_LEFT, |
|
|
|
/* U+1fb10 - U+1fb1f */ |
|
UPPER_LEFT | LOWER_LEFT, |
|
UPPER_RIGHT | LOWER_LEFT, |
|
UPPER_LEFT | UPPER_RIGHT | LOWER_LEFT, |
|
MIDDLE_LEFT | LOWER_LEFT, |
|
UPPER_RIGHT | MIDDLE_LEFT | LOWER_LEFT, |
|
UPPER_LEFT | UPPER_RIGHT | MIDDLE_LEFT | LOWER_LEFT, |
|
MIDDLE_RIGHT | LOWER_LEFT, |
|
UPPER_LEFT | MIDDLE_RIGHT | LOWER_LEFT, |
|
UPPER_RIGHT | MIDDLE_RIGHT | LOWER_LEFT, |
|
UPPER_LEFT | UPPER_RIGHT | MIDDLE_RIGHT | LOWER_LEFT, |
|
MIDDLE_LEFT | MIDDLE_RIGHT | LOWER_LEFT, |
|
UPPER_LEFT | MIDDLE_LEFT | MIDDLE_RIGHT | LOWER_LEFT, |
|
UPPER_RIGHT | MIDDLE_LEFT | MIDDLE_RIGHT | LOWER_LEFT, |
|
UPPER_LEFT | UPPER_RIGHT | MIDDLE_LEFT | MIDDLE_RIGHT | LOWER_LEFT, |
|
LOWER_RIGHT, |
|
UPPER_LEFT | LOWER_RIGHT, |
|
|
|
/* U+1fb20 - U+1fb2f */ |
|
UPPER_RIGHT | LOWER_RIGHT, |
|
UPPER_LEFT | UPPER_RIGHT | LOWER_RIGHT, |
|
MIDDLE_LEFT | LOWER_RIGHT, |
|
UPPER_LEFT | MIDDLE_LEFT | LOWER_RIGHT, |
|
UPPER_RIGHT | MIDDLE_LEFT | LOWER_RIGHT, |
|
UPPER_LEFT | UPPER_RIGHT | MIDDLE_LEFT | LOWER_RIGHT, |
|
MIDDLE_RIGHT | LOWER_RIGHT, |
|
UPPER_LEFT | MIDDLE_RIGHT | LOWER_RIGHT, |
|
UPPER_LEFT | UPPER_RIGHT | MIDDLE_RIGHT | LOWER_RIGHT, |
|
MIDDLE_LEFT | MIDDLE_RIGHT | LOWER_RIGHT, |
|
UPPER_LEFT | MIDDLE_LEFT | MIDDLE_RIGHT | LOWER_RIGHT, |
|
UPPER_RIGHT | MIDDLE_LEFT | MIDDLE_RIGHT | LOWER_RIGHT, |
|
UPPER_LEFT | UPPER_RIGHT | MIDDLE_LEFT | MIDDLE_RIGHT | LOWER_RIGHT, |
|
LOWER_LEFT | LOWER_RIGHT, |
|
UPPER_LEFT | LOWER_LEFT | LOWER_RIGHT, |
|
UPPER_RIGHT | LOWER_LEFT | LOWER_RIGHT, |
|
|
|
/* U+1fb30 - U+1fb3b */ |
|
UPPER_LEFT | UPPER_RIGHT | LOWER_LEFT | LOWER_RIGHT, |
|
MIDDLE_LEFT | LOWER_LEFT | LOWER_RIGHT, |
|
UPPER_LEFT | MIDDLE_LEFT | LOWER_LEFT | LOWER_RIGHT, |
|
UPPER_RIGHT | MIDDLE_LEFT | LOWER_LEFT | LOWER_RIGHT, |
|
UPPER_LEFT | UPPER_RIGHT | MIDDLE_LEFT | LOWER_LEFT | LOWER_RIGHT, |
|
MIDDLE_RIGHT | LOWER_LEFT | LOWER_RIGHT, |
|
UPPER_LEFT | MIDDLE_RIGHT | LOWER_LEFT | LOWER_RIGHT, |
|
UPPER_RIGHT | MIDDLE_RIGHT | LOWER_LEFT | LOWER_RIGHT, |
|
UPPER_LEFT | UPPER_RIGHT | MIDDLE_RIGHT | LOWER_LEFT | LOWER_RIGHT, |
|
MIDDLE_LEFT | MIDDLE_RIGHT | LOWER_LEFT | LOWER_RIGHT, |
|
UPPER_LEFT | MIDDLE_LEFT | MIDDLE_RIGHT | LOWER_LEFT | LOWER_RIGHT, |
|
UPPER_RIGHT | MIDDLE_LEFT | MIDDLE_RIGHT | LOWER_LEFT | LOWER_RIGHT, |
|
}; |
|
|
|
xassert(wc >= 0x1fb00 && wc <= 0x1fb3b); |
|
const size_t idx = wc - 0x1fb00; |
|
|
|
xassert(idx < ALEN(matrix)); |
|
uint8_t encoded = matrix[idx]; |
|
|
|
if (encoded & UPPER_LEFT) |
|
sextant_upper_left(buf); |
|
|
|
if (encoded & MIDDLE_LEFT) |
|
sextant_middle_left(buf); |
|
|
|
if (encoded & LOWER_LEFT) |
|
sextant_lower_left(buf); |
|
|
|
if (encoded & UPPER_RIGHT) |
|
sextant_upper_right(buf); |
|
|
|
if (encoded & MIDDLE_RIGHT) |
|
sextant_middle_right(buf); |
|
|
|
if (encoded & LOWER_RIGHT) |
|
sextant_lower_right(buf); |
|
} |
|
|
|
static void NOINLINE |
|
draw_wedge_triangle(struct buf *buf, wchar_t wc) |
|
{ |
|
const int width = buf->width; |
|
const int height = buf->height; |
|
|
|
int halfs0 = buf->x_halfs[0]; |
|
int halfs1 = buf->x_halfs[1]; |
|
int thirds0 = buf->y_thirds[0]; |
|
int thirds1 = buf->y_thirds[1]; |
|
|
|
int p1_x, p1_y, p2_x, p2_y, p3_x, p3_y; |
|
|
|
switch (wc) { |
|
case 0x1fb3c: /* 🬼 */ |
|
p1_x = p2_x = 0; p3_x = halfs0; |
|
p1_y = thirds1; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb52: /* 🭒 */ |
|
p1_x = p2_x = 0; p3_x = halfs0; |
|
p1_y = thirds1; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb3d: /* 🬽 */ |
|
p1_x = p2_x = 0; p3_x = width; |
|
p1_y = thirds1; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb53: /* 🭓 */ |
|
p1_x = p2_x = 0; p3_x = width; |
|
p1_y = thirds1; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb3e: /* 🬾 */ |
|
p1_x = p2_x = 0; p3_x = halfs0; |
|
p1_y = thirds0; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb54: /* 🭔 */ |
|
p1_x = p2_x = 0; p3_x = halfs0; |
|
p1_y = thirds0; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb3f: /* 🬿 */ |
|
p1_x = p2_x = 0; p3_x = width; |
|
p1_y = thirds0; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb55: /* 🭕 */ |
|
p1_x = p2_x = 0; p3_x = width; |
|
p1_y = thirds0; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb40: /* 🭀 */ |
|
case 0x1fb56: /* 🭖 */ |
|
p1_x = p2_x = 0; p3_x = halfs0; |
|
p1_y = 0; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb47: /* 🭇 */ |
|
p1_x = p2_x = width; p3_x = halfs1; |
|
p1_y = thirds1; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb5d: /* 🭝 */ |
|
p1_x = p2_x = width; p3_x = halfs1; |
|
p1_y = thirds1; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb48: /* 🭈 */ |
|
p1_x = p2_x = width; p3_x = 0; |
|
p1_y = thirds1; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb5e: /* 🭞 */ |
|
p1_x = p2_x = width; p3_x = 0; |
|
p1_y = thirds1; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb49: /* 🭉 */ |
|
p1_x = p2_x = width; p3_x = halfs1; |
|
p1_y = thirds0; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb5f: /* 🭟 */ |
|
p1_x = p2_x = width; p3_x = halfs1; |
|
p1_y = thirds0; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb4a: /* 🭊 */ |
|
p1_x = p2_x = width; p3_x = 0; |
|
p1_y = thirds0; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb60: /* 🭠 */ |
|
p1_x = p2_x = width; p3_x = 0; |
|
p1_y = thirds0; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb4b: /* 🭋 */ |
|
case 0x1fb61: /* 🭡 */ |
|
p1_x = p2_x = width; p3_x = halfs1; |
|
p1_y = 0; p2_y = p3_y = height; |
|
break; |
|
|
|
case 0x1fb57: /* 🭗 */ |
|
p1_x = p2_x = 0; p3_x = halfs0; |
|
p1_y = p3_y = 0; p2_y = thirds0; |
|
break; |
|
|
|
case 0x1fb41: /* 🭁 */ |
|
p1_x = p2_x = 0; p3_x = halfs0; |
|
p1_y = p3_y = 0; p2_y = thirds0; |
|
break; |
|
|
|
case 0x1fb58: /* 🭘 */ |
|
p1_x = p2_x = 0; p3_x = width; |
|
p1_y = p3_y = 0; p2_y = thirds0; |
|
break; |
|
|
|
case 0x1fb42: /* 🭂 */ |
|
p1_x = p2_x = 0; p3_x = width; |
|
p1_y = p3_y = 0; p2_y = thirds0; |
|
break; |
|
|
|
case 0x1fb59: /* 🭙 */ |
|
p1_x = p2_x = 0; p3_x = halfs0; |
|
p1_y = p3_y = 0; p2_y = thirds1; |
|
break; |
|
|
|
case 0x1fb43: /* 🭃 */ |
|
p1_x = p2_x = 0; p3_x = halfs0; |
|
p1_y = p3_y = 0; p2_y = thirds1; |
|
break; |
|
|
|
case 0x1fb5a: /* 🭚 */ |
|
p1_x = p2_x = 0; p3_x = width; |
|
p1_y = p3_y = 0; p2_y = thirds1; |
|
break; |
|
|
|
case 0x1fb44: /* 🭄 */ |
|
p1_x = p2_x = 0; p3_x = width; |
|
p1_y = p3_y = 0; p2_y = thirds1; |
|
break; |
|
|
|
case 0x1fb5b: /* 🭛 */ |
|
case 0x1fb45: /* 🭅 */ |
|
p1_x = p2_x = 0; p3_x = halfs0; |
|
p1_y = p3_y = 0; p2_y = height; |
|
break; |
|
|
|
case 0x1fb62: /* 🭢 */ |
|
p1_x = p2_x = width; p3_x = halfs1; |
|
p1_y = p3_y = 0; p2_y = thirds0; |
|
break; |
|
|
|
case 0x1fb4c: /* 🭌 */ |
|
p1_x = p2_x = width; p3_x = halfs1; |
|
p1_y = p3_y = 0; p2_y = thirds0; |
|
break; |
|
|
|
case 0x1fb63: /* 🭣 */ |
|
p1_x = p2_x = width; p3_x = 0; |
|
p1_y = p3_y = 0; p2_y = thirds0; |
|
break; |
|
|
|
case 0x1fb4d: /* 🭍 */ |
|
p1_x = p2_x = width; p3_x = 0; |
|
p1_y = p3_y = 0; p2_y = thirds0; |
|
break; |
|
|
|
case 0x1fb64: /* 🭤 */ |
|
p1_x = p2_x = width; p3_x = halfs1; |
|
p1_y = p3_y = 0; p2_y = thirds1; |
|
break; |
|
|
|
case 0x1fb4e: /* 🭎 */ |
|
p1_x = p2_x = width; p3_x = halfs1; |
|
p1_y = p3_y = 0; p2_y = thirds1; |
|
break; |
|
|
|
case 0x1fb65: /* 🭥 */ |
|
p1_x = p2_x = width; p3_x = 0; |
|
p1_y = p3_y = 0; p2_y = thirds1; |
|
break; |
|
|
|
case 0x1fb4f: /* 🭏 */ |
|
p1_x = p2_x = width; p3_x = 0; |
|
p1_y = p3_y = 0; p2_y = thirds1; |
|
break; |
|
|
|
case 0x1fb66: /* 🭦 */ |
|
case 0x1fb50: /* 🭐 */ |
|
p1_x = p2_x = width; p3_x = halfs1; |
|
p1_y = p3_y = 0; p2_y = height; |
|
break; |
|
|
|
case 0x1fb46: /* 🭆 */ |
|
p1_x = 0; p1_y = thirds1; |
|
p2_x = width; p2_y = thirds0; |
|
p3_x = width; p3_y = p1_y; |
|
break; |
|
|
|
case 0x1fb51: /* 🭑 */ |
|
p1_x = 0; p1_y |