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.
pull/1589/head
nick black 3 years ago
parent 5a72383cb0
commit 95072d0f5c
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC

@ -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);

@ -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<uint32_t> 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<uint32_t> 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<uint32_t> 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));
}

Loading…
Cancel
Save