mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
scroll: destroy scrolled out sixels before scroll is applied
The logic that breaks out of sixel loops does not work for rows that has already wrapped around. Thus, we need to destroy sixels that are about to be scrolled out *before* we actually scroll. Since this is the *only* time we destroy sixels (instead of overwriting it), rename the sixel functions. And, since they now do a very specific thing, they can be greatly simplified (and thus faster).
This commit is contained in:
parent
a136987678
commit
62be729c45
4 changed files with 64 additions and 142 deletions
|
|
@ -72,13 +72,12 @@
|
|||
* Do not auto-resize a sixel image for which the cllent has specified
|
||||
a size. This fixes an issue where an image would incorrectly
|
||||
overflow into the cell row beneath.
|
||||
* Erase scrolled out sixel image that crossed the scrollback wrap
|
||||
around boundary.
|
||||
* Text printed, or other sixel images drawn, on top of a sixel image
|
||||
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.
|
||||
* Sixel handling when scrollback wraps around.
|
||||
|
||||
|
||||
### Security
|
||||
|
|
|
|||
186
sixel.c
186
sixel.c
|
|
@ -87,26 +87,40 @@ sixel_erase(struct terminal *term, struct sixel *sixel)
|
|||
sixel_destroy(sixel);
|
||||
}
|
||||
|
||||
static int
|
||||
rebase_row(const struct terminal *term, int abs_row)
|
||||
{
|
||||
int scrollback_start = term->grid->offset + term->rows;
|
||||
int rebased_row = abs_row - scrollback_start + term->grid->num_rows;
|
||||
|
||||
rebased_row &= term->grid->num_rows - 1;
|
||||
return rebased_row;
|
||||
}
|
||||
|
||||
static bool
|
||||
verify_sixel_list_order(const struct terminal *term)
|
||||
{
|
||||
#if defined(_DEBUG)
|
||||
int prev_row = INT_MAX;
|
||||
|
||||
tll_foreach(term->grid->sixel_images, it) {
|
||||
int row = rebase_row(term, it->item.pos.row + it->item.rows - 1);
|
||||
assert(row < prev_row);
|
||||
if (row >= prev_row)
|
||||
return false;
|
||||
prev_row = row;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
sixel_insert(struct terminal *term, struct sixel sixel)
|
||||
{
|
||||
const int scrollback_end
|
||||
= (term->grid->offset + term->rows) & (term->grid->num_rows - 1);
|
||||
|
||||
const int end_row
|
||||
= (sixel.pos.row + sixel.rows
|
||||
- scrollback_end
|
||||
+ term->grid->num_rows) & (term->grid->num_rows - 1);
|
||||
assert(end_row >= 0 && end_row < term->grid->num_rows);
|
||||
int end_row = rebase_row(term, sixel.pos.row + sixel.rows - 1);
|
||||
|
||||
tll_foreach(term->grid->sixel_images, it) {
|
||||
const int e
|
||||
= (it->item.pos.row + it->item.rows
|
||||
- scrollback_end
|
||||
+ term->grid->num_rows) & (term->grid->num_rows - 1);
|
||||
assert(e >= 0 && e < term->grid->num_rows);
|
||||
|
||||
if (e < end_row) {
|
||||
if (rebase_row(term, it->item.pos.row + it->item.rows - 1) < end_row) {
|
||||
tll_insert_before(term->grid->sixel_images, it, sixel);
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -121,106 +135,44 @@ out:
|
|||
LOG_DBG(" rows=%d+%d", it->item.pos.row, it->item.rows);
|
||||
}
|
||||
#else
|
||||
;
|
||||
verify_sixel_list_order(term);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Row numbers are absolute */
|
||||
static void
|
||||
sixel_delete_at_point(struct terminal *term, int row, int col)
|
||||
{
|
||||
assert(row >= 0);
|
||||
assert(row < term->grid->num_rows);
|
||||
assert(col < term->grid->num_cols);
|
||||
|
||||
if (likely(tll_length(term->grid->sixel_images) == 0))
|
||||
return;
|
||||
|
||||
tll_foreach(term->grid->sixel_images, it) {
|
||||
struct sixel *six = &it->item;
|
||||
const int six_start = six->pos.row;
|
||||
const int six_end = (six_start + six->rows - 1) & (term->grid->num_rows - 1);
|
||||
|
||||
/* We should never generate scrollback wrapping sixels */
|
||||
assert(six_end >= six_start);
|
||||
|
||||
if (row >= six_start && row <= six_end) {
|
||||
const int col_start = six->pos.col;
|
||||
const int col_end = six->pos.col + six->cols;
|
||||
|
||||
if (col < 0 || (col >= col_start && col < col_end)) {
|
||||
sixel_erase(term, six);
|
||||
tll_remove(term->grid->sixel_images, it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: remove */
|
||||
void
|
||||
sixel_delete_at_row(struct terminal *term, int row)
|
||||
sixel_scroll_up(struct terminal *term, int rows)
|
||||
{
|
||||
if (likely(tll_length(term->grid->sixel_images) == 0))
|
||||
return;
|
||||
|
||||
sixel_delete_at_point(
|
||||
term, (term->grid->offset + row) & (term->grid->num_rows - 1), -1);
|
||||
}
|
||||
|
||||
/* Row numbers are absolute */
|
||||
static void
|
||||
_sixel_delete_in_range(struct terminal *term, int start, int end)
|
||||
{
|
||||
assert(end >= start);
|
||||
assert(start >= 0);
|
||||
assert(start < term->grid->num_rows);
|
||||
assert(end >= 0);
|
||||
assert(end < term->grid->num_rows);
|
||||
|
||||
tll_foreach(term->grid->sixel_images, it) {
|
||||
tll_rforeach(term->grid->sixel_images, it) {
|
||||
struct sixel *six = &it->item;
|
||||
|
||||
const int six_start = six->pos.row;
|
||||
const int six_end = (six_start + six->rows - 1) & (term->grid->num_rows - 1);
|
||||
|
||||
/* We should never generate scrollback wrapping sixels */
|
||||
assert(six_end >= six_start);
|
||||
|
||||
if ((start <= six_start && end >= six_start) || /* Crosses sixel start boundary */
|
||||
(start <= six_end && end >= six_end) || /* Crosses sixel end boundary */
|
||||
(start >= six_start && end <= six_end)) /* Fully within sixel range */
|
||||
{
|
||||
sixel_erase(term, six);
|
||||
int six_start = rebase_row(term, six->pos.row);
|
||||
if (six_start < rows) {
|
||||
sixel_destroy(six);
|
||||
tll_remove(term->grid->sixel_images, it);
|
||||
}
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
verify_sixel_list_order(term);
|
||||
}
|
||||
|
||||
void
|
||||
sixel_delete_in_range(struct terminal *term, int _start, int _end)
|
||||
sixel_scroll_down(struct terminal *term, int rows)
|
||||
{
|
||||
if (likely(tll_length(term->grid->sixel_images) == 0))
|
||||
return;
|
||||
assert(term->grid->num_rows >= rows);
|
||||
|
||||
if (_start == _end) {
|
||||
/* Avoid expensive wrap calculation */
|
||||
return sixel_delete_at_point(
|
||||
term, (term->grid->offset + _start) & (term->grid->num_rows - 1), -1);
|
||||
tll_foreach(term->grid->sixel_images, it) {
|
||||
struct sixel *six = &it->item;
|
||||
|
||||
int six_end = rebase_row(term, six->pos.row + six->rows - 1);
|
||||
if (six_end >= term->grid->num_rows - rows) {
|
||||
sixel_destroy(six);
|
||||
tll_remove(term->grid->sixel_images, it);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
assert(_end >= _start);
|
||||
const int lines = _end - _start + 1;
|
||||
const int start = (term->grid->offset + _start) & (term->grid->num_rows - 1);
|
||||
const int end = (start + lines - 1) & (term->grid->num_rows - 1);
|
||||
const bool wraps = end < start;
|
||||
|
||||
if (wraps) {
|
||||
int rows_to_wrap_around = term->grid->num_rows - start;
|
||||
assert(lines - rows_to_wrap_around > 0);
|
||||
_sixel_delete_in_range(term, start, term->grid->num_rows);
|
||||
_sixel_delete_in_range(term, 0, lines - rows_to_wrap_around);
|
||||
} else
|
||||
_sixel_delete_in_range(term, start, end);
|
||||
verify_sixel_list_order(term);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -331,39 +283,24 @@ static void
|
|||
_sixel_overwrite_by_rectangle(
|
||||
struct terminal *term, int row, int col, int height, int width)
|
||||
{
|
||||
assert(row + height <= term->grid->num_rows);
|
||||
|
||||
assert(row >= 0);
|
||||
assert(row + height <= term->grid->num_rows);
|
||||
assert(col >= 0);
|
||||
assert(col + width <= term->grid->num_cols);
|
||||
|
||||
/* We don't handle rectangle wrapping around */
|
||||
assert(row + height <= term->grid->num_rows);
|
||||
|
||||
const int start = row;
|
||||
const int end = row + height - 1;
|
||||
|
||||
const int scrollback_end
|
||||
= (term->grid->offset + term->rows) & (term->grid->num_rows - 1);
|
||||
|
||||
const int grid_relative_start
|
||||
= (start
|
||||
- scrollback_end
|
||||
+ term->grid->num_rows) & (term->grid->num_rows - 1);
|
||||
const int scrollback_rel_start = rebase_row(term, start);
|
||||
|
||||
tll_foreach(term->grid->sixel_images, it) {
|
||||
struct sixel *six = &it->item;
|
||||
|
||||
const int six_start = six->pos.row;
|
||||
const int six_end = (six_start + six->rows - 1) & (term->grid->num_rows - 1);
|
||||
const int six_scrollback_rel_end = rebase_row(term, six_end);
|
||||
|
||||
const int six_grid_relative_end =
|
||||
(six_end
|
||||
- scrollback_end
|
||||
+ + term->grid->num_rows) & (term->grid->num_rows - 1);
|
||||
|
||||
if (six_grid_relative_end < grid_relative_start) {
|
||||
if (six_scrollback_rel_end < scrollback_rel_start) {
|
||||
/* All remaining sixels are *before* our rectangle */
|
||||
break;
|
||||
}
|
||||
|
|
@ -424,14 +361,8 @@ sixel_overwrite_by_row(struct terminal *term, int _row, int col, int width)
|
|||
if (likely(tll_length(term->grid->sixel_images) == 0))
|
||||
return;
|
||||
|
||||
const int scrollback_end
|
||||
= (term->grid->offset + term->rows) & (term->grid->num_rows - 1);
|
||||
|
||||
const int row = (term->grid->offset + _row) & (term->grid->num_rows - 1);
|
||||
const int grid_relative_row
|
||||
= (term->grid->offset + row
|
||||
- scrollback_end
|
||||
+ term->grid->num_rows) & (term->grid->num_rows - 1);
|
||||
const int scrollback_rel_row = rebase_row(term, row);
|
||||
|
||||
tll_foreach(term->grid->sixel_images, it) {
|
||||
struct sixel *six = &it->item;
|
||||
|
|
@ -441,12 +372,9 @@ sixel_overwrite_by_row(struct terminal *term, int _row, int col, int width)
|
|||
/* We should never generate scrollback wrapping sixels */
|
||||
assert(six_end >= six_start);
|
||||
|
||||
const int six_grid_relative_end
|
||||
= (six->pos.row + six->rows - 1
|
||||
- scrollback_end
|
||||
+ term->grid->num_rows) & (term->grid->num_rows - 1);
|
||||
const int six_scrollback_rel_end = rebase_row(term, six_end);
|
||||
|
||||
if (six_grid_relative_end < grid_relative_row) {
|
||||
if (six_scrollback_rel_end < scrollback_rel_row) {
|
||||
/* All remaining sixels are *before* "our" row */
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
11
sixel.h
11
sixel.h
|
|
@ -12,15 +12,8 @@ void sixel_unhook(struct terminal *term);
|
|||
|
||||
void sixel_destroy(struct sixel *sixel);
|
||||
|
||||
/*
|
||||
* Deletes all sixels that are touched by the specified row(s). Used
|
||||
* when scrolling, to competely remove sixels that has either
|
||||
* completely, or partly scrolled out of history.
|
||||
*
|
||||
* Row numbers are relative to the current grid offset.
|
||||
*/
|
||||
void sixel_delete_in_range(struct terminal *term, int row_start, int row_end);
|
||||
void sixel_delete_at_row(struct terminal *term, int row);
|
||||
void sixel_scroll_up(struct terminal *term, int rows);
|
||||
void sixel_scroll_down(struct terminal *term, int rows);
|
||||
|
||||
/*
|
||||
* Remove sixel data from the specified location. Used when printing
|
||||
|
|
|
|||
|
|
@ -1779,6 +1779,8 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows
|
|||
}
|
||||
}
|
||||
|
||||
sixel_scroll_up(term, rows);
|
||||
|
||||
bool view_follows = term->grid->view == term->grid->offset;
|
||||
term->grid->offset += rows;
|
||||
term->grid->offset &= term->grid->num_rows - 1;
|
||||
|
|
@ -1800,7 +1802,6 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows
|
|||
for (int r = region.end - rows; r < region.end; r++)
|
||||
erase_line(term, grid_row_and_alloc(term->grid, r));
|
||||
|
||||
sixel_delete_in_range(term, region.end - rows, region.end - 1);
|
||||
term_damage_scroll(term, DAMAGE_SCROLL, region, rows);
|
||||
term->grid->cur_row = grid_row(term->grid, term->grid->cursor.point.row);
|
||||
|
||||
|
|
@ -1841,6 +1842,8 @@ term_scroll_reverse_partial(struct terminal *term,
|
|||
}
|
||||
}
|
||||
|
||||
sixel_scroll_down(term, rows);
|
||||
|
||||
bool view_follows = term->grid->view == term->grid->offset;
|
||||
term->grid->offset -= rows;
|
||||
while (term->grid->offset < 0)
|
||||
|
|
@ -1867,7 +1870,6 @@ term_scroll_reverse_partial(struct terminal *term,
|
|||
for (int r = region.start; r < region.start + rows; r++)
|
||||
erase_line(term, grid_row_and_alloc(term->grid, r));
|
||||
|
||||
sixel_delete_in_range(term, region.start, region.start + rows - 1);
|
||||
term_damage_scroll(term, DAMAGE_SCROLL_REVERSE, region, rows);
|
||||
term->grid->cur_row = grid_row(term->grid, term->grid->cursor.point.row);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue