@@ -310,6 +310,61 @@ def findSystemFonts(fontpaths=None, fontext='ttf'):
310310 return [fname for fname in fontfiles if os .path .exists (fname )]
311311
312312
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+
313368@dataclasses .dataclass (frozen = True )
314369class FontEntry :
315370 """
@@ -1326,7 +1381,7 @@ def findfont(self, prop, fontext='ttf', directory=None,
13261381
13271382 Returns
13281383 -------
1329- str
1384+ FontPath
13301385 The filename of the best matching font.
13311386
13321387 Notes
@@ -1396,7 +1451,7 @@ def _find_fonts_by_props(self, prop, fontext='ttf', directory=None,
13961451
13971452 Returns
13981453 -------
1399- list[str ]
1454+ list[FontPath ]
14001455 The paths of the fonts found.
14011456
14021457 Notes
@@ -1542,7 +1597,7 @@ def _findfont_cached(self, prop, fontext, directory, fallback_to_default,
15421597 # actually raised.
15431598 return cbook ._ExceptionInfo (ValueError , "No valid font could be found" )
15441599
1545- return _cached_realpath (result )
1600+ return FontPath ( _cached_realpath (result ), best_font . index )
15461601
15471602
15481603@_api .deprecated ("3.11" )
@@ -1562,15 +1617,16 @@ def is_opentype_cff_font(filename):
15621617@lru_cache (64 )
15631618def _get_font (font_filepaths , hinting_factor , * , _kerning_factor , thread_id ,
15641619 enable_last_resort ):
1565- first_fontpath , * rest = font_filepaths
1620+ ( first_fontpath , first_fontindex ) , * rest = font_filepaths
15661621 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
15691625 ]
15701626 last_resort_path = _cached_realpath (
15711627 cbook ._get_data_path ('fonts' , 'ttf' , 'LastResortHE-Regular.ttf' ))
15721628 try :
1573- last_resort_index = font_filepaths .index (last_resort_path )
1629+ last_resort_index = font_filepaths .index (( last_resort_path , 0 ) )
15741630 except ValueError :
15751631 last_resort_index = - 1
15761632 # 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,
15821638 _warn_if_used = True ))
15831639 last_resort_index = len (fallback_list )
15841640 font = ft2font .FT2Font (
1585- first_fontpath , hinting_factor ,
1641+ first_fontpath , hinting_factor , face_index = first_fontindex ,
15861642 _fallback_list = fallback_list ,
15871643 _kerning_factor = _kerning_factor
15881644 )
@@ -1617,7 +1673,8 @@ def get_font(font_filepaths, hinting_factor=None):
16171673
16181674 Parameters
16191675 ----------
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
16211678 Relative or absolute paths to the font files to be used.
16221679
16231680 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):
16321689 `.ft2font.FT2Font`
16331690
16341691 """
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 )
16391702
16401703 hinting_factor = mpl ._val_or_rc (hinting_factor , 'text.hinting_factor' )
16411704
0 commit comments