diff --git a/kitty/core_text.m b/kitty/core_text.m index 3e4297616..ad3cd96e9 100644 --- a/kitty/core_text.m +++ b/kitty/core_text.m @@ -939,6 +939,12 @@ get_best_name(CTFace *self, PyObject *nameid) { return get_best_name_from_name_table(self->name_lookup_table, nameid); } +static PyObject* +get_variation(CTFace *self) { + RAII_CoreFoundation(CFDictionaryRef, src, CTFontCopyVariation(self->ct_font)); + return variation_to_python(src); +} + static PyObject* get_variable_data(CTFace *self) { if (!ensure_name_table(self)) return NULL; @@ -982,6 +988,7 @@ static PyMethodDef methods[] = { METHODB(display_name, METH_NOARGS), METHODB(postscript_name, METH_NOARGS), METHODB(get_variable_data, METH_NOARGS), + METHODB(get_variation, METH_NOARGS), METHODB(identify_for_debug, METH_NOARGS), METHODB(set_size, METH_VARARGS), METHODB(render_sample_text, METH_VARARGS), diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 5057bd9f8..352bc7eaa 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -429,6 +429,7 @@ class Face: def postscript_name(self) -> str: ... def set_size(self, sz_in_pts: float, dpi_x: float, dpi_y: float) -> None: ... def render_sample_text(self, text: str, width: int, height: int, fg_color: int = 0xffffff) -> bytes: ... + def get_variation(self) -> Optional[Dict[str, float]]: ... class CoreTextFont(TypedDict): @@ -461,6 +462,7 @@ class CTFace: def postscript_name(self) -> str: ... def set_size(self, sz_in_pts: float, dpi_x: float, dpi_y: float) -> None: ... def render_sample_text(self, text: str, width: int, height: int, fg_color: int = 0xffffff) -> bytes: ... + def get_variation(self) -> Optional[Dict[str, float]]: ... def coretext_all_fonts(monospaced_only: bool) -> Tuple[CoreTextFont, ...]: diff --git a/kitty/fonts/common.py b/kitty/fonts/common.py index 6a3e0bc90..fcb949399 100644 --- a/kitty/fonts/common.py +++ b/kitty/fonts/common.py @@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, Sequence, Tuple, TypedDict, Union from kitty.constants import is_macos -from kitty.fonts import Descriptor, DesignAxis, FontSpec, Scorer, VariableData, family_name_to_key +from kitty.fonts import Descriptor, DesignAxis, FontSpec, NamedStyle, Scorer, VariableData, family_name_to_key from kitty.options.types import Options if TYPE_CHECKING: @@ -289,5 +289,16 @@ def develop(family: str = '') -> None: print('Bold-Italic:', s(ff['bi'])) +def get_named_style(face: Face) -> Optional[NamedStyle]: + axis_map = face.get_variation() + if axis_map is None: + return None + vd = face.get_variable_data() + for ns in vd['named_styles']: + if ns['axis_values'] == axis_map: + return ns + return None + + if __name__ == '__main__': develop() diff --git a/kitty/freetype.c b/kitty/freetype.c index 0136f5471..4e08bb76e 100644 --- a/kitty/freetype.c +++ b/kitty/freetype.c @@ -820,6 +820,28 @@ convert_axis_to_python(Face *face, const FT_Var_Axis *src, FT_UInt flags) { ); } +static PyObject* +get_variation(Face *self, PyObject *a UNUSED) { + RAII_FTMMVar(mm); + FT_Error err; + if ((err = FT_Get_MM_Var(self->face, &mm))) { Py_RETURN_NONE; } + RAII_ALLOC(FT_Fixed, coords, malloc(mm->num_axis * sizeof(FT_Fixed))); + if (!coords) return PyErr_NoMemory(); + if ((err = FT_Get_Var_Design_Coordinates(self->face, mm->num_axis, coords))) { + set_freetype_error("Failed to load the variation data from font with error:", err); return NULL; + } + RAII_PyObject(ans, PyDict_New()); if (!ans) return NULL; + uint8_t tag[5]; + for (FT_UInt i = 0; i < mm->num_axis; i++) { + double val = coords[i] / 65536.0; + tag_to_string(mm->axis[i].tag, tag); + RAII_PyObject(pval, PyFloat_FromDouble(val)); + if (!pval) return NULL; + if (PyDict_SetItemString(ans, (const char*)tag, pval) != 0) return NULL; + } + Py_INCREF(ans); return ans; +} + static PyObject* get_variable_data(Face *self, PyObject *a UNUSED) { if (!ensure_name_table(self)) return NULL; @@ -969,6 +991,7 @@ static PyMethodDef methods[] = { METHODB(identify_for_debug, METH_NOARGS), METHODB(extra_data, METH_NOARGS), METHODB(get_variable_data, METH_NOARGS), + METHODB(get_variation, METH_NOARGS), METHODB(get_best_name, METH_O), METHODB(set_size, METH_VARARGS), METHODB(render_sample_text, METH_VARARGS),