Browse Source

Merge pull request #61772 from bruvzg/ft_ot_collect

Rémi Verschelde 3 years ago
parent
commit
136f84fc35

+ 12 - 2
doc/classes/FontData.xml

@@ -3,7 +3,7 @@
 	<brief_description>
 	<brief_description>
 		Font source data and prerendered glyph cache, imported from dynamic or bitmap font.
 		Font source data and prerendered glyph cache, imported from dynamic or bitmap font.
 		Supported font formats:
 		Supported font formats:
-		- Dynamic font importer: TrueType (.ttf), OpenType (.otf), WOFF (.woff), WOFF2 (.woff2), Type 1 (.pfb, .pfm).
+		- Dynamic font importer: TrueType (.ttf), TrueType collection (.ttc), OpenType (.otf), OpenType collection (.otc), WOFF (.woff), WOFF2 (.woff2), Type 1 (.pfb, .pfm).
 		- Bitmap font importer: AngelCode BMFont (.fnt, .font), text and binary (version 3) format variants.
 		- Bitmap font importer: AngelCode BMFont (.fnt, .font), text and binary (version 3) format variants.
 		- Monospace image font importer: All supported image formats.
 		- Monospace image font importer: All supported image formats.
 	</brief_description>
 	</brief_description>
@@ -87,6 +87,12 @@
 				Returns font descent (number of pixels below the baseline).
 				Returns font descent (number of pixels below the baseline).
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="get_face_count" qualifiers="const">
+			<return type="int" />
+			<description>
+				Returns number of faces in the TrueType / OpenType collection.
+			</description>
+		</method>
 		<method name="get_glyph_advance" qualifiers="const">
 		<method name="get_glyph_advance" qualifiers="const">
 			<return type="Vector2" />
 			<return type="Vector2" />
 			<argument index="0" name="cache_index" type="int" />
 			<argument index="0" name="cache_index" type="int" />
@@ -318,7 +324,8 @@
 			<return type="int" enum="Error" />
 			<return type="int" enum="Error" />
 			<argument index="0" name="path" type="String" />
 			<argument index="0" name="path" type="String" />
 			<description>
 			<description>
-				Loads a TrueType (.ttf), OpenType (.otf), WOFF (.woff), WOFF2 (.woff2) or Type 1 (.pfb, .pfm) dynamic font from file [code]path[/code].
+				Loads a TrueType (.ttf), TrueType collection (.ttc), OpenType (.otf), OpenType collection (.otc), WOFF (.woff), WOFF2 (.woff2) or Type 1 (.pfb, .pfm) dynamic font from file [code]path[/code].
+				[b]Note:[/b] Use [member face_index] to select specific face from the collection file.
 				[b]Warning:[/b] This method should only be used in the editor or in cases when you need to load external fonts at run-time, such as fonts located at the [code]user://[/code] directory.
 				[b]Warning:[/b] This method should only be used in the editor or in cases when you need to load external fonts at run-time, such as fonts located at the [code]user://[/code] directory.
 			</description>
 			</description>
 		</method>
 		</method>
@@ -570,6 +577,9 @@
 		<member name="embolden" type="float" setter="set_embolden" getter="get_embolden" default="0.0">
 		<member name="embolden" type="float" setter="set_embolden" getter="get_embolden" default="0.0">
 			If is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness.
 			If is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness.
 		</member>
 		</member>
+		<member name="face_index" type="int" setter="set_face_index" getter="get_face_index" default="0">
+			Active face index in the TrueType / OpenType collection file.
+		</member>
 		<member name="fixed_size" type="int" setter="set_fixed_size" getter="get_fixed_size" default="0">
 		<member name="fixed_size" type="int" setter="set_fixed_size" getter="get_fixed_size" default="0">
 			Font size, used only for the bitmap fonts.
 			Font size, used only for the bitmap fonts.
 		</member>
 		</member>

+ 22 - 0
doc/classes/TextServer.xml

@@ -121,6 +121,20 @@
 				Returns font embolden strength.
 				Returns font embolden strength.
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="font_get_face_count" qualifiers="const">
+			<return type="int" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Returns number of faces in the TrueType / OpenType collection.
+			</description>
+		</method>
+		<method name="font_get_face_index" qualifiers="const">
+			<return type="int" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Recturns an active face index in the TrueType / OpenType collection.
+			</description>
+		</method>
 		<method name="font_get_fixed_size" qualifiers="const">
 		<method name="font_get_fixed_size" qualifiers="const">
 			<return type="int" />
 			<return type="int" />
 			<argument index="0" name="font_rid" type="RID" />
 			<argument index="0" name="font_rid" type="RID" />
@@ -593,6 +607,14 @@
 				Sets font embolden strength. If [code]strength[/code] is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness.
 				Sets font embolden strength. If [code]strength[/code] is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness.
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="font_set_face_index">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="face_index" type="int" />
+			<description>
+				Sets an active face index in the TrueType / OpenType collection.
+			</description>
+		</method>
 		<method name="font_set_fixed_size">
 		<method name="font_set_fixed_size">
 			<return type="void" />
 			<return type="void" />
 			<argument index="0" name="font_rid" type="RID" />
 			<argument index="0" name="font_rid" type="RID" />

+ 22 - 0
doc/classes/TextServerExtension.xml

@@ -114,6 +114,20 @@
 				Returns font embolden strength.
 				Returns font embolden strength.
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="font_get_face_count" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Returns number of faces in the TrueType / OpenType collection.
+			</description>
+		</method>
+		<method name="font_get_face_index" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Returns an active face index in the TrueType / OpenType collection.
+			</description>
+		</method>
 		<method name="font_get_fixed_size" qualifiers="virtual const">
 		<method name="font_get_fixed_size" qualifiers="virtual const">
 			<return type="int" />
 			<return type="int" />
 			<argument index="0" name="font_rid" type="RID" />
 			<argument index="0" name="font_rid" type="RID" />
@@ -590,6 +604,14 @@
 				Sets font embolden strength. If [code]strength[/code] is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness.
 				Sets font embolden strength. If [code]strength[/code] is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness.
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="font_set_face_index" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="face_index" type="int" />
+			<description>
+				Sets an active face index in the TrueType / OpenType collection.
+			</description>
+		</method>
 		<method name="font_set_fixed_size" qualifiers="virtual">
 		<method name="font_set_fixed_size" qualifiers="virtual">
 			<return type="void" />
 			<return type="void" />
 			<argument index="0" name="font_rid" type="RID" />
 			<argument index="0" name="font_rid" type="RID" />

+ 8 - 1
editor/import/dynamic_font_import_settings.cpp

@@ -454,7 +454,11 @@ void DynamicFontImportSettings::_add_glyph_range_item(int32_t p_start, int32_t p
 void DynamicFontImportSettings::_main_prop_changed(const String &p_edited_property) {
 void DynamicFontImportSettings::_main_prop_changed(const String &p_edited_property) {
 	// Update font preview.
 	// Update font preview.
 
 
-	if (p_edited_property == "antialiased") {
+	if (p_edited_property == "face_index") {
+		if (font_preview->get_data_count() > 0) {
+			font_preview->get_data(0)->set_face_index(import_settings_data->get("face_index"));
+		}
+	} else if (p_edited_property == "antialiased") {
 		if (font_preview->get_data_count() > 0) {
 		if (font_preview->get_data_count() > 0) {
 			font_preview->get_data(0)->set_antialiased(import_settings_data->get("antialiased"));
 			font_preview->get_data(0)->set_antialiased(import_settings_data->get("antialiased"));
 		}
 		}
@@ -945,6 +949,7 @@ void DynamicFontImportSettings::_notification(int p_what) {
 void DynamicFontImportSettings::_re_import() {
 void DynamicFontImportSettings::_re_import() {
 	HashMap<StringName, Variant> main_settings;
 	HashMap<StringName, Variant> main_settings;
 
 
+	main_settings["face_index"] = import_settings_data->get("face_index");
 	main_settings["antialiased"] = import_settings_data->get("antialiased");
 	main_settings["antialiased"] = import_settings_data->get("antialiased");
 	main_settings["generate_mipmaps"] = import_settings_data->get("generate_mipmaps");
 	main_settings["generate_mipmaps"] = import_settings_data->get("generate_mipmaps");
 	main_settings["multichannel_signed_distance_field"] = import_settings_data->get("multichannel_signed_distance_field");
 	main_settings["multichannel_signed_distance_field"] = import_settings_data->get("multichannel_signed_distance_field");
@@ -1299,6 +1304,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) {
 	import_settings_data->notify_property_list_changed();
 	import_settings_data->notify_property_list_changed();
 
 
 	if (font_preview->get_data_count() > 0) {
 	if (font_preview->get_data_count() > 0) {
+		font_preview->get_data(0)->set_face_index(import_settings_data->get("face_index"));
 		font_preview->get_data(0)->set_antialiased(import_settings_data->get("antialiased"));
 		font_preview->get_data(0)->set_antialiased(import_settings_data->get("antialiased"));
 		font_preview->get_data(0)->set_multichannel_signed_distance_field(import_settings_data->get("multichannel_signed_distance_field"));
 		font_preview->get_data(0)->set_multichannel_signed_distance_field(import_settings_data->get("multichannel_signed_distance_field"));
 		font_preview->get_data(0)->set_msdf_pixel_range(import_settings_data->get("msdf_pixel_range"));
 		font_preview->get_data(0)->set_msdf_pixel_range(import_settings_data->get("msdf_pixel_range"));
@@ -1360,6 +1366,7 @@ DynamicFontImportSettings *DynamicFontImportSettings::get_singleton() {
 DynamicFontImportSettings::DynamicFontImportSettings() {
 DynamicFontImportSettings::DynamicFontImportSettings() {
 	singleton = this;
 	singleton = this;
 
 
+	options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "face_index"), 0));
 	options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "antialiased"), true));
 	options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "antialiased"), true));
 	options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "generate_mipmaps"), false));
 	options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "generate_mipmaps"), false));
 	options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
 	options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));

+ 7 - 0
editor/import/resource_importer_dynamic_font.cpp

@@ -50,7 +50,9 @@ void ResourceImporterDynamicFont::get_recognized_extensions(List<String> *p_exte
 	if (p_extensions) {
 	if (p_extensions) {
 #ifdef MODULE_FREETYPE_ENABLED
 #ifdef MODULE_FREETYPE_ENABLED
 		p_extensions->push_back("ttf");
 		p_extensions->push_back("ttf");
+		p_extensions->push_back("ttc");
 		p_extensions->push_back("otf");
 		p_extensions->push_back("otf");
+		p_extensions->push_back("otc");
 		p_extensions->push_back("woff");
 		p_extensions->push_back("woff");
 		p_extensions->push_back("woff2");
 		p_extensions->push_back("woff2");
 		p_extensions->push_back("pfb");
 		p_extensions->push_back("pfb");
@@ -101,6 +103,8 @@ String ResourceImporterDynamicFont::get_preset_name(int p_idx) const {
 void ResourceImporterDynamicFont::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const {
 void ResourceImporterDynamicFont::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const {
 	bool msdf = p_preset == PRESET_MSDF;
 	bool msdf = p_preset == PRESET_MSDF;
 
 
+	r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "face_index"), 0));
+
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "antialiased"), true));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "antialiased"), true));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_mipmaps"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_mipmaps"), false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), (msdf) ? true : false));
 	r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), (msdf) ? true : false));
@@ -179,6 +183,8 @@ void ResourceImporterDynamicFont::show_advanced_options(const String &p_path) {
 Error ResourceImporterDynamicFont::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
 Error ResourceImporterDynamicFont::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
 	print_verbose("Importing dynamic font from: " + p_source_file);
 	print_verbose("Importing dynamic font from: " + p_source_file);
 
 
+	int face_index = p_options["face_index"];
+
 	bool antialiased = p_options["antialiased"];
 	bool antialiased = p_options["antialiased"];
 	bool generate_mipmaps = p_options["generate_mipmaps"];
 	bool generate_mipmaps = p_options["generate_mipmaps"];
 	bool msdf = p_options["multichannel_signed_distance_field"];
 	bool msdf = p_options["multichannel_signed_distance_field"];
@@ -200,6 +206,7 @@ Error ResourceImporterDynamicFont::import(const String &p_source_file, const Str
 	Ref<FontData> font;
 	Ref<FontData> font;
 	font.instantiate();
 	font.instantiate();
 	font->set_data(data);
 	font->set_data(data);
+	font->set_face_index(face_index);
 	font->set_antialiased(antialiased);
 	font->set_antialiased(antialiased);
 	font->set_generate_mipmaps(generate_mipmaps);
 	font->set_generate_mipmaps(generate_mipmaps);
 	font->set_multichannel_signed_distance_field(msdf);
 	font->set_multichannel_signed_distance_field(msdf);

+ 73 - 1
modules/text_server_adv/text_server_adv.cpp

@@ -1288,7 +1288,16 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
 		fargs.memory_size = p_font_data->data_size;
 		fargs.memory_size = p_font_data->data_size;
 		fargs.flags = FT_OPEN_MEMORY;
 		fargs.flags = FT_OPEN_MEMORY;
 		fargs.stream = &fd->stream;
 		fargs.stream = &fd->stream;
-		error = FT_Open_Face(ft_library, &fargs, 0, &fd->face);
+
+		int max_index = 0;
+		FT_Face tmp_face;
+		error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
+		if (error == 0) {
+			max_index = tmp_face->num_faces - 1;
+		}
+		FT_Done_Face(tmp_face);
+
+		error = FT_Open_Face(ft_library, &fargs, CLAMP(p_font_data->face_index, 0, max_index), &fd->face);
 		if (error) {
 		if (error) {
 			FT_Done_Face(fd->face);
 			FT_Done_Face(fd->face);
 			fd->face = nullptr;
 			fd->face = nullptr;
@@ -1720,6 +1729,69 @@ void TextServerAdvanced::font_set_data_ptr(const RID &p_font_rid, const uint8_t
 	fd->data_size = p_data_size;
 	fd->data_size = p_data_size;
 }
 }
 
 
+void TextServerAdvanced::font_set_face_index(const RID &p_font_rid, int64_t p_face_index) {
+	ERR_FAIL_COND(p_face_index < 0);
+	ERR_FAIL_COND(p_face_index >= 0x7FFF);
+
+	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+	ERR_FAIL_COND(!fd);
+
+	MutexLock lock(fd->mutex);
+	if (fd->face_index != p_face_index) {
+		fd->face_index = p_face_index;
+		_font_clear_cache(fd);
+	}
+}
+
+int64_t TextServerAdvanced::font_get_face_index(const RID &p_font_rid) const {
+	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+	ERR_FAIL_COND_V(!fd, 0);
+
+	MutexLock lock(fd->mutex);
+	return fd->face_index;
+}
+
+int64_t TextServerAdvanced::font_get_face_count(const RID &p_font_rid) const {
+	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+	ERR_FAIL_COND_V(!fd, 0);
+
+	MutexLock lock(fd->mutex);
+	int face_count = 0;
+
+	if (fd->data_ptr && (fd->data_size > 0)) {
+		// Init dynamic font.
+#ifdef MODULE_FREETYPE_ENABLED
+		int error = 0;
+		if (!ft_library) {
+			error = FT_Init_FreeType(&ft_library);
+			ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+		}
+
+		FT_StreamRec stream;
+		memset(&stream, 0, sizeof(FT_StreamRec));
+		stream.base = (unsigned char *)fd->data_ptr;
+		stream.size = fd->data_size;
+		stream.pos = 0;
+
+		FT_Open_Args fargs;
+		memset(&fargs, 0, sizeof(FT_Open_Args));
+		fargs.memory_base = (unsigned char *)fd->data_ptr;
+		fargs.memory_size = fd->data_size;
+		fargs.flags = FT_OPEN_MEMORY;
+		fargs.stream = &stream;
+
+		FT_Face tmp_face;
+		error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
+		if (error == 0) {
+			face_count = tmp_face->num_faces;
+		}
+		FT_Done_Face(tmp_face);
+#endif
+	}
+
+	return face_count;
+}
+
 void TextServerAdvanced::font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) {
 void TextServerAdvanced::font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) {
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 	ERR_FAIL_COND(!fd);

+ 6 - 0
modules/text_server_adv/text_server_adv.h

@@ -247,6 +247,7 @@ class TextServerAdvanced : public TextServerExtension {
 		PackedByteArray data;
 		PackedByteArray data;
 		const uint8_t *data_ptr;
 		const uint8_t *data_ptr;
 		size_t data_size;
 		size_t data_size;
+		int face_index = 0;
 		mutable ThreadWorkPool work_pool;
 		mutable ThreadWorkPool work_pool;
 
 
 		~FontDataAdvanced() {
 		~FontDataAdvanced() {
@@ -473,6 +474,11 @@ public:
 	virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) override;
 	virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) override;
 	virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) override;
 	virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) override;
 
 
+	virtual void font_set_face_index(const RID &p_font_rid, int64_t p_index) override;
+	virtual int64_t font_get_face_index(const RID &p_font_rid) const override;
+
+	virtual int64_t font_get_face_count(const RID &p_font_rid) const override;
+
 	virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) override;
 	virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) override;
 	virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const override;
 	virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const override;
 
 

+ 73 - 1
modules/text_server_fb/text_server_fb.cpp

@@ -733,7 +733,16 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
 		fargs.memory_size = p_font_data->data_size;
 		fargs.memory_size = p_font_data->data_size;
 		fargs.flags = FT_OPEN_MEMORY;
 		fargs.flags = FT_OPEN_MEMORY;
 		fargs.stream = &fd->stream;
 		fargs.stream = &fd->stream;
-		error = FT_Open_Face(ft_library, &fargs, 0, &fd->face);
+
+		int max_index = 0;
+		FT_Face tmp_face;
+		error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
+		if (error == 0) {
+			max_index = tmp_face->num_faces - 1;
+		}
+		FT_Done_Face(tmp_face);
+
+		error = FT_Open_Face(ft_library, &fargs, CLAMP(p_font_data->face_index, 0, max_index), &fd->face);
 		if (error) {
 		if (error) {
 			FT_Done_Face(fd->face);
 			FT_Done_Face(fd->face);
 			fd->face = nullptr;
 			fd->face = nullptr;
@@ -892,6 +901,69 @@ void TextServerFallback::font_set_style(const RID &p_font_rid, int64_t /*FontSty
 	fd->style_flags = p_style;
 	fd->style_flags = p_style;
 }
 }
 
 
+void TextServerFallback::font_set_face_index(const RID &p_font_rid, int64_t p_face_index) {
+	ERR_FAIL_COND(p_face_index < 0);
+	ERR_FAIL_COND(p_face_index >= 0x7FFF);
+
+	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
+	ERR_FAIL_COND(!fd);
+
+	MutexLock lock(fd->mutex);
+	if (fd->face_index != p_face_index) {
+		fd->face_index = p_face_index;
+		_font_clear_cache(fd);
+	}
+}
+
+int64_t TextServerFallback::font_get_face_index(const RID &p_font_rid) const {
+	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
+	ERR_FAIL_COND_V(!fd, 0);
+
+	MutexLock lock(fd->mutex);
+	return fd->face_index;
+}
+
+int64_t TextServerFallback::font_get_face_count(const RID &p_font_rid) const {
+	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
+	ERR_FAIL_COND_V(!fd, 0);
+
+	MutexLock lock(fd->mutex);
+	int face_count = 0;
+
+	if (fd->data_ptr && (fd->data_size > 0)) {
+		// Init dynamic font.
+#ifdef MODULE_FREETYPE_ENABLED
+		int error = 0;
+		if (!ft_library) {
+			error = FT_Init_FreeType(&ft_library);
+			ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+		}
+
+		FT_StreamRec stream;
+		memset(&stream, 0, sizeof(FT_StreamRec));
+		stream.base = (unsigned char *)fd->data_ptr;
+		stream.size = fd->data_size;
+		stream.pos = 0;
+
+		FT_Open_Args fargs;
+		memset(&fargs, 0, sizeof(FT_Open_Args));
+		fargs.memory_base = (unsigned char *)fd->data_ptr;
+		fargs.memory_size = fd->data_size;
+		fargs.flags = FT_OPEN_MEMORY;
+		fargs.stream = &stream;
+
+		FT_Face tmp_face;
+		error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
+		if (error == 0) {
+			face_count = tmp_face->num_faces;
+		}
+		FT_Done_Face(tmp_face);
+#endif
+	}
+
+	return face_count;
+}
+
 int64_t /*FontStyle*/ TextServerFallback::font_get_style(const RID &p_font_rid) const {
 int64_t /*FontStyle*/ TextServerFallback::font_get_style(const RID &p_font_rid) const {
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0);
 	ERR_FAIL_COND_V(!fd, 0);

+ 6 - 0
modules/text_server_fb/text_server_fb.h

@@ -209,6 +209,7 @@ class TextServerFallback : public TextServerExtension {
 		PackedByteArray data;
 		PackedByteArray data;
 		const uint8_t *data_ptr;
 		const uint8_t *data_ptr;
 		size_t data_size;
 		size_t data_size;
+		int face_index = 0;
 
 
 		mutable ThreadWorkPool work_pool;
 		mutable ThreadWorkPool work_pool;
 
 
@@ -364,6 +365,11 @@ public:
 	virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) override;
 	virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) override;
 	virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) override;
 	virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) override;
 
 
+	virtual void font_set_face_index(const RID &p_font_rid, int64_t p_index) override;
+	virtual int64_t font_get_face_index(const RID &p_font_rid) const override;
+
+	virtual int64_t font_get_face_count(const RID &p_font_rid) const override;
+
 	virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) override;
 	virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) override;
 	virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const override;
 	virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const override;
 
 

+ 33 - 0
scene/resources/font.cpp

@@ -54,6 +54,7 @@ _FORCE_INLINE_ void FontData::_ensure_rid(int p_cache_index) const {
 	if (unlikely(!cache[p_cache_index].is_valid())) {
 	if (unlikely(!cache[p_cache_index].is_valid())) {
 		cache.write[p_cache_index] = TS->create_font();
 		cache.write[p_cache_index] = TS->create_font();
 		TS->font_set_data_ptr(cache[p_cache_index], data_ptr, data_size);
 		TS->font_set_data_ptr(cache[p_cache_index], data_ptr, data_size);
+		TS->font_set_face_index(cache[p_cache_index], face_index);
 		TS->font_set_antialiased(cache[p_cache_index], antialiased);
 		TS->font_set_antialiased(cache[p_cache_index], antialiased);
 		TS->font_set_generate_mipmaps(cache[p_cache_index], mipmaps);
 		TS->font_set_generate_mipmaps(cache[p_cache_index], mipmaps);
 		TS->font_set_multichannel_signed_distance_field(cache[p_cache_index], msdf);
 		TS->font_set_multichannel_signed_distance_field(cache[p_cache_index], msdf);
@@ -76,6 +77,11 @@ void FontData::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_data", "data"), &FontData::set_data);
 	ClassDB::bind_method(D_METHOD("set_data", "data"), &FontData::set_data);
 	ClassDB::bind_method(D_METHOD("get_data"), &FontData::get_data);
 	ClassDB::bind_method(D_METHOD("get_data"), &FontData::get_data);
 
 
+	ClassDB::bind_method(D_METHOD("set_face_index", "face_index"), &FontData::set_face_index);
+	ClassDB::bind_method(D_METHOD("get_face_index"), &FontData::get_face_index);
+
+	ClassDB::bind_method(D_METHOD("get_face_count"), &FontData::get_face_count);
+
 	ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontData::set_antialiased);
 	ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontData::set_antialiased);
 	ClassDB::bind_method(D_METHOD("is_antialiased"), &FontData::is_antialiased);
 	ClassDB::bind_method(D_METHOD("is_antialiased"), &FontData::is_antialiased);
 
 
@@ -217,6 +223,7 @@ void FontData::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_supported_variation_list"), &FontData::get_supported_variation_list);
 	ClassDB::bind_method(D_METHOD("get_supported_variation_list"), &FontData::get_supported_variation_list);
 
 
 	ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_data", "get_data");
 	ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_data", "get_data");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "face_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_face_index", "get_face_index");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_generate_mipmaps", "get_generate_mipmaps");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_generate_mipmaps", "get_generate_mipmaps");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_antialiased", "is_antialiased");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_antialiased", "is_antialiased");
 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "font_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_name", "get_font_name");
 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "font_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_name", "get_font_name");
@@ -445,6 +452,7 @@ void FontData::reset_state() {
 	data.clear();
 	data.clear();
 	data_ptr = nullptr;
 	data_ptr = nullptr;
 	data_size = 0;
 	data_size = 0;
+	face_index = 0;
 	cache.clear();
 	cache.clear();
 
 
 	antialiased = true;
 	antialiased = true;
@@ -1244,6 +1252,31 @@ void FontData::set_data(const PackedByteArray &p_data) {
 	}
 	}
 }
 }
 
 
+void FontData::set_face_index(int64_t p_index) {
+	ERR_FAIL_COND(p_index < 0);
+	ERR_FAIL_COND(p_index >= 0x7FFF);
+
+	if (face_index != p_index) {
+		face_index = p_index;
+		if (data_ptr != nullptr) {
+			for (int i = 0; i < cache.size(); i++) {
+				if (cache[i].is_valid()) {
+					TS->font_set_face_index(cache[i], face_index);
+				}
+			}
+		}
+	}
+}
+
+int64_t FontData::get_face_index() const {
+	return face_index;
+}
+
+int64_t FontData::get_face_count() const {
+	_ensure_rid(0);
+	return TS->font_get_face_count(cache[0]);
+}
+
 PackedByteArray FontData::get_data() const {
 PackedByteArray FontData::get_data() const {
 	if (unlikely((size_t)data.size() != data_size)) {
 	if (unlikely((size_t)data.size() != data_size)) {
 		PackedByteArray *data_w = const_cast<PackedByteArray *>(&data);
 		PackedByteArray *data_w = const_cast<PackedByteArray *>(&data);

+ 6 - 0
scene/resources/font.h

@@ -46,6 +46,7 @@ class FontData : public Resource {
 	// Font source data.
 	// Font source data.
 	const uint8_t *data_ptr = nullptr;
 	const uint8_t *data_ptr = nullptr;
 	size_t data_size = 0;
 	size_t data_size = 0;
+	int face_index = 0;
 	PackedByteArray data;
 	PackedByteArray data;
 
 
 	bool antialiased = true;
 	bool antialiased = true;
@@ -91,6 +92,11 @@ public:
 	virtual void set_data(const PackedByteArray &p_data);
 	virtual void set_data(const PackedByteArray &p_data);
 	virtual PackedByteArray get_data() const;
 	virtual PackedByteArray get_data() const;
 
 
+	virtual void set_face_index(int64_t p_index);
+	virtual int64_t get_face_index() const;
+
+	virtual int64_t get_face_count() const;
+
 	// Common properties.
 	// Common properties.
 	virtual void set_font_name(const String &p_name);
 	virtual void set_font_name(const String &p_name);
 	virtual String get_font_name() const;
 	virtual String get_font_name() const;

+ 25 - 0
servers/text/text_server_extension.cpp

@@ -55,6 +55,11 @@ void TextServerExtension::_bind_methods() {
 	GDVIRTUAL_BIND(font_set_data, "font_rid", "data");
 	GDVIRTUAL_BIND(font_set_data, "font_rid", "data");
 	GDVIRTUAL_BIND(font_set_data_ptr, "font_rid", "data_ptr", "data_size");
 	GDVIRTUAL_BIND(font_set_data_ptr, "font_rid", "data_ptr", "data_size");
 
 
+	GDVIRTUAL_BIND(font_set_face_index, "font_rid", "face_index");
+	GDVIRTUAL_BIND(font_get_face_index, "font_rid");
+
+	GDVIRTUAL_BIND(font_get_face_count, "font_rid");
+
 	GDVIRTUAL_BIND(font_set_style, "font_rid", "style");
 	GDVIRTUAL_BIND(font_set_style, "font_rid", "style");
 	GDVIRTUAL_BIND(font_get_style, "font_rid");
 	GDVIRTUAL_BIND(font_get_style, "font_rid");
 
 
@@ -413,6 +418,26 @@ void TextServerExtension::font_set_data_ptr(const RID &p_font_rid, const uint8_t
 	GDVIRTUAL_CALL(font_set_data_ptr, p_font_rid, p_data_ptr, p_data_size);
 	GDVIRTUAL_CALL(font_set_data_ptr, p_font_rid, p_data_ptr, p_data_size);
 }
 }
 
 
+void TextServerExtension::font_set_face_index(const RID &p_font_rid, int64_t p_index) {
+	GDVIRTUAL_CALL(font_set_face_index, p_font_rid, p_index);
+}
+
+int64_t TextServerExtension::font_get_face_index(const RID &p_font_rid) const {
+	int64_t ret;
+	if (GDVIRTUAL_CALL(font_get_face_index, p_font_rid, ret)) {
+		return ret;
+	}
+	return 0;
+}
+
+int64_t TextServerExtension::font_get_face_count(const RID &p_font_rid) const {
+	int64_t ret;
+	if (GDVIRTUAL_CALL(font_get_face_count, p_font_rid, ret)) {
+		return ret;
+	}
+	return 0;
+}
+
 void TextServerExtension::font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) {
 void TextServerExtension::font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) {
 	GDVIRTUAL_CALL(font_set_style, p_font_rid, p_style);
 	GDVIRTUAL_CALL(font_set_style, p_font_rid, p_style);
 }
 }

+ 8 - 0
servers/text/text_server_extension.h

@@ -84,6 +84,14 @@ public:
 	GDVIRTUAL2(font_set_data, RID, const PackedByteArray &);
 	GDVIRTUAL2(font_set_data, RID, const PackedByteArray &);
 	GDVIRTUAL3(font_set_data_ptr, RID, GDNativeConstPtr<const uint8_t>, int64_t);
 	GDVIRTUAL3(font_set_data_ptr, RID, GDNativeConstPtr<const uint8_t>, int64_t);
 
 
+	virtual void font_set_face_index(const RID &p_font_rid, int64_t p_index) override;
+	virtual int64_t font_get_face_index(const RID &p_font_rid) const override;
+	GDVIRTUAL2(font_set_face_index, RID, int64_t);
+	GDVIRTUAL1RC(int64_t, font_get_face_index, RID);
+
+	virtual int64_t font_get_face_count(const RID &p_font_rid) const override;
+	GDVIRTUAL1RC(int64_t, font_get_face_count, RID);
+
 	virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) override;
 	virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) override;
 	virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const override;
 	virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const override;
 	GDVIRTUAL2(font_set_style, RID, int64_t);
 	GDVIRTUAL2(font_set_style, RID, int64_t);

+ 5 - 0
servers/text_server.cpp

@@ -208,6 +208,11 @@ void TextServer::_bind_methods() {
 
 
 	ClassDB::bind_method(D_METHOD("font_set_data", "font_rid", "data"), &TextServer::font_set_data);
 	ClassDB::bind_method(D_METHOD("font_set_data", "font_rid", "data"), &TextServer::font_set_data);
 
 
+	ClassDB::bind_method(D_METHOD("font_set_face_index", "font_rid", "face_index"), &TextServer::font_set_face_index);
+	ClassDB::bind_method(D_METHOD("font_get_face_index", "font_rid"), &TextServer::font_get_face_index);
+
+	ClassDB::bind_method(D_METHOD("font_get_face_count", "font_rid"), &TextServer::font_get_face_count);
+
 	ClassDB::bind_method(D_METHOD("font_set_style", "font_rid", "style"), &TextServer::font_set_style);
 	ClassDB::bind_method(D_METHOD("font_set_style", "font_rid", "style"), &TextServer::font_set_style);
 	ClassDB::bind_method(D_METHOD("font_get_style", "font_rid"), &TextServer::font_get_style);
 	ClassDB::bind_method(D_METHOD("font_get_style", "font_rid"), &TextServer::font_get_style);
 
 

+ 5 - 0
servers/text_server.h

@@ -189,6 +189,11 @@ public:
 	virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) = 0;
 	virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) = 0;
 	virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) = 0;
 	virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) = 0;
 
 
+	virtual void font_set_face_index(const RID &p_font_rid, int64_t p_index) = 0;
+	virtual int64_t font_get_face_index(const RID &p_font_rid) const = 0;
+
+	virtual int64_t font_get_face_count(const RID &p_font_rid) const = 0;
+
 	virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) = 0;
 	virtual void font_set_style(const RID &p_font_rid, int64_t /*FontStyle*/ p_style) = 0;
 	virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const = 0;
 	virtual int64_t /*FontStyle*/ font_get_style(const RID &p_font_rid) const = 0;