From ca6ecf2f35c1d530d8b35ff1228441806f0ee4c3 Mon Sep 17 00:00:00 2001 From: nick black Date: Fri, 31 Jul 2020 23:00:26 -0400 Subject: [PATCH] ncplane_resize(): fix irregular keep areas #842 --- src/lib/notcurses.c | 90 +++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 40 deletions(-) diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index 3c603d6d7..464ef40e2 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -453,22 +453,28 @@ int ncplane_resize_internal(ncplane* n, int keepy, int keepx, int keepleny, logerror(n->nc, "Can't retain negative size %dx%d\n", keepleny, keeplenx); return -1; } - if(ylen <= 0 || xlen <= 0){ // can't resize to trivial or negative size - logerror(n->nc, "Can't achieve negative size %dx%d\n", ylen, xlen); - return -1; - } if((!keepleny && keeplenx) || (keepleny && !keeplenx)){ // both must be 0 logerror(n->nc, "Can't retain null dimension %dx%d\n", keepleny, keeplenx); return -1; } - if(ylen < keepleny || xlen < keeplenx){ // can't be smaller than our keep - logerror(n->nc, "Can't violate space %dx%d vs %dx%d\n", keepleny, keeplenx, ylen, xlen); + // can't be smaller than keep length + abs(offset from keep area) + const int yprescribed = keepleny + (yoff < 0 ? -yoff : yoff); + if(ylen < yprescribed){ + logerror(n->nc, "Can't map in y dimension: %d < %d\n", ylen, yprescribed); + return -1; + } + const int xprescribed = keeplenx + (xoff < 0 ? -xoff : xoff); + if(xlen < xprescribed){ + logerror(n->nc, "Can't map in x dimension: %d < %d\n", xlen, xprescribed); + return -1; + } + if(ylen <= 0 || xlen <= 0){ // can't resize to trivial or negative size + logerror(n->nc, "Can't achieve meaningless size %dx%d\n", ylen, xlen); return -1; } int rows, cols; ncplane_dim_yx(n, &rows, &cols); -//fprintf(stderr, "NCPLANE(RESIZING) to %dx%d at %d/%d (keeping %dx%d from %d/%d)\n", -// ylen, xlen, yoff, xoff, keepleny, keeplenx, keepy, keepx); + loginfo(n->nc, "%dx%d @ %d/%d → %d/%d @ %d/%d (keeping %dx%d from %d/%d)\n", rows, cols, n->absy, n->absx, ylen, xlen, n->absy + keepy + yoff, n->absx + keepx + xoff, keepleny, keeplenx, keepy, keepx); // we're good to resize. we'll need alloc up a new framebuffer, and copy in // those elements we're retaining, zeroing out the rest. alternatively, if // we've shrunk, we will be filling the new structure. @@ -490,11 +496,16 @@ int ncplane_resize_internal(ncplane* n, int keepy, int keepx, int keepleny, n->nc->stats.fbbytes -= sizeof(*preserved) * (rows * cols); n->nc->stats.fbbytes += fbsize; n->fb = fb; + const int oldabsy = n->absy; + // go ahead and move. we can no longer fail at this point. but don't yet + // resize, because n->len[xy] are used in fbcellidx() in the loop below. we + // don't use ncplane_move_yx(), because we want to planebinding-invariant. n->absy += keepy + yoff; n->absx += keepx + xoff; - // if we're keeping nothing, dump the old egcspool. otherwise, we go ahead - // and keep it. perhaps we ought compact it? +//fprintf(stderr, "absx: %d keepx: %d xoff: %d\n", n->absx, keepx, xoff); if(keptarea == 0){ // keep nothing, resize/move only + // if we're keeping nothing, dump the old egcspool. otherwise, we go ahead + // and keep it. perhaps we ought compact it? memset(fb, 0, sizeof(*fb) * newarea); egcpool_dump(&n->pool); n->lenx = xlen; @@ -503,36 +514,35 @@ int ncplane_resize_internal(ncplane* n, int keepy, int keepx, int keepleny, return 0; } // we currently have maxy rows of maxx cells each. we will be keeping rows - // keepy..keepy + keepleny - 1 and columns keepx..keepx + keeplenx - 1. they - // will end up at keepy + yoff..keepy + keepleny - 1 + yoff and - // keepx + xoff..keepx + keeplenx - 1 + xoff. everything else is zerod out. - int itery; - // we'll prepare each cell in our new framebuffer with either zeroes or a copy - // from the old one. - int sourceline = keepy; - for(itery = 0 ; itery < ylen ; ++itery){ - int copyoff = itery * xlen; // our target at any given time - // FIXME in memset()s here of existing text, don't we need cell_release()? + // keepy..keepy + keepleny - 1 and columns keepx..keepx + keeplenx - 1. + // anything else is zerod out. itery is the row we're writing *to*, and we + // must write to each (and every cell in each). + for(int itery = 0 ; itery < ylen ; ++itery){ + int truey = itery + n->absy; + int sourceoffy = truey - oldabsy; +//fprintf(stderr, "sourceoffy: %d keepy: %d ylen: %d\n", sourceoffy, keepy, ylen); // if we have nothing copied to this line, zero it out in one go - if(itery < keepy || itery > keepy + keepleny - 1){ - memset(fb + copyoff, 0, sizeof(*fb) * xlen); - continue; - } - // we do have something to copy, and zero, one, or two regions to zero out - int copied = 0; - if(xoff < 0){ - memset(fb + copyoff, 0, sizeof(*fb) * -xoff); - copyoff += -xoff; - copied += -xoff; - } - const int sourceidx = nfbcellidx(n, sourceline, keepx); - memcpy(fb + copyoff, preserved + sourceidx, sizeof(*fb) * keeplenx); - copyoff += keeplenx; - copied += keeplenx; - if(xlen > copied){ - memset(fb + copyoff, 0, sizeof(*fb) * (xlen - copied)); - } - ++sourceline; + if(sourceoffy < keepy || sourceoffy >= keepy + keepleny){ +//fprintf(stderr, "writing 0s to line %d of %d\n", itery, ylen); + memset(fb + (itery * xlen), 0, sizeof(*fb) * xlen); + }else{ + int copyoff = itery * xlen; // our target at any given time + // we do have something to copy, and zero, one, or two regions to zero out + int copied = 0; + if(xoff < 0){ + memset(fb + copyoff, 0, sizeof(*fb) * -xoff); + copyoff += -xoff; + copied += -xoff; + } + const int sourceidx = nfbcellidx(n, sourceoffy, keepx); +//fprintf(stderr, "copying line %d (%d) to %d (%d)\n", sourceoffy, sourceidx, copyoff / xlen, copyoff); + memcpy(fb + copyoff, preserved + sourceidx, sizeof(*fb) * keeplenx); + copyoff += keeplenx; + copied += keeplenx; + if(xlen > copied){ + memset(fb + copyoff, 0, sizeof(*fb) * (xlen - copied)); + } + } } n->lenx = xlen; n->leny = ylen; @@ -1743,7 +1753,7 @@ int ncplane_puttext(ncplane* n, int y, ncalign_e align, const char* text, size_t const int xpos = ncplane_align(n, align, breakercol); // blows out if we supply a y beyond leny //fprintf(stderr, "y: %d %ld %.*s\n", y, breaker - linestart, (int)(breaker - linestart), linestart); - if(ncplane_putnstr_yx(n, y, xpos, breaker - linestart, linestart) <= 0){ + if(ncplane_putnstr_yx(n, y, xpos, breaker - linestart, linestart) <= 0){ if(bytes){ *bytes = linestart - beginning; }