From 43bc44e3b0211753598cc989b1dc3f5dfa637067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pa=CC=84vels=20Nadtoc=CC=8Cajevs?= <7645683+bruvzg@users.noreply.github.com> Date: Thu, 16 Jan 2025 08:57:27 +0200 Subject: [PATCH] [TextServer] Fix text buffer not processing strings added after `shape`. --- modules/text_server_adv/text_server_adv.cpp | 30 +++++++++----- tests/servers/test_text_server.h | 43 ++++++++++++++++++++- 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index aa97a4073d2..8655a219f8d 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -4773,17 +4773,24 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S } } + Vector bidi_ranges; + if (p_sd->bidi_override.is_empty()) { + bidi_ranges.push_back(Vector3i(p_sd->start, p_sd->end, DIRECTION_INHERITED)); + } else { + bidi_ranges = p_sd->bidi_override; + } + int sd_size = p_sd->glyphs.size(); const Glyph *sd_glyphs = p_sd->glyphs.ptr(); - for (int ov = 0; ov < p_sd->bidi_override.size(); ov++) { + for (int ov = 0; ov < bidi_ranges.size(); ov++) { UErrorCode err = U_ZERO_ERROR; - if (p_sd->bidi_override[ov].x >= p_start + p_length || p_sd->bidi_override[ov].y <= p_start) { + if (bidi_ranges[ov].x >= p_start + p_length || bidi_ranges[ov].y <= p_start) { continue; } - int ov_start = _convert_pos_inv(p_sd, p_sd->bidi_override[ov].x); + int ov_start = _convert_pos_inv(p_sd, bidi_ranges[ov].x); int start = MAX(0, _convert_pos_inv(p_sd, p_start) - ov_start); - int end = MIN(_convert_pos_inv(p_sd, p_start + p_length), _convert_pos_inv(p_sd, p_sd->bidi_override[ov].y)) - ov_start; + int end = MIN(_convert_pos_inv(p_sd, p_start + p_length), _convert_pos_inv(p_sd, bidi_ranges[ov].y)) - ov_start; ERR_FAIL_COND_V_MSG((start < 0 || end - start > p_new_sd->utf16.length()), false, "Invalid BiDi override range."); @@ -4797,7 +4804,7 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S // Line BiDi failed (string contains incompatible control characters), try full paragraph BiDi instead. err = U_ZERO_ERROR; const UChar *data = p_sd->utf16.get_data(); - switch (static_cast(p_sd->bidi_override[ov].z)) { + switch (static_cast(bidi_ranges[ov].z)) { case DIRECTION_LTR: { ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err); } break; @@ -6490,14 +6497,17 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) { } break; } + Vector bidi_ranges; if (sd->bidi_override.is_empty()) { - sd->bidi_override.push_back(Vector3i(sd->start, sd->end, DIRECTION_INHERITED)); + bidi_ranges.push_back(Vector3i(sd->start, sd->end, DIRECTION_INHERITED)); + } else { + bidi_ranges = sd->bidi_override; } - for (int ov = 0; ov < sd->bidi_override.size(); ov++) { + for (int ov = 0; ov < bidi_ranges.size(); ov++) { // Create BiDi iterator. - int start = _convert_pos_inv(sd, sd->bidi_override[ov].x - sd->start); - int end = _convert_pos_inv(sd, sd->bidi_override[ov].y - sd->start); + int start = _convert_pos_inv(sd, bidi_ranges[ov].x - sd->start); + int end = _convert_pos_inv(sd, bidi_ranges[ov].y - sd->start); if (start < 0 || end - start > sd->utf16.length()) { continue; @@ -6506,7 +6516,7 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) { UErrorCode err = U_ZERO_ERROR; UBiDi *bidi_iter = ubidi_openSized(end - start, 0, &err); if (U_SUCCESS(err)) { - switch (static_cast(sd->bidi_override[ov].z)) { + switch (static_cast(bidi_ranges[ov].z)) { case DIRECTION_LTR: { ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err); } break; diff --git a/tests/servers/test_text_server.h b/tests/servers/test_text_server.h index da21399cb8a..3e863b61ca8 100644 --- a/tests/servers/test_text_server.h +++ b/tests/servers/test_text_server.h @@ -815,12 +815,12 @@ TEST_SUITE("[TextServer]") { SUBCASE("[TextServer] Word break") { for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { Ref ts = TextServerManager::get_singleton()->get_interface(i); + CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface."); if (!ts->has_feature(TextServer::FEATURE_SIMPLE_LAYOUT)) { continue; } - CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface."); { String text1 = U"linguistically similar and effectively form"; // 14^ 22^ 26^ 38^ @@ -918,6 +918,47 @@ TEST_SUITE("[TextServer]") { } } } + + SUBCASE("[TextServer] Buffer invalidation") { + for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) { + Ref ts = TextServerManager::get_singleton()->get_interface(i); + CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface."); + + if (!ts->has_feature(TextServer::FEATURE_SIMPLE_LAYOUT)) { + continue; + } + + RID font1 = ts->create_font(); + ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size); + + Array font; + font.push_back(font1); + + RID ctx = ts->create_shaped_text(); + CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed."); + bool ok = ts->shaped_text_add_string(ctx, "T", font, 16); + CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed."); + int gl_size = ts->shaped_text_get_glyph_count(ctx); + CHECK_MESSAGE(gl_size == 1, "Shaping failed, invalid glyph count"); + + ok = ts->shaped_text_add_object(ctx, "key", Size2(20, 20), INLINE_ALIGNMENT_CENTER, 1, 0.0); + CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed."); + gl_size = ts->shaped_text_get_glyph_count(ctx); + CHECK_MESSAGE(gl_size == 2, "Shaping failed, invalid glyph count"); + + ok = ts->shaped_text_add_string(ctx, "B", font, 16); + CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed."); + gl_size = ts->shaped_text_get_glyph_count(ctx); + CHECK_MESSAGE(gl_size == 3, "Shaping failed, invalid glyph count"); + + ts->free_rid(ctx); + + for (int j = 0; j < font.size(); j++) { + ts->free_rid(font[j]); + } + font.clear(); + } + } } } }; // namespace TestTextServer