ui/compositor: add redraws needed due to intersected doublewidth chars.

This commit is contained in:
Björn Linse
2019-01-24 21:37:38 +01:00
parent 2405cf8255
commit 69bdc4f072
9 changed files with 99 additions and 68 deletions

View File

@@ -461,7 +461,7 @@ static void remote_ui_put(UI *ui, const char *cell)
static void remote_ui_raw_line(UI *ui, Integer grid, Integer row, static void remote_ui_raw_line(UI *ui, Integer grid, Integer row,
Integer startcol, Integer endcol, Integer startcol, Integer endcol,
Integer clearcol, Integer clearattr, Integer clearcol, Integer clearattr,
Boolean wrap, const schar_T *chunk, LineFlags flags, const schar_T *chunk,
const sattr_T *attrs) const sattr_T *attrs)
{ {
UIData *data = ui->data; UIData *data = ui->data;

View File

@@ -92,7 +92,7 @@ void grid_destroy(Integer grid)
// translate this in to the public grid_line format. // translate this in to the public grid_line format.
void raw_line(Integer grid, Integer row, Integer startcol, void raw_line(Integer grid, Integer row, Integer startcol,
Integer endcol, Integer clearcol, Integer clearattr, Integer endcol, Integer clearcol, Integer clearattr,
Boolean wrap, const schar_T *chunk, const sattr_T *attrs) LineFlags flags, const schar_T *chunk, const sattr_T *attrs)
FUNC_API_NOEXPORT FUNC_API_COMPOSITOR_IMPL; FUNC_API_NOEXPORT FUNC_API_COMPOSITOR_IMPL;
void event(char *name, Array args, bool *args_consumed) void event(char *name, Array args, bool *args_consumed)

View File

@@ -363,7 +363,7 @@ void pum_redraw(void)
if (!pum_grid.chars if (!pum_grid.chars
|| pum_grid.Rows != pum_height || pum_grid.Columns != grid_width) { || pum_grid.Rows != pum_height || pum_grid.Columns != grid_width) {
grid_alloc(&pum_grid, pum_height, grid_width, !moved); grid_alloc(&pum_grid, pum_height, grid_width, !moved, false);
ui_call_grid_resize(pum_grid.handle, pum_grid.Columns, pum_grid.Rows); ui_call_grid_resize(pum_grid.handle, pum_grid.Columns, pum_grid.Rows);
} else if (moved) { } else if (moved) {
grid_invalidate(&pum_grid); grid_invalidate(&pum_grid);

View File

@@ -5316,7 +5316,7 @@ void grid_puts(ScreenGrid *grid, char_u *text, int row, int col, int attr)
} }
static int put_dirty_row = -1; static int put_dirty_row = -1;
static int put_dirty_first = -1; static int put_dirty_first = INT_MAX;
static int put_dirty_last = 0; static int put_dirty_last = 0;
/// Start a group of screen_puts_len calls that builds a single screen line. /// Start a group of screen_puts_len calls that builds a single screen line.
@@ -5347,8 +5347,6 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row,
int prev_c = 0; /* previous Arabic character */ int prev_c = 0; /* previous Arabic character */
int pc, nc, nc1; int pc, nc, nc1;
int pcc[MAX_MCO]; int pcc[MAX_MCO];
int force_redraw_this;
int force_redraw_next = FALSE;
int need_redraw; int need_redraw;
bool do_flush = false; bool do_flush = false;
@@ -5371,16 +5369,10 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row,
/* When drawing over the right halve of a double-wide char clear out the /* When drawing over the right halve of a double-wide char clear out the
* left halve. Only needed in a terminal. */ * left halve. Only needed in a terminal. */
if (col > 0 && col < grid->Columns && grid_fix_col(grid, col, row) != col) { if (grid != &default_grid && col == 0 && grid_invalid_row(grid, row)) {
schar_from_ascii(grid->chars[off - 1], ' ');
grid->attrs[off - 1] = 0;
// redraw the previous cell, make it empty // redraw the previous cell, make it empty
if (put_dirty_first == -1) { put_dirty_first = -1;
put_dirty_first = col-1; put_dirty_last = MAX(put_dirty_last, 1);
}
put_dirty_last = col+1;
// force the cell at "col" to be redrawn
force_redraw_next = true;
} }
max_off = grid->line_offset[row] + grid->Columns; max_off = grid->line_offset[row] + grid->Columns;
@@ -5428,15 +5420,12 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row,
schar_from_cc(buf, u8c, u8cc); schar_from_cc(buf, u8c, u8cc);
force_redraw_this = force_redraw_next;
force_redraw_next = FALSE;
need_redraw = schar_cmp(grid->chars[off], buf) need_redraw = schar_cmp(grid->chars[off], buf)
|| (mbyte_cells == 2 && grid->chars[off + 1][0] != 0) || (mbyte_cells == 2 && grid->chars[off + 1][0] != 0)
|| grid->attrs[off] != attr || grid->attrs[off] != attr
|| exmode_active; || exmode_active;
if (need_redraw || force_redraw_this) { if (need_redraw) {
// When at the end of the text and overwriting a two-cell // When at the end of the text and overwriting a two-cell
// character with a one-cell character, need to clear the next // character with a one-cell character, need to clear the next
// cell. Also when overwriting the left halve of a two-cell char // cell. Also when overwriting the left halve of a two-cell char
@@ -5460,9 +5449,7 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row,
grid->chars[off + 1][0] = 0; grid->chars[off + 1][0] = 0;
grid->attrs[off + 1] = attr; grid->attrs[off + 1] = attr;
} }
if (put_dirty_first == -1 || col < put_dirty_first) { put_dirty_first = MIN(put_dirty_first, col);
put_dirty_first = col;
}
put_dirty_last = MAX(put_dirty_last, col+mbyte_cells); put_dirty_last = MAX(put_dirty_last, col+mbyte_cells);
} }
@@ -5491,14 +5478,14 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row,
void grid_puts_line_flush(ScreenGrid *grid, bool set_cursor) void grid_puts_line_flush(ScreenGrid *grid, bool set_cursor)
{ {
assert(put_dirty_row != -1); assert(put_dirty_row != -1);
if (put_dirty_first != -1) { if (put_dirty_first < put_dirty_last) {
if (set_cursor) { if (set_cursor) {
ui_grid_cursor_goto(grid->handle, put_dirty_row, ui_grid_cursor_goto(grid->handle, put_dirty_row,
MIN(put_dirty_last, grid->Columns-1)); MIN(put_dirty_last, grid->Columns-1));
} }
ui_line(grid, put_dirty_row, put_dirty_first, put_dirty_last, ui_line(grid, put_dirty_row, put_dirty_first, put_dirty_last,
put_dirty_last, 0, false); put_dirty_last, 0, false);
put_dirty_first = -1; put_dirty_first = INT_MAX;
put_dirty_last = 0; put_dirty_last = 0;
} }
put_dirty_row = -1; put_dirty_row = -1;
@@ -5870,9 +5857,7 @@ void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col,
if (dirty_last > dirty_first) { if (dirty_last > dirty_first) {
// TODO(bfredl): support a cleared suffix even with a batched line? // TODO(bfredl): support a cleared suffix even with a batched line?
if (put_dirty_row == row) { if (put_dirty_row == row) {
if (put_dirty_first == -1 || dirty_first < put_dirty_first) { put_dirty_first = MIN(put_dirty_first, dirty_first);
put_dirty_first = dirty_first;
}
put_dirty_last = MAX(put_dirty_last, dirty_last); put_dirty_last = MAX(put_dirty_last, dirty_last);
} else { } else {
int last = c2 != ' ' ? dirty_last : dirty_first + (c1 != ' '); int last = c2 != ' ' ? dirty_last : dirty_first + (c1 != ' ');
@@ -5958,7 +5943,7 @@ void win_grid_alloc(win_T *wp)
|| grid->Rows != rows || grid->Rows != rows
|| grid->Columns != cols) { || grid->Columns != cols) {
if (want_allocation) { if (want_allocation) {
grid_alloc(grid, rows, cols, true); grid_alloc(grid, rows, cols, true, true);
} else { } else {
// Single grid mode, all rendering will be redirected to default_grid. // Single grid mode, all rendering will be redirected to default_grid.
// Only keep track of the size and offset of the window. // Only keep track of the size and offset of the window.
@@ -6054,7 +6039,7 @@ retry:
// Continuing with the old arrays may result in a crash, because the // Continuing with the old arrays may result in a crash, because the
// size is wrong. // size is wrong.
grid_alloc(&default_grid, Rows, Columns, !doclear); grid_alloc(&default_grid, Rows, Columns, !doclear, true);
StlClickDefinition *new_tab_page_click_defs = xcalloc( StlClickDefinition *new_tab_page_click_defs = xcalloc(
(size_t)Columns, sizeof(*new_tab_page_click_defs)); (size_t)Columns, sizeof(*new_tab_page_click_defs));
@@ -6088,7 +6073,7 @@ retry:
} }
} }
void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy) void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy, bool valid)
{ {
int new_row; int new_row;
ScreenGrid new = *grid; ScreenGrid new = *grid;
@@ -6106,7 +6091,7 @@ void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy)
new.line_offset[new_row] = new_row * new.Columns; new.line_offset[new_row] = new_row * new.Columns;
new.line_wraps[new_row] = false; new.line_wraps[new_row] = false;
grid_clear_line(&new, new.line_offset[new_row], columns, true); grid_clear_line(&new, new.line_offset[new_row], columns, valid);
if (copy) { if (copy) {
// If the screen is not going to be cleared, copy as much as // If the screen is not going to be cleared, copy as much as
@@ -6234,6 +6219,12 @@ void grid_invalidate(ScreenGrid *grid)
(void)memset(grid->attrs, -1, grid->Rows * grid->Columns * sizeof(sattr_T)); (void)memset(grid->attrs, -1, grid->Rows * grid->Columns * sizeof(sattr_T));
} }
bool grid_invalid_row(ScreenGrid *grid, int row)
{
return grid->attrs[grid->line_offset[row]] < 0;
}
/// Copy part of a grid line for vertically split window. /// Copy part of a grid line for vertically split window.
static void linecopy(ScreenGrid *grid, int to, int from, int col, int width) static void linecopy(ScreenGrid *grid, int to, int from, int col, int width)

View File

@@ -1273,7 +1273,7 @@ static void tui_option_set(UI *ui, String name, Object value)
static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol, static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol,
Integer endcol, Integer clearcol, Integer clearattr, Integer endcol, Integer clearcol, Integer clearattr,
Boolean wrap, const schar_T *chunk, LineFlags flags, const schar_T *chunk,
const sattr_T *attrs) const sattr_T *attrs)
{ {
TUIData *data = ui->data; TUIData *data = ui->data;
@@ -1295,7 +1295,8 @@ static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol,
(int)clearattr); (int)clearattr);
} }
if (wrap && ui->width == grid->width && linerow + 1 < grid->height) { if (flags & kLineFlagWrap && ui->width == grid->width
&& linerow + 1 < grid->height) {
// Only do line wrapping if the grid width is equal to the terminal // Only do line wrapping if the grid width is equal to the terminal
// width and the line continuation is within the grid. // width and the line continuation is within the grid.

View File

@@ -315,11 +315,17 @@ void ui_set_ext_option(UI *ui, UIExtension ext, bool active)
void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol, void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol,
int clearattr, bool wrap) int clearattr, bool wrap)
{ {
LineFlags flags = wrap ? kLineFlagWrap : 0;
if (startcol == -1) {
startcol = 0;
flags |= kLineFlagInvalid;
}
size_t off = grid->line_offset[row] + (size_t)startcol; size_t off = grid->line_offset[row] + (size_t)startcol;
ui_call_raw_line(grid->handle, row, startcol, endcol, ui_call_raw_line(grid->handle, row, startcol, endcol, clearcol, clearattr,
clearcol, clearattr, wrap, (const schar_T *)grid->chars + off, flags, (const schar_T *)grid->chars + off,
(const sattr_T *)grid->attrs + off); (const sattr_T *)grid->attrs + off);
if (p_wd) { // 'writedelay': flush & delay each time. if (p_wd) { // 'writedelay': flush & delay each time.
int old_row = cursor_row, old_col = cursor_col; int old_row = cursor_row, old_col = cursor_col;

View File

@@ -34,6 +34,13 @@ EXTERN const char *ui_ext_names[] INIT(= {
typedef struct ui_t UI; typedef struct ui_t UI;
enum {
kLineFlagWrap = 1,
kLineFlagInvalid = 2,
};
typedef int LineFlags;
struct ui_t { struct ui_t {
bool rgb; bool rgb;
bool composed; bool composed;

View File

@@ -153,14 +153,14 @@ static void ui_bridge_raw_line_event(void **argv)
UI *ui = UI(argv[0]); UI *ui = UI(argv[0]);
ui->raw_line(ui, PTR2INT(argv[1]), PTR2INT(argv[2]), PTR2INT(argv[3]), ui->raw_line(ui, PTR2INT(argv[1]), PTR2INT(argv[2]), PTR2INT(argv[3]),
PTR2INT(argv[4]), PTR2INT(argv[5]), PTR2INT(argv[6]), PTR2INT(argv[4]), PTR2INT(argv[5]), PTR2INT(argv[6]),
PTR2INT(argv[7]), argv[8], argv[9]); (LineFlags)PTR2INT(argv[7]), argv[8], argv[9]);
xfree(argv[8]); xfree(argv[8]);
xfree(argv[9]); xfree(argv[9]);
} }
static void ui_bridge_raw_line(UI *ui, Integer grid, Integer row, static void ui_bridge_raw_line(UI *ui, Integer grid, Integer row,
Integer startcol, Integer endcol, Integer startcol, Integer endcol,
Integer clearcol, Integer clearattr, Integer clearcol, Integer clearattr,
Boolean wrap, const schar_T *chunk, LineFlags flags, const schar_T *chunk,
const sattr_T *attrs) const sattr_T *attrs)
{ {
size_t ncol = (size_t)(endcol-startcol); size_t ncol = (size_t)(endcol-startcol);
@@ -168,7 +168,7 @@ static void ui_bridge_raw_line(UI *ui, Integer grid, Integer row,
sattr_T *hl = xmemdup(attrs, ncol * sizeof(sattr_T)); sattr_T *hl = xmemdup(attrs, ncol * sizeof(sattr_T));
UI_BRIDGE_CALL(ui, raw_line, 10, ui, INT2PTR(grid), INT2PTR(row), UI_BRIDGE_CALL(ui, raw_line, 10, ui, INT2PTR(grid), INT2PTR(row),
INT2PTR(startcol), INT2PTR(endcol), INT2PTR(clearcol), INT2PTR(startcol), INT2PTR(endcol), INT2PTR(clearcol),
INT2PTR(clearattr), INT2PTR(wrap), c, hl); INT2PTR(clearattr), INT2PTR(flags), c, hl);
} }
static void ui_bridge_suspend(UI *b) static void ui_bridge_suspend(UI *b)

View File

@@ -217,8 +217,16 @@ static void ui_comp_grid_cursor_goto(UI *ui, Integer grid_handle,
/// do something more efficient (where efficiency means smaller deltas to /// do something more efficient (where efficiency means smaller deltas to
/// the downstream UI.) /// the downstream UI.)
static void compose_line(Integer row, Integer startcol, Integer endcol, static void compose_line(Integer row, Integer startcol, Integer endcol,
bool wrap) LineFlags flags)
{ {
// in case we start on the right half of a double-width char, we need to
// check the left half. But skip it in output if it wasn't doublewidth.
int skip = 0;
if (startcol > 0 && (flags & kLineFlagInvalid)) {
startcol--;
skip = 1;
}
int col = (int)startcol; int col = (int)startcol;
ScreenGrid *grid = NULL; ScreenGrid *grid = NULL;
@@ -247,15 +255,37 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
+ (size_t)(col-grid->comp_col); + (size_t)(col-grid->comp_col);
memcpy(linebuf+(col-startcol), grid->chars+off, n * sizeof(*linebuf)); memcpy(linebuf+(col-startcol), grid->chars+off, n * sizeof(*linebuf));
memcpy(attrbuf+(col-startcol), grid->attrs+off, n * sizeof(*attrbuf)); memcpy(attrbuf+(col-startcol), grid->attrs+off, n * sizeof(*attrbuf));
// Tricky: if overlap caused a doublewidth char to get cut-off, must
// replace the visible half with a space.
if (linebuf[col-startcol][0] == NUL) {
linebuf[col-startcol][0] = ' ';
linebuf[col-startcol][1] = NUL;
} else if (n > 1 && linebuf[col-startcol+1][0] == NUL) {
skip = 0;
}
if (grid->comp_col+grid->Columns > until
&& grid->chars[off+n][0] == NUL) {
linebuf[until-1-startcol][0] = ' ';
linebuf[until-1-startcol][1] = '\0';
if (col == startcol && n == 1) {
skip = 0;
}
}
col = until; col = until;
} }
assert(endcol <= chk_width); assert(endcol <= chk_width);
assert(row < chk_height); assert(row < chk_height);
// TODO(bfredl): too conservative, need check
// grid->line_wraps if grid->Width == Width if (!(grid && grid == &default_grid)) {
wrap = wrap && grid && grid->handle == 1; // TODO(bfredl): too conservative, need check
ui_composed_call_raw_line(1, row, startcol, endcol, endcol, 0, wrap, // grid->line_wraps if grid->Width == Width
(const schar_T *)linebuf, (const sattr_T *)attrbuf); flags = flags & ~kLineFlagWrap;
}
ui_composed_call_raw_line(1, row, startcol+skip, endcol, endcol, 0, flags,
(const schar_T *)linebuf+skip,
(const sattr_T *)attrbuf+skip);
} }
static void compose_area(Integer startrow, Integer endrow, static void compose_area(Integer startrow, Integer endrow,
@@ -264,39 +294,35 @@ static void compose_area(Integer startrow, Integer endrow,
endrow = MIN(endrow, default_grid.Rows); endrow = MIN(endrow, default_grid.Rows);
endcol = MIN(endcol, default_grid.Columns); endcol = MIN(endcol, default_grid.Columns);
for (int r = (int)startrow; r < endrow; r++) { for (int r = (int)startrow; r < endrow; r++) {
compose_line(r, startcol, endcol, false); compose_line(r, startcol, endcol, kLineFlagInvalid);
} }
} }
static void draw_line(ScreenGrid *grid, Integer row, Integer startcol,
Integer endcol, Integer clearcol, Integer clearattr,
bool wrap, const schar_T *chunk, const sattr_T *attrs)
{
row += grid->comp_row;
startcol += grid->comp_col;
endcol += grid->comp_col;
clearcol += grid->comp_col;
wrap = wrap && grid->handle == 1;
assert(clearcol <= default_grid.Columns);
if (kv_size(layers) > grid->comp_index+1) {
compose_line(row, startcol, clearcol, wrap);
} else {
ui_composed_call_raw_line(1, row, startcol, endcol, clearcol, clearattr,
wrap, chunk, attrs);
}
}
static void ui_comp_raw_line(UI *ui, Integer grid, Integer row, static void ui_comp_raw_line(UI *ui, Integer grid, Integer row,
Integer startcol, Integer endcol, Integer startcol, Integer endcol,
Integer clearcol, Integer clearattr, bool wrap, Integer clearcol, Integer clearattr,
const schar_T *chunk, const sattr_T *attrs) LineFlags flags, const schar_T *chunk,
const sattr_T *attrs)
{ {
if (!ui_comp_should_draw() || !ui_comp_set_grid((int)grid)) { if (!ui_comp_should_draw() || !ui_comp_set_grid((int)grid)) {
return; return;
} }
draw_line(curgrid, row, startcol, endcol, clearcol, clearattr, wrap, chunk,
attrs); row += curgrid->comp_row;
startcol += curgrid->comp_col;
endcol += curgrid->comp_col;
clearcol += curgrid->comp_col;
if (curgrid != &default_grid) {
flags = flags & ~kLineFlagWrap;
}
assert(clearcol <= default_grid.Columns);
if (flags & kLineFlagInvalid || kv_size(layers) > curgrid->comp_index+1) {
compose_line(row, startcol, clearcol, flags);
} else {
ui_composed_call_raw_line(1, row, startcol, endcol, clearcol, clearattr,
flags, chunk, attrs);
}
} }
/// The screen is invalid and will soon be cleared /// The screen is invalid and will soon be cleared