Finish up harfbuzz based rendering

This commit is contained in:
Kovid Goyal 2017-10-28 09:33:43 +05:30
parent a5e6ab2bee
commit 0652fa1696
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 65 additions and 28 deletions

View File

@ -193,13 +193,16 @@ def render_char(text, bold=False, italic=False, width=1):
def render_complex_char(text, bold=False, italic=False, width=1):
font, face = face_for_text(text, bold, italic)
buf, m, width, height = face.draw_complex_glyph(text)
return CharBitmap(
buf,
ceil_int(abs(m.horiBearingX) / 64),
ceil_int(abs(m.horiBearingY) / 64),
ceil_int(m.horiAdvance / 64), height, width
)
if width == 1:
buf = CharTexture()
ans = (buf,)
else:
buf = (ctypes.c_ubyte * (cell_width * width * cell_height))()
ans = tuple(CharTexture() for i in range(width))
face.draw_complex_glyph(text, cell_width, cell_height, ctypes.addressof(buf), width, bold, italic, baseline)
if width > 1:
face.split_cells(cell_width, cell_height, ctypes.addressof(buf), *(ctypes.addressof(x) for x in ans))
return ans
def place_char_in_cell(bitmap_char):
@ -273,26 +276,35 @@ def missing_glyph(width):
def render_cell(text=' ', bold=False, italic=False):
width = wcwidth(text[0])
try:
if len(text) > 1:
bitmap_char = render_complex_char(text, bold, italic, width)
else:
bitmap_char = render_char(text, bold, italic, width)
except FontNotFound as err:
safe_print('ERROR:', err, file=sys.stderr)
return missing_glyph(width)
except FreeTypeError as err:
safe_print('Failed to render text:', repr(text), 'with error:', err, file=sys.stderr)
return missing_glyph(width)
second = None
if width == 2:
if bitmap_char.columns > cell_width:
bitmap_char, second = split_char_bitmap(bitmap_char)
second = place_char_in_cell(second)
else:
second = render_cell()[0]
def safe_freetype(func):
try:
return func(text, bold, italic, width)
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)
first = place_char_in_cell(bitmap_char)
if len(text) > 1:
ret = safe_freetype(render_complex_char)
if ret is None:
return missing_glyph(width)
if width == 1:
first, second = ret[0], None
else:
first, second = ret
else:
bitmap_char = safe_freetype(render_char)
if bitmap_char is None:
return missing_glyph(width)
second = None
if width == 2:
if bitmap_char.columns > cell_width:
bitmap_char, second = split_char_bitmap(bitmap_char)
second = place_char_in_cell(second)
else:
second = render_cell()[0]
first = place_char_in_cell(bitmap_char)
return first, second

View File

@ -380,7 +380,7 @@ place_bitmap_in_cell(unsigned char *cell, ProcessedBitmap *bm, size_t cell_width
ssize_t dy = (ssize_t)((float)metrics->horiBearingY / 64.f + y_offset);
size_t src_start_row, dest_start_row;
if (dy > 0 && (size_t)dy > baseline) {
src_start_row = dy - baseline;
src_start_row = 0;
dest_start_row = 0;
} else {
src_start_row = 0;
@ -405,7 +405,7 @@ draw_complex_glyph(Face *self, PyObject *args) {
unsigned int cell_width, cell_height, num_cells, baseline;
PyObject *addr;
float x = 0.f, y = 0.f;
if (!PyArg_ParseTuple(args, "s#IIO!Ipp", &text, &text_len, &cell_width, &cell_height, &PyLong_Type, &addr, &num_cells, &bold, &italic, &baseline)) return NULL;
if (!PyArg_ParseTuple(args, "s#IIO!IppI", &text, &text_len, &cell_width, &cell_height, &PyLong_Type, &addr, &num_cells, &bold, &italic, &baseline)) return NULL;
unsigned char *cell = PyLong_AsVoidPtr(addr);
ShapeData sd;
_shape(self, text, text_len, &sd);
@ -423,6 +423,30 @@ draw_complex_glyph(Face *self, PyObject *args) {
Py_RETURN_NONE;
}
static PyObject*
split_cells(Face UNUSED *self, PyObject *args) {
#define split_cells_doc "split_cells(cell_width, cell_height, src, *cells)"
unsigned int cell_width, cell_height;
unsigned char *cells[10], *src;
size_t num_cells = PyTuple_GET_SIZE(args) - 3;
if (num_cells > sizeof(cells)/sizeof(cells[0])) { PyErr_SetString(PyExc_ValueError, "Too many cells being split"); return NULL; }
cell_width = PyLong_AsUnsignedLong(PyTuple_GET_ITEM(args, 0));
cell_height = PyLong_AsUnsignedLong(PyTuple_GET_ITEM(args, 1));
src = PyLong_AsVoidPtr(PyTuple_GET_ITEM(args, 2));
for (size_t i = 3; i < num_cells + 3; i++) cells[i - 3] = PyLong_AsVoidPtr(PyTuple_GET_ITEM(args, i));
size_t stride = num_cells * cell_width;
for (size_t y = 0; y < cell_height; y++) {
for (size_t i = 0; i < num_cells; i++) {
unsigned char *dest = cells[i] + y * cell_width;
for (size_t x = 0; x < cell_width; x++) {
dest[x] = src[y * stride + i * cell_width + x];
}
}
}
Py_RETURN_NONE;
}
static PyObject*
trim_to_width(Face UNUSED *self, PyObject *args) {
@ -486,6 +510,7 @@ static PyMethodDef methods[] = {
METHOD(load_char, METH_O)
METHOD(shape, METH_VARARGS)
METHOD(draw_complex_glyph, METH_VARARGS)
METHOD(split_cells, METH_VARARGS)
METHOD(get_char_index, METH_VARARGS)
METHOD(glyph_metrics, METH_NOARGS)
METHOD(bitmap, METH_NOARGS)