From 7acdb3a0dd5633ac79aa7664df300b1fdbe715f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 26 Dec 2020 16:24:16 +0100 Subject: [PATCH] box-drawing: add infrastructure for rendering box drawing characters ourselves MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ‘term’ struct contains an array of 160 fcft glyph pointers * the glyph pointers are lazily allocated when we need to draw a box drawings character * Filtering out box drawings characters is easy - they are (except unicode 13, which isn’t handled yet )all in a single range. --- box-drawing.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++ box-drawing.h | 6 ++ meson.build | 1 + render.c | 22 ++++- stride.h | 9 ++ terminal.c | 7 ++ terminal.h | 2 + 7 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 box-drawing.c create mode 100644 box-drawing.h create mode 100644 stride.h diff --git a/box-drawing.c b/box-drawing.c new file mode 100644 index 00000000..c7e5ec7f --- /dev/null +++ b/box-drawing.c @@ -0,0 +1,228 @@ +#include "box-drawing.h" + +#include +#include + +#define LOG_MODULE "box-drawing" +#define LOG_ENABLE_DBG 1 +#include "log.h" +#include "stride.h" +#include "terminal.h" +#include "xmalloc.h" + +static void +draw_glyph(wchar_t wc, pixman_image_t *pix, int width, int height, int stride) +{ + switch (wc) { + case 0x2500: + case 0x2501: + case 0x2502: + case 0x2503: + case 0x2504: + case 0x2505: + case 0x2506: + case 0x2507: + case 0x2508: + case 0x2509: + case 0x250a: + case 0x250b: + case 0x250c: + case 0x250d: + case 0x250e: + case 0x250f: + + case 0x2510: + case 0x2511: + case 0x2512: + case 0x2513: + case 0x2514: + case 0x2515: + case 0x2516: + case 0x2517: + case 0x2518: + case 0x2519: + case 0x251a: + case 0x251b: + case 0x251c: + case 0x251d: + case 0x251e: + case 0x251f: + + case 0x2520: + case 0x2521: + case 0x2522: + case 0x2523: + case 0x2524: + case 0x2525: + case 0x2526: + case 0x2527: + case 0x2528: + case 0x2529: + case 0x252a: + case 0x252b: + case 0x252c: + case 0x252d: + case 0x252e: + case 0x252f: + + case 0x2530: + case 0x2531: + case 0x2532: + case 0x2533: + case 0x2534: + case 0x2535: + case 0x2536: + case 0x2537: + case 0x2538: + case 0x2539: + case 0x253a: + case 0x253b: + case 0x253c: + case 0x253d: + case 0x253e: + case 0x253f: + + case 0x2540: + case 0x2541: + case 0x2542: + case 0x2543: + case 0x2544: + case 0x2545: + case 0x2546: + case 0x2547: + case 0x2548: + case 0x2549: + case 0x254a: + case 0x254b: + case 0x254c: + case 0x254d: + case 0x254e: + case 0x254f: + + case 0x2550: + case 0x2551: + case 0x2552: + case 0x2553: + case 0x2554: + case 0x2555: + case 0x2556: + case 0x2557: + case 0x2558: + case 0x2559: + case 0x255a: + case 0x255b: + case 0x255c: + case 0x255d: + case 0x255e: + case 0x255f: + + case 0x2560: + case 0x2561: + case 0x2562: + case 0x2563: + case 0x2564: + case 0x2565: + case 0x2566: + case 0x2567: + case 0x2568: + case 0x2569: + case 0x256a: + case 0x256b: + case 0x256c: + case 0x256d: + case 0x256e: + case 0x256f: + + case 0x2570: + case 0x2571: + case 0x2572: + case 0x2573: + case 0x2574: + case 0x2575: + case 0x2576: + case 0x2577: + case 0x2578: + case 0x2579: + case 0x257a: + case 0x257b: + case 0x257c: + case 0x257d: + case 0x257e: + case 0x257f: + + case 0x2580: + case 0x2581: + case 0x2582: + case 0x2583: + case 0x2584: + case 0x2585: + case 0x2586: + case 0x2587: + case 0x2588: + case 0x2589: + case 0x258a: + case 0x258b: + case 0x258c: + case 0x258d: + case 0x258e: + case 0x258f: + + case 0x2590: + case 0x2591: + case 0x2592: + case 0x2593: + case 0x2594: + case 0x2595: + case 0x2596: + case 0x2597: + case 0x2598: + case 0x2599: + case 0x259a: + case 0x259b: + case 0x259c: + case 0x259d: + case 0x259e: + case 0x259f: + LOG_WARN("unimplemented: box drawing: wc=%04x", wc); + //assert(false); + break; + } +} + +struct fcft_glyph * +box_drawing(struct terminal *term, wchar_t wc) +{ + LOG_DBG("rendering 0x%04x", wc); + + int width = term->cell_width; + int height = term->cell_height; + int stride = stride_for_format_and_width(PIXMAN_a1, width); + uint8_t *data = xcalloc(height * stride, 1); + + pixman_image_t *pix = pixman_image_create_bits_no_clear( + PIXMAN_a1, width, height, (uint32_t*)data, stride); + + if (pix == NULL) { + errno = ENOMEM; + perror(__func__); + abort(); + } + + draw_glyph(wc, pix, width, height, stride); + + struct fcft_glyph *glyph = xmalloc(sizeof(*glyph)); + *glyph = (struct fcft_glyph){ + .wc = wc, + .cols = 1, + .pix = pix, + .x = 0, + .y = term->fonts[0]->ascent, + .width = width, + .height = height, + .advance = { + .x = width, + .y = height, + }, + }; + return glyph; +} diff --git a/box-drawing.h b/box-drawing.h new file mode 100644 index 00000000..aecbf1b3 --- /dev/null +++ b/box-drawing.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +struct terminal; +struct fcft_glyph *box_drawing(struct terminal *term, wchar_t wc); diff --git a/meson.build b/meson.build index b382b496..dc76f041 100644 --- a/meson.build +++ b/meson.build @@ -149,6 +149,7 @@ executable( executable( 'foot', 'async.c', 'async.h', + 'box-drawing.c', 'box-drawing.h', 'config.c', 'config.h', 'commands.c', 'commands.h', 'extract.c', 'extract.h', diff --git a/render.c b/render.c index f66e277e..77e6ba5f 100644 --- a/render.c +++ b/render.c @@ -16,6 +16,7 @@ #define LOG_MODULE "render" #define LOG_ENABLE_DBG 0 #include "log.h" +#include "box-drawing.h" #include "config.h" #include "grid.h" #include "hsl.h" @@ -449,7 +450,26 @@ render_cell(struct terminal *term, pixman_image_t *pix, base = composed->base; } - glyph = fcft_glyph_rasterize(font, base, term->font_subpixel); + if (unlikely(base >= 0x2500 && base <= 0x259f)) { + /* Box drawing characters */ + size_t idx = base - 0x2500; + assert(idx < ALEN(term->box_drawing)); + + if (likely(term->box_drawing[idx] != NULL)) + glyph = term->box_drawing[idx]; + else { + mtx_lock(&term->render.workers.lock); + + /* Parallel thread may have instantiated it while we took the lock */ + if (term->box_drawing[idx] == NULL) + term->box_drawing[idx] = box_drawing(term, base); + mtx_unlock(&term->render.workers.lock); + + glyph = term->box_drawing[idx]; + assert(glyph != NULL); + } + } else + glyph = fcft_glyph_rasterize(font, base, term->font_subpixel); } const int cols_left = term->cols - col; diff --git a/stride.h b/stride.h new file mode 100644 index 00000000..b2c71a71 --- /dev/null +++ b/stride.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +static inline int +stride_for_format_and_width(pixman_format_code_t format, int width) +{ + return (((PIXMAN_FORMAT_BPP(format) * width + 7) / 8 + 4 - 1) & -4); +} diff --git a/terminal.c b/terminal.c index ecb4e6cc..1a0a9cf9 100644 --- a/terminal.c +++ b/terminal.c @@ -1412,6 +1412,13 @@ term_destroy(struct terminal *term) for (size_t i = 0; i < 4; i++) free(term->font_sizes[i]); + for (size_t i = 0; i < ALEN(term->box_drawing); i++) { + if (term->box_drawing[i] != NULL) { + pixman_image_unref(term->box_drawing[i]->pix); + free(term->box_drawing[i]); + } + } + free(term->search.buf); if (term->render.workers.threads != NULL) { diff --git a/terminal.h b/terminal.h index e13243a2..8dea2435 100644 --- a/terminal.h +++ b/terminal.h @@ -261,6 +261,8 @@ struct terminal { int font_scale; enum fcft_subpixel font_subpixel; + struct fcft_glyph *box_drawing[160]; + bool is_sending_paste_data; ptmx_buffer_list_t ptmx_buffers; ptmx_buffer_list_t ptmx_paste_buffers;