From 226cc92b01784f9fb7583821f2e982232068599c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 29 Jun 2024 16:18:43 +0530 Subject: [PATCH] API to add font file to system font lookup --- kitty/core_text.m | 11 +++++++++++ kitty/fast_data_types.pyi | 4 ++++ kitty/fontconfig.c | 15 +++++++++++++++ kitty/fonts/render.py | 2 ++ 4 files changed, 32 insertions(+) diff --git a/kitty/core_text.m b/kitty/core_text.m index 88ec9bda3..471432018 100644 --- a/kitty/core_text.m +++ b/kitty/core_text.m @@ -1103,8 +1103,19 @@ repr(CTFace *self) { } +static PyObject* +coretext_add_font_file(PyObject UNUSED *_self, PyObject *args) { + const unsigned char *path = NULL; Py_ssize_t sz; + if (!PyArg_ParseTuple(args, "s#", &path, &sz)) return NULL; + RAII_CoreFoundation(CFURLRef, url, CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, path, sz, false)); + RAII_CoreFoundation(CFArrayRef, descriptors, CTFontManagerCreateFontDescriptorsFromURL(url)); + CTFontManagerEnableFontDescriptors(descriptors, true); + Py_RETURN_TRUE; +} + static PyMethodDef module_methods[] = { METHODB(coretext_all_fonts, METH_O), + METHODB(coretext_add_font_file, METH_VARARGS), {NULL, NULL, 0, NULL} /* Sentinel */ }; diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index a8c715f6f..5411d5c7a 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -425,6 +425,10 @@ def fc_match_postscript_name( pass +def fc_add_font_file(path: str) -> bool: ... +def coretext_add_font_file(path: str) -> bool: ... + + class FeatureData(TypedDict): name: NotRequired[str] tooltip: NotRequired[str] diff --git a/kitty/fontconfig.c b/kitty/fontconfig.c index bd82a5b44..7f75467d5 100644 --- a/kitty/fontconfig.c +++ b/kitty/fontconfig.c @@ -41,6 +41,7 @@ static void* libfontconfig_handle = NULL; #define FcPatternCreate dynamically_loaded_fc_symbol.PatternCreate #define FcPatternGetBool dynamically_loaded_fc_symbol.PatternGetBool #define FcPatternAddCharSet dynamically_loaded_fc_symbol.PatternAddCharSet +#define FcConfigAppFontAddFile dynamically_loaded_fc_symbol.ConfigAppFontAddFile static struct { FcBool(*Init)(void); @@ -65,6 +66,7 @@ static struct { FcPattern * (*PatternCreate) (void); FcResult (*PatternGetBool) (const FcPattern *p, const char *object, int n, FcBool *b); FcBool (*PatternAddCharSet) (FcPattern *p, const char *object, const FcCharSet *c); + FcBool (*ConfigAppFontAddFile) (FcConfig *config, const FcChar8 *file); } dynamically_loaded_fc_symbol = {0}; #define LOAD_FUNC(name) {\ *(void **) (&dynamically_loaded_fc_symbol.name) = dlsym(libfontconfig_handle, "Fc" #name); \ @@ -115,6 +117,7 @@ load_fontconfig_lib(void) { LOAD_FUNC(PatternCreate); LOAD_FUNC(PatternGetBool); LOAD_FUNC(PatternAddCharSet); + LOAD_FUNC(ConfigAppFontAddFile); } #undef LOAD_FUNC @@ -491,10 +494,22 @@ end: } #undef AP + +static PyObject* +fc_add_font_file(PyObject UNUSED *self, PyObject *args) { + ensure_initialized(); + const char *path = NULL; + if (!PyArg_ParseTuple(args, "s", &path)) return NULL; + if (FcConfigAppFontAddFile(NULL, (const unsigned char*)path)) Py_RETURN_TRUE; + Py_RETURN_FALSE; +} + + static PyMethodDef module_methods[] = { {"fc_list", (PyCFunction)(void (*) (void))(fc_list), METH_VARARGS | METH_KEYWORDS, NULL}, METHODB(fc_match, METH_VARARGS), METHODB(fc_match_postscript_name, METH_VARARGS), + METHODB(fc_add_font_file, METH_VARARGS), {NULL, NULL, 0, NULL} /* Sentinel */ }; diff --git a/kitty/fonts/render.py b/kitty/fonts/render.py index 2db1c3dcb..091480405 100644 --- a/kitty/fonts/render.py +++ b/kitty/fonts/render.py @@ -33,7 +33,9 @@ from .common import get_font_files if is_macos: from .core_text import font_for_family as font_for_family_macos + from kitty.fast_data_types import coretext_add_font_file as add_font_file else: + from kitty.fast_data_types import fc_add_font_file as add_font_file from .fontconfig import font_for_family as font_for_family_fontconfig FontObject = Union[CoreTextFont, FontConfigPattern]