@@ -310,6 +310,61 @@ def findSystemFonts(fontpaths=None, fontext='ttf'):
310
310
return [fname for fname in fontfiles if os .path .exists (fname )]
311
311
312
312
313
+ class FontPath (str ):
314
+ """
315
+ A class to describe a path to a font with a face index.
316
+
317
+ Parameters
318
+ ----------
319
+ path : str
320
+ The path to a font.
321
+ face_index : int
322
+ The face index in the font.
323
+ """
324
+
325
+ __match_args__ = ('path' , 'face_index' )
326
+
327
+ def __new__ (cls , path , face_index ):
328
+ ret = super ().__new__ (cls , path )
329
+ ret ._face_index = face_index
330
+ return ret
331
+
332
+ @property
333
+ def path (self ):
334
+ """The path to a font."""
335
+ return str (self )
336
+
337
+ @property
338
+ def face_index (self ):
339
+ """The face index in a font."""
340
+ return self ._face_index
341
+
342
+ def _as_tuple (self ):
343
+ return (self .path , self .face_index )
344
+
345
+ def __eq__ (self , other ):
346
+ if isinstance (other , FontPath ):
347
+ return self ._as_tuple () == other ._as_tuple ()
348
+ return super ().__eq__ (other )
349
+
350
+ def __ne__ (self , other ):
351
+ return not (self == other )
352
+
353
+ def __lt__ (self , other ):
354
+ if isinstance (other , FontPath ):
355
+ return self ._as_tuple () < other ._as_tuple ()
356
+ return super ().__lt__ (other )
357
+
358
+ def __gt__ (self , other ):
359
+ return not (self == other or self < other )
360
+
361
+ def __hash__ (self ):
362
+ return hash (self ._as_tuple ())
363
+
364
+ def __repr__ (self ):
365
+ return f'FontPath{ self ._as_tuple ()} '
366
+
367
+
313
368
@dataclasses .dataclass (frozen = True )
314
369
class FontEntry :
315
370
"""
@@ -1326,7 +1381,7 @@ def findfont(self, prop, fontext='ttf', directory=None,
1326
1381
1327
1382
Returns
1328
1383
-------
1329
- str
1384
+ FontPath
1330
1385
The filename of the best matching font.
1331
1386
1332
1387
Notes
@@ -1396,7 +1451,7 @@ def _find_fonts_by_props(self, prop, fontext='ttf', directory=None,
1396
1451
1397
1452
Returns
1398
1453
-------
1399
- list[str ]
1454
+ list[FontPath ]
1400
1455
The paths of the fonts found.
1401
1456
1402
1457
Notes
@@ -1542,7 +1597,7 @@ def _findfont_cached(self, prop, fontext, directory, fallback_to_default,
1542
1597
# actually raised.
1543
1598
return cbook ._ExceptionInfo (ValueError , "No valid font could be found" )
1544
1599
1545
- return _cached_realpath (result )
1600
+ return FontPath ( _cached_realpath (result ), best_font . index )
1546
1601
1547
1602
1548
1603
@_api .deprecated ("3.11" )
@@ -1562,15 +1617,16 @@ def is_opentype_cff_font(filename):
1562
1617
@lru_cache (64 )
1563
1618
def _get_font (font_filepaths , hinting_factor , * , _kerning_factor , thread_id ,
1564
1619
enable_last_resort ):
1565
- first_fontpath , * rest = font_filepaths
1620
+ ( first_fontpath , first_fontindex ) , * rest = font_filepaths
1566
1621
fallback_list = [
1567
- ft2font .FT2Font (fpath , hinting_factor , _kerning_factor = _kerning_factor )
1568
- for fpath in rest
1622
+ ft2font .FT2Font (fpath , hinting_factor , face_index = index ,
1623
+ _kerning_factor = _kerning_factor )
1624
+ for fpath , index in rest
1569
1625
]
1570
1626
last_resort_path = _cached_realpath (
1571
1627
cbook ._get_data_path ('fonts' , 'ttf' , 'LastResortHE-Regular.ttf' ))
1572
1628
try :
1573
- last_resort_index = font_filepaths .index (last_resort_path )
1629
+ last_resort_index = font_filepaths .index (( last_resort_path , 0 ) )
1574
1630
except ValueError :
1575
1631
last_resort_index = - 1
1576
1632
# Add Last Resort font so we always have glyphs regardless of font, unless we're
@@ -1582,7 +1638,7 @@ def _get_font(font_filepaths, hinting_factor, *, _kerning_factor, thread_id,
1582
1638
_warn_if_used = True ))
1583
1639
last_resort_index = len (fallback_list )
1584
1640
font = ft2font .FT2Font (
1585
- first_fontpath , hinting_factor ,
1641
+ first_fontpath , hinting_factor , face_index = first_fontindex ,
1586
1642
_fallback_list = fallback_list ,
1587
1643
_kerning_factor = _kerning_factor
1588
1644
)
@@ -1617,7 +1673,8 @@ def get_font(font_filepaths, hinting_factor=None):
1617
1673
1618
1674
Parameters
1619
1675
----------
1620
- font_filepaths : Iterable[str, bytes, os.PathLike], str, bytes, os.PathLike
1676
+ font_filepaths : Iterable[str, bytes, os.PathLike, FontPath], \
1677
+ str, bytes, os.PathLike, FontPath
1621
1678
Relative or absolute paths to the font files to be used.
1622
1679
1623
1680
If a single string, bytes, or `os.PathLike`, then it will be treated
@@ -1632,10 +1689,16 @@ def get_font(font_filepaths, hinting_factor=None):
1632
1689
`.ft2font.FT2Font`
1633
1690
1634
1691
"""
1635
- if isinstance (font_filepaths , (str , bytes , os .PathLike )):
1636
- paths = (_cached_realpath (font_filepaths ),)
1637
- else :
1638
- paths = tuple (_cached_realpath (fname ) for fname in font_filepaths )
1692
+ match font_filepaths :
1693
+ case FontPath (path , index ):
1694
+ paths = ((_cached_realpath (path ), index ), )
1695
+ case str () | bytes () | os .PathLike () as path :
1696
+ paths = ((_cached_realpath (path ), 0 ), )
1697
+ case _:
1698
+ paths = tuple (
1699
+ (_cached_realpath (fname .path ), fname .face_index )
1700
+ if isinstance (fname , FontPath ) else (_cached_realpath (fname ), 0 )
1701
+ for fname in font_filepaths )
1639
1702
1640
1703
hinting_factor = mpl ._val_or_rc (hinting_factor , 'text.hinting_factor' )
1641
1704
0 commit comments