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).
This commit is contained in:
Daniel Eklöf 2020-06-29 21:59:40 +02:00
parent 6ee76c21f2
commit a136987678
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
2 changed files with 63 additions and 32 deletions

View file

@ -78,6 +78,7 @@
no longer erases the entire image, only the part(s) covered by the no longer erases the entire image, only the part(s) covered by the
new text or image. new text or image.
* Sixel images being erased when printing text next to them. * Sixel images being erased when printing text next to them.
* Sixel handling when resizing window.
### Security ### Security

94
grid.c
View file

@ -76,7 +76,10 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
* at the output that is *oldest* */ * at the output that is *oldest* */
int offset = grid->offset + old_screen_rows; 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 */ /* Turn cursor coordinates into grid absolute coordinates */
struct coord cursor = grid->cursor.point; 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) if (old_row == NULL)
continue; continue;
/* /* Map sixels on current "old" row to current "new row" */
* Update 'row' in all sixels that *begin* at current row tll_foreach(old_sixels, it) {
* if (it->item.pos.row != old_row_idx)
* Since we might end up pushing the sixel down, we can't continue;
* simply update the row inline - we'd then end up pushing the
* sixel down again, when we reach the next 'old' struct sixel sixel = it->item;
* row. Instead, copy the sixel (with 'row' updated), to a sixel.pos.row = new_row_idx;
* temporary list and remove the original sixel.
* /* Make sure it doesn't cross the wrap-around after being re-based */
* After we've reflowed the grid we'll move the sixels back to int end = (sixel.pos.row + sixel.rows - 1) & (new_rows - 1);
* the "real" sixel list. if (end < sixel.pos.row) {
*/ /* TODO: split instead of destroying */
tll_foreach(grid->sixel_images, it) { sixel_destroy(&it->item);
if (it->item.pos.row == old_row_idx) { } else {
struct sixel six = it->item;
six.pos.row = new_row_idx; /* 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() \ #define line_wrap() \
@ -145,6 +174,12 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
} else { \ } else { \
memset(new_row->cells, 0, new_cols * sizeof(new_row->cells[0])); \ memset(new_row->cells, 0, new_cols * sizeof(new_row->cells[0])); \
new_row->linebreak = false; \ 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) } while(0)
@ -279,15 +314,10 @@ grid_reflow(struct grid *grid, int new_rows, int new_cols,
grid->cursor.lcf = false; grid->cursor.lcf = false;
grid->saved_cursor.lcf = false; grid->saved_cursor.lcf = false;
/* Destroy any non-moved sixels */ /* Free sixels we failed to "map" to the new grid */
tll_foreach(grid->sixel_images, it) tll_foreach(old_sixels, it)
sixel_destroy(&it->item); sixel_destroy(&it->item);
tll_free(grid->sixel_images); tll_free(old_sixels);
/* Move updated sixels back */
tll_foreach(new_sixels, it)
tll_push_back(grid->sixel_images, it->item);
tll_free(new_sixels);
tll_free(tracking_points); tll_free(tracking_points);
} }