summaryrefslogtreecommitdiffstats
path: root/modules/text_server_adv
diff options
context:
space:
mode:
authorbruvzg <7645683+bruvzg@users.noreply.github.com>2023-08-15 11:42:40 +0300
committerbruvzg <7645683+bruvzg@users.noreply.github.com>2023-08-15 11:42:40 +0300
commit5d3fcc57669c4104a85c79327f7c2662a0d191a3 (patch)
tree0d1984613e38e1aaabe5a80338d46a415c8bba01 /modules/text_server_adv
parentc495eb5102278a110c14bbffbf833ed436d1594d (diff)
downloadredot-engine-5d3fcc57669c4104a85c79327f7c2662a0d191a3.tar.gz
[TextServer] Fix system font fallback and caret/selection behavior for composite characters.
Diffstat (limited to 'modules/text_server_adv')
-rw-r--r--modules/text_server_adv/text_server_adv.cpp107
-rw-r--r--modules/text_server_adv/text_server_adv.h6
2 files changed, 112 insertions, 1 deletions
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 043a33ab35..09a0fe5e8e 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -3782,6 +3782,7 @@ void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *
p_shaped->script_iter = nullptr;
}
p_shaped->break_ops_valid = false;
+ p_shaped->chars_valid = false;
p_shaped->js_ops_valid = false;
}
}
@@ -4835,6 +4836,76 @@ int64_t TextServerAdvanced::_shaped_text_get_ellipsis_glyph_count(const RID &p_s
return sd->overrun_trim_data.ellipsis_glyph_buf.size();
}
+void TextServerAdvanced::_update_chars(ShapedTextDataAdvanced *p_sd) const {
+ if (!p_sd->chars_valid) {
+ p_sd->chars.clear();
+
+ const UChar *data = p_sd->utf16.get_data();
+ UErrorCode err = U_ZERO_ERROR;
+ int prev = -1;
+ int i = 0;
+
+ Vector<ShapedTextDataAdvanced::Span> &spans = p_sd->spans;
+ if (p_sd->parent != RID()) {
+ ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(p_sd->parent);
+ ERR_FAIL_COND(!parent_sd->valid);
+ spans = parent_sd->spans;
+ }
+
+ while (i < spans.size()) {
+ if (spans[i].start > p_sd->end) {
+ break;
+ }
+ if (spans[i].end < p_sd->start) {
+ i++;
+ continue;
+ }
+
+ int r_start = MAX(0, spans[i].start - p_sd->start);
+ String language = spans[i].language;
+ while (i + 1 < spans.size() && language == spans[i + 1].language) {
+ i++;
+ }
+ int r_end = MIN(spans[i].end - p_sd->start, p_sd->text.size());
+
+ UBreakIterator *bi = ubrk_open(UBRK_CHARACTER, (language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale().ascii().get_data() : language.ascii().get_data(), data + _convert_pos_inv(p_sd, r_start), _convert_pos_inv(p_sd, r_end - r_start), &err);
+ if (U_SUCCESS(err)) {
+ while (ubrk_next(bi) != UBRK_DONE) {
+ int pos = _convert_pos(p_sd, ubrk_current(bi)) + r_start + p_sd->start;
+ if (prev != pos) {
+ p_sd->chars.push_back(pos);
+ }
+ prev = pos;
+ }
+ ubrk_close(bi);
+ } else {
+ for (int j = r_start; j <= r_end; j++) {
+ if (prev != j) {
+ p_sd->chars.push_back(j + p_sd->start);
+ }
+ prev = j;
+ }
+ }
+ i++;
+ }
+ p_sd->chars_valid = true;
+ }
+}
+
+PackedInt32Array TextServerAdvanced::_shaped_text_get_character_breaks(const RID &p_shaped) const {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V(!sd, PackedInt32Array());
+
+ MutexLock lock(sd->mutex);
+ if (!sd->valid) {
+ const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);
+ }
+
+ _update_chars(sd);
+
+ return sd->chars;
+}
+
bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -5338,7 +5409,17 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
// Try system fallback.
RID fdef = p_fonts[0];
if (_font_is_allow_system_fallback(fdef)) {
- String text = p_sd->text.substr(p_start, 1);
+ _update_chars(p_sd);
+
+ int64_t next = p_end;
+ for (const int32_t &E : p_sd->chars) {
+ if (E > p_start) {
+ next = E;
+ break;
+ }
+ }
+ String text = p_sd->text.substr(p_start, next - p_start);
+
String font_name = _font_get_name(fdef);
BitField<FontStyle> font_style = _font_get_style(fdef);
int font_weight = _font_get_weight(fdef);
@@ -6602,6 +6683,30 @@ PackedInt32Array TextServerAdvanced::_string_get_word_breaks(const String &p_str
return ret;
}
+PackedInt32Array TextServerAdvanced::_string_get_character_breaks(const String &p_string, const String &p_language) const {
+ const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
+ // Convert to UTF-16.
+ Char16String utf16 = p_string.utf16();
+
+ PackedInt32Array ret;
+
+ UErrorCode err = U_ZERO_ERROR;
+ UBreakIterator *bi = ubrk_open(UBRK_CHARACTER, lang.ascii().get_data(), (const UChar *)utf16.get_data(), utf16.length(), &err);
+ if (U_SUCCESS(err)) {
+ while (ubrk_next(bi) != UBRK_DONE) {
+ int pos = _convert_pos(p_string, utf16, ubrk_current(bi));
+ ret.push_back(pos);
+ }
+ ubrk_close(bi);
+ } else {
+ for (int i = 0; i <= p_string.size(); i++) {
+ ret.push_back(i);
+ }
+ }
+
+ return ret;
+}
+
bool TextServerAdvanced::_is_valid_identifier(const String &p_string) const {
#ifndef ICU_STATIC_DATA
if (!icu_data_loaded) {
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 44700e045b..f27fa1dee9 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -509,9 +509,11 @@ class TextServerAdvanced : public TextServerExtension {
HashMap<int, bool> jstops;
HashMap<int, bool> breaks;
+ PackedInt32Array chars;
int break_inserts = 0;
bool break_ops_valid = false;
bool js_ops_valid = false;
+ bool chars_valid = false;
~ShapedTextDataAdvanced() {
for (int i = 0; i < bidi_iter.size(); i++) {
@@ -609,6 +611,7 @@ class TextServerAdvanced : public TextServerExtension {
mutable HashMap<SystemFontKey, SystemFontCache, SystemFontKeyHasher> system_fonts;
mutable HashMap<String, PackedByteArray> system_font_data;
+ void _update_chars(ShapedTextDataAdvanced *p_sd) const;
void _realign(ShapedTextDataAdvanced *p_sd) const;
int64_t _convert_pos(const String &p_utf32, const Char16String &p_utf16, int64_t p_pos) const;
int64_t _convert_pos(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const;
@@ -920,11 +923,14 @@ public:
MODBIND1RC(double, shaped_text_get_underline_position, const RID &);
MODBIND1RC(double, shaped_text_get_underline_thickness, const RID &);
+ MODBIND1RC(PackedInt32Array, shaped_text_get_character_breaks, const RID &);
+
MODBIND2RC(String, format_number, const String &, const String &);
MODBIND2RC(String, parse_number, const String &, const String &);
MODBIND1RC(String, percent_sign, const String &);
MODBIND3RC(PackedInt32Array, string_get_word_breaks, const String &, const String &, int64_t);
+ MODBIND2RC(PackedInt32Array, string_get_character_breaks, const String &, const String &);
MODBIND2RC(int64_t, is_confusable, const String &, const PackedStringArray &);
MODBIND1RC(bool, spoof_check, const String &);