Move the text attributes out of the char type

This means that more text attributes can be added in the future (there
are 8 bits available) and there is no need to keep bit twiddling when
accessing the chars themselves. Also means less data needs to be sent to
the GPU. Cell size does not change since there were currently 2 unused
bytes because of alignment.
This commit is contained in:
Kovid Goyal 2017-09-16 11:02:42 +05:30
parent 85ed5c1515
commit a92b3c605f
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
9 changed files with 75 additions and 70 deletions

View File

@ -9,8 +9,7 @@ uniform uvec4 url_range; // The range for the currently highlighted URL (start_x
uniform ColorTable { uniform ColorTable {
uint color_table[256]; // The color table uint color_table[256]; // The color table
}; };
in uint text_attrs; in uvec4 sprite_coords;
in uvec3 sprite_coords;
in uvec3 colors; in uvec3 colors;
in float is_selected; in float is_selected;
out vec3 sprite_pos; out vec3 sprite_pos;
@ -95,7 +94,8 @@ void main() {
gl_Position = vec4(xpos[pos.x], ypos[pos.y], 0, 1); gl_Position = vec4(xpos[pos.x], ypos[pos.y], 0, 1);
sprite_pos = to_sprite_pos(pos, sprite_coords.x, sprite_coords.y, sprite_coords.z & SHORT_MASK); sprite_pos = to_sprite_pos(pos, sprite_coords.x, sprite_coords.y, sprite_coords.z & SHORT_MASK);
uint reverse = (text_attrs >> 30) & STRIKE_MASK; uint text_attrs = sprite_coords[3];
uint reverse = (text_attrs >> 6) & STRIKE_MASK;
uint fg = colors[color_indices[reverse]]; uint fg = colors[color_indices[reverse]];
uint bg = colors[color_indices[ONE - reverse]]; uint bg = colors[color_indices[ONE - reverse]];
uint resolved_fg = as_color(fg, default_colors[color_indices[0]]); uint resolved_fg = as_color(fg, default_colors[color_indices[0]]);
@ -103,6 +103,6 @@ void main() {
background = apply_selection(to_color(bg, default_colors[color_indices[1]]), default_colors[3]); background = apply_selection(to_color(bg, default_colors[color_indices[1]]), default_colors[3]);
float in_url = in_range(url_range, c, r); float in_url = in_range(url_range, c, r);
decoration_fg = mix_vecs(in_url, color_to_vec(url_color), to_color(colors[2], resolved_fg)); decoration_fg = mix_vecs(in_url, color_to_vec(url_color), to_color(colors[2], resolved_fg));
underline_pos = mix_vecs(in_url, to_sprite_pos(pos, TWO, ZERO, ZERO), to_sprite_pos(pos, (text_attrs >> 26) & DECORATION_MASK, ZERO, ZERO)); underline_pos = mix_vecs(in_url, to_sprite_pos(pos, TWO, ZERO, ZERO), to_sprite_pos(pos, (text_attrs >> 2) & DECORATION_MASK, ZERO, ZERO));
strike_pos = to_sprite_pos(pos, ((text_attrs >> 31) & STRIKE_MASK) * THREE, ZERO, ZERO); strike_pos = to_sprite_pos(pos, ((text_attrs >> 7) & STRIKE_MASK) * THREE, ZERO, ZERO);
} }

View File

@ -29,6 +29,7 @@ typedef uint32_t color_type;
typedef uint32_t combining_type; typedef uint32_t combining_type;
typedef unsigned int index_type; typedef unsigned int index_type;
typedef uint16_t sprite_index; typedef uint16_t sprite_index;
typedef uint16_t attrs_type;
typedef enum CursorShapes { NO_CURSOR_SHAPE, CURSOR_BLOCK, CURSOR_BEAM, CURSOR_UNDERLINE, NUM_OF_CURSOR_SHAPES } CursorShape; typedef enum CursorShapes { NO_CURSOR_SHAPE, CURSOR_BLOCK, CURSOR_BEAM, CURSOR_UNDERLINE, NUM_OF_CURSOR_SHAPES } CursorShape;
#define ERROR_PREFIX "[PARSE ERROR]" #define ERROR_PREFIX "[PARSE ERROR]"
@ -38,15 +39,12 @@ typedef enum MouseShapes { BEAM, HAND, ARROW } MouseShape;
#define MAX_CHILDREN 256 #define MAX_CHILDREN 256
#define BLANK_CHAR 0 #define BLANK_CHAR 0
#define CHAR_MASK 0xFFFFFF #define ATTRS_MASK_WITHOUT_WIDTH 0xFFC
#define ATTRS_SHIFT 24
#define ATTRS_MASK_WITHOUT_WIDTH 0xFC000000
#define WIDTH_MASK 3 #define WIDTH_MASK 3
#define DECORATION_SHIFT 2 #define DECORATION_SHIFT 2
#define DECORATION_MASK 3 #define DECORATION_MASK 3
#define BOLD_SHIFT 4 #define BOLD_SHIFT 4
#define ITALIC_SHIFT 5 #define ITALIC_SHIFT 5
#define POSCHAR_MASK 0x30FFFFFF
#define REVERSE_SHIFT 6 #define REVERSE_SHIFT 6
#define STRIKE_SHIFT 7 #define STRIKE_SHIFT 7
#define COL_MASK 0xFFFFFFFF #define COL_MASK 0xFFFFFFFF
@ -56,14 +54,14 @@ typedef enum MouseShapes { BEAM, HAND, ARROW } MouseShape;
#define UTF8_REJECT 1 #define UTF8_REJECT 1
#define UNDERCURL_CODE 6 #define UNDERCURL_CODE 6
#define DECORATION_FG_CODE 58 #define DECORATION_FG_CODE 58
#define CHAR_IS_BLANK(ch) ((ch & CHAR_MASK) == 32 || (ch & CHAR_MASK) == 0) #define CHAR_IS_BLANK(ch) ((ch) == 32 || (ch) == 0)
#define FG 1 #define FG 1
#define BG 2 #define BG 2
#define CURSOR_TO_ATTRS(c, w) \ #define CURSOR_TO_ATTRS(c, w) \
((w) | (((c->decoration & 3) << DECORATION_SHIFT) | ((c->bold & 1) << BOLD_SHIFT) | \ ((w) | (((c->decoration & 3) << DECORATION_SHIFT) | ((c->bold & 1) << BOLD_SHIFT) | \
((c->italic & 1) << ITALIC_SHIFT) | ((c->reverse & 1) << REVERSE_SHIFT) | ((c->strikethrough & 1) << STRIKE_SHIFT))) << ATTRS_SHIFT ((c->italic & 1) << ITALIC_SHIFT) | ((c->reverse & 1) << REVERSE_SHIFT) | ((c->strikethrough & 1) << STRIKE_SHIFT)))
#define ATTRS_TO_CURSOR(a, c) \ #define ATTRS_TO_CURSOR(a, c) \
c->decoration = (a >> DECORATION_SHIFT) & 3; c->bold = (a >> BOLD_SHIFT) & 1; c->italic = (a >> ITALIC_SHIFT) & 1; \ c->decoration = (a >> DECORATION_SHIFT) & 3; c->bold = (a >> BOLD_SHIFT) & 1; c->italic = (a >> ITALIC_SHIFT) & 1; \
@ -126,6 +124,7 @@ typedef struct {
color_type fg, bg, decoration_fg; color_type fg, bg, decoration_fg;
combining_type cc; combining_type cc;
sprite_index sprite_x, sprite_y, sprite_z; sprite_index sprite_x, sprite_y, sprite_z;
attrs_type attrs;
} Cell; } Cell;
typedef struct { typedef struct {
@ -280,8 +279,9 @@ PyTypeObject ChildMonitor_Type;
for(index_type __i__ = (at); __i__ < (line)->xnum - (num); __i__++) { \ for(index_type __i__ = (at); __i__ < (line)->xnum - (num); __i__++) { \
COPY_CELL(line, __i__ + (num), line, __i__) \ COPY_CELL(line, __i__ + (num), line, __i__) \
} \ } \
if ((((line)->cells[(at)].ch >> ATTRS_SHIFT) & WIDTH_MASK) != 1) { \ if ((((line)->cells[(at)].attrs) & WIDTH_MASK) != 1) { \
(line)->cells[(at)].ch = (1 << ATTRS_SHIFT) | BLANK_CHAR; \ (line)->cells[(at)].ch = BLANK_CHAR; \
(line)->cells[(at)].attrs = BLANK_CHAR ? 1 : 0; \
clear_sprite_position((line)->cells[(at)]); \ clear_sprite_position((line)->cells[(at)]); \
} }

View File

@ -116,7 +116,7 @@ line(LineBuf *self, PyObject *y) {
unsigned int unsigned int
linebuf_char_width_at(LineBuf *self, index_type x, index_type y) { linebuf_char_width_at(LineBuf *self, index_type x, index_type y) {
return (lineptr(self, self->line_map[y])[x].ch >> ATTRS_SHIFT) & WIDTH_MASK; return (lineptr(self, self->line_map[y])[x].attrs) & WIDTH_MASK;
} }
void void
@ -453,7 +453,7 @@ linebuf_rewrap(LineBuf *self, LineBuf *other, int *cursor_y_out, HistoryBuf *his
for (first = self->ynum - 1; true; first--) { for (first = self->ynum - 1; true; first--) {
Cell *cells = lineptr(self, first); Cell *cells = lineptr(self, first);
for(i = 0; i < self->xnum; i++) { for(i = 0; i < self->xnum; i++) {
if ((cells[i].ch & CHAR_MASK) != BLANK_CHAR) { is_empty = false; break; } if ((cells[i].ch) != BLANK_CHAR) { is_empty = false; break; }
} }
if (!is_empty || !first) break; if (!is_empty || !first) break;
} }

View File

@ -27,7 +27,7 @@ unsigned int
line_length(Line *self) { line_length(Line *self) {
index_type last = self->xnum - 1; index_type last = self->xnum - 1;
for (index_type i = 0; i < self->xnum; i++) { for (index_type i = 0; i < self->xnum; i++) {
if ((self->cells[last - i].ch & CHAR_MASK) != BLANK_CHAR) return self->xnum - i; if ((self->cells[last - i].ch) != BLANK_CHAR) return self->xnum - i;
} }
return 0; return 0;
} }
@ -68,7 +68,7 @@ find_colon_slash(Line *self, index_type x, index_type limit) {
limit = MAX(2, limit); limit = MAX(2, limit);
if (pos < limit) return 0; if (pos < limit) return 0;
do { do {
char_type ch = self->cells[pos].ch & CHAR_MASK; char_type ch = self->cells[pos].ch;
if (!is_url_char(ch)) return false; if (!is_url_char(ch)) return false;
switch(state) { switch(state) {
case ANY: case ANY:
@ -92,7 +92,7 @@ prefix_matches(Line *self, index_type at, const char* prefix, index_type prefix_
if (prefix_len > at) return false; if (prefix_len > at) return false;
index_type p, i; index_type p, i;
for (p = at - prefix_len, i = 0; i < prefix_len && p < self->xnum; i++, p++) { for (p = at - prefix_len, i = 0; i < prefix_len && p < self->xnum; i++, p++) {
if ((self->cells[p].ch & CHAR_MASK) != (unsigned char)prefix[i]) return false; if ((self->cells[p].ch) != (unsigned char)prefix[i]) return false;
} }
return i == prefix_len; return i == prefix_len;
} }
@ -117,7 +117,7 @@ static inline bool
has_url_beyond(Line *self, index_type x) { has_url_beyond(Line *self, index_type x) {
if (self->xnum <= x + MIN_URL_LEN + 3) return false; if (self->xnum <= x + MIN_URL_LEN + 3) return false;
for (index_type i = x; i < MIN(x + MIN_URL_LEN + 3, self->xnum); i++) { for (index_type i = x; i < MIN(x + MIN_URL_LEN + 3, self->xnum); i++) {
if (!is_url_char(self->cells[i].ch & CHAR_MASK)) return false; if (!is_url_char(self->cells[i].ch)) return false;
} }
return true; return true;
} }
@ -143,9 +143,9 @@ index_type
line_url_end_at(Line *self, index_type x) { line_url_end_at(Line *self, index_type x) {
index_type ans = x; index_type ans = x;
if (x >= self->xnum || self->xnum <= MIN_URL_LEN + 3) return 0; if (x >= self->xnum || self->xnum <= MIN_URL_LEN + 3) return 0;
while (ans < self->xnum && is_url_char(self->cells[ans].ch & CHAR_MASK)) ans++; while (ans < self->xnum && is_url_char(self->cells[ans].ch)) ans++;
ans--; ans--;
while (ans > x && can_strip_from_end_of_url(self->cells[ans].ch & CHAR_MASK)) ans--; while (ans > x && can_strip_from_end_of_url(self->cells[ans].ch)) ans--;
return ans; return ans;
} }
@ -167,7 +167,7 @@ static PyObject*
text_at(Line* self, Py_ssize_t xval) { text_at(Line* self, Py_ssize_t xval) {
#define text_at_doc "[x] -> Return the text in the specified cell" #define text_at_doc "[x] -> Return the text in the specified cell"
if (xval >= self->xnum) { PyErr_SetString(PyExc_IndexError, "Column number out of bounds"); return NULL; } if (xval >= self->xnum) { PyErr_SetString(PyExc_IndexError, "Column number out of bounds"); return NULL; }
return line_text_at(self->cells[xval].ch & CHAR_MASK, self->cells[xval].cc); return line_text_at(self->cells[xval].ch, self->cells[xval].cc);
} }
PyObject* PyObject*
@ -177,7 +177,7 @@ unicode_in_range(Line *self, index_type start, index_type limit, bool include_cc
if (leading_char) buf[n++] = leading_char; if (leading_char) buf[n++] = leading_char;
char_type previous_width = 0; char_type previous_width = 0;
for(index_type i = start; i < limit && n < sizeof(buf)/sizeof(buf[0]) - 4; i++) { for(index_type i = start; i < limit && n < sizeof(buf)/sizeof(buf[0]) - 4; i++) {
char_type ch = self->cells[i].ch & CHAR_MASK; char_type ch = self->cells[i].ch;
if (ch == 0) { if (ch == 0) {
if (previous_width == 2) { previous_width = 0; continue; }; if (previous_width == 2) { previous_width = 0; continue; };
ch = ' '; ch = ' ';
@ -192,7 +192,7 @@ unicode_in_range(Line *self, index_type start, index_type limit, bool include_cc
if (cc2) buf[n++] = cc2; if (cc2) buf[n++] = cc2;
} }
} }
previous_width = (self->cells[i].ch >> ATTRS_SHIFT) & WIDTH_MASK; previous_width = self->cells[i].attrs & WIDTH_MASK;
} }
return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buf, n); return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buf, n);
} }
@ -247,7 +247,7 @@ line_as_ansi(Line *self, Py_UCS4 *buf, index_type buflen) {
WRITE_SGR(0); WRITE_SGR(0);
for (index_type pos=0; pos < limit; pos++) { for (index_type pos=0; pos < limit; pos++) {
char_type attrs = self->cells[pos].ch >> ATTRS_SHIFT, ch = self->cells[pos].ch & CHAR_MASK; char_type attrs = self->cells[pos].attrs, ch = self->cells[pos].ch;
if (ch == 0) { if (ch == 0) {
if (previous_width == 2) { previous_width = 0; continue; } if (previous_width == 2) { previous_width = 0; continue; }
ch = ' '; ch = ' ';
@ -319,7 +319,7 @@ width(Line *self, PyObject *val) {
#define width_doc "width(x) -> the width of the character at x" #define width_doc "width(x) -> the width of the character at x"
unsigned long x = PyLong_AsUnsignedLong(val); unsigned long x = PyLong_AsUnsignedLong(val);
if (x >= self->xnum) { PyErr_SetString(PyExc_ValueError, "Out of bounds"); return NULL; } if (x >= self->xnum) { PyErr_SetString(PyExc_ValueError, "Out of bounds"); return NULL; }
char_type attrs = self->cells[x].ch >> ATTRS_SHIFT; char_type attrs = self->cells[x].attrs;
return PyLong_FromUnsignedLong((unsigned long) (attrs & WIDTH_MASK)); return PyLong_FromUnsignedLong((unsigned long) (attrs & WIDTH_MASK));
} }
@ -375,7 +375,8 @@ set_text(Line* self, PyObject *args) {
color_type dfg = cursor->decoration_fg & COL_MASK; color_type dfg = cursor->decoration_fg & COL_MASK;
for (index_type i = cursor->x; offset < limit && i < self->xnum; i++, offset++) { for (index_type i = cursor->x; offset < limit && i < self->xnum; i++, offset++) {
self->cells[i].ch = (PyUnicode_READ(kind, buf, offset) & CHAR_MASK) | attrs; self->cells[i].ch = (PyUnicode_READ(kind, buf, offset));
self->cells[i].attrs = attrs;
self->cells[i].fg = fg; self->cells[i].fg = fg;
self->cells[i].bg = bg; self->cells[i].bg = bg;
self->cells[i].decoration_fg = dfg; self->cells[i].decoration_fg = dfg;
@ -399,7 +400,7 @@ cursor_from(Line* self, PyObject *args) {
ans = alloc_cursor(); ans = alloc_cursor();
if (ans == NULL) { PyErr_NoMemory(); return NULL; } if (ans == NULL) { PyErr_NoMemory(); return NULL; }
ans->x = x; ans->y = y; ans->x = x; ans->y = y;
char_type attrs = self->cells[x].ch >> ATTRS_SHIFT; char_type attrs = self->cells[x].attrs;
ATTRS_TO_CURSOR(attrs, ans); ATTRS_TO_CURSOR(attrs, ans);
ans->fg = self->cells[x].fg; ans->bg = self->cells[x].bg; ans->fg = self->cells[x].fg; ans->bg = self->cells[x].bg;
ans->decoration_fg = self->cells[x].decoration_fg & COL_MASK; ans->decoration_fg = self->cells[x].decoration_fg & COL_MASK;
@ -408,12 +409,12 @@ cursor_from(Line* self, PyObject *args) {
} }
void void
line_clear_text(Line *self, unsigned int at, unsigned int num, int ch) { line_clear_text(Line *self, unsigned int at, unsigned int num, char_type ch) {
const char_type repl = ((char_type)ch & CHAR_MASK) | ( (ch ? 1 : 0) << ATTRS_SHIFT); attrs_type width = ch ? 1 : 0;
#define PREFIX \ #define PREFIX \
for (index_type i = at; i < MIN(self->xnum, at + num); i++) { \ for (index_type i = at; i < MIN(self->xnum, at + num); i++) { \
self->cells[i].ch = (self->cells[i].ch & ATTRS_MASK_WITHOUT_WIDTH) | repl; \ self->cells[i].ch = ch; self->cells[i].cc = 0; \
self->cells[i].cc = 0; self->cells[i].attrs = (self->cells[i].attrs & ATTRS_MASK_WITHOUT_WIDTH) | width;
if (CHAR_IS_BLANK(ch)) { if (CHAR_IS_BLANK(ch)) {
PREFIX PREFIX
clear_sprite_position(self->cells[i]); } clear_sprite_position(self->cells[i]); }
@ -438,16 +439,17 @@ line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num,
char_type attrs = CURSOR_TO_ATTRS(cursor, 1); char_type attrs = CURSOR_TO_ATTRS(cursor, 1);
color_type fg = (cursor->fg & COL_MASK), bg = (cursor->bg & COL_MASK); color_type fg = (cursor->fg & COL_MASK), bg = (cursor->bg & COL_MASK);
color_type dfg = cursor->decoration_fg & COL_MASK; color_type dfg = cursor->decoration_fg & COL_MASK;
if (!clear_char) attrs = ((attrs >> ATTRS_SHIFT) & ~WIDTH_MASK) << ATTRS_SHIFT; if (!clear_char) attrs = attrs & ATTRS_MASK_WITHOUT_WIDTH;
for (index_type i = at; i < self->xnum && i < at + num; i++) { for (index_type i = at; i < self->xnum && i < at + num; i++) {
if (clear_char) { if (clear_char) {
self->cells[i].ch = BLANK_CHAR | attrs; self->cells[i].ch = BLANK_CHAR;
self->cells[i].cc = 0; self->cells[i].cc = 0;
self->cells[i].attrs = attrs;
clear_sprite_position(self->cells[i]); clear_sprite_position(self->cells[i]);
} else { } else {
char_type w = ((self->cells[i].ch >> ATTRS_SHIFT) & WIDTH_MASK) << ATTRS_SHIFT; attrs_type w = self->cells[i].attrs & WIDTH_MASK;
self->cells[i].ch = (self->cells[i].ch & CHAR_MASK) | attrs | w; self->cells[i].attrs = attrs | w;
set_sprite_position_at(i); set_sprite_position_at(i);
} }
self->cells[i].fg = fg; self->cells[i].bg = bg; self->cells[i].fg = fg; self->cells[i].bg = bg;
@ -471,9 +473,10 @@ void line_right_shift(Line *self, unsigned int at, unsigned int num) {
COPY_SELF_CELL(i - num, i) COPY_SELF_CELL(i - num, i)
} }
// Check if a wide character was split at the right edge // Check if a wide character was split at the right edge
char_type w = (self->cells[self->xnum - 1].ch >> ATTRS_SHIFT) & WIDTH_MASK; char_type w = (self->cells[self->xnum - 1].attrs) & WIDTH_MASK;
if (w != 1) { if (w != 1) {
self->cells[self->xnum - 1].ch = ((BLANK_CHAR ? 1 : 0) << ATTRS_SHIFT) | BLANK_CHAR; self->cells[self->xnum - 1].ch = BLANK_CHAR;
self->cells[self->xnum - 1].attrs = BLANK_CHAR ? 1 : 0;
clear_sprite_position(self->cells[self->xnum - 1]); clear_sprite_position(self->cells[self->xnum - 1]);
} }
} }
@ -508,16 +511,15 @@ left_shift(Line *self, PyObject *args) {
void void
line_set_char(Line *self, unsigned int at, uint32_t ch, unsigned int width, Cursor *cursor, bool is_second) { line_set_char(Line *self, unsigned int at, uint32_t ch, unsigned int width, Cursor *cursor, bool is_second) {
char_type attrs;
if (cursor == NULL) { if (cursor == NULL) {
attrs = (((self->cells[at].ch >> ATTRS_SHIFT) & ~WIDTH_MASK) | (width & WIDTH_MASK)) << ATTRS_SHIFT; self->cells[at].attrs = (self->cells[at].attrs & ATTRS_MASK_WITHOUT_WIDTH) | width;
} else { } else {
attrs = CURSOR_TO_ATTRS(cursor, width & WIDTH_MASK); self->cells[at].attrs = CURSOR_TO_ATTRS(cursor, width & WIDTH_MASK);
self->cells[at].fg = (cursor->fg & COL_MASK); self->cells[at].fg = (cursor->fg & COL_MASK);
self->cells[at].bg = (cursor->bg & COL_MASK); self->cells[at].bg = (cursor->bg & COL_MASK);
self->cells[at].decoration_fg = cursor->decoration_fg & COL_MASK; self->cells[at].decoration_fg = cursor->decoration_fg & COL_MASK;
} }
self->cells[at].ch = (ch & CHAR_MASK) | attrs; self->cells[at].ch = ch;
self->cells[at].cc = 0; self->cells[at].cc = 0;
if (!is_second && CHAR_IS_BLANK(ch)) { clear_sprite_position(self->cells[at]); } if (!is_second && CHAR_IS_BLANK(ch)) { clear_sprite_position(self->cells[at]); }
else set_sprite_position_at(at); else set_sprite_position_at(at);

View File

@ -22,10 +22,11 @@ update_sprites_in_line(Cell *cells, index_type xnum) {
static inline void static inline void
set_attribute_on_line(Cell *cells, uint32_t shift, uint32_t val, index_type xnum) { set_attribute_on_line(Cell *cells, uint32_t shift, uint32_t val, index_type xnum) {
uint32_t mask = shift == DECORATION_SHIFT ? 3 : 1; // Set a single attribute on all cells in the line
uint32_t aval = (val & mask) << (ATTRS_SHIFT + shift); attrs_type mask = shift == DECORATION_SHIFT ? 3 : 1;
mask = ~(mask << (ATTRS_SHIFT + shift)); attrs_type aval = (val & mask) << shift;
for (index_type i = 0; i < xnum; i++) cells[i].ch = (cells[i].ch & mask) | aval; mask = ~(mask << shift);
for (index_type i = 0; i < xnum; i++) cells[i].attrs = (cells[i].attrs & mask) | aval;
if (shift == BOLD_SHIFT || shift == ITALIC_SHIFT) update_sprites_in_line(cells, xnum); if (shift == BOLD_SHIFT || shift == ITALIC_SHIFT) update_sprites_in_line(cells, xnum);
} }
@ -42,21 +43,22 @@ copy_line(const Line *src, Line *dest) {
static inline void static inline void
clear_chars_in_line(Cell *cells, index_type xnum, char_type ch) { clear_chars_in_line(Cell *cells, index_type xnum, char_type ch) {
// Clear only the char part of each cell, the rest must have been cleared by a memset or similar // Clear only the char part of each cell, the rest must have been cleared by a memset or similar
char_type c = (1 << ATTRS_SHIFT) | ch; if (ch) {
for (index_type i = 0; i < xnum; i++) cells[i].ch = c; for (index_type i = 0; i < xnum; i++) { cells[i].ch = ch; cells[i].attrs = 1; }
}
} }
static inline index_type static inline index_type
xlimit_for_line(Line *line) { xlimit_for_line(Line *line) {
index_type xlimit = line->xnum; index_type xlimit = line->xnum;
if (BLANK_CHAR == 0) { if (BLANK_CHAR == 0) {
while (xlimit > 0 && (line->cells[xlimit - 1].ch & CHAR_MASK) == BLANK_CHAR) xlimit--; while (xlimit > 0 && (line->cells[xlimit - 1].ch) == BLANK_CHAR) xlimit--;
} }
return xlimit; return xlimit;
} }
PyObject* line_text_at(char_type, combining_type); PyObject* line_text_at(char_type, combining_type);
void line_clear_text(Line *self, unsigned int at, unsigned int num, int ch); void line_clear_text(Line *self, unsigned int at, unsigned int num, char_type ch);
void line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num, bool clear_char); void line_apply_cursor(Line *self, Cursor *cursor, unsigned int at, unsigned int num, bool clear_char);
void line_set_char(Line *, unsigned int , uint32_t , unsigned int , Cursor *, bool); void line_set_char(Line *, unsigned int , uint32_t , unsigned int , Cursor *, bool);
void line_right_shift(Line *, unsigned int , unsigned int ); void line_right_shift(Line *, unsigned int , unsigned int );

View File

@ -59,7 +59,7 @@ rewrap_inner(BufType *src, BufType *dest, const index_type src_limit, HistoryBuf
src_x_limit = src->xnum; src_x_limit = src->xnum;
if (!src_line_is_continued) { if (!src_line_is_continued) {
// Trim trailing blanks since there is a hard line break at the end of this line // Trim trailing blanks since there is a hard line break at the end of this line
while(src_x_limit && (src->line->cells[src_x_limit - 1].ch & CHAR_MASK) == BLANK_CHAR) src_x_limit--; while(src_x_limit && (src->line->cells[src_x_limit - 1].ch) == BLANK_CHAR) src_x_limit--;
} }
while (src_x < src_x_limit) { while (src_x < src_x_limit) {

View File

@ -1366,7 +1366,7 @@ screen_selection_range_for_word(Screen *self, index_type x, index_type y, index_
if (y >= self->lines || x >= self->columns) return false; if (y >= self->lines || x >= self->columns) return false;
index_type start, end; index_type start, end;
Line *line = visual_line_(self, y); Line *line = visual_line_(self, y);
#define is_ok(x) (is_word_char((line->cells[x].ch) & CHAR_MASK) || is_opt_word_char(line->cells[x].ch & CHAR_MASK)) #define is_ok(x) (is_word_char((line->cells[x].ch)) || is_opt_word_char(line->cells[x].ch))
if (!is_ok(x)) { if (!is_ok(x)) {
start = x; end = x + 1; start = x; end = x + 1;
} else { } else {

View File

@ -591,8 +591,7 @@ create_cell_vao() {
#define A1(name, size, dtype, offset) A(name, size, dtype, (void*)(offsetof(Cell, offset)), sizeof(Cell)) #define A1(name, size, dtype, offset) A(name, size, dtype, (void*)(offsetof(Cell, offset)), sizeof(Cell))
add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER); add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER);
A1(text_attrs, 1, GL_UNSIGNED_INT, ch); A1(sprite_coords, 4, GL_UNSIGNED_SHORT, sprite_x);
A1(sprite_coords, 3, GL_UNSIGNED_SHORT, sprite_x);
A1(colors, 3, GL_UNSIGNED_INT, fg); A1(colors, 3, GL_UNSIGNED_INT, fg);
add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER); add_buffer_to_vao(vao_idx, GL_ARRAY_BUFFER);
A(is_selected, 1, GL_FLOAT, NULL, 0); A(is_selected, 1, GL_FLOAT, NULL, 0);

View File

@ -15,6 +15,7 @@ struct SpritePosition {
sprite_index x, y, z; sprite_index x, y, z;
char_type ch; char_type ch;
combining_type cc; combining_type cc;
bool bold, italic;
bool is_second; bool is_second;
bool filled; bool filled;
bool rendered; bool rendered;
@ -88,15 +89,15 @@ do_increment(int *error) {
} }
SpritePosition* SpritePosition*
sprite_map_position_for(char_type ch, combining_type cc, bool is_second, int *error) { sprite_map_position_for(char_type ch, attrs_type attrs, combining_type cc, bool is_second, int *error) {
char_type pos_char = ch & POSCHAR_MASK; // Includes only the char and bold and italic bits uint8_t bold_italic = (attrs >> BOLD_SHIFT) & 3;
unsigned int idx = ((ch >> (ATTRS_SHIFT - 4)) & 0x300) | (ch & 0xFF); // Includes only italic, bold and lowest byte of ch unsigned int idx = (ch & 0xFF) | (bold_italic << 8); // Only bold italic bits and lowest byte of char
SpritePosition *s = &(sprite_map.cache[idx]); SpritePosition *s = &(sprite_map.cache[idx]);
// Optimize for the common case of an ASCII char already in the cache // Optimize for the common case of an ASCII char already in the cache
if (LIKELY(s->ch == pos_char && s->filled && s->cc == cc && s->is_second == is_second)) return s; // Cache hit if (LIKELY(s->ch == ch && s->filled && s->cc == cc && s->is_second == is_second)) return s; // Cache hit
while(true) { while(true) {
if (s->filled) { if (s->filled) {
if (s->ch == pos_char && s->cc == cc && s->is_second == is_second) return s; // Cache hit if (s->ch == ch && s->cc == cc && s->is_second == is_second) return s; // Cache hit
} else { } else {
break; break;
} }
@ -106,11 +107,13 @@ sprite_map_position_for(char_type ch, combining_type cc, bool is_second, int *er
} }
s = s->next; s = s->next;
} }
s->ch = pos_char; s->ch = ch;
s->cc = cc; s->cc = cc;
s->is_second = is_second; s->is_second = is_second;
s->filled = true; s->filled = true;
s->rendered = false; s->rendered = false;
s->bold = bold_italic & 1;
s->italic = bold_italic >> 1;
s->x = sprite_map.x; s->y = sprite_map.y; s->z = sprite_map.z; s->x = sprite_map.x; s->y = sprite_map.y; s->z = sprite_map.z;
do_increment(error); do_increment(error);
sprite_map.dirty = true; sprite_map.dirty = true;
@ -122,10 +125,10 @@ void
set_sprite_position(Cell *cell, Cell *previous_cell) { set_sprite_position(Cell *cell, Cell *previous_cell) {
SpritePosition *sp; SpritePosition *sp;
static int error; static int error;
if (UNLIKELY(previous_cell != NULL && ((previous_cell->ch >> ATTRS_SHIFT) & WIDTH_MASK) == 2)) { if (UNLIKELY(previous_cell != NULL && ((previous_cell->attrs) & WIDTH_MASK) == 2)) {
sp = sprite_map_position_for(previous_cell->ch, 0, true, &error); sp = sprite_map_position_for(previous_cell->ch, previous_cell->attrs, 0, true, &error);
} else { } else {
sp = sprite_map_position_for(cell->ch, cell->cc, false, &error); sp = sprite_map_position_for(cell->ch, cell->attrs, cell->cc, false, &error);
} }
cell->sprite_x = sp->x; cell->sprite_x = sp->x;
cell->sprite_y = sp->y; cell->sprite_y = sp->y;
@ -178,12 +181,13 @@ sprite_map_current_layout(unsigned int *x, unsigned int *y, unsigned int *z) {
PyObject* PyObject*
sprite_position_for(PyObject UNUSED *self, PyObject *args) { sprite_position_for(PyObject UNUSED *self, PyObject *args) {
#define position_for_doc "position_for(ch, cc, is_second) -> x, y, z the sprite position for the specified text" #define sprite_position_for_doc "sprite_position_for(ch, cc, is_second, attrs) -> x, y, z the sprite position for the specified text"
unsigned long ch = 0; unsigned long ch = 0;
unsigned long long cc = 0; unsigned long long cc = 0;
unsigned int attrs = 1;
int is_second = 0, error = 0; int is_second = 0, error = 0;
if (!PyArg_ParseTuple(args, "|kKp", &ch, &cc, &is_second)) return NULL; if (!PyArg_ParseTuple(args, "|kKpI", &ch, &cc, &is_second, &attrs)) return NULL;
SpritePosition *pos = sprite_map_position_for(ch, cc, is_second, &error); SpritePosition *pos = sprite_map_position_for(ch, attrs, cc, is_second, &error);
if (pos == NULL) { sprite_map_set_error(error); return NULL; } if (pos == NULL) { sprite_map_set_error(error); return NULL; }
return Py_BuildValue("III", pos->x, pos->y, pos->z); return Py_BuildValue("III", pos->x, pos->y, pos->z);
} }
@ -197,10 +201,8 @@ render_dirty_sprites(void (*render)(PyObject*, bool, bool, bool, sprite_index, s
SpritePosition *sp = &(sprite_map.cache[i]); SpritePosition *sp = &(sprite_map.cache[i]);
do { do {
if (sp->filled && !sp->rendered) { if (sp->filled && !sp->rendered) {
PyObject *text = line_text_at(sp->ch & CHAR_MASK, sp->cc); PyObject *text = line_text_at(sp->ch, sp->cc);
char_type attrs = sp->ch >> ATTRS_SHIFT; render(text, sp->bold, sp->italic, sp->is_second, sp->x, sp->y, sp->z);
bool bold = (attrs >> BOLD_SHIFT) & 1, italic = (attrs >> ITALIC_SHIFT) & 1;
render(text, bold, italic, sp->is_second, sp->x, sp->y, sp->z);
Py_CLEAR(text); Py_CLEAR(text);
sp->rendered = true; sp->rendered = true;
} }