From 19bf558e6cee456eabe6b87d9d51e8f220e20cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 27 Jun 2024 18:36:17 +0200 Subject: [PATCH] render: underlines: improve the appearance of the 'dotted' style Try to make the 'dotted' style appear more even, and less like each cell is rendered separately (even though they are). Algorithm: Each dot is a square; it's sides are that of the font's line thickness. The spacing (gaps) between the dots is initially the same width as the dots themselves. This means the number of dots per cell is the cell width divided by the dots' length/width, divided by two. At this point, there may be "left-over" pixels.I.e. the widths of the dots and the gaps between them may not add up to the width of the cell. These pixels are evenly (as possible) across the gaps. There are still visual inaccuracies at small font sizes. This is impossible to fix without changing the way underlines are rendered, to render an entire line in one go. This is not something we want to do, since it'll make styled underlines, for a specific cell/character, look differently, depending on the surrounding context. --- render.c | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/render.c b/render.c index d66bce65..65fd1739 100644 --- a/render.c +++ b/render.c @@ -432,17 +432,43 @@ draw_styled_underline(const struct terminal *term, pixman_image_t *pix, PIXMAN_OP_SRC, pix, color, 2, rects); break; } - case CURLY_DOTTED: { - const int ceil_w = cols * term->cell_width; - const int nrects = min(ceil_w / thickness / 2, 16); - pixman_rectangle16_t rects[16] = {0}; - for (int i = 0; i < nrects; i++) { + case CURLY_DOTTED: { + /* Number of dots per cell */ + int per_cell = (term->cell_width / thickness) / 2; + if (per_cell == 0) + per_cell = 1; + + xassert(per_cell >= 1); + + /* Spacing between dots; start with the same width as the dots + themselves, then widen them if necessary, to consume unused + pixels */ + int spacing[per_cell]; + for (int i = 0; i < per_cell; i++) + spacing[i] = thickness; + + /* Pixels remaining at the end of the cell */ + int remaining = term->cell_width - (per_cell * 2) * thickness; + + /* Spread out the left-over pixels across the spacing between + the dots */ + for (int i = 0; remaining > 0; i = (i + 1) % per_cell, remaining--) + spacing[i]++; + + xassert(remaining <= 0); + + pixman_rectangle16_t rects[per_cell]; + int dot_x = x; + for (int i = 0; i < per_cell; i++) { rects[i] = (pixman_rectangle16_t){ - x + i * thickness * 2, y + y_ofs, thickness, thickness}; + dot_x, y + y_ofs, thickness, thickness + }; + + dot_x += thickness + spacing[i]; } - pixman_image_fill_rectangles(PIXMAN_OP_SRC, pix, color, nrects, rects); + pixman_image_fill_rectangles(PIXMAN_OP_SRC, pix, color, per_cell, rects); break; }