mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-13 12:09:10 +02:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48ee061454 | ||
|
|
aa4e94cef5 | ||
|
|
8a39929c15 | ||
|
|
8be2a10b29 | ||
|
|
779a49acde |
@@ -78,11 +78,11 @@
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sqlite 3.53.0",
|
||||
"name": "sqlite 3.53.2",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"hash": "sha256:851e9b38192fe2ceaa65e0baa665e7fa06230c3d9bd1a6a9662d02380d73365a",
|
||||
"urls": ["https://www.sqlite.org/2026/{name}-autoconf-3530000.{file_extension}"]
|
||||
"hash": "sha256:588ad51949419a56ebe81fe56193d510c559eb94c9a57748387860b5d3069316",
|
||||
"urls": ["https://www.sqlite.org/2026/{name}-autoconf-3530200.{file_extension}"]
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -173,6 +173,11 @@ consumption to do the same tasks.
|
||||
Detailed list of changes
|
||||
-------------------------------------
|
||||
|
||||
0.50.0 [future]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Linux: Allow fake italics defined via a matrix in fontconfig settings to work for fonts like Fira Code that do not ship with an italic face (:pull:`10120`)
|
||||
|
||||
0.47.3 [2026-06-12]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -458,6 +458,10 @@ specialize_font_descriptor(PyObject *base_descriptor, double font_sz_in_pts, dou
|
||||
if (axes) {
|
||||
if (PyDict_SetItemString(ans, "axes", axes) != 0) return NULL;
|
||||
}
|
||||
PyObject *matrix = PyDict_GetItemString(base_descriptor, "matrix");
|
||||
if (matrix) {
|
||||
if (PyDict_SetItemString(ans, "matrix", matrix) != 0) return NULL;
|
||||
}
|
||||
PyObject *ff = PyDict_GetItemString(ans, "fontfeatures");
|
||||
if (ff && PyList_GET_SIZE(ff)) {
|
||||
for (Py_ssize_t i = 0; i < PyList_GET_SIZE(ff); i++) {
|
||||
|
||||
@@ -401,7 +401,38 @@ def get_font_files(opts: Options) -> FontFiles:
|
||||
font = medium_font
|
||||
key = kd[(bold, italic)]
|
||||
ans[key] = font
|
||||
return {'medium': ans['medium'], 'bold': ans['bold'], 'italic': ans['italic'], 'bi': ans['bi']}
|
||||
|
||||
def apply_synthetic_matrix(font: Descriptor, bold: bool, italic: bool) -> Descriptor:
|
||||
# fontconfig's FcFontList (used by find_best_match) omits FC_MATRIX from
|
||||
# its object set, so a roman font found there carries no synthetic-italic
|
||||
# shear and its "italic" renders upright. Fira Code is the case (it ships
|
||||
# no italic), in both its static and variable builds. The italic intent
|
||||
# exists only here at selection finalize, not at face construction, so
|
||||
# recover the matrix now: for an italic slot whose chosen face is upright
|
||||
# (no slant) and has no matrix yet, ask fc_match what fontconfig would do.
|
||||
# fc_match returns a synthetic matrix only when there is no real italic to
|
||||
# use (no italic face and no slanted named instance or variable slant
|
||||
# axis); when a real italic exists it returns no matrix, so a font that is
|
||||
# already italic, static or variable, is never double-slanted. Face construction applies the matrix
|
||||
# via FT_Set_Transform; specialize_font_descriptor preserves it when the
|
||||
# descriptor is sized for rendering. Only the matrix is taken, so
|
||||
# selection is unchanged. Covers the four configured faces; fc_match
|
||||
# re-matches by family name (see commit message).
|
||||
if (italic and font['descriptor_type'] == 'fontconfig'
|
||||
and not font.get('matrix') and not font.get('slant')):
|
||||
from kitty.fast_data_types import FC_MONO
|
||||
from kitty.fonts.fontconfig import fc_match
|
||||
mtx = fc_match(font['family'], bold, italic, FC_MONO if is_monospace(font) else -1).get('matrix')
|
||||
if mtx:
|
||||
new_font = font.copy()
|
||||
new_font['matrix'] = mtx
|
||||
return new_font
|
||||
return font
|
||||
return {
|
||||
'medium': ans['medium'], 'bold': ans['bold'],
|
||||
'italic': apply_synthetic_matrix(ans['italic'], False, True),
|
||||
'bi': apply_synthetic_matrix(ans['bi'], True, True),
|
||||
}
|
||||
|
||||
|
||||
def axis_values_are_equal(defaults: dict[str, float], a: dict[str, float], b: dict[str, float]) -> bool:
|
||||
|
||||
@@ -173,6 +173,41 @@ class Selection(BaseTest):
|
||||
self.ae(face_from_descriptor(ff['medium']).applied_features(), {'dlig': 'dlig', 'test': 'test=3'})
|
||||
self.ae(face_from_descriptor(ff['bold']).applied_features(), {'dlig': 'dlig', 'test': 'test=3'})
|
||||
|
||||
def test_synthetic_italic_matrix(self):
|
||||
# A roman-only font that find_best_match finds (e.g. Fira Code, which ships
|
||||
# no italic face) must get fontconfig's synthetic-italic FC_MATRIX
|
||||
# (90-synthetic.conf) attached, so its italic renders slanted rather than
|
||||
# upright; real-italic faces must not. The shear value is fontconfig's, not
|
||||
# ours, so assert the invariant (a non-identity matrix is present), not the
|
||||
# exact tuple, for cross-config stability.
|
||||
if is_macos:
|
||||
self.skipTest('synthetic-italic FC_MATRIX is a fontconfig feature')
|
||||
from kitty.fonts.fontconfig import FC_MONO, fc_match
|
||||
names = set(all_fonts_map(True)['family_map']) | set(all_fonts_map(True)['variable_map'])
|
||||
if family_name_to_key('fira code') not in names:
|
||||
self.skipTest('Fira Code not installed')
|
||||
# Probe fc_match directly so we can tell "environment lacks the rule" (skip)
|
||||
# from "code did not attach the matrix" (fail).
|
||||
if fc_match('Fira Code', False, True, FC_MONO).get('matrix') is None:
|
||||
self.skipTest('fontconfig 90-synthetic.conf not active; no synthetic-italic matrix')
|
||||
opts = Options()
|
||||
opts.font_family = parse_font_spec('Fira Code')
|
||||
ff = get_font_files(opts)
|
||||
self.assertIsNone(ff['medium'].get('matrix')) # upright stays upright
|
||||
mi = ff['italic'].get('matrix')
|
||||
self.assertIsNotNone(mi) # roman, no italic -> sheared
|
||||
self.assertNotEqual(mi[1], 0.0) # actually slanted, not identity
|
||||
# Faces are built from a size-specialized descriptor at render time; the
|
||||
# matrix must survive specialize_font_descriptor or the glyphs render
|
||||
# upright despite the descriptor above being correct.
|
||||
from kitty.fast_data_types import specialize_font_descriptor
|
||||
sd = specialize_font_descriptor(dict(ff['italic']), 12.0, 96.0, 96.0)
|
||||
self.ae(sd.get('matrix'), mi)
|
||||
if family_name_to_key('liberation mono') in names: # real-italic control
|
||||
opts.font_family = parse_font_spec('Liberation Mono')
|
||||
self.assertIsNone(get_font_files(opts)['italic'].get('matrix'))
|
||||
|
||||
|
||||
def block_helpers(s, sprites, cell_width, cell_height):
|
||||
mr = {}
|
||||
actual = b''
|
||||
|
||||
Reference in New Issue
Block a user