Browse Source

Merge pull request #69288 from bruvzg/gde_low_level_funcs

[GDExtension] Expose some low level functions and String operators.
Rémi Verschelde 2 years ago
parent
commit
f6c662264e

+ 75 - 0
core/extension/gdextension_interface.cpp

@@ -31,8 +31,11 @@
 #include "gdextension_interface.h"
 
 #include "core/config/engine.h"
+#include "core/io/file_access.h"
+#include "core/io/xml_parser.h"
 #include "core/object/class_db.h"
 #include "core/object/script_language_extension.h"
+#include "core/object/worker_thread_pool.h"
 #include "core/os/memory.h"
 #include "core/variant/variant.h"
 #include "core/version.h"
@@ -678,6 +681,59 @@ static const char32_t *gdextension_string_operator_index_const(GDExtensionConstS
 	return &self->ptr()[p_index];
 }
 
+static void gdextension_string_operator_plus_eq_string(GDExtensionStringPtr p_self, GDExtensionConstStringPtr p_b) {
+	String *self = (String *)p_self;
+	const String *b = (const String *)p_b;
+	*self += *b;
+}
+
+static void gdextension_string_operator_plus_eq_char(GDExtensionStringPtr p_self, char32_t p_b) {
+	String *self = (String *)p_self;
+	*self += p_b;
+}
+
+static void gdextension_string_operator_plus_eq_cstr(GDExtensionStringPtr p_self, const char *p_b) {
+	String *self = (String *)p_self;
+	*self += p_b;
+}
+
+static void gdextension_string_operator_plus_eq_wcstr(GDExtensionStringPtr p_self, const wchar_t *p_b) {
+	String *self = (String *)p_self;
+	*self += p_b;
+}
+
+static void gdextension_string_operator_plus_eq_c32str(GDExtensionStringPtr p_self, const char32_t *p_b) {
+	String *self = (String *)p_self;
+	*self += p_b;
+}
+
+static GDExtensionInt gdextension_xml_parser_open_buffer(GDExtensionObjectPtr p_instance, const uint8_t *p_buffer, size_t p_size) {
+	XMLParser *xml = (XMLParser *)p_instance;
+	return (GDExtensionInt)xml->_open_buffer(p_buffer, p_size);
+}
+
+static void gdextension_file_access_store_buffer(GDExtensionObjectPtr p_instance, const uint8_t *p_src, uint64_t p_length) {
+	FileAccess *fa = (FileAccess *)p_instance;
+	fa->store_buffer(p_src, p_length);
+}
+
+static uint64_t gdextension_file_access_get_buffer(GDExtensionConstObjectPtr p_instance, uint8_t *p_dst, uint64_t p_length) {
+	const FileAccess *fa = (FileAccess *)p_instance;
+	return fa->get_buffer(p_dst, p_length);
+}
+
+static int64_t gdextension_worker_thread_pool_add_native_group_task(GDExtensionObjectPtr p_instance, void (*p_func)(void *, uint32_t), void *p_userdata, int p_elements, int p_tasks, bool p_high_priority, GDExtensionConstStringPtr p_description) {
+	WorkerThreadPool *p = (WorkerThreadPool *)p_instance;
+	const String *description = (const String *)p_description;
+	return (int64_t)p->add_native_group_task(p_func, p_userdata, p_elements, p_tasks, p_high_priority, *description);
+}
+
+static int64_t gdextension_worker_thread_pool_add_native_task(GDExtensionObjectPtr p_instance, void (*p_func)(void *), void *p_userdata, bool p_high_priority, GDExtensionConstStringPtr p_description) {
+	WorkerThreadPool *p = (WorkerThreadPool *)p_instance;
+	const String *description = (const String *)p_description;
+	return (int64_t)p->add_native_task(p_func, p_userdata, p_high_priority, *description);
+}
+
 /* Packed array functions */
 
 static uint8_t *gdextension_packed_byte_array_operator_index(GDExtensionTypePtr p_self, GDExtensionInt p_index) {
@@ -1025,6 +1081,25 @@ void gdextension_setup_interface(GDExtensionInterface *p_interface) {
 	gde_interface.string_to_wide_chars = gdextension_string_to_wide_chars;
 	gde_interface.string_operator_index = gdextension_string_operator_index;
 	gde_interface.string_operator_index_const = gdextension_string_operator_index_const;
+	gde_interface.string_operator_plus_eq_string = gdextension_string_operator_plus_eq_string;
+	gde_interface.string_operator_plus_eq_char = gdextension_string_operator_plus_eq_char;
+	gde_interface.string_operator_plus_eq_cstr = gdextension_string_operator_plus_eq_cstr;
+	gde_interface.string_operator_plus_eq_wcstr = gdextension_string_operator_plus_eq_wcstr;
+	gde_interface.string_operator_plus_eq_c32str = gdextension_string_operator_plus_eq_c32str;
+
+	/*  XMLParser extra utilities */
+
+	gde_interface.xml_parser_open_buffer = gdextension_xml_parser_open_buffer;
+
+	/*  FileAccess extra utilities */
+
+	gde_interface.file_access_store_buffer = gdextension_file_access_store_buffer;
+	gde_interface.file_access_get_buffer = gdextension_file_access_get_buffer;
+
+	/*  WorkerThreadPool extra utilities */
+
+	gde_interface.worker_thread_pool_add_native_group_task = gdextension_worker_thread_pool_add_native_group_task;
+	gde_interface.worker_thread_pool_add_native_task = gdextension_worker_thread_pool_add_native_task;
 
 	/* Packed array functions */
 

+ 20 - 0
core/extension/gdextension_interface.h

@@ -503,6 +503,26 @@ typedef struct {
 	char32_t *(*string_operator_index)(GDExtensionStringPtr p_self, GDExtensionInt p_index);
 	const char32_t *(*string_operator_index_const)(GDExtensionConstStringPtr p_self, GDExtensionInt p_index);
 
+	void (*string_operator_plus_eq_string)(GDExtensionStringPtr p_self, GDExtensionConstStringPtr p_b);
+	void (*string_operator_plus_eq_char)(GDExtensionStringPtr p_self, char32_t p_b);
+	void (*string_operator_plus_eq_cstr)(GDExtensionStringPtr p_self, const char *p_b);
+	void (*string_operator_plus_eq_wcstr)(GDExtensionStringPtr p_self, const wchar_t *p_b);
+	void (*string_operator_plus_eq_c32str)(GDExtensionStringPtr p_self, const char32_t *p_b);
+
+	/*  XMLParser extra utilities */
+
+	GDExtensionInt (*xml_parser_open_buffer)(GDExtensionObjectPtr p_instance, const uint8_t *p_buffer, size_t p_size);
+
+	/*  FileAccess extra utilities */
+
+	void (*file_access_store_buffer)(GDExtensionObjectPtr p_instance, const uint8_t *p_src, uint64_t p_length);
+	uint64_t (*file_access_get_buffer)(GDExtensionConstObjectPtr p_instance, uint8_t *p_dst, uint64_t p_length);
+
+	/*  WorkerThreadPool extra utilities */
+
+	int64_t (*worker_thread_pool_add_native_group_task)(GDExtensionObjectPtr p_instance, void (*p_func)(void *, uint32_t), void *p_userdata, int p_elements, int p_tasks, bool p_high_priority, GDExtensionConstStringPtr p_description);
+	int64_t (*worker_thread_pool_add_native_task)(GDExtensionObjectPtr p_instance, void (*p_func)(void *), void *p_userdata, bool p_high_priority, GDExtensionConstStringPtr p_description);
+
 	/* Packed array functions */
 
 	uint8_t *(*packed_byte_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedByteArray

+ 6 - 6
core/io/file_access.cpp

@@ -292,7 +292,7 @@ real_t FileAccess::get_real() const {
 
 Variant FileAccess::get_var(bool p_allow_objects) const {
 	uint32_t len = get_32();
-	Vector<uint8_t> buff = _get_buffer(len);
+	Vector<uint8_t> buff = get_buffer(len);
 	ERR_FAIL_COND_V((uint32_t)buff.size() != len, Variant());
 
 	const uint8_t *r = buff.ptr();
@@ -469,7 +469,7 @@ uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
 	return i;
 }
 
-Vector<uint8_t> FileAccess::_get_buffer(int64_t p_length) const {
+Vector<uint8_t> FileAccess::get_buffer(int64_t p_length) const {
 	Vector<uint8_t> data;
 
 	ERR_FAIL_COND_V_MSG(p_length < 0, data, "Length of buffer cannot be smaller than 0.");
@@ -663,7 +663,7 @@ void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) {
 	}
 }
 
-void FileAccess::_store_buffer(const Vector<uint8_t> &p_buffer) {
+void FileAccess::store_buffer(const Vector<uint8_t> &p_buffer) {
 	uint64_t len = p_buffer.size();
 	if (len == 0) {
 		return;
@@ -687,7 +687,7 @@ void FileAccess::store_var(const Variant &p_var, bool p_full_objects) {
 	ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
 
 	store_32(len);
-	_store_buffer(buff);
+	store_buffer(buff);
 }
 
 Vector<uint8_t> FileAccess::get_file_as_bytes(const String &p_path, Error *r_error) {
@@ -829,7 +829,7 @@ void FileAccess::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_float"), &FileAccess::get_float);
 	ClassDB::bind_method(D_METHOD("get_double"), &FileAccess::get_double);
 	ClassDB::bind_method(D_METHOD("get_real"), &FileAccess::get_real);
-	ClassDB::bind_method(D_METHOD("get_buffer", "length"), &FileAccess::_get_buffer);
+	ClassDB::bind_method(D_METHOD("get_buffer", "length"), (Vector<uint8_t>(FileAccess::*)(int64_t) const) & FileAccess::get_buffer);
 	ClassDB::bind_method(D_METHOD("get_line"), &FileAccess::get_line);
 	ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &FileAccess::get_csv_line, DEFVAL(","));
 	ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr"), &FileAccess::get_as_text, DEFVAL(false));
@@ -847,7 +847,7 @@ void FileAccess::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("store_float", "value"), &FileAccess::store_float);
 	ClassDB::bind_method(D_METHOD("store_double", "value"), &FileAccess::store_double);
 	ClassDB::bind_method(D_METHOD("store_real", "value"), &FileAccess::store_real);
-	ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), &FileAccess::_store_buffer);
+	ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), (void(FileAccess::*)(const Vector<uint8_t> &)) & FileAccess::store_buffer);
 	ClassDB::bind_method(D_METHOD("store_line", "line"), &FileAccess::store_line);
 	ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &FileAccess::store_csv_line, DEFVAL(","));
 	ClassDB::bind_method(D_METHOD("store_string", "string"), &FileAccess::store_string);

+ 2 - 2
core/io/file_access.h

@@ -127,7 +127,7 @@ public:
 	Variant get_var(bool p_allow_objects = false) const;
 
 	virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; ///< get an array of bytes
-	Vector<uint8_t> _get_buffer(int64_t p_length) const;
+	Vector<uint8_t> get_buffer(int64_t p_length) const;
 	virtual String get_line() const;
 	virtual String get_token() const;
 	virtual Vector<String> get_csv_line(const String &p_delim = ",") const;
@@ -162,7 +162,7 @@ public:
 	virtual String get_pascal_string();
 
 	virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
-	void _store_buffer(const Vector<uint8_t> &p_buffer);
+	void store_buffer(const Vector<uint8_t> &p_buffer);
 
 	void store_var(const Variant &p_var, bool p_full_objects = false);
 

+ 5 - 5
core/io/xml_parser.cpp

@@ -354,10 +354,10 @@ void XMLParser::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_node_offset"), &XMLParser::get_node_offset);
 	ClassDB::bind_method(D_METHOD("get_attribute_count"), &XMLParser::get_attribute_count);
 	ClassDB::bind_method(D_METHOD("get_attribute_name", "idx"), &XMLParser::get_attribute_name);
-	ClassDB::bind_method(D_METHOD("get_attribute_value", "idx"), (String(XMLParser::*)(int) const) & XMLParser::get_attribute_value);
+	ClassDB::bind_method(D_METHOD("get_attribute_value", "idx"), &XMLParser::get_attribute_value);
 	ClassDB::bind_method(D_METHOD("has_attribute", "name"), &XMLParser::has_attribute);
-	ClassDB::bind_method(D_METHOD("get_named_attribute_value", "name"), (String(XMLParser::*)(const String &) const) & XMLParser::get_attribute_value);
-	ClassDB::bind_method(D_METHOD("get_named_attribute_value_safe", "name"), &XMLParser::get_attribute_value_safe);
+	ClassDB::bind_method(D_METHOD("get_named_attribute_value", "name"), &XMLParser::get_named_attribute_value);
+	ClassDB::bind_method(D_METHOD("get_named_attribute_value_safe", "name"), &XMLParser::get_named_attribute_value_safe);
 	ClassDB::bind_method(D_METHOD("is_empty"), &XMLParser::is_empty);
 	ClassDB::bind_method(D_METHOD("get_current_line"), &XMLParser::get_current_line);
 	ClassDB::bind_method(D_METHOD("skip_section"), &XMLParser::skip_section);
@@ -422,7 +422,7 @@ bool XMLParser::has_attribute(const String &p_name) const {
 	return false;
 }
 
-String XMLParser::get_attribute_value(const String &p_name) const {
+String XMLParser::get_named_attribute_value(const String &p_name) const {
 	int idx = -1;
 	for (int i = 0; i < attributes.size(); i++) {
 		if (attributes[i].name == p_name) {
@@ -436,7 +436,7 @@ String XMLParser::get_attribute_value(const String &p_name) const {
 	return attributes[idx].value;
 }
 
-String XMLParser::get_attribute_value_safe(const String &p_name) const {
+String XMLParser::get_named_attribute_value_safe(const String &p_name) const {
 	int idx = -1;
 	for (int i = 0; i < attributes.size(); i++) {
 		if (attributes[i].name == p_name) {

+ 2 - 2
core/io/xml_parser.h

@@ -109,8 +109,8 @@ public:
 	String get_attribute_name(int p_idx) const;
 	String get_attribute_value(int p_idx) const;
 	bool has_attribute(const String &p_name) const;
-	String get_attribute_value(const String &p_name) const;
-	String get_attribute_value_safe(const String &p_name) const; // do not print error if doesn't exist
+	String get_named_attribute_value(const String &p_name) const;
+	String get_named_attribute_value_safe(const String &p_name) const; // do not print error if doesn't exist
 	bool is_empty() const;
 	int get_current_line() const;
 

+ 31 - 31
editor/doc_tools.cpp

@@ -1021,15 +1021,15 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &
 			if (parser->get_node_name() == element) {
 				DocData::MethodDoc method;
 				ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
-				method.name = parser->get_attribute_value("name");
+				method.name = parser->get_named_attribute_value("name");
 				if (parser->has_attribute("qualifiers")) {
-					method.qualifiers = parser->get_attribute_value("qualifiers");
+					method.qualifiers = parser->get_named_attribute_value("qualifiers");
 				}
 				if (parser->has_attribute("is_deprecated")) {
-					method.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
+					method.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true";
 				}
 				if (parser->has_attribute("is_experimental")) {
-					method.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
+					method.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true";
 				}
 
 				while (parser->read() == OK) {
@@ -1037,21 +1037,21 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &
 						String name = parser->get_node_name();
 						if (name == "return") {
 							ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
-							method.return_type = parser->get_attribute_value("type");
+							method.return_type = parser->get_named_attribute_value("type");
 							if (parser->has_attribute("enum")) {
-								method.return_enum = parser->get_attribute_value("enum");
+								method.return_enum = parser->get_named_attribute_value("enum");
 							}
 						} else if (name == "returns_error") {
 							ERR_FAIL_COND_V(!parser->has_attribute("number"), ERR_FILE_CORRUPT);
-							method.errors_returned.push_back(parser->get_attribute_value("number").to_int());
+							method.errors_returned.push_back(parser->get_named_attribute_value("number").to_int());
 						} else if (name == "param") {
 							DocData::ArgumentDoc argument;
 							ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
-							argument.name = parser->get_attribute_value("name");
+							argument.name = parser->get_named_attribute_value("name");
 							ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
-							argument.type = parser->get_attribute_value("type");
+							argument.type = parser->get_named_attribute_value("type");
 							if (parser->has_attribute("enum")) {
-								argument.enumeration = parser->get_attribute_value("enum");
+								argument.enumeration = parser->get_named_attribute_value("enum");
 							}
 
 							method.arguments.push_back(argument);
@@ -1153,21 +1153,21 @@ Error DocTools::_load(Ref<XMLParser> parser) {
 		ERR_FAIL_COND_V(parser->get_node_name() != "class", ERR_FILE_CORRUPT);
 
 		ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
-		String name = parser->get_attribute_value("name");
+		String name = parser->get_named_attribute_value("name");
 		class_list[name] = DocData::ClassDoc();
 		DocData::ClassDoc &c = class_list[name];
 
 		c.name = name;
 		if (parser->has_attribute("inherits")) {
-			c.inherits = parser->get_attribute_value("inherits");
+			c.inherits = parser->get_named_attribute_value("inherits");
 		}
 
 		if (parser->has_attribute("is_deprecated")) {
-			c.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
+			c.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true";
 		}
 
 		if (parser->has_attribute("is_experimental")) {
-			c.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
+			c.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true";
 		}
 
 		while (parser->read() == OK) {
@@ -1193,7 +1193,7 @@ Error DocTools::_load(Ref<XMLParser> parser) {
 							if (name3 == "link") {
 								DocData::TutorialDoc tutorial;
 								if (parser->has_attribute("title")) {
-									tutorial.title = parser->get_attribute_value("title");
+									tutorial.title = parser->get_named_attribute_value("title");
 								}
 								parser->read();
 								if (parser->get_node_type() == XMLParser::NODE_TEXT) {
@@ -1231,23 +1231,23 @@ Error DocTools::_load(Ref<XMLParser> parser) {
 								DocData::PropertyDoc prop2;
 
 								ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
-								prop2.name = parser->get_attribute_value("name");
+								prop2.name = parser->get_named_attribute_value("name");
 								ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
-								prop2.type = parser->get_attribute_value("type");
+								prop2.type = parser->get_named_attribute_value("type");
 								if (parser->has_attribute("setter")) {
-									prop2.setter = parser->get_attribute_value("setter");
+									prop2.setter = parser->get_named_attribute_value("setter");
 								}
 								if (parser->has_attribute("getter")) {
-									prop2.getter = parser->get_attribute_value("getter");
+									prop2.getter = parser->get_named_attribute_value("getter");
 								}
 								if (parser->has_attribute("enum")) {
-									prop2.enumeration = parser->get_attribute_value("enum");
+									prop2.enumeration = parser->get_named_attribute_value("enum");
 								}
 								if (parser->has_attribute("is_deprecated")) {
-									prop2.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
+									prop2.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true";
 								}
 								if (parser->has_attribute("is_experimental")) {
-									prop2.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
+									prop2.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true";
 								}
 								if (!parser->is_empty()) {
 									parser->read();
@@ -1274,11 +1274,11 @@ Error DocTools::_load(Ref<XMLParser> parser) {
 								DocData::ThemeItemDoc prop2;
 
 								ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
-								prop2.name = parser->get_attribute_value("name");
+								prop2.name = parser->get_named_attribute_value("name");
 								ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
-								prop2.type = parser->get_attribute_value("type");
+								prop2.type = parser->get_named_attribute_value("type");
 								ERR_FAIL_COND_V(!parser->has_attribute("data_type"), ERR_FILE_CORRUPT);
-								prop2.data_type = parser->get_attribute_value("data_type");
+								prop2.data_type = parser->get_named_attribute_value("data_type");
 								if (!parser->is_empty()) {
 									parser->read();
 									if (parser->get_node_type() == XMLParser::NODE_TEXT) {
@@ -1303,21 +1303,21 @@ Error DocTools::_load(Ref<XMLParser> parser) {
 							if (name3 == "constant") {
 								DocData::ConstantDoc constant2;
 								ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
-								constant2.name = parser->get_attribute_value("name");
+								constant2.name = parser->get_named_attribute_value("name");
 								ERR_FAIL_COND_V(!parser->has_attribute("value"), ERR_FILE_CORRUPT);
-								constant2.value = parser->get_attribute_value("value");
+								constant2.value = parser->get_named_attribute_value("value");
 								constant2.is_value_valid = true;
 								if (parser->has_attribute("enum")) {
-									constant2.enumeration = parser->get_attribute_value("enum");
+									constant2.enumeration = parser->get_named_attribute_value("enum");
 								}
 								if (parser->has_attribute("is_bitfield")) {
-									constant2.is_bitfield = parser->get_attribute_value("is_bitfield").to_lower() == "true";
+									constant2.is_bitfield = parser->get_named_attribute_value("is_bitfield").to_lower() == "true";
 								}
 								if (parser->has_attribute("is_deprecated")) {
-									constant2.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
+									constant2.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true";
 								}
 								if (parser->has_attribute("is_experimental")) {
-									constant2.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
+									constant2.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true";
 								}
 								if (!parser->is_empty()) {
 									parser->read();

+ 82 - 82
editor/import/collada.cpp

@@ -262,7 +262,7 @@ void Collada::_parse_asset(XMLParser &parser) {
 
 				COLLADA_PRINT("up axis: " + parser.get_node_data());
 			} else if (name == "unit") {
-				state.unit_scale = parser.get_attribute_value("meter").to_float();
+				state.unit_scale = parser.get_named_attribute_value("meter").to_float();
 				COLLADA_PRINT("unit scale: " + rtos(state.unit_scale));
 			}
 
@@ -273,7 +273,7 @@ void Collada::_parse_asset(XMLParser &parser) {
 }
 
 void Collada::_parse_image(XMLParser &parser) {
-	String id = parser.get_attribute_value("id");
+	String id = parser.get_named_attribute_value("id");
 
 	if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
 		if (!parser.is_empty()) {
@@ -286,7 +286,7 @@ void Collada::_parse_image(XMLParser &parser) {
 
 	if (state.version < State::Version(1, 4, 0)) {
 		/* <1.4 */
-		String path = parser.get_attribute_value("source").strip_edges();
+		String path = parser.get_named_attribute_value("source").strip_edges();
 		if (!path.contains("://") && path.is_relative_path()) {
 			// path is relative to file being loaded, so convert to a resource path
 			image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().path_join(path.uri_decode()));
@@ -337,9 +337,9 @@ void Collada::_parse_material(XMLParser &parser) {
 
 	Material material;
 
-	String id = parser.get_attribute_value("id");
+	String id = parser.get_named_attribute_value("id");
 	if (parser.has_attribute("name")) {
-		material.name = parser.get_attribute_value("name");
+		material.name = parser.get_named_attribute_value("name");
 	}
 
 	if (state.version < State::Version(1, 4, 0)) {
@@ -348,7 +348,7 @@ void Collada::_parse_material(XMLParser &parser) {
 	} else {
 		while (parser.read() == OK) {
 			if (parser.get_node_type() == XMLParser::NODE_ELEMENT && parser.get_node_name() == "instance_effect") {
-				material.instance_effect = _uri_to_id(parser.get_attribute_value("url"));
+				material.instance_effect = _uri_to_id(parser.get_named_attribute_value("url"));
 			} else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "material") {
 				break; //end of <asset>
 			}
@@ -549,7 +549,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
 				_parse_effect_material(parser, effect, id); // try again
 
 			} else if (parser.get_node_name() == "newparam") {
-				String name = parser.get_attribute_value("sid");
+				String name = parser.get_named_attribute_value("sid");
 				Variant value = _parse_param(parser);
 				effect.params[name] = value;
 				COLLADA_PRINT("param: " + name + " value:" + String(value));
@@ -591,7 +591,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
 										}
 
 									} else if (parser.get_node_name() == "texture") {
-										String sampler = parser.get_attribute_value("texture");
+										String sampler = parser.get_named_attribute_value("texture");
 										if (!effect.params.has(sampler)) {
 											ERR_PRINT(String("Couldn't find sampler: " + sampler + " in material:" + id).utf8().get_data());
 										} else {
@@ -609,7 +609,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
 												} else if (what == "emission") {
 													effect.emission.texture = uri;
 												} else if (what == "bump") {
-													if (parser.has_attribute("bumptype") && parser.get_attribute_value("bumptype") != "NORMALMAP") {
+													if (parser.has_attribute("bumptype") && parser.get_named_attribute_value("bumptype") != "NORMALMAP") {
 														WARN_PRINT("'bump' texture type is not NORMALMAP, only NORMALMAP is supported.");
 													}
 
@@ -654,7 +654,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
 				while (parser.read() == OK) {
 					if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
 						if (parser.get_node_name() == "texture") {
-							String sampler = parser.get_attribute_value("texture");
+							String sampler = parser.get_named_attribute_value("texture");
 							if (!effect.params.has(sampler)) {
 								ERR_PRINT(String("Couldn't find sampler: " + sampler + " in material:" + id).utf8().get_data());
 							} else {
@@ -665,7 +665,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
 								} else {
 									String uri = effect.params[surface];
 
-									if (parser.has_attribute("bumptype") && parser.get_attribute_value("bumptype") != "NORMALMAP") {
+									if (parser.has_attribute("bumptype") && parser.get_named_attribute_value("bumptype") != "NORMALMAP") {
 										WARN_PRINT("'bump' texture type is not NORMALMAP, only NORMALMAP is supported.");
 									}
 
@@ -703,11 +703,11 @@ void Collada::_parse_effect(XMLParser &parser) {
 		return;
 	}
 
-	String id = parser.get_attribute_value("id");
+	String id = parser.get_named_attribute_value("id");
 
 	Effect effect;
 	if (parser.has_attribute("name")) {
-		effect.name = parser.get_attribute_value("name");
+		effect.name = parser.get_named_attribute_value("name");
 	}
 	_parse_effect_material(parser, effect, id);
 
@@ -724,7 +724,7 @@ void Collada::_parse_camera(XMLParser &parser) {
 		return;
 	}
 
-	String id = parser.get_attribute_value("id");
+	String id = parser.get_named_attribute_value("id");
 
 	state.camera_data_map[id] = CameraData();
 	CameraData &camera = state.camera_data_map[id];
@@ -780,7 +780,7 @@ void Collada::_parse_light(XMLParser &parser) {
 		return;
 	}
 
-	String id = parser.get_attribute_value("id");
+	String id = parser.get_named_attribute_value("id");
 
 	state.light_data_map[id] = LightData();
 	LightData &light = state.light_data_map[id];
@@ -848,7 +848,7 @@ void Collada::_parse_curve_geometry(XMLParser &parser, String p_id, String p_nam
 
 	CurveData &curvedata = state.curve_data_map[p_id];
 	curvedata.name = p_name;
-	String closed = parser.get_attribute_value_safe("closed").to_lower();
+	String closed = parser.get_named_attribute_value_safe("closed").to_lower();
 	curvedata.closed = closed == "true" || closed == "1";
 
 	COLLADA_PRINT("curve name: " + p_name);
@@ -865,7 +865,7 @@ void Collada::_parse_curve_geometry(XMLParser &parser, String p_id, String p_nam
 			String section = parser.get_node_name();
 
 			if (section == "source") {
-				String id = parser.get_attribute_value("id");
+				String id = parser.get_named_attribute_value("id");
 				curvedata.sources[id] = CurveData::Source();
 				current_source = id;
 				COLLADA_PRINT("source data: " + id);
@@ -888,15 +888,15 @@ void Collada::_parse_curve_geometry(XMLParser &parser, String p_id, String p_nam
 			} else if (section == "accessor") { // child of source (below a technique tag)
 
 				if (curvedata.sources.has(current_source)) {
-					curvedata.sources[current_source].stride = parser.get_attribute_value("stride").to_int();
+					curvedata.sources[current_source].stride = parser.get_named_attribute_value("stride").to_int();
 					COLLADA_PRINT("section: " + current_source + " stride " + itos(curvedata.sources[current_source].stride));
 				}
 			} else if (section == "control_vertices") {
 				while (parser.read() == OK) {
 					if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
 						if (parser.get_node_name() == "input") {
-							String semantic = parser.get_attribute_value("semantic");
-							String source = _uri_to_id(parser.get_attribute_value("source"));
+							String semantic = parser.get_named_attribute_value("semantic");
+							String source = _uri_to_id(parser.get_named_attribute_value("source"));
 
 							curvedata.control_vertices[semantic] = source;
 
@@ -945,7 +945,7 @@ void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name
 			String section = parser.get_node_name();
 
 			if (section == "source") {
-				String id = parser.get_attribute_value("id");
+				String id = parser.get_named_attribute_value("id");
 				meshdata.sources[id] = MeshData::Source();
 				current_source = id;
 				COLLADA_PRINT("source data: " + id);
@@ -961,19 +961,19 @@ void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name
 			} else if (section == "accessor") { // child of source (below a technique tag)
 
 				if (meshdata.sources.has(current_source)) {
-					meshdata.sources[current_source].stride = parser.get_attribute_value("stride").to_int();
+					meshdata.sources[current_source].stride = parser.get_named_attribute_value("stride").to_int();
 					COLLADA_PRINT("section: " + current_source + " stride " + itos(meshdata.sources[current_source].stride));
 				}
 			} else if (section == "vertices") {
 				MeshData::Vertices vert;
-				String id = parser.get_attribute_value("id");
+				String id = parser.get_named_attribute_value("id");
 				int last_ref = 0;
 
 				while (parser.read() == OK) {
 					if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
 						if (parser.get_node_name() == "input") {
-							String semantic = parser.get_attribute_value("semantic");
-							String source = _uri_to_id(parser.get_attribute_value("source"));
+							String semantic = parser.get_named_attribute_value("semantic");
+							String source = _uri_to_id(parser.get_named_attribute_value("source"));
 
 							if (semantic == "TEXCOORD") {
 								semantic = "TEXCOORD" + itos(last_ref++);
@@ -998,22 +998,22 @@ void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name
 				MeshData::Primitives prim;
 
 				if (parser.has_attribute("material")) {
-					prim.material = parser.get_attribute_value("material");
+					prim.material = parser.get_named_attribute_value("material");
 				}
-				prim.count = parser.get_attribute_value("count").to_int();
+				prim.count = parser.get_named_attribute_value("count").to_int();
 				prim.vertex_size = 0;
 				int last_ref = 0;
 
 				while (parser.read() == OK) {
 					if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
 						if (parser.get_node_name() == "input") {
-							String semantic = parser.get_attribute_value("semantic");
-							String source = _uri_to_id(parser.get_attribute_value("source"));
+							String semantic = parser.get_named_attribute_value("semantic");
+							String source = _uri_to_id(parser.get_named_attribute_value("source"));
 
 							if (semantic == "TEXCOORD") {
 								semantic = "TEXCOORD" + itos(last_ref++);
 							}
-							int offset = parser.get_attribute_value("offset").to_int();
+							int offset = parser.get_named_attribute_value("offset").to_int();
 
 							MeshData::Primitives::SourceRef sref;
 							sref.source = source;
@@ -1074,7 +1074,7 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
 	state.skin_controller_data_map[p_id] = SkinControllerData();
 	SkinControllerData &skindata = state.skin_controller_data_map[p_id];
 
-	skindata.base = _uri_to_id(parser.get_attribute_value("source"));
+	skindata.base = _uri_to_id(parser.get_named_attribute_value("source"));
 
 	String current_source;
 
@@ -1091,7 +1091,7 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
 				COLLADA_PRINT("skeleton bind shape transform: " + skindata.bind_shape);
 
 			} else if (section == "source") {
-				String id = parser.get_attribute_value("id");
+				String id = parser.get_named_attribute_value("id");
 				skindata.sources[id] = SkinControllerData::Source();
 				current_source = id;
 				COLLADA_PRINT("source data: " + id);
@@ -1125,7 +1125,7 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
 				if (skindata.sources.has(current_source)) {
 					int stride = 1;
 					if (parser.has_attribute("stride")) {
-						stride = parser.get_attribute_value("stride").to_int();
+						stride = parser.get_named_attribute_value("stride").to_int();
 					}
 
 					skindata.sources[current_source].stride = stride;
@@ -1138,8 +1138,8 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
 				while (parser.read() == OK) {
 					if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
 						if (parser.get_node_name() == "input") {
-							String semantic = parser.get_attribute_value("semantic");
-							String source = _uri_to_id(parser.get_attribute_value("source"));
+							String semantic = parser.get_named_attribute_value("semantic");
+							String source = _uri_to_id(parser.get_named_attribute_value("source"));
 
 							joint.sources[semantic] = source;
 
@@ -1155,15 +1155,15 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
 			} else if (section == "vertex_weights") {
 				SkinControllerData::Weights weights;
 
-				weights.count = parser.get_attribute_value("count").to_int();
+				weights.count = parser.get_named_attribute_value("count").to_int();
 
 				while (parser.read() == OK) {
 					if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
 						if (parser.get_node_name() == "input") {
-							String semantic = parser.get_attribute_value("semantic");
-							String source = _uri_to_id(parser.get_attribute_value("source"));
+							String semantic = parser.get_named_attribute_value("semantic");
+							String source = _uri_to_id(parser.get_named_attribute_value("source"));
 
-							int offset = parser.get_attribute_value("offset").to_int();
+							int offset = parser.get_named_attribute_value("offset").to_int();
 
 							SkinControllerData::Weights::SourceRef sref;
 							sref.source = source;
@@ -1228,8 +1228,8 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
 	state.morph_controller_data_map[p_id] = MorphControllerData();
 	MorphControllerData &morphdata = state.morph_controller_data_map[p_id];
 
-	morphdata.mesh = _uri_to_id(parser.get_attribute_value("source"));
-	morphdata.mode = parser.get_attribute_value("method");
+	morphdata.mesh = _uri_to_id(parser.get_named_attribute_value("source"));
+	morphdata.mode = parser.get_named_attribute_value("method");
 	String current_source;
 
 	while (parser.read() == OK) {
@@ -1237,7 +1237,7 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
 			String section = parser.get_node_name();
 
 			if (section == "source") {
-				String id = parser.get_attribute_value("id");
+				String id = parser.get_named_attribute_value("id");
 				morphdata.sources[id] = MorphControllerData::Source();
 				current_source = id;
 				COLLADA_PRINT("source data: " + id);
@@ -1261,7 +1261,7 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
 				if (morphdata.sources.has(current_source)) {
 					int stride = 1;
 					if (parser.has_attribute("stride")) {
-						stride = parser.get_attribute_value("stride").to_int();
+						stride = parser.get_named_attribute_value("stride").to_int();
 					}
 
 					morphdata.sources[current_source].stride = stride;
@@ -1272,8 +1272,8 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
 				while (parser.read() == OK) {
 					if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
 						if (parser.get_node_name() == "input") {
-							String semantic = parser.get_attribute_value("semantic");
-							String source = _uri_to_id(parser.get_attribute_value("source"));
+							String semantic = parser.get_named_attribute_value("semantic");
+							String source = _uri_to_id(parser.get_named_attribute_value("source"));
 
 							morphdata.targets[semantic] = source;
 
@@ -1295,7 +1295,7 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
 }
 
 void Collada::_parse_controller(XMLParser &parser) {
-	String id = parser.get_attribute_value("id");
+	String id = parser.get_named_attribute_value("id");
 
 	if (parser.is_empty()) {
 		return;
@@ -1320,7 +1320,7 @@ Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) {
 	String type = parser.get_node_name();
 	NodeGeometry *geom = memnew(NodeGeometry);
 	geom->controller = type == "instance_controller";
-	geom->source = _uri_to_id(parser.get_attribute_value_safe("url"));
+	geom->source = _uri_to_id(parser.get_named_attribute_value_safe("url"));
 
 	if (parser.is_empty()) { //nothing else to parse...
 		return geom;
@@ -1329,8 +1329,8 @@ Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) {
 	while (parser.read() == OK) {
 		if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
 			if (parser.get_node_name() == "instance_material") {
-				String symbol = parser.get_attribute_value("symbol");
-				String target = _uri_to_id(parser.get_attribute_value("target"));
+				String symbol = parser.get_named_attribute_value("symbol");
+				String target = _uri_to_id(parser.get_named_attribute_value("target"));
 
 				NodeGeometry::Material mat;
 				mat.target = target;
@@ -1370,7 +1370,7 @@ Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) {
 
 Collada::Node *Collada::_parse_visual_instance_camera(XMLParser &parser) {
 	NodeCamera *cam = memnew(NodeCamera);
-	cam->camera = _uri_to_id(parser.get_attribute_value_safe("url"));
+	cam->camera = _uri_to_id(parser.get_named_attribute_value_safe("url"));
 
 	if (state.up_axis == Vector3::AXIS_Z) { //collada weirdness
 		cam->post_transform.basis.rotate(Vector3(1, 0, 0), -Math_PI * 0.5);
@@ -1391,7 +1391,7 @@ Collada::Node *Collada::_parse_visual_instance_camera(XMLParser &parser) {
 
 Collada::Node *Collada::_parse_visual_instance_light(XMLParser &parser) {
 	NodeLight *cam = memnew(NodeLight);
-	cam->light = _uri_to_id(parser.get_attribute_value_safe("url"));
+	cam->light = _uri_to_id(parser.get_named_attribute_value_safe("url"));
 
 	if (state.up_axis == Vector3::AXIS_Z) { //collada weirdness
 		cam->post_transform.basis.rotate(Vector3(1, 0, 0), -Math_PI * 0.5);
@@ -1437,7 +1437,7 @@ Collada::Node *Collada::_parse_visual_node_instance_data(XMLParser &parser) {
 Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
 	String name;
 
-	String id = parser.get_attribute_value_safe("id");
+	String id = parser.get_named_attribute_value_safe("id");
 
 	bool found_name = false;
 
@@ -1455,25 +1455,25 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
 
 	Node *node = nullptr;
 
-	name = parser.has_attribute("name") ? parser.get_attribute_value_safe("name") : parser.get_attribute_value_safe("id");
+	name = parser.has_attribute("name") ? parser.get_named_attribute_value_safe("name") : parser.get_named_attribute_value_safe("id");
 	if (name.is_empty()) {
 		name = id;
 	} else {
 		found_name = true;
 	}
 
-	if ((parser.has_attribute("type") && parser.get_attribute_value("type") == "JOINT") || state.idref_joints.has(name)) {
+	if ((parser.has_attribute("type") && parser.get_named_attribute_value("type") == "JOINT") || state.idref_joints.has(name)) {
 		// handle a bone
 
 		NodeJoint *joint = memnew(NodeJoint);
 
 		if (parser.has_attribute("sid")) { //bones may not have sid
-			joint->sid = parser.get_attribute_value("sid");
+			joint->sid = parser.get_named_attribute_value("sid");
 			//state.bone_map[joint->sid]=joint;
 		} else if (state.idref_joints.has(name)) {
 			joint->sid = name; //kind of a cheat but..
 		} else if (parser.has_attribute("name")) {
-			joint->sid = parser.get_attribute_value_safe("name");
+			joint->sid = parser.get_named_attribute_value_safe("name");
 		}
 
 		if (!joint->sid.is_empty()) {
@@ -1490,7 +1490,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
 			if (section == "translate") {
 				Node::XForm xf;
 				if (parser.has_attribute("sid")) {
-					xf.id = parser.get_attribute_value("sid");
+					xf.id = parser.get_named_attribute_value("sid");
 				}
 				xf.op = Node::XForm::OP_TRANSLATE;
 
@@ -1501,7 +1501,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
 			} else if (section == "rotate") {
 				Node::XForm xf;
 				if (parser.has_attribute("sid")) {
-					xf.id = parser.get_attribute_value("sid");
+					xf.id = parser.get_named_attribute_value("sid");
 				}
 				xf.op = Node::XForm::OP_ROTATE;
 
@@ -1513,7 +1513,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
 			} else if (section == "scale") {
 				Node::XForm xf;
 				if (parser.has_attribute("sid")) {
-					xf.id = parser.get_attribute_value("sid");
+					xf.id = parser.get_named_attribute_value("sid");
 				}
 
 				xf.op = Node::XForm::OP_SCALE;
@@ -1527,7 +1527,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
 			} else if (section == "matrix") {
 				Node::XForm xf;
 				if (parser.has_attribute("sid")) {
-					xf.id = parser.get_attribute_value("sid");
+					xf.id = parser.get_named_attribute_value("sid");
 				}
 				xf.op = Node::XForm::OP_MATRIX;
 
@@ -1544,7 +1544,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
 			} else if (section == "visibility") {
 				Node::XForm xf;
 				if (parser.has_attribute("sid")) {
-					xf.id = parser.get_attribute_value("sid");
+					xf.id = parser.get_named_attribute_value("sid");
 				}
 				xf.op = Node::XForm::OP_VISIBILITY;
 
@@ -1609,7 +1609,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
 }
 
 void Collada::_parse_visual_scene(XMLParser &parser) {
-	String id = parser.get_attribute_value("id");
+	String id = parser.get_named_attribute_value("id");
 
 	if (parser.is_empty()) {
 		return;
@@ -1619,7 +1619,7 @@ void Collada::_parse_visual_scene(XMLParser &parser) {
 	VisualScene &vscene = state.visual_scene_map[id];
 
 	if (parser.has_attribute("name")) {
-		vscene.name = parser.get_attribute_value("name");
+		vscene.name = parser.get_named_attribute_value("name");
 	}
 
 	while (parser.read() == OK) {
@@ -1656,7 +1656,7 @@ void Collada::_parse_animation(XMLParser &parser) {
 
 	String id = "";
 	if (parser.has_attribute("id")) {
-		id = parser.get_attribute_value("id");
+		id = parser.get_named_attribute_value("id");
 	}
 
 	String current_source;
@@ -1668,7 +1668,7 @@ void Collada::_parse_animation(XMLParser &parser) {
 		if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
 			String name = parser.get_node_name();
 			if (name == "source") {
-				current_source = parser.get_attribute_value("id");
+				current_source = parser.get_named_attribute_value("id");
 				source_param_names[current_source] = Vector<String>();
 				source_param_types[current_source] = Vector<String>();
 
@@ -1683,32 +1683,32 @@ void Collada::_parse_animation(XMLParser &parser) {
 				}
 			} else if (name == "accessor") {
 				if (!current_source.is_empty() && parser.has_attribute("stride")) {
-					source_strides[current_source] = parser.get_attribute_value("stride").to_int();
+					source_strides[current_source] = parser.get_named_attribute_value("stride").to_int();
 				}
 			} else if (name == "sampler") {
-				current_sampler = parser.get_attribute_value("id");
+				current_sampler = parser.get_named_attribute_value("id");
 				samplers[current_sampler] = HashMap<String, String>();
 			} else if (name == "param") {
 				if (parser.has_attribute("name")) {
-					source_param_names[current_source].push_back(parser.get_attribute_value("name"));
+					source_param_names[current_source].push_back(parser.get_named_attribute_value("name"));
 				} else {
 					source_param_names[current_source].push_back("");
 				}
 
 				if (parser.has_attribute("type")) {
-					source_param_types[current_source].push_back(parser.get_attribute_value("type"));
+					source_param_types[current_source].push_back(parser.get_named_attribute_value("type"));
 				} else {
 					source_param_types[current_source].push_back("");
 				}
 
 			} else if (name == "input") {
 				if (!current_sampler.is_empty()) {
-					samplers[current_sampler][parser.get_attribute_value("semantic")] = parser.get_attribute_value("source");
+					samplers[current_sampler][parser.get_named_attribute_value("semantic")] = parser.get_named_attribute_value("source");
 				}
 
 			} else if (name == "channel") {
-				channel_sources.push_back(parser.get_attribute_value("source"));
-				channel_targets.push_back(parser.get_attribute_value("target"));
+				channel_sources.push_back(parser.get_named_attribute_value("source"));
+				channel_targets.push_back(parser.get_named_attribute_value("target"));
 			}
 
 		} else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "animation") {
@@ -1857,22 +1857,22 @@ void Collada::_parse_animation_clip(XMLParser &parser) {
 	AnimationClip clip;
 
 	if (parser.has_attribute("name")) {
-		clip.name = parser.get_attribute_value("name");
+		clip.name = parser.get_named_attribute_value("name");
 	} else if (parser.has_attribute("id")) {
-		clip.name = parser.get_attribute_value("id");
+		clip.name = parser.get_named_attribute_value("id");
 	}
 	if (parser.has_attribute("start")) {
-		clip.begin = parser.get_attribute_value("start").to_float();
+		clip.begin = parser.get_named_attribute_value("start").to_float();
 	}
 	if (parser.has_attribute("end")) {
-		clip.end = parser.get_attribute_value("end").to_float();
+		clip.end = parser.get_named_attribute_value("end").to_float();
 	}
 
 	while (parser.read() == OK) {
 		if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
 			String name = parser.get_node_name();
 			if (name == "instance_animation") {
-				String url = _uri_to_id(parser.get_attribute_value("url"));
+				String url = _uri_to_id(parser.get_named_attribute_value("url"));
 				clip.tracks.push_back(url);
 			}
 
@@ -1894,9 +1894,9 @@ void Collada::_parse_scene(XMLParser &parser) {
 			String name = parser.get_node_name();
 
 			if (name == "instance_visual_scene") {
-				state.root_visual_scene = _uri_to_id(parser.get_attribute_value("url"));
+				state.root_visual_scene = _uri_to_id(parser.get_named_attribute_value("url"));
 			} else if (name == "instance_physics_scene") {
-				state.root_physics_scene = _uri_to_id(parser.get_attribute_value("url"));
+				state.root_physics_scene = _uri_to_id(parser.get_named_attribute_value("url"));
 			}
 
 		} else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "scene") {
@@ -1925,8 +1925,8 @@ void Collada::_parse_library(XMLParser &parser) {
 			} else if (name == "light") {
 				_parse_light(parser);
 			} else if (name == "geometry") {
-				String id = parser.get_attribute_value("id");
-				String name2 = parser.get_attribute_value_safe("name");
+				String id = parser.get_named_attribute_value("id");
+				String name2 = parser.get_named_attribute_value_safe("name");
 				while (parser.read() == OK) {
 					if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
 						if (parser.get_node_name() == "mesh") {
@@ -2346,7 +2346,7 @@ Error Collada::load(const String &p_path, int p_flags) {
 
 	{
 		//version
-		String version = parser.get_attribute_value("version");
+		String version = parser.get_named_attribute_value("version");
 		state.version.major = version.get_slice(".", 0).to_int();
 		state.version.minor = version.get_slice(".", 1).to_int();
 		state.version.rev = version.get_slice(".", 2).to_int();

+ 5 - 31
modules/text_server_adv/text_server_adv.cpp

@@ -423,11 +423,7 @@ bool TextServerAdvanced::_load_support_data(const String &p_filename) {
 			return false;
 		}
 		uint64_t len = f->get_length();
-#ifdef GDEXTENSION
 		PackedByteArray icu_data = f->get_buffer(len);
-#else
-		PackedByteArray icu_data = f->_get_buffer(len);
-#endif
 
 		UErrorCode err = U_ZERO_ERROR;
 		udata_setCommonData(icu_data.ptr(), &err);
@@ -476,11 +472,7 @@ bool TextServerAdvanced::_save_support_data(const String &p_filename) const {
 	PackedByteArray icu_data;
 	icu_data.resize(U_ICUDATA_SIZE);
 	memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);
-#ifdef GDEXTENSION
 	f->store_buffer(icu_data);
-#else
-	f->_store_buffer(icu_data);
-#endif
 
 	return true;
 #else
@@ -824,29 +816,17 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
 		// Could not find texture to fit, create one.
 		int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
 
-#ifdef GDEXTENSION
-		texsize = Math::next_power_of_2(texsize);
-#else
 		texsize = next_power_of_2(texsize);
-#endif
 		if (p_msdf) {
 			texsize = MIN(texsize, 2048);
 		} else {
 			texsize = MIN(texsize, 1024);
 		}
 		if (mw > texsize) { // Special case, adapt to it?
-#ifdef GDEXTENSION
-			texsize = Math::next_power_of_2(mw);
-#else
 			texsize = next_power_of_2(mw);
-#endif
 		}
 		if (mh > texsize) { // Special case, adapt to it?
-#ifdef GDEXTENSION
-			texsize = Math::next_power_of_2(mh);
-#else
 			texsize = next_power_of_2(mh);
-#endif
 		}
 
 		ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);
@@ -949,14 +929,14 @@ static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, con
 	return 0;
 }
 
-void TextServerAdvanced::_generateMTSDF_threaded(uint32_t y, void *p_td) const {
+void TextServerAdvanced::_generateMTSDF_threaded(void *p_td, uint32_t p_y) {
 	MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td);
 
 	msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape);
-	int row = td->shape->inverseYAxis ? td->output->height() - y - 1 : y;
+	int row = td->shape->inverseYAxis ? td->output->height() - p_y - 1 : p_y;
 	for (int col = 0; col < td->output->width(); ++col) {
-		int x = (y % 2) ? td->output->width() - col - 1 : col;
-		msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, y + .5));
+		int x = (p_y % 2) ? td->output->width() - col - 1 : col;
+		msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, p_y + .5));
 		msdfgen::MultiAndTrueDistance distance = distanceFinder.distance(p);
 		td->distancePixelConversion->operator()(td->output->operator()(x, row), distance);
 	}
@@ -1026,14 +1006,8 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
 		td.projection = &projection;
 		td.distancePixelConversion = &distancePixelConversion;
 
-#ifdef GDEXTENSION
-		for (int i = 0; i < h; i++) {
-			_generateMTSDF_threaded(i, &td);
-		}
-#else
-		WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &TextServerAdvanced::_generateMTSDF_threaded, &td, h, -1, true, SNAME("FontServerRasterizeMSDF"));
+		WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_native_group_task(&TextServerAdvanced::_generateMTSDF_threaded, &td, h, -1, true, String("FontServerRasterizeMSDF"));
 		WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
-#endif
 
 		msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config);
 

+ 1 - 2
modules/text_server_adv/text_server_adv.h

@@ -72,7 +72,6 @@
 #include <godot_cpp/templates/hash_map.hpp>
 #include <godot_cpp/templates/hash_set.hpp>
 #include <godot_cpp/templates/rid_owner.hpp>
-
 #include <godot_cpp/templates/vector.hpp>
 
 using namespace godot;
@@ -350,7 +349,7 @@ class TextServerAdvanced : public TextServerExtension {
 	_FORCE_INLINE_ bool _ensure_glyph(FontAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph) const;
 	_FORCE_INLINE_ bool _ensure_cache_for_size(FontAdvanced *p_font_data, const Vector2i &p_size) const;
 	_FORCE_INLINE_ void _font_clear_cache(FontAdvanced *p_font_data);
-	void _generateMTSDF_threaded(uint32_t y, void *p_td) const;
+	static void _generateMTSDF_threaded(void *p_td, uint32_t p_y);
 
 	_FORCE_INLINE_ Vector2i _get_size(const FontAdvanced *p_font_data, int p_size) const {
 		if (p_font_data->msdf) {

+ 0 - 33
modules/text_server_adv/thorvg_svg_in_ot.cpp

@@ -88,24 +88,13 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
 	if (!gl_state.ready) {
 		Ref<XMLParser> parser;
 		parser.instantiate();
-#ifdef GDEXTENSION
-		PackedByteArray data;
-		data.resize(document->svg_document_length);
-		memcpy(data.ptrw(), document->svg_document, document->svg_document_length);
-		parser->open_buffer(data);
-#else
 		parser->_open_buffer((const uint8_t *)document->svg_document, document->svg_document_length);
-#endif
 
 		float aspect = 1.0f;
 		String xml_body;
 		while (parser->read() == OK) {
 			if (parser->has_attribute("id")) {
-#ifdef GDEXTENSION
 				const String &gl_name = parser->get_named_attribute_value("id");
-#else
-				const String &gl_name = parser->get_attribute_value("id");
-#endif
 				if (gl_name.begins_with("glyph")) {
 					int dot_pos = gl_name.find(".");
 					int64_t gl_idx = gl_name.substr(5, (dot_pos > 0) ? dot_pos - 5 : -1).to_int();
@@ -117,11 +106,7 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
 			}
 			if (parser->get_node_type() == XMLParser::NODE_ELEMENT && parser->get_node_name() == "svg") {
 				if (parser->has_attribute("viewBox")) {
-#ifdef GDEXTENSION
 					PackedStringArray vb = parser->get_named_attribute_value("viewBox").split(" ");
-#else
-					Vector<String> vb = parser->get_attribute_value("viewBox").split(" ");
-#endif
 
 					if (vb.size() == 4) {
 						aspect = vb[2].to_float() / vb[3].to_float();
@@ -129,19 +114,6 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
 				}
 				continue;
 			}
-#ifdef GDEXTENSION
-			if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
-				xml_body = xml_body + "<" + parser->get_node_name();
-				for (int i = 0; i < parser->get_attribute_count(); i++) {
-					xml_body = xml_body + " " + parser->get_attribute_name(i) + "=\"" + parser->get_attribute_value(i) + "\"";
-				}
-				xml_body = xml_body + ">";
-			} else if (parser->get_node_type() == XMLParser::NODE_TEXT) {
-				xml_body = xml_body + parser->get_node_data();
-			} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) {
-				xml_body = xml_body + "</" + parser->get_node_name() + ">";
-			}
-#else
 			if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
 				xml_body += vformat("<%s", parser->get_node_name());
 				for (int i = 0; i < parser->get_attribute_count(); i++) {
@@ -153,7 +125,6 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
 			} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) {
 				xml_body += vformat("</%s>", parser->get_node_name());
 			}
-#endif
 		}
 		String temp_xml = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 0 0\">" + xml_body;
 
@@ -175,11 +146,7 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
 			new_h = (new_w / aspect);
 		}
 
-#ifdef GDEXTENSION
 		gl_state.xml_code = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"" + rtos(min_x) + " " + rtos(min_y) + " " + rtos(new_w) + " " + rtos(new_h) + "\">" + xml_body;
-#else
-		gl_state.xml_code = vformat("<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"%f %f %f %f\">", min_x, min_y, new_w, new_h) + xml_body;
-#endif
 
 		picture = tvg::Picture::gen();
 		result = picture->load(gl_state.xml_code.utf8().get_data(), gl_state.xml_code.utf8().length(), "svg+xml", false);

+ 6 - 24
modules/text_server_fb/text_server_fb.cpp

@@ -248,11 +248,7 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
 		// Could not find texture to fit, create one.
 		int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
 
-#ifdef GDEXTENSION
-		texsize = Math::next_power_of_2(texsize);
-#else
 		texsize = next_power_of_2(texsize);
-#endif
 
 		if (p_msdf) {
 			texsize = MIN(texsize, 2048);
@@ -260,18 +256,10 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
 			texsize = MIN(texsize, 1024);
 		}
 		if (mw > texsize) { // Special case, adapt to it?
-#ifdef GDEXTENSION
-			texsize = Math::next_power_of_2(mw);
-#else
 			texsize = next_power_of_2(mw);
-#endif
 		}
 		if (mh > texsize) { // Special case, adapt to it?
-#ifdef GDEXTENSION
-			texsize = Math::next_power_of_2(mh);
-#else
 			texsize = next_power_of_2(mh);
-#endif
 		}
 
 		ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);
@@ -374,14 +362,14 @@ static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, con
 	return 0;
 }
 
-void TextServerFallback::_generateMTSDF_threaded(uint32_t y, void *p_td) const {
+void TextServerFallback::_generateMTSDF_threaded(void *p_td, uint32_t p_y) {
 	MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td);
 
 	msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape);
-	int row = td->shape->inverseYAxis ? td->output->height() - y - 1 : y;
+	int row = td->shape->inverseYAxis ? td->output->height() - p_y - 1 : p_y;
 	for (int col = 0; col < td->output->width(); ++col) {
-		int x = (y % 2) ? td->output->width() - col - 1 : col;
-		msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, y + .5));
+		int x = (p_y % 2) ? td->output->width() - col - 1 : col;
+		msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, p_y + .5));
 		msdfgen::MultiAndTrueDistance distance = distanceFinder.distance(p);
 		td->distancePixelConversion->operator()(td->output->operator()(x, row), distance);
 	}
@@ -451,14 +439,8 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
 		td.projection = &projection;
 		td.distancePixelConversion = &distancePixelConversion;
 
-#ifdef GDEXTENSION
-		for (int i = 0; i < h; i++) {
-			_generateMTSDF_threaded(i, &td);
-		}
-#else
-		WorkerThreadPool::GroupID group_id = WorkerThreadPool::get_singleton()->add_template_group_task(this, &TextServerFallback::_generateMTSDF_threaded, &td, h, -1, true, SNAME("TextServerFBRenderMSDF"));
-		WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_id);
-#endif
+		WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_native_group_task(&TextServerFallback::_generateMTSDF_threaded, &td, h, -1, true, String("TextServerFBRenderMSDF"));
+		WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
 
 		msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config);
 

+ 2 - 2
modules/text_server_fb/text_server_fb.h

@@ -67,11 +67,11 @@
 #include <godot_cpp/classes/image.hpp>
 #include <godot_cpp/classes/image_texture.hpp>
 #include <godot_cpp/classes/ref.hpp>
+#include <godot_cpp/classes/worker_thread_pool.hpp>
 
 #include <godot_cpp/templates/hash_map.hpp>
 #include <godot_cpp/templates/hash_set.hpp>
 #include <godot_cpp/templates/rid_owner.hpp>
-#include <godot_cpp/templates/thread_work_pool.hpp>
 #include <godot_cpp/templates/vector.hpp>
 
 using namespace godot;
@@ -303,7 +303,7 @@ class TextServerFallback : public TextServerExtension {
 	_FORCE_INLINE_ bool _ensure_glyph(FontFallback *p_font_data, const Vector2i &p_size, int32_t p_glyph) const;
 	_FORCE_INLINE_ bool _ensure_cache_for_size(FontFallback *p_font_data, const Vector2i &p_size) const;
 	_FORCE_INLINE_ void _font_clear_cache(FontFallback *p_font_data);
-	void _generateMTSDF_threaded(uint32_t y, void *p_td) const;
+	static void _generateMTSDF_threaded(void *p_td, uint32_t p_y);
 
 	_FORCE_INLINE_ Vector2i _get_size(const FontFallback *p_font_data, int p_size) const {
 		if (p_font_data->msdf) {

+ 0 - 33
modules/text_server_fb/thorvg_svg_in_ot.cpp

@@ -88,24 +88,13 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
 	if (!gl_state.ready) {
 		Ref<XMLParser> parser;
 		parser.instantiate();
-#ifdef GDEXTENSION
-		PackedByteArray data;
-		data.resize(document->svg_document_length);
-		memcpy(data.ptrw(), document->svg_document, document->svg_document_length);
-		parser->open_buffer(data);
-#else
 		parser->_open_buffer((const uint8_t *)document->svg_document, document->svg_document_length);
-#endif
 
 		float aspect = 1.0f;
 		String xml_body;
 		while (parser->read() == OK) {
 			if (parser->has_attribute("id")) {
-#ifdef GDEXTENSION
 				const String &gl_name = parser->get_named_attribute_value("id");
-#else
-				const String &gl_name = parser->get_attribute_value("id");
-#endif
 				if (gl_name.begins_with("glyph")) {
 					int dot_pos = gl_name.find(".");
 					int64_t gl_idx = gl_name.substr(5, (dot_pos > 0) ? dot_pos - 5 : -1).to_int();
@@ -117,11 +106,7 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
 			}
 			if (parser->get_node_type() == XMLParser::NODE_ELEMENT && parser->get_node_name() == "svg") {
 				if (parser->has_attribute("viewBox")) {
-#ifdef GDEXTENSION
 					PackedStringArray vb = parser->get_named_attribute_value("viewBox").split(" ");
-#else
-					Vector<String> vb = parser->get_attribute_value("viewBox").split(" ");
-#endif
 
 					if (vb.size() == 4) {
 						aspect = vb[2].to_float() / vb[3].to_float();
@@ -129,19 +114,6 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
 				}
 				continue;
 			}
-#ifdef GDEXTENSION
-			if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
-				xml_body = xml_body + "<" + parser->get_node_name();
-				for (int i = 0; i < parser->get_attribute_count(); i++) {
-					xml_body = xml_body + " " + parser->get_attribute_name(i) + "=\"" + parser->get_attribute_value(i) + "\"";
-				}
-				xml_body = xml_body + ">";
-			} else if (parser->get_node_type() == XMLParser::NODE_TEXT) {
-				xml_body = xml_body + parser->get_node_data();
-			} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) {
-				xml_body = xml_body + "</" + parser->get_node_name() + ">";
-			}
-#else
 			if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
 				xml_body += vformat("<%s", parser->get_node_name());
 				for (int i = 0; i < parser->get_attribute_count(); i++) {
@@ -153,7 +125,6 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
 			} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) {
 				xml_body += vformat("</%s>", parser->get_node_name());
 			}
-#endif
 		}
 		String temp_xml = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 0 0\">" + xml_body;
 
@@ -175,11 +146,7 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
 			new_h = (new_w / aspect);
 		}
 
-#ifdef GDEXTENSION
 		gl_state.xml_code = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"" + rtos(min_x) + " " + rtos(min_y) + " " + rtos(new_w) + " " + rtos(new_h) + "\">" + xml_body;
-#else
-		gl_state.xml_code = vformat("<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"%f %f %f %f\">", min_x, min_y, new_w, new_h) + xml_body;
-#endif
 
 		picture = tvg::Picture::gen();
 		result = picture->load(gl_state.xml_code.utf8().get_data(), gl_state.xml_code.utf8().length(), "svg+xml", false);

+ 8 - 8
platform/android/os_android.cpp

@@ -355,20 +355,20 @@ void OS_Android::_load_system_font_config() {
 			if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
 				in_font_node = false;
 				if (parser->get_node_name() == "familyset") {
-					int ver = parser->has_attribute("version") ? parser->get_attribute_value("version").to_int() : 0;
+					int ver = parser->has_attribute("version") ? parser->get_named_attribute_value("version").to_int() : 0;
 					if (ver < 21) {
 						ERR_PRINT(vformat("Unsupported font config version %s", ver));
 						break;
 					}
 				} else if (parser->get_node_name() == "alias") {
-					String name = parser->has_attribute("name") ? parser->get_attribute_value("name").strip_edges() : String();
-					String to = parser->has_attribute("to") ? parser->get_attribute_value("to").strip_edges() : String();
+					String name = parser->has_attribute("name") ? parser->get_named_attribute_value("name").strip_edges() : String();
+					String to = parser->has_attribute("to") ? parser->get_named_attribute_value("to").strip_edges() : String();
 					if (!name.is_empty() && !to.is_empty()) {
 						font_aliases[name] = to;
 					}
 				} else if (parser->get_node_name() == "family") {
-					fn = parser->has_attribute("name") ? parser->get_attribute_value("name").strip_edges() : String();
-					String lang_code = parser->has_attribute("lang") ? parser->get_attribute_value("lang").strip_edges() : String();
+					fn = parser->has_attribute("name") ? parser->get_named_attribute_value("name").strip_edges() : String();
+					String lang_code = parser->has_attribute("lang") ? parser->get_named_attribute_value("lang").strip_edges() : String();
 					Vector<String> lang_codes = lang_code.split(",");
 					for (int i = 0; i < lang_codes.size(); i++) {
 						Vector<String> lang_code_elements = lang_codes[i].split("-");
@@ -412,9 +412,9 @@ void OS_Android::_load_system_font_config() {
 					}
 				} else if (parser->get_node_name() == "font") {
 					in_font_node = true;
-					fb = parser->has_attribute("fallbackFor") ? parser->get_attribute_value("fallbackFor").strip_edges() : String();
-					fi.weight = parser->has_attribute("weight") ? parser->get_attribute_value("weight").to_int() : 400;
-					fi.italic = parser->has_attribute("style") && parser->get_attribute_value("style").strip_edges() == "italic";
+					fb = parser->has_attribute("fallbackFor") ? parser->get_named_attribute_value("fallbackFor").strip_edges() : String();
+					fi.weight = parser->has_attribute("weight") ? parser->get_named_attribute_value("weight").to_int() : 400;
+					fi.italic = parser->has_attribute("style") && parser->get_named_attribute_value("style").strip_edges() == "italic";
 				}
 			}
 			if (parser->get_node_type() == XMLParser::NODE_TEXT) {

+ 1 - 1
tests/core/io/test_xml_parser.h

@@ -54,7 +54,7 @@ TEST_CASE("[XMLParser] End-to-end") {
 	CHECK(parser.get_node_type() == XMLParser::NodeType::NODE_ELEMENT);
 	CHECK(parser.get_node_name() == "top");
 	CHECK(parser.has_attribute("attr"));
-	CHECK(parser.get_attribute_value("attr") == "attr value");
+	CHECK(parser.get_named_attribute_value("attr") == "attr value");
 
 	CHECK(parser.read() == OK);
 	CHECK(parser.get_node_type() == XMLParser::NodeType::NODE_TEXT);