From 41a8f2fc6556e7b8c9832ede21c6b45f624207cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 10 Aug 2021 18:33:18 +0200 Subject: [PATCH] =?UTF-8?q?render:=20run=20the=20=E2=80=9Coverflowing=20gl?= =?UTF-8?q?yphs=E2=80=9D=20prepass=20*before*=20rendering=20sixels?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes an issue where the left-most column of a sixel was “overwritten” by the cell content. This patch also rewrites the prepass logic, to try to reduce the number of loads performed. The new logic loops each row from left to right, looking for dirty cells. When a dirty cell is found, we first scan backwards, until we find a non-overflowing cell. That cell is unaffected by the overflowing cell we’re currently dealing with. We can also stop as soon as we see a dirty cell, since that cell will already have been dealt with. Then, we scan forward, dirtying cells until we see a non-overflowing cell. That first non-overflowing cell is also dirtied, but after that we break. The last loop, that scans forward, advances the same cell pointer used in the outer loop. --- CHANGELOG.md | 2 ++ render.c | 86 +++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 70 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a22e77e2..671fb78b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,8 @@ scaling factor. * Slow-to-terminate client applications causing other footclient instances to freeze when closing a footclient window. +* Underlying cell content showing through in the left-most column of + sixels. ### Security diff --git a/render.c b/render.c index b8a013f1..68a53082 100644 --- a/render.c +++ b/render.c @@ -439,20 +439,6 @@ draw_cursor(const struct terminal *term, const struct cell *cell, } } -static inline void -render_cell_prepass(struct terminal *term, struct row *row, int col) -{ - for (; col < term->cols - 1; col++) { - if (row->cells[col].attrs.confined || - (row->cells[col].attrs.clean == row->cells[col + 1].attrs.clean)) { - break; - } - - row->cells[col].attrs.clean = 0; - row->cells[col + 1].attrs.clean = 0; - } -} - static int render_cell(struct terminal *term, pixman_image_t *pix, struct row *row, int col, int row_no, bool has_cursor) @@ -767,10 +753,6 @@ static void render_row(struct terminal *term, pixman_image_t *pix, struct row *row, int row_no, int cursor_col) { - if (term->conf->tweak.overflowing_glyphs) - for (int col = term->cols - 1; col >= 0; col--) - render_cell_prepass(term, row, col); - for (int col = term->cols - 1; col >= 0; col--) render_cell(term, pix, row, col, row_no, cursor_col == col); } @@ -2452,6 +2434,74 @@ grid_render(struct terminal *term) cursor.row &= term->grid->num_rows - 1; } + if (term->conf->tweak.overflowing_glyphs) { + /* + * Pre-pass to dirty cells affected by overflowing glyphs. + * + * Given any two pair of cells where the first cell is + * overflowing into the second, *both* cells must be + * re-rendered if any one of them is dirty. + * + * Thus, given a string of overflowing glyphs, with a single + * dirty cell in the middle, we need to re-render the entire + * string. + */ + for (int r = 0; r < term->rows; r++) { + struct row *row = grid_row_in_view(term->grid, r); + + if (!row->dirty) + continue; + + /* Loop row from left to right, looking for dirty cells */ + for (struct cell *cell = &row->cells[0]; + cell < &row->cells[term->cols]; + cell++) + { + if (cell->attrs.clean) + continue; + + /* + * Cell is dirty, go back and dirty previous cells, if + * they are overflowing. + * + * As soon as we see a non-overflowing cell we can + * stop, since it isn’t affecting the string of + * overflowing glyphs that follows it. + * + * As soon as we see a dirty cell, we can stop, since + * that means we’ve already handled it (remember the + * outer loop goes from left to right). + */ + for (struct cell *c = cell - 1; c >= &row->cells[0]; c--) { + if (c->attrs.confined) + break; + if (!c->attrs.clean) + break; + c->attrs.clean = false; + } + + /* + * Now move forward, dirtying all cells until we hit a + * non-overflowing cell. + * + * Note that the first non-overflowing cell must be + * re-rendered as well, but any cell *after* that is + * unaffected by the string of overflowing glyphs + * we’re dealing with right now. + * + * For performance, this iterates the *outer* loop’s + * cell pointer - no point in re-checking all these + * glyphs again, in the outer loop. + */ + for (; cell < &row->cells[term->cols]; cell++) { + cell->attrs.clean = false; + if (cell->attrs.confined) + break; + } + } + } + } + render_sixel_images(term, buf->pix[0], &cursor); if (term->render.workers.count > 0) {