mirror of
https://github.com/kovidgoyal/kitty.git
synced 2025-12-13 20:36:22 +01:00
Fix rendering of ligatures in the latest release of Cascadia code
For some reason it puts empty glyphs after the ligature glyph rather than before it. There is a possibility this fix might break something else, we will see. Fixes #3313
This commit is contained in:
@@ -64,6 +64,10 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||
|
||||
- Fix OS window sizes under 100px resulting in scaled display (:iss:`3307`)
|
||||
|
||||
- Fix rendering of ligatures in the latest release of Cascadia code, which for
|
||||
some reason puts empty glyphs after the ligature glyph rather than before it
|
||||
(:iss:`3313`)
|
||||
|
||||
|
||||
0.19.3 [2020-12-19]
|
||||
-------------------
|
||||
|
||||
@@ -767,7 +767,7 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
unsigned int first_glyph_idx, first_cell_idx, num_glyphs, num_cells;
|
||||
bool has_special_glyph, is_space_ligature;
|
||||
bool has_special_glyph, is_space_ligature, started_with_empty_glyph;
|
||||
} Group;
|
||||
|
||||
typedef struct {
|
||||
@@ -905,6 +905,7 @@ shape_run(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells
|
||||
* Ligature fonts, take two common approaches:
|
||||
* 1. ABC becomes EMPTY, EMPTY, WIDE GLYPH this means we have to render N glyphs in N cells (example Fira Code)
|
||||
* 2. ABC becomes WIDE GLYPH this means we have to render one glyph in N cells (example Operator Mono Lig)
|
||||
* 3. ABC becomes WIDE GLYPH, EMPTY, EMPTY this means we have to render N glyphs in N cells (example Cascadia Code)
|
||||
*
|
||||
* We rely on the cluster numbers from harfbuzz to tell us how many unicode codepoints a glyph corresponds to.
|
||||
* Then we check if the glyph is a ligature glyph (is_special_glyph) and if it is an empty glyph. These three
|
||||
@@ -933,7 +934,8 @@ shape_run(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells
|
||||
add_to_current_group = true;
|
||||
} else {
|
||||
if (is_special) {
|
||||
add_to_current_group = G(prev_was_empty);
|
||||
if (current_group->started_with_empty_glyph) add_to_current_group = G(prev_was_empty);
|
||||
else add_to_current_group = is_empty;
|
||||
} else {
|
||||
add_to_current_group = !G(prev_was_special);
|
||||
}
|
||||
@@ -941,6 +943,7 @@ shape_run(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells
|
||||
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) { G(group_idx)++; current_group = G(groups) + G(group_idx); }
|
||||
if (is_empty && !current_group->num_glyphs) current_group->started_with_empty_glyph = true;
|
||||
if (!current_group->num_glyphs++) {
|
||||
current_group->first_glyph_idx = G(glyph_idx);
|
||||
current_group->first_cell_idx = G(cell_idx);
|
||||
|
||||
BIN
kitty_tests/CascadiaCode-Regular.otf
Normal file
BIN
kitty_tests/CascadiaCode-Regular.otf
Normal file
Binary file not shown.
@@ -4,6 +4,7 @@
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
from functools import partial
|
||||
|
||||
from kitty.constants import is_macos
|
||||
from kitty.fast_data_types import (
|
||||
@@ -71,19 +72,29 @@ class Rendering(BaseTest):
|
||||
|
||||
def test_shaping(self):
|
||||
|
||||
def groups(text, path=None):
|
||||
return [x[:2] for x in shape_string(text, path=path)]
|
||||
def ss(text, font=None):
|
||||
path = f'kitty_tests/{font}' if font else None
|
||||
return shape_string(text, path=path)
|
||||
|
||||
def groups(text, font=None):
|
||||
return [x[:2] for x in ss(text, font)]
|
||||
|
||||
self.ae(groups('abcd'), [(1, 1) for i in range(4)])
|
||||
self.ae(groups('A=>>B!=C', path='kitty_tests/FiraCode-Medium.otf'), [(1, 1), (3, 3), (1, 1), (2, 2), (1, 1)])
|
||||
self.ae(groups('F--a--', path='kitty_tests/FiraCode-Medium.otf'), [(1, 1), (2, 2), (1, 1), (2, 2)])
|
||||
self.ae(groups('==!=<>==<><><>', path='kitty_tests/FiraCode-Medium.otf'), [(2, 2), (2, 2), (2, 2), (2, 2), (2, 2), (2, 2), (2, 2)])
|
||||
colon_glyph = shape_string('9:30', path='kitty_tests/FiraCode-Medium.otf')[1][2]
|
||||
self.assertNotEqual(colon_glyph, shape_string(':', path='kitty_tests/FiraCode-Medium.otf')[0][2])
|
||||
self.ae(groups('A=>>B!=C', font='FiraCode-Medium.otf'), [(1, 1), (3, 3), (1, 1), (2, 2), (1, 1)])
|
||||
self.ae(groups('==!=<>==<><><>', font='FiraCode-Medium.otf'), [(2, 2), (2, 2), (2, 2), (2, 2), (2, 2), (2, 2), (2, 2)])
|
||||
|
||||
for font in ('FiraCode-Medium.otf', 'CascadiaCode-Regular.otf'):
|
||||
g = partial(groups, font=font)
|
||||
self.ae(g('A===B!=C'), [(1, 1), (3, 3), (1, 1), (2, 2), (1, 1)])
|
||||
self.ae(g('F--a--'), [(1, 1), (2, 2), (1, 1), (2, 2)])
|
||||
self.ae(g('===--<>=='), [(3, 3), (2, 2), (2, 2), (2, 2)])
|
||||
colon_glyph = ss('9:30', font='FiraCode-Medium.otf')[1][2]
|
||||
self.assertNotEqual(colon_glyph, ss(':', font='FiraCode-Medium.otf')[0][2])
|
||||
self.ae(colon_glyph, 998)
|
||||
self.ae(groups('9:30', path='kitty_tests/FiraCode-Medium.otf'), [(1, 1), (1, 1), (1, 1), (1, 1)])
|
||||
self.ae(groups('9:30', font='FiraCode-Medium.otf'), [(1, 1), (1, 1), (1, 1), (1, 1)])
|
||||
|
||||
self.ae(groups('|\U0001F601|\U0001F64f|\U0001F63a|'), [(1, 1), (2, 1), (1, 1), (2, 1), (1, 1), (2, 1), (1, 1)])
|
||||
self.ae(groups('He\u0347\u0305llo\u0337,', path='kitty_tests/LiberationMono-Regular.ttf'),
|
||||
self.ae(groups('He\u0347\u0305llo\u0337,', font='LiberationMono-Regular.ttf'),
|
||||
[(1, 1), (1, 3), (1, 1), (1, 1), (1, 2), (1, 1)])
|
||||
|
||||
def test_emoji_presentation(self):
|
||||
|
||||
Reference in New Issue
Block a user