From daa613333ec4ac53964e2ba3f22f10e0f5212991 Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Sat, 6 Mar 2021 11:52:16 +0200 Subject: [PATCH] [Text Server] Add support for user defined punctuation list, used for word breaking. --- doc/classes/TextParagraph.xml | 3 ++ doc/classes/TextServer.xml | 15 ++++++ doc/classes/TextServerExtension.xml | 15 ++++++ modules/text_server_adv/text_server_adv.cpp | 40 +++++++++++++-- modules/text_server_adv/text_server_adv.h | 3 ++ modules/text_server_fb/text_server_fb.cpp | 54 +++++++++++++++++---- modules/text_server_fb/text_server_fb.h | 3 ++ scene/resources/text_paragraph.cpp | 14 ++++++ scene/resources/text_paragraph.h | 3 ++ servers/text/text_server_extension.cpp | 15 ++++++ servers/text/text_server_extension.h | 5 ++ servers/text_server.cpp | 3 ++ servers/text_server.h | 4 ++ 13 files changed, 165 insertions(+), 12 deletions(-) diff --git a/doc/classes/TextParagraph.xml b/doc/classes/TextParagraph.xml index e06dfee698..808e1d9ac4 100644 --- a/doc/classes/TextParagraph.xml +++ b/doc/classes/TextParagraph.xml @@ -278,6 +278,9 @@ Paragraph horizontal alignment. + + Custom punctuation character list, used for word breaking. If set to empty string, server defaults are used. + Text writing direction. diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index 18ace85465..3dec669b86 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -911,6 +911,13 @@ Returns shapes of the carets corresponding to the character offset [code]position[/code] in the text. Returned caret shape is 1 pixel wide rectangle. + + + + + Returns custom punctuation character list, used for word breaking. If set to empty string, server defaults are used. + + @@ -1161,6 +1168,14 @@ Override ranges should cover full source text without overlaps. BiDi algorithm will be used on each range separately. + + + + + + Sets custom punctuation character list, used for word breaking. If set to empty string, server defaults are used. + + diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml index 29571463d2..6d89b9751e 100644 --- a/doc/classes/TextServerExtension.xml +++ b/doc/classes/TextServerExtension.xml @@ -918,6 +918,13 @@ Returns shapes of the carets corresponding to the character offset [code]position[/code] in the text. Returned caret shape is 1 pixel wide rectangle. + + + + + Returns custom punctuation character list, used for word breaking. If set to empty string, server defaults are used. + + @@ -1170,6 +1177,14 @@ Override ranges should cover full source text without overlaps. BiDi algorithm will be used on each range separately. + + + + + + Sets custom punctuation character list, used for word breaking. If set to empty string, server defaults are used. + + diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index f5d159040f..eaa8825a1d 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -2928,6 +2928,27 @@ TextServer::Direction TextServerAdvanced::shaped_text_get_direction(RID p_shaped return sd->direction; } +void TextServerAdvanced::shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) { + _THREAD_SAFE_METHOD_ + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND(!sd); + + if (sd->custom_punct != p_punct) { + if (sd->parent != RID()) { + full_copy(sd); + } + sd->custom_punct = p_punct; + invalidate(sd); + } +} + +String TextServerAdvanced::shaped_text_get_custom_punctuation(RID p_shaped) const { + _THREAD_SAFE_METHOD_ + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, String()); + return sd->custom_punct; +} + void TextServerAdvanced::shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3227,6 +3248,7 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->orientation = sd->orientation; new_sd->direction = sd->direction; + new_sd->custom_punct = sd->custom_punct; new_sd->para_direction = sd->para_direction; new_sd->line_breaks_valid = sd->line_breaks_valid; new_sd->justification_ops_valid = sd->justification_ops_valid; @@ -3807,6 +3829,9 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { const char32_t *ch = sd->text.ptr(); Glyph *sd_glyphs = sd->glyphs.ptrw(); + int c_punct_size = sd->custom_punct.length(); + const char32_t *c_punct = sd->custom_punct.ptr(); + for (i = 0; i < sd_size; i++) { if (sd_glyphs[i].count > 0) { char32_t c = ch[sd_glyphs[i].start - sd->start]; @@ -3819,12 +3844,21 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { if (is_whitespace(c)) { sd_glyphs[i].flags |= GRAPHEME_IS_SPACE; } + if (c_punct_size == 0) { + if (u_ispunct(c) && c != 0x005F) { + sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; + } + } else { + for (int j = 0; j < c_punct_size; j++) { + if (c_punct[j] == c) { + sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; + break; + } + } + } if (is_underscore(c)) { sd_glyphs[i].flags |= GRAPHEME_IS_UNDERSCORE; } - if (u_ispunct(c) && c != 0x005F) { - sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; - } if (breaks.has(sd->glyphs[i].start)) { if (breaks[sd->glyphs[i].start]) { sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD; diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 1feeada76d..afb46c22e2 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -436,6 +436,9 @@ public: virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override; + virtual void shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) override; + virtual String shaped_text_get_custom_punctuation(RID p_shaped) const override; + virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; virtual Orientation shaped_text_get_orientation(RID p_shaped) const override; diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 3d868d7be3..ca735bdb6c 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -2031,6 +2031,27 @@ TextServer::Direction TextServerFallback::shaped_text_get_direction(RID p_shaped return TextServer::DIRECTION_LTR; } +void TextServerFallback::shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) { + _THREAD_SAFE_METHOD_ + ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND(!sd); + + if (sd->custom_punct != p_punct) { + if (sd->parent != RID()) { + full_copy(sd); + } + sd->custom_punct = p_punct; + invalidate(sd); + } +} + +String TextServerFallback::shaped_text_get_custom_punctuation(RID p_shaped) const { + _THREAD_SAFE_METHOD_ + const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, String()); + return sd->custom_punct; +} + void TextServerFallback::shaped_text_set_orientation(RID p_shaped, TextServer::Orientation p_orientation) { ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -2333,6 +2354,7 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng new_sd->orientation = sd->orientation; new_sd->direction = sd->direction; + new_sd->custom_punct = sd->custom_punct; new_sd->para_direction = sd->para_direction; new_sd->line_breaks_valid = sd->line_breaks_valid; new_sd->justification_ops_valid = sd->justification_ops_valid; @@ -2616,27 +2638,41 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) { } int sd_size = sd->glyphs.size(); + Glyph *sd_glyphs = sd->glyphs.ptrw(); + + int c_punct_size = sd->custom_punct.length(); + const char32_t *c_punct = sd->custom_punct.ptr(); + for (int i = 0; i < sd_size; i++) { - if (sd->glyphs[i].count > 0) { - char32_t c = sd->text[sd->glyphs[i].start]; - if (is_punct(c)) { - sd->glyphs.write[i].flags |= GRAPHEME_IS_PUNCTUATION; + if (sd_glyphs[i].count > 0) { + char32_t c = sd->text[sd_glyphs[i].start]; + if (c_punct_size == 0) { + if (is_punct(c)) { + sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; + } + } else { + for (int j = 0; j < c_punct_size; j++) { + if (c_punct[j] == c) { + sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; + break; + } + } } if (is_underscore(c)) { sd->glyphs.write[i].flags |= GRAPHEME_IS_UNDERSCORE; } if (is_whitespace(c) && !is_linebreak(c)) { - sd->glyphs.write[i].flags |= GRAPHEME_IS_SPACE; - sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_SOFT; + sd_glyphs[i].flags |= GRAPHEME_IS_SPACE; + sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT; } if (is_linebreak(c)) { - sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_HARD; + sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD; } if (c == 0x0009 || c == 0x000b) { - sd->glyphs.write[i].flags |= GRAPHEME_IS_TAB; + sd_glyphs[i].flags |= GRAPHEME_IS_TAB; } - i += (sd->glyphs[i].count - 1); + i += (sd_glyphs[i].count - 1); } } sd->line_breaks_valid = true; diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index 992ce5018f..f442f7e77e 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -355,6 +355,9 @@ public: virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override; + virtual void shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) override; + virtual String shaped_text_get_custom_punctuation(RID p_shaped) const override; + virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; virtual Orientation shaped_text_get_orientation(RID p_shaped) const override; diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp index b2e18e2451..ff17683ad6 100644 --- a/scene/resources/text_paragraph.cpp +++ b/scene/resources/text_paragraph.cpp @@ -38,6 +38,11 @@ void TextParagraph::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "direction", PROPERTY_HINT_ENUM, "Auto,Light-to-right,Right-to-left"), "set_direction", "get_direction"); + ClassDB::bind_method(D_METHOD("set_custom_punctuation", "custom_punctuation"), &TextParagraph::set_custom_punctuation); + ClassDB::bind_method(D_METHOD("get_custom_punctuation"), &TextParagraph::get_custom_punctuation); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "custom_punctuation"), "set_custom_punctuation", "get_custom_punctuation"); + ClassDB::bind_method(D_METHOD("set_orientation", "orientation"), &TextParagraph::set_orientation); ClassDB::bind_method(D_METHOD("get_orientation"), &TextParagraph::get_orientation); @@ -304,6 +309,15 @@ TextServer::Direction TextParagraph::get_direction() const { return TS->shaped_text_get_direction(rid); } +void TextParagraph::set_custom_punctuation(const String &p_punct) { + TS->shaped_text_set_custom_punctuation(rid, p_punct); + lines_dirty = true; +} + +String TextParagraph::get_custom_punctuation() const { + return TS->shaped_text_get_custom_punctuation(rid); +} + void TextParagraph::set_orientation(TextServer::Orientation p_orientation) { TS->shaped_text_set_orientation(rid, p_orientation); TS->shaped_text_set_orientation(dropcap_rid, p_orientation); diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h index 69c50559df..59e68fa0ff 100644 --- a/scene/resources/text_paragraph.h +++ b/scene/resources/text_paragraph.h @@ -96,6 +96,9 @@ public: void set_bidi_override(const Array &p_override); + void set_custom_punctuation(const String &p_punct); + String get_custom_punctuation() const; + bool set_dropcap(const String &p_text, const Ref &p_fonts, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Dictionary &p_opentype_features = Dictionary(), const String &p_language = ""); void clear_dropcap(); diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp index a44fee7c95..26792a2c2d 100644 --- a/servers/text/text_server_extension.cpp +++ b/servers/text/text_server_extension.cpp @@ -185,6 +185,9 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_shaped_text_set_bidi_override, "shaped", "override"); + GDVIRTUAL_BIND(_shaped_text_set_custom_punctuation, "shaped", "punct"); + GDVIRTUAL_BIND(_shaped_text_get_custom_punctuation, "shaped"); + GDVIRTUAL_BIND(_shaped_text_set_orientation, "shaped", "orientation"); GDVIRTUAL_BIND(_shaped_text_get_orientation, "shaped"); @@ -906,6 +909,18 @@ void TextServerExtension::shaped_text_set_bidi_override(RID p_shaped, const Arra GDVIRTUAL_CALL(_shaped_text_set_bidi_override, p_shaped, p_override); } +void TextServerExtension::shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) { + GDVIRTUAL_CALL(_shaped_text_set_custom_punctuation, p_shaped, p_punct); +} + +String TextServerExtension::shaped_text_get_custom_punctuation(RID p_shaped) const { + String ret; + if (GDVIRTUAL_CALL(_shaped_text_get_custom_punctuation, p_shaped, ret)) { + return ret; + } + return String(); +} + void TextServerExtension::shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) { GDVIRTUAL_CALL(_shaped_text_set_preserve_invalid, p_shaped, p_enabled); } diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h index 88a8c0cb0c..aa965d94e3 100644 --- a/servers/text/text_server_extension.h +++ b/servers/text/text_server_extension.h @@ -300,6 +300,11 @@ public: virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override; GDVIRTUAL2(_shaped_text_set_bidi_override, RID, const Array &); + virtual void shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) override; + virtual String shaped_text_get_custom_punctuation(RID p_shaped) const override; + GDVIRTUAL2(_shaped_text_set_custom_punctuation, RID, String); + GDVIRTUAL1RC(String, _shaped_text_get_custom_punctuation, RID); + virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; virtual Orientation shaped_text_get_orientation(RID p_shaped) const override; GDVIRTUAL2(_shaped_text_set_orientation, RID, Orientation); diff --git a/servers/text_server.cpp b/servers/text_server.cpp index a365fde64a..37020db587 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -342,6 +342,9 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("shaped_text_set_bidi_override", "shaped", "override"), &TextServer::shaped_text_set_bidi_override); + ClassDB::bind_method(D_METHOD("shaped_text_set_custom_punctuation", "shaped", "punct"), &TextServer::shaped_text_set_custom_punctuation); + ClassDB::bind_method(D_METHOD("shaped_text_get_custom_punctuation", "shaped"), &TextServer::shaped_text_get_custom_punctuation); + ClassDB::bind_method(D_METHOD("shaped_text_set_orientation", "shaped", "orientation"), &TextServer::shaped_text_set_orientation, DEFVAL(ORIENTATION_HORIZONTAL)); ClassDB::bind_method(D_METHOD("shaped_text_get_orientation", "shaped"), &TextServer::shaped_text_get_orientation); diff --git a/servers/text_server.h b/servers/text_server.h index da62ff8ef4..7f450d6774 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -145,6 +145,7 @@ protected: int end = 0; // Substring end offset in the parent string. String text; + String custom_punct; TextServer::Direction direction = DIRECTION_LTR; // Desired text direction. TextServer::Orientation orientation = ORIENTATION_HORIZONTAL; @@ -357,6 +358,9 @@ public: virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) = 0; + virtual void shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) = 0; + virtual String shaped_text_get_custom_punctuation(RID p_shaped) const = 0; + virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) = 0; virtual Orientation shaped_text_get_orientation(RID p_shaped) const = 0;