fonts: make the color emoji regression test environment-independent

The coverage threshold (0.5 in fbd4e5ad1, lowered to 0.3 in d4106ef2d to
get CI green) is environment-dependent: a correctly sized emoji covers
~0.84 of its cell on one box but ~0.39 in CI, while the buggy render is
~0.28, so the margin is thin and font/cell dependent.

Render the same font two ways at one size instead: via its fontconfig
descriptor (which carries the size-fixup matrix) and via its file path
(which does not). They must come out the same size; the bug shrinks the
descriptor one. Only the matrix differs, so the check no longer depends
on the environment or the emoji artwork.
This commit is contained in:
Strykar 2026-06-14 21:00:12 +05:30
parent d4106ef2db
commit fc23ef57ec
No known key found for this signature in database
GPG key ID: E4A8486E91D492EA

View file

@ -392,28 +392,27 @@ class Rendering(FontBaseTest):
def test_color_emoji_not_shrunk(self):
# Regression test for https://github.com/kovidgoyal/kitty/issues/10144.
# fontconfig encodes the pixel-size fixup of fixed-size color faces (such
# as Noto Color Emoji, a ~109px bitmap strike) as FC_MATRIX. That scale
# must not reach the cairo font matrix, where glyph size is owned by
# cairo_set_font_size() + fit_cairo_glyph(); applying it there shrinks the
# glyph by the fixup factor (requested_px / strike_px), and fit_cairo_glyph()
# only shrinks so it never grows it back (ee937bdd1b). The shrink ranges
# from ~9x at tiny cells to ~1x near the strike; at 48pt/96dpi (~64px) the
# bug gives ~0.28 coverage versus ~0.84 when correct.
# fontconfig gives fixed-size color faces (e.g. Noto Color Emoji) a
# pixel-size fixup encoded as FC_MATRIX. That scale must not reach the
# cairo font matrix used for color glyphs; applying it shrinks color emoji
# to a dot (ee937bdd1b). Render the same font two ways at the same size:
# from its fontconfig descriptor, which carries the fixup matrix, and from
# its file path, which does not. A correct build renders both at the same
# size; the bug shrinks the descriptor one. Comparing the two is
# environment-independent since only the matrix differs.
if is_macos:
self.skipTest('this is a fontconfig FC_MATRIX issue, not present on macOS')
self.skipTest('FC_MATRIX is a fontconfig feature, not used on macOS')
from kitty.fonts.fontconfig import fc_match
emoji = fc_match('emoji', False, False, 0)
if not (emoji.get('color') and emoji.get('matrix')):
# Only a fixed-size color face that fontconfig gives a fixup matrix can
# trigger this. A scalable COLR emoji font has none, so a pass there
# would be a false negative rather than a real check.
desc = dict(fc_match('emoji', False, False, 0))
if not (desc.get('color') and desc.get('matrix')):
self.skipTest('no fixed-size color emoji font with a fontconfig fixup matrix')
cells = render_string('\U0001F40D', 'monospace', 48.0, 96.0)[2]
pixels = array.array('I', b''.join(cells))
coverage = sum(1 for p in pixels if p) / max(len(pixels), 1)
del cells, pixels
self.assertGreater(coverage, 0.3, f'color emoji coverage {coverage:.2f} too low, likely shrunk (#10144)')
with_matrix = face_from_descriptor(desc)
with_matrix.set_size(64, 96, 96)
without_matrix = create_face(desc['path'])
without_matrix.set_size(64, 96, 96)
_, mw, mh = with_matrix.render_codepoint(0x1F40D)
_, rw, rh = without_matrix.render_codepoint(0x1F40D)
self.assertGreater(mh, 0.5 * rh, f'color emoji shrunk by FC_MATRIX: {mh}px vs {rh}px (#10144)')
def test_shaping(self):