diff --git a/kitty/fonts.c b/kitty/fonts.c index 934f7e5d6..a26d93b4c 100644 --- a/kitty/fonts.c +++ b/kitty/fonts.c @@ -387,10 +387,10 @@ set_cell_sprite(Cell *cell, SpritePosition *sp) { } static inline uint8_t* -extract_cell_from_canvas(unsigned int i) { - uint8_t *ans = canvas + (cell_width * cell_height * (CELLS_IN_CANVAS - 1)), *dest = ans; - uint8_t *src = canvas + (cell_width * cell_height * i); - for (unsigned int r = 0; r < cell_height; r++, dest += cell_width, src += cell_width) memcpy(dest, src, cell_width); +extract_cell_from_canvas(unsigned int i, unsigned int num_cells) { + uint8_t *ans = canvas + (cell_width * cell_height * (CELLS_IN_CANVAS - 1)), *dest = ans, *src = canvas + (i * cell_width); + unsigned int stride = cell_width * num_cells; + for (unsigned int r = 0; r < cell_height; r++, dest += cell_width, src += stride) memcpy(dest, src, cell_width); return ans; } @@ -434,7 +434,7 @@ render_group(unsigned int num_cells, unsigned int num_glyphs, Cell *cells, hb_gl for (unsigned int i = 0; i < num_cells; i++) { sprite_position[i]->rendered = true; set_cell_sprite(cells + i, sprite_position[i]); - uint8_t *buf = num_cells == 1 ? canvas : extract_cell_from_canvas(i); + uint8_t *buf = num_cells == 1 ? canvas : extract_cell_from_canvas(i, num_cells); current_send_sprite_to_gpu(sprite_position[i]->x, sprite_position[i]->y, sprite_position[i]->z, buf); } diff --git a/kitty/fonts/render.py b/kitty/fonts/render.py index 493512316..0585faa59 100644 --- a/kitty/fonts/render.py +++ b/kitty/fonts/render.py @@ -177,7 +177,7 @@ def render_box_drawing(codepoint): return ctypes.addressof(buf), buf -def test_render_string(text='\'Qing👁a⧽', size=200.0, dpi=96.0): +def test_render_string(text='Hello, world!', family='monospace', size=144.0, dpi=96.0): from tempfile import NamedTemporaryFile from kitty.fast_data_types import concat_cells, set_send_sprite_to_gpu, Screen, sprite_map_set_limits, test_render_line from kitty.icat import detect_support, show @@ -190,8 +190,9 @@ def test_render_string(text='\'Qing👁a⧽', size=200.0, dpi=96.0): sprite_map_set_limits(100000, 100) set_send_sprite_to_gpu(send_to_gpu) + opts = defaults._replace(font_family=family) try: - cell_width, cell_height = set_font_family(override_dpi=(dpi, dpi), override_font_size=size) + cell_width, cell_height = set_font_family(opts, override_dpi=(dpi, dpi), override_font_size=size) s = Screen(None, 1, len(text)*2) line = s.line(0) s.draw(text) @@ -206,6 +207,11 @@ def test_render_string(text='\'Qing👁a⧽', size=200.0, dpi=96.0): rgb_data = concat_cells(cell_width, cell_height, tuple(cells)) with NamedTemporaryFile(delete=False) as f: f.write(rgb_data) - print('Rendered string below: ({}x{})'.format(cell_width, cell_height)) + print('Rendered string {!r} below: ({}x{})'.format(text, cell_width, cell_height)) show(f.name, cell_width * len(cells), cell_height, 24) - print() + print('\n') + + +def showcase(): + test_render_string(family='Fira Code Medium') + test_render_string('==A=== -> -->', family='Fira Code Medium') diff --git a/kitty/freetype.c b/kitty/freetype.c index 5fffaeaba..5c18f807f 100644 --- a/kitty/freetype.c +++ b/kitty/freetype.c @@ -251,12 +251,13 @@ render_bitmap(Face *self, int glyph_id, ProcessedBitmap *ans, unsigned int cell_ } static inline void -place_bitmap_in_cell(unsigned char *cell, ProcessedBitmap *bm, size_t cell_width, size_t cell_height, float x_offset, float y_offset, FT_Glyph_Metrics *metrics, size_t baseline) { +place_bitmap_in_canvas(unsigned char *cell, ProcessedBitmap *bm, size_t cell_width, size_t cell_height, float x_offset, float y_offset, FT_Glyph_Metrics *metrics, size_t baseline) { // We want the glyph to be positioned inside the cell based on the bearingX // and bearingY values, making sure that it does not overflow the cell. // Calculate column bounds - ssize_t xoff = (ssize_t)(x_offset + (float)metrics->horiBearingX / 64.f); + float bearing_x = (float)metrics->horiBearingX / 64.f; + ssize_t xoff = (ssize_t)(x_offset + bearing_x); size_t src_start_column = bm->start_x, dest_start_column = 0, extra; if (xoff < 0) src_start_column += -xoff; else dest_start_column = xoff; @@ -267,7 +268,8 @@ place_bitmap_in_cell(unsigned char *cell, ProcessedBitmap *bm, size_t cell_width } // Calculate row bounds - ssize_t yoff = (ssize_t)(y_offset + (float)metrics->horiBearingY / 64.f); + float bearing_y = (float)metrics->horiBearingY / 64.f; + ssize_t yoff = (ssize_t)(y_offset + bearing_y); size_t src_start_row, dest_start_row; if (yoff > 0 && (size_t)yoff > baseline) { src_start_row = 0; @@ -299,7 +301,7 @@ render_glyphs_in_cells(PyObject *f, bool bold, bool italic, hb_glyph_info_t *inf if (!render_bitmap(self, info[i].codepoint, &bm, cell_width, num_cells, bold, italic, true)) return false; x += (float)positions[i].x_offset / 64.0f; y = (float)positions[i].y_offset / 64.0f; - place_bitmap_in_cell(canvas, &bm, cell_width * num_cells, cell_height, x, y, &self->face->glyph->metrics, baseline); + if (self->face->glyph->metrics.width > 0 && bm.width > 0) place_bitmap_in_canvas(canvas, &bm, cell_width * num_cells, cell_height, x, y, &self->face->glyph->metrics, baseline); x += (float)positions[i].x_advance / 64.0f; } return true;