From a136987678afcaa7b8ad22456a0632ee8a743943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Mon, 29 Jun 2020 21:59:40 +0200 Subject: [PATCH] reflow: ensure sixels are correctly sorted when re-inserted And make sure to remove re-inserted sixels that has wrapped around the scrollback (this may happen when the window size decreases). --- CHANGELOG.md | 1 + grid.c | 94 ++++++++++++++++++++++++++++++++++------------------ 2 files changed, 63 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 761beb2f..5da11320 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -78,6 +78,7 @@ no longer erases the entire image, only the part(s) covered by the new text or image. * Sixel images being erased when printing text next to them. +* Sixel handling when resizing window. ### Security diff --git a/grid.c b/grid.c index d1d625c6..cdc5db72 100644 --- a/grid.c +++ b/grid.c @@ -76,7 +76,10 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, * at the output that is *oldest* */ int offset = grid->offset + old_screen_rows; - tll(struct sixel) new_sixels = tll_init(); + tll(struct sixel) old_sixels = tll_init(); + tll_foreach(grid->sixel_images, it) + tll_push_back(old_sixels, it->item); + tll_free(grid->sixel_images); /* Turn cursor coordinates into grid absolute coordinates */ struct coord cursor = grid->cursor.point; @@ -106,31 +109,57 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, if (old_row == NULL) continue; - /* - * Update 'row' in all sixels that *begin* at current row - * - * Since we might end up pushing the sixel down, we can't - * simply update the row inline - we'd then end up pushing the - * sixel down again, when we reach the next 'old' - * row. Instead, copy the sixel (with 'row' updated), to a - * temporary list and remove the original sixel. - * - * After we've reflowed the grid we'll move the sixels back to - * the "real" sixel list. - */ - tll_foreach(grid->sixel_images, it) { - if (it->item.pos.row == old_row_idx) { - struct sixel six = it->item; - six.pos.row = new_row_idx; + /* Map sixels on current "old" row to current "new row" */ + tll_foreach(old_sixels, it) { + if (it->item.pos.row != old_row_idx) + continue; + + struct sixel sixel = it->item; + sixel.pos.row = new_row_idx; + + /* Make sure it doesn't cross the wrap-around after being re-based */ + int end = (sixel.pos.row + sixel.rows - 1) & (new_rows - 1); + if (end < sixel.pos.row) { + /* TODO: split instead of destroying */ + sixel_destroy(&it->item); + } else { + + /* Insert sixel into the *sorted* list. */ + + /* Based on rebase_row() in sixel.c */ + /* Uses 'old' offset to ensure old sixels are treated as such */ +#define rebase_row(t, row) \ + (((row) - (grid->offset + new_screen_rows) + new_rows) & (new_rows - 1)) + + int end_row = rebase_row(term, sixel.pos.row + sixel.rows - 1); + + /* + * TODO: this is basically sixel_insert(), except we + * cannot use it since: + * + * a) we don't have a 'term' reference + * b) the grid hasn't been fully * updated yet + * (e.g. grid->num_rows is invalid etc). + */ + + bool inserted = false; + tll_foreach(grid->sixel_images, it2) { + const struct sixel *s = &it2->item; + if (rebase_row(term, s->pos.row + s->rows - 1) < end_row) { + tll_insert_before(grid->sixel_images, it2, sixel); + inserted = true; + break; + } + } + + if (!inserted) + tll_push_back(grid->sixel_images, sixel); - int end = (six.pos.row + six.rows - 1) & (new_rows - 1); - if (end < six.pos.row) { - /* TODO: split sixel instead of removing it... */ - sixel_destroy(&it->item); - } else - tll_push_back(new_sixels, six); - tll_remove(grid->sixel_images, it); } + + /* Sixel has been either re-mapped, or destroyed */ + tll_remove(old_sixels, it); +#undef rebase_row } #define line_wrap() \ @@ -145,6 +174,12 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, } else { \ memset(new_row->cells, 0, new_cols * sizeof(new_row->cells[0])); \ new_row->linebreak = false; \ + tll_foreach(grid->sixel_images, it) { \ + if (it->item.pos.row == new_row_idx) { \ + sixel_destroy(&it->item); \ + tll_remove(grid->sixel_images, it); \ + } \ + } \ } \ } while(0) @@ -279,15 +314,10 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols, grid->cursor.lcf = false; grid->saved_cursor.lcf = false; - /* Destroy any non-moved sixels */ - tll_foreach(grid->sixel_images, it) + /* Free sixels we failed to "map" to the new grid */ + tll_foreach(old_sixels, it) sixel_destroy(&it->item); - tll_free(grid->sixel_images); - - /* Move updated sixels back */ - tll_foreach(new_sixels, it) - tll_push_back(grid->sixel_images, it->item); - tll_free(new_sixels); + tll_free(old_sixels); tll_free(tracking_points); }