Avoid drawing sixel to the bottom row

Sixels, unlike Kitties, can't be drawn to the bottom row,
lest we scroll. We were properly guarding against creation
of a sixel that touched the bottom row when creating the
plane within ncvisual_blit(), but not when we were provided
with a plane. This used to be fine because ncplayer cut the
plane off less one row, but when we enabled the bottom row
for Kitties, this ceased. We don't want to expose this wart
to userspace, so instead clamp sixel_maxy based off the screen
height when appropriate. Closes #1789.

1789?!?! Liberté, Egalité, Fraternité!
This commit is contained in:
nick black 2021-06-18 18:42:30 -04:00
parent fc390da020
commit 50a304bada
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC
6 changed files with 22 additions and 8 deletions

View File

@ -1051,7 +1051,7 @@ pump_control_read(init_state* inits, unsigned char c){
break;
case STATE_SIXEL_HEIGHT:
if(c == 'S'){
inits->tcache->sixel_maxy = inits->numeric;
inits->tcache->sixel_maxy_pristine = inits->numeric;
inits->state = STATE_NULL;
}else if(ruts_numeric(&inits->numeric, c)){
return -1;

View File

@ -944,6 +944,7 @@ clamp_to_sixelmax(const tinfo* t, int* y, int* x, int* outy, ncscale_e scaling){
*outy = *y;
if(*outy % t->sprixel_scale_height){
*outy += t->sprixel_scale_height - (*outy % t->sprixel_scale_height);
// FIXME use closed form
while(t->sixel_maxy && *outy > t->sixel_maxy){
*outy -= t->sprixel_scale_height;
}

View File

@ -30,6 +30,16 @@ notcurses_resize_internal(ncplane* pp, int* restrict rows, int* restrict cols){
if(*rows <= 0){
*rows = 1;
}
if(n->tcache.sixel_maxy_pristine){
n->tcache.sixel_maxy = n->tcache.sixel_maxy_pristine;
int sixelrows = *rows - 1;
// if the bottom margin is at least one row, we can draw into the last
// row of our visible area. we must leave the true bottom row alone.
if(n->margin_b){
++sixelrows;
}
n->tcache.sixel_maxy = sixelrows * n->tcache.cellpixy;
}
*cols -= n->margin_l + n->margin_r;
if(*cols <= 0){
*cols = 1;

View File

@ -28,7 +28,6 @@ setup_kitty_bitmaps(tinfo* ti, int fd){
ti->sprixel_scale_height = 1;
ti->pixel_rebuild = kitty_rebuild;
ti->pixel_clear_all = kitty_clear_all;
ti->bitmap_lowest_line = true;
set_pixel_blitter(kitty_blit);
sprite_init(ti, fd);
}

View File

@ -117,7 +117,15 @@ typedef struct tinfo {
// on TERM heuristics. otherwise, we attempt to detect sixel support, and
// query the details of the implementation.
int color_registers; // sixel color registers (post pixel_query_done)
int sixel_maxx, sixel_maxy; // sixel size maxima (post pixel_query_done)
int sixel_maxx; // maximum theoretical sixel width
// in sixel, we can't render to the bottom row, lest we force a one-line
// scroll. we thus clamp sixel_maxy_pristine to the minimum of
// sixel_maxy_pristine (the reported sixel_maxy), and the number of rows
// less one times the cell height. sixel_maxy is thus recomputed whenever
// we get a resize event. it is only defined if we have sixel_maxy_pristine,
// so kitty graphics (which don't force a scroll) never deal with this.
int sixel_maxy; // maximum working sixel height
int sixel_maxy_pristine; // maximum theoretical sixel height, as queried
int (*pixel_destroy)(const struct notcurses* nc, const struct ncpile* p, FILE* out, struct sprixel* s);
// wipe out a cell's worth of pixels from within a sprixel. for sixel, this
// means leaving out the pixels (and likely resizes the string). for kitty,
@ -135,7 +143,6 @@ typedef struct tinfo {
struct termios tpreserved; // terminal state upon entry
ncinputlayer input; // input layer
bool bitmap_supported; // do we support bitmaps (post pixel_query_done)?
bool bitmap_lowest_line; // can we render pixels to the bottom row?
bool BCEflag; // "BCE" flag for erases with background color
bool AMflag; // "AM" flag for automatic movement to next line

View File

@ -770,11 +770,9 @@ make_sprixel_plane(notcurses* nc, ncplane* parent, ncvisual* ncv,
uint64_t flags, int* outy, int* placey, int* placex){
if(scaling != NCSCALE_NONE && scaling != NCSCALE_NONE_HIRES){
ncplane_dim_yx(parent, disppixy, disppixx);
// FIXME why do we clamp only vertical, not horizontal, here?
if(*placey + *disppixy >= ncplane_dim_y(notcurses_stdplane_const(nc))){
*disppixy = ncplane_dim_y(notcurses_stdplane_const(nc)) - *placey;
if(!nc->tcache.bitmap_lowest_line){
--*disppixy;
}
}
if(!(flags & NCVISUAL_OPTION_VERALIGNED)){
*disppixy -= *placey;
@ -845,7 +843,6 @@ ncplane* ncvisual_render_pixels(notcurses* nc, ncvisual* ncv, const struct blits
}
int disppixy = 0, disppixx = 0, outy = 0;
ncplane* createdn = NULL;
//fprintf(stderr, "INPUT N: %p rows: %d cols: %d 0x%016lx\n", n ? n : NULL, disppixy, disppixx, flags);
if(n == NULL || (flags & NCVISUAL_OPTION_CHILDPLANE)){ // create plane
if(n == NULL){
n = notcurses_stdplane(nc);