render: render combining characters

This is basically just a loop that renders additional glyphs on top
off the base glyph.

Since we now need access to the row struct, for the combining
characters, the function prototype for 'render_cell()' has changed.

When rendering the combining characters we also need to deal with
broken fonts; some fonts use positive offsets (as if the combining
character was a regular character), while others use a negative
offset (to be used as if you had already advanced the pen position).

We handle both - a positive offset is rendered just like a regular
glyph. When we see a negative offset we simply add the width of a cell
first.
This commit is contained in:
Daniel Eklöf 2020-05-01 11:56:13 +02:00
parent 40bf01a8e6
commit 76567e9ef0
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
3 changed files with 35 additions and 12 deletions

View file

@ -356,8 +356,9 @@ draw_cursor(const struct terminal *term, const struct cell *cell,
static int
render_cell(struct terminal *term, pixman_image_t *pix,
struct cell *cell, int col, int row, bool has_cursor)
struct row *row, int col, int row_no, bool has_cursor)
{
struct cell *cell = &row->cells[col];
if (cell->attrs.clean)
return 0;
@ -366,7 +367,7 @@ render_cell(struct terminal *term, pixman_image_t *pix,
int width = term->cell_width;
int height = term->cell_height;
int x = term->margins.left + col * width;
int y = term->margins.top + row * height;
int y = term->margins.top + row_no * height;
assert(cell->attrs.selected == 0 || cell->attrs.selected == 1);
bool is_selected = cell->attrs.selected;
@ -441,6 +442,26 @@ render_cell(struct terminal *term, pixman_image_t *pix,
}
}
/* Combining characters */
const struct combining_chars *comb_chars = &row->comb_chars[col];
for (size_t i = 0; i < comb_chars->count; i++) {
const struct fcft_glyph *g = fcft_glyph_rasterize(
font, comb_chars->chars[i], term->font_subpixel);
if (g == NULL)
continue;
pixman_image_t *src = pixman_image_create_solid_fill(&fg);
pixman_image_composite32(
PIXMAN_OP_OVER, src, g->pix, pix, 0, 0, 0, 0,
/* Some fonts use a negative offset, while others use a
* "normal" offset */
x + (g->x < 0 ? term->cell_width : 0) + g->x,
y + font_baseline(term) - g->y,
g->width, g->height);
pixman_image_unref(src);
}
/* Underline */
if (cell->attrs.underline) {
draw_underline(term, pix, attrs_to_font(term, &cell->attrs),
@ -760,7 +781,7 @@ static void
render_row(struct terminal *term, pixman_image_t *pix, struct row *row, int row_no)
{
for (int col = term->cols - 1; col >= 0; col--)
render_cell(term, pix, &row->cells[col], col, row_no, false);
render_cell(term, pix, row, col, row_no, false);
}
int
@ -1271,16 +1292,18 @@ grid_render(struct terminal *term)
pixman_image_set_clip_region(buf->pix, &clip);
/* Erase old cursor (if we rendered a cursor last time) */
if (term->render.last_cursor.cell != NULL) {
if (term->render.last_cursor.row != NULL) {
struct cell *cell = term->render.last_cursor.cell;
struct row *row = term->render.last_cursor.row;
struct coord at = term->render.last_cursor.in_view;
term->render.last_cursor.cell = NULL;
term->render.last_cursor.row = NULL;
struct cell *cell = &row->cells[at.col];
/* If cell is already dirty, it will be rendered anyway */
if (cell->attrs.clean) {
cell->attrs.clean = 0;
int cols = render_cell(term, buf->pix, cell, at.col, at.row, false);
int cols = render_cell(term, buf->pix, row, at.col, at.row, false);
wl_surface_damage_buffer(
term->window->surface,
@ -1408,9 +1431,9 @@ grid_render(struct terminal *term)
struct cell *cell = &row->cells[term->grid->cursor.point.col];
cell->attrs.clean = 0;
term->render.last_cursor.cell = cell;
term->render.last_cursor.row = row;
int cols_updated = render_cell(
term, buf->pix, cell, term->grid->cursor.point.col, view_aligned_row, true);
term, buf->pix, row, term->grid->cursor.point.col, view_aligned_row, true);
wl_surface_damage_buffer(
term->window->surface,
@ -1804,7 +1827,7 @@ maybe_resize(struct terminal *term, int width, int height, bool force)
if (term->scroll_region.end >= old_rows)
term->scroll_region.end = term->rows;
term->render.last_cursor.cell = NULL;
term->render.last_cursor.row = NULL;
damage_view:
if (!term->window->is_maximized && !term->window->is_fullscreen) {

View file

@ -1319,7 +1319,7 @@ term_reset(struct terminal *term, bool hard)
tll_free(term->normal.scroll_damage);
tll_free(term->alt.damage);
tll_free(term->alt.scroll_damage);
term->render.last_cursor.cell = NULL;
term->render.last_cursor.row = NULL;
term->render.was_flashing = false;
term_damage_all(term);
}

View file

@ -374,7 +374,7 @@ struct terminal {
struct {
struct coord actual; /* Absolute */
struct coord in_view; /* Offset by view */
struct cell *cell; /* For easy access to content */
struct row *row; /* Actual row TODO: remove */
} last_cursor;
struct buffer *last_buf; /* Buffer we rendered to last time */