ncplane_putegc_yx() copies directly as opposed to going through putc() #797

dankamongmen/speedypainter
nick black 4 years ago committed by Nick Black
parent 0767aaec01
commit 97571e86af

@ -1626,6 +1626,21 @@ void cell_release(struct ncplane* n, cell* c);
#define NCSTYLE_PROTECT 0x00010000ul
#define NCSTYLE_ITALIC 0x01000000ul
// copy the UTF8-encoded EGC out of the cell, whether simple or complex. the
// result is not tied to the ncplane, and persists across erases / destruction.
static inline char*
cell_strdup(const struct ncplane* n, const cell* c){
char* ret;
if(cell_simple_p(c)){
if( (ret = (char*)malloc(2)) ){ // cast is here for C++ clients
ret[0] = c->gcluster;
ret[1] = '\0';
}
}else{
ret = strdup(cell_extended_gcluster(n, c));
}
return ret;
}
// Set the specified style bits for the cell 'c', whether they're actively
// supported or not.

@ -729,7 +729,8 @@ cell_simple_p(const cell* c){
// is invalidated by any further operation on the plane 'n', so...watch out!
API const char* cell_extended_gcluster(const struct ncplane* n, const cell* c);
// Extract the EGC from 'c' as a nul-terminated string.
// copy the UTF8-encoded EGC out of the cell, whether simple or complex. the
// result is not tied to the ncplane, and persists across erases / destruction.
static inline char*
cell_strdup(const struct ncplane* n, const cell* c){
char* ret;

@ -410,13 +410,6 @@ pool_egc_copy(const egcpool* e, const cell* c){
return ret;
}
// copy the UTF8-encoded EGC out of the cell, whether simple or complex. the
// result is not tied to the ncplane, and persists across erases / destruction.
static inline char*
cell_egc_copy(const ncplane* n, const cell* c){
return pool_egc_copy(&n->pool, c);
}
// For our first attempt, O(1) uniform conversion from 8-bit r/g/b down to
// ~2.4-bit 6x6x6 cube + greyscale (assumed on entry; I know no way to
// even semi-portably recover the palette) proceeds via: map each 8-bit to

@ -1284,17 +1284,66 @@ int ncplane_putc_yx(ncplane* n, int y, int x, const cell* c){
}
int ncplane_putegc_yx(ncplane* n, int y, int x, const char* gclust, int* sbytes){
cell c = CELL_TRIVIAL_INITIALIZER;
int primed = cell_prime(n, &c, gclust, n->attrword, n->channels);
int cols;
int bytes = utf8_egc_len(gclust, &cols);
if(sbytes){
*sbytes = primed;
*sbytes = bytes;
}
// if scrolling is enabled, check *before ncplane_cursor_move_yx()* whether
// we're past the end of the line, and move to the next line if so.
bool wide = cols > 1;
if(x == -1 && y == -1 && n->x + wide >= n->lenx){
if(!n->scrolling){
return -1;
}
scroll_down(n);
}
if(primed < 0){
if(ncplane_cursor_move_yx(n, y, x)){
return -1;
}
int ret = ncplane_putc_yx(n, y, x, &c);
cell_release(n, &c);
return ret;
if(*gclust == '\n'){
if(n->scrolling){
scroll_down(n);
return 0;
}
}
// A wide character obliterates anything to its immediate right (and marks
// that cell as wide). Any character placed atop one half of a wide character
// obliterates the other half. Note that a wide char can thus obliterate two
// wide chars, totalling four columns.
cell* targ = ncplane_cell_ref_yx(n, n->y, n->x);
if(n->x > 0){
if(cell_double_wide_p(targ)){ // replaced cell is half of a wide char
if(targ->gcluster == 0){ // we're the right half
cell_obliterate(n, &n->fb[nfbcellidx(n, n->y, n->x - 1)]);
}else{
cell_obliterate(n, &n->fb[nfbcellidx(n, n->y, n->x + 1)]);
}
}
}
uint64_t channels = n->channels & ~CELL_WIDEASIAN_MASK;
if(wide){
channels |= CELL_WIDEASIAN_MASK;
}
if(cell_prime(n, targ, gclust, n->attrword, channels) < 0){
return -1;
}
if(wide){ // must set our right wide, and check for further damage
if(n->x < n->lenx - 1){ // check to our right
cell* candidate = &n->fb[nfbcellidx(n, n->y, n->x + 1)];
if(n->x < n->lenx - 2){
if(cell_wide_left_p(candidate)){
cell_obliterate(n, &n->fb[nfbcellidx(n, n->y, n->x + 2)]);
}
}
cell_obliterate(n, candidate);
cell_set_wide(candidate);
candidate->channels = channels;
candidate->attrword = n->attrword;
}
}
n->x += cols;
return cols;
}
int ncplane_putsimple_stainable(ncplane* n, char c){
@ -1867,7 +1916,7 @@ void ncplane_erase(ncplane* n){
// we must preserve the background, but a pure cell_duplicate() would be
// wiped out by the egcpool_dump(). do a duplication (to get the attrword
// and channels), and then reload.
char* egc = cell_egc_copy(n, &n->basecell);
char* egc = cell_strdup(n, &n->basecell);
memset(n->fb, 0, sizeof(*n->fb) * n->lenx * n->leny);
egcpool_dump(&n->pool);
egcpool_init(&n->pool);

@ -284,7 +284,7 @@ TEST_CASE("Wide") {
// should be wide char 1
REQUIRE(3 == ncplane_at_yx_cell(n_, 0, 0, &c));
egc = cell_egc_copy(n_, &c);
egc = cell_strdup(n_, &c);
REQUIRE(egc);
CHECK(!strcmp("\xe5\x85\xa8", egc));
CHECK(cell_double_wide_p(&c));
@ -297,7 +297,7 @@ TEST_CASE("Wide") {
cell_init(&c);
// should be wide char 1 right side
REQUIRE(0 == ncplane_at_yx_cell(n_, 0, 1, &c));
egc = cell_egc_copy(n_, &c);
egc = cell_strdup(n_, &c);
REQUIRE(egc);
CHECK(!strcmp("", egc));
CHECK(cell_double_wide_p(&c));
@ -311,7 +311,7 @@ TEST_CASE("Wide") {
// should be wide char 2
REQUIRE(3 == ncplane_at_yx_cell(n_, 0, 2, &c));
egc = cell_egc_copy(n_, &c);
egc = cell_strdup(n_, &c);
REQUIRE(egc);
CHECK(!strcmp("\xe5\xbd\xa2", egc));
CHECK(cell_double_wide_p(&c));
@ -324,7 +324,7 @@ TEST_CASE("Wide") {
cell_init(&c);
// should be wide char 2 right side
CHECK(0 == ncplane_at_yx_cell(n_, 0, 3, &c));
egc = cell_egc_copy(n_, &c);
egc = cell_strdup(n_, &c);
REQUIRE(egc);
CHECK(!strcmp("", egc));
CHECK(cell_double_wide_p(&c));

Loading…
Cancel
Save