@@ -264,6 +264,8 @@ def _win32RegistryFonts(reg_domain, base_dir):
264
264
return items
265
265
266
266
267
+ # Also remove _win32RegistryFonts when this is removed.
268
+ @_api .deprecated ("3.5" )
267
269
def win32InstalledFonts (directory = None , fontext = 'ttf' ):
268
270
"""
269
271
Search for fonts in the specified font directory, or use the
@@ -291,9 +293,41 @@ def win32InstalledFonts(directory=None, fontext='ttf'):
291
293
return [str (path ) for path in items if path .suffix .lower () in fontext ]
292
294
293
295
296
+ def _get_win32_installed_fonts ():
297
+ """List the font paths known to the Windows registry."""
298
+ import winreg
299
+ items = set ()
300
+ # Search and resolve fonts listed in the registry.
301
+ for domain , base_dirs in [
302
+ (winreg .HKEY_LOCAL_MACHINE , [win32FontDirectory ()]), # System.
303
+ (winreg .HKEY_CURRENT_USER , MSUserFontDirectories ), # User.
304
+ ]:
305
+ for base_dir in base_dirs :
306
+ for reg_path in MSFontDirectories :
307
+ try :
308
+ with winreg .OpenKey (domain , reg_path ) as local :
309
+ for j in range (winreg .QueryInfoKey (local )[1 ]):
310
+ # value may contain the filename of the font or its
311
+ # absolute path.
312
+ key , value , tp = winreg .EnumValue (local , j )
313
+ if not isinstance (value , str ):
314
+ continue
315
+ try :
316
+ # If value contains already an absolute path,
317
+ # then it is not changed further.
318
+ path = Path (base_dir , value ).resolve ()
319
+ except RuntimeError :
320
+ # Don't fail with invalid entries.
321
+ continue
322
+ items .add (path )
323
+ except (OSError , MemoryError ):
324
+ continue
325
+ return items
326
+
327
+
294
328
@lru_cache ()
295
- def _call_fc_list ():
296
- """Cache and list the font filenames known to `fc-list`."""
329
+ def _get_fontconfig_fonts ():
330
+ """Cache and list the font paths known to `fc-list`."""
297
331
try :
298
332
if b'--format' not in subprocess .check_output (['fc-list' , '--help' ]):
299
333
_log .warning ( # fontconfig 2.7 implemented --format.
@@ -302,14 +336,15 @@ def _call_fc_list():
302
336
out = subprocess .check_output (['fc-list' , '--format=%{file}\\ n' ])
303
337
except (OSError , subprocess .CalledProcessError ):
304
338
return []
305
- return [os .fsdecode (fname ) for fname in out .split (b'\n ' )]
339
+ return [Path ( os .fsdecode (fname ) ) for fname in out .split (b'\n ' )]
306
340
307
341
342
+ @_api .deprecated ("3.5" )
308
343
def get_fontconfig_fonts (fontext = 'ttf' ):
309
344
"""List font filenames known to `fc-list` having the given extension."""
310
345
fontext = ['.' + ext for ext in get_fontext_synonyms (fontext )]
311
- return [fname for fname in _call_fc_list ()
312
- if Path ( fname ) .suffix .lower () in fontext ]
346
+ return [str ( path ) for path in _get_fontconfig_fonts ()
347
+ if path .suffix .lower () in fontext ]
313
348
314
349
315
350
def findSystemFonts (fontpaths = None , fontext = 'ttf' ):
@@ -325,14 +360,16 @@ def findSystemFonts(fontpaths=None, fontext='ttf'):
325
360
326
361
if fontpaths is None :
327
362
if sys .platform == 'win32' :
363
+ installed_fonts = _get_win32_installed_fonts ()
328
364
fontpaths = MSUserFontDirectories + [win32FontDirectory ()]
329
- # now get all installed fonts directly...
330
- fontfiles .update (win32InstalledFonts (fontext = fontext ))
331
365
else :
332
- fontpaths = X11FontDirectories
366
+ installed_fonts = _get_fontconfig_fonts ()
333
367
if sys .platform == 'darwin' :
334
368
fontpaths = [* X11FontDirectories , * OSXFontDirectories ]
335
- fontfiles .update (get_fontconfig_fonts (fontext ))
369
+ else :
370
+ fontpaths = X11FontDirectories
371
+ fontfiles .update (str (path ) for path in installed_fonts
372
+ if path .suffix .lower ()[1 :] in fontexts )
336
373
337
374
elif isinstance (fontpaths , str ):
338
375
fontpaths = [fontpaths ]
0 commit comments