From fb3e899efd4f080b04257d09b5e55182fa73178e Mon Sep 17 00:00:00 2001 From: HOLZSCHUCH Nicolas Date: Fri, 30 Oct 2020 17:54:03 +0100 Subject: [PATCH 1/9] Modifications for work on iOS: don't depend on static function members --- setup.cfg | 43 +++++++++++++++++++++++ setupext.py | 14 +++++++- src/_backend_agg_wrapper.cpp | 66 ++++++++++++++++++++++++++++++++++++ src/_contour_wrapper.cpp | 13 +++++++ src/_image_wrapper.cpp | 32 +++++++++++++++++ src/_path_wrapper.cpp | 9 +++++ src/numpy_cpp.h | 32 +++++++++++++++++ src/tri/_tri_wrapper.cpp | 35 +++++++++++++++++++ 8 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 setup.cfg diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 000000000000..3371fa6664f2 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,43 @@ +# Rename this file to setup.cfg to modify Matplotlib's build options. + +[metadata] +license_files = LICENSE/* + +[egg_info] + +[libs] +# By default, Matplotlib builds with LTO, which may be slow if you re-compile +# often, and don't need the space saving/speedup. +#enable_lto = True +# By default, Matplotlib downloads and builds its own copy of FreeType, and +# builds its own copy of Qhull. You may set the following to True to instead +# link against a system FreeType/Qhull. +system_freetype = True +#system_qhull = False + +[packages] +# There are a number of data subpackages from Matplotlib that are +# considered optional. All except 'tests' data (meaning the baseline +# image files) are installed by default, but that can be changed here. +tests = False +sample_data = False + +[gui_support] +# Matplotlib supports multiple GUI toolkits, known as backends. +# The MacOSX backend requires the Cocoa headers included with XCode. +# You can select whether to build it by uncommenting the following line. +# It is never built on Linux or Windows, regardless of the config value. +# +macosx = False + +[rc_options] +# User-configurable options +# +# Default backend, one of: Agg, Cairo, GTK3Agg, GTK3Cairo, MacOSX, Pdf, Ps, +# Qt4Agg, Qt5Agg, SVG, TkAgg, WX, WXAgg. +# +# The Agg, Ps, Pdf and SVG backends do not require external dependencies. Do +# not choose MacOSX if you have disabled the relevant extension modules. The +# default is determined by fallback. +# +#backend = Agg diff --git a/setupext.py b/setupext.py index 0742230844fc..ab68b7d1071b 100644 --- a/setupext.py +++ b/setupext.py @@ -531,7 +531,19 @@ class FreeType(SetupPackage): def add_flags(self, ext): ext.sources.insert(0, 'src/checkdep_freetype2.c') if options.get('system_freetype'): - pkg_config_setup_extension( + # iOS: we need to use freetype as a framework, not as a library. + platform = os.getenv('PLATFORM') or 'macosx' + if platform.startswith('iphone'): + pkg_config_setup_extension( + # FreeType 2.3 has libtool version 9.11.3 as can be checked + # from the tarball. For FreeType>=2.4, there is a conversion + # table in docs/VERSIONS.txt in the FreeType source tree. + ext, 'freetype2', + atleast_version='9.11.3', + alt_exec=['freetype-config'], + default_libraries=[]) + else: + pkg_config_setup_extension( # FreeType 2.3 has libtool version 9.11.3 as can be checked # from the tarball. For FreeType>=2.4, there is a conversion # table in docs/VERSIONS.txt in the FreeType source tree. diff --git a/src/_backend_agg_wrapper.cpp b/src/_backend_agg_wrapper.cpp index e08642e248ef..9a330a34f8e0 100644 --- a/src/_backend_agg_wrapper.cpp +++ b/src/_backend_agg_wrapper.cpp @@ -227,6 +227,11 @@ static PyObject *PyRendererAgg_draw_path(PyRendererAgg *self, PyObject *args, Py Py_RETURN_NONE; } +#if TARGET_OS_IPHONE +// iOS: need non static member functions. This replaces image.converter_contiguous: +static int (*image2_converter_contiguous)(PyObject *obj, void *arrp) = numpy::numpy_converter_contiguous; +#endif + static PyObject *PyRendererAgg_draw_text_image(PyRendererAgg *self, PyObject *args, PyObject *kwds) { numpy::array_view image; @@ -237,7 +242,11 @@ static PyObject *PyRendererAgg_draw_text_image(PyRendererAgg *self, PyObject *ar if (!PyArg_ParseTuple(args, "O&dddO&:draw_text_image", +#if !TARGET_OS_IPHONE &image.converter_contiguous, +#else + image2_converter_contiguous, +#endif &image, &x, &y, @@ -288,6 +297,11 @@ PyObject *PyRendererAgg_draw_markers(PyRendererAgg *self, PyObject *args, PyObje Py_RETURN_NONE; } +#if TARGET_OS_IPHONE +// iOS: need non static member functions. This replaces image.converter_contiguous: +static int (*image3_converter_contiguous)(PyObject *obj, void *arrp) = numpy::numpy_converter_contiguous; +#endif + static PyObject *PyRendererAgg_draw_image(PyRendererAgg *self, PyObject *args, PyObject *kwds) { GCAgg gc; @@ -301,7 +315,11 @@ static PyObject *PyRendererAgg_draw_image(PyRendererAgg *self, PyObject *args, P &gc, &x, &y, +#if !TARGET_OS_IPHONE &image.converter_contiguous, +#else + image3_converter_contiguous, +#endif &image)) { return NULL; } @@ -315,6 +333,12 @@ static PyObject *PyRendererAgg_draw_image(PyRendererAgg *self, PyObject *args, P Py_RETURN_NONE; } +#if TARGET_OS_IPHONE +// iOS: need non static member functions. This replaces linewidths.converter and antialiaseds.converter: +static int (*linewidths_converter)(PyObject *, void *) = numpy::numpy_converter; +static int (*antialiaseds_converter)(PyObject *, void *) = numpy::numpy_converter; +#endif + static PyObject * PyRendererAgg_draw_path_collection(PyRendererAgg *self, PyObject *args, PyObject *kwds) { @@ -349,11 +373,19 @@ PyRendererAgg_draw_path_collection(PyRendererAgg *self, PyObject *args, PyObject &facecolors, &convert_colors, &edgecolors, +#if !TARGET_OS_IPHONE &linewidths.converter, +#else + linewidths_converter, +#endif &linewidths, &convert_dashes_vector, &dashes, +#if !TARGET_OS_IPHONE &antialiaseds.converter, +#else + antialiaseds_converter, +#endif &antialiaseds, &ignored, &convert_offset_position, @@ -387,6 +419,12 @@ PyRendererAgg_draw_path_collection(PyRendererAgg *self, PyObject *args, PyObject Py_RETURN_NONE; } + +#if TARGET_OS_IPHONE +// iOS: need non static member functions. This replaces coordinates.converter: +int (*coordinates_converter)(PyObject *, void *) = numpy::numpy_converter; +#endif + static PyObject *PyRendererAgg_draw_quad_mesh(PyRendererAgg *self, PyObject *args, PyObject *kwds) { GCAgg gc; @@ -408,7 +446,11 @@ static PyObject *PyRendererAgg_draw_quad_mesh(PyRendererAgg *self, PyObject *arg &master_transform, &mesh_width, &mesh_height, +#if !TARGET_OS_IPHONE &coordinates.converter, +#else + coordinates_converter, +#endif &coordinates, &convert_points, &offsets, @@ -438,6 +480,12 @@ static PyObject *PyRendererAgg_draw_quad_mesh(PyRendererAgg *self, PyObject *arg Py_RETURN_NONE; } +#if TARGET_OS_IPHONE +// iOS: need non static member functions. This replaces points.converter and colors.converter: +static int (*points2_converter)(PyObject *, void *) = numpy::numpy_converter; +static int (*colors2_converter)(PyObject *, void *) = numpy::numpy_converter; +#endif + static PyObject * PyRendererAgg_draw_gouraud_triangle(PyRendererAgg *self, PyObject *args, PyObject *kwds) { @@ -450,9 +498,15 @@ PyRendererAgg_draw_gouraud_triangle(PyRendererAgg *self, PyObject *args, PyObjec "O&O&O&O&|O:draw_gouraud_triangle", &convert_gcagg, &gc, +#if !TARGET_OS_IPHONE &points.converter, &points, &colors.converter, +#else + points2_converter, + &points, + colors2_converter, +#endif &colors, &convert_trans_affine, &trans)) { @@ -479,6 +533,12 @@ PyRendererAgg_draw_gouraud_triangle(PyRendererAgg *self, PyObject *args, PyObjec Py_RETURN_NONE; } +#if TARGET_OS_IPHONE +// iOS: need non static member functions. This replaces points.converter and colors.converter: +static int (*points3_converter)(PyObject *, void *) = numpy::numpy_converter; +static int (*colors3_converter)(PyObject *, void *) = numpy::numpy_converter; +#endif + static PyObject * PyRendererAgg_draw_gouraud_triangles(PyRendererAgg *self, PyObject *args, PyObject *kwds) { @@ -491,9 +551,15 @@ PyRendererAgg_draw_gouraud_triangles(PyRendererAgg *self, PyObject *args, PyObje "O&O&O&O&|O:draw_gouraud_triangles", &convert_gcagg, &gc, +#if !TARGET_OS_IPHONE &points.converter, &points, &colors.converter, +#else + points3_converter, + &points, + colors3_converter, +#endif &colors, &convert_trans_affine, &trans)) { diff --git a/src/_contour_wrapper.cpp b/src/_contour_wrapper.cpp index da891eb70048..d9b4138c812c 100644 --- a/src/_contour_wrapper.cpp +++ b/src/_contour_wrapper.cpp @@ -26,6 +26,12 @@ const char* PyQuadContourGenerator_init__doc__ = "--\n\n" "Create a new C++ QuadContourGenerator object\n"; +#if TARGET_OS_IPHONE +// iOS: need non static member functions. This replaces x.converter and d.converter_contiguous: +static int (*x_converter_contiguous)(PyObject *, void *) = numpy::numpy_converter_contiguous; +static int (*mask_converter_contiguous)(PyObject *, void *) = numpy::numpy_converter_contiguous ; +#endif + static int PyQuadContourGenerator_init(PyQuadContourGenerator* self, PyObject* args, PyObject* kwds) { QuadContourGenerator::CoordinateArray x, y, z; @@ -34,10 +40,17 @@ static int PyQuadContourGenerator_init(PyQuadContourGenerator* self, PyObject* a long chunk_size; if (!PyArg_ParseTuple(args, "O&O&O&O&O&l", +#if !TARGET_OS_IPHONE &x.converter_contiguous, &x, &y.converter_contiguous, &y, &z.converter_contiguous, &z, &mask.converter_contiguous, &mask, +#else + x_converter_contiguous, &x, + x_converter_contiguous, &y, + x_converter_contiguous, &z, + mask_converter_contiguous, &mask, +#endif &convert_bool, &corner_mask, &chunk_size)) { return -1; diff --git a/src/_image_wrapper.cpp b/src/_image_wrapper.cpp index 73d093aa3b18..13fc20ec6471 100644 --- a/src/_image_wrapper.cpp +++ b/src/_image_wrapper.cpp @@ -299,6 +299,12 @@ const char *image_pcolor__doc__ = "bounds = (x_min, x_max, y_min, y_max)\n" "interpolation = NEAREST or BILINEAR \n"; +#if TARGET_OS_IPHONE +// iOS: need non static member functions. This replaces x.converter and d.converter_contiguous: +static int (*xf_converter)(PyObject *, void *) = numpy::numpy_converter; +static int (*d_converter_contiguous)(PyObject *, void *) = numpy::numpy_converter_contiguous; +#endif + static PyObject *image_pcolor(PyObject *self, PyObject *args, PyObject *kwds) { numpy::array_view x; @@ -310,11 +316,19 @@ static PyObject *image_pcolor(PyObject *self, PyObject *args, PyObject *kwds) if (!PyArg_ParseTuple(args, "O&O&O&nn(ffff)i:pcolor", +#if !TARGET_OS_IPHONE &x.converter, &x, &y.converter, &y, &d.converter_contiguous, +#else + xf_converter, + &x, + xf_converter, + &y, + d_converter_contiguous, +#endif &d, &rows, &cols, @@ -342,6 +356,12 @@ const char *image_pcolor2__doc__ = "bounds = (x_left, x_right, y_bot, y_top)\n" "bg = ndarray of 4 uint8 representing background rgba\n"; +#if TARGET_OS_IPHONE +// iOS: need non static member functions. This replaces x.converter_contiguous: +static int (*xd_converter_contiguous)(PyObject *, void *) = numpy::numpy_converter_contiguous; +static int (*bg_converter)(PyObject *, void *) = numpy::numpy_converter; +#endif + static PyObject *image_pcolor2(PyObject *self, PyObject *args, PyObject *kwds) { numpy::array_view x; @@ -353,11 +373,19 @@ static PyObject *image_pcolor2(PyObject *self, PyObject *args, PyObject *kwds) if (!PyArg_ParseTuple(args, "O&O&O&nn(ffff)O&:pcolor2", +#if !TARGET_OS_IPHONE &x.converter_contiguous, &x, &y.converter_contiguous, &y, &d.converter_contiguous, +#else + xd_converter_contiguous, + &x, + xd_converter_contiguous, + &y, + d_converter_contiguous, +#endif &d, &rows, &cols, @@ -365,7 +393,11 @@ static PyObject *image_pcolor2(PyObject *self, PyObject *args, PyObject *kwds) &bounds[1], &bounds[2], &bounds[3], +#if !TARGET_OS_IPHONE &bg.converter, +#else + bg_converter, +#endif &bg)) { return NULL; } diff --git a/src/_path_wrapper.cpp b/src/_path_wrapper.cpp index 708d7d36e67a..6e113f6f0fbd 100644 --- a/src/_path_wrapper.cpp +++ b/src/_path_wrapper.cpp @@ -176,6 +176,11 @@ static PyObject *Py_get_path_extents(PyObject *self, PyObject *args, PyObject *k const char *Py_update_path_extents__doc__ = "update_path_extents(path, trans, rect, minpos, ignore)"; +#if TARGET_OS_IPHONE +// iOS: need non static member functions. This replaces minpos.converter: +static int (*minpos_converter)(PyObject *obj, void *arrp) = numpy::numpy_converter; +#endif + static PyObject *Py_update_path_extents(PyObject *self, PyObject *args, PyObject *kwds) { py::PathIterator path; @@ -193,7 +198,11 @@ static PyObject *Py_update_path_extents(PyObject *self, PyObject *args, PyObject &trans, &convert_rect, &rect, +#if !TARGET_OS_IPHONE &minpos.converter, +#else + minpos_converter, +#endif &minpos, &ignore)) { return NULL; diff --git a/src/numpy_cpp.h b/src/numpy_cpp.h index 36c763d1584e..bbd0a631c257 100644 --- a/src/numpy_cpp.h +++ b/src/numpy_cpp.h @@ -549,6 +549,9 @@ class array_view : public detail::array_view_accessors return (PyObject *)m_arr; } + // iOS: we need static members because we need pointers to that function. + // But we also need to re-initialize this pointer for each library. +#if !TARGET_OS_IPHONE static int converter(PyObject *obj, void *arrp) { array_view *arr = (array_view *)arrp; @@ -570,8 +573,37 @@ class array_view : public detail::array_view_accessors return 1; } +#endif }; +#ifdef TARGET_OS_IPHONE +// iOS: non-static member versions of converter and converter_contiguous. +template +static int numpy_converter(PyObject *obj, void *arrp) +{ + array_view *arr = (array_view *)arrp; + + if (!arr->set(obj)) { + return 0; + } + + return 1; +} + +template +static int numpy_converter_contiguous(PyObject *obj, void *arrp) +{ + array_view *arr = (array_view *)arrp; + + if (!arr->set(obj, true)) { + return 0; + } + + return 1; +} +#endif + + } // namespace numpy diff --git a/src/tri/_tri_wrapper.cpp b/src/tri/_tri_wrapper.cpp index fcf155721ecc..69e7c22fbb70 100644 --- a/src/tri/_tri_wrapper.cpp +++ b/src/tri/_tri_wrapper.cpp @@ -28,6 +28,15 @@ const char* PyTriangulation_init__doc__ = "This should not be called directly, instead use the python class\n" "matplotlib.tri.Triangulation instead.\n"; +#if TARGET_OS_IPHONE +// iOS: need non static member functions. This replaces x.converter, triangles.converter, mask.converter, edges.converter, neighbors.converter: +static int (*x_converter)(PyObject *obj, void *arrp) = numpy::numpy_converter; +static int (*triangles_converter)(PyObject *obj, void *arrp) = numpy::numpy_converter; +static int (*mask_converter)(PyObject *obj, void *arrp) = numpy::numpy_converter; +static int (*edges_converter)(PyObject *obj, void *arrp) = numpy::numpy_converter; +static int (*neighbors_converter)(PyObject *obj, void *arrp) = numpy::numpy_converter; +#endif + static int PyTriangulation_init(PyTriangulation* self, PyObject* args, PyObject* kwds) { Triangulation::CoordinateArray x, y; @@ -39,12 +48,21 @@ static int PyTriangulation_init(PyTriangulation* self, PyObject* args, PyObject* if (!PyArg_ParseTuple(args, "O&O&O&O&O&O&i", +#if !TARGET_OS_IPHONE &x.converter, &x, &y.converter, &y, &triangles.converter, &triangles, &mask.converter, &mask, &edges.converter, &edges, &neighbors.converter, &neighbors, +#else + x_converter, &x, + x_converter, &y, + triangles_converter, &triangles, + mask_converter, &mask, + edges_converter, &edges, + neighbors_converter, &neighbors, +#endif &correct_triangle_orientations)) { return -1; } @@ -107,7 +125,11 @@ static PyObject* PyTriangulation_calculate_plane_coefficients(PyTriangulation* s { Triangulation::CoordinateArray z; if (!PyArg_ParseTuple(args, "O&:calculate_plane_coefficients", +#if !TARGET_OS_IPHONE &z.converter, &z)) { +#else + x_converter, &z)) { +#endif return NULL; } @@ -166,7 +188,11 @@ static PyObject* PyTriangulation_set_mask(PyTriangulation* self, PyObject* args, { Triangulation::MaskArray mask; +#if !TARGET_OS_IPHONE if (!PyArg_ParseTuple(args, "O&:set_mask", &mask.converter, &mask)) { +#else + if (!PyArg_ParseTuple(args, "O&:set_mask", mask_converter, &mask)) { +#endif return NULL; } @@ -246,7 +272,11 @@ static int PyTriContourGenerator_init(PyTriContourGenerator* self, PyObject* arg if (!PyArg_ParseTuple(args, "O!O&", &PyTriangulationType, &triangulation_arg, +#if !TARGET_OS_IPHONE &z.converter, &z)) { +#else + x_converter, &z)) { +#endif return -1; } @@ -408,8 +438,13 @@ static PyObject* PyTrapezoidMapTriFinder_find_many(PyTrapezoidMapTriFinder* self { TrapezoidMapTriFinder::CoordinateArray x, y; if (!PyArg_ParseTuple(args, "O&O&:find_many", +#if !TARGET_OS_IPHONE &x.converter, &x, &y.converter, &y)) { +#else + x_converter, &x, + x_converter, &y)) { +#endif return NULL; } From 2eca71b9682f0267126a68932984542c53424175 Mon Sep 17 00:00:00 2001 From: HOLZSCHUCH Nicolas Date: Sat, 31 Oct 2020 16:00:04 +0100 Subject: [PATCH 2/9] Edited font_manager so we don't need "fc-list" (not available on iOS) --- .../backends/web_backend/single_figure.html | 2 ++ lib/matplotlib/font_manager.py | 20 +++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/backends/web_backend/single_figure.html b/lib/matplotlib/backends/web_backend/single_figure.html index 71fe451f6f14..ac4d40e61ef5 100644 --- a/lib/matplotlib/backends/web_backend/single_figure.html +++ b/lib/matplotlib/backends/web_backend/single_figure.html @@ -6,6 +6,8 @@ + +