Skip to content

Commit 2c0c213

Browse files
committed
ft2font: Convert loading flags into an enum
Unfortunately, FreeType doesn't define this as an enum of any sort, just as a bunch of macro `#define`s. So we have to make our own for pybind11 to bind.
1 parent 1651119 commit 2c0c213

File tree

11 files changed

+290
-98
lines changed

11 files changed

+290
-98
lines changed

lib/matplotlib/_mathtext.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
from ._mathtext_data import (
3030
latex_to_bakoma, stix_glyph_fixes, stix_virtual_fonts, tex2uni)
3131
from .font_manager import FontProperties, findfont, get_font
32-
from .ft2font import FT2Font, FT2Image, Kerning
32+
from .ft2font import FT2Font, FT2Image, Kerning, LoadFlags
3333

3434
from packaging.version import parse as parse_version
3535
from pyparsing import __version__ as pyparsing_version
@@ -227,14 +227,14 @@ class Fonts(abc.ABC):
227227
to do the actual drawing.
228228
"""
229229

230-
def __init__(self, default_font_prop: FontProperties, load_glyph_flags: int):
230+
def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags):
231231
"""
232232
Parameters
233233
----------
234234
default_font_prop : `~.font_manager.FontProperties`
235235
The default non-math font, or the base font for Unicode (generic)
236236
font rendering.
237-
load_glyph_flags : int
237+
load_glyph_flags : `.ft2font.LoadFlags`
238238
Flags passed to the glyph loader (e.g. ``FT_Load_Glyph`` and
239239
``FT_Load_Char`` for FreeType-based fonts).
240240
"""
@@ -332,7 +332,7 @@ class TruetypeFonts(Fonts, metaclass=abc.ABCMeta):
332332
(through FT2Font).
333333
"""
334334

335-
def __init__(self, default_font_prop: FontProperties, load_glyph_flags: int):
335+
def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags):
336336
super().__init__(default_font_prop, load_glyph_flags)
337337
# Per-instance cache.
338338
self._get_info = functools.cache(self._get_info) # type: ignore[method-assign]
@@ -448,7 +448,7 @@ class BakomaFonts(TruetypeFonts):
448448
'ex': 'cmex10',
449449
}
450450

451-
def __init__(self, default_font_prop: FontProperties, load_glyph_flags: int):
451+
def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags):
452452
self._stix_fallback = StixFonts(default_font_prop, load_glyph_flags)
453453

454454
super().__init__(default_font_prop, load_glyph_flags)
@@ -557,7 +557,7 @@ class UnicodeFonts(TruetypeFonts):
557557
0x2212: 0x00A1, # Minus sign.
558558
}
559559

560-
def __init__(self, default_font_prop: FontProperties, load_glyph_flags: int):
560+
def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags):
561561
# This must come first so the backend's owner is set correctly
562562
fallback_rc = mpl.rcParams['mathtext.fallback']
563563
font_cls: type[TruetypeFonts] | None = {
@@ -672,7 +672,7 @@ def get_sized_alternatives_for_symbol(self, fontname: str,
672672
class DejaVuFonts(UnicodeFonts, metaclass=abc.ABCMeta):
673673
_fontmap: dict[str | int, str] = {}
674674

675-
def __init__(self, default_font_prop: FontProperties, load_glyph_flags: int):
675+
def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags):
676676
# This must come first so the backend's owner is set correctly
677677
if isinstance(self, DejaVuSerifFonts):
678678
self._fallback_font = StixFonts(default_font_prop, load_glyph_flags)
@@ -776,7 +776,7 @@ class StixFonts(UnicodeFonts):
776776
_fallback_font = None
777777
_sans = False
778778

779-
def __init__(self, default_font_prop: FontProperties, load_glyph_flags: int):
779+
def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags):
780780
TruetypeFonts.__init__(self, default_font_prop, load_glyph_flags)
781781
for key, name in self._fontmap.items():
782782
fullpath = findfont(name)

lib/matplotlib/_text_helpers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import dataclasses
88

99
from . import _api
10-
from .ft2font import LOAD_NO_HINTING, FT2Font, Kerning
10+
from .ft2font import FT2Font, Kerning, LoadFlags
1111

1212

1313
@dataclasses.dataclass(frozen=True)
@@ -76,7 +76,7 @@ def layout(string, font, *, kern_mode=Kerning.DEFAULT):
7676
if prev_glyph_idx is not None else 0.
7777
)
7878
x += kern
79-
glyph = font.load_glyph(glyph_idx, flags=LOAD_NO_HINTING)
79+
glyph = font.load_glyph(glyph_idx, flags=LoadFlags.NO_HINTING)
8080
yield LayoutItem(font, char, glyph_idx, x, kern)
8181
x += glyph.linearHoriAdvance / 65536
8282
prev_glyph_idx = glyph_idx

lib/matplotlib/backends/_backend_pdf_ps.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def get_text_width_height_descent(self, s, prop, ismath):
123123
return w, h, d
124124
else:
125125
font = self._get_font_ttf(prop)
126-
font.set_text(s, 0.0, flags=ft2font.LOAD_NO_HINTING)
126+
font.set_text(s, 0.0, flags=ft2font.LoadFlags.NO_HINTING)
127127
w, h = font.get_width_height()
128128
d = font.get_descent()
129129
scale = 1 / 64

lib/matplotlib/backends/backend_agg.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,7 @@
3131
from matplotlib.backend_bases import (
3232
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase)
3333
from matplotlib.font_manager import fontManager as _fontManager, get_font
34-
from matplotlib.ft2font import (LOAD_FORCE_AUTOHINT, LOAD_NO_HINTING,
35-
LOAD_DEFAULT, LOAD_NO_AUTOHINT)
34+
from matplotlib.ft2font import LoadFlags
3635
from matplotlib.mathtext import MathTextParser
3736
from matplotlib.path import Path
3837
from matplotlib.transforms import Bbox, BboxBase
@@ -41,16 +40,16 @@
4140

4241
def get_hinting_flag():
4342
mapping = {
44-
'default': LOAD_DEFAULT,
45-
'no_autohint': LOAD_NO_AUTOHINT,
46-
'force_autohint': LOAD_FORCE_AUTOHINT,
47-
'no_hinting': LOAD_NO_HINTING,
48-
True: LOAD_FORCE_AUTOHINT,
49-
False: LOAD_NO_HINTING,
50-
'either': LOAD_DEFAULT,
51-
'native': LOAD_NO_AUTOHINT,
52-
'auto': LOAD_FORCE_AUTOHINT,
53-
'none': LOAD_NO_HINTING,
43+
'default': LoadFlags.DEFAULT,
44+
'no_autohint': LoadFlags.NO_AUTOHINT,
45+
'force_autohint': LoadFlags.FORCE_AUTOHINT,
46+
'no_hinting': LoadFlags.NO_HINTING,
47+
True: LoadFlags.FORCE_AUTOHINT,
48+
False: LoadFlags.NO_HINTING,
49+
'either': LoadFlags.DEFAULT,
50+
'native': LoadFlags.NO_AUTOHINT,
51+
'auto': LoadFlags.FORCE_AUTOHINT,
52+
'none': LoadFlags.NO_HINTING,
5453
}
5554
return mapping[mpl.rcParams['text.hinting']]
5655

lib/matplotlib/backends/backend_pdf.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +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, LOAD_NO_SCALE,
39-
LOAD_NO_HINTING, FT2Font, Kerning)
38+
from matplotlib.ft2font import FIXED_WIDTH, ITALIC, FT2Font, Kerning, LoadFlags
4039
from matplotlib.transforms import Affine2D, BboxBase
4140
from matplotlib.path import Path
4241
from matplotlib.dates import UTC
@@ -617,7 +616,7 @@ def _get_pdf_charprocs(font_path, glyph_ids):
617616
conv = 1000 / font.units_per_EM # Conversion to PS units (1/1000's).
618617
procs = {}
619618
for glyph_id in glyph_ids:
620-
g = font.load_glyph(glyph_id, LOAD_NO_SCALE)
619+
g = font.load_glyph(glyph_id, LoadFlags.NO_SCALE)
621620
# NOTE: We should be using round(), but instead use
622621
# "(x+.5).astype(int)" to keep backcompat with the old ttconv code
623622
# (this is different for negative x's).
@@ -1185,7 +1184,7 @@ def embedTTFType3(font, characters, descriptor):
11851184
def get_char_width(charcode):
11861185
s = ord(cp1252.decoding_table[charcode])
11871186
width = font.load_char(
1188-
s, flags=LOAD_NO_SCALE | LOAD_NO_HINTING).horiAdvance
1187+
s, flags=LoadFlags.NO_SCALE | LoadFlags.NO_HINTING).horiAdvance
11891188
return cvt(width)
11901189
with warnings.catch_warnings():
11911190
# Ignore 'Required glyph missing from current font' warning
@@ -1321,7 +1320,7 @@ def embedTTFType42(font, characters, descriptor):
13211320
ccode = c
13221321
gind = font.get_char_index(ccode)
13231322
glyph = font.load_char(ccode,
1324-
flags=LOAD_NO_SCALE | LOAD_NO_HINTING)
1323+
flags=LoadFlags.NO_SCALE | LoadFlags.NO_HINTING)
13251324
widths.append((ccode, cvt(glyph.horiAdvance)))
13261325
if ccode < 65536:
13271326
cid_to_gid_map[ccode] = chr(gind)

lib/matplotlib/backends/backend_ps.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase)
2626
from matplotlib.cbook import is_writable_file_like, file_requires_unicode
2727
from matplotlib.font_manager import get_font
28-
from matplotlib.ft2font import LOAD_NO_SCALE, FT2Font
28+
from matplotlib.ft2font import FT2Font, LoadFlags
2929
from matplotlib._ttconv import convert_ttf_to_ps
3030
from matplotlib._mathtext_data import uni2type1
3131
from matplotlib.path import Path
@@ -160,7 +160,7 @@ def _font_to_ps_type3(font_path, chars):
160160

161161
entries = []
162162
for glyph_id in glyph_ids:
163-
g = font.load_glyph(glyph_id, LOAD_NO_SCALE)
163+
g = font.load_glyph(glyph_id, LoadFlags.NO_SCALE)
164164
v, c = font.get_path()
165165
entries.append(
166166
"/%(name)s{%(bbox)s sc\n" % {

lib/matplotlib/ft2font.pyi

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,6 @@ GLYPH_NAMES: int
1717
HORIZONTAL: int
1818
ITALIC: int
1919
KERNING: int
20-
LOAD_CROP_BITMAP: int
21-
LOAD_DEFAULT: int
22-
LOAD_FORCE_AUTOHINT: int
23-
LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH: int
24-
LOAD_IGNORE_TRANSFORM: int
25-
LOAD_LINEAR_DESIGN: int
26-
LOAD_MONOCHROME: int
27-
LOAD_NO_AUTOHINT: int
28-
LOAD_NO_BITMAP: int
29-
LOAD_NO_HINTING: int
30-
LOAD_NO_RECURSE: int
31-
LOAD_NO_SCALE: int
32-
LOAD_PEDANTIC: int
33-
LOAD_RENDER: int
34-
LOAD_TARGET_LCD: int
35-
LOAD_TARGET_LCD_V: int
36-
LOAD_TARGET_LIGHT: int
37-
LOAD_TARGET_MONO: int
38-
LOAD_TARGET_NORMAL: int
39-
LOAD_VERTICAL_LAYOUT: int
4020
MULTIPLE_MASTERS: int
4121
SCALABLE: int
4222
SFNT: int
@@ -50,6 +30,45 @@ class Kerning(Enum):
5030
def __index__(self) -> int: ...
5131
def __int__(self) -> int: ...
5232

33+
class LoadFlags(Enum):
34+
DEFAULT: LoadFlags
35+
NO_SCALE: LoadFlags
36+
NO_HINTING: LoadFlags
37+
RENDER: LoadFlags
38+
NO_BITMAP: LoadFlags
39+
VERTICAL_LAYOUT: LoadFlags
40+
FORCE_AUTOHINT: LoadFlags
41+
CROP_BITMAP: LoadFlags
42+
PEDANTIC: LoadFlags
43+
IGNORE_GLOBAL_ADVANCE_WIDTH: LoadFlags
44+
NO_RECURSE: LoadFlags
45+
IGNORE_TRANSFORM: LoadFlags
46+
MONOCHROME: LoadFlags
47+
LINEAR_DESIGN: LoadFlags
48+
NO_AUTOHINT: LoadFlags
49+
COLOR: LoadFlags
50+
COMPUTE_METRICS: LoadFlags # FT 2.6.1
51+
# BITMAP_METRICS_ONLY: LoadFlags # FT 2.7.1
52+
# NO_SVG: LoadFlags # FT 2.13.1
53+
# The following should be unique, but the above can be OR'd together.
54+
TARGET_NORMAL: LoadFlags
55+
TARGET_LIGHT: LoadFlags
56+
TARGET_MONO: LoadFlags
57+
TARGET_LCD: LoadFlags
58+
TARGET_LCD_V: LoadFlags
59+
__members__: dict[str, LoadFlags]
60+
def __and__(self, other: LoadFlags) -> LoadFlags: ...
61+
def __contains__(self, other: LoadFlags) -> bool: ...
62+
def __ge__(self, other: LoadFlags) -> bool: ...
63+
def __gt__(self, other: LoadFlags) -> bool: ...
64+
def __index__(self) -> int: ...
65+
def __int__(self) -> int: ...
66+
def __invert__(self) -> LoadFlags: ...
67+
def __le__(self, other: LoadFlags) -> bool: ...
68+
def __lt__(self, other: LoadFlags) -> bool: ...
69+
def __or__(self, other: LoadFlags) -> LoadFlags: ...
70+
def __xor__(self, other: LoadFlags) -> LoadFlags: ...
71+
5372
class _SfntHeadDict(TypedDict):
5473
version: tuple[int, int]
5574
fontRevision: tuple[int, int]
@@ -213,13 +232,13 @@ class FT2Font(Buffer):
213232
@overload
214233
def get_sfnt_table(self, name: Literal["pclt"]) -> _SfntPcltDict | None: ...
215234
def get_width_height(self) -> tuple[int, int]: ...
216-
def load_char(self, charcode: int, flags: int = ...) -> Glyph: ...
217-
def load_glyph(self, glyphindex: int, flags: int = ...) -> Glyph: ...
235+
def load_char(self, charcode: int, flags: LoadFlags = ...) -> Glyph: ...
236+
def load_glyph(self, glyphindex: int, flags: LoadFlags = ...) -> Glyph: ...
218237
def select_charmap(self, i: int) -> None: ...
219238
def set_charmap(self, i: int) -> None: ...
220239
def set_size(self, ptsize: float, dpi: float) -> None: ...
221240
def set_text(
222-
self, string: str, angle: float = ..., flags: int = ...
241+
self, string: str, angle: float = ..., flags: LoadFlags = ...
223242
) -> NDArray[np.float64]: ...
224243
@property
225244
def ascender(self) -> int: ...

lib/matplotlib/mathtext.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
import matplotlib as mpl
2222
from matplotlib import _api, _mathtext
23-
from matplotlib.ft2font import LOAD_NO_HINTING
23+
from matplotlib.ft2font import LoadFlags
2424
from matplotlib.font_manager import FontProperties
2525
from ._mathtext import ( # noqa: F401, reexported API
2626
RasterParse, VectorParse, get_unicode_index)
@@ -80,7 +80,7 @@ def parse(self, s, dpi=72, prop=None, *, antialiased=None):
8080
antialiased = mpl._val_or_rc(antialiased, 'text.antialiased')
8181
from matplotlib.backends import backend_agg
8282
load_glyph_flags = {
83-
"vector": LOAD_NO_HINTING,
83+
"vector": LoadFlags.NO_HINTING,
8484
"raster": backend_agg.get_hinting_flag(),
8585
}[self._output_type]
8686
return self._parse_cached(s, dpi, prop, antialiased, load_glyph_flags)

lib/matplotlib/tests/test_font_manager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ def test_missing_family(caplog):
250250

251251
def _test_threading():
252252
import threading
253-
from matplotlib.ft2font import LOAD_NO_HINTING
253+
from matplotlib.ft2font import LoadFlags
254254
import matplotlib.font_manager as fm
255255

256256
def loud_excepthook(args):
@@ -265,7 +265,7 @@ def bad_idea(n):
265265
b.wait(timeout=5)
266266
for j in range(100):
267267
font = fm.get_font(fm.findfont("DejaVu Sans"))
268-
font.set_text(str(n), 0.0, flags=LOAD_NO_HINTING)
268+
font.set_text(str(n), 0.0, flags=LoadFlags.NO_HINTING)
269269

270270
threads = [
271271
threading.Thread(target=bad_idea, name=f"bad_thread_{j}", args=(j,))

lib/matplotlib/textpath.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from matplotlib.font_manager import (
99
FontProperties, get_font, fontManager as _fontManager
1010
)
11-
from matplotlib.ft2font import LOAD_NO_HINTING, LOAD_TARGET_LIGHT
11+
from matplotlib.ft2font import LoadFlags
1212
from matplotlib.mathtext import MathTextParser
1313
from matplotlib.path import Path
1414
from matplotlib.texmanager import TexManager
@@ -37,7 +37,7 @@ def _get_font(self, prop):
3737
return font
3838

3939
def _get_hinting_flag(self):
40-
return LOAD_NO_HINTING
40+
return LoadFlags.NO_HINTING
4141

4242
def _get_char_id(self, font, ccode):
4343
"""
@@ -61,7 +61,7 @@ def get_text_width_height_descent(self, s, prop, ismath):
6161
return width * scale, height * scale, descent * scale
6262

6363
font = self._get_font(prop)
64-
font.set_text(s, 0.0, flags=LOAD_NO_HINTING)
64+
font.set_text(s, 0.0, flags=LoadFlags.NO_HINTING)
6565
w, h = font.get_width_height()
6666
w /= 64.0 # convert from subpixels
6767
h /= 64.0
@@ -190,7 +190,7 @@ def get_glyphs_mathtext(self, prop, s, glyph_map=None,
190190
if char_id not in glyph_map:
191191
font.clear()
192192
font.set_size(self.FONT_SCALE, self.DPI)
193-
font.load_char(ccode, flags=LOAD_NO_HINTING)
193+
font.load_char(ccode, flags=LoadFlags.NO_HINTING)
194194
glyph_map_new[char_id] = font.get_path()
195195

196196
xpositions.append(ox)
@@ -241,11 +241,11 @@ def get_glyphs_tex(self, prop, s, glyph_map=None,
241241
glyph_name_or_index = text.glyph_name_or_index
242242
if isinstance(glyph_name_or_index, str):
243243
index = font.get_name_index(glyph_name_or_index)
244-
font.load_glyph(index, flags=LOAD_TARGET_LIGHT)
244+
font.load_glyph(index, flags=LoadFlags.TARGET_LIGHT)
245245
elif isinstance(glyph_name_or_index, int):
246246
self._select_native_charmap(font)
247247
font.load_char(
248-
glyph_name_or_index, flags=LOAD_TARGET_LIGHT)
248+
glyph_name_or_index, flags=LoadFlags.TARGET_LIGHT)
249249
else: # Should not occur.
250250
raise TypeError(f"Glyph spec of unexpected type: "
251251
f"{glyph_name_or_index!r}")

0 commit comments

Comments
 (0)