diff --git a/kitty/fontconfig.c b/kitty/fontconfig.c index 7bfacf1ac..e931d3d46 100644 --- a/kitty/fontconfig.c +++ b/kitty/fontconfig.c @@ -10,6 +10,7 @@ #include "fonts.h" #include #include "emoji.h" +#include "freetype_render_ui_text.h" #ifndef FC_COLOR #define FC_COLOR "color" #endif @@ -168,28 +169,36 @@ end: if (charset != NULL) FcCharSetDestroy(charset); } -const char* -file_path_for_font(const char *family, bool bold, bool italic) { - const char *ans = NULL; +bool +information_for_font_family(const char *family, bool bold, bool italic, FontConfigFace *ans) { + memset(ans, 0, sizeof(FontConfigFace)); FcPattern *match = NULL; FcPattern *pat = FcPatternCreate(); - if (pat == NULL) { PyErr_NoMemory(); return NULL; } + bool ok = false; + if (pat == NULL) { PyErr_NoMemory(); return ok; } if (family && strlen(family) > 0) AP(FcPatternAddString, FC_FAMILY, (const FcChar8*)family, "family"); if (bold) { AP(FcPatternAddInteger, FC_WEIGHT, FC_WEIGHT_BOLD, "weight"); } if (italic) { AP(FcPatternAddInteger, FC_SLANT, FC_SLANT_ITALIC, "slant"); } FcResult result; FcConfigSubstitute(NULL, pat, FcMatchPattern); FcDefaultSubstitute(pat); + /* printf("fc_match = %s\n", FcNameUnparse(pat)); */ match = FcFontMatch(NULL, pat, &result); if (match == NULL) { PyErr_SetString(PyExc_KeyError, "FcFontMatch() failed"); goto end; } FcChar8 *out; - if (FcPatternGetString(pat, FC_FILE, 0, &out) != FcResultMatch) { PyErr_SetString(PyExc_ValueError, "No path found in fontconfig result"); goto end; } - ans = strdup((char*)out); - if (!ans) { PyErr_NoMemory(); goto end; } +#define g(func, prop, output) if (func(match, prop, 0, &output) != FcResultMatch) { PyErr_SetString(PyExc_ValueError, "No " #prop " found in fontconfig match result"); goto end; } + g(FcPatternGetString, FC_FILE, out); + g(FcPatternGetInteger, FC_INDEX, ans->index); + g(FcPatternGetInteger, FC_HINT_STYLE, ans->hintstyle); + g(FcPatternGetBool, FC_HINTING, ans->hinting); +#undef g + ans->path = strdup((char*)out); + if (!ans->path) { PyErr_NoMemory(); goto end; } + ok = true; end: if (match != NULL) FcPatternDestroy(match); if (pat != NULL) FcPatternDestroy(pat); - return ans; + return ok; } diff --git a/kitty/fonts.h b/kitty/fonts.h index a4524670e..7a9cb6f21 100644 --- a/kitty/fonts.h +++ b/kitty/fonts.h @@ -50,8 +50,3 @@ right_shift_canvas(pixel *canvas, size_t width, size_t height, size_t amt) { zero_at_ptr_count(src, amt); } } - - -#ifndef __APPLE__ -const char* file_path_for_font(const char *family, bool bold, bool italic); -#endif diff --git a/kitty/freetype.c b/kitty/freetype.c index 6ff33e66b..df214847f 100644 --- a/kitty/freetype.c +++ b/kitty/freetype.c @@ -252,6 +252,15 @@ face_from_descriptor(PyObject *descriptor, FONTS_DATA_HANDLE fg) { return (PyObject*)self; } +FT_Face +native_face_from_path(const char *path, int index) { + int error; + FT_Face ans; + error = FT_New_Face(library, path, index, &ans); + if (error) { set_freetype_error("Failed to load face, with error:", error); return NULL; } + return ans; +} + PyObject* face_from_path(const char *path, int index, FONTS_DATA_HANDLE fg) { Face *ans = (Face*)Face_Type.tp_alloc(&Face_Type, 0); diff --git a/kitty/freetype_render_ui_text.c b/kitty/freetype_render_ui_text.c index d2599290d..d1565b31a 100644 --- a/kitty/freetype_render_ui_text.c +++ b/kitty/freetype_render_ui_text.c @@ -5,16 +5,54 @@ * Distributed under terms of the GPL3 license. */ -#include "data-types.h" -#include "fonts.h" +#include "freetype_render_ui_text.h" +#include +#include + +typedef struct FamilyInformation { + char *name; + bool bold, italic; +} FamilyInformation; + +FT_Face main_face = NULL; +FontConfigFace main_face_information = {0}; +FamilyInformation main_face_family = {0}; + + +static void +cleanup(void) { + if (main_face) FT_Done_Face(main_face); + main_face = NULL; + free(main_face_information.path); main_face_information.path = NULL; + free(main_face_family.name); + memset(&main_face_family, 0, sizeof(FamilyInformation)); +} + +void +set_main_face_family(const char *family, bool bold, bool italic) { + cleanup(); + main_face_family.name = strdup(family); + main_face_family.bold = bold; main_face_family.italic = italic; +} + +static bool +ensure_state(void) { + if (main_face) return false; + if (!information_for_font_family(main_face_family.name, main_face_family.bold, main_face_family.italic, &main_face_information)) return false; + main_face = native_face_from_path(main_face_information.path, main_face_information.index); + return !!main_face; +} static PyObject* path_for_font(PyObject *self UNUSED, PyObject *args) { + (void)ensure_state; const char *family = NULL; int bold = 0, italic = 0; if (!PyArg_ParseTuple(args, "|zpp", &family, &bold, &italic)) return NULL; - const char *ans = file_path_for_font(family, bold, italic); - if (!ans) return NULL; - return PyUnicode_FromString(ans); + FontConfigFace f; + if (!information_for_font_family(family, bold, italic, &f)) return NULL; + PyObject *ret = Py_BuildValue("{ss si si si}", "path", f.path, "index", f.index, "hinting", f.hinting, "hintstyle", f.hintstyle); + free(f.path); + return ret; } static PyMethodDef module_methods[] = { @@ -27,5 +65,9 @@ static PyMethodDef module_methods[] = { bool init_freetype_render_ui_text(PyObject *module) { if (PyModule_AddFunctions(module, module_methods) != 0) return false; + if (Py_AtExit(cleanup) != 0) { + PyErr_SetString(PyExc_RuntimeError, "Failed to register the fontconfig library at exit handler"); + return false; + } return true; } diff --git a/kitty/freetype_render_ui_text.h b/kitty/freetype_render_ui_text.h new file mode 100644 index 000000000..c8277a29a --- /dev/null +++ b/kitty/freetype_render_ui_text.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2021 Kovid Goyal + * + * Distributed under terms of the GPL3 license. + */ + +#pragma once + +#include "data-types.h" +#include + +typedef struct FontConfigFace { + char *path; + int index; + int hinting; + int hintstyle; +} FontConfigFace; + +bool information_for_font_family(const char *family, bool bold, bool italic, FontConfigFace *ans); +FT_Face native_face_from_path(const char *path, int index); + + +void set_main_face_family(const char *family, bool bold, bool italic);