From 95072d0f5cf97b4e4c8283bb5747b01e671b9533 Mon Sep 17 00:00:00 2001 From: nick black Date: Sat, 24 Apr 2021 04:47:05 -0400 Subject: [PATCH] No glyph emission on sprixelated planes Guard against attempts to output glyphs to a sprixelated plane in ncplane_putc_yx(), the lowest-level common end of all ncplane_put*() functions. Add unit test #1572. --- src/lib/notcurses.c | 9 ++++-- src/tests/bitmap.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index 3bddf1f0a..faadc4578 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -1454,19 +1454,24 @@ int cell_load(ncplane* n, nccell* c, const char* gcluster){ static inline int ncplane_put(ncplane* n, int y, int x, const char* egc, int cols, uint16_t stylemask, uint64_t channels, int bytes){ + const notcurses* nc = ncplane_notcurses_const(n); + if(n->sprite){ + logerror(nc, "Can't write glyphs (%s) to sprixelated plane\n", egc); + return -1; + } // FIXME reject any control or space characters here--should be iswgraph() // check *before ncplane_cursor_move_yx()* whether we're past the end of the // line. if scrolling is enabled, move to the next line if so. if x or y are // specified, we must always try to print at exactly that location. if(x != -1){ if(x + cols > n->lenx){ - logerror(ncplane_notcurses(n), "Target x %d + %d cols >= length %d\n", x, cols, n->lenx); + logerror(nc, "Target x %d + %d cols >= length %d\n", x, cols, n->lenx); ncplane_cursor_move_yx(n, y, x); // update cursor, though return -1; } }else if(y == -1 && n->x + cols > n->lenx){ if(!n->scrolling){ - logerror(ncplane_notcurses(n), "No room to output [%.*s] %d/%d\n", bytes, egc, n->y, n->x); + logerror(nc, "No room to output [%.*s] %d/%d\n", bytes, egc, n->y, n->x); return -1; } scroll_down(n); diff --git a/src/tests/bitmap.cpp b/src/tests/bitmap.cpp index c4582f833..4244694b5 100644 --- a/src/tests/bitmap.cpp +++ b/src/tests/bitmap.cpp @@ -47,8 +47,38 @@ TEST_CASE("Bitmaps") { } // a sprixel requires a plane large enough to hold it - SUBCASE("SprixelTooBig") { + SUBCASE("SprixelTooTall") { auto y = nc_->tcache.cellpixy + 1; + auto x = nc_->tcache.cellpixx; + std::vector v(x * y, htole(0xe61c28ff)); + auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x); + REQUIRE(nullptr != ncv); + struct ncplane_options nopts = { + .y = 0, .x = 0, + .rows = 1, .cols = 1, + .userptr = nullptr, .name = "small", .resizecb = nullptr, + .flags = 0, .margin_b = 0, .margin_r = 0, + }; + auto n = ncplane_create(n_, &nopts); + struct ncvisual_options vopts = { + .n = n, + .scaling = NCSCALE_NONE, + .y = 0, + .x = 0, + .begy = 0, .begx = 0, + .leny = 0, .lenx = 0, + .blitter = NCBLIT_PIXEL, + .flags = NCVISUAL_OPTION_NODEGRADE, + .transcolor = 0, + }; + CHECK(nullptr == ncvisual_render(nc_, ncv, &vopts)); + CHECK(0 == notcurses_render(nc_)); + ncvisual_destroy(ncv); + CHECK(0 == ncplane_destroy(n)); + } + + SUBCASE("SprixelTooWide") { + auto y = nc_->tcache.cellpixy; auto x = nc_->tcache.cellpixx + 1; std::vector v(x * y, htole(0xe61c28ff)); auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x); @@ -73,7 +103,38 @@ TEST_CASE("Bitmaps") { }; CHECK(nullptr == ncvisual_render(nc_, ncv, &vopts)); CHECK(0 == notcurses_render(nc_)); -sleep(2); + ncvisual_destroy(ncv); + CHECK(0 == ncplane_destroy(n)); + } + + // should not be able to emit glyphs to a sprixelated plane + SUBCASE("SprixelNoGlyphs") { + auto y = nc_->tcache.cellpixy; + auto x = nc_->tcache.cellpixx; + std::vector v(x * y, htole(0xe61c28ff)); + auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x); + REQUIRE(nullptr != ncv); + struct ncplane_options nopts = { + .y = 0, .x = 0, + .rows = 1, .cols = 1, + .userptr = nullptr, .name = "small", .resizecb = nullptr, + .flags = 0, .margin_b = 0, .margin_r = 0, + }; + auto n = ncplane_create(n_, &nopts); + struct ncvisual_options vopts = { + .n = n, + .scaling = NCSCALE_NONE, + .y = 0, + .x = 0, + .begy = 0, .begx = 0, + .leny = 0, .lenx = 0, + .blitter = NCBLIT_PIXEL, + .flags = NCVISUAL_OPTION_NODEGRADE, + .transcolor = 0, + }; + CHECK(nullptr != ncvisual_render(nc_, ncv, &vopts)); + CHECK(0 > ncplane_putchar_yx(n, ' ', 0, 0)); + CHECK(0 == notcurses_render(nc_)); ncvisual_destroy(ncv); CHECK(0 == ncplane_destroy(n)); }