mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-27 02:31:45 +02:00
Refactor the fontconfig API
Makes it more flexible and DRYer
This commit is contained in:
@@ -15,55 +15,70 @@ def escape_family_name(name):
|
|||||||
return re.sub(r'([-:,\\])', lambda m: '\\' + m.group(1), name)
|
return re.sub(r'([-:,\\])', lambda m: '\\' + m.group(1), name)
|
||||||
|
|
||||||
|
|
||||||
Font = namedtuple('Font', 'face hinting hintstyle bold italic')
|
Font = namedtuple(
|
||||||
|
'Font', 'face hinting hintstyle bold italic scalable outline weight slant'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class FontNotFound(ValueError):
|
class FontNotFound(ValueError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def get_font(query, bold, italic):
|
def to_bool(x):
|
||||||
query += ':scalable=true:outline=true'
|
return x.lower() == 'true'
|
||||||
raw = subprocess.check_output(
|
|
||||||
['fc-match', query, '-f', '%{file}\x1e%{hinting}\x1e%{hintstyle}'
|
|
||||||
]).decode('utf-8')
|
def get_font(
|
||||||
|
family, bold, italic, allow_bitmaped_fonts=False, size_in_pts=None, character=None
|
||||||
|
):
|
||||||
|
query = escape_family_name(family)
|
||||||
|
if character is not None:
|
||||||
|
query += ':charset={:x}'.format(ord(character[0]))
|
||||||
|
if not allow_bitmaped_fonts:
|
||||||
|
query += ':scalable=true:outline=true'
|
||||||
|
if size_in_pts is not None:
|
||||||
|
query += ':size={:.1f}'.format(size_in_pts)
|
||||||
|
if bold:
|
||||||
|
query += ':weight=200'
|
||||||
|
if italic:
|
||||||
|
query += ':slant=100'
|
||||||
|
raw = subprocess.check_output([
|
||||||
|
'fc-match', query, '-f',
|
||||||
|
'%{file}\x1e%{hinting}\x1e%{hintstyle}\x1e%{scalable}\x1e%{outline}\x1e%{weight}\x1e%{slant}'
|
||||||
|
]).decode('utf-8')
|
||||||
parts = raw.split('\x1e')
|
parts = raw.split('\x1e')
|
||||||
hintstyle, hinting = 1, 'True'
|
try:
|
||||||
if len(parts) == 3:
|
path, hinting, hintstyle, scalable, outline, weight, slant = parts
|
||||||
path, hinting, hintstyle = parts
|
except ValueError:
|
||||||
else:
|
|
||||||
path = parts[0]
|
path = parts[0]
|
||||||
hinting = hinting.lower() == 'true'
|
hintstyle, hinting, scalable, outline, weight, slant = 1, 'True', 'True', 'True', 100, 0
|
||||||
hintstyle = int(hintstyle)
|
return Font(
|
||||||
return Font(path, hinting, hintstyle, bold, italic)
|
path,
|
||||||
|
to_bool(hinting),
|
||||||
|
int(hintstyle), bold, italic,
|
||||||
|
to_bool(scalable), to_bool(outline), int(weight), int(slant)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=4096)
|
@lru_cache(maxsize=4096)
|
||||||
def find_font_for_character(family, char, bold=False, italic=False):
|
def find_font_for_character(family, char, bold=False, italic=False):
|
||||||
q = escape_family_name(family) + ':charset={:x}'.format(ord(char[0]))
|
|
||||||
if bold:
|
|
||||||
q += ':weight=200'
|
|
||||||
if italic:
|
|
||||||
q += ':slant=100'
|
|
||||||
try:
|
try:
|
||||||
ans = get_font(q, bold, italic)
|
ans = get_font(family, bold, italic, character=char)
|
||||||
except subprocess.CalledProcessError as err:
|
except subprocess.CalledProcessError as err:
|
||||||
raise FontNotFound(
|
raise FontNotFound(
|
||||||
'Failed to find font for character U+{:X}, error from fontconfig: {}'.
|
'Failed to find font for character U+{:X}, error from fontconfig: {}'.
|
||||||
format(ord(char[0]), err))
|
format(ord(char[0]), err)
|
||||||
|
)
|
||||||
if not ans.face or not os.path.exists(ans.face):
|
if not ans.face or not os.path.exists(ans.face):
|
||||||
raise FontNotFound('Failed to find font for character U+{:X}'.format(ord(char[0])))
|
raise FontNotFound(
|
||||||
|
'Failed to find font for character U+{:X}'.format(ord(char[0]))
|
||||||
|
)
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=64)
|
@lru_cache(maxsize=64)
|
||||||
def get_font_information(q, bold=False, italic=False):
|
def get_font_information(family, bold=False, italic=False):
|
||||||
q = escape_family_name(q)
|
return get_font(family, bold, italic)
|
||||||
if bold:
|
|
||||||
q += ':weight=200'
|
|
||||||
if italic:
|
|
||||||
q += ':slant=100'
|
|
||||||
return get_font(q, bold, italic)
|
|
||||||
|
|
||||||
|
|
||||||
def get_font_files(opts):
|
def get_font_files(opts):
|
||||||
@@ -81,17 +96,16 @@ def get_font_files(opts):
|
|||||||
return ans
|
return ans
|
||||||
|
|
||||||
n = get_font_information(get_family())
|
n = get_font_information(get_family())
|
||||||
ans['regular'] = Font(
|
ans['regular'] = n._replace(face=Face(n.face))
|
||||||
Face(n.face), n.hinting, n.hintstyle, n.bold, n.italic)
|
|
||||||
|
|
||||||
def do(key):
|
def do(key):
|
||||||
b = get_font_information(
|
b = get_font_information(
|
||||||
get_family(key),
|
get_family(key),
|
||||||
bold=key in ('bold', 'bi'),
|
bold=key in ('bold', 'bi'),
|
||||||
italic=key in ('italic', 'bi'))
|
italic=key in ('italic', 'bi')
|
||||||
|
)
|
||||||
if b.face != n.face:
|
if b.face != n.face:
|
||||||
ans[key] = Font(
|
ans[key] = b._replace(face=Face(b.face))
|
||||||
Face(b.face), b.hinting, b.hintstyle, b.bold, b.italic)
|
|
||||||
|
|
||||||
do('bold'), do('italic'), do('bi')
|
do('bold'), do('italic'), do('bi')
|
||||||
return ans
|
return ans
|
||||||
|
|||||||
Reference in New Issue
Block a user