From 25be2f1a1330eaebe727d1d3c93b11f71d569f73 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Thu, 22 Feb 2024 22:03:42 -0500 Subject: [PATCH 1/5] BLD: Make ft2font classes final There appears to be no reason for them to be subtyped, as they are semi-private, and we don't do that. --- doc/api/next_api_changes/behavior/27891-ES.rst | 5 +++++ lib/matplotlib/ft2font.pyi | 5 ++++- src/ft2font_wrapper.cpp | 6 +++--- 3 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 doc/api/next_api_changes/behavior/27891-ES.rst diff --git a/doc/api/next_api_changes/behavior/27891-ES.rst b/doc/api/next_api_changes/behavior/27891-ES.rst new file mode 100644 index 000000000000..f60b4b320a44 --- /dev/null +++ b/doc/api/next_api_changes/behavior/27891-ES.rst @@ -0,0 +1,5 @@ +ft2font classes are now final +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ft2font classes `.ft2font.FT2Font`, and `.ft2font.FT2Image` are now final +and can no longer be subclassed. diff --git a/lib/matplotlib/ft2font.pyi b/lib/matplotlib/ft2font.pyi index 6a0716e993a5..d47614cc6f48 100644 --- a/lib/matplotlib/ft2font.pyi +++ b/lib/matplotlib/ft2font.pyi @@ -1,4 +1,4 @@ -from typing import BinaryIO, Literal, TypedDict, overload +from typing import BinaryIO, Literal, TypedDict, final, overload import numpy as np from numpy.typing import NDArray @@ -158,6 +158,7 @@ class _SfntPcltDict(TypedDict): widthType: int serifStyle: int +@final class FT2Font: ascender: int bbox: tuple[int, int, int, int] @@ -233,11 +234,13 @@ class FT2Font: self, string: str, angle: float = ..., flags: int = ... ) -> NDArray[np.float64]: ... +@final class FT2Image: # TODO: When updating mypy>=1.4, subclass from Buffer. def __init__(self, width: float, height: float) -> None: ... def draw_rect(self, x0: float, y0: float, x1: float, y1: float) -> None: ... def draw_rect_filled(self, x0: float, y0: float, x1: float, y1: float) -> None: ... +@final class Glyph: width: int height: int diff --git a/src/ft2font_wrapper.cpp b/src/ft2font_wrapper.cpp index 0fdb0165b462..9e0226455972 100644 --- a/src/ft2font_wrapper.cpp +++ b/src/ft2font_wrapper.cpp @@ -146,7 +146,7 @@ static PyTypeObject* PyFT2Image_init_type() PyFT2ImageType.tp_name = "matplotlib.ft2font.FT2Image"; PyFT2ImageType.tp_basicsize = sizeof(PyFT2Image); PyFT2ImageType.tp_dealloc = (destructor)PyFT2Image_dealloc; - PyFT2ImageType.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; + PyFT2ImageType.tp_flags = Py_TPFLAGS_DEFAULT; PyFT2ImageType.tp_methods = methods; PyFT2ImageType.tp_new = PyFT2Image_new; PyFT2ImageType.tp_init = (initproc)PyFT2Image_init; @@ -236,7 +236,7 @@ static PyTypeObject *PyGlyph_init_type() PyGlyphType.tp_name = "matplotlib.ft2font.Glyph"; PyGlyphType.tp_basicsize = sizeof(PyGlyph); PyGlyphType.tp_dealloc = (destructor)PyGlyph_dealloc; - PyGlyphType.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; + PyGlyphType.tp_flags = Py_TPFLAGS_DEFAULT; PyGlyphType.tp_members = members; PyGlyphType.tp_getset = getset; @@ -1495,7 +1495,7 @@ static PyTypeObject *PyFT2Font_init_type() PyFT2FontType.tp_doc = PyFT2Font_init__doc__; PyFT2FontType.tp_basicsize = sizeof(PyFT2Font); PyFT2FontType.tp_dealloc = (destructor)PyFT2Font_dealloc; - PyFT2FontType.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; + PyFT2FontType.tp_flags = Py_TPFLAGS_DEFAULT; PyFT2FontType.tp_methods = methods; PyFT2FontType.tp_getset = getset; PyFT2FontType.tp_new = PyFT2Font_new; From 5f2a89ab3a85e90eab41492acd94a78432ad2bf5 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Tue, 5 Mar 2024 23:51:22 -0500 Subject: [PATCH 2/5] Move Python code from ft2font to its wrapper This improves the encapsulation and separation of concerns between the files. --- src/ft2font.cpp | 86 +++++++++++++---------------------------- src/ft2font.h | 10 +++-- src/ft2font_wrapper.cpp | 71 +++++++++++++++++++++++++++------- 3 files changed, 90 insertions(+), 77 deletions(-) diff --git a/src/ft2font.cpp b/src/ft2font.cpp index b20f224715bf..41203340dd47 100644 --- a/src/ft2font.cpp +++ b/src/ft2font.cpp @@ -1,18 +1,16 @@ /* -*- mode: c++; c-basic-offset: 4 -*- */ -#define NO_IMPORT_ARRAY - #include +#include #include #include #include #include #include +#include #include "ft2font.h" #include "mplutils.h" -#include "numpy_cpp.h" -#include "py_exceptions.h" #ifndef M_PI #define M_PI 3.14159265358979323846264338328 @@ -185,30 +183,6 @@ FT2Image::draw_rect_filled(unsigned long x0, unsigned long y0, unsigned long x1, m_dirty = true; } -static void ft_glyph_warn(FT_ULong charcode, std::set family_names) -{ - PyObject *text_helpers = NULL, *tmp = NULL; - std::set::iterator it = family_names.begin(); - std::stringstream ss; - ss<<*it; - while(++it != family_names.end()){ - ss<<", "<<*it; - } - - if (!(text_helpers = PyImport_ImportModule("matplotlib._text_helpers")) || - !(tmp = PyObject_CallMethod(text_helpers, - "warn_on_missing_glyph", "(k, s)", - charcode, ss.str().c_str()))) { - goto exit; - } -exit: - Py_XDECREF(text_helpers); - Py_XDECREF(tmp); - if (PyErr_Occurred()) { - throw mpl::exception(); - } -} - // ft_outline_decomposer should be passed to FT_Outline_Decompose. On the // first pass, vertices and codes are set to NULL, and index is simply // incremented for each vertex that should be inserted, so that it is set, at @@ -296,52 +270,41 @@ static FT_Outline_Funcs ft_outline_funcs = { ft_outline_conic_to, ft_outline_cubic_to}; -PyObject* -FT2Font::get_path() +void +FT2Font::get_path(std::vector &vertices, std::vector &codes) { if (!face->glyph) { - PyErr_SetString(PyExc_RuntimeError, "No glyph loaded"); - return NULL; + throw std::runtime_error("No glyph loaded"); } ft_outline_decomposer decomposer = {}; - if (FT_Error error = - FT_Outline_Decompose( - &face->glyph->outline, &ft_outline_funcs, &decomposer)) { - PyErr_Format(PyExc_RuntimeError, - "FT_Outline_Decompose failed with error 0x%x", error); - return NULL; + if (FT_Error error = FT_Outline_Decompose( + &face->glyph->outline, &ft_outline_funcs, &decomposer)) { + throw std::runtime_error("FT_Outline_Decompose failed with error " + + std::to_string(error)); } if (!decomposer.index) { // Don't append CLOSEPOLY to null glyphs. - npy_intp vertices_dims[2] = { 0, 2 }; - numpy::array_view vertices(vertices_dims); - npy_intp codes_dims[1] = { 0 }; - numpy::array_view codes(codes_dims); - return Py_BuildValue("NN", vertices.pyobj(), codes.pyobj()); - } - npy_intp vertices_dims[2] = { decomposer.index + 1, 2 }; - numpy::array_view vertices(vertices_dims); - npy_intp codes_dims[1] = { decomposer.index + 1 }; - numpy::array_view codes(codes_dims); + return; + } + vertices.resize((decomposer.index + 1) * 2); + codes.resize(decomposer.index + 1); decomposer.index = 0; decomposer.vertices = vertices.data(); decomposer.codes = codes.data(); - if (FT_Error error = - FT_Outline_Decompose( - &face->glyph->outline, &ft_outline_funcs, &decomposer)) { - PyErr_Format(PyExc_RuntimeError, - "FT_Outline_Decompose failed with error 0x%x", error); - return NULL; + if (FT_Error error = FT_Outline_Decompose( + &face->glyph->outline, &ft_outline_funcs, &decomposer)) { + throw std::runtime_error("FT_Outline_Decompose failed with error " + + std::to_string(error)); } *(decomposer.vertices++) = 0; *(decomposer.vertices++) = 0; *(decomposer.codes++) = CLOSEPOLY; - return Py_BuildValue("NN", vertices.pyobj(), codes.pyobj()); } FT2Font::FT2Font(FT_Open_Args &open_args, long hinting_factor_, - std::vector &fallback_list) - : image(), face(NULL) + std::vector &fallback_list, + FT2Font::WarnFunc warn) + : ft_glyph_warn(warn), image(), face(NULL) { clear(); @@ -819,7 +782,8 @@ void FT2Font::draw_glyph_to_bitmap(FT2Image &im, int x, int y, size_t glyphInd, im.draw_bitmap(&bitmap->bitmap, x + bitmap->left, y); } -void FT2Font::get_glyph_name(unsigned int glyph_number, char *buffer, bool fallback = false) +void FT2Font::get_glyph_name(unsigned int glyph_number, std::string &buffer, + bool fallback = false) { if (fallback && glyph_to_font.find(glyph_number) != glyph_to_font.end()) { // cache is only for parent FT2Font @@ -830,9 +794,11 @@ void FT2Font::get_glyph_name(unsigned int glyph_number, char *buffer, bool fallb if (!FT_HAS_GLYPH_NAMES(face)) { /* Note that this generated name must match the name that is generated by ttconv in ttfont_CharStrings_getname. */ - PyOS_snprintf(buffer, 128, "uni%08x", glyph_number); + buffer.replace(0, 3, "uni"); + std::to_chars(buffer.data() + 3, buffer.data() + buffer.size(), + glyph_number, 16); } else { - if (FT_Error error = FT_Get_Glyph_Name(face, glyph_number, buffer, 128)) { + if (FT_Error error = FT_Get_Glyph_Name(face, glyph_number, buffer.data(), buffer.size())) { throw_ft_error("Could not get glyph names", error); } } diff --git a/src/ft2font.h b/src/ft2font.h index 66b218316e90..0b2db6fe1510 100644 --- a/src/ft2font.h +++ b/src/ft2font.h @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -71,9 +72,11 @@ 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, std::vector &fallback_list); + FT2Font(FT_Open_Args &open_args, long hinting_factor, + std::vector &fallback_list, WarnFunc warn); virtual ~FT2Font(); void clear(); void set_size(double ptsize, double dpi); @@ -106,10 +109,10 @@ class FT2Font void get_xys(bool antialiased, std::vector &xys); void draw_glyphs_to_bitmap(bool antialiased); void draw_glyph_to_bitmap(FT2Image &im, int x, int y, size_t glyphInd, bool antialiased); - void get_glyph_name(unsigned int glyph_number, char *buffer, bool fallback); + void get_glyph_name(unsigned int glyph_number, std::string &buffer, bool fallback); long get_name_index(char *name); FT_UInt get_char_index(FT_ULong charcode, bool fallback); - PyObject* get_path(); + void get_path(std::vector &vertices, std::vector &codes); bool get_char_fallback_index(FT_ULong charcode, int& index) const; FT_Face const &get_face() const @@ -143,6 +146,7 @@ class FT2Font } private: + WarnFunc ft_glyph_warn; FT2Image image; FT_Face face; FT_Vector pen; /* untransformed origin */ diff --git a/src/ft2font_wrapper.cpp b/src/ft2font_wrapper.cpp index 9e0226455972..3551d82f48e9 100644 --- a/src/ft2font_wrapper.cpp +++ b/src/ft2font_wrapper.cpp @@ -1,11 +1,13 @@ #include "mplutils.h" #include "ft2font.h" +#include "numpy_cpp.h" #include "py_converters.h" #include "py_exceptions.h" // From Python #include +#include #include static PyObject *convert_xys_to_array(std::vector &xys) @@ -308,6 +310,31 @@ static void close_file_callback(FT_Stream stream) PyErr_Restore(type, value, traceback); } +static void +ft_glyph_warn(FT_ULong charcode, std::set family_names) +{ + PyObject *text_helpers = NULL, *tmp = NULL; + std::set::iterator it = family_names.begin(); + std::stringstream ss; + ss<<*it; + while(++it != family_names.end()){ + ss<<", "<<*it; + } + + if (!(text_helpers = PyImport_ImportModule("matplotlib._text_helpers")) || + !(tmp = PyObject_CallMethod(text_helpers, + "warn_on_missing_glyph", "(k, s)", + charcode, ss.str().c_str()))) { + goto exit; + } +exit: + Py_XDECREF(text_helpers); + Py_XDECREF(tmp); + if (PyErr_Occurred()) { + throw mpl::exception(); + } +} + static PyObject *PyFT2Font_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyFT2Font *self; @@ -455,7 +482,8 @@ static int PyFT2Font_init(PyFT2Font *self, PyObject *args, PyObject *kwds) Py_CLEAR(data); CALL_CPP_FULL( - "FT2Font", (self->x = new FT2Font(open_args, hinting_factor, fallback_fonts)), + "FT2Font", + (self->x = new FT2Font(open_args, hinting_factor, fallback_fonts, ft_glyph_warn)), Py_CLEAR(self->py_file), -1); CALL_CPP_INIT("FT2Font->set_kerning_factor", (self->x->set_kerning_factor(kerning_factor))); @@ -555,13 +583,13 @@ static PyObject *PyFT2Font_get_kerning(PyFT2Font *self, PyObject *args) { FT_UInt left, right, mode; int result; - int fallback = 1; + bool fallback = true; if (!PyArg_ParseTuple(args, "III:get_kerning", &left, &right, &mode)) { return NULL; } - CALL_CPP("get_kerning", (result = self->x->get_kerning(left, right, mode, (bool)fallback))); + CALL_CPP("get_kerning", (result = self->x->get_kerning(left, right, mode, fallback))); return PyLong_FromLong(result); } @@ -704,7 +732,7 @@ const char *PyFT2Font_load_char__doc__ = static PyObject *PyFT2Font_load_char(PyFT2Font *self, PyObject *args, PyObject *kwds) { long charcode; - int fallback = 1; + bool fallback = true; FT_Int32 flags = FT_LOAD_FORCE_AUTOHINT; const char *names[] = { "charcode", "flags", NULL }; @@ -717,7 +745,7 @@ static PyObject *PyFT2Font_load_char(PyFT2Font *self, PyObject *args, PyObject * } FT2Font *ft_object = NULL; - CALL_CPP("load_char", (self->x->load_char(charcode, flags, ft_object, (bool)fallback))); + CALL_CPP("load_char", (self->x->load_char(charcode, flags, ft_object, fallback))); return PyGlyph_from_FT2Font(ft_object); } @@ -743,7 +771,7 @@ static PyObject *PyFT2Font_load_glyph(PyFT2Font *self, PyObject *args, PyObject { FT_UInt glyph_index; FT_Int32 flags = FT_LOAD_FORCE_AUTOHINT; - int fallback = 1; + bool fallback = true; const char *names[] = { "glyph_index", "flags", NULL }; /* This makes a technically incorrect assumption that FT_Int32 is @@ -755,7 +783,7 @@ static PyObject *PyFT2Font_load_glyph(PyFT2Font *self, PyObject *args, PyObject } FT2Font *ft_object = NULL; - CALL_CPP("load_glyph", (self->x->load_glyph(glyph_index, flags, ft_object, (bool)fallback))); + CALL_CPP("load_glyph", (self->x->load_glyph(glyph_index, flags, ft_object, fallback))); return PyGlyph_from_FT2Font(ft_object); } @@ -912,14 +940,16 @@ const char *PyFT2Font_get_glyph_name__doc__ = static PyObject *PyFT2Font_get_glyph_name(PyFT2Font *self, PyObject *args) { unsigned int glyph_number; - char buffer[128]; - int fallback = 1; + std::string buffer; + bool fallback = true; if (!PyArg_ParseTuple(args, "I:get_glyph_name", &glyph_number)) { return NULL; } - CALL_CPP("get_glyph_name", (self->x->get_glyph_name(glyph_number, buffer, (bool)fallback))); - return PyUnicode_FromString(buffer); + buffer.resize(128); + CALL_CPP("get_glyph_name", + (self->x->get_glyph_name(glyph_number, buffer, fallback))); + return PyUnicode_FromString(buffer.c_str()); } const char *PyFT2Font_get_charmap__doc__ = @@ -962,13 +992,13 @@ static PyObject *PyFT2Font_get_char_index(PyFT2Font *self, PyObject *args) { FT_UInt index; FT_ULong ccode; - int fallback = 1; + bool fallback = true; if (!PyArg_ParseTuple(args, "k:get_char_index", &ccode)) { return NULL; } - CALL_CPP("get_char_index", index = self->x->get_char_index(ccode, (bool)fallback)); + CALL_CPP("get_char_index", index = self->x->get_char_index(ccode, fallback)); return PyLong_FromLong(index); } @@ -1270,7 +1300,20 @@ const char *PyFT2Font_get_path__doc__ = static PyObject *PyFT2Font_get_path(PyFT2Font *self, PyObject *args) { - CALL_CPP("get_path", return self->x->get_path()); + std::vector vertices; + std::vector codes; + + CALL_CPP("get_path", self->x->get_path(vertices, codes)); + + npy_intp length = codes.size(); + npy_intp vertices_dims[2] = { length, 2 }; + numpy::array_view vertices_arr(vertices_dims); + memcpy(vertices_arr.data(), vertices.data(), sizeof(double) * vertices.size()); + npy_intp codes_dims[1] = { length }; + numpy::array_view codes_arr(codes_dims); + memcpy(codes_arr.data(), codes.data(), codes.size()); + + return Py_BuildValue("NN", vertices_arr.pyobj(), codes_arr.pyobj()); } const char *PyFT2Font_get_image__doc__ = From 9765ea168c8efec9175a1cd9fa0226c5f990389b Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 6 Mar 2024 04:12:59 -0500 Subject: [PATCH 3/5] Use std::vector directly with FT_Outline_Decompose This means we only need to do one pass through. --- src/ft2font.cpp | 108 ++++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 63 deletions(-) diff --git a/src/ft2font.cpp b/src/ft2font.cpp index 41203340dd47..f2dc2adf91f5 100644 --- a/src/ft2font.cpp +++ b/src/ft2font.cpp @@ -183,35 +183,26 @@ FT2Image::draw_rect_filled(unsigned long x0, unsigned long y0, unsigned long x1, m_dirty = true; } -// ft_outline_decomposer should be passed to FT_Outline_Decompose. On the -// first pass, vertices and codes are set to NULL, and index is simply -// incremented for each vertex that should be inserted, so that it is set, at -// the end, to the total number of vertices. On a second pass, vertices and -// codes should point to correctly sized arrays, and index set again to zero, -// to get fill vertices and codes with the outline decomposition. +// ft_outline_decomposer should be passed to FT_Outline_Decompose. struct ft_outline_decomposer { - int index; - double* vertices; - unsigned char* codes; + std::vector &vertices; + std::vector &codes; }; static int ft_outline_move_to(FT_Vector const* to, void* user) { ft_outline_decomposer* d = reinterpret_cast(user); - if (d->codes) { - if (d->index) { - // Appending CLOSEPOLY is important to make patheffects work. - *(d->vertices++) = 0; - *(d->vertices++) = 0; - *(d->codes++) = CLOSEPOLY; - } - *(d->vertices++) = to->x * (1. / 64.); - *(d->vertices++) = to->y * (1. / 64.); - *(d->codes++) = MOVETO; - } - d->index += d->index ? 2 : 1; + if (!d->vertices.empty()) { + // Appending CLOSEPOLY is important to make patheffects work. + d->vertices.push_back(0); + d->vertices.push_back(0); + d->codes.push_back(CLOSEPOLY); + } + d->vertices.push_back(to->x * (1. / 64.)); + d->vertices.push_back(to->y * (1. / 64.)); + d->codes.push_back(MOVETO); return 0; } @@ -219,12 +210,9 @@ static int ft_outline_line_to(FT_Vector const* to, void* user) { ft_outline_decomposer* d = reinterpret_cast(user); - if (d->codes) { - *(d->vertices++) = to->x * (1. / 64.); - *(d->vertices++) = to->y * (1. / 64.); - *(d->codes++) = LINETO; - } - d->index++; + d->vertices.push_back(to->x * (1. / 64.)); + d->vertices.push_back(to->y * (1. / 64.)); + d->codes.push_back(LINETO); return 0; } @@ -232,15 +220,12 @@ static int ft_outline_conic_to(FT_Vector const* control, FT_Vector const* to, void* user) { ft_outline_decomposer* d = reinterpret_cast(user); - if (d->codes) { - *(d->vertices++) = control->x * (1. / 64.); - *(d->vertices++) = control->y * (1. / 64.); - *(d->vertices++) = to->x * (1. / 64.); - *(d->vertices++) = to->y * (1. / 64.); - *(d->codes++) = CURVE3; - *(d->codes++) = CURVE3; - } - d->index += 2; + d->vertices.push_back(control->x * (1. / 64.)); + d->vertices.push_back(control->y * (1. / 64.)); + d->vertices.push_back(to->x * (1. / 64.)); + d->vertices.push_back(to->y * (1. / 64.)); + d->codes.push_back(CURVE3); + d->codes.push_back(CURVE3); return 0; } @@ -249,18 +234,15 @@ ft_outline_cubic_to( FT_Vector const* c1, FT_Vector const* c2, FT_Vector const* to, void* user) { ft_outline_decomposer* d = reinterpret_cast(user); - if (d->codes) { - *(d->vertices++) = c1->x * (1. / 64.); - *(d->vertices++) = c1->y * (1. / 64.); - *(d->vertices++) = c2->x * (1. / 64.); - *(d->vertices++) = c2->y * (1. / 64.); - *(d->vertices++) = to->x * (1. / 64.); - *(d->vertices++) = to->y * (1. / 64.); - *(d->codes++) = CURVE4; - *(d->codes++) = CURVE4; - *(d->codes++) = CURVE4; - } - d->index += 3; + d->vertices.push_back(c1->x * (1. / 64.)); + d->vertices.push_back(c1->y * (1. / 64.)); + d->vertices.push_back(c2->x * (1. / 64.)); + d->vertices.push_back(c2->y * (1. / 64.)); + d->vertices.push_back(to->x * (1. / 64.)); + d->vertices.push_back(to->y * (1. / 64.)); + d->codes.push_back(CURVE4); + d->codes.push_back(CURVE4); + d->codes.push_back(CURVE4); return 0; } @@ -276,28 +258,28 @@ FT2Font::get_path(std::vector &vertices, std::vector &cod if (!face->glyph) { throw std::runtime_error("No glyph loaded"); } - ft_outline_decomposer decomposer = {}; + ft_outline_decomposer decomposer = { + vertices, + codes, + }; + // We can make a close-enough estimate based on number of points and number of + // contours (which produce a MOVETO each), though it's slightly underestimating due + // to higher-order curves. + size_t estimated_points = static_cast(face->glyph->outline.n_contours) + + static_cast(face->glyph->outline.n_points); + vertices.reserve(2 * estimated_points); + codes.reserve(estimated_points); if (FT_Error error = FT_Outline_Decompose( &face->glyph->outline, &ft_outline_funcs, &decomposer)) { throw std::runtime_error("FT_Outline_Decompose failed with error " + std::to_string(error)); } - if (!decomposer.index) { // Don't append CLOSEPOLY to null glyphs. + if (vertices.empty()) { // Don't append CLOSEPOLY to null glyphs. return; } - vertices.resize((decomposer.index + 1) * 2); - codes.resize(decomposer.index + 1); - decomposer.index = 0; - decomposer.vertices = vertices.data(); - decomposer.codes = codes.data(); - if (FT_Error error = FT_Outline_Decompose( - &face->glyph->outline, &ft_outline_funcs, &decomposer)) { - throw std::runtime_error("FT_Outline_Decompose failed with error " + - std::to_string(error)); - } - *(decomposer.vertices++) = 0; - *(decomposer.vertices++) = 0; - *(decomposer.codes++) = CLOSEPOLY; + vertices.push_back(0); + vertices.push_back(0); + codes.push_back(CLOSEPOLY); } FT2Font::FT2Font(FT_Open_Args &open_args, From d3da65f5d10e05c8cfd7a3cccfdfc8df115fc7b2 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 14 Aug 2024 19:35:23 -0400 Subject: [PATCH 4/5] Remove deprecated ft2font API --- .../next_api_changes/removals/27891-ES.rst | 4 ++ lib/matplotlib/ft2font.pyi | 2 - src/ft2font.cpp | 44 ------------- src/ft2font.h | 4 -- src/ft2font_wrapper.cpp | 62 ------------------- 5 files changed, 4 insertions(+), 112 deletions(-) create mode 100644 doc/api/next_api_changes/removals/27891-ES.rst diff --git a/doc/api/next_api_changes/removals/27891-ES.rst b/doc/api/next_api_changes/removals/27891-ES.rst new file mode 100644 index 000000000000..cb658e9bc671 --- /dev/null +++ b/doc/api/next_api_changes/removals/27891-ES.rst @@ -0,0 +1,4 @@ +``ft2font.FT2Image.draw_rect`` and ``ft2font.FT2Font.get_xys`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... have been removed as they are unused. diff --git a/lib/matplotlib/ft2font.pyi b/lib/matplotlib/ft2font.pyi index d47614cc6f48..0a27411ff39c 100644 --- a/lib/matplotlib/ft2font.pyi +++ b/lib/matplotlib/ft2font.pyi @@ -224,7 +224,6 @@ class FT2Font: @overload def get_sfnt_table(self, name: Literal["pclt"]) -> _SfntPcltDict | None: ... def get_width_height(self) -> tuple[int, int]: ... - def get_xys(self, antialiased: bool = ...) -> NDArray[np.float64]: ... def load_char(self, charcode: int, flags: int = ...) -> Glyph: ... def load_glyph(self, glyphindex: int, flags: int = ...) -> Glyph: ... def select_charmap(self, i: int) -> None: ... @@ -237,7 +236,6 @@ class FT2Font: @final class FT2Image: # TODO: When updating mypy>=1.4, subclass from Buffer. def __init__(self, width: float, height: float) -> None: ... - def draw_rect(self, x0: float, y0: float, x1: float, y1: float) -> None: ... def draw_rect_filled(self, x0: float, y0: float, x1: float, y1: float) -> None: ... @final diff --git a/src/ft2font.cpp b/src/ft2font.cpp index f2dc2adf91f5..d78d696e118f 100644 --- a/src/ft2font.cpp +++ b/src/ft2font.cpp @@ -145,27 +145,6 @@ void FT2Image::draw_bitmap(FT_Bitmap *bitmap, FT_Int x, FT_Int y) m_dirty = true; } -void FT2Image::draw_rect(unsigned long x0, unsigned long y0, unsigned long x1, unsigned long y1) -{ - if (x0 > m_width || x1 > m_width || y0 > m_height || y1 > m_height) { - throw std::runtime_error("Rect coords outside image bounds"); - } - - size_t top = y0 * m_width; - size_t bottom = y1 * m_width; - for (size_t i = x0; i < x1 + 1; ++i) { - m_buffer[i + top] = 255; - m_buffer[i + bottom] = 255; - } - - for (size_t j = y0 + 1; j < y1; ++j) { - m_buffer[x0 + j * m_width] = 255; - m_buffer[x1 + j * m_width] = 255; - } - - m_dirty = true; -} - void FT2Image::draw_rect_filled(unsigned long x0, unsigned long y0, unsigned long x1, unsigned long y1) { @@ -716,29 +695,6 @@ void FT2Font::draw_glyphs_to_bitmap(bool antialiased) } } -void FT2Font::get_xys(bool antialiased, std::vector &xys) -{ - for (size_t n = 0; n < glyphs.size(); n++) { - - FT_Error error = FT_Glyph_To_Bitmap( - &glyphs[n], antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, 0, 1); - if (error) { - throw_ft_error("Could not convert glyph to bitmap", error); - } - - FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyphs[n]; - - // bitmap left and top in pixel, string bbox in subpixel - FT_Int x = (FT_Int)(bitmap->left - bbox.xMin * (1. / 64.)); - FT_Int y = (FT_Int)(bbox.yMax * (1. / 64.) - bitmap->top + 1); - // make sure the index is non-neg - x = x < 0 ? 0 : x; - y = y < 0 ? 0 : y; - xys.push_back(x); - xys.push_back(y); - } -} - void FT2Font::draw_glyph_to_bitmap(FT2Image &im, int x, int y, size_t glyphInd, bool antialiased) { FT_Vector sub_offset; diff --git a/src/ft2font.h b/src/ft2font.h index 0b2db6fe1510..4bd924497978 100644 --- a/src/ft2font.h +++ b/src/ft2font.h @@ -41,7 +41,6 @@ class FT2Image void resize(long width, long height); void draw_bitmap(FT_Bitmap *bitmap, FT_Int x, FT_Int y); - void draw_rect(unsigned long x0, unsigned long y0, unsigned long x1, unsigned long y1); void draw_rect_filled(unsigned long x0, unsigned long y0, unsigned long x1, unsigned long y1); unsigned char *get_buffer() @@ -104,9 +103,6 @@ class FT2Font void get_width_height(long *width, long *height); void get_bitmap_offset(long *x, long *y); long get_descent(); - // TODO: Since we know the size of the array upfront, we probably don't - // need to dynamically allocate like this - void get_xys(bool antialiased, std::vector &xys); void draw_glyphs_to_bitmap(bool antialiased); void draw_glyph_to_bitmap(FT2Image &im, int x, int y, size_t glyphInd, bool antialiased); void get_glyph_name(unsigned int glyph_number, std::string &buffer, bool fallback); diff --git a/src/ft2font_wrapper.cpp b/src/ft2font_wrapper.cpp index 3551d82f48e9..6d6e8722b63b 100644 --- a/src/ft2font_wrapper.cpp +++ b/src/ft2font_wrapper.cpp @@ -63,35 +63,6 @@ static void PyFT2Image_dealloc(PyFT2Image *self) Py_TYPE(self)->tp_free((PyObject *)self); } -const char *PyFT2Image_draw_rect__doc__ = - "draw_rect(self, x0, y0, x1, y1)\n" - "--\n\n" - "Draw an empty rectangle to the image.\n" - "\n" - ".. deprecated:: 3.8\n"; -; - -static PyObject *PyFT2Image_draw_rect(PyFT2Image *self, PyObject *args) -{ - char const* msg = - "FT2Image.draw_rect is deprecated since Matplotlib 3.8 and will be removed " - "in Matplotlib 3.10 as it is not used in the library. If you rely on it, " - "please let us know."; - if (PyErr_WarnEx(PyExc_DeprecationWarning, msg, 1)) { - return NULL; - } - - double x0, y0, x1, y1; - - if (!PyArg_ParseTuple(args, "dddd:draw_rect", &x0, &y0, &x1, &y1)) { - return NULL; - } - - CALL_CPP("draw_rect", (self->x->draw_rect(x0, y0, x1, y1))); - - Py_RETURN_NONE; -} - const char *PyFT2Image_draw_rect_filled__doc__ = "draw_rect_filled(self, x0, y0, x1, y1)\n" "--\n\n" @@ -137,7 +108,6 @@ static int PyFT2Image_get_buffer(PyFT2Image *self, Py_buffer *buf, int flags) static PyTypeObject* PyFT2Image_init_type() { static PyMethodDef methods[] = { - {"draw_rect", (PyCFunction)PyFT2Image_draw_rect, METH_VARARGS, PyFT2Image_draw_rect__doc__}, {"draw_rect_filled", (PyCFunction)PyFT2Image_draw_rect_filled, METH_VARARGS, PyFT2Image_draw_rect_filled__doc__}, {NULL} }; @@ -856,37 +826,6 @@ static PyObject *PyFT2Font_draw_glyphs_to_bitmap(PyFT2Font *self, PyObject *args Py_RETURN_NONE; } -const char *PyFT2Font_get_xys__doc__ = - "get_xys(self, antialiased=True)\n" - "--\n\n" - "Get the xy locations of the current glyphs.\n" - "\n" - ".. deprecated:: 3.8\n"; - -static PyObject *PyFT2Font_get_xys(PyFT2Font *self, PyObject *args, PyObject *kwds) -{ - char const* msg = - "FT2Font.get_xys is deprecated since Matplotlib 3.8 and will be removed in " - "Matplotlib 3.10 as it is not used in the library. If you rely on it, " - "please let us know."; - if (PyErr_WarnEx(PyExc_DeprecationWarning, msg, 1)) { - return NULL; - } - - bool antialiased = true; - std::vector xys; - const char *names[] = { "antialiased", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&:get_xys", - (char **)names, &convert_bool, &antialiased)) { - return NULL; - } - - CALL_CPP("get_xys", (self->x->get_xys(antialiased, xys))); - - return convert_xys_to_array(xys); -} - const char *PyFT2Font_draw_glyph_to_bitmap__doc__ = "draw_glyph_to_bitmap(self, image, x, y, glyph, antialiased=True)\n" "--\n\n" @@ -1517,7 +1456,6 @@ static PyTypeObject *PyFT2Font_init_type() {"get_bitmap_offset", (PyCFunction)PyFT2Font_get_bitmap_offset, METH_NOARGS, PyFT2Font_get_bitmap_offset__doc__}, {"get_descent", (PyCFunction)PyFT2Font_get_descent, METH_NOARGS, PyFT2Font_get_descent__doc__}, {"draw_glyphs_to_bitmap", (PyCFunction)PyFT2Font_draw_glyphs_to_bitmap, METH_VARARGS|METH_KEYWORDS, PyFT2Font_draw_glyphs_to_bitmap__doc__}, - {"get_xys", (PyCFunction)PyFT2Font_get_xys, METH_VARARGS|METH_KEYWORDS, PyFT2Font_get_xys__doc__}, {"draw_glyph_to_bitmap", (PyCFunction)PyFT2Font_draw_glyph_to_bitmap, METH_VARARGS|METH_KEYWORDS, PyFT2Font_draw_glyph_to_bitmap__doc__}, {"get_glyph_name", (PyCFunction)PyFT2Font_get_glyph_name, METH_VARARGS, PyFT2Font_get_glyph_name__doc__}, {"get_charmap", (PyCFunction)PyFT2Font_get_charmap, METH_NOARGS, PyFT2Font_get_charmap__doc__}, From 276fade9e375c3598a35f373e07f778c95baa066 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Thu, 22 Aug 2024 21:29:39 -0400 Subject: [PATCH 5/5] Remove unused FT2Image.m_dirty It is set in a few places, but never read. --- src/ft2font.cpp | 10 ++-------- src/ft2font.h | 1 - 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/ft2font.cpp b/src/ft2font.cpp index d78d696e118f..cb9952f3b374 100644 --- a/src/ft2font.cpp +++ b/src/ft2font.cpp @@ -63,12 +63,12 @@ void throw_ft_error(std::string message, FT_Error error) { throw std::runtime_error(os.str()); } -FT2Image::FT2Image() : m_dirty(true), m_buffer(NULL), m_width(0), m_height(0) +FT2Image::FT2Image() : m_buffer(NULL), m_width(0), m_height(0) { } FT2Image::FT2Image(unsigned long width, unsigned long height) - : m_dirty(true), m_buffer(NULL), m_width(0), m_height(0) + : m_buffer(NULL), m_width(0), m_height(0) { resize(width, height); } @@ -102,8 +102,6 @@ void FT2Image::resize(long width, long height) if (numBytes && m_buffer) { memset(m_buffer, 0, numBytes); } - - m_dirty = true; } void FT2Image::draw_bitmap(FT_Bitmap *bitmap, FT_Int x, FT_Int y) @@ -141,8 +139,6 @@ void FT2Image::draw_bitmap(FT_Bitmap *bitmap, FT_Int x, FT_Int y) } else { throw std::runtime_error("Unknown pixel mode"); } - - m_dirty = true; } void @@ -158,8 +154,6 @@ FT2Image::draw_rect_filled(unsigned long x0, unsigned long y0, unsigned long x1, m_buffer[i + j * m_width] = 255; } } - - m_dirty = true; } // ft_outline_decomposer should be passed to FT_Outline_Decompose. diff --git a/src/ft2font.h b/src/ft2font.h index 4bd924497978..2f24bfb01f79 100644 --- a/src/ft2font.h +++ b/src/ft2font.h @@ -57,7 +57,6 @@ class FT2Image } private: - bool m_dirty; unsigned char *m_buffer; unsigned long m_width; unsigned long m_height; 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