Browse Source

Merge pull request #61142 from bruvzg/rtl_threaded

Rémi Verschelde 3 years ago
parent
commit
b9bb3de6a1

+ 27 - 0
doc/classes/RichTextLabel.xml

@@ -60,6 +60,7 @@
 			<argument index="0" name="character" type="int" />
 			<argument index="0" name="character" type="int" />
 			<description>
 			<description>
 				Returns the line number of the character position provided.
 				Returns the line number of the character position provided.
+				[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="get_character_paragraph">
 		<method name="get_character_paragraph">
@@ -67,24 +68,28 @@
 			<argument index="0" name="character" type="int" />
 			<argument index="0" name="character" type="int" />
 			<description>
 			<description>
 				Returns the paragraph number of the character position provided.
 				Returns the paragraph number of the character position provided.
+				[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="get_content_height" qualifiers="const">
 		<method name="get_content_height" qualifiers="const">
 			<return type="int" />
 			<return type="int" />
 			<description>
 			<description>
 				Returns the height of the content.
 				Returns the height of the content.
+				[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="get_content_width" qualifiers="const">
 		<method name="get_content_width" qualifiers="const">
 			<return type="int" />
 			<return type="int" />
 			<description>
 			<description>
 				Returns the width of the content.
 				Returns the width of the content.
+				[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="get_line_count" qualifiers="const">
 		<method name="get_line_count" qualifiers="const">
 			<return type="int" />
 			<return type="int" />
 			<description>
 			<description>
 				Returns the total number of lines in the text. Wrapped text is counted as multiple lines.
 				Returns the total number of lines in the text. Wrapped text is counted as multiple lines.
+				[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="get_line_offset">
 		<method name="get_line_offset">
@@ -92,6 +97,7 @@
 			<argument index="0" name="line" type="int" />
 			<argument index="0" name="line" type="int" />
 			<description>
 			<description>
 				Returns the vertical offset of the line found at the provided index.
 				Returns the vertical offset of the line found at the provided index.
+				[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="get_menu" qualifiers="const">
 		<method name="get_menu" qualifiers="const">
@@ -112,6 +118,7 @@
 			<argument index="0" name="paragraph" type="int" />
 			<argument index="0" name="paragraph" type="int" />
 			<description>
 			<description>
 				Returns the vertical offset of the paragraph found at the provided index.
 				Returns the vertical offset of the paragraph found at the provided index.
+				[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="get_parsed_text" qualifiers="const">
 		<method name="get_parsed_text" qualifiers="const">
@@ -155,12 +162,14 @@
 			<return type="int" />
 			<return type="int" />
 			<description>
 			<description>
 				Returns the number of visible lines.
 				Returns the number of visible lines.
+				[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="get_visible_paragraph_count" qualifiers="const">
 		<method name="get_visible_paragraph_count" qualifiers="const">
 			<return type="int" />
 			<return type="int" />
 			<description>
 			<description>
 				Returns the number of visible paragraphs. A paragraph is considered visible if at least one of its lines is visible.
 				Returns the number of visible paragraphs. A paragraph is considered visible if at least one of its lines is visible.
+				[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="install_effect">
 		<method name="install_effect">
@@ -176,6 +185,12 @@
 				Returns whether the menu is visible. Use this instead of [code]get_menu().visible[/code] to improve performance (so the creation of the menu is avoided).
 				Returns whether the menu is visible. Use this instead of [code]get_menu().visible[/code] to improve performance (so the creation of the menu is avoided).
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="is_ready" qualifiers="const">
+			<return type="bool" />
+			<description>
+				If [member threaded] is enabled, returns [code]true[/code] if the background thread has finished text processing, otherwise always return [code]true[/code].
+			</description>
+		</method>
 		<method name="newline">
 		<method name="newline">
 			<return type="void" />
 			<return type="void" />
 			<description>
 			<description>
@@ -476,6 +491,10 @@
 			The range of characters to display, as a [float] between 0.0 and 1.0. When assigned an out of range value, it's the same as assigning 1.0.
 			The range of characters to display, as a [float] between 0.0 and 1.0. When assigned an out of range value, it's the same as assigning 1.0.
 			[b]Note:[/b] Setting this property updates [member visible_characters] based on current [method get_total_character_count].
 			[b]Note:[/b] Setting this property updates [member visible_characters] based on current [method get_total_character_count].
 		</member>
 		</member>
+		<member name="progress_bar_delay" type="int" setter="set_progress_bar_delay" getter="get_progress_bar_delay" default="1000">
+			The delay after which the loading progress bar is displayed, in milliseconds. Set to [code]-1[/code] to disable progress bar entirely.
+			[b]Note:[/b] Progress bar is dislayed only if [member threaded] is enabled.
+		</member>
 		<member name="scroll_active" type="bool" setter="set_scroll_active" getter="is_scroll_active" default="true">
 		<member name="scroll_active" type="bool" setter="set_scroll_active" getter="is_scroll_active" default="true">
 			If [code]true[/code], the scrollbar is visible. Setting this to [code]false[/code] does not block scrolling completely. See [method scroll_to_line].
 			If [code]true[/code], the scrollbar is visible. Setting this to [code]false[/code] does not block scrolling completely. See [method scroll_to_line].
 		</member>
 		</member>
@@ -504,6 +523,9 @@
 		<member name="text_direction" type="int" setter="set_text_direction" getter="get_text_direction" enum="Control.TextDirection" default="0">
 		<member name="text_direction" type="int" setter="set_text_direction" getter="get_text_direction" enum="Control.TextDirection" default="0">
 			Base text writing direction.
 			Base text writing direction.
 		</member>
 		</member>
+		<member name="threaded" type="bool" setter="set_threaded" getter="is_threaded" default="false">
+			If [code]true[/code], text processing is done in a background thread.
+		</member>
 		<member name="visible_characters" type="int" setter="set_visible_characters" getter="get_visible_characters" default="-1">
 		<member name="visible_characters" type="int" setter="set_visible_characters" getter="get_visible_characters" default="-1">
 			The restricted number of characters to display in the label. If [code]-1[/code], all characters will be displayed.
 			The restricted number of characters to display in the label. If [code]-1[/code], all characters will be displayed.
 			[b]Note:[/b] Setting this property updates [member percent_visible] based on current [method get_total_character_count].
 			[b]Note:[/b] Setting this property updates [member percent_visible] based on current [method get_total_character_count].
@@ -513,6 +535,11 @@
 		</member>
 		</member>
 	</members>
 	</members>
 	<signals>
 	<signals>
+		<signal name="finished">
+			<description>
+				Triggered when the document is fully loaded.
+			</description>
+		</signal>
 		<signal name="meta_clicked">
 		<signal name="meta_clicked">
 			<argument index="0" name="meta" type="Variant" />
 			<argument index="0" name="meta" type="Variant" />
 			<description>
 			<description>

+ 2 - 0
editor/editor_about.cpp

@@ -196,6 +196,7 @@ EditorAbout::EditorAbout() {
 	// License
 	// License
 
 
 	_license_text = memnew(RichTextLabel);
 	_license_text = memnew(RichTextLabel);
+	_license_text->set_threaded(true);
 	_license_text->set_name(TTR("License"));
 	_license_text->set_name(TTR("License"));
 	_license_text->set_h_size_flags(Control::SIZE_EXPAND_FILL);
 	_license_text->set_h_size_flags(Control::SIZE_EXPAND_FILL);
 	_license_text->set_v_size_flags(Control::SIZE_EXPAND_FILL);
 	_license_text->set_v_size_flags(Control::SIZE_EXPAND_FILL);
@@ -272,6 +273,7 @@ EditorAbout::EditorAbout() {
 	tpl_hbc->add_child(_tpl_tree);
 	tpl_hbc->add_child(_tpl_tree);
 
 
 	_tpl_text = memnew(RichTextLabel);
 	_tpl_text = memnew(RichTextLabel);
+	_tpl_text->set_threaded(true);
 	_tpl_text->set_h_size_flags(Control::SIZE_EXPAND_FILL);
 	_tpl_text->set_h_size_flags(Control::SIZE_EXPAND_FILL);
 	_tpl_text->set_v_size_flags(Control::SIZE_EXPAND_FILL);
 	_tpl_text->set_v_size_flags(Control::SIZE_EXPAND_FILL);
 	tpl_hbc->add_child(_tpl_text);
 	tpl_hbc->add_child(_tpl_text);

+ 23 - 22
editor/editor_help.cpp

@@ -235,7 +235,7 @@ String EditorHelp::_fix_constant(const String &p_constant) const {
 }
 }
 
 
 void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview) {
 void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview) {
-	method_line[p_method.name] = class_desc->get_line_count() - 2; //gets overridden if description
+	method_line[p_method.name] = class_desc->get_paragraph_count() - 2; //gets overridden if description
 
 
 	const bool is_vararg = p_method.qualifiers.contains("vararg");
 	const bool is_vararg = p_method.qualifiers.contains("vararg");
 
 
@@ -593,8 +593,8 @@ void EditorHelp::_update_doc() {
 
 
 	// Class description
 	// Class description
 	if (!cd.description.is_empty()) {
 	if (!cd.description.is_empty()) {
-		section_line.push_back(Pair<String, int>(TTR("Description"), class_desc->get_line_count() - 2));
-		description_line = class_desc->get_line_count() - 2;
+		section_line.push_back(Pair<String, int>(TTR("Description"), class_desc->get_paragraph_count() - 2));
+		description_line = class_desc->get_paragraph_count() - 2;
 		class_desc->push_color(title_color);
 		class_desc->push_color(title_color);
 		class_desc->push_font(doc_title_font);
 		class_desc->push_font(doc_title_font);
 		class_desc->add_text(TTR("Description"));
 		class_desc->add_text(TTR("Description"));
@@ -664,7 +664,7 @@ void EditorHelp::_update_doc() {
 	}
 	}
 
 
 	if (has_properties) {
 	if (has_properties) {
-		section_line.push_back(Pair<String, int>(TTR("Properties"), class_desc->get_line_count() - 2));
+		section_line.push_back(Pair<String, int>(TTR("Properties"), class_desc->get_paragraph_count() - 2));
 		class_desc->push_color(title_color);
 		class_desc->push_color(title_color);
 		class_desc->push_font(doc_title_font);
 		class_desc->push_font(doc_title_font);
 		class_desc->add_text(TTR("Properties"));
 		class_desc->add_text(TTR("Properties"));
@@ -682,7 +682,7 @@ void EditorHelp::_update_doc() {
 			if (cd.properties[i].name.begins_with("_") && cd.properties[i].description.is_empty()) {
 			if (cd.properties[i].name.begins_with("_") && cd.properties[i].description.is_empty()) {
 				continue;
 				continue;
 			}
 			}
-			property_line[cd.properties[i].name] = class_desc->get_line_count() - 2; //gets overridden if description
+			property_line[cd.properties[i].name] = class_desc->get_paragraph_count() - 2; //gets overridden if description
 
 
 			// Property type.
 			// Property type.
 			class_desc->push_cell();
 			class_desc->push_cell();
@@ -828,7 +828,7 @@ void EditorHelp::_update_doc() {
 			cd.constructors.sort();
 			cd.constructors.sort();
 		}
 		}
 
 
-		section_line.push_back(Pair<String, int>(TTR("Constructors"), class_desc->get_line_count() - 2));
+		section_line.push_back(Pair<String, int>(TTR("Constructors"), class_desc->get_paragraph_count() - 2));
 		class_desc->push_color(title_color);
 		class_desc->push_color(title_color);
 		class_desc->push_font(doc_title_font);
 		class_desc->push_font(doc_title_font);
 		class_desc->add_text(TTR("Constructors"));
 		class_desc->add_text(TTR("Constructors"));
@@ -839,7 +839,7 @@ void EditorHelp::_update_doc() {
 		if (sort_methods) {
 		if (sort_methods) {
 			methods.sort();
 			methods.sort();
 		}
 		}
-		section_line.push_back(Pair<String, int>(TTR("Methods"), class_desc->get_line_count() - 2));
+		section_line.push_back(Pair<String, int>(TTR("Methods"), class_desc->get_paragraph_count() - 2));
 		class_desc->push_color(title_color);
 		class_desc->push_color(title_color);
 		class_desc->push_font(doc_title_font);
 		class_desc->push_font(doc_title_font);
 		class_desc->add_text(TTR("Methods"));
 		class_desc->add_text(TTR("Methods"));
@@ -851,7 +851,7 @@ void EditorHelp::_update_doc() {
 			cd.operators.sort();
 			cd.operators.sort();
 		}
 		}
 
 
-		section_line.push_back(Pair<String, int>(TTR("Operators"), class_desc->get_line_count() - 2));
+		section_line.push_back(Pair<String, int>(TTR("Operators"), class_desc->get_paragraph_count() - 2));
 		class_desc->push_color(title_color);
 		class_desc->push_color(title_color);
 		class_desc->push_font(doc_title_font);
 		class_desc->push_font(doc_title_font);
 		class_desc->add_text(TTR("Operators"));
 		class_desc->add_text(TTR("Operators"));
@@ -860,7 +860,7 @@ void EditorHelp::_update_doc() {
 
 
 	// Theme properties
 	// Theme properties
 	if (!cd.theme_properties.is_empty()) {
 	if (!cd.theme_properties.is_empty()) {
-		section_line.push_back(Pair<String, int>(TTR("Theme Properties"), class_desc->get_line_count() - 2));
+		section_line.push_back(Pair<String, int>(TTR("Theme Properties"), class_desc->get_paragraph_count() - 2));
 		class_desc->push_color(title_color);
 		class_desc->push_color(title_color);
 		class_desc->push_font(doc_title_font);
 		class_desc->push_font(doc_title_font);
 		class_desc->add_text(TTR("Theme Properties"));
 		class_desc->add_text(TTR("Theme Properties"));
@@ -882,7 +882,7 @@ void EditorHelp::_update_doc() {
 		data_type_names["style"] = TTR("Styles");
 		data_type_names["style"] = TTR("Styles");
 
 
 		for (int i = 0; i < cd.theme_properties.size(); i++) {
 		for (int i = 0; i < cd.theme_properties.size(); i++) {
-			theme_property_line[cd.theme_properties[i].name] = class_desc->get_line_count() - 2; // Gets overridden if description.
+			theme_property_line[cd.theme_properties[i].name] = class_desc->get_paragraph_count() - 2; // Gets overridden if description.
 
 
 			if (theme_data_type != cd.theme_properties[i].data_type) {
 			if (theme_data_type != cd.theme_properties[i].data_type) {
 				theme_data_type = cd.theme_properties[i].data_type;
 				theme_data_type = cd.theme_properties[i].data_type;
@@ -954,7 +954,7 @@ void EditorHelp::_update_doc() {
 			cd.signals.sort();
 			cd.signals.sort();
 		}
 		}
 
 
-		section_line.push_back(Pair<String, int>(TTR("Signals"), class_desc->get_line_count() - 2));
+		section_line.push_back(Pair<String, int>(TTR("Signals"), class_desc->get_paragraph_count() - 2));
 		class_desc->push_color(title_color);
 		class_desc->push_color(title_color);
 		class_desc->push_font(doc_title_font);
 		class_desc->push_font(doc_title_font);
 		class_desc->add_text(TTR("Signals"));
 		class_desc->add_text(TTR("Signals"));
@@ -967,7 +967,7 @@ void EditorHelp::_update_doc() {
 		class_desc->push_indent(1);
 		class_desc->push_indent(1);
 
 
 		for (int i = 0; i < cd.signals.size(); i++) {
 		for (int i = 0; i < cd.signals.size(); i++) {
-			signal_line[cd.signals[i].name] = class_desc->get_line_count() - 2; // Gets overridden if description.
+			signal_line[cd.signals[i].name] = class_desc->get_paragraph_count() - 2; // Gets overridden if description.
 
 
 			class_desc->push_font(doc_code_font); // monofont
 			class_desc->push_font(doc_code_font); // monofont
 			class_desc->push_color(headline_color);
 			class_desc->push_color(headline_color);
@@ -1040,7 +1040,7 @@ void EditorHelp::_update_doc() {
 
 
 		// Enums
 		// Enums
 		if (enums.size()) {
 		if (enums.size()) {
-			section_line.push_back(Pair<String, int>(TTR("Enumerations"), class_desc->get_line_count() - 2));
+			section_line.push_back(Pair<String, int>(TTR("Enumerations"), class_desc->get_paragraph_count() - 2));
 			class_desc->push_color(title_color);
 			class_desc->push_color(title_color);
 			class_desc->push_font(doc_title_font);
 			class_desc->push_font(doc_title_font);
 			class_desc->add_text(TTR("Enumerations"));
 			class_desc->add_text(TTR("Enumerations"));
@@ -1051,7 +1051,7 @@ void EditorHelp::_update_doc() {
 			class_desc->add_newline();
 			class_desc->add_newline();
 
 
 			for (KeyValue<String, Vector<DocData::ConstantDoc>> &E : enums) {
 			for (KeyValue<String, Vector<DocData::ConstantDoc>> &E : enums) {
-				enum_line[E.key] = class_desc->get_line_count() - 2;
+				enum_line[E.key] = class_desc->get_paragraph_count() - 2;
 
 
 				class_desc->push_font(doc_code_font);
 				class_desc->push_font(doc_code_font);
 				class_desc->push_color(title_color);
 				class_desc->push_color(title_color);
@@ -1098,7 +1098,7 @@ void EditorHelp::_update_doc() {
 					}
 					}
 
 
 					// Add the enum constant line to the constant_line map so we can locate it as a constant.
 					// Add the enum constant line to the constant_line map so we can locate it as a constant.
-					constant_line[enum_list[i].name] = class_desc->get_line_count() - 2;
+					constant_line[enum_list[i].name] = class_desc->get_paragraph_count() - 2;
 
 
 					class_desc->push_font(doc_code_font);
 					class_desc->push_font(doc_code_font);
 					class_desc->push_color(headline_color);
 					class_desc->push_color(headline_color);
@@ -1144,7 +1144,7 @@ void EditorHelp::_update_doc() {
 
 
 		// Constants
 		// Constants
 		if (constants.size()) {
 		if (constants.size()) {
-			section_line.push_back(Pair<String, int>(TTR("Constants"), class_desc->get_line_count() - 2));
+			section_line.push_back(Pair<String, int>(TTR("Constants"), class_desc->get_paragraph_count() - 2));
 			class_desc->push_color(title_color);
 			class_desc->push_color(title_color);
 			class_desc->push_font(doc_title_font);
 			class_desc->push_font(doc_title_font);
 			class_desc->add_text(TTR("Constants"));
 			class_desc->add_text(TTR("Constants"));
@@ -1155,7 +1155,7 @@ void EditorHelp::_update_doc() {
 			class_desc->add_newline();
 			class_desc->add_newline();
 
 
 			for (int i = 0; i < constants.size(); i++) {
 			for (int i = 0; i < constants.size(); i++) {
-				constant_line[constants[i].name] = class_desc->get_line_count() - 2;
+				constant_line[constants[i].name] = class_desc->get_paragraph_count() - 2;
 				class_desc->push_font(doc_code_font);
 				class_desc->push_font(doc_code_font);
 
 
 				if (constants[i].value.begins_with("Color(") && constants[i].value.ends_with(")")) {
 				if (constants[i].value.begins_with("Color(") && constants[i].value.ends_with(")")) {
@@ -1205,7 +1205,7 @@ void EditorHelp::_update_doc() {
 
 
 	// Property descriptions
 	// Property descriptions
 	if (property_descr) {
 	if (property_descr) {
-		section_line.push_back(Pair<String, int>(TTR("Property Descriptions"), class_desc->get_line_count() - 2));
+		section_line.push_back(Pair<String, int>(TTR("Property Descriptions"), class_desc->get_paragraph_count() - 2));
 		class_desc->push_color(title_color);
 		class_desc->push_color(title_color);
 		class_desc->push_font(doc_title_font);
 		class_desc->push_font(doc_title_font);
 		class_desc->add_text(TTR("Property Descriptions"));
 		class_desc->add_text(TTR("Property Descriptions"));
@@ -1220,7 +1220,7 @@ void EditorHelp::_update_doc() {
 				continue;
 				continue;
 			}
 			}
 
 
-			property_line[cd.properties[i].name] = class_desc->get_line_count() - 2;
+			property_line[cd.properties[i].name] = class_desc->get_paragraph_count() - 2;
 
 
 			class_desc->push_table(2);
 			class_desc->push_table(2);
 			class_desc->set_table_column_expand(1, true);
 			class_desc->set_table_column_expand(1, true);
@@ -1371,7 +1371,7 @@ void EditorHelp::_update_doc() {
 
 
 	// Constructor descriptions
 	// Constructor descriptions
 	if (constructor_descriptions) {
 	if (constructor_descriptions) {
-		section_line.push_back(Pair<String, int>(TTR("Constructor Descriptions"), class_desc->get_line_count() - 2));
+		section_line.push_back(Pair<String, int>(TTR("Constructor Descriptions"), class_desc->get_paragraph_count() - 2));
 		class_desc->push_color(title_color);
 		class_desc->push_color(title_color);
 		class_desc->push_font(doc_title_font);
 		class_desc->push_font(doc_title_font);
 		class_desc->add_text(TTR("Constructor Descriptions"));
 		class_desc->add_text(TTR("Constructor Descriptions"));
@@ -1380,7 +1380,7 @@ void EditorHelp::_update_doc() {
 
 
 	// Method descriptions
 	// Method descriptions
 	if (method_descriptions) {
 	if (method_descriptions) {
-		section_line.push_back(Pair<String, int>(TTR("Method Descriptions"), class_desc->get_line_count() - 2));
+		section_line.push_back(Pair<String, int>(TTR("Method Descriptions"), class_desc->get_paragraph_count() - 2));
 		class_desc->push_color(title_color);
 		class_desc->push_color(title_color);
 		class_desc->push_font(doc_title_font);
 		class_desc->push_font(doc_title_font);
 		class_desc->add_text(TTR("Method Descriptions"));
 		class_desc->add_text(TTR("Method Descriptions"));
@@ -1389,7 +1389,7 @@ void EditorHelp::_update_doc() {
 
 
 	// Operator descriptions
 	// Operator descriptions
 	if (operator_descriptions) {
 	if (operator_descriptions) {
-		section_line.push_back(Pair<String, int>(TTR("Operator Descriptions"), class_desc->get_line_count() - 2));
+		section_line.push_back(Pair<String, int>(TTR("Operator Descriptions"), class_desc->get_paragraph_count() - 2));
 		class_desc->push_color(title_color);
 		class_desc->push_color(title_color);
 		class_desc->push_font(doc_title_font);
 		class_desc->push_font(doc_title_font);
 		class_desc->add_text(TTR("Operator Descriptions"));
 		class_desc->add_text(TTR("Operator Descriptions"));
@@ -1868,6 +1868,7 @@ EditorHelp::EditorHelp() {
 
 
 	class_desc = memnew(RichTextLabel);
 	class_desc = memnew(RichTextLabel);
 	add_child(class_desc);
 	add_child(class_desc);
+	class_desc->set_threaded(true);
 	class_desc->set_v_size_flags(SIZE_EXPAND_FILL);
 	class_desc->set_v_size_flags(SIZE_EXPAND_FILL);
 	class_desc->add_theme_color_override("selection_color", get_theme_color(SNAME("accent_color"), SNAME("Editor")) * Color(1, 1, 1, 0.4));
 	class_desc->add_theme_color_override("selection_color", get_theme_color(SNAME("accent_color"), SNAME("Editor")) * Color(1, 1, 1, 0.4));
 
 

+ 5 - 0
modules/text_server_adv/text_server_adv.cpp

@@ -1691,6 +1691,8 @@ hb_font_t *TextServerAdvanced::_font_get_hb_handle(const RID &p_font_rid, int64_
 }
 }
 
 
 RID TextServerAdvanced::create_font() {
 RID TextServerAdvanced::create_font() {
+	_THREAD_SAFE_METHOD_
+
 	FontDataAdvanced *fd = memnew(FontDataAdvanced);
 	FontDataAdvanced *fd = memnew(FontDataAdvanced);
 
 
 	return font_owner.make_rid(fd);
 	return font_owner.make_rid(fd);
@@ -3359,6 +3361,7 @@ void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) {
 
 
 RID TextServerAdvanced::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
 RID TextServerAdvanced::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
+
 	ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced);
 	ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced);
 	sd->hb_buffer = hb_buffer_create();
 	sd->hb_buffer = hb_buffer_create();
 	sd->direction = p_direction;
 	sd->direction = p_direction;
@@ -3748,6 +3751,8 @@ void TextServerAdvanced::_realign(ShapedTextDataAdvanced *p_sd) const {
 }
 }
 
 
 RID TextServerAdvanced::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {
 RID TextServerAdvanced::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {
+	_THREAD_SAFE_METHOD_
+
 	const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, RID());
 	ERR_FAIL_COND_V(!sd, RID());
 
 

+ 5 - 0
modules/text_server_fb/text_server_fb.cpp

@@ -853,6 +853,8 @@ _FORCE_INLINE_ void TextServerFallback::_font_clear_cache(FontDataFallback *p_fo
 }
 }
 
 
 RID TextServerFallback::create_font() {
 RID TextServerFallback::create_font() {
+	_THREAD_SAFE_METHOD_
+
 	FontDataFallback *fd = memnew(FontDataFallback);
 	FontDataFallback *fd = memnew(FontDataFallback);
 
 
 	return font_owner.make_rid(fd);
 	return font_owner.make_rid(fd);
@@ -2429,6 +2431,7 @@ void TextServerFallback::full_copy(ShapedTextDataFallback *p_shaped) {
 
 
 RID TextServerFallback::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
 RID TextServerFallback::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
+
 	ShapedTextDataFallback *sd = memnew(ShapedTextDataFallback);
 	ShapedTextDataFallback *sd = memnew(ShapedTextDataFallback);
 	sd->direction = p_direction;
 	sd->direction = p_direction;
 	sd->orientation = p_orientation;
 	sd->orientation = p_orientation;
@@ -2807,6 +2810,8 @@ void TextServerFallback::_realign(ShapedTextDataFallback *p_sd) const {
 }
 }
 
 
 RID TextServerFallback::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {
 RID TextServerFallback::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {
+	_THREAD_SAFE_METHOD_
+
 	const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
 	const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, RID());
 	ERR_FAIL_COND_V(!sd, RID());
 
 

File diff suppressed because it is too large
+ 336 - 212
scene/gui/rich_text_label.cpp


+ 39 - 11
scene/gui/rich_text_label.h

@@ -141,10 +141,10 @@ private:
 	struct ItemFrame : public Item {
 	struct ItemFrame : public Item {
 		bool cell = false;
 		bool cell = false;
 
 
-		Vector<Line> lines;
-		int first_invalid_line = 0;
-		int first_invalid_font_line = 0;
-		int first_resized_line = 0;
+		LocalVector<Line> lines;
+		std::atomic<int> first_invalid_line;
+		std::atomic<int> first_invalid_font_line;
+		std::atomic<int> first_resized_line;
 
 
 		ItemFrame *parent_frame = nullptr;
 		ItemFrame *parent_frame = nullptr;
 
 
@@ -155,7 +155,12 @@ private:
 		Size2 max_size_over = Size2(-1, -1);
 		Size2 max_size_over = Size2(-1, -1);
 		Rect2 padding;
 		Rect2 padding;
 
 
-		ItemFrame() { type = ITEM_FRAME; }
+		ItemFrame() {
+			type = ITEM_FRAME;
+			first_invalid_line.store(0);
+			first_invalid_font_line.store(0);
+			first_resized_line.store(0);
+		}
 	};
 	};
 
 
 	struct ItemText : public Item {
 	struct ItemText : public Item {
@@ -263,8 +268,8 @@ private:
 			int width = 0;
 			int width = 0;
 		};
 		};
 
 
-		Vector<Column> columns;
-		Vector<float> rows;
+		LocalVector<Column> columns;
+		LocalVector<float> rows;
 
 
 		int total_width = 0;
 		int total_width = 0;
 		int total_height = 0;
 		int total_height = 0;
@@ -363,6 +368,16 @@ private:
 	Item *current = nullptr;
 	Item *current = nullptr;
 	ItemFrame *current_frame = nullptr;
 	ItemFrame *current_frame = nullptr;
 
 
+	Thread thread;
+	Mutex data_mutex;
+	bool threaded = false;
+	std::atomic<bool> stop_thread;
+	std::atomic<bool> updating;
+	std::atomic<double> loaded;
+
+	uint64_t loading_started = 0;
+	int progress_delay = 1000;
+
 	VScrollBar *vscroll = nullptr;
 	VScrollBar *vscroll = nullptr;
 
 
 	AutowrapMode autowrap_mode = AUTOWRAP_WORD_SMART;
 	AutowrapMode autowrap_mode = AUTOWRAP_WORD_SMART;
@@ -392,7 +407,11 @@ private:
 	Array custom_effects;
 	Array custom_effects;
 
 
 	void _invalidate_current_line(ItemFrame *p_frame);
 	void _invalidate_current_line(ItemFrame *p_frame);
-	void _validate_line_caches(ItemFrame *p_frame);
+
+	static void _thread_function(void *self);
+	void _stop_thread();
+	bool _validate_line_caches();
+	void _process_line_caches();
 
 
 	void _add_item(Item *p_item, bool p_enter = false, bool p_ensure_newline = false);
 	void _add_item(Item *p_item, bool p_enter = false, bool p_ensure_newline = false);
 	void _remove_item(Item *p_item, const int p_line, const int p_subitem_line);
 	void _remove_item(Item *p_item, const int p_line, const int p_subitem_line);
@@ -446,8 +465,9 @@ private:
 	bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, int p_char_idx, bool p_reverse_search);
 	bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, int p_char_idx, bool p_reverse_search);
 	bool _search_table(ItemTable *p_table, List<Item *>::Element *p_from, const String &p_string, bool p_reverse_search);
 	bool _search_table(ItemTable *p_table, List<Item *>::Element *p_from, const String &p_string, bool p_reverse_search);
 
 
-	void _shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, int *r_char_offset);
-	void _resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width);
+	float _shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, float p_h, int *r_char_offset);
+	float _resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, float p_h);
+
 	void _update_line_font(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size);
 	void _update_line_font(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size);
 	int _draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs, int &r_processed_glyphs);
 	int _draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs, int &r_processed_glyphs);
 	float _find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool p_table = false);
 	float _find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool p_table = false);
@@ -480,9 +500,9 @@ private:
 	bool _find_layout_subitem(Item *from, Item *to);
 	bool _find_layout_subitem(Item *from, Item *to);
 	void _fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack);
 	void _fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack);
 
 
-	void _update_scroll();
 	void _update_fx(ItemFrame *p_frame, double p_delta_time);
 	void _update_fx(ItemFrame *p_frame, double p_delta_time);
 	void _scroll_changed(double);
 	void _scroll_changed(double);
+	int _find_first_line(int p_from, int p_to, int p_vofs) const;
 
 
 	virtual void gui_input(const Ref<InputEvent> &p_event) override;
 	virtual void gui_input(const Ref<InputEvent> &p_event) override;
 	virtual String get_tooltip(const Point2 &p_pos) const override;
 	virtual String get_tooltip(const Point2 &p_pos) const override;
@@ -611,6 +631,14 @@ public:
 	bool is_deselect_on_focus_loss_enabled() const;
 	bool is_deselect_on_focus_loss_enabled() const;
 	void deselect();
 	void deselect();
 
 
+	bool is_ready() const;
+
+	void set_threaded(bool p_threaded);
+	bool is_threaded() const;
+
+	void set_progress_bar_delay(int p_delay_ms);
+	int get_progress_bar_delay() const;
+
 	// Context menu.
 	// Context menu.
 	PopupMenu *get_menu() const;
 	PopupMenu *get_menu() const;
 	bool is_menu_visible() const;
 	bool is_menu_visible() const;

+ 113 - 25
scene/resources/text_paragraph.cpp

@@ -139,7 +139,7 @@ void TextParagraph::_bind_methods() {
 
 
 void TextParagraph::_shape_lines() {
 void TextParagraph::_shape_lines() {
 	if (lines_dirty) {
 	if (lines_dirty) {
-		for (int i = 0; i < lines_rid.size(); i++) {
+		for (int i = 0; i < (int)lines_rid.size(); i++) {
 			TS->free_rid(lines_rid[i]);
 			TS->free_rid(lines_rid[i]);
 		}
 		}
 		lines_rid.clear();
 		lines_rid.clear();
@@ -218,14 +218,14 @@ void TextParagraph::_shape_lines() {
 
 
 		// Fill after min_size calculation.
 		// Fill after min_size calculation.
 		if (autowrap_enabled) {
 		if (autowrap_enabled) {
-			int visible_lines = (max_lines_visible >= 0) ? MIN(max_lines_visible, lines_rid.size()) : lines_rid.size();
-			bool lines_hidden = visible_lines > 0 && visible_lines < lines_rid.size();
+			int visible_lines = (max_lines_visible >= 0) ? MIN(max_lines_visible, (int)lines_rid.size()) : (int)lines_rid.size();
+			bool lines_hidden = visible_lines > 0 && visible_lines < (int)lines_rid.size();
 			if (lines_hidden) {
 			if (lines_hidden) {
 				overrun_flags |= TextServer::OVERRUN_ENFORCE_ELLIPSIS;
 				overrun_flags |= TextServer::OVERRUN_ENFORCE_ELLIPSIS;
 			}
 			}
 			if (alignment == HORIZONTAL_ALIGNMENT_FILL) {
 			if (alignment == HORIZONTAL_ALIGNMENT_FILL) {
-				for (int i = 0; i < lines_rid.size(); i++) {
-					if (i < visible_lines - 1 || lines_rid.size() == 1) {
+				for (int i = 0; i < (int)lines_rid.size(); i++) {
+					if (i < visible_lines - 1 || (int)lines_rid.size() == 1) {
 						TS->shaped_text_fit_to_width(lines_rid[i], width, flags);
 						TS->shaped_text_fit_to_width(lines_rid[i], width, flags);
 					} else if (i == (visible_lines - 1)) {
 					} else if (i == (visible_lines - 1)) {
 						TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
 						TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
@@ -238,7 +238,7 @@ void TextParagraph::_shape_lines() {
 
 
 		} else {
 		} else {
 			// Autowrap disabled.
 			// Autowrap disabled.
-			for (int i = 0; i < lines_rid.size(); i++) {
+			for (int i = 0; i < (int)lines_rid.size(); i++) {
 				if (alignment == HORIZONTAL_ALIGNMENT_FILL) {
 				if (alignment == HORIZONTAL_ALIGNMENT_FILL) {
 					TS->shaped_text_fit_to_width(lines_rid[i], width, flags);
 					TS->shaped_text_fit_to_width(lines_rid[i], width, flags);
 					overrun_flags |= TextServer::OVERRUN_JUSTIFICATION_AWARE;
 					overrun_flags |= TextServer::OVERRUN_JUSTIFICATION_AWARE;
@@ -258,8 +258,10 @@ RID TextParagraph::get_rid() const {
 }
 }
 
 
 RID TextParagraph::get_line_rid(int p_line) const {
 RID TextParagraph::get_line_rid(int p_line) const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
-	ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), RID());
+	ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), RID());
 	return lines_rid[p_line];
 	return lines_rid[p_line];
 }
 }
 
 
@@ -268,9 +270,11 @@ RID TextParagraph::get_dropcap_rid() const {
 }
 }
 
 
 void TextParagraph::clear() {
 void TextParagraph::clear() {
+	_THREAD_SAFE_METHOD_
+
 	spacing_top = 0;
 	spacing_top = 0;
 	spacing_bottom = 0;
 	spacing_bottom = 0;
-	for (int i = 0; i < lines_rid.size(); i++) {
+	for (int i = 0; i < (int)lines_rid.size(); i++) {
 		TS->free_rid(lines_rid[i]);
 		TS->free_rid(lines_rid[i]);
 	}
 	}
 	lines_rid.clear();
 	lines_rid.clear();
@@ -279,57 +283,79 @@ void TextParagraph::clear() {
 }
 }
 
 
 void TextParagraph::set_preserve_invalid(bool p_enabled) {
 void TextParagraph::set_preserve_invalid(bool p_enabled) {
+	_THREAD_SAFE_METHOD_
+
 	TS->shaped_text_set_preserve_invalid(rid, p_enabled);
 	TS->shaped_text_set_preserve_invalid(rid, p_enabled);
 	TS->shaped_text_set_preserve_invalid(dropcap_rid, p_enabled);
 	TS->shaped_text_set_preserve_invalid(dropcap_rid, p_enabled);
 	lines_dirty = true;
 	lines_dirty = true;
 }
 }
 
 
 bool TextParagraph::get_preserve_invalid() const {
 bool TextParagraph::get_preserve_invalid() const {
+	_THREAD_SAFE_METHOD_
+
 	return TS->shaped_text_get_preserve_invalid(rid);
 	return TS->shaped_text_get_preserve_invalid(rid);
 }
 }
 
 
 void TextParagraph::set_preserve_control(bool p_enabled) {
 void TextParagraph::set_preserve_control(bool p_enabled) {
+	_THREAD_SAFE_METHOD_
+
 	TS->shaped_text_set_preserve_control(rid, p_enabled);
 	TS->shaped_text_set_preserve_control(rid, p_enabled);
 	TS->shaped_text_set_preserve_control(dropcap_rid, p_enabled);
 	TS->shaped_text_set_preserve_control(dropcap_rid, p_enabled);
 	lines_dirty = true;
 	lines_dirty = true;
 }
 }
 
 
 bool TextParagraph::get_preserve_control() const {
 bool TextParagraph::get_preserve_control() const {
+	_THREAD_SAFE_METHOD_
+
 	return TS->shaped_text_get_preserve_control(rid);
 	return TS->shaped_text_get_preserve_control(rid);
 }
 }
 
 
 void TextParagraph::set_direction(TextServer::Direction p_direction) {
 void TextParagraph::set_direction(TextServer::Direction p_direction) {
+	_THREAD_SAFE_METHOD_
+
 	TS->shaped_text_set_direction(rid, p_direction);
 	TS->shaped_text_set_direction(rid, p_direction);
 	TS->shaped_text_set_direction(dropcap_rid, p_direction);
 	TS->shaped_text_set_direction(dropcap_rid, p_direction);
 	lines_dirty = true;
 	lines_dirty = true;
 }
 }
 
 
 TextServer::Direction TextParagraph::get_direction() const {
 TextServer::Direction TextParagraph::get_direction() const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	return TS->shaped_text_get_direction(rid);
 	return TS->shaped_text_get_direction(rid);
 }
 }
 
 
 void TextParagraph::set_custom_punctuation(const String &p_punct) {
 void TextParagraph::set_custom_punctuation(const String &p_punct) {
+	_THREAD_SAFE_METHOD_
+
 	TS->shaped_text_set_custom_punctuation(rid, p_punct);
 	TS->shaped_text_set_custom_punctuation(rid, p_punct);
 	lines_dirty = true;
 	lines_dirty = true;
 }
 }
 
 
 String TextParagraph::get_custom_punctuation() const {
 String TextParagraph::get_custom_punctuation() const {
+	_THREAD_SAFE_METHOD_
+
 	return TS->shaped_text_get_custom_punctuation(rid);
 	return TS->shaped_text_get_custom_punctuation(rid);
 }
 }
 
 
 void TextParagraph::set_orientation(TextServer::Orientation p_orientation) {
 void TextParagraph::set_orientation(TextServer::Orientation p_orientation) {
+	_THREAD_SAFE_METHOD_
+
 	TS->shaped_text_set_orientation(rid, p_orientation);
 	TS->shaped_text_set_orientation(rid, p_orientation);
 	TS->shaped_text_set_orientation(dropcap_rid, p_orientation);
 	TS->shaped_text_set_orientation(dropcap_rid, p_orientation);
 	lines_dirty = true;
 	lines_dirty = true;
 }
 }
 
 
 TextServer::Orientation TextParagraph::get_orientation() const {
 TextServer::Orientation TextParagraph::get_orientation() const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	return TS->shaped_text_get_orientation(rid);
 	return TS->shaped_text_get_orientation(rid);
 }
 }
 
 
 bool TextParagraph::set_dropcap(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Rect2 &p_dropcap_margins, const Dictionary &p_opentype_features, const String &p_language) {
 bool TextParagraph::set_dropcap(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Rect2 &p_dropcap_margins, const Dictionary &p_opentype_features, const String &p_language) {
+	_THREAD_SAFE_METHOD_
+
 	ERR_FAIL_COND_V(p_fonts.is_null(), false);
 	ERR_FAIL_COND_V(p_fonts.is_null(), false);
 	TS->shaped_text_clear(dropcap_rid);
 	TS->shaped_text_clear(dropcap_rid);
 	dropcap_margins = p_dropcap_margins;
 	dropcap_margins = p_dropcap_margins;
@@ -339,12 +365,16 @@ bool TextParagraph::set_dropcap(const String &p_text, const Ref<Font> &p_fonts,
 }
 }
 
 
 void TextParagraph::clear_dropcap() {
 void TextParagraph::clear_dropcap() {
+	_THREAD_SAFE_METHOD_
+
 	dropcap_margins = Rect2();
 	dropcap_margins = Rect2();
 	TS->shaped_text_clear(dropcap_rid);
 	TS->shaped_text_clear(dropcap_rid);
 	lines_dirty = true;
 	lines_dirty = true;
 }
 }
 
 
 bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
 bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
+	_THREAD_SAFE_METHOD_
+
 	ERR_FAIL_COND_V(p_fonts.is_null(), false);
 	ERR_FAIL_COND_V(p_fonts.is_null(), false);
 	bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language, p_meta);
 	bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language, p_meta);
 	spacing_top = p_fonts->get_spacing(TextServer::SPACING_TOP);
 	spacing_top = p_fonts->get_spacing(TextServer::SPACING_TOP);
@@ -362,23 +392,31 @@ int TextParagraph::get_spacing_bottom() const {
 }
 }
 
 
 void TextParagraph::set_bidi_override(const Array &p_override) {
 void TextParagraph::set_bidi_override(const Array &p_override) {
+	_THREAD_SAFE_METHOD_
+
 	TS->shaped_text_set_bidi_override(rid, p_override);
 	TS->shaped_text_set_bidi_override(rid, p_override);
 	lines_dirty = true;
 	lines_dirty = true;
 }
 }
 
 
 bool TextParagraph::add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align, int p_length) {
 bool TextParagraph::add_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align, int p_length) {
+	_THREAD_SAFE_METHOD_
+
 	bool res = TS->shaped_text_add_object(rid, p_key, p_size, p_inline_align, p_length);
 	bool res = TS->shaped_text_add_object(rid, p_key, p_size, p_inline_align, p_length);
 	lines_dirty = true;
 	lines_dirty = true;
 	return res;
 	return res;
 }
 }
 
 
 bool TextParagraph::resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align) {
 bool TextParagraph::resize_object(Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align) {
+	_THREAD_SAFE_METHOD_
+
 	bool res = TS->shaped_text_resize_object(rid, p_key, p_size, p_inline_align);
 	bool res = TS->shaped_text_resize_object(rid, p_key, p_size, p_inline_align);
 	lines_dirty = true;
 	lines_dirty = true;
 	return res;
 	return res;
 }
 }
 
 
 void TextParagraph::set_alignment(HorizontalAlignment p_alignment) {
 void TextParagraph::set_alignment(HorizontalAlignment p_alignment) {
+	_THREAD_SAFE_METHOD_
+
 	if (alignment != p_alignment) {
 	if (alignment != p_alignment) {
 		if (alignment == HORIZONTAL_ALIGNMENT_FILL || p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
 		if (alignment == HORIZONTAL_ALIGNMENT_FILL || p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
 			alignment = p_alignment;
 			alignment = p_alignment;
@@ -394,11 +432,15 @@ HorizontalAlignment TextParagraph::get_alignment() const {
 }
 }
 
 
 void TextParagraph::tab_align(const Vector<float> &p_tab_stops) {
 void TextParagraph::tab_align(const Vector<float> &p_tab_stops) {
+	_THREAD_SAFE_METHOD_
+
 	tab_stops = p_tab_stops;
 	tab_stops = p_tab_stops;
 	lines_dirty = true;
 	lines_dirty = true;
 }
 }
 
 
 void TextParagraph::set_flags(uint16_t p_flags) {
 void TextParagraph::set_flags(uint16_t p_flags) {
+	_THREAD_SAFE_METHOD_
+
 	if (flags != p_flags) {
 	if (flags != p_flags) {
 		flags = p_flags;
 		flags = p_flags;
 		lines_dirty = true;
 		lines_dirty = true;
@@ -410,6 +452,8 @@ uint16_t TextParagraph::get_flags() const {
 }
 }
 
 
 void TextParagraph::set_text_overrun_behavior(TextParagraph::OverrunBehavior p_behavior) {
 void TextParagraph::set_text_overrun_behavior(TextParagraph::OverrunBehavior p_behavior) {
+	_THREAD_SAFE_METHOD_
+
 	if (overrun_behavior != p_behavior) {
 	if (overrun_behavior != p_behavior) {
 		overrun_behavior = p_behavior;
 		overrun_behavior = p_behavior;
 		lines_dirty = true;
 		lines_dirty = true;
@@ -421,6 +465,8 @@ TextParagraph::OverrunBehavior TextParagraph::get_text_overrun_behavior() const
 }
 }
 
 
 void TextParagraph::set_width(float p_width) {
 void TextParagraph::set_width(float p_width) {
+	_THREAD_SAFE_METHOD_
+
 	if (width != p_width) {
 	if (width != p_width) {
 		width = p_width;
 		width = p_width;
 		lines_dirty = true;
 		lines_dirty = true;
@@ -432,6 +478,8 @@ float TextParagraph::get_width() const {
 }
 }
 
 
 Size2 TextParagraph::get_non_wrapped_size() const {
 Size2 TextParagraph::get_non_wrapped_size() const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
 	if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
 		return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y + spacing_top + spacing_bottom);
 		return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y + spacing_top + spacing_bottom);
@@ -441,9 +489,11 @@ Size2 TextParagraph::get_non_wrapped_size() const {
 }
 }
 
 
 Size2 TextParagraph::get_size() const {
 Size2 TextParagraph::get_size() const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	Size2 size;
 	Size2 size;
-	int visible_lines = (max_lines_visible >= 0) ? MIN(max_lines_visible, lines_rid.size()) : lines_rid.size();
+	int visible_lines = (max_lines_visible >= 0) ? MIN(max_lines_visible, (int)lines_rid.size()) : (int)lines_rid.size();
 	for (int i = 0; i < visible_lines; i++) {
 	for (int i = 0; i < visible_lines; i++) {
 		Size2 lsize = TS->shaped_text_get_size(lines_rid[i]);
 		Size2 lsize = TS->shaped_text_get_size(lines_rid[i]);
 		if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
 		if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
@@ -458,11 +508,15 @@ Size2 TextParagraph::get_size() const {
 }
 }
 
 
 int TextParagraph::get_line_count() const {
 int TextParagraph::get_line_count() const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
-	return lines_rid.size();
+	return (int)lines_rid.size();
 }
 }
 
 
 void TextParagraph::set_max_lines_visible(int p_lines) {
 void TextParagraph::set_max_lines_visible(int p_lines) {
+	_THREAD_SAFE_METHOD_
+
 	if (p_lines != max_lines_visible) {
 	if (p_lines != max_lines_visible) {
 		max_lines_visible = p_lines;
 		max_lines_visible = p_lines;
 		lines_dirty = true;
 		lines_dirty = true;
@@ -474,14 +528,18 @@ int TextParagraph::get_max_lines_visible() const {
 }
 }
 
 
 Array TextParagraph::get_line_objects(int p_line) const {
 Array TextParagraph::get_line_objects(int p_line) const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
-	ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Array());
+	ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Array());
 	return TS->shaped_text_get_objects(lines_rid[p_line]);
 	return TS->shaped_text_get_objects(lines_rid[p_line]);
 }
 }
 
 
 Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
 Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
-	ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Rect2());
+	ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Rect2());
 	Rect2 xrect = TS->shaped_text_get_object_rect(lines_rid[p_line], p_key);
 	Rect2 xrect = TS->shaped_text_get_object_rect(lines_rid[p_line], p_key);
 	for (int i = 0; i < p_line; i++) {
 	for (int i = 0; i < p_line; i++) {
 		Size2 lsize = TS->shaped_text_get_size(lines_rid[i]);
 		Size2 lsize = TS->shaped_text_get_size(lines_rid[i]);
@@ -495,8 +553,10 @@ Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
 }
 }
 
 
 Size2 TextParagraph::get_line_size(int p_line) const {
 Size2 TextParagraph::get_line_size(int p_line) const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
-	ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Size2());
+	ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Size2());
 	if (TS->shaped_text_get_orientation(lines_rid[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
 	if (TS->shaped_text_get_orientation(lines_rid[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
 		return Size2(TS->shaped_text_get_size(lines_rid[p_line]).x, TS->shaped_text_get_size(lines_rid[p_line]).y + spacing_top + spacing_bottom);
 		return Size2(TS->shaped_text_get_size(lines_rid[p_line]).x, TS->shaped_text_get_size(lines_rid[p_line]).y + spacing_top + spacing_bottom);
 	} else {
 	} else {
@@ -505,42 +565,56 @@ Size2 TextParagraph::get_line_size(int p_line) const {
 }
 }
 
 
 Vector2i TextParagraph::get_line_range(int p_line) const {
 Vector2i TextParagraph::get_line_range(int p_line) const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
-	ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), Vector2i());
+	ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Vector2i());
 	return TS->shaped_text_get_range(lines_rid[p_line]);
 	return TS->shaped_text_get_range(lines_rid[p_line]);
 }
 }
 
 
 float TextParagraph::get_line_ascent(int p_line) const {
 float TextParagraph::get_line_ascent(int p_line) const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
-	ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
+	ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
 	return TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
 	return TS->shaped_text_get_ascent(lines_rid[p_line]) + spacing_top;
 }
 }
 
 
 float TextParagraph::get_line_descent(int p_line) const {
 float TextParagraph::get_line_descent(int p_line) const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
-	ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
+	ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
 	return TS->shaped_text_get_descent(lines_rid[p_line]) + spacing_bottom;
 	return TS->shaped_text_get_descent(lines_rid[p_line]) + spacing_bottom;
 }
 }
 
 
 float TextParagraph::get_line_width(int p_line) const {
 float TextParagraph::get_line_width(int p_line) const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
-	ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
+	ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
 	return TS->shaped_text_get_width(lines_rid[p_line]);
 	return TS->shaped_text_get_width(lines_rid[p_line]);
 }
 }
 
 
 float TextParagraph::get_line_underline_position(int p_line) const {
 float TextParagraph::get_line_underline_position(int p_line) const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
-	ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
+	ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
 	return TS->shaped_text_get_underline_position(lines_rid[p_line]);
 	return TS->shaped_text_get_underline_position(lines_rid[p_line]);
 }
 }
 
 
 float TextParagraph::get_line_underline_thickness(int p_line) const {
 float TextParagraph::get_line_underline_thickness(int p_line) const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
-	ERR_FAIL_COND_V(p_line < 0 || p_line >= lines_rid.size(), 0.f);
+	ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), 0.f);
 	return TS->shaped_text_get_underline_thickness(lines_rid[p_line]);
 	return TS->shaped_text_get_underline_thickness(lines_rid[p_line]);
 }
 }
 
 
 Size2 TextParagraph::get_dropcap_size() const {
 Size2 TextParagraph::get_dropcap_size() const {
+	_THREAD_SAFE_METHOD_
+
 	return TS->shaped_text_get_size(dropcap_rid) + dropcap_margins.size + dropcap_margins.position;
 	return TS->shaped_text_get_size(dropcap_rid) + dropcap_margins.size + dropcap_margins.position;
 }
 }
 
 
@@ -549,6 +623,8 @@ int TextParagraph::get_dropcap_lines() const {
 }
 }
 
 
 void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color, const Color &p_dc_color) const {
 void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color, const Color &p_dc_color) const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	Vector2 ofs = p_pos;
 	Vector2 ofs = p_pos;
 	float h_offset = 0.f;
 	float h_offset = 0.f;
@@ -571,7 +647,7 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
 		TS->shaped_text_draw(dropcap_rid, p_canvas, dc_off + Vector2(0, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.size.y + dropcap_margins.position.y / 2), -1, -1, p_dc_color);
 		TS->shaped_text_draw(dropcap_rid, p_canvas, dc_off + Vector2(0, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.size.y + dropcap_margins.position.y / 2), -1, -1, p_dc_color);
 	}
 	}
 
 
-	int lines_visible = (max_lines_visible >= 0) ? MIN(max_lines_visible, lines_rid.size()) : lines_rid.size();
+	int lines_visible = (max_lines_visible >= 0) ? MIN(max_lines_visible, (int)lines_rid.size()) : (int)lines_rid.size();
 
 
 	for (int i = 0; i < lines_visible; i++) {
 	for (int i = 0; i < lines_visible; i++) {
 		float l_width = width;
 		float l_width = width;
@@ -650,6 +726,8 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
 }
 }
 
 
 void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size, const Color &p_color, const Color &p_dc_color) const {
 void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size, const Color &p_color, const Color &p_dc_color) const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	Vector2 ofs = p_pos;
 	Vector2 ofs = p_pos;
 
 
@@ -673,7 +751,7 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
 		TS->shaped_text_draw_outline(dropcap_rid, p_canvas, dc_off + Vector2(dropcap_margins.position.x, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.position.y), -1, -1, p_outline_size, p_dc_color);
 		TS->shaped_text_draw_outline(dropcap_rid, p_canvas, dc_off + Vector2(dropcap_margins.position.x, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.position.y), -1, -1, p_outline_size, p_dc_color);
 	}
 	}
 
 
-	for (int i = 0; i < lines_rid.size(); i++) {
+	for (int i = 0; i < (int)lines_rid.size(); i++) {
 		float l_width = width;
 		float l_width = width;
 		if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
 		if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
 			ofs.x = p_pos.x;
 			ofs.x = p_pos.x;
@@ -750,6 +828,8 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli
 }
 }
 
 
 int TextParagraph::hit_test(const Point2 &p_coords) const {
 int TextParagraph::hit_test(const Point2 &p_coords) const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	Vector2 ofs;
 	Vector2 ofs;
 	if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
 	if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
@@ -761,7 +841,7 @@ int TextParagraph::hit_test(const Point2 &p_coords) const {
 			return 0;
 			return 0;
 		}
 		}
 	}
 	}
-	for (int i = 0; i < lines_rid.size(); i++) {
+	for (int i = 0; i < (int)lines_rid.size(); i++) {
 		if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
 		if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
 			if ((p_coords.y >= ofs.y) && (p_coords.y <= ofs.y + TS->shaped_text_get_size(lines_rid[i]).y)) {
 			if ((p_coords.y >= ofs.y) && (p_coords.y <= ofs.y + TS->shaped_text_get_size(lines_rid[i]).y)) {
 				return TS->shaped_text_hit_test_position(lines_rid[i], p_coords.x);
 				return TS->shaped_text_hit_test_position(lines_rid[i], p_coords.x);
@@ -778,6 +858,8 @@ int TextParagraph::hit_test(const Point2 &p_coords) const {
 }
 }
 
 
 void TextParagraph::draw_dropcap(RID p_canvas, const Vector2 &p_pos, const Color &p_color) const {
 void TextParagraph::draw_dropcap(RID p_canvas, const Vector2 &p_pos, const Color &p_color) const {
+	_THREAD_SAFE_METHOD_
+
 	Vector2 ofs = p_pos;
 	Vector2 ofs = p_pos;
 	float h_offset = 0.f;
 	float h_offset = 0.f;
 	if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
 	if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
@@ -800,6 +882,8 @@ void TextParagraph::draw_dropcap(RID p_canvas, const Vector2 &p_pos, const Color
 }
 }
 
 
 void TextParagraph::draw_dropcap_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size, const Color &p_color) const {
 void TextParagraph::draw_dropcap_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size, const Color &p_color) const {
+	_THREAD_SAFE_METHOD_
+
 	Vector2 ofs = p_pos;
 	Vector2 ofs = p_pos;
 	float h_offset = 0.f;
 	float h_offset = 0.f;
 	if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
 	if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
@@ -822,8 +906,10 @@ void TextParagraph::draw_dropcap_outline(RID p_canvas, const Vector2 &p_pos, int
 }
 }
 
 
 void TextParagraph::draw_line(RID p_canvas, const Vector2 &p_pos, int p_line, const Color &p_color) const {
 void TextParagraph::draw_line(RID p_canvas, const Vector2 &p_pos, int p_line, const Color &p_color) const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
-	ERR_FAIL_COND(p_line < 0 || p_line >= lines_rid.size());
+	ERR_FAIL_COND(p_line < 0 || p_line >= (int)lines_rid.size());
 
 
 	Vector2 ofs = p_pos;
 	Vector2 ofs = p_pos;
 
 
@@ -836,8 +922,10 @@ void TextParagraph::draw_line(RID p_canvas, const Vector2 &p_pos, int p_line, co
 }
 }
 
 
 void TextParagraph::draw_line_outline(RID p_canvas, const Vector2 &p_pos, int p_line, int p_outline_size, const Color &p_color) const {
 void TextParagraph::draw_line_outline(RID p_canvas, const Vector2 &p_pos, int p_line, int p_outline_size, const Color &p_color) const {
+	_THREAD_SAFE_METHOD_
+
 	const_cast<TextParagraph *>(this)->_shape_lines();
 	const_cast<TextParagraph *>(this)->_shape_lines();
-	ERR_FAIL_COND(p_line < 0 || p_line >= lines_rid.size());
+	ERR_FAIL_COND(p_line < 0 || p_line >= (int)lines_rid.size());
 
 
 	Vector2 ofs = p_pos;
 	Vector2 ofs = p_pos;
 	if (TS->shaped_text_get_orientation(lines_rid[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
 	if (TS->shaped_text_get_orientation(lines_rid[p_line]) == TextServer::ORIENTATION_HORIZONTAL) {
@@ -862,7 +950,7 @@ TextParagraph::TextParagraph() {
 }
 }
 
 
 TextParagraph::~TextParagraph() {
 TextParagraph::~TextParagraph() {
-	for (int i = 0; i < lines_rid.size(); i++) {
+	for (int i = 0; i < (int)lines_rid.size(); i++) {
 		TS->free_rid(lines_rid[i]);
 		TS->free_rid(lines_rid[i]);
 	}
 	}
 	lines_rid.clear();
 	lines_rid.clear();

+ 5 - 1
scene/resources/text_paragraph.h

@@ -31,6 +31,7 @@
 #ifndef TEXT_PARAGRAPH_H
 #ifndef TEXT_PARAGRAPH_H
 #define TEXT_PARAGRAPH_H
 #define TEXT_PARAGRAPH_H
 
 
+#include "core/templates/local_vector.h"
 #include "scene/resources/font.h"
 #include "scene/resources/font.h"
 #include "servers/text_server.h"
 #include "servers/text_server.h"
 
 
@@ -38,6 +39,7 @@
 
 
 class TextParagraph : public RefCounted {
 class TextParagraph : public RefCounted {
 	GDCLASS(TextParagraph, RefCounted);
 	GDCLASS(TextParagraph, RefCounted);
+	_THREAD_SAFE_CLASS_
 
 
 public:
 public:
 	enum OverrunBehavior {
 	enum OverrunBehavior {
@@ -54,7 +56,7 @@ private:
 	Rect2 dropcap_margins;
 	Rect2 dropcap_margins;
 
 
 	RID rid;
 	RID rid;
-	Vector<RID> lines_rid;
+	LocalVector<RID> lines_rid;
 	int spacing_top = 0;
 	int spacing_top = 0;
 	int spacing_bottom = 0;
 	int spacing_bottom = 0;
 
 
@@ -156,6 +158,8 @@ public:
 
 
 	int hit_test(const Point2 &p_coords) const;
 	int hit_test(const Point2 &p_coords) const;
 
 
+	Mutex &get_mutex() const { return _thread_safe_; };
+
 	TextParagraph(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", float p_width = -1.f, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
 	TextParagraph(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", float p_width = -1.f, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
 	TextParagraph();
 	TextParagraph();
 	~TextParagraph();
 	~TextParagraph();

Some files were not shown because too many files changed in this diff