summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/config/engine.cpp4
-rw-r--r--core/core_globals.cpp35
-rw-r--r--core/core_globals.h44
-rw-r--r--core/io/file_access_compressed.h32
-rw-r--r--core/io/file_access_encrypted.h38
-rw-r--r--core/io/file_access_memory.h34
-rw-r--r--core/io/file_access_network.h32
-rw-r--r--core/io/file_access_pack.h74
-rw-r--r--core/io/file_access_zip.h32
-rw-r--r--core/io/logger.cpp3
-rw-r--r--core/string/char_range.inc1456
-rw-r--r--core/string/char_utils.h20
-rw-r--r--core/string/print_string.cpp9
-rw-r--r--core/string/print_string.h2
-rw-r--r--core/templates/paged_allocator.h10
-rw-r--r--core/variant/variant.cpp54
-rw-r--r--core/variant/variant.h19
-rw-r--r--core/variant/variant_internal.h14
-rw-r--r--doc/classes/ParticlesMaterial.xml18
-rw-r--r--doc/classes/TextServer.xml41
-rw-r--r--doc/classes/TextServerExtension.xml22
-rw-r--r--doc/classes/VisualShaderNodeTextureUniform.xml9
-rw-r--r--drivers/gles3/effects/copy_effects.cpp1
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp18
-rw-r--r--drivers/gles3/shaders/cubemap_filter.glsl8
-rw-r--r--drivers/gles3/shaders/scene.glsl4
-rw-r--r--drivers/gles3/storage/material_storage.cpp8
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp2
-rw-r--r--drivers/gles3/storage/texture_storage.cpp11
-rw-r--r--drivers/gles3/storage/texture_storage.h1
-rw-r--r--drivers/unix/dir_access_unix.h46
-rw-r--r--drivers/unix/file_access_unix.h38
-rw-r--r--drivers/windows/dir_access_windows.h38
-rw-r--r--drivers/windows/file_access_windows.h38
-rw-r--r--editor/code_editor.cpp2
-rw-r--r--editor/editor_node.cpp9
-rw-r--r--editor/editor_property_name_processor.cpp1
-rw-r--r--editor/editor_themes.cpp3
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp4
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp4
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp107
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h42
-rw-r--r--editor/project_converter_3_to_4.cpp8
-rw-r--r--editor/property_editor.cpp1866
-rw-r--r--editor/property_editor.h168
-rw-r--r--editor/scene_tree_editor.cpp4
-rw-r--r--main/main.cpp5
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp5
-rw-r--r--modules/regex/doc_classes/RegEx.xml9
-rw-r--r--modules/regex/regex.cpp13
-rw-r--r--modules/regex/regex.h5
-rw-r--r--modules/text_server_adv/SCsub11
-rw-r--r--modules/text_server_adv/text_server_adv.cpp249
-rw-r--r--modules/text_server_adv/text_server_adv.h5
-rw-r--r--modules/visual_script/editor/visual_script_editor.cpp67
-rw-r--r--modules/visual_script/editor/visual_script_editor.h26
-rw-r--r--platform/android/file_access_android.h36
-rw-r--r--platform/linuxbsd/detect_prime_x11.cpp5
-rw-r--r--platform/macos/dir_access_macos.h8
-rw-r--r--scene/gui/color_picker.cpp69
-rw-r--r--scene/gui/color_picker.h3
-rw-r--r--scene/gui/graph_node.cpp1
-rw-r--r--scene/resources/particles_material.cpp32
-rw-r--r--scene/resources/particles_material.h12
-rw-r--r--scene/resources/visual_shader.cpp8
-rw-r--r--scene/resources/visual_shader_nodes.cpp7
-rw-r--r--scene/resources/visual_shader_nodes.h1
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp20
-rw-r--r--servers/rendering/renderer_rd/environment/gi.cpp30
-rw-r--r--servers/rendering/renderer_rd/environment/gi.h9
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp6
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp5
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp5
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl24
-rw-r--r--servers/rendering/renderer_rd/shaders/particles.glsl4
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.cpp3
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp18
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.h1
-rw-r--r--servers/rendering/shader_language.cpp9
-rw-r--r--servers/rendering/shader_language.h2
-rw-r--r--servers/rendering/shader_types.cpp10
-rw-r--r--servers/text/text_server_extension.cpp28
-rw-r--r--servers/text/text_server_extension.h8
-rw-r--r--servers/text_server.cpp26
-rw-r--r--servers/text_server.h6
-rw-r--r--tests/servers/test_text_server.h23
-rw-r--r--tests/test_macros.h13
-rw-r--r--tests/test_validate_testing.h5
-rw-r--r--thirdparty/README.md2
-rw-r--r--thirdparty/icu4c/godot_data.json3
-rw-r--r--thirdparty/icu4c/i18n/scriptset.cpp313
-rw-r--r--thirdparty/icu4c/i18n/scriptset.h86
-rw-r--r--thirdparty/icu4c/i18n/ucln_in.cpp65
-rw-r--r--thirdparty/icu4c/i18n/ucln_in.h74
-rw-r--r--thirdparty/icu4c/i18n/unicode/uspoof.h1577
-rw-r--r--thirdparty/icu4c/i18n/uspoof.cpp839
-rw-r--r--thirdparty/icu4c/i18n/uspoof_impl.cpp959
-rw-r--r--thirdparty/icu4c/i18n/uspoof_impl.h343
-rw-r--r--thirdparty/icu4c/icudt71l.datbin4226000 -> 4271680 bytes
99 files changed, 7016 insertions, 2510 deletions
diff --git a/core/config/engine.cpp b/core/config/engine.cpp
index 44ad4961d9..1a6093869f 100644
--- a/core/config/engine.cpp
+++ b/core/config/engine.cpp
@@ -194,11 +194,11 @@ bool Engine::is_validation_layers_enabled() const {
}
void Engine::set_print_error_messages(bool p_enabled) {
- _print_error_enabled = p_enabled;
+ CoreGlobals::print_error_enabled = p_enabled;
}
bool Engine::is_printing_error_messages() const {
- return _print_error_enabled;
+ return CoreGlobals::print_error_enabled;
}
void Engine::add_singleton(const Singleton &p_singleton) {
diff --git a/core/core_globals.cpp b/core/core_globals.cpp
new file mode 100644
index 0000000000..45297b459f
--- /dev/null
+++ b/core/core_globals.cpp
@@ -0,0 +1,35 @@
+/*************************************************************************/
+/* core_globals.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "core_globals.h"
+
+bool CoreGlobals::leak_reporting_enabled = true;
+bool CoreGlobals::print_line_enabled = true;
+bool CoreGlobals::print_error_enabled = true;
diff --git a/core/core_globals.h b/core/core_globals.h
new file mode 100644
index 0000000000..c5e614dc0a
--- /dev/null
+++ b/core/core_globals.h
@@ -0,0 +1,44 @@
+/*************************************************************************/
+/* core_globals.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef CORE_GLOBALS_H
+#define CORE_GLOBALS_H
+
+// Home for state needed from global functions
+// that cannot be stored in Engine or OS due to e.g. circular includes
+
+class CoreGlobals {
+public:
+ static bool leak_reporting_enabled;
+ static bool print_line_enabled;
+ static bool print_error_enabled;
+};
+
+#endif // CORE_GLOBALS_H
diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h
index b8382e61d9..e41491a92c 100644
--- a/core/io/file_access_compressed.h
+++ b/core/io/file_access_compressed.h
@@ -70,29 +70,29 @@ public:
Error open_after_magic(Ref<FileAccess> p_base);
- virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual bool is_open() const; ///< true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual bool is_open() const override; ///< true when file is open
- virtual void seek(uint64_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual uint64_t get_position() const; ///< get position in the file
- virtual uint64_t get_length() const; ///< get size of the file
+ virtual void seek(uint64_t p_position) override; ///< seek to a given position
+ virtual void seek_end(int64_t p_position = 0) override; ///< seek from the end of file
+ virtual uint64_t get_position() const override; ///< get position in the file
+ virtual uint64_t get_length() const override; ///< get size of the file
- virtual bool eof_reached() const; ///< reading passed EOF
+ virtual bool eof_reached() const override; ///< reading passed EOF
- virtual uint8_t get_8() const; ///< get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint8_t get_8() const override; ///< get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual Error get_error() const; ///< get last error
+ virtual Error get_error() const override; ///< get last error
- virtual void flush();
- virtual void store_8(uint8_t p_dest); ///< store a byte
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override; ///< store a byte
- virtual bool file_exists(const String &p_name); ///< return true if a file exists
+ virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
- virtual uint64_t _get_modified_time(const String &p_file);
- virtual uint32_t _get_unix_permissions(const String &p_file);
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
+ virtual uint64_t _get_modified_time(const String &p_file) override;
+ virtual uint32_t _get_unix_permissions(const String &p_file) override;
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override;
FileAccessCompressed() {}
virtual ~FileAccessCompressed();
diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h
index 0d1ee6a4d8..6200f87a7a 100644
--- a/core/io/file_access_encrypted.h
+++ b/core/io/file_access_encrypted.h
@@ -60,33 +60,33 @@ public:
Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true);
Error open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode);
- virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual bool is_open() const; ///< true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual bool is_open() const override; ///< true when file is open
- virtual String get_path() const; /// returns the path for the current open file
- virtual String get_path_absolute() const; /// returns the absolute path for the current open file
+ virtual String get_path() const override; /// returns the path for the current open file
+ virtual String get_path_absolute() const override; /// returns the absolute path for the current open file
- virtual void seek(uint64_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual uint64_t get_position() const; ///< get position in the file
- virtual uint64_t get_length() const; ///< get size of the file
+ virtual void seek(uint64_t p_position) override; ///< seek to a given position
+ virtual void seek_end(int64_t p_position = 0) override; ///< seek from the end of file
+ virtual uint64_t get_position() const override; ///< get position in the file
+ virtual uint64_t get_length() const override; ///< get size of the file
- virtual bool eof_reached() const; ///< reading passed EOF
+ virtual bool eof_reached() const override; ///< reading passed EOF
- virtual uint8_t get_8() const; ///< get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint8_t get_8() const override; ///< get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual Error get_error() const; ///< get last error
+ virtual Error get_error() const override; ///< get last error
- virtual void flush();
- virtual void store_8(uint8_t p_dest); ///< store a byte
- virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override; ///< store a byte
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
- virtual bool file_exists(const String &p_name); ///< return true if a file exists
+ virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
- virtual uint64_t _get_modified_time(const String &p_file);
- virtual uint32_t _get_unix_permissions(const String &p_file);
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
+ virtual uint64_t _get_modified_time(const String &p_file) override;
+ virtual uint32_t _get_unix_permissions(const String &p_file) override;
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override;
FileAccessEncrypted() {}
~FileAccessEncrypted();
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index 868b8ed481..f2bd2aa832 100644
--- a/core/io/file_access_memory.h
+++ b/core/io/file_access_memory.h
@@ -45,31 +45,31 @@ public:
static void cleanup();
virtual Error open_custom(const uint8_t *p_data, uint64_t p_len); ///< open a file
- virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual bool is_open() const; ///< true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual bool is_open() const override; ///< true when file is open
- virtual void seek(uint64_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position); ///< seek from the end of file
- virtual uint64_t get_position() const; ///< get position in the file
- virtual uint64_t get_length() const; ///< get size of the file
+ virtual void seek(uint64_t p_position) override; ///< seek to a given position
+ virtual void seek_end(int64_t p_position) override; ///< seek from the end of file
+ virtual uint64_t get_position() const override; ///< get position in the file
+ virtual uint64_t get_length() const override; ///< get size of the file
- virtual bool eof_reached() const; ///< reading passed EOF
+ virtual bool eof_reached() const override; ///< reading passed EOF
- virtual uint8_t get_8() const; ///< get a byte
+ virtual uint8_t get_8() const override; ///< get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; ///< get an array of bytes
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override; ///< get an array of bytes
- virtual Error get_error() const; ///< get last error
+ virtual Error get_error() const override; ///< get last error
- virtual void flush();
- virtual void store_8(uint8_t p_byte); ///< store a byte
- virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_byte) override; ///< store a byte
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
- virtual bool file_exists(const String &p_name); ///< return true if a file exists
+ virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
- virtual uint64_t _get_modified_time(const String &p_file) { return 0; }
- virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
+ virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
+ virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; }
FileAccessMemory() {}
};
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
index c7431752c0..ceadc715a1 100644
--- a/core/io/file_access_network.h
+++ b/core/io/file_access_network.h
@@ -132,29 +132,29 @@ public:
RESPONSE_GET_MODTIME,
};
- virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual bool is_open() const; ///< true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual bool is_open() const override; ///< true when file is open
- virtual void seek(uint64_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual uint64_t get_position() const; ///< get position in the file
- virtual uint64_t get_length() const; ///< get size of the file
+ virtual void seek(uint64_t p_position) override; ///< seek to a given position
+ virtual void seek_end(int64_t p_position = 0) override; ///< seek from the end of file
+ virtual uint64_t get_position() const override; ///< get position in the file
+ virtual uint64_t get_length() const override; ///< get size of the file
- virtual bool eof_reached() const; ///< reading passed EOF
+ virtual bool eof_reached() const override; ///< reading passed EOF
- virtual uint8_t get_8() const; ///< get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint8_t get_8() const override; ///< get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual Error get_error() const; ///< get last error
+ virtual Error get_error() const override; ///< get last error
- virtual void flush();
- virtual void store_8(uint8_t p_dest); ///< store a byte
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override; ///< store a byte
- virtual bool file_exists(const String &p_path); ///< return true if a file exists
+ virtual bool file_exists(const String &p_path) override; ///< return true if a file exists
- virtual uint64_t _get_modified_time(const String &p_file);
- virtual uint32_t _get_unix_permissions(const String &p_file);
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
+ virtual uint64_t _get_modified_time(const String &p_file) override;
+ virtual uint32_t _get_unix_permissions(const String &p_file) override;
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override;
static void configure();
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index e656f6b885..023758ac0f 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -148,35 +148,35 @@ class FileAccessPack : public FileAccess {
uint64_t off;
Ref<FileAccess> f;
- virtual Error _open(const String &p_path, int p_mode_flags);
- virtual uint64_t _get_modified_time(const String &p_file) { return 0; }
- virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
+ virtual Error _open(const String &p_path, int p_mode_flags) override;
+ virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
+ virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; }
public:
- virtual bool is_open() const;
+ virtual bool is_open() const override;
- virtual void seek(uint64_t p_position);
- virtual void seek_end(int64_t p_position = 0);
- virtual uint64_t get_position() const;
- virtual uint64_t get_length() const;
+ virtual void seek(uint64_t p_position) override;
+ virtual void seek_end(int64_t p_position = 0) override;
+ virtual uint64_t get_position() const override;
+ virtual uint64_t get_length() const override;
- virtual bool eof_reached() const;
+ virtual bool eof_reached() const override;
- virtual uint8_t get_8() const;
+ virtual uint8_t get_8() const override;
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual void set_big_endian(bool p_big_endian);
+ virtual void set_big_endian(bool p_big_endian) override;
- virtual Error get_error() const;
+ virtual Error get_error() const override;
- virtual void flush();
- virtual void store_8(uint8_t p_dest);
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override;
- virtual void store_buffer(const uint8_t *p_src, uint64_t p_length);
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override;
- virtual bool file_exists(const String &p_name);
+ virtual bool file_exists(const String &p_name) override;
FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file);
};
@@ -217,33 +217,33 @@ class DirAccessPack : public DirAccess {
PackedData::PackedDir *_find_dir(String p_dir);
public:
- virtual Error list_dir_begin();
- virtual String get_next();
- virtual bool current_is_dir() const;
- virtual bool current_is_hidden() const;
- virtual void list_dir_end();
+ virtual Error list_dir_begin() override;
+ virtual String get_next() override;
+ virtual bool current_is_dir() const override;
+ virtual bool current_is_hidden() const override;
+ virtual void list_dir_end() override;
- virtual int get_drive_count();
- virtual String get_drive(int p_drive);
+ virtual int get_drive_count() override;
+ virtual String get_drive(int p_drive) override;
- virtual Error change_dir(String p_dir);
- virtual String get_current_dir(bool p_include_drive = true) const;
+ virtual Error change_dir(String p_dir) override;
+ virtual String get_current_dir(bool p_include_drive = true) const override;
- virtual bool file_exists(String p_file);
- virtual bool dir_exists(String p_dir);
+ virtual bool file_exists(String p_file) override;
+ virtual bool dir_exists(String p_dir) override;
- virtual Error make_dir(String p_dir);
+ virtual Error make_dir(String p_dir) override;
- virtual Error rename(String p_from, String p_to);
- virtual Error remove(String p_name);
+ virtual Error rename(String p_from, String p_to) override;
+ virtual Error remove(String p_name) override;
- uint64_t get_space_left();
+ uint64_t get_space_left() override;
- virtual bool is_link(String p_file) { return false; }
- virtual String read_link(String p_file) { return p_file; }
- virtual Error create_link(String p_source, String p_target) { return FAILED; }
+ virtual bool is_link(String p_file) override { return false; }
+ virtual String read_link(String p_file) override { return p_file; }
+ virtual Error create_link(String p_source, String p_target) override { return FAILED; }
- virtual String get_filesystem_type() const;
+ virtual String get_filesystem_type() const override;
DirAccessPack();
};
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
index 6ea603546a..74a48192f3 100644
--- a/core/io/file_access_zip.h
+++ b/core/io/file_access_zip.h
@@ -85,29 +85,29 @@ class FileAccessZip : public FileAccess {
void _close();
public:
- virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual bool is_open() const; ///< true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual bool is_open() const override; ///< true when file is open
- virtual void seek(uint64_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual uint64_t get_position() const; ///< get position in the file
- virtual uint64_t get_length() const; ///< get size of the file
+ virtual void seek(uint64_t p_position) override; ///< seek to a given position
+ virtual void seek_end(int64_t p_position = 0) override; ///< seek from the end of file
+ virtual uint64_t get_position() const override; ///< get position in the file
+ virtual uint64_t get_length() const override; ///< get size of the file
- virtual bool eof_reached() const; ///< reading passed EOF
+ virtual bool eof_reached() const override; ///< reading passed EOF
- virtual uint8_t get_8() const; ///< get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint8_t get_8() const override; ///< get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual Error get_error() const; ///< get last error
+ virtual Error get_error() const override; ///< get last error
- virtual void flush();
- virtual void store_8(uint8_t p_dest); ///< store a byte
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override; ///< store a byte
- virtual bool file_exists(const String &p_name); ///< return true if a file exists
+ virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
- virtual uint64_t _get_modified_time(const String &p_file) { return 0; } // todo
- virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
+ virtual uint64_t _get_modified_time(const String &p_file) override { return 0; } // todo
+ virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; }
FileAccessZip(const String &p_path, const PackedData::PackedFile &p_file);
~FileAccessZip();
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index 5820ec0c09..b0f74f8db5 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -31,6 +31,7 @@
#include "logger.h"
#include "core/config/project_settings.h"
+#include "core/core_globals.h"
#include "core/io/dir_access.h"
#include "core/os/os.h"
#include "core/os/time.h"
@@ -41,7 +42,7 @@
#endif
bool Logger::should_log(bool p_err) {
- return (!p_err || _print_error_enabled) && (p_err || _print_line_enabled);
+ return (!p_err || CoreGlobals::print_error_enabled) && (p_err || CoreGlobals::print_line_enabled);
}
bool Logger::_flush_stdout_on_print = true;
diff --git a/core/string/char_range.inc b/core/string/char_range.inc
new file mode 100644
index 0000000000..c0be9016ad
--- /dev/null
+++ b/core/string/char_range.inc
@@ -0,0 +1,1456 @@
+/*************************************************************************/
+/* char_range.inc */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef CHAR_RANGE_INC
+#define CHAR_RANGE_INC
+
+#include "core/typedefs.h"
+
+struct CharRange {
+ char32_t start;
+ char32_t end;
+};
+
+static CharRange xid_start[] = {
+ { 0x41, 0x5a },
+ { 0x5f, 0x5f },
+ { 0x61, 0x7a },
+ { 0xaa, 0xaa },
+ { 0xb5, 0xb5 },
+ { 0xba, 0xba },
+ { 0xc0, 0xd6 },
+ { 0xd8, 0xf6 },
+ { 0xf8, 0x2c1 },
+ { 0x2c6, 0x2d1 },
+ { 0x2e0, 0x2e4 },
+ { 0x2ec, 0x2ec },
+ { 0x2ee, 0x2ee },
+ { 0x370, 0x374 },
+ { 0x376, 0x377 },
+ { 0x37a, 0x37d },
+ { 0x37f, 0x37f },
+ { 0x386, 0x386 },
+ { 0x388, 0x38a },
+ { 0x38c, 0x38c },
+ { 0x38e, 0x3a1 },
+ { 0x3a3, 0x3f5 },
+ { 0x3f7, 0x481 },
+ { 0x48a, 0x52f },
+ { 0x531, 0x556 },
+ { 0x559, 0x559 },
+ { 0x560, 0x588 },
+ { 0x5d0, 0x5ea },
+ { 0x5ef, 0x5f2 },
+ { 0x620, 0x64a },
+ { 0x66e, 0x66f },
+ { 0x671, 0x6d3 },
+ { 0x6d5, 0x6d5 },
+ { 0x6e5, 0x6e6 },
+ { 0x6ee, 0x6ef },
+ { 0x6fa, 0x6fc },
+ { 0x6ff, 0x6ff },
+ { 0x710, 0x710 },
+ { 0x712, 0x72f },
+ { 0x74d, 0x7a5 },
+ { 0x7b1, 0x7b1 },
+ { 0x7ca, 0x7ea },
+ { 0x7f4, 0x7f5 },
+ { 0x7fa, 0x7fa },
+ { 0x800, 0x815 },
+ { 0x81a, 0x81a },
+ { 0x824, 0x824 },
+ { 0x828, 0x828 },
+ { 0x840, 0x858 },
+ { 0x860, 0x86a },
+ { 0x870, 0x887 },
+ { 0x889, 0x88e },
+ { 0x8a0, 0x8c9 },
+ { 0x904, 0x939 },
+ { 0x93d, 0x93d },
+ { 0x950, 0x950 },
+ { 0x958, 0x961 },
+ { 0x971, 0x980 },
+ { 0x985, 0x98c },
+ { 0x98f, 0x990 },
+ { 0x993, 0x9a8 },
+ { 0x9aa, 0x9b0 },
+ { 0x9b2, 0x9b2 },
+ { 0x9b6, 0x9b9 },
+ { 0x9bd, 0x9bd },
+ { 0x9ce, 0x9ce },
+ { 0x9dc, 0x9dd },
+ { 0x9df, 0x9e1 },
+ { 0x9f0, 0x9f1 },
+ { 0x9fc, 0x9fc },
+ { 0xa05, 0xa0a },
+ { 0xa0f, 0xa10 },
+ { 0xa13, 0xa28 },
+ { 0xa2a, 0xa30 },
+ { 0xa32, 0xa33 },
+ { 0xa35, 0xa36 },
+ { 0xa38, 0xa39 },
+ { 0xa59, 0xa5c },
+ { 0xa5e, 0xa5e },
+ { 0xa72, 0xa74 },
+ { 0xa85, 0xa8d },
+ { 0xa8f, 0xa91 },
+ { 0xa93, 0xaa8 },
+ { 0xaaa, 0xab0 },
+ { 0xab2, 0xab3 },
+ { 0xab5, 0xab9 },
+ { 0xabd, 0xabd },
+ { 0xad0, 0xad0 },
+ { 0xae0, 0xae1 },
+ { 0xaf9, 0xaf9 },
+ { 0xb05, 0xb0c },
+ { 0xb0f, 0xb10 },
+ { 0xb13, 0xb28 },
+ { 0xb2a, 0xb30 },
+ { 0xb32, 0xb33 },
+ { 0xb35, 0xb39 },
+ { 0xb3d, 0xb3d },
+ { 0xb5c, 0xb5d },
+ { 0xb5f, 0xb61 },
+ { 0xb71, 0xb71 },
+ { 0xb83, 0xb83 },
+ { 0xb85, 0xb8a },
+ { 0xb8e, 0xb90 },
+ { 0xb92, 0xb95 },
+ { 0xb99, 0xb9a },
+ { 0xb9c, 0xb9c },
+ { 0xb9e, 0xb9f },
+ { 0xba3, 0xba4 },
+ { 0xba8, 0xbaa },
+ { 0xbae, 0xbb9 },
+ { 0xbd0, 0xbd0 },
+ { 0xc05, 0xc0c },
+ { 0xc0e, 0xc10 },
+ { 0xc12, 0xc28 },
+ { 0xc2a, 0xc39 },
+ { 0xc3d, 0xc3d },
+ { 0xc58, 0xc5a },
+ { 0xc5d, 0xc5d },
+ { 0xc60, 0xc61 },
+ { 0xc80, 0xc80 },
+ { 0xc85, 0xc8c },
+ { 0xc8e, 0xc90 },
+ { 0xc92, 0xca8 },
+ { 0xcaa, 0xcb3 },
+ { 0xcb5, 0xcb9 },
+ { 0xcbd, 0xcbd },
+ { 0xcdd, 0xcde },
+ { 0xce0, 0xce1 },
+ { 0xcf1, 0xcf2 },
+ { 0xd04, 0xd0c },
+ { 0xd0e, 0xd10 },
+ { 0xd12, 0xd3a },
+ { 0xd3d, 0xd3d },
+ { 0xd4e, 0xd4e },
+ { 0xd54, 0xd56 },
+ { 0xd5f, 0xd61 },
+ { 0xd7a, 0xd7f },
+ { 0xd85, 0xd96 },
+ { 0xd9a, 0xdb1 },
+ { 0xdb3, 0xdbb },
+ { 0xdbd, 0xdbd },
+ { 0xdc0, 0xdc6 },
+ { 0xe01, 0xe30 },
+ { 0xe32, 0xe33 },
+ { 0xe40, 0xe46 },
+ { 0xe81, 0xe82 },
+ { 0xe84, 0xe84 },
+ { 0xe86, 0xe8a },
+ { 0xe8c, 0xea3 },
+ { 0xea5, 0xea5 },
+ { 0xea7, 0xeb0 },
+ { 0xeb2, 0xeb3 },
+ { 0xebd, 0xebd },
+ { 0xec0, 0xec4 },
+ { 0xec6, 0xec6 },
+ { 0xedc, 0xedf },
+ { 0xf00, 0xf00 },
+ { 0xf40, 0xf47 },
+ { 0xf49, 0xf6c },
+ { 0xf88, 0xf8c },
+ { 0x1000, 0x102a },
+ { 0x103f, 0x103f },
+ { 0x1050, 0x1055 },
+ { 0x105a, 0x105d },
+ { 0x1061, 0x1061 },
+ { 0x1065, 0x1066 },
+ { 0x106e, 0x1070 },
+ { 0x1075, 0x1081 },
+ { 0x108e, 0x108e },
+ { 0x10a0, 0x10c5 },
+ { 0x10c7, 0x10c7 },
+ { 0x10cd, 0x10cd },
+ { 0x10d0, 0x10fa },
+ { 0x10fc, 0x1248 },
+ { 0x124a, 0x124d },
+ { 0x1250, 0x1256 },
+ { 0x1258, 0x1258 },
+ { 0x125a, 0x125d },
+ { 0x1260, 0x1288 },
+ { 0x128a, 0x128d },
+ { 0x1290, 0x12b0 },
+ { 0x12b2, 0x12b5 },
+ { 0x12b8, 0x12be },
+ { 0x12c0, 0x12c0 },
+ { 0x12c2, 0x12c5 },
+ { 0x12c8, 0x12d6 },
+ { 0x12d8, 0x1310 },
+ { 0x1312, 0x1315 },
+ { 0x1318, 0x135a },
+ { 0x1380, 0x138f },
+ { 0x13a0, 0x13f5 },
+ { 0x13f8, 0x13fd },
+ { 0x1401, 0x166c },
+ { 0x166f, 0x167f },
+ { 0x1681, 0x169a },
+ { 0x16a0, 0x16ea },
+ { 0x16ee, 0x16f8 },
+ { 0x1700, 0x1711 },
+ { 0x171f, 0x1731 },
+ { 0x1740, 0x1751 },
+ { 0x1760, 0x176c },
+ { 0x176e, 0x1770 },
+ { 0x1780, 0x17b3 },
+ { 0x17d7, 0x17d7 },
+ { 0x17dc, 0x17dc },
+ { 0x1820, 0x1878 },
+ { 0x1880, 0x1884 },
+ { 0x1887, 0x18a8 },
+ { 0x18aa, 0x18aa },
+ { 0x18b0, 0x18f5 },
+ { 0x1900, 0x191e },
+ { 0x1950, 0x196d },
+ { 0x1970, 0x1974 },
+ { 0x1980, 0x19ab },
+ { 0x19b0, 0x19c9 },
+ { 0x1a00, 0x1a16 },
+ { 0x1a20, 0x1a54 },
+ { 0x1aa7, 0x1aa7 },
+ { 0x1b05, 0x1b33 },
+ { 0x1b45, 0x1b4c },
+ { 0x1b83, 0x1ba0 },
+ { 0x1bae, 0x1baf },
+ { 0x1bba, 0x1be5 },
+ { 0x1c00, 0x1c23 },
+ { 0x1c4d, 0x1c4f },
+ { 0x1c5a, 0x1c7d },
+ { 0x1c80, 0x1c88 },
+ { 0x1c90, 0x1cba },
+ { 0x1cbd, 0x1cbf },
+ { 0x1ce9, 0x1cec },
+ { 0x1cee, 0x1cf3 },
+ { 0x1cf5, 0x1cf6 },
+ { 0x1cfa, 0x1cfa },
+ { 0x1d00, 0x1dbf },
+ { 0x1e00, 0x1f15 },
+ { 0x1f18, 0x1f1d },
+ { 0x1f20, 0x1f45 },
+ { 0x1f48, 0x1f4d },
+ { 0x1f50, 0x1f57 },
+ { 0x1f59, 0x1f59 },
+ { 0x1f5b, 0x1f5b },
+ { 0x1f5d, 0x1f5d },
+ { 0x1f5f, 0x1f7d },
+ { 0x1f80, 0x1fb4 },
+ { 0x1fb6, 0x1fbc },
+ { 0x1fbe, 0x1fbe },
+ { 0x1fc2, 0x1fc4 },
+ { 0x1fc6, 0x1fcc },
+ { 0x1fd0, 0x1fd3 },
+ { 0x1fd6, 0x1fdb },
+ { 0x1fe0, 0x1fec },
+ { 0x1ff2, 0x1ff4 },
+ { 0x1ff6, 0x1ffc },
+ { 0x2071, 0x2071 },
+ { 0x207f, 0x207f },
+ { 0x2090, 0x209c },
+ { 0x2102, 0x2102 },
+ { 0x2107, 0x2107 },
+ { 0x210a, 0x2113 },
+ { 0x2115, 0x2115 },
+ { 0x2118, 0x211d },
+ { 0x2124, 0x2124 },
+ { 0x2126, 0x2126 },
+ { 0x2128, 0x2128 },
+ { 0x212a, 0x2139 },
+ { 0x213c, 0x213f },
+ { 0x2145, 0x2149 },
+ { 0x214e, 0x214e },
+ { 0x2160, 0x2188 },
+ { 0x2c00, 0x2ce4 },
+ { 0x2ceb, 0x2cee },
+ { 0x2cf2, 0x2cf3 },
+ { 0x2d00, 0x2d25 },
+ { 0x2d27, 0x2d27 },
+ { 0x2d2d, 0x2d2d },
+ { 0x2d30, 0x2d67 },
+ { 0x2d6f, 0x2d6f },
+ { 0x2d80, 0x2d96 },
+ { 0x2da0, 0x2da6 },
+ { 0x2da8, 0x2dae },
+ { 0x2db0, 0x2db6 },
+ { 0x2db8, 0x2dbe },
+ { 0x2dc0, 0x2dc6 },
+ { 0x2dc8, 0x2dce },
+ { 0x2dd0, 0x2dd6 },
+ { 0x2dd8, 0x2dde },
+ { 0x3005, 0x3007 },
+ { 0x3021, 0x3029 },
+ { 0x3031, 0x3035 },
+ { 0x3038, 0x303c },
+ { 0x3041, 0x3096 },
+ { 0x309b, 0x309f },
+ { 0x30a1, 0x30fa },
+ { 0x30fc, 0x30ff },
+ { 0x3105, 0x312f },
+ { 0x3131, 0x318e },
+ { 0x31a0, 0x31bf },
+ { 0x31f0, 0x31ff },
+ { 0x3400, 0x4dbf },
+ { 0x4e00, 0xa48c },
+ { 0xa4d0, 0xa4fd },
+ { 0xa500, 0xa60c },
+ { 0xa610, 0xa61f },
+ { 0xa62a, 0xa62b },
+ { 0xa640, 0xa66e },
+ { 0xa67f, 0xa69d },
+ { 0xa6a0, 0xa6ef },
+ { 0xa717, 0xa71f },
+ { 0xa722, 0xa788 },
+ { 0xa78b, 0xa7ca },
+ { 0xa7d0, 0xa7d1 },
+ { 0xa7d3, 0xa7d3 },
+ { 0xa7d5, 0xa7d9 },
+ { 0xa7f2, 0xa801 },
+ { 0xa803, 0xa805 },
+ { 0xa807, 0xa80a },
+ { 0xa80c, 0xa822 },
+ { 0xa840, 0xa873 },
+ { 0xa882, 0xa8b3 },
+ { 0xa8f2, 0xa8f7 },
+ { 0xa8fb, 0xa8fb },
+ { 0xa8fd, 0xa8fe },
+ { 0xa90a, 0xa925 },
+ { 0xa930, 0xa946 },
+ { 0xa960, 0xa97c },
+ { 0xa984, 0xa9b2 },
+ { 0xa9cf, 0xa9cf },
+ { 0xa9e0, 0xa9e4 },
+ { 0xa9e6, 0xa9ef },
+ { 0xa9fa, 0xa9fe },
+ { 0xaa00, 0xaa28 },
+ { 0xaa40, 0xaa42 },
+ { 0xaa44, 0xaa4b },
+ { 0xaa60, 0xaa76 },
+ { 0xaa7a, 0xaa7a },
+ { 0xaa7e, 0xaaaf },
+ { 0xaab1, 0xaab1 },
+ { 0xaab5, 0xaab6 },
+ { 0xaab9, 0xaabd },
+ { 0xaac0, 0xaac0 },
+ { 0xaac2, 0xaac2 },
+ { 0xaadb, 0xaadd },
+ { 0xaae0, 0xaaea },
+ { 0xaaf2, 0xaaf4 },
+ { 0xab01, 0xab06 },
+ { 0xab09, 0xab0e },
+ { 0xab11, 0xab16 },
+ { 0xab20, 0xab26 },
+ { 0xab28, 0xab2e },
+ { 0xab30, 0xab5a },
+ { 0xab5c, 0xab69 },
+ { 0xab70, 0xabe2 },
+ { 0xac00, 0xd7a3 },
+ { 0xd7b0, 0xd7c6 },
+ { 0xd7cb, 0xd7fb },
+ { 0xf900, 0xfa6d },
+ { 0xfa70, 0xfad9 },
+ { 0xfb00, 0xfb06 },
+ { 0xfb13, 0xfb17 },
+ { 0xfb1d, 0xfb1d },
+ { 0xfb1f, 0xfb28 },
+ { 0xfb2a, 0xfb36 },
+ { 0xfb38, 0xfb3c },
+ { 0xfb3e, 0xfb3e },
+ { 0xfb40, 0xfb41 },
+ { 0xfb43, 0xfb44 },
+ { 0xfb46, 0xfbb1 },
+ { 0xfbd3, 0xfd3d },
+ { 0xfd50, 0xfd8f },
+ { 0xfd92, 0xfdc7 },
+ { 0xfdf0, 0xfdfb },
+ { 0xfe70, 0xfe74 },
+ { 0xfe76, 0xfefc },
+ { 0xff21, 0xff3a },
+ { 0xff41, 0xff5a },
+ { 0xff66, 0xffbe },
+ { 0xffc2, 0xffc7 },
+ { 0xffca, 0xffcf },
+ { 0xffd2, 0xffd7 },
+ { 0xffda, 0xffdc },
+ { 0x10000, 0x1000b },
+ { 0x1000d, 0x10026 },
+ { 0x10028, 0x1003a },
+ { 0x1003c, 0x1003d },
+ { 0x1003f, 0x1004d },
+ { 0x10050, 0x1005d },
+ { 0x10080, 0x100fa },
+ { 0x10140, 0x10174 },
+ { 0x10280, 0x1029c },
+ { 0x102a0, 0x102d0 },
+ { 0x10300, 0x1031f },
+ { 0x1032d, 0x1034a },
+ { 0x10350, 0x10375 },
+ { 0x10380, 0x1039d },
+ { 0x103a0, 0x103c3 },
+ { 0x103c8, 0x103cf },
+ { 0x103d1, 0x103d5 },
+ { 0x10400, 0x1049d },
+ { 0x104b0, 0x104d3 },
+ { 0x104d8, 0x104fb },
+ { 0x10500, 0x10527 },
+ { 0x10530, 0x10563 },
+ { 0x10570, 0x1057a },
+ { 0x1057c, 0x1058a },
+ { 0x1058c, 0x10592 },
+ { 0x10594, 0x10595 },
+ { 0x10597, 0x105a1 },
+ { 0x105a3, 0x105b1 },
+ { 0x105b3, 0x105b9 },
+ { 0x105bb, 0x105bc },
+ { 0x10600, 0x10736 },
+ { 0x10740, 0x10755 },
+ { 0x10760, 0x10767 },
+ { 0x10780, 0x10785 },
+ { 0x10787, 0x107b0 },
+ { 0x107b2, 0x107ba },
+ { 0x10800, 0x10805 },
+ { 0x10808, 0x10808 },
+ { 0x1080a, 0x10835 },
+ { 0x10837, 0x10838 },
+ { 0x1083c, 0x1083c },
+ { 0x1083f, 0x10855 },
+ { 0x10860, 0x10876 },
+ { 0x10880, 0x1089e },
+ { 0x108e0, 0x108f2 },
+ { 0x108f4, 0x108f5 },
+ { 0x10900, 0x10915 },
+ { 0x10920, 0x10939 },
+ { 0x10980, 0x109b7 },
+ { 0x109be, 0x109bf },
+ { 0x10a00, 0x10a00 },
+ { 0x10a10, 0x10a13 },
+ { 0x10a15, 0x10a17 },
+ { 0x10a19, 0x10a35 },
+ { 0x10a60, 0x10a7c },
+ { 0x10a80, 0x10a9c },
+ { 0x10ac0, 0x10ac7 },
+ { 0x10ac9, 0x10ae4 },
+ { 0x10b00, 0x10b35 },
+ { 0x10b40, 0x10b55 },
+ { 0x10b60, 0x10b72 },
+ { 0x10b80, 0x10b91 },
+ { 0x10c00, 0x10c48 },
+ { 0x10c80, 0x10cb2 },
+ { 0x10cc0, 0x10cf2 },
+ { 0x10d00, 0x10d23 },
+ { 0x10e80, 0x10ea9 },
+ { 0x10eb0, 0x10eb1 },
+ { 0x10f00, 0x10f1c },
+ { 0x10f27, 0x10f27 },
+ { 0x10f30, 0x10f45 },
+ { 0x10f70, 0x10f81 },
+ { 0x10fb0, 0x10fc4 },
+ { 0x10fe0, 0x10ff6 },
+ { 0x11003, 0x11037 },
+ { 0x11071, 0x11072 },
+ { 0x11075, 0x11075 },
+ { 0x11083, 0x110af },
+ { 0x110d0, 0x110e8 },
+ { 0x11103, 0x11126 },
+ { 0x11144, 0x11144 },
+ { 0x11147, 0x11147 },
+ { 0x11150, 0x11172 },
+ { 0x11176, 0x11176 },
+ { 0x11183, 0x111b2 },
+ { 0x111c1, 0x111c4 },
+ { 0x111da, 0x111da },
+ { 0x111dc, 0x111dc },
+ { 0x11200, 0x11211 },
+ { 0x11213, 0x1122b },
+ { 0x11280, 0x11286 },
+ { 0x11288, 0x11288 },
+ { 0x1128a, 0x1128d },
+ { 0x1128f, 0x1129d },
+ { 0x1129f, 0x112a8 },
+ { 0x112b0, 0x112de },
+ { 0x11305, 0x1130c },
+ { 0x1130f, 0x11310 },
+ { 0x11313, 0x11328 },
+ { 0x1132a, 0x11330 },
+ { 0x11332, 0x11333 },
+ { 0x11335, 0x11339 },
+ { 0x1133d, 0x1133d },
+ { 0x11350, 0x11350 },
+ { 0x1135d, 0x11361 },
+ { 0x11400, 0x11434 },
+ { 0x11447, 0x1144a },
+ { 0x1145f, 0x11461 },
+ { 0x11480, 0x114af },
+ { 0x114c4, 0x114c5 },
+ { 0x114c7, 0x114c7 },
+ { 0x11580, 0x115ae },
+ { 0x115d8, 0x115db },
+ { 0x11600, 0x1162f },
+ { 0x11644, 0x11644 },
+ { 0x11680, 0x116aa },
+ { 0x116b8, 0x116b8 },
+ { 0x11700, 0x1171a },
+ { 0x11740, 0x11746 },
+ { 0x11800, 0x1182b },
+ { 0x118a0, 0x118df },
+ { 0x118ff, 0x11906 },
+ { 0x11909, 0x11909 },
+ { 0x1190c, 0x11913 },
+ { 0x11915, 0x11916 },
+ { 0x11918, 0x1192f },
+ { 0x1193f, 0x1193f },
+ { 0x11941, 0x11941 },
+ { 0x119a0, 0x119a7 },
+ { 0x119aa, 0x119d0 },
+ { 0x119e1, 0x119e1 },
+ { 0x119e3, 0x119e3 },
+ { 0x11a00, 0x11a00 },
+ { 0x11a0b, 0x11a32 },
+ { 0x11a3a, 0x11a3a },
+ { 0x11a50, 0x11a50 },
+ { 0x11a5c, 0x11a89 },
+ { 0x11a9d, 0x11a9d },
+ { 0x11ab0, 0x11af8 },
+ { 0x11c00, 0x11c08 },
+ { 0x11c0a, 0x11c2e },
+ { 0x11c40, 0x11c40 },
+ { 0x11c72, 0x11c8f },
+ { 0x11d00, 0x11d06 },
+ { 0x11d08, 0x11d09 },
+ { 0x11d0b, 0x11d30 },
+ { 0x11d46, 0x11d46 },
+ { 0x11d60, 0x11d65 },
+ { 0x11d67, 0x11d68 },
+ { 0x11d6a, 0x11d89 },
+ { 0x11d98, 0x11d98 },
+ { 0x11ee0, 0x11ef2 },
+ { 0x11fb0, 0x11fb0 },
+ { 0x12000, 0x12399 },
+ { 0x12400, 0x1246e },
+ { 0x12480, 0x12543 },
+ { 0x12f90, 0x12ff0 },
+ { 0x13000, 0x1342e },
+ { 0x14400, 0x14646 },
+ { 0x16800, 0x16a38 },
+ { 0x16a40, 0x16a5e },
+ { 0x16a70, 0x16abe },
+ { 0x16ad0, 0x16aed },
+ { 0x16b00, 0x16b2f },
+ { 0x16b40, 0x16b43 },
+ { 0x16b63, 0x16b77 },
+ { 0x16b7d, 0x16b8f },
+ { 0x16e40, 0x16e7f },
+ { 0x16f00, 0x16f4a },
+ { 0x16f50, 0x16f50 },
+ { 0x16f93, 0x16f9f },
+ { 0x16fe0, 0x16fe1 },
+ { 0x16fe3, 0x16fe3 },
+ { 0x17000, 0x187f7 },
+ { 0x18800, 0x18cd5 },
+ { 0x18d00, 0x18d08 },
+ { 0x1aff0, 0x1aff3 },
+ { 0x1aff5, 0x1affb },
+ { 0x1affd, 0x1affe },
+ { 0x1b000, 0x1b122 },
+ { 0x1b150, 0x1b152 },
+ { 0x1b164, 0x1b167 },
+ { 0x1b170, 0x1b2fb },
+ { 0x1bc00, 0x1bc6a },
+ { 0x1bc70, 0x1bc7c },
+ { 0x1bc80, 0x1bc88 },
+ { 0x1bc90, 0x1bc99 },
+ { 0x1d400, 0x1d454 },
+ { 0x1d456, 0x1d49c },
+ { 0x1d49e, 0x1d49f },
+ { 0x1d4a2, 0x1d4a2 },
+ { 0x1d4a5, 0x1d4a6 },
+ { 0x1d4a9, 0x1d4ac },
+ { 0x1d4ae, 0x1d4b9 },
+ { 0x1d4bb, 0x1d4bb },
+ { 0x1d4bd, 0x1d4c3 },
+ { 0x1d4c5, 0x1d505 },
+ { 0x1d507, 0x1d50a },
+ { 0x1d50d, 0x1d514 },
+ { 0x1d516, 0x1d51c },
+ { 0x1d51e, 0x1d539 },
+ { 0x1d53b, 0x1d53e },
+ { 0x1d540, 0x1d544 },
+ { 0x1d546, 0x1d546 },
+ { 0x1d54a, 0x1d550 },
+ { 0x1d552, 0x1d6a5 },
+ { 0x1d6a8, 0x1d6c0 },
+ { 0x1d6c2, 0x1d6da },
+ { 0x1d6dc, 0x1d6fa },
+ { 0x1d6fc, 0x1d714 },
+ { 0x1d716, 0x1d734 },
+ { 0x1d736, 0x1d74e },
+ { 0x1d750, 0x1d76e },
+ { 0x1d770, 0x1d788 },
+ { 0x1d78a, 0x1d7a8 },
+ { 0x1d7aa, 0x1d7c2 },
+ { 0x1d7c4, 0x1d7cb },
+ { 0x1df00, 0x1df1e },
+ { 0x1e100, 0x1e12c },
+ { 0x1e137, 0x1e13d },
+ { 0x1e14e, 0x1e14e },
+ { 0x1e290, 0x1e2ad },
+ { 0x1e2c0, 0x1e2eb },
+ { 0x1e7e0, 0x1e7e6 },
+ { 0x1e7e8, 0x1e7eb },
+ { 0x1e7ed, 0x1e7ee },
+ { 0x1e7f0, 0x1e7fe },
+ { 0x1e800, 0x1e8c4 },
+ { 0x1e900, 0x1e943 },
+ { 0x1e94b, 0x1e94b },
+ { 0x1ee00, 0x1ee03 },
+ { 0x1ee05, 0x1ee1f },
+ { 0x1ee21, 0x1ee22 },
+ { 0x1ee24, 0x1ee24 },
+ { 0x1ee27, 0x1ee27 },
+ { 0x1ee29, 0x1ee32 },
+ { 0x1ee34, 0x1ee37 },
+ { 0x1ee39, 0x1ee39 },
+ { 0x1ee3b, 0x1ee3b },
+ { 0x1ee42, 0x1ee42 },
+ { 0x1ee47, 0x1ee47 },
+ { 0x1ee49, 0x1ee49 },
+ { 0x1ee4b, 0x1ee4b },
+ { 0x1ee4d, 0x1ee4f },
+ { 0x1ee51, 0x1ee52 },
+ { 0x1ee54, 0x1ee54 },
+ { 0x1ee57, 0x1ee57 },
+ { 0x1ee59, 0x1ee59 },
+ { 0x1ee5b, 0x1ee5b },
+ { 0x1ee5d, 0x1ee5d },
+ { 0x1ee5f, 0x1ee5f },
+ { 0x1ee61, 0x1ee62 },
+ { 0x1ee64, 0x1ee64 },
+ { 0x1ee67, 0x1ee6a },
+ { 0x1ee6c, 0x1ee72 },
+ { 0x1ee74, 0x1ee77 },
+ { 0x1ee79, 0x1ee7c },
+ { 0x1ee7e, 0x1ee7e },
+ { 0x1ee80, 0x1ee89 },
+ { 0x1ee8b, 0x1ee9b },
+ { 0x1eea1, 0x1eea3 },
+ { 0x1eea5, 0x1eea9 },
+ { 0x1eeab, 0x1eebb },
+ { 0x20000, 0x2a6df },
+ { 0x2a700, 0x2b738 },
+ { 0x2b740, 0x2b81d },
+ { 0x2b820, 0x2cea1 },
+ { 0x2ceb0, 0x2ebe0 },
+ { 0x2f800, 0x2fa1d },
+ { 0x30000, 0x3134a },
+ { 0x0, 0x0 },
+};
+
+static CharRange xid_continue[] = {
+ { 0x30, 0x39 },
+ { 0x41, 0x5a },
+ { 0x5f, 0x5f },
+ { 0x61, 0x7a },
+ { 0xaa, 0xaa },
+ { 0xb5, 0xb5 },
+ { 0xb7, 0xb7 },
+ { 0xba, 0xba },
+ { 0xc0, 0xd6 },
+ { 0xd8, 0xf6 },
+ { 0xf8, 0x2c1 },
+ { 0x2c6, 0x2d1 },
+ { 0x2e0, 0x2e4 },
+ { 0x2ec, 0x2ec },
+ { 0x2ee, 0x2ee },
+ { 0x300, 0x374 },
+ { 0x376, 0x377 },
+ { 0x37a, 0x37d },
+ { 0x37f, 0x37f },
+ { 0x386, 0x38a },
+ { 0x38c, 0x38c },
+ { 0x38e, 0x3a1 },
+ { 0x3a3, 0x3f5 },
+ { 0x3f7, 0x481 },
+ { 0x483, 0x487 },
+ { 0x48a, 0x52f },
+ { 0x531, 0x556 },
+ { 0x559, 0x559 },
+ { 0x560, 0x588 },
+ { 0x591, 0x5bd },
+ { 0x5bf, 0x5bf },
+ { 0x5c1, 0x5c2 },
+ { 0x5c4, 0x5c5 },
+ { 0x5c7, 0x5c7 },
+ { 0x5d0, 0x5ea },
+ { 0x5ef, 0x5f2 },
+ { 0x610, 0x61a },
+ { 0x620, 0x669 },
+ { 0x66e, 0x6d3 },
+ { 0x6d5, 0x6dc },
+ { 0x6df, 0x6e8 },
+ { 0x6ea, 0x6fc },
+ { 0x6ff, 0x6ff },
+ { 0x710, 0x74a },
+ { 0x74d, 0x7b1 },
+ { 0x7c0, 0x7f5 },
+ { 0x7fa, 0x7fa },
+ { 0x7fd, 0x7fd },
+ { 0x800, 0x82d },
+ { 0x840, 0x85b },
+ { 0x860, 0x86a },
+ { 0x870, 0x887 },
+ { 0x889, 0x88e },
+ { 0x898, 0x8e1 },
+ { 0x8e3, 0x963 },
+ { 0x966, 0x96f },
+ { 0x971, 0x983 },
+ { 0x985, 0x98c },
+ { 0x98f, 0x990 },
+ { 0x993, 0x9a8 },
+ { 0x9aa, 0x9b0 },
+ { 0x9b2, 0x9b2 },
+ { 0x9b6, 0x9b9 },
+ { 0x9bc, 0x9c4 },
+ { 0x9c7, 0x9c8 },
+ { 0x9cb, 0x9ce },
+ { 0x9d7, 0x9d7 },
+ { 0x9dc, 0x9dd },
+ { 0x9df, 0x9e3 },
+ { 0x9e6, 0x9f1 },
+ { 0x9fc, 0x9fc },
+ { 0x9fe, 0x9fe },
+ { 0xa01, 0xa03 },
+ { 0xa05, 0xa0a },
+ { 0xa0f, 0xa10 },
+ { 0xa13, 0xa28 },
+ { 0xa2a, 0xa30 },
+ { 0xa32, 0xa33 },
+ { 0xa35, 0xa36 },
+ { 0xa38, 0xa39 },
+ { 0xa3c, 0xa3c },
+ { 0xa3e, 0xa42 },
+ { 0xa47, 0xa48 },
+ { 0xa4b, 0xa4d },
+ { 0xa51, 0xa51 },
+ { 0xa59, 0xa5c },
+ { 0xa5e, 0xa5e },
+ { 0xa66, 0xa75 },
+ { 0xa81, 0xa83 },
+ { 0xa85, 0xa8d },
+ { 0xa8f, 0xa91 },
+ { 0xa93, 0xaa8 },
+ { 0xaaa, 0xab0 },
+ { 0xab2, 0xab3 },
+ { 0xab5, 0xab9 },
+ { 0xabc, 0xac5 },
+ { 0xac7, 0xac9 },
+ { 0xacb, 0xacd },
+ { 0xad0, 0xad0 },
+ { 0xae0, 0xae3 },
+ { 0xae6, 0xaef },
+ { 0xaf9, 0xaff },
+ { 0xb01, 0xb03 },
+ { 0xb05, 0xb0c },
+ { 0xb0f, 0xb10 },
+ { 0xb13, 0xb28 },
+ { 0xb2a, 0xb30 },
+ { 0xb32, 0xb33 },
+ { 0xb35, 0xb39 },
+ { 0xb3c, 0xb44 },
+ { 0xb47, 0xb48 },
+ { 0xb4b, 0xb4d },
+ { 0xb55, 0xb57 },
+ { 0xb5c, 0xb5d },
+ { 0xb5f, 0xb63 },
+ { 0xb66, 0xb6f },
+ { 0xb71, 0xb71 },
+ { 0xb82, 0xb83 },
+ { 0xb85, 0xb8a },
+ { 0xb8e, 0xb90 },
+ { 0xb92, 0xb95 },
+ { 0xb99, 0xb9a },
+ { 0xb9c, 0xb9c },
+ { 0xb9e, 0xb9f },
+ { 0xba3, 0xba4 },
+ { 0xba8, 0xbaa },
+ { 0xbae, 0xbb9 },
+ { 0xbbe, 0xbc2 },
+ { 0xbc6, 0xbc8 },
+ { 0xbca, 0xbcd },
+ { 0xbd0, 0xbd0 },
+ { 0xbd7, 0xbd7 },
+ { 0xbe6, 0xbef },
+ { 0xc00, 0xc0c },
+ { 0xc0e, 0xc10 },
+ { 0xc12, 0xc28 },
+ { 0xc2a, 0xc39 },
+ { 0xc3c, 0xc44 },
+ { 0xc46, 0xc48 },
+ { 0xc4a, 0xc4d },
+ { 0xc55, 0xc56 },
+ { 0xc58, 0xc5a },
+ { 0xc5d, 0xc5d },
+ { 0xc60, 0xc63 },
+ { 0xc66, 0xc6f },
+ { 0xc80, 0xc83 },
+ { 0xc85, 0xc8c },
+ { 0xc8e, 0xc90 },
+ { 0xc92, 0xca8 },
+ { 0xcaa, 0xcb3 },
+ { 0xcb5, 0xcb9 },
+ { 0xcbc, 0xcc4 },
+ { 0xcc6, 0xcc8 },
+ { 0xcca, 0xccd },
+ { 0xcd5, 0xcd6 },
+ { 0xcdd, 0xcde },
+ { 0xce0, 0xce3 },
+ { 0xce6, 0xcef },
+ { 0xcf1, 0xcf2 },
+ { 0xd00, 0xd0c },
+ { 0xd0e, 0xd10 },
+ { 0xd12, 0xd44 },
+ { 0xd46, 0xd48 },
+ { 0xd4a, 0xd4e },
+ { 0xd54, 0xd57 },
+ { 0xd5f, 0xd63 },
+ { 0xd66, 0xd6f },
+ { 0xd7a, 0xd7f },
+ { 0xd81, 0xd83 },
+ { 0xd85, 0xd96 },
+ { 0xd9a, 0xdb1 },
+ { 0xdb3, 0xdbb },
+ { 0xdbd, 0xdbd },
+ { 0xdc0, 0xdc6 },
+ { 0xdca, 0xdca },
+ { 0xdcf, 0xdd4 },
+ { 0xdd6, 0xdd6 },
+ { 0xdd8, 0xddf },
+ { 0xde6, 0xdef },
+ { 0xdf2, 0xdf3 },
+ { 0xe01, 0xe3a },
+ { 0xe40, 0xe4e },
+ { 0xe50, 0xe59 },
+ { 0xe81, 0xe82 },
+ { 0xe84, 0xe84 },
+ { 0xe86, 0xe8a },
+ { 0xe8c, 0xea3 },
+ { 0xea5, 0xea5 },
+ { 0xea7, 0xebd },
+ { 0xec0, 0xec4 },
+ { 0xec6, 0xec6 },
+ { 0xec8, 0xecd },
+ { 0xed0, 0xed9 },
+ { 0xedc, 0xedf },
+ { 0xf00, 0xf00 },
+ { 0xf18, 0xf19 },
+ { 0xf20, 0xf29 },
+ { 0xf35, 0xf35 },
+ { 0xf37, 0xf37 },
+ { 0xf39, 0xf39 },
+ { 0xf3e, 0xf47 },
+ { 0xf49, 0xf6c },
+ { 0xf71, 0xf84 },
+ { 0xf86, 0xf97 },
+ { 0xf99, 0xfbc },
+ { 0xfc6, 0xfc6 },
+ { 0x1000, 0x1049 },
+ { 0x1050, 0x109d },
+ { 0x10a0, 0x10c5 },
+ { 0x10c7, 0x10c7 },
+ { 0x10cd, 0x10cd },
+ { 0x10d0, 0x10fa },
+ { 0x10fc, 0x1248 },
+ { 0x124a, 0x124d },
+ { 0x1250, 0x1256 },
+ { 0x1258, 0x1258 },
+ { 0x125a, 0x125d },
+ { 0x1260, 0x1288 },
+ { 0x128a, 0x128d },
+ { 0x1290, 0x12b0 },
+ { 0x12b2, 0x12b5 },
+ { 0x12b8, 0x12be },
+ { 0x12c0, 0x12c0 },
+ { 0x12c2, 0x12c5 },
+ { 0x12c8, 0x12d6 },
+ { 0x12d8, 0x1310 },
+ { 0x1312, 0x1315 },
+ { 0x1318, 0x135a },
+ { 0x135d, 0x135f },
+ { 0x1369, 0x1369 },
+ { 0x1371, 0x1371 },
+ { 0x1380, 0x138f },
+ { 0x13a0, 0x13f5 },
+ { 0x13f8, 0x13fd },
+ { 0x1401, 0x166c },
+ { 0x166f, 0x167f },
+ { 0x1681, 0x169a },
+ { 0x16a0, 0x16ea },
+ { 0x16ee, 0x16f8 },
+ { 0x1700, 0x1715 },
+ { 0x171f, 0x1734 },
+ { 0x1740, 0x1753 },
+ { 0x1760, 0x176c },
+ { 0x176e, 0x1770 },
+ { 0x1772, 0x1773 },
+ { 0x1780, 0x17d3 },
+ { 0x17d7, 0x17d7 },
+ { 0x17dc, 0x17dd },
+ { 0x17e0, 0x17e9 },
+ { 0x180b, 0x180d },
+ { 0x180f, 0x1819 },
+ { 0x1820, 0x1878 },
+ { 0x1880, 0x18aa },
+ { 0x18b0, 0x18f5 },
+ { 0x1900, 0x191e },
+ { 0x1920, 0x192b },
+ { 0x1930, 0x193b },
+ { 0x1946, 0x196d },
+ { 0x1970, 0x1974 },
+ { 0x1980, 0x19ab },
+ { 0x19b0, 0x19c9 },
+ { 0x19d0, 0x19da },
+ { 0x1a00, 0x1a1b },
+ { 0x1a20, 0x1a5e },
+ { 0x1a60, 0x1a7c },
+ { 0x1a7f, 0x1a89 },
+ { 0x1a90, 0x1a99 },
+ { 0x1aa7, 0x1aa7 },
+ { 0x1ab0, 0x1abd },
+ { 0x1abf, 0x1ace },
+ { 0x1b00, 0x1b4c },
+ { 0x1b50, 0x1b59 },
+ { 0x1b6b, 0x1b73 },
+ { 0x1b80, 0x1bf3 },
+ { 0x1c00, 0x1c37 },
+ { 0x1c40, 0x1c49 },
+ { 0x1c4d, 0x1c7d },
+ { 0x1c80, 0x1c88 },
+ { 0x1c90, 0x1cba },
+ { 0x1cbd, 0x1cbf },
+ { 0x1cd0, 0x1cd2 },
+ { 0x1cd4, 0x1cfa },
+ { 0x1d00, 0x1f15 },
+ { 0x1f18, 0x1f1d },
+ { 0x1f20, 0x1f45 },
+ { 0x1f48, 0x1f4d },
+ { 0x1f50, 0x1f57 },
+ { 0x1f59, 0x1f59 },
+ { 0x1f5b, 0x1f5b },
+ { 0x1f5d, 0x1f5d },
+ { 0x1f5f, 0x1f7d },
+ { 0x1f80, 0x1fb4 },
+ { 0x1fb6, 0x1fbc },
+ { 0x1fbe, 0x1fbe },
+ { 0x1fc2, 0x1fc4 },
+ { 0x1fc6, 0x1fcc },
+ { 0x1fd0, 0x1fd3 },
+ { 0x1fd6, 0x1fdb },
+ { 0x1fe0, 0x1fec },
+ { 0x1ff2, 0x1ff4 },
+ { 0x1ff6, 0x1ffc },
+ { 0x203f, 0x2040 },
+ { 0x2054, 0x2054 },
+ { 0x2071, 0x2071 },
+ { 0x207f, 0x207f },
+ { 0x2090, 0x209c },
+ { 0x20d0, 0x20dc },
+ { 0x20e1, 0x20e1 },
+ { 0x20e5, 0x20f0 },
+ { 0x2102, 0x2102 },
+ { 0x2107, 0x2107 },
+ { 0x210a, 0x2113 },
+ { 0x2115, 0x2115 },
+ { 0x2118, 0x211d },
+ { 0x2124, 0x2124 },
+ { 0x2126, 0x2126 },
+ { 0x2128, 0x2128 },
+ { 0x212a, 0x2139 },
+ { 0x213c, 0x213f },
+ { 0x2145, 0x2149 },
+ { 0x214e, 0x214e },
+ { 0x2160, 0x2188 },
+ { 0x2c00, 0x2ce4 },
+ { 0x2ceb, 0x2cf3 },
+ { 0x2d00, 0x2d25 },
+ { 0x2d27, 0x2d27 },
+ { 0x2d2d, 0x2d2d },
+ { 0x2d30, 0x2d67 },
+ { 0x2d6f, 0x2d6f },
+ { 0x2d7f, 0x2d96 },
+ { 0x2da0, 0x2da6 },
+ { 0x2da8, 0x2dae },
+ { 0x2db0, 0x2db6 },
+ { 0x2db8, 0x2dbe },
+ { 0x2dc0, 0x2dc6 },
+ { 0x2dc8, 0x2dce },
+ { 0x2dd0, 0x2dd6 },
+ { 0x2dd8, 0x2dde },
+ { 0x2de0, 0x2dff },
+ { 0x3005, 0x3007 },
+ { 0x3021, 0x302f },
+ { 0x3031, 0x3035 },
+ { 0x3038, 0x303c },
+ { 0x3041, 0x3096 },
+ { 0x3099, 0x309f },
+ { 0x30a1, 0x30fa },
+ { 0x30fc, 0x30ff },
+ { 0x3105, 0x312f },
+ { 0x3131, 0x318e },
+ { 0x31a0, 0x31bf },
+ { 0x31f0, 0x31ff },
+ { 0x3400, 0x4dbf },
+ { 0x4e00, 0xa48c },
+ { 0xa4d0, 0xa4fd },
+ { 0xa500, 0xa60c },
+ { 0xa610, 0xa62b },
+ { 0xa640, 0xa66f },
+ { 0xa674, 0xa67d },
+ { 0xa67f, 0xa6f1 },
+ { 0xa717, 0xa71f },
+ { 0xa722, 0xa788 },
+ { 0xa78b, 0xa7ca },
+ { 0xa7d0, 0xa7d1 },
+ { 0xa7d3, 0xa7d3 },
+ { 0xa7d5, 0xa7d9 },
+ { 0xa7f2, 0xa827 },
+ { 0xa82c, 0xa82c },
+ { 0xa840, 0xa873 },
+ { 0xa880, 0xa8c5 },
+ { 0xa8d0, 0xa8d9 },
+ { 0xa8e0, 0xa8f7 },
+ { 0xa8fb, 0xa8fb },
+ { 0xa8fd, 0xa92d },
+ { 0xa930, 0xa953 },
+ { 0xa960, 0xa97c },
+ { 0xa980, 0xa9c0 },
+ { 0xa9cf, 0xa9d9 },
+ { 0xa9e0, 0xa9fe },
+ { 0xaa00, 0xaa36 },
+ { 0xaa40, 0xaa4d },
+ { 0xaa50, 0xaa59 },
+ { 0xaa60, 0xaa76 },
+ { 0xaa7a, 0xaac2 },
+ { 0xaadb, 0xaadd },
+ { 0xaae0, 0xaaef },
+ { 0xaaf2, 0xaaf6 },
+ { 0xab01, 0xab06 },
+ { 0xab09, 0xab0e },
+ { 0xab11, 0xab16 },
+ { 0xab20, 0xab26 },
+ { 0xab28, 0xab2e },
+ { 0xab30, 0xab5a },
+ { 0xab5c, 0xab69 },
+ { 0xab70, 0xabea },
+ { 0xabec, 0xabed },
+ { 0xabf0, 0xabf9 },
+ { 0xac00, 0xd7a3 },
+ { 0xd7b0, 0xd7c6 },
+ { 0xd7cb, 0xd7fb },
+ { 0xf900, 0xfa6d },
+ { 0xfa70, 0xfad9 },
+ { 0xfb00, 0xfb06 },
+ { 0xfb13, 0xfb17 },
+ { 0xfb1d, 0xfb28 },
+ { 0xfb2a, 0xfb36 },
+ { 0xfb38, 0xfb3c },
+ { 0xfb3e, 0xfb3e },
+ { 0xfb40, 0xfb41 },
+ { 0xfb43, 0xfb44 },
+ { 0xfb46, 0xfbb1 },
+ { 0xfbd3, 0xfd3d },
+ { 0xfd50, 0xfd8f },
+ { 0xfd92, 0xfdc7 },
+ { 0xfdf0, 0xfdfb },
+ { 0xfe00, 0xfe0f },
+ { 0xfe20, 0xfe2f },
+ { 0xfe33, 0xfe34 },
+ { 0xfe4d, 0xfe4f },
+ { 0xfe70, 0xfe74 },
+ { 0xfe76, 0xfefc },
+ { 0xff10, 0xff19 },
+ { 0xff21, 0xff3a },
+ { 0xff3f, 0xff3f },
+ { 0xff41, 0xff5a },
+ { 0xff66, 0xffbe },
+ { 0xffc2, 0xffc7 },
+ { 0xffca, 0xffcf },
+ { 0xffd2, 0xffd7 },
+ { 0xffda, 0xffdc },
+ { 0x10000, 0x1000b },
+ { 0x1000d, 0x10026 },
+ { 0x10028, 0x1003a },
+ { 0x1003c, 0x1003d },
+ { 0x1003f, 0x1004d },
+ { 0x10050, 0x1005d },
+ { 0x10080, 0x100fa },
+ { 0x10140, 0x10174 },
+ { 0x101fd, 0x101fd },
+ { 0x10280, 0x1029c },
+ { 0x102a0, 0x102d0 },
+ { 0x102e0, 0x102e0 },
+ { 0x10300, 0x1031f },
+ { 0x1032d, 0x1034a },
+ { 0x10350, 0x1037a },
+ { 0x10380, 0x1039d },
+ { 0x103a0, 0x103c3 },
+ { 0x103c8, 0x103cf },
+ { 0x103d1, 0x103d5 },
+ { 0x10400, 0x1049d },
+ { 0x104a0, 0x104a9 },
+ { 0x104b0, 0x104d3 },
+ { 0x104d8, 0x104fb },
+ { 0x10500, 0x10527 },
+ { 0x10530, 0x10563 },
+ { 0x10570, 0x1057a },
+ { 0x1057c, 0x1058a },
+ { 0x1058c, 0x10592 },
+ { 0x10594, 0x10595 },
+ { 0x10597, 0x105a1 },
+ { 0x105a3, 0x105b1 },
+ { 0x105b3, 0x105b9 },
+ { 0x105bb, 0x105bc },
+ { 0x10600, 0x10736 },
+ { 0x10740, 0x10755 },
+ { 0x10760, 0x10767 },
+ { 0x10780, 0x10785 },
+ { 0x10787, 0x107b0 },
+ { 0x107b2, 0x107ba },
+ { 0x10800, 0x10805 },
+ { 0x10808, 0x10808 },
+ { 0x1080a, 0x10835 },
+ { 0x10837, 0x10838 },
+ { 0x1083c, 0x1083c },
+ { 0x1083f, 0x10855 },
+ { 0x10860, 0x10876 },
+ { 0x10880, 0x1089e },
+ { 0x108e0, 0x108f2 },
+ { 0x108f4, 0x108f5 },
+ { 0x10900, 0x10915 },
+ { 0x10920, 0x10939 },
+ { 0x10980, 0x109b7 },
+ { 0x109be, 0x109bf },
+ { 0x10a00, 0x10a03 },
+ { 0x10a05, 0x10a06 },
+ { 0x10a0c, 0x10a13 },
+ { 0x10a15, 0x10a17 },
+ { 0x10a19, 0x10a35 },
+ { 0x10a38, 0x10a3a },
+ { 0x10a3f, 0x10a3f },
+ { 0x10a60, 0x10a7c },
+ { 0x10a80, 0x10a9c },
+ { 0x10ac0, 0x10ac7 },
+ { 0x10ac9, 0x10ae6 },
+ { 0x10b00, 0x10b35 },
+ { 0x10b40, 0x10b55 },
+ { 0x10b60, 0x10b72 },
+ { 0x10b80, 0x10b91 },
+ { 0x10c00, 0x10c48 },
+ { 0x10c80, 0x10cb2 },
+ { 0x10cc0, 0x10cf2 },
+ { 0x10d00, 0x10d27 },
+ { 0x10d30, 0x10d39 },
+ { 0x10e80, 0x10ea9 },
+ { 0x10eab, 0x10eac },
+ { 0x10eb0, 0x10eb1 },
+ { 0x10f00, 0x10f1c },
+ { 0x10f27, 0x10f27 },
+ { 0x10f30, 0x10f50 },
+ { 0x10f70, 0x10f85 },
+ { 0x10fb0, 0x10fc4 },
+ { 0x10fe0, 0x10ff6 },
+ { 0x11000, 0x11046 },
+ { 0x11066, 0x11075 },
+ { 0x1107f, 0x110ba },
+ { 0x110c2, 0x110c2 },
+ { 0x110d0, 0x110e8 },
+ { 0x110f0, 0x110f9 },
+ { 0x11100, 0x11134 },
+ { 0x11136, 0x1113f },
+ { 0x11144, 0x11147 },
+ { 0x11150, 0x11173 },
+ { 0x11176, 0x11176 },
+ { 0x11180, 0x111c4 },
+ { 0x111c9, 0x111cc },
+ { 0x111ce, 0x111da },
+ { 0x111dc, 0x111dc },
+ { 0x11200, 0x11211 },
+ { 0x11213, 0x11237 },
+ { 0x1123e, 0x1123e },
+ { 0x11280, 0x11286 },
+ { 0x11288, 0x11288 },
+ { 0x1128a, 0x1128d },
+ { 0x1128f, 0x1129d },
+ { 0x1129f, 0x112a8 },
+ { 0x112b0, 0x112ea },
+ { 0x112f0, 0x112f9 },
+ { 0x11300, 0x11303 },
+ { 0x11305, 0x1130c },
+ { 0x1130f, 0x11310 },
+ { 0x11313, 0x11328 },
+ { 0x1132a, 0x11330 },
+ { 0x11332, 0x11333 },
+ { 0x11335, 0x11339 },
+ { 0x1133b, 0x11344 },
+ { 0x11347, 0x11348 },
+ { 0x1134b, 0x1134d },
+ { 0x11350, 0x11350 },
+ { 0x11357, 0x11357 },
+ { 0x1135d, 0x11363 },
+ { 0x11366, 0x1136c },
+ { 0x11370, 0x11374 },
+ { 0x11400, 0x1144a },
+ { 0x11450, 0x11459 },
+ { 0x1145e, 0x11461 },
+ { 0x11480, 0x114c5 },
+ { 0x114c7, 0x114c7 },
+ { 0x114d0, 0x114d9 },
+ { 0x11580, 0x115b5 },
+ { 0x115b8, 0x115c0 },
+ { 0x115d8, 0x115dd },
+ { 0x11600, 0x11640 },
+ { 0x11644, 0x11644 },
+ { 0x11650, 0x11659 },
+ { 0x11680, 0x116b8 },
+ { 0x116c0, 0x116c9 },
+ { 0x11700, 0x1171a },
+ { 0x1171d, 0x1172b },
+ { 0x11730, 0x11739 },
+ { 0x11740, 0x11746 },
+ { 0x11800, 0x1183a },
+ { 0x118a0, 0x118e9 },
+ { 0x118ff, 0x11906 },
+ { 0x11909, 0x11909 },
+ { 0x1190c, 0x11913 },
+ { 0x11915, 0x11916 },
+ { 0x11918, 0x11935 },
+ { 0x11937, 0x11938 },
+ { 0x1193b, 0x11943 },
+ { 0x11950, 0x11959 },
+ { 0x119a0, 0x119a7 },
+ { 0x119aa, 0x119d7 },
+ { 0x119da, 0x119e1 },
+ { 0x119e3, 0x119e4 },
+ { 0x11a00, 0x11a3e },
+ { 0x11a47, 0x11a47 },
+ { 0x11a50, 0x11a99 },
+ { 0x11a9d, 0x11a9d },
+ { 0x11ab0, 0x11af8 },
+ { 0x11c00, 0x11c08 },
+ { 0x11c0a, 0x11c36 },
+ { 0x11c38, 0x11c40 },
+ { 0x11c50, 0x11c59 },
+ { 0x11c72, 0x11c8f },
+ { 0x11c92, 0x11ca7 },
+ { 0x11ca9, 0x11cb6 },
+ { 0x11d00, 0x11d06 },
+ { 0x11d08, 0x11d09 },
+ { 0x11d0b, 0x11d36 },
+ { 0x11d3a, 0x11d3a },
+ { 0x11d3c, 0x11d3d },
+ { 0x11d3f, 0x11d47 },
+ { 0x11d50, 0x11d59 },
+ { 0x11d60, 0x11d65 },
+ { 0x11d67, 0x11d68 },
+ { 0x11d6a, 0x11d8e },
+ { 0x11d90, 0x11d91 },
+ { 0x11d93, 0x11d98 },
+ { 0x11da0, 0x11da9 },
+ { 0x11ee0, 0x11ef6 },
+ { 0x11fb0, 0x11fb0 },
+ { 0x12000, 0x12399 },
+ { 0x12400, 0x1246e },
+ { 0x12480, 0x12543 },
+ { 0x12f90, 0x12ff0 },
+ { 0x13000, 0x1342e },
+ { 0x14400, 0x14646 },
+ { 0x16800, 0x16a38 },
+ { 0x16a40, 0x16a5e },
+ { 0x16a60, 0x16a69 },
+ { 0x16a70, 0x16abe },
+ { 0x16ac0, 0x16ac9 },
+ { 0x16ad0, 0x16aed },
+ { 0x16af0, 0x16af4 },
+ { 0x16b00, 0x16b36 },
+ { 0x16b40, 0x16b43 },
+ { 0x16b50, 0x16b59 },
+ { 0x16b63, 0x16b77 },
+ { 0x16b7d, 0x16b8f },
+ { 0x16e40, 0x16e7f },
+ { 0x16f00, 0x16f4a },
+ { 0x16f4f, 0x16f87 },
+ { 0x16f8f, 0x16f9f },
+ { 0x16fe0, 0x16fe1 },
+ { 0x16fe3, 0x16fe4 },
+ { 0x16ff0, 0x16ff1 },
+ { 0x17000, 0x187f7 },
+ { 0x18800, 0x18cd5 },
+ { 0x18d00, 0x18d08 },
+ { 0x1aff0, 0x1aff3 },
+ { 0x1aff5, 0x1affb },
+ { 0x1affd, 0x1affe },
+ { 0x1b000, 0x1b122 },
+ { 0x1b150, 0x1b152 },
+ { 0x1b164, 0x1b167 },
+ { 0x1b170, 0x1b2fb },
+ { 0x1bc00, 0x1bc6a },
+ { 0x1bc70, 0x1bc7c },
+ { 0x1bc80, 0x1bc88 },
+ { 0x1bc90, 0x1bc99 },
+ { 0x1bc9d, 0x1bc9e },
+ { 0x1cf00, 0x1cf2d },
+ { 0x1cf30, 0x1cf46 },
+ { 0x1d165, 0x1d169 },
+ { 0x1d16d, 0x1d172 },
+ { 0x1d17b, 0x1d182 },
+ { 0x1d185, 0x1d18b },
+ { 0x1d1aa, 0x1d1ad },
+ { 0x1d242, 0x1d244 },
+ { 0x1d400, 0x1d454 },
+ { 0x1d456, 0x1d49c },
+ { 0x1d49e, 0x1d49f },
+ { 0x1d4a2, 0x1d4a2 },
+ { 0x1d4a5, 0x1d4a6 },
+ { 0x1d4a9, 0x1d4ac },
+ { 0x1d4ae, 0x1d4b9 },
+ { 0x1d4bb, 0x1d4bb },
+ { 0x1d4bd, 0x1d4c3 },
+ { 0x1d4c5, 0x1d505 },
+ { 0x1d507, 0x1d50a },
+ { 0x1d50d, 0x1d514 },
+ { 0x1d516, 0x1d51c },
+ { 0x1d51e, 0x1d539 },
+ { 0x1d53b, 0x1d53e },
+ { 0x1d540, 0x1d544 },
+ { 0x1d546, 0x1d546 },
+ { 0x1d54a, 0x1d550 },
+ { 0x1d552, 0x1d6a5 },
+ { 0x1d6a8, 0x1d6c0 },
+ { 0x1d6c2, 0x1d6da },
+ { 0x1d6dc, 0x1d6fa },
+ { 0x1d6fc, 0x1d714 },
+ { 0x1d716, 0x1d734 },
+ { 0x1d736, 0x1d74e },
+ { 0x1d750, 0x1d76e },
+ { 0x1d770, 0x1d788 },
+ { 0x1d78a, 0x1d7a8 },
+ { 0x1d7aa, 0x1d7c2 },
+ { 0x1d7c4, 0x1d7cb },
+ { 0x1d7ce, 0x1d7ff },
+ { 0x1da00, 0x1da36 },
+ { 0x1da3b, 0x1da6c },
+ { 0x1da75, 0x1da75 },
+ { 0x1da84, 0x1da84 },
+ { 0x1da9b, 0x1da9f },
+ { 0x1daa1, 0x1daaf },
+ { 0x1df00, 0x1df1e },
+ { 0x1e000, 0x1e006 },
+ { 0x1e008, 0x1e018 },
+ { 0x1e01b, 0x1e021 },
+ { 0x1e023, 0x1e024 },
+ { 0x1e026, 0x1e02a },
+ { 0x1e100, 0x1e12c },
+ { 0x1e130, 0x1e13d },
+ { 0x1e140, 0x1e149 },
+ { 0x1e14e, 0x1e14e },
+ { 0x1e290, 0x1e2ae },
+ { 0x1e2c0, 0x1e2f9 },
+ { 0x1e7e0, 0x1e7e6 },
+ { 0x1e7e8, 0x1e7eb },
+ { 0x1e7ed, 0x1e7ee },
+ { 0x1e7f0, 0x1e7fe },
+ { 0x1e800, 0x1e8c4 },
+ { 0x1e8d0, 0x1e8d6 },
+ { 0x1e900, 0x1e94b },
+ { 0x1e950, 0x1e959 },
+ { 0x1ee00, 0x1ee03 },
+ { 0x1ee05, 0x1ee1f },
+ { 0x1ee21, 0x1ee22 },
+ { 0x1ee24, 0x1ee24 },
+ { 0x1ee27, 0x1ee27 },
+ { 0x1ee29, 0x1ee32 },
+ { 0x1ee34, 0x1ee37 },
+ { 0x1ee39, 0x1ee39 },
+ { 0x1ee3b, 0x1ee3b },
+ { 0x1ee42, 0x1ee42 },
+ { 0x1ee47, 0x1ee47 },
+ { 0x1ee49, 0x1ee49 },
+ { 0x1ee4b, 0x1ee4b },
+ { 0x1ee4d, 0x1ee4f },
+ { 0x1ee51, 0x1ee52 },
+ { 0x1ee54, 0x1ee54 },
+ { 0x1ee57, 0x1ee57 },
+ { 0x1ee59, 0x1ee59 },
+ { 0x1ee5b, 0x1ee5b },
+ { 0x1ee5d, 0x1ee5d },
+ { 0x1ee5f, 0x1ee5f },
+ { 0x1ee61, 0x1ee62 },
+ { 0x1ee64, 0x1ee64 },
+ { 0x1ee67, 0x1ee6a },
+ { 0x1ee6c, 0x1ee72 },
+ { 0x1ee74, 0x1ee77 },
+ { 0x1ee79, 0x1ee7c },
+ { 0x1ee7e, 0x1ee7e },
+ { 0x1ee80, 0x1ee89 },
+ { 0x1ee8b, 0x1ee9b },
+ { 0x1eea1, 0x1eea3 },
+ { 0x1eea5, 0x1eea9 },
+ { 0x1eeab, 0x1eebb },
+ { 0x1fbf0, 0x1fbf9 },
+ { 0x20000, 0x2a6df },
+ { 0x2a700, 0x2b738 },
+ { 0x2b740, 0x2b81d },
+ { 0x2b820, 0x2cea1 },
+ { 0x2ceb0, 0x2ebe0 },
+ { 0x2f800, 0x2fa1d },
+ { 0x30000, 0x3134a },
+ { 0xe0100, 0xe01ef },
+ { 0x0, 0x0 },
+};
+
+#endif // CHAR_RANGE_INC
diff --git a/core/string/char_utils.h b/core/string/char_utils.h
index 0afd058f01..67147a4327 100644
--- a/core/string/char_utils.h
+++ b/core/string/char_utils.h
@@ -33,6 +33,26 @@
#include "core/typedefs.h"
+#include "char_range.inc"
+
+static _FORCE_INLINE_ bool is_unicode_identifier_start(char32_t c) {
+ for (int i = 0; xid_start[i].start != 0; i++) {
+ if (c >= xid_start[i].start && c <= xid_start[i].end) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static _FORCE_INLINE_ bool is_unicode_identifier_continue(char32_t c) {
+ for (int i = 0; xid_continue[i].start != 0; i++) {
+ if (c >= xid_continue[i].start && c <= xid_continue[i].end) {
+ return true;
+ }
+ }
+ return false;
+}
+
static _FORCE_INLINE_ bool is_ascii_upper_case(char32_t c) {
return (c >= 'A' && c <= 'Z');
}
diff --git a/core/string/print_string.cpp b/core/string/print_string.cpp
index f58486e0a5..592da58fe7 100644
--- a/core/string/print_string.cpp
+++ b/core/string/print_string.cpp
@@ -30,13 +30,12 @@
#include "print_string.h"
+#include "core/core_globals.h"
#include "core/os/os.h"
#include <stdio.h>
static PrintHandlerList *print_handler_list = nullptr;
-bool _print_line_enabled = true;
-bool _print_error_enabled = true;
void add_print_handler(PrintHandlerList *p_handler) {
_global_lock();
@@ -70,7 +69,7 @@ void remove_print_handler(const PrintHandlerList *p_handler) {
}
void __print_line(String p_string) {
- if (!_print_line_enabled) {
+ if (!CoreGlobals::print_line_enabled) {
return;
}
@@ -87,7 +86,7 @@ void __print_line(String p_string) {
}
void __print_line_rich(String p_string) {
- if (!_print_line_enabled) {
+ if (!CoreGlobals::print_line_enabled) {
return;
}
@@ -178,7 +177,7 @@ void __print_line_rich(String p_string) {
}
void print_error(String p_string) {
- if (!_print_error_enabled) {
+ if (!CoreGlobals::print_error_enabled) {
return;
}
diff --git a/core/string/print_string.h b/core/string/print_string.h
index 823e2c29e8..ca930a3a0f 100644
--- a/core/string/print_string.h
+++ b/core/string/print_string.h
@@ -56,8 +56,6 @@ String stringify_variants(Variant p_var, Args... p_args) {
void add_print_handler(PrintHandlerList *p_handler);
void remove_print_handler(const PrintHandlerList *p_handler);
-extern bool _print_line_enabled;
-extern bool _print_error_enabled;
extern void __print_line(String p_string);
extern void __print_line_rich(String p_string);
extern void print_error(String p_string);
diff --git a/core/templates/paged_allocator.h b/core/templates/paged_allocator.h
index cf5911a847..43aab052fd 100644
--- a/core/templates/paged_allocator.h
+++ b/core/templates/paged_allocator.h
@@ -31,11 +31,14 @@
#ifndef PAGED_ALLOCATOR_H
#define PAGED_ALLOCATOR_H
+#include "core/core_globals.h"
#include "core/os/memory.h"
#include "core/os/spin_lock.h"
+#include "core/string/ustring.h"
#include "core/typedefs.h"
#include <type_traits>
+#include <typeinfo>
template <class T, bool thread_safe = false>
class PagedAllocator {
@@ -132,7 +135,12 @@ public:
}
~PagedAllocator() {
- ERR_FAIL_COND_MSG(allocs_available < pages_allocated * page_size, "Pages in use exist at exit in PagedAllocator");
+ if (allocs_available < pages_allocated * page_size) {
+ if (CoreGlobals::leak_reporting_enabled) {
+ ERR_FAIL_COND_MSG(allocs_available < pages_allocated * page_size, String("Pages in use exist at exit in PagedAllocator: ") + String(typeid(T).name()));
+ }
+ return;
+ }
reset();
}
};
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 6763dd66b0..504eaa4de6 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -39,6 +39,9 @@
#include "core/string/print_string.h"
#include "core/variant/variant_parser.h"
+PagedAllocator<Variant::Pools::BucketSmall, true> Variant::Pools::_bucket_small;
+PagedAllocator<Variant::Pools::BucketLarge, true> Variant::Pools::_bucket_large;
+
String Variant::get_type_name(Variant::Type p_type) {
switch (p_type) {
case NIL: {
@@ -1162,7 +1165,8 @@ void Variant::reference(const Variant &p_variant) {
memnew_placement(_data._mem, Rect2i(*reinterpret_cast<const Rect2i *>(p_variant._data._mem)));
} break;
case TRANSFORM2D: {
- _data._transform2d = memnew(Transform2D(*p_variant._data._transform2d));
+ _data._transform2d = (Transform2D *)Pools::_bucket_small.alloc();
+ memnew_placement(_data._transform2d, Transform2D(*p_variant._data._transform2d));
} break;
case VECTOR3: {
memnew_placement(_data._mem, Vector3(*reinterpret_cast<const Vector3 *>(p_variant._data._mem)));
@@ -1179,20 +1183,20 @@ void Variant::reference(const Variant &p_variant) {
case PLANE: {
memnew_placement(_data._mem, Plane(*reinterpret_cast<const Plane *>(p_variant._data._mem)));
} break;
-
case AABB: {
- _data._aabb = memnew(::AABB(*p_variant._data._aabb));
+ _data._aabb = (::AABB *)Pools::_bucket_small.alloc();
+ memnew_placement(_data._aabb, ::AABB(*p_variant._data._aabb));
} break;
case QUATERNION: {
memnew_placement(_data._mem, Quaternion(*reinterpret_cast<const Quaternion *>(p_variant._data._mem)));
-
} break;
case BASIS: {
- _data._basis = memnew(Basis(*p_variant._data._basis));
-
+ _data._basis = (Basis *)Pools::_bucket_large.alloc();
+ memnew_placement(_data._basis, Basis(*p_variant._data._basis));
} break;
case TRANSFORM3D: {
- _data._transform3d = memnew(Transform3D(*p_variant._data._transform3d));
+ _data._transform3d = (Transform3D *)Pools::_bucket_large.alloc();
+ memnew_placement(_data._transform3d, Transform3D(*p_variant._data._transform3d));
} break;
case PROJECTION: {
_data._projection = memnew(Projection(*p_variant._data._projection));
@@ -1381,16 +1385,32 @@ void Variant::_clear_internal() {
RECT2
*/
case TRANSFORM2D: {
- memdelete(_data._transform2d);
+ if (_data._transform2d) {
+ _data._transform2d->~Transform2D();
+ Pools::_bucket_small.free((Pools::BucketSmall *)_data._transform2d);
+ _data._transform2d = nullptr;
+ }
} break;
case AABB: {
- memdelete(_data._aabb);
+ if (_data._aabb) {
+ _data._aabb->~AABB();
+ Pools::_bucket_small.free((Pools::BucketSmall *)_data._aabb);
+ _data._aabb = nullptr;
+ }
} break;
case BASIS: {
- memdelete(_data._basis);
+ if (_data._basis) {
+ _data._basis->~Basis();
+ Pools::_bucket_large.free((Pools::BucketLarge *)_data._basis);
+ _data._basis = nullptr;
+ }
} break;
case TRANSFORM3D: {
- memdelete(_data._transform3d);
+ if (_data._transform3d) {
+ _data._transform3d->~Transform3D();
+ Pools::_bucket_large.free((Pools::BucketLarge *)_data._transform3d);
+ _data._transform3d = nullptr;
+ }
} break;
case PROJECTION: {
memdelete(_data._projection);
@@ -2609,12 +2629,14 @@ Variant::Variant(const Plane &p_plane) {
Variant::Variant(const ::AABB &p_aabb) {
type = AABB;
- _data._aabb = memnew(::AABB(p_aabb));
+ _data._aabb = (::AABB *)Pools::_bucket_small.alloc();
+ memnew_placement(_data._aabb, ::AABB(p_aabb));
}
Variant::Variant(const Basis &p_matrix) {
type = BASIS;
- _data._basis = memnew(Basis(p_matrix));
+ _data._basis = (Basis *)Pools::_bucket_large.alloc();
+ memnew_placement(_data._basis, Basis(p_matrix));
}
Variant::Variant(const Quaternion &p_quaternion) {
@@ -2624,7 +2646,8 @@ Variant::Variant(const Quaternion &p_quaternion) {
Variant::Variant(const Transform3D &p_transform) {
type = TRANSFORM3D;
- _data._transform3d = memnew(Transform3D(p_transform));
+ _data._transform3d = (Transform3D *)Pools::_bucket_large.alloc();
+ memnew_placement(_data._transform3d, Transform3D(p_transform));
}
Variant::Variant(const Projection &pp_projection) {
@@ -2634,7 +2657,8 @@ Variant::Variant(const Projection &pp_projection) {
Variant::Variant(const Transform2D &p_transform) {
type = TRANSFORM2D;
- _data._transform2d = memnew(Transform2D(p_transform));
+ _data._transform2d = (Transform2D *)Pools::_bucket_small.alloc();
+ memnew_placement(_data._transform2d, Transform2D(p_transform));
}
Variant::Variant(const Color &p_color) {
diff --git a/core/variant/variant.h b/core/variant/variant.h
index bfa110842a..ea75dce4ce 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -54,6 +54,7 @@
#include "core/os/keyboard.h"
#include "core/string/node_path.h"
#include "core/string/ustring.h"
+#include "core/templates/paged_allocator.h"
#include "core/templates/rid.h"
#include "core/variant/array.h"
#include "core/variant/callable.h"
@@ -134,6 +135,24 @@ public:
};
private:
+ struct Pools {
+ union BucketSmall {
+ BucketSmall() {}
+ ~BucketSmall() {}
+ Transform2D _transform2d;
+ ::AABB _aabb;
+ };
+ union BucketLarge {
+ BucketLarge() {}
+ ~BucketLarge() {}
+ Basis _basis;
+ Transform3D _transform3d;
+ };
+
+ static PagedAllocator<BucketSmall, true> _bucket_small;
+ static PagedAllocator<BucketLarge, true> _bucket_large;
+ };
+
friend struct _VariantCall;
friend class VariantInternal;
// Variant takes 20 bytes when real_t is float, and 36 if double
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
index 961c0f3a51..51ca4971db 100644
--- a/core/variant/variant_internal.h
+++ b/core/variant/variant_internal.h
@@ -36,6 +36,8 @@
// For use when you want to access the internal pointer of a Variant directly.
// Use with caution. You need to be sure that the type is correct.
class VariantInternal {
+ friend class Variant;
+
public:
// Set type.
_FORCE_INLINE_ static void initialize(Variant *v, Variant::Type p_type) {
@@ -215,19 +217,23 @@ public:
}
_FORCE_INLINE_ static void init_transform2d(Variant *v) {
- v->_data._transform2d = memnew(Transform2D);
+ v->_data._transform2d = (Transform2D *)Variant::Pools::_bucket_small.alloc();
+ memnew_placement(v->_data._transform2d, Transform2D);
v->type = Variant::TRANSFORM2D;
}
_FORCE_INLINE_ static void init_aabb(Variant *v) {
- v->_data._aabb = memnew(AABB);
+ v->_data._aabb = (AABB *)Variant::Pools::_bucket_small.alloc();
+ memnew_placement(v->_data._aabb, AABB);
v->type = Variant::AABB;
}
_FORCE_INLINE_ static void init_basis(Variant *v) {
- v->_data._basis = memnew(Basis);
+ v->_data._basis = (Basis *)Variant::Pools::_bucket_large.alloc();
+ memnew_placement(v->_data._basis, Basis);
v->type = Variant::BASIS;
}
_FORCE_INLINE_ static void init_transform(Variant *v) {
- v->_data._transform3d = memnew(Transform3D);
+ v->_data._transform3d = (Transform3D *)Variant::Pools::_bucket_large.alloc();
+ memnew_placement(v->_data._transform3d, Transform3D);
v->type = Variant::TRANSFORM3D;
}
_FORCE_INLINE_ static void init_projection(Variant *v) {
diff --git a/doc/classes/ParticlesMaterial.xml b/doc/classes/ParticlesMaterial.xml
index ef3b94e2a1..7badd826d9 100644
--- a/doc/classes/ParticlesMaterial.xml
+++ b/doc/classes/ParticlesMaterial.xml
@@ -271,40 +271,40 @@
<member name="tangential_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
Minimum equivalent of [member tangential_accel_max].
</member>
- <member name="turbulence_active" type="bool" setter="set_turbulence_active" getter="get_turbulence_active" default="false">
+ <member name="turbulence_enabled" type="bool" setter="set_turbulence_enabled" getter="get_turbulence_enabled" default="false">
Enables and disables Turbulence for the particle system.
</member>
- <member name="turbulence_influence_max" type="float" setter="set_param_max" getter="get_param_max">
+ <member name="turbulence_influence_max" type="float" setter="set_param_max" getter="get_param_max" default="0.1">
Minimum turbulence influence on each particle.
The actual amount of turbulence influence on each particle is calculated as a random value between [member turbulence_influence_min] and [member turbulence_influence_max] and multiplied by the amount of turbulence influence from [member turbulence_influence_over_life].
</member>
- <member name="turbulence_influence_min" type="float" setter="set_param_min" getter="get_param_min">
+ <member name="turbulence_influence_min" type="float" setter="set_param_min" getter="get_param_min" default="0.1">
Maximum turbulence influence on each particle.
The actual amount of turbulence influence on each particle is calculated as a random value between [member turbulence_influence_min] and [member turbulence_influence_max] and multiplied by the amount of turbulence influence from [member turbulence_influence_over_life].
</member>
<member name="turbulence_influence_over_life" type="Texture2D" setter="set_param_texture" getter="get_param_texture">
Each particle's amount of turbulence will be influenced along this [CurveTexture] over its life time.
</member>
- <member name="turbulence_initial_displacement_max" type="float" setter="set_param_max" getter="get_param_max">
+ <member name="turbulence_initial_displacement_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
Maximum displacement of each particles spawn position by the turbulence.
The actual amount of displacement will be a factor of the underlying turbulence multiplied by a random value between [member turbulence_initial_displacement_min] and [member turbulence_initial_displacement_max].
</member>
- <member name="turbulence_initial_displacement_min" type="float" setter="set_param_min" getter="get_param_min">
+ <member name="turbulence_initial_displacement_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
Minimum displacement of each particles spawn position by the turbulence.
The actual amount of displacement will be a factor of the underlying turbulence multiplied by a random value between [member turbulence_initial_displacement_min] and [member turbulence_initial_displacement_max].
</member>
- <member name="turbulence_noise_scale" type="float" setter="set_turbulence_noise_scale" getter="get_turbulence_noise_scale">
+ <member name="turbulence_noise_scale" type="float" setter="set_turbulence_noise_scale" getter="get_turbulence_noise_scale" default="9.0">
This value controls the overall scale/frequency of the turbulence noise pattern.
A small scale will result in smaller features with more detail while a high scale will result in smoother noise with larger features.
</member>
- <member name="turbulence_noise_speed" type="Vector3" setter="set_turbulence_noise_speed" getter="get_turbulence_noise_speed">
+ <member name="turbulence_noise_speed" type="Vector3" setter="set_turbulence_noise_speed" getter="get_turbulence_noise_speed" default="Vector3(0.5, 0.5, 0.5)">
The movement speed of the turbulence pattern. This changes how quickly the noise changes over time.
A value of [code]Vector3(0.0, 0.0, 0.0)[/code] will freeze the turbulence pattern in place.
</member>
- <member name="turbulence_noise_speed_random" type="float" setter="set_turbulence_noise_speed_random" getter="get_turbulence_noise_speed_random">
+ <member name="turbulence_noise_speed_random" type="float" setter="set_turbulence_noise_speed_random" getter="get_turbulence_noise_speed_random" default="0.0">
Use to influence the noise speed in a random pattern. This helps to break up visible movement patterns.
</member>
- <member name="turbulence_noise_strength" type="float" setter="set_turbulence_noise_strength" getter="get_turbulence_noise_strength">
+ <member name="turbulence_noise_strength" type="float" setter="set_turbulence_noise_strength" getter="get_turbulence_noise_strength" default="1.0">
The turbulence noise strength. Increasing this will result in a stronger, more contrasting, noise pattern.
</member>
</members>
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index e1b676427b..9f35ddc353 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -937,6 +937,16 @@
Returns [code]true[/code] if the server supports a feature.
</description>
</method>
+ <method name="is_confusable" qualifiers="const">
+ <return type="int" />
+ <argument index="0" name="string" type="String" />
+ <argument index="1" name="dict" type="PackedStringArray" />
+ <description>
+ Returns index of the first string in [code]dict[/dict] which is visually confusable with the [code]string[/string], or [code]-1[/code] if none is found.
+ [b]Note:[/b] This method doesn't detect invisible characters, for spoof detection use it in combination with [method spoof_check].
+ [b]Note:[/b] Always returns [code]-1[/code] if the server does not support the [constant FEATURE_UNICODE_SECURITY] feature.
+ </description>
+ </method>
<method name="is_locale_right_to_left" qualifiers="const">
<return type="bool" />
<argument index="0" name="locale" type="String" />
@@ -944,6 +954,21 @@
Returns [code]true[/code] if locale is right-to-left.
</description>
</method>
+ <method name="is_valid_identifier" qualifiers="const">
+ <return type="bool" />
+ <argument index="0" name="string" type="String" />
+ <description>
+ Returns [code]true[/code] is [code]string[/code] is a valid identifier.
+ If the text server supports the [constant FEATURE_UNICODE_IDENTIFIERS] feature, a valid identifier must:
+ - Conform to normalization form C.
+ - Begin with a Unicode character of class XID_Start or [code]"_"[/code].
+ - May contain Unicode characters of class XID_Continue in the other positions.
+ - Use UAX #31 recommended scripts only (mixed scripts are allowed).
+ If the [constant FEATURE_UNICODE_IDENTIFIERS] feature is not supported, a valid identifier must:
+ - Begin with a Unicode character of class XID_Start or [code]"_"[/code].
+ - May contain Unicode characters of class XID_Continue in the other positions.
+ </description>
+ </method>
<method name="load_support_data">
<return type="bool" />
<argument index="0" name="filename" type="String" />
@@ -1461,6 +1486,14 @@
Aligns shaped text to the given tab-stops.
</description>
</method>
+ <method name="spoof_check" qualifiers="const">
+ <return type="bool" />
+ <argument index="0" name="string" type="String" />
+ <description>
+ Returns [code]true[/code] if [code]string[/code] is likely to be an attempt at confusing the reader.
+ [b]Note:[/b] Always returns [code]false[/code] if the server does not support the [constant FEATURE_UNICODE_SECURITY] feature.
+ </description>
+ </method>
<method name="string_get_word_breaks" qualifiers="const">
<return type="PackedInt32Array" />
<argument index="0" name="string" type="String" />
@@ -1713,7 +1746,13 @@
TextServer supports locale dependent and context sensitive case conversion.
</constant>
<constant name="FEATURE_USE_SUPPORT_DATA" value="4096" enum="Feature">
- TextServer require external data file for some features.
+ TextServer require external data file for some features, see [method load_support_data].
+ </constant>
+ <constant name="FEATURE_UNICODE_IDENTIFIERS" value="8192" enum="Feature">
+ TextServer supports UAX #31 identifier validation, see [method is_valid_identifier].
+ </constant>
+ <constant name="FEATURE_UNICODE_SECURITY" value="16384" enum="Feature">
+ TextServer supports [url=https://unicode.org/reports/tr36/]Unicode Technical Report #36[/url] and [url=https://unicode.org/reports/tr39/]Unicode Technical Standard #39[/url] based spoof detection features.
</constant>
<constant name="CONTOUR_CURVE_TAG_ON" value="1" enum="ContourPointTag">
Contour point is on the curve.
diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml
index 4501ec744a..c686a06e5e 100644
--- a/doc/classes/TextServerExtension.xml
+++ b/doc/classes/TextServerExtension.xml
@@ -934,6 +934,14 @@
Returns [code]true[/code] if the server supports a feature.
</description>
</method>
+ <method name="is_confusable" qualifiers="virtual const">
+ <return type="int" />
+ <argument index="0" name="string" type="String" />
+ <argument index="1" name="dict" type="PackedStringArray" />
+ <description>
+ Returns index of the first string in [code]dict[/dict] which is visually confusable with the [code]string[/string], or [code]-1[/code] if none is found.
+ </description>
+ </method>
<method name="is_locale_right_to_left" qualifiers="virtual const">
<return type="bool" />
<argument index="0" name="locale" type="String" />
@@ -941,6 +949,13 @@
Returns [code]true[/code] if locale is right-to-left.
</description>
</method>
+ <method name="is_valid_identifier" qualifiers="virtual const">
+ <return type="bool" />
+ <argument index="0" name="string" type="String" />
+ <description>
+ Returns [code]true[/code] is [code]string[/code] is a valid identifier.
+ </description>
+ </method>
<method name="load_support_data" qualifiers="virtual">
<return type="bool" />
<argument index="0" name="filename" type="String" />
@@ -1481,6 +1496,13 @@
[b]Note:[/b] This method is used by default line/word breaking methods, and its implementation might be omitted if custom line breaking in implemented.
</description>
</method>
+ <method name="spoof_check" qualifiers="virtual const">
+ <return type="bool" />
+ <argument index="0" name="string" type="String" />
+ <description>
+ Returns [code]true[/code] if [code]string[/code] is likely to be an attempt at confusing the reader.
+ </description>
+ </method>
<method name="string_get_word_breaks" qualifiers="virtual const">
<return type="PackedInt32Array" />
<argument index="0" name="string" type="String" />
diff --git a/doc/classes/VisualShaderNodeTextureUniform.xml b/doc/classes/VisualShaderNodeTextureUniform.xml
index bff6f2015d..9014f79f54 100644
--- a/doc/classes/VisualShaderNodeTextureUniform.xml
+++ b/doc/classes/VisualShaderNodeTextureUniform.xml
@@ -39,12 +39,15 @@
Represents the size of the [enum TextureType] enum.
</constant>
<constant name="COLOR_DEFAULT_WHITE" value="0" enum="ColorDefault">
- Defaults to white color.
+ Defaults to fully opaque white color.
</constant>
<constant name="COLOR_DEFAULT_BLACK" value="1" enum="ColorDefault">
- Defaults to black color.
+ Defaults to fully opaque black color.
</constant>
- <constant name="COLOR_DEFAULT_MAX" value="2" enum="ColorDefault">
+ <constant name="COLOR_DEFAULT_TRANSPARENT" value="2" enum="ColorDefault">
+ Defaults to fully transparent black color.
+ </constant>
+ <constant name="COLOR_DEFAULT_MAX" value="3" enum="ColorDefault">
Represents the size of the [enum ColorDefault] enum.
</constant>
<constant name="FILTER_DEFAULT" value="0" enum="TextureFilter">
diff --git a/drivers/gles3/effects/copy_effects.cpp b/drivers/gles3/effects/copy_effects.cpp
index c8e6c2b476..de0181f887 100644
--- a/drivers/gles3/effects/copy_effects.cpp
+++ b/drivers/gles3/effects/copy_effects.cpp
@@ -111,6 +111,7 @@ CopyEffects::~CopyEffects() {
glDeleteVertexArrays(1, &screen_triangle_array);
glDeleteBuffers(1, &quad);
glDeleteVertexArrays(1, &quad_array);
+ copy.shader.version_free(copy.shader_version);
}
void CopyEffects::copy_to_rect(const Rect2i &p_rect) {
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 279cbccb0e..410cd376a7 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -496,7 +496,7 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
while (sky) {
if (sky->radiance == 0) {
- sky->mipmap_count = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBA8) - 2;
+ sky->mipmap_count = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBA8) - 1;
// Left uninitialized, will attach a texture at render time
glGenFramebuffers(1, &sky->radiance_framebuffer);
@@ -523,7 +523,7 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count - 1);
glGenTextures(1, &sky->raw_radiance);
glBindTexture(GL_TEXTURE_CUBE_MAP, sky->raw_radiance);
@@ -544,7 +544,8 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count - 1);
+
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}
@@ -701,6 +702,7 @@ void RasterizerSceneGLES3::_setup_sky(RID p_env, RID p_render_buffers, const Pag
}
if (!sky->radiance) {
+ _invalidate_sky(sky);
_update_dirty_skys();
}
}
@@ -879,7 +881,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
}
if (update_single_frame) {
- for (int i = 0; i <= max_processing_layer; i++) {
+ for (int i = 0; i < max_processing_layer; i++) {
_filter_sky_radiance(sky, i);
}
} else {
@@ -889,7 +891,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
sky->reflection_dirty = false;
} else {
- if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer <= max_processing_layer) {
+ if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) {
_filter_sky_radiance(sky, sky->processing_layer);
sky->processing_layer++;
}
@@ -1005,7 +1007,9 @@ void RasterizerSceneGLES3::_filter_sky_radiance(Sky *p_sky, int p_base_layer) {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, p_sky->radiance, p_base_layer);
#ifdef DEBUG_ENABLED
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ WARN_PRINT("Could not bind sky radiance face: " + itos(i) + ", status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
+ }
#endif
material_storage->shaders.cubemap_filter_shader.version_set_uniform(CubemapFilterShaderGLES3::FACE_ID, i, scene_globals.cubemap_filter_shader_version, mode);
@@ -2303,7 +2307,7 @@ void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_
glGenTextures(1, &rb->depth_texture);
glBindTexture(GL_TEXTURE_2D, rb->depth_texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl
index 57f0d7d0b8..88464876f1 100644
--- a/drivers/gles3/shaders/cubemap_filter.glsl
+++ b/drivers/gles3/shaders/cubemap_filter.glsl
@@ -106,12 +106,12 @@ void main() {
T[2] = N;
for (int sample_num = 0; sample_num < sample_count; sample_num++) {
- vec4 sample = sample_directions_mip[sample_num];
- vec3 L = T * sample.xyz;
- vec3 val = textureLod(source_cube, L, sample.w).rgb;
+ vec4 sample_direction_mip = sample_directions_mip[sample_num];
+ vec3 L = T * sample_direction_mip.xyz;
+ vec3 val = textureLod(source_cube, L, sample_direction_mip.w).rgb;
// Mix using linear
val = srgb_to_linear(val);
- sum.rgb += val * sample.z;
+ sum.rgb += val * sample_direction_mip.z;
}
sum /= weight;
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 93bb4c191d..4081d73ab0 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -754,7 +754,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
if (omni_lights[idx].size > 0.0) {
float t = omni_lights[idx].size / max(0.001, light_length);
- size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
+ size_A = max(0.0, 1.0 - 1.0 / sqrt(1.0 + t * t));
}
light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, omni_attenuation, f0, roughness, metallic, omni_lights[idx].specular_amount, albedo, alpha,
@@ -803,7 +803,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
if (spot_lights[idx].size > 0.0) {
float t = spot_lights[idx].size / max(0.001, light_length);
- size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
+ size_A = max(0.0, 1.0 - 1.0 / sqrt(1.0 + t * t));
}
light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, spot_attenuation, f0, roughness, metallic, spot_lights[idx].specular_amount, albedo, alpha,
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index ac2f4f0019..9440a3a0ae 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -1156,6 +1156,9 @@ void MaterialData::update_textures(const HashMap<StringName, Variant> &p_paramet
case ShaderLanguage::ShaderNode::Uniform::HINT_DEFAULT_BLACK: {
gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_BLACK);
} break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_DEFAULT_TRANSPARENT: {
+ gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_TRANSPARENT);
+ } break;
case ShaderLanguage::ShaderNode::Uniform::HINT_ANISOTROPY: {
gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_ANISO);
} break;
@@ -1505,6 +1508,11 @@ MaterialStorage::MaterialStorage() {
actions.renames["CUSTOM3"] = "custom3_attrib";
actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
+ actions.renames["NODE_POSITION_WORLD"] = "model_matrix[3].xyz";
+ actions.renames["CAMERA_POSITION_WORLD"] = "scene_data.inv_view_matrix[3].xyz";
+ actions.renames["CAMERA_DIRECTION_WORLD"] = "scene_data.view_matrix[3].xyz";
+ actions.renames["NODE_POSITION_VIEW"] = "(model_matrix * scene_data.view_matrix)[3].xyz";
+
actions.renames["VIEW_INDEX"] = "ViewIndex";
actions.renames["VIEW_MONO_LEFT"] = "0";
actions.renames["VIEW_RIGHT"] = "1";
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
index 88b81805fa..667ba4f5e6 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -1347,7 +1347,7 @@ void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_b
_multimesh_mark_all_dirty(multimesh, false, true); //update AABB
} else if (multimesh->mesh.is_valid()) {
//if we have a mesh set, we need to re-generate the AABB from the new data
- const float *data = multimesh->data_cache.ptr();
+ const float *data = p_buffer.ptr();
_multimesh_re_create_aabb(multimesh, data, multimesh->instances);
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index c05f516548..543638e8ff 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -115,6 +115,17 @@ TextureStorage::TextureStorage() {
texture_2d_layered_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_CUBEMAP_BLACK], images, RS::TEXTURE_LAYERED_CUBEMAP);
}
+ { // transparent black
+ Ref<Image> image;
+ image.instantiate();
+ image->create(4, 4, true, Image::FORMAT_RGBA8);
+ image->fill(Color(0, 0, 0, 0));
+ image->generate_mipmaps();
+
+ default_gl_textures[DEFAULT_GL_TEXTURE_TRANSPARENT] = texture_allocate();
+ texture_2d_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_TRANSPARENT], image);
+ }
+
{
Ref<Image> image;
image.instantiate();
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index 77ec1da6f5..71f713bc9f 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -103,6 +103,7 @@ namespace GLES3 {
enum DefaultGLTexture {
DEFAULT_GL_TEXTURE_WHITE,
DEFAULT_GL_TEXTURE_BLACK,
+ DEFAULT_GL_TEXTURE_TRANSPARENT,
DEFAULT_GL_TEXTURE_NORMAL,
DEFAULT_GL_TEXTURE_ANISO,
DEFAULT_GL_TEXTURE_DEPTH,
diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h
index 18f435f942..f5dca7c282 100644
--- a/drivers/unix/dir_access_unix.h
+++ b/drivers/unix/dir_access_unix.h
@@ -52,39 +52,39 @@ protected:
virtual bool is_hidden(const String &p_name);
public:
- virtual Error list_dir_begin(); ///< This starts dir listing
- virtual String get_next();
- virtual bool current_is_dir() const;
- virtual bool current_is_hidden() const;
+ virtual Error list_dir_begin() override; ///< This starts dir listing
+ virtual String get_next() override;
+ virtual bool current_is_dir() const override;
+ virtual bool current_is_hidden() const override;
- virtual void list_dir_end(); ///<
+ virtual void list_dir_end() override; ///<
- virtual int get_drive_count();
- virtual String get_drive(int p_drive);
- virtual int get_current_drive();
- virtual bool drives_are_shortcuts();
+ virtual int get_drive_count() override;
+ virtual String get_drive(int p_drive) override;
+ virtual int get_current_drive() override;
+ virtual bool drives_are_shortcuts() override;
- virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success
- virtual String get_current_dir(bool p_include_drive = true) const; ///< return current dir location
- virtual Error make_dir(String p_dir);
+ virtual Error change_dir(String p_dir) override; ///< can be relative or absolute, return false on success
+ virtual String get_current_dir(bool p_include_drive = true) const override; ///< return current dir location
+ virtual Error make_dir(String p_dir) override;
- virtual bool file_exists(String p_file);
- virtual bool dir_exists(String p_dir);
- virtual bool is_readable(String p_dir);
- virtual bool is_writable(String p_dir);
+ virtual bool file_exists(String p_file) override;
+ virtual bool dir_exists(String p_dir) override;
+ virtual bool is_readable(String p_dir) override;
+ virtual bool is_writable(String p_dir) override;
virtual uint64_t get_modified_time(String p_file);
- virtual Error rename(String p_path, String p_new_path);
- virtual Error remove(String p_path);
+ virtual Error rename(String p_path, String p_new_path) override;
+ virtual Error remove(String p_path) override;
- virtual bool is_link(String p_file);
- virtual String read_link(String p_file);
- virtual Error create_link(String p_source, String p_target);
+ virtual bool is_link(String p_file) override;
+ virtual String read_link(String p_file) override;
+ virtual Error create_link(String p_source, String p_target) override;
- virtual uint64_t get_space_left();
+ virtual uint64_t get_space_left() override;
- virtual String get_filesystem_type() const;
+ virtual String get_filesystem_type() const override;
DirAccessUnix();
~DirAccessUnix();
diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h
index d61fc08f57..297c34e454 100644
--- a/drivers/unix/file_access_unix.h
+++ b/drivers/unix/file_access_unix.h
@@ -54,33 +54,33 @@ class FileAccessUnix : public FileAccess {
public:
static CloseNotificationFunc close_notification_func;
- virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual bool is_open() const; ///< true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual bool is_open() const override; ///< true when file is open
- virtual String get_path() const; /// returns the path for the current open file
- virtual String get_path_absolute() const; /// returns the absolute path for the current open file
+ virtual String get_path() const override; /// returns the path for the current open file
+ virtual String get_path_absolute() const override; /// returns the absolute path for the current open file
- virtual void seek(uint64_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual uint64_t get_position() const; ///< get position in the file
- virtual uint64_t get_length() const; ///< get size of the file
+ virtual void seek(uint64_t p_position) override; ///< seek to a given position
+ virtual void seek_end(int64_t p_position = 0) override; ///< seek from the end of file
+ virtual uint64_t get_position() const override; ///< get position in the file
+ virtual uint64_t get_length() const override; ///< get size of the file
- virtual bool eof_reached() const; ///< reading passed EOF
+ virtual bool eof_reached() const override; ///< reading passed EOF
- virtual uint8_t get_8() const; ///< get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint8_t get_8() const override; ///< get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual Error get_error() const; ///< get last error
+ virtual Error get_error() const override; ///< get last error
- virtual void flush();
- virtual void store_8(uint8_t p_dest); ///< store a byte
- virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override; ///< store a byte
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
- virtual bool file_exists(const String &p_path); ///< return true if a file exists
+ virtual bool file_exists(const String &p_path) override; ///< return true if a file exists
- virtual uint64_t _get_modified_time(const String &p_file);
- virtual uint32_t _get_unix_permissions(const String &p_file);
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
+ virtual uint64_t _get_modified_time(const String &p_file) override;
+ virtual uint32_t _get_unix_permissions(const String &p_file) override;
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override;
FileAccessUnix() {}
virtual ~FileAccessUnix();
diff --git a/drivers/windows/dir_access_windows.h b/drivers/windows/dir_access_windows.h
index fbb07ddef8..c2835b3347 100644
--- a/drivers/windows/dir_access_windows.h
+++ b/drivers/windows/dir_access_windows.h
@@ -54,33 +54,33 @@ class DirAccessWindows : public DirAccess {
bool _cishidden = false;
public:
- virtual Error list_dir_begin(); ///< This starts dir listing
- virtual String get_next();
- virtual bool current_is_dir() const;
- virtual bool current_is_hidden() const;
- virtual void list_dir_end(); ///<
+ virtual Error list_dir_begin() override; ///< This starts dir listing
+ virtual String get_next() override;
+ virtual bool current_is_dir() const override;
+ virtual bool current_is_hidden() const override;
+ virtual void list_dir_end() override; ///<
- virtual int get_drive_count();
- virtual String get_drive(int p_drive);
+ virtual int get_drive_count() override;
+ virtual String get_drive(int p_drive) override;
- virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success
- virtual String get_current_dir(bool p_include_drive = true) const; ///< return current dir location
+ virtual Error change_dir(String p_dir) override; ///< can be relative or absolute, return false on success
+ virtual String get_current_dir(bool p_include_drive = true) const override; ///< return current dir location
- virtual bool file_exists(String p_file);
- virtual bool dir_exists(String p_dir);
+ virtual bool file_exists(String p_file) override;
+ virtual bool dir_exists(String p_dir) override;
- virtual Error make_dir(String p_dir);
+ virtual Error make_dir(String p_dir) override;
- virtual Error rename(String p_path, String p_new_path);
- virtual Error remove(String p_path);
+ virtual Error rename(String p_path, String p_new_path) override;
+ virtual Error remove(String p_path) override;
- virtual bool is_link(String p_file) { return false; };
- virtual String read_link(String p_file) { return p_file; };
- virtual Error create_link(String p_source, String p_target) { return FAILED; };
+ virtual bool is_link(String p_file) override { return false; };
+ virtual String read_link(String p_file) override { return p_file; };
+ virtual Error create_link(String p_source, String p_target) override { return FAILED; };
- uint64_t get_space_left();
+ uint64_t get_space_left() override;
- virtual String get_filesystem_type() const;
+ virtual String get_filesystem_type() const override;
DirAccessWindows();
~DirAccessWindows();
diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h
index 5d67b6ca4f..8629bb936b 100644
--- a/drivers/windows/file_access_windows.h
+++ b/drivers/windows/file_access_windows.h
@@ -51,33 +51,33 @@ class FileAccessWindows : public FileAccess {
void _close();
public:
- virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual bool is_open() const; ///< true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual bool is_open() const override; ///< true when file is open
- virtual String get_path() const; /// returns the path for the current open file
- virtual String get_path_absolute() const; /// returns the absolute path for the current open file
+ virtual String get_path() const override; /// returns the path for the current open file
+ virtual String get_path_absolute() const override; /// returns the absolute path for the current open file
- virtual void seek(uint64_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual uint64_t get_position() const; ///< get position in the file
- virtual uint64_t get_length() const; ///< get size of the file
+ virtual void seek(uint64_t p_position) override; ///< seek to a given position
+ virtual void seek_end(int64_t p_position = 0) override; ///< seek from the end of file
+ virtual uint64_t get_position() const override; ///< get position in the file
+ virtual uint64_t get_length() const override; ///< get size of the file
- virtual bool eof_reached() const; ///< reading passed EOF
+ virtual bool eof_reached() const override; ///< reading passed EOF
- virtual uint8_t get_8() const; ///< get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint8_t get_8() const override; ///< get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual Error get_error() const; ///< get last error
+ virtual Error get_error() const override; ///< get last error
- virtual void flush();
- virtual void store_8(uint8_t p_dest); ///< store a byte
- virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override; ///< store a byte
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
- virtual bool file_exists(const String &p_name); ///< return true if a file exists
+ virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
- uint64_t _get_modified_time(const String &p_file);
- virtual uint32_t _get_unix_permissions(const String &p_file);
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
+ uint64_t _get_modified_time(const String &p_file) override;
+ virtual uint32_t _get_unix_permissions(const String &p_file) override;
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override;
FileAccessWindows() {}
virtual ~FileAccessWindows();
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 99ca82b311..b0eb384efc 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -1045,6 +1045,8 @@ void CodeTextEditor::update_editor_settings() {
guideline_cols.append(EditorSettings::get_singleton()->get("text_editor/appearance/guidelines/line_length_guideline_soft_column"));
}
text_editor->set_line_length_guidelines(guideline_cols);
+ } else {
+ text_editor->set_line_length_guidelines(TypedArray<int>());
}
}
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index e9aceb684f..ce885032a3 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -2202,9 +2202,10 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
Object *prev_inspected_object = InspectorDock::get_inspector_singleton()->get_edited_object();
bool disable_folding = bool(EDITOR_GET("interface/inspector/disable_folding"));
- bool stay_in_script_editor_on_node_selected = bool(EDITOR_GET("text_editor/behavior/navigation/stay_in_script_editor_on_node_selected"));
bool is_resource = current_obj->is_class("Resource");
bool is_node = current_obj->is_class("Node");
+ bool stay_in_script_editor_on_node_selected = bool(EDITOR_GET("text_editor/behavior/navigation/stay_in_script_editor_on_node_selected"));
+ bool skip_main_plugin = false;
String editable_warning; // None by default.
@@ -2241,8 +2242,8 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
NodeDock::get_singleton()->set_node(current_node);
SceneTreeDock::get_singleton()->set_selected(current_node);
InspectorDock::get_singleton()->update(current_node);
- if (!inspector_only) {
- inspector_only = stay_in_script_editor_on_node_selected && ScriptEditor::get_singleton()->is_visible_in_tree();
+ if (!inspector_only && !skip_main_plugin) {
+ skip_main_plugin = stay_in_script_editor_on_node_selected && ScriptEditor::get_singleton()->is_visible_in_tree();
}
} else {
NodeDock::get_singleton()->set_node(nullptr);
@@ -2318,7 +2319,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
}
}
- if (main_plugin) {
+ if (main_plugin && !skip_main_plugin) {
// Special case if use of external editor is true.
Resource *current_res = Object::cast_to<Resource>(current_obj);
if (main_plugin->get_name() == "Script" && !current_obj->is_class("VisualScript") && current_res && !current_res->is_built_in() && (bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor")) || overrides_external_editor(current_obj))) {
diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp
index 09d2992e07..6c713de94a 100644
--- a/editor/editor_property_name_processor.cpp
+++ b/editor/editor_property_name_processor.cpp
@@ -114,6 +114,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["bidi"] = "BiDi";
capitalize_string_remaps["bp"] = "BP";
capitalize_string_remaps["bpc"] = "BPC";
+ capitalize_string_remaps["bpm"] = "BPM";
capitalize_string_remaps["bptc"] = "BPTC";
capitalize_string_remaps["bvh"] = "BVH";
capitalize_string_remaps["ca"] = "CA";
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index da7105c94c..02380c4e39 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -1660,6 +1660,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_dictionary_add_item->set_expand_margin_size(SIDE_RIGHT, 4 * EDSCALE);
theme->set_stylebox("DictionaryAddItem", "EditorStyles", style_dictionary_add_item);
+ Ref<StyleBoxEmpty> vshader_label_style = make_empty_stylebox(2, 1, 2, 1);
+ theme->set_stylebox("label_style", "VShaderEditor", vshader_label_style);
+
// adaptive script theme constants
// for comments and elements with lower relevance
const Color dim_color = Color(font_color.r, font_color.g, font_color.b, 0.5);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 8de1ba326d..6f8d33532f 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -5216,7 +5216,7 @@ CanvasItemEditor::CanvasItemEditor() {
group_button->set_flat(true);
main_menu_hbox->add_child(group_button);
group_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(GROUP_SELECTED));
- group_button->set_tooltip(TTR("Makes sure the object's children are not selectable."));
+ group_button->set_tooltip(TTR("Make selected node's children not selectable."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
group_button->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KeyModifierMask::CMD | Key::G));
@@ -5224,7 +5224,7 @@ CanvasItemEditor::CanvasItemEditor() {
ungroup_button->set_flat(true);
main_menu_hbox->add_child(ungroup_button);
ungroup_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(UNGROUP_SELECTED));
- ungroup_button->set_tooltip(TTR("Restores the object's children's ability to be selected."));
+ ungroup_button->set_tooltip(TTR("Make selected node's children selectable."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
ungroup_button->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::G));
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 7628a95310..ba505a9abb 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -7796,7 +7796,7 @@ Node3DEditor::Node3DEditor() {
main_menu_hbox->add_child(tool_button[TOOL_GROUP_SELECTED]);
tool_button[TOOL_GROUP_SELECTED]->set_flat(true);
tool_button[TOOL_GROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_GROUP_SELECTED));
- tool_button[TOOL_GROUP_SELECTED]->set_tooltip(TTR("Makes sure the object's children are not selectable."));
+ tool_button[TOOL_GROUP_SELECTED]->set_tooltip(TTR("Make selected node's children not selectable."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
tool_button[TOOL_GROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KeyModifierMask::CMD | Key::G));
@@ -7804,7 +7804,7 @@ Node3DEditor::Node3DEditor() {
main_menu_hbox->add_child(tool_button[TOOL_UNGROUP_SELECTED]);
tool_button[TOOL_UNGROUP_SELECTED]->set_flat(true);
tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNGROUP_SELECTED));
- tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip(TTR("Restores the object's children's ability to be selected."));
+ tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip(TTR("Make selected node's children selectable."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
tool_button[TOOL_UNGROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::G));
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 626071aa72..65d684c2a1 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -40,10 +40,17 @@
#include "editor/editor_node.h"
#include "editor/editor_properties.h"
#include "editor/editor_scale.h"
+#include "editor/plugins/curve_editor_plugin.h"
#include "editor/plugins/shader_editor_plugin.h"
#include "scene/animation/animation_player.h"
+#include "scene/gui/button.h"
+#include "scene/gui/code_edit.h"
+#include "scene/gui/graph_edit.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
+#include "scene/gui/popup.h"
+#include "scene/gui/rich_text_label.h"
+#include "scene/gui/tree.h"
#include "scene/gui/view_panner.h"
#include "scene/main/window.h"
#include "scene/resources/visual_shader_nodes.h"
@@ -91,17 +98,6 @@ void VisualShaderNodePlugin::_bind_methods() {
///////////////////
-static Ref<StyleBoxEmpty> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) {
- Ref<StyleBoxEmpty> style(memnew(StyleBoxEmpty));
- style->set_default_margin(SIDE_LEFT, p_margin_left * EDSCALE);
- style->set_default_margin(SIDE_RIGHT, p_margin_right * EDSCALE);
- style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * EDSCALE);
- style->set_default_margin(SIDE_TOP, p_margin_top * EDSCALE);
- return style;
-}
-
-///////////////////
-
VisualShaderGraphPlugin::VisualShaderGraphPlugin() {
}
@@ -364,8 +360,6 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
Control *offset;
- static Ref<StyleBoxEmpty> label_style = make_empty_stylebox(2, 1, 2, 1);
-
static const Color type_color[] = {
Color(0.38, 0.85, 0.96), // scalar (float)
Color(0.49, 0.78, 0.94), // scalar (int)
@@ -765,14 +759,14 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
} else {
Label *label = memnew(Label);
label->set_text(name_left);
- label->add_theme_style_override("normal", label_style); //more compact
+ label->add_theme_style_override("normal", editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor"))); //more compact
hb->add_child(label);
if (vsnode->is_input_port_default(i, mode) && !port_left_used) {
Label *hint_label = memnew(Label);
hint_label->set_text(TTR("[default]"));
hint_label->add_theme_color_override("font_color", editor->get_theme_color(SNAME("font_readonly_color"), SNAME("TextEdit")));
- hint_label->add_theme_style_override("normal", label_style);
+ hint_label->add_theme_style_override("normal", editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor")));
hb->add_child(hint_label);
}
}
@@ -813,7 +807,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
} else {
Label *label = memnew(Label);
label->set_text(name_right);
- label->add_theme_style_override("normal", label_style); //more compact
+ label->add_theme_style_override("normal", editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor"))); //more compact
hb->add_child(label);
}
}
@@ -1080,6 +1074,23 @@ VisualShaderGraphPlugin::~VisualShaderGraphPlugin() {
/////////////////
+void VisualShaderEditedProperty::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_edited_property", "value"), &VisualShaderEditedProperty::set_edited_property);
+ ClassDB::bind_method(D_METHOD("get_edited_property"), &VisualShaderEditedProperty::get_edited_property);
+
+ ADD_PROPERTY(PropertyInfo(Variant::NIL, "edited_property", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_edited_property", "get_edited_property");
+}
+
+void VisualShaderEditedProperty::set_edited_property(Variant p_variant) {
+ edited_property = p_variant;
+}
+
+Variant VisualShaderEditedProperty::get_edited_property() const {
+ return edited_property;
+}
+
+/////////////////
+
Vector2 VisualShaderEditor::selection_center;
List<VisualShaderEditor::CopyItem> VisualShaderEditor::copy_items_buffer;
List<VisualShader::Connection> VisualShaderEditor::copy_connections_buffer;
@@ -2287,10 +2298,8 @@ void VisualShaderEditor::_port_name_focus_out(Object *line_edit, int p_node_id,
}
}
-void VisualShaderEditor::_port_edited() {
+void VisualShaderEditor::_port_edited(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing) {
VisualShader::Type type = get_current_shader_type();
-
- Variant value = property_editor->get_variant();
Ref<VisualShaderNode> vsn = visual_shader->get_node(type, editing_node);
ERR_FAIL_COND(!vsn.is_valid());
@@ -2298,30 +2307,51 @@ void VisualShaderEditor::_port_edited() {
Ref<VisualShaderNodeCustom> custom = Object::cast_to<VisualShaderNodeCustom>(vsn.ptr());
if (custom.is_valid()) {
- undo_redo->add_do_method(custom.ptr(), "_set_input_port_default_value", editing_port, value);
+ undo_redo->add_do_method(custom.ptr(), "_set_input_port_default_value", editing_port, p_value);
undo_redo->add_undo_method(custom.ptr(), "_set_input_port_default_value", editing_port, vsn->get_input_port_default_value(editing_port));
} else {
- undo_redo->add_do_method(vsn.ptr(), "set_input_port_default_value", editing_port, value);
+ undo_redo->add_do_method(vsn.ptr(), "set_input_port_default_value", editing_port, p_value);
undo_redo->add_undo_method(vsn.ptr(), "set_input_port_default_value", editing_port, vsn->get_input_port_default_value(editing_port));
}
- undo_redo->add_do_method(graph_plugin.ptr(), "set_input_port_default_value", type, editing_node, editing_port, value);
+ undo_redo->add_do_method(graph_plugin.ptr(), "set_input_port_default_value", type, editing_node, editing_port, p_value);
undo_redo->add_undo_method(graph_plugin.ptr(), "set_input_port_default_value", type, editing_node, editing_port, vsn->get_input_port_default_value(editing_port));
undo_redo->commit_action();
-
- property_editor->hide();
}
void VisualShaderEditor::_edit_port_default_input(Object *p_button, int p_node, int p_port) {
VisualShader::Type type = get_current_shader_type();
+ Ref<VisualShaderNode> vs_node = visual_shader->get_node(type, p_node);
+ Variant value = vs_node->get_input_port_default_value(p_port);
+
+ edited_property_holder->set_edited_property(value);
+
+ if (property_editor) {
+ property_editor->disconnect("property_changed", callable_mp(this, &VisualShaderEditor::_port_edited));
+ property_editor_popup->remove_child(property_editor);
+ }
- Ref<VisualShaderNode> vsn = visual_shader->get_node(type, p_node);
+ // TODO: Define these properties with actual PropertyInfo and feed it to the property editor widget.
+ property_editor = EditorInspector::instantiate_property_editor(edited_property_holder.ptr(), value.get_type(), "edited_property", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE);
+ if (property_editor) {
+ property_editor->set_object_and_property(edited_property_holder.ptr(), "edited_property");
+ property_editor->update_property();
+ property_editor->set_name_split_ratio(0);
+ property_editor_popup->add_child(property_editor);
+
+ property_editor->connect("property_changed", callable_mp(this, &VisualShaderEditor::_port_edited));
+
+ Button *button = Object::cast_to<Button>(p_button);
+ if (button) {
+ property_editor_popup->set_position(button->get_screen_position() + Vector2(0, button->get_size().height) * graph->get_zoom());
+ }
+ property_editor_popup->reset_size();
+ if (button) {
+ property_editor_popup->popup();
+ } else {
+ property_editor_popup->popup_centered_ratio();
+ }
+ }
- Button *button = Object::cast_to<Button>(p_button);
- ERR_FAIL_COND(!button);
- Variant value = vsn->get_input_port_default_value(p_port);
- property_editor->set_position(button->get_screen_position() + Vector2(0, button->get_size().height));
- property_editor->edit(nullptr, "", value.get_type(), value, 0, "");
- property_editor->popup();
editing_node = p_node;
editing_port = p_port;
}
@@ -5147,6 +5177,10 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("ViewIndex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_index", "VIEW_INDEX"), { "view_index" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ViewMonoLeft", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_mono_left", "VIEW_MONO_LEFT"), { "view_mono_left" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ViewRight", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_right", "VIEW_RIGHT"), { "view_right" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("NodePositionWorld", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("CameraPositionWorld", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("CameraDirectionWorld", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("NodePositionView", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Binormal", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal", "BINORMAL"), { "binormal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color", "COLOR"), { "color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
@@ -5162,6 +5196,10 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("ViewIndex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_index", "VIEW_INDEX"), { "view_index" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ViewMonoLeft", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_mono_left", "VIEW_MONO_LEFT"), { "view_mono_left" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ViewRight", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_right", "VIEW_RIGHT"), { "view_right" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("NodePositionWorld", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("CameraPositionWorld", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("CameraDirectionWorld", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("NodePositionView", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Albedo", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "albedo", "ALBEDO"), { "albedo" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Attenuation", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "attenuation", "ATTENUATION"), { "attenuation" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
@@ -5636,10 +5674,11 @@ VisualShaderEditor::VisualShaderEditor() {
graph_plugin.instantiate();
graph_plugin->set_editor(this);
- property_editor = memnew(CustomPropertyEditor);
- add_child(property_editor);
+ property_editor_popup = memnew(PopupPanel);
+ property_editor_popup->set_min_size(Size2i(180, 0) * EDSCALE);
+ add_child(property_editor_popup);
- property_editor->connect("variant_changed", callable_mp(this, &VisualShaderEditor::_port_edited));
+ edited_property_holder.instantiate();
}
class VisualShaderNodePluginInputEditor : public OptionButton {
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index ecaad1e540..b846c34f9e 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -32,17 +32,21 @@
#define VISUAL_SHADER_EDITOR_PLUGIN_H
#include "editor/editor_plugin.h"
-#include "editor/plugins/curve_editor_plugin.h"
#include "editor/plugins/editor_resource_conversion_plugin.h"
-#include "editor/property_editor.h"
-#include "scene/gui/button.h"
-#include "scene/gui/code_edit.h"
-#include "scene/gui/graph_edit.h"
-#include "scene/gui/popup.h"
-#include "scene/gui/rich_text_label.h"
-#include "scene/gui/tree.h"
#include "scene/resources/visual_shader.h"
+class Button;
+class CodeEdit;
+class CodeHighlighter;
+class CurveEditor;
+class GraphEdit;
+class GraphNode;
+class PopupMenu;
+class PopupPanel;
+class RichTextLabel;
+class TextEdit;
+class Tree;
+
class VisualShaderEditor;
class VisualShaderNodePlugin : public RefCounted {
@@ -138,13 +142,31 @@ public:
~VisualShaderGraphPlugin();
};
+class VisualShaderEditedProperty : public RefCounted {
+ GDCLASS(VisualShaderEditedProperty, RefCounted);
+
+private:
+ Variant edited_property;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_edited_property(Variant p_variant);
+ Variant get_edited_property() const;
+
+ VisualShaderEditedProperty() {}
+};
+
class VisualShaderEditor : public VBoxContainer {
GDCLASS(VisualShaderEditor, VBoxContainer);
friend class VisualShaderGraphPlugin;
- CustomPropertyEditor *property_editor = nullptr;
+ PopupPanel *property_editor_popup = nullptr;
+ EditorProperty *property_editor = nullptr;
int editing_node = -1;
int editing_port = -1;
+ Ref<VisualShaderEditedProperty> edited_property_holder;
Ref<VisualShader> visual_shader;
GraphEdit *graph = nullptr;
@@ -359,7 +381,7 @@ class VisualShaderEditor : public VBoxContainer {
void _node_changed(int p_id);
void _edit_port_default_input(Object *p_button, int p_node, int p_port);
- void _port_edited();
+ void _port_edited(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing);
int to_node = -1;
int to_slot = -1;
diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index 658258d98b..b564195911 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -2519,7 +2519,7 @@ Vector<String> ProjectConverter3To4::check_for_rename_enums(Vector<String> &file
int current_line = 1;
for (String &line : file_content) {
- Array reg_match = reg.search_all(line);
+ TypedArray<RegExMatch> reg_match = reg.search_all(line);
if (reg_match.size() > 0) {
found_things.append(line_formatter(current_line, colors_renames[current_index][0], colors_renames[current_index][1], line));
}
@@ -2596,7 +2596,7 @@ Vector<String> ProjectConverter3To4::check_for_rename_classes(Vector<String> &fi
line = reg_before.sub(line, "TEMP_RENAMED_CLASS.tscn", true);
line = reg_before2.sub(line, "TEMP_RENAMED_CLASS.gd", true);
- Array reg_match = reg.search_all(line);
+ TypedArray<RegExMatch> reg_match = reg.search_all(line);
if (reg_match.size() > 0) {
found_things.append(line_formatter(current_line, class_renames[current_index][0], class_renames[current_index][1], line));
}
@@ -3810,7 +3810,7 @@ Vector<String> ProjectConverter3To4::check_for_custom_rename(Vector<String> &fil
int current_line = 1;
for (String &line : file_content) {
- Array reg_match = reg.search_all(line);
+ TypedArray<RegExMatch> reg_match = reg.search_all(line);
if (reg_match.size() > 0) {
found_things.append(line_formatter(current_line, from.replace("\\.", "."), to, line)); // Without replacing it will print "\.shader" instead ".shader"
}
@@ -3841,7 +3841,7 @@ Vector<String> ProjectConverter3To4::check_for_rename_common(const char *array[]
int current_line = 1;
for (String &line : file_content) {
- Array reg_match = reg.search_all(line);
+ TypedArray<RegExMatch> reg_match = reg.search_all(line);
if (reg_match.size() > 0) {
found_things.append(line_formatter(current_line, array[current_index][0], array[current_index][1], line));
}
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
deleted file mode 100644
index 3906827027..0000000000
--- a/editor/property_editor.cpp
+++ /dev/null
@@ -1,1866 +0,0 @@
-/*************************************************************************/
-/* property_editor.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "property_editor.h"
-
-#include "core/config/project_settings.h"
-#include "core/input/input.h"
-#include "core/io/image_loader.h"
-#include "core/io/marshalls.h"
-#include "core/io/resource_loader.h"
-#include "core/math/expression.h"
-#include "core/object/class_db.h"
-#include "core/os/keyboard.h"
-#include "core/string/print_string.h"
-#include "core/templates/pair.h"
-#include "editor/array_property_edit.h"
-#include "editor/create_dialog.h"
-#include "editor/dictionary_property_edit.h"
-#include "editor/editor_file_dialog.h"
-#include "editor/editor_file_system.h"
-#include "editor/editor_help.h"
-#include "editor/editor_node.h"
-#include "editor/editor_scale.h"
-#include "editor/editor_settings.h"
-#include "editor/filesystem_dock.h"
-#include "editor/multi_node_edit.h"
-#include "editor/plugins/editor_resource_conversion_plugin.h"
-#include "editor/property_selector.h"
-#include "editor/scene_tree_dock.h"
-#include "scene/gui/label.h"
-#include "scene/main/window.h"
-#include "scene/resources/font.h"
-#include "scene/resources/packed_scene.h"
-#include "scene/scene_string_names.h"
-
-void CustomPropertyEditor::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_WM_CLOSE_REQUEST: {
- hide();
- } break;
- }
-}
-
-void CustomPropertyEditor::_menu_option(int p_which) {
- switch (type) {
- case Variant::INT: {
- if (hint == PROPERTY_HINT_FLAGS) {
- int idx = menu->get_item_index(p_which);
- uint32_t item_value = menu->get_item_metadata(idx);
- uint32_t value = v;
- // If the item wasn't previously checked it means it was pressed,
- // otherwise it was unpressed.
- if (!menu->is_item_checked(idx)) {
- v = value | item_value;
- } else {
- v = value & ~item_value;
- }
- emit_signal(SNAME("variant_changed"));
- } else if (hint == PROPERTY_HINT_ENUM) {
- v = menu->get_item_metadata(p_which);
- emit_signal(SNAME("variant_changed"));
- }
- } break;
- case Variant::STRING: {
- if (hint == PROPERTY_HINT_ENUM) {
- v = hint_text.get_slice(",", p_which);
- emit_signal(SNAME("variant_changed"));
- }
- } break;
- case Variant::OBJECT: {
- switch (p_which) {
- case OBJ_MENU_LOAD: {
- file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
- String type = (hint == PROPERTY_HINT_RESOURCE_TYPE) ? hint_text : String();
-
- List<String> extensions;
- for (int i = 0; i < type.get_slice_count(","); i++) {
- ResourceLoader::get_recognized_extensions_for_type(type.get_slice(",", i), &extensions);
- }
-
- HashSet<String> valid_extensions;
- for (const String &E : extensions) {
- valid_extensions.insert(E);
- }
-
- file->clear_filters();
- for (const String &E : valid_extensions) {
- file->add_filter("*." + E, E.to_upper());
- }
-
- file->popup_file_dialog();
- } break;
-
- case OBJ_MENU_EDIT: {
- Ref<RefCounted> r = v;
-
- if (!r.is_null()) {
- emit_signal(SNAME("resource_edit_request"));
- hide();
- }
- } break;
- case OBJ_MENU_CLEAR: {
- v = Variant();
- emit_signal(SNAME("variant_changed"));
- hide();
- } break;
-
- case OBJ_MENU_MAKE_UNIQUE: {
- Ref<Resource> res_orig = v;
- if (res_orig.is_null()) {
- return;
- }
-
- List<PropertyInfo> property_list;
- res_orig->get_property_list(&property_list);
- List<Pair<String, Variant>> propvalues;
-
- for (const PropertyInfo &pi : property_list) {
- Pair<String, Variant> p;
- if (pi.usage & PROPERTY_USAGE_STORAGE) {
- p.first = pi.name;
- p.second = res_orig->get(pi.name);
- }
-
- propvalues.push_back(p);
- }
-
- String orig_type = res_orig->get_class();
-
- Object *inst = ClassDB::instantiate(orig_type);
-
- Ref<Resource> res = Ref<Resource>(Object::cast_to<Resource>(inst));
-
- ERR_FAIL_COND(res.is_null());
-
- for (const Pair<String, Variant> &p : propvalues) {
- res->set(p.first, p.second);
- }
-
- v = res;
- emit_signal(SNAME("variant_changed"));
- hide();
- } break;
-
- case OBJ_MENU_COPY: {
- EditorSettings::get_singleton()->set_resource_clipboard(v);
-
- } break;
- case OBJ_MENU_PASTE: {
- v = EditorSettings::get_singleton()->get_resource_clipboard();
- emit_signal(SNAME("variant_changed"));
-
- } break;
- case OBJ_MENU_NEW_SCRIPT: {
- if (Object::cast_to<Node>(owner)) {
- SceneTreeDock::get_singleton()->open_script_dialog(Object::cast_to<Node>(owner), false);
- }
-
- } break;
- case OBJ_MENU_EXTEND_SCRIPT: {
- if (Object::cast_to<Node>(owner)) {
- SceneTreeDock::get_singleton()->open_script_dialog(Object::cast_to<Node>(owner), true);
- }
-
- } break;
- case OBJ_MENU_SHOW_IN_FILE_SYSTEM: {
- Ref<Resource> r = v;
- FileSystemDock *file_system_dock = FileSystemDock::get_singleton();
- file_system_dock->navigate_to_path(r->get_path());
- // Ensure that the FileSystem dock is visible.
- TabContainer *tab_container = (TabContainer *)file_system_dock->get_parent_control();
- tab_container->set_current_tab(tab_container->get_tab_idx_from_control(file_system_dock));
- } break;
- default: {
- if (p_which >= CONVERT_BASE_ID) {
- int to_type = p_which - CONVERT_BASE_ID;
-
- Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(Ref<Resource>(v));
-
- ERR_FAIL_INDEX(to_type, conversions.size());
-
- Ref<Resource> new_res = conversions[to_type]->convert(v);
-
- v = new_res;
- emit_signal(SNAME("variant_changed"));
- break;
- }
- ERR_FAIL_COND(inheritors_array.is_empty());
-
- String intype = inheritors_array[p_which - TYPE_BASE_ID];
-
- if (intype == "ViewportTexture") {
- scene_tree->set_title(TTR("Pick a Viewport"));
- scene_tree->popup_scenetree_dialog();
- picking_viewport = true;
- return;
- }
-
- Variant obj = ClassDB::instantiate(intype);
-
- if (!obj) {
- if (ScriptServer::is_global_class(intype)) {
- obj = EditorNode::get_editor_data().script_class_instance(intype);
- } else {
- obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource");
- }
- }
-
- ERR_BREAK(!obj);
- Resource *res = Object::cast_to<Resource>(obj);
- ERR_BREAK(!res);
- if (owner && hint == PROPERTY_HINT_RESOURCE_TYPE && hint_text == "Script") {
- //make visual script the right type
- res->call("set_instance_base_type", owner->get_class());
- }
-
- EditorNode::get_editor_data().instantiate_object_properties(obj);
- v = obj;
-
- emit_signal(SNAME("variant_changed"));
-
- } break;
- }
-
- } break;
- default: {
- }
- }
-}
-
-void CustomPropertyEditor::hide_menu() {
- menu->hide();
-}
-
-Variant CustomPropertyEditor::get_variant() const {
- return v;
-}
-
-String CustomPropertyEditor::get_name() const {
- return name;
-}
-
-bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::Type p_type, const Variant &p_variant, int p_hint, String p_hint_text) {
- owner = p_owner;
- updating = true;
- name = p_name;
- v = p_variant;
- field_names.clear();
- hint = p_hint;
- hint_text = p_hint_text;
- type_button->hide();
- if (color_picker) {
- color_picker->hide();
- }
- texture_preview->hide();
- inheritors_array.clear();
- text_edit->hide();
- easing_draw->hide();
- spinbox->hide();
- slider->hide();
- menu->clear();
- menu->reset_size();
-
- for (int i = 0; i < MAX_VALUE_EDITORS; i++) {
- if (i < MAX_VALUE_EDITORS / 4) {
- value_hboxes[i]->hide();
- }
- value_editor[i]->hide();
- value_label[i]->hide();
- if (i < 4) {
- scroll[i]->hide();
- }
- }
-
- for (int i = 0; i < MAX_ACTION_BUTTONS; i++) {
- action_buttons[i]->hide();
- }
-
- checks20gc->hide();
- for (int i = 0; i < 20; i++) {
- checks20[i]->hide();
- }
-
- type = (p_variant.get_type() != Variant::NIL && p_variant.get_type() != Variant::RID && p_type != Variant::OBJECT) ? p_variant.get_type() : p_type;
-
- switch (type) {
- case Variant::BOOL: {
- checks20gc->show();
-
- CheckBox *c = checks20[0];
- c->set_text("True");
- checks20gc->set_position(Vector2(4, 4) * EDSCALE);
- c->set_pressed(v);
- c->show();
-
- checks20gc->set_size(checks20gc->get_minimum_size());
- set_size(checks20gc->get_position() + checks20gc->get_size() + c->get_size() + Vector2(4, 4) * EDSCALE);
-
- } break;
- case Variant::INT:
- case Variant::FLOAT: {
- if (hint == PROPERTY_HINT_RANGE) {
- int c = hint_text.get_slice_count(",");
- float min = 0, max = 100, step = type == Variant::FLOAT ? .01 : 1;
- if (c >= 1) {
- if (!hint_text.get_slice(",", 0).is_empty()) {
- min = hint_text.get_slice(",", 0).to_float();
- }
- }
- if (c >= 2) {
- if (!hint_text.get_slice(",", 1).is_empty()) {
- max = hint_text.get_slice(",", 1).to_float();
- }
- }
-
- if (c >= 3) {
- if (!hint_text.get_slice(",", 2).is_empty()) {
- step = hint_text.get_slice(",", 2).to_float();
- }
- }
-
- if (c >= 4 && hint_text.get_slice(",", 3) == "slider") {
- slider->set_min(min);
- slider->set_max(max);
- slider->set_step(step);
- slider->set_value(v);
- slider->show();
- set_size(Size2(110, 30) * EDSCALE);
- } else {
- spinbox->set_min(min);
- spinbox->set_max(max);
- spinbox->set_step(step);
- spinbox->set_value(v);
- spinbox->show();
- set_size(Size2(70, 35) * EDSCALE);
- }
-
- } else if (hint == PROPERTY_HINT_ENUM) {
- Vector<String> options = hint_text.split(",");
- int current_val = 0;
- for (int i = 0; i < options.size(); i++) {
- Vector<String> text_split = options[i].split(":");
- if (text_split.size() != 1) {
- current_val = text_split[1].to_int();
- }
- menu->add_item(text_split[0]);
- menu->set_item_metadata(i, current_val);
- current_val += 1;
- }
- menu->set_position(get_position());
- menu->popup();
- hide();
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_LAYERS_2D_PHYSICS ||
- hint == PROPERTY_HINT_LAYERS_2D_RENDER ||
- hint == PROPERTY_HINT_LAYERS_2D_NAVIGATION ||
- hint == PROPERTY_HINT_LAYERS_3D_PHYSICS ||
- hint == PROPERTY_HINT_LAYERS_3D_RENDER ||
- hint == PROPERTY_HINT_LAYERS_3D_NAVIGATION) {
- String basename;
- switch (hint) {
- case PROPERTY_HINT_LAYERS_2D_RENDER:
- basename = "layer_names/2d_render";
- break;
- case PROPERTY_HINT_LAYERS_2D_PHYSICS:
- basename = "layer_names/2d_physics";
- break;
- case PROPERTY_HINT_LAYERS_2D_NAVIGATION:
- basename = "layer_names/2d_navigation";
- break;
- case PROPERTY_HINT_LAYERS_3D_RENDER:
- basename = "layer_names/3d_render";
- break;
- case PROPERTY_HINT_LAYERS_3D_PHYSICS:
- basename = "layer_names/3d_physics";
- break;
- case PROPERTY_HINT_LAYERS_3D_NAVIGATION:
- basename = "layer_names/3d_navigation";
- break;
- }
-
- checks20gc->show();
- uint32_t flgs = v;
- for (int i = 0; i < 2; i++) {
- Point2 ofs(4, 4);
- ofs.y += 22 * i;
- for (int j = 0; j < 10; j++) {
- int idx = i * 10 + j;
- CheckBox *c = checks20[idx];
- c->set_text(ProjectSettings::get_singleton()->get(basename + "/layer_" + itos(idx + 1)));
- c->set_pressed(flgs & (1 << (i * 10 + j)));
- c->show();
- }
- }
-
- show();
-
- checks20gc->set_position(Vector2(4, 4) * EDSCALE);
- checks20gc->set_size(checks20gc->get_minimum_size());
-
- set_size(Vector2(4, 4) * EDSCALE + checks20gc->get_position() + checks20gc->get_size());
-
- } else if (hint == PROPERTY_HINT_EXP_EASING) {
- easing_draw->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 5 * EDSCALE);
- easing_draw->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -5 * EDSCALE);
- easing_draw->set_anchor_and_offset(SIDE_TOP, Control::ANCHOR_BEGIN, 5 * EDSCALE);
- easing_draw->set_anchor_and_offset(SIDE_BOTTOM, Control::ANCHOR_END, -30 * EDSCALE);
- type_button->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 3 * EDSCALE);
- type_button->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -3 * EDSCALE);
- type_button->set_anchor_and_offset(SIDE_TOP, Control::ANCHOR_END, -25 * EDSCALE);
- type_button->set_anchor_and_offset(SIDE_BOTTOM, Control::ANCHOR_END, -7 * EDSCALE);
- type_button->set_text(TTR("Preset..."));
- type_button->get_popup()->clear();
- type_button->get_popup()->add_item(TTR("Linear"), EASING_LINEAR);
- type_button->get_popup()->add_item(TTR("Ease In"), EASING_EASE_IN);
- type_button->get_popup()->add_item(TTR("Ease Out"), EASING_EASE_OUT);
- if (hint_text != "attenuation") {
- type_button->get_popup()->add_item(TTR("Zero"), EASING_ZERO);
- type_button->get_popup()->add_item(TTR("Ease In-Out"), EASING_IN_OUT);
- type_button->get_popup()->add_item(TTR("Ease Out-In"), EASING_OUT_IN);
- }
-
- type_button->show();
- easing_draw->show();
- set_size(Size2(200, 150) * EDSCALE);
- } else if (hint == PROPERTY_HINT_FLAGS) {
- Vector<String> flags = hint_text.split(",");
- uint32_t value = v;
- for (int i = 0; i < flags.size(); i++) {
- uint32_t current_val;
- Vector<String> text_split = flags[i].split(":");
- if (text_split.size() != 1) {
- current_val = text_split[1].to_int();
- } else {
- current_val = 1 << i;
- }
- menu->add_check_item(text_split[0], current_val);
- menu->set_item_metadata(i, current_val);
- if ((value & current_val) == current_val) {
- menu->set_item_checked(menu->get_item_index(current_val), true);
- }
- }
- menu->set_position(get_position());
- menu->popup();
- hide();
- updating = false;
- return false;
-
- } else {
- List<String> names;
- names.push_back("value:");
- config_value_editors(1, 1, 50, names);
- value_editor[0]->set_text(TS->format_number(String::num(v)));
- }
-
- } break;
- case Variant::STRING: {
- if (hint == PROPERTY_HINT_LOCALE_ID) {
- List<String> names;
- names.push_back(TTR("Locale..."));
- names.push_back(TTR("Clear"));
- config_action_buttons(names);
- } else if (hint == PROPERTY_HINT_FILE || hint == PROPERTY_HINT_GLOBAL_FILE) {
- List<String> names;
- names.push_back(TTR("File..."));
- names.push_back(TTR("Clear"));
- config_action_buttons(names);
- } else if (hint == PROPERTY_HINT_DIR || hint == PROPERTY_HINT_GLOBAL_DIR) {
- List<String> names;
- names.push_back(TTR("Dir..."));
- names.push_back(TTR("Clear"));
- config_action_buttons(names);
- } else if (hint == PROPERTY_HINT_ENUM) {
- Vector<String> options = hint_text.split(",");
- for (int i = 0; i < options.size(); i++) {
- menu->add_item(options[i], i);
- }
- menu->set_position(get_position());
- menu->popup();
- hide();
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_MULTILINE_TEXT) {
- text_edit->show();
- text_edit->set_text(v);
- text_edit->deselect();
-
- int button_margin = text_edit->get_theme_constant(SNAME("button_margin"), SNAME("Dialogs"));
- int margin = text_edit->get_theme_constant(SNAME("margin"), SNAME("Dialogs"));
-
- action_buttons[0]->set_anchor(SIDE_LEFT, Control::ANCHOR_END);
- action_buttons[0]->set_anchor(SIDE_TOP, Control::ANCHOR_END);
- action_buttons[0]->set_anchor(SIDE_RIGHT, Control::ANCHOR_END);
- action_buttons[0]->set_anchor(SIDE_BOTTOM, Control::ANCHOR_END);
- action_buttons[0]->set_begin(Point2(-70 * EDSCALE, -button_margin + 5 * EDSCALE));
- action_buttons[0]->set_end(Point2(-margin, -margin));
- action_buttons[0]->set_text(TTR("Close"));
- action_buttons[0]->show();
-
- } else if (hint == PROPERTY_HINT_TYPE_STRING) {
- if (!create_dialog) {
- create_dialog = memnew(CreateDialog);
- create_dialog->connect("create", callable_mp(this, &CustomPropertyEditor::_create_dialog_callback));
- add_child(create_dialog);
- }
-
- if (!hint_text.is_empty()) {
- create_dialog->set_base_type(hint_text);
- } else {
- create_dialog->set_base_type("Object");
- }
-
- create_dialog->popup_create(false);
- hide();
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_METHOD_OF_VARIANT_TYPE) {
-#define MAKE_PROPSELECT \
- if (!property_select) { \
- property_select = memnew(PropertySelector); \
- property_select->connect("selected", callable_mp(this, &CustomPropertyEditor::_create_selected_property)); \
- add_child(property_select); \
- } \
- hide();
-
- MAKE_PROPSELECT;
-
- Variant::Type type = Variant::NIL;
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- if (hint_text == Variant::get_type_name(Variant::Type(i))) {
- type = Variant::Type(i);
- }
- }
- if (type != Variant::NIL) {
- property_select->select_method_from_basic_type(type, v);
- }
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_METHOD_OF_BASE_TYPE) {
- MAKE_PROPSELECT
-
- property_select->select_method_from_base_type(hint_text, v);
-
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_METHOD_OF_INSTANCE) {
- MAKE_PROPSELECT
-
- Object *instance = ObjectDB::get_instance(ObjectID(hint_text.to_int()));
- if (instance) {
- property_select->select_method_from_instance(instance, v);
- }
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_METHOD_OF_SCRIPT) {
- MAKE_PROPSELECT
-
- Object *obj = ObjectDB::get_instance(ObjectID(hint_text.to_int()));
- if (Object::cast_to<Script>(obj)) {
- property_select->select_method_from_script(Object::cast_to<Script>(obj), v);
- }
-
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE) {
- MAKE_PROPSELECT
- Variant::Type type = Variant::NIL;
- String tname = hint_text;
- if (tname.contains(".")) {
- tname = tname.get_slice(".", 0);
- }
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- if (tname == Variant::get_type_name(Variant::Type(i))) {
- type = Variant::Type(Variant::Type(i));
- }
- }
-
- if (type != Variant::NIL) {
- property_select->select_property_from_basic_type(type, v);
- }
-
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_PROPERTY_OF_BASE_TYPE) {
- MAKE_PROPSELECT
-
- property_select->select_property_from_base_type(hint_text, v);
-
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_PROPERTY_OF_INSTANCE) {
- MAKE_PROPSELECT
-
- Object *instance = ObjectDB::get_instance(ObjectID(hint_text.to_int()));
- if (instance) {
- property_select->select_property_from_instance(instance, v);
- }
-
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_PROPERTY_OF_SCRIPT) {
- MAKE_PROPSELECT
-
- Object *obj = ObjectDB::get_instance(ObjectID(hint_text.to_int()));
- if (Object::cast_to<Script>(obj)) {
- property_select->select_property_from_script(Object::cast_to<Script>(obj), v);
- }
-
- updating = false;
- return false;
-
- } else {
- List<String> names;
- names.push_back("string:");
- config_value_editors(1, 1, 50, names);
- value_editor[0]->set_text(v);
- }
-
- } break;
- case Variant::VECTOR2: {
- field_names.push_back("x");
- field_names.push_back("y");
- config_value_editors(2, 2, 10, field_names);
- Vector2 vec = v;
- value_editor[0]->set_text(String::num(vec.x));
- value_editor[1]->set_text(String::num(vec.y));
- } break;
- case Variant::RECT2: {
- field_names.push_back("x");
- field_names.push_back("y");
- field_names.push_back("w");
- field_names.push_back("h");
- config_value_editors(4, 4, 10, field_names);
- Rect2 r = v;
- value_editor[0]->set_text(String::num(r.position.x));
- value_editor[1]->set_text(String::num(r.position.y));
- value_editor[2]->set_text(String::num(r.size.x));
- value_editor[3]->set_text(String::num(r.size.y));
- } break;
- case Variant::VECTOR3: {
- field_names.push_back("x");
- field_names.push_back("y");
- field_names.push_back("z");
- config_value_editors(3, 3, 10, field_names);
- Vector3 vec = v;
- value_editor[0]->set_text(String::num(vec.x));
- value_editor[1]->set_text(String::num(vec.y));
- value_editor[2]->set_text(String::num(vec.z));
- } break;
- case Variant::PLANE: {
- field_names.push_back("x");
- field_names.push_back("y");
- field_names.push_back("z");
- field_names.push_back("d");
- config_value_editors(4, 4, 10, field_names);
- Plane plane = v;
- value_editor[0]->set_text(String::num(plane.normal.x));
- value_editor[1]->set_text(String::num(plane.normal.y));
- value_editor[2]->set_text(String::num(plane.normal.z));
- value_editor[3]->set_text(String::num(plane.d));
-
- } break;
- case Variant::QUATERNION: {
- field_names.push_back("x");
- field_names.push_back("y");
- field_names.push_back("z");
- field_names.push_back("w");
- config_value_editors(4, 4, 10, field_names);
- Quaternion q = v;
- value_editor[0]->set_text(String::num(q.x));
- value_editor[1]->set_text(String::num(q.y));
- value_editor[2]->set_text(String::num(q.z));
- value_editor[3]->set_text(String::num(q.w));
-
- } break;
- case Variant::AABB: {
- field_names.push_back("px");
- field_names.push_back("py");
- field_names.push_back("pz");
- field_names.push_back("sx");
- field_names.push_back("sy");
- field_names.push_back("sz");
- config_value_editors(6, 3, 16, field_names);
-
- AABB aabb = v;
- value_editor[0]->set_text(String::num(aabb.position.x));
- value_editor[1]->set_text(String::num(aabb.position.y));
- value_editor[2]->set_text(String::num(aabb.position.z));
- value_editor[3]->set_text(String::num(aabb.size.x));
- value_editor[4]->set_text(String::num(aabb.size.y));
- value_editor[5]->set_text(String::num(aabb.size.z));
-
- } break;
- case Variant::TRANSFORM2D: {
- field_names.push_back("xx");
- field_names.push_back("xy");
- field_names.push_back("yx");
- field_names.push_back("yy");
- field_names.push_back("ox");
- field_names.push_back("oy");
- config_value_editors(6, 2, 16, field_names);
-
- Transform2D basis = v;
- for (int i = 0; i < 6; i++) {
- value_editor[i]->set_text(String::num(basis.columns[i / 2][i % 2]));
- }
-
- } break;
- case Variant::BASIS: {
- field_names.push_back("xx");
- field_names.push_back("xy");
- field_names.push_back("xz");
- field_names.push_back("yx");
- field_names.push_back("yy");
- field_names.push_back("yz");
- field_names.push_back("zx");
- field_names.push_back("zy");
- field_names.push_back("zz");
- config_value_editors(9, 3, 16, field_names);
-
- Basis basis = v;
- for (int i = 0; i < 9; i++) {
- value_editor[i]->set_text(String::num(basis.rows[i / 3][i % 3]));
- }
-
- } break;
- case Variant::TRANSFORM3D: {
- field_names.push_back("xx");
- field_names.push_back("xy");
- field_names.push_back("xz");
- field_names.push_back("xo");
- field_names.push_back("yx");
- field_names.push_back("yy");
- field_names.push_back("yz");
- field_names.push_back("yo");
- field_names.push_back("zx");
- field_names.push_back("zy");
- field_names.push_back("zz");
- field_names.push_back("zo");
- config_value_editors(12, 4, 16, field_names);
-
- Transform3D tr = v;
- for (int i = 0; i < 9; i++) {
- value_editor[(i / 3) * 4 + i % 3]->set_text(String::num(tr.basis.rows[i / 3][i % 3]));
- }
-
- value_editor[3]->set_text(String::num(tr.origin.x));
- value_editor[7]->set_text(String::num(tr.origin.y));
- value_editor[11]->set_text(String::num(tr.origin.z));
-
- } break;
- case Variant::COLOR: {
- if (!color_picker) {
- //late init for performance
- color_picker = memnew(ColorPicker);
- color_picker->set_deferred_mode(true);
- value_vbox->add_child(color_picker);
- color_picker->hide();
- color_picker->connect("color_changed", callable_mp(this, &CustomPropertyEditor::_color_changed));
- color_picker->connect("show", callable_mp(EditorNode::get_singleton(), &EditorNode::setup_color_picker).bind(color_picker));
- }
-
- color_picker->show();
- color_picker->set_edit_alpha(hint != PROPERTY_HINT_COLOR_NO_ALPHA);
- color_picker->set_pick_color(v);
- color_picker->set_focus_on_line_edit();
-
- } break;
-
- case Variant::NODE_PATH: {
- List<String> names;
- names.push_back(TTR("Assign"));
- names.push_back(TTR("Clear"));
-
- if (owner && owner->is_class("Node") && (v.get_type() == Variant::NODE_PATH) && Object::cast_to<Node>(owner)->has_node(v)) {
- names.push_back(TTR("Select Node"));
- }
-
- config_action_buttons(names);
-
- } break;
- case Variant::OBJECT: {
- if (hint != PROPERTY_HINT_RESOURCE_TYPE) {
- break;
- }
-
- if (p_name == "script" && hint_text == "Script" && Object::cast_to<Node>(owner)) {
- menu->add_item(TTR("New Script"), OBJ_MENU_NEW_SCRIPT);
- menu->add_separator();
- } else if (!hint_text.is_empty()) {
- int idx = 0;
-
- Vector<EditorData::CustomType> custom_resources;
-
- if (EditorNode::get_editor_data().get_custom_types().has("Resource")) {
- custom_resources = EditorNode::get_editor_data().get_custom_types()["Resource"];
- }
-
- for (int i = 0; i < hint_text.get_slice_count(","); i++) {
- String base = hint_text.get_slice(",", i);
-
- HashSet<String> valid_inheritors;
- valid_inheritors.insert(base);
- List<StringName> inheritors;
- ClassDB::get_inheriters_from_class(base.strip_edges(), &inheritors);
-
- for (int j = 0; j < custom_resources.size(); j++) {
- inheritors.push_back(custom_resources[j].name);
- }
-
- List<StringName>::Element *E = inheritors.front();
- while (E) {
- valid_inheritors.insert(E->get());
- E = E->next();
- }
-
- for (const String &j : valid_inheritors) {
- const String &t = j;
-
- bool is_custom_resource = false;
- Ref<Texture2D> icon;
- if (!custom_resources.is_empty()) {
- for (int k = 0; k < custom_resources.size(); k++) {
- if (custom_resources[k].name == t) {
- is_custom_resource = true;
- if (custom_resources[k].icon.is_valid()) {
- icon = custom_resources[k].icon;
- }
- break;
- }
- }
- }
-
- if (!is_custom_resource && (!ClassDB::can_instantiate(t) || ClassDB::is_virtual(t))) {
- continue;
- }
-
- inheritors_array.push_back(t);
-
- int id = TYPE_BASE_ID + idx;
-
- menu->add_item(vformat(TTR("New %s"), t), id);
-
- idx++;
- }
- }
-
- if (menu->get_item_count()) {
- menu->add_separator();
- }
- }
-
- menu->add_item(TTR("Load"), OBJ_MENU_LOAD);
-
- if (!Ref<Resource>(v).is_null()) {
- menu->add_item(TTR("Edit"), OBJ_MENU_EDIT);
- menu->add_item(TTR("Clear"), OBJ_MENU_CLEAR);
- menu->add_item(TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE);
-
- Ref<Resource> r = v;
- if (r.is_valid() && r->get_path().is_resource_file()) {
- menu->add_separator();
- menu->add_item(TTR("Show in FileSystem"), OBJ_MENU_SHOW_IN_FILE_SYSTEM);
- }
- }
-
- Ref<Resource> cb = EditorSettings::get_singleton()->get_resource_clipboard();
- bool paste_valid = false;
- if (cb.is_valid()) {
- if (hint_text.is_empty()) {
- paste_valid = true;
- } else {
- for (int i = 0; i < hint_text.get_slice_count(","); i++) {
- if (ClassDB::is_parent_class(cb->get_class(), hint_text.get_slice(",", i))) {
- paste_valid = true;
- break;
- }
- }
- }
- }
-
- if (!Ref<Resource>(v).is_null() || paste_valid) {
- menu->add_separator();
-
- if (!Ref<Resource>(v).is_null()) {
- menu->add_item(TTR("Copy"), OBJ_MENU_COPY);
- }
-
- if (paste_valid) {
- menu->add_item(TTR("Paste"), OBJ_MENU_PASTE);
- }
- }
-
- if (!Ref<Resource>(v).is_null()) {
- Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(Ref<Resource>(v));
- if (conversions.size()) {
- menu->add_separator();
- }
- for (int i = 0; i < conversions.size(); i++) {
- String what = conversions[i]->converts_to();
- menu->add_item(vformat(TTR("Convert to %s"), what), CONVERT_BASE_ID + i);
- }
- }
-
- menu->set_position(get_position());
- menu->popup();
- hide();
- updating = false;
- return false;
- } break;
- case Variant::DICTIONARY: {
- } break;
- case Variant::PACKED_BYTE_ARRAY: {
- } break;
- case Variant::PACKED_INT32_ARRAY: {
- } break;
- case Variant::PACKED_FLOAT32_ARRAY: {
- } break;
- case Variant::PACKED_INT64_ARRAY: {
- } break;
- case Variant::PACKED_FLOAT64_ARRAY: {
- } break;
- case Variant::PACKED_STRING_ARRAY: {
- } break;
- case Variant::PACKED_VECTOR3_ARRAY: {
- } break;
- case Variant::PACKED_COLOR_ARRAY: {
- } break;
- default: {
- }
- }
-
- updating = false;
- return true;
-}
-
-void CustomPropertyEditor::_file_selected(String p_file) {
- switch (type) {
- case Variant::STRING: {
- if (hint == PROPERTY_HINT_FILE || hint == PROPERTY_HINT_DIR) {
- v = ProjectSettings::get_singleton()->localize_path(p_file);
- emit_signal(SNAME("variant_changed"));
- hide();
- }
-
- if (hint == PROPERTY_HINT_GLOBAL_FILE || hint == PROPERTY_HINT_GLOBAL_DIR) {
- v = p_file;
- emit_signal(SNAME("variant_changed"));
- hide();
- }
-
- } break;
- case Variant::OBJECT: {
- String type = (hint == PROPERTY_HINT_RESOURCE_TYPE) ? hint_text : String();
-
- Ref<Resource> res = ResourceLoader::load(p_file, type);
- if (res.is_null()) {
- error->set_text(TTR("Error loading file: Not a resource!"));
- error->popup_centered();
- break;
- }
- v = res;
- emit_signal(SNAME("variant_changed"));
- hide();
- } break;
- default: {
- }
- }
-}
-
-void CustomPropertyEditor::_locale_selected(String p_locale) {
- if (type == Variant::STRING && hint == PROPERTY_HINT_LOCALE_ID) {
- v = p_locale;
- emit_signal(SNAME("variant_changed"));
- hide();
- }
-}
-
-void CustomPropertyEditor::_type_create_selected(int p_idx) {
- if (type == Variant::INT || type == Variant::FLOAT) {
- float newval = 0;
- switch (p_idx) {
- case EASING_LINEAR: {
- newval = 1;
- } break;
- case EASING_EASE_IN: {
- newval = 2.0;
- } break;
- case EASING_EASE_OUT: {
- newval = 0.5;
- } break;
- case EASING_ZERO: {
- newval = 0;
- } break;
- case EASING_IN_OUT: {
- newval = -0.5;
- } break;
- case EASING_OUT_IN: {
- newval = -2.0;
- } break;
- }
-
- v = newval;
- emit_signal(SNAME("variant_changed"));
- easing_draw->update();
-
- } else if (type == Variant::OBJECT) {
- ERR_FAIL_INDEX(p_idx, inheritors_array.size());
-
- String intype = inheritors_array[p_idx];
-
- Variant obj = ClassDB::instantiate(intype);
-
- if (!obj) {
- if (ScriptServer::is_global_class(intype)) {
- obj = EditorNode::get_editor_data().script_class_instance(intype);
- } else {
- obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource");
- }
- }
-
- ERR_FAIL_COND(!obj);
- ERR_FAIL_COND(!Object::cast_to<Resource>(obj));
-
- EditorNode::get_editor_data().instantiate_object_properties(obj);
- v = obj;
-
- emit_signal(SNAME("variant_changed"));
- hide();
- }
-}
-
-void CustomPropertyEditor::_color_changed(const Color &p_color) {
- v = p_color;
- emit_signal(SNAME("variant_changed"));
-}
-
-void CustomPropertyEditor::_node_path_selected(NodePath p_path) {
- if (picking_viewport) {
- Node *to_node = get_node(p_path);
- if (!Object::cast_to<Viewport>(to_node)) {
- EditorNode::get_singleton()->show_warning(TTR("Selected node is not a Viewport!"));
- return;
- }
-
- Ref<ViewportTexture> vt;
- vt.instantiate();
- vt->set_viewport_path_in_scene(get_tree()->get_edited_scene_root()->get_path_to(to_node));
- vt->setup_local_to_scene();
- v = vt;
- emit_signal(SNAME("variant_changed"));
- return;
- }
-
- if (hint == PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE && !hint_text.is_empty()) {
- Node *node = get_node(hint_text);
- if (node) {
- Node *tonode = node->get_node(p_path);
- if (tonode) {
- p_path = node->get_path_to(tonode);
- }
- }
-
- } else if (owner) {
- Node *node = nullptr;
-
- if (owner->is_class("Node")) {
- node = Object::cast_to<Node>(owner);
- } else if (owner->is_class("ArrayPropertyEdit")) {
- node = Object::cast_to<ArrayPropertyEdit>(owner)->get_node();
- } else if (owner->is_class("DictionaryPropertyEdit")) {
- node = Object::cast_to<DictionaryPropertyEdit>(owner)->get_node();
- }
- if (!node) {
- v = p_path;
- emit_signal(SNAME("variant_changed"));
- call_deferred(SNAME("hide")); //to not mess with dialogs
- return;
- }
-
- Node *tonode = node->get_node(p_path);
- if (tonode) {
- p_path = node->get_path_to(tonode);
- }
- }
-
- v = p_path;
- emit_signal(SNAME("variant_changed"));
- call_deferred(SNAME("hide")); //to not mess with dialogs
-}
-
-void CustomPropertyEditor::_action_pressed(int p_which) {
- if (updating) {
- return;
- }
-
- switch (type) {
- case Variant::BOOL: {
- v = checks20[0]->is_pressed();
- emit_signal(SNAME("variant_changed"));
- } break;
- case Variant::INT: {
- if (hint == PROPERTY_HINT_LAYERS_2D_PHYSICS ||
- hint == PROPERTY_HINT_LAYERS_2D_RENDER ||
- hint == PROPERTY_HINT_LAYERS_2D_NAVIGATION ||
- hint == PROPERTY_HINT_LAYERS_3D_PHYSICS ||
- hint == PROPERTY_HINT_LAYERS_3D_RENDER ||
- hint == PROPERTY_HINT_LAYERS_3D_NAVIGATION) {
- uint32_t f = v;
- if (checks20[p_which]->is_pressed()) {
- f |= (1 << p_which);
- } else {
- f &= ~(1 << p_which);
- }
-
- v = f;
- emit_signal(SNAME("variant_changed"));
- }
-
- } break;
- case Variant::STRING: {
- if (hint == PROPERTY_HINT_MULTILINE_TEXT) {
- hide();
- } else if (hint == PROPERTY_HINT_LOCALE_ID) {
- locale->popup_locale_dialog();
- } else if (hint == PROPERTY_HINT_FILE || hint == PROPERTY_HINT_GLOBAL_FILE) {
- if (p_which == 0) {
- if (hint == PROPERTY_HINT_FILE) {
- file->set_access(EditorFileDialog::ACCESS_RESOURCES);
- } else {
- file->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
- }
-
- file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
- file->clear_filters();
-
- file->clear_filters();
-
- if (!hint_text.is_empty()) {
- Vector<String> extensions = hint_text.split(",");
- for (int i = 0; i < extensions.size(); i++) {
- String filter = extensions[i];
- if (filter.begins_with(".")) {
- filter = "*" + extensions[i];
- } else if (!filter.begins_with("*")) {
- filter = "*." + extensions[i];
- }
-
- file->add_filter(filter, extensions[i].to_upper());
- }
- }
- file->popup_file_dialog();
- } else {
- v = "";
- emit_signal(SNAME("variant_changed"));
- hide();
- }
-
- } else if (hint == PROPERTY_HINT_DIR || hint == PROPERTY_HINT_GLOBAL_DIR) {
- if (p_which == 0) {
- if (hint == PROPERTY_HINT_DIR) {
- file->set_access(EditorFileDialog::ACCESS_RESOURCES);
- } else {
- file->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
- }
- file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR);
- file->clear_filters();
- file->popup_file_dialog();
- } else {
- v = "";
- emit_signal(SNAME("variant_changed"));
- hide();
- }
- }
-
- } break;
- case Variant::NODE_PATH: {
- if (p_which == 0) {
- picking_viewport = false;
- scene_tree->set_title(TTR("Pick a Node"));
- scene_tree->popup_scenetree_dialog();
-
- } else if (p_which == 1) {
- v = NodePath();
- emit_signal(SNAME("variant_changed"));
- hide();
- } else if (p_which == 2) {
- if (owner->is_class("Node") && (v.get_type() == Variant::NODE_PATH) && Object::cast_to<Node>(owner)->has_node(v)) {
- Node *target_node = Object::cast_to<Node>(owner)->get_node(v);
- EditorNode::get_singleton()->get_editor_selection()->clear();
- SceneTreeDock::get_singleton()->set_selected(target_node);
- }
-
- hide();
- }
-
- } break;
- case Variant::OBJECT: {
- if (p_which == 0) {
- ERR_FAIL_COND(inheritors_array.is_empty());
-
- String intype = inheritors_array[0];
-
- if (hint == PROPERTY_HINT_RESOURCE_TYPE) {
- Variant obj = ClassDB::instantiate(intype);
-
- if (!obj) {
- if (ScriptServer::is_global_class(intype)) {
- obj = EditorNode::get_editor_data().script_class_instance(intype);
- } else {
- obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource");
- }
- }
-
- ERR_BREAK(!obj);
- ERR_BREAK(!Object::cast_to<Resource>(obj));
-
- EditorNode::get_editor_data().instantiate_object_properties(obj);
- v = obj;
-
- emit_signal(SNAME("variant_changed"));
- hide();
- }
- } else if (p_which == 1) {
- file->set_access(EditorFileDialog::ACCESS_RESOURCES);
- file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
- List<String> extensions;
- String type = (hint == PROPERTY_HINT_RESOURCE_TYPE) ? hint_text : String();
-
- ResourceLoader::get_recognized_extensions_for_type(type, &extensions);
- file->clear_filters();
- for (const String &E : extensions) {
- file->add_filter("*." + E, E.to_upper());
- }
-
- file->popup_file_dialog();
-
- } else if (p_which == 2) {
- Ref<Resource> r = v;
-
- if (!r.is_null()) {
- emit_signal(SNAME("resource_edit_request"));
- hide();
- }
-
- } else if (p_which == 3) {
- v = Variant();
- emit_signal(SNAME("variant_changed"));
- hide();
- } else if (p_which == 4) {
- Ref<Resource> res_orig = v;
- if (res_orig.is_null()) {
- return;
- }
-
- List<PropertyInfo> property_list;
- res_orig->get_property_list(&property_list);
- List<Pair<String, Variant>> propvalues;
-
- for (const PropertyInfo &pi : property_list) {
- Pair<String, Variant> p;
- if (pi.usage & PROPERTY_USAGE_STORAGE) {
- p.first = pi.name;
- p.second = res_orig->get(pi.name);
- }
-
- propvalues.push_back(p);
- }
-
- Ref<Resource> res = Ref<Resource>(ClassDB::instantiate(res_orig->get_class()));
-
- ERR_FAIL_COND(res.is_null());
-
- for (const Pair<String, Variant> &p : propvalues) {
- res->set(p.first, p.second);
- }
-
- v = res;
- emit_signal(SNAME("variant_changed"));
- hide();
- }
-
- } break;
-
- default: {
- };
- }
-}
-
-void CustomPropertyEditor::_drag_easing(const Ref<InputEvent> &p_ev) {
- Ref<InputEventMouseMotion> mm = p_ev;
-
- if (mm.is_valid() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
- float rel = mm->get_relative().x;
- if (rel == 0) {
- return;
- }
-
- bool flip = hint_text == "attenuation";
-
- if (flip) {
- rel = -rel;
- }
-
- float val = v;
- if (val == 0) {
- return;
- }
- bool sg = val < 0;
- val = Math::absf(val);
-
- val = Math::log(val) / Math::log((float)2.0);
- //logspace
- val += rel * 0.05;
-
- val = Math::pow(2.0f, val);
- if (sg) {
- val = -val;
- }
-
- v = val;
- easing_draw->update();
- emit_signal(SNAME("variant_changed"));
- }
-}
-
-void CustomPropertyEditor::_draw_easing() {
- RID ci = easing_draw->get_canvas_item();
-
- Size2 s = easing_draw->get_size();
- Rect2 r(Point2(), s);
- r = r.grow(3);
- easing_draw->get_theme_stylebox(SNAME("normal"), SNAME("LineEdit"))->draw(ci, r);
-
- int points = 48;
-
- float prev = 1.0;
- float exp = v;
- bool flip = hint_text == "attenuation";
-
- Ref<Font> f = easing_draw->get_theme_font(SNAME("font"), SNAME("Label"));
- int font_size = easing_draw->get_theme_font_size(SNAME("font_size"), SNAME("Label"));
- Color color = easing_draw->get_theme_color(SNAME("font_color"), SNAME("Label"));
-
- for (int i = 1; i <= points; i++) {
- float ifl = i / float(points);
- float iflp = (i - 1) / float(points);
-
- float h = 1.0 - Math::ease(ifl, exp);
-
- if (flip) {
- ifl = 1.0 - ifl;
- iflp = 1.0 - iflp;
- }
-
- RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2(iflp * s.width, prev * s.height), Point2(ifl * s.width, h * s.height), color);
- prev = h;
- }
-
- f->draw_string(ci, Point2(10, 10 + f->get_ascent(font_size)), String::num(exp, 2), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, color);
-}
-
-void CustomPropertyEditor::_text_edit_changed() {
- v = text_edit->get_text();
- emit_signal(SNAME("variant_changed"));
-}
-
-void CustomPropertyEditor::_create_dialog_callback() {
- v = create_dialog->get_selected_type();
- emit_signal(SNAME("variant_changed"));
-}
-
-void CustomPropertyEditor::_create_selected_property(const String &p_prop) {
- v = p_prop;
- emit_signal(SNAME("variant_changed"));
-}
-
-void CustomPropertyEditor::_modified(String p_string) {
- if (updating) {
- return;
- }
-
- Variant prev_v = v;
-
- updating = true;
- switch (type) {
- case Variant::INT: {
- String text = TS->parse_number(value_editor[0]->get_text());
- Ref<Expression> expr;
- expr.instantiate();
- Error err = expr->parse(text);
- if (err != OK) {
- v = value_editor[0]->get_text().to_int();
- return;
- } else {
- v = expr->execute(Array(), nullptr, false, false);
- }
-
- if (v != prev_v) {
- emit_signal(SNAME("variant_changed"));
- }
- } break;
- case Variant::FLOAT: {
- if (hint != PROPERTY_HINT_EXP_EASING) {
- String text = TS->parse_number(value_editor[0]->get_text());
- v = _parse_real_expression(text);
- if (v != prev_v) {
- emit_signal(SNAME("variant_changed"));
- }
- }
-
- } break;
- case Variant::STRING: {
- v = value_editor[0]->get_text();
- emit_signal(SNAME("variant_changed"));
- } break;
- case Variant::VECTOR2: {
- Vector2 vec;
- vec.x = _parse_real_expression(value_editor[0]->get_text());
- vec.y = _parse_real_expression(value_editor[1]->get_text());
- v = vec;
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
- case Variant::RECT2: {
- Rect2 r2;
-
- r2.position.x = _parse_real_expression(value_editor[0]->get_text());
- r2.position.y = _parse_real_expression(value_editor[1]->get_text());
- r2.size.x = _parse_real_expression(value_editor[2]->get_text());
- r2.size.y = _parse_real_expression(value_editor[3]->get_text());
- v = r2;
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
-
- case Variant::VECTOR3: {
- Vector3 vec;
- vec.x = _parse_real_expression(value_editor[0]->get_text());
- vec.y = _parse_real_expression(value_editor[1]->get_text());
- vec.z = _parse_real_expression(value_editor[2]->get_text());
- v = vec;
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
- case Variant::PLANE: {
- Plane pl;
- pl.normal.x = _parse_real_expression(value_editor[0]->get_text());
- pl.normal.y = _parse_real_expression(value_editor[1]->get_text());
- pl.normal.z = _parse_real_expression(value_editor[2]->get_text());
- pl.d = _parse_real_expression(value_editor[3]->get_text());
- v = pl;
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
- case Variant::QUATERNION: {
- Quaternion q;
- q.x = _parse_real_expression(value_editor[0]->get_text());
- q.y = _parse_real_expression(value_editor[1]->get_text());
- q.z = _parse_real_expression(value_editor[2]->get_text());
- q.w = _parse_real_expression(value_editor[3]->get_text());
- v = q;
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
- case Variant::AABB: {
- Vector3 pos;
- Vector3 size;
-
- pos.x = _parse_real_expression(value_editor[0]->get_text());
- pos.y = _parse_real_expression(value_editor[1]->get_text());
- pos.z = _parse_real_expression(value_editor[2]->get_text());
- size.x = _parse_real_expression(value_editor[3]->get_text());
- size.y = _parse_real_expression(value_editor[4]->get_text());
- size.z = _parse_real_expression(value_editor[5]->get_text());
- v = AABB(pos, size);
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
- case Variant::TRANSFORM2D: {
- Transform2D m;
- for (int i = 0; i < 6; i++) {
- m.columns[i / 2][i % 2] = _parse_real_expression(value_editor[i]->get_text());
- }
-
- v = m;
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
- case Variant::BASIS: {
- Basis m;
- for (int i = 0; i < 9; i++) {
- m.rows[i / 3][i % 3] = _parse_real_expression(value_editor[i]->get_text());
- }
-
- v = m;
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
- case Variant::TRANSFORM3D: {
- Basis basis;
- for (int i = 0; i < 9; i++) {
- basis.rows[i / 3][i % 3] = _parse_real_expression(value_editor[(i / 3) * 4 + i % 3]->get_text());
- }
-
- Vector3 origin;
-
- origin.x = _parse_real_expression(value_editor[3]->get_text());
- origin.y = _parse_real_expression(value_editor[7]->get_text());
- origin.z = _parse_real_expression(value_editor[11]->get_text());
-
- v = Transform3D(basis, origin);
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
- case Variant::COLOR: {
- } break;
-
- case Variant::NODE_PATH: {
- v = NodePath(value_editor[0]->get_text());
- if (v != prev_v) {
- emit_signal(SNAME("variant_changed"));
- }
- } break;
- case Variant::DICTIONARY: {
- } break;
- case Variant::PACKED_BYTE_ARRAY: {
- } break;
- case Variant::PACKED_INT32_ARRAY: {
- } break;
- case Variant::PACKED_FLOAT32_ARRAY: {
- } break;
- case Variant::PACKED_STRING_ARRAY: {
- } break;
- case Variant::PACKED_VECTOR3_ARRAY: {
- } break;
- case Variant::PACKED_COLOR_ARRAY: {
- } break;
- default: {
- }
- }
-
- updating = false;
-}
-
-real_t CustomPropertyEditor::_parse_real_expression(String text) {
- Ref<Expression> expr;
- expr.instantiate();
- Error err = expr->parse(text);
- real_t out;
- if (err != OK) {
- out = value_editor[0]->get_text().to_float();
- } else {
- out = expr->execute(Array(), nullptr, false, true);
- }
- return out;
-}
-
-void CustomPropertyEditor::_emit_changed_whole_or_field() {
- if (!Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
- emit_signal(SNAME("variant_changed"));
- } else {
- emit_signal(SNAME("variant_field_changed"), field_names[focused_value_editor]);
- }
-}
-
-void CustomPropertyEditor::_range_modified(double p_value) {
- v = p_value;
- emit_signal(SNAME("variant_changed"));
-}
-
-void CustomPropertyEditor::_focus_enter() {
- switch (type) {
- case Variant::FLOAT:
- case Variant::STRING:
- case Variant::VECTOR2:
- case Variant::RECT2:
- case Variant::VECTOR3:
- case Variant::PLANE:
- case Variant::QUATERNION:
- case Variant::AABB:
- case Variant::TRANSFORM2D:
- case Variant::BASIS:
- case Variant::TRANSFORM3D: {
- for (int i = 0; i < MAX_VALUE_EDITORS; ++i) {
- if (value_editor[i]->has_focus()) {
- focused_value_editor = i;
- value_editor[i]->select_all();
- break;
- }
- }
- } break;
- default: {
- }
- }
-}
-
-void CustomPropertyEditor::_focus_exit() {
- _modified(String());
-}
-
-void CustomPropertyEditor::config_action_buttons(const List<String> &p_strings) {
- Ref<StyleBox> sb = action_buttons[0]->get_theme_stylebox(SNAME("button"));
- int margin_top = sb->get_margin(SIDE_TOP);
- int margin_left = sb->get_margin(SIDE_LEFT);
- int margin_bottom = sb->get_margin(SIDE_BOTTOM);
- int margin_right = sb->get_margin(SIDE_RIGHT);
-
- int max_width = 0;
- int height = 0;
-
- for (int i = 0; i < MAX_ACTION_BUTTONS; i++) {
- if (i < p_strings.size()) {
- action_buttons[i]->show();
- action_buttons[i]->set_text(p_strings[i]);
-
- Size2 btn_m_size = action_buttons[i]->get_minimum_size();
- if (btn_m_size.width > max_width) {
- max_width = btn_m_size.width;
- }
-
- } else {
- action_buttons[i]->hide();
- }
- }
-
- for (int i = 0; i < p_strings.size(); i++) {
- Size2 btn_m_size = action_buttons[i]->get_size();
- action_buttons[i]->set_position(Point2(0, height) + Point2(margin_left, margin_top));
- action_buttons[i]->set_size(Size2(max_width, btn_m_size.height));
-
- height += btn_m_size.height;
- }
- set_size(Size2(max_width, height) + Size2(margin_left + margin_right, margin_top + margin_bottom));
-}
-
-void CustomPropertyEditor::config_value_editors(int p_amount, int p_columns, int p_label_w, const List<String> &p_strings) {
- int cell_width = 95;
- int cell_height = 25;
- int cell_margin = 5;
- int rows = ((p_amount - 1) / p_columns) + 1;
-
- set_size(Size2(cell_margin + p_label_w + (cell_width + cell_margin + p_label_w) * p_columns, cell_margin + (cell_height + cell_margin) * rows) * EDSCALE);
-
- for (int i = 0; i < MAX_VALUE_EDITORS; i++) {
- value_label[i]->get_parent()->remove_child(value_label[i]);
- value_editor[i]->get_parent()->remove_child(value_editor[i]);
-
- int box_id = i / p_columns;
- value_hboxes[box_id]->add_child(value_label[i]);
- value_hboxes[box_id]->add_child(value_editor[i]);
-
- if (i < MAX_VALUE_EDITORS / 4) {
- if (i <= p_amount / 4) {
- value_hboxes[i]->show();
- } else {
- value_hboxes[i]->hide();
- }
- }
-
- if (i < p_amount) {
- value_editor[i]->show();
- value_label[i]->show();
- value_label[i]->set_text(i < p_strings.size() ? p_strings[i] : String(""));
- value_editor[i]->set_editable(!read_only);
- } else {
- value_editor[i]->hide();
- value_label[i]->hide();
- }
- }
-}
-
-void CustomPropertyEditor::_bind_methods() {
- ADD_SIGNAL(MethodInfo("variant_changed"));
- ADD_SIGNAL(MethodInfo("variant_field_changed", PropertyInfo(Variant::STRING, "field")));
- ADD_SIGNAL(MethodInfo("resource_edit_request"));
-}
-
-CustomPropertyEditor::CustomPropertyEditor() {
- value_vbox = memnew(VBoxContainer);
- add_child(value_vbox);
-
- for (int i = 0; i < MAX_VALUE_EDITORS; i++) {
- if (i < MAX_VALUE_EDITORS / 4) {
- value_hboxes[i] = memnew(HBoxContainer);
- value_vbox->add_child(value_hboxes[i]);
- value_hboxes[i]->hide();
- }
- int hbox_idx = i / 4;
- value_label[i] = memnew(Label);
- value_hboxes[hbox_idx]->add_child(value_label[i]);
- value_label[i]->hide();
- value_editor[i] = memnew(LineEdit);
- value_hboxes[hbox_idx]->add_child(value_editor[i]);
- value_editor[i]->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- value_editor[i]->hide();
- value_editor[i]->connect("text_submitted", callable_mp(this, &CustomPropertyEditor::_modified));
- value_editor[i]->connect("focus_entered", callable_mp(this, &CustomPropertyEditor::_focus_enter));
- value_editor[i]->connect("focus_exited", callable_mp(this, &CustomPropertyEditor::_focus_exit));
- }
- focused_value_editor = -1;
-
- for (int i = 0; i < 4; i++) {
- scroll[i] = memnew(HScrollBar);
- scroll[i]->hide();
- scroll[i]->set_min(0);
- scroll[i]->set_max(1.0);
- scroll[i]->set_step(0.01);
- add_child(scroll[i]);
- }
-
- checks20gc = memnew(GridContainer);
- add_child(checks20gc);
- checks20gc->set_columns(11);
-
- for (int i = 0; i < 20; i++) {
- if (i == 5 || i == 15) {
- Control *space = memnew(Control);
- space->set_custom_minimum_size(Size2(20, 0) * EDSCALE);
- checks20gc->add_child(space);
- }
-
- checks20[i] = memnew(CheckBox);
- checks20[i]->set_toggle_mode(true);
- checks20[i]->set_focus_mode(Control::FOCUS_NONE);
- checks20gc->add_child(checks20[i]);
- checks20[i]->hide();
- checks20[i]->connect("pressed", callable_mp(this, &CustomPropertyEditor::_action_pressed).bind(i));
- checks20[i]->set_tooltip(vformat(TTR("Bit %d, val %d."), i, 1 << i));
- }
-
- text_edit = memnew(TextEdit);
- value_vbox->add_child(text_edit);
- text_edit->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 5);
- text_edit->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- text_edit->set_offset(SIDE_BOTTOM, -30);
-
- text_edit->hide();
- text_edit->connect("text_changed", callable_mp(this, &CustomPropertyEditor::_text_edit_changed));
-
- color_picker = nullptr;
-
- file = memnew(EditorFileDialog);
- value_vbox->add_child(file);
- file->hide();
-
- file->connect("file_selected", callable_mp(this, &CustomPropertyEditor::_file_selected));
- file->connect("dir_selected", callable_mp(this, &CustomPropertyEditor::_file_selected));
-
- locale = memnew(EditorLocaleDialog);
- value_vbox->add_child(locale);
- locale->hide();
-
- locale->connect("locale_selected", callable_mp(this, &CustomPropertyEditor::_locale_selected));
-
- error = memnew(ConfirmationDialog);
- error->set_title(TTR("Error!"));
- value_vbox->add_child(error);
-
- scene_tree = memnew(SceneTreeDialog);
- value_vbox->add_child(scene_tree);
- scene_tree->connect("selected", callable_mp(this, &CustomPropertyEditor::_node_path_selected));
- scene_tree->get_scene_tree()->set_show_enabled_subscene(true);
-
- texture_preview = memnew(TextureRect);
- value_vbox->add_child(texture_preview);
- texture_preview->hide();
-
- easing_draw = memnew(Control);
- value_vbox->add_child(easing_draw);
- easing_draw->hide();
- easing_draw->connect("draw", callable_mp(this, &CustomPropertyEditor::_draw_easing));
- easing_draw->connect("gui_input", callable_mp(this, &CustomPropertyEditor::_drag_easing));
- easing_draw->set_default_cursor_shape(Control::CURSOR_MOVE);
-
- type_button = memnew(MenuButton);
- value_vbox->add_child(type_button);
- type_button->hide();
- type_button->get_popup()->connect("id_pressed", callable_mp(this, &CustomPropertyEditor::_type_create_selected));
-
- menu = memnew(PopupMenu);
- // menu->set_pass_on_modal_close_click(false);
- value_vbox->add_child(menu);
- menu->connect("id_pressed", callable_mp(this, &CustomPropertyEditor::_menu_option));
-
- evaluator = nullptr;
-
- spinbox = memnew(SpinBox);
- value_vbox->add_child(spinbox);
- spinbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 5);
- spinbox->connect("value_changed", callable_mp(this, &CustomPropertyEditor::_range_modified));
-
- slider = memnew(HSlider);
- value_vbox->add_child(slider);
- slider->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 5);
- slider->connect("value_changed", callable_mp(this, &CustomPropertyEditor::_range_modified));
-
- action_hboxes = memnew(HBoxContainer);
- action_hboxes->set_alignment(BoxContainer::ALIGNMENT_CENTER);
- value_vbox->add_child(action_hboxes);
- for (int i = 0; i < MAX_ACTION_BUTTONS; i++) {
- action_buttons[i] = memnew(Button);
- action_buttons[i]->hide();
- action_hboxes->add_child(action_buttons[i]);
- action_buttons[i]->connect("pressed", callable_mp(this, &CustomPropertyEditor::_action_pressed).bind(i));
- }
-
- create_dialog = nullptr;
- property_select = nullptr;
-}
diff --git a/editor/property_editor.h b/editor/property_editor.h
deleted file mode 100644
index 195eb89b81..0000000000
--- a/editor/property_editor.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*************************************************************************/
-/* property_editor.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef PROPERTY_EDITOR_H
-#define PROPERTY_EDITOR_H
-
-#include "editor/editor_locale_dialog.h"
-#include "editor/scene_tree_editor.h"
-#include "scene/gui/button.h"
-#include "scene/gui/check_box.h"
-#include "scene/gui/check_button.h"
-#include "scene/gui/color_picker.h"
-#include "scene/gui/dialogs.h"
-#include "scene/gui/grid_container.h"
-#include "scene/gui/label.h"
-#include "scene/gui/menu_button.h"
-#include "scene/gui/split_container.h"
-#include "scene/gui/text_edit.h"
-#include "scene/gui/texture_rect.h"
-#include "scene/gui/tree.h"
-
-class CreateDialog;
-class EditorFileDialog;
-class PropertyValueEvaluator;
-class PropertySelector;
-
-class CustomPropertyEditor : public PopupPanel {
- GDCLASS(CustomPropertyEditor, PopupPanel);
-
- enum {
- MAX_VALUE_EDITORS = 12,
- MAX_ACTION_BUTTONS = 5,
- OBJ_MENU_LOAD = 0,
- OBJ_MENU_EDIT = 1,
- OBJ_MENU_CLEAR = 2,
- OBJ_MENU_MAKE_UNIQUE = 3,
- OBJ_MENU_COPY = 4,
- OBJ_MENU_PASTE = 5,
- OBJ_MENU_NEW_SCRIPT = 6,
- OBJ_MENU_EXTEND_SCRIPT = 7,
- OBJ_MENU_SHOW_IN_FILE_SYSTEM = 8,
- TYPE_BASE_ID = 100,
- CONVERT_BASE_ID = 1000
- };
-
- enum {
- EASING_LINEAR,
- EASING_EASE_IN,
- EASING_EASE_OUT,
- EASING_ZERO,
- EASING_IN_OUT,
- EASING_OUT_IN
- };
-
- PopupMenu *menu = nullptr;
- SceneTreeDialog *scene_tree = nullptr;
- EditorFileDialog *file = nullptr;
- EditorLocaleDialog *locale = nullptr;
- ConfirmationDialog *error = nullptr;
- String name;
- Variant::Type type;
- Variant v;
- List<String> field_names;
- int hint = 0;
- String hint_text;
- HBoxContainer *value_hboxes[MAX_VALUE_EDITORS / 4];
- VBoxContainer *value_vbox = nullptr;
- LineEdit *value_editor[MAX_VALUE_EDITORS];
- int focused_value_editor;
- Label *value_label[MAX_VALUE_EDITORS];
- HScrollBar *scroll[4];
- HBoxContainer *action_hboxes = nullptr;
- Button *action_buttons[MAX_ACTION_BUTTONS];
- MenuButton *type_button = nullptr;
- Vector<String> inheritors_array;
- TextureRect *texture_preview = nullptr;
- ColorPicker *color_picker = nullptr;
- TextEdit *text_edit = nullptr;
- bool read_only = false;
- bool picking_viewport = false;
- GridContainer *checks20gc = nullptr;
- CheckBox *checks20[20];
- SpinBox *spinbox = nullptr;
- HSlider *slider = nullptr;
-
- Control *easing_draw = nullptr;
- CreateDialog *create_dialog = nullptr;
- PropertySelector *property_select = nullptr;
-
- Object *owner = nullptr;
-
- bool updating = false;
-
- PropertyValueEvaluator *evaluator = nullptr;
-
- void _text_edit_changed();
- void _file_selected(String p_file);
- void _locale_selected(String p_locale);
- void _modified(String p_string);
-
- real_t _parse_real_expression(String text);
-
- void _range_modified(double p_value);
- void _focus_enter();
- void _focus_exit();
- void _action_pressed(int p_which);
- void _type_create_selected(int p_idx);
- void _create_dialog_callback();
- void _create_selected_property(const String &p_prop);
-
- void _color_changed(const Color &p_color);
- void _draw_easing();
- void _menu_option(int p_which);
-
- void _drag_easing(const Ref<InputEvent> &p_ev);
-
- void _node_path_selected(NodePath p_path);
- void show_value_editors(int p_amount);
- void config_value_editors(int p_amount, int p_columns, int p_label_w, const List<String> &p_strings);
- void config_action_buttons(const List<String> &p_strings);
-
- void _emit_changed_whole_or_field();
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void hide_menu();
-
- Variant get_variant() const;
- String get_name() const;
-
- void set_read_only(bool p_read_only) { read_only = p_read_only; }
-
- bool edit(Object *p_owner, const String &p_name, Variant::Type p_type, const Variant &p_variant, int p_hint, String p_hint_text);
-
- CustomPropertyEditor();
-};
-
-#endif // PROPERTY_EDITOR_H
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index c74a4c884d..a77687677b 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -375,7 +375,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
}
if (p_node->has_meta("_edit_group_")) {
- item->add_button(0, get_theme_icon(SNAME("Group"), SNAME("EditorIcons")), BUTTON_GROUP, false, TTR("Children are not selectable.\nClick to make selectable."));
+ item->add_button(0, get_theme_icon(SNAME("Group"), SNAME("EditorIcons")), BUTTON_GROUP, false, TTR("Children are not selectable.\nClick to make them selectable."));
}
bool v = p_node->call("is_visible");
@@ -407,7 +407,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
}
if (p_node->has_meta("_edit_group_")) {
- item->add_button(0, get_theme_icon(SNAME("Group"), SNAME("EditorIcons")), BUTTON_GROUP, false, TTR("Children are not selectable.\nClick to make selectable."));
+ item->add_button(0, get_theme_icon(SNAME("Group"), SNAME("EditorIcons")), BUTTON_GROUP, false, TTR("Children are not selectable.\nClick to make them selectable."));
}
bool v = p_node->call("is_visible");
diff --git a/main/main.cpp b/main/main.cpp
index 190f25dbe6..fe510d1c9c 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -31,6 +31,7 @@
#include "main.h"
#include "core/config/project_settings.h"
+#include "core/core_globals.h"
#include "core/core_string_names.h"
#include "core/crypto/crypto.h"
#include "core/debugger/engine_debugger.h"
@@ -1375,11 +1376,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
quiet_stdout = true;
}
if (bool(ProjectSettings::get_singleton()->get("application/run/disable_stderr"))) {
- _print_error_enabled = false;
+ CoreGlobals::print_error_enabled = false;
};
if (quiet_stdout) {
- _print_line_enabled = false;
+ CoreGlobals::print_line_enabled = false;
}
Logger::set_flush_stdout_on_print(ProjectSettings::get_singleton()->get("application/run/flush_stdout_on_print"));
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
index ff4832bde0..e3b956369d 100644
--- a/modules/gdscript/tests/gdscript_test_runner.cpp
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -36,6 +36,7 @@
#include "../gdscript_parser.h"
#include "core/config/project_settings.h"
+#include "core/core_globals.h"
#include "core/core_string_names.h"
#include "core/io/dir_access.h"
#include "core/io/file_access_pack.h"
@@ -142,8 +143,8 @@ GDScriptTestRunner::GDScriptTestRunner(const String &p_source_dir, bool p_init_l
#endif
// Enable printing to show results
- _print_line_enabled = true;
- _print_error_enabled = true;
+ CoreGlobals::print_line_enabled = true;
+ CoreGlobals::print_error_enabled = true;
}
GDScriptTestRunner::~GDScriptTestRunner() {
diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml
index deabc5ccd3..52a7fe492f 100644
--- a/modules/regex/doc_classes/RegEx.xml
+++ b/modules/regex/doc_classes/RegEx.xml
@@ -62,6 +62,13 @@
Compiles and assign the search pattern to use. Returns [constant OK] if the compilation is successful. If an error is encountered, details are printed to standard output and an error is returned.
</description>
</method>
+ <method name="create_from_string" qualifiers="static">
+ <return type="RegEx" />
+ <argument index="0" name="pattern" type="String" />
+ <description>
+ Creates and compiles a new [RegEx] object.
+ </description>
+ </method>
<method name="get_group_count" qualifiers="const">
<return type="int" />
<description>
@@ -96,7 +103,7 @@
</description>
</method>
<method name="search_all" qualifiers="const">
- <return type="Array" />
+ <return type="RegExMatch[]" />
<argument index="0" name="subject" type="String" />
<argument index="1" name="offset" type="int" default="0" />
<argument index="2" name="end" type="int" default="-1" />
diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp
index 67ce37219b..569066867a 100644
--- a/modules/regex/regex.cpp
+++ b/modules/regex/regex.cpp
@@ -159,6 +159,13 @@ void RegEx::_pattern_info(uint32_t what, void *where) const {
pcre2_pattern_info_32((pcre2_code_32 *)code, what, where);
}
+Ref<RegEx> RegEx::create_from_string(const String &p_pattern) {
+ Ref<RegEx> ret;
+ ret.instantiate();
+ ret->compile(p_pattern);
+ return ret;
+}
+
void RegEx::clear() {
if (code) {
pcre2_code_free_32((pcre2_code_32 *)code);
@@ -258,11 +265,11 @@ Ref<RegExMatch> RegEx::search(const String &p_subject, int p_offset, int p_end)
return result;
}
-Array RegEx::search_all(const String &p_subject, int p_offset, int p_end) const {
+TypedArray<RegExMatch> RegEx::search_all(const String &p_subject, int p_offset, int p_end) const {
ERR_FAIL_COND_V_MSG(p_offset < 0, Array(), "RegEx search offset must be >= 0");
int last_end = -1;
- Array result;
+ TypedArray<RegExMatch> result;
Ref<RegExMatch> match = search(p_subject, p_offset, p_end);
while (match.is_valid()) {
if (last_end == match->get_end(0)) {
@@ -384,6 +391,8 @@ RegEx::~RegEx() {
}
void RegEx::_bind_methods() {
+ ClassDB::bind_static_method("RegEx", D_METHOD("create_from_string", "pattern"), &RegEx::create_from_string);
+
ClassDB::bind_method(D_METHOD("clear"), &RegEx::clear);
ClassDB::bind_method(D_METHOD("compile", "pattern"), &RegEx::compile);
ClassDB::bind_method(D_METHOD("search", "subject", "offset", "end"), &RegEx::search, DEFVAL(0), DEFVAL(-1));
diff --git a/modules/regex/regex.h b/modules/regex/regex.h
index 1455188670..9296de929f 100644
--- a/modules/regex/regex.h
+++ b/modules/regex/regex.h
@@ -37,6 +37,7 @@
#include "core/templates/vector.h"
#include "core/variant/array.h"
#include "core/variant/dictionary.h"
+#include "core/variant/typed_array.h"
class RegExMatch : public RefCounted {
GDCLASS(RegExMatch, RefCounted);
@@ -81,11 +82,13 @@ protected:
static void _bind_methods();
public:
+ static Ref<RegEx> create_from_string(const String &p_pattern);
+
void clear();
Error compile(const String &p_pattern);
Ref<RegExMatch> search(const String &p_subject, int p_offset = 0, int p_end = -1) const;
- Array search_all(const String &p_subject, int p_offset = 0, int p_end = -1) const;
+ TypedArray<RegExMatch> search_all(const String &p_subject, int p_offset = 0, int p_end = -1) const;
String sub(const String &p_subject, const String &p_replacement, bool p_all = false, int p_offset = 0, int p_end = -1) const;
bool is_valid() const;
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index d212fe62b4..73e5c2bf74 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -121,7 +121,7 @@ if env["builtin_harfbuzz"]:
env_harfbuzz.Append(CCFLAGS=["-DHAVE_ICU"])
if env["builtin_icu"]:
- env_harfbuzz.Prepend(CPPPATH=["#thirdparty/icu4c/common/"])
+ env_harfbuzz.Prepend(CPPPATH=["#thirdparty/icu4c/common/", "#thirdparty/icu4c/i18n/"])
env_harfbuzz.Append(CCFLAGS=["-DU_HAVE_LIB_SUFFIX=1", "-DU_LIB_SUFFIX_C_NAME=_godot", "-DHAVE_ICU_BUILTIN"])
if freetype_enabled:
@@ -439,6 +439,10 @@ if env["builtin_icu"]:
"common/uvectr32.cpp",
"common/uvectr64.cpp",
"common/wintz.cpp",
+ "i18n/scriptset.cpp",
+ "i18n/ucln_in.cpp",
+ "i18n/uspoof.cpp",
+ "i18n/uspoof_impl.cpp",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
@@ -451,7 +455,7 @@ if env["builtin_icu"]:
else:
thirdparty_sources += ["icu_data/icudata_stub.cpp"]
- env_icu.Prepend(CPPPATH=["#thirdparty/icu4c/common/"])
+ env_icu.Prepend(CPPPATH=["#thirdparty/icu4c/common/", "#thirdparty/icu4c/i18n/"])
env_icu.Append(
CXXFLAGS=[
"-DU_STATIC_IMPLEMENTATION",
@@ -463,6 +467,7 @@ if env["builtin_icu"]:
"-DUCONFIG_NO_IDNA",
"-DUCONFIG_NO_FILE_IO",
"-DUCONFIG_NO_TRANSLITERATION",
+ "-DUCONFIG_NO_REGULAR_EXPRESSIONS",
"-DPKGDATA_MODE=static",
"-DU_ENABLE_DYLOAD=0",
"-DU_HAVE_LIB_SUFFIX=1",
@@ -480,7 +485,7 @@ if env["builtin_icu"]:
if env_text_server_adv["tools"]:
env_text_server_adv.Append(CXXFLAGS=["-DICU_STATIC_DATA"])
- env_text_server_adv.Prepend(CPPPATH=["#thirdparty/icu4c/common/"])
+ env_text_server_adv.Prepend(CPPPATH=["#thirdparty/icu4c/common/", "#thirdparty/icu4c/i18n/"])
lib = env_icu.add_library("icu_builtin", thirdparty_sources)
thirdparty_obj += lib
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 64788bfeff..bb49fb5248 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -346,6 +346,8 @@ bool TextServerAdvanced::has_feature(Feature p_feature) const {
case FEATURE_FONT_VARIABLE:
case FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION:
case FEATURE_USE_SUPPORT_DATA:
+ case FEATURE_UNICODE_IDENTIFIERS:
+ case FEATURE_UNICODE_SECURITY:
return true;
default: {
}
@@ -5639,6 +5641,68 @@ String TextServerAdvanced::percent_sign(const String &p_language) const {
return "%";
}
+int TextServerAdvanced::is_confusable(const String &p_string, const PackedStringArray &p_dict) const {
+ UErrorCode status = U_ZERO_ERROR;
+ int match_index = -1;
+
+ Char16String utf16 = p_string.utf16();
+ Vector<UChar *> skeletons;
+ skeletons.resize(p_dict.size());
+
+ USpoofChecker *sc = uspoof_open(&status);
+ uspoof_setChecks(sc, USPOOF_CONFUSABLE, &status);
+ for (int i = 0; i < p_dict.size(); i++) {
+ Char16String word = p_dict[i].utf16();
+ int32_t len = uspoof_getSkeleton(sc, 0, word.get_data(), -1, NULL, 0, &status);
+ skeletons.write[i] = (UChar *)memalloc(++len * sizeof(UChar));
+ status = U_ZERO_ERROR;
+ uspoof_getSkeleton(sc, 0, word.get_data(), -1, skeletons.write[i], len, &status);
+ }
+
+ int32_t len = uspoof_getSkeleton(sc, 0, utf16.get_data(), -1, NULL, 0, &status);
+ UChar *skel = (UChar *)memalloc(++len * sizeof(UChar));
+ status = U_ZERO_ERROR;
+ uspoof_getSkeleton(sc, 0, utf16.get_data(), -1, skel, len, &status);
+ for (int i = 0; i < skeletons.size(); i++) {
+ if (u_strcmp(skel, skeletons[i]) == 0) {
+ match_index = i;
+ break;
+ }
+ }
+ memfree(skel);
+
+ for (int i = 0; i < skeletons.size(); i++) {
+ memfree(skeletons.write[i]);
+ }
+ uspoof_close(sc);
+
+ ERR_FAIL_COND_V_MSG(U_FAILURE(status), -1, u_errorName(status));
+
+ return match_index;
+}
+
+bool TextServerAdvanced::spoof_check(const String &p_string) const {
+ UErrorCode status = U_ZERO_ERROR;
+ Char16String utf16 = p_string.utf16();
+
+ USet *allowed = uset_openEmpty();
+ uset_addAll(allowed, uspoof_getRecommendedSet(&status));
+ uset_addAll(allowed, uspoof_getInclusionSet(&status));
+
+ USpoofChecker *sc = uspoof_open(&status);
+ uspoof_setAllowedChars(sc, allowed, &status);
+ uspoof_setRestrictionLevel(sc, USPOOF_MODERATELY_RESTRICTIVE);
+
+ int32_t bitmask = uspoof_check(sc, utf16.get_data(), -1, NULL, &status);
+
+ uspoof_close(sc);
+ uset_close(allowed);
+
+ ERR_FAIL_COND_V_MSG(U_FAILURE(status), false, u_errorName(status));
+
+ return (bitmask != 0);
+}
+
String TextServerAdvanced::strip_diacritics(const String &p_string) const {
UErrorCode err = U_ZERO_ERROR;
@@ -5757,6 +5821,191 @@ PackedInt32Array TextServerAdvanced::string_get_word_breaks(const String &p_stri
return ret;
}
+bool TextServerAdvanced::is_valid_identifier(const String &p_string) const {
+ enum UAX31SequenceStatus {
+ SEQ_NOT_STARTED,
+ SEQ_STARTED,
+ SEQ_STARTED_VIR,
+ SEQ_NEAR_END,
+ };
+
+ const char32_t *str = p_string.ptr();
+ int len = p_string.length();
+
+ if (len == 0) {
+ return false; // Empty string.
+ }
+
+ UErrorCode err = U_ZERO_ERROR;
+ Char16String utf16 = p_string.utf16();
+ const UNormalizer2 *norm_c = unorm2_getNFCInstance(&err);
+ if (U_FAILURE(err)) {
+ return false; // Failed to load normalizer.
+ }
+ bool isnurom = unorm2_isNormalized(norm_c, utf16.ptr(), utf16.length(), &err);
+ if (U_FAILURE(err) || !isnurom) {
+ return false; // Do not conform to Normalization Form C.
+ }
+
+ UAX31SequenceStatus A1_sequence_status = SEQ_NOT_STARTED;
+ UScriptCode A1_scr = USCRIPT_INHERITED;
+ UAX31SequenceStatus A2_sequence_status = SEQ_NOT_STARTED;
+ UScriptCode A2_scr = USCRIPT_INHERITED;
+ UAX31SequenceStatus B_sequence_status = SEQ_NOT_STARTED;
+ UScriptCode B_scr = USCRIPT_INHERITED;
+
+ for (int i = 0; i < len; i++) {
+ err = U_ZERO_ERROR;
+ UScriptCode scr = uscript_getScript(str[i], &err);
+ if (U_FAILURE(err)) {
+ return false; // Invalid script.
+ }
+ if (uscript_getUsage(scr) != USCRIPT_USAGE_RECOMMENDED) {
+ return false; // Not a recommended script.
+ }
+ uint8_t cat = u_charType(str[i]);
+ int32_t jt = u_getIntPropertyValue(str[i], UCHAR_JOINING_TYPE);
+
+ // UAX #31 section 2.3 subsections A1, A2 and B, check ZWNJ and ZWJ usage.
+ switch (A1_sequence_status) {
+ case SEQ_NEAR_END: {
+ if ((A1_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A1_scr)) {
+ return false; // Mixed script.
+ }
+ if (jt == U_JT_RIGHT_JOINING || jt == U_JT_DUAL_JOINING) {
+ A1_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.
+ } else if (jt != U_JT_TRANSPARENT) {
+ return false; // Invalid end of sequence.
+ }
+ } break;
+ case SEQ_STARTED: {
+ if ((A1_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A1_scr)) {
+ A1_sequence_status = SEQ_NOT_STARTED; // Reset.
+ } else {
+ if (jt != U_JT_TRANSPARENT) {
+ if (str[i] == 0x200C /*ZWNJ*/) {
+ A1_sequence_status = SEQ_NEAR_END;
+ continue;
+ } else {
+ A1_sequence_status = SEQ_NOT_STARTED; // Reset.
+ }
+ }
+ }
+ } break;
+ default:
+ break;
+ }
+ if (A1_sequence_status == SEQ_NOT_STARTED) {
+ if (jt == U_JT_LEFT_JOINING || jt == U_JT_DUAL_JOINING) {
+ A1_sequence_status = SEQ_STARTED;
+ A1_scr = scr;
+ }
+ };
+
+ switch (A2_sequence_status) {
+ case SEQ_NEAR_END: {
+ if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {
+ return false; // Mixed script.
+ }
+ if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {
+ A2_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.
+ } else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {
+ return false; // Invalid end of sequence.
+ }
+ } break;
+ case SEQ_STARTED_VIR: {
+ if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {
+ A2_sequence_status = SEQ_NOT_STARTED; // Reset.
+ } else {
+ if (str[i] == 0x200C /*ZWNJ*/) {
+ A2_sequence_status = SEQ_NEAR_END;
+ continue;
+ } else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {
+ A2_sequence_status = SEQ_NOT_STARTED; // Reset.
+ }
+ }
+ } break;
+ case SEQ_STARTED: {
+ if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {
+ A2_sequence_status = SEQ_NOT_STARTED; // Reset.
+ } else {
+ if (u_getCombiningClass(str[i]) == 9 /*Virama Combining Class*/) {
+ A2_sequence_status = SEQ_STARTED_VIR;
+ } else if (cat != U_MODIFIER_LETTER) {
+ A2_sequence_status = SEQ_NOT_STARTED; // Reset.
+ }
+ }
+ } break;
+ default:
+ break;
+ }
+ if (A2_sequence_status == SEQ_NOT_STARTED) {
+ if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {
+ A2_sequence_status = SEQ_STARTED;
+ A2_scr = scr;
+ }
+ }
+
+ switch (B_sequence_status) {
+ case SEQ_NEAR_END: {
+ if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {
+ return false; // Mixed script.
+ }
+ if (u_getIntPropertyValue(str[i], UCHAR_INDIC_SYLLABIC_CATEGORY) != U_INSC_VOWEL_DEPENDENT) {
+ B_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.
+ } else {
+ return false; // Invalid end of sequence.
+ }
+ } break;
+ case SEQ_STARTED_VIR: {
+ if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {
+ B_sequence_status = SEQ_NOT_STARTED; // Reset.
+ } else {
+ if (str[i] == 0x200D /*ZWJ*/) {
+ B_sequence_status = SEQ_NEAR_END;
+ continue;
+ } else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {
+ B_sequence_status = SEQ_NOT_STARTED; // Reset.
+ }
+ }
+ } break;
+ case SEQ_STARTED: {
+ if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {
+ B_sequence_status = SEQ_NOT_STARTED; // Reset.
+ } else {
+ if (u_getCombiningClass(str[i]) == 9 /*Virama Combining Class*/) {
+ B_sequence_status = SEQ_STARTED_VIR;
+ } else if (cat != U_MODIFIER_LETTER) {
+ B_sequence_status = SEQ_NOT_STARTED; // Reset.
+ }
+ }
+ } break;
+ default:
+ break;
+ }
+ if (B_sequence_status == SEQ_NOT_STARTED) {
+ if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {
+ B_sequence_status = SEQ_STARTED;
+ B_scr = scr;
+ }
+ }
+
+ if (u_hasBinaryProperty(str[i], UCHAR_PATTERN_SYNTAX) || u_hasBinaryProperty(str[i], UCHAR_PATTERN_WHITE_SPACE) || u_hasBinaryProperty(str[i], UCHAR_NONCHARACTER_CODE_POINT)) {
+ return false; // Not a XID_Start or XID_Continue character.
+ }
+ if (i == 0) {
+ if (!(cat == U_LOWERCASE_LETTER || cat == U_UPPERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_OTHER_LETTER || cat == U_MODIFIER_LETTER || cat == U_LETTER_NUMBER || str[0] == 0x2118 || str[0] == 0x212E || str[0] == 0x309B || str[0] == 0x309C || str[0] == 0x005F)) {
+ return false; // Not a XID_Start character.
+ }
+ } else {
+ if (!(cat == U_LOWERCASE_LETTER || cat == U_UPPERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_OTHER_LETTER || cat == U_MODIFIER_LETTER || cat == U_LETTER_NUMBER || cat == U_NON_SPACING_MARK || cat == U_COMBINING_SPACING_MARK || cat == U_DECIMAL_DIGIT_NUMBER || cat == U_CONNECTOR_PUNCTUATION || str[i] == 0x2118 || str[i] == 0x212E || str[i] == 0x309B || str[i] == 0x309C || str[i] == 0x1369 || str[i] == 0x1371 || str[i] == 0x00B7 || str[i] == 0x0387 || str[i] == 0x19DA || str[i] == 0x0E33 || str[i] == 0x0EB3 || str[i] == 0xFF9E || str[i] == 0xFF9F)) {
+ return false; // Not a XID_Continue character.
+ }
+ }
+ }
+ return true;
+}
+
TextServerAdvanced::TextServerAdvanced() {
_insert_num_systems_lang();
_insert_feature_sets();
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 8cd0e753ba..b337abea7a 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -101,6 +101,7 @@ using namespace godot;
#include <unicode/uloc.h>
#include <unicode/unorm2.h>
#include <unicode/uscript.h>
+#include <unicode/uspoof.h>
#include <unicode/ustring.h>
#include <unicode/utypes.h>
@@ -701,7 +702,11 @@ public:
virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const override;
+ virtual int is_confusable(const String &p_string, const PackedStringArray &p_dict) const override;
+ virtual bool spoof_check(const String &p_string) const override;
+
virtual String strip_diacritics(const String &p_string) const override;
+ virtual bool is_valid_identifier(const String &p_string) const override;
virtual String string_to_upper(const String &p_string, const String &p_language = "") const override;
virtual String string_to_lower(const String &p_string, const String &p_language = "") const override;
diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp
index 1e9755f45f..7f8e9d8254 100644
--- a/modules/visual_script/editor/visual_script_editor.cpp
+++ b/modules/visual_script/editor/visual_script_editor.cpp
@@ -42,10 +42,32 @@
#include "editor/editor_node.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
+#include "editor/editor_settings.h"
+#include "scene/gui/check_button.h"
+#include "scene/gui/graph_edit.h"
+#include "scene/gui/separator.h"
#include "scene/gui/view_panner.h"
#include "scene/main/window.h"
#ifdef TOOLS_ENABLED
+
+void VisualScriptEditedProperty::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_edited_property", "value"), &VisualScriptEditedProperty::set_edited_property);
+ ClassDB::bind_method(D_METHOD("get_edited_property"), &VisualScriptEditedProperty::get_edited_property);
+
+ ADD_PROPERTY(PropertyInfo(Variant::NIL, "edited_property", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_edited_property", "get_edited_property");
+}
+
+void VisualScriptEditedProperty::set_edited_property(Variant p_variant) {
+ edited_property = p_variant;
+}
+
+Variant VisualScriptEditedProperty::get_edited_property() const {
+ return edited_property;
+}
+
+/////////////////
+
class VisualScriptEditorSignalEdit : public Object {
GDCLASS(VisualScriptEditorSignalEdit, Object);
@@ -3898,14 +3920,14 @@ int VisualScriptEditor::_create_new_node_from_name(const String &p_text, const V
return new_id;
}
-void VisualScriptEditor::_default_value_changed() {
+void VisualScriptEditor::_default_value_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing) {
Ref<VisualScriptNode> vsn = script->get_node(editing_id);
if (vsn.is_null()) {
return;
}
undo_redo->create_action(TTR("Change Input Value"));
- undo_redo->add_do_method(vsn.ptr(), "set_default_input_value", editing_input, default_value_edit->get_variant());
+ undo_redo->add_do_method(vsn.ptr(), "set_default_input_value", editing_input, p_value);
undo_redo->add_undo_method(vsn.ptr(), "set_default_input_value", editing_input, vsn->get_default_input_value(editing_input));
undo_redo->add_do_method(this, "_update_graph", editing_id);
@@ -3928,9 +3950,6 @@ void VisualScriptEditor::_default_value_edited(Node *p_button, int p_id, int p_i
Variant::construct(pinfo.type, existing, &existingp, 1, ce);
}
- default_value_edit->set_position(Object::cast_to<Control>(p_button)->get_screen_position() + Vector2(0, Object::cast_to<Control>(p_button)->get_size().y) * graph->get_zoom());
- default_value_edit->reset_size();
-
if (pinfo.type == Variant::NODE_PATH) {
Node *edited_scene = get_tree()->get_edited_scene_root();
if (edited_scene) { // Fixing an old crash bug ( Visual Script Crashes on editing NodePath with an empty scene open).
@@ -3948,11 +3967,33 @@ void VisualScriptEditor::_default_value_edited(Node *p_button, int p_id, int p_i
}
}
- if (default_value_edit->edit(nullptr, pinfo.name, pinfo.type, existing, pinfo.hint, pinfo.hint_string)) {
- if (pinfo.hint == PROPERTY_HINT_MULTILINE_TEXT) {
- default_value_edit->popup_centered_ratio();
+ edited_default_property_holder->set_edited_property(existing);
+
+ if (default_property_editor) {
+ default_property_editor->disconnect("property_changed", callable_mp(this, &VisualScriptEditor::_default_value_changed));
+ default_property_editor_popup->remove_child(default_property_editor);
+ }
+
+ default_property_editor = EditorInspector::instantiate_property_editor(edited_default_property_holder.ptr(), pinfo.type, "edited_property", pinfo.hint, pinfo.hint_string, PROPERTY_USAGE_NONE);
+ if (default_property_editor) {
+ default_property_editor->set_object_and_property(edited_default_property_holder.ptr(), "edited_property");
+ default_property_editor->update_property();
+ default_property_editor->set_name_split_ratio(0);
+ default_property_editor_popup->add_child(default_property_editor);
+
+ default_property_editor->connect("property_changed", callable_mp(this, &VisualScriptEditor::_default_value_changed));
+
+ Button *button = Object::cast_to<Button>(p_button);
+ if (button) {
+ default_property_editor_popup->set_position(button->get_screen_position() + Vector2(0, button->get_size().height) * graph->get_zoom());
+ }
+
+ default_property_editor_popup->reset_size();
+
+ if (pinfo.hint == PROPERTY_HINT_MULTILINE_TEXT || !button) {
+ default_property_editor_popup->popup_centered_ratio();
} else {
- default_value_edit->popup();
+ default_property_editor_popup->popup();
}
}
@@ -4795,9 +4836,11 @@ VisualScriptEditor::VisualScriptEditor() {
set_process_input(true);
- default_value_edit = memnew(CustomPropertyEditor);
- add_child(default_value_edit);
- default_value_edit->connect("variant_changed", callable_mp(this, &VisualScriptEditor::_default_value_changed));
+ default_property_editor_popup = memnew(PopupPanel);
+ default_property_editor_popup->set_min_size(Size2i(180, 0) * EDSCALE);
+ add_child(default_property_editor_popup);
+
+ edited_default_property_holder.instantiate();
new_connect_node_select = memnew(VisualScriptPropertySelector);
add_child(new_connect_node_select);
diff --git a/modules/visual_script/editor/visual_script_editor.h b/modules/visual_script/editor/visual_script_editor.h
index a6df7bba73..6b337e52f6 100644
--- a/modules/visual_script/editor/visual_script_editor.h
+++ b/modules/visual_script/editor/visual_script_editor.h
@@ -34,15 +34,31 @@
#include "../visual_script.h"
#include "editor/create_dialog.h"
#include "editor/plugins/script_editor_plugin.h"
-#include "editor/property_editor.h"
-#include "scene/gui/graph_edit.h"
#include "visual_script_property_selector.h"
+class GraphEdit;
+
class VisualScriptEditorSignalEdit;
class VisualScriptEditorVariableEdit;
#ifdef TOOLS_ENABLED
+class VisualScriptEditedProperty : public RefCounted {
+ GDCLASS(VisualScriptEditedProperty, RefCounted);
+
+private:
+ Variant edited_property;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_edited_property(Variant p_variant);
+ Variant get_edited_property() const;
+
+ VisualScriptEditedProperty() {}
+};
+
// TODO: Maybe this class should be refactored.
// See https://github.com/godotengine/godot/issues/51913
class VisualScriptEditor : public ScriptEditorBase {
@@ -115,7 +131,9 @@ class VisualScriptEditor : public ScriptEditorBase {
AcceptDialog *edit_variable_dialog = nullptr;
EditorInspector *edit_variable_edit = nullptr;
- CustomPropertyEditor *default_value_edit = nullptr;
+ PopupPanel *default_property_editor_popup = nullptr;
+ EditorProperty *default_property_editor = nullptr;
+ Ref<VisualScriptEditedProperty> edited_default_property_holder;
UndoRedo *undo_redo = nullptr;
@@ -276,7 +294,7 @@ class VisualScriptEditor : public ScriptEditorBase {
int data_disconnect_node = 0;
int data_disconnect_port = 0;
- void _default_value_changed();
+ void _default_value_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing);
void _default_value_edited(Node *p_button, int p_id, int p_input_port);
void _menu_option(int p_what);
diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h
index e6fd8c857b..8d7ade8ead 100644
--- a/platform/android/file_access_android.h
+++ b/platform/android/file_access_android.h
@@ -49,34 +49,34 @@ class FileAccessAndroid : public FileAccess {
public:
static AAssetManager *asset_manager;
- virtual Error _open(const String &p_path, int p_mode_flags); // open a file
- virtual bool is_open() const; // true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; // open a file
+ virtual bool is_open() const override; // true when file is open
/// returns the path for the current open file
- virtual String get_path() const;
+ virtual String get_path() const override;
/// returns the absolute path for the current open file
- virtual String get_path_absolute() const;
+ virtual String get_path_absolute() const override;
- virtual void seek(uint64_t p_position); // seek to a given position
- virtual void seek_end(int64_t p_position = 0); // seek from the end of file
- virtual uint64_t get_position() const; // get position in the file
- virtual uint64_t get_length() const; // get size of the file
+ virtual void seek(uint64_t p_position) override; // seek to a given position
+ virtual void seek_end(int64_t p_position = 0) override; // seek from the end of file
+ virtual uint64_t get_position() const override; // get position in the file
+ virtual uint64_t get_length() const override; // get size of the file
- virtual bool eof_reached() const; // reading passed EOF
+ virtual bool eof_reached() const override; // reading passed EOF
- virtual uint8_t get_8() const; // get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint8_t get_8() const override; // get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual Error get_error() const; // get last error
+ virtual Error get_error() const override; // get last error
- virtual void flush();
- virtual void store_8(uint8_t p_dest); // store a byte
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override; // store a byte
- virtual bool file_exists(const String &p_path); // return true if a file exists
+ virtual bool file_exists(const String &p_path) override; // return true if a file exists
- virtual uint64_t _get_modified_time(const String &p_file) { return 0; }
- virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
+ virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
+ virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; }
~FileAccessAndroid();
};
diff --git a/platform/linuxbsd/detect_prime_x11.cpp b/platform/linuxbsd/detect_prime_x11.cpp
index 42b7f68a5e..fb833ab5e6 100644
--- a/platform/linuxbsd/detect_prime_x11.cpp
+++ b/platform/linuxbsd/detect_prime_x11.cpp
@@ -177,6 +177,11 @@ int detect_prime() {
} else {
// In child, exit() here will not quit the engine.
+ // Prevent false leak reports as we will not be properly
+ // cleaning up these processes, and fork() makes a copy
+ // of all globals.
+ CoreGlobals::leak_reporting_enabled = false;
+
char string[201];
close(fdset[0]);
diff --git a/platform/macos/dir_access_macos.h b/platform/macos/dir_access_macos.h
index 1ac1b995de..920e69ef3e 100644
--- a/platform/macos/dir_access_macos.h
+++ b/platform/macos/dir_access_macos.h
@@ -43,12 +43,12 @@
class DirAccessMacOS : public DirAccessUnix {
protected:
- virtual String fix_unicode_name(const char *p_name) const;
+ virtual String fix_unicode_name(const char *p_name) const override;
- virtual int get_drive_count();
- virtual String get_drive(int p_drive);
+ virtual int get_drive_count() override;
+ virtual String get_drive(int p_drive) override;
- virtual bool is_hidden(const String &p_name);
+ virtual bool is_hidden(const String &p_name) override;
};
#endif // UNIX ENABLED || LIBC_FILEIO_ENABLED
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index e2ead6415a..788feacdd9 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -264,15 +264,7 @@ void ColorPicker::_update_controls() {
void ColorPicker::_set_pick_color(const Color &p_color, bool p_update_sliders) {
color = p_color;
if (color != last_color) {
- if (_get_actual_shape() == SHAPE_OKHSL_CIRCLE) {
- h = color.get_ok_hsl_h();
- s = color.get_ok_hsl_s();
- v = color.get_ok_hsl_l();
- } else {
- h = color.get_h();
- s = color.get_s();
- v = color.get_v();
- }
+ _copy_color_to_hsv();
last_color = color;
}
@@ -386,6 +378,26 @@ Vector<float> ColorPicker::get_active_slider_values() {
return values;
}
+void ColorPicker::_copy_color_to_hsv() {
+ if (_get_actual_shape() == SHAPE_OKHSL_CIRCLE) {
+ h = color.get_ok_hsl_h();
+ s = color.get_ok_hsl_s();
+ v = color.get_ok_hsl_l();
+ } else {
+ h = color.get_h();
+ s = color.get_s();
+ v = color.get_v();
+ }
+}
+
+void ColorPicker::_copy_hsv_to_color() {
+ if (_get_actual_shape() == SHAPE_OKHSL_CIRCLE) {
+ color.set_ok_hsl(h, s, v, color.a);
+ } else {
+ color.set_hsv(h, s, v, color.a);
+ }
+}
+
ColorPicker::PickerShapeType ColorPicker::_get_actual_shape() const {
return modes[current_mode]->get_shape_override() != SHAPE_MAX ? modes[current_mode]->get_shape_override() : current_shape;
}
@@ -499,6 +511,8 @@ void ColorPicker::set_picker_shape(PickerShapeType p_shape) {
ERR_FAIL_INDEX(p_shape, SHAPE_MAX);
current_shape = p_shape;
+ _copy_color_to_hsv();
+
_update_controls();
_update_color();
}
@@ -640,8 +654,7 @@ void ColorPicker::_sample_input(const Ref<InputEvent> &p_event) {
const Rect2 rect_old = Rect2(Point2(), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95));
if (rect_old.has_point(mb->get_position())) {
// Revert to the old color when left-clicking the old color sample.
- color = old_color;
- _update_color();
+ set_pick_color(old_color);
emit_signal(SNAME("color_changed"), color);
}
}
@@ -887,17 +900,14 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) {
v = 1.0 - (y - c->get_position().y - corner_y) / real_size.y;
}
}
+
changing_color = true;
- if (current_picker == SHAPE_OKHSL_CIRCLE) {
- color.set_ok_hsl(h, s, v, color.a);
- } else {
- color.set_hsv(h, s, v, color.a);
- }
+ _copy_hsv_to_color();
last_color = color;
-
set_pick_color(color);
_update_color();
+
if (!deferred_mode_enabled) {
emit_signal(SNAME("color_changed"), color);
}
@@ -940,14 +950,12 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) {
v = 1.0 - (y - corner_y) / real_size.y;
}
}
- if (current_picker != SHAPE_OKHSL_CIRCLE) {
- color.set_hsv(h, s, v, color.a);
- } else {
- color.set_ok_hsl(h, s, v, color.a);
- }
+
+ _copy_hsv_to_color();
last_color = color;
set_pick_color(color);
_update_color();
+
if (!deferred_mode_enabled) {
emit_signal(SNAME("color_changed"), color);
}
@@ -970,14 +978,12 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
} else {
changing_color = false;
}
- if (actual_shape != SHAPE_OKHSL_CIRCLE) {
- color.set_hsv(h, s, v, color.a);
- } else {
- color.set_ok_hsl(h, s, v, color.a);
- }
+
+ _copy_hsv_to_color();
last_color = color;
set_pick_color(color);
_update_color();
+
if (!deferred_mode_enabled) {
emit_signal(SNAME("color_changed"), color);
} else if (!bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) {
@@ -998,15 +1004,11 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
h = y / w_edit->get_size().height;
}
- if (actual_shape == SHAPE_OKHSL_CIRCLE) {
- color.set_ok_hsl(h, s, v, color.a);
- } else {
- color.set_hsv(h, s, v, color.a);
- }
-
+ _copy_hsv_to_color();
last_color = color;
set_pick_color(color);
_update_color();
+
if (!deferred_mode_enabled) {
emit_signal(SNAME("color_changed"), color);
}
@@ -1019,7 +1021,6 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event, const Color &p_c
if (bev.is_valid()) {
if (bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) {
set_pick_color(p_color);
- _update_color();
emit_signal(SNAME("color_changed"), p_color);
} else if (bev->is_pressed() && bev->get_button_index() == MouseButton::RIGHT && presets_enabled) {
erase_preset(p_color);
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 8e65ee1861..05b760b109 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -156,6 +156,9 @@ private:
float v = 0.0;
Color last_color;
+ void _copy_color_to_hsv();
+ void _copy_hsv_to_color();
+
PickerShapeType _get_actual_shape() const;
void create_slider(GridContainer *gc, int idx);
void _reset_theme();
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 92016ca42e..c5054525a7 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -1051,6 +1051,7 @@ void GraphNode::_bind_methods() {
ADD_GROUP("BiDi", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language");
+ ADD_GROUP("", "");
ADD_SIGNAL(MethodInfo("position_offset_changed"));
ADD_SIGNAL(MethodInfo("slot_updated", PropertyInfo(Variant::INT, "idx")));
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index 4b2fdbed5b..e0918b17c7 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -98,7 +98,7 @@ void ParticlesMaterial::init_shaders() {
shader_names->emission_ring_radius = "emission_ring_radius";
shader_names->emission_ring_inner_radius = "emission_ring_inner_radius";
- shader_names->turbulence_active = "turbulence_active";
+ shader_names->turbulence_enabled = "turbulence_enabled";
shader_names->turbulence_noise_strength = "turbulence_noise_strength";
shader_names->turbulence_noise_scale = "turbulence_noise_scale";
shader_names->turbulence_noise_speed = "turbulence_noise_speed";
@@ -292,7 +292,7 @@ void ParticlesMaterial::_update_shader() {
code += "uniform float collision_bounce;\n";
}
- if (turbulence_active) {
+ if (turbulence_enabled) {
code += "uniform float turbulence_noise_strength;\n";
code += "uniform float turbulence_noise_scale;\n";
code += "uniform float turbulence_influence_min;\n";
@@ -546,7 +546,7 @@ void ParticlesMaterial::_update_shader() {
}
code += " if (RESTART_VELOCITY) VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n";
// Apply noise/turbulence: initial displacement.
- if (turbulence_active) {
+ if (turbulence_enabled) {
if (get_turbulence_noise_speed_random() >= 0.0) {
code += " vec3 time_noise = noise_3d( vec3(TIME) * turbulence_noise_speed_random ) * -turbulence_noise_speed;\n";
} else {
@@ -680,7 +680,7 @@ void ParticlesMaterial::_update_shader() {
}
// Apply noise/turbulence.
- if (turbulence_active) {
+ if (turbulence_enabled) {
code += " // apply turbulence\n";
if (tex_parameters[PARAM_TURB_INFLUENCE_OVER_LIFE].is_valid()) {
code += " float turbulence_influence = textureLod(turbulence_influence_over_life, vec2(tv, 0.0), 0.0).r;\n";
@@ -837,7 +837,7 @@ void ParticlesMaterial::_update_shader() {
code += " } else {\n";
code += " VELOCITY = vec3(0.0);\n";
// If turbulence is enabled, set the noise direction to up so the turbulence color is "neutral"
- if (turbulence_active) {
+ if (turbulence_enabled) {
code += " noise_direction = vec3(1.0, 0.0, 0.0);\n";
}
code += " }\n";
@@ -1311,15 +1311,15 @@ real_t ParticlesMaterial::get_emission_ring_inner_radius() const {
return emission_ring_inner_radius;
}
-void ParticlesMaterial::set_turbulence_active(const bool p_turbulence_active) {
- turbulence_active = p_turbulence_active;
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_active, turbulence_active);
+void ParticlesMaterial::set_turbulence_enabled(const bool p_turbulence_enabled) {
+ turbulence_enabled = p_turbulence_enabled;
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_enabled, turbulence_enabled);
_queue_shader_change();
notify_property_list_changed();
}
-bool ParticlesMaterial::get_turbulence_active() const {
- return turbulence_active;
+bool ParticlesMaterial::get_turbulence_enabled() const {
+ return turbulence_enabled;
}
void ParticlesMaterial::set_turbulence_noise_strength(float p_turbulence_noise_strength) {
@@ -1423,7 +1423,7 @@ void ParticlesMaterial::_validate_property(PropertyInfo &property) const {
property.usage = PROPERTY_USAGE_NONE;
}
- if (!turbulence_active) {
+ if (!turbulence_enabled) {
if (property.name == "turbulence_noise_strength" ||
property.name == "turbulence_noise_scale" ||
property.name == "turbulence_noise_speed" ||
@@ -1433,7 +1433,7 @@ void ParticlesMaterial::_validate_property(PropertyInfo &property) const {
property.name == "turbulence_influence_max" ||
property.name == "turbulence_initial_displacement_min" ||
property.name == "turbulence_initial_displacement_max") {
- property.usage = PROPERTY_USAGE_NONE;
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
}
@@ -1587,8 +1587,8 @@ void ParticlesMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emission_ring_inner_radius", "inner_radius"), &ParticlesMaterial::set_emission_ring_inner_radius);
ClassDB::bind_method(D_METHOD("get_emission_ring_inner_radius"), &ParticlesMaterial::get_emission_ring_inner_radius);
- ClassDB::bind_method(D_METHOD("get_turbulence_active"), &ParticlesMaterial::get_turbulence_active);
- ClassDB::bind_method(D_METHOD("set_turbulence_active", "turbulence_active"), &ParticlesMaterial::set_turbulence_active);
+ ClassDB::bind_method(D_METHOD("get_turbulence_enabled"), &ParticlesMaterial::get_turbulence_enabled);
+ ClassDB::bind_method(D_METHOD("set_turbulence_enabled", "turbulence_enabled"), &ParticlesMaterial::set_turbulence_enabled);
ClassDB::bind_method(D_METHOD("get_turbulence_noise_strength"), &ParticlesMaterial::get_turbulence_noise_strength);
ClassDB::bind_method(D_METHOD("set_turbulence_noise_strength", "turbulence_noise_strength"), &ParticlesMaterial::set_turbulence_noise_strength);
@@ -1706,7 +1706,7 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_HUE_VARIATION);
ADD_GROUP("Turbulence", "turbulence_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "turbulence_active"), "set_turbulence_active", "get_turbulence_active");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "turbulence_enabled"), "set_turbulence_enabled", "get_turbulence_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbulence_noise_strength", PROPERTY_HINT_RANGE, "0,20,0.01"), "set_turbulence_noise_strength", "get_turbulence_noise_strength");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbulence_noise_scale", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_turbulence_noise_scale", "get_turbulence_noise_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "turbulence_noise_speed"), "set_turbulence_noise_speed", "get_turbulence_noise_speed");
@@ -1815,7 +1815,7 @@ ParticlesMaterial::ParticlesMaterial() :
set_emission_ring_radius(1);
set_emission_ring_inner_radius(0);
- set_turbulence_active(false);
+ set_turbulence_enabled(false);
set_turbulence_noise_speed(Vector3(0.5, 0.5, 0.5));
set_turbulence_noise_strength(1);
set_turbulence_noise_scale(9);
diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h
index 18ab60a431..7fb46d6ac5 100644
--- a/scene/resources/particles_material.h
+++ b/scene/resources/particles_material.h
@@ -108,7 +108,7 @@ private:
uint32_t attractor_enabled : 1;
uint32_t collision_enabled : 1;
uint32_t collision_scale : 1;
- uint32_t turbulence_active : 1;
+ uint32_t turbulence_enabled : 1;
};
uint64_t key = 0;
@@ -156,7 +156,7 @@ private:
mk.collision_enabled = collision_enabled;
mk.attractor_enabled = attractor_interaction_enabled;
mk.collision_scale = collision_scale;
- mk.turbulence_active = turbulence_active;
+ mk.turbulence_enabled = turbulence_enabled;
return mk;
}
@@ -221,7 +221,7 @@ private:
StringName emission_ring_radius;
StringName emission_ring_inner_radius;
- StringName turbulence_active;
+ StringName turbulence_enabled;
StringName turbulence_noise_strength;
StringName turbulence_noise_scale;
StringName turbulence_noise_speed;
@@ -282,7 +282,7 @@ private:
bool anim_loop = false;
- bool turbulence_active;
+ bool turbulence_enabled;
Vector3 turbulence_noise_speed;
Ref<Texture2D> turbulence_color_ramp;
float turbulence_noise_strength = 0.0f;
@@ -364,13 +364,13 @@ public:
real_t get_emission_ring_inner_radius() const;
int get_emission_point_count() const;
- void set_turbulence_active(bool p_turbulence_active);
+ void set_turbulence_enabled(bool p_turbulence_enabled);
void set_turbulence_noise_strength(float p_turbulence_noise_strength);
void set_turbulence_noise_scale(float p_turbulence_noise_scale);
void set_turbulence_noise_speed_random(float p_turbulence_noise_speed_random);
void set_turbulence_noise_speed(const Vector3 &p_turbulence_noise_speed);
- bool get_turbulence_active() const;
+ bool get_turbulence_enabled() const;
float get_turbulence_noise_strength() const;
float get_turbulence_noise_scale() const;
float get_turbulence_noise_speed_random() const;
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 5e0627a7d9..a67716d52b 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -2647,6 +2647,10 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_index", "VIEW_INDEX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_mono_left", "VIEW_MONO_LEFT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_world", "NODE_POSITION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_position_world", "CAMERA_POSITION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_direction_world", "CAMERA_DIRECTION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_view", "NODE_POSITION_VIEW" },
// Node3D, Fragment
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
@@ -2675,6 +2679,10 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_index", "VIEW_INDEX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_mono_left", "VIEW_MONO_LEFT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_world", "NODE_POSITION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_position_world", "CAMERA_POSITION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_direction_world", "CAMERA_DIRECTION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_view", "NODE_POSITION_VIEW" },
// Node3D, Light
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index b8667f07fe..5cc2073ca5 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -5581,12 +5581,16 @@ String get_sampler_hint(VisualShaderNodeTextureUniform::TextureType p_texture_ty
case VisualShaderNodeTextureUniform::TYPE_DATA:
if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_BLACK) {
type_code = "hint_default_black";
+ } else if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_TRANSPARENT) {
+ type_code = "hint_default_transparent";
}
break;
case VisualShaderNodeTextureUniform::TYPE_COLOR:
type_code = "source_color";
if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_BLACK) {
type_code += ", hint_default_black";
+ } else if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_TRANSPARENT) {
+ type_code += ", hint_default_transparent";
}
break;
case VisualShaderNodeTextureUniform::TYPE_NORMAL_MAP:
@@ -5812,7 +5816,7 @@ void VisualShaderNodeTextureUniform::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_texture_repeat"), &VisualShaderNodeTextureUniform::get_texture_repeat);
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normal Map,Anisotropic"), "set_texture_type", "get_texture_type");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "color_default", PROPERTY_HINT_ENUM, "White,Black"), "set_color_default", "get_color_default");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "color_default", PROPERTY_HINT_ENUM, "White,Black,Transparent"), "set_color_default", "get_color_default");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Default,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Default,Enabled,Disabled"), "set_texture_repeat", "get_texture_repeat");
@@ -5824,6 +5828,7 @@ void VisualShaderNodeTextureUniform::_bind_methods() {
BIND_ENUM_CONSTANT(COLOR_DEFAULT_WHITE);
BIND_ENUM_CONSTANT(COLOR_DEFAULT_BLACK);
+ BIND_ENUM_CONSTANT(COLOR_DEFAULT_TRANSPARENT);
BIND_ENUM_CONSTANT(COLOR_DEFAULT_MAX);
BIND_ENUM_CONSTANT(FILTER_DEFAULT);
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index 1eb7b7240f..f770156d14 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -2131,6 +2131,7 @@ public:
enum ColorDefault {
COLOR_DEFAULT_WHITE,
COLOR_DEFAULT_BLACK,
+ COLOR_DEFAULT_TRANSPARENT,
COLOR_DEFAULT_MAX,
};
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index 6da48fde9c..86e5e4802b 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -605,9 +605,13 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from,
}
if (p_antialiased) {
- float border_size = 2.0;
- if (p_width < border_size) {
- border_size = p_width;
+ // Use the same antialiasing feather size as StyleBoxFlat's default
+ // (but doubled, as it's specified for both sides here).
+ // This value is empirically determined to provide good antialiasing quality
+ // while not making lines appear too soft.
+ float border_size = 1.25f;
+ if (p_width < 1.0f) {
+ border_size *= p_width;
}
Vector2 dir2 = diff.normalized();
@@ -774,9 +778,13 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
Color *colors_ptr = colors.ptrw();
if (p_antialiased) {
- float border_size = 2.0;
- if (p_width < border_size) {
- border_size = p_width;
+ // Use the same antialiasing feather size as StyleBoxFlat's default
+ // (but doubled, as it's specified for both sides here).
+ // This value is empirically determined to provide good antialiasing quality
+ // while not making lines appear too soft.
+ float border_size = 1.25f;
+ if (p_width < 1.0f) {
+ border_size *= p_width;
}
Color color2 = Color(1, 1, 1, 0);
diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp
index 7cda0337b8..feafcc42c9 100644
--- a/servers/rendering/renderer_rd/environment/gi.cpp
+++ b/servers/rendering/renderer_rd/environment/gi.cpp
@@ -1591,34 +1591,24 @@ void GI::SDFGI::debug_draw(uint32_t p_view_count, const Projection *p_projection
push_constant.max_cascades = cascades.size();
push_constant.screen_size[0] = p_width;
push_constant.screen_size[1] = p_height;
- push_constant.probe_axis_size = probe_axis_count;
- push_constant.use_occlusion = uses_occlusion;
push_constant.y_mult = y_mult;
push_constant.z_near = -p_projections[v].get_z_near();
- push_constant.cam_transform[0] = p_transform.basis.rows[0][0];
- push_constant.cam_transform[1] = p_transform.basis.rows[1][0];
- push_constant.cam_transform[2] = p_transform.basis.rows[2][0];
- push_constant.cam_transform[3] = 0;
- push_constant.cam_transform[4] = p_transform.basis.rows[0][1];
- push_constant.cam_transform[5] = p_transform.basis.rows[1][1];
- push_constant.cam_transform[6] = p_transform.basis.rows[2][1];
- push_constant.cam_transform[7] = 0;
- push_constant.cam_transform[8] = p_transform.basis.rows[0][2];
- push_constant.cam_transform[9] = p_transform.basis.rows[1][2];
- push_constant.cam_transform[10] = p_transform.basis.rows[2][2];
- push_constant.cam_transform[11] = 0;
- push_constant.cam_transform[12] = p_transform.origin.x;
- push_constant.cam_transform[13] = p_transform.origin.y;
- push_constant.cam_transform[14] = p_transform.origin.z;
- push_constant.cam_transform[15] = 1;
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ push_constant.cam_basis[i][j] = p_transform.basis.rows[j][i];
+ }
+ }
+ push_constant.cam_origin[0] = p_transform.origin[0];
+ push_constant.cam_origin[1] = p_transform.origin[1];
+ push_constant.cam_origin[2] = p_transform.origin[2];
// need to properly unproject for asymmetric projection matrices in stereo..
Projection inv_projection = p_projections[v].inverse();
for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- push_constant.inv_projection[i * 4 + j] = inv_projection.matrix[i][j];
+ for (int j = 0; j < 3; j++) {
+ push_constant.inv_projection[j][i] = inv_projection.matrix[i][j];
}
}
diff --git a/servers/rendering/renderer_rd/environment/gi.h b/servers/rendering/renderer_rd/environment/gi.h
index d4d4182950..304df1605b 100644
--- a/servers/rendering/renderer_rd/environment/gi.h
+++ b/servers/rendering/renderer_rd/environment/gi.h
@@ -232,16 +232,13 @@ private:
uint32_t max_cascades;
int32_t screen_size[2];
- uint32_t use_occlusion;
float y_mult;
- uint32_t probe_axis_size;
float z_near;
- float reserved1;
- float reserved2;
- float cam_transform[16];
- float inv_projection[16];
+ float inv_projection[3][4];
+ float cam_basis[3][3];
+ float cam_origin[3];
};
SdfgiDebugShaderRD debug;
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 7eddc1fb5b..827cce6047 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -2662,7 +2662,11 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
RD::Uniform u;
u.binding = 1;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.append_id(scene_state.instance_buffer[RENDER_LIST_SECONDARY]);
+ RID instance_buffer = scene_state.instance_buffer[RENDER_LIST_SECONDARY];
+ if (instance_buffer == RID()) {
+ instance_buffer = scene_shader.default_vec4_xform_buffer; // any buffer will do since its not used
+ }
+ u.append_id(instance_buffer);
uniforms.push_back(u);
}
{
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index 0faf2e2463..50ac08b57a 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -693,6 +693,11 @@ void SceneShaderForwardClustered::init(const String p_defines) {
actions.renames["CUSTOM3"] = "custom3_attrib";
actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
+ actions.renames["NODE_POSITION_WORLD"] = "model_matrix[3].xyz";
+ actions.renames["CAMERA_POSITION_WORLD"] = "scene_data.inv_view_matrix[3].xyz";
+ actions.renames["CAMERA_DIRECTION_WORLD"] = "scene_data.view_matrix[3].xyz";
+ actions.renames["NODE_POSITION_VIEW"] = "(model_matrix * scene_data.view_matrix)[3].xyz";
+
actions.renames["VIEW_INDEX"] = "ViewIndex";
actions.renames["VIEW_MONO_LEFT"] = "0";
actions.renames["VIEW_RIGHT"] = "1";
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index 0593178829..ed5399a3af 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -595,6 +595,11 @@ void SceneShaderForwardMobile::init(const String p_defines) {
actions.renames["CUSTOM3"] = "custom3_attrib";
actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
+ actions.renames["NODE_POSITION_WORLD"] = "model_matrix[3].xyz";
+ actions.renames["CAMERA_POSITION_WORLD"] = "scene_data.inv_view_matrix[3].xyz";
+ actions.renames["CAMERA_DIRECTION_WORLD"] = "scene_data.view_matrix[3].xyz";
+ actions.renames["NODE_POSITION_VIEW"] = "(model_matrix * scene_data.view_matrix)[3].xyz";
+
actions.renames["VIEW_INDEX"] = "ViewIndex";
actions.renames["VIEW_MONO_LEFT"] = "0";
actions.renames["VIEW_RIGHT"] = "1";
diff --git a/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl b/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl
index af5f7d0a58..9640d30e78 100644
--- a/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl
@@ -37,16 +37,14 @@ layout(push_constant, std430) uniform Params {
uint max_cascades;
ivec2 screen_size;
- bool use_occlusion;
float y_mult;
- int probe_axis_size;
float z_near;
- float reserved1;
- float reserved2;
- mat4 cam_transform;
- mat4 inv_projection;
+ mat3x4 inv_projection;
+ // We pack these more tightly than mat3 and vec3, which will require some reconstruction trickery.
+ float cam_basis[3][3];
+ float cam_origin[3];
}
params;
@@ -82,13 +80,21 @@ void main() {
vec3 ray_pos;
vec3 ray_dir;
{
- ray_pos = params.cam_transform[3].xyz;
+ ray_pos = vec3(params.cam_origin[0], params.cam_origin[1], params.cam_origin[2]);
ray_dir.xy = ((vec2(screen_pos) / vec2(params.screen_size)) * 2.0 - 1.0);
ray_dir.z = params.z_near;
- ray_dir = (params.inv_projection * vec4(ray_dir, 1.0)).xyz;
- ray_dir = normalize(mat3(params.cam_transform) * ray_dir);
+ ray_dir = (vec4(ray_dir, 1.0) * mat4(params.inv_projection)).xyz;
+
+ mat3 cam_basis;
+ {
+ vec3 c0 = vec3(params.cam_basis[0][0], params.cam_basis[0][1], params.cam_basis[0][2]);
+ vec3 c1 = vec3(params.cam_basis[1][0], params.cam_basis[1][1], params.cam_basis[1][2]);
+ vec3 c2 = vec3(params.cam_basis[2][0], params.cam_basis[2][1], params.cam_basis[2][2]);
+ cam_basis = mat3(c0, c1, c2);
+ }
+ ray_dir = normalize(cam_basis * ray_dir);
}
ray_pos.y *= params.y_mult;
diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl
index 4369bddc83..fb5759bc17 100644
--- a/servers/rendering/renderer_rd/shaders/particles.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles.glsl
@@ -458,11 +458,11 @@ void main() {
} break;
case ATTRACTOR_TYPE_VECTOR_FIELD: {
- vec3 uvw_pos = (local_pos / FRAME.attractors[i].extents) * 2.0 - 1.0;
+ vec3 uvw_pos = (local_pos / FRAME.attractors[i].extents + 1.0) * 0.5;
if (any(lessThan(uvw_pos, vec3(0.0))) || any(greaterThan(uvw_pos, vec3(1.0)))) {
continue;
}
- vec3 s = texture(sampler3D(sdf_vec_textures[FRAME.attractors[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).xyz;
+ vec3 s = texture(sampler3D(sdf_vec_textures[FRAME.attractors[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).xyz * 2.0 - 1.0;
dir = mat3(FRAME.attractors[i].transform) * safe_normalize(s); //revert direction
amount = length(s);
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
index 8297e72260..88ce6c261c 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
@@ -1125,6 +1125,9 @@ void MaterialStorage::MaterialData::update_textures(const HashMap<StringName, Va
case ShaderLanguage::ShaderNode::Uniform::HINT_DEFAULT_BLACK: {
rd_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
} break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_DEFAULT_TRANSPARENT: {
+ rd_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_TRANSPARENT);
+ } break;
case ShaderLanguage::ShaderNode::Uniform::HINT_ANISOTROPY: {
rd_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_ANISO);
} break;
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index 17a6ad57f9..e20a04ff2a 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -96,6 +96,7 @@ TextureStorage::TextureStorage() {
Vector<uint8_t> pv;
pv.resize(16 * 4);
for (int i = 0; i < 16; i++) {
+ // Opaque white.
pv.set(i * 4 + 0, 255);
pv.set(i * 4 + 1, 255);
pv.set(i * 4 + 2, 255);
@@ -109,6 +110,7 @@ TextureStorage::TextureStorage() {
}
for (int i = 0; i < 16; i++) {
+ // Opaque black.
pv.set(i * 4 + 0, 0);
pv.set(i * 4 + 1, 0);
pv.set(i * 4 + 2, 0);
@@ -122,6 +124,21 @@ TextureStorage::TextureStorage() {
}
for (int i = 0; i < 16; i++) {
+ // Transparent black.
+ pv.set(i * 4 + 0, 0);
+ pv.set(i * 4 + 1, 0);
+ pv.set(i * 4 + 2, 0);
+ pv.set(i * 4 + 3, 0);
+ }
+
+ {
+ Vector<Vector<uint8_t>> vpv;
+ vpv.push_back(pv);
+ default_rd_textures[DEFAULT_RD_TEXTURE_TRANSPARENT] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ }
+
+ for (int i = 0; i < 16; i++) {
+ // Opaque normal map "flat" color.
pv.set(i * 4 + 0, 128);
pv.set(i * 4 + 1, 128);
pv.set(i * 4 + 2, 255);
@@ -135,6 +152,7 @@ TextureStorage::TextureStorage() {
}
for (int i = 0; i < 16; i++) {
+ // Opaque flowmap "flat" color.
pv.set(i * 4 + 0, 255);
pv.set(i * 4 + 1, 128);
pv.set(i * 4 + 2, 255);
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
index f07f764761..682c951f63 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
@@ -46,6 +46,7 @@ public:
enum DefaultRDTexture {
DEFAULT_RD_TEXTURE_WHITE,
DEFAULT_RD_TEXTURE_BLACK,
+ DEFAULT_RD_TEXTURE_TRANSPARENT,
DEFAULT_RD_TEXTURE_NORMAL,
DEFAULT_RD_TEXTURE_ANISO,
DEFAULT_RD_TEXTURE_DEPTH,
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 2dd0f7006b..7de175647b 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -195,6 +195,7 @@ const char *ShaderLanguage::token_names[TK_MAX] = {
"SOURCE_COLOR",
"HINT_DEFAULT_WHITE_TEXTURE",
"HINT_DEFAULT_BLACK_TEXTURE",
+ "HINT_DEFAULT_TRANSPARENT_TEXTURE",
"HINT_NORMAL_TEXTURE",
"HINT_ANISOTROPY_TEXTURE",
"HINT_RANGE",
@@ -354,6 +355,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
{ TK_HINT_NORMAL_TEXTURE, "hint_normal", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_DEFAULT_WHITE_TEXTURE, "hint_default_white", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_DEFAULT_BLACK_TEXTURE, "hint_default_black", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_DEFAULT_TRANSPARENT_TEXTURE, "hint_default_transparent", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_ANISOTROPY_TEXTURE, "hint_anisotropy", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_ROUGHNESS_R, "hint_roughness_r", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_ROUGHNESS_G, "hint_roughness_g", CF_UNSPECIFIED, {}, {} },
@@ -1088,6 +1090,9 @@ String ShaderLanguage::get_uniform_hint_name(ShaderNode::Uniform::Hint p_hint) {
case ShaderNode::Uniform::HINT_DEFAULT_WHITE: {
result = "hint_default_white";
} break;
+ case ShaderNode::Uniform::HINT_DEFAULT_TRANSPARENT: {
+ result = "hint_default_transparent";
+ } break;
case ShaderNode::Uniform::HINT_ANISOTROPY: {
result = "hint_anisotropy";
} break;
@@ -8410,6 +8415,9 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
case TK_HINT_DEFAULT_WHITE_TEXTURE: {
new_hint = ShaderNode::Uniform::HINT_DEFAULT_WHITE;
} break;
+ case TK_HINT_DEFAULT_TRANSPARENT_TEXTURE: {
+ new_hint = ShaderNode::Uniform::HINT_DEFAULT_TRANSPARENT;
+ } break;
case TK_HINT_NORMAL_TEXTURE: {
new_hint = ShaderNode::Uniform::HINT_NORMAL;
} break;
@@ -10248,6 +10256,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
options.push_back("hint_anisotropy");
options.push_back("hint_default_black");
options.push_back("hint_default_white");
+ options.push_back("hint_default_transparent");
options.push_back("hint_normal");
options.push_back("hint_roughness_a");
options.push_back("hint_roughness_b");
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index 09160e2949..bfec6e1df6 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -164,6 +164,7 @@ public:
TK_RENDER_MODE,
TK_HINT_DEFAULT_WHITE_TEXTURE,
TK_HINT_DEFAULT_BLACK_TEXTURE,
+ TK_HINT_DEFAULT_TRANSPARENT_TEXTURE,
TK_HINT_NORMAL_TEXTURE,
TK_HINT_ROUGHNESS_NORMAL_TEXTURE,
TK_HINT_ROUGHNESS_R,
@@ -664,6 +665,7 @@ public:
HINT_ROUGHNESS_GRAY,
HINT_DEFAULT_BLACK,
HINT_DEFAULT_WHITE,
+ HINT_DEFAULT_TRANSPARENT,
HINT_ANISOTROPY,
HINT_MAX
};
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index 5772179d68..43c483a00d 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -97,6 +97,11 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NODE_POSITION_WORLD"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_POSITION_WORLD"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_DIRECTION_WORLD"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NODE_POSITION_VIEW"] = ShaderLanguage::TYPE_VEC3;
+
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_INDEX"] = constt(ShaderLanguage::TYPE_INT);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_MONO_LEFT"] = constt(ShaderLanguage::TYPE_INT);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_RIGHT"] = constt(ShaderLanguage::TYPE_INT);
@@ -139,6 +144,11 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NODE_POSITION_WORLD"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_POSITION_WORLD"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_DIRECTION_WORLD"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NODE_POSITION_VIEW"] = ShaderLanguage::TYPE_VEC3;
+
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_INDEX"] = constt(ShaderLanguage::TYPE_INT);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_MONO_LEFT"] = constt(ShaderLanguage::TYPE_INT);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_RIGHT"] = constt(ShaderLanguage::TYPE_INT);
diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp
index 47598abce7..59310ab69b 100644
--- a/servers/text/text_server_extension.cpp
+++ b/servers/text/text_server_extension.cpp
@@ -297,9 +297,13 @@ void TextServerExtension::_bind_methods() {
GDVIRTUAL_BIND(percent_sign, "language");
GDVIRTUAL_BIND(strip_diacritics, "string");
+ GDVIRTUAL_BIND(is_valid_identifier, "string");
GDVIRTUAL_BIND(string_get_word_breaks, "string", "language");
+ GDVIRTUAL_BIND(is_confusable, "string", "dict");
+ GDVIRTUAL_BIND(spoof_check, "string");
+
GDVIRTUAL_BIND(string_to_upper, "string", "language");
GDVIRTUAL_BIND(string_to_lower, "string", "language");
@@ -1498,6 +1502,14 @@ String TextServerExtension::percent_sign(const String &p_language) const {
return "%";
}
+bool TextServerExtension::is_valid_identifier(const String &p_string) const {
+ bool ret;
+ if (GDVIRTUAL_CALL(is_valid_identifier, p_string, ret)) {
+ return ret;
+ }
+ return TextServer::is_valid_identifier(p_string);
+}
+
String TextServerExtension::strip_diacritics(const String &p_string) const {
String ret;
if (GDVIRTUAL_CALL(strip_diacritics, p_string, ret)) {
@@ -1538,6 +1550,22 @@ PackedInt32Array TextServerExtension::string_get_word_breaks(const String &p_str
return PackedInt32Array();
}
+int TextServerExtension::is_confusable(const String &p_string, const PackedStringArray &p_dict) const {
+ int ret;
+ if (GDVIRTUAL_CALL(is_confusable, p_string, p_dict, ret)) {
+ return ret;
+ }
+ return TextServer::is_confusable(p_string, p_dict);
+}
+
+bool TextServerExtension::spoof_check(const String &p_string) const {
+ bool ret;
+ if (GDVIRTUAL_CALL(spoof_check, p_string, ret)) {
+ return ret;
+ }
+ return TextServer::spoof_check(p_string);
+}
+
TextServerExtension::TextServerExtension() {
//NOP
}
diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h
index 571753ea67..81af1b60e5 100644
--- a/servers/text/text_server_extension.h
+++ b/servers/text/text_server_extension.h
@@ -496,6 +496,9 @@ public:
virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const override;
GDVIRTUAL2RC(PackedInt32Array, string_get_word_breaks, const String &, const String &);
+ virtual bool is_valid_identifier(const String &p_string) const override;
+ GDVIRTUAL1RC(bool, is_valid_identifier, const String &);
+
virtual String string_to_upper(const String &p_string, const String &p_language = "") const override;
virtual String string_to_lower(const String &p_string, const String &p_language = "") const override;
GDVIRTUAL2RC(String, string_to_upper, const String &, const String &);
@@ -504,6 +507,11 @@ public:
Array parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
GDVIRTUAL3RC(Array, parse_structured_text, StructuredTextParser, const Array &, const String &);
+ virtual int is_confusable(const String &p_string, const PackedStringArray &p_dict) const override;
+ virtual bool spoof_check(const String &p_string) const override;
+ GDVIRTUAL2RC(int, is_confusable, const String &, const PackedStringArray &);
+ GDVIRTUAL1RC(bool, spoof_check, const String &);
+
TextServerExtension();
~TextServerExtension();
};
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index 4a6b03d943..fd63a7b99d 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -446,7 +446,11 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("string_get_word_breaks", "string", "language"), &TextServer::string_get_word_breaks, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("is_confusable", "string", "dict"), &TextServer::is_confusable);
+ ClassDB::bind_method(D_METHOD("spoof_check", "string"), &TextServer::spoof_check);
+
ClassDB::bind_method(D_METHOD("strip_diacritics", "string"), &TextServer::strip_diacritics);
+ ClassDB::bind_method(D_METHOD("is_valid_identifier", "string"), &TextServer::is_valid_identifier);
ClassDB::bind_method(D_METHOD("string_to_upper", "string", "language"), &TextServer::string_to_upper, DEFVAL(""));
ClassDB::bind_method(D_METHOD("string_to_lower", "string", "language"), &TextServer::string_to_lower, DEFVAL(""));
@@ -545,6 +549,8 @@ void TextServer::_bind_methods() {
BIND_ENUM_CONSTANT(FEATURE_FONT_VARIABLE);
BIND_ENUM_CONSTANT(FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION);
BIND_ENUM_CONSTANT(FEATURE_USE_SUPPORT_DATA);
+ BIND_ENUM_CONSTANT(FEATURE_UNICODE_IDENTIFIERS);
+ BIND_ENUM_CONSTANT(FEATURE_UNICODE_SECURITY);
/* FT Contour Point Types */
BIND_ENUM_CONSTANT(CONTOUR_CURVE_TAG_ON);
@@ -1730,6 +1736,26 @@ Array TextServer::_shaped_text_get_ellipsis_glyphs_wrapper(const RID &p_shaped)
return ret;
}
+bool TextServer::is_valid_identifier(const String &p_string) const {
+ const char32_t *str = p_string.ptr();
+ int len = p_string.length();
+
+ if (len == 0) {
+ return false; // Empty string.
+ }
+
+ if (!is_unicode_identifier_start(str[0])) {
+ return false;
+ }
+
+ for (int i = 1; i < len; i++) {
+ if (!is_unicode_identifier_continue(str[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
TextServer::TextServer() {
_init_diacritics_map();
}
diff --git a/servers/text_server.h b/servers/text_server.h
index f6ab165bfc..5874b8f6e8 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -148,6 +148,8 @@ public:
FEATURE_FONT_VARIABLE = 1 << 10,
FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION = 1 << 11,
FEATURE_USE_SUPPORT_DATA = 1 << 12,
+ FEATURE_UNICODE_IDENTIFIERS = 1 << 13,
+ FEATURE_UNICODE_SECURITY = 1 << 14,
};
enum ContourPointTag {
@@ -463,7 +465,11 @@ public:
// String functions.
virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const = 0;
+ virtual int is_confusable(const String &p_string, const PackedStringArray &p_dict) const { return -1; };
+ virtual bool spoof_check(const String &p_string) const { return false; };
+
virtual String strip_diacritics(const String &p_string) const;
+ virtual bool is_valid_identifier(const String &p_string) const;
// Other string operations.
virtual String string_to_upper(const String &p_string, const String &p_language = "") const = 0;
diff --git a/tests/servers/test_text_server.h b/tests/servers/test_text_server.h
index 61207216fc..57a2cae37f 100644
--- a/tests/servers/test_text_server.h
+++ b/tests/servers/test_text_server.h
@@ -39,7 +39,7 @@
namespace TestTextServer {
-TEST_SUITE("[[TextServer]") {
+TEST_SUITE("[TextServer]") {
TEST_CASE("[TextServer] Init, font loading and shaping") {
SUBCASE("[TextServer] Loading fonts") {
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
@@ -492,6 +492,27 @@ TEST_SUITE("[[TextServer]") {
}
}
+ SUBCASE("[TextServer] Unicode identifiers") {
+ for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
+ Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i);
+ TEST_FAIL_COND(ts.is_null(), "Invalid TS interface.");
+
+ static const char32_t *data[19] = { U"-30", U"100", U"10.1", U"10,1", U"1e2", U"1e-2", U"1e2e3", U"0xAB", U"AB", U"Test1", U"1Test", U"Test*1", U"test_testeT", U"test_tes teT", U"عَلَيْكُمْ", U"عَلَيْكُمْTest", U"ӒӖӚӜ", U"_test", U"ÂÃÄÅĀĂĄÇĆĈĊ" };
+ static bool isid[19] = { false, false, false, false, false, false, false, false, true, true, false, false, true, false, true, true, true, true, true };
+ for (int j = 0; j < 19; j++) {
+ String s = String(data[j]);
+ CHECK(ts->is_valid_identifier(s) == isid[j]);
+ }
+
+ if (ts->has_feature(TextServer::FEATURE_UNICODE_IDENTIFIERS)) {
+ // Test UAX 3.2 ZW(N)J usage.
+ CHECK(ts->is_valid_identifier(U"\u0646\u0627\u0645\u0647\u200C\u0627\u06CC"));
+ CHECK(ts->is_valid_identifier(U"\u0D26\u0D43\u0D15\u0D4D\u200C\u0D38\u0D3E\u0D15\u0D4D\u0D37\u0D3F"));
+ CHECK(ts->is_valid_identifier(U"\u0DC1\u0DCA\u200D\u0DBB\u0DD3"));
+ }
+ }
+ }
+
SUBCASE("[TextServer] Strip Diacritics") {
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i);
diff --git a/tests/test_macros.h b/tests/test_macros.h
index eff09fb4b0..69ae0d3124 100644
--- a/tests/test_macros.h
+++ b/tests/test_macros.h
@@ -31,6 +31,7 @@
#ifndef TEST_MACROS_H
#define TEST_MACROS_H
+#include "core/core_globals.h"
#include "core/input/input_map.h"
#include "core/object/message_queue.h"
#include "core/variant/variant.h"
@@ -53,12 +54,12 @@
// Temporarily disable error prints to test failure paths.
// This allows to avoid polluting the test summary with error messages.
-// The `_print_error_enabled` boolean is defined in `core/print_string.cpp` and
+// The `print_error_enabled` boolean is defined in `core/core_globals.cpp` and
// works at global scope. It's used by various loggers in `should_log()` method,
// which are used by error macros which call into `OS::print_error`, effectively
// disabling any error messages to be printed from the engine side (not tests).
-#define ERR_PRINT_OFF _print_error_enabled = false;
-#define ERR_PRINT_ON _print_error_enabled = true;
+#define ERR_PRINT_OFF CoreGlobals::print_error_enabled = false;
+#define ERR_PRINT_ON CoreGlobals::print_error_enabled = true;
// Stringify all `Variant` compatible types for doctest output by default.
// https://github.com/onqtam/doctest/blob/master/doc/markdown/stringification.md
@@ -199,8 +200,8 @@ int register_test_command(String p_command, TestFunc p_function);
// We toggle _print_error_enabled to prevent display server not supported warnings.
#define SEND_GUI_MOUSE_MOTION_EVENT(m_object, m_local_pos, m_mask, m_modifers) \
{ \
- bool errors_enabled = _print_error_enabled; \
- _print_error_enabled = false; \
+ bool errors_enabled = CoreGlobals::print_error_enabled; \
+ CoreGlobals::print_error_enabled = false; \
Ref<InputEventMouseMotion> event; \
event.instantiate(); \
event->set_position(m_local_pos); \
@@ -209,7 +210,7 @@ int register_test_command(String p_command, TestFunc p_function);
_UPDATE_EVENT_MODIFERS(event, m_modifers); \
m_object->get_viewport()->push_input(event); \
MessageQueue::get_singleton()->flush(); \
- _print_error_enabled = errors_enabled; \
+ CoreGlobals::print_error_enabled = errors_enabled; \
}
// Utility class / macros for testing signals
diff --git a/tests/test_validate_testing.h b/tests/test_validate_testing.h
index 413a7e351d..1471a952cd 100644
--- a/tests/test_validate_testing.h
+++ b/tests/test_validate_testing.h
@@ -31,6 +31,7 @@
#ifndef TEST_VALIDATE_TESTING_H
#define TEST_VALIDATE_TESTING_H
+#include "core/core_globals.h"
#include "core/os/os.h"
#include "tests/test_macros.h"
@@ -49,10 +50,10 @@ TEST_SUITE("Validate tests") {
}
TEST_CASE("Muting Godot error messages") {
ERR_PRINT_OFF;
- CHECK_MESSAGE(!_print_error_enabled, "Error printing should be disabled.");
+ CHECK_MESSAGE(!CoreGlobals::print_error_enabled, "Error printing should be disabled.");
ERR_PRINT("Still waiting for Godot!"); // This should never get printed!
ERR_PRINT_ON;
- CHECK_MESSAGE(_print_error_enabled, "Error printing should be re-enabled.");
+ CHECK_MESSAGE(CoreGlobals::print_error_enabled, "Error printing should be re-enabled.");
}
TEST_CASE("Stringify Variant types") {
Variant var;
diff --git a/thirdparty/README.md b/thirdparty/README.md
index b06d9cec81..6db011d3c6 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -231,6 +231,8 @@ Files extracted from upstream source:
Files extracted from upstream source:
- the `common` folder
+- `scriptset.*`, `ucln_in.*`, `uspoof.cpp"` and `uspoof_impl.cpp` from the `i18n` folder
+- `uspoof.h` from the `i18n/unicode` folder
- `LICENSE`
Files generated from upstream source:
diff --git a/thirdparty/icu4c/godot_data.json b/thirdparty/icu4c/godot_data.json
index 3a9c28af4c..e36e2b078b 100644
--- a/thirdparty/icu4c/godot_data.json
+++ b/thirdparty/icu4c/godot_data.json
@@ -6,5 +6,6 @@
brkitr_tree: include
misc: include
normalization: include
+ confusables: include
}
-} \ No newline at end of file
+}
diff --git a/thirdparty/icu4c/i18n/scriptset.cpp b/thirdparty/icu4c/i18n/scriptset.cpp
new file mode 100644
index 0000000000..6a1db8c01c
--- /dev/null
+++ b/thirdparty/icu4c/i18n/scriptset.cpp
@@ -0,0 +1,313 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+**********************************************************************
+* Copyright (C) 2014, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+*
+* scriptset.cpp
+*
+* created on: 2013 Jan 7
+* created by: Andy Heninger
+*/
+
+#include "unicode/utypes.h"
+
+#include "unicode/uchar.h"
+#include "unicode/unistr.h"
+
+#include "scriptset.h"
+#include "uassert.h"
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+//----------------------------------------------------------------------------
+//
+// ScriptSet implementation
+//
+//----------------------------------------------------------------------------
+ScriptSet::ScriptSet() {
+ uprv_memset(bits, 0, sizeof(bits));
+}
+
+ScriptSet::~ScriptSet() {
+}
+
+ScriptSet::ScriptSet(const ScriptSet &other) {
+ *this = other;
+}
+
+ScriptSet & ScriptSet::operator =(const ScriptSet &other) {
+ uprv_memcpy(bits, other.bits, sizeof(bits));
+ return *this;
+}
+
+bool ScriptSet::operator == (const ScriptSet &other) const {
+ for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
+ if (bits[i] != other.bits[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+UBool ScriptSet::test(UScriptCode script, UErrorCode &status) const {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (script < 0 || (int32_t)script >= SCRIPT_LIMIT) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return FALSE;
+ }
+ uint32_t index = script / 32;
+ uint32_t bit = 1 << (script & 31);
+ return ((bits[index] & bit) != 0);
+}
+
+
+ScriptSet &ScriptSet::set(UScriptCode script, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ if (script < 0 || (int32_t)script >= SCRIPT_LIMIT) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return *this;
+ }
+ uint32_t index = script / 32;
+ uint32_t bit = 1 << (script & 31);
+ bits[index] |= bit;
+ return *this;
+}
+
+ScriptSet &ScriptSet::reset(UScriptCode script, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ if (script < 0 || (int32_t)script >= SCRIPT_LIMIT) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return *this;
+ }
+ uint32_t index = script / 32;
+ uint32_t bit = 1 << (script & 31);
+ bits[index] &= ~bit;
+ return *this;
+}
+
+
+
+ScriptSet &ScriptSet::Union(const ScriptSet &other) {
+ for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
+ bits[i] |= other.bits[i];
+ }
+ return *this;
+}
+
+ScriptSet &ScriptSet::intersect(const ScriptSet &other) {
+ for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
+ bits[i] &= other.bits[i];
+ }
+ return *this;
+}
+
+ScriptSet &ScriptSet::intersect(UScriptCode script, UErrorCode &status) {
+ ScriptSet t;
+ t.set(script, status);
+ if (U_SUCCESS(status)) {
+ this->intersect(t);
+ }
+ return *this;
+}
+
+UBool ScriptSet::intersects(const ScriptSet &other) const {
+ for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
+ if ((bits[i] & other.bits[i]) != 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+UBool ScriptSet::contains(const ScriptSet &other) const {
+ ScriptSet t(*this);
+ t.intersect(other);
+ return (t == other);
+}
+
+
+ScriptSet &ScriptSet::setAll() {
+ for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
+ bits[i] = 0xffffffffu;
+ }
+ return *this;
+}
+
+
+ScriptSet &ScriptSet::resetAll() {
+ uprv_memset(bits, 0, sizeof(bits));
+ return *this;
+}
+
+int32_t ScriptSet::countMembers() const {
+ // This bit counter is good for sparse numbers of '1's, which is
+ // very much the case that we will usually have.
+ int32_t count = 0;
+ for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
+ uint32_t x = bits[i];
+ while (x > 0) {
+ count++;
+ x &= (x - 1); // and off the least significant one bit.
+ }
+ }
+ return count;
+}
+
+int32_t ScriptSet::hashCode() const {
+ int32_t hash = 0;
+ for (int32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
+ hash ^= bits[i];
+ }
+ return hash;
+}
+
+int32_t ScriptSet::nextSetBit(int32_t fromIndex) const {
+ // TODO: Wants a better implementation.
+ if (fromIndex < 0) {
+ return -1;
+ }
+ UErrorCode status = U_ZERO_ERROR;
+ for (int32_t scriptIndex = fromIndex; scriptIndex < SCRIPT_LIMIT; scriptIndex++) {
+ if (test((UScriptCode)scriptIndex, status)) {
+ return scriptIndex;
+ }
+ }
+ return -1;
+}
+
+UBool ScriptSet::isEmpty() const {
+ for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
+ if (bits[i] != 0) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+UnicodeString &ScriptSet::displayScripts(UnicodeString &dest) const {
+ UBool firstTime = TRUE;
+ for (int32_t i = nextSetBit(0); i >= 0; i = nextSetBit(i + 1)) {
+ if (!firstTime) {
+ dest.append((UChar)0x20);
+ }
+ firstTime = FALSE;
+ const char *scriptName = uscript_getShortName((UScriptCode(i)));
+ dest.append(UnicodeString(scriptName, -1, US_INV));
+ }
+ return dest;
+}
+
+ScriptSet &ScriptSet::parseScripts(const UnicodeString &scriptString, UErrorCode &status) {
+ resetAll();
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ UnicodeString oneScriptName;
+ for (int32_t i=0; i<scriptString.length();) {
+ UChar32 c = scriptString.char32At(i);
+ i = scriptString.moveIndex32(i, 1);
+ if (!u_isUWhiteSpace(c)) {
+ oneScriptName.append(c);
+ if (i < scriptString.length()) {
+ continue;
+ }
+ }
+ if (oneScriptName.length() > 0) {
+ char buf[40];
+ oneScriptName.extract(0, oneScriptName.length(), buf, sizeof(buf)-1, US_INV);
+ buf[sizeof(buf)-1] = 0;
+ int32_t sc = u_getPropertyValueEnum(UCHAR_SCRIPT, buf);
+ if (sc == UCHAR_INVALID_CODE) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ } else {
+ this->set((UScriptCode)sc, status);
+ }
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ oneScriptName.remove();
+ }
+ }
+ return *this;
+}
+
+void ScriptSet::setScriptExtensions(UChar32 codePoint, UErrorCode& status) {
+ if (U_FAILURE(status)) { return; }
+ static const int32_t FIRST_GUESS_SCRIPT_CAPACITY = 20;
+ MaybeStackArray<UScriptCode,FIRST_GUESS_SCRIPT_CAPACITY> scripts;
+ UErrorCode internalStatus = U_ZERO_ERROR;
+ int32_t script_count = -1;
+
+ while (TRUE) {
+ script_count = uscript_getScriptExtensions(
+ codePoint, scripts.getAlias(), scripts.getCapacity(), &internalStatus);
+ if (internalStatus == U_BUFFER_OVERFLOW_ERROR) {
+ // Need to allocate more space
+ if (scripts.resize(script_count) == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ internalStatus = U_ZERO_ERROR;
+ } else {
+ break;
+ }
+ }
+
+ // Check if we failed for some reason other than buffer overflow
+ if (U_FAILURE(internalStatus)) {
+ status = internalStatus;
+ return;
+ }
+
+ // Load the scripts into the ScriptSet and return
+ for (int32_t i = 0; i < script_count; i++) {
+ this->set(scripts[i], status);
+ if (U_FAILURE(status)) { return; }
+ }
+}
+
+U_NAMESPACE_END
+
+U_CAPI UBool U_EXPORT2
+uhash_equalsScriptSet(const UElement key1, const UElement key2) {
+ icu::ScriptSet *s1 = static_cast<icu::ScriptSet *>(key1.pointer);
+ icu::ScriptSet *s2 = static_cast<icu::ScriptSet *>(key2.pointer);
+ return (*s1 == *s2);
+}
+
+U_CAPI int8_t U_EXPORT2
+uhash_compareScriptSet(UElement key0, UElement key1) {
+ icu::ScriptSet *s0 = static_cast<icu::ScriptSet *>(key0.pointer);
+ icu::ScriptSet *s1 = static_cast<icu::ScriptSet *>(key1.pointer);
+ int32_t diff = s0->countMembers() - s1->countMembers();
+ if (diff != 0) return static_cast<UBool>(diff);
+ int32_t i0 = s0->nextSetBit(0);
+ int32_t i1 = s1->nextSetBit(0);
+ while ((diff = i0-i1) == 0 && i0 > 0) {
+ i0 = s0->nextSetBit(i0+1);
+ i1 = s1->nextSetBit(i1+1);
+ }
+ return (int8_t)diff;
+}
+
+U_CAPI int32_t U_EXPORT2
+uhash_hashScriptSet(const UElement key) {
+ icu::ScriptSet *s = static_cast<icu::ScriptSet *>(key.pointer);
+ return s->hashCode();
+}
+
+U_CAPI void U_EXPORT2
+uhash_deleteScriptSet(void *obj) {
+ icu::ScriptSet *s = static_cast<icu::ScriptSet *>(obj);
+ delete s;
+}
diff --git a/thirdparty/icu4c/i18n/scriptset.h b/thirdparty/icu4c/i18n/scriptset.h
new file mode 100644
index 0000000000..51980ab7b3
--- /dev/null
+++ b/thirdparty/icu4c/i18n/scriptset.h
@@ -0,0 +1,86 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+**********************************************************************
+* Copyright (C) 2013, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+*
+* scriptset.h
+*
+* created on: 2013 Jan 7
+* created by: Andy Heninger
+*/
+
+#ifndef __SCRIPTSET_H__
+#define __SCRIPTSET_H__
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/uscript.h"
+
+#include "uelement.h"
+
+U_NAMESPACE_BEGIN
+
+//-------------------------------------------------------------------------------
+//
+// ScriptSet - A bit set representing a set of scripts.
+//
+// This class was originally used exclusively with script sets appearing
+// as part of the spoof check whole script confusable binary data. Its
+// use has since become more general, but the continued use to wrap
+// prebuilt binary data does constrain the design.
+//
+//-------------------------------------------------------------------------------
+class U_I18N_API ScriptSet: public UMemory {
+ public:
+ static constexpr int32_t SCRIPT_LIMIT = 224; // multiple of 32!
+
+ ScriptSet();
+ ScriptSet(const ScriptSet &other);
+ ~ScriptSet();
+
+ bool operator == (const ScriptSet &other) const;
+ bool operator != (const ScriptSet &other) const {return !(*this == other);}
+ ScriptSet & operator = (const ScriptSet &other);
+
+ UBool test(UScriptCode script, UErrorCode &status) const;
+ ScriptSet &Union(const ScriptSet &other);
+ ScriptSet &set(UScriptCode script, UErrorCode &status);
+ ScriptSet &reset(UScriptCode script, UErrorCode &status);
+ ScriptSet &intersect(const ScriptSet &other);
+ ScriptSet &intersect(UScriptCode script, UErrorCode &status);
+ UBool intersects(const ScriptSet &other) const; // Sets contain at least one script in common.
+ UBool contains(const ScriptSet &other) const; // All set bits in other are also set in this.
+
+ ScriptSet &setAll();
+ ScriptSet &resetAll();
+ int32_t countMembers() const;
+ int32_t hashCode() const;
+ int32_t nextSetBit(int32_t script) const;
+
+ UBool isEmpty() const;
+
+ UnicodeString &displayScripts(UnicodeString &dest) const; // append script names to dest string.
+ ScriptSet & parseScripts(const UnicodeString &scriptsString, UErrorCode &status); // Replaces ScriptSet contents.
+
+ // Wraps around UScript::getScriptExtensions() and adds the corresponding scripts to this instance.
+ void setScriptExtensions(UChar32 codePoint, UErrorCode& status);
+
+ private:
+ uint32_t bits[SCRIPT_LIMIT / 32];
+};
+
+U_NAMESPACE_END
+
+U_CAPI UBool U_EXPORT2
+uhash_compareScriptSet(const UElement key1, const UElement key2);
+
+U_CAPI int32_t U_EXPORT2
+uhash_hashScriptSet(const UElement key);
+
+U_CAPI void U_EXPORT2
+uhash_deleteScriptSet(void *obj);
+
+#endif // __SCRIPTSET_H__
diff --git a/thirdparty/icu4c/i18n/ucln_in.cpp b/thirdparty/icu4c/i18n/ucln_in.cpp
new file mode 100644
index 0000000000..f29cbe41dd
--- /dev/null
+++ b/thirdparty/icu4c/i18n/ucln_in.cpp
@@ -0,0 +1,65 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+******************************************************************************
+* *
+* Copyright (C) 2001-2014, International Business Machines *
+* Corporation and others. All Rights Reserved. *
+* *
+******************************************************************************
+* file name: ucln_in.cpp
+* encoding: UTF-8
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2001July05
+* created by: George Rhoten
+*/
+
+#include "ucln.h"
+#include "ucln_in.h"
+#include "mutex.h"
+#include "uassert.h"
+
+/** Auto-client for UCLN_I18N **/
+#define UCLN_TYPE UCLN_I18N
+#include "ucln_imp.h"
+
+/* Leave this copyright notice here! It needs to go somewhere in this library. */
+static const char copyright[] = U_COPYRIGHT_STRING;
+
+static cleanupFunc *gCleanupFunctions[UCLN_I18N_COUNT];
+
+static UBool U_CALLCONV i18n_cleanup(void)
+{
+ int32_t libType = UCLN_I18N_START;
+ (void)copyright; /* Suppress unused variable warning with clang. */
+
+ while (++libType<UCLN_I18N_COUNT) {
+ if (gCleanupFunctions[libType])
+ {
+ gCleanupFunctions[libType]();
+ gCleanupFunctions[libType] = NULL;
+ }
+ }
+#if !UCLN_NO_AUTO_CLEANUP && (defined(UCLN_AUTO_ATEXIT) || defined(UCLN_AUTO_LOCAL))
+ ucln_unRegisterAutomaticCleanup();
+#endif
+ return TRUE;
+}
+
+void ucln_i18n_registerCleanup(ECleanupI18NType type,
+ cleanupFunc *func) {
+ U_ASSERT(UCLN_I18N_START < type && type < UCLN_I18N_COUNT);
+ {
+ icu::Mutex m; // See ticket 10295 for discussion.
+ ucln_registerCleanup(UCLN_I18N, i18n_cleanup);
+ if (UCLN_I18N_START < type && type < UCLN_I18N_COUNT) {
+ gCleanupFunctions[type] = func;
+ }
+ }
+#if !UCLN_NO_AUTO_CLEANUP && (defined(UCLN_AUTO_ATEXIT) || defined(UCLN_AUTO_LOCAL))
+ ucln_registerAutomaticCleanup();
+#endif
+}
+
diff --git a/thirdparty/icu4c/i18n/ucln_in.h b/thirdparty/icu4c/i18n/ucln_in.h
new file mode 100644
index 0000000000..765cdd559f
--- /dev/null
+++ b/thirdparty/icu4c/i18n/ucln_in.h
@@ -0,0 +1,74 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+******************************************************************************
+* Copyright (C) 2001-2016, International Business Machines
+* Corporation and others. All Rights Reserved.
+******************************************************************************
+* file name: ucln_in.h
+* encoding: UTF-8
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2001July05
+* created by: George Rhoten
+*/
+
+#ifndef __UCLN_IN_H__
+#define __UCLN_IN_H__
+
+#include "unicode/utypes.h"
+#include "ucln.h"
+
+/*
+Please keep the order of enums declared in same order
+as the functions are suppose to be called.
+It's usually best to have child dependencies called first. */
+typedef enum ECleanupI18NType {
+ UCLN_I18N_START = -1,
+ UCLN_I18N_UNIT_EXTRAS,
+ UCLN_I18N_NUMBER_SKELETONS,
+ UCLN_I18N_CURRENCY_SPACING,
+ UCLN_I18N_SPOOF,
+ UCLN_I18N_SPOOFDATA,
+ UCLN_I18N_TRANSLITERATOR,
+ UCLN_I18N_REGEX,
+ UCLN_I18N_JAPANESE_CALENDAR,
+ UCLN_I18N_ISLAMIC_CALENDAR,
+ UCLN_I18N_CHINESE_CALENDAR,
+ UCLN_I18N_HEBREW_CALENDAR,
+ UCLN_I18N_ASTRO_CALENDAR,
+ UCLN_I18N_DANGI_CALENDAR,
+ UCLN_I18N_CALENDAR,
+ UCLN_I18N_TIMEZONEFORMAT,
+ UCLN_I18N_TZDBTIMEZONENAMES,
+ UCLN_I18N_TIMEZONEGENERICNAMES,
+ UCLN_I18N_TIMEZONENAMES,
+ UCLN_I18N_ZONEMETA,
+ UCLN_I18N_TIMEZONE,
+ UCLN_I18N_DIGITLIST,
+ UCLN_I18N_DECFMT,
+ UCLN_I18N_NUMFMT,
+ UCLN_I18N_ALLOWED_HOUR_FORMATS,
+ UCLN_I18N_DAYPERIODRULES,
+ UCLN_I18N_SMPDTFMT,
+ UCLN_I18N_USEARCH,
+ UCLN_I18N_COLLATOR,
+ UCLN_I18N_UCOL_RES,
+ UCLN_I18N_CSDET,
+ UCLN_I18N_COLLATION_ROOT,
+ UCLN_I18N_GENDERINFO,
+ UCLN_I18N_CDFINFO,
+ UCLN_I18N_REGION,
+ UCLN_I18N_LIST_FORMATTER,
+ UCLN_I18N_NUMSYS,
+ UCLN_I18N_COUNT /* This must be last */
+} ECleanupI18NType;
+
+/* Main library cleanup registration function. */
+/* See common/ucln.h for details on adding a cleanup function. */
+/* Note: the global mutex must not be held when calling this function. */
+U_CFUNC void U_EXPORT2 ucln_i18n_registerCleanup(ECleanupI18NType type,
+ cleanupFunc *func);
+
+#endif
diff --git a/thirdparty/icu4c/i18n/unicode/uspoof.h b/thirdparty/icu4c/i18n/unicode/uspoof.h
new file mode 100644
index 0000000000..b674c91b2c
--- /dev/null
+++ b/thirdparty/icu4c/i18n/unicode/uspoof.h
@@ -0,0 +1,1577 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+***************************************************************************
+* Copyright (C) 2008-2016, International Business Machines Corporation
+* and others. All Rights Reserved.
+***************************************************************************
+* file name: uspoof.h
+* encoding: UTF-8
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2008Feb13
+* created by: Andy Heninger
+*
+* Unicode Spoof Detection
+*/
+
+#ifndef USPOOF_H
+#define USPOOF_H
+
+#include "unicode/utypes.h"
+#include "unicode/uset.h"
+#include "unicode/parseerr.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+
+#if U_SHOW_CPLUSPLUS_API
+#include "unicode/localpointer.h"
+#include "unicode/unistr.h"
+#include "unicode/uniset.h"
+#endif
+
+
+/**
+ * \file
+ * \brief Unicode Security and Spoofing Detection, C API.
+ *
+ * <p>
+ * This class, based on <a href="http://unicode.org/reports/tr36">Unicode Technical Report #36</a> and
+ * <a href="http://unicode.org/reports/tr39">Unicode Technical Standard #39</a>, has two main functions:
+ *
+ * <ol>
+ * <li>Checking whether two strings are visually <em>confusable</em> with each other, such as "Harvest" and
+ * &quot;&Eta;arvest&quot;, where the second string starts with the Greek capital letter Eta.</li>
+ * <li>Checking whether an individual string is likely to be an attempt at confusing the reader (<em>spoof
+ * detection</em>), such as "paypal" with some Latin characters substituted with Cyrillic look-alikes.</li>
+ * </ol>
+ *
+ * <p>
+ * Although originally designed as a method for flagging suspicious identifier strings such as URLs,
+ * <code>USpoofChecker</code> has a number of other practical use cases, such as preventing attempts to evade bad-word
+ * content filters.
+ *
+ * <p>
+ * The functions of this class are exposed as C API, with a handful of syntactical conveniences for C++.
+ *
+ * <h2>Confusables</h2>
+ *
+ * <p>
+ * The following example shows how to use <code>USpoofChecker</code> to check for confusability between two strings:
+ *
+ * \code{.c}
+ * UErrorCode status = U_ZERO_ERROR;
+ * UChar* str1 = (UChar*) u"Harvest";
+ * UChar* str2 = (UChar*) u"\u0397arvest"; // with U+0397 GREEK CAPITAL LETTER ETA
+ *
+ * USpoofChecker* sc = uspoof_open(&status);
+ * uspoof_setChecks(sc, USPOOF_CONFUSABLE, &status);
+ *
+ * int32_t bitmask = uspoof_areConfusable(sc, str1, -1, str2, -1, &status);
+ * UBool result = bitmask != 0;
+ * // areConfusable: 1 (status: U_ZERO_ERROR)
+ * printf("areConfusable: %d (status: %s)\n", result, u_errorName(status));
+ * uspoof_close(sc);
+ * \endcode
+ *
+ * <p>
+ * The call to {@link uspoof_open} creates a <code>USpoofChecker</code> object; the call to {@link uspoof_setChecks}
+ * enables confusable checking and disables all other checks; the call to {@link uspoof_areConfusable} performs the
+ * confusability test; and the following line extracts the result out of the return value. For best performance,
+ * the instance should be created once (e.g., upon application startup), and the efficient
+ * {@link uspoof_areConfusable} method can be used at runtime.
+ *
+ * <p>
+ * The type {@link LocalUSpoofCheckerPointer} is exposed for C++ programmers. It will automatically call
+ * {@link uspoof_close} when the object goes out of scope:
+ *
+ * \code{.cpp}
+ * UErrorCode status = U_ZERO_ERROR;
+ * LocalUSpoofCheckerPointer sc(uspoof_open(&status));
+ * uspoof_setChecks(sc.getAlias(), USPOOF_CONFUSABLE, &status);
+ * // ...
+ * \endcode
+ *
+ * UTS 39 defines two strings to be <em>confusable</em> if they map to the same <em>skeleton string</em>. A skeleton can
+ * be thought of as a "hash code". {@link uspoof_getSkeleton} computes the skeleton for a particular string, so
+ * the following snippet is equivalent to the example above:
+ *
+ * \code{.c}
+ * UErrorCode status = U_ZERO_ERROR;
+ * UChar* str1 = (UChar*) u"Harvest";
+ * UChar* str2 = (UChar*) u"\u0397arvest"; // with U+0397 GREEK CAPITAL LETTER ETA
+ *
+ * USpoofChecker* sc = uspoof_open(&status);
+ * uspoof_setChecks(sc, USPOOF_CONFUSABLE, &status);
+ *
+ * // Get skeleton 1
+ * int32_t skel1Len = uspoof_getSkeleton(sc, 0, str1, -1, NULL, 0, &status);
+ * UChar* skel1 = (UChar*) malloc(++skel1Len * sizeof(UChar));
+ * status = U_ZERO_ERROR;
+ * uspoof_getSkeleton(sc, 0, str1, -1, skel1, skel1Len, &status);
+ *
+ * // Get skeleton 2
+ * int32_t skel2Len = uspoof_getSkeleton(sc, 0, str2, -1, NULL, 0, &status);
+ * UChar* skel2 = (UChar*) malloc(++skel2Len * sizeof(UChar));
+ * status = U_ZERO_ERROR;
+ * uspoof_getSkeleton(sc, 0, str2, -1, skel2, skel2Len, &status);
+ *
+ * // Are the skeletons the same?
+ * UBool result = u_strcmp(skel1, skel2) == 0;
+ * // areConfusable: 1 (status: U_ZERO_ERROR)
+ * printf("areConfusable: %d (status: %s)\n", result, u_errorName(status));
+ * uspoof_close(sc);
+ * free(skel1);
+ * free(skel2);
+ * \endcode
+ *
+ * If you need to check if a string is confusable with any string in a dictionary of many strings, rather than calling
+ * {@link uspoof_areConfusable} many times in a loop, {@link uspoof_getSkeleton} can be used instead, as shown below:
+ *
+ * \code{.c}
+ * UErrorCode status = U_ZERO_ERROR;
+ * #define DICTIONARY_LENGTH 2
+ * UChar* dictionary[DICTIONARY_LENGTH] = { (UChar*) u"lorem", (UChar*) u"ipsum" };
+ * UChar* skeletons[DICTIONARY_LENGTH];
+ * UChar* str = (UChar*) u"1orern";
+ *
+ * // Setup:
+ * USpoofChecker* sc = uspoof_open(&status);
+ * uspoof_setChecks(sc, USPOOF_CONFUSABLE, &status);
+ * for (size_t i=0; i<DICTIONARY_LENGTH; i++) {
+ * UChar* word = dictionary[i];
+ * int32_t len = uspoof_getSkeleton(sc, 0, word, -1, NULL, 0, &status);
+ * skeletons[i] = (UChar*) malloc(++len * sizeof(UChar));
+ * status = U_ZERO_ERROR;
+ * uspoof_getSkeleton(sc, 0, word, -1, skeletons[i], len, &status);
+ * }
+ *
+ * // Live Check:
+ * {
+ * int32_t len = uspoof_getSkeleton(sc, 0, str, -1, NULL, 0, &status);
+ * UChar* skel = (UChar*) malloc(++len * sizeof(UChar));
+ * status = U_ZERO_ERROR;
+ * uspoof_getSkeleton(sc, 0, str, -1, skel, len, &status);
+ * UBool result = false;
+ * for (size_t i=0; i<DICTIONARY_LENGTH; i++) {
+ * result = u_strcmp(skel, skeletons[i]) == 0;
+ * if (result == true) { break; }
+ * }
+ * // Has confusable in dictionary: 1 (status: U_ZERO_ERROR)
+ * printf("Has confusable in dictionary: %d (status: %s)\n", result, u_errorName(status));
+ * free(skel);
+ * }
+ *
+ * for (size_t i=0; i<DICTIONARY_LENGTH; i++) {
+ * free(skeletons[i]);
+ * }
+ * uspoof_close(sc);
+ * \endcode
+ *
+ * <b>Note:</b> Since the Unicode confusables mapping table is frequently updated, confusable skeletons are <em>not</em>
+ * guaranteed to be the same between ICU releases. We therefore recommend that you always compute confusable skeletons
+ * at runtime and do not rely on creating a permanent, or difficult to update, database of skeletons.
+ *
+ * <h2>Spoof Detection</h2>
+ *
+ * The following snippet shows a minimal example of using <code>USpoofChecker</code> to perform spoof detection on a
+ * string:
+ *
+ * \code{.c}
+ * UErrorCode status = U_ZERO_ERROR;
+ * UChar* str = (UChar*) u"p\u0430ypal"; // with U+0430 CYRILLIC SMALL LETTER A
+ *
+ * // Get the default set of allowable characters:
+ * USet* allowed = uset_openEmpty();
+ * uset_addAll(allowed, uspoof_getRecommendedSet(&status));
+ * uset_addAll(allowed, uspoof_getInclusionSet(&status));
+ *
+ * USpoofChecker* sc = uspoof_open(&status);
+ * uspoof_setAllowedChars(sc, allowed, &status);
+ * uspoof_setRestrictionLevel(sc, USPOOF_MODERATELY_RESTRICTIVE);
+ *
+ * int32_t bitmask = uspoof_check(sc, str, -1, NULL, &status);
+ * UBool result = bitmask != 0;
+ * // fails checks: 1 (status: U_ZERO_ERROR)
+ * printf("fails checks: %d (status: %s)\n", result, u_errorName(status));
+ * uspoof_close(sc);
+ * uset_close(allowed);
+ * \endcode
+ *
+ * As in the case for confusability checking, it is good practice to create one <code>USpoofChecker</code> instance at
+ * startup, and call the cheaper {@link uspoof_check} online. We specify the set of
+ * allowed characters to be those with type RECOMMENDED or INCLUSION, according to the recommendation in UTS 39.
+ *
+ * In addition to {@link uspoof_check}, the function {@link uspoof_checkUTF8} is exposed for UTF8-encoded char* strings,
+ * and {@link uspoof_checkUnicodeString} is exposed for C++ programmers.
+ *
+ * If the {@link USPOOF_AUX_INFO} check is enabled, a limited amount of information on why a string failed the checks
+ * is available in the returned bitmask. For complete information, use the {@link uspoof_check2} class of functions
+ * with a {@link USpoofCheckResult} parameter:
+ *
+ * \code{.c}
+ * UErrorCode status = U_ZERO_ERROR;
+ * UChar* str = (UChar*) u"p\u0430ypal"; // with U+0430 CYRILLIC SMALL LETTER A
+ *
+ * // Get the default set of allowable characters:
+ * USet* allowed = uset_openEmpty();
+ * uset_addAll(allowed, uspoof_getRecommendedSet(&status));
+ * uset_addAll(allowed, uspoof_getInclusionSet(&status));
+ *
+ * USpoofChecker* sc = uspoof_open(&status);
+ * uspoof_setAllowedChars(sc, allowed, &status);
+ * uspoof_setRestrictionLevel(sc, USPOOF_MODERATELY_RESTRICTIVE);
+ *
+ * USpoofCheckResult* checkResult = uspoof_openCheckResult(&status);
+ * int32_t bitmask = uspoof_check2(sc, str, -1, checkResult, &status);
+ *
+ * int32_t failures1 = bitmask;
+ * int32_t failures2 = uspoof_getCheckResultChecks(checkResult, &status);
+ * assert(failures1 == failures2);
+ * // checks that failed: 0x00000010 (status: U_ZERO_ERROR)
+ * printf("checks that failed: %#010x (status: %s)\n", failures1, u_errorName(status));
+ *
+ * // Cleanup:
+ * uspoof_close(sc);
+ * uset_close(allowed);
+ * uspoof_closeCheckResult(checkResult);
+ * \endcode
+ *
+ * C++ users can take advantage of a few syntactical conveniences. The following snippet is functionally
+ * equivalent to the one above:
+ *
+ * \code{.cpp}
+ * UErrorCode status = U_ZERO_ERROR;
+ * UnicodeString str((UChar*) u"p\u0430ypal"); // with U+0430 CYRILLIC SMALL LETTER A
+ *
+ * // Get the default set of allowable characters:
+ * UnicodeSet allowed;
+ * allowed.addAll(*uspoof_getRecommendedUnicodeSet(&status));
+ * allowed.addAll(*uspoof_getInclusionUnicodeSet(&status));
+ *
+ * LocalUSpoofCheckerPointer sc(uspoof_open(&status));
+ * uspoof_setAllowedChars(sc.getAlias(), allowed.toUSet(), &status);
+ * uspoof_setRestrictionLevel(sc.getAlias(), USPOOF_MODERATELY_RESTRICTIVE);
+ *
+ * LocalUSpoofCheckResultPointer checkResult(uspoof_openCheckResult(&status));
+ * int32_t bitmask = uspoof_check2UnicodeString(sc.getAlias(), str, checkResult.getAlias(), &status);
+ *
+ * int32_t failures1 = bitmask;
+ * int32_t failures2 = uspoof_getCheckResultChecks(checkResult.getAlias(), &status);
+ * assert(failures1 == failures2);
+ * // checks that failed: 0x00000010 (status: U_ZERO_ERROR)
+ * printf("checks that failed: %#010x (status: %s)\n", failures1, u_errorName(status));
+ *
+ * // Explicit cleanup not necessary.
+ * \endcode
+ *
+ * The return value is a bitmask of the checks that failed. In this case, there was one check that failed:
+ * {@link USPOOF_RESTRICTION_LEVEL}, corresponding to the fifth bit (16). The possible checks are:
+ *
+ * <ul>
+ * <li><code>RESTRICTION_LEVEL</code>: flags strings that violate the
+ * <a href="http://unicode.org/reports/tr39/#Restriction_Level_Detection">Restriction Level</a> test as specified in UTS
+ * 39; in most cases, this means flagging strings that contain characters from multiple different scripts.</li>
+ * <li><code>INVISIBLE</code>: flags strings that contain invisible characters, such as zero-width spaces, or character
+ * sequences that are likely not to display, such as multiple occurrences of the same non-spacing mark.</li>
+ * <li><code>CHAR_LIMIT</code>: flags strings that contain characters outside of a specified set of acceptable
+ * characters. See {@link uspoof_setAllowedChars} and {@link uspoof_setAllowedLocales}.</li>
+ * <li><code>MIXED_NUMBERS</code>: flags strings that contain digits from multiple different numbering systems.</li>
+ * </ul>
+ *
+ * <p>
+ * These checks can be enabled independently of each other. For example, if you were interested in checking for only the
+ * INVISIBLE and MIXED_NUMBERS conditions, you could do:
+ *
+ * \code{.c}
+ * UErrorCode status = U_ZERO_ERROR;
+ * UChar* str = (UChar*) u"8\u09EA"; // 8 mixed with U+09EA BENGALI DIGIT FOUR
+ *
+ * USpoofChecker* sc = uspoof_open(&status);
+ * uspoof_setChecks(sc, USPOOF_INVISIBLE | USPOOF_MIXED_NUMBERS, &status);
+ *
+ * int32_t bitmask = uspoof_check2(sc, str, -1, NULL, &status);
+ * UBool result = bitmask != 0;
+ * // fails checks: 1 (status: U_ZERO_ERROR)
+ * printf("fails checks: %d (status: %s)\n", result, u_errorName(status));
+ * uspoof_close(sc);
+ * \endcode
+ *
+ * Here is an example in C++ showing how to compute the restriction level of a string:
+ *
+ * \code{.cpp}
+ * UErrorCode status = U_ZERO_ERROR;
+ * UnicodeString str((UChar*) u"p\u0430ypal"); // with U+0430 CYRILLIC SMALL LETTER A
+ *
+ * // Get the default set of allowable characters:
+ * UnicodeSet allowed;
+ * allowed.addAll(*uspoof_getRecommendedUnicodeSet(&status));
+ * allowed.addAll(*uspoof_getInclusionUnicodeSet(&status));
+ *
+ * LocalUSpoofCheckerPointer sc(uspoof_open(&status));
+ * uspoof_setAllowedChars(sc.getAlias(), allowed.toUSet(), &status);
+ * uspoof_setRestrictionLevel(sc.getAlias(), USPOOF_MODERATELY_RESTRICTIVE);
+ * uspoof_setChecks(sc.getAlias(), USPOOF_RESTRICTION_LEVEL | USPOOF_AUX_INFO, &status);
+ *
+ * LocalUSpoofCheckResultPointer checkResult(uspoof_openCheckResult(&status));
+ * int32_t bitmask = uspoof_check2UnicodeString(sc.getAlias(), str, checkResult.getAlias(), &status);
+ *
+ * URestrictionLevel restrictionLevel = uspoof_getCheckResultRestrictionLevel(checkResult.getAlias(), &status);
+ * // Since USPOOF_AUX_INFO was enabled, the restriction level is also available in the upper bits of the bitmask:
+ * assert((restrictionLevel & bitmask) == restrictionLevel);
+ * // Restriction level: 0x50000000 (status: U_ZERO_ERROR)
+ * printf("Restriction level: %#010x (status: %s)\n", restrictionLevel, u_errorName(status));
+ * \endcode
+ *
+ * The code '0x50000000' corresponds to the restriction level USPOOF_MINIMALLY_RESTRICTIVE. Since
+ * USPOOF_MINIMALLY_RESTRICTIVE is weaker than USPOOF_MODERATELY_RESTRICTIVE, the string fails the check.
+ *
+ * <b>Note:</b> The Restriction Level is the most powerful of the checks. The full logic is documented in
+ * <a href="http://unicode.org/reports/tr39/#Restriction_Level_Detection">UTS 39</a>, but the basic idea is that strings
+ * are restricted to contain characters from only a single script, <em>except</em> that most scripts are allowed to have
+ * Latin characters interspersed. Although the default restriction level is <code>HIGHLY_RESTRICTIVE</code>, it is
+ * recommended that users set their restriction level to <code>MODERATELY_RESTRICTIVE</code>, which allows Latin mixed
+ * with all other scripts except Cyrillic, Greek, and Cherokee, with which it is often confusable. For more details on
+ * the levels, see UTS 39 or {@link URestrictionLevel}. The Restriction Level test is aware of the set of
+ * allowed characters set in {@link uspoof_setAllowedChars}. Note that characters which have script code
+ * COMMON or INHERITED, such as numbers and punctuation, are ignored when computing whether a string has multiple
+ * scripts.
+ *
+ * <h2>Additional Information</h2>
+ *
+ * A <code>USpoofChecker</code> instance may be used repeatedly to perform checks on any number of identifiers.
+ *
+ * <b>Thread Safety:</b> The test functions for checking a single identifier, or for testing whether
+ * two identifiers are possible confusable, are thread safe. They may called concurrently, from multiple threads,
+ * using the same USpoofChecker instance.
+ *
+ * More generally, the standard ICU thread safety rules apply: functions that take a const USpoofChecker parameter are
+ * thread safe. Those that take a non-const USpoofChecker are not thread safe..
+ *
+ * @stable ICU 4.6
+ */
+
+U_CDECL_BEGIN
+
+struct USpoofChecker;
+/**
+ * @stable ICU 4.2
+ */
+typedef struct USpoofChecker USpoofChecker; /**< typedef for C of USpoofChecker */
+
+struct USpoofCheckResult;
+/**
+ * @see uspoof_openCheckResult
+ * @stable ICU 58
+ */
+typedef struct USpoofCheckResult USpoofCheckResult;
+
+/**
+ * Enum for the kinds of checks that USpoofChecker can perform.
+ * These enum values are used both to select the set of checks that
+ * will be performed, and to report results from the check function.
+ *
+ * @stable ICU 4.2
+ */
+typedef enum USpoofChecks {
+ /**
+ * When performing the two-string {@link uspoof_areConfusable} test, this flag in the return value indicates
+ * that the two strings are visually confusable and that they are from the same script, according to UTS 39 section
+ * 4.
+ *
+ * @see uspoof_areConfusable
+ * @stable ICU 4.2
+ */
+ USPOOF_SINGLE_SCRIPT_CONFUSABLE = 1,
+
+ /**
+ * When performing the two-string {@link uspoof_areConfusable} test, this flag in the return value indicates
+ * that the two strings are visually confusable and that they are <b>not</b> from the same script, according to UTS
+ * 39 section 4.
+ *
+ * @see uspoof_areConfusable
+ * @stable ICU 4.2
+ */
+ USPOOF_MIXED_SCRIPT_CONFUSABLE = 2,
+
+ /**
+ * When performing the two-string {@link uspoof_areConfusable} test, this flag in the return value indicates
+ * that the two strings are visually confusable and that they are not from the same script but both of them are
+ * single-script strings, according to UTS 39 section 4.
+ *
+ * @see uspoof_areConfusable
+ * @stable ICU 4.2
+ */
+ USPOOF_WHOLE_SCRIPT_CONFUSABLE = 4,
+
+ /**
+ * Enable this flag in {@link uspoof_setChecks} to turn on all types of confusables. You may set
+ * the checks to some subset of SINGLE_SCRIPT_CONFUSABLE, MIXED_SCRIPT_CONFUSABLE, or WHOLE_SCRIPT_CONFUSABLE to
+ * make {@link uspoof_areConfusable} return only those types of confusables.
+ *
+ * @see uspoof_areConfusable
+ * @see uspoof_getSkeleton
+ * @stable ICU 58
+ */
+ USPOOF_CONFUSABLE = USPOOF_SINGLE_SCRIPT_CONFUSABLE | USPOOF_MIXED_SCRIPT_CONFUSABLE | USPOOF_WHOLE_SCRIPT_CONFUSABLE,
+
+#ifndef U_HIDE_DEPRECATED_API
+ /**
+ * This flag is deprecated and no longer affects the behavior of SpoofChecker.
+ *
+ * @deprecated ICU 58 Any case confusable mappings were removed from UTS 39; the corresponding ICU API was deprecated.
+ */
+ USPOOF_ANY_CASE = 8,
+#endif /* U_HIDE_DEPRECATED_API */
+
+ /**
+ * Check that an identifier is no looser than the specified RestrictionLevel.
+ * The default if {@link uspoof_setRestrictionLevel} is not called is HIGHLY_RESTRICTIVE.
+ *
+ * If USPOOF_AUX_INFO is enabled the actual restriction level of the
+ * identifier being tested will also be returned by uspoof_check().
+ *
+ * @see URestrictionLevel
+ * @see uspoof_setRestrictionLevel
+ * @see USPOOF_AUX_INFO
+ *
+ * @stable ICU 51
+ */
+ USPOOF_RESTRICTION_LEVEL = 16,
+
+#ifndef U_HIDE_DEPRECATED_API
+ /** Check that an identifier contains only characters from a
+ * single script (plus chars from the common and inherited scripts.)
+ * Applies to checks of a single identifier check only.
+ * @deprecated ICU 51 Use RESTRICTION_LEVEL instead.
+ */
+ USPOOF_SINGLE_SCRIPT = USPOOF_RESTRICTION_LEVEL,
+#endif /* U_HIDE_DEPRECATED_API */
+
+ /** Check an identifier for the presence of invisible characters,
+ * such as zero-width spaces, or character sequences that are
+ * likely not to display, such as multiple occurrences of the same
+ * non-spacing mark. This check does not test the input string as a whole
+ * for conformance to any particular syntax for identifiers.
+ */
+ USPOOF_INVISIBLE = 32,
+
+ /** Check that an identifier contains only characters from a specified set
+ * of acceptable characters. See {@link uspoof_setAllowedChars} and
+ * {@link uspoof_setAllowedLocales}. Note that a string that fails this check
+ * will also fail the {@link USPOOF_RESTRICTION_LEVEL} check.
+ */
+ USPOOF_CHAR_LIMIT = 64,
+
+ /**
+ * Check that an identifier does not mix numbers from different numbering systems.
+ * For more information, see UTS 39 section 5.3.
+ *
+ * @stable ICU 51
+ */
+ USPOOF_MIXED_NUMBERS = 128,
+
+ /**
+ * Check that an identifier does not have a combining character following a character in which that
+ * combining character would be hidden; for example 'i' followed by a U+0307 combining dot.
+ *
+ * More specifically, the following characters are forbidden from preceding a U+0307:
+ * <ul>
+ * <li>Those with the Soft_Dotted Unicode property (which includes 'i' and 'j')</li>
+ * <li>Latin lowercase letter 'l'</li>
+ * <li>Dotless 'i' and 'j' ('ı' and 'ȷ', U+0131 and U+0237)</li>
+ * <li>Any character whose confusable prototype ends with such a character
+ * (Soft_Dotted, 'l', 'ı', or 'ȷ')</li>
+ * </ul>
+ * In addition, combining characters are allowed between the above characters and U+0307 except those
+ * with combining class 0 or combining class "Above" (230, same class as U+0307).
+ *
+ * This list and the number of combing characters considered by this check may grow over time.
+ *
+ * @stable ICU 62
+ */
+ USPOOF_HIDDEN_OVERLAY = 256,
+
+ /**
+ * Enable all spoof checks.
+ *
+ * @stable ICU 4.6
+ */
+ USPOOF_ALL_CHECKS = 0xFFFF,
+
+ /**
+ * Enable the return of auxiliary (non-error) information in the
+ * upper bits of the check results value.
+ *
+ * If this "check" is not enabled, the results of {@link uspoof_check} will be
+ * zero when an identifier passes all of the enabled checks.
+ *
+ * If this "check" is enabled, (uspoof_check() & {@link USPOOF_ALL_CHECKS}) will
+ * be zero when an identifier passes all checks.
+ *
+ * @stable ICU 51
+ */
+ USPOOF_AUX_INFO = 0x40000000
+
+ } USpoofChecks;
+
+
+ /**
+ * Constants from UAX #39 for use in {@link uspoof_setRestrictionLevel}, and
+ * for returned identifier restriction levels in check results.
+ *
+ * @stable ICU 51
+ *
+ * @see uspoof_setRestrictionLevel
+ * @see uspoof_check
+ */
+ typedef enum URestrictionLevel {
+ /**
+ * All characters in the string are in the identifier profile and all characters in the string are in the
+ * ASCII range.
+ *
+ * @stable ICU 51
+ */
+ USPOOF_ASCII = 0x10000000,
+ /**
+ * The string classifies as ASCII-Only, or all characters in the string are in the identifier profile and
+ * the string is single-script, according to the definition in UTS 39 section 5.1.
+ *
+ * @stable ICU 53
+ */
+ USPOOF_SINGLE_SCRIPT_RESTRICTIVE = 0x20000000,
+ /**
+ * The string classifies as Single Script, or all characters in the string are in the identifier profile and
+ * the string is covered by any of the following sets of scripts, according to the definition in UTS 39
+ * section 5.1:
+ * <ul>
+ * <li>Latin + Han + Bopomofo (or equivalently: Latn + Hanb)</li>
+ * <li>Latin + Han + Hiragana + Katakana (or equivalently: Latn + Jpan)</li>
+ * <li>Latin + Han + Hangul (or equivalently: Latn +Kore)</li>
+ * </ul>
+ * This is the default restriction in ICU.
+ *
+ * @stable ICU 51
+ */
+ USPOOF_HIGHLY_RESTRICTIVE = 0x30000000,
+ /**
+ * The string classifies as Highly Restrictive, or all characters in the string are in the identifier profile
+ * and the string is covered by Latin and any one other Recommended or Aspirational script, except Cyrillic,
+ * Greek, and Cherokee.
+ *
+ * @stable ICU 51
+ */
+ USPOOF_MODERATELY_RESTRICTIVE = 0x40000000,
+ /**
+ * All characters in the string are in the identifier profile. Allow arbitrary mixtures of scripts.
+ *
+ * @stable ICU 51
+ */
+ USPOOF_MINIMALLY_RESTRICTIVE = 0x50000000,
+ /**
+ * Any valid identifiers, including characters outside of the Identifier Profile.
+ *
+ * @stable ICU 51
+ */
+ USPOOF_UNRESTRICTIVE = 0x60000000,
+ /**
+ * Mask for selecting the Restriction Level bits from the return value of {@link uspoof_check}.
+ *
+ * @stable ICU 53
+ */
+ USPOOF_RESTRICTION_LEVEL_MASK = 0x7F000000,
+#ifndef U_HIDE_INTERNAL_API
+ /**
+ * An undefined restriction level.
+ * @internal
+ */
+ USPOOF_UNDEFINED_RESTRICTIVE = -1
+#endif /* U_HIDE_INTERNAL_API */
+ } URestrictionLevel;
+
+/**
+ * Create a Unicode Spoof Checker, configured to perform all
+ * checks except for USPOOF_LOCALE_LIMIT and USPOOF_CHAR_LIMIT.
+ * Note that additional checks may be added in the future,
+ * resulting in the changes to the default checking behavior.
+ *
+ * @param status The error code, set if this function encounters a problem.
+ * @return the newly created Spoof Checker
+ * @stable ICU 4.2
+ */
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_open(UErrorCode *status);
+
+
+/**
+ * Open a Spoof checker from its serialized form, stored in 32-bit-aligned memory.
+ * Inverse of uspoof_serialize().
+ * The memory containing the serialized data must remain valid and unchanged
+ * as long as the spoof checker, or any cloned copies of the spoof checker,
+ * are in use. Ownership of the memory remains with the caller.
+ * The spoof checker (and any clones) must be closed prior to deleting the
+ * serialized data.
+ *
+ * @param data a pointer to 32-bit-aligned memory containing the serialized form of spoof data
+ * @param length the number of bytes available at data;
+ * can be more than necessary
+ * @param pActualLength receives the actual number of bytes at data taken up by the data;
+ * can be NULL
+ * @param pErrorCode ICU error code
+ * @return the spoof checker.
+ *
+ * @see uspoof_open
+ * @see uspoof_serialize
+ * @stable ICU 4.2
+ */
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_openFromSerialized(const void *data, int32_t length, int32_t *pActualLength,
+ UErrorCode *pErrorCode);
+
+/**
+ * Open a Spoof Checker from the source form of the spoof data.
+ * The input corresponds to the Unicode data file confusables.txt
+ * as described in Unicode UAX #39. The syntax of the source data
+ * is as described in UAX #39 for this file, and the content of
+ * this file is acceptable input.
+ *
+ * The character encoding of the (char *) input text is UTF-8.
+ *
+ * @param confusables a pointer to the confusable characters definitions,
+ * as found in file confusables.txt from unicode.org.
+ * @param confusablesLen The length of the confusables text, or -1 if the
+ * input string is zero terminated.
+ * @param confusablesWholeScript
+ * Deprecated in ICU 58. No longer used.
+ * @param confusablesWholeScriptLen
+ * Deprecated in ICU 58. No longer used.
+ * @param errType In the event of an error in the input, indicates
+ * which of the input files contains the error.
+ * The value is one of USPOOF_SINGLE_SCRIPT_CONFUSABLE or
+ * USPOOF_WHOLE_SCRIPT_CONFUSABLE, or
+ * zero if no errors are found.
+ * @param pe In the event of an error in the input, receives the position
+ * in the input text (line, offset) of the error.
+ * @param status an in/out ICU UErrorCode. Among the possible errors is
+ * U_PARSE_ERROR, which is used to report syntax errors
+ * in the input.
+ * @return A spoof checker that uses the rules from the input files.
+ * @stable ICU 4.2
+ */
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_openFromSource(const char *confusables, int32_t confusablesLen,
+ const char *confusablesWholeScript, int32_t confusablesWholeScriptLen,
+ int32_t *errType, UParseError *pe, UErrorCode *status);
+
+
+/**
+ * Close a Spoof Checker, freeing any memory that was being held by
+ * its implementation.
+ * @stable ICU 4.2
+ */
+U_CAPI void U_EXPORT2
+uspoof_close(USpoofChecker *sc);
+
+/**
+ * Clone a Spoof Checker. The clone will be set to perform the same checks
+ * as the original source.
+ *
+ * @param sc The source USpoofChecker
+ * @param status The error code, set if this function encounters a problem.
+ * @return
+ * @stable ICU 4.2
+ */
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_clone(const USpoofChecker *sc, UErrorCode *status);
+
+
+/**
+ * Specify the bitmask of checks that will be performed by {@link uspoof_check}. Calling this method
+ * overwrites any checks that may have already been enabled. By default, all checks are enabled.
+ *
+ * To enable specific checks and disable all others,
+ * OR together only the bit constants for the desired checks.
+ * For example, to fail strings containing characters outside of
+ * the set specified by {@link uspoof_setAllowedChars} and
+ * also strings that contain digits from mixed numbering systems:
+ *
+ * <pre>
+ * {@code
+ * uspoof_setChecks(USPOOF_CHAR_LIMIT | USPOOF_MIXED_NUMBERS);
+ * }
+ * </pre>
+ *
+ * To disable specific checks and enable all others,
+ * start with ALL_CHECKS and "AND away" the not-desired checks.
+ * For example, if you are not planning to use the {@link uspoof_areConfusable} functionality,
+ * it is good practice to disable the CONFUSABLE check:
+ *
+ * <pre>
+ * {@code
+ * uspoof_setChecks(USPOOF_ALL_CHECKS & ~USPOOF_CONFUSABLE);
+ * }
+ * </pre>
+ *
+ * Note that methods such as {@link uspoof_setAllowedChars}, {@link uspoof_setAllowedLocales}, and
+ * {@link uspoof_setRestrictionLevel} will enable certain checks when called. Those methods will OR the check they
+ * enable onto the existing bitmask specified by this method. For more details, see the documentation of those
+ * methods.
+ *
+ * @param sc The USpoofChecker
+ * @param checks The set of checks that this spoof checker will perform.
+ * The value is a bit set, obtained by OR-ing together
+ * values from enum USpoofChecks.
+ * @param status The error code, set if this function encounters a problem.
+ * @stable ICU 4.2
+ *
+ */
+U_CAPI void U_EXPORT2
+uspoof_setChecks(USpoofChecker *sc, int32_t checks, UErrorCode *status);
+
+/**
+ * Get the set of checks that this Spoof Checker has been configured to perform.
+ *
+ * @param sc The USpoofChecker
+ * @param status The error code, set if this function encounters a problem.
+ * @return The set of checks that this spoof checker will perform.
+ * The value is a bit set, obtained by OR-ing together
+ * values from enum USpoofChecks.
+ * @stable ICU 4.2
+ *
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_getChecks(const USpoofChecker *sc, UErrorCode *status);
+
+/**
+ * Set the loosest restriction level allowed for strings. The default if this is not called is
+ * {@link USPOOF_HIGHLY_RESTRICTIVE}. Calling this method enables the {@link USPOOF_RESTRICTION_LEVEL} and
+ * {@link USPOOF_MIXED_NUMBERS} checks, corresponding to Sections 5.1 and 5.2 of UTS 39. To customize which checks are
+ * to be performed by {@link uspoof_check}, see {@link uspoof_setChecks}.
+ *
+ * @param sc The USpoofChecker
+ * @param restrictionLevel The loosest restriction level allowed.
+ * @see URestrictionLevel
+ * @stable ICU 51
+ */
+U_CAPI void U_EXPORT2
+uspoof_setRestrictionLevel(USpoofChecker *sc, URestrictionLevel restrictionLevel);
+
+
+/**
+ * Get the Restriction Level that will be tested if the checks include {@link USPOOF_RESTRICTION_LEVEL}.
+ *
+ * @return The restriction level
+ * @see URestrictionLevel
+ * @stable ICU 51
+ */
+U_CAPI URestrictionLevel U_EXPORT2
+uspoof_getRestrictionLevel(const USpoofChecker *sc);
+
+/**
+ * Limit characters that are acceptable in identifiers being checked to those
+ * normally used with the languages associated with the specified locales.
+ * Any previously specified list of locales is replaced by the new settings.
+ *
+ * A set of languages is determined from the locale(s), and
+ * from those a set of acceptable Unicode scripts is determined.
+ * Characters from this set of scripts, along with characters from
+ * the "common" and "inherited" Unicode Script categories
+ * will be permitted.
+ *
+ * Supplying an empty string removes all restrictions;
+ * characters from any script will be allowed.
+ *
+ * The {@link USPOOF_CHAR_LIMIT} test is automatically enabled for this
+ * USpoofChecker when calling this function with a non-empty list
+ * of locales.
+ *
+ * The Unicode Set of characters that will be allowed is accessible
+ * via the uspoof_getAllowedChars() function. uspoof_setAllowedLocales()
+ * will <i>replace</i> any previously applied set of allowed characters.
+ *
+ * Adjustments, such as additions or deletions of certain classes of characters,
+ * can be made to the result of uspoof_setAllowedLocales() by
+ * fetching the resulting set with uspoof_getAllowedChars(),
+ * manipulating it with the Unicode Set API, then resetting the
+ * spoof detectors limits with uspoof_setAllowedChars().
+ *
+ * @param sc The USpoofChecker
+ * @param localesList A list list of locales, from which the language
+ * and associated script are extracted. The locales
+ * are comma-separated if there is more than one.
+ * White space may not appear within an individual locale,
+ * but is ignored otherwise.
+ * The locales are syntactically like those from the
+ * HTTP Accept-Language header.
+ * If the localesList is empty, no restrictions will be placed on
+ * the allowed characters.
+ *
+ * @param status The error code, set if this function encounters a problem.
+ * @stable ICU 4.2
+ */
+U_CAPI void U_EXPORT2
+uspoof_setAllowedLocales(USpoofChecker *sc, const char *localesList, UErrorCode *status);
+
+/**
+ * Get a list of locales for the scripts that are acceptable in strings
+ * to be checked. If no limitations on scripts have been specified,
+ * an empty string will be returned.
+ *
+ * uspoof_setAllowedChars() will reset the list of allowed to be empty.
+ *
+ * The format of the returned list is the same as that supplied to
+ * uspoof_setAllowedLocales(), but returned list may not be identical
+ * to the originally specified string; the string may be reformatted,
+ * and information other than languages from
+ * the originally specified locales may be omitted.
+ *
+ * @param sc The USpoofChecker
+ * @param status The error code, set if this function encounters a problem.
+ * @return A string containing a list of locales corresponding
+ * to the acceptable scripts, formatted like an
+ * HTTP Accept Language value.
+ *
+ * @stable ICU 4.2
+ */
+U_CAPI const char * U_EXPORT2
+uspoof_getAllowedLocales(USpoofChecker *sc, UErrorCode *status);
+
+
+/**
+ * Limit the acceptable characters to those specified by a Unicode Set.
+ * Any previously specified character limit is
+ * is replaced by the new settings. This includes limits on
+ * characters that were set with the uspoof_setAllowedLocales() function.
+ *
+ * The USPOOF_CHAR_LIMIT test is automatically enabled for this
+ * USpoofChecker by this function.
+ *
+ * @param sc The USpoofChecker
+ * @param chars A Unicode Set containing the list of
+ * characters that are permitted. Ownership of the set
+ * remains with the caller. The incoming set is cloned by
+ * this function, so there are no restrictions on modifying
+ * or deleting the USet after calling this function.
+ * @param status The error code, set if this function encounters a problem.
+ * @stable ICU 4.2
+ */
+U_CAPI void U_EXPORT2
+uspoof_setAllowedChars(USpoofChecker *sc, const USet *chars, UErrorCode *status);
+
+
+/**
+ * Get a USet for the characters permitted in an identifier.
+ * This corresponds to the limits imposed by the Set Allowed Characters
+ * functions. Limitations imposed by other checks will not be
+ * reflected in the set returned by this function.
+ *
+ * The returned set will be frozen, meaning that it cannot be modified
+ * by the caller.
+ *
+ * Ownership of the returned set remains with the Spoof Detector. The
+ * returned set will become invalid if the spoof detector is closed,
+ * or if a new set of allowed characters is specified.
+ *
+ *
+ * @param sc The USpoofChecker
+ * @param status The error code, set if this function encounters a problem.
+ * @return A USet containing the characters that are permitted by
+ * the USPOOF_CHAR_LIMIT test.
+ * @stable ICU 4.2
+ */
+U_CAPI const USet * U_EXPORT2
+uspoof_getAllowedChars(const USpoofChecker *sc, UErrorCode *status);
+
+
+/**
+ * Check the specified string for possible security issues.
+ * The text to be checked will typically be an identifier of some sort.
+ * The set of checks to be performed is specified with uspoof_setChecks().
+ *
+ * \note
+ * Consider using the newer API, {@link uspoof_check2}, instead.
+ * The newer API exposes additional information from the check procedure
+ * and is otherwise identical to this method.
+ *
+ * @param sc The USpoofChecker
+ * @param id The identifier to be checked for possible security issues,
+ * in UTF-16 format.
+ * @param length the length of the string to be checked, expressed in
+ * 16 bit UTF-16 code units, or -1 if the string is
+ * zero terminated.
+ * @param position Deprecated in ICU 51. Always returns zero.
+ * Originally, an out parameter for the index of the first
+ * string position that failed a check.
+ * This parameter may be NULL.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Spoofing or security issues detected with the input string are
+ * not reported here, but through the function's return value.
+ * @return An integer value with bits set for any potential security
+ * or spoofing issues detected. The bits are defined by
+ * enum USpoofChecks. (returned_value & USPOOF_ALL_CHECKS)
+ * will be zero if the input string passes all of the
+ * enabled checks.
+ * @see uspoof_check2
+ * @stable ICU 4.2
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_check(const USpoofChecker *sc,
+ const UChar *id, int32_t length,
+ int32_t *position,
+ UErrorCode *status);
+
+
+/**
+ * Check the specified string for possible security issues.
+ * The text to be checked will typically be an identifier of some sort.
+ * The set of checks to be performed is specified with uspoof_setChecks().
+ *
+ * \note
+ * Consider using the newer API, {@link uspoof_check2UTF8}, instead.
+ * The newer API exposes additional information from the check procedure
+ * and is otherwise identical to this method.
+ *
+ * @param sc The USpoofChecker
+ * @param id A identifier to be checked for possible security issues, in UTF8 format.
+ * @param length the length of the string to be checked, or -1 if the string is
+ * zero terminated.
+ * @param position Deprecated in ICU 51. Always returns zero.
+ * Originally, an out parameter for the index of the first
+ * string position that failed a check.
+ * This parameter may be NULL.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Spoofing or security issues detected with the input string are
+ * not reported here, but through the function's return value.
+ * If the input contains invalid UTF-8 sequences,
+ * a status of U_INVALID_CHAR_FOUND will be returned.
+ * @return An integer value with bits set for any potential security
+ * or spoofing issues detected. The bits are defined by
+ * enum USpoofChecks. (returned_value & USPOOF_ALL_CHECKS)
+ * will be zero if the input string passes all of the
+ * enabled checks.
+ * @see uspoof_check2UTF8
+ * @stable ICU 4.2
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_checkUTF8(const USpoofChecker *sc,
+ const char *id, int32_t length,
+ int32_t *position,
+ UErrorCode *status);
+
+
+/**
+ * Check the specified string for possible security issues.
+ * The text to be checked will typically be an identifier of some sort.
+ * The set of checks to be performed is specified with uspoof_setChecks().
+ *
+ * @param sc The USpoofChecker
+ * @param id The identifier to be checked for possible security issues,
+ * in UTF-16 format.
+ * @param length the length of the string to be checked, or -1 if the string is
+ * zero terminated.
+ * @param checkResult An instance of USpoofCheckResult to be filled with
+ * details about the identifier. Can be NULL.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Spoofing or security issues detected with the input string are
+ * not reported here, but through the function's return value.
+ * @return An integer value with bits set for any potential security
+ * or spoofing issues detected. The bits are defined by
+ * enum USpoofChecks. (returned_value & USPOOF_ALL_CHECKS)
+ * will be zero if the input string passes all of the
+ * enabled checks. Any information in this bitmask will be
+ * consistent with the information saved in the optional
+ * checkResult parameter.
+ * @see uspoof_openCheckResult
+ * @see uspoof_check2UTF8
+ * @see uspoof_check2UnicodeString
+ * @stable ICU 58
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_check2(const USpoofChecker *sc,
+ const UChar* id, int32_t length,
+ USpoofCheckResult* checkResult,
+ UErrorCode *status);
+
+/**
+ * Check the specified string for possible security issues.
+ * The text to be checked will typically be an identifier of some sort.
+ * The set of checks to be performed is specified with uspoof_setChecks().
+ *
+ * This version of {@link uspoof_check} accepts a USpoofCheckResult, which
+ * returns additional information about the identifier. For more
+ * information, see {@link uspoof_openCheckResult}.
+ *
+ * @param sc The USpoofChecker
+ * @param id A identifier to be checked for possible security issues, in UTF8 format.
+ * @param length the length of the string to be checked, or -1 if the string is
+ * zero terminated.
+ * @param checkResult An instance of USpoofCheckResult to be filled with
+ * details about the identifier. Can be NULL.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Spoofing or security issues detected with the input string are
+ * not reported here, but through the function's return value.
+ * @return An integer value with bits set for any potential security
+ * or spoofing issues detected. The bits are defined by
+ * enum USpoofChecks. (returned_value & USPOOF_ALL_CHECKS)
+ * will be zero if the input string passes all of the
+ * enabled checks. Any information in this bitmask will be
+ * consistent with the information saved in the optional
+ * checkResult parameter.
+ * @see uspoof_openCheckResult
+ * @see uspoof_check2
+ * @see uspoof_check2UnicodeString
+ * @stable ICU 58
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_check2UTF8(const USpoofChecker *sc,
+ const char *id, int32_t length,
+ USpoofCheckResult* checkResult,
+ UErrorCode *status);
+
+/**
+ * Create a USpoofCheckResult, used by the {@link uspoof_check2} class of functions to return
+ * information about the identifier. Information includes:
+ * <ul>
+ * <li>A bitmask of the checks that failed</li>
+ * <li>The identifier's restriction level (UTS 39 section 5.2)</li>
+ * <li>The set of numerics in the string (UTS 39 section 5.3)</li>
+ * </ul>
+ * The data held in a USpoofCheckResult is cleared whenever it is passed into a new call
+ * of {@link uspoof_check2}.
+ *
+ * @param status The error code, set if this function encounters a problem.
+ * @return the newly created USpoofCheckResult
+ * @see uspoof_check2
+ * @see uspoof_check2UTF8
+ * @see uspoof_check2UnicodeString
+ * @stable ICU 58
+ */
+U_CAPI USpoofCheckResult* U_EXPORT2
+uspoof_openCheckResult(UErrorCode *status);
+
+/**
+ * Close a USpoofCheckResult, freeing any memory that was being held by
+ * its implementation.
+ *
+ * @param checkResult The instance of USpoofCheckResult to close
+ * @stable ICU 58
+ */
+U_CAPI void U_EXPORT2
+uspoof_closeCheckResult(USpoofCheckResult *checkResult);
+
+/**
+ * Indicates which of the spoof check(s) have failed. The value is a bitwise OR of the constants for the tests
+ * in question: USPOOF_RESTRICTION_LEVEL, USPOOF_CHAR_LIMIT, and so on.
+ *
+ * @param checkResult The instance of USpoofCheckResult created by {@link uspoof_openCheckResult}
+ * @param status The error code, set if an error occurred.
+ * @return An integer value with bits set for any potential security
+ * or spoofing issues detected. The bits are defined by
+ * enum USpoofChecks. (returned_value & USPOOF_ALL_CHECKS)
+ * will be zero if the input string passes all of the
+ * enabled checks.
+ * @see uspoof_setChecks
+ * @stable ICU 58
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_getCheckResultChecks(const USpoofCheckResult *checkResult, UErrorCode *status);
+
+/**
+ * Gets the restriction level that the text meets, if the USPOOF_RESTRICTION_LEVEL check
+ * was enabled; otherwise, undefined.
+ *
+ * @param checkResult The instance of USpoofCheckResult created by {@link uspoof_openCheckResult}
+ * @param status The error code, set if an error occurred.
+ * @return The restriction level contained in the USpoofCheckResult
+ * @see uspoof_setRestrictionLevel
+ * @stable ICU 58
+ */
+U_CAPI URestrictionLevel U_EXPORT2
+uspoof_getCheckResultRestrictionLevel(const USpoofCheckResult *checkResult, UErrorCode *status);
+
+/**
+ * Gets the set of numerics found in the string, if the USPOOF_MIXED_NUMBERS check was enabled;
+ * otherwise, undefined. The set will contain the zero digit from each decimal number system found
+ * in the input string. Ownership of the returned USet remains with the USpoofCheckResult.
+ * The USet will be free'd when {@link uspoof_closeCheckResult} is called.
+ *
+ * @param checkResult The instance of USpoofCheckResult created by {@link uspoof_openCheckResult}
+ * @return The set of numerics contained in the USpoofCheckResult
+ * @param status The error code, set if an error occurred.
+ * @stable ICU 58
+ */
+U_CAPI const USet* U_EXPORT2
+uspoof_getCheckResultNumerics(const USpoofCheckResult *checkResult, UErrorCode *status);
+
+
+/**
+ * Check the whether two specified strings are visually confusable.
+ *
+ * If the strings are confusable, the return value will be nonzero, as long as
+ * {@link USPOOF_CONFUSABLE} was enabled in uspoof_setChecks().
+ *
+ * The bits in the return value correspond to flags for each of the classes of
+ * confusables applicable to the two input strings. According to UTS 39
+ * section 4, the possible flags are:
+ *
+ * <ul>
+ * <li>{@link USPOOF_SINGLE_SCRIPT_CONFUSABLE}</li>
+ * <li>{@link USPOOF_MIXED_SCRIPT_CONFUSABLE}</li>
+ * <li>{@link USPOOF_WHOLE_SCRIPT_CONFUSABLE}</li>
+ * </ul>
+ *
+ * If one or more of the above flags were not listed in uspoof_setChecks(), this
+ * function will never report that class of confusable. The check
+ * {@link USPOOF_CONFUSABLE} enables all three flags.
+ *
+ *
+ * @param sc The USpoofChecker
+ * @param id1 The first of the two identifiers to be compared for
+ * confusability. The strings are in UTF-16 format.
+ * @param length1 the length of the first identifier, expressed in
+ * 16 bit UTF-16 code units, or -1 if the string is
+ * nul terminated.
+ * @param id2 The second of the two identifiers to be compared for
+ * confusability. The identifiers are in UTF-16 format.
+ * @param length2 The length of the second identifiers, expressed in
+ * 16 bit UTF-16 code units, or -1 if the string is
+ * nul terminated.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Confusability of the identifiers is not reported here,
+ * but through this function's return value.
+ * @return An integer value with bit(s) set corresponding to
+ * the type of confusability found, as defined by
+ * enum USpoofChecks. Zero is returned if the identifiers
+ * are not confusable.
+ *
+ * @stable ICU 4.2
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusable(const USpoofChecker *sc,
+ const UChar *id1, int32_t length1,
+ const UChar *id2, int32_t length2,
+ UErrorCode *status);
+
+
+
+/**
+ * A version of {@link uspoof_areConfusable} accepting strings in UTF-8 format.
+ *
+ * @param sc The USpoofChecker
+ * @param id1 The first of the two identifiers to be compared for
+ * confusability. The strings are in UTF-8 format.
+ * @param length1 the length of the first identifiers, in bytes, or -1
+ * if the string is nul terminated.
+ * @param id2 The second of the two identifiers to be compared for
+ * confusability. The strings are in UTF-8 format.
+ * @param length2 The length of the second string in bytes, or -1
+ * if the string is nul terminated.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Confusability of the strings is not reported here,
+ * but through this function's return value.
+ * @return An integer value with bit(s) set corresponding to
+ * the type of confusability found, as defined by
+ * enum USpoofChecks. Zero is returned if the strings
+ * are not confusable.
+ *
+ * @stable ICU 4.2
+ *
+ * @see uspoof_areConfusable
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusableUTF8(const USpoofChecker *sc,
+ const char *id1, int32_t length1,
+ const char *id2, int32_t length2,
+ UErrorCode *status);
+
+
+
+
+/**
+ * Get the "skeleton" for an identifier.
+ * Skeletons are a transformation of the input identifier;
+ * Two identifiers are confusable if their skeletons are identical.
+ * See Unicode UAX #39 for additional information.
+ *
+ * Using skeletons directly makes it possible to quickly check
+ * whether an identifier is confusable with any of some large
+ * set of existing identifiers, by creating an efficiently
+ * searchable collection of the skeletons.
+ *
+ * @param sc The USpoofChecker
+ * @param type Deprecated in ICU 58. You may pass any number.
+ * Originally, controlled which of the Unicode confusable data
+ * tables to use.
+ * @param id The input identifier whose skeleton will be computed.
+ * @param length The length of the input identifier, expressed in 16 bit
+ * UTF-16 code units, or -1 if the string is zero terminated.
+ * @param dest The output buffer, to receive the skeleton string.
+ * @param destCapacity The length of the output buffer, in 16 bit units.
+ * The destCapacity may be zero, in which case the function will
+ * return the actual length of the skeleton.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * @return The length of the skeleton string. The returned length
+ * is always that of the complete skeleton, even when the
+ * supplied buffer is too small (or of zero length)
+ *
+ * @stable ICU 4.2
+ * @see uspoof_areConfusable
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_getSkeleton(const USpoofChecker *sc,
+ uint32_t type,
+ const UChar *id, int32_t length,
+ UChar *dest, int32_t destCapacity,
+ UErrorCode *status);
+
+/**
+ * Get the "skeleton" for an identifier.
+ * Skeletons are a transformation of the input identifier;
+ * Two identifiers are confusable if their skeletons are identical.
+ * See Unicode UAX #39 for additional information.
+ *
+ * Using skeletons directly makes it possible to quickly check
+ * whether an identifier is confusable with any of some large
+ * set of existing identifiers, by creating an efficiently
+ * searchable collection of the skeletons.
+ *
+ * @param sc The USpoofChecker
+ * @param type Deprecated in ICU 58. You may pass any number.
+ * Originally, controlled which of the Unicode confusable data
+ * tables to use.
+ * @param id The UTF-8 format identifier whose skeleton will be computed.
+ * @param length The length of the input string, in bytes,
+ * or -1 if the string is zero terminated.
+ * @param dest The output buffer, to receive the skeleton string.
+ * @param destCapacity The length of the output buffer, in bytes.
+ * The destCapacity may be zero, in which case the function will
+ * return the actual length of the skeleton.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check. Possible Errors include U_INVALID_CHAR_FOUND
+ * for invalid UTF-8 sequences, and
+ * U_BUFFER_OVERFLOW_ERROR if the destination buffer is too small
+ * to hold the complete skeleton.
+ * @return The length of the skeleton string, in bytes. The returned length
+ * is always that of the complete skeleton, even when the
+ * supplied buffer is too small (or of zero length)
+ *
+ * @stable ICU 4.2
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_getSkeletonUTF8(const USpoofChecker *sc,
+ uint32_t type,
+ const char *id, int32_t length,
+ char *dest, int32_t destCapacity,
+ UErrorCode *status);
+
+/**
+ * Get the set of Candidate Characters for Inclusion in Identifiers, as defined
+ * in http://unicode.org/Public/security/latest/xidmodifications.txt
+ * and documented in http://www.unicode.org/reports/tr39/, Unicode Security Mechanisms.
+ *
+ * The returned set is frozen. Ownership of the set remains with the ICU library; it must not
+ * be deleted by the caller.
+ *
+ * @param status The error code, set if a problem occurs while creating the set.
+ *
+ * @stable ICU 51
+ */
+U_CAPI const USet * U_EXPORT2
+uspoof_getInclusionSet(UErrorCode *status);
+
+/**
+ * Get the set of characters from Recommended Scripts for Inclusion in Identifiers, as defined
+ * in http://unicode.org/Public/security/latest/xidmodifications.txt
+ * and documented in http://www.unicode.org/reports/tr39/, Unicode Security Mechanisms.
+ *
+ * The returned set is frozen. Ownership of the set remains with the ICU library; it must not
+ * be deleted by the caller.
+ *
+ * @param status The error code, set if a problem occurs while creating the set.
+ *
+ * @stable ICU 51
+ */
+U_CAPI const USet * U_EXPORT2
+uspoof_getRecommendedSet(UErrorCode *status);
+
+/**
+ * Serialize the data for a spoof detector into a chunk of memory.
+ * The flattened spoof detection tables can later be used to efficiently
+ * instantiate a new Spoof Detector.
+ *
+ * The serialized spoof checker includes only the data compiled from the
+ * Unicode data tables by uspoof_openFromSource(); it does not include
+ * include any other state or configuration that may have been set.
+ *
+ * @param sc the Spoof Detector whose data is to be serialized.
+ * @param data a pointer to 32-bit-aligned memory to be filled with the data,
+ * can be NULL if capacity==0
+ * @param capacity the number of bytes available at data,
+ * or 0 for preflighting
+ * @param status an in/out ICU UErrorCode; possible errors include:
+ * - U_BUFFER_OVERFLOW_ERROR if the data storage block is too small for serialization
+ * - U_ILLEGAL_ARGUMENT_ERROR the data or capacity parameters are bad
+ * @return the number of bytes written or needed for the spoof data
+ *
+ * @see utrie2_openFromSerialized()
+ * @stable ICU 4.2
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_serialize(USpoofChecker *sc,
+ void *data, int32_t capacity,
+ UErrorCode *status);
+
+U_CDECL_END
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUSpoofCheckerPointer
+ * "Smart pointer" class, closes a USpoofChecker via uspoof_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+/**
+ * \cond
+ * Note: Doxygen is giving a bogus warning on this U_DEFINE_LOCAL_OPEN_POINTER.
+ * For now, suppress with a Doxygen cond
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUSpoofCheckerPointer, USpoofChecker, uspoof_close);
+/** \endcond */
+
+/**
+ * \class LocalUSpoofCheckResultPointer
+ * "Smart pointer" class, closes a USpoofCheckResult via `uspoof_closeCheckResult()`.
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 58
+ */
+
+/**
+ * \cond
+ * Note: Doxygen is giving a bogus warning on this U_DEFINE_LOCAL_OPEN_POINTER.
+ * For now, suppress with a Doxygen cond
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUSpoofCheckResultPointer, USpoofCheckResult, uspoof_closeCheckResult);
+/** \endcond */
+
+U_NAMESPACE_END
+
+/**
+ * Limit the acceptable characters to those specified by a Unicode Set.
+ * Any previously specified character limit is
+ * is replaced by the new settings. This includes limits on
+ * characters that were set with the uspoof_setAllowedLocales() function.
+ *
+ * The USPOOF_CHAR_LIMIT test is automatically enabled for this
+ * USoofChecker by this function.
+ *
+ * @param sc The USpoofChecker
+ * @param chars A Unicode Set containing the list of
+ * characters that are permitted. Ownership of the set
+ * remains with the caller. The incoming set is cloned by
+ * this function, so there are no restrictions on modifying
+ * or deleting the UnicodeSet after calling this function.
+ * @param status The error code, set if this function encounters a problem.
+ * @stable ICU 4.2
+ */
+U_CAPI void U_EXPORT2
+uspoof_setAllowedUnicodeSet(USpoofChecker *sc, const icu::UnicodeSet *chars, UErrorCode *status);
+
+
+/**
+ * Get a UnicodeSet for the characters permitted in an identifier.
+ * This corresponds to the limits imposed by the Set Allowed Characters /
+ * UnicodeSet functions. Limitations imposed by other checks will not be
+ * reflected in the set returned by this function.
+ *
+ * The returned set will be frozen, meaning that it cannot be modified
+ * by the caller.
+ *
+ * Ownership of the returned set remains with the Spoof Detector. The
+ * returned set will become invalid if the spoof detector is closed,
+ * or if a new set of allowed characters is specified.
+ *
+ *
+ * @param sc The USpoofChecker
+ * @param status The error code, set if this function encounters a problem.
+ * @return A UnicodeSet containing the characters that are permitted by
+ * the USPOOF_CHAR_LIMIT test.
+ * @stable ICU 4.2
+ */
+U_CAPI const icu::UnicodeSet * U_EXPORT2
+uspoof_getAllowedUnicodeSet(const USpoofChecker *sc, UErrorCode *status);
+
+/**
+ * Check the specified string for possible security issues.
+ * The text to be checked will typically be an identifier of some sort.
+ * The set of checks to be performed is specified with uspoof_setChecks().
+ *
+ * \note
+ * Consider using the newer API, {@link uspoof_check2UnicodeString}, instead.
+ * The newer API exposes additional information from the check procedure
+ * and is otherwise identical to this method.
+ *
+ * @param sc The USpoofChecker
+ * @param id A identifier to be checked for possible security issues.
+ * @param position Deprecated in ICU 51. Always returns zero.
+ * Originally, an out parameter for the index of the first
+ * string position that failed a check.
+ * This parameter may be NULL.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Spoofing or security issues detected with the input string are
+ * not reported here, but through the function's return value.
+ * @return An integer value with bits set for any potential security
+ * or spoofing issues detected. The bits are defined by
+ * enum USpoofChecks. (returned_value & USPOOF_ALL_CHECKS)
+ * will be zero if the input string passes all of the
+ * enabled checks.
+ * @see uspoof_check2UnicodeString
+ * @stable ICU 4.2
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_checkUnicodeString(const USpoofChecker *sc,
+ const icu::UnicodeString &id,
+ int32_t *position,
+ UErrorCode *status);
+
+/**
+ * Check the specified string for possible security issues.
+ * The text to be checked will typically be an identifier of some sort.
+ * The set of checks to be performed is specified with uspoof_setChecks().
+ *
+ * @param sc The USpoofChecker
+ * @param id A identifier to be checked for possible security issues.
+ * @param checkResult An instance of USpoofCheckResult to be filled with
+ * details about the identifier. Can be NULL.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Spoofing or security issues detected with the input string are
+ * not reported here, but through the function's return value.
+ * @return An integer value with bits set for any potential security
+ * or spoofing issues detected. The bits are defined by
+ * enum USpoofChecks. (returned_value & USPOOF_ALL_CHECKS)
+ * will be zero if the input string passes all of the
+ * enabled checks. Any information in this bitmask will be
+ * consistent with the information saved in the optional
+ * checkResult parameter.
+ * @see uspoof_openCheckResult
+ * @see uspoof_check2
+ * @see uspoof_check2UTF8
+ * @stable ICU 58
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_check2UnicodeString(const USpoofChecker *sc,
+ const icu::UnicodeString &id,
+ USpoofCheckResult* checkResult,
+ UErrorCode *status);
+
+/**
+ * A version of {@link uspoof_areConfusable} accepting UnicodeStrings.
+ *
+ * @param sc The USpoofChecker
+ * @param s1 The first of the two identifiers to be compared for
+ * confusability. The strings are in UTF-8 format.
+ * @param s2 The second of the two identifiers to be compared for
+ * confusability. The strings are in UTF-8 format.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Confusability of the identifiers is not reported here,
+ * but through this function's return value.
+ * @return An integer value with bit(s) set corresponding to
+ * the type of confusability found, as defined by
+ * enum USpoofChecks. Zero is returned if the identifiers
+ * are not confusable.
+ *
+ * @stable ICU 4.2
+ *
+ * @see uspoof_areConfusable
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusableUnicodeString(const USpoofChecker *sc,
+ const icu::UnicodeString &s1,
+ const icu::UnicodeString &s2,
+ UErrorCode *status);
+
+/**
+ * Get the "skeleton" for an identifier.
+ * Skeletons are a transformation of the input identifier;
+ * Two identifiers are confusable if their skeletons are identical.
+ * See Unicode UAX #39 for additional information.
+ *
+ * Using skeletons directly makes it possible to quickly check
+ * whether an identifier is confusable with any of some large
+ * set of existing identifiers, by creating an efficiently
+ * searchable collection of the skeletons.
+ *
+ * @param sc The USpoofChecker.
+ * @param type Deprecated in ICU 58. You may pass any number.
+ * Originally, controlled which of the Unicode confusable data
+ * tables to use.
+ * @param id The input identifier whose skeleton will be computed.
+ * @param dest The output identifier, to receive the skeleton string.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * @return A reference to the destination (skeleton) string.
+ *
+ * @stable ICU 4.2
+ */
+U_I18N_API icu::UnicodeString & U_EXPORT2
+uspoof_getSkeletonUnicodeString(const USpoofChecker *sc,
+ uint32_t type,
+ const icu::UnicodeString &id,
+ icu::UnicodeString &dest,
+ UErrorCode *status);
+
+/**
+ * Get the set of Candidate Characters for Inclusion in Identifiers, as defined
+ * in http://unicode.org/Public/security/latest/xidmodifications.txt
+ * and documented in http://www.unicode.org/reports/tr39/, Unicode Security Mechanisms.
+ *
+ * The returned set is frozen. Ownership of the set remains with the ICU library; it must not
+ * be deleted by the caller.
+ *
+ * @param status The error code, set if a problem occurs while creating the set.
+ *
+ * @stable ICU 51
+ */
+U_CAPI const icu::UnicodeSet * U_EXPORT2
+uspoof_getInclusionUnicodeSet(UErrorCode *status);
+
+/**
+ * Get the set of characters from Recommended Scripts for Inclusion in Identifiers, as defined
+ * in http://unicode.org/Public/security/latest/xidmodifications.txt
+ * and documented in http://www.unicode.org/reports/tr39/, Unicode Security Mechanisms.
+ *
+ * The returned set is frozen. Ownership of the set remains with the ICU library; it must not
+ * be deleted by the caller.
+ *
+ * @param status The error code, set if a problem occurs while creating the set.
+ *
+ * @stable ICU 51
+ */
+U_CAPI const icu::UnicodeSet * U_EXPORT2
+uspoof_getRecommendedUnicodeSet(UErrorCode *status);
+
+#endif /* U_SHOW_CPLUSPLUS_API */
+
+#endif /* UCONFIG_NO_NORMALIZATION */
+
+#endif /* USPOOF_H */
diff --git a/thirdparty/icu4c/i18n/uspoof.cpp b/thirdparty/icu4c/i18n/uspoof.cpp
new file mode 100644
index 0000000000..dd4618baa7
--- /dev/null
+++ b/thirdparty/icu4c/i18n/uspoof.cpp
@@ -0,0 +1,839 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+***************************************************************************
+* Copyright (C) 2008-2015, International Business Machines Corporation
+* and others. All Rights Reserved.
+***************************************************************************
+* file name: uspoof.cpp
+* encoding: UTF-8
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2008Feb13
+* created by: Andy Heninger
+*
+* Unicode Spoof Detection
+*/
+#include "unicode/utypes.h"
+#include "unicode/normalizer2.h"
+#include "unicode/uspoof.h"
+#include "unicode/ustring.h"
+#include "unicode/utf16.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "mutex.h"
+#include "scriptset.h"
+#include "uassert.h"
+#include "ucln_in.h"
+#include "uspoof_impl.h"
+#include "umutex.h"
+
+
+#if !UCONFIG_NO_NORMALIZATION
+
+U_NAMESPACE_USE
+
+
+//
+// Static Objects used by the spoof impl, their thread safe initialization and their cleanup.
+//
+static UnicodeSet *gInclusionSet = NULL;
+static UnicodeSet *gRecommendedSet = NULL;
+static const Normalizer2 *gNfdNormalizer = NULL;
+static UInitOnce gSpoofInitStaticsOnce = U_INITONCE_INITIALIZER;
+
+namespace {
+
+UBool U_CALLCONV
+uspoof_cleanup(void) {
+ delete gInclusionSet;
+ gInclusionSet = NULL;
+ delete gRecommendedSet;
+ gRecommendedSet = NULL;
+ gNfdNormalizer = NULL;
+ gSpoofInitStaticsOnce.reset();
+ return TRUE;
+}
+
+void U_CALLCONV initializeStatics(UErrorCode &status) {
+ static const char16_t *inclusionPat =
+ u"['\\-.\\:\\u00B7\\u0375\\u058A\\u05F3\\u05F4\\u06FD\\u06FE\\u0F0B\\u200C"
+ u"\\u200D\\u2010\\u2019\\u2027\\u30A0\\u30FB]";
+ gInclusionSet = new UnicodeSet(UnicodeString(inclusionPat), status);
+ if (gInclusionSet == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ gInclusionSet->freeze();
+
+ // Note: data from IdentifierStatus.txt & IdentifierType.txt
+ // There is tooling to generate this constant in the unicodetools project:
+ // org.unicode.text.tools.RecommendedSetGenerator
+ // It will print the Java and C++ code to the console for easy copy-paste into this file.
+ static const char16_t *recommendedPat =
+ u"[0-9A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u0131\\u0134-\\u013E"
+ u"\\u0141-\\u0148\\u014A-\\u017E\\u018F\\u01A0\\u01A1\\u01AF\\u01B0\\u01CD-"
+ u"\\u01DC\\u01DE-\\u01E3\\u01E6-\\u01F0\\u01F4\\u01F5\\u01F8-\\u021B\\u021E"
+ u"\\u021F\\u0226-\\u0233\\u0259\\u02BB\\u02BC\\u02EC\\u0300-\\u0304\\u0306-"
+ u"\\u030C\\u030F-\\u0311\\u0313\\u0314\\u031B\\u0323-\\u0328\\u032D\\u032E"
+ u"\\u0330\\u0331\\u0335\\u0338\\u0339\\u0342\\u0345\\u037B-\\u037D\\u0386"
+ u"\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03CE\\u03FC-\\u045F\\u048A-"
+ u"\\u04FF\\u0510-\\u0529\\u052E\\u052F\\u0531-\\u0556\\u0559\\u0561-\\u0586"
+ u"\\u05B4\\u05D0-\\u05EA\\u05EF-\\u05F2\\u0620-\\u063F\\u0641-\\u0655\\u0660-"
+ u"\\u0669\\u0670-\\u0672\\u0674\\u0679-\\u068D\\u068F-\\u06A0\\u06A2-\\u06D3"
+ u"\\u06D5\\u06E5\\u06E6\\u06EE-\\u06FC\\u06FF\\u0750-\\u07B1\\u0870-\\u0887"
+ u"\\u0889-\\u088E\\u08A0-\\u08AC\\u08B2\\u08B5-\\u08C9\\u0901-\\u094D\\u094F"
+ u"\\u0950\\u0956\\u0957\\u0960-\\u0963\\u0966-\\u096F\\u0971-\\u0977\\u0979-"
+ u"\\u097F\\u0981-\\u0983\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-"
+ u"\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BC-\\u09C4\\u09C7\\u09C8\\u09CB-\\u09CE"
+ u"\\u09D7\\u09E0-\\u09E3\\u09E6-\\u09F1\\u09FE\\u0A01-\\u0A03\\u0A05-\\u0A0A"
+ u"\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A35\\u0A38\\u0A39"
+ u"\\u0A3C\\u0A3E-\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A5C\\u0A66-\\u0A74"
+ u"\\u0A81-\\u0A83\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0"
+ u"\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABC-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD"
+ u"\\u0AD0\\u0AE0-\\u0AE3\\u0AE6-\\u0AEF\\u0AFA-\\u0AFF\\u0B01-\\u0B03\\u0B05-"
+ u"\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-"
+ u"\\u0B39\\u0B3C-\\u0B43\\u0B47\\u0B48\\u0B4B-\\u0B4D\\u0B55-\\u0B57\\u0B5F-"
+ u"\\u0B61\\u0B66-\\u0B6F\\u0B71\\u0B82\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90"
+ u"\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-"
+ u"\\u0BAA\\u0BAE-\\u0BB9\\u0BBE-\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD0"
+ u"\\u0BD7\\u0BE6-\\u0BEF\\u0C01-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-"
+ u"\\u0C33\\u0C35-\\u0C39\\u0C3C-\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55"
+ u"\\u0C56\\u0C5D\\u0C60\\u0C61\\u0C66-\\u0C6F\\u0C80\\u0C82\\u0C83\\u0C85-"
+ u"\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBC-"
+ u"\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5\\u0CD6\\u0CDD\\u0CE0-\\u0CE3"
+ u"\\u0CE6-\\u0CEF\\u0CF1\\u0CF2\\u0D00\\u0D02\\u0D03\\u0D05-\\u0D0C\\u0D0E-"
+ u"\\u0D10\\u0D12-\\u0D3A\\u0D3D-\\u0D43\\u0D46-\\u0D48\\u0D4A-\\u0D4E\\u0D54-"
+ u"\\u0D57\\u0D60\\u0D61\\u0D66-\\u0D6F\\u0D7A-\\u0D7F\\u0D82\\u0D83\\u0D85-"
+ u"\\u0D8E\\u0D91-\\u0D96\\u0D9A-\\u0DA5\\u0DA7-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD"
+ u"\\u0DC0-\\u0DC6\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDE\\u0DF2\\u0E01-"
+ u"\\u0E32\\u0E34-\\u0E3A\\u0E40-\\u0E4E\\u0E50-\\u0E59\\u0E81\\u0E82\\u0E84"
+ u"\\u0E86-\\u0E8A\\u0E8C-\\u0EA3\\u0EA5\\u0EA7-\\u0EB2\\u0EB4-\\u0EBD\\u0EC0-"
+ u"\\u0EC4\\u0EC6\\u0EC8-\\u0ECD\\u0ED0-\\u0ED9\\u0EDE\\u0EDF\\u0F00\\u0F20-"
+ u"\\u0F29\\u0F35\\u0F37\\u0F3E-\\u0F42\\u0F44-\\u0F47\\u0F49-\\u0F4C\\u0F4E-"
+ u"\\u0F51\\u0F53-\\u0F56\\u0F58-\\u0F5B\\u0F5D-\\u0F68\\u0F6A-\\u0F6C\\u0F71"
+ u"\\u0F72\\u0F74\\u0F7A-\\u0F80\\u0F82-\\u0F84\\u0F86-\\u0F92\\u0F94-\\u0F97"
+ u"\\u0F99-\\u0F9C\\u0F9E-\\u0FA1\\u0FA3-\\u0FA6\\u0FA8-\\u0FAB\\u0FAD-\\u0FB8"
+ u"\\u0FBA-\\u0FBC\\u0FC6\\u1000-\\u1049\\u1050-\\u109D\\u10C7\\u10CD\\u10D0-"
+ u"\\u10F0\\u10F7-\\u10FA\\u10FD-\\u10FF\\u1200-\\u1248\\u124A-\\u124D\\u1250-"
+ u"\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0"
+ u"\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-"
+ u"\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u135D-\\u135F\\u1380-\\u138F\\u1780-"
+ u"\\u17A2\\u17A5-\\u17A7\\u17A9-\\u17B3\\u17B6-\\u17CD\\u17D0\\u17D2\\u17D7"
+ u"\\u17DC\\u17E0-\\u17E9\\u1C90-\\u1CBA\\u1CBD-\\u1CBF\\u1E00-\\u1E99\\u1E9E"
+ u"\\u1EA0-\\u1EF9\\u1F00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D"
+ u"\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F70\\u1F72\\u1F74\\u1F76"
+ u"\\u1F78\\u1F7A\\u1F7C\\u1F80-\\u1FB4\\u1FB6-\\u1FBA\\u1FBC\\u1FC2-\\u1FC4"
+ u"\\u1FC6-\\u1FC8\\u1FCA\\u1FCC\\u1FD0-\\u1FD2\\u1FD6-\\u1FDA\\u1FE0-\\u1FE2"
+ u"\\u1FE4-\\u1FEA\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FF8\\u1FFA\\u1FFC\\u2D27"
+ u"\\u2D2D\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-"
+ u"\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u3005-"
+ u"\\u3007\\u3041-\\u3096\\u3099\\u309A\\u309D\\u309E\\u30A1-\\u30FA\\u30FC-"
+ u"\\u30FE\\u3105-\\u312D\\u312F\\u31A0-\\u31BF\\u3400-\\u4DBF\\u4E00-\\u9FFF"
+ u"\\uA67F\\uA717-\\uA71F\\uA788\\uA78D\\uA792\\uA793\\uA7AA\\uA7AE\\uA7B8"
+ u"\\uA7B9\\uA7C0-\\uA7CA\\uA7D0\\uA7D1\\uA7D3\\uA7D5-\\uA7D9\\uA9E7-\\uA9FE"
+ u"\\uAA60-\\uAA76\\uAA7A-\\uAA7F\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16"
+ u"\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB66\\uAB67\\uAC00-\\uD7A3\\uFA0E\\uFA0F"
+ u"\\uFA11\\uFA13\\uFA14\\uFA1F\\uFA21\\uFA23\\uFA24\\uFA27-\\uFA29\\U00011301"
+ u"\\U00011303\\U0001133B\\U0001133C\\U00016FF0\\U00016FF1\\U0001B11F-"
+ u"\\U0001B122\\U0001B150-\\U0001B152\\U0001B164-\\U0001B167\\U0001DF00-"
+ u"\\U0001DF1E\\U0001E7E0-\\U0001E7E6\\U0001E7E8-\\U0001E7EB\\U0001E7ED"
+ u"\\U0001E7EE\\U0001E7F0-\\U0001E7FE\\U00020000-\\U0002A6DF\\U0002A700-"
+ u"\\U0002B738\\U0002B740-\\U0002B81D\\U0002B820-\\U0002CEA1\\U0002CEB0-"
+ u"\\U0002EBE0\\U00030000-\\U0003134A]";
+
+ gRecommendedSet = new UnicodeSet(UnicodeString(recommendedPat), status);
+ if (gRecommendedSet == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ delete gInclusionSet;
+ return;
+ }
+ gRecommendedSet->freeze();
+ gNfdNormalizer = Normalizer2::getNFDInstance(status);
+ ucln_i18n_registerCleanup(UCLN_I18N_SPOOF, uspoof_cleanup);
+}
+
+} // namespace
+
+U_CFUNC void uspoof_internalInitStatics(UErrorCode *status) {
+ umtx_initOnce(gSpoofInitStaticsOnce, &initializeStatics, *status);
+}
+
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_open(UErrorCode *status) {
+ umtx_initOnce(gSpoofInitStaticsOnce, &initializeStatics, *status);
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ SpoofImpl *si = new SpoofImpl(*status);
+ if (si == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ if (U_FAILURE(*status)) {
+ delete si;
+ return NULL;
+ }
+ return si->asUSpoofChecker();
+}
+
+
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_openFromSerialized(const void *data, int32_t length, int32_t *pActualLength,
+ UErrorCode *status) {
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ if (data == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+ umtx_initOnce(gSpoofInitStaticsOnce, &initializeStatics, *status);
+ if (U_FAILURE(*status))
+ {
+ return NULL;
+ }
+
+ SpoofData *sd = new SpoofData(data, length, *status);
+ if (sd == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ if (U_FAILURE(*status)) {
+ delete sd;
+ return NULL;
+ }
+
+ SpoofImpl *si = new SpoofImpl(sd, *status);
+ if (si == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ delete sd; // explicit delete as the destructor for si won't be called.
+ return NULL;
+ }
+
+ if (U_FAILURE(*status)) {
+ delete si; // no delete for sd, as the si destructor will delete it.
+ return NULL;
+ }
+
+ if (pActualLength != NULL) {
+ *pActualLength = sd->size();
+ }
+ return si->asUSpoofChecker();
+}
+
+
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_clone(const USpoofChecker *sc, UErrorCode *status) {
+ const SpoofImpl *src = SpoofImpl::validateThis(sc, *status);
+ if (src == NULL) {
+ return NULL;
+ }
+ SpoofImpl *result = new SpoofImpl(*src, *status); // copy constructor
+ if (result == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ if (U_FAILURE(*status)) {
+ delete result;
+ result = NULL;
+ }
+ return result->asUSpoofChecker();
+}
+
+
+U_CAPI void U_EXPORT2
+uspoof_close(USpoofChecker *sc) {
+ UErrorCode status = U_ZERO_ERROR;
+ SpoofImpl *This = SpoofImpl::validateThis(sc, status);
+ delete This;
+}
+
+
+U_CAPI void U_EXPORT2
+uspoof_setChecks(USpoofChecker *sc, int32_t checks, UErrorCode *status) {
+ SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return;
+ }
+
+ // Verify that the requested checks are all ones (bits) that
+ // are acceptable, known values.
+ if (checks & ~(USPOOF_ALL_CHECKS | USPOOF_AUX_INFO)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ This->fChecks = checks;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_getChecks(const USpoofChecker *sc, UErrorCode *status) {
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return 0;
+ }
+ return This->fChecks;
+}
+
+U_CAPI void U_EXPORT2
+uspoof_setRestrictionLevel(USpoofChecker *sc, URestrictionLevel restrictionLevel) {
+ UErrorCode status = U_ZERO_ERROR;
+ SpoofImpl *This = SpoofImpl::validateThis(sc, status);
+ if (This != NULL) {
+ This->fRestrictionLevel = restrictionLevel;
+ This->fChecks |= USPOOF_RESTRICTION_LEVEL;
+ }
+}
+
+U_CAPI URestrictionLevel U_EXPORT2
+uspoof_getRestrictionLevel(const USpoofChecker *sc) {
+ UErrorCode status = U_ZERO_ERROR;
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, status);
+ if (This == NULL) {
+ return USPOOF_UNRESTRICTIVE;
+ }
+ return This->fRestrictionLevel;
+}
+
+U_CAPI void U_EXPORT2
+uspoof_setAllowedLocales(USpoofChecker *sc, const char *localesList, UErrorCode *status) {
+ SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return;
+ }
+ This->setAllowedLocales(localesList, *status);
+}
+
+U_CAPI const char * U_EXPORT2
+uspoof_getAllowedLocales(USpoofChecker *sc, UErrorCode *status) {
+ SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return NULL;
+ }
+ return This->getAllowedLocales(*status);
+}
+
+
+U_CAPI const USet * U_EXPORT2
+uspoof_getAllowedChars(const USpoofChecker *sc, UErrorCode *status) {
+ const UnicodeSet *result = uspoof_getAllowedUnicodeSet(sc, status);
+ return result->toUSet();
+}
+
+U_CAPI const UnicodeSet * U_EXPORT2
+uspoof_getAllowedUnicodeSet(const USpoofChecker *sc, UErrorCode *status) {
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return NULL;
+ }
+ return This->fAllowedCharsSet;
+}
+
+
+U_CAPI void U_EXPORT2
+uspoof_setAllowedChars(USpoofChecker *sc, const USet *chars, UErrorCode *status) {
+ const UnicodeSet *set = UnicodeSet::fromUSet(chars);
+ uspoof_setAllowedUnicodeSet(sc, set, status);
+}
+
+
+U_CAPI void U_EXPORT2
+uspoof_setAllowedUnicodeSet(USpoofChecker *sc, const UnicodeSet *chars, UErrorCode *status) {
+ SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return;
+ }
+ if (chars->isBogus()) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ UnicodeSet *clonedSet = chars->clone();
+ if (clonedSet == NULL || clonedSet->isBogus()) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ clonedSet->freeze();
+ delete This->fAllowedCharsSet;
+ This->fAllowedCharsSet = clonedSet;
+ This->fChecks |= USPOOF_CHAR_LIMIT;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_check(const USpoofChecker *sc,
+ const UChar *id, int32_t length,
+ int32_t *position,
+ UErrorCode *status) {
+
+ // Backwards compatibility:
+ if (position != NULL) {
+ *position = 0;
+ }
+
+ // Delegate to uspoof_check2
+ return uspoof_check2(sc, id, length, NULL, status);
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_check2(const USpoofChecker *sc,
+ const UChar* id, int32_t length,
+ USpoofCheckResult* checkResult,
+ UErrorCode *status) {
+
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return 0;
+ }
+ if (length < -1) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UnicodeString idStr((length == -1), id, length); // Aliasing constructor.
+ int32_t result = uspoof_check2UnicodeString(sc, idStr, checkResult, status);
+ return result;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_checkUTF8(const USpoofChecker *sc,
+ const char *id, int32_t length,
+ int32_t *position,
+ UErrorCode *status) {
+
+ // Backwards compatibility:
+ if (position != NULL) {
+ *position = 0;
+ }
+
+ // Delegate to uspoof_check2
+ return uspoof_check2UTF8(sc, id, length, NULL, status);
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_check2UTF8(const USpoofChecker *sc,
+ const char *id, int32_t length,
+ USpoofCheckResult* checkResult,
+ UErrorCode *status) {
+
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ UnicodeString idStr = UnicodeString::fromUTF8(StringPiece(id, length>=0 ? length : static_cast<int32_t>(uprv_strlen(id))));
+ int32_t result = uspoof_check2UnicodeString(sc, idStr, checkResult, status);
+ return result;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusable(const USpoofChecker *sc,
+ const UChar *id1, int32_t length1,
+ const UChar *id2, int32_t length2,
+ UErrorCode *status) {
+ SpoofImpl::validateThis(sc, *status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ if (length1 < -1 || length2 < -1) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ UnicodeString id1Str((length1==-1), id1, length1); // Aliasing constructor
+ UnicodeString id2Str((length2==-1), id2, length2); // Aliasing constructor
+ return uspoof_areConfusableUnicodeString(sc, id1Str, id2Str, status);
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusableUTF8(const USpoofChecker *sc,
+ const char *id1, int32_t length1,
+ const char *id2, int32_t length2,
+ UErrorCode *status) {
+ SpoofImpl::validateThis(sc, *status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ if (length1 < -1 || length2 < -1) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UnicodeString id1Str = UnicodeString::fromUTF8(StringPiece(id1, length1>=0? length1 : static_cast<int32_t>(uprv_strlen(id1))));
+ UnicodeString id2Str = UnicodeString::fromUTF8(StringPiece(id2, length2>=0? length2 : static_cast<int32_t>(uprv_strlen(id2))));
+ int32_t results = uspoof_areConfusableUnicodeString(sc, id1Str, id2Str, status);
+ return results;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusableUnicodeString(const USpoofChecker *sc,
+ const icu::UnicodeString &id1,
+ const icu::UnicodeString &id2,
+ UErrorCode *status) {
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ //
+ // See section 4 of UAX 39 for the algorithm for checking whether two strings are confusable,
+ // and for definitions of the types (single, whole, mixed-script) of confusables.
+
+ // We only care about a few of the check flags. Ignore the others.
+ // If no tests relevant to this function have been specified, return an error.
+ // TODO: is this really the right thing to do? It's probably an error on the caller's part,
+ // but logically we would just return 0 (no error).
+ if ((This->fChecks & USPOOF_CONFUSABLE) == 0) {
+ *status = U_INVALID_STATE_ERROR;
+ return 0;
+ }
+
+ // Compute the skeletons and check for confusability.
+ UnicodeString id1Skeleton;
+ uspoof_getSkeletonUnicodeString(sc, 0 /* deprecated */, id1, id1Skeleton, status);
+ UnicodeString id2Skeleton;
+ uspoof_getSkeletonUnicodeString(sc, 0 /* deprecated */, id2, id2Skeleton, status);
+ if (U_FAILURE(*status)) { return 0; }
+ if (id1Skeleton != id2Skeleton) {
+ return 0;
+ }
+
+ // If we get here, the strings are confusable. Now we just need to set the flags for the appropriate classes
+ // of confusables according to UTS 39 section 4.
+ // Start by computing the resolved script sets of id1 and id2.
+ ScriptSet id1RSS;
+ This->getResolvedScriptSet(id1, id1RSS, *status);
+ ScriptSet id2RSS;
+ This->getResolvedScriptSet(id2, id2RSS, *status);
+
+ // Turn on all applicable flags
+ int32_t result = 0;
+ if (id1RSS.intersects(id2RSS)) {
+ result |= USPOOF_SINGLE_SCRIPT_CONFUSABLE;
+ } else {
+ result |= USPOOF_MIXED_SCRIPT_CONFUSABLE;
+ if (!id1RSS.isEmpty() && !id2RSS.isEmpty()) {
+ result |= USPOOF_WHOLE_SCRIPT_CONFUSABLE;
+ }
+ }
+
+ // Turn off flags that the user doesn't want
+ if ((This->fChecks & USPOOF_SINGLE_SCRIPT_CONFUSABLE) == 0) {
+ result &= ~USPOOF_SINGLE_SCRIPT_CONFUSABLE;
+ }
+ if ((This->fChecks & USPOOF_MIXED_SCRIPT_CONFUSABLE) == 0) {
+ result &= ~USPOOF_MIXED_SCRIPT_CONFUSABLE;
+ }
+ if ((This->fChecks & USPOOF_WHOLE_SCRIPT_CONFUSABLE) == 0) {
+ result &= ~USPOOF_WHOLE_SCRIPT_CONFUSABLE;
+ }
+
+ return result;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_checkUnicodeString(const USpoofChecker *sc,
+ const icu::UnicodeString &id,
+ int32_t *position,
+ UErrorCode *status) {
+
+ // Backwards compatibility:
+ if (position != NULL) {
+ *position = 0;
+ }
+
+ // Delegate to uspoof_check2
+ return uspoof_check2UnicodeString(sc, id, NULL, status);
+}
+
+namespace {
+
+int32_t checkImpl(const SpoofImpl* This, const UnicodeString& id, CheckResult* checkResult, UErrorCode* status) {
+ U_ASSERT(This != NULL);
+ U_ASSERT(checkResult != NULL);
+ checkResult->clear();
+ int32_t result = 0;
+
+ if (0 != (This->fChecks & USPOOF_RESTRICTION_LEVEL)) {
+ URestrictionLevel idRestrictionLevel = This->getRestrictionLevel(id, *status);
+ if (idRestrictionLevel > This->fRestrictionLevel) {
+ result |= USPOOF_RESTRICTION_LEVEL;
+ }
+ checkResult->fRestrictionLevel = idRestrictionLevel;
+ }
+
+ if (0 != (This->fChecks & USPOOF_MIXED_NUMBERS)) {
+ UnicodeSet numerics;
+ This->getNumerics(id, numerics, *status);
+ if (numerics.size() > 1) {
+ result |= USPOOF_MIXED_NUMBERS;
+ }
+ checkResult->fNumerics = numerics; // UnicodeSet::operator=
+ }
+
+ if (0 != (This->fChecks & USPOOF_HIDDEN_OVERLAY)) {
+ int32_t index = This->findHiddenOverlay(id, *status);
+ if (index != -1) {
+ result |= USPOOF_HIDDEN_OVERLAY;
+ }
+ }
+
+
+ if (0 != (This->fChecks & USPOOF_CHAR_LIMIT)) {
+ int32_t i;
+ UChar32 c;
+ int32_t length = id.length();
+ for (i=0; i<length ;) {
+ c = id.char32At(i);
+ i += U16_LENGTH(c);
+ if (!This->fAllowedCharsSet->contains(c)) {
+ result |= USPOOF_CHAR_LIMIT;
+ break;
+ }
+ }
+ }
+
+ if (0 != (This->fChecks & USPOOF_INVISIBLE)) {
+ // This check needs to be done on NFD input
+ UnicodeString nfdText;
+ gNfdNormalizer->normalize(id, nfdText, *status);
+ int32_t nfdLength = nfdText.length();
+
+ // scan for more than one occurrence of the same non-spacing mark
+ // in a sequence of non-spacing marks.
+ int32_t i;
+ UChar32 c;
+ UChar32 firstNonspacingMark = 0;
+ UBool haveMultipleMarks = FALSE;
+ UnicodeSet marksSeenSoFar; // Set of combining marks in a single combining sequence.
+
+ for (i=0; i<nfdLength ;) {
+ c = nfdText.char32At(i);
+ i += U16_LENGTH(c);
+ if (u_charType(c) != U_NON_SPACING_MARK) {
+ firstNonspacingMark = 0;
+ if (haveMultipleMarks) {
+ marksSeenSoFar.clear();
+ haveMultipleMarks = FALSE;
+ }
+ continue;
+ }
+ if (firstNonspacingMark == 0) {
+ firstNonspacingMark = c;
+ continue;
+ }
+ if (!haveMultipleMarks) {
+ marksSeenSoFar.add(firstNonspacingMark);
+ haveMultipleMarks = TRUE;
+ }
+ if (marksSeenSoFar.contains(c)) {
+ // report the error, and stop scanning.
+ // No need to find more than the first failure.
+ result |= USPOOF_INVISIBLE;
+ break;
+ }
+ marksSeenSoFar.add(c);
+ }
+ }
+
+ checkResult->fChecks = result;
+ return checkResult->toCombinedBitmask(This->fChecks);
+}
+
+} // namespace
+
+U_CAPI int32_t U_EXPORT2
+uspoof_check2UnicodeString(const USpoofChecker *sc,
+ const icu::UnicodeString &id,
+ USpoofCheckResult* checkResult,
+ UErrorCode *status) {
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return FALSE;
+ }
+
+ if (checkResult != NULL) {
+ CheckResult* ThisCheckResult = CheckResult::validateThis(checkResult, *status);
+ if (ThisCheckResult == NULL) {
+ return FALSE;
+ }
+ return checkImpl(This, id, ThisCheckResult, status);
+ } else {
+ // Stack-allocate the checkResult since this method doesn't return it
+ CheckResult stackCheckResult;
+ return checkImpl(This, id, &stackCheckResult, status);
+ }
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_getSkeleton(const USpoofChecker *sc,
+ uint32_t type,
+ const UChar *id, int32_t length,
+ UChar *dest, int32_t destCapacity,
+ UErrorCode *status) {
+
+ SpoofImpl::validateThis(sc, *status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ if (length<-1 || destCapacity<0 || (destCapacity==0 && dest!=NULL)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ UnicodeString idStr((length==-1), id, length); // Aliasing constructor
+ UnicodeString destStr;
+ uspoof_getSkeletonUnicodeString(sc, type, idStr, destStr, status);
+ destStr.extract(dest, destCapacity, *status);
+ return destStr.length();
+}
+
+
+
+U_I18N_API UnicodeString & U_EXPORT2
+uspoof_getSkeletonUnicodeString(const USpoofChecker *sc,
+ uint32_t /*type*/,
+ const UnicodeString &id,
+ UnicodeString &dest,
+ UErrorCode *status) {
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (U_FAILURE(*status)) {
+ return dest;
+ }
+
+ UnicodeString nfdId;
+ gNfdNormalizer->normalize(id, nfdId, *status);
+
+ // Apply the skeleton mapping to the NFD normalized input string
+ // Accumulate the skeleton, possibly unnormalized, in a UnicodeString.
+ int32_t inputIndex = 0;
+ UnicodeString skelStr;
+ int32_t normalizedLen = nfdId.length();
+ for (inputIndex=0; inputIndex < normalizedLen; ) {
+ UChar32 c = nfdId.char32At(inputIndex);
+ inputIndex += U16_LENGTH(c);
+ This->fSpoofData->confusableLookup(c, skelStr);
+ }
+
+ gNfdNormalizer->normalize(skelStr, dest, *status);
+ return dest;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_getSkeletonUTF8(const USpoofChecker *sc,
+ uint32_t type,
+ const char *id, int32_t length,
+ char *dest, int32_t destCapacity,
+ UErrorCode *status) {
+ SpoofImpl::validateThis(sc, *status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ if (length<-1 || destCapacity<0 || (destCapacity==0 && dest!=NULL)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ UnicodeString srcStr = UnicodeString::fromUTF8(StringPiece(id, length>=0 ? length : static_cast<int32_t>(uprv_strlen(id))));
+ UnicodeString destStr;
+ uspoof_getSkeletonUnicodeString(sc, type, srcStr, destStr, status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+
+ int32_t lengthInUTF8 = 0;
+ u_strToUTF8(dest, destCapacity, &lengthInUTF8,
+ destStr.getBuffer(), destStr.length(), status);
+ return lengthInUTF8;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_serialize(USpoofChecker *sc,void *buf, int32_t capacity, UErrorCode *status) {
+ SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ U_ASSERT(U_FAILURE(*status));
+ return 0;
+ }
+
+ return This->fSpoofData->serialize(buf, capacity, *status);
+}
+
+U_CAPI const USet * U_EXPORT2
+uspoof_getInclusionSet(UErrorCode *status) {
+ umtx_initOnce(gSpoofInitStaticsOnce, &initializeStatics, *status);
+ return gInclusionSet->toUSet();
+}
+
+U_CAPI const USet * U_EXPORT2
+uspoof_getRecommendedSet(UErrorCode *status) {
+ umtx_initOnce(gSpoofInitStaticsOnce, &initializeStatics, *status);
+ return gRecommendedSet->toUSet();
+}
+
+U_I18N_API const UnicodeSet * U_EXPORT2
+uspoof_getInclusionUnicodeSet(UErrorCode *status) {
+ umtx_initOnce(gSpoofInitStaticsOnce, &initializeStatics, *status);
+ return gInclusionSet;
+}
+
+U_I18N_API const UnicodeSet * U_EXPORT2
+uspoof_getRecommendedUnicodeSet(UErrorCode *status) {
+ umtx_initOnce(gSpoofInitStaticsOnce, &initializeStatics, *status);
+ return gRecommendedSet;
+}
+
+//------------------
+// CheckResult APIs
+//------------------
+
+U_CAPI USpoofCheckResult* U_EXPORT2
+uspoof_openCheckResult(UErrorCode *status) {
+ CheckResult* checkResult = new CheckResult();
+ if (checkResult == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ return checkResult->asUSpoofCheckResult();
+}
+
+U_CAPI void U_EXPORT2
+uspoof_closeCheckResult(USpoofCheckResult* checkResult) {
+ UErrorCode status = U_ZERO_ERROR;
+ CheckResult* This = CheckResult::validateThis(checkResult, status);
+ delete This;
+}
+
+U_CAPI int32_t U_EXPORT2
+uspoof_getCheckResultChecks(const USpoofCheckResult *checkResult, UErrorCode *status) {
+ const CheckResult* This = CheckResult::validateThis(checkResult, *status);
+ if (U_FAILURE(*status)) { return 0; }
+ return This->fChecks;
+}
+
+U_CAPI URestrictionLevel U_EXPORT2
+uspoof_getCheckResultRestrictionLevel(const USpoofCheckResult *checkResult, UErrorCode *status) {
+ const CheckResult* This = CheckResult::validateThis(checkResult, *status);
+ if (U_FAILURE(*status)) { return USPOOF_UNRESTRICTIVE; }
+ return This->fRestrictionLevel;
+}
+
+U_CAPI const USet* U_EXPORT2
+uspoof_getCheckResultNumerics(const USpoofCheckResult *checkResult, UErrorCode *status) {
+ const CheckResult* This = CheckResult::validateThis(checkResult, *status);
+ if (U_FAILURE(*status)) { return NULL; }
+ return This->fNumerics.toUSet();
+}
+
+
+
+#endif // !UCONFIG_NO_NORMALIZATION
diff --git a/thirdparty/icu4c/i18n/uspoof_impl.cpp b/thirdparty/icu4c/i18n/uspoof_impl.cpp
new file mode 100644
index 0000000000..b283d81321
--- /dev/null
+++ b/thirdparty/icu4c/i18n/uspoof_impl.cpp
@@ -0,0 +1,959 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+**********************************************************************
+* Copyright (C) 2008-2016, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uspoof.h"
+#include "unicode/uchar.h"
+#include "unicode/uniset.h"
+#include "unicode/utf16.h"
+#include "utrie2.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "scriptset.h"
+#include "umutex.h"
+#include "udataswp.h"
+#include "uassert.h"
+#include "ucln_in.h"
+#include "uspoof_impl.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SpoofImpl)
+
+SpoofImpl::SpoofImpl(SpoofData *data, UErrorCode& status) {
+ construct(status);
+ fSpoofData = data;
+}
+
+SpoofImpl::SpoofImpl(UErrorCode& status) {
+ construct(status);
+
+ // TODO: Call this method where it is actually needed, instead of in the
+ // constructor, to allow for lazy data loading. See #12696.
+ fSpoofData = SpoofData::getDefault(status);
+}
+
+SpoofImpl::SpoofImpl() {
+ UErrorCode status = U_ZERO_ERROR;
+ construct(status);
+
+ // TODO: Call this method where it is actually needed, instead of in the
+ // constructor, to allow for lazy data loading. See #12696.
+ fSpoofData = SpoofData::getDefault(status);
+}
+
+void SpoofImpl::construct(UErrorCode& status) {
+ fChecks = USPOOF_ALL_CHECKS;
+ fSpoofData = NULL;
+ fAllowedCharsSet = NULL;
+ fAllowedLocales = NULL;
+ fRestrictionLevel = USPOOF_HIGHLY_RESTRICTIVE;
+
+ if (U_FAILURE(status)) { return; }
+
+ UnicodeSet *allowedCharsSet = new UnicodeSet(0, 0x10ffff);
+ fAllowedCharsSet = allowedCharsSet;
+ fAllowedLocales = uprv_strdup("");
+ if (fAllowedCharsSet == NULL || fAllowedLocales == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ allowedCharsSet->freeze();
+}
+
+
+// Copy Constructor, used by the user level clone() function.
+SpoofImpl::SpoofImpl(const SpoofImpl &src, UErrorCode &status) :
+ fChecks(USPOOF_ALL_CHECKS), fSpoofData(NULL), fAllowedCharsSet(NULL) ,
+ fAllowedLocales(NULL) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fChecks = src.fChecks;
+ if (src.fSpoofData != NULL) {
+ fSpoofData = src.fSpoofData->addReference();
+ }
+ fAllowedCharsSet = src.fAllowedCharsSet->clone();
+ fAllowedLocales = uprv_strdup(src.fAllowedLocales);
+ if (fAllowedCharsSet == NULL || fAllowedLocales == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ fRestrictionLevel = src.fRestrictionLevel;
+}
+
+SpoofImpl::~SpoofImpl() {
+ if (fSpoofData != NULL) {
+ fSpoofData->removeReference(); // Will delete if refCount goes to zero.
+ }
+ delete fAllowedCharsSet;
+ uprv_free((void *)fAllowedLocales);
+}
+
+// Cast this instance as a USpoofChecker for the C API.
+USpoofChecker *SpoofImpl::asUSpoofChecker() {
+ return exportForC();
+}
+
+//
+// Incoming parameter check on Status and the SpoofChecker object
+// received from the C API.
+//
+const SpoofImpl *SpoofImpl::validateThis(const USpoofChecker *sc, UErrorCode &status) {
+ auto* This = validate(sc, status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ if (This->fSpoofData != NULL && !This->fSpoofData->validateDataVersion(status)) {
+ return NULL;
+ }
+ return This;
+}
+
+SpoofImpl *SpoofImpl::validateThis(USpoofChecker *sc, UErrorCode &status) {
+ return const_cast<SpoofImpl *>
+ (SpoofImpl::validateThis(const_cast<const USpoofChecker *>(sc), status));
+}
+
+
+void SpoofImpl::setAllowedLocales(const char *localesList, UErrorCode &status) {
+ UnicodeSet allowedChars;
+ UnicodeSet *tmpSet = NULL;
+ const char *locStart = localesList;
+ const char *locEnd = NULL;
+ const char *localesListEnd = localesList + uprv_strlen(localesList);
+ int32_t localeListCount = 0; // Number of locales provided by caller.
+
+ // Loop runs once per locale from the localesList, a comma separated list of locales.
+ do {
+ locEnd = uprv_strchr(locStart, ',');
+ if (locEnd == NULL) {
+ locEnd = localesListEnd;
+ }
+ while (*locStart == ' ') {
+ locStart++;
+ }
+ const char *trimmedEnd = locEnd-1;
+ while (trimmedEnd > locStart && *trimmedEnd == ' ') {
+ trimmedEnd--;
+ }
+ if (trimmedEnd <= locStart) {
+ break;
+ }
+ const char *locale = uprv_strndup(locStart, (int32_t)(trimmedEnd + 1 - locStart));
+ localeListCount++;
+
+ // We have one locale from the locales list.
+ // Add the script chars for this locale to the accumulating set of allowed chars.
+ // If the locale is no good, we will be notified back via status.
+ addScriptChars(locale, &allowedChars, status);
+ uprv_free((void *)locale);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ locStart = locEnd + 1;
+ } while (locStart < localesListEnd);
+
+ // If our caller provided an empty list of locales, we disable the allowed characters checking
+ if (localeListCount == 0) {
+ uprv_free((void *)fAllowedLocales);
+ fAllowedLocales = uprv_strdup("");
+ tmpSet = new UnicodeSet(0, 0x10ffff);
+ if (fAllowedLocales == NULL || tmpSet == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ tmpSet->freeze();
+ delete fAllowedCharsSet;
+ fAllowedCharsSet = tmpSet;
+ fChecks &= ~USPOOF_CHAR_LIMIT;
+ return;
+ }
+
+
+ // Add all common and inherited characters to the set of allowed chars.
+ UnicodeSet tempSet;
+ tempSet.applyIntPropertyValue(UCHAR_SCRIPT, USCRIPT_COMMON, status);
+ allowedChars.addAll(tempSet);
+ tempSet.applyIntPropertyValue(UCHAR_SCRIPT, USCRIPT_INHERITED, status);
+ allowedChars.addAll(tempSet);
+
+ // If anything went wrong, we bail out without changing
+ // the state of the spoof checker.
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // Store the updated spoof checker state.
+ tmpSet = allowedChars.clone();
+ const char *tmpLocalesList = uprv_strdup(localesList);
+ if (tmpSet == NULL || tmpLocalesList == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ uprv_free((void *)fAllowedLocales);
+ fAllowedLocales = tmpLocalesList;
+ tmpSet->freeze();
+ delete fAllowedCharsSet;
+ fAllowedCharsSet = tmpSet;
+ fChecks |= USPOOF_CHAR_LIMIT;
+}
+
+
+const char * SpoofImpl::getAllowedLocales(UErrorCode &/*status*/) {
+ return fAllowedLocales;
+}
+
+
+// Given a locale (a language), add all the characters from all of the scripts used with that language
+// to the allowedChars UnicodeSet
+
+void SpoofImpl::addScriptChars(const char *locale, UnicodeSet *allowedChars, UErrorCode &status) {
+ UScriptCode scripts[30];
+
+ int32_t numScripts = uscript_getCode(locale, scripts, UPRV_LENGTHOF(scripts), &status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (status == U_USING_DEFAULT_WARNING) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ UnicodeSet tmpSet;
+ int32_t i;
+ for (i=0; i<numScripts; i++) {
+ tmpSet.applyIntPropertyValue(UCHAR_SCRIPT, scripts[i], status);
+ allowedChars->addAll(tmpSet);
+ }
+}
+
+// Computes the augmented script set for a code point, according to UTS 39 section 5.1.
+void SpoofImpl::getAugmentedScriptSet(UChar32 codePoint, ScriptSet& result, UErrorCode& status) {
+ result.resetAll();
+ result.setScriptExtensions(codePoint, status);
+ if (U_FAILURE(status)) { return; }
+
+ // Section 5.1 step 1
+ if (result.test(USCRIPT_HAN, status)) {
+ result.set(USCRIPT_HAN_WITH_BOPOMOFO, status);
+ result.set(USCRIPT_JAPANESE, status);
+ result.set(USCRIPT_KOREAN, status);
+ }
+ if (result.test(USCRIPT_HIRAGANA, status)) {
+ result.set(USCRIPT_JAPANESE, status);
+ }
+ if (result.test(USCRIPT_KATAKANA, status)) {
+ result.set(USCRIPT_JAPANESE, status);
+ }
+ if (result.test(USCRIPT_HANGUL, status)) {
+ result.set(USCRIPT_KOREAN, status);
+ }
+ if (result.test(USCRIPT_BOPOMOFO, status)) {
+ result.set(USCRIPT_HAN_WITH_BOPOMOFO, status);
+ }
+
+ // Section 5.1 step 2
+ if (result.test(USCRIPT_COMMON, status) || result.test(USCRIPT_INHERITED, status)) {
+ result.setAll();
+ }
+}
+
+// Computes the resolved script set for a string, according to UTS 39 section 5.1.
+void SpoofImpl::getResolvedScriptSet(const UnicodeString& input, ScriptSet& result, UErrorCode& status) const {
+ getResolvedScriptSetWithout(input, USCRIPT_CODE_LIMIT, result, status);
+}
+
+// Computes the resolved script set for a string, omitting characters having the specified script.
+// If USCRIPT_CODE_LIMIT is passed as the second argument, all characters are included.
+void SpoofImpl::getResolvedScriptSetWithout(const UnicodeString& input, UScriptCode script, ScriptSet& result, UErrorCode& status) const {
+ result.setAll();
+
+ ScriptSet temp;
+ UChar32 codePoint;
+ for (int32_t i = 0; i < input.length(); i += U16_LENGTH(codePoint)) {
+ codePoint = input.char32At(i);
+
+ // Compute the augmented script set for the character
+ getAugmentedScriptSet(codePoint, temp, status);
+ if (U_FAILURE(status)) { return; }
+
+ // Intersect the augmented script set with the resolved script set, but only if the character doesn't
+ // have the script specified in the function call
+ if (script == USCRIPT_CODE_LIMIT || !temp.test(script, status)) {
+ result.intersect(temp);
+ }
+ }
+}
+
+// Computes the set of numerics for a string, according to UTS 39 section 5.3.
+void SpoofImpl::getNumerics(const UnicodeString& input, UnicodeSet& result, UErrorCode& /*status*/) const {
+ result.clear();
+
+ UChar32 codePoint;
+ for (int32_t i = 0; i < input.length(); i += U16_LENGTH(codePoint)) {
+ codePoint = input.char32At(i);
+
+ // Store a representative character for each kind of decimal digit
+ if (u_charType(codePoint) == U_DECIMAL_DIGIT_NUMBER) {
+ // Store the zero character as a representative for comparison.
+ // Unicode guarantees it is codePoint - value
+ result.add(codePoint - (UChar32)u_getNumericValue(codePoint));
+ }
+ }
+}
+
+// Computes the restriction level of a string, according to UTS 39 section 5.2.
+URestrictionLevel SpoofImpl::getRestrictionLevel(const UnicodeString& input, UErrorCode& status) const {
+ // Section 5.2 step 1:
+ if (!fAllowedCharsSet->containsAll(input)) {
+ return USPOOF_UNRESTRICTIVE;
+ }
+
+ // Section 5.2 step 2
+ // Java use a static UnicodeSet for this test. In C++, avoid the static variable
+ // and just do a simple for loop.
+ UBool allASCII = TRUE;
+ for (int32_t i=0, length=input.length(); i<length; i++) {
+ if (input.charAt(i) > 0x7f) {
+ allASCII = FALSE;
+ break;
+ }
+ }
+ if (allASCII) {
+ return USPOOF_ASCII;
+ }
+
+ // Section 5.2 steps 3:
+ ScriptSet resolvedScriptSet;
+ getResolvedScriptSet(input, resolvedScriptSet, status);
+ if (U_FAILURE(status)) { return USPOOF_UNRESTRICTIVE; }
+
+ // Section 5.2 step 4:
+ if (!resolvedScriptSet.isEmpty()) {
+ return USPOOF_SINGLE_SCRIPT_RESTRICTIVE;
+ }
+
+ // Section 5.2 step 5:
+ ScriptSet resolvedNoLatn;
+ getResolvedScriptSetWithout(input, USCRIPT_LATIN, resolvedNoLatn, status);
+ if (U_FAILURE(status)) { return USPOOF_UNRESTRICTIVE; }
+
+ // Section 5.2 step 6:
+ if (resolvedNoLatn.test(USCRIPT_HAN_WITH_BOPOMOFO, status)
+ || resolvedNoLatn.test(USCRIPT_JAPANESE, status)
+ || resolvedNoLatn.test(USCRIPT_KOREAN, status)) {
+ return USPOOF_HIGHLY_RESTRICTIVE;
+ }
+
+ // Section 5.2 step 7:
+ if (!resolvedNoLatn.isEmpty()
+ && !resolvedNoLatn.test(USCRIPT_CYRILLIC, status)
+ && !resolvedNoLatn.test(USCRIPT_GREEK, status)
+ && !resolvedNoLatn.test(USCRIPT_CHEROKEE, status)) {
+ return USPOOF_MODERATELY_RESTRICTIVE;
+ }
+
+ // Section 5.2 step 8:
+ return USPOOF_MINIMALLY_RESTRICTIVE;
+}
+
+int32_t SpoofImpl::findHiddenOverlay(const UnicodeString& input, UErrorCode&) const {
+ bool sawLeadCharacter = false;
+ for (int32_t i=0; i<input.length();) {
+ UChar32 cp = input.char32At(i);
+ if (sawLeadCharacter && cp == 0x0307) {
+ return i;
+ }
+ uint8_t combiningClass = u_getCombiningClass(cp);
+ // Skip over characters except for those with combining class 0 (non-combining characters) or with
+ // combining class 230 (same class as U+0307)
+ U_ASSERT(u_getCombiningClass(0x0307) == 230);
+ if (combiningClass == 0 || combiningClass == 230) {
+ sawLeadCharacter = isIllegalCombiningDotLeadCharacter(cp);
+ }
+ i += U16_LENGTH(cp);
+ }
+ return -1;
+}
+
+static inline bool isIllegalCombiningDotLeadCharacterNoLookup(UChar32 cp) {
+ return cp == u'i' || cp == u'j' || cp == u'ı' || cp == u'ȷ' || cp == u'l' ||
+ u_hasBinaryProperty(cp, UCHAR_SOFT_DOTTED);
+}
+
+bool SpoofImpl::isIllegalCombiningDotLeadCharacter(UChar32 cp) const {
+ if (isIllegalCombiningDotLeadCharacterNoLookup(cp)) {
+ return true;
+ }
+ UnicodeString skelStr;
+ fSpoofData->confusableLookup(cp, skelStr);
+ UChar32 finalCp = skelStr.char32At(skelStr.moveIndex32(skelStr.length(), -1));
+ if (finalCp != cp && isIllegalCombiningDotLeadCharacterNoLookup(finalCp)) {
+ return true;
+ }
+ return false;
+}
+
+
+
+// Convert a text format hex number. Utility function used by builder code. Static.
+// Input: UChar *string text. Output: a UChar32
+// Input has been pre-checked, and will have no non-hex chars.
+// The number must fall in the code point range of 0..0x10ffff
+// Static Function.
+UChar32 SpoofImpl::ScanHex(const UChar *s, int32_t start, int32_t limit, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+ U_ASSERT(limit-start > 0);
+ uint32_t val = 0;
+ int i;
+ for (i=start; i<limit; i++) {
+ int digitVal = s[i] - 0x30;
+ if (digitVal>9) {
+ digitVal = 0xa + (s[i] - 0x41); // Upper Case 'A'
+ }
+ if (digitVal>15) {
+ digitVal = 0xa + (s[i] - 0x61); // Lower Case 'a'
+ }
+ U_ASSERT(digitVal <= 0xf);
+ val <<= 4;
+ val += digitVal;
+ }
+ if (val > 0x10ffff) {
+ status = U_PARSE_ERROR;
+ val = 0;
+ }
+ return (UChar32)val;
+}
+
+
+//-----------------------------------------
+//
+// class CheckResult Implementation
+//
+//-----------------------------------------
+
+CheckResult::CheckResult() {
+ clear();
+}
+
+USpoofCheckResult* CheckResult::asUSpoofCheckResult() {
+ return exportForC();
+}
+
+//
+// Incoming parameter check on Status and the CheckResult object
+// received from the C API.
+//
+const CheckResult* CheckResult::validateThis(const USpoofCheckResult *ptr, UErrorCode &status) {
+ return validate(ptr, status);
+}
+
+CheckResult* CheckResult::validateThis(USpoofCheckResult *ptr, UErrorCode &status) {
+ return validate(ptr, status);
+}
+
+void CheckResult::clear() {
+ fChecks = 0;
+ fNumerics.clear();
+ fRestrictionLevel = USPOOF_UNDEFINED_RESTRICTIVE;
+}
+
+int32_t CheckResult::toCombinedBitmask(int32_t enabledChecks) {
+ if ((enabledChecks & USPOOF_AUX_INFO) != 0 && fRestrictionLevel != USPOOF_UNDEFINED_RESTRICTIVE) {
+ return fChecks | fRestrictionLevel;
+ } else {
+ return fChecks;
+ }
+}
+
+CheckResult::~CheckResult() {
+}
+
+//----------------------------------------------------------------------------------------------
+//
+// class SpoofData Implementation
+//
+//----------------------------------------------------------------------------------------------
+
+
+UBool SpoofData::validateDataVersion(UErrorCode &status) const {
+ if (U_FAILURE(status) ||
+ fRawData == NULL ||
+ fRawData->fMagic != USPOOF_MAGIC ||
+ fRawData->fFormatVersion[0] != USPOOF_CONFUSABLE_DATA_FORMAT_VERSION ||
+ fRawData->fFormatVersion[1] != 0 ||
+ fRawData->fFormatVersion[2] != 0 ||
+ fRawData->fFormatVersion[3] != 0) {
+ status = U_INVALID_FORMAT_ERROR;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static UBool U_CALLCONV
+spoofDataIsAcceptable(void *context,
+ const char * /* type */, const char * /*name*/,
+ const UDataInfo *pInfo) {
+ if(
+ pInfo->size >= 20 &&
+ pInfo->isBigEndian == U_IS_BIG_ENDIAN &&
+ pInfo->charsetFamily == U_CHARSET_FAMILY &&
+ pInfo->dataFormat[0] == 0x43 && // dataFormat="Cfu "
+ pInfo->dataFormat[1] == 0x66 &&
+ pInfo->dataFormat[2] == 0x75 &&
+ pInfo->dataFormat[3] == 0x20 &&
+ pInfo->formatVersion[0] == USPOOF_CONFUSABLE_DATA_FORMAT_VERSION
+ ) {
+ UVersionInfo *version = static_cast<UVersionInfo *>(context);
+ if(version != NULL) {
+ uprv_memcpy(version, pInfo->dataVersion, 4);
+ }
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+// Methods for the loading of the default confusables data file. The confusable
+// data is loaded only when it is needed.
+//
+// SpoofData::getDefault() - Return the default confusables data, and call the
+// initOnce() if it is not available. Adds a reference
+// to the SpoofData that the caller is responsible for
+// decrementing when they are done with the data.
+//
+// uspoof_loadDefaultData - Called once, from initOnce(). The resulting SpoofData
+// is shared by all spoof checkers using the default data.
+//
+// uspoof_cleanupDefaultData - Called during cleanup.
+//
+
+static UInitOnce gSpoofInitDefaultOnce = U_INITONCE_INITIALIZER;
+static SpoofData* gDefaultSpoofData;
+
+static UBool U_CALLCONV
+uspoof_cleanupDefaultData(void) {
+ if (gDefaultSpoofData) {
+ // Will delete, assuming all user-level spoof checkers were closed.
+ gDefaultSpoofData->removeReference();
+ gDefaultSpoofData = nullptr;
+ gSpoofInitDefaultOnce.reset();
+ }
+ return TRUE;
+}
+
+static void U_CALLCONV uspoof_loadDefaultData(UErrorCode& status) {
+ UDataMemory *udm = udata_openChoice(nullptr, "cfu", "confusables",
+ spoofDataIsAcceptable,
+ nullptr, // context, would receive dataVersion if supplied.
+ &status);
+ if (U_FAILURE(status)) { return; }
+ gDefaultSpoofData = new SpoofData(udm, status);
+ if (U_FAILURE(status)) {
+ delete gDefaultSpoofData;
+ gDefaultSpoofData = nullptr;
+ return;
+ }
+ if (gDefaultSpoofData == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ ucln_i18n_registerCleanup(UCLN_I18N_SPOOFDATA, uspoof_cleanupDefaultData);
+}
+
+SpoofData* SpoofData::getDefault(UErrorCode& status) {
+ umtx_initOnce(gSpoofInitDefaultOnce, &uspoof_loadDefaultData, status);
+ if (U_FAILURE(status)) { return NULL; }
+ gDefaultSpoofData->addReference();
+ return gDefaultSpoofData;
+}
+
+
+
+SpoofData::SpoofData(UDataMemory *udm, UErrorCode &status)
+{
+ reset();
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fUDM = udm;
+ // fRawData is non-const because it may be constructed by the data builder.
+ fRawData = reinterpret_cast<SpoofDataHeader *>(
+ const_cast<void *>(udata_getMemory(udm)));
+ validateDataVersion(status);
+ initPtrs(status);
+}
+
+
+SpoofData::SpoofData(const void *data, int32_t length, UErrorCode &status)
+{
+ reset();
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if ((size_t)length < sizeof(SpoofDataHeader)) {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ if (data == NULL) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ void *ncData = const_cast<void *>(data);
+ fRawData = static_cast<SpoofDataHeader *>(ncData);
+ if (length < fRawData->fLength) {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ validateDataVersion(status);
+ initPtrs(status);
+}
+
+
+// Spoof Data constructor for use from data builder.
+// Initializes a new, empty data area that will be populated later.
+SpoofData::SpoofData(UErrorCode &status) {
+ reset();
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fDataOwned = true;
+
+ // The spoof header should already be sized to be a multiple of 16 bytes.
+ // Just in case it's not, round it up.
+ uint32_t initialSize = (sizeof(SpoofDataHeader) + 15) & ~15;
+ U_ASSERT(initialSize == sizeof(SpoofDataHeader));
+
+ fRawData = static_cast<SpoofDataHeader *>(uprv_malloc(initialSize));
+ fMemLimit = initialSize;
+ if (fRawData == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ uprv_memset(fRawData, 0, initialSize);
+
+ fRawData->fMagic = USPOOF_MAGIC;
+ fRawData->fFormatVersion[0] = USPOOF_CONFUSABLE_DATA_FORMAT_VERSION;
+ fRawData->fFormatVersion[1] = 0;
+ fRawData->fFormatVersion[2] = 0;
+ fRawData->fFormatVersion[3] = 0;
+ initPtrs(status);
+}
+
+// reset() - initialize all fields.
+// Should be updated if any new fields are added.
+// Called by constructors to put things in a known initial state.
+void SpoofData::reset() {
+ fRawData = NULL;
+ fDataOwned = FALSE;
+ fUDM = NULL;
+ fMemLimit = 0;
+ fRefCount = 1;
+ fCFUKeys = NULL;
+ fCFUValues = NULL;
+ fCFUStrings = NULL;
+}
+
+
+// SpoofData::initPtrs()
+// Initialize the pointers to the various sections of the raw data.
+//
+// This function is used both during the Trie building process (multiple
+// times, as the individual data sections are added), and
+// during the opening of a Spoof Checker from prebuilt data.
+//
+// The pointers for non-existent data sections (identified by an offset of 0)
+// are set to NULL.
+//
+// Note: During building the data, adding each new data section
+// reallocs the raw data area, which likely relocates it, which
+// in turn requires reinitializing all of the pointers into it, hence
+// multiple calls to this function during building.
+//
+void SpoofData::initPtrs(UErrorCode &status) {
+ fCFUKeys = NULL;
+ fCFUValues = NULL;
+ fCFUStrings = NULL;
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (fRawData->fCFUKeys != 0) {
+ fCFUKeys = (int32_t *)((char *)fRawData + fRawData->fCFUKeys);
+ }
+ if (fRawData->fCFUStringIndex != 0) {
+ fCFUValues = (uint16_t *)((char *)fRawData + fRawData->fCFUStringIndex);
+ }
+ if (fRawData->fCFUStringTable != 0) {
+ fCFUStrings = (UChar *)((char *)fRawData + fRawData->fCFUStringTable);
+ }
+}
+
+
+SpoofData::~SpoofData() {
+ if (fDataOwned) {
+ uprv_free(fRawData);
+ }
+ fRawData = NULL;
+ if (fUDM != NULL) {
+ udata_close(fUDM);
+ }
+ fUDM = NULL;
+}
+
+
+void SpoofData::removeReference() {
+ if (umtx_atomic_dec(&fRefCount) == 0) {
+ delete this;
+ }
+}
+
+
+SpoofData *SpoofData::addReference() {
+ umtx_atomic_inc(&fRefCount);
+ return this;
+}
+
+
+void *SpoofData::reserveSpace(int32_t numBytes, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ if (!fDataOwned) {
+ UPRV_UNREACHABLE_EXIT;
+ }
+
+ numBytes = (numBytes + 15) & ~15; // Round up to a multiple of 16
+ uint32_t returnOffset = fMemLimit;
+ fMemLimit += numBytes;
+ fRawData = static_cast<SpoofDataHeader *>(uprv_realloc(fRawData, fMemLimit));
+ fRawData->fLength = fMemLimit;
+ uprv_memset((char *)fRawData + returnOffset, 0, numBytes);
+ initPtrs(status);
+ return (char *)fRawData + returnOffset;
+}
+
+int32_t SpoofData::serialize(void *buf, int32_t capacity, UErrorCode &status) const {
+ int32_t dataSize = fRawData->fLength;
+ if (capacity < dataSize) {
+ status = U_BUFFER_OVERFLOW_ERROR;
+ return dataSize;
+ }
+ uprv_memcpy(buf, fRawData, dataSize);
+ return dataSize;
+}
+
+int32_t SpoofData::size() const {
+ return fRawData->fLength;
+}
+
+//-------------------------------
+//
+// Front-end APIs for SpoofData
+//
+//-------------------------------
+
+int32_t SpoofData::confusableLookup(UChar32 inChar, UnicodeString &dest) const {
+ // Perform a binary search.
+ // [lo, hi), i.e lo is inclusive, hi is exclusive.
+ // The result after the loop will be in lo.
+ int32_t lo = 0;
+ int32_t hi = length();
+ do {
+ int32_t mid = (lo + hi) / 2;
+ if (codePointAt(mid) > inChar) {
+ hi = mid;
+ } else if (codePointAt(mid) < inChar) {
+ lo = mid;
+ } else {
+ // Found result. Break early.
+ lo = mid;
+ break;
+ }
+ } while (hi - lo > 1);
+
+ // Did we find an entry? If not, the char maps to itself.
+ if (codePointAt(lo) != inChar) {
+ dest.append(inChar);
+ return 1;
+ }
+
+ // Add the element to the string builder and return.
+ return appendValueTo(lo, dest);
+}
+
+int32_t SpoofData::length() const {
+ return fRawData->fCFUKeysSize;
+}
+
+UChar32 SpoofData::codePointAt(int32_t index) const {
+ return ConfusableDataUtils::keyToCodePoint(fCFUKeys[index]);
+}
+
+int32_t SpoofData::appendValueTo(int32_t index, UnicodeString& dest) const {
+ int32_t stringLength = ConfusableDataUtils::keyToLength(fCFUKeys[index]);
+
+ // Value is either a char (for strings of length 1) or
+ // an index into the string table (for longer strings)
+ uint16_t value = fCFUValues[index];
+ if (stringLength == 1) {
+ dest.append((UChar)value);
+ } else {
+ dest.append(fCFUStrings + value, stringLength);
+ }
+
+ return stringLength;
+}
+
+
+U_NAMESPACE_END
+
+U_NAMESPACE_USE
+
+//-----------------------------------------------------------------------------
+//
+// uspoof_swap - byte swap and char encoding swap of spoof data
+//
+//-----------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uspoof_swap(const UDataSwapper *ds, const void *inData, int32_t length, void *outData,
+ UErrorCode *status) {
+
+ if (status == NULL || U_FAILURE(*status)) {
+ return 0;
+ }
+ if(ds==NULL || inData==NULL || length<-1 || (length>0 && outData==NULL)) {
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ //
+ // Check that the data header is for spoof data.
+ // (Header contents are defined in gencfu.cpp)
+ //
+ const UDataInfo *pInfo = (const UDataInfo *)((const char *)inData+4);
+ if(!( pInfo->dataFormat[0]==0x43 && /* dataFormat="Cfu " */
+ pInfo->dataFormat[1]==0x66 &&
+ pInfo->dataFormat[2]==0x75 &&
+ pInfo->dataFormat[3]==0x20 &&
+ pInfo->formatVersion[0]==USPOOF_CONFUSABLE_DATA_FORMAT_VERSION &&
+ pInfo->formatVersion[1]==0 &&
+ pInfo->formatVersion[2]==0 &&
+ pInfo->formatVersion[3]==0 )) {
+ udata_printError(ds, "uspoof_swap(): data format %02x.%02x.%02x.%02x "
+ "(format version %02x %02x %02x %02x) is not recognized\n",
+ pInfo->dataFormat[0], pInfo->dataFormat[1],
+ pInfo->dataFormat[2], pInfo->dataFormat[3],
+ pInfo->formatVersion[0], pInfo->formatVersion[1],
+ pInfo->formatVersion[2], pInfo->formatVersion[3]);
+ *status=U_UNSUPPORTED_ERROR;
+ return 0;
+ }
+
+ //
+ // Swap the data header. (This is the generic ICU Data Header, not the uspoof Specific
+ // header). This swap also conveniently gets us
+ // the size of the ICU d.h., which lets us locate the start
+ // of the uspoof specific data.
+ //
+ int32_t headerSize=udata_swapDataHeader(ds, inData, length, outData, status);
+
+
+ //
+ // Get the Spoof Data Header, and check that it appears to be OK.
+ //
+ //
+ const uint8_t *inBytes =(const uint8_t *)inData+headerSize;
+ SpoofDataHeader *spoofDH = (SpoofDataHeader *)inBytes;
+ if (ds->readUInt32(spoofDH->fMagic) != USPOOF_MAGIC ||
+ ds->readUInt32(spoofDH->fLength) < sizeof(SpoofDataHeader))
+ {
+ udata_printError(ds, "uspoof_swap(): Spoof Data header is invalid.\n");
+ *status=U_UNSUPPORTED_ERROR;
+ return 0;
+ }
+
+ //
+ // Prefight operation? Just return the size
+ //
+ int32_t spoofDataLength = ds->readUInt32(spoofDH->fLength);
+ int32_t totalSize = headerSize + spoofDataLength;
+ if (length < 0) {
+ return totalSize;
+ }
+
+ //
+ // Check that length passed in is consistent with length from Spoof data header.
+ //
+ if (length < totalSize) {
+ udata_printError(ds, "uspoof_swap(): too few bytes (%d after ICU Data header) for spoof data.\n",
+ spoofDataLength);
+ *status=U_INDEX_OUTOFBOUNDS_ERROR;
+ return 0;
+ }
+
+
+ //
+ // Swap the Data. Do the data itself first, then the Spoof Data Header, because
+ // we need to reference the header to locate the data, and an
+ // inplace swap of the header leaves it unusable.
+ //
+ uint8_t *outBytes = (uint8_t *)outData + headerSize;
+ SpoofDataHeader *outputDH = (SpoofDataHeader *)outBytes;
+
+ int32_t sectionStart;
+ int32_t sectionLength;
+
+ //
+ // If not swapping in place, zero out the output buffer before starting.
+ // Gaps may exist between the individual sections, and these must be zeroed in
+ // the output buffer. The simplest way to do that is to just zero the whole thing.
+ //
+ if (inBytes != outBytes) {
+ uprv_memset(outBytes, 0, spoofDataLength);
+ }
+
+ // Confusables Keys Section (fCFUKeys)
+ sectionStart = ds->readUInt32(spoofDH->fCFUKeys);
+ sectionLength = ds->readUInt32(spoofDH->fCFUKeysSize) * 4;
+ ds->swapArray32(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+ // String Index Section
+ sectionStart = ds->readUInt32(spoofDH->fCFUStringIndex);
+ sectionLength = ds->readUInt32(spoofDH->fCFUStringIndexSize) * 2;
+ ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+ // String Table Section
+ sectionStart = ds->readUInt32(spoofDH->fCFUStringTable);
+ sectionLength = ds->readUInt32(spoofDH->fCFUStringTableLen) * 2;
+ ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+ // And, last, swap the header itself.
+ // int32_t fMagic // swap this
+ // uint8_t fFormatVersion[4] // Do not swap this, just copy
+ // int32_t fLength and all the rest // Swap the rest, all is 32 bit stuff.
+ //
+ uint32_t magic = ds->readUInt32(spoofDH->fMagic);
+ ds->writeUInt32((uint32_t *)&outputDH->fMagic, magic);
+
+ if (outputDH->fFormatVersion != spoofDH->fFormatVersion) {
+ uprv_memcpy(outputDH->fFormatVersion, spoofDH->fFormatVersion, sizeof(spoofDH->fFormatVersion));
+ }
+ // swap starting at fLength
+ ds->swapArray32(ds, &spoofDH->fLength, sizeof(SpoofDataHeader)-8 /* minus magic and fFormatVersion[4] */, &outputDH->fLength, status);
+
+ return totalSize;
+}
+
+#endif
+
+
diff --git a/thirdparty/icu4c/i18n/uspoof_impl.h b/thirdparty/icu4c/i18n/uspoof_impl.h
new file mode 100644
index 0000000000..e75ae262bd
--- /dev/null
+++ b/thirdparty/icu4c/i18n/uspoof_impl.h
@@ -0,0 +1,343 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+***************************************************************************
+* Copyright (C) 2008-2013, International Business Machines Corporation
+* and others. All Rights Reserved.
+***************************************************************************
+*
+* uspoof_impl.h
+*
+* Implementation header for spoof detection
+*
+*/
+
+#ifndef USPOOFIM_H
+#define USPOOFIM_H
+
+#include "uassert.h"
+#include "unicode/utypes.h"
+#include "unicode/uspoof.h"
+#include "unicode/uscript.h"
+#include "unicode/udata.h"
+#include "udataswp.h"
+#include "utrie2.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#ifdef __cplusplus
+
+#include "capi_helper.h"
+
+U_NAMESPACE_BEGIN
+
+// The maximum length (in UTF-16 UChars) of the skeleton replacement string resulting from
+// a single input code point. This is function of the unicode.org data.
+#define USPOOF_MAX_SKELETON_EXPANSION 20
+
+// The default stack buffer size for copies or conversions or normalizations
+// of input strings being checked. (Used in multiple places.)
+#define USPOOF_STACK_BUFFER_SIZE 100
+
+// Magic number for sanity checking spoof data.
+#define USPOOF_MAGIC 0x3845fdef
+
+// Magic number for sanity checking spoof checkers.
+#define USPOOF_CHECK_MAGIC 0x2734ecde
+
+class ScriptSet;
+class SpoofData;
+struct SpoofDataHeader;
+class ConfusableDataUtils;
+
+/**
+ * Class SpoofImpl corresponds directly to the plain C API opaque type
+ * USpoofChecker. One can be cast to the other.
+ */
+class SpoofImpl : public UObject,
+ public IcuCApiHelper<USpoofChecker, SpoofImpl, USPOOF_MAGIC> {
+public:
+ SpoofImpl(SpoofData *data, UErrorCode& status);
+ SpoofImpl(UErrorCode& status);
+ SpoofImpl();
+ void construct(UErrorCode& status);
+ virtual ~SpoofImpl();
+
+ /** Copy constructor, used by the user level uspoof_clone() function.
+ */
+ SpoofImpl(const SpoofImpl &src, UErrorCode &status);
+
+ USpoofChecker *asUSpoofChecker();
+ static SpoofImpl *validateThis(USpoofChecker *sc, UErrorCode &status);
+ static const SpoofImpl *validateThis(const USpoofChecker *sc, UErrorCode &status);
+
+ /** Set and Get AllowedLocales, implementations of the corresponding API */
+ void setAllowedLocales(const char *localesList, UErrorCode &status);
+ const char * getAllowedLocales(UErrorCode &status);
+
+ // Add (union) to the UnicodeSet all of the characters for the scripts used for
+ // the specified locale. Part of the implementation of setAllowedLocales.
+ void addScriptChars(const char *locale, UnicodeSet *allowedChars, UErrorCode &status);
+
+ // Functions implementing the features of UTS 39 section 5.
+ static void getAugmentedScriptSet(UChar32 codePoint, ScriptSet& result, UErrorCode& status);
+ void getResolvedScriptSet(const UnicodeString& input, ScriptSet& result, UErrorCode& status) const;
+ void getResolvedScriptSetWithout(const UnicodeString& input, UScriptCode script, ScriptSet& result, UErrorCode& status) const;
+ void getNumerics(const UnicodeString& input, UnicodeSet& result, UErrorCode& status) const;
+ URestrictionLevel getRestrictionLevel(const UnicodeString& input, UErrorCode& status) const;
+
+ int32_t findHiddenOverlay(const UnicodeString& input, UErrorCode& status) const;
+ bool isIllegalCombiningDotLeadCharacter(UChar32 cp) const;
+
+ /** parse a hex number. Untility used by the builders. */
+ static UChar32 ScanHex(const UChar *s, int32_t start, int32_t limit, UErrorCode &status);
+
+ static UClassID U_EXPORT2 getStaticClassID(void);
+ virtual UClassID getDynamicClassID(void) const override;
+
+ //
+ // Data Members
+ //
+
+ int32_t fChecks; // Bit vector of checks to perform.
+
+ SpoofData *fSpoofData;
+
+ const UnicodeSet *fAllowedCharsSet; // The UnicodeSet of allowed characters.
+ // for this Spoof Checker. Defaults to all chars.
+
+ const char *fAllowedLocales; // The list of allowed locales.
+ URestrictionLevel fRestrictionLevel; // The maximum restriction level for an acceptable identifier.
+};
+
+/**
+ * Class CheckResult corresponds directly to the plain C API opaque type
+ * USpoofCheckResult. One can be cast to the other.
+ */
+class CheckResult : public UObject,
+ public IcuCApiHelper<USpoofCheckResult, CheckResult, USPOOF_CHECK_MAGIC> {
+public:
+ CheckResult();
+ virtual ~CheckResult();
+
+ USpoofCheckResult *asUSpoofCheckResult();
+ static CheckResult *validateThis(USpoofCheckResult *ptr, UErrorCode &status);
+ static const CheckResult *validateThis(const USpoofCheckResult *ptr, UErrorCode &status);
+
+ void clear();
+
+ // Used to convert this CheckResult to the older int32_t return value API
+ int32_t toCombinedBitmask(int32_t expectedChecks);
+
+ // Data Members
+ int32_t fChecks; // Bit vector of checks that were failed.
+ UnicodeSet fNumerics; // Set of numerics found in the string.
+ URestrictionLevel fRestrictionLevel; // The restriction level of the string.
+};
+
+
+//
+// Confusable Mappings Data Structures, version 2.0
+//
+// For the confusable data, we are essentially implementing a map,
+// key: a code point
+// value: a string. Most commonly one char in length, but can be more.
+//
+// The keys are stored as a sorted array of 32 bit ints.
+// bits 0-23 a code point value
+// bits 24-31 length of value string, in UChars (between 1 and 256 UChars).
+// The key table is sorted in ascending code point order. (not on the
+// 32 bit int value, the flag bits do not participate in the sorting.)
+//
+// Lookup is done by means of a binary search in the key table.
+//
+// The corresponding values are kept in a parallel array of 16 bit ints.
+// If the value string is of length 1, it is literally in the value array.
+// For longer strings, the value array contains an index into the strings table.
+//
+// String Table:
+// The strings table contains all of the value strings (those of length two or greater)
+// concatenated together into one long UChar (UTF-16) array.
+//
+// There is no nul character or other mark between adjacent strings.
+//
+//----------------------------------------------------------------------------
+//
+// Changes from format version 1 to format version 2:
+// 1) Removal of the whole-script confusable data tables.
+// 2) Removal of the SL/SA/ML/MA and multi-table flags in the key bitmask.
+// 3) Expansion of string length value in the key bitmask from 2 bits to 8 bits.
+// 4) Removal of the string lengths table since 8 bits is sufficient for the
+// lengths of all entries in confusables.txt.
+
+
+
+// Internal functions for manipulating confusable data table keys
+#define USPOOF_CONFUSABLE_DATA_FORMAT_VERSION 2 // version for ICU 58
+class ConfusableDataUtils {
+public:
+ inline static UChar32 keyToCodePoint(int32_t key) {
+ return key & 0x00ffffff;
+ }
+ inline static int32_t keyToLength(int32_t key) {
+ return ((key & 0xff000000) >> 24) + 1;
+ }
+ inline static int32_t codePointAndLengthToKey(UChar32 codePoint, int32_t length) {
+ U_ASSERT((codePoint & 0x00ffffff) == codePoint);
+ U_ASSERT(length <= 256);
+ return codePoint | ((length - 1) << 24);
+ }
+};
+
+
+//-------------------------------------------------------------------------------------
+//
+// SpoofData
+//
+// A small class that wraps the raw (usually memory mapped) spoof data.
+// Serves two primary functions:
+// 1. Convenience. Contains real pointers to the data, to avoid dealing with
+// the offsets in the raw data.
+// 2. Reference counting. When a spoof checker is cloned, the raw data is shared
+// and must be retained until all checkers using the data are closed.
+// Nothing in this struct includes state that is specific to any particular
+// USpoofDetector object.
+//
+//---------------------------------------------------------------------------------------
+class SpoofData: public UMemory {
+ public:
+ static SpoofData* getDefault(UErrorCode &status); // Get standard ICU spoof data.
+ static void releaseDefault(); // Cleanup reference to default spoof data.
+
+ SpoofData(UErrorCode &status); // Create new spoof data wrapper.
+ // Only used when building new data from rules.
+
+ // Constructor for use when creating from prebuilt default data.
+ // A UDataMemory is what the ICU internal data loading functions provide.
+ // The udm is adopted by the SpoofData.
+ SpoofData(UDataMemory *udm, UErrorCode &status);
+
+ // Constructor for use when creating from serialized data.
+ //
+ SpoofData(const void *serializedData, int32_t length, UErrorCode &status);
+
+ // Check raw Spoof Data Version compatibility.
+ // Return true it looks good.
+ UBool validateDataVersion(UErrorCode &status) const;
+
+ ~SpoofData(); // Destructor not normally used.
+ // Use removeReference() instead.
+ // Reference Counting functions.
+ // Clone of a user-level spoof detector increments the ref count on the data.
+ // Close of a user-level spoof detector decrements the ref count.
+ // If the data is owned by us, it will be deleted when count goes to zero.
+ SpoofData *addReference();
+ void removeReference();
+
+ // Reset all fields to an initial state.
+ // Called from the top of all constructors.
+ void reset();
+
+ // Copy this instance's raw data buffer to the specified address.
+ int32_t serialize(void *buf, int32_t capacity, UErrorCode &status) const;
+
+ // Get the total number of bytes of data backed by this SpoofData.
+ // Not to be confused with length, which returns the number of confusable entries.
+ int32_t size() const;
+
+ // Get the confusable skeleton transform for a single code point.
+ // The result is a string with a length between 1 and 18 as of Unicode 9.
+ // This is the main public endpoint for this class.
+ // @return The length in UTF-16 code units of the substitution string.
+ int32_t confusableLookup(UChar32 inChar, UnicodeString &dest) const;
+
+ // Get the number of confusable entries in this SpoofData.
+ int32_t length() const;
+
+ // Get the code point (key) at the specified index.
+ UChar32 codePointAt(int32_t index) const;
+
+ // Get the confusable skeleton (value) at the specified index.
+ // Append it to the specified UnicodeString&.
+ // @return The length in UTF-16 code units of the skeleton string.
+ int32_t appendValueTo(int32_t index, UnicodeString& dest) const;
+
+ private:
+ // Reserve space in the raw data. For use by builder when putting together a
+ // new set of data. Init the new storage to zero, to prevent inconsistent
+ // results if it is not all otherwise set by the requester.
+ // Return:
+ // pointer to the new space that was added by this function.
+ void *reserveSpace(int32_t numBytes, UErrorCode &status);
+
+ // initialize the pointers from this object to the raw data.
+ void initPtrs(UErrorCode &status);
+
+ SpoofDataHeader *fRawData; // Ptr to the raw memory-mapped data
+ UBool fDataOwned; // True if the raw data is owned, and needs
+ // to be deleted when refcount goes to zero.
+ UDataMemory *fUDM; // If not NULL, our data came from a
+ // UDataMemory, which we must close when
+ // we are done.
+
+ uint32_t fMemLimit; // Limit of available raw data space
+ u_atomic_int32_t fRefCount;
+
+ // Confusable data
+ int32_t *fCFUKeys;
+ uint16_t *fCFUValues;
+ UChar *fCFUStrings;
+
+ friend class ConfusabledataBuilder;
+};
+
+//---------------------------------------------------------------------------------------
+//
+// Raw Binary Data Formats, as loaded from the ICU data file,
+// or as built by the builder.
+//
+//---------------------------------------------------------------------------------------
+struct SpoofDataHeader {
+ int32_t fMagic; // (0x3845fdef)
+ uint8_t fFormatVersion[4]; // Data Format. Same as the value in struct UDataInfo
+ // if there is one associated with this data.
+ int32_t fLength; // Total length in bytes of this spoof data,
+ // including all sections, not just the header.
+
+ // The following four sections refer to data representing the confusable data
+ // from the Unicode.org data from "confusables.txt"
+
+ int32_t fCFUKeys; // byte offset to Keys table (from SpoofDataHeader *)
+ int32_t fCFUKeysSize; // number of entries in keys table (32 bits each)
+
+ // TODO: change name to fCFUValues, for consistency.
+ int32_t fCFUStringIndex; // byte offset to String Indexes table
+ int32_t fCFUStringIndexSize; // number of entries in String Indexes table (16 bits each)
+ // (number of entries must be same as in Keys table
+
+ int32_t fCFUStringTable; // byte offset of String table
+ int32_t fCFUStringTableLen; // length of string table (in 16 bit UChars)
+
+ // The following sections are for data from xidmodifications.txt
+
+ int32_t unused[15]; // Padding, Room for Expansion
+};
+
+
+
+U_NAMESPACE_END
+#endif /* __cplusplus */
+
+/**
+ * Endianness swap function for binary spoof data.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_swap(const UDataSwapper *ds, const void *inData, int32_t length, void *outData,
+ UErrorCode *status);
+
+
+#endif
+
+#endif /* USPOOFIM_H */
+
diff --git a/thirdparty/icu4c/icudt71l.dat b/thirdparty/icu4c/icudt71l.dat
index 4c2c1c4d16..3fa3af9c23 100644
--- a/thirdparty/icu4c/icudt71l.dat
+++ b/thirdparty/icu4c/icudt71l.dat
Binary files differ