From 55319cd6d6c81b1f76c88fc0f43502628a01dc21 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 4 Aug 2021 08:35:51 +0530 Subject: [PATCH] FreeType: Round glyph advances The old code would simply add advances and store as a float with individual glyph positioning using floor() based on the advance + offset. This breaks rendering of infinite length ligatures at some font sizes as they either under or overflow. Rounding the advances seems to fix it. Dont know if it will have other ill-effects for non infinite length ligatures. If it does we can test total ligature length and use rounding only for long ligatures. Fixes #3896 --- docs/changelog.rst | 2 ++ kitty/freetype.c | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 592968f57..22d16b70f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -15,6 +15,8 @@ To update |kitty|, :doc:`follow the instructions `. windows, allowing individual tabs/windows to have their own titles, even when the OS Window has a fixed overall title (:iss:`3893`) +- Linux: Fix some very long ligatures being rendered incorrectly at some font + sizes (:iss:`3896`) 0.22.2 [2021-08-02] ---------------------- diff --git a/kitty/freetype.c b/kitty/freetype.c index 581935c82..96c6c36d1 100644 --- a/kitty/freetype.c +++ b/kitty/freetype.c @@ -566,6 +566,8 @@ copy_color_bitmap(uint8_t *src, pixel* dest, Region *src_rect, Region *dest_rect } } +static const bool debug_placement = false; + static void place_bitmap_in_canvas(pixel *cell, ProcessedBitmap *bm, size_t cell_width, size_t cell_height, float x_offset, float y_offset, size_t baseline, unsigned int glyph_num) { // We want the glyph to be positioned inside the cell based on the bearingX @@ -575,6 +577,7 @@ place_bitmap_in_canvas(pixel *cell, ProcessedBitmap *bm, size_t cell_width, size // Calculate column bounds int32_t xoff = (int32_t)(x_offset + bm->bitmap_left); + if (debug_placement) printf(" bitmap_left: %d xoff: %d", bm->bitmap_left, xoff); if (xoff < 0) src.left += -xoff; else dest.left = xoff; // Move the dest start column back if the width overflows because of it, but only if we are not in a very long/infinite ligature @@ -629,10 +632,17 @@ render_glyphs_in_cells(PyObject *f, bool bold, bool italic, hb_glyph_info_t *inf } x_offset = x + (float)positions[i].x_offset / 64.0f; y = (float)positions[i].y_offset / 64.0f; + if (debug_placement) printf("%d: x=%f canvas: %u", i, x_offset, canvas_width); if ((*was_colored || self->face->glyph->metrics.width > 0) && bm.width > 0) { place_bitmap_in_canvas(canvas, &bm, canvas_width, cell_height, x_offset, y, baseline, i); } - x += (float)positions[i].x_advance / 64.0f; + if (debug_placement) printf(" adv: %f\n", (float)positions[i].x_advance / 64.0f); + // the roundf() below is needed for infinite length ligatures, for a test case + // use: kitty --config None -o 'font_family Fira Code' -o 'font_size 4.5' sh -c + // "echo '|---|--------|-------|-------------|-------------|HH'; read" + // if this causes issues with non-infinite ligatures, we could choose this behavior + // based on num_glyphs and/or num_cells + x += roundf((float)positions[i].x_advance / 64.0f); free_processed_bitmap(&bm); }