Skip to content

Commit 60fa3ec

Browse files
committed
CodeEdit: improve render speed
1 parent 40b378e commit 60fa3ec

File tree

4 files changed

+357
-245
lines changed

4 files changed

+357
-245
lines changed

scene/gui/code_edit.cpp

Lines changed: 76 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,18 @@ void CodeEdit::_notification(int p_what) {
4040
switch (p_what) {
4141
case NOTIFICATION_THEME_CHANGED: {
4242
set_gutter_width(main_gutter, get_line_height());
43-
set_gutter_width(line_number_gutter, (line_number_digits + 1) * theme_cache.font->get_char_size('0', theme_cache.font_size).width);
43+
_update_line_number_gutter_width();
4444
set_gutter_width(fold_gutter, get_line_height() / 1.2);
45+
_clear_line_number_text_cache();
46+
} break;
47+
48+
case NOTIFICATION_TRANSLATION_CHANGED:
49+
[[fallthrough]];
50+
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
51+
[[fallthrough]];
52+
case NOTIFICATION_VISIBILITY_CHANGED: {
53+
// Avoid having many hidden text editors with unused cache filling up memory.
54+
_clear_line_number_text_cache();
4555
} break;
4656

4757
case NOTIFICATION_DRAW: {
@@ -1287,9 +1297,9 @@ bool CodeEdit::is_drawing_executing_lines_gutter() const {
12871297
}
12881298

12891299
void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) {
1300+
bool hovering = get_hovered_gutter() == Vector2i(main_gutter, p_line);
12901301
if (draw_breakpoints && theme_cache.breakpoint_icon.is_valid()) {
12911302
bool breakpointed = is_line_breakpointed(p_line);
1292-
bool hovering = p_region.has_point(get_local_mouse_pos());
12931303
bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT);
12941304

12951305
if (breakpointed || (hovering && !is_dragging_cursor() && !shift_pressed)) {
@@ -1308,7 +1318,6 @@ void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2
13081318

13091319
if (draw_bookmarks && theme_cache.bookmark_icon.is_valid()) {
13101320
bool bookmarked = is_line_bookmarked(p_line);
1311-
bool hovering = p_region.has_point(get_local_mouse_pos());
13121321
bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT);
13131322

13141323
if (bookmarked || (hovering && !is_dragging_cursor() && shift_pressed)) {
@@ -1442,7 +1451,13 @@ bool CodeEdit::is_draw_line_numbers_enabled() const {
14421451
}
14431452

14441453
void CodeEdit::set_line_numbers_zero_padded(bool p_zero_padded) {
1445-
p_zero_padded ? line_number_padding = "0" : line_number_padding = " ";
1454+
String new_line_number_padding = p_zero_padded ? "0" : " ";
1455+
if (line_number_padding == new_line_number_padding) {
1456+
return;
1457+
}
1458+
1459+
line_number_padding = new_line_number_padding;
1460+
_clear_line_number_text_cache();
14461461
queue_redraw();
14471462
}
14481463

@@ -1451,19 +1466,55 @@ bool CodeEdit::is_line_numbers_zero_padded() const {
14511466
}
14521467

14531468
void CodeEdit::_line_number_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) {
1454-
String fc = String::num(p_line + 1).lpad(line_number_digits, line_number_padding);
1455-
if (is_localizing_numeral_system()) {
1456-
fc = TS->format_number(fc);
1457-
}
1458-
Ref<TextLine> tl;
1459-
tl.instantiate();
1460-
tl->add_string(fc, theme_cache.font, theme_cache.font_size);
1461-
int yofs = p_region.position.y + (get_line_height() - tl->get_size().y) / 2;
1469+
if (!Rect2(Vector2(0, 0), get_size()).intersects(p_region)) {
1470+
return;
1471+
}
1472+
1473+
bool rtl = is_layout_rtl();
1474+
HashMap<int, RID>::Iterator E = line_number_text_cache.find(p_line);
1475+
RID text_rid;
1476+
if (E) {
1477+
text_rid = E->value;
1478+
} else {
1479+
String fc = String::num(p_line + 1).lpad(line_number_digits, line_number_padding);
1480+
if (is_localizing_numeral_system()) {
1481+
fc = TS->format_number(fc);
1482+
}
1483+
1484+
text_rid = TS->create_shaped_text();
1485+
if (theme_cache.font.is_valid()) {
1486+
TS->shaped_text_add_string(text_rid, fc, theme_cache.font->get_rids(), theme_cache.font_size, theme_cache.font->get_opentype_features());
1487+
}
1488+
line_number_text_cache.insert(p_line, text_rid);
1489+
}
1490+
1491+
Size2 text_size = TS->shaped_text_get_size(text_rid);
1492+
Point2 ofs = p_region.get_center() - text_size / 2;
1493+
ofs.y += TS->shaped_text_get_ascent(text_rid);
1494+
1495+
if (rtl) {
1496+
ofs.x = p_region.position.x;
1497+
} else {
1498+
ofs.x = p_region.get_end().x - text_size.width;
1499+
}
1500+
14621501
Color number_color = get_line_gutter_item_color(p_line, line_number_gutter);
14631502
if (number_color == Color(1, 1, 1)) {
14641503
number_color = theme_cache.line_number_color;
14651504
}
1466-
tl->draw(get_canvas_item(), Point2(p_region.position.x, yofs), number_color);
1505+
1506+
TS->shaped_text_draw(text_rid, get_canvas_item(), ofs, -1, -1, number_color);
1507+
}
1508+
1509+
void CodeEdit::_clear_line_number_text_cache() {
1510+
for (const KeyValue<int, RID> &KV : line_number_text_cache) {
1511+
TS->free_rid(KV.value);
1512+
}
1513+
line_number_text_cache.clear();
1514+
}
1515+
1516+
void CodeEdit::_update_line_number_gutter_width() {
1517+
set_gutter_width(line_number_gutter, (line_number_digits + 1) * theme_cache.font->get_char_size('0', theme_cache.font_size).width);
14671518
}
14681519

14691520
/* Fold Gutter */
@@ -1983,12 +2034,18 @@ Point2 CodeEdit::get_delimiter_end_position(int p_line, int p_column) const {
19832034

19842035
/* Code hint */
19852036
void CodeEdit::set_code_hint(const String &p_hint) {
2037+
if (code_hint == p_hint) {
2038+
return;
2039+
}
19862040
code_hint = p_hint;
19872041
code_hint_xpos = -0xFFFF;
19882042
queue_redraw();
19892043
}
19902044

19912045
void CodeEdit::set_code_hint_draw_below(bool p_below) {
2046+
if (code_hint_draw_below == p_below) {
2047+
return;
2048+
}
19922049
code_hint_draw_below = p_below;
19932050
queue_redraw();
19942051
}
@@ -3609,16 +3666,13 @@ void CodeEdit::_text_changed() {
36093666
}
36103667

36113668
int lc = get_line_count();
3612-
line_number_digits = 1;
3613-
while (lc /= 10) {
3614-
line_number_digits++;
3615-
}
3616-
3617-
if (theme_cache.font.is_valid()) {
3618-
set_gutter_width(line_number_gutter, (line_number_digits + 1) * theme_cache.font->get_char_size('0', theme_cache.font_size).width);
3669+
int new_line_number_digits = log10l(lc) + 1;
3670+
if (line_number_digits != new_line_number_digits) {
3671+
_clear_line_number_text_cache();
36193672
}
3673+
line_number_digits = new_line_number_digits;
3674+
_update_line_number_gutter_width();
36203675

3621-
lc = get_line_count();
36223676
List<int> breakpoints;
36233677
for (const KeyValue<int, bool> &E : breakpointed_lines) {
36243678
breakpoints.push_back(E.key);
@@ -3705,6 +3759,7 @@ CodeEdit::CodeEdit() {
37053759
}
37063760

37073761
CodeEdit::~CodeEdit() {
3762+
_clear_line_number_text_cache();
37083763
}
37093764

37103765
// Return true if l should come before r

scene/gui/code_edit.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ class CodeEdit : public TextEdit {
113113
int line_number_gutter = -1;
114114
int line_number_digits = 1;
115115
String line_number_padding = " ";
116+
HashMap<int, RID> line_number_text_cache;
117+
void _clear_line_number_text_cache();
118+
void _update_line_number_gutter_width();
116119
void _line_number_draw_callback(int p_line, int p_gutter, const Rect2 &p_region);
117120

118121
/* Fold Gutter */

0 commit comments

Comments
 (0)