Prune listings of variable fonts

Show only one entry per style per variable font as identified by path
This commit is contained in:
Kovid Goyal
2024-04-22 19:44:36 +05:30
parent fa52066156
commit 3b84498af9
4 changed files with 45 additions and 9 deletions

View File

@@ -845,10 +845,13 @@ get_variable_data(CTFace *self) {
RAII_CoreFoundation(CFArrayRef, descriptors, CTFontCollectionCreateMatchingFontDescriptors(collection));
RAII_PyObject(named_styles, PyTuple_New(CFArrayGetCount(descriptors)));
Py_ssize_t actual_num = 0;
RAII_CoreFoundation(CFURLRef, url, CTFontCopyAttribute(self->ct_font, kCTFontURLAttribute));
for (CFIndex i = 0; i < CFArrayGetCount(descriptors); i++) {
CTFontDescriptorRef descriptor = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descriptors, i);
RAII_CoreFoundation(CFDictionaryRef, variation, CTFontDescriptorCopyAttribute(descriptor, kCTFontVariationAttribute));
if (!variation) continue;
RAII_CoreFoundation(CFURLRef, candidate_url, CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute));
if (!CFEqual(url, candidate_url)) continue;
RAII_CoreFoundation(CFStringRef, style, CTFontDescriptorCopyAttribute(descriptor, kCTFontStyleNameAttribute));
RAII_CoreFoundation(CFStringRef, psname, CTFontDescriptorCopyAttribute(descriptor, kCTFontNameAttribute));
RAII_PyObject(axis_values, PyDict_New());

View File

@@ -118,6 +118,26 @@ def font_for_family(family: str) -> Tuple[CoreTextFont, bool, bool]:
def get_variable_data_for_descriptor(f: ListedFont) -> VariableData:
return CTFace(descriptor=descriptor(f)).get_variable_data()
def descriptor(f: ListedFont) -> CoreTextFont:
d = f['descriptor']
assert d['descriptor_type'] == 'core_text'
return CTFace(descriptor=d).get_variable_data()
return d
def prune_family_group(g: List[ListedFont]) -> List[ListedFont]:
# CoreText returns a separate font for every style in the variable font, so
# merge them.
variable_paths = {descriptor(f)['path']: False for f in g if f['is_variable']}
if not variable_paths:
return g
def is_ok(d: CoreTextFont) -> bool:
if d['path'] not in variable_paths:
return True
if not variable_paths[d['path']]:
variable_paths[d['path']] = True
return True
return False
return [x for x in g if is_ok(descriptor(x))]

View File

@@ -177,7 +177,22 @@ def font_for_family(family: str) -> Tuple[FontConfigPattern, bool, bool]:
return ans, ans.get('weight', 0) >= FC_WEIGHT_BOLD, ans.get('slant', FC_SLANT_ROMAN) != FC_SLANT_ROMAN
def get_variable_data_for_descriptor(f: ListedFont) -> VariableData:
def descriptor(f: ListedFont) -> FontConfigPattern:
d = f['descriptor']
assert d['descriptor_type'] == 'fontconfig'
return Face(descriptor=d).get_variable_data()
return d
def get_variable_data_for_descriptor(f: ListedFont) -> VariableData:
return Face(descriptor=descriptor(f)).get_variable_data()
def prune_family_group(g: List[ListedFont]) -> List[ListedFont]:
# fontconfig creates dummy entries for named styles in variable fonts, prune them
variable_paths = {descriptor(f)['path'] for f in g if f['is_variable']}
if not variable_paths:
return g
def is_ok(d: FontConfigPattern) -> bool:
return d['variable'] or d['path'] not in variable_paths
return [x for x in g if is_ok(descriptor(x))]

View File

@@ -11,9 +11,9 @@ from kitty.types import run_once
from . import ListedFont
if is_macos:
from .core_text import get_variable_data_for_descriptor, list_fonts
from .core_text import get_variable_data_for_descriptor, list_fonts, prune_family_group
else:
from .fontconfig import get_variable_data_for_descriptor, list_fonts
from .fontconfig import get_variable_data_for_descriptor, list_fonts, prune_family_group
@run_once
@@ -54,14 +54,12 @@ def create_family_groups(monospaced: bool = True) -> Dict[str, List[ListedFont]]
for f in list_fonts():
if not monospaced or f['is_monospace']:
g.setdefault(f['family'], []).append(f)
return g
return {k: prune_family_group(v) for k, v in g.items()}
def show_variable(f: ListedFont, psnames: bool) -> None:
vd = get_variable_data_for_descriptor(f)
p = italic(f['full_name'])
if psnames and f['postscript_name']:
p += f' ({f["postscript_name"]})'
p = italic(f['family'])
p = f"{p} {variable_font_label('Variable font')}"
print(indented(p))
print(indented(variable_font_label('Axes of variation'), level=2))