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 e06dfee698e..808e1d9ac48 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 18ace85465b..3dec669b86d 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 29571463d27..6d89b9751e4 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 f5d159040f3..eaa8825a1d7 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 1feeada76de..afb46c22e2a 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 3d868d7be3f..ca735bdb6ca 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 992ce5018fb..f442f7e77e2 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 b2e18e24514..ff17683ad67 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 69c50559df0..59e68fa0ffc 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 a44fee7c95c..26792a2c2dd 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 88a8c0cb0cb..aa965d94e35 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 a365fde64a3..37020db5877 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 da62ff8ef47..7f450d67744 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;