8000 Allow font manager to parse all families · matplotlib/matplotlib@c160470 · GitHub
[go: up one dir, main page]

Skip to content

Commit c160470

Browse files
committed
Allow font manager to parse all families
1 parent 077393e commit c160470

File tree

1 file changed

+66
-6
lines changed

1 file changed

+66
-6
lines changed

lib/matplotlib/font_manager.py

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
# - setWeights function needs improvement
2424
# - 'light' is an invalid weight value, remove it.
2525

26+
from collections import OrderedDict
2627
import dataclasses
2728
from functools import lru_cache
2829
import json
@@ -947,6 +948,24 @@ def copy(self):
947948
return new
948949

949950

951+
class FontsInterface:
952+
def __init__(self, ordered_family):
953+
self.set_orderedfamily(ordered_family)
954+
955+
def set_orderedfamily(self, ordered_family):
956+
self.families = []
957+
self.filepaths = []
958+
for key, value in ordered_family.items():
959+
self.families.append(key)
960+
self.filepaths.append(value)
961+
962+
def get_families(self):
963+
return self.families
964+
965+
def get_filepaths(self):
966+
return self.filepaths
967+
968+
950969
class _JSONEncoder(json.JSONEncoder):
951970
def default(self, o):
952971
if isinstance(o, FontManager):
@@ -1304,16 +1323,51 @@ def findfont(self, prop, fontext='ttf', directory=None,
13041323
rc_params = tuple(tuple(rcParams[key]) for key in [
13051324
"font.serif", "font.sans-serif", "font.cursive", "font.fantasy",
13061325
"font.monospace"])
1326+
1327+
if not isinstance(prop, FontProperties):
1328+
prop = FontProperties._from_any(prop)
1329+
13071330
return self._findfont_cached(
13081331
prop, fontext, directory, fallback_to_default, rebuild_if_missing,
13091332
rc_params)
13101333

1334+
def find_fontsprop(self, prop, fontext='ttf', directory=None,
1335+
fallback_to_default=True, rebuild_if_missing=True):
1336+
1337+
prop = FontProperties._from_any(prop)
1338+
ffamily = prop.get_family()
1339+
1340+
# maintain two dicts, one for available paths,
1341+
# the other for fallback paths
1342+
fpaths, fbpaths = OrderedDict(), OrderedDict()
1343+
for fidx in range(len(ffamily)):
1344+
cprop = prop.copy()
1345+
1346+
# set current prop's family
1347+
cprop.set_family(ffamily[fidx])
1348+
1349+
try:
1350+
fpath = self.findfont(cprop, fontext, directory,
1351+
False, rebuild_if_missing)
1352+
fpaths[ffamily[fidx]] = fpath
1353+
1354+
except ValueError as e:
1355+
if fallback_to_default:
1356+
fpath = self.findfont(cprop, fontext, directory,
1357+
True, rebuild_if_missing)
1358+
fbpaths.update({self.defaultFamily[fontext]: fpath})
1359+
else:
1360+
raise e
1361+
1362+
# append fallback font(s) to the very end
1363+
fpaths.update(fbpaths)
1364+
1365+
return FontsInterface(fpaths)
1366+
13111367
@lru_cache()
13121368
def _findfont_cached(self, prop, fontext, directory, fallback_to_default,
13131369
rebuild_if_missing, rc_params):
13141370

1315-
prop = FontProperties._from_any(prop)
1316-
13171371
fname = prop.get_file()
13181372
if fname is not None:
13191373
return fname
@@ -1401,9 +1455,11 @@ def is_opentype_cff_font(filename):
14011455

14021456

14031457
@lru_cache(64)
1404-
def _get_font(filename, hinting_factor, *, _kerning_factor, thread_id):
1458+
def _get_font(fpaths, hinting_factor, *, _kerning_factor, thread_id):
1459+
# multiple paths, take first one
1460+
# for now, which is always guaranteed
14051461
return ft2font.FT2Font(
1406-
filename, hinting_factor, _kerning_factor=_kerning_factor)
1462+
fpaths[0], hinting_factor, _kerning_factor=_kerning_factor)
14071463

14081464

14091465
# FT2Font objects cannot be used across fork()s because they reference the same
@@ -1417,11 +1473,14 @@ def _get_font(filename, hinting_factor, *, _kerning_factor, thread_id):
14171473
def get_font(filename, hinting_factor=None):
14181474
# Resolving the path avoids embedding the font twice in pdf/ps output if a
14191475
# single font is selected using two different relative paths.
1420-
filename = _cached_realpath(filename)
1476+
if isinstance(filename, FontsInterface):
1477+
paths = tuple([_cached_realpath(fname) for fname in filename.get_filepaths()])
1478+
else:
1479+
paths = tuple([_cached_realpath(filename)])
14211480
if hinting_factor is None:
14221481
hinting_factor = rcParams['text.hinting_factor']
14231482
# also key on the thread ID to prevent segfaults with multi-threading
1424-
return _get_font(filename, hinting_factor,
1483+
return _get_font(paths, hinting_factor,
14251484
_kerning_factor=rcParams['text.kerning_factor'],
14261485
thread_id=threading.get_ident())
14271486

@@ -1446,3 +1505,4 @@ def _load_fontmanager(*, try_read_cache=True):
14461505

14471506
fontManager = _load_fontmanager()
14481507
findfont = fontManager.findfont
1508+
find_fontsprop = fontManager.find_fontsprop

0 commit comments

Comments
 (0)
0