From 15d7885c785fa0898eb72657494e508aaf40beb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 21 Jul 2023 09:00:57 +0200 Subject: [PATCH 01/19] =?UTF-8?q?changelog:=20add=20new=20=E2=80=98unrelea?= =?UTF-8?q?sed=E2=80=99=20section?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c55f4eee..84a8aef4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Changelog +* [Unreleased](#unreleased) * [1.15.1](#1-15-1) * [1.15.0](#1-15-0) * [1.14.0](#1-14-0) @@ -43,6 +44,16 @@ * [1.2.0](#1-2-0) +## Unreleased +### Added +### Changed +### Deprecated +### Removed +### Fixed +### Security +### Contributors + + ## 1.15.1 ### Changed From fc973a3bb934de7fe6001be7b6c39714e7b5470d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 22 Jul 2023 11:21:12 +0200 Subject: [PATCH 02/19] selection: send_clipboard_or_primary(): handle selection text being NULL --- selection.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/selection.c b/selection.c index f6349d7f..d1a7ea28 100644 --- a/selection.c +++ b/selection.c @@ -1662,7 +1662,7 @@ send_clipboard_or_primary(struct seat *seat, int fd, const char *selection, return; } - size_t len = strlen(selection); + size_t len = selection != NULL ? strlen(selection) : 0; size_t async_idx = 0; switch (async_write(fd, selection, len, &async_idx)) { @@ -1701,7 +1701,6 @@ send(void *data, struct wl_data_source *wl_data_source, const char *mime_type, struct seat *seat = data; const struct wl_clipboard *clipboard = &seat->clipboard; - xassert(clipboard->text != NULL); send_clipboard_or_primary(seat, fd, clipboard->text, "clipboard"); } @@ -1756,7 +1755,6 @@ primary_send(void *data, struct seat *seat = data; const struct wl_primary *primary = &seat->primary; - xassert(primary->text != NULL); send_clipboard_or_primary(seat, fd, primary->text, "primary"); } From b59fd7c388c8d59a08e7e30f07e4639d2fd5451f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 22 Jul 2023 11:21:41 +0200 Subject: [PATCH 03/19] vt: detect and ignore invalid UTF-8 sequences This patch detects invalid codepoints in the UTF-8 EDxxxx range, and the F4xxxxxx range. Note that we still allow the E0xxxx and F0xxxxxx ranges. These contains overlong encodings. We allow them, because they still decode into correct UTF-32. Closes #1423 --- vt.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/vt.c b/vt.c index 51b69c7e..772bd41f 100644 --- a/vt.c +++ b/vt.c @@ -913,6 +913,16 @@ action_utf8_33(struct terminal *term, uint8_t c) { // wc = ((utf8[0] & 0xf) << 12) | ((utf8[1] & 0x3f) << 6) | (utf8[2] & 0x3f) term->vt.utf8 |= c & 0x3f; + + const char32_t utf32 = term->vt.utf8; + if (unlikely(utf32 >= 0xd800 && utf32 <= 0xdfff)) { + /* Invalid sequence - invalid UTF-16 surrogate halves */ + return; + } + + /* Note: the E0 range contains overlong encodings. We don’t try to + detect, as they’ll still decode to valid UTF-32. */ + action_utf8_print(term, term->vt.utf8); } @@ -942,6 +952,17 @@ action_utf8_44(struct terminal *term, uint8_t c) { // wc = ((utf8[0] & 7) << 18) | ((utf8[1] & 0x3f) << 12) | ((utf8[2] & 0x3f) << 6) | (utf8[3] & 0x3f); term->vt.utf8 |= c & 0x3f; + + const char32_t utf32 = term->vt.utf8; + + if (unlikely(utf32 > 0x10FFFF)) { + /* Invalid UTF-8 */ + return; + } + + /* Note: the F0 range contains overlong encodings. We don’t try to + detect, as they’ll still decode to valid UTF-32. */ + action_utf8_print(term, term->vt.utf8); } From 8223b4b76cb6ab0d4320859b2497dc222c9762bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 22 Jul 2023 11:23:22 +0200 Subject: [PATCH 04/19] changelog: ignore invalid UTF-8 in input --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84a8aef4..ed0990eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,12 @@ ### Deprecated ### Removed ### Fixed + +* Crash when copying text that contains invalid UTF-8 ([#1423][1423]). + +[1423]: https://codeberg.org/dnkl/foot/issues/1423 + + ### Security ### Contributors From 0a61cfc3beb881fc8942ae99bf3ad3b5de5e6345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 23 Jul 2023 20:03:31 +0200 Subject: [PATCH 05/19] wayland: update terminals (fonts etc) on xdg_output_handle_done() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Monitor DPI depends on information from both the wl_output and the xdg_output interfaces. Before this patch, terminals were only updated after changes to the wl_output interfaces (thus depending on xdg output changes being pushed by the compositor before wl_output changes). That assumption (xdg_output happening before wl_output) isn’t always true. This patch fixes the issue by updating the terminals in the xdg_output’s “done” event. Closes #1431 --- CHANGELOG.md | 2 ++ wayland.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed0990eb..b6471b92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,8 +52,10 @@ ### Fixed * Crash when copying text that contains invalid UTF-8 ([#1423][1423]). +* Wrong font size after suspending the monitor ([#1431][1431]). [1423]: https://codeberg.org/dnkl/foot/issues/1423 +[1431]: https://codeberg.org/dnkl/foot/issues/1431 ### Security diff --git a/wayland.c b/wayland.c index 7e51bfe9..a297c76a 100644 --- a/wayland.c +++ b/wayland.c @@ -620,6 +620,8 @@ xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, static void xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output) { + struct monitor *mon = data; + update_terms_on_monitor(mon); } static void From a36f67cbe311bebd9321fbf58773dace8128fcd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 23 Jul 2023 17:35:57 +0200 Subject: [PATCH 06/19] render: apply new baseline calculation everywhere * URL jump labels * Scrollback position indicator * Line/box drawings characters Closes #1430 --- CHANGELOG.md | 6 ++++++ box-drawing.c | 2 +- render.c | 31 ++++++++++--------------------- terminal.c | 11 +++++++++++ terminal.h | 1 + 5 files changed, 29 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6471b92..7f1ed9f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,9 +53,15 @@ * Crash when copying text that contains invalid UTF-8 ([#1423][1423]). * Wrong font size after suspending the monitor ([#1431][1431]). +* Vertical alignment in URL jump labels, and the scrollback position + indicator ([#1430][1430]). +* Regression: line- and box drawing characters not covering the full + height of the line, when a custom `line-height` is being used + ([#1430][1430]). [1423]: https://codeberg.org/dnkl/foot/issues/1423 [1431]: https://codeberg.org/dnkl/foot/issues/1431 +[1430]: https://codeberg.org/dnkl/foot/issues/1430 ### Security diff --git a/box-drawing.c b/box-drawing.c index 3962e341..07f415cb 100644 --- a/box-drawing.c +++ b/box-drawing.c @@ -3011,7 +3011,7 @@ box_drawing(const struct terminal *term, char32_t wc) .cols = 1, .pix = buf.pix, .x = -term->font_x_ofs, - .y = term->font_y_ofs + term->fonts[0]->ascent, + .y = term_font_baseline(term), .width = width, .height = height, .advance = { diff --git a/render.c b/render.c index 48957a0a..9c37f765 100644 --- a/render.c +++ b/render.c @@ -302,17 +302,6 @@ color_brighten(const struct terminal *term, uint32_t color) return hsl_to_rgb(hue, sat, min(100, lum * 1.3)); } -static inline int -font_baseline(const struct terminal *term) -{ - const struct fcft_font *font = term->fonts[0]; - const int line_height = term->cell_height; - const int font_height = font->ascent + font->descent; - const int glyph_top_y = round((line_height - font_height) / 2.); - - return term->font_y_ofs + glyph_top_y + font->ascent; -} - static void draw_unfocused_block(const struct terminal *term, pixman_image_t *pix, const pixman_color_t *color, int x, int y, int cell_cols) @@ -335,7 +324,7 @@ draw_beam_cursor(const struct terminal *term, pixman_image_t *pix, const struct fcft_font *font, const pixman_color_t *color, int x, int y) { - int baseline = y + font_baseline(term) - term->fonts[0]->ascent; + int baseline = y + term_font_baseline(term) - term->fonts[0]->ascent; pixman_image_fill_rectangles( PIXMAN_OP_SRC, pix, color, 1, &(pixman_rectangle16_t){ @@ -347,7 +336,7 @@ draw_beam_cursor(const struct terminal *term, pixman_image_t *pix, static int underline_offset(const struct terminal *term, const struct fcft_font *font) { - return font_baseline(term) - + return term_font_baseline(term) - (term->conf->use_custom_underline_offset ? -term_pt_or_px_as_pixels(term, &term->conf->underline_offset) : font->underline.position); @@ -401,7 +390,7 @@ draw_strikeout(const struct terminal *term, pixman_image_t *pix, pixman_image_fill_rectangles( PIXMAN_OP_SRC, pix, color, 1, &(pixman_rectangle16_t){ - x, y + font_baseline(term) - font->strikeout.position, + x, y + term_font_baseline(term) - font->strikeout.position, cols * term->cell_width, font->strikeout.thickness}); } @@ -767,13 +756,13 @@ render_cell(struct terminal *term, pixman_image_t *pix, if (!(cell->attrs.blink && term->blink.state == BLINK_OFF)) { pixman_image_composite32( PIXMAN_OP_OVER, glyph->pix, NULL, pix, 0, 0, 0, 0, - pen_x + letter_x_ofs + g_x, y + font_baseline(term) - g_y, + pen_x + letter_x_ofs + g_x, y + term_font_baseline(term) - g_y, glyph->width, glyph->height); } } else { pixman_image_composite32( PIXMAN_OP_OVER, clr_pix, glyph->pix, pix, 0, 0, 0, 0, - pen_x + letter_x_ofs + g_x, y + font_baseline(term) - g_y, + pen_x + letter_x_ofs + g_x, y + term_font_baseline(term) - g_y, glyph->width, glyph->height); /* Combining characters */ @@ -813,7 +802,7 @@ render_cell(struct terminal *term, pixman_image_t *pix, /* Some fonts use a negative offset, while others use a * "normal" offset */ pen_x + x_ofs + g->x, - y + font_baseline(term) - g->y, + y + term_font_baseline(term) - g->y, g->width, g->height); } } @@ -1937,12 +1926,12 @@ render_osd(struct terminal *term, const struct wayl_sub_surface *sub_surf, if (pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8) { pixman_image_composite32( PIXMAN_OP_OVER, glyph->pix, NULL, buf->pix[0], 0, 0, 0, 0, - x + x_ofs + glyph->x, y + term->font_y_ofs + font->ascent - glyph->y, + x + x_ofs + glyph->x, y + /*term->font_y_ofs + font->ascent*/ term_font_baseline(term) - glyph->y, glyph->width, glyph->height); } else { pixman_image_composite32( PIXMAN_OP_OVER, src, glyph->pix, buf->pix[0], 0, 0, 0, 0, - x + x_ofs + glyph->x, y + term->font_y_ofs + font->ascent - glyph->y, + x + x_ofs + glyph->x, y + /*term->font_y_ofs + font->ascent*/ term_font_baseline(term) - glyph->y, glyph->width, glyph->height); } @@ -3364,7 +3353,7 @@ render_search_box(struct terminal *term) /* Glyph surface is a pre-rendered image (typically a color emoji...) */ pixman_image_composite32( PIXMAN_OP_OVER, glyph->pix, NULL, buf->pix[0], 0, 0, 0, 0, - x + x_ofs + glyph->x, y + font_baseline(term) - glyph->y, + x + x_ofs + glyph->x, y + term_font_baseline(term) - glyph->y, glyph->width, glyph->height); } else { int combining_ofs = width == 0 @@ -3376,7 +3365,7 @@ render_search_box(struct terminal *term) pixman_image_composite32( PIXMAN_OP_OVER, src, glyph->pix, buf->pix[0], 0, 0, 0, 0, x + x_ofs + combining_ofs + glyph->x, - y + font_baseline(term) - glyph->y, + y + term_font_baseline(term) - glyph->y, glyph->width, glyph->height); pixman_image_unref(src); } diff --git a/terminal.c b/terminal.c index c22646f2..41dc3305 100644 --- a/terminal.c +++ b/terminal.c @@ -2166,6 +2166,17 @@ term_font_subpixel_changed(struct terminal *term) render_refresh(term); } +int +term_font_baseline(const struct terminal *term) +{ + const struct fcft_font *font = term->fonts[0]; + const int line_height = term->cell_height; + const int font_height = font->ascent + font->descent; + const int glyph_top_y = round((line_height - font_height) / 2.); + + return term->font_y_ofs + glyph_top_y + font->ascent; +} + void term_damage_rows(struct terminal *term, int start, int end) { diff --git a/terminal.h b/terminal.h index 4b1d1d0d..00cfcf31 100644 --- a/terminal.h +++ b/terminal.h @@ -742,6 +742,7 @@ bool term_font_size_decrease(struct terminal *term); bool term_font_size_reset(struct terminal *term); bool term_font_dpi_changed(struct terminal *term, float old_scale); void term_font_subpixel_changed(struct terminal *term); +int term_font_baseline(const struct terminal *term); int term_pt_or_px_as_pixels( const struct terminal *term, const struct pt_or_px *pt_or_px); From 76e471c4bc9e80aa25ee6aa125078ed5b92d0cf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 25 Jul 2023 16:45:29 +0200 Subject: [PATCH 07/19] ci: alpine no longer allows pip installing to the system installation --- .woodpecker.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.woodpecker.yml b/.woodpecker.yml index acd30fc7..c98ea217 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -8,8 +8,11 @@ pipeline: commands: - apk add python3 - apk add py3-pip + - python3 -m venv codespell-venv + - source codespell-venv/bin/activate - pip install codespell - codespell -Lser,doas,zar README.md INSTALL.md CHANGELOG.md *.c *.h doc/*.scd + - deactivate subprojects: when: From 391bc119de711fe2fc8a460d5990f7a8e872738a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 25 Jul 2023 16:47:40 +0200 Subject: [PATCH 08/19] ci (sr.ht): alpine no longer allows pip installing to the system installation --- .builds/alpine-x64.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.builds/alpine-x64.yml b/.builds/alpine-x64.yml index 6ec489fc..d1336b64 100644 --- a/.builds/alpine-x64.yml +++ b/.builds/alpine-x64.yml @@ -47,6 +47,9 @@ tasks: ninja -C bld/release -k0 meson test -C bld/release --print-errorlogs - codespell: | + python3 -m venv codespell-venv + source codespell-venv/bin/activate pip install codespell cd foot ~/.local/bin/codespell -Lser,doas,zar README.md INSTALL.md CHANGELOG.md *.c *.h doc/*.scd + deactivate From 613c61abb44e49236a893376764eb21702c0ef32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 25 Jul 2023 15:56:30 +0200 Subject: [PATCH 09/19] scaling: always round the scaling factor when converting to int * In all calls to wl_subsurface_set_position() * (wp_viewport_set_destination() already does this) * Whenever we use the scale to calculate margins (search box, scrollback indicator etc) * Since the scaling factor is stored as a float (and not a double), use roundf() instead of round() --- csi.c | 12 +++--- render.c | 113 ++++++++++++++++++++++++++++++++--------------------- terminal.c | 28 ++++++++----- terminal.h | 1 + wayland.c | 30 +++++--------- 5 files changed, 104 insertions(+), 80 deletions(-) diff --git a/csi.c b/csi.c index 153a1099..959c913d 100644 --- a/csi.c +++ b/csi.c @@ -1208,8 +1208,8 @@ csi_dispatch(struct terminal *term, uint8_t final) char reply[64]; size_t n = xsnprintf( reply, sizeof(reply), "\033[4;%d;%dt", - (int)round(height / term->scale), - (int)(width / term->scale)); + (int)roundf(height / term->scale), + (int)roundf((width / term->scale))); term_to_slave(term, reply, n); } break; @@ -1233,8 +1233,8 @@ csi_dispatch(struct terminal *term, uint8_t final) char reply[64]; size_t n = xsnprintf( reply, sizeof(reply), "\033[6;%d;%dt", - (int)round(term->cell_height / term->scale), - (int)round(term->cell_width / term->scale)); + (int)roundf(term->cell_height / term->scale), + (int)roundf(term->cell_width / term->scale)); term_to_slave(term, reply, n); break; } @@ -1252,8 +1252,8 @@ csi_dispatch(struct terminal *term, uint8_t final) char reply[64]; size_t n = xsnprintf( reply, sizeof(reply), "\033[9;%d;%dt", - (int)round(it->item->dim.px_real.height / term->cell_height / term->scale), - (int)round(it->item->dim.px_real.width / term->cell_width / term->scale)); + (int)roundf(it->item->dim.px_real.height / term->cell_height / term->scale), + (int)roundf(it->item->dim.px_real.width / term->cell_width / term->scale)); term_to_slave(term, reply, n); break; } diff --git a/render.c b/render.c index 9c37f765..847e57e3 100644 --- a/render.c +++ b/render.c @@ -306,7 +306,7 @@ static void draw_unfocused_block(const struct terminal *term, pixman_image_t *pix, const pixman_color_t *color, int x, int y, int cell_cols) { - const int scale = round(term->scale); + const int scale = (int)roundf(term->scale); const int width = min(min(scale, term->cell_width), term->cell_height); pixman_image_fill_rectangles( @@ -2022,8 +2022,8 @@ render_csd_border(struct terminal *term, enum csd_surface surf_idx, */ float scale = term->scale; - int bwidth = round(term->conf->csd.border_width * scale); - int vwidth = round(term->conf->csd.border_width_visible * scale); /* Visible size */ + int bwidth = (int)roundf(term->conf->csd.border_width * scale); + int vwidth = (int)roundf(term->conf->csd.border_width_visible * scale); /* Visible size */ xassert(bwidth >= vwidth); @@ -2396,7 +2396,10 @@ render_csd(struct terminal *term) widths[i] = width; heights[i] = height; - wl_subsurface_set_position(sub, x / term->scale, y / term->scale); + wl_subsurface_set_position( + sub, + (int32_t)roundf(x / term->scale), + (int32_t)roundf(y / term->scale)); } struct buffer *bufs[CSD_SURF_COUNT]; @@ -2487,7 +2490,7 @@ render_scrollback_position(struct terminal *term) char lineno_str[64]; snprintf(lineno_str, sizeof(lineno_str), "%d", rebased_view + 1); mbstoc32(_text, lineno_str, ALEN(_text)); - cell_count = ceil(log10(term->grid->num_rows)); + cell_count = (int)ceilf(log10f(term->grid->num_rows)); break; } @@ -2497,13 +2500,16 @@ render_scrollback_position(struct terminal *term) break; } - const int scale = term->scale; - const int margin = 3 * scale; + const int iscale = (int)ceilf(term->scale); + const int margin = (int)roundf(3. * term->scale); - const int width = - (2 * margin + cell_count * term->cell_width + scale - 1) / scale * scale; - const int height = - (2 * margin + term->cell_height + scale - 1) / scale * scale; + int width = margin + cell_count * term->cell_width + margin; + int height = margin + term->cell_height + margin; + + if (!term_fractional_scaling(term)) { + width = (width + iscale - 1) / iscale * iscale; + height = (height + iscale - 1) / iscale * iscale; + } /* *Where* to render - parent relative coordinates */ int surf_top = 0; @@ -2531,8 +2537,13 @@ render_scrollback_position(struct terminal *term) } } - const int x = (term->width - margin - width) / scale * scale; - const int y = (term->margins.top + surf_top) / scale * scale; + int x = term->width - margin - width; + int y = term->margins.top + surf_top; + + if (!term_fractional_scaling(term)) { + x = (x + iscale - 1) / iscale * iscale; + y = (y + iscale - 1) / iscale * iscale; + } if (y + height > term->height) { wl_surface_attach(win->scrollback_indicator.surface.surf, NULL, 0, 0); @@ -2544,7 +2555,9 @@ render_scrollback_position(struct terminal *term) struct buffer *buf = shm_get_buffer(chain, width, height); wl_subsurface_set_position( - win->scrollback_indicator.sub, x / scale, y / scale); + win->scrollback_indicator.sub, + (int32_t)roundf(x / term->scale), + (int32_t)roundf(y / term->scale)); uint32_t fg = term->colors.table[0]; uint32_t bg = term->colors.table[8 + 4]; @@ -2573,21 +2586,25 @@ render_render_timer(struct terminal *term, struct timespec render_time) char32_t text[256]; mbstoc32(text, usecs_str, ALEN(text)); - const int scale = round(term->scale); + const int iscale = (int)ceilf(term->scale); const int cell_count = c32len(text); - const int margin = 3 * scale; - const int width = - (2 * margin + cell_count * term->cell_width + scale - 1) / scale * scale; - const int height = - (2 * margin + term->cell_height + scale - 1) / scale * scale; + const int margin = (int)roundf(3. * term->scale); + + int width = margin + cell_count * term->cell_width + margin; + int height = margin + term->cell_height + margin; + + if (!term_fractional_scaling(term)) { + width = (width + iscale - 1) / iscale * iscale; + height = (height + iscale - 1) / iscale * iscale; + } struct buffer_chain *chain = term->render.chains.render_timer; struct buffer *buf = shm_get_buffer(chain, width, height); wl_subsurface_set_position( win->render_timer.sub, - margin / term->scale, - (term->margins.top + term->cell_height - margin) / term->scale); + (int32_t)roundf(margin / term->scale), + (int32_t)roundf((term->margins.top + term->cell_height - margin) / term->scale)); render_osd( term, @@ -3132,19 +3149,24 @@ render_search_box(struct terminal *term) const size_t total_cells = c32swidth(text, text_len); const size_t wanted_visible_cells = max(20, total_cells); - xassert(term->scale >= 1); - const int rounded_scale = round(term->scale); - - const size_t margin = 3 * rounded_scale; + xassert(term->scale >= 1.); + const size_t margin = (size_t)roundf(3 * term->scale); const size_t width = term->width - 2 * margin; - const size_t visible_width = min( + size_t visible_width = min( term->width - 2 * margin, - (2 * margin + wanted_visible_cells * term->cell_width + rounded_scale - 1) / rounded_scale * rounded_scale); - const size_t height = min( - term->height - 2 * margin, - (2 * margin + 1 * term->cell_height + rounded_scale - 1) / rounded_scale * rounded_scale); + margin + wanted_visible_cells * term->cell_width + margin); + size_t height = min( + term->height - 2 * margin, + margin + 1 * term->cell_height + margin); + + if (!term_fractional_scaling(term)) { + const int iscale = (int)ceilf(term->scale); + visible_width = (visible_width + iscale - 1) / iscale * iscale; + height = (height + iscale - 1) / iscale * iscale; + } + const size_t visible_cells = (visible_width - 2 * margin) / term->cell_width; size_t glyph_offset = term->render.search_glyph_offset; @@ -3390,8 +3412,8 @@ render_search_box(struct terminal *term) /* TODO: this is only necessary on a window resize */ wl_subsurface_set_position( term->window->search.sub, - margin / term->scale, - max(0, (int32_t)term->height - height - margin) / term->scale); + (int32_t)roundf(margin / term->scale), + (int32_t)roundf(max(0, (int32_t)term->height - height - margin) / term->scale)); wayl_surface_scale(term->window, &term->window->search.surface, buf, term->scale); wl_surface_attach(term->window->search.surface.surf, buf->wl_buf, 0, 0); @@ -3420,9 +3442,8 @@ render_urls(struct terminal *term) struct wl_window *win = term->window; xassert(tll_length(win->urls) > 0); - const int scale = round(term->scale); - const int x_margin = 2 * scale; - const int y_margin = 1 * scale; + const int x_margin = (int)roundf(2 * term->scale); + const int y_margin = (int)roundf(1 * term->scale); /* Calculate view start, counted from the *current* scrollback start */ const int scrollback_end @@ -3592,10 +3613,14 @@ render_urls(struct terminal *term) if (cols == 0) continue; - const int width = - (2 * x_margin + cols * term->cell_width + scale - 1) / scale * scale; - const int height = - (2 * y_margin + term->cell_height + scale - 1) / scale * scale; + int width = x_margin + cols * term->cell_width + x_margin; + int height = y_margin + term->cell_height + y_margin; + + if (!term_fractional_scaling(term)) { + const int iscale = (int)ceilf(term->scale); + width = (width + iscale - 1) / iscale * iscale; + height = (height + iscale - 1) / iscale * iscale; + } info[render_count].url = &it->item; info[render_count].text = xc32dup(label); @@ -3631,8 +3656,8 @@ render_urls(struct terminal *term) wl_subsurface_set_position( sub_surf->sub, - (term->margins.left + x) / term->scale, - (term->margins.top + y) / term->scale); + (int32_t)roundf((term->margins.left + x) / term->scale), + (int32_t)roundf((term->margins.top + y) / term->scale)); render_osd( term, sub_surf, term->fonts[0], bufs[i], label, @@ -3909,8 +3934,8 @@ maybe_resize(struct terminal *term, int width, int height, bool force) * Ensure we can scale to logical size, and back to * pixels without truncating. */ - if (wayl_fractional_scaling(term->wl)) { - xassert((int)round(scale) == (int)scale); + if (!term_fractional_scaling(term)) { + xassert((int)ceilf(scale) == (int)scale); int iscale = scale; if (width % iscale) diff --git a/terminal.c b/terminal.c index 41dc3305..5736400b 100644 --- a/terminal.c +++ b/terminal.c @@ -784,8 +784,8 @@ term_set_fonts(struct terminal *term, struct fcft_font *fonts[static 4], /* Use force, since cell-width/height may have changed */ render_resize_force( term, - round(term->width / term->scale), - round(term->height / term->scale)); + (int)roundf(term->width / term->scale), + (int)roundf(term->height / term->scale)); } return true; } @@ -825,7 +825,7 @@ get_font_dpi(const struct terminal *term) ? tll_back(win->on_outputs) : &tll_front(term->wl->monitors); - if (wayl_fractional_scaling(term->wl)) + if (term_fractional_scaling(term)) return mon->dpi.physical; else return mon->dpi.scaled; @@ -880,12 +880,12 @@ int term_pt_or_px_as_pixels(const struct terminal *term, const struct pt_or_px *pt_or_px) { - double scale = !term->font_is_sized_by_dpi ? term->scale : 1.; - double dpi = term->font_is_sized_by_dpi ? term->font_dpi : 96.; + float scale = !term->font_is_sized_by_dpi ? term->scale : 1.; + float dpi = term->font_is_sized_by_dpi ? term->font_dpi : 96.; return pt_or_px->px == 0 - ? round(pt_or_px->pt * scale * dpi / 72) - : pt_or_px->px * scale; + ? (int)roundf(pt_or_px->pt * scale * dpi / 72) + : (int)roundf(pt_or_px->px * scale); } struct font_load_data { @@ -932,7 +932,7 @@ reload_fonts(struct terminal *term, bool resize_grid) if (use_px_size) snprintf(size, sizeof(size), ":pixelsize=%d", - (int)round(term->font_sizes[i][j].px_size * scale)); + (int)roundf(term->font_sizes[i][j].px_size * scale)); else snprintf(size, sizeof(size), ":size=%.2f", term->font_sizes[i][j].pt_size * scale); @@ -2077,6 +2077,16 @@ term_font_size_reset(struct terminal *term) return load_fonts_from_conf(term); } +bool +term_fractional_scaling(const struct terminal *term) +{ +#if defined(HAVE_FRACTIONAL_SCALE) + return term->wl->fractional_scale_manager != NULL && term->window->scale > 0.; +#else + return false; +#endif +} + bool term_update_scale(struct terminal *term) { @@ -2093,7 +2103,7 @@ term_update_scale(struct terminal *term) * - if there aren’t any outputs available, use 1.0 */ const float new_scale = - (wayl_fractional_scaling(term->wl) && win->scale > 0. + (term_fractional_scaling(term) ? win->scale : (tll_length(win->on_outputs) > 0 ? tll_back(win->on_outputs)->scale diff --git a/terminal.h b/terminal.h index 00cfcf31..25019ecd 100644 --- a/terminal.h +++ b/terminal.h @@ -736,6 +736,7 @@ bool term_to_slave(struct terminal *term, const void *data, size_t len); bool term_paste_data_to_slave( struct terminal *term, const void *data, size_t len); +bool term_fractional_scaling(const struct terminal *term); bool term_update_scale(struct terminal *term); bool term_font_size_increase(struct terminal *term); bool term_font_size_decrease(struct terminal *term); diff --git a/wayland.c b/wayland.c index a297c76a..acf078aa 100644 --- a/wayland.c +++ b/wayland.c @@ -57,7 +57,7 @@ csd_reload_font(struct wl_window *win, float old_scale) char pixelsize[32]; snprintf(pixelsize, sizeof(pixelsize), "pixelsize=%u", - (int)round(conf->csd.title_height * scale * 1 / 2)); + (int)roundf(conf->csd.title_height * scale * 1 / 2)); LOG_DBG("loading CSD font \"%s:%s\" (old-scale=%.2f, scale=%.2f)", patterns[0], pixelsize, old_scale, scale); @@ -416,7 +416,7 @@ update_term_for_output_change(struct terminal *term) * buffer dimensions may not have been updated (in which case * render_size() normally shortcuts and returns early). */ - render_resize_force(term, round(logical_width), round(logical_height)); + render_resize_force(term, (int)roundf(logical_width), (int)roundf(logical_height)); } else if (scale_updated) { @@ -425,7 +425,7 @@ update_term_for_output_change(struct terminal *term) * been updated, even though the window logical dimensions * haven’t changed. */ - render_resize(term, round(logical_width), round(logical_height)); + render_resize(term, (int)roundf(logical_width), (int)roundf(logical_height)); } } @@ -1528,7 +1528,7 @@ wayl_init(struct fdm *fdm, struct key_binding_manager *key_binding_manager, LOG_INFO( "%s: %dx%d+%dx%d@%dHz %s %.2f\" scale=%d, DPI=%.2f/%.2f (physical/scaled)", it->item.name, it->item.dim.px_real.width, it->item.dim.px_real.height, - it->item.x, it->item.y, (int)round(it->item.refresh), + it->item.x, it->item.y, (int)roundf(it->item.refresh), it->item.model != NULL ? it->item.model : it->item.description, it->item.inch, it->item.scale, it->item.dpi.physical, it->item.dpi.scaled); @@ -1996,24 +1996,12 @@ wayl_roundtrip(struct wayland *wayl) wayl_flush(wayl); } - -bool -wayl_fractional_scaling(const struct wayland *wayl) -{ -#if defined(HAVE_FRACTIONAL_SCALE) - return wayl->fractional_scale_manager != NULL; -#else - return false; -#endif -} - void wayl_surface_scale_explicit_width_height( const struct wl_window *win, const struct wayl_surface *surf, int width, int height, float scale) { - - if (wayl_fractional_scaling(win->term->wl) && win->scale > 0.) { + if (term_fractional_scaling(win->term)) { #if defined(HAVE_FRACTIONAL_SCALE) LOG_DBG("scaling by a factor of %.2f using fractional scaling " "(width=%d, height=%d) ", scale, width, height); @@ -2021,8 +2009,8 @@ wayl_surface_scale_explicit_width_height( wl_surface_set_buffer_scale(surf->surf, 1); wp_viewport_set_destination( surf->viewport, - round((float)width / scale), - round((float)height / scale)); + (int32_t)roundf((float)width / scale), + (int32_t)roundf((float)height / scale)); #else BUG("wayl_fraction_scaling() returned true, " "but fractional scaling was not available at compile time"); @@ -2031,9 +2019,9 @@ wayl_surface_scale_explicit_width_height( LOG_DBG("scaling by a factor of %.2f using legacy mode " "(width=%d, height=%d)", scale, width, height); - xassert(scale == floor(scale)); + xassert(scale == floorf(scale)); - const int iscale = (int)scale; + const int iscale = (int)floorf(scale); xassert(width % iscale == 0); xassert(height % iscale == 0); From fd813d0e6cfff57cf8a8f55e9a249ddb6fbdb6d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 28 Jul 2023 15:36:48 +0200 Subject: [PATCH 10/19] font baseline: use max(font->height, font->ascent + font->descent) when calculating font height This is how it's done when calculating the cell height, and we should do the same thing when calculating the font baseline. --- terminal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terminal.c b/terminal.c index 5736400b..d4132c24 100644 --- a/terminal.c +++ b/terminal.c @@ -2181,7 +2181,7 @@ term_font_baseline(const struct terminal *term) { const struct fcft_font *font = term->fonts[0]; const int line_height = term->cell_height; - const int font_height = font->ascent + font->descent; + const int font_height = max(font->height, font->ascent + font->descent); const int glyph_top_y = round((line_height - font_height) / 2.); return term->font_y_ofs + glyph_top_y + font->ascent; From e912656682cd6645241fd5ba9ce3c1d1533c03b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 28 Jul 2023 15:37:48 +0200 Subject: [PATCH 11/19] render: revert part of a36f67cbe311bebd9321fbf58773dace8128fcd7 render_osd() shouldn't use term_font_baseline(). This is because term_font_baseline() uses the line height to determine the position, while render_osd() renders to surfaces that aren't sized like the grid. This fixes a regression, where the CSD title were sometimes rendered too high up, and sometimes too low. --- render.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/render.c b/render.c index 847e57e3..37c0c97d 100644 --- a/render.c +++ b/render.c @@ -1926,12 +1926,12 @@ render_osd(struct terminal *term, const struct wayl_sub_surface *sub_surf, if (pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8) { pixman_image_composite32( PIXMAN_OP_OVER, glyph->pix, NULL, buf->pix[0], 0, 0, 0, 0, - x + x_ofs + glyph->x, y + /*term->font_y_ofs + font->ascent*/ term_font_baseline(term) - glyph->y, + x + x_ofs + glyph->x, y + term->font_y_ofs + font->ascent /*term_font_baseline(term)*/ - glyph->y, glyph->width, glyph->height); } else { pixman_image_composite32( PIXMAN_OP_OVER, src, glyph->pix, buf->pix[0], 0, 0, 0, 0, - x + x_ofs + glyph->x, y + /*term->font_y_ofs + font->ascent*/ term_font_baseline(term) - glyph->y, + x + x_ofs + glyph->x, y + term->font_y_ofs + font->ascent /* term_font_baseline(term)*/ - glyph->y, glyph->width, glyph->height); } From f3c5b82c8276feda3c9eec522e549062c1589484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 26 Jul 2023 16:12:36 +0200 Subject: [PATCH 12/19] config: add tweak.bold-text-in-bright-amount By how much to increase the luminance when brightening bold fonts. This was previously hard-coded to a factor of 1.3, which is now the default value of the new config option. Closes #1434 --- CHANGELOG.md | 6 ++++++ config.c | 14 +++++++++----- config.h | 1 + doc/foot.ini.5.scd | 8 +++++++- hsl.c | 6 +++--- render.c | 4 +++- tests/test-config.c | 9 ++++++--- 7 files changed, 35 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f1ed9f3..85eeae1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,12 @@ ## Unreleased ### Added + +* `[tweak].bold-text-in-bright-amount` option ([#1434][1434]). + +[1434]: https://codeberg.org/dnkl/foot/issues/1434 + + ### Changed ### Deprecated ### Removed diff --git a/config.c b/config.c index 58a655e6..302e30f0 100644 --- a/config.c +++ b/config.c @@ -480,7 +480,7 @@ value_to_dimensions(struct context *ctx, uint32_t *x, uint32_t *y) } static bool NOINLINE -value_to_double(struct context *ctx, float *res) +value_to_float(struct context *ctx, float *res) { const char *s = ctx->value; @@ -659,7 +659,7 @@ value_to_pt_or_px(struct context *ctx, struct pt_or_px *res) res->px = value; } else { float value; - if (!value_to_double(ctx, &value)) + if (!value_to_float(ctx, &value)) return false; res->pt = value; res->px = 0; @@ -1089,7 +1089,7 @@ parse_section_scrollback(struct context *ctx) } else if (strcmp(key, "multiplier") == 0) - return value_to_double(ctx, &conf->scrollback.multiplier); + return value_to_float(ctx, &conf->scrollback.multiplier); else { LOG_CONTEXTUAL_ERR("not a valid option: %s", key); @@ -1298,7 +1298,7 @@ parse_section_colors(struct context *ctx) else if (strcmp(key, "alpha") == 0) { float alpha; - if (!value_to_double(ctx, &alpha)) + if (!value_to_float(ctx, &alpha)) return false; if (alpha < 0. || alpha > 1.) { @@ -2461,7 +2461,7 @@ parse_section_tweak(struct context *ctx) } else if (strcmp(key, "box-drawing-base-thickness") == 0) - return value_to_double(ctx, &conf->tweak.box_drawing_base_thickness); + return value_to_float(ctx, &conf->tweak.box_drawing_base_thickness); else if (strcmp(key, "box-drawing-solid-shades") == 0) return value_to_bool(ctx, &conf->tweak.box_drawing_solid_shades); @@ -2472,6 +2472,9 @@ parse_section_tweak(struct context *ctx) else if (strcmp(key, "sixel") == 0) return value_to_bool(ctx, &conf->tweak.sixel); + else if (strcmp(key, "bold-text-in-bright-amount") == 0) + return value_to_float(ctx, &conf->bold_in_bright.amount); + else { LOG_CONTEXTUAL_ERR("not a valid option: %s", key); return false; @@ -2939,6 +2942,7 @@ config_load(struct config *conf, const char *conf_path, .bold_in_bright = { .enabled = false, .palette_based = false, + .amount = 1.3, }, .startup_mode = STARTUP_WINDOWED, .fonts = {{0}}, diff --git a/config.h b/config.h index 8189e56d..4d2838c4 100644 --- a/config.h +++ b/config.h @@ -133,6 +133,7 @@ struct config { struct { bool enabled; bool palette_based; + float amount; } bold_in_bright; enum { STARTUP_WINDOWED, STARTUP_MAXIMIZED, STARTUP_FULLSCREEN } startup_mode; diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index ae91ddf5..8726da0c 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -1337,7 +1337,13 @@ any of these options. Default: _512_. Maximum allowed: _2048_ (2GB). *sixel* - Boolean. When enabled, foot will process sixel images. Default: _yes_ + Boolean. When enabled, foot will process sixel images. Default: + _yes_ + +*bold-text-in-bright-amount* + Amount by which bold fonts are brightened when + *bold-text-in-bright* is set to *yes* (the *palette-based* variant + is not affected by this option). Default: _1.3_. # SEE ALSO diff --git a/hsl.c b/hsl.c index 3ebe4beb..d5d00e67 100644 --- a/hsl.c +++ b/hsl.c @@ -83,7 +83,7 @@ hsl_to_rgb(int hue, int sat, int lum) b += m; return ( - (int)round(r * 255.) << 16 | - (int)round(g * 255.) << 8 | - (int)round(b * 255.) << 0); + (uint8_t)round(r * 255.) << 16 | + (uint8_t)round(g * 255.) << 8 | + (uint8_t)round(b * 255.) << 0); } diff --git a/render.c b/render.c index 37c0c97d..6771fae5 100644 --- a/render.c +++ b/render.c @@ -299,7 +299,9 @@ color_brighten(const struct terminal *term, uint32_t color) int hue, sat, lum; rgb_to_hsl(color, &hue, &sat, &lum); - return hsl_to_rgb(hue, sat, min(100, lum * 1.3)); + + lum = (int)roundf(lum * term->conf->bold_in_bright.amount); + return hsl_to_rgb(hue, sat, min(lum, 100)); } static void diff --git a/tests/test-config.c b/tests/test-config.c index 54efd13a..2ae891e8 100644 --- a/tests/test-config.c +++ b/tests/test-config.c @@ -265,7 +265,7 @@ test_uint32(struct context *ctx, bool (*parse_fun)(struct context *ctx), } static void -test_double(struct context *ctx, bool (*parse_fun)(struct context *ctx), +test_float(struct context *ctx, bool (*parse_fun)(struct context *ctx), const char *key, const float *ptr) { ctx->key = key; @@ -580,7 +580,7 @@ test_section_scrollback(void) test_uint32(&ctx, &parse_section_scrollback, "lines", &conf.scrollback.lines); - test_double(&ctx, parse_section_scrollback, "multiplier", &conf.scrollback.multiplier); + test_float(&ctx, parse_section_scrollback, "multiplier", &conf.scrollback.multiplier); test_enum( &ctx, &parse_section_scrollback, "indicator-position", @@ -1312,7 +1312,7 @@ test_section_tweak(void) RENDER_TIMER_BOTH}, (int *)&conf.tweak.render_timer); - test_double(&ctx, &parse_section_tweak, "box-drawing-base-thickness", + test_float(&ctx, &parse_section_tweak, "box-drawing-base-thickness", &conf.tweak.box_drawing_base_thickness); test_boolean(&ctx, &parse_section_tweak, "box-drawing-solid-shades", &conf.tweak.box_drawing_solid_shades); @@ -1345,6 +1345,9 @@ test_section_tweak(void) test_boolean(&ctx, &parse_section_tweak, "font-monospace-warn", &conf.tweak.font_monospace_warn); + test_float(&ctx, &parse_section_tweak, "bold-text-in-bright-amount", + &conf.bold_in_bright.amount); + #if 0 /* Must be equal to, or less than INT32_MAX */ test_uint32(&ctx, &parse_section_tweak, "max-shm-pool-size-mb", &conf.tweak.max_shm_pool_size); From 139fd6d55cbdd2833be3d3eb7f2c96c87a7fa42d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 26 Jul 2023 16:14:38 +0200 Subject: [PATCH 13/19] meson: add -Dterminfo-base-name option This defines the base name of the generated terminfo files. It defaults to the value of -Ddefault-terminfo (i.e. 'foot') Example: meson -Ddefault-terminfo=foot-bananas -Dterminfo-base-name=foot-apples The generated terminfo files will be * terminfo/f/foot-apples * terminfo/f/foot-apples-direct The default value of $TERM will be 'foot-bananas' --- CHANGELOG.md | 5 +++++ INSTALL.md | 15 +++++++++++++-- meson.build | 12 +++++++++--- meson_options.txt | 3 ++- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85eeae1f..26f1d1fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,11 @@ ### Added * `[tweak].bold-text-in-bright-amount` option ([#1434][1434]). +* `-Dterminfo-base-name` meson option, allowing you to name the + terminfo files to something other than `-Ddefault-terminfo`. Use + case: have foot default to using the terminfo from ncurses (`foot`, + `foot-direct`), while still packaging foot's terminfo files, but + under a different name (e.g. `foot-extra`, `foot-extra-direct`). [1434]: https://codeberg.org/dnkl/foot/issues/1434 diff --git a/INSTALL.md b/INSTALL.md index 9e2da8ec..67e6b910 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -151,6 +151,7 @@ Available compile-time options: | `-Dgrapheme-clustering` | feature | `auto` | Enables grapheme clustering | libutf8proc | | `-Dterminfo` | feature | `enabled` | Build and install terminfo files | tic (ncurses) | | `-Ddefault-terminfo` | string | `foot` | Default value of `TERM` | None | +| `-Dterminfo-base-name` | string | `-Ddefault-terminfo` | Base name of the generated terminfo files | None | | `-Dcustom-terminfo-install-location` | string | `${datadir}/terminfo` | Value to set `TERMINFO` to | None | | `-Dsystemd-units-dir` | string | `${systemduserunitdir}` | Where to install the systemd service files (absolute) | None | | `-Dutmp-backend` | combo | `auto` | Which utmp backend to use (`none`, `libutempter`, `ulog` or `auto`) | libutempter or ulog | @@ -165,8 +166,18 @@ under a different name. Setting this changes the default value of `$TERM`, and the names of the terminfo files (if `-Dterminfo=enabled`). -`-Dcustom-terminfo-install-location` enables foot’s terminfo to -co-exist with ncurses’ version, without changing the terminfo +If you want foot to use the terminfo files from ncurses, but still +package foot's own terminfo files under a different name, you can use +the `-Dterminfo-base-name` option. Many distributions use the name +`foot-extra`, and thus it might be a good idea to re-use that: + +```sh +meson ... -Ddefault-terminfo=foot -Dterminfo-base-name=foot-extra +``` +(or just leave out `-Ddefault-terminfo`, since it defaults to `foot` anyway). + +Finally, `-Dcustom-terminfo-install-location` enables foot’s terminfo +to co-exist with ncurses’ version, without changing the terminfo names. The idea is that you install foot’s terminfo to a non-standard location, for example `/usr/share/foot/terminfo`. Use `-Dcustom-terminfo-install-location` to tell foot where the terminfo diff --git a/meson.build b/meson.build index aeb2daa6..87af1edd 100644 --- a/meson.build +++ b/meson.build @@ -352,11 +352,16 @@ if get_option('themes') install_subdir('themes', install_dir: join_paths(get_option('datadir'), 'foot')) endif +terminfo_base_name = get_option('terminfo-base-name') +if terminfo_base_name == '' + terminfo_base_name = get_option('default-terminfo') +endif + tic = find_program('tic', native: true, required: get_option('terminfo')) if tic.found() conf_data = configuration_data( { - 'default_terminfo': get_option('default-terminfo'), + 'default_terminfo': terminfo_base_name } ) @@ -367,9 +372,9 @@ if tic.found() ) custom_target( 'terminfo', - output: get_option('default-terminfo')[0], + output: terminfo_base_name[0], input: preprocessed, - command: [tic, '-x', '-o', '@OUTDIR@', '-e', '@0@,@0@-direct'.format(get_option('default-terminfo')), '@INPUT@'], + command: [tic, '-x', '-o', '@OUTDIR@', '-e', '@0@,@0@-direct'.format(terminfo_base_name), '@INPUT@'], install: true, install_dir: terminfo_install_location ) @@ -395,6 +400,7 @@ summary( 'utmp backend': utmp_backend, 'utmp helper default path': utmp_default_helper_path, 'Build terminfo': tic.found(), + 'Terminfo base name': terminfo_base_name, 'Terminfo install location': terminfo_install_location, 'Default TERM': get_option('default-terminfo'), 'Set TERMINFO': get_option('custom-terminfo-install-location') != '', diff --git a/meson_options.txt b/meson_options.txt index d16e23ae..ab7a07be 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -15,7 +15,8 @@ option('tests', type: 'boolean', value: true, description: 'Build tests') option('terminfo', type: 'feature', value: 'enabled', description: 'Build and install foot\'s terminfo files.') option('default-terminfo', type: 'string', value: 'foot', description: 'Default value of the "term" option in foot.ini.') - +option('terminfo-base-name', type: 'string', + description: 'Base name of the generated terminfo files. Defaults to the value of the \'default-terminfo\' meson option') option('custom-terminfo-install-location', type: 'string', value: '', description: 'Path to foot\'s terminfo, relative to ${prefix}. If set, foot will set $TERMINFO to this value in the client process.') From 9d75c551465fa3dbb3cd20ae87d6de294fcebce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 28 Jul 2023 15:32:42 +0200 Subject: [PATCH 14/19] wayland: don't try to use a non-existing viewporter interface When instantiating the viewport for a pointer surface, we didn't first check if the compositor implements the viewporter interface. This triggered a crash when a) foot was compiled with fractional scaling, and b) the compositor did not implement the viewporter interface. Closes #1444 --- CHANGELOG.md | 3 +++ wayland.c | 24 ++++++++++++++---------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26f1d1fe..a60ccef5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,10 +69,13 @@ * Regression: line- and box drawing characters not covering the full height of the line, when a custom `line-height` is being used ([#1430][1430]). +* Crash when compositor does not implement the _viewporter_ interface + ([#1444][1444]). [1423]: https://codeberg.org/dnkl/foot/issues/1423 [1431]: https://codeberg.org/dnkl/foot/issues/1431 [1430]: https://codeberg.org/dnkl/foot/issues/1430 +[1444]: https://codeberg.org/dnkl/foot/issues/1444 ### Security diff --git a/wayland.c b/wayland.c index acf078aa..9a6609f4 100644 --- a/wayland.c +++ b/wayland.c @@ -315,15 +315,17 @@ seat_handle_capabilities(void *data, struct wl_seat *wl_seat, } #if defined(HAVE_FRACTIONAL_SCALE) - xassert(seat->pointer.surface.viewport == NULL); - seat->pointer.surface.viewport = wp_viewporter_get_viewport( - seat->wayl->viewporter, seat->pointer.surface.surf); + if (seat->wayl->viewporter != NULL) { + xassert(seat->pointer.surface.viewport == NULL); + seat->pointer.surface.viewport = wp_viewporter_get_viewport( + seat->wayl->viewporter, seat->pointer.surface.surf); - if (seat->pointer.surface.viewport == NULL) { - LOG_ERR("%s: failed to create pointer viewport", seat->name); - wl_surface_destroy(seat->pointer.surface.surf); - seat->pointer.surface.surf = NULL; - return; + if (seat->pointer.surface.viewport == NULL) { + LOG_ERR("%s: failed to create pointer viewport", seat->name); + wl_surface_destroy(seat->pointer.surface.surf); + seat->pointer.surface.surf = NULL; + return; + } } #endif @@ -351,8 +353,10 @@ seat_handle_capabilities(void *data, struct wl_seat *wl_seat, wl_surface_destroy(seat->pointer.surface.surf); #if defined(HAVE_FRACTIONAL_SCALE) - wp_viewport_destroy(seat->pointer.surface.viewport); - seat->pointer.surface.viewport = NULL; + if (seat->pointer.surface.viewport != NULL) { + wp_viewport_destroy(seat->pointer.surface.viewport); + seat->pointer.surface.viewport = NULL; + } #endif if (seat->pointer.theme != NULL) From 753c4b5d4fb51574524af06ba56333f4241b1a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 27 Jul 2023 20:07:05 +0200 Subject: [PATCH 15/19] render: round scaled border/title/button widths And calculation of compounded offsets/widths/heights, to compensate for compositor rounding when positioning and scaling/sizing subsurfaces. Closes #1441 --- render.c | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/render.c b/render.c index 6771fae5..ffac3d70 100644 --- a/render.c +++ b/render.c @@ -1808,33 +1808,49 @@ get_csd_data(const struct terminal *term, enum csd_surface surf_idx) const bool borders_visible = wayl_win_csd_borders_visible(term->window); const bool title_visible = wayl_win_csd_titlebar_visible(term->window); - /* Only title bar is rendered in maximized mode */ + const float scale = term->scale; + const int border_width = borders_visible - ? term->conf->csd.border_width * term->scale : 0; + ? roundf(term->conf->csd.border_width * scale) : 0; const int title_height = title_visible - ? term->conf->csd.title_height * term->scale : 0; + ? roundf(term->conf->csd.title_height * scale) : 0; const int button_width = title_visible - ? term->conf->csd.button_width * term->scale : 0; + ? roundf(term->conf->csd.button_width * scale) : 0; const int button_close_width = term->width >= 1 * button_width ? button_width : 0; const int button_maximize_width = term->width >= 2 * button_width && term->window->wm_capabilities.maximize - ? button_width : 0; + ? button_width : 0; const int button_minimize_width = term->width >= 3 * button_width && term->window->wm_capabilities.minimize - ? button_width : 0; + ? button_width : 0; + + /* + * With fractional scaling, we must ensure the offset, when + * divided by the scale (in set_position()), and the scaled back + * (by the compositor), matches the actual pixel count made up by + * the titlebar and the border. + */ + const int top_offset = roundf( + scale * (roundf(-title_height / scale) - roundf(border_width / scale))); + + const int top_bottom_width = roundf( + scale * (roundf(term->width / scale) + 2 * roundf(border_width / scale))); + + const int left_right_height = roundf( + scale * (roundf(title_height / scale) + roundf(term->height / scale))); switch (surf_idx) { - case CSD_SURF_TITLE: return (struct csd_data){ 0, -title_height, term->width, title_height}; - case CSD_SURF_LEFT: return (struct csd_data){-border_width, -title_height, border_width, title_height + term->height}; - case CSD_SURF_RIGHT: return (struct csd_data){ term->width, -title_height, border_width, title_height + term->height}; - case CSD_SURF_TOP: return (struct csd_data){-border_width, -title_height - border_width, term->width + 2 * border_width, border_width}; - case CSD_SURF_BOTTOM: return (struct csd_data){-border_width, term->height, term->width + 2 * border_width, border_width}; + case CSD_SURF_TITLE: return (struct csd_data){ 0, -title_height, term->width, title_height}; + case CSD_SURF_LEFT: return (struct csd_data){-border_width, -title_height, border_width, left_right_height}; + case CSD_SURF_RIGHT: return (struct csd_data){ term->width, -title_height, border_width, left_right_height}; + case CSD_SURF_TOP: return (struct csd_data){-border_width, top_offset, top_bottom_width, border_width}; + case CSD_SURF_BOTTOM: return (struct csd_data){-border_width, term->height, top_bottom_width, border_width}; /* Positioned relative to CSD_SURF_TITLE */ case CSD_SURF_MINIMIZE: return (struct csd_data){term->width - 3 * button_width, 0, button_minimize_width, title_height}; From 17824744812c16560dd214b98f28977b0d2fb47d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 28 Jul 2023 15:28:10 +0200 Subject: [PATCH 16/19] fractional scaling: another round(!) of rounding fixes * Ensure buffer sizes are valid. That is, ensure that size / scale * scale == size. * Do size calculation of the window geometry in the same way we calculate the CSD offsets. --- render.c | 132 ++++++++++++++++++++++++++++-------------------------- wayland.c | 7 +-- 2 files changed, 73 insertions(+), 66 deletions(-) diff --git a/render.c b/render.c index ffac3d70..893b461a 100644 --- a/render.c +++ b/render.c @@ -2386,6 +2386,7 @@ render_csd(struct terminal *term) if (term->window->is_fullscreen) return; + const float scale = term->scale; struct csd_data infos[CSD_SURF_COUNT]; int widths[CSD_SURF_COUNT]; int heights[CSD_SURF_COUNT]; @@ -2413,11 +2414,7 @@ render_csd(struct terminal *term) widths[i] = width; heights[i] = height; - - wl_subsurface_set_position( - sub, - (int32_t)roundf(x / term->scale), - (int32_t)roundf(y / term->scale)); + wl_subsurface_set_position(sub, roundf(x / scale), roundf(y / scale)); } struct buffer *bufs[CSD_SURF_COUNT]; @@ -2518,16 +2515,14 @@ render_scrollback_position(struct terminal *term) break; } - const int iscale = (int)ceilf(term->scale); - const int margin = (int)roundf(3. * term->scale); + const float scale = term->scale; + const int margin = (int)roundf(3. * scale); int width = margin + cell_count * term->cell_width + margin; int height = margin + term->cell_height + margin; - if (!term_fractional_scaling(term)) { - width = (width + iscale - 1) / iscale * iscale; - height = (height + iscale - 1) / iscale * iscale; - } + width = roundf(scale * ceilf(width / scale)); + height = roundf(scale * ceilf(height / scale)); /* *Where* to render - parent relative coordinates */ int surf_top = 0; @@ -2558,10 +2553,8 @@ render_scrollback_position(struct terminal *term) int x = term->width - margin - width; int y = term->margins.top + surf_top; - if (!term_fractional_scaling(term)) { - x = (x + iscale - 1) / iscale * iscale; - y = (y + iscale - 1) / iscale * iscale; - } + x = roundf(scale * ceilf(x / scale)); + y = roundf(scale * ceilf(y / scale)); if (y + height > term->height) { wl_surface_attach(win->scrollback_indicator.surface.surf, NULL, 0, 0); @@ -2573,9 +2566,7 @@ render_scrollback_position(struct terminal *term) struct buffer *buf = shm_get_buffer(chain, width, height); wl_subsurface_set_position( - win->scrollback_indicator.sub, - (int32_t)roundf(x / term->scale), - (int32_t)roundf(y / term->scale)); + win->scrollback_indicator.sub, roundf(x / scale), roundf(y / scale)); uint32_t fg = term->colors.table[0]; uint32_t bg = term->colors.table[8 + 4]; @@ -2604,25 +2595,23 @@ render_render_timer(struct terminal *term, struct timespec render_time) char32_t text[256]; mbstoc32(text, usecs_str, ALEN(text)); - const int iscale = (int)ceilf(term->scale); + const float scale = term->scale; const int cell_count = c32len(text); - const int margin = (int)roundf(3. * term->scale); + const int margin = (int)roundf(3. * scale); int width = margin + cell_count * term->cell_width + margin; int height = margin + term->cell_height + margin; - if (!term_fractional_scaling(term)) { - width = (width + iscale - 1) / iscale * iscale; - height = (height + iscale - 1) / iscale * iscale; - } + width = roundf(scale * ceilf(width / scale)); + height = roundf(scale * ceilf(height / scale)); struct buffer_chain *chain = term->render.chains.render_timer; struct buffer *buf = shm_get_buffer(chain, width, height); wl_subsurface_set_position( win->render_timer.sub, - (int32_t)roundf(margin / term->scale), - (int32_t)roundf((term->margins.top + term->cell_height - margin) / term->scale)); + roundf(margin / scale), + roundf((term->margins.top + term->cell_height - margin) / scale)); render_osd( term, @@ -3167,24 +3156,22 @@ render_search_box(struct terminal *term) const size_t total_cells = c32swidth(text, text_len); const size_t wanted_visible_cells = max(20, total_cells); - xassert(term->scale >= 1.); - const size_t margin = (size_t)roundf(3 * term->scale); - - const size_t width = term->width - 2 * margin; - size_t visible_width = min( - term->width - 2 * margin, - margin + wanted_visible_cells * term->cell_width + margin); + const float scale = term->scale; + xassert(scale >= 1.); + const size_t margin = (size_t)roundf(3 * scale); + size_t width = term->width - 2 * margin; size_t height = min( term->height - 2 * margin, margin + 1 * term->cell_height + margin); - if (!term_fractional_scaling(term)) { - const int iscale = (int)ceilf(term->scale); - visible_width = (visible_width + iscale - 1) / iscale * iscale; - height = (height + iscale - 1) / iscale * iscale; - } - + width = roundf(scale * ceilf((term->width - 2 * margin) / scale)); + height = roundf(scale * ceilf(height / scale)); + + size_t visible_width = min( + term->width - 2 * margin, + margin + wanted_visible_cells * term->cell_width + margin); + const size_t visible_cells = (visible_width - 2 * margin) / term->cell_width; size_t glyph_offset = term->render.search_glyph_offset; @@ -3430,10 +3417,10 @@ render_search_box(struct terminal *term) /* TODO: this is only necessary on a window resize */ wl_subsurface_set_position( term->window->search.sub, - (int32_t)roundf(margin / term->scale), - (int32_t)roundf(max(0, (int32_t)term->height - height - margin) / term->scale)); + roundf(margin / scale), + roundf(max(0, (int32_t)term->height - height - margin) / scale)); - wayl_surface_scale(term->window, &term->window->search.surface, buf, term->scale); + wayl_surface_scale(term->window, &term->window->search.surface, buf, scale); wl_surface_attach(term->window->search.surface.surf, buf->wl_buf, 0, 0); wl_surface_damage_buffer(term->window->search.surface.surf, 0, 0, width, height); @@ -3460,8 +3447,9 @@ render_urls(struct terminal *term) struct wl_window *win = term->window; xassert(tll_length(win->urls) > 0); - const int x_margin = (int)roundf(2 * term->scale); - const int y_margin = (int)roundf(1 * term->scale); + const float scale = term->scale; + const int x_margin = (int)roundf(2 * scale); + const int y_margin = (int)roundf(1 * scale); /* Calculate view start, counted from the *current* scrollback start */ const int scrollback_end @@ -3634,11 +3622,8 @@ render_urls(struct terminal *term) int width = x_margin + cols * term->cell_width + x_margin; int height = y_margin + term->cell_height + y_margin; - if (!term_fractional_scaling(term)) { - const int iscale = (int)ceilf(term->scale); - width = (width + iscale - 1) / iscale * iscale; - height = (height + iscale - 1) / iscale * iscale; - } + width = roundf(scale * ceilf(width / scale)); + height = roundf(scale * ceilf(height / scale)); info[render_count].url = &it->item; info[render_count].text = xc32dup(label); @@ -3674,8 +3659,8 @@ render_urls(struct terminal *term) wl_subsurface_set_position( sub_surf->sub, - (int32_t)roundf((term->margins.left + x) / term->scale), - (int32_t)roundf((term->margins.top + y) / term->scale)); + roundf((term->margins.left + x) / scale), + roundf((term->margins.top + y) / scale)); render_osd( term, sub_surf, term->fonts[0], bufs[i], label, @@ -3974,8 +3959,8 @@ maybe_resize(struct terminal *term, int width, int height, bool force) const int min_rows = 1; /* Minimum window size (must be divisible by the scaling factor)*/ - const int min_width = (min_cols * term->cell_width + scale - 1) / scale * scale; - const int min_height = (min_rows * term->cell_height + scale - 1) / scale * scale; + const int min_width = roundf(scale * ceilf((min_cols * term->cell_width) / scale)); + const int min_height = roundf(scale * ceilf((min_rows * term->cell_height) / scale)); width = max(width, min_width); height = max(height, min_height); @@ -4235,22 +4220,43 @@ damage_view: const bool title_shown = wayl_win_csd_titlebar_visible(term->window); const bool border_shown = wayl_win_csd_borders_visible(term->window); - const int title_height = - title_shown ? term->conf->csd.title_height : 0; - const int border_width = - border_shown ? term->conf->csd.border_width_visible : 0; + const int title = title_shown + ? roundf(term->conf->csd.title_height * scale) + : 0; + const int border = border_shown + ? roundf(term->conf->csd.border_width_visible * scale) + : 0; + + /* Must use surface logical coordinates (same calculations as + in get_csd_data(), but with different inputs) */ + const int toplevel_min_width = roundf(border / scale) + + roundf(min_width / scale) + + roundf(border / scale); + + const int toplevel_min_height = roundf(border / scale) + + roundf(title / scale) + + roundf(min_height / scale) + + roundf(border / scale); + + const int toplevel_width = roundf(border / scale) + + roundf(term->width / scale) + + roundf(border / scale); + + const int toplevel_height = roundf(border / scale) + + roundf(title / scale) + + roundf(term->height / scale) + + roundf(border / scale); + + const int x = roundf(-border / scale); + const int y = roundf(-title / scale) - roundf(border / scale); xdg_toplevel_set_min_size( term->window->xdg_toplevel, - min_width / scale + 2 * border_width, - min_height / scale + title_height + 2 * border_width); + toplevel_min_width, toplevel_min_height); xdg_surface_set_window_geometry( term->window->xdg_surface, - -border_width, - -title_height - border_width, - term->width / term->scale + 2 * border_width, - term->height / term->scale + title_height + 2 * border_width); + x, y, toplevel_width, toplevel_height); } tll_free(term->normal.scroll_damage); diff --git a/wayland.c b/wayland.c index 9a6609f4..66e06c10 100644 --- a/wayland.c +++ b/wayland.c @@ -2010,11 +2010,12 @@ wayl_surface_scale_explicit_width_height( LOG_DBG("scaling by a factor of %.2f using fractional scaling " "(width=%d, height=%d) ", scale, width, height); + xassert((int)roundf(scale * (int)roundf(width / scale)) == width); + xassert((int)roundf(scale * (int)roundf(height / scale)) == height); + wl_surface_set_buffer_scale(surf->surf, 1); wp_viewport_set_destination( - surf->viewport, - (int32_t)roundf((float)width / scale), - (int32_t)roundf((float)height / scale)); + surf->viewport, roundf(width / scale), roundf(height / scale)); #else BUG("wayl_fraction_scaling() returned true, " "but fractional scaling was not available at compile time"); From 764248bb0d846f65c20931024c1f4adca57aae29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 29 Jul 2023 08:18:00 +0200 Subject: [PATCH 17/19] =?UTF-8?q?wayl=5Fsurface=5Fscale=5Fexplicit=5Fwidth?= =?UTF-8?q?=5Fheight():=20don=E2=80=99t=20assert=20width/height=20are=20va?= =?UTF-8?q?lid=20for=20scale?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function is only called directly when scaling the mouse pointer. The mouse pointer is never guaranteed to have a valid width and height, so skip the width/height assertions for it. --- wayland.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/wayland.c b/wayland.c index 66e06c10..c338bef8 100644 --- a/wayland.c +++ b/wayland.c @@ -2000,18 +2000,31 @@ wayl_roundtrip(struct wayland *wayl) wayl_flush(wayl); } -void -wayl_surface_scale_explicit_width_height( +static void +surface_scale_explicit_width_height( const struct wl_window *win, const struct wayl_surface *surf, - int width, int height, float scale) + int width, int height, float scale, bool verify) { if (term_fractional_scaling(win->term)) { #if defined(HAVE_FRACTIONAL_SCALE) LOG_DBG("scaling by a factor of %.2f using fractional scaling " "(width=%d, height=%d) ", scale, width, height); - xassert((int)roundf(scale * (int)roundf(width / scale)) == width); - xassert((int)roundf(scale * (int)roundf(height / scale)) == height); + if (verify) { + if ((int)roundf(scale * (int)roundf(width / scale)) != width) { + BUG("width=%d is not valid with scaling factor %.2f (%d != %d)", + width, scale, + (int)roundf(scale * (int)roundf(width / scale)), + width); + } + + if ((int)roundf(scale * (int)roundf(height / scale)) != height) { + BUG("height=%d is not valid with scaling factor %.2f (%d != %d)", + height, scale, + (int)roundf(scale * (int)roundf(height / scale)), + height); + } + } wl_surface_set_buffer_scale(surf->surf, 1); wp_viewport_set_destination( @@ -2034,12 +2047,20 @@ wayl_surface_scale_explicit_width_height( } } +void +wayl_surface_scale_explicit_width_height( + const struct wl_window *win, const struct wayl_surface *surf, + int width, int height, float scale) +{ + surface_scale_explicit_width_height(win, surf, width, height, scale, false); +} + void wayl_surface_scale(const struct wl_window *win, const struct wayl_surface *surf, const struct buffer *buf, float scale) { - wayl_surface_scale_explicit_width_height( - win, surf, buf->width, buf->height, scale); + surface_scale_explicit_width_height( + win, surf, buf->width, buf->height, scale, true); } void From aea687c0a1d6b14a302aeb7916358abb0ba10b3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 29 Jul 2023 09:09:59 +0200 Subject: [PATCH 18/19] changelog: CSDs with fractional scaling --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a60ccef5..6a5bd8be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,11 +71,13 @@ ([#1430][1430]). * Crash when compositor does not implement the _viewporter_ interface ([#1444][1444]). +* CSD rendering with fractional scaling ([#1441][1441]). [1423]: https://codeberg.org/dnkl/foot/issues/1423 [1431]: https://codeberg.org/dnkl/foot/issues/1431 [1430]: https://codeberg.org/dnkl/foot/issues/1430 [1444]: https://codeberg.org/dnkl/foot/issues/1444 +[1441]: https://codeberg.org/dnkl/foot/issues/1441 ### Security From 1af0277564f6347caa85fda4b46071c0cf03234c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 30 Jul 2023 07:53:33 +0200 Subject: [PATCH 19/19] --window-size-chars: ensure width/height are valid for current scaling factor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this patch, we didn’t ensure width and height were valid for the current scaling factor, when fractional scaling _is_ available. That is, we didn’t ensure the width/height values multiplied back to their original values after dividing with the scaling factor. Closes #1446 --- CHANGELOG.md | 4 ++++ render.c | 19 +++---------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a5bd8be..916880c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,12 +72,16 @@ * Crash when compositor does not implement the _viewporter_ interface ([#1444][1444]). * CSD rendering with fractional scaling ([#1441][1441]). +* Regression: crash with certain combinations of + `--window-size-chars=NxM` and desktop scaling factors + ([#1446][1446]). [1423]: https://codeberg.org/dnkl/foot/issues/1423 [1431]: https://codeberg.org/dnkl/foot/issues/1431 [1430]: https://codeberg.org/dnkl/foot/issues/1430 [1444]: https://codeberg.org/dnkl/foot/issues/1444 [1441]: https://codeberg.org/dnkl/foot/issues/1441 +[1446]: https://codeberg.org/dnkl/foot/issues/1446 ### Security diff --git a/render.c b/render.c index 893b461a..5c6eeb92 100644 --- a/render.c +++ b/render.c @@ -3933,22 +3933,9 @@ maybe_resize(struct terminal *term, int width, int height, bool force) width += 2 * term->conf->pad_x * scale; height += 2 * term->conf->pad_y * scale; - /* - * Ensure we can scale to logical size, and back to - * pixels without truncating. - */ - if (!term_fractional_scaling(term)) { - xassert((int)ceilf(scale) == (int)scale); - - int iscale = scale; - if (width % iscale) - width += iscale - width % iscale; - if (height % iscale) - height += iscale - height % iscale; - - xassert(width % iscale == 0); - xassert(height % iscale == 0); - } + /* Ensure width/height is a valid multiple of scale */ + width = roundf(scale * roundf(width / scale)); + height = roundf(scale * roundf(height / scale)); break; } }