Skip to content

Commit 9d4a5f0

Browse files
committed
ft2font: Convert flag properties to enums
1 parent 4f0cadd commit 9d4a5f0

File tree

5 files changed

+167
-53
lines changed

5 files changed

+167
-53
lines changed

lib/matplotlib/backends/backend_pdf.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
from matplotlib.figure import Figure
3636
from matplotlib.font_manager import get_font, fontManager as _fontManager
3737
from matplotlib._afm import AFM
38-
from matplotlib.ft2font import FIXED_WIDTH, ITALIC, FT2Font, Kerning, LoadFlags
38+
from matplotlib.ft2font import FT2Font, FaceFlags, Kerning, LoadFlags, StyleFlags
3939
from matplotlib.transforms import Affine2D, BboxBase
4040
from matplotlib.path import Path
4141
from matplotlib.dates import UTC
@@ -1416,15 +1416,15 @@ def embedTTFType42(font, characters, descriptor):
14161416

14171417
flags = 0
14181418
symbolic = False # ps_name.name in ('Cmsy10', 'Cmmi10', 'Cmex10')
1419-
if ff & FIXED_WIDTH:
1419+
if FaceFlags.FIXED_WIDTH in ff:
14201420
flags |= 1 << 0
14211421
if 0: # TODO: serif
14221422
flags |= 1 << 1
14231423
if symbolic:
14241424
flags |= 1 << 2
14251425
else:
14261426
flags |= 1 << 5
1427-
if sf & ITALIC:
1427+
if StyleFlags.ITALIC in sf:
14281428
flags |= 1 << 6
14291429
if 0: # TODO: all caps
14301430
flags |= 1 << 16

lib/matplotlib/font_manager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ def ttfFontProperty(font):
381381
style = 'italic'
382382
elif sfnt2.find('regular') >= 0:
383383
style = 'normal'
384-
elif font.style_flags & ft2font.ITALIC:
384+
elif ft2font.StyleFlags.ITALIC in font.style_flags:
385385
style = 'italic'
386386
else:
387387
style = 'normal'
@@ -430,7 +430,7 @@ def get_weight(): # From fontconfig's FcFreeTypeQueryFaceInternal.
430430
for regex, weight in _weight_regexes:
431431
if re.search(regex, style, re.I):
432432
return weight
433-
if font.style_flags & ft2font.BOLD:
433+
if ft2font.StyleFlags.BOLD in font.style_flags:
434434
return 700 # "bold"
435435
return 500 # "medium", not "regular"!
436436

lib/matplotlib/ft2font.pyi

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,27 @@ from numpy.typing import NDArray
88

99
__freetype_build_type__: str
1010
__freetype_version__: str
11-
BOLD: int
12-
EXTERNAL_STREAM: int
13-
FAST_GLYPHS: int
14-
FIXED_SIZES: int
15-
FIXED_WIDTH: int
16-
GLYPH_NAMES: int
17-
HORIZONTAL: int
18-
ITALIC: int
19-
KERNING: int
20-
MULTIPLE_MASTERS: int
21-
SCALABLE: int
22-
SFNT: int
23-
VERTICAL: int
11+
12+
class FaceFlags(Enum):
13+
SCALABLE = ...
14+
FIXED_SIZES = ...
15+
FIXED_WIDTH = ...
16+
SFNT = ...
17+
HORIZONTAL = ...
18+
VERTICAL = ...
19+
KERNING = ...
20+
FAST_GLYPHS = ...
21+
MULTIPLE_MASTERS = ...
22+
GLYPH_NAMES = ...
23+
EXTERNAL_STREAM = ...
24+
HINTER = ...
25+
CID_KEYED = ...
26+
TRICKY = ...
27+
COLOR = ...
28+
# VARIATION = ... # FT 2.9
29+
# SVG = ... # FT 2.12
30+
# SBIX = ... # FT 2.12
31+
# SBIX_OVERLAY = ... # FT 2.12
2432

2533
class Kerning(Enum):
2634
DEFAULT = ...
@@ -54,6 +62,10 @@ class LoadFlags(Enum):
5462
TARGET_LCD = ...
5563
TARGET_LCD_V = ...
5664

65+
class StyleFlags(Enum):
66+
ITALIC = ...
67+
BOLD = ...
68+
5769
class _SfntHeadDict(TypedDict):
5870
version: tuple[int, int]
5971
fontRevision: tuple[int, int]
@@ -232,7 +244,7 @@ class FT2Font(Buffer):
232244
@property
233245
def descender(self) -> int: ...
234246
@property
235-
def face_flags(self) -> int: ...
247+
def face_flags(self) -> FaceFlags: ...
236248
@property
237249
def family_name(self) -> str: ...
238250
@property
@@ -256,7 +268,7 @@ class FT2Font(Buffer):
256268
@property
257269
def scalable(self) -> bool: ...
258270
@property
259-
def style_flags(self) -> int: ...
271+
def style_flags(self) -> StyleFlags: ...
260272
@property
261273
def style_name(self) -> str: ...
262274
@property

lib/matplotlib/tests/test_ft2font.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,11 @@ def test_ft2font_dejavu_attrs():
4444
assert font.num_fixed_sizes == 0 # All glyphs are scalable.
4545
assert font.num_charmaps == 5
4646
# Other internal flags are set, so only check the ones we're allowed to test.
47-
expected_flags = (ft2font.SCALABLE | ft2font.SFNT | ft2font.HORIZONTAL |
48-
ft2font.KERNING | ft2font.GLYPH_NAMES)
49-
assert (font.face_flags & expected_flags) == expected_flags
50-
assert font.style_flags == 0 # Not italic or bold.
47+
expected_flags = (ft2font.FaceFlags.SCALABLE | ft2font.FaceFlags.SFNT |
48+
ft2font.FaceFlags.HORIZONTAL | ft2font.FaceFlags.KERNING |
49+
ft2font.FaceFlags.GLYPH_NAMES)
50+
assert expected_flags in font.face_flags
51+
assert font.style_flags == ft2font.StyleFlags.NORMAL
5152
assert font.scalable
5253
# From FontForge: Font Information → General tab → entry name below.
5354
assert font.units_per_EM == 2048 # Em Size.
@@ -76,10 +77,10 @@ def test_ft2font_cm_attrs():
7677
assert font.num_fixed_sizes == 0 # All glyphs are scalable.
7778
assert font.num_charmaps == 2
7879
# Other internal flags are set, so only check the ones we're allowed to test.
79-
expected_flags = (ft2font.SCALABLE | ft2font.SFNT | ft2font.HORIZONTAL |
80-
ft2font.GLYPH_NAMES)
81-
assert (font.face_flags & expected_flags) == expected_flags, font.face_flags
82-
assert font.style_flags == 0 # Not italic or bold.
80+
expected_flags = (ft2font.FaceFlags.SCALABLE | ft2font.FaceFlags.SFNT |
81+
ft2font.FaceFlags.HORIZONTAL | ft2font.FaceFlags.GLYPH_NAMES)
82+
assert expected_flags in font.face_flags
83+
assert font.style_flags == ft2font.StyleFlags.NORMAL
8384
assert font.scalable
8485
# From FontForge: Font Information → General tab → entry name below.
8586
assert font.units_per_EM == 2048 # Em Size.
@@ -108,10 +109,10 @@ def test_ft2font_stix_bold_attrs():
108109
assert font.num_fixed_sizes == 0 # All glyphs are scalable.
109110
assert font.num_charmaps == 3
110111
# Other internal flags are set, so only check the ones we're allowed to test.
111-
expected_flags = (ft2font.SCALABLE | ft2font.SFNT | ft2font.HORIZONTAL |
112-
ft2font.GLYPH_NAMES)
113-
assert (font.face_flags & expected_flags) == expected_flags, font.face_flags
114-
assert font.style_flags == ft2font.BOLD
112+
expected_flags = (ft2font.FaceFlags.SCALABLE | ft2font.FaceFlags.SFNT |
113+
ft2font.FaceFlags.HORIZONTAL | ft2font.FaceFlags.GLYPH_NAMES)
114+
assert expected_flags in font.face_flags
115+
assert font.style_flags == ft2font.StyleFlags.BOLD
115116
assert font.scalable
116117
# From FontForge: Font Information → General tab → entry name below.
117118
assert font.units_per_EM == 1000 # Em Size.

src/ft2font_wrapper.cpp

Lines changed: 122 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,38 @@ using namespace pybind11::literals;
1919
* Enumerations in a C++ form.
2020
* */
2121

22+
enum class FaceFlags : FT_Long {
23+
#define DECLARE_FLAG(name) name = FT_FACE_FLAG_##name
24+
DECLARE_FLAG(SCALABLE),
25+
DECLARE_FLAG(FIXED_SIZES),
26+
DECLARE_FLAG(FIXED_WIDTH),
27+
DECLARE_FLAG(SFNT),
28+
DECLARE_FLAG(HORIZONTAL),
29+
DECLARE_FLAG(VERTICAL),
30+
DECLARE_FLAG(KERNING),
31+
DECLARE_FLAG(FAST_GLYPHS),
32+
DECLARE_FLAG(MULTIPLE_MASTERS),
33+
DECLARE_FLAG(GLYPH_NAMES),
34+
DECLARE_FLAG(EXTERNAL_STREAM),
35+
DECLARE_FLAG(HINTER),
36+
DECLARE_FLAG(CID_KEYED),
37+
DECLARE_FLAG(TRICKY),
38+
DECLARE_FLAG(COLOR),
39+
#ifdef FT_FACE_FLAG_VARIATION // backcompat: ft 2.9.0.
40+
DECLARE_FLAG(VARIATION),
41+
#endif
42+
#ifdef FT_FACE_FLAG_SVG // backcompat: ft 2.12.0.
43+
DECLARE_FLAG(SVG),
44+
#endif
45+
#ifdef FT_FACE_FLAG_SBIX // backcompat: ft 2.12.0.
46+
DECLARE_FLAG(SBIX),
47+
#endif
48+
#ifdef FT_FACE_FLAG_SBIX_OVERLAY // backcompat: ft 2.12.0.
49+
DECLARE_FLAG(SBIX_OVERLAY),
50+
#endif
51+
#undef DECLARE_FLAG
52+
};
53+
2254
enum class LoadFlags : FT_Int32 {
2355
#define DECLARE_FLAG(name) name = FT_LOAD_##name
2456
DECLARE_FLAG(DEFAULT),
@@ -54,34 +86,54 @@ enum class LoadFlags : FT_Int32 {
5486
#undef DECLARE_FLAG
5587
};
5688

89+
enum class StyleFlags : FT_Long {
90+
NORMAL = 0,
91+
#define DECLARE_FLAG(name) name = FT_STYLE_FLAG_##name
92+
DECLARE_FLAG(ITALIC),
93+
DECLARE_FLAG(BOLD),
94+
#undef DECLARE_FLAG
95+
};
96+
5797
template <typename E>
5898
inline E operator&(E a, const E& b)
5999
{
60-
static_assert(std::is_same<E, LoadFlags>::value, "You must use LoadFlags here");
100+
static_assert(std::is_same<E, FaceFlags>::value ||
101+
std::is_same<E, LoadFlags>::value ||
102+
std::is_same<E, StyleFlags>::value,
103+
"You must use Flags here");
61104
return static_cast<E>(static_cast<std::underlying_type_t<E>>(a) &
62105
static_cast<std::underlying_type_t<E>>(b));
63106
}
64107

65108
template <typename E>
66109
inline E operator|(E a, const E& b)
67110
{
68-
static_assert(std::is_same<E, LoadFlags>::value, "You must use LoadFlags here");
111+
static_assert(std::is_same<E, FaceFlags>::value ||
112+
std::is_same<E, LoadFlags>::value ||
113+
std::is_same<E, StyleFlags>::value,
114+
"You must use Flags here");
69115
return static_cast<E>(static_cast<std::underlying_type_t<E>>(a) |
70116
static_cast<std::underlying_type_t<E>>(b));
71117
}
72118

73119
template <typename E>
74120
inline E operator^(E a, const E& b)
75121
{
76-
static_assert(std::is_same<E, LoadFlags>::value, "You must use LoadFlags here");
122+
static_assert(std::is_same<E, FaceFlags>::value ||
123+
std::is_same<E, LoadFlags>::value ||
124+
std::is_same<E, StyleFlags>::value,
125+
"You must use Flags here");
77126
return static_cast<E>(static_cast<std::underlying_type_t<E>>(a) ^
78127
static_cast<std::underlying_type_t<E>>(b));
79128
}
80129

81130
template <typename E>
82131
inline E operator~(E a)
83132
{
84-
static_assert(std::is_same<E, LoadFlags>::value, "You must use LoadFlags here");
133+
static_assert(std::is_same<E, FaceFlags>::value ||
134+
std::is_same<E, LoadFlags>::value ||
135+
std::is_same<E, StyleFlags>::value,
136+
"You must use Flags here");
85137
return static_cast<E>(~static_cast<std::underlying_type_t<E>>(a));
86138
}
87139

@@ -989,16 +1041,16 @@ PyFT2Font_style_name(PyFT2Font *self)
9891041
return name;
9901042
}
9911043

992-
static FT_Long
1044+
static FaceFlags
9931045
PyFT2Font_face_flags(PyFT2Font *self)
9941046
{
995-
return self->x->get_face()->face_flags;
1047+
return static_cast<FaceFlags>(self->x->get_face()->face_flags);
9961048
}
9971049

998-
static FT_Long
1050+
static StyleFlags
9991051
PyFT2Font_style_flags(PyFT2Font *self)
10001052
{
1001-
return self->x->get_face()->style_flags;
1053+
return static_cast<StyleFlags>(self->x->get_face()->style_flags);
10021054
}
10031055

10041056
static FT_Long
@@ -1145,6 +1197,20 @@ ft2font__getattr__(std::string name) {
11451197
DEPRECATE_ATTR_FROM_FLAG(LOAD_TARGET_LCD, LoadFlags, TARGET_LCD);
11461198
DEPRECATE_ATTR_FROM_FLAG(LOAD_TARGET_LCD_V, LoadFlags, TARGET_LCD_V);
11471199

1200+
DEPRECATE_ATTR_FROM_FLAG(SCALABLE, FaceFlags, SCALABLE);
1201+
DEPRECATE_ATTR_FROM_FLAG(FIXED_SIZES, FaceFlags, FIXED_SIZES);
1202+
DEPRECATE_ATTR_FROM_FLAG(FIXED_WIDTH, FaceFlags, FIXED_WIDTH);
1203+
DEPRECATE_ATTR_FROM_FLAG(SFNT, FaceFlags, SFNT);
1204+
DEPRECATE_ATTR_FROM_FLAG(HORIZONTAL, FaceFlags, HORIZONTAL);
1205+
DEPRECATE_ATTR_FROM_FLAG(VERTICAL, FaceFlags, VERTICAL);
1206+
DEPRECATE_ATTR_FROM_FLAG(KERNING, FaceFlags, KERNING);
1207+
DEPRECATE_ATTR_FROM_FLAG(FAST_GLYPHS, FaceFlags, FAST_GLYPHS);
1208+
DEPRECATE_ATTR_FROM_FLAG(MULTIPLE_MASTERS, FaceFlags, MULTIPLE_MASTERS);
1209+
DEPRECATE_ATTR_FROM_FLAG(GLYPH_NAMES, FaceFlags, GLYPH_NAMES);
1210+
DEPRECATE_ATTR_FROM_FLAG(EXTERNAL_STREAM, FaceFlags, EXTERNAL_STREAM);
1211+
1212+
DEPRECATE_ATTR_FROM_FLAG(ITALIC, StyleFlags, ITALIC);
1213+
DEPRECATE_ATTR_FROM_FLAG(BOLD, StyleFlags, BOLD);
11481214
#undef DEPRECATE_ATTR_FROM_FLAG
11491215

11501216
throw py::attribute_error(
@@ -1177,6 +1243,42 @@ PYBIND11_MODULE(ft2font, m)
11771243
.def(py::self ^ py::self) \
11781244
.def(~py::self)
11791245

1246+
py::enum_<FaceFlags>(m, "FaceFlags", py::arithmetic())
1247+
#define DECLARE_ENUM(name) .value(#name, FaceFlags::name)
1248+
DECLARE_ENUM(SCALABLE)
1249+
DECLARE_ENUM(FIXED_SIZES)
1250+
DECLARE_ENUM(FIXED_WIDTH)
1251+
DECLARE_ENUM(SFNT)
1252+
DECLARE_ENUM(HORIZONTAL)
1253+
DECLARE_ENUM(VERTICAL)
1254+
DECLARE_ENUM(KERNING)
1255+
DECLARE_ENUM(FAST_GLYPHS)
1256+
DECLARE_ENUM(MULTIPLE_MASTERS)
1257+
DECLARE_ENUM(GLYPH_NAMES)
1258+
DECLARE_ENUM(EXTERNAL_STREAM)
1259+
DECLARE_ENUM(HINTER)
1260+
DECLARE_ENUM(CID_KEYED)
1261+
DECLARE_ENUM(TRICKY)
1262+
DECLARE_ENUM(COLOR)
1263+
#ifdef FT_FACE_FLAG_VARIATION // backcompat: ft 2.9.0.
1264+
DECLARE_ENUM(VARIATION)
1265+
#endif
1266+
#ifdef FT_FACE_FLAG_SVG // backcompat: ft 2.12.0.
1267+
DECLARE_ENUM(SVG)
1268+
#endif
1269+
#ifdef FT_FACE_FLAG_SBIX // backcompat: ft 2.12.0.
1270+
DECLARE_ENUM(SBIX)
1271+
#endif
1272+
#ifdef FT_FACE_FLAG_SBIX_OVERLAY // backcompat: ft 2.12.0.
1273+
DECLARE_ENUM(SBIX_OVERLAY)
1274+
#endif
1275+
#undef DECLARE_ENUM
1276+
ENUM_BITWISE_OPS
1277+
.def("__contains__", [](const FaceFlags a, const FaceFlags b) -> bool {
1278+
return (a & b) == b;
1279+
}, py::is_operator())
1280+
;
1281+
11801282
py::enum_<LoadFlags>(m, "LoadFlags", py::arithmetic())
11811283
#define DECLARE_ENUM(name) .value(#name, LoadFlags::name)
11821284
DECLARE_ENUM(DEFAULT)
@@ -1218,6 +1320,18 @@ PYBIND11_MODULE(ft2font, m)
12181320
}, py::is_operator())
12191321
;
12201322

1323+
py::enum_<StyleFlags>(m, "StyleFlags", py::arithmetic())
1324+
#define DECLARE_ENUM(name) .value(#name, StyleFlags::name)
1325+
DECLARE_ENUM(NORMAL)
1326+
DECLARE_ENUM(ITALIC)
1327+
DECLARE_ENUM(BOLD)
1328+
#undef DECLARE_ENUM
1329+
ENUM_BITWISE_OPS
1330+
.def("__contains__", [](const StyleFlags a, const StyleFlags b) -> bool {
1331+
return (a & b) == b;
1332+
}, py::is_operator())
1333+
;
1334+
12211335
py::enum_<FT_Kerning_Mode>(m, "Kerning")
12221336
#define DECLARE_ENUM(name) .value(#name, FT_KERNING_##name)
12231337
DECLARE_ENUM(DEFAULT)
@@ -1368,17 +1482,4 @@ PYBIND11_MODULE(ft2font, m)
13681482
m.attr("__freetype_version__") = version_string;
13691483
m.attr("__freetype_build_type__") = FREETYPE_BUILD_TYPE;
13701484
m.def("__getattr__", ft2font__getattr__);
1371-
m.attr("SCALABLE") = FT_FACE_FLAG_SCALABLE;
1372-
m.attr("FIXED_SIZES") = FT_FACE_FLAG_FIXED_SIZES;
1373-
m.attr("FIXED_WIDTH") = FT_FACE_FLAG_FIXED_WIDTH;
1374-
m.attr("SFNT") = FT_FACE_FLAG_SFNT;
1375-
m.attr("HORIZONTAL") = FT_FACE_FLAG_HORIZONTAL;
1376-
m.attr("VERTICAL") = FT_FACE_FLAG_VERTICAL;
1377-
m.attr("KERNING") = FT_FACE_FLAG_KERNING;
1378-
m.attr("FAST_GLYPHS") = FT_FACE_FLAG_FAST_GLYPHS;
1379-
m.attr("MULTIPLE_MASTERS") = FT_FACE_FLAG_MULTIPLE_MASTERS;
1380-
m.attr("GLYPH_NAMES") = FT_FACE_FLAG_GLYPH_NAMES;
1381-
m.attr("EXTERNAL_STREAM") = FT_FACE_FLAG_EXTERNAL_STREAM;
1382-
m.attr("ITALIC") = FT_STYLE_FLAG_ITALIC;
1383-
m.attr("BOLD") = FT_STYLE_FLAG_BOLD;
13841485
}

0 commit comments

Comments
 (0)