diff --git a/manimpango/__init__.py b/manimpango/__init__.py index 70987451..b1481f22 100644 --- a/manimpango/__init__.py +++ b/manimpango/__init__.py @@ -1,8 +1,10 @@ # -*- coding: utf-8 -*- import os import sys +import threading +from functools import wraps -from ._version import __version__ # noqa: F403,F401 +from ._version import __version__ # noqa: F401 if os.name == "nt": # pragma: no cover os.environ["PATH"] = ( @@ -10,10 +12,47 @@ f"{os.pathsep}" f"{os.environ['PATH']}" ) + +# Module-level lock for thread safety. Pango/Cairo access global state (the default +# PangoCairoFontMap, Fontconfig config, etc.) and the `registered_fonts` set is shared +# mutable state read during rendering and written during font registration. This lock +# serializes all access to these shared resources. +_pango_lock = threading.Lock() + + +def _synchronized(func): + @wraps(func) + def wrapper(*args, **kwargs): + with _pango_lock: + return func(*args, **kwargs) + return wrapper + + try: - from .register_font import * # isort:skip # noqa: F403,F401 - from .cmanimpango import * # noqa: F403,F401 - from .enums import * # noqa: F403,F401 + from .register_font import ( # noqa: F401 + registered_fonts, + RegisteredFont, + ) + from .cmanimpango import ( # noqa: F401 + TextSetting, + MarkupUtils, + pango_version, + cairo_version, + ) + from .cmanimpango import text2svg as _text2svg_impl + from .register_font import ( + register_font as _register_font_impl, + unregister_font as _unregister_font_impl, + fc_register_font as _fc_register_font_impl, + fc_unregister_font as _fc_unregister_font_impl, + list_fonts as _list_fonts_impl, + ) + from .enums import ( # noqa: F401 + Style, + Weight, + Variant, + Alignment, + ) except ImportError as ie: # pragma: no cover py_ver = ".".join(map(str, sys.version_info[:3])) msg = f""" @@ -33,3 +72,11 @@ Original error: {ie} """ raise ImportError(msg) + +text2svg = _synchronized(_text2svg_impl) +register_font = _synchronized(_register_font_impl) +unregister_font = _synchronized(_unregister_font_impl) +fc_register_font = _synchronized(_fc_register_font_impl) +fc_unregister_font = _synchronized(_fc_unregister_font_impl) +list_fonts = _synchronized(_list_fonts_impl) +MarkupUtils.text2svg = staticmethod(_synchronized(MarkupUtils.text2svg))