diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 7fc86666e5cc..cbabce52353b 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -5632,8 +5632,12 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) { i++; } int r_end = sd->spans[i].end; - UBreakIterator *bi = ubrk_open(UBRK_LINE, (language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale().ascii().get_data() : language.ascii().get_data(), data + _convert_pos_inv(sd, r_start), _convert_pos_inv(sd, r_end - r_start), &err); - if (U_FAILURE(err)) { + UBreakIterator *bi = sd->_get_break_iterator_for_locale(language, &err); + if (!U_FAILURE(err) && bi) { + ubrk_setText(bi, data + _convert_pos_inv(sd, r_start), _convert_pos_inv(sd, r_end - r_start), &err); + } + + if (U_FAILURE(err) || !bi) { // No data loaded - use fallback. for (int j = r_start; j < r_end; j++) { char32_t c = sd->text[j - sd->start]; @@ -5662,7 +5666,6 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) { } } } - ubrk_close(bi); i++; } sd->break_ops_valid = true; @@ -6110,6 +6113,15 @@ _FORCE_INLINE_ void TextServerAdvanced::_add_featuers(const Dictionary &p_source } } +UBreakIterator *TextServerAdvanced::ShapedTextDataAdvanced::_get_break_iterator_for_locale(const String &p_language, UErrorCode *r_err) { + HashMap::Iterator key_value = line_break_iterators_per_language.find(p_language); + if (key_value) { + return key_value->value; + } + UBreakIterator *brk = ubrk_open(UBRK_LINE, p_language.is_empty() ? TranslationServer::get_singleton()->get_tool_locale().ascii().get_data() : p_language.ascii().get_data(), nullptr, 0, r_err); + return line_break_iterators_per_language.insert(p_language, brk)->value; +} + void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, TypedArray p_fonts, int64_t p_span, int64_t p_fb_index, int64_t p_prev_start, int64_t p_prev_end, RID p_prev_font) { RID f; int fs = p_sd->spans[p_span].font_size; diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index ab37abc6f7e3..4eb5ce0f4e0b 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -544,6 +544,11 @@ class TextServerAdvanced : public TextServerExtension { bool js_ops_valid = false; bool chars_valid = false; + HashMap line_break_iterators_per_language; + + // Creating UBreakIterator is surprisingly costly. To improve efficiency, we cache them. + UBreakIterator *_get_break_iterator_for_locale(const String &p_language, UErrorCode *r_err); + ~ShapedTextDataAdvanced() { for (int i = 0; i < bidi_iter.size(); i++) { if (bidi_iter[i]) { @@ -556,6 +561,9 @@ class TextServerAdvanced : public TextServerExtension { if (hb_buffer) { hb_buffer_destroy(hb_buffer); } + for (const KeyValue &bi : line_break_iterators_per_language) { + ubrk_close(bi.value); + } } };