Skip to content

Commit

Permalink
[mac_fonts] Replace CFURLGetFileSystemRepresentation to CFURLCopyFile…
Browse files Browse the repository at this point in the history
…SystemPath

I thought it would be a bit faster to use CFURLCopyFileSystemPath instead of CFURLGetFileSystemRepresentation since the buffer isn't always 1024, but after some performance testing, it reveal that CFURLGetFileSystemRepresentation is actually faster.

So, this is totally useless, but it might be good to keep it.
  • Loading branch information
moi15moi committed Jun 6, 2023
1 parent c6620f9 commit 7fc7d69
Showing 1 changed file with 46 additions and 16 deletions.
62 changes: 46 additions & 16 deletions find_system_fonts_filename/mac_fonts.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
from ctypes import c_bool, c_char_p, c_long, c_void_p, cdll, create_string_buffer, util
from os import pathconf
from ctypes import c_bool, c_char_p, c_int, c_long, c_uint32, c_void_p, cdll, create_string_buffer, util
from enum import IntEnum
from pathlib import Path
from platform import mac_ver
from typing import Set
from .exceptions import OSNotSupported
from .system_fonts import SystemFonts


class CFURLPathStyle(IntEnum):
# https://developer.apple.com/documentation/corefoundation/cfurlpathstyle?language=objc
kCFURLPOSIXPathStyle = 0
kCFURLHFSPathStyle = 1
kCFURLWindowsPathStyle = 2


class MacFonts(SystemFonts):
_core_foundation = None
_core_text = None
# CoreText has an API to get the format of the font: https://developer.apple.com/documentation/coretext/ctfontformat
# But, the API is "semi-broken" since it says .dfont are TrueType. This is kinda true, but it is not a behaviour that we want.
# So, we only check the file extension and see if it is valid.
VALID_FONT_FORMATS = ["ttf", "otf", "ttc"]
kCFStringEncodingUTF8 = 0x08000100 # https://developer.apple.com/documentation/corefoundation/cfstringbuiltinencodings/kcfstringencodingutf8?language=objc

def get_system_fonts_filename() -> Set[str]:
if MacVersionHelpers.is_mac_version_or_greater(10, 6):
Expand All @@ -25,28 +33,37 @@ def get_system_fonts_filename() -> Set[str]:
font_urls = MacFonts._core_text.CTFontManagerCopyAvailableFontURLs()
font_count = MacFonts._core_foundation.CFArrayGetCount(font_urls)

max_length = pathconf("/", "PC_PATH_MAX")

for i in range(font_count):
url = MacFonts._core_foundation.CFArrayGetValueAtIndex(font_urls, i)

file_name_ptr = create_string_buffer(max_length)
no_error = MacFonts._core_foundation.CFURLGetFileSystemRepresentation(url, True, file_name_ptr, max_length)

if no_error:
filename = file_name_ptr.value.decode()
filename = MacFonts._cfstring_to_string(MacFonts._core_text.CFURLCopyFileSystemPath(url, CFURLPathStyle.kCFURLPOSIXPathStyle))

if Path(filename).suffix.lstrip(".").strip().lower() in MacFonts.VALID_FONT_FORMATS:
fonts_filename.add(filename)
else:
raise Exception("An unexpected error has occurred while decoded the CFURL.")
if Path(filename).suffix.lstrip(".").strip().lower() in MacFonts.VALID_FONT_FORMATS:
fonts_filename.add(filename)

MacFonts._core_foundation.CFRelease(font_urls)
else:
raise OSNotSupported("FindSystemFontsFilename only works on Mac 10.6 or more")

return fonts_filename

@staticmethod
def _cfstring_to_string(cfstring: c_void_p) -> str:
"""
Parameters:
cfstring (c_void_p): An CFString instance.
Returns:
The decoded CFString.
"""
length = MacFonts._core_foundation.CFStringGetLength(cfstring)
size = MacFonts._core_foundation.CFStringGetMaximumSizeForEncoding(length, MacFonts.kCFStringEncodingUTF8)
buffer = create_string_buffer(size + 1)
result = MacFonts._core_foundation.CFStringGetCString(cfstring, buffer, len(buffer), MacFonts.kCFStringEncodingUTF8)
if result:
return str(buffer.value, 'utf-8')
else:
raise Exception("An unexpected error has occurred while decoded the CFString.")

@staticmethod
def _load_core_library():
core_foundation_library_name = util.find_library("CoreFoundation")
Expand All @@ -64,6 +81,8 @@ def _load_core_library():
MacFonts._core_text = cdll.LoadLibrary(core_text_library_name)

CFIndex = c_long
CFStringEncoding = c_uint32
CFURLPathStyle = c_int

# https://developer.apple.com/documentation/corefoundation/1521153-cfrelease
MacFonts._core_foundation.CFRelease.restype = c_void_p
Expand All @@ -77,14 +96,25 @@ def _load_core_library():
MacFonts._core_foundation.CFArrayGetValueAtIndex.restype = c_void_p
MacFonts._core_foundation.CFArrayGetValueAtIndex.argtypes = [c_void_p, CFIndex]

# https://developer.apple.com/documentation/corefoundation/1541515-cfurlgetfilesystemrepresentation?language=objc
MacFonts._core_foundation.CFURLGetFileSystemRepresentation.restype = c_bool
MacFonts._core_foundation.CFURLGetFileSystemRepresentation.argtypes = [c_void_p, c_bool, c_char_p, CFIndex]
# https://developer.apple.com/documentation/corefoundation/1542853-cfstringgetlength?language=objc
MacFonts._core_foundation.CFStringGetLength.restype = CFIndex
MacFonts._core_foundation.CFStringGetLength.argtypes = [c_void_p]

# https://developer.apple.com/documentation/corefoundation/1542143-cfstringgetmaximumsizeforencodin?language=objc
MacFonts._core_foundation.CFStringGetMaximumSizeForEncoding.restype = CFIndex
MacFonts._core_foundation.CFStringGetMaximumSizeForEncoding.argtypes = [c_void_p, CFStringEncoding]

# https://developer.apple.com/documentation/corefoundation/1542721-cfstringgetcstring?language=objc
MacFonts._core_foundation.CFStringGetCString.restype = c_bool
MacFonts._core_foundation.CFStringGetCString.argtypes = [c_void_p, c_char_p, CFIndex, CFStringEncoding]

# https://developer.apple.com/documentation/coretext/1499478-ctfontmanagercopyavailablefontur?language=objc
MacFonts._core_text.CTFontManagerCopyAvailableFontURLs.restype = c_void_p
MacFonts._core_text.CTFontManagerCopyAvailableFontURLs.argtypes = []

# https://developer.apple.com/documentation/corefoundation/1541581-cfurlcopyfilesystempath?language=objc
MacFonts._core_text.CFURLCopyFileSystemPath.restype = c_void_p
MacFonts._core_text.CFURLCopyFileSystemPath.argtypes = [c_void_p, CFURLPathStyle]

class MacVersionHelpers:
@staticmethod
Expand Down

0 comments on commit 7fc7d69

Please sign in to comment.