Browse Source

Merge pull request #56860 from bruvzg/icu_case

Rémi Verschelde 3 years ago
parent
commit
57ad84537d

+ 28 - 5
doc/classes/TextServer.xml

@@ -21,8 +21,8 @@
 			<argument index="1" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
 			<description>
 				Creates new buffer for complex text layout, with the given [code]direction[/code] and [code]orientation[/code]. To free the resulting buffer, use [method free_rid] method.
-				[b]Note:[/b] Direction is ignored if server does not support [code]FEATURE_BIDI_LAYOUT[/code] feature.
-				[b]Note:[/b] Orientation is ignored if server does not support [code]FEATURE_VERTICAL_LAYOUT[/code] feature.
+				[b]Note:[/b] Direction is ignored if server does not support [constant FEATURE_BIDI_LAYOUT] feature (supported by [TextServerAdvanced]).
+				[b]Note:[/b] Orientation is ignored if server does not support [constant FEATURE_VERTICAL_LAYOUT] feature (supported by [TextServerAdvanced]).
 			</description>
 		</method>
 		<method name="draw_hex_code_box" qualifiers="const">
@@ -1263,7 +1263,7 @@
 			<argument index="1" name="direction" type="int" enum="TextServer.Direction" default="0" />
 			<description>
 				Sets desired text direction. If set to [code]TEXT_DIRECTION_AUTO[/code], direction will be detected based on the buffer contents and current locale.
-				[b]Note:[/b] Direction is ignored if server does not support [code]FEATURE_BIDI_LAYOUT[/code] feature.
+				[b]Note:[/b] Direction is ignored if server does not support [constant FEATURE_BIDI_LAYOUT] feature (supported by [TextServerAdvanced]).
 			</description>
 		</method>
 		<method name="shaped_text_set_orientation">
@@ -1272,7 +1272,7 @@
 			<argument index="1" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
 			<description>
 				Sets desired text orientation.
-				[b]Note:[/b] Orientation is ignored if server does not support [code]FEATURE_VERTICAL_LAYOUT[/code] feature.
+				[b]Note:[/b] Orientation is ignored if server does not support [constant FEATURE_VERTICAL_LAYOUT] feature (supported by [TextServerAdvanced]).
 			</description>
 		</method>
 		<method name="shaped_text_set_preserve_control">
@@ -1323,6 +1323,26 @@
 				Aligns shaped text to the given tab-stops.
 			</description>
 		</method>
+		<method name="string_to_lower" qualifiers="const">
+			<return type="String" />
+			<argument index="0" name="string" type="String" />
+			<argument index="1" name="language" type="String" default="&quot;&quot;" />
+			<description>
+				Returns the string converted to lowercase.
+				[b]Note:[/b] Casing is locale dependent and context sensitive if server support [constant FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION] feature (supported by [TextServerAdvanced]).
+				[b]Note:[/b] The result may be longer or shorter than the original.
+			</description>
+		</method>
+		<method name="string_to_upper" qualifiers="const">
+			<return type="String" />
+			<argument index="0" name="string" type="String" />
+			<argument index="1" name="language" type="String" default="&quot;&quot;" />
+			<description>
+				Returns the string converted to uppercase.
+				[b]Note:[/b] Casing is locale dependent and context sensitive if server support [constant FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION] feature (supported by [TextServerAdvanced]).
+				[b]Note:[/b] The result may be longer or shorter than the original.
+			</description>
+		</method>
 		<method name="strip_diacritics" qualifiers="const">
 			<return type="String" />
 			<argument index="0" name="string" type="String" />
@@ -1468,7 +1488,10 @@
 		<constant name="FEATURE_FONT_VARIABLE" value="64" enum="Feature">
 			TextServer supports variable fonts.
 		</constant>
-		<constant name="FEATURE_USE_SUPPORT_DATA" value="128" enum="Feature">
+		<constant name="FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION" value="128" enum="Feature">
+			TextServer supports locale dependent and context sensitive case conversion.
+		</constant>
+		<constant name="FEATURE_USE_SUPPORT_DATA" value="256" enum="Feature">
 			TextServer require external data file for some features.
 		</constant>
 		<constant name="CONTOUR_CURVE_TAG_ON" value="1" enum="ContourPointTag">

+ 16 - 0
doc/classes/TextServerExtension.xml

@@ -1348,6 +1348,22 @@
 				Updates justification opportunities (spaces, kashidas, etc.).
 			</description>
 		</method>
+		<method name="_string_to_lower" qualifiers="virtual const">
+			<return type="String" />
+			<argument index="0" name="string" type="String" />
+			<argument index="1" name="language" type="String" />
+			<description>
+				Returns the string converted to lowercase. Casing is locale dependent and context sensitive. The result may be longer or shorter than the original.
+			</description>
+		</method>
+		<method name="_string_to_upper" qualifiers="virtual const">
+			<return type="String" />
+			<argument index="0" name="string" type="String" />
+			<argument index="1" name="language" type="String" />
+			<description>
+				Returns the string converted to uppercase. Casing is locale dependent and context sensitive. The result may be longer or shorter than the original.
+			</description>
+		</method>
 		<method name="_tag_to_name" qualifiers="virtual const">
 			<return type="String" />
 			<argument index="0" name="tag" type="int" />

+ 35 - 1
modules/text_server_adv/text_server_adv.cpp

@@ -322,7 +322,7 @@ _FORCE_INLINE_ bool is_underscore(char32_t p_char) {
 /*************************************************************************/
 
 String TextServerAdvanced::interface_name = "ICU / HarfBuzz / Graphite";
-uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA | FEATURE_FONT_VARIABLE;
+uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA | FEATURE_FONT_VARIABLE | FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION;
 
 bool TextServerAdvanced::has_feature(Feature p_feature) const {
 	return (interface_features & p_feature) == p_feature;
@@ -5229,6 +5229,40 @@ String TextServerAdvanced::strip_diacritics(const String &p_string) const {
 	return result;
 }
 
+String TextServerAdvanced::string_to_upper(const String &p_string, const String &p_language) const {
+	// Convert to UTF-16.
+	Char16String utf16 = p_string.utf16();
+
+	Char16String upper;
+	UErrorCode err = U_ZERO_ERROR;
+	int32_t len = u_strToUpper(nullptr, 0, utf16.ptr(), -1, p_language.ascii().get_data(), &err);
+	ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));
+	upper.resize(len);
+	err = U_ZERO_ERROR;
+	u_strToUpper(upper.ptrw(), len, utf16.ptr(), -1, p_language.ascii().get_data(), &err);
+	ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));
+
+	// Convert back to UTF-32.
+	return String::utf16(upper.ptr(), len);
+}
+
+String TextServerAdvanced::string_to_lower(const String &p_string, const String &p_language) const {
+	// Convert to UTF-16.
+	Char16String utf16 = p_string.utf16();
+
+	Char16String lower;
+	UErrorCode err = U_ZERO_ERROR;
+	int32_t len = u_strToLower(nullptr, 0, utf16.ptr(), -1, p_language.ascii().get_data(), &err);
+	ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));
+	lower.resize(len);
+	err = U_ZERO_ERROR;
+	u_strToLower(lower.ptrw(), len, utf16.ptr(), -1, p_language.ascii().get_data(), &err);
+	ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));
+
+	// Convert back to UTF-32.
+	return String::utf16(lower.ptr(), len);
+}
+
 TextServerAdvanced::TextServerAdvanced() {
 	_insert_num_systems_lang();
 	_insert_feature_sets();

+ 3 - 0
modules/text_server_adv/text_server_adv.h

@@ -527,6 +527,9 @@ public:
 
 	virtual String strip_diacritics(const String &p_string) const override;
 
+	virtual String string_to_upper(const String &p_string, const String &p_language = "") const override;
+	virtual String string_to_lower(const String &p_string, const String &p_language = "") const override;
+
 	TextServerAdvanced();
 	~TextServerAdvanced();
 };

+ 29 - 0
modules/text_server_fb/text_server_fb.cpp

@@ -32,6 +32,7 @@
 
 #include "core/error/error_macros.h"
 #include "core/string/print_string.h"
+#include "core/string/ucaps.h"
 
 #include "modules/modules_enabled.gen.h" // For freetype, msdfgen.
 
@@ -3356,6 +3357,34 @@ float TextServerFallback::shaped_text_get_underline_thickness(RID p_shaped) cons
 	return sd->uthk;
 }
 
+String TextServerFallback::string_to_upper(const String &p_string, const String &p_language) const {
+	String upper = p_string;
+
+	for (int i = 0; i < upper.size(); i++) {
+		const char32_t s = upper[i];
+		const char32_t t = _find_upper(s);
+		if (s != t) { // avoid copy on write
+			upper[i] = t;
+		}
+	}
+
+	return upper;
+}
+
+String TextServerFallback::string_to_lower(const String &p_string, const String &p_language) const {
+	String lower = p_string;
+
+	for (int i = 0; i < lower.size(); i++) {
+		const char32_t s = lower[i];
+		const char32_t t = _find_lower(s);
+		if (s != t) { // avoid copy on write
+			lower[i] = t;
+		}
+	}
+
+	return lower;
+}
+
 TextServerFallback::TextServerFallback() {
 	_insert_feature_sets();
 };

+ 3 - 0
modules/text_server_fb/text_server_fb.h

@@ -430,6 +430,9 @@ public:
 	virtual float shaped_text_get_underline_position(RID p_shaped) const override;
 	virtual float shaped_text_get_underline_thickness(RID p_shaped) const override;
 
+	virtual String string_to_upper(const String &p_string, const String &p_language = "") const override;
+	virtual String string_to_lower(const String &p_string, const String &p_language = "") const override;
+
 	TextServerFallback();
 	~TextServerFallback();
 };

+ 3 - 2
scene/gui/label.cpp

@@ -83,6 +83,7 @@ void Label::_shape() {
 	int width = (get_size().width - style->get_minimum_size().width);
 
 	if (dirty) {
+		String lang = (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale();
 		TS->shaped_text_clear(text_rid);
 		if (text_direction == Control::TEXT_DIRECTION_INHERITED) {
 			TS->shaped_text_set_direction(text_rid, is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
@@ -92,11 +93,11 @@ void Label::_shape() {
 		const Ref<Font> &font = get_theme_font(SNAME("font"));
 		int font_size = get_theme_font_size(SNAME("font_size"));
 		ERR_FAIL_COND(font.is_null());
-		String text = (uppercase) ? xl_text.to_upper() : xl_text;
+		String text = (uppercase) ? TS->string_to_upper(xl_text, lang) : xl_text;
 		if (visible_chars >= 0 && visible_chars_behavior == VC_CHARS_BEFORE_SHAPING) {
 			text = text.substr(0, visible_chars);
 		}
-		TS->shaped_text_add_string(text_rid, text, font->get_rids(), font_size, opentype_features, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale());
+		TS->shaped_text_add_string(text_rid, text, font->get_rids(), font_size, opentype_features, lang);
 		TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, text));
 		dirty = false;
 		lines_dirty = true;

+ 19 - 0
servers/text/text_server_extension.cpp

@@ -271,6 +271,9 @@ void TextServerExtension::_bind_methods() {
 	GDVIRTUAL_BIND(_format_number, "string", "language");
 	GDVIRTUAL_BIND(_parse_number, "string", "language");
 	GDVIRTUAL_BIND(_percent_sign, "language");
+
+	GDVIRTUAL_BIND(_string_to_upper, "string", "language");
+	GDVIRTUAL_BIND(_string_to_lower, "string", "language");
 }
 
 bool TextServerExtension::has_feature(Feature p_feature) const {
@@ -1365,6 +1368,22 @@ String TextServerExtension::percent_sign(const String &p_language) const {
 	return TextServer::percent_sign(p_language);
 }
 
+String TextServerExtension::string_to_upper(const String &p_string, const String &p_language) const {
+	String ret;
+	if (GDVIRTUAL_CALL(_string_to_upper, p_string, p_language, ret)) {
+		return ret;
+	}
+	return p_string;
+}
+
+String TextServerExtension::string_to_lower(const String &p_string, const String &p_language) const {
+	String ret;
+	if (GDVIRTUAL_CALL(_string_to_lower, p_string, p_language, ret)) {
+		return ret;
+	}
+	return p_string;
+}
+
 TextServerExtension::TextServerExtension() {
 	//NOP
 }

+ 5 - 0
servers/text/text_server_extension.h

@@ -449,6 +449,11 @@ public:
 	GDVIRTUAL2RC(String, _parse_number, const String &, const String &);
 	GDVIRTUAL1RC(String, _percent_sign, const String &);
 
+	virtual String string_to_upper(const String &p_string, const String &p_language = "") const override;
+	virtual String string_to_lower(const String &p_string, const String &p_language = "") const override;
+	GDVIRTUAL2RC(String, _string_to_upper, const String &, const String &);
+	GDVIRTUAL2RC(String, _string_to_lower, const String &, const String &);
+
 	TextServerExtension();
 	~TextServerExtension();
 };

+ 4 - 0
servers/text_server.cpp

@@ -422,6 +422,9 @@ void TextServer::_bind_methods() {
 
 	ClassDB::bind_method(D_METHOD("strip_diacritics", "string"), &TextServer::strip_diacritics);
 
+	ClassDB::bind_method(D_METHOD("string_to_upper", "string", "language"), &TextServer::string_to_upper, DEFVAL(""));
+	ClassDB::bind_method(D_METHOD("string_to_lower", "string", "language"), &TextServer::string_to_lower, DEFVAL(""));
+
 	/* Direction */
 	BIND_ENUM_CONSTANT(DIRECTION_AUTO);
 	BIND_ENUM_CONSTANT(DIRECTION_LTR);
@@ -480,6 +483,7 @@ void TextServer::_bind_methods() {
 	BIND_ENUM_CONSTANT(FEATURE_BREAK_ITERATORS);
 	BIND_ENUM_CONSTANT(FEATURE_FONT_SYSTEM);
 	BIND_ENUM_CONSTANT(FEATURE_FONT_VARIABLE);
+	BIND_ENUM_CONSTANT(FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION);
 	BIND_ENUM_CONSTANT(FEATURE_USE_SUPPORT_DATA);
 
 	/* FT Contour Point Types */

+ 6 - 1
servers/text_server.h

@@ -109,7 +109,8 @@ public:
 		FEATURE_BREAK_ITERATORS = 1 << 4,
 		FEATURE_FONT_SYSTEM = 1 << 5,
 		FEATURE_FONT_VARIABLE = 1 << 6,
-		FEATURE_USE_SUPPORT_DATA = 1 << 7
+		FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION = 1 << 7,
+		FEATURE_USE_SUPPORT_DATA = 1 << 8,
 	};
 
 	enum ContourPointTag {
@@ -457,6 +458,10 @@ public:
 
 	virtual String strip_diacritics(const String &p_string) const;
 
+	// Other string operations.
+	virtual String string_to_upper(const String &p_string, const String &p_language = "") const = 0;
+	virtual String string_to_lower(const String &p_string, const String &p_language = "") const = 0;
+
 	TextServer();
 	~TextServer();
 };