Support default font_features from fontconfig
This commit is contained in:
parent
e96ff19a7a
commit
822c9367c6
@ -21,6 +21,7 @@ from .conf.utils import (
|
||||
)
|
||||
from .config_data import all_options, parse_mods, type_convert
|
||||
from .constants import cache_dir, defconf, is_macos
|
||||
from .fonts import FontFeature
|
||||
from .key_names import get_key_name_lookup, key_name_aliases
|
||||
from .options_stub import Options as OptionsStub
|
||||
from .typing import TypedDict
|
||||
@ -524,14 +525,6 @@ def handle_symbol_map(key: str, val: str, ans: Dict[str, Any]) -> None:
|
||||
ans['symbol_map'].update(parse_symbol_map(val))
|
||||
|
||||
|
||||
class FontFeature(str):
|
||||
|
||||
def __new__(cls, name: str, parsed: bytes) -> 'FontFeature':
|
||||
ans: FontFeature = str.__new__(cls, name) # type: ignore
|
||||
ans.parsed = parsed # type: ignore
|
||||
return ans
|
||||
|
||||
|
||||
@special_handler
|
||||
def handle_font_features(key: str, val: str, ans: Dict[str, Any]) -> None:
|
||||
if val != 'none':
|
||||
|
||||
@ -410,6 +410,7 @@ class FontConfigPattern(TypedDict):
|
||||
postscript_name: str
|
||||
style: str
|
||||
spacing: str
|
||||
fontfeatures: str
|
||||
weight: int
|
||||
width: int
|
||||
slant: int
|
||||
@ -441,6 +442,12 @@ def fc_match(
|
||||
pass
|
||||
|
||||
|
||||
def fc_match_postscript_name(
|
||||
postscript_name: str
|
||||
) -> FontConfigPattern:
|
||||
pass
|
||||
|
||||
|
||||
class CoreTextFont(TypedDict):
|
||||
path: str
|
||||
postscript_name: str
|
||||
|
||||
@ -46,6 +46,7 @@ pattern_as_dict(FcPattern *pat) {
|
||||
S(FC_STYLE, style);
|
||||
S(FC_FULLNAME, full_name);
|
||||
S(FC_POSTSCRIPT_NAME, postscript_name);
|
||||
S(FC_FONT_FEATURES, fontfeatures);
|
||||
I(FC_WEIGHT, weight);
|
||||
I(FC_WIDTH, width)
|
||||
I(FC_SLANT, slant);
|
||||
@ -179,6 +180,26 @@ end:
|
||||
return ans;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
fc_match_postscript_name(PyObject UNUSED *self, PyObject *args) {
|
||||
char *postscript_name = NULL;
|
||||
FcPattern *pat = NULL;
|
||||
PyObject *ans = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|z", &postscript_name)) return NULL;
|
||||
pat = FcPatternCreate();
|
||||
if (pat == NULL) return PyErr_NoMemory();
|
||||
if (!postscript_name || strlen(postscript_name) == 0) return NULL;
|
||||
|
||||
AP(FcPatternAddString, FC_POSTSCRIPT_NAME, (const FcChar8*)postscript_name, "postscript_name");
|
||||
|
||||
ans = _fc_match(pat);
|
||||
|
||||
end:
|
||||
if (pat != NULL) FcPatternDestroy(pat);
|
||||
return ans;
|
||||
}
|
||||
|
||||
PyObject*
|
||||
specialize_font_descriptor(PyObject *base_descriptor, FONTS_DATA_HANDLE fg) {
|
||||
PyObject *p = PyDict_GetItemString(base_descriptor, "path"), *ans = NULL;
|
||||
@ -224,6 +245,7 @@ end:
|
||||
static PyMethodDef module_methods[] = {
|
||||
METHODB(fc_list, METH_VARARGS),
|
||||
METHODB(fc_match, METH_VARARGS),
|
||||
METHODB(fc_match_postscript_name, METH_VARARGS),
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
||||
@ -9,3 +9,11 @@ class ListedFont(TypedDict):
|
||||
full_name: str
|
||||
postscript_name: str
|
||||
is_monospace: bool
|
||||
|
||||
|
||||
class FontFeature(str):
|
||||
|
||||
def __new__(cls, name: str, parsed: bytes) -> 'FontFeature':
|
||||
ans: FontFeature = str.__new__(cls, name) # type: ignore
|
||||
ans.parsed = parsed # type: ignore
|
||||
return ans
|
||||
|
||||
@ -50,6 +50,11 @@ def list_fonts() -> Generator[ListedFont, None, None]:
|
||||
yield {'family': f, 'full_name': fn, 'postscript_name': fd['postscript_name'] or '', 'is_monospace': is_mono}
|
||||
|
||||
|
||||
def find_font_features(postscript_name: str) -> Tuple[str, ...]:
|
||||
"""Not Implemented"""
|
||||
return tuple()
|
||||
|
||||
|
||||
def find_best_match(family: str, bold: bool = False, italic: bool = False) -> CoreTextFont:
|
||||
q = re.sub(r'\s+', ' ', family.lower())
|
||||
font_map = all_fonts_map()
|
||||
|
||||
@ -8,12 +8,14 @@ from typing import Dict, Generator, List, Optional, Tuple, cast
|
||||
|
||||
from kitty.fast_data_types import (
|
||||
FC_DUAL, FC_MONO, FC_SLANT_ITALIC, FC_SLANT_ROMAN, FC_WEIGHT_BOLD,
|
||||
FC_WEIGHT_REGULAR, FC_WIDTH_NORMAL, fc_list, fc_match as fc_match_impl
|
||||
FC_WEIGHT_REGULAR, FC_WIDTH_NORMAL, fc_list, fc_match as fc_match_impl,
|
||||
fc_match_postscript_name, parse_font_feature
|
||||
)
|
||||
from kitty.options_stub import Options
|
||||
from kitty.typing import FontConfigPattern
|
||||
from kitty.utils import log_error
|
||||
|
||||
from . import ListedFont
|
||||
from . import ListedFont, FontFeature
|
||||
|
||||
attr_map = {(False, False): 'font_family',
|
||||
(True, False): 'bold_font',
|
||||
@ -69,6 +71,24 @@ def fc_match(family: str, bold: bool, italic: bool, spacing: int = FC_MONO) -> F
|
||||
return fc_match_impl(family, bold, italic, spacing)
|
||||
|
||||
|
||||
def find_font_features(postscript_name: str) -> Tuple[str, ...]:
|
||||
pat = fc_match_postscript_name(postscript_name)
|
||||
|
||||
if 'postscript_name' not in pat or pat['postscript_name'] != postscript_name or 'fontfeatures' not in pat:
|
||||
return tuple()
|
||||
|
||||
features = []
|
||||
for feat in pat['fontfeatures'].split():
|
||||
try:
|
||||
parsed = parse_font_feature(feat)
|
||||
except ValueError:
|
||||
log_error('Ignoring invalid font feature: {}'.format(feat))
|
||||
else:
|
||||
features.append(FontFeature(feat, parsed))
|
||||
|
||||
return tuple(features)
|
||||
|
||||
|
||||
def find_best_match(family: str, bold: bool = False, italic: bool = False, monospaced: bool = True) -> FontConfigPattern:
|
||||
q = family_name_to_key(family)
|
||||
font_map = all_fonts_map(monospaced)
|
||||
|
||||
@ -25,9 +25,9 @@ from kitty.typing import CoreTextFont, FontConfigPattern
|
||||
from kitty.utils import log_error
|
||||
|
||||
if is_macos:
|
||||
from .core_text import get_font_files as get_font_files_coretext, font_for_family as font_for_family_macos
|
||||
from .core_text import get_font_files as get_font_files_coretext, font_for_family as font_for_family_macos, find_font_features
|
||||
else:
|
||||
from .fontconfig import get_font_files as get_font_files_fontconfig, font_for_family as font_for_family_fontconfig
|
||||
from .fontconfig import get_font_files as get_font_files_fontconfig, font_for_family as font_for_family_fontconfig, find_font_features
|
||||
|
||||
FontObject = Union[CoreTextFont, FontConfigPattern]
|
||||
current_faces: List[Tuple[FontObject, bool, bool]] = []
|
||||
@ -189,12 +189,16 @@ def set_font_family(opts: Optional[OptionsStub] = None, override_font_size: Opti
|
||||
before = len(current_faces)
|
||||
sm = create_symbol_map(opts)
|
||||
num_symbol_fonts = len(current_faces) - before
|
||||
font_features = {}
|
||||
for face, _, _ in current_faces:
|
||||
font_features[face['postscript_name']] = find_font_features(face['postscript_name'])
|
||||
font_features.update(opts.font_features)
|
||||
if debug_font_matching:
|
||||
dump_faces(ftypes, indices)
|
||||
set_font_data(
|
||||
render_box_drawing, prerender_function, descriptor_for_idx,
|
||||
indices['bold'], indices['italic'], indices['bi'], num_symbol_fonts,
|
||||
sm, sz, opts.font_features
|
||||
sm, sz, font_features
|
||||
)
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user