mirror of
https://github.com/kovidgoyal/kitty.git
synced 2024-09-21 19:47:21 +03:00
Support infinite length ligatures
This commit is contained in:
parent
8e36056dd8
commit
33287115de
@ -7,6 +7,8 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
|
|||||||
0.20.4 [future]
|
0.20.4 [future]
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
- Support infinite length ligatures
|
||||||
|
|
||||||
- Unicode input kitten: Fix a regression in 0.20.0 that broke keyboard handling
|
- Unicode input kitten: Fix a regression in 0.20.0 that broke keyboard handling
|
||||||
when the num lock or caps lock modifiers were engaged. (:iss:`3587`)
|
when the num lock or caps lock modifiers were engaged. (:iss:`3587`)
|
||||||
|
|
||||||
|
@ -97,6 +97,7 @@ ensure_canvas_can_fit(FontGroup *fg, unsigned cells) {
|
|||||||
if (!fg->canvas.buf) fatal("Out of memory allocating canvas");
|
if (!fg->canvas.buf) fatal("Out of memory allocating canvas");
|
||||||
}
|
}
|
||||||
fg->canvas.current_cells = cells;
|
fg->canvas.current_cells = cells;
|
||||||
|
if (fg->canvas.buf) memset(fg->canvas.buf, 0, sizeof(fg->canvas.buf[0]) * fg->canvas.current_cells * 3u * fg->cell_width * fg->cell_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -200,11 +201,6 @@ font_group_for(double font_sz_in_pts, double logical_dpi_x, double logical_dpi_y
|
|||||||
return fg;
|
return fg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
|
||||||
clear_canvas(FontGroup *fg) {
|
|
||||||
if (fg->canvas.buf) memset(fg->canvas.buf, 0, sizeof(fg->canvas.buf[0]) * fg->canvas.current_cells * 3u * fg->cell_width * fg->cell_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Sprites {{{
|
// Sprites {{{
|
||||||
@ -594,7 +590,6 @@ render_box_cell(FontGroup *fg, CPUCell *cpu_cell, GPUCell *gpu_cell) {
|
|||||||
if (ret == NULL) { PyErr_Print(); return; }
|
if (ret == NULL) { PyErr_Print(); return; }
|
||||||
uint8_t *alpha_mask = PyLong_AsVoidPtr(PyTuple_GET_ITEM(ret, 0));
|
uint8_t *alpha_mask = PyLong_AsVoidPtr(PyTuple_GET_ITEM(ret, 0));
|
||||||
ensure_canvas_can_fit(fg, 1);
|
ensure_canvas_can_fit(fg, 1);
|
||||||
clear_canvas(fg);
|
|
||||||
Region r = { .right = fg->cell_width, .bottom = fg->cell_height };
|
Region r = { .right = fg->cell_width, .bottom = fg->cell_height };
|
||||||
render_alpha_mask(alpha_mask, fg->canvas.buf, &r, &r, fg->cell_width, fg->cell_width);
|
render_alpha_mask(alpha_mask, fg->canvas.buf, &r, &r, fg->cell_width, fg->cell_width);
|
||||||
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, sp->x, sp->y, sp->z, fg->canvas.buf);
|
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, sp->x, sp->y, sp->z, fg->canvas.buf);
|
||||||
@ -656,9 +651,8 @@ render_group(FontGroup *fg, unsigned int num_cells, unsigned int num_glyphs, CPU
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_canvas(fg);
|
|
||||||
bool was_colored = (gpu_cells->attrs & WIDTH_MASK) == 2 && is_emoji(cpu_cells->ch);
|
|
||||||
ensure_canvas_can_fit(fg, num_cells + 1);
|
ensure_canvas_can_fit(fg, num_cells + 1);
|
||||||
|
bool was_colored = (gpu_cells->attrs & WIDTH_MASK) == 2 && is_emoji(cpu_cells->ch);
|
||||||
render_glyphs_in_cells(font->face, font->bold, font->italic, info, positions, num_glyphs, fg->canvas.buf, fg->cell_width, fg->cell_height, num_cells, fg->baseline, &was_colored, (FONTS_DATA_HANDLE)fg, center_glyph);
|
render_glyphs_in_cells(font->face, font->bold, font->italic, info, positions, num_glyphs, fg->canvas.buf, fg->cell_width, fg->cell_height, num_cells, fg->baseline, &was_colored, (FONTS_DATA_HANDLE)fg, center_glyph);
|
||||||
if (PyErr_Occurred()) PyErr_Print();
|
if (PyErr_Occurred()) PyErr_Print();
|
||||||
|
|
||||||
@ -861,7 +855,6 @@ shape_run(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells
|
|||||||
bool add_to_current_group;
|
bool add_to_current_group;
|
||||||
char glyph_name[128]; glyph_name[arraysz(glyph_name)-1] = 0;
|
char glyph_name[128]; glyph_name[arraysz(glyph_name)-1] = 0;
|
||||||
bool prev_glyph_was_inifinte_ligature_end = false;
|
bool prev_glyph_was_inifinte_ligature_end = false;
|
||||||
#define MAX_GLYPHS_IN_GROUP (8u + 1u)
|
|
||||||
while (G(glyph_idx) < G(num_glyphs) && G(cell_idx) < G(num_cells)) {
|
while (G(glyph_idx) < G(num_glyphs) && G(cell_idx) < G(num_cells)) {
|
||||||
glyph_index glyph_id = G(info)[G(glyph_idx)].codepoint;
|
glyph_index glyph_id = G(info)[G(glyph_idx)].codepoint;
|
||||||
hb_font_glyph_to_string(hbf, glyph_id, glyph_name, arraysz(glyph_name)-1);
|
hb_font_glyph_to_string(hbf, glyph_id, glyph_name, arraysz(glyph_name)-1);
|
||||||
@ -904,7 +897,6 @@ shape_run(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells
|
|||||||
ch, G(glyph_idx), glyph_id, glyph_name, G(group_idx), cluster, next_cluster, is_special,
|
ch, G(glyph_idx), glyph_id, glyph_name, G(group_idx), cluster, next_cluster, is_special,
|
||||||
num_codepoints_used_by_glyph, current_group->num_cells, current_group->num_glyphs, add_to_current_group);
|
num_codepoints_used_by_glyph, current_group->num_cells, current_group->num_glyphs, add_to_current_group);
|
||||||
}
|
}
|
||||||
if (current_group->num_glyphs >= MAX_GLYPHS_IN_GROUP || current_group->num_cells >= MAX_GLYPHS_IN_GROUP) add_to_current_group = false;
|
|
||||||
|
|
||||||
if (!add_to_current_group) { current_group = G(groups) + ++G(group_idx); }
|
if (!add_to_current_group) { current_group = G(groups) + ++G(group_idx); }
|
||||||
if (!current_group->num_glyphs++) {
|
if (!current_group->num_glyphs++) {
|
||||||
@ -924,13 +916,11 @@ shape_run(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells
|
|||||||
// soak up all remaining cells
|
// soak up all remaining cells
|
||||||
if (G(cell_idx) < G(num_cells)) {
|
if (G(cell_idx) < G(num_cells)) {
|
||||||
unsigned int num_left = G(num_cells) - G(cell_idx);
|
unsigned int num_left = G(num_cells) - G(cell_idx);
|
||||||
if (current_group->num_cells + num_left > MAX_GLYPHS_IN_GROUP) MOVE_GLYPH_TO_NEXT_GROUP(G(cell_idx));
|
|
||||||
current_group->num_cells += num_left;
|
current_group->num_cells += num_left;
|
||||||
if (current_group->num_cells > MAX_GLYPHS_IN_GROUP) current_group->num_cells = MAX_GLYPHS_IN_GROUP; // leave any trailing cells empty
|
|
||||||
G(cell_idx) += num_left;
|
G(cell_idx) += num_left;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsigned int num_cells_consumed = 0, start_cell_idx = G(cell_idx);
|
unsigned int num_cells_consumed = 0;
|
||||||
while (num_codepoints_used_by_glyph && G(cell_idx) < G(num_cells)) {
|
while (num_codepoints_used_by_glyph && G(cell_idx) < G(num_cells)) {
|
||||||
unsigned int w = check_cell_consumed(&G(current_cell_data), G(last_cpu_cell));
|
unsigned int w = check_cell_consumed(&G(current_cell_data), G(last_cpu_cell));
|
||||||
G(cell_idx) += w;
|
G(cell_idx) += w;
|
||||||
@ -938,24 +928,9 @@ shape_run(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells
|
|||||||
num_codepoints_used_by_glyph--;
|
num_codepoints_used_by_glyph--;
|
||||||
}
|
}
|
||||||
if (num_cells_consumed) {
|
if (num_cells_consumed) {
|
||||||
if (num_cells_consumed > MAX_GLYPHS_IN_GROUP) {
|
current_group->num_cells += num_cells_consumed;
|
||||||
// Nasty, a single glyph used more than MAX_GLYPHS_IN_GROUP cells, we cannot render this case correctly
|
if (!is_special) { // not a ligature, end the group
|
||||||
log_error("The glyph: %u needs more than %u cells, cannot render it", glyph_id, MAX_GLYPHS_IN_GROUP);
|
G(group_idx)++; current_group = G(groups) + G(group_idx);
|
||||||
current_group->num_glyphs--;
|
|
||||||
while (num_cells_consumed) {
|
|
||||||
G(group_idx)++; current_group = G(groups) + G(group_idx);
|
|
||||||
current_group->num_glyphs = 1; current_group->first_glyph_idx = G(glyph_idx);
|
|
||||||
current_group->num_cells = MIN(num_cells_consumed, MAX_GLYPHS_IN_GROUP);
|
|
||||||
current_group->first_cell_idx = start_cell_idx;
|
|
||||||
start_cell_idx += current_group->num_cells;
|
|
||||||
num_cells_consumed -= current_group->num_cells;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (num_cells_consumed + current_group->num_cells > MAX_GLYPHS_IN_GROUP) MOVE_GLYPH_TO_NEXT_GROUP(start_cell_idx);
|
|
||||||
current_group->num_cells += num_cells_consumed;
|
|
||||||
if (!is_special) { // not a ligature, end the group
|
|
||||||
G(group_idx)++; current_group = G(groups) + G(group_idx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -974,14 +949,12 @@ merge_groups_for_pua_space_ligature(void) {
|
|||||||
Group *g = G(groups), *g1 = G(groups) + 1;
|
Group *g = G(groups), *g1 = G(groups) + 1;
|
||||||
g->num_cells += g1->num_cells;
|
g->num_cells += g1->num_cells;
|
||||||
g->num_glyphs += g1->num_glyphs;
|
g->num_glyphs += g1->num_glyphs;
|
||||||
g->num_glyphs = MIN(g->num_glyphs, MAX_GLYPHS_IN_GROUP);
|
|
||||||
G(group_idx)--;
|
G(group_idx)--;
|
||||||
}
|
}
|
||||||
G(groups)->is_space_ligature = true;
|
G(groups)->is_space_ligature = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef MOVE_GLYPH_TO_NEXT_GROUP
|
#undef MOVE_GLYPH_TO_NEXT_GROUP
|
||||||
#undef MAX_GLYPHS_IN_GROUP
|
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
is_group_calt_ligature(const Group *group) {
|
is_group_calt_ligature(const Group *group) {
|
||||||
@ -1236,7 +1209,6 @@ send_prerendered_sprites(FontGroup *fg) {
|
|||||||
sprite_index x = 0, y = 0, z = 0;
|
sprite_index x = 0, y = 0, z = 0;
|
||||||
// blank cell
|
// blank cell
|
||||||
ensure_canvas_can_fit(fg, 1);
|
ensure_canvas_can_fit(fg, 1);
|
||||||
clear_canvas(fg);
|
|
||||||
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, x, y, z, fg->canvas.buf);
|
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, x, y, z, fg->canvas.buf);
|
||||||
do_increment(fg, &error);
|
do_increment(fg, &error);
|
||||||
if (error != 0) { sprite_map_set_error(error); PyErr_Print(); fatal("Failed"); }
|
if (error != 0) { sprite_map_set_error(error); PyErr_Print(); fatal("Failed"); }
|
||||||
@ -1248,7 +1220,7 @@ send_prerendered_sprites(FontGroup *fg) {
|
|||||||
do_increment(fg, &error);
|
do_increment(fg, &error);
|
||||||
if (error != 0) { sprite_map_set_error(error); PyErr_Print(); fatal("Failed"); }
|
if (error != 0) { sprite_map_set_error(error); PyErr_Print(); fatal("Failed"); }
|
||||||
uint8_t *alpha_mask = PyLong_AsVoidPtr(PyTuple_GET_ITEM(args, i));
|
uint8_t *alpha_mask = PyLong_AsVoidPtr(PyTuple_GET_ITEM(args, i));
|
||||||
clear_canvas(fg);
|
ensure_canvas_can_fit(fg, 1); // clear canvas
|
||||||
Region r = { .right = fg->cell_width, .bottom = fg->cell_height };
|
Region r = { .right = fg->cell_width, .bottom = fg->cell_height };
|
||||||
render_alpha_mask(alpha_mask, fg->canvas.buf, &r, &r, fg->cell_width, fg->cell_width);
|
render_alpha_mask(alpha_mask, fg->canvas.buf, &r, &r, fg->cell_width, fg->cell_width);
|
||||||
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, x, y, z, fg->canvas.buf);
|
current_send_sprite_to_gpu((FONTS_DATA_HANDLE)fg, x, y, z, fg->canvas.buf);
|
||||||
|
@ -108,7 +108,7 @@ def groups(text, font=None):
|
|||||||
self.ae(g('===--<>=='), [(3, 3), (2, 2), (2, 2), (2, 2)])
|
self.ae(g('===--<>=='), [(3, 3), (2, 2), (2, 2), (2, 2)])
|
||||||
self.ae(g('==!=<>==<><><>'), [(4, 4), (2, 2), (2, 2), (2, 2), (2, 2), (2, 2)])
|
self.ae(g('==!=<>==<><><>'), [(4, 4), (2, 2), (2, 2), (2, 2), (2, 2), (2, 2)])
|
||||||
self.ae(g('A=>>B!=C'), [(1, 1), (3, 3), (1, 1), (2, 2), (1, 1)])
|
self.ae(g('A=>>B!=C'), [(1, 1), (3, 3), (1, 1), (2, 2), (1, 1)])
|
||||||
self.ae(g('-' * 18), [(9, 9), (9, 9)])
|
self.ae(g('-' * 18), [(18, 18)])
|
||||||
colon_glyph = ss('9:30', font='FiraCode-Medium.otf')[1][2]
|
colon_glyph = ss('9:30', font='FiraCode-Medium.otf')[1][2]
|
||||||
self.assertNotEqual(colon_glyph, ss(':', font='FiraCode-Medium.otf')[0][2])
|
self.assertNotEqual(colon_glyph, ss(':', font='FiraCode-Medium.otf')[0][2])
|
||||||
self.ae(colon_glyph, 1031)
|
self.ae(colon_glyph, 1031)
|
||||||
|
Loading…
Reference in New Issue
Block a user