diff --git a/meson.build b/meson.build index 54249473fe8e..49415fb5a397 100644 --- a/meson.build +++ b/meson.build @@ -39,7 +39,7 @@ py_mod = import('python') py3 = py_mod.find_installation(pure: false) py3_dep = py3.dependency() -pybind11_dep = dependency('pybind11', version: '>=2.13.2') +pybind11_dep = dependency('pybind11', version: '>=3') subdir('extern') subdir('src') diff --git a/pyproject.toml b/pyproject.toml index cf8503a0f3fe..3b4f01b91214 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,7 @@ requires-python = ">=3.11" # Should be a copy of the build dependencies below. dev = [ "meson-python>=0.13.1,!=0.17.*", - "pybind11>=2.13.2,!=2.13.3", + "pybind11>=3", "setuptools_scm>=7", # Not required by us but setuptools_scm without a version, cso _if_ # installed, then setuptools_scm 8 requires at least this version. @@ -73,7 +73,7 @@ requires = [ # meson-python 0.17.x breaks symlinks in sdists. You can remove this pin if # you really need it and aren't using an sdist. "meson-python>=0.13.1,!=0.17.*", - "pybind11>=2.13.2,!=2.13.3", + "pybind11>=3", "setuptools_scm>=7", ] diff --git a/requirements/dev/build-requirements.txt b/requirements/dev/build-requirements.txt index 4d2a098c3c4f..7b1c77f6fdd3 100644 --- a/requirements/dev/build-requirements.txt +++ b/requirements/dev/build-requirements.txt @@ -1,3 +1,3 @@ -pybind11>=2.13.2,!=2.13.3 +pybind11>=3 meson-python setuptools-scm diff --git a/src/_backend_agg_wrapper.cpp b/src/_backend_agg_wrapper.cpp index 3dd50b31f64a..5e2000c25178 100644 --- a/src/_backend_agg_wrapper.cpp +++ b/src/_backend_agg_wrapper.cpp @@ -1,6 +1,10 @@ #include #include #include +#ifdef PYBIND11_HAS_SUBINTERPRETER_SUPPORT +#include +#endif + #include "mplutils.h" #include "py_converters.h" #include "_backend_agg.h" @@ -214,9 +218,13 @@ PyRendererAgg_draw_gouraud_triangles(RendererAgg *self, self->draw_gouraud_triangles(gc, points, colors, trans); } -PYBIND11_MODULE(_backend_agg, m, py::mod_gil_not_used()) +PYBIND11_MODULE(_backend_agg, m, py::mod_gil_not_used() +#ifdef PYBIND11_HAS_SUBINTERPRETER_SUPPORT + ,py::multiple_interpreters::per_interpreter_gil() +#endif +) { - py::class_(m, "RendererAgg", py::buffer_protocol()) + py::classh(m, "RendererAgg", py::buffer_protocol()) .def(py::init(), "width"_a, "height"_a, "dpi"_a) @@ -266,7 +274,7 @@ PYBIND11_MODULE(_backend_agg, m, py::mod_gil_not_used()) return py::buffer_info(renderer->pixBuffer, shape, strides); }); - py::class_(m, "BufferRegion", py::buffer_protocol()) + py::classh(m, "BufferRegion", py::buffer_protocol()) // BufferRegion is not constructible from Python, thus no py::init is added. .def("set_x", &PyBufferRegion_set_x) .def("set_y", &PyBufferRegion_set_y) diff --git a/src/_enums.h b/src/_enums.h deleted file mode 100644 index 18f3d9aac9fa..000000000000 --- a/src/_enums.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef MPL_ENUMS_H -#define MPL_ENUMS_H - -#include - -// Extension for pybind11: Pythonic enums. -// This allows creating classes based on ``enum.*`` types. -// This code was copied from mplcairo, with some slight tweaks. -// The API is: -// -// - P11X_DECLARE_ENUM(py_name: str, py_base_cls: str, ...: {str, enum value}): -// py_name: The name to expose in the module. -// py_base_cls: The name of the enum base class to use. -// ...: The enum name/value pairs to expose. -// -// Use this macro to declare an enum and its values. -// -// - py11x::bind_enums(m: pybind11::module): -// m: The module to use to register the enum classes. -// -// Place this in PYBIND11_MODULE to register the enums declared by P11X_DECLARE_ENUM. - -// a1 includes the opening brace and a2 the closing brace. -// This definition is compatible with older compiler versions compared to -// #define P11X_ENUM_TYPE(...) decltype(std::map{std::pair __VA_ARGS__})::mapped_type -#define P11X_ENUM_TYPE(a1, a2, ...) decltype(std::pair a1, a2)::second_type - -#define P11X_CAT2(a, b) a##b -#define P11X_CAT(a, b) P11X_CAT2(a, b) - -namespace p11x { - namespace { - namespace py = pybind11; - - // Holder is (py_base_cls, [(name, value), ...]) before module init; - // converted to the Python class object after init. - auto enums = std::unordered_map{}; - - auto bind_enums(py::module mod) -> void - { - for (auto& [py_name, spec]: enums) { - auto const& [py_base_cls, pairs] = - spec.cast>(); - mod.attr(py::cast(py_name)) = spec = - py::module::import("enum").attr(py_base_cls.c_str())( - py_name, pairs, py::arg("module") = mod.attr("__name__")); - } - } - } -} - -// Immediately converting the args to a vector outside of the lambda avoids -// name collisions. -#define P11X_DECLARE_ENUM(py_name, py_base_cls, ...) \ - namespace p11x { \ - namespace { \ - [[maybe_unused]] auto const P11X_CAT(enum_placeholder_, __COUNTER__) = \ - [](auto args) { \ - py::gil_scoped_acquire gil; \ - using int_t = std::underlying_type_t; \ - auto pairs = std::vector>{}; \ - for (auto& [k, v]: args) { \ - pairs.emplace_back(k, int_t(v)); \ - } \ - p11x::enums[py_name] = pybind11::cast(std::pair{py_base_cls, pairs}); \ - return 0; \ - } (std::vector{std::pair __VA_ARGS__}); \ - } \ - } \ - namespace pybind11::detail { \ - template<> struct type_caster { \ - using type = P11X_ENUM_TYPE(__VA_ARGS__); \ - static_assert(std::is_enum_v, "Not an enum"); \ - PYBIND11_TYPE_CASTER(type, _(py_name)); \ - bool load(handle src, bool) { \ - auto cls = p11x::enums.at(py_name); \ - PyObject* tmp = nullptr; \ - if (pybind11::isinstance(src, cls) \ - && (tmp = PyNumber_Index(src.attr("value").ptr()))) { \ - auto ival = PyLong_AsLong(tmp); \ - value = decltype(value)(ival); \ - Py_DECREF(tmp); \ - return !(ival == -1 && !PyErr_Occurred()); \ - } else { \ - return false; \ - } \ - } \ - static handle cast(decltype(value) obj, return_value_policy, handle) { \ - auto cls = p11x::enums.at(py_name); \ - return cls(std::underlying_type_t(obj)).inc_ref(); \ - } \ - }; \ - } - -#endif /* MPL_ENUMS_H */ diff --git a/src/_image_wrapper.cpp b/src/_image_wrapper.cpp index 6528c4a9270c..9346abb104d4 100644 --- a/src/_image_wrapper.cpp +++ b/src/_image_wrapper.cpp @@ -1,5 +1,9 @@ #include +#include #include +#ifdef PYBIND11_HAS_SUBINTERPRETER_SUPPORT +#include +#endif #include @@ -278,9 +282,13 @@ calculate_rms_and_diff(py::array_t expected_image, } -PYBIND11_MODULE(_image, m, py::mod_gil_not_used()) +PYBIND11_MODULE(_image, m, py::mod_gil_not_used() +#ifdef PYBIND11_HAS_SUBINTERPRETER_SUPPORT + ,py::multiple_interpreters::per_interpreter_gil() +#endif +) { - py::enum_(m, "_InterpolationType") + py::native_enum(m, "_InterpolationType", "enum.Enum") .value("NEAREST", NEAREST) .value("BILINEAR", BILINEAR) .value("BICUBIC", BICUBIC) @@ -298,7 +306,8 @@ PYBIND11_MODULE(_image, m, py::mod_gil_not_used()) .value("SINC", SINC) .value("LANCZOS", LANCZOS) .value("BLACKMAN", BLACKMAN) - .export_values(); + .export_values() + .finalize(); m.def("resample", &image_resample, "input_array"_a, diff --git a/src/_path_wrapper.cpp b/src/_path_wrapper.cpp index 2a297e49ac92..4b52cb3e2fe1 100644 --- a/src/_path_wrapper.cpp +++ b/src/_path_wrapper.cpp @@ -1,5 +1,8 @@ #include #include +#ifdef PYBIND11_HAS_SUBINTERPRETER_SUPPORT +#include +#endif #include #include @@ -310,7 +313,11 @@ Py_is_sorted_and_has_non_nan(py::object obj) return result; } -PYBIND11_MODULE(_path, m, py::mod_gil_not_used()) +PYBIND11_MODULE(_path, m, py::mod_gil_not_used() +#ifdef PYBIND11_HAS_SUBINTERPRETER_SUPPORT + ,py::multiple_interpreters::per_interpreter_gil() +#endif +) { m.def("point_in_path", &Py_point_in_path, "x"_a, "y"_a, "radius"_a, "path"_a, "trans"_a); diff --git a/src/_qhull_wrapper.cpp b/src/_qhull_wrapper.cpp index f8a3103b65f1..4f3ca648490a 100644 --- a/src/_qhull_wrapper.cpp +++ b/src/_qhull_wrapper.cpp @@ -7,6 +7,9 @@ */ #include #include +#ifdef PYBIND11_HAS_SUBINTERPRETER_SUPPORT +#include +#endif #ifdef _MSC_VER /* The Qhull header does not declare this as extern "C", but only MSVC seems to @@ -276,7 +279,11 @@ delaunay(const CoordArray& x, const CoordArray& y, int verbose) return delaunay_impl(npoints, x.data(), y.data(), verbose == 0); } -PYBIND11_MODULE(_qhull, m, py::mod_gil_not_used()) +PYBIND11_MODULE(_qhull, m, py::mod_gil_not_used() +#ifdef PYBIND11_HAS_SUBINTERPRETER_SUPPORT + ,py::multiple_interpreters::per_interpreter_gil() +#endif +) { m.doc() = "Computing Delaunay triangulations.\n"; diff --git a/src/ft2font.cpp b/src/ft2font.cpp index da1bd19dca57..b4b1e8f5231b 100644 --- a/src/ft2font.cpp +++ b/src/ft2font.cpp @@ -41,8 +41,6 @@ you have disabled hints). */ -FT_Library _ft2Library; - FT2Image::FT2Image(unsigned long width, unsigned long height) : m_buffer((unsigned char *)calloc(width * height, 1)), m_width(width), m_height(height) { @@ -207,7 +205,7 @@ FT2Font::get_path(std::vector &vertices, std::vector &cod codes.push_back(CLOSEPOLY); } -FT2Font::FT2Font(FT_Open_Args &open_args, +FT2Font::FT2Font(FT_Library ft2Library, FT_Open_Args &open_args, long hinting_factor_, std::vector &fallback_list, FT2Font::WarnFunc warn, bool warn_if_used) @@ -217,7 +215,7 @@ FT2Font::FT2Font(FT_Open_Args &open_args, kerning_factor(0) { clear(); - FT_CHECK(FT_Open_Face, _ft2Library, &open_args, 0, &face); + FT_CHECK(FT_Open_Face, ft2Library, &open_args, 0, &face); if (open_args.stream != nullptr) { face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM; } diff --git a/src/ft2font.h b/src/ft2font.h index 6676a7dd4818..6402b82f2f68 100644 --- a/src/ft2font.h +++ b/src/ft2font.h @@ -92,14 +92,12 @@ class FT2Image FT2Image &operator=(const FT2Image &); }; -extern FT_Library _ft2Library; - class FT2Font { typedef void (*WarnFunc)(FT_ULong charcode, std::set family_names); public: - FT2Font(FT_Open_Args &open_args, long hinting_factor, + FT2Font(FT_Library ft2Library, FT_Open_Args &open_args, long hinting_factor, std::vector &fallback_list, WarnFunc warn, bool warn_if_used); virtual ~FT2Font(); diff --git a/src/ft2font_wrapper.cpp b/src/ft2font_wrapper.cpp index ca2db6aa0e5b..99e41bb63be7 100644 --- a/src/ft2font_wrapper.cpp +++ b/src/ft2font_wrapper.cpp @@ -1,10 +1,13 @@ #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #include +#include #include #include +#ifdef PYBIND11_HAS_SUBINTERPRETER_SUPPORT +#include +#endif #include "ft2font.h" -#include "_enums.h" #include #include @@ -50,13 +53,6 @@ const char *Kerning__doc__ = R"""( .. versionadded:: 3.10 )"""; -P11X_DECLARE_ENUM( - "Kerning", "Enum", - {"DEFAULT", FT_KERNING_DEFAULT}, - {"UNFITTED", FT_KERNING_UNFITTED}, - {"UNSCALED", FT_KERNING_UNSCALED}, -); - const char *FaceFlags__doc__ = R"""( Flags returned by `FT2Font.face_flags`. @@ -103,29 +99,6 @@ enum class FaceFlags : FT_Long { #undef DECLARE_FLAG }; -P11X_DECLARE_ENUM( - "FaceFlags", "Flag", - {"SCALABLE", FaceFlags::SCALABLE}, - {"FIXED_SIZES", FaceFlags::FIXED_SIZES}, - {"FIXED_WIDTH", FaceFlags::FIXED_WIDTH}, - {"SFNT", FaceFlags::SFNT}, - {"HORIZONTAL", FaceFlags::HORIZONTAL}, - {"VERTICAL", FaceFlags::VERTICAL}, - {"KERNING", FaceFlags::KERNING}, - {"FAST_GLYPHS", FaceFlags::FAST_GLYPHS}, - {"MULTIPLE_MASTERS", FaceFlags::MULTIPLE_MASTERS}, - {"GLYPH_NAMES", FaceFlags::GLYPH_NAMES}, - {"EXTERNAL_STREAM", FaceFlags::EXTERNAL_STREAM}, - {"HINTER", FaceFlags::HINTER}, - {"CID_KEYED", FaceFlags::CID_KEYED}, - {"TRICKY", FaceFlags::TRICKY}, - {"COLOR", FaceFlags::COLOR}, - {"VARIATION", FaceFlags::VARIATION}, - {"SVG", FaceFlags::SVG}, - {"SBIX", FaceFlags::SBIX}, - {"SBIX_OVERLAY", FaceFlags::SBIX_OVERLAY}, -); - const char *LoadFlags__doc__ = R"""( Flags for `FT2Font.load_char`, `FT2Font.load_glyph`, and `FT2Font.set_text`. @@ -174,36 +147,6 @@ enum class LoadFlags : FT_Int32 { #undef DECLARE_FLAG }; -P11X_DECLARE_ENUM( - "LoadFlags", "Flag", - {"DEFAULT", LoadFlags::DEFAULT}, - {"NO_SCALE", LoadFlags::NO_SCALE}, - {"NO_HINTING", LoadFlags::NO_HINTING}, - {"RENDER", LoadFlags::RENDER}, - {"NO_BITMAP", LoadFlags::NO_BITMAP}, - {"VERTICAL_LAYOUT", LoadFlags::VERTICAL_LAYOUT}, - {"FORCE_AUTOHINT", LoadFlags::FORCE_AUTOHINT}, - {"CROP_BITMAP", LoadFlags::CROP_BITMAP}, - {"PEDANTIC", LoadFlags::PEDANTIC}, - {"IGNORE_GLOBAL_ADVANCE_WIDTH", LoadFlags::IGNORE_GLOBAL_ADVANCE_WIDTH}, - {"NO_RECURSE", LoadFlags::NO_RECURSE}, - {"IGNORE_TRANSFORM", LoadFlags::IGNORE_TRANSFORM}, - {"MONOCHROME", LoadFlags::MONOCHROME}, - {"LINEAR_DESIGN", LoadFlags::LINEAR_DESIGN}, - {"NO_AUTOHINT", LoadFlags::NO_AUTOHINT}, - {"COLOR", LoadFlags::COLOR}, - {"COMPUTE_METRICS", LoadFlags::COMPUTE_METRICS}, - {"BITMAP_METRICS_ONLY", LoadFlags::BITMAP_METRICS_ONLY}, - {"NO_SVG", LoadFlags::NO_SVG}, - // These must be unique, but the others can be OR'd together; I don't know if - // there's any way to really enforce that. - {"TARGET_NORMAL", LoadFlags::TARGET_NORMAL}, - {"TARGET_LIGHT", LoadFlags::TARGET_LIGHT}, - {"TARGET_MONO", LoadFlags::TARGET_MONO}, - {"TARGET_LCD", LoadFlags::TARGET_LCD}, - {"TARGET_LCD_V", LoadFlags::TARGET_LCD_V}, -); - const char *StyleFlags__doc__ = R"""( Flags returned by `FT2Font.style_flags`. @@ -221,13 +164,6 @@ enum class StyleFlags : FT_Long { #undef DECLARE_FLAG }; -P11X_DECLARE_ENUM( - "StyleFlags", "Flag", - {"NORMAL", StyleFlags::NORMAL}, - {"ITALIC", StyleFlags::ITALIC}, - {"BOLD", StyleFlags::BOLD}, -); - /********************************************************************** * FT2Image * */ @@ -446,7 +382,7 @@ const char *PyFT2Font_init__doc__ = R"""( )"""; static PyFT2Font * -PyFT2Font_init(py::object filename, long hinting_factor = 8, +PyFT2Font_init(FT_Library ft2Library, py::object filename, long hinting_factor = 8, std::optional> fallback_list = std::nullopt, int kerning_factor = 0, bool warn_if_used = false) { @@ -497,8 +433,8 @@ PyFT2Font_init(py::object filename, long hinting_factor = 8, self->stream.close = nullptr; } - self->x = new FT2Font(open_args, hinting_factor, fallback_fonts, ft_glyph_warn, - warn_if_used); + self->x = new FT2Font(ft2Library, open_args, hinting_factor, fallback_fonts, + ft_glyph_warn, warn_if_used); self->x->set_kerning_factor(kerning_factor); @@ -1542,23 +1478,86 @@ ft2font__getattr__(std::string name) { "module 'matplotlib.ft2font' has no attribute {!r}"_s.format(name)); } -PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used()) +PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used() +#ifdef PYBIND11_HAS_SUBINTERPRETER_SUPPORT + ,py::multiple_interpreters::per_interpreter_gil() +#endif +) { - if (FT_Init_FreeType(&_ft2Library)) { // initialize library + FT_Library ft2Library = nullptr; + + if (FT_Init_FreeType(&ft2Library)) { // initialize library throw std::runtime_error("Could not initialize the freetype2 library"); } FT_Int major, minor, patch; char version_string[64]; - FT_Library_Version(_ft2Library, &major, &minor, &patch); + FT_Library_Version(ft2Library, &major, &minor, &patch); snprintf(version_string, sizeof(version_string), "%d.%d.%d", major, minor, patch); - p11x::bind_enums(m); - p11x::enums["Kerning"].attr("__doc__") = Kerning__doc__; - p11x::enums["LoadFlags"].attr("__doc__") = LoadFlags__doc__; - p11x::enums["FaceFlags"].attr("__doc__") = FaceFlags__doc__; - p11x::enums["StyleFlags"].attr("__doc__") = StyleFlags__doc__; - - py::class_(m, "FT2Image", py::is_final(), py::buffer_protocol(), + py::native_enum(m, "Kerning", "enum.Enum", Kerning__doc__) + .value("DEFAULT", FT_KERNING_DEFAULT) + .value("UNFITTED", FT_KERNING_UNFITTED) + .value("UNSCALED", FT_KERNING_UNSCALED) + .finalize(); + + py::native_enum(m, "LoadFlags", "enum.Flag", LoadFlags__doc__) + .value("DEFAULT", LoadFlags::DEFAULT) + .value("NO_SCALE", LoadFlags::NO_SCALE) + .value("NO_HINTING", LoadFlags::NO_HINTING) + .value("RENDER", LoadFlags::RENDER) + .value("NO_BITMAP", LoadFlags::NO_BITMAP) + .value("VERTICAL_LAYOUT", LoadFlags::VERTICAL_LAYOUT) + .value("FORCE_AUTOHINT", LoadFlags::FORCE_AUTOHINT) + .value("CROP_BITMAP", LoadFlags::CROP_BITMAP) + .value("PEDANTIC", LoadFlags::PEDANTIC) + .value("IGNORE_GLOBAL_ADVANCE_WIDTH", LoadFlags::IGNORE_GLOBAL_ADVANCE_WIDTH) + .value("NO_RECURSE", LoadFlags::NO_RECURSE) + .value("IGNORE_TRANSFORM", LoadFlags::IGNORE_TRANSFORM) + .value("MONOCHROME", LoadFlags::MONOCHROME) + .value("LINEAR_DESIGN", LoadFlags::LINEAR_DESIGN) + .value("NO_AUTOHINT", LoadFlags::NO_AUTOHINT) + .value("COLOR", LoadFlags::COLOR) + .value("COMPUTE_METRICS", LoadFlags::COMPUTE_METRICS) + .value("BITMAP_METRICS_ONLY", LoadFlags::BITMAP_METRICS_ONLY) + .value("NO_SVG", LoadFlags::NO_SVG) + // These must be unique, but the others can be OR'd together; I don't know if + // there's any way to really enforce that. + .value("TARGET_NORMAL", LoadFlags::TARGET_NORMAL) + .value("TARGET_LIGHT", LoadFlags::TARGET_LIGHT) + .value("TARGET_MONO", LoadFlags::TARGET_MONO) + .value("TARGET_LCD", LoadFlags::TARGET_LCD) + .value("TARGET_LCD_V", LoadFlags::TARGET_LCD_V) + .finalize(); + + py::native_enum(m, "FaceFlags", "enum.Flag", FaceFlags__doc__) + .value("SCALABLE", FaceFlags::SCALABLE) + .value("FIXED_SIZES", FaceFlags::FIXED_SIZES) + .value("FIXED_WIDTH", FaceFlags::FIXED_WIDTH) + .value("SFNT", FaceFlags::SFNT) + .value("HORIZONTAL", FaceFlags::HORIZONTAL) + .value("VERTICAL", FaceFlags::VERTICAL) + .value("KERNING", FaceFlags::KERNING) + .value("FAST_GLYPHS", FaceFlags::FAST_GLYPHS) + .value("MULTIPLE_MASTERS", FaceFlags::MULTIPLE_MASTERS) + .value("GLYPH_NAMES", FaceFlags::GLYPH_NAMES) + .value("EXTERNAL_STREAM", FaceFlags::EXTERNAL_STREAM) + .value("HINTER", FaceFlags::HINTER) + .value("CID_KEYED", FaceFlags::CID_KEYED) + .value("TRICKY", FaceFlags::TRICKY) + .value("COLOR", FaceFlags::COLOR) + .value("VARIATION", FaceFlags::VARIATION) + .value("SVG", FaceFlags::SVG) + .value("SBIX", FaceFlags::SBIX) + .value("SBIX_OVERLAY", FaceFlags::SBIX_OVERLAY) + .finalize(); + + py::native_enum(m, "StyleFlags", "enum.Flag", StyleFlags__doc__) + .value("NORMAL", StyleFlags::NORMAL) + .value("ITALIC", StyleFlags::ITALIC) + .value("BOLD", StyleFlags::BOLD) + .finalize(); + + py::classh(m, "FT2Image", py::is_final(), py::buffer_protocol(), PyFT2Image__doc__) .def(py::init( [](double_or_ width, double_or_ height) { @@ -1581,7 +1580,7 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used()) return py::buffer_info(self.get_buffer(), shape, strides); }); - py::class_(m, "Glyph", py::is_final(), PyGlyph__doc__) + py::classh(m, "Glyph", py::is_final(), PyGlyph__doc__) .def(py::init<>([]() -> PyGlyph { // Glyph is not useful from Python, so mark it as not constructible. throw std::runtime_error("Glyph is not constructible"); @@ -1605,9 +1604,16 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used()) .def_property_readonly("bbox", &PyGlyph_get_bbox, "The control box of the glyph."); - auto cls = py::class_(m, "FT2Font", py::is_final(), py::buffer_protocol(), - PyFT2Font__doc__) - .def(py::init(&PyFT2Font_init), + py::classh(m, "FT2Font", py::is_final(), py::buffer_protocol(), + PyFT2Font__doc__) + .def(py::init( + [ft2Library](py::object filename, long hinting_factor = 8, + std::optional> fallback_list = std::nullopt, + int kerning_factor = 0, bool warn_if_used = false) -> PyFT2Font * + { + return PyFT2Font_init(ft2Library, filename, hinting_factor, + fallback_list, kerning_factor, warn_if_used); + }), "filename"_a, "hinting_factor"_a=8, py::kw_only(), "_fallback_list"_a=py::none(), "_kerning_factor"_a=0, "_warn_if_used"_a=false, @@ -1640,20 +1646,10 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used()) .def("get_descent", &PyFT2Font_get_descent, PyFT2Font_get_descent__doc__) .def("draw_glyphs_to_bitmap", &PyFT2Font_draw_glyphs_to_bitmap, py::kw_only(), "antialiased"_a=true, - PyFT2Font_draw_glyphs_to_bitmap__doc__); - // The generated docstring uses an unqualified "Buffer" as type hint, - // which causes an error in sphinx. This is fixed as of pybind11 - // master (since #5566) which now uses "collections.abc.Buffer"; - // restore the signature once that version is released. - { - py::options options{}; - options.disable_function_signatures(); - cls - .def("draw_glyph_to_bitmap", &PyFT2Font_draw_glyph_to_bitmap, - "image"_a, "x"_a, "y"_a, "glyph"_a, py::kw_only(), "antialiased"_a=true, - PyFT2Font_draw_glyph_to_bitmap__doc__); - } - cls + PyFT2Font_draw_glyphs_to_bitmap__doc__) + .def("draw_glyph_to_bitmap", &PyFT2Font_draw_glyph_to_bitmap, + "image"_a, "x"_a, "y"_a, "glyph"_a, py::kw_only(), "antialiased"_a=true, + PyFT2Font_draw_glyph_to_bitmap__doc__) .def("get_glyph_name", &PyFT2Font_get_glyph_name, "index"_a, PyFT2Font_get_glyph_name__doc__) .def("get_charmap", &PyFT2Font_get_charmap, PyFT2Font_get_charmap__doc__) @@ -1774,6 +1770,18 @@ PYBIND11_MODULE(ft2font, m, py::mod_gil_not_used()) return self.x->get_image().request(); }); + // Ensure FreeType library is closed after all instances of FT2Font are gone by + // tying a weak ref to the class itself. + (void)py::weakref( + m.attr("FT2Font"), + py::cpp_function( + [ft2Library](py::handle weakref) { + FT_Done_FreeType(ft2Library); + weakref.dec_ref(); + } + ) + ).release(); + m.attr("__freetype_version__") = version_string; m.attr("__freetype_build_type__") = FREETYPE_BUILD_TYPE; m.def("__getattr__", ft2font__getattr__); diff --git a/src/tri/_tri_wrapper.cpp b/src/tri/_tri_wrapper.cpp index 732e1af5f310..d3bf30e4153c 100644 --- a/src/tri/_tri_wrapper.cpp +++ b/src/tri/_tri_wrapper.cpp @@ -1,10 +1,17 @@ #include "_tri.h" +#ifdef PYBIND11_HAS_SUBINTERPRETER_SUPPORT +#include +#endif using namespace pybind11::literals; -PYBIND11_MODULE(_tri, m, py::mod_gil_not_used()) +PYBIND11_MODULE(_tri, m, py::mod_gil_not_used() +#ifdef PYBIND11_HAS_SUBINTERPRETER_SUPPORT + ,py::multiple_interpreters::per_interpreter_gil() +#endif +) { - py::class_(m, "Triangulation", py::is_final()) + py::classh(m, "Triangulation", py::is_final()) .def(py::init(m, "TriContourGenerator", py::is_final()) + py::classh(m, "TriContourGenerator", py::is_final()) .def(py::init(), "triangulation"_a, @@ -44,7 +51,7 @@ PYBIND11_MODULE(_tri, m, py::mod_gil_not_used()) .def("create_filled_contour", &TriContourGenerator::create_filled_contour, "Create and return a filled contour."); - py::class_(m, "TrapezoidMapTriFinder", py::is_final()) + py::classh(m, "TrapezoidMapTriFinder", py::is_final()) .def(py::init(), "triangulation"_a, "Create a new C++ TrapezoidMapTriFinder object.\n" pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy