From ed445153189fa8f4c4aa8fe200ee49cd0afa5a35 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 25 May 2018 14:18:22 +0530 Subject: [PATCH] All tests pass --- kitty/core_text.m | 14 ++-- kitty/fonts.c | 147 +++++++++++++++++++----------------------- kitty/fonts/render.py | 99 +++++++++++++++++----------- kitty/shaders.c | 6 +- kitty_tests/fonts.py | 19 ++++-- 5 files changed, 151 insertions(+), 134 deletions(-) diff --git a/kitty/core_text.m b/kitty/core_text.m index 9647e50a4..b1246ac8c 100644 --- a/kitty/core_text.m +++ b/kitty/core_text.m @@ -178,7 +178,7 @@ find_substitute_face(CFStringRef str, CTFontRef old_font) { } PyObject* -create_fallback_face(PyObject *base_face, Cell* cell, bool UNUSED bold, bool UNUSED italic, bool emoji_presentation, FONT_DATA_HANDLE fg UNUSED) { +create_fallback_face(PyObject *base_face, Cell* cell, bool UNUSED bold, bool UNUSED italic, bool emoji_presentation, FONTS_DATA_HANDLE fg UNUSED) { CTFace *self = (CTFace*)base_face; CTFontRef new_font; if (emoji_presentation) new_font = CTFontCreateWithName((CFStringRef)@"AppleColorEmoji", self->scaled_point_sz, NULL); @@ -214,12 +214,12 @@ is_glyph_empty(PyObject *s, glyph_index g) { } static inline float -scaled_point_sz(FONT_DATA_HANDLE fg) { +scaled_point_sz(FONTS_DATA_HANDLE fg) { return ((fg->logical_dpi_x + fg->logical_dpi_y) / 144.0) * fg->font_sz_in_pts; } bool -set_size_for_face(PyObject *s, unsigned int UNUSED desired_height, bool force, FONT_DATA_HANDLE fg) { +set_size_for_face(PyObject *s, unsigned int UNUSED desired_height, bool force, FONTS_DATA_HANDLE fg) { CTFace *self = (CTFace*)s; float sz = scaled_point_sz(fg); if (!force && self->scaled_point_sz == sz) return true; @@ -282,7 +282,7 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u } PyObject* -face_from_descriptor(PyObject *descriptor, FONT_DATA_HANDLE fg) { +face_from_descriptor(PyObject *descriptor, FONTS_DATA_HANDLE fg) { CTFontDescriptorRef desc = font_descriptor_from_python(descriptor); if (!desc) return NULL; CTFontRef font = CTFontCreateWithFontDescriptor(desc, scaled_point_sz(fg), NULL); @@ -292,7 +292,7 @@ face_from_descriptor(PyObject *descriptor, FONT_DATA_HANDLE fg) { } PyObject* -face_from_path(const char *path, int UNUSED index, FONT_DATA_HANDLE fg UNUSED) { +face_from_path(const char *path, int UNUSED index, FONTS_DATA_HANDLE fg UNUSED) { CFStringRef s = CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8); CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, s, kCFURLPOSIXPathStyle, false); CGDataProviderRef dp = CGDataProviderCreateWithURL(url); @@ -371,7 +371,7 @@ render_glyphs(CTFontRef font, unsigned int width, unsigned int height, unsigned } static inline bool -do_render(CTFontRef ct_font, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *hb_positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, bool allow_resize, FONT_DATA_HANDLE fg) { +do_render(CTFontRef ct_font, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *hb_positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, bool allow_resize, FONTS_DATA_HANDLE fg) { unsigned int canvas_width = cell_width * num_cells; CGRect br = CTFontGetBoundingRectsForGlyphs(ct_font, kCTFontOrientationHorizontal, glyphs, boxes, num_glyphs); if (allow_resize) { @@ -408,7 +408,7 @@ do_render(CTFontRef ct_font, bool bold, bool italic, hb_glyph_info_t *info, hb_g } bool -render_glyphs_in_cells(PyObject *s, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *hb_positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, FONT_DATA_HANDLE fg) { +render_glyphs_in_cells(PyObject *s, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *hb_positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored, FONTS_DATA_HANDLE fg) { CTFace *self = (CTFace*)s; for (unsigned i=0; i < num_glyphs; i++) glyphs[i] = info[i].codepoint; return do_render(self->ct_font, bold, italic, info, hb_positions, num_glyphs, canvas, cell_width, cell_height, num_cells, baseline, was_colored, true, fg); diff --git a/kitty/fonts.c b/kitty/fonts.c index bbe9fb73c..88efbb030 100644 --- a/kitty/fonts.c +++ b/kitty/fonts.c @@ -60,19 +60,13 @@ static hb_buffer_t *harfbuzz_buffer = NULL; static char_type shape_buffer[4096] = {0}; static size_t max_texture_size = 1024, max_array_len = 1024; -typedef struct { - PyObject *face; - bool bold, italic; -} Descriptor; - typedef struct { char_type left, right; size_t font_idx; } SymbolMap; -static Descriptor *descriptors = NULL; -static size_t num_symbol_fonts = 0; static SymbolMap *symbol_maps = NULL; +static size_t num_symbol_maps = 0; @@ -99,6 +93,7 @@ static FontGroup* font_groups = NULL; static size_t font_groups_capacity = 0; static size_t num_font_groups = 0; static id_type font_group_id_counter = 0; +static void initialize_font_group(FontGroup *fg); static inline void save_window_font_groups() { @@ -151,7 +146,7 @@ add_font_group() { if (num_font_groups >= font_groups_capacity) { save_window_font_groups(); font_groups_capacity += 5; - font_groups = realloc(font_groups, sizeof(FontGroup) * num_font_groups); + font_groups = realloc(font_groups, sizeof(FontGroup) * font_groups_capacity); if (font_groups == NULL) fatal("Out of memory creating a new font group"); restore_window_font_groups(); } @@ -171,6 +166,7 @@ font_group_for(double font_sz_in_pts, double logical_dpi_x, double logical_dpi_y fg->logical_dpi_x = logical_dpi_x; fg->logical_dpi_y = logical_dpi_y; fg->id = ++font_group_id_counter; + initialize_font_group(fg); return fg; } @@ -349,11 +345,8 @@ desc_to_face(PyObject *desc, FONTS_DATA_HANDLE fg) { static inline bool -init_font(Font *f, PyObject *descriptor, bool bold, bool italic, bool is_face, bool emoji_presentation, FONTS_DATA_HANDLE fg) { - PyObject *face; - if (is_face) { face = descriptor; Py_INCREF(face); } - else { face = desc_to_face(descriptor, fg); if (face == NULL) return false; } - f->face = face; +init_font(Font *f, PyObject *face, bool bold, bool italic, bool emoji_presentation) { + f->face = face; Py_INCREF(f->face); f->bold = bold; f->italic = italic; f->emoji_presentation = emoji_presentation; return true; } @@ -384,7 +377,7 @@ free_font_groups() { static void python_send_to_gpu(FONTS_DATA_HANDLE fg, unsigned int x, unsigned int y, unsigned int z, pixel* buf) { - if (python_send_to_gpu_impl != NULL && python_send_to_gpu_impl != Py_None) { + if (python_send_to_gpu_impl) { if (!num_font_groups) fatal("Cannot call send to gpu with no font groups"); PyObject *ret = PyObject_CallFunction(python_send_to_gpu_impl, "IIIN", x, y, z, PyBytes_FromStringAndSize((const char*)buf, sizeof(pixel) * fg->cell_width * fg->cell_height)); if (ret == NULL) PyErr_Print(); @@ -415,6 +408,7 @@ calc_cell_metrics(FontGroup *fg) { } sprite_tracker_set_layout(&fg->sprite_tracker, cell_width, cell_height); fg->cell_width = cell_width; fg->cell_height = cell_height; + fg->baseline = baseline; fg->underline_position = underline_position; fg->underline_thickness = underline_thickness; free(fg->canvas); fg->canvas = calloc(CELLS_IN_CANVAS * fg->cell_width * fg->cell_height, sizeof(pixel)); if (!fg->canvas) fatal("Out of memory allocating canvas for font group"); @@ -473,7 +467,7 @@ load_fallback_font(FontGroup *fg, Cell *cell, bool bold, bool italic, bool emoji ensure_space_for(fg, fonts, Font, fg->fonts_count + 1, fonts_capacity, 5, true); ssize_t ans = fg->first_fallback_font_idx + fg->fallback_fonts_count; Font *af = &fg->fonts[ans]; - if (!init_font(af, face, bold, italic, true, emoji_presentation, (FONTS_DATA_HANDLE)fg)) fatal("Out of memory"); + if (!init_font(af, face, bold, italic, emoji_presentation)) fatal("Out of memory"); Py_DECREF(face); fg->fallback_fonts_count++; fg->fonts_count++; @@ -500,7 +494,7 @@ fallback_font(FontGroup *fg, Cell *cell) { static inline ssize_t in_symbol_maps(FontGroup *fg, char_type ch) { - for (size_t i = 0; i < num_symbol_fonts; i++) { + for (size_t i = 0; i < num_symbol_maps; i++) { if (symbol_maps[i].left <= ch && ch <= symbol_maps[i].right) return fg->first_symbol_font_idx + symbol_maps[i].font_idx; } return NO_FONT; @@ -567,7 +561,7 @@ START_ALLOW_CASE_RANGE END_ALLOW_CASE_RANGE } -static PyObject* box_drawing_function = NULL, *prerender_function = NULL; +static PyObject* box_drawing_function = NULL, *prerender_function = NULL, *descriptor_for_idx = NULL; void render_alpha_mask(uint8_t *alpha_mask, pixel* dest, Region *src_rect, Region *dest_rect, size_t src_stride, size_t dest_stride) { @@ -961,7 +955,7 @@ test_shape(PyObject UNUSED *self, PyObject *args) { PyList_Append(ans, Py_BuildValue("IIHN", group->num_cells, group->num_glyphs, first_glyph, eg)); idx++; } - if (face) { Py_CLEAR(face); free(font); } + if (face) { Py_CLEAR(face); free_maps(font); free(font); } return ans; } #undef G @@ -1030,48 +1024,31 @@ render_line(FONTS_DATA_HANDLE fg_, Line *line) { } static inline void -clear_descriptors() { - if (descriptors) { - Descriptor *d = descriptors; - while(d) { - Py_CLEAR(d->face); - d++; - } - free(descriptors); descriptors = NULL; - } - free(symbol_maps); symbol_maps = NULL; +clear_symbol_maps() { + if (symbol_maps) { free(symbol_maps); symbol_maps = NULL; num_symbol_maps = 0; } } +typedef struct { + unsigned int main, bold, italic, bi, num_symbol_fonts; +} DescriptorIndices; + +DescriptorIndices descriptor_indices = {0}; + static PyObject* set_font_data(PyObject UNUSED *m, PyObject *args) { - PyObject *sm, *smf, *medium, *bold = NULL, *italic = NULL, *bi = NULL; + PyObject *sm; + Py_CLEAR(box_drawing_function); Py_CLEAR(prerender_function); Py_CLEAR(descriptor_for_idx); + if (!PyArg_ParseTuple(args, "OOOIIIIO!d", + &box_drawing_function, &prerender_function, &descriptor_for_idx, + &descriptor_indices.bold, &descriptor_indices.italic, &descriptor_indices.bi, &descriptor_indices.num_symbol_fonts, + &PyTuple_Type, &sm, &global_state.font_sz_in_pts)) return NULL; + Py_INCREF(box_drawing_function); Py_INCREF(prerender_function); Py_INCREF(descriptor_for_idx); free_font_groups(); - Py_CLEAR(box_drawing_function); Py_CLEAR(prerender_function); - clear_descriptors(); - if (!PyArg_ParseTuple(args, "OOO!O!fO|OOO", &box_drawing_function, &prerender_function, &PyTuple_Type, &sm, &PyTuple_Type, &smf, &global_state.font_sz_in_pts, &medium, &bold, &italic, &bi)) return NULL; - Py_INCREF(box_drawing_function); Py_INCREF(prerender_function); - descriptors = calloc(5 + PyTuple_GET_SIZE(smf), sizeof(Descriptor)); - if (descriptors == NULL) return PyErr_NoMemory(); - symbol_maps = calloc(1 + PyTuple_GET_SIZE(sm), sizeof(SymbolMap)); + clear_symbol_maps(); + num_symbol_maps = PyTuple_GET_SIZE(sm); + symbol_maps = calloc(num_symbol_maps, sizeof(SymbolMap)); if (symbol_maps == NULL) return PyErr_NoMemory(); - size_t desc_idx = 0; -#define AF(name) { \ - if (name) { Py_INCREF(name); descriptors[desc_idx].face = name; descriptors[desc_idx].bold = desc_idx & 1; descriptors[desc_idx].italic = desc_idx & 2; } \ - desc_idx++; \ -} - AF(medium); AF(bold); AF(italic); AF(bi); -#undef AF - num_symbol_fonts = 0; - for (Py_ssize_t s = 0; s < PyTuple_GET_SIZE(smf); s++, desc_idx++) { - Descriptor *d = descriptors + desc_idx; - PyObject *face; - int bold, italic; - if (!PyArg_ParseTuple(PyTuple_GET_ITEM(smf, s), "Opp", &face, &bold, &italic)) return NULL; - Py_INCREF(face); - d->face = face; d->bold = bold != 0; d->italic = italic != 0; - num_symbol_fonts++; - } - for (Py_ssize_t s = 0; s < PyTuple_GET_SIZE(sm); s++) { + for (size_t s = 0; s < num_symbol_maps; s++) { unsigned int left, right, font_idx; SymbolMap *x = symbol_maps + s; if (!PyArg_ParseTuple(PyTuple_GET_ITEM(sm, s), "III", &left, &right, &font_idx)) return NULL; @@ -1104,33 +1081,39 @@ send_prerendered_sprites(FontGroup *fg) { Py_CLEAR(args); } +static inline size_t +initialize_font(FontGroup *fg, unsigned int desc_idx, const char *ftype) { + PyObject *d = PyObject_CallFunction(descriptor_for_idx, "I", desc_idx); + if (d == NULL) { PyErr_Print(); fatal("failed for %s font", ftype); } + bool bold = PyObject_IsTrue(PyTuple_GET_ITEM(d, 1)); + bool italic = PyObject_IsTrue(PyTuple_GET_ITEM(d, 2)); + PyObject *face = desc_to_face(PyTuple_GET_ITEM(d, 0), (FONTS_DATA_HANDLE)fg); + Py_CLEAR(d); + if (face == NULL) { PyErr_Print(); fatal("failed to convert descriptor to face for %s font", ftype); } + size_t idx = fg->fonts_count++; + bool ok = init_font(fg->fonts + idx, face, bold, italic, false); + Py_CLEAR(face); + if (!ok) { + if (PyErr_Occurred()) { PyErr_Print(); } + fatal("Failed to initialize %s font: %d", ftype, idx); + } + return idx; +} static void initialize_font_group(FontGroup *fg) { - if (!descriptors) fatal("Must call set_font_data() before initializing a font group"); - fg->fonts_capacity = 10 + num_symbol_fonts; + fg->fonts_capacity = 10 + descriptor_indices.num_symbol_fonts; fg->fonts = calloc(fg->fonts_capacity, sizeof(Font)); if (fg->fonts == NULL) fatal("Out of memory allocating fonts array"); fg->fonts_count = 1; // the 0 index font is the box font -#define I(ftype) { \ - size_t idx = fg->fonts_count; \ - if (!init_font(fg->fonts + fg->fonts_count++, d->face, d->bold, d->italic, false, false, (FONTS_DATA_HANDLE)fg)) { \ - if (PyErr_Occurred()) PyErr_Print(); \ - fatal("Failed to initialize %s font: %d", #ftype, idx); \ - }} -#define IF(idx, attr) { \ - Descriptor *d = descriptors + idx; \ - if (d->face) { \ - fg->attr##_font_idx = fg->fonts_count; I(basic); \ - } else fg->attr##_font_idx = -1; \ - IF(0, medium); IF(1, bold); IF(2, italic); IF(3, bi); \ -} -#undef IF +#define I(attr) if (descriptor_indices.attr) fg->attr##_font_idx = initialize_font(fg, descriptor_indices.attr, #attr); else fg->attr##_font_idx = -1; + fg->medium_font_idx = initialize_font(fg, 0, "medium"); + I(bold); I(italic); I(bi); +#undef I fg->first_symbol_font_idx = fg->fonts_count; fg->first_fallback_font_idx = fg->fonts_count; fg->fallback_fonts_count = 0; - for (size_t i = 0; i < num_symbol_fonts; i++) { - Descriptor *d = descriptors + i + 4; - I(symbol_mapped); + for (size_t i = 0; i < descriptor_indices.num_symbol_fonts; i++) { + initialize_font(fg, descriptor_indices.bi + 1 + i, "symbol_map"); fg->first_fallback_font_idx++; } #undef I @@ -1144,16 +1127,16 @@ void load_fonts_for_window(OSWindow *w) { w->fonts_data = NULL; FontGroup *fg = font_group_for(w->font_sz_in_pts, w->logical_dpi_x, w->logical_dpi_y); - if (!fg->cell_width) initialize_font_group(fg); w->fonts_data = (FONTS_DATA_HANDLE)fg; } static void finalize(void) { Py_CLEAR(python_send_to_gpu_impl); - clear_descriptors(); + clear_symbol_maps(); Py_CLEAR(box_drawing_function); Py_CLEAR(prerender_function); + Py_CLEAR(descriptor_for_idx); free_font_groups(); if (harfbuzz_buffer) hb_buffer_destroy(harfbuzz_buffer); free(group_state.groups); @@ -1184,9 +1167,11 @@ test_sprite_position_for(PyObject UNUSED *self, PyObject *args) { static PyObject* set_send_sprite_to_gpu(PyObject UNUSED *self, PyObject *func) { Py_CLEAR(python_send_to_gpu_impl); - python_send_to_gpu_impl = func; - Py_INCREF(func); - current_send_sprite_to_gpu = func == Py_None ? send_sprite_to_gpu : python_send_to_gpu; + if (func != Py_None) { + python_send_to_gpu_impl = func; + Py_INCREF(python_send_to_gpu_impl); + } + current_send_sprite_to_gpu = python_send_to_gpu_impl ? python_send_to_gpu : send_sprite_to_gpu; Py_RETURN_NONE; } @@ -1244,9 +1229,9 @@ current_fonts(PYNOARG) { FontGroup *fg = font_groups; #define SET(key, val) {if (PyDict_SetItemString(ans, #key, fg->fonts[val].face) != 0) { goto error; }} SET(medium, fg->medium_font_idx); - if (fg->bold_font_idx) SET(bold, fg->bold_font_idx); - if (fg->italic_font_idx) SET(italic, fg->italic_font_idx); - if (fg->bi_font_idx) SET(bi, fg->bi_font_idx); + if (fg->bold_font_idx > 0) SET(bold, fg->bold_font_idx); + if (fg->italic_font_idx > 0) SET(italic, fg->italic_font_idx); + if (fg->bi_font_idx > 0) SET(bi, fg->bi_font_idx); PyObject *ff = PyTuple_New(fg->fallback_fonts_count); if (!ff) goto error; for (size_t i = 0; i < fg->fallback_fonts_count; i++) { diff --git a/kitty/fonts/render.py b/kitty/fonts/render.py index 442cee4e1..4f449242c 100644 --- a/kitty/fonts/render.py +++ b/kitty/fonts/render.py @@ -21,31 +21,50 @@ if is_macos: else: from .fontconfig import get_font_files, font_for_family +current_faces = None + def create_symbol_map(opts): val = opts.symbol_map family_map = {} - faces = [] + count = 0 for family in val.values(): if family not in family_map: font, bold, italic = font_for_family(family) - family_map[family] = len(faces) - faces.append((font, bold, italic)) + family_map[family] = count + count += 1 + current_faces.append((font, bold, italic)) sm = tuple((a, b, family_map[f]) for (a, b), f in val.items()) - return sm, tuple(faces) + return sm + + +def descriptor_for_idx(idx): + return current_faces[idx] def set_font_family(opts=None, override_font_size=None): + global current_faces opts = opts or defaults sz = override_font_size or opts.font_size font_map = get_font_files(opts) - faces = [font_map['medium']] + current_faces = [(font_map['medium'], False, False)] + bold_idx = italic_idx = bi_idx = 0 for k in 'bold italic bi'.split(): if k in font_map: - faces.append(font_map[k]) - sm, sfonts = create_symbol_map(opts) + if k == 'bold': + bold_idx = len(current_faces) + elif k == 'italic': + italic_idx = len(current_faces) + elif k == 'bi': + bi_idx = len(current_faces) + current_faces.append((font_map[k], 'b' in k, 'i' in k)) + before = len(current_faces) + sm = create_symbol_map(opts) + num_symbol_fonts = len(current_faces) - before set_font_data( - render_box_drawing, prerender_function, sm, sfonts, sz, *faces + render_box_drawing, prerender_function, descriptor_for_idx, + bold_idx, italic_idx, bi_idx, num_symbol_fonts, + sm, sz ) @@ -141,36 +160,45 @@ def prerender_function(cell_width, cell_height, baseline, underline_position, un def render_box_drawing(codepoint, cell_width, cell_height, dpi): CharTexture = ctypes.c_ubyte * (cell_width * cell_height) buf = render_box_char( - chr(codepoint), CharTexture(), cell_width, dpi + chr(codepoint), CharTexture(), cell_width, cell_height, dpi ) return ctypes.addressof(buf), buf -def setup_for_testing(family='monospace', size=11.0, dpi=96.0, send_to_gpu=None): - from collections import OrderedDict - opts = defaults._replace(font_family=family, font_size=size) - set_options(opts) - sprites = OrderedDict() +class setup_for_testing: - def _send_to_gpu(x, y, z, data): - sprites[(x, y, z)] = data + def __init__(self, family='monospace', size=11.0, dpi=96.0): + self.family, self.size, self.dpi = family, size, dpi - sprite_map_set_limits(100000, 100) - set_send_sprite_to_gpu(send_to_gpu or _send_to_gpu) - set_font_family(opts) - cell_width, cell_height = create_test_font_group(size, dpi, dpi) - return sprites, cell_width, cell_height + def __enter__(self): + from collections import OrderedDict + opts = defaults._replace(font_family=self.family, font_size=self.size) + set_options(opts) + sprites = OrderedDict() + + def send_to_gpu(x, y, z, data): + sprites[(x, y, z)] = data + + sprite_map_set_limits(100000, 100) + set_send_sprite_to_gpu(send_to_gpu) + try: + set_font_family(opts) + cell_width, cell_height = create_test_font_group(self.size, self.dpi, self.dpi) + return sprites, cell_width, cell_height + except Exception: + set_send_sprite_to_gpu(None) + raise + + def __exit__(self, *args): + set_send_sprite_to_gpu(None) def render_string(text, family='monospace', size=11.0, dpi=96.0): - try: - sprites, cell_width, cell_height = setup_for_testing(family, size, dpi) + with setup_for_testing(family, size, dpi) as (sprites, cell_width, cell_height): s = Screen(None, 1, len(text)*2) line = s.line(0) s.draw(text) test_render_line(line) - finally: - set_send_sprite_to_gpu(None) cells = [] found_content = False for i in reversed(range(s.columns)): @@ -185,14 +213,11 @@ def render_string(text, family='monospace', size=11.0, dpi=96.0): def shape_string(text="abcd", family='monospace', size=11.0, dpi=96.0, path=None): - try: - sprites, cell_width, cell_height = setup_for_testing(family, size, dpi) + with setup_for_testing(family, size, dpi) as (sprites, cell_width, cell_height): s = Screen(None, 1, len(text)*2) line = s.line(0) s.draw(text) return test_shape(line, path) - finally: - set_send_sprite_to_gpu(None) def display_bitmap(rgb_data, width, height): @@ -225,14 +250,14 @@ def test_render_string(text='Hello, world!', family='monospace', size=64.0, dpi= def test_fallback_font(qtext=None, bold=False, italic=False): - setup_for_testing() - trials = (qtext,) if qtext else ('你', 'He\u0347\u0305', '\U0001F929') - for text in trials: - f = get_fallback_font(text, bold, italic) - try: - print(text, f) - except UnicodeEncodeError: - sys.stdout.buffer.write((text + ' %s\n' % f).encode('utf-8')) + with setup_for_testing(): + trials = (qtext,) if qtext else ('你', 'He\u0347\u0305', '\U0001F929') + for text in trials: + f = get_fallback_font(text, bold, italic) + try: + print(text, f) + except UnicodeEncodeError: + sys.stdout.buffer.write((text + ' %s\n' % f).encode('utf-8')) def showcase(): diff --git a/kitty/shaders.c b/kitty/shaders.c index f0c53b598..d15d4c1c3 100644 --- a/kitty/shaders.c +++ b/kitty/shaders.c @@ -30,17 +30,17 @@ alloc_sprite_map(unsigned int cell_width, unsigned int cell_height) { #ifdef __APPLE__ // Since on Apple we could have multiple GPUs, with different capabilities, // upper bound the values according to the data from http://developer.apple.com/graphicsimaging/opengl/capabilities/ - max_texture_size = MIN(8192, sprite_map.max_texture_size); - max_array_texture_layers = MIN(512, sprite_map.max_array_texture_layers); + max_texture_size = MIN(8192, max_texture_size); + max_array_texture_layers = MIN(512, max_array_texture_layers); #endif sprite_tracker_set_limits(max_texture_size, max_array_texture_layers); } SpriteMap *ans = calloc(1, sizeof(SpriteMap)); - ans->cell_width = cell_width; ans->cell_height = cell_height; if (ans) { *ans = NEW_SPRITE_MAP; ans->max_texture_size = max_texture_size; ans->max_array_texture_layers = max_array_texture_layers; + ans->cell_width = cell_width; ans->cell_height = cell_height; } return (SPRITE_MAP_HANDLE)ans; } diff --git a/kitty_tests/fonts.py b/kitty_tests/fonts.py index ac14ef63f..7eca56443 100644 --- a/kitty_tests/fonts.py +++ b/kitty_tests/fonts.py @@ -4,8 +4,8 @@ from kitty.constants import is_macos from kitty.fast_data_types import ( - DECAWM, set_send_sprite_to_gpu, sprite_map_set_layout, - sprite_map_set_limits, test_render_line, test_sprite_position_for, wcwidth + DECAWM, sprite_map_set_layout, sprite_map_set_limits, test_render_line, + test_sprite_position_for, wcwidth ) from kitty.fonts.box_drawing import box_chars from kitty.fonts.render import render_string, setup_for_testing, shape_string @@ -16,12 +16,19 @@ from . import BaseTest class Rendering(BaseTest): def setUp(self): - self.sprites, self.cell_width, self.cell_height = setup_for_testing() - self.assertEqual([k[0] for k in self.sprites], [0, 1, 2, 3, 4, 5]) + self.test_ctx = setup_for_testing() + self.test_ctx.__enter__() + self.sprites, self.cell_width, self.cell_height = self.test_ctx.__enter__() + try: + self.assertEqual([k[0] for k in self.sprites], [0, 1, 2, 3, 4, 5]) + except Exception: + self.test_ctx.__exit__() + del self.test_ctx + raise def tearDown(self): - set_send_sprite_to_gpu(None) - del self.sprites, self.cell_width, self.cell_height + self.test_ctx.__exit__() + del self.sprites, self.cell_width, self.cell_height, self.test_ctx def test_sprite_map(self): sprite_map_set_limits(10, 2)