Browse Source

Prefer family name in fonts' names table

Haoyu Qiu 1 year ago
parent
commit
9bcda8f94c

+ 7 - 3
core/string/ustring.cpp

@@ -2110,12 +2110,12 @@ CharString String::utf8() const {
 
 
 String String::utf16(const char16_t *p_utf16, int p_len) {
 String String::utf16(const char16_t *p_utf16, int p_len) {
 	String ret;
 	String ret;
-	ret.parse_utf16(p_utf16, p_len);
+	ret.parse_utf16(p_utf16, p_len, true);
 
 
 	return ret;
 	return ret;
 }
 }
 
 
-Error String::parse_utf16(const char16_t *p_utf16, int p_len) {
+Error String::parse_utf16(const char16_t *p_utf16, int p_len, bool p_default_little_endian) {
 	if (!p_utf16) {
 	if (!p_utf16) {
 		return ERR_INVALID_DATA;
 		return ERR_INVALID_DATA;
 	}
 	}
@@ -2125,8 +2125,12 @@ Error String::parse_utf16(const char16_t *p_utf16, int p_len) {
 	int cstr_size = 0;
 	int cstr_size = 0;
 	int str_size = 0;
 	int str_size = 0;
 
 
+#ifdef BIG_ENDIAN_ENABLED
+	bool byteswap = p_default_little_endian;
+#else
+	bool byteswap = !p_default_little_endian;
+#endif
 	/* HANDLE BOM (Byte Order Mark) */
 	/* HANDLE BOM (Byte Order Mark) */
-	bool byteswap = false; // assume correct endianness if no BOM found
 	if (p_len < 0 || p_len >= 1) {
 	if (p_len < 0 || p_len >= 1) {
 		bool has_bom = false;
 		bool has_bom = false;
 		if (uint16_t(p_utf16[0]) == 0xfeff) { // correct BOM, read as is
 		if (uint16_t(p_utf16[0]) == 0xfeff) { // correct BOM, read as is

+ 1 - 1
core/string/ustring.h

@@ -393,7 +393,7 @@ public:
 	static String utf8(const char *p_utf8, int p_len = -1);
 	static String utf8(const char *p_utf8, int p_len = -1);
 
 
 	Char16String utf16() const;
 	Char16String utf16() const;
-	Error parse_utf16(const char16_t *p_utf16, int p_len = -1);
+	Error parse_utf16(const char16_t *p_utf16, int p_len = -1, bool p_default_little_endian = true);
 	static String utf16(const char16_t *p_utf16, int p_len = -1);
 	static String utf16(const char16_t *p_utf16, int p_len = -1);
 
 
 	static uint32_t hash(const char32_t *p_cstr, int p_len); /* hash the string */
 	static uint32_t hash(const char32_t *p_cstr, int p_len); /* hash the string */

+ 19 - 3
modules/text_server_adv/text_server_adv.cpp

@@ -1432,8 +1432,25 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
 #endif
 #endif
 
 
 		if (!p_font_data->face_init) {
 		if (!p_font_data->face_init) {
-			// Get style flags and name.
-			if (fd->face->family_name != nullptr) {
+			// When a font does not provide a `family_name`, FreeType tries to synthesize one based on other names.
+			// FreeType automatically converts non-ASCII characters to "?" in the synthesized name.
+			// To avoid that behavior, use the format-specific name directly if available.
+			hb_face_t *hb_face = hb_font_get_face(fd->hb_handle);
+			unsigned int num_entries = 0;
+			const hb_ot_name_entry_t *names = hb_ot_name_list_names(hb_face, &num_entries);
+			const hb_language_t english = hb_language_from_string("en", -1);
+			for (unsigned int i = 0; i < num_entries; i++) {
+				if (names[i].name_id != HB_OT_NAME_ID_FONT_FAMILY) {
+					continue;
+				}
+				if (!p_font_data->font_name.is_empty() && names[i].language != english) {
+					continue;
+				}
+				unsigned int text_size = hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, nullptr, nullptr) + 1;
+				p_font_data->font_name.resize(text_size);
+				hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, &text_size, (uint32_t *)p_font_data->font_name.ptrw());
+			}
+			if (p_font_data->font_name.is_empty() && fd->face->family_name != nullptr) {
 				p_font_data->font_name = String::utf8((const char *)fd->face->family_name);
 				p_font_data->font_name = String::utf8((const char *)fd->face->family_name);
 			}
 			}
 			if (fd->face->style_name != nullptr) {
 			if (fd->face->style_name != nullptr) {
@@ -1452,7 +1469,6 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
 				p_font_data->style_flags.set_flag(FONT_FIXED_WIDTH);
 				p_font_data->style_flags.set_flag(FONT_FIXED_WIDTH);
 			}
 			}
 
 
-			hb_face_t *hb_face = hb_font_get_face(fd->hb_handle);
 			// Get supported scripts from OpenType font data.
 			// Get supported scripts from OpenType font data.
 			p_font_data->supported_scripts.clear();
 			p_font_data->supported_scripts.clear();
 			unsigned int count = hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, nullptr, nullptr);
 			unsigned int count = hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, nullptr, nullptr);

+ 34 - 3
modules/text_server_fb/text_server_fb.cpp

@@ -71,8 +71,10 @@ using namespace godot;
 #endif
 #endif
 #endif
 #endif
 
 
-#ifdef MODULE_SVG_ENABLED
 #ifdef MODULE_FREETYPE_ENABLED
 #ifdef MODULE_FREETYPE_ENABLED
+#include FT_SFNT_NAMES_H
+#include FT_TRUETYPE_IDS_H
+#ifdef MODULE_SVG_ENABLED
 #include "thorvg_svg_in_ot.h"
 #include "thorvg_svg_in_ot.h"
 #endif
 #endif
 #endif
 #endif
@@ -857,8 +859,37 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f
 		fd->underline_thickness = (FT_MulFix(fd->face->underline_thickness, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale;
 		fd->underline_thickness = (FT_MulFix(fd->face->underline_thickness, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale;
 
 
 		if (!p_font_data->face_init) {
 		if (!p_font_data->face_init) {
-			// Get style flags and name.
-			if (fd->face->family_name != nullptr) {
+			// When a font does not provide a `family_name`, FreeType tries to synthesize one based on other names.
+			// FreeType automatically converts non-ASCII characters to "?" in the synthesized name.
+			// To avoid that behavior, use the format-specific name directly if available.
+			if (FT_IS_SFNT(fd->face)) {
+				int name_count = FT_Get_Sfnt_Name_Count(fd->face);
+				for (int i = 0; i < name_count; i++) {
+					FT_SfntName sfnt_name;
+					if (FT_Get_Sfnt_Name(fd->face, i, &sfnt_name) != 0) {
+						continue;
+					}
+					if (sfnt_name.name_id != TT_NAME_ID_FONT_FAMILY && sfnt_name.name_id != TT_NAME_ID_TYPOGRAPHIC_FAMILY) {
+						continue;
+					}
+					if (!p_font_data->font_name.is_empty() && sfnt_name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES) {
+						continue;
+					}
+
+					switch (sfnt_name.platform_id) {
+						case TT_PLATFORM_APPLE_UNICODE: {
+							p_font_data->font_name.parse_utf16((const char16_t *)sfnt_name.string, sfnt_name.string_len / 2, false);
+						} break;
+
+						case TT_PLATFORM_MICROSOFT: {
+							if (sfnt_name.encoding_id == TT_MS_ID_UNICODE_CS || sfnt_name.encoding_id == TT_MS_ID_UCS_4) {
+								p_font_data->font_name.parse_utf16((const char16_t *)sfnt_name.string, sfnt_name.string_len / 2, false);
+							}
+						} break;
+					}
+				}
+			}
+			if (p_font_data->font_name.is_empty() && fd->face->family_name != nullptr) {
 				p_font_data->font_name = String::utf8((const char *)fd->face->family_name);
 				p_font_data->font_name = String::utf8((const char *)fd->face->family_name);
 			}
 			}
 			if (fd->face->style_name != nullptr) {
 			if (fd->face->style_name != nullptr) {