From 7fc7d69a882f8d9abefdf7e1a0c995aa8d6d3da2 Mon Sep 17 00:00:00 2001 From: moi15moi Date: Mon, 5 Jun 2023 20:54:22 -0400 Subject: [PATCH] [mac_fonts] Replace CFURLGetFileSystemRepresentation to CFURLCopyFileSystemPath 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. --- find_system_fonts_filename/mac_fonts.py | 62 ++++++++++++++++++------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/find_system_fonts_filename/mac_fonts.py b/find_system_fonts_filename/mac_fonts.py index f0a5335..b0a57ab 100644 --- a/find_system_fonts_filename/mac_fonts.py +++ b/find_system_fonts_filename/mac_fonts.py @@ -1,5 +1,5 @@ -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 @@ -7,6 +7,13 @@ 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 @@ -14,6 +21,7 @@ class MacFonts(SystemFonts): # 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): @@ -25,21 +33,13 @@ 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: @@ -47,6 +47,23 @@ def get_system_fonts_filename() -> Set[str]: 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") @@ -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 @@ -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