From 307acb3f64ef5ab0d17611dea6096b6873e48ee8 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 12 Nov 2023 10:30:10 +0530 Subject: [PATCH] Add API to Screen to draw a set of printable ascii chars fast --- kitty/line.c | 9 +++++++ kitty/lineops.h | 1 + kitty/screen.c | 67 ++++++++++++++++++++++++++++++++++++++++++------- kitty/screen.h | 1 + 4 files changed, 69 insertions(+), 9 deletions(-) diff --git a/kitty/line.c b/kitty/line.c index 8463096d5..06d9709bd 100644 --- a/kitty/line.c +++ b/kitty/line.c @@ -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; diff --git a/kitty/lineops.h b/kitty/lineops.h index 22dc9e8b5..b9d6df081 100644 --- a/kitty/lineops.h +++ b/kitty/lineops.h @@ -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); diff --git a/kitty/screen.c b/kitty/screen.c index ae36373f3..110c9efac 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -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); diff --git a/kitty/screen.h b/kitty/screen.h index 502d8c23c..4aeb16d79 100644 --- a/kitty/screen.h +++ b/kitty/screen.h @@ -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);