Linux: Fix a regression in 0.36.0 that caused font features defined via fontconfig to be ignored

Fixes #7773
This commit is contained in:
Kovid Goyal 2024-08-24 17:17:37 +05:30
parent 2560a024b9
commit 611d8baf28
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
4 changed files with 40 additions and 13 deletions

View file

@ -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]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -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:

View file

@ -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;

View file

@ -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);