Skip to content

Commit

Permalink
Avoid drawing sixel to the bottom row
Browse files Browse the repository at this point in the history
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é!
  • Loading branch information
dankamongmen committed Jun 18, 2021
1 parent fc390da commit 50a304b
Show file tree
Hide file tree
Showing 6 changed files with 22 additions and 8 deletions.
2 changes: 1 addition & 1 deletion src/lib/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/lib/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
10 changes: 10 additions & 0 deletions src/lib/render.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 0 additions & 1 deletion src/lib/termdesc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
11 changes: 9 additions & 2 deletions src/lib/termdesc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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

Expand Down
5 changes: 1 addition & 4 deletions src/lib/visual.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 50a304b

Please sign in to comment.