diff options
author | RĂ©mi Verschelde <remi@verschelde.fr> | 2021-12-10 09:46:15 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-10 09:46:15 +0100 |
commit | 7e32a27879ceb8622ca0351b896fe2ec304858f7 (patch) | |
tree | 885ea129312bd47ded3a1a7d5ce075c2160df37a | |
parent | dcf359450080f44b20845893ea7398cd082f9a61 (diff) | |
parent | bfe2cd2f036698d4f018db1c0628494729b37369 (diff) |
Merge pull request #55739 from Paulb23/text-edit-base-performance
-rw-r--r-- | scene/gui/control.cpp | 2 | ||||
-rw-r--r-- | scene/gui/control.h | 2 | ||||
-rw-r--r-- | scene/gui/text_edit.cpp | 134 | ||||
-rw-r--r-- | scene/gui/text_edit.h | 5 |
4 files changed, 93 insertions, 50 deletions
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 249eb95ed8..1fdc30eb6d 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -2597,7 +2597,7 @@ bool Control::is_text_field() const { 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; switch (p_theme_type) { case STRUCTURED_TEXT_URI: { diff --git a/scene/gui/control.h b/scene/gui/control.h index 4cc949d0a8..ae9ca1489a 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -279,7 +279,7 @@ protected: //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 _get(const StringName &p_name, Variant &r_ret) const; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 2986be28c2..c9060033f2 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -155,30 +155,30 @@ _FORCE_INLINE_ const String &TextEdit::Text::operator[](int p_line) const { void TextEdit::Text::_calculate_line_height() { 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. - if (text[i].height == line_height) { + if (l.height == line_height) { height = line_height; break; } - height = MAX(height, text[i].height); + height = MAX(height, l.height); } line_height = height; } void TextEdit::Text::_calculate_max_line_width() { int width = 0; - for (int i = 0; i < text.size(); i++) { - if (is_hidden(i)) { + for (const Line &l : text) { + if (l.hidden) { continue; } // Found another line with the same width...nothing to update. - if (text[i].width == max_width) { + if (l.width == max_width) { width = max_width; break; } - width = MAX(width, text[i].width); + width = MAX(width, l.width); } max_width = width; } @@ -216,7 +216,7 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, const String &p_ // Update height. const int old_height = text.write[p_line].height; 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++) { height = MAX(height, text[p_line].data_buf->get_line_size(i).y); } @@ -267,6 +267,13 @@ void TextEdit::Text::invalidate_all() { 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++) { invalidate_cache(i); } @@ -275,7 +282,15 @@ void TextEdit::Text::invalidate_all() { void TextEdit::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 { @@ -290,30 +305,64 @@ void TextEdit::Text::set(int p_line, const String &p_text, const Array &p_bidi_o invalidate_cache(p_line); } -void TextEdit::Text::insert(int p_at, const String &p_text, const Array &p_bidi_override) { - Line line; - line.gutters.resize(gutter_count); - line.hidden = false; - line.data = p_text; - line.bidi_override = p_bidi_override; - text.insert(p_at, line); +void TextEdit::Text::insert(int p_at, const Vector<String> &p_text, const Vector<Array> &p_bidi_override) { + int new_line_count = p_text.size() - 1; + if (new_line_count > 0) { + text.resize(text.size() + new_line_count); + for (int i = (text.size() - 1); i > p_at; i--) { + if ((i - new_line_count) <= 0) { + 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) { - int height = text[p_index].height; - int width = text[p_index].width; +void TextEdit::Text::remove_range(int p_from_line, int p_to_line) { + if (p_from_line == p_to_line) { + 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 (!dirty_width && text[i].width == max_width) { + 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 this is the tallest line, we need to get the next tallest. - if (height == line_height) { + if (dirty_height) { _calculate_line_height(); } - // If this is the longest line, we need to get the next longest. - if (width == max_width) { + if (dirty_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); /* STEP 1: Remove \r from source text and separate in substrings. */ - - Vector<String> substrings = p_text.replace("\r", "").split("\n"); + const String text_to_insert = p_text.replace("\r", ""); + Vector<String> substrings = text_to_insert.split("\n"); // 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. */ 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. */ - - String preinsert_text = text[p_line].substr(0, p_char); String postinsert_text = text[p_line].substr(p_char, text[p_line].size()); - for (int j = 0; j < substrings.size(); j++) { - // Insert the substrings. - - if (j == 0) { - text.set(p_line, preinsert_text + substrings[j], structured_text_parser(st_parser, st_args, preinsert_text + substrings[j])); - } else { - text.insert(p_line + j, substrings[j], structured_text_parser(st_parser, st_args, substrings[j])); - } + substrings.write[0] = text[p_line].substr(0, p_char) + substrings[0]; + substrings.write[substrings.size() - 1] += postinsert_text; - 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)); - } + Vector<Array> bidi_override; + bidi_override.resize(substrings.size()); + for (int i = 0; i < substrings.size(); i++) { + bidi_override.write[i] = structured_text_parser(st_parser, st_args, substrings[i]); } + text.insert(p_line, substrings, bidi_override); + if (shift_first_line) { text.move_gutters(p_line, p_line + 1); 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 && p_to_column < p_from_column, String()); // 'from > to'. - String ret; + StringBuilder ret; for (int i = p_from_line; i <= p_to_line; i++) { 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); } - 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) { @@ -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 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_at(p_from_line + 1); - } + text.remove_range(p_from_line, p_to_line); 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) { diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index a1b2ed59f5..df3edca943 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -159,6 +159,7 @@ private: mutable Vector<Line> text; Ref<Font> font; int font_size = -1; + int font_height = 0; Dictionary opentype_features; String language; @@ -204,8 +205,8 @@ private: } } 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 remove_at(int p_index); + void insert(int p_at, const Vector<String> &p_text, const Vector<Array> &p_bidi_override); + void remove_range(int p_from_line, int p_to_line); int size() const { return text.size(); } void clear(); |