diff options
author | bruvzg <7645683+bruvzg@users.noreply.github.com> | 2023-04-12 11:39:05 +0300 |
---|---|---|
committer | Yuri Sizov <yuris@humnom.net> | 2023-04-24 17:03:55 +0200 |
commit | 9c1ea280927a1376cd31e1b0dfe7ca5abd12e693 (patch) | |
tree | 7d2a57f114ab3c176f3feb30464995aadd7445c7 /modules/text_server_adv | |
parent | 3a1af9393f0accfed8d05a257e2ff8af6b2e7050 (diff) |
Improve line BiDi handling, prevent crash on recursive log updates.
(cherry picked from commit 282e4231c26c172b186a5bf22a8ba7f0337ba3d6)
Diffstat (limited to 'modules/text_server_adv')
-rw-r--r-- | modules/text_server_adv/text_server_adv.cpp | 45 | ||||
-rw-r--r-- | modules/text_server_adv/text_server_adv.h | 1 |
2 files changed, 36 insertions, 10 deletions
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index ae32a08c58..e1aa467fdc 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -4105,6 +4105,7 @@ RID TextServerAdvanced::_shaped_text_substr(const RID &p_shaped, int64_t p_start new_sd->direction = sd->direction; new_sd->custom_punct = sd->custom_punct; new_sd->para_direction = sd->para_direction; + new_sd->base_para_direction = sd->base_para_direction; for (int i = 0; i < TextServer::SPACING_MAX; i++) { new_sd->extra_spacing[i] = sd->extra_spacing[i]; } @@ -4155,9 +4156,33 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S if (U_SUCCESS(err)) { ubidi_setLine(p_sd->bidi_iter[ov], start, end, bidi_iter, &err); if (U_FAILURE(err)) { - ubidi_close(bidi_iter); - bidi_iter = nullptr; - ERR_PRINT(vformat("BiDi reordering for the line failed: %s", u_errorName(err))); + // 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<TextServer::Direction>(p_sd->bidi_override[ov].z)) { + case DIRECTION_LTR: { + ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err); + } break; + case DIRECTION_RTL: { + ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err); + } break; + case DIRECTION_INHERITED: { + ubidi_setPara(bidi_iter, data + start, end - start, p_sd->base_para_direction, nullptr, &err); + } break; + case DIRECTION_AUTO: { + UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start); + if (direction != UBIDI_NEUTRAL) { + ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err); + } else { + ubidi_setPara(bidi_iter, data + start, end - start, p_sd->base_para_direction, nullptr, &err); + } + } break; + } + if (U_FAILURE(err)) { + ubidi_close(bidi_iter); + bidi_iter = nullptr; + ERR_PRINT(vformat("BiDi reordering for the line failed: %s", u_errorName(err))); + } } } else { bidi_iter = nullptr; @@ -5586,25 +5611,25 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) { sd->script_iter = memnew(ScriptIterator(sd->text, 0, sd->text.length())); } - int base_para_direction = UBIDI_DEFAULT_LTR; + sd->base_para_direction = UBIDI_DEFAULT_LTR; switch (sd->direction) { case DIRECTION_LTR: { sd->para_direction = DIRECTION_LTR; - base_para_direction = UBIDI_LTR; + sd->base_para_direction = UBIDI_LTR; } break; case DIRECTION_RTL: { sd->para_direction = DIRECTION_RTL; - base_para_direction = UBIDI_RTL; + sd->base_para_direction = UBIDI_RTL; } break; case DIRECTION_INHERITED: case DIRECTION_AUTO: { UBiDiDirection direction = ubidi_getBaseDirection(data, sd->utf16.length()); if (direction != UBIDI_NEUTRAL) { sd->para_direction = (direction == UBIDI_RTL) ? DIRECTION_RTL : DIRECTION_LTR; - base_para_direction = direction; + sd->base_para_direction = direction; } else { sd->para_direction = DIRECTION_LTR; - base_para_direction = UBIDI_DEFAULT_LTR; + sd->base_para_direction = UBIDI_DEFAULT_LTR; } } break; } @@ -5633,14 +5658,14 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) { ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err); } break; case DIRECTION_INHERITED: { - ubidi_setPara(bidi_iter, data + start, end - start, base_para_direction, nullptr, &err); + ubidi_setPara(bidi_iter, data + start, end - start, sd->base_para_direction, nullptr, &err); } break; case DIRECTION_AUTO: { UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start); if (direction != UBIDI_NEUTRAL) { ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err); } else { - ubidi_setPara(bidi_iter, data + start, end - start, base_para_direction, nullptr, &err); + ubidi_setPara(bidi_iter, data + start, end - start, sd->base_para_direction, nullptr, &err); } } break; } diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 046a85d2f7..dff87f3d74 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -475,6 +475,7 @@ class TextServerAdvanced : public TextServerExtension { /* Shaped data */ TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction. + int base_para_direction = UBIDI_DEFAULT_LTR; bool valid = false; // String is shaped. bool line_breaks_valid = false; // Line and word break flags are populated (and virtual zero width spaces inserted). bool justification_ops_valid = false; // Virtual elongation glyphs are added to the string. |