diff --git a/src_c/_freetype.c b/src_c/_freetype.c index 3ee6241e05..7953dbd6e4 100644 --- a/src_c/_freetype.c +++ b/src_c/_freetype.c @@ -30,9 +30,17 @@ #define MODULE_NAME "_freetype" #define FONT_TYPE_NAME "Font" +#define DEFAULT_FONT_NAME "freesans" +#define DEFAULT_FONT_FILE "freesansbold.ttf" +#define PKGDATA_MODULE_NAME "pygame.pkgdata" +#define RESOURCE_FUNC_NAME "getResource" + /* * FreeType module declarations */ + +PyObject *_freetypemodule = NULL; + static const Scale_t FACE_SIZE_NONE = {0, 0}; static int @@ -210,10 +218,6 @@ free_string(PGFT_String *); _var = PyObject_IsTrue(_pyobj); \ } -#define DEFAULT_FONT_NAME "freesansbold.ttf" -#define PKGDATA_MODULE_NAME "pygame.pkgdata" -#define RESOURCE_FUNC_NAME "getResource" - static unsigned int current_freetype_generation = 0; #define FreetypeFont_GenerationCheck(x) \ @@ -705,7 +709,11 @@ _ftfont_init(pgFontObject *self, PyObject *args, PyObject *kwds) SDL_RWops *source; FreeTypeInstance *ft; +#if defined(__EMSCRIPTEN__) + ft = FREETYPE_MOD_STATE(_freetypemodule)->freetype; +#else ASSERT_GRAB_FREETYPE(ft, -1); +#endif if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&lIi", kwlist, &file, obj_to_scale, (void *)&face_size, @@ -739,7 +747,7 @@ _ftfont_init(pgFontObject *self, PyObject *args, PyObject *kwds) self->resolution = FREETYPE_STATE->resolution; } if (file == Py_None) { - file = load_font_res(DEFAULT_FONT_NAME); + file = load_font_res(DEFAULT_FONT_FILE); if (!file) { PyErr_SetString(PyExc_RuntimeError, "Failed to find default font"); @@ -2219,6 +2227,14 @@ _ft_get_error(PyObject *self, PyObject *_null) Py_RETURN_NONE; } +#if defined(__EMSCRIPTEN__) +static PyObject * +_ft_get_version(PyObject *self, PyObject *args, PyObject *kwargs) +{ + return Py_BuildValue("iii", FREETYPE_MAJOR, FREETYPE_MINOR, + FREETYPE_PATCH); +} +#else static PyObject * _ft_get_version(PyObject *self, PyObject *args, PyObject *kwargs) { @@ -2265,6 +2281,7 @@ _ft_get_version(PyObject *self, PyObject *args, PyObject *kwargs) FREETYPE_PATCH); } } +#endif // defined(__EMSCRIPTEN__) static PyObject * _ft_get_cache_size(PyObject *self, PyObject *_null) @@ -2304,7 +2321,7 @@ _ft_get_init(PyObject *self, PyObject *_null) static PyObject * _ft_get_default_font(PyObject *self, PyObject *_null) { - return PyUnicode_FromString(DEFAULT_FONT_NAME); + return PyUnicode_FromString(DEFAULT_FONT_FILE); } static int @@ -2327,13 +2344,13 @@ _ft_clear(PyObject *mod) * FREETYPE MODULE DECLARATION ****************************************************/ #ifndef PYPY_VERSION -struct PyModuleDef _freetypemodule = { +struct PyModuleDef _freetypemoduledef = { PyModuleDef_HEAD_INIT, MODULE_NAME, DOC_FREETYPE, sizeof(_FreeTypeState), _ft_methods, 0, _ft_traverse, _ft_clear, 0}; #else /* PYPY_VERSION */ _FreeTypeState _modstate; -struct PyModuleDef _freetypemodule = { +struct PyModuleDef _freetypemoduledef = { PyModuleDef_HEAD_INIT, MODULE_NAME, DOC_FREETYPE, @@ -2347,7 +2364,7 @@ struct PyModuleDef _freetypemodule = { MODINIT_DEFINE(_freetype) { - PyObject *module, *apiobj; + PyObject *apiobj; static void *c_api[PYGAMEAPI_FREETYPE_NUMSLOTS]; import_pygame_base(); @@ -2380,27 +2397,28 @@ MODINIT_DEFINE(_freetype) return NULL; } - module = PyModule_Create(&_freetypemodule); + _freetypemodule = PyModule_Create(&_freetypemoduledef); - if (!module) { + if (!_freetypemodule) { return NULL; } - FREETYPE_MOD_STATE(module)->freetype = 0; - FREETYPE_MOD_STATE(module)->cache_size = 0; - FREETYPE_MOD_STATE(module)->resolution = PGFT_DEFAULT_RESOLUTION; + FREETYPE_MOD_STATE(_freetypemodule)->freetype = 0; + FREETYPE_MOD_STATE(_freetypemodule)->cache_size = 0; + FREETYPE_MOD_STATE(_freetypemodule)->resolution = PGFT_DEFAULT_RESOLUTION; Py_INCREF(&pgFont_Type); - if (PyModule_AddObject(module, FONT_TYPE_NAME, (PyObject *)&pgFont_Type)) { + if (PyModule_AddObject(_freetypemodule, FONT_TYPE_NAME, + (PyObject *)&pgFont_Type)) { Py_DECREF(&pgFont_Type); - Py_DECREF(module); + Py_DECREF(_freetypemodule); return NULL; } -#define DEC_CONST(x) \ - if (PyModule_AddIntConstant(module, #x, (int)FT_##x)) { \ - Py_DECREF(module); \ - return NULL; \ +#define DEC_CONST(x) \ + if (PyModule_AddIntConstant(_freetypemodule, #x, (int)FT_##x)) { \ + Py_DECREF(_freetypemodule); \ + return NULL; \ } DEC_CONST(STYLE_NORMAL); @@ -2423,11 +2441,11 @@ MODINIT_DEFINE(_freetype) c_api[1] = &pgFont_New; apiobj = encapsulate_api(c_api, "freetype"); - if (PyModule_AddObject(module, PYGAMEAPI_LOCAL_ENTRY, apiobj)) { + if (PyModule_AddObject(_freetypemodule, PYGAMEAPI_LOCAL_ENTRY, apiobj)) { Py_XDECREF(apiobj); - Py_DECREF(module); + Py_DECREF(_freetypemodule); return NULL; } - return module; + return _freetypemodule; } diff --git a/src_c/freetype/ft_wrap.h b/src_c/freetype/ft_wrap.h index 5fc059e556..034cccff01 100644 --- a/src_c/freetype/ft_wrap.h +++ b/src_c/freetype/ft_wrap.h @@ -232,9 +232,10 @@ typedef struct { } _FreeTypeState; #if !defined(PYPY_VERSION) -extern struct PyModuleDef _freetypemodule; +extern struct PyModuleDef _freetypemoduledef; #define FREETYPE_MOD_STATE(mod) ((_FreeTypeState *)PyModule_GetState(mod)) -#define FREETYPE_STATE FREETYPE_MOD_STATE(PyState_FindModule(&_freetypemodule)) +#define FREETYPE_STATE \ + FREETYPE_MOD_STATE(PyState_FindModule(&_freetypemoduledef)) #else /* defined(PYPY_VERSION) */ extern _FreeTypeState _modstate; #define FREETYPE_MOD_STATE(mod) (&_modstate) diff --git a/src_py/freetype.py b/src_py/freetype.py index 6c8dc0e4e2..d981a9ae06 100644 --- a/src_py/freetype.py +++ b/src_py/freetype.py @@ -45,7 +45,7 @@ def SysFont(name, size, bold=False, italic=False, constructor=None): - """pygame.ftfont.SysFont(name, size, bold=False, italic=False, constructor=None) -> Font + """pygame.freetype.SysFont(name, size, bold=False, italic=False, constructor=None) -> Font Create a pygame Font from system font resources. This will search the system fonts for the given font diff --git a/src_py/sysfont.py b/src_py/sysfont.py index cc05f983d8..59f0155b88 100644 --- a/src_py/sysfont.py +++ b/src_py/sysfont.py @@ -203,14 +203,40 @@ def initsysfonts_darwin(): return fonts -# read the fonts on unix +# read the fonts on posix/unix def initsysfonts_unix(path="fc-list"): - """use the fc-list from fontconfig to get a list of fonts""" + """if not embedded, use the fc-list from fontconfig to get a list of fonts""" fonts = {} - if sys.platform == "emscripten": + # these are embedded and cannot get os to list fonts a simple way. + if hasattr(sys, "getandroidapilevel") or sys.platform == "emscripten": + from pathlib import Path + + # default font + import importlib.resources + import pygame + + entry = importlib.resources.files(pygame) / "freesansbold.ttf" + _parse_font_entry_unix(f"{entry}: FreeSans:style=Bold", fonts) + + # cache in search order main script folder, then /tmp + main = __import__("__main__") + if hasattr(main, "__file__"): + fc_cache = Path(main.__file__).parent / "fc_cache" + else: + fc_cache = Path(__import__("tempfile").gettempdir()) / "fc_cache" + + if fc_cache.is_file(): + with open(fc_cache, "rb") as file: + for entry in file.read().decode("utf-8").splitlines(): + _parse_font_entry_unix(entry, fonts) + else: + warnings.warn(f"no fc_cache font cache file at {fc_cache}") + return fonts + # fallback to os support + try: proc = subprocess.run( [path, ":", "file", "family", "style"],