diff --git a/box-drawing.c b/box-drawing.c index 0fa44cd3..6bfaef82 100644 --- a/box-drawing.c +++ b/box-drawing.c @@ -2064,13 +2064,23 @@ box_drawing(const struct terminal *term, wchar_t wc) }; draw_glyph(wc, &buf); + const struct config *conf = term->conf; + + int x_ofs = conf->horizontal_letter_offset.px > 0 + ? conf->horizontal_letter_offset.px + : conf->horizontal_letter_offset.pt * term->font_dpi / 72.; + int y_ofs = conf->vertical_letter_offset.px > 0 + ? conf->vertical_letter_offset.px + : conf->vertical_letter_offset.pt * term->font_dpi / 72.; + + struct fcft_glyph *glyph = xmalloc(sizeof(*glyph)); *glyph = (struct fcft_glyph){ .wc = wc, .cols = 1, .pix = pix, - .x = -term->conf->horizontal_letter_offset, - .y = term->conf->vertical_letter_offset + term->fonts[0]->ascent, + .x = -x_ofs, + .y = y_ofs + term->fonts[0]->ascent, .width = width, .height = height, .advance = { diff --git a/config.c b/config.c index 03474e49..51615389 100644 --- a/config.c +++ b/config.c @@ -360,19 +360,6 @@ str_to_bool(const char *s) strtoul(s, NULL, 0) > 0; } -static bool -str_to_long(const char *s, int base, long *res) -{ - if (s == NULL) - return false; - - errno = 0; - char *end = NULL; - - *res = strtol(s, &end, base); - return errno == 0 && *end == '\0'; -} - static bool str_to_ulong(const char *s, int base, unsigned long *res) { @@ -422,6 +409,40 @@ str_to_color(const char *s, uint32_t *color, bool allow_alpha, return true; } +static bool +str_to_pt_or_px(const char *s, union pt_or_px *res, struct config *conf, + const char *path, int lineno, const char *section, const char *key) +{ + size_t len = s != NULL ? strlen(s) : 0; + if (len >= 2 && s[len - 2] == 'p' && s[len - 1] == 'x') { + errno = 0; + char *end = NULL; + + long value = strtol(s, &end, 10); + if (!(errno == 0 && end == s + len - 2)) { + LOG_AND_NOTIFY_ERR( + "%s:%d: [%s]: %s: " + "expected an integer directly followed by 'px', got '%s'", + path, lineno, section, key, s); + return false; + } + res->pt = 0; + res->px = value; + } else { + double value; + if (!str_to_double(s, &value)) { + LOG_AND_NOTIFY_ERR( + "%s:%d: [%s]: %s: expected a decimal value, got '%s'", + path, lineno, section, key, s); + return false; + } + res->pt = value; + res->px = 0; + } + + return true; +} + static bool parse_section_main(const char *key, const char *value, struct config *conf, const char *path, unsigned lineno) @@ -572,47 +593,29 @@ parse_section_main(const char *key, const char *value, struct config *conf, } else if (strcmp(key, "line-height") == 0) { - unsigned long height; - if (!str_to_ulong(value, 10, &height)) { - LOG_AND_NOTIFY_ERR( - "%s:%d: [default]: line-height: expected an integer, got '%s'", - path, lineno, value); + if (!str_to_pt_or_px(value, &conf->line_height, + conf, path, lineno, "default", "line-height")) return false; - } - conf->line_height = height; } else if (strcmp(key, "letter-spacing") == 0) { - long spacing; - if (!str_to_long(value, 10, &spacing)) { - LOG_AND_NOTIFY_ERR( - "%s:%d: [default]: letter-spacing: expected an integer, got '%s'", - path, lineno, value); + if (!str_to_pt_or_px(value, &conf->letter_spacing, + conf, path, lineno, "default", "letter-spacing")) return false; - } - conf->letter_spacing = spacing; } else if (strcmp(key, "horizontal-letter-offset") == 0) { - long offset; - if (!str_to_long(value, 10, &offset)) { - LOG_AND_NOTIFY_ERR( - "%s:%d: [default]: horizontal-letter-offset: " - "expected an integer, got '%s'", path, lineno, value); + if (!str_to_pt_or_px( + value, &conf->horizontal_letter_offset, + conf, path, lineno, "default", "horizontal-letter-offset")) return false; - } - conf->horizontal_letter_offset = offset; } else if (strcmp(key, "vertical-letter-offset") == 0) { - long offset; - if (!str_to_long(value, 10, &offset)) { - LOG_AND_NOTIFY_ERR( - "%s:%d: [default]: horizontal-letter-offset: " - "expected an integer, got '%s'", path, lineno, value); + if (!str_to_pt_or_px( + value, &conf->horizontal_letter_offset, + conf, path, lineno, "default", "vertical-letter-offset")) return false; - } - conf->vertical_letter_offset = offset; } else if (strcmp(key, "dpi-aware") == 0) { @@ -2039,10 +2042,10 @@ config_load(struct config *conf, const char *conf_path, .bell_action = BELL_ACTION_NONE, .startup_mode = STARTUP_WINDOWED, .fonts = {tll_init(), tll_init(), tll_init(), tll_init()}, - .line_height = -1, - .letter_spacing = -1, - .horizontal_letter_offset = 0, - .vertical_letter_offset = 0, + .line_height = { .pt = 0, .px = -1, }, + .letter_spacing = { .pt = 0, .px = 0, }, + .horizontal_letter_offset = {.pt = 0, .px = 0, }, + .vertical_letter_offset = {.pt = 0, .px = 0, }, .dpi_aware = DPI_AWARE_AUTO, /* DPI-aware when scaling-factor == 1 */ .scrollback = { .lines = 1000, diff --git a/config.h b/config.h index 9b33b37f..e9bc310f 100644 --- a/config.h +++ b/config.h @@ -54,6 +54,12 @@ struct config_mouse_binding { } pipe; }; +/* If px == -1, neither px nor pt is valid. If px == 0, pt is valid, else px */ +union pt_or_px { + int16_t px; + float pt; +}; + struct config { char *term; char *shell; @@ -85,12 +91,12 @@ struct config { config_font_list_t fonts[4]; /* Custom font metrics (-1 = use real font metrics) */ - int16_t line_height; - int16_t letter_spacing; + union pt_or_px line_height; + union pt_or_px letter_spacing; /* Adjusted letter x/y offsets */ - int16_t horizontal_letter_offset; - int16_t vertical_letter_offset; + union pt_or_px horizontal_letter_offset; + union pt_or_px vertical_letter_offset; struct { int lines; diff --git a/render.c b/render.c index 4e531207..51341365 100644 --- a/render.c +++ b/render.c @@ -256,7 +256,7 @@ color_dim_for_search(pixman_color_t *color) static inline int font_baseline(const struct terminal *term) { - return term->conf->vertical_letter_offset + term->fonts[0]->ascent; + return term->font_y_ofs + term->fonts[0]->ascent; } static void @@ -541,7 +541,7 @@ render_cell(struct terminal *term, pixman_image_t *pix, pixman_image_t *clr_pix = pixman_image_create_solid_fill(&fg); if (glyph != NULL) { - const int letter_x_ofs = term->conf->horizontal_letter_offset; + const int letter_x_ofs = term->font_x_ofs; if (unlikely(pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8)) { /* Glyph surface is a pre-rendered image (typically a color emoji...) */ @@ -1693,7 +1693,7 @@ render_osd(struct terminal *term, struct fcft_font *font = term->fonts[0]; pixman_color_t fg = color_hex_to_pixman(_fg); - const int x_ofs = term->conf->horizontal_letter_offset; + const int x_ofs = term->font_x_ofs; for (size_t i = 0; i < wcslen(text); i++) { const struct fcft_glyph *glyph = fcft_glyph_rasterize( @@ -2272,7 +2272,7 @@ render_search_box(struct terminal *term) struct fcft_font *font = term->fonts[0]; const int x_left = width - visible_width + margin; - const int x_ofs = term->conf->horizontal_letter_offset; + const int x_ofs = term->font_x_ofs; int x = x_left; int y = margin; pixman_color_t fg = color_hex_to_pixman(term->colors.table[0]); diff --git a/terminal.c b/terminal.c index c23450fb..676f0cb4 100644 --- a/terminal.c +++ b/terminal.c @@ -629,15 +629,30 @@ term_set_fonts(struct terminal *term, struct fcft_font *fonts[static 4]) const int old_cell_width = term->cell_width; const int old_cell_height = term->cell_height; - term->cell_width = (term->fonts[0]->space_advance.x > 0 - ? term->fonts[0]->space_advance.x - : term->fonts[0]->max_advance.x) - + term->conf->letter_spacing; + const struct config *conf = term->conf; - term->cell_height = term->conf->line_height >= 0 - ? term->conf->line_height + term->cell_width = + (term->fonts[0]->space_advance.x > 0 + ? term->fonts[0]->space_advance.x + : term->fonts[0]->max_advance.x) + + (conf->letter_spacing.px > 0 + ? conf->letter_spacing.px + : conf->letter_spacing.pt * term->font_dpi / 72.); + + term->cell_height = conf->line_height.px >= 0 + ? (conf->line_height.px > 0 + ? conf->line_height.px + : conf->line_height.pt * term->font_dpi / 72.) : max(term->fonts[0]->height, term->fonts[0]->ascent + term->fonts[0]->descent); + + term->font_x_ofs = conf->horizontal_letter_offset.px > 0 + ? conf->horizontal_letter_offset.px + : conf->horizontal_letter_offset.pt * term->font_dpi / 72.; + term->font_y_ofs = conf->vertical_letter_offset.px > 0 + ? conf->vertical_letter_offset.px + : conf->vertical_letter_offset.pt * term->font_dpi / 72.; + LOG_INFO("cell width=%d, height=%d", term->cell_width, term->cell_height); if (term->cell_width < old_cell_width || diff --git a/terminal.h b/terminal.h index 128694e7..19fff0e2 100644 --- a/terminal.h +++ b/terminal.h @@ -265,6 +265,8 @@ struct terminal { struct config_font *font_sizes[4]; float font_dpi; int font_scale; + int16_t font_x_ofs; + int16_t font_y_ofs; enum fcft_subpixel font_subpixel; /*