Optimise TextEdit base operations

This commit is contained in:
Paulb23 2021-12-08 15:29:40 +00:00
parent e53e357a2b
commit bfe2cd2f03
4 changed files with 93 additions and 50 deletions

View File

@ -2597,7 +2597,7 @@ bool Control::is_text_field() const {
return false; return false;
} }
Array Control::structured_text_parser(StructuredTextParser p_theme_type, const Array &p_args, const String p_text) const { Array Control::structured_text_parser(StructuredTextParser p_theme_type, const Array &p_args, const String &p_text) const {
Array ret; Array ret;
switch (p_theme_type) { switch (p_theme_type) {
case STRUCTURED_TEXT_URI: { case STRUCTURED_TEXT_URI: {

View File

@ -279,7 +279,7 @@ protected:
//virtual void _window_gui_input(InputEvent p_event); //virtual void _window_gui_input(InputEvent p_event);
virtual Array structured_text_parser(StructuredTextParser p_theme_type, const Array &p_args, const String p_text) const; virtual Array structured_text_parser(StructuredTextParser p_theme_type, const Array &p_args, const String &p_text) const;
bool _set(const StringName &p_name, const Variant &p_value); bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const; bool _get(const StringName &p_name, Variant &r_ret) const;

View File

@ -155,30 +155,30 @@ _FORCE_INLINE_ const String &TextEdit::Text::operator[](int p_line) const {
void TextEdit::Text::_calculate_line_height() { void TextEdit::Text::_calculate_line_height() {
int height = 0; int height = 0;
for (int i = 0; i < text.size(); i++) { for (const Line &l : text) {
// Found another line with the same height...nothing to update. // Found another line with the same height...nothing to update.
if (text[i].height == line_height) { if (l.height == line_height) {
height = line_height; height = line_height;
break; break;
} }
height = MAX(height, text[i].height); height = MAX(height, l.height);
} }
line_height = height; line_height = height;
} }
void TextEdit::Text::_calculate_max_line_width() { void TextEdit::Text::_calculate_max_line_width() {
int width = 0; int width = 0;
for (int i = 0; i < text.size(); i++) { for (const Line &l : text) {
if (is_hidden(i)) { if (l.hidden) {
continue; continue;
} }
// Found another line with the same width...nothing to update. // Found another line with the same width...nothing to update.
if (text[i].width == max_width) { if (l.width == max_width) {
width = max_width; width = max_width;
break; break;
} }
width = MAX(width, text[i].width); width = MAX(width, l.width);
} }
max_width = width; max_width = width;
} }
@ -216,7 +216,7 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, const String &p_
// Update height. // Update height.
const int old_height = text.write[p_line].height; const int old_height = text.write[p_line].height;
const int wrap_amount = get_line_wrap_amount(p_line); const int wrap_amount = get_line_wrap_amount(p_line);
int height = font->get_height(font_size); int height = font_height;
for (int i = 0; i <= wrap_amount; i++) { for (int i = 0; i <= wrap_amount; i++) {
height = MAX(height, text[p_line].data_buf->get_line_size(i).y); height = MAX(height, text[p_line].data_buf->get_line_size(i).y);
} }
@ -267,6 +267,13 @@ void TextEdit::Text::invalidate_all() {
return; return;
} }
max_width = -1;
line_height = -1;
if (!font.is_null() && font_size > 0) {
font_height = font->get_height(font_size);
}
for (int i = 0; i < text.size(); i++) { for (int i = 0; i < text.size(); i++) {
invalidate_cache(i); invalidate_cache(i);
} }
@ -275,7 +282,15 @@ void TextEdit::Text::invalidate_all() {
void TextEdit::Text::clear() { void TextEdit::Text::clear() {
text.clear(); text.clear();
insert(0, "", Array());
max_width = -1;
line_height = -1;
Line line;
line.gutters.resize(gutter_count);
line.data = "";
text.insert(0, line);
invalidate_cache(0);
} }
int TextEdit::Text::get_max_width() const { int TextEdit::Text::get_max_width() const {
@ -290,30 +305,64 @@ void TextEdit::Text::set(int p_line, const String &p_text, const Array &p_bidi_o
invalidate_cache(p_line); invalidate_cache(p_line);
} }
void TextEdit::Text::insert(int p_at, const String &p_text, const Array &p_bidi_override) { void TextEdit::Text::insert(int p_at, const Vector<String> &p_text, const Vector<Array> &p_bidi_override) {
Line line; int new_line_count = p_text.size() - 1;
line.gutters.resize(gutter_count); if (new_line_count > 0) {
line.hidden = false; text.resize(text.size() + new_line_count);
line.data = p_text; for (int i = (text.size() - 1); i > p_at; i--) {
line.bidi_override = p_bidi_override; if ((i - new_line_count) <= 0) {
text.insert(p_at, line); break;
}
text.write[i] = text[i - new_line_count];
}
}
invalidate_cache(p_at); for (int i = 0; i < p_text.size(); i++) {
if (i == 0) {
set(p_at + i, p_text[i], p_bidi_override[i]);
continue;
}
Line line;
line.gutters.resize(gutter_count);
line.data = p_text[i];
line.bidi_override = p_bidi_override[i];
text.write[p_at + i] = line;
invalidate_cache(p_at + i);
}
} }
void TextEdit::Text::remove_at(int p_index) { void TextEdit::Text::remove_range(int p_from_line, int p_to_line) {
int height = text[p_index].height; if (p_from_line == p_to_line) {
int width = text[p_index].width; return;
}
text.remove_at(p_index); bool dirty_height = false;
bool dirty_width = false;
for (int i = p_from_line; i < p_to_line; i++) {
if (!dirty_height && text[i].height == line_height) {
dirty_height = true;
}
// If this is the tallest line, we need to get the next tallest. if (!dirty_width && text[i].width == max_width) {
if (height == line_height) { dirty_width = true;
}
if (dirty_height && dirty_width) {
break;
}
}
int diff = (p_to_line - p_from_line);
for (int i = p_to_line; i < text.size() - 1; i++) {
text.write[(i - diff) + 1] = text[i + 1];
}
text.resize(text.size() - diff);
if (dirty_height) {
_calculate_line_height(); _calculate_line_height();
} }
// If this is the longest line, we need to get the next longest. if (dirty_width) {
if (width == max_width) {
_calculate_max_line_width(); _calculate_max_line_width();
} }
} }
@ -6289,11 +6338,11 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
ERR_FAIL_COND(p_char < 0); ERR_FAIL_COND(p_char < 0);
/* STEP 1: Remove \r from source text and separate in substrings. */ /* STEP 1: Remove \r from source text and separate in substrings. */
const String text_to_insert = p_text.replace("\r", "");
Vector<String> substrings = p_text.replace("\r", "").split("\n"); Vector<String> substrings = text_to_insert.split("\n");
// Is this just a new empty line? // Is this just a new empty line?
bool shift_first_line = p_char == 0 && p_text.replace("\r", "") == "\n"; bool shift_first_line = p_char == 0 && substrings.size() == 2 && text_to_insert == "\n";
/* STEP 2: Add spaces if the char is greater than the end of the line. */ /* STEP 2: Add spaces if the char is greater than the end of the line. */
while (p_char > text[p_line].length()) { while (p_char > text[p_line].length()) {
@ -6301,24 +6350,19 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
} }
/* STEP 3: Separate dest string in pre and post text. */ /* STEP 3: Separate dest string in pre and post text. */
String preinsert_text = text[p_line].substr(0, p_char);
String postinsert_text = text[p_line].substr(p_char, text[p_line].size()); String postinsert_text = text[p_line].substr(p_char, text[p_line].size());
for (int j = 0; j < substrings.size(); j++) { substrings.write[0] = text[p_line].substr(0, p_char) + substrings[0];
// Insert the substrings. substrings.write[substrings.size() - 1] += postinsert_text;
if (j == 0) { Vector<Array> bidi_override;
text.set(p_line, preinsert_text + substrings[j], structured_text_parser(st_parser, st_args, preinsert_text + substrings[j])); bidi_override.resize(substrings.size());
} else { for (int i = 0; i < substrings.size(); i++) {
text.insert(p_line + j, substrings[j], structured_text_parser(st_parser, st_args, substrings[j])); bidi_override.write[i] = structured_text_parser(st_parser, st_args, substrings[i]);
}
if (j == substrings.size() - 1) {
text.set(p_line + j, text[p_line + j] + postinsert_text, structured_text_parser(st_parser, st_args, text[p_line + j] + postinsert_text));
}
} }
text.insert(p_line, substrings, bidi_override);
if (shift_first_line) { if (shift_first_line) {
text.move_gutters(p_line, p_line + 1); text.move_gutters(p_line, p_line + 1);
text.set_hidden(p_line + 1, text.is_hidden(p_line)); text.set_hidden(p_line + 1, text.is_hidden(p_line));
@ -6351,7 +6395,7 @@ String TextEdit::_base_get_text(int p_from_line, int p_from_column, int p_to_lin
ERR_FAIL_COND_V(p_to_line < p_from_line, String()); // 'from > to'. ERR_FAIL_COND_V(p_to_line < p_from_line, String()); // 'from > to'.
ERR_FAIL_COND_V(p_to_line == p_from_line && p_to_column < p_from_column, String()); // 'from > to'. ERR_FAIL_COND_V(p_to_line == p_from_line && p_to_column < p_from_column, String()); // 'from > to'.
String ret; StringBuilder ret;
for (int i = p_from_line; i <= p_to_line; i++) { for (int i = p_from_line; i <= p_to_line; i++) {
int begin = (i == p_from_line) ? p_from_column : 0; int begin = (i == p_from_line) ? p_from_column : 0;
@ -6363,7 +6407,7 @@ String TextEdit::_base_get_text(int p_from_line, int p_from_column, int p_to_lin
ret += text[i].substr(begin, end - begin); ret += text[i].substr(begin, end - begin);
} }
return ret; return ret.as_string();
} }
void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column) { void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column) {
@ -6377,9 +6421,7 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li
String pre_text = text[p_from_line].substr(0, p_from_column); String pre_text = text[p_from_line].substr(0, p_from_column);
String post_text = text[p_to_line].substr(p_to_column, text[p_to_line].length()); String post_text = text[p_to_line].substr(p_to_column, text[p_to_line].length());
for (int i = p_from_line; i < p_to_line; i++) { text.remove_range(p_from_line, p_to_line);
text.remove_at(p_from_line + 1);
}
text.set(p_from_line, pre_text + post_text, structured_text_parser(st_parser, st_args, pre_text + post_text)); text.set(p_from_line, pre_text + post_text, structured_text_parser(st_parser, st_args, pre_text + post_text));
if (!text_changed_dirty && !setting_text) { if (!text_changed_dirty && !setting_text) {

View File

@ -159,6 +159,7 @@ private:
mutable Vector<Line> text; mutable Vector<Line> text;
Ref<Font> font; Ref<Font> font;
int font_size = -1; int font_size = -1;
int font_height = 0;
Dictionary opentype_features; Dictionary opentype_features;
String language; String language;
@ -204,8 +205,8 @@ private:
} }
} }
bool is_hidden(int p_line) const { return text[p_line].hidden; } bool is_hidden(int p_line) const { return text[p_line].hidden; }
void insert(int p_at, const String &p_text, const Array &p_bidi_override); void insert(int p_at, const Vector<String> &p_text, const Vector<Array> &p_bidi_override);
void remove_at(int p_index); void remove_range(int p_from_line, int p_to_line);
int size() const { return text.size(); } int size() const { return text.size(); }
void clear(); void clear();