diff --git a/kitty/fonts/freetype.py b/kitty/fonts/freetype.py deleted file mode 100644 index 45bd7fedf..000000000 --- a/kitty/fonts/freetype.py +++ /dev/null @@ -1,189 +0,0 @@ -#!/usr/bin/env python -# vim:fileencoding=utf-8 -# License: GPL v3 Copyright: 2016, Kovid Goyal - -import ctypes -import sys -from functools import lru_cache, partial -from itertools import chain - -from kitty.fast_data_types import Face, FreeTypeError -from kitty.fonts.box_drawing import render_missing_glyph -from kitty.utils import ceil_int, get_logical_dpi, safe_print, wcwidth, adjust_line_height - -from .fontconfig import ( - FontNotFound, find_font_for_characters, font_for_family, get_font_files -) - -current_font_family = current_font_family_name = cff_size = cell_width = cell_height = baseline = None -CharTexture = underline_position = underline_thickness = None -alt_face_cache = {} -symbol_map = {} - - -def set_char_size(face, width=0, height=0, hres=0, vres=0): - face.set_char_size(width, height, hres, vres) - - -@lru_cache(maxsize=2**10) -def font_for_text(char, bold=False, italic=False, allow_bitmaped_fonts=False): - if allow_bitmaped_fonts: - return find_font_for_characters( - current_font_family_name, - char, - bold, - italic, - allow_bitmaped_fonts=True, - size_in_pts=cff_size['width'] / 64, - dpi=(cff_size['hres'] + cff_size['vres']) / 2 - ) - return find_font_for_characters( - current_font_family_name, char, bold, italic - ) - - -def install_symbol_map(val): - global symbol_map - symbol_map = {} - family_map = {f: font_for_family(f) for f in set(val.values())} - for ch, family in val.items(): - symbol_map[ch] = family_map[family] - - -def font_units_to_pixels(x, units_per_em, size_in_pts, dpi): - return ceil_int(x * ((size_in_pts * dpi) / (72 * units_per_em))) - - -def set_font_family(opts, override_font_size=None): - global current_font_family, current_font_family_name, cff_size, cell_width, cell_height, CharTexture, baseline - global underline_position, underline_thickness - size_in_pts = override_font_size or opts.font_size - current_font_family = get_font_files(opts) - current_font_family_name = opts.font_family - dpi = get_logical_dpi() - cff_size = ceil_int(64 * size_in_pts) - cff_size = { - 'width': cff_size, - 'height': cff_size, - 'hres': int(dpi[0]), - 'vres': int(dpi[1]) - } - install_symbol_map(opts.symbol_map) - for fobj in chain(current_font_family.values(), symbol_map.values()): - set_char_size(fobj.face, **cff_size) - face = current_font_family['regular'].face - cell_width = face.calc_cell_width() - cell_height = font_units_to_pixels( - face.height, face.units_per_EM, size_in_pts, dpi[1] - ) - cell_height = adjust_line_height(cell_height, opts.adjust_line_height) - baseline = font_units_to_pixels( - face.ascender, face.units_per_EM, size_in_pts, dpi[1] - ) - underline_position = min( - baseline - font_units_to_pixels( - face.underline_position, face.units_per_EM, size_in_pts, dpi[1] - ), cell_height - 1 - ) - underline_thickness = font_units_to_pixels( - face.underline_thickness, face.units_per_EM, size_in_pts, dpi[1] - ) - CharTexture = ctypes.c_ubyte * (cell_width * cell_height) - font_for_text.cache_clear() - alt_face_cache.clear() - return cell_width, cell_height - - -def font_has_text(font, text): - for c in text: - if not font.face.get_char_index(c): - return False - return True - - -def face_for_text(text, bold=False, italic=False): - key = 'regular' - if bold: - key = 'bi' if italic else 'bold' - elif italic: - key = 'italic' - font = symbol_map.get(text[0]) - if font is None or not font_has_text(font, text): - font = current_font_family.get(key) or current_font_family['regular'] - face = font.face - if not font_has_text(font, text): - try: - font = font_for_text(text, bold, italic) - except FontNotFound: - font = font_for_text( - text, bold, italic, allow_bitmaped_fonts=True - ) - face = alt_face_cache.get(font) - if face is None: - face = alt_face_cache[font] = Face(font.face, font.index, font.hinting, font.hintstyle) - if face.is_scalable: - set_char_size(face, **cff_size) - else: - face = font.face - return font, face - - -def render_text(text, bold=False, italic=False, num_cells=1): - if text == ' ' and num_cells == 1: - return (CharTexture(),) - font, face = face_for_text(text, bold, italic) - func = partial(face.draw_single_glyph, ord(text[0])) if len(text) == 1 else partial(face.draw_complex_glyph, text) - if num_cells == 1: - buf = CharTexture() - ans = (buf,) - else: - buf = (ctypes.c_ubyte * (cell_width * num_cells * cell_height))() - ans = tuple(CharTexture() for i in range(num_cells)) - func(cell_width, cell_height, ctypes.addressof(buf), num_cells, bold, italic, baseline) - if num_cells > 1: - face.split_cells(cell_width, cell_height, ctypes.addressof(buf), *(ctypes.addressof(x) for x in ans)) - return ans - - -def current_cell(): - return CharTexture, cell_width, cell_height, baseline, underline_thickness, underline_position - - -@lru_cache(maxsize=8) -def missing_glyph(num_cells, cell_width, cell_height): - w = cell_width * num_cells - ans = bytearray(w * cell_height) - render_missing_glyph(ans, w, cell_height) - buf = (ctypes.c_ubyte * w * cell_height).from_buffer(ans) - face = current_font_family['regular'].face - bufs = tuple(CharTexture() for i in range(num_cells)) - face.split_cells(cell_width, cell_height, ctypes.addressof(buf), *(ctypes.addressof(x) for x in bufs)) - if num_cells == 2: - first, second = bufs - else: - first, second = bufs[0], None - return first, second - - -def render_cell(text=' ', bold=False, italic=False): - num_cells = wcwidth(text[0]) - if num_cells < 1: - return render_cell() - - def safe_freetype(func): - try: - return func(text, bold, italic, num_cells) - except FontNotFound as err: - safe_print('ERROR:', err, file=sys.stderr) - except FreeTypeError as err: - safe_print('Failed to render text:', repr(text), 'with error:', err, file=sys.stderr) - - ret = safe_freetype(render_text) - if ret is None: - return missing_glyph(num_cells, cell_width, cell_height) - if num_cells == 1: - first, second = ret[0], None - else: - first, second = ret - - return first, second