Add API to Screen to draw a set of printable ascii chars fast

This commit is contained in:
Kovid Goyal 2023-11-12 10:30:10 +05:30
parent e5675e9537
commit 307acb3f64
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
4 changed files with 69 additions and 9 deletions

View file

@ -647,6 +647,15 @@ line_get_char(Line *self, index_type at) {
return ch;
}
void
line_set_printable_ascii_chars(Line *self, unsigned int at, const uint8_t *chars, unsigned num, GPUCell g, CPUCell cc) {
for (unsigned i = at; i < at + num; i++, chars++) {
cc.ch = *chars;
self->gpu_cells[i] = g;
self->cpu_cells[i] = cc;
}
}
void
line_set_char(Line *self, unsigned int at, uint32_t ch, unsigned int width, Cursor *cursor, hyperlink_id_type hyperlink_id) {
GPUCell *g = self->gpu_cells + at;

View file

@ -86,6 +86,7 @@ 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);
char_type line_get_char(Line *self, index_type at);
void line_set_char(Line *, unsigned int , uint32_t , unsigned int , Cursor *, hyperlink_id_type);
void line_set_printable_ascii_chars(Line *self, unsigned int at, const uint8_t *chars, unsigned num, GPUCell g, CPUCell cc);
void line_right_shift(Line *, unsigned int , unsigned int );
void line_add_combining_char(Line *, uint32_t , unsigned int );
index_type line_url_start_at(Line *self, index_type x);

View file

@ -638,8 +638,7 @@ draw_combining_char(Screen *self, char_type ch) {
}
static void
draw_codepoint(Screen *self, char_type ch, bool from_input_stream) {
if (is_ignored_char(ch)) return;
screen_on_input(Screen *self) {
if (!self->has_activity_since_last_focus && !self->has_focus && self->callbacks != Py_None) {
PyObject *ret = PyObject_CallMethod(self->callbacks, "on_activity_since_last_focus", NULL);
if (ret == NULL) PyErr_Print();
@ -648,6 +647,61 @@ draw_codepoint(Screen *self, char_type ch, bool from_input_stream) {
Py_DECREF(ret);
}
}
}
static void
screen_continue_to_next_line(Screen *self) {
linebuf_set_last_char_as_continuation(self->linebuf, self->cursor->y, true);
self->cursor->x = 0;
screen_linefeed(self);
}
void
screen_draw_printable_ascii(Screen *self, const uint8_t *chars, size_t num) {
screen_on_input(self);
self->last_graphic_char = chars[num-1];
self->is_dirty = true;
CPUCell cc = {.hyperlink_id=self->active_hyperlink_id};
GPUCell g = {.attrs=cursor_to_attrs(self->cursor, 1), .fg=self->cursor->fg & COL_MASK, .bg=self->cursor->bg & COL_MASK, .decoration_fg=self->cursor->decoration_fg & COL_MASK};
if (OPT(underline_hyperlinks) == UNDERLINE_ALWAYS && cc.hyperlink_id) {
g.decoration_fg = ((OPT(url_color) & COL_MASK) << 8) | 2;
g.attrs.decoration = OPT(url_style);
}
#define fill_single_line(chars, num) { \
linebuf_init_line(self->linebuf, self->cursor->y); \
if (self->modes.mIRM) line_right_shift(self->linebuf->line, self->cursor->x, num); \
line_set_printable_ascii_chars(self->linebuf->line, self->cursor->x, chars, num, g, cc); \
self->cursor->x += num; \
if (selection_has_screen_line(&self->selections, self->cursor->y)) clear_selection(&self->selections); \
linebuf_mark_line_dirty(self->linebuf, self->cursor->y); \
}
int avail = self->columns - self->cursor->x;
if (avail >= (int)num) {
fill_single_line(chars, num);
} else {
if (self->modes.mDECAWM) {
while (num) {
avail = self->columns - self->cursor->x;
if (!avail) { screen_continue_to_next_line(self); avail = self->columns; }
unsigned nc = MIN((unsigned)avail, num);
fill_single_line(chars, nc);
num -= nc;
chars += nc;
}
} else {
if (avail > 1) { fill_single_line(chars, avail - 1); }
else if (avail == 0) self->cursor->x--;
fill_single_line(chars + num - 1, 1);
}
}
}
static void
draw_codepoint(Screen *self, char_type ch, bool from_input_stream) {
if (from_input_stream) screen_on_input(self);
if (is_ignored_char(ch)) return;
if (UNLIKELY(is_combining_char(ch))) {
if (UNLIKELY(is_flag_codepoint(ch))) {
if (draw_second_flag_codepoint(self, ch)) return;
@ -663,13 +717,8 @@ draw_codepoint(Screen *self, char_type ch, bool from_input_stream) {
}
if (from_input_stream) self->last_graphic_char = ch;
if (UNLIKELY(self->columns - self->cursor->x < (unsigned int)char_width)) {
if (self->modes.mDECAWM) {
linebuf_set_last_char_as_continuation(self->linebuf, self->cursor->y, true);
screen_carriage_return(self);
screen_linefeed(self);
} else {
self->cursor->x = self->columns - char_width;
}
if (self->modes.mDECAWM) screen_continue_to_next_line(self);
else self->cursor->x = self->columns - char_width;
}
linebuf_init_line(self->linebuf, self->cursor->y);

View file

@ -167,6 +167,7 @@ void screen_cursor_back(Screen *self, unsigned int count/*=1*/, int move_directi
void screen_erase_in_line(Screen *, unsigned int, bool);
void screen_erase_in_display(Screen *, unsigned int, bool);
void screen_draw(Screen *screen, uint32_t codepoint);
void screen_draw_printable_ascii(Screen *self, const uint8_t *chars, size_t num);
void screen_ensure_bounds(Screen *self, bool use_margins, bool cursor_was_within_margins);
void screen_toggle_screen_buffer(Screen *self, bool, bool);
void screen_normal_keypad_mode(Screen *self);