track+use width for polycolumn EGCs #1203 (#1205)

Some EGCs are more than 2 columns (wcwidth() never returns more than 2, so far as i can tell, but when multiple characters combine, we use the sum). An example would be ကြေ (Myanmar) which occupies three columns over the course of three characters. Track the width (biased by 1) in cell->width, taking over 8 bits from cell->reserved. Use this width in rasterization. Closes #1203.
pull/1206/head
Nick Black 4 years ago committed by GitHub
parent 8497ee1877
commit 6106dea18a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -26,7 +26,7 @@ int notcurses_inputready_fd(struct notcurses* n);
typedef struct cell {
uint32_t gcluster; // 4B 4B
uint8_t gcluster_backstop; // 1B 5B (8 bits of zero)
uint8_t reserved; // 1B 6B (8 reserved bits, ought be zero)
uint8_t width; // 1B 6B (8 bits, width biased-1)
uint16_t stylemask; // 2B 8B (16 bits of NCSTYLE_* attributes)
uint64_t channels; // + 8b == 16b
} cell;

@ -565,7 +565,11 @@ typedef struct cell {
// must not be allowed through the API, or havoc will result.
uint32_t gcluster; // 4B → 4B little endian EGC
uint8_t gcluster_backstop; // 1B → 5B (8 bits of zero)
uint8_t reserved; // 1B → 6B (8 reserved bits, ought be zero)
// we store the column width minus 1 in this field. this is necessary to
// handle EGCs of more than 2 columns...for now. eventually, such an EGC will
// set more than one subsequent cell to WIDE_RIGHT, and this won't be
// necessary. it can then be used as a bytecount. see #1203. FIXME
uint8_t width; // 1B → 6B (8 bits of EGC width, bias-1)
uint16_t stylemask; // 2B → 8B (16 bits of NCSTYLE_* attributes)
// (channels & 0x8000000000000000ull): part of a wide glyph
// (channels & 0x4000000000000000ull): foreground is *not* "default color"
@ -588,11 +592,12 @@ typedef struct cell {
uint64_t channels; // + 8B == 16B
} cell;
#define CELL_TRIVIAL_INITIALIZER { .gcluster = 0, .gcluster_backstop = 0, .reserved = 0, .stylemask = 0, .channels = 0, }
// do *not* load control characters nor invalid EGCs using these macros! there
// is no way for us to protect against such misuse here. problems *will* ensue.
#define CELL_CHAR_INITIALIZER(c) { .gcluster = (htole(c)), .gcluster_backstop = 0, .reserved = 0, .stylemask = 0, .channels = 0, }
#define CELL_INITIALIZER(c, s, chan) { .gcluster = (htole(c)), .gcluster_backstop = 0, .reserved = 0, .stylemask = (s), .channels = (chan), }
#define CELL_TRIVIAL_INITIALIZER { .gcluster = 0, .gcluster_backstop = 0, .width = 0, .stylemask = 0, .channels = 0, }
// do *not* load control characters, wide EGCs, nor invalid EGCs using these
// macros! there is no way for us to protect against such misuse here. problems
// *will* ensue. similarly, do not set channel flags other than colors/alpha.
#define CELL_CHAR_INITIALIZER(c) { .gcluster = (htole(c)), .gcluster_backstop = 0, .width = 0, .stylemask = 0, .channels = 0, }
#define CELL_INITIALIZER(c, s, chan) { .gcluster = (htole(c)), .gcluster_backstop = 0, .width = 0, .stylemask = (s), .channels = (chan), }
static inline void
cell_init(cell* c){

@ -13,7 +13,7 @@ impl NcCell {
NcCell {
gcluster: ch as u32,
gcluster_backstop: 0 as NcEgcBackstop,
reserved: 0,
width: 0,
stylemask,
channels,
}

@ -92,7 +92,7 @@ pub use reimplemented::*;
/// NcCell: 128 bits structure comprised of the following 5 elements:
///
/// GCLUSTER GCLUSTER GCLUSTER GCLUSTER 1. NcEgc
/// 00000000 ~~~~~~~~ 11111111 11111111 2. NcEgcBackstop + 3. reserved + 4. NcStyleMask
/// 00000000 ~~~~~~~~ 11111111 11111111 2. NcEgcBackstop + 3. width + 4. NcStyleMask
/// ~~AA~~~~ RRRRRRRR GGGGGGGG BBBBBBBB 5. NcChannelPair
/// ~~AA~~~~ RRRRRRRR GGGGGGGG BBBBBBBB |
///
@ -107,7 +107,7 @@ pub use reimplemented::*;
/// 2. (8b) Backstop (zero)
/// 00000000
///
/// 3. (8b) reserved (ought to be zero)
/// 3. (8b) width (biased 1)
/// ~~~~~~~~
///
/// 4. (16b) NcStyleMask

@ -586,8 +586,6 @@ pool_extended_gcluster(const egcpool* pool, const cell* c){
static inline cell*
ncplane_cell_ref_yx(ncplane* n, int y, int x){
assert(y < n->leny);
assert(x < n->lenx);
return &n->fb[nfbcellidx(n, y, x)];
}
@ -652,11 +650,11 @@ cell_duplicate_far(egcpool* tpool, cell* targ, const ncplane* splane, const cell
pool_release(tpool, targ);
targ->stylemask = c->stylemask;
targ->channels = c->channels;
targ->width = c->width;
if(cell_simple_p(c)){
targ->gcluster = c->gcluster;
return 0;
}
assert(splane);
const char* egc = cell_extended_gcluster(splane, c);
// FIXME we could eliminate this strlen() with a cell_extended_gcluster_len()
// that returned the length, combined with O(1) length for inlined EGCs...
@ -742,10 +740,6 @@ int ncvisual_bounding_box(const struct ncvisual* ncv, int* leny, int* lenx,
static int
calc_gradient_component(unsigned tl, unsigned tr, unsigned bl, unsigned br,
int y, int x, int ylen, int xlen){
assert(y >= 0);
assert(y < ylen);
assert(x >= 0);
assert(x < xlen);
const int avm = (ylen - 1) - y;
const int ahm = (xlen - 1) - x;
if(xlen < 2){
@ -988,6 +982,7 @@ pool_blit_direct(egcpool* pool, cell* c, const char* gcluster, int bytes, int co
static inline int
pool_load_direct(egcpool* pool, cell* c, const char* gcluster, int bytes, int cols){
char* rtl = NULL;
c->width = cols - 1;
if(cols < 2){
c->channels &= ~CELL_WIDEASIAN_MASK;
if(bytes == 3 && memcmp(gcluster, "\xe2\x96\x88", 4) == 0){

@ -2605,7 +2605,7 @@ int ncplane_putstr_yx(struct ncplane* n, int y, int x, const char* gclusters){
while(*gclusters){
int wcs;
int cols = ncplane_putegc_yx(n, y, x, gclusters, &wcs);
//fprintf(stderr, "wrote %d cols %d bytes now at %d/%d\n", cols, wcs, n->y, n->x);
//fprintf(stderr, "wrote %.*s %d cols %d bytes now at %d/%d\n", wcs, gclusters, cols, wcs, n->y, n->x);
if(cols < 0){
return -ret;
}

@ -303,6 +303,7 @@ paint(const ncplane* p, struct crender* rvec, int dstleny, int dstlenx,
cell_set_wide(targc);
crender->p = p;
}
targc->width = vis->width;
}
// Background color takes effect independently of whether we have a
@ -609,9 +610,6 @@ static const char* const NUMBERS[] = {
static inline int
term_esc_rgb(FILE* out, bool foreground, unsigned r, unsigned g, unsigned b){
assert(r < 256);
assert(g < 256);
assert(b < 256);
// The correct way to do this is using tiparm+tputs, but doing so (at least
// as of terminfo 6.1.20191019) both emits ~3% more bytes for a run of 'rgb'
// and gives rise to some inaccurate colors (possibly due to special handling
@ -916,15 +914,12 @@ notcurses_rasterize_inner(notcurses* nc, const ncpile* p, FILE* out){
nc->rstate.defaultelidable = false;
nc->rstate.bgpalelidable = false;
}
//fprintf(stderr, "RAST %08x [%s] to %d/%d %016lx\n", srccell->gcluster, pool_extended_gcluster(&nc->pool, srccell), y, x, srccell->channels);
//fprintf(stderr, "RAST %08x [%s] to %d/%d cols: %u %016lx\n", srccell->gcluster, pool_extended_gcluster(&nc->pool, srccell), y, x, srccell->width + 1, srccell->channels);
if(term_putc(out, &nc->pool, srccell)){
return -1;
}
++nc->rstate.x;
if(cell_wide_left_p(srccell)){
++nc->rstate.x;
++x;
}
nc->rstate.x += srccell->width + 1;
x += srccell->width;
}
//fprintf(stderr, "damageidx: %ld\n", damageidx);
}

Loading…
Cancel
Save