Add curly-pixelated option for blocky undercurl style

This commit is contained in:
txf 2026-01-22 01:23:53 +00:00
parent b78cc92322
commit 7a41aab30e
3 changed files with 58 additions and 35 deletions

View file

@ -1075,6 +1075,9 @@ parse_section_main(struct context *ctx)
else if (streq(key, "underline-thickness")) else if (streq(key, "underline-thickness"))
return value_to_pt_or_px(ctx, &conf->underline_thickness); return value_to_pt_or_px(ctx, &conf->underline_thickness);
else if (streq(key, "curly-pixelated"))
return value_to_bool(ctx, &conf->curly_pixelated);
else if (streq(key, "strikeout-thickness")) else if (streq(key, "strikeout-thickness"))
return value_to_pt_or_px(ctx, &conf->strikeout_thickness); return value_to_pt_or_px(ctx, &conf->strikeout_thickness);
@ -3475,6 +3478,7 @@ config_load(struct config *conf, const char *conf_path,
.use_custom_underline_offset = false, .use_custom_underline_offset = false,
.box_drawings_uses_font_glyphs = false, .box_drawings_uses_font_glyphs = false,
.underline_thickness = {.pt = 0., .px = -1}, .underline_thickness = {.pt = 0., .px = -1},
.curly_pixelated = false,
.strikeout_thickness = {.pt = 0., .px = -1}, .strikeout_thickness = {.pt = 0., .px = -1},
.dpi_aware = false, .dpi_aware = false,
.gamma_correct = false, .gamma_correct = false,

View file

@ -270,6 +270,7 @@ struct config {
bool use_custom_underline_offset; bool use_custom_underline_offset;
struct pt_or_px underline_offset; struct pt_or_px underline_offset;
struct pt_or_px underline_thickness; struct pt_or_px underline_thickness;
bool curly_pixelated;
struct pt_or_px strikeout_thickness; struct pt_or_px strikeout_thickness;

View file

@ -524,48 +524,66 @@ draw_styled_underline(const struct terminal *term, pixman_image_t *pix,
} }
case UNDERLINE_CURLY: { case UNDERLINE_CURLY: {
const int top = y + y_ofs; if (term->conf->curly_pixelated) {
const int bot = top + thickness * 3; /* Pixelated curly: 4px blocks, 4px gaps, alternating rows */
const int half_x = x + ceil_w / 2.0, full_x = x + ceil_w; const int y_top = y + underline_offset(term, font);
const int y_bot = y_top + thickness;
const double bt_2 = (bot - top) * (bot - top); for (int bx = x; bx < x + ceil_w; bx += 8) {
const double th_2 = thickness * thickness; int w1 = min(4, x + ceil_w - bx);
const double hx_2 = ceil_w * ceil_w / 4.0; int w2 = min(4, x + ceil_w - bx - 4);
const int th = round(sqrt(th_2 + (th_2 * bt_2 / hx_2)) / 2.); if (w1 > 0)
pixman_image_fill_rectangles(PIXMAN_OP_SRC, pix, color, 1,
&(pixman_rectangle16_t){bx, y_top, w1, thickness});
if (w2 > 0)
pixman_image_fill_rectangles(PIXMAN_OP_SRC, pix, color, 1,
&(pixman_rectangle16_t){bx + 4, y_bot, w2, thickness});
}
} else {
/* Smooth curly using trapezoids */
const int top = y + y_ofs;
const int bot = top + thickness * 3;
const int half_x = x + ceil_w / 2.0, full_x = x + ceil_w;
#define I(x) pixman_int_to_fixed(x) const double bt_2 = (bot - top) * (bot - top);
const pixman_trapezoid_t traps[] = { const double th_2 = thickness * thickness;
const double hx_2 = ceil_w * ceil_w / 4.0;
const int th = round(sqrt(th_2 + (th_2 * bt_2 / hx_2)) / 2.);
#define I(x) pixman_int_to_fixed(x)
const pixman_trapezoid_t traps[] = {
#if 0 /* characters sit within the "dips" of the curlies */ #if 0 /* characters sit within the "dips" of the curlies */
{ {
I(top), I(bot), I(top), I(bot),
{{I(x), I(top + th)}, {I(half_x), I(bot + th)}}, {{I(x), I(top + th)}, {I(half_x), I(bot + th)}},
{{I(x), I(top - th)}, {I(half_x), I(bot - th)}}, {{I(x), I(top - th)}, {I(half_x), I(bot - th)}},
}, },
{ {
I(top), I(bot), I(top), I(bot),
{{I(half_x), I(bot - th)}, {I(full_x), I(top - th)}}, {{I(half_x), I(bot - th)}, {I(full_x), I(top - th)}},
{{I(half_x), I(bot + th)}, {I(full_x), I(top + th)}}, {{I(half_x), I(bot + th)}, {I(full_x), I(top + th)}},
} }
#else /* characters sit on top of the curlies */ #else /* characters sit on top of the curlies */
{ {
I(top), I(bot), I(top), I(bot),
{{I(x), I(bot - th)}, {I(half_x), I(top - th)}}, {{I(x), I(bot - th)}, {I(half_x), I(top - th)}},
{{I(x), I(bot + th)}, {I(half_x), I(top + th)}}, {{I(x), I(bot + th)}, {I(half_x), I(top + th)}},
}, },
{ {
I(top), I(bot), I(top), I(bot),
{{I(half_x), I(top + th)}, {I(full_x), I(bot + th)}}, {{I(half_x), I(top + th)}, {I(full_x), I(bot + th)}},
{{I(half_x), I(top - th)}, {I(full_x), I(bot - th)}}, {{I(half_x), I(top - th)}, {I(full_x), I(bot - th)}},
} }
#endif #endif
}; };
pixman_image_t *fill = pixman_image_create_solid_fill(color); pixman_image_t *fill = pixman_image_create_solid_fill(color);
pixman_composite_trapezoids( pixman_composite_trapezoids(
PIXMAN_OP_OVER, fill, pix, PIXMAN_a8, 0, 0, 0, 0, PIXMAN_OP_OVER, fill, pix, PIXMAN_a8, 0, 0, 0, 0,
sizeof(traps) / sizeof(traps[0]), traps); sizeof(traps) / sizeof(traps[0]), traps);
pixman_image_unref(fill); pixman_image_unref(fill);
}
break; break;
} }