Clean up font features merge

This commit is contained in:
Kovid Goyal 2020-01-07 08:54:32 +05:30
parent db85e07d41
commit 14560b008a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 50 additions and 51 deletions

View File

@ -4,6 +4,13 @@ Changelog
|kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator.
To update |kitty|, :doc:`follow the instructions <binary>`.
0.15.12 [future]
--------------------
- Allow choosing OpenType features for individual fonts via the
:opt:`font_features` option.
0.15.1 [2019-12-21]
--------------------

View File

@ -411,16 +411,13 @@ def handle_symbol_map(key, val, ans):
@special_handler
def handle_font_feature_settings(key, val, ans):
parts = val.split(':', maxsplit=2)
if len(parts) != 2:
if parts[0] == "none":
return
def handle_font_features(key, val, ans):
if val != 'none':
parts = val.split()
if len(parts) < 2:
log_error("Ignoring invalid font_features {}".format(val))
else:
log_error("Ignoring invalid font_feature_settings for font {}".format(parts[0]))
else:
font, features = parts
ans['font_feature_settings'].update({font.strip(): features.strip().split()})
ans['font_features'][parts[0]] = parts[1:]
@special_handler
@ -508,7 +505,7 @@ def option_names_for_completion():
def parse_config(lines, check_keys=True, accumulate_bad_lines=None):
ans = {'symbol_map': {}, 'keymap': {}, 'sequence_map': {}, 'key_definitions': [], 'env': {}, 'kitten_aliases': {}, 'font_feature_settings': {}}
ans = {'symbol_map': {}, 'keymap': {}, 'sequence_map': {}, 'key_definitions': [], 'env': {}, 'kitten_aliases': {}, 'font_features': {}}
parse_config_base(
lines,
defaults,

View File

@ -277,23 +277,21 @@ or by defining shortcuts for it in kitty.conf, for example::
map alt+2 disable_ligatures_in all never
map alt+3 disable_ligatures_in tab cursor
Note: This function is equivalent to setting :code:`font_feature_settings` to
:code:`-liga -dlig -calt`.
'''))
o('font_feature_settings', 'none', long_text=_('''
o('font_features', 'none', long_text=_('''
Choose exactly which OpenType features to enable or disable. This is useful as
some fonts might have many features worthwhile in a terminalfor example, Fira
some fonts might have features worthwhile in a terminal. For example, Fira
Code Retina includes a discretionary feature, :code:`zero`, which in that font
changes the appearance of the zero (0), to make it more easily distinguishable
from Ø. Fira Code Retina also includes other discretionary features known as
Stylistic Sets which have the tags :code:`ss01` through :code:`ss20`.
Note that this code is indexed by PostScript name, and not TTF name or font
family; this allows you to define very precise feature settings; e.g. you can
Note that this code is indexed by PostScript name, and not the font
family. This allows you to define very precise feature settings; e.g. you can
disable a feature in the italic font but not in the regular font.
To get the PostScript name for a font, ask Fontconfig for it, using your family
To get the PostScript name for a font, ask Fontconfig for it, using the family
name::
$ fc-match "Fira Code" postscriptname
@ -305,16 +303,16 @@ name::
Enable alternate zero and oldstyle numerals::
font_feature_settings FiraCode-Retina: +zero +onum
font_features FiraCode-Retina +zero +onum
Enable only alternate zero::
font_feature_settings FiraCode-Retina: +zero
font_features FiraCode-Retina +zero
Disable the normal ligatures, but keep the :code:`calt` feature which (in this
font) breaks up monotony::
font_feature_settings TT2020StyleB-Regular: -liga +calt
font_features TT2020StyleB-Regular -liga +calt
'''))

View File

@ -76,9 +76,7 @@ typedef struct {
PyObject *face;
// Map glyphs to sprite map co-ords
SpritePosition sprite_map[1024];
hb_feature_t hb_features[8];
hb_feature_t* ffs_hb_features;
size_t num_hb_features;
size_t num_ffs_hb_features;
SpecialGlyphCache special_glyph_cache[SPECIAL_GLYPH_CACHE_SIZE];
bool bold, italic, emoji_presentation;
@ -349,45 +347,47 @@ desc_to_face(PyObject *desc, FONTS_DATA_HANDLE fg) {
return ans;
}
static inline void
copy_hb_feature(Font *f, HBFeature which) {
memcpy(f->hb_features + f->num_hb_features++, hb_features + which, sizeof(hb_features[0]));
}
static inline bool
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;
f->num_hb_features = 0;
f->num_ffs_hb_features = 0;
const char *psname = postscript_name_for_face(face);
copy_hb_feature(f, LIGA_FEATURE);
copy_hb_feature(f, DLIG_FEATURE);
copy_hb_feature(f, CALT_FEATURE);
if (font_feature_settings != NULL){
PyObject* o = PyDict_GetItemString(font_feature_settings, psname);
if (o != NULL) {
long len = PyList_Size(o);
if (len==0) return true;
f->num_ffs_hb_features = len + f->num_hb_features;
hb_feature_t* hb_feat = calloc(f->num_ffs_hb_features, sizeof(hb_feature_t));
for (long i = len-1; i >= 0; i--) {
PyObject* item = PyList_GetItem(o, i);
const char* feat = PyUnicode_AsUTF8(item);
hb_feature_from_string(feat, -1, &hb_feat[i]);
Py_ssize_t len = PySequence_Size(o);
if (len > 0) {
f->num_ffs_hb_features = len + 1;
f->ffs_hb_features = calloc(f->num_ffs_hb_features, sizeof(hb_feature_t));
if (!f->ffs_hb_features) return false;
for (Py_ssize_t i = 0; i < len; i++) {
PyObject* item = PySequence_GetItem(o, i);
if (!PyUnicode_Check(item)) fatal("A font feature is not a unicode string");
if (!hb_feature_from_string(PyUnicode_AsUTF8(item), -1, &f->ffs_hb_features[i])) {
fatal("Invalid font feature: %s", PyUnicode_AsUTF8(item));
}
}
memcpy(f->ffs_hb_features + len, &hb_features[CALT_FEATURE], sizeof(hb_feature_t));
}
for (size_t i = 0; i < f->num_hb_features; i++)
hb_feat[len+i] = hb_features[i];
f->ffs_hb_features = hb_feat;
}
}
if (!f->num_ffs_hb_features) {
f->ffs_hb_features = calloc(4, sizeof(hb_feature_t));
if (!f->ffs_hb_features) return false;
if (strstr(psname, "NimbusMonoPS-") == psname) {
memcpy(f->ffs_hb_features + f->num_ffs_hb_features++, &hb_features[LIGA_FEATURE], sizeof(hb_feature_t));
memcpy(f->ffs_hb_features + f->num_ffs_hb_features++, &hb_features[DLIG_FEATURE], sizeof(hb_feature_t));
}
memcpy(f->ffs_hb_features + f->num_ffs_hb_features++, &hb_features[CALT_FEATURE], sizeof(hb_feature_t));
}
return true;
}
static inline void
del_font(Font *f) {
Py_CLEAR(f->face);
if (f->num_ffs_hb_features > 0)
free(f->ffs_hb_features);
free(f->ffs_hb_features); f->ffs_hb_features = NULL;
free_maps(f);
f->bold = false; f->italic = false;
}
@ -795,10 +795,9 @@ shape(CPUCell *first_cpu_cell, GPUCell *first_gpu_cell, index_type num_cells, hb
group_state.last_gpu_cell = first_gpu_cell + (num_cells ? num_cells - 1 : 0);
load_hb_buffer(first_cpu_cell, first_gpu_cell, num_cells);
if (fobj->num_ffs_hb_features > 0)
hb_shape(font, harfbuzz_buffer, fobj->ffs_hb_features, fobj->num_ffs_hb_features - (disable_ligature ? 0 : fobj->num_hb_features));
else
hb_shape(font, harfbuzz_buffer, fobj->hb_features, fobj->num_hb_features - (disable_ligature ? 0 : fobj->num_hb_features));
size_t num_features = fobj->num_ffs_hb_features;
if (num_features && !disable_ligature) num_features--; // the last feature is always -calt
hb_shape(font, harfbuzz_buffer, fobj->ffs_hb_features, num_features);
unsigned int info_length, positions_length;
group_state.info = hb_buffer_get_glyph_infos(harfbuzz_buffer, &info_length);
@ -1049,8 +1048,6 @@ test_shape(PyObject UNUSED *self, PyObject *args) {
if (face == NULL) return NULL;
font = calloc(1, sizeof(Font));
font->face = face;
font->hb_features[0] = hb_features[CALT_FEATURE];
font->num_hb_features = 1;
} else {
FontGroup *fg = font_groups;
font = fg->fonts + fg->medium_font_idx;

View File

@ -103,7 +103,7 @@ def set_font_family(opts=None, override_font_size=None, debug_font_matching=Fals
set_font_data(
render_box_drawing, prerender_function, descriptor_for_idx,
indices['bold'], indices['italic'], indices['bi'], num_symbol_fonts,
sm, sz, opts['font_feature_settings']
sm, sz, opts.font_features
)