diff --git a/docs/changelog.rst b/docs/changelog.rst index 0b8e63c0a..c6ef44fcd 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -74,6 +74,11 @@ consumption to do the same tasks. Detailed list of changes ------------------------------------- +0.36.1 [future] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- Linux: Fix a regression in 0.36.0 that caused font features defined via fontconfig to be ignored (:iss:`7773`) + 0.36.1 [2024-08-24] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/kitty/fontconfig.c b/kitty/fontconfig.c index ffc12cb1a..224cb5f43 100644 --- a/kitty/fontconfig.c +++ b/kitty/fontconfig.c @@ -419,6 +419,9 @@ specialize_font_descriptor(PyObject *base_descriptor, double font_sz_in_pts, dou FcPattern *pat = FcPatternCreate(); if (pat == NULL) return PyErr_NoMemory(); + RAII_PyObject(features, PyList_New(0)); + if (!features) return NULL; + RAII_PyObject(final_features, NULL); RAII_PyObject(ans, NULL); AP(FcPatternAddString, FC_FILE, (const FcChar8*)PyUnicode_AsUTF8(p), "path"); AP(FcPatternAddInteger, FC_INDEX, face_idx, "index"); @@ -445,10 +448,23 @@ specialize_font_descriptor(PyObject *base_descriptor, double font_sz_in_pts, dou if (axes) { if (PyDict_SetItemString(ans, "axes", axes) != 0) return NULL; } - PyObject *features = PyDict_GetItemString(base_descriptor, "features"); - if (features) { - if (PyDict_SetItemString(ans, "features", features) != 0) return NULL; + PyObject *ff = PyDict_GetItemString(ans, "fontfeatures"); + if (ff && PyList_GET_SIZE(ff)) { + for (Py_ssize_t i = 0; i < PyList_GET_SIZE(ff); i++) { + RAII_PyObject(pff, (PyObject*)parse_font_feature(PyUnicode_AsUTF8(PyList_GET_ITEM(ff, i)))); + if (pff == NULL) { + PyErr_Print(); fprintf(stderr, "\n"); + } else if (PyList_Append(features, pff) != 0) return NULL; + } } + PyObject *base_features = PyDict_GetItemString(base_descriptor, "features"); + final_features = PyTuple_New(PyList_GET_SIZE(features) + (base_features ? PyTuple_GET_SIZE(base_features) : 0)); + if (!final_features) return NULL; + for (Py_ssize_t i = 0; i < PyList_GET_SIZE(features); i++) { PyTuple_SET_ITEM(final_features, i, Py_NewRef(PyList_GET_ITEM(features, i))); } + if (base_features) { + for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(base_features); i++) { PyTuple_SET_ITEM(final_features, i + PyList_GET_SIZE(features), Py_NewRef(PyTuple_GET_ITEM(base_features, i))); } + } + if (PyDict_SetItemString(ans, "features", final_features) != 0) return NULL; Py_INCREF(ans); return ans; end: diff --git a/kitty/fonts.c b/kitty/fonts.c index e1d9e7bcf..889e1b58b 100644 --- a/kitty/fonts.c +++ b/kitty/fonts.c @@ -1740,18 +1740,25 @@ free_font_data(PyObject *self UNUSED, PyObject *args UNUSED) { Py_RETURN_NONE; } -static PyObject * -parsed_font_feature_new(PyTypeObject *type, PyObject *args, PyObject *kwds UNUSED) { - const char *s; - if (!PyArg_ParseTuple(args, "s", &s)) return NULL; - ParsedFontFeature *self = (ParsedFontFeature *)type->tp_alloc(type, 0); +PyTypeObject ParsedFontFeature_Type; + +ParsedFontFeature* +parse_font_feature(const char *spec) { + ParsedFontFeature *self = (ParsedFontFeature*)ParsedFontFeature_Type.tp_alloc(&ParsedFontFeature_Type, 0); if (self != NULL) { - if (!hb_feature_from_string(s, -1, &self->feature)) { - PyErr_Format(PyExc_ValueError, "%s is not a valid font feature", s); + if (!hb_feature_from_string(spec, -1, &self->feature)) { + PyErr_Format(PyExc_ValueError, "%s is not a valid font feature", self); Py_CLEAR(self); } } - return (PyObject*) self; + return self; +} + +static PyObject * +parsed_font_feature_new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds UNUSED) { + const char *s; + if (!PyArg_ParseTuple(args, "s", &s)) return NULL; + return (PyObject*)parse_font_feature(s); } static PyObject* @@ -1768,8 +1775,6 @@ parsed_font_feature_repr(PyObject *self_) { } -PyTypeObject ParsedFontFeature_Type; - static PyObject* parsed_font_feature_cmp(PyObject *self, PyObject *other, int op) { if (op != Py_EQ && op != Py_NE) return Py_NotImplemented; diff --git a/kitty/fonts.h b/kitty/fonts.h index 36674ee0d..dd89e4d54 100644 --- a/kitty/fonts.h +++ b/kitty/fonts.h @@ -31,6 +31,7 @@ typedef struct ParsedFontFeature { bool hash_computed; } ParsedFontFeature; +ParsedFontFeature* parse_font_feature(const char *spec); // API that font backends need to implement unsigned int glyph_id_for_codepoint(const PyObject *, char_type);