Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 53d1fed

Browse files
committed
Move Python code from ft2font to its wrapper
This improves the encapsulation and separation of concerns between the files.
1 parent 0a25159 commit 53d1fed

File tree

3 files changed

+89
-76
lines changed

3 files changed

+89
-76
lines changed

src/ft2font.cpp

Lines changed: 26 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
/* -*- mode: c++; c-basic-offset: 4 -*- */
22

3-
#define NO_IMPORT_ARRAY
4-
53
#include <algorithm>
4+
#include <charconv>
65
#include <iterator>
76
#include <set>
87
#include <sstream>
98
#include <stdexcept>
109
#include <string>
10+
#include <vector>
1111

1212
#include "ft2font.h"
1313
#include "mplutils.h"
14-
#include "numpy_cpp.h"
15-
#include "py_exceptions.h"
1614

1715
#ifndef M_PI
1816
#define M_PI 3.14159265358979323846264338328
@@ -185,30 +183,6 @@ FT2Image::draw_rect_filled(unsigned long x0, unsigned long y0, unsigned long x1,
185183
m_dirty = true;
186184
}
187185

188-
static void ft_glyph_warn(FT_ULong charcode, std::set<FT_String*> family_names)
189-
{
190-
PyObject *text_helpers = NULL, *tmp = NULL;
191-
std::set<FT_String*>::iterator it = family_names.begin();
192-
std::stringstream ss;
193-
ss<<*it;
194-
while(++it != family_names.end()){
195-
ss<<", "<<*it;
196-
}
197-
198-
if (!(text_helpers = PyImport_ImportModule("matplotlib._text_helpers")) ||
199-
!(tmp = PyObject_CallMethod(text_helpers,
200-
"warn_on_missing_glyph", "(k, s)",
201-
charcode, ss.str().c_str()))) {
202-
goto exit;
203-
}
204-
exit:
205-
Py_XDECREF(text_helpers);
206-
Py_XDECREF(tmp);
207-
if (PyErr_Occurred()) {
208-
throw mpl::exception();
209-
}
210-
}
211-
212186
// ft_outline_decomposer should be passed to FT_Outline_Decompose. On the
213187
// first pass, vertices and codes are set to NULL, and index is simply
214188
// 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 = {
296270
ft_outline_conic_to,
297271
ft_outline_cubic_to};
298272

299-
PyObject*
300-
FT2Font::get_path()
273+
void
274+
FT2Font::get_path(std::vector<double> &vertices, std::vector<unsigned char> &codes)
301275
{
302276
if (!face->glyph) {
303-
PyErr_SetString(PyExc_RuntimeError, "No glyph loaded");
304-
return NULL;
277+
throw std::runtime_error("No glyph loaded");
305278
}
306279
ft_outline_decomposer decomposer = {};
307-
if (FT_Error error =
308-
FT_Outline_Decompose(
309-
&face->glyph->outline, &ft_outline_funcs, &decomposer)) {
310-
PyErr_Format(PyExc_RuntimeError,
311-
"FT_Outline_Decompose failed with error 0x%x", error);
312-
return NULL;
280+
if (FT_Error error = FT_Outline_Decompose(
281+
&face->glyph->outline, &ft_outline_funcs, &decomposer)) {
282+
throw std::runtime_error("FT_Outline_Decompose failed with error " +
283+
std::to_string(error));
313284
}
314285
if (!decomposer.index) { // Don't append CLOSEPOLY to null glyphs.
315-
npy_intp vertices_dims[2] = { 0, 2 };
316-
numpy::array_view<double, 2> vertices(vertices_dims);
317-
npy_intp codes_dims[1] = { 0 };
318-
numpy::array_view<unsigned char, 1> codes(codes_dims);
319-
return Py_BuildValue("NN", vertices.pyobj(), codes.pyobj());
320-
}
321-
npy_intp vertices_dims[2] = { decomposer.index + 1, 2 };
322-
numpy::array_view<double, 2> vertices(vertices_dims);
323-
npy_intp codes_dims[1] = { decomposer.index + 1 };
324-
numpy::array_view<unsigned char, 1> codes(codes_dims);
286+
return;
287+
}
288+
vertices.resize((decomposer.index + 1) * 2);
289+
codes.resize(decomposer.index + 1);
325290
decomposer.index = 0;
326291
decomposer.vertices = vertices.data();
327292
decomposer.codes = codes.data();
328-
if (FT_Error error =
329-
FT_Outline_Decompose(
330-
&face->glyph->outline, &ft_outline_funcs, &decomposer)) {
331-
PyErr_Format(PyExc_RuntimeError,
332-
"FT_Outline_Decompose failed with error 0x%x", error);
333-
return NULL;
293+
if (FT_Error error = FT_Outline_Decompose(
294+
&face->glyph->outline, &ft_outline_funcs, &decomposer)) {
295+
throw std::runtime_error("FT_Outline_Decompose failed with error " +
296+
std::to_string(error));
334297
}
335298
*(decomposer.vertices++) = 0;
336299
*(decomposer.vertices++) = 0;
337300
*(decomposer.codes++) = CLOSEPOLY;
338-
return Py_BuildValue("NN", vertices.pyobj(), codes.pyobj());
339301
}
340302

341303
FT2Font::FT2Font(FT_Open_Args &open_args,
342304
long hinting_factor_,
343-
std::vector<FT2Font *> &fallback_list)
344-
: image(), face(NULL)
305+
std::vector<FT2Font *> &fallback_list,
306+
FT2Font::WarnFunc warn)
307+
: ft_glyph_warn(warn), image(), face(NULL)
345308
{
346309
clear();
347310

@@ -819,7 +782,8 @@ void FT2Font::draw_glyph_to_bitmap(FT2Image &im, int x, int y, size_t glyphInd,
819782
im.draw_bitmap(&bitmap->bitmap, x + bitmap->left, y);
820783
}
821784

822-
void FT2Font::get_glyph_name(unsigned int glyph_number, char *buffer, bool fallback = false)
785+
void FT2Font::get_glyph_name(unsigned int glyph_number, std::string &buffer,
786+
bool fallback = false)
823787
{
824788
if (fallback && glyph_to_font.find(glyph_number) != glyph_to_font.end()) {
825789
// cache is only for parent FT2Font
@@ -830,9 +794,11 @@ void FT2Font::get_glyph_name(unsigned int glyph_number, char *buffer, bool fallb
830794
if (!FT_HAS_GLYPH_NAMES(face)) {
831795
/* Note that this generated name must match the name that
832796
is generated by ttconv in ttfont_CharStrings_getname. */
833-
PyOS_snprintf(buffer, 128, "uni%08x", glyph_number);
797+
buffer.replace(0, 3, "uni");
798+
std::to_chars(buffer.data() + 3, buffer.data() + buffer.size(),
799+
glyph_number, 16);
834800
} else {
835-
if (FT_Error error = FT_Get_Glyph_Name(face, glyph_number, buffer, 128)) {
801+
if (FT_Error error = FT_Get_Glyph_Name(face, glyph_number, buffer.data(), buffer.size())) {
836802
throw_ft_error("Could not get glyph names", error);
837803
}
838804
}

src/ft2font.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <cstdint>
1313
#include <set>
14+
#include <string>
1415
#include <unordered_map>
1516
#include <vector>
1617

@@ -71,9 +72,11 @@ extern FT_Library _ft2Library;
7172

7273
class FT2Font
7374
{
75+
typedef void (*WarnFunc)(FT_ULong charcode, std::set<FT_String*> family_names);
7476

7577
public:
76-
FT2Font(FT_Open_Args &open_args, long hinting_factor, std::vector<FT2Font *> &fallback_list);
78+
FT2Font(FT_Open_Args &open_args, long hinting_factor,
79+
std::vector<FT2Font *> &fallback_list, WarnFunc warn);
7780
virtual ~FT2Font();
7881
void clear();
7982
void set_size(double ptsize, double dpi);
@@ -106,10 +109,10 @@ class FT2Font
106109
void get_xys(bool antialiased, std::vector<double> &xys);
107110
void draw_glyphs_to_bitmap(bool antialiased);
108111
void draw_glyph_to_bitmap(FT2Image &im, int x, int y, size_t glyphInd, bool antialiased);
109-
void get_glyph_name(unsigned int glyph_number, char *buffer, bool fallback);
112+
void get_glyph_name(unsigned int glyph_number, std::string &buffer, bool fallback);
110113
long get_name_index(char *name);
111114
FT_UInt get_char_index(FT_ULong charcode, bool fallback);
112-
PyObject* get_path();
115+
void get_path(std::vector<double> &vertices, std::vector<unsigned char> &codes);
113116
bool get_char_fallback_index(FT_ULong charcode, int& index) const;
114117

115118
FT_Face const &get_face() const
@@ -143,6 +146,7 @@ class FT2Font
143146
}
144147

145148
private:
149+
WarnFunc ft_glyph_warn;
146150
FT2Image image;
147151
FT_Face face;
148152
FT_Vector pen; /* untransformed origin */

src/ft2font_wrapper.cpp

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
#include "mplutils.h"
22
#include "ft2font.h"
3+
#include "numpy_cpp.h"
34
#include "py_converters.h"
45
#include "py_exceptions.h"
56

67
// From Python
78
#include <structmember.h>
89

10+
#include <sstream>
911
#include <set>
1012

1113
static PyObject *convert_xys_to_array(std::vector<double> &xys)
@@ -308,6 +310,31 @@ static void close_file_callback(FT_Stream stream)
308310
PyErr_Restore(type, value, traceback);
309311
}
310312

313+
static void
314+
ft_glyph_warn(FT_ULong charcode, std::set<FT_String*> family_names)
315+
{
316+
PyObject *text_helpers = NULL, *tmp = NULL;
317+
std::set<FT_String*>::iterator it = family_names.begin();
318+
std::stringstream ss;
319+
ss<<*it;
320+
while(++it != family_names.end()){
321+
ss<<", "<<*it;
322+
}
323+
324+
if (!(text_helpers = PyImport_ImportModule("matplotlib._text_helpers")) ||
325+
!(tmp = PyObject_CallMethod(text_helpers,
326+
"warn_on_missing_glyph", "(k, s)",
327+
charcode, ss.str().c_str()))) {
328+
goto exit;
329+
}
330+
exit:
331+
Py_XDECREF(text_helpers);
332+
Py_XDECREF(tmp);
333+
if (PyErr_Occurred()) {
334+
throw mpl::exception();
335+
}
336+
}
337+
311338
static PyObject *PyFT2Font_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
312339
{
313340
PyFT2Font *self;
@@ -455,7 +482,8 @@ static int PyFT2Font_init(PyFT2Font *self, PyObject *args, PyObject *kwds)
455482
Py_CLEAR(data);
456483

457484
CALL_CPP_FULL(
458-
"FT2Font", (self->x = new FT2Font(open_args, hinting_factor, fallback_fonts)),
485+
"FT2Font",
486+
(self->x = new FT2Font(open_args, hinting_factor, fallback_fonts, ft_glyph_warn)),
459487
Py_CLEAR(self->py_file), -1);
460488

461489
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)
555583
{
556584
FT_UInt left, right, mode;
557585
int result;
558-
int fallback = 1;
586+
bool fallback = true;
559587

560588
if (!PyArg_ParseTuple(args, "III:get_kerning", &left, &right, &mode)) {
561589
return NULL;
562590
}
563591

564-
CALL_CPP("get_kerning", (result = self->x->get_kerning(left, right, mode, (bool)fallback)));
592+
CALL_CPP("get_kerning", (result = self->x->get_kerning(left, right, mode, fallback)));
565593

566594
return PyLong_FromLong(result);
567595
}
@@ -704,7 +732,7 @@ const char *PyFT2Font_load_char__doc__ =
704732
static PyObject *PyFT2Font_load_char(PyFT2Font *self, PyObject *args, PyObject *kwds)
705733
{
706734
long charcode;
707-
int fallback = 1;
735+
bool fallback = true;
708736
FT_Int32 flags = FT_LOAD_FORCE_AUTOHINT;
709737
const char *names[] = { "charcode", "flags", NULL };
710738

@@ -717,7 +745,7 @@ static PyObject *PyFT2Font_load_char(PyFT2Font *self, PyObject *args, PyObject *
717745
}
718746

719747
FT2Font *ft_object = NULL;
720-
CALL_CPP("load_char", (self->x->load_char(charcode, flags, ft_object, (bool)fallback)));
748+
CALL_CPP("load_char", (self->x->load_char(charcode, flags, ft_object, fallback)));
721749

722750
return PyGlyph_from_FT2Font(ft_object);
723751
}
@@ -743,7 +771,7 @@ static PyObject *PyFT2Font_load_glyph(PyFT2Font *self, PyObject *args, PyObject
743771
{
744772
FT_UInt glyph_index;
745773
FT_Int32 flags = FT_LOAD_FORCE_AUTOHINT;
746-
int fallback = 1;
774+
bool fallback = true;
747775
const char *names[] = { "glyph_index", "flags", NULL };
748776

749777
/* This makes a technically incorrect assumption that FT_Int32 is
@@ -755,7 +783,7 @@ static PyObject *PyFT2Font_load_glyph(PyFT2Font *self, PyObject *args, PyObject
755783
}
756784

757785
FT2Font *ft_object = NULL;
758-
CALL_CPP("load_glyph", (self->x->load_glyph(glyph_index, flags, ft_object, (bool)fallback)));
786+
CALL_CPP("load_glyph", (self->x->load_glyph(glyph_index, flags, ft_object, fallback)));
759787

760788
return PyGlyph_from_FT2Font(ft_object);
761789
}
@@ -912,14 +940,16 @@ const char *PyFT2Font_get_glyph_name__doc__ =
912940
static PyObject *PyFT2Font_get_glyph_name(PyFT2Font *self, PyObject *args)
913941
{
914942
unsigned int glyph_number;
915-
char buffer[128];
943+
std::string buffer;
916944
int fallback = 1;
917945

918946
if (!PyArg_ParseTuple(args, "I:get_glyph_name", &glyph_number)) {
919947
return NULL;
920948
}
921-
CALL_CPP("get_glyph_name", (self->x->get_glyph_name(glyph_number, buffer, (bool)fallback)));
922-
return PyUnicode_FromString(buffer);
949+
buffer.resize(128);
950+
CALL_CPP("get_glyph_name",
951+
(self->x->get_glyph_name(glyph_number, buffer, fallback)));
952+
return PyUnicode_FromString(buffer.c_str());
923953
}
924954

925955
const char *PyFT2Font_get_charmap__doc__ =
@@ -962,13 +992,13 @@ static PyObject *PyFT2Font_get_char_index(PyFT2Font *self, PyObject *args)
962992
{
963993
FT_UInt index;
964994
FT_ULong ccode;
965-
int fallback = 1;
995+
bool fallback = true;
966996

967997
if (!PyArg_ParseTuple(args, "k:get_char_index", &ccode)) {
968998
return NULL;
969999
}
9701000

971-
CALL_CPP("get_char_index", index = self->x->get_char_index(ccode, (bool)fallback));
1001+
CALL_CPP("get_char_index", index = self->x->get_char_index(ccode, fallback));
9721002

9731003
return PyLong_FromLong(index);
9741004
}
@@ -1270,7 +1300,20 @@ const char *PyFT2Font_get_path__doc__ =
12701300

12711301
static PyObject *PyFT2Font_get_path(PyFT2Font *self, PyObject *args)
12721302
{
1273-
CALL_CPP("get_path", return self->x->get_path());
1303+
std::vector<double> vertices;
1304+
std::vector<unsigned char> codes;
1305+
1306+
CALL_CPP("get_path", self->x->get_path(vertices, codes));
1307+
1308+
npy_intp length = codes.size();
1309+
npy_intp vertices_dims[2] = { length, 2 };
1310+
numpy::array_view<double, 2> vertices_arr(vertices_dims);
1311+
memcpy(vertices_arr.data(), vertices.data(), sizeof(double) * vertices.size());
1312+
npy_intp codes_dims[1] = { length };
1313+
numpy::array_view<unsigned char, 1> codes_arr(codes_dims);
1314+
memcpy(codes_arr.data(), codes.data(), codes.size());
1315+
1316+
return Py_BuildValue("NN", vertices_arr.pyobj(), codes_arr.pyobj());
12741317
}
12751318

12761319
const char *PyFT2Font_get_image__doc__ =

0 commit comments

Comments
 (0)