Infrastructure for rendering cells in the test suite

This commit is contained in:
Kovid Goyal
2017-11-01 05:36:29 +05:30
parent 7d7d82a68d
commit 0518cabef6
4 changed files with 81 additions and 9 deletions

View File

@@ -13,6 +13,7 @@
typedef uint16_t glyph_index; typedef uint16_t glyph_index;
typedef void (*send_sprite_to_gpu_func)(unsigned int, unsigned int, unsigned int, uint8_t*); typedef void (*send_sprite_to_gpu_func)(unsigned int, unsigned int, unsigned int, uint8_t*);
send_sprite_to_gpu_func current_send_sprite_to_gpu = NULL; send_sprite_to_gpu_func current_send_sprite_to_gpu = NULL;
static PyObject *python_send_to_gpu_impl = NULL;
typedef struct SpritePosition SpritePosition; typedef struct SpritePosition SpritePosition;
@@ -166,6 +167,15 @@ free_font(Font *f) {
f->bold = false; f->italic = false; f->bold = false; f->italic = false;
} }
static inline void
clear_font(Font *f) {
f->hb_font = NULL;
Py_CLEAR(f->face);
clear_sprite_map(f);
f->bold = false; f->italic = false;
}
static Font medium_font = {0}, bold_font = {0}, italic_font = {0}, bi_font = {0}, box_font = {0}, missing_font = {0}, blank_font = {0}; static Font medium_font = {0}, bold_font = {0}, italic_font = {0}, bi_font = {0}, box_font = {0}, missing_font = {0}, blank_font = {0};
static Font fallback_fonts[256] = {{0}}; static Font fallback_fonts[256] = {{0}};
static PyObject *get_fallback_font = NULL; static PyObject *get_fallback_font = NULL;
@@ -182,6 +192,16 @@ static unsigned int cell_width = 0, cell_height = 0, baseline = 0, underline_pos
static uint8_t *canvas = NULL; static uint8_t *canvas = NULL;
static inline void clear_canvas(void) { memset(canvas, 0, cell_width * cell_height); } static inline void clear_canvas(void) { memset(canvas, 0, cell_width * cell_height); }
static void
python_send_to_gpu(unsigned int x, unsigned int y, unsigned int z, uint8_t* buf) {
if (python_send_to_gpu_impl) {
PyObject *ret = PyObject_CallFunction(python_send_to_gpu_impl, "IIIy#", x, y, z, buf, cell_width * cell_height);
if (ret == NULL) PyErr_Print();
else Py_DECREF(ret);
}
}
static inline PyObject* static inline PyObject*
update_cell_metrics(float pt_sz, float xdpi, float ydpi) { update_cell_metrics(float pt_sz, float xdpi, float ydpi) {
#define CALL(f) { if ((f)->face) { if(!set_size_for_face((f)->face, pt_sz, xdpi, ydpi)) return NULL; clear_sprite_map(f); } } #define CALL(f) { if ((f)->face) { if(!set_size_for_face((f)->face, pt_sz, xdpi, ydpi)) return NULL; clear_sprite_map(f); } }
@@ -373,10 +393,15 @@ set_font(PyObject UNUSED *m, PyObject *args) {
Py_CLEAR(get_fallback_font); Py_CLEAR(box_drawing_function); Py_CLEAR(get_fallback_font); Py_CLEAR(box_drawing_function);
if (!PyArg_ParseTuple(args, "OOO!O!fffO|OOO", &get_fallback_font, &box_drawing_function, &PyTuple_Type, &sm, &PyTuple_Type, &smf, &pt_sz, &xdpi, &ydpi, &medium, &bold, &italic, &bi)) return NULL; if (!PyArg_ParseTuple(args, "OOO!O!fffO|OOO", &get_fallback_font, &box_drawing_function, &PyTuple_Type, &sm, &PyTuple_Type, &smf, &pt_sz, &xdpi, &ydpi, &medium, &bold, &italic, &bi)) return NULL;
Py_INCREF(get_fallback_font); Py_INCREF(box_drawing_function); Py_INCREF(get_fallback_font); Py_INCREF(box_drawing_function);
clear_font(&medium_font); clear_font(&bold_font); clear_font(&italic_font); clear_font(&bi_font);
if (!alloc_font(&medium_font, medium, false, false)) return PyErr_NoMemory(); if (!alloc_font(&medium_font, medium, false, false)) return PyErr_NoMemory();
if (bold && !alloc_font(&bold_font, bold, false, false)) return PyErr_NoMemory(); if (bold && !alloc_font(&bold_font, bold, false, false)) return PyErr_NoMemory();
if (italic && !alloc_font(&italic_font, italic, false, false)) return PyErr_NoMemory(); if (italic && !alloc_font(&italic_font, italic, false, false)) return PyErr_NoMemory();
if (bi && !alloc_font(&bi_font, bi, false, false)) return PyErr_NoMemory(); if (bi && !alloc_font(&bi_font, bi, false, false)) return PyErr_NoMemory();
for (size_t i = 0; fallback_fonts[i].face != NULL; i++) clear_font(fallback_fonts + i);
for (size_t i = 0; symbol_map_fonts_count; i++) free_font(symbol_map_fonts + i);
free(symbol_maps); free(symbol_map_fonts); symbol_maps = NULL; symbol_map_fonts = NULL;
symbol_maps_count = 0; symbol_map_fonts_count = 0;
symbol_maps_count = PyTuple_GET_SIZE(sm); symbol_maps_count = PyTuple_GET_SIZE(sm);
if (symbol_maps_count > 0) { if (symbol_maps_count > 0) {
@@ -404,6 +429,7 @@ static hb_buffer_t *harfbuzz_buffer = NULL;
static void static void
finalize(void) { finalize(void) {
Py_CLEAR(python_send_to_gpu_impl);
free(canvas); free(canvas);
Py_CLEAR(get_fallback_font); Py_CLEAR(get_fallback_font);
Py_CLEAR(box_drawing_function); Py_CLEAR(box_drawing_function);
@@ -459,6 +485,14 @@ send_prerendered_sprites(PyObject UNUSED *s, PyObject *args) {
return Py_BuildValue("H", x); return Py_BuildValue("H", x);
} }
static PyObject*
set_send_sprite_to_gpu(PyObject UNUSED *self, PyObject *func) {
Py_CLEAR(python_send_to_gpu_impl);
python_send_to_gpu_impl = func;
Py_INCREF(func);
current_send_sprite_to_gpu = func == Py_None ? send_sprite_to_gpu : python_send_to_gpu;
Py_RETURN_NONE;
}
static PyMethodDef module_methods[] = { static PyMethodDef module_methods[] = {
METHODB(set_font_size, METH_VARARGS), METHODB(set_font_size, METH_VARARGS),
@@ -467,6 +501,7 @@ static PyMethodDef module_methods[] = {
METHODB(sprite_map_set_layout, METH_VARARGS), METHODB(sprite_map_set_layout, METH_VARARGS),
METHODB(send_prerendered_sprites, METH_VARARGS), METHODB(send_prerendered_sprites, METH_VARARGS),
METHODB(test_sprite_position_for, METH_VARARGS), METHODB(test_sprite_position_for, METH_VARARGS),
METHODB(set_send_sprite_to_gpu, METH_O),
{NULL, NULL, 0, NULL} /* Sentinel */ {NULL, NULL, 0, NULL} /* Sentinel */
}; };

View File

@@ -7,6 +7,7 @@ from collections import namedtuple
from math import ceil, floor, pi, sin, sqrt from math import ceil, floor, pi, sin, sqrt
from kitty.constants import isosx from kitty.constants import isosx
from kitty.config import defaults
from kitty.fast_data_types import ( from kitty.fast_data_types import (
send_prerendered_sprites, set_font, set_font_size send_prerendered_sprites, set_font, set_font_size
) )
@@ -56,13 +57,10 @@ def get_fallback_font(text, bold, italic):
) )
def set_font_family(opts, override_font_size=None): def set_font_family(opts=None, override_font_size=None, override_dpi=None):
if hasattr(set_font_family, 'state'): opts = opts or defaults
raise ValueError(
'Cannot set font family more than once, use resize_fonts() to change size'
)
sz = override_font_size or opts.font_size sz = override_font_size or opts.font_size
xdpi, ydpi = get_logical_dpi() xdpi, ydpi = get_logical_dpi(override_dpi)
set_font_family.state = FontState('', sz, xdpi, ydpi, 0, 0, 0, 0, 0) set_font_family.state = FontState('', sz, xdpi, ydpi, 0, 0, 0, 0, 0)
font_map = get_font_files(opts) font_map = get_font_files(opts)
faces = [create_face(font_map['medium'])] faces = [create_face(font_map['medium'])]
@@ -136,7 +134,7 @@ def render_special(underline=0, strikethrough=False, missing=False):
s = set_font_family.state s = set_font_family.state
cell_width, cell_height, baseline = s.cell_width, s.cell_height, s.baseline cell_width, cell_height, baseline = s.cell_width, s.cell_height, s.baseline
underline_position, underline_thickness = s.underline_position, s.underline_thickness underline_position, underline_thickness = s.underline_position, s.underline_thickness
CharTexture = ctypes.c_ubyte * cell_width * cell_height CharTexture = ctypes.c_ubyte * (cell_width * cell_height)
ans = CharTexture if missing else CharTexture() ans = CharTexture if missing else CharTexture()
def dl(f, *a): def dl(f, *a):
@@ -171,7 +169,7 @@ def prerender():
def render_box_drawing(codepoint): def render_box_drawing(codepoint):
s = set_font_family.state s = set_font_family.state
cell_width, cell_height = s.cell_width, s.cell_height cell_width, cell_height = s.cell_width, s.cell_height
CharTexture = ctypes.c_ubyte * cell_width * cell_height CharTexture = ctypes.c_ubyte * (cell_width * cell_height)
buf = render_box_char( buf = render_box_char(
chr(codepoint), CharTexture(), cell_width, cell_height chr(codepoint), CharTexture(), cell_width, cell_height
) )

View File

@@ -107,9 +107,11 @@ def x11_dpi():
pass pass
def get_logical_dpi(): def get_logical_dpi(override_dpi=None):
# See https://github.com/glfw/glfw/issues/1019 for why we cant use # See https://github.com/glfw/glfw/issues/1019 for why we cant use
# glfw_get_physical_dpi() # glfw_get_physical_dpi()
if override_dpi is not None:
get_logical_dpi.ans = override_dpi
if not hasattr(get_logical_dpi, 'ans'): if not hasattr(get_logical_dpi, 'ans'):
if isosx: if isosx:
# TODO: Investigate if this needs a different implementation on OS X # TODO: Investigate if this needs a different implementation on OS X

37
kitty_tests/fonts.py Normal file
View File

@@ -0,0 +1,37 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
from collections import OrderedDict
from kitty.fast_data_types import set_send_sprite_to_gpu
from kitty.fonts.render import set_font_family
from . import BaseTest
class Rendering(BaseTest):
sprites = OrderedDict()
@classmethod
def setUpClass(cls):
def send_to_gpu(x, y, z, data):
cls.sprites[(x, y, z)] = data
set_send_sprite_to_gpu(send_to_gpu)
cls.cell_width, cls.cell_height = set_font_family(override_dpi=(96.0, 96.0))
@classmethod
def tearDownClass(cls):
set_send_sprite_to_gpu(None)
cls.sprites.clear()
def setUp(self):
self.sprites.clear()
def tearDown(self):
self.sprites.clear()
def test_box_drawing(self):
pass