diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 7783cc58c43..97157855755 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -5656,7 +5656,8 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) { i++; } int r_end = sd->spans[i].end; - UBreakIterator *bi = sd->_get_break_iterator_for_locale(language, &err); + UBreakIterator *bi = _create_line_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); } @@ -5689,6 +5690,7 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) { sd->break_inserts++; } } + ubrk_close(bi); } i++; } @@ -6135,13 +6137,22 @@ _FORCE_INLINE_ void TextServerAdvanced::_add_features(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); +UBreakIterator *TextServerAdvanced::_create_line_break_iterator_for_locale(const String &p_language, UErrorCode *r_err) const { + // Creating UBreakIterator (ubrk_open) is surprisingly costly. + // However, cloning (ubrk_clone) is cheaper, so we keep around blueprints to accelerate creating new ones. + + const String language = p_language.is_empty() ? TranslationServer::get_singleton()->get_tool_locale() : p_language; + _THREAD_SAFE_METHOD_ + const HashMap::Iterator key_value = line_break_iterators_per_language.find(language); if (key_value) { - return key_value->value; + return ubrk_clone(key_value->value, r_err); } - 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; + UBreakIterator *bi = ubrk_open(UBRK_LINE, language.ascii().get_data(), nullptr, 0, r_err); + if (U_FAILURE(*r_err) || !bi) { + return nullptr; + } + line_break_iterators_per_language.insert(language, bi); + return ubrk_clone(bi, r_err); } 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) { @@ -7719,6 +7730,9 @@ TextServerAdvanced::~TextServerAdvanced() { uset_close(allowed); allowed = nullptr; } + for (const KeyValue &bi : line_break_iterators_per_language) { + ubrk_close(bi.value); + } std::atexit(u_cleanup); } diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index a027e920ee9..315bb426784 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -176,6 +176,10 @@ class TextServerAdvanced : public TextServerExtension { mutable USpoofChecker *sc_spoof = nullptr; mutable USpoofChecker *sc_conf = nullptr; + mutable HashMap line_break_iterators_per_language; + + UBreakIterator *_create_line_break_iterator_for_locale(const String &p_language, UErrorCode *r_err) const; + // Font cache data. #ifdef MODULE_FREETYPE_ENABLED @@ -545,11 +549,6 @@ 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]) { @@ -562,9 +561,6 @@ 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); - } } };