Make CoreText signatures for some font finding methods the same as their equivalents in fontconfig

This commit is contained in:
Kovid Goyal
2024-04-25 20:43:35 +05:30
parent 53be33f14d
commit 7e232b33be
3 changed files with 37 additions and 21 deletions

View File

@@ -137,7 +137,7 @@ font_descriptor_to_python(CTFontDescriptorRef descriptor) {
"bold", (symbolic_traits & kCTFontBoldTrait) != 0 ? Py_True : Py_False, "bold", (symbolic_traits & kCTFontBoldTrait) != 0 ? Py_True : Py_False,
"italic", (symbolic_traits & kCTFontItalicTrait) != 0 ? Py_True : Py_False, "italic", (symbolic_traits & kCTFontItalicTrait) != 0 ? Py_True : Py_False,
"monospace", (symbolic_traits & kCTFontMonoSpaceTrait) != 0 ? Py_True : Py_False, "monospace", (symbolic_traits & kCTFontTraitMonoSpace) != 0 ? Py_True : Py_False,
"expanded", (symbolic_traits & kCTFontExpandedTrait) != 0 ? Py_True : Py_False, "expanded", (symbolic_traits & kCTFontExpandedTrait) != 0 ? Py_True : Py_False,
"condensed", (symbolic_traits & kCTFontCondensedTrait) != 0 ? Py_True : Py_False, "condensed", (symbolic_traits & kCTFontCondensedTrait) != 0 ? Py_True : Py_False,
"color_glyphs", (symbolic_traits & kCTFontColorGlyphsTrait) != 0 ? Py_True : Py_False, "color_glyphs", (symbolic_traits & kCTFontColorGlyphsTrait) != 0 ? Py_True : Py_False,
@@ -185,17 +185,33 @@ all_fonts_collection(void) {
} }
static PyObject* static PyObject*
coretext_all_fonts(PyObject UNUSED *_self) { coretext_all_fonts(PyObject UNUSED *_self, PyObject *monospaced_only_) {
CFArrayRef matches = CTFontCollectionCreateMatchingFontDescriptors(all_fonts_collection()); int monospaced_only = PyObject_IsTrue(monospaced_only_);
RAII_CoreFoundation(CFArrayRef, matches, CTFontCollectionCreateMatchingFontDescriptors(all_fonts_collection()));
const CFIndex count = CFArrayGetCount(matches); const CFIndex count = CFArrayGetCount(matches);
PyObject *ans = PyTuple_New(count), *temp; RAII_PyObject(ans, PyTuple_New(count));
if (ans == NULL) { CFRelease(matches); return PyErr_NoMemory(); } if (ans == NULL) return NULL;
PyObject *temp;
Py_ssize_t num = 0;
for (CFIndex i = 0; i < count; i++) { for (CFIndex i = 0; i < count; i++) {
temp = font_descriptor_to_python((CTFontDescriptorRef) CFArrayGetValueAtIndex(matches, i)); CTFontDescriptorRef desc = (CTFontDescriptorRef) CFArrayGetValueAtIndex(matches, i);
if (temp == NULL) { CFRelease(matches); Py_DECREF(ans); return NULL; } if (monospaced_only) {
PyTuple_SET_ITEM(ans, i, temp); temp = NULL; RAII_CoreFoundation(CFDictionaryRef, traits, CTFontDescriptorCopyAttribute(desc, kCTFontTraitsAttribute));
if (traits) {
unsigned long symbolic_traits;
CFNumberRef value = (CFNumberRef)CFDictionaryGetValue(traits, kCTFontSymbolicTrait);
if (value) {
CFNumberGetValue(value, kCFNumberLongType, &symbolic_traits);
if (!(symbolic_traits & kCTFontTraitMonoSpace)) continue;
}
}
}
temp = font_descriptor_to_python(desc);
if (temp == NULL) return NULL;
PyTuple_SET_ITEM(ans, num++, temp); temp = NULL;
} }
CFRelease(matches); if (_PyTuple_Resize(&ans, num) == -1) return NULL;
Py_INCREF(ans);
return ans; return ans;
} }
@@ -855,7 +871,7 @@ repr(CTFace *self) {
static PyMethodDef module_methods[] = { static PyMethodDef module_methods[] = {
METHODB(coretext_all_fonts, METH_NOARGS), METHODB(coretext_all_fonts, METH_O),
{NULL, NULL, 0, NULL} /* Sentinel */ {NULL, NULL, 0, NULL} /* Sentinel */
}; };

View File

@@ -455,7 +455,7 @@ class CTFace:
def display_name(self) -> str: ... def display_name(self) -> str: ...
def coretext_all_fonts() -> Tuple[CoreTextFont, ...]: def coretext_all_fonts(monospaced_only: bool) -> Tuple[CoreTextFont, ...]:
pass pass

View File

@@ -2,6 +2,7 @@
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net> # License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
import re import re
from functools import lru_cache
from typing import Dict, Generator, Iterable, List, Optional, Tuple from typing import Dict, Generator, Iterable, List, Optional, Tuple
from kitty.fast_data_types import coretext_all_fonts from kitty.fast_data_types import coretext_all_fonts
@@ -33,16 +34,13 @@ def create_font_map(all_fonts: Iterable[CoreTextFont]) -> FontMap:
return ans return ans
def all_fonts_map() -> FontMap: @lru_cache(maxsize=2)
ans: Optional[FontMap] = getattr(all_fonts_map, 'ans', None) def all_fonts_map(monospaced: bool = True) -> FontMap:
if ans is None: return create_font_map(coretext_all_fonts(monospaced))
ans = create_font_map(coretext_all_fonts())
setattr(all_fonts_map, 'ans', ans)
return ans
def list_fonts() -> Generator[ListedFont, None, None]: def list_fonts() -> Generator[ListedFont, None, None]:
for fd in coretext_all_fonts(): for fd in coretext_all_fonts(False):
f = fd['family'] f = fd['family']
if f: if f:
fn = fd['display_name'] fn = fd['display_name']
@@ -52,9 +50,11 @@ def list_fonts() -> Generator[ListedFont, None, None]:
'is_variable': fd['variable'], 'descriptor': fd} 'is_variable': fd['variable'], 'descriptor': fd}
def find_best_match(family: str, bold: bool = False, italic: bool = False, ignore_face: Optional[CoreTextFont] = None) -> CoreTextFont: def find_best_match(
family: str, bold: bool = False, italic: bool = False, monospaced: bool = True, ignore_face: Optional[CoreTextFont] = None
) -> CoreTextFont:
q = re.sub(r'\s+', ' ', family.lower()) q = re.sub(r'\s+', ' ', family.lower())
font_map = all_fonts_map() font_map = all_fonts_map(monospaced)
def score(candidate: CoreTextFont) -> Tuple[int, int, int, float]: def score(candidate: CoreTextFont) -> Tuple[int, int, int, float]:
style_match = 1 if candidate['bold'] == bold and candidate[ style_match = 1 if candidate['bold'] == bold and candidate[
@@ -115,7 +115,7 @@ def get_font_files(opts: Options) -> Dict[str, CoreTextFont]:
def font_for_family(family: str) -> Tuple[CoreTextFont, bool, bool]: def font_for_family(family: str) -> Tuple[CoreTextFont, bool, bool]:
ans = find_best_match(family) ans = find_best_match(family, monospaced=False)
return ans, ans['bold'], ans['italic'] return ans, ans['bold'], ans['italic']