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 1f58af3f58
commit 6d7c54bcb2
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,
"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,
"condensed", (symbolic_traits & kCTFontCondensedTrait) != 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*
coretext_all_fonts(PyObject UNUSED *_self) {
CFArrayRef matches = CTFontCollectionCreateMatchingFontDescriptors(all_fonts_collection());
coretext_all_fonts(PyObject UNUSED *_self, PyObject *monospaced_only_) {
int monospaced_only = PyObject_IsTrue(monospaced_only_);
RAII_CoreFoundation(CFArrayRef, matches, CTFontCollectionCreateMatchingFontDescriptors(all_fonts_collection()));
const CFIndex count = CFArrayGetCount(matches);
PyObject *ans = PyTuple_New(count), *temp;
if (ans == NULL) { CFRelease(matches); return PyErr_NoMemory(); }
RAII_PyObject(ans, PyTuple_New(count));
if (ans == NULL) return NULL;
PyObject *temp;
Py_ssize_t num = 0;
for (CFIndex i = 0; i < count; i++) {
temp = font_descriptor_to_python((CTFontDescriptorRef) CFArrayGetValueAtIndex(matches, i));
if (temp == NULL) { CFRelease(matches); Py_DECREF(ans); return NULL; }
PyTuple_SET_ITEM(ans, i, temp); temp = NULL;
CTFontDescriptorRef desc = (CTFontDescriptorRef) CFArrayGetValueAtIndex(matches, i);
if (monospaced_only) {
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;
}
@@ -855,7 +871,7 @@ repr(CTFace *self) {
static PyMethodDef module_methods[] = {
METHODB(coretext_all_fonts, METH_NOARGS),
METHODB(coretext_all_fonts, METH_O),
{NULL, NULL, 0, NULL} /* Sentinel */
};

View File

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

View File

@@ -2,6 +2,7 @@
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
import re
from functools import lru_cache
from typing import Dict, Generator, Iterable, List, Optional, Tuple
from kitty.fast_data_types import coretext_all_fonts
@@ -33,16 +34,13 @@ def create_font_map(all_fonts: Iterable[CoreTextFont]) -> FontMap:
return ans
def all_fonts_map() -> FontMap:
ans: Optional[FontMap] = getattr(all_fonts_map, 'ans', None)
if ans is None:
ans = create_font_map(coretext_all_fonts())
setattr(all_fonts_map, 'ans', ans)
return ans
@lru_cache(maxsize=2)
def all_fonts_map(monospaced: bool = True) -> FontMap:
return create_font_map(coretext_all_fonts(monospaced))
def list_fonts() -> Generator[ListedFont, None, None]:
for fd in coretext_all_fonts():
for fd in coretext_all_fonts(False):
f = fd['family']
if f:
fn = fd['display_name']
@@ -52,9 +50,11 @@ def list_fonts() -> Generator[ListedFont, None, None]:
'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())
font_map = all_fonts_map()
font_map = all_fonts_map(monospaced)
def score(candidate: CoreTextFont) -> Tuple[int, int, int, float]:
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]:
ans = find_best_match(family)
ans = find_best_match(family, monospaced=False)
return ans, ans['bold'], ans['italic']