summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/d3d12/d3d12ma.cpp12
-rw-r--r--drivers/d3d12/rendering_context_driver_d3d12.cpp8
-rw-r--r--drivers/d3d12/rendering_context_driver_d3d12.h9
-rw-r--r--drivers/d3d12/rendering_device_driver_d3d12.cpp25
-rw-r--r--drivers/d3d12/rendering_device_driver_d3d12.h16
-rw-r--r--editor/editor_file_system.cpp63
-rw-r--r--editor/editor_file_system.h6
-rw-r--r--editor/filesystem_dock.cpp37
-rw-r--r--editor/filesystem_dock.h2
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp46
-rw-r--r--editor/themes/editor_theme_manager.cpp5
-rw-r--r--modules/gdscript/tests/scripts/completion/common/identifiers.cfg21
-rw-r--r--modules/gdscript/tests/scripts/completion/common/identifiers.gd16
-rw-r--r--modules/gdscript/tests/scripts/completion/common/self.cfg21
-rw-r--r--modules/gdscript/tests/scripts/completion/common/self.gd16
-rw-r--r--modules/gdscript/tests/scripts/completion/filter/organized_export.cfg6
-rw-r--r--modules/gdscript/tests/scripts/completion/filter/organized_export.gd8
-rw-r--r--modules/gdscript/tests/scripts/completion/filter/usage_internal.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/filter/usage_internal.gd3
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/interfered.cfg12
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/interfered.gd8
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/no_type.cfg12
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/no_type.gd8
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/typehint.cfg12
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/typehint.gd8
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg12
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/typehint_broad.gd8
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg12
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.gd8
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/interfered.cfg12
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/interfered.gd9
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/no_type.cfg12
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/no_type.gd9
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/typehint.cfg12
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/typehint.gd9
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg13
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/typehint_broad.gd9
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg12
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.gd9
-rw-r--r--modules/multiplayer/multiplayer_spawner.cpp2
-rw-r--r--platform/web/js/libs/library_godot_audio.js176
-rw-r--r--thirdparty/thorvg/inc/config.h2
-rw-r--r--thirdparty/thorvg/patches/pr2338-float_t.patch13
-rw-r--r--thirdparty/thorvg/src/common/tvgLock.h2
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp161
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h20
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp84
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h12
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h49
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp2
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp1
-rw-r--r--thirdparty/thorvg/src/renderer/tvgCommon.h12
-rw-r--r--thirdparty/thorvg/src/renderer/tvgPaint.cpp78
-rw-r--r--thirdparty/thorvg/src/renderer/tvgTaskScheduler.h2
-rwxr-xr-xthirdparty/thorvg/update-thorvg.sh2
55 files changed, 892 insertions, 256 deletions
diff --git a/drivers/d3d12/d3d12ma.cpp b/drivers/d3d12/d3d12ma.cpp
index 51171141de..b7c9eb7ec0 100644
--- a/drivers/d3d12/d3d12ma.cpp
+++ b/drivers/d3d12/d3d12ma.cpp
@@ -43,6 +43,18 @@
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma GCC diagnostic ignored "-Wnonnull-compare"
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#elif defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#pragma clang diagnostic ignored "-Wstring-plus-int"
+#pragma clang diagnostic ignored "-Wswitch"
+#pragma clang diagnostic ignored "-Wmissing-field-initializers"
+#pragma clang diagnostic ignored "-Wtautological-undefined-compare"
+#pragma clang diagnostic ignored "-Wunused-variable"
+#pragma clang diagnostic ignored "-Wunused-but-set-variable"
+#pragma clang diagnostic ignored "-Wunused-function"
+#pragma clang diagnostic ignored "-Wunused-private-field"
+#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#endif
#if defined(_MSC_VER)
diff --git a/drivers/d3d12/rendering_context_driver_d3d12.cpp b/drivers/d3d12/rendering_context_driver_d3d12.cpp
index 128b8bcd03..c4cb99fcaa 100644
--- a/drivers/d3d12/rendering_context_driver_d3d12.cpp
+++ b/drivers/d3d12/rendering_context_driver_d3d12.cpp
@@ -43,12 +43,20 @@
#pragma GCC diagnostic ignored "-Wshadow"
#pragma GCC diagnostic ignored "-Wswitch"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#elif defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#pragma clang diagnostic ignored "-Wstring-plus-int"
+#pragma clang diagnostic ignored "-Wswitch"
+#pragma clang diagnostic ignored "-Wmissing-field-initializers"
#endif
#include "dxcapi.h"
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
+#elif defined(__clang__)
+#pragma clang diagnostic pop
#endif
#if !defined(_MSC_VER)
diff --git a/drivers/d3d12/rendering_context_driver_d3d12.h b/drivers/d3d12/rendering_context_driver_d3d12.h
index 2e286b6927..a2d828ded1 100644
--- a/drivers/d3d12/rendering_context_driver_d3d12.h
+++ b/drivers/d3d12/rendering_context_driver_d3d12.h
@@ -46,6 +46,13 @@
#pragma GCC diagnostic ignored "-Wswitch"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
+#elif defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#pragma clang diagnostic ignored "-Wstring-plus-int"
+#pragma clang diagnostic ignored "-Wswitch"
+#pragma clang diagnostic ignored "-Wmissing-field-initializers"
+#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#endif
#if defined(AS)
@@ -59,6 +66,8 @@
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
+#elif defined(__clang__)
+#pragma clang diagnostic pop
#endif
using Microsoft::WRL::ComPtr;
diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp
index fb278a4d56..ca2b392e66 100644
--- a/drivers/d3d12/rendering_device_driver_d3d12.cpp
+++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp
@@ -51,6 +51,12 @@
#pragma GCC diagnostic ignored "-Wshadow"
#pragma GCC diagnostic ignored "-Wswitch"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#elif defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#pragma clang diagnostic ignored "-Wstring-plus-int"
+#pragma clang diagnostic ignored "-Wswitch"
+#pragma clang diagnostic ignored "-Wmissing-field-initializers"
#endif
#include "dxil_validator.h"
@@ -63,6 +69,8 @@ extern "C" {
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
+#elif defined(__clang__)
+#pragma clang diagnostic pop
#endif
#if defined(_MSC_VER)
@@ -96,11 +104,6 @@ static const D3D12_RANGE VOID_RANGE = {};
static const uint32_t ROOT_CONSTANT_REGISTER = GODOT_NIR_DESCRIPTOR_SET_MULTIPLIER * (RDD::MAX_UNIFORM_SETS + 1);
static const uint32_t RUNTIME_DATA_REGISTER = GODOT_NIR_DESCRIPTOR_SET_MULTIPLIER * (RDD::MAX_UNIFORM_SETS + 2);
-#ifdef DEV_ENABLED
-//#define DEBUG_COUNT_BARRIERS
-#define CUSTOM_INFO_QUEUE_ENABLED 0
-#endif
-
/*****************/
/**** GENERIC ****/
/*****************/
@@ -1462,7 +1465,7 @@ RDD::TextureID RenderingDeviceDriverD3D12::_texture_create_shared_from_slice(Tex
uav_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format;
}
- if (p_slice_type != -1) {
+ if (p_slice_type != (TextureSliceType)-1) {
// Complete description with slicing.
switch (p_slice_type) {
@@ -1560,7 +1563,7 @@ RDD::TextureID RenderingDeviceDriverD3D12::_texture_create_shared_from_slice(Tex
tex_info->states_ptr = owner_tex_info->states_ptr;
tex_info->format = p_view.format;
tex_info->desc = new_tex_resource_desc;
- if (p_slice_type == -1) {
+ if (p_slice_type == (TextureSliceType)-1) {
tex_info->base_layer = owner_tex_info->base_layer;
tex_info->layers = owner_tex_info->layers;
tex_info->base_mip = owner_tex_info->base_mip;
@@ -1741,7 +1744,7 @@ RDD::SamplerID RenderingDeviceDriverD3D12::sampler_create(const SamplerState &p_
slot = 1;
} else {
for (uint32_t i = 1; i < samplers.size(); i++) {
- if (samplers[i].Filter == INT_MAX) {
+ if ((int)samplers[i].Filter == INT_MAX) {
slot = i;
break;
}
@@ -2703,6 +2706,8 @@ D3D12_UNORDERED_ACCESS_VIEW_DESC RenderingDeviceDriverD3D12::_make_ranged_uav_fo
uav_desc.Texture3D.MipSlice = mip;
uav_desc.Texture3D.WSize >>= p_mipmap_offset;
} break;
+ default:
+ break;
}
return uav_desc;
@@ -4094,7 +4099,6 @@ RDD::UniformSetID RenderingDeviceDriverD3D12::uniform_set_create(VectorView<Boun
{
uniform_set_info->resource_states.reserve(resource_states.size());
- uint32_t i = 0;
for (const KeyValue<ResourceInfo *, NeededState> &E : resource_states) {
UniformSetInfo::StateRequirement sr;
sr.resource = E.key;
@@ -4102,7 +4106,6 @@ RDD::UniformSetID RenderingDeviceDriverD3D12::uniform_set_create(VectorView<Boun
sr.states = E.value.states;
sr.shader_uniform_idx_mask = E.value.shader_uniform_idx_mask;
uniform_set_info->resource_states.push_back(sr);
- i++;
}
}
@@ -6635,7 +6638,7 @@ Error RenderingDeviceDriverD3D12::_initialize_frames(uint32_t p_frame_count) {
D3D12MA::ALLOCATION_DESC allocation_desc = {};
allocation_desc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
- CD3DX12_RESOURCE_DESC resource_desc = CD3DX12_RESOURCE_DESC::Buffer(D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
+ //CD3DX12_RESOURCE_DESC resource_desc = CD3DX12_RESOURCE_DESC::Buffer(D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
uint32_t resource_descriptors_per_frame = GLOBAL_GET("rendering/rendering_device/d3d12/max_resource_descriptors_per_frame");
uint32_t sampler_descriptors_per_frame = GLOBAL_GET("rendering/rendering_device/d3d12/max_sampler_descriptors_per_frame");
uint32_t misc_descriptors_per_frame = GLOBAL_GET("rendering/rendering_device/d3d12/max_misc_descriptors_per_frame");
diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h
index 1782819238..92e8e494d4 100644
--- a/drivers/d3d12/rendering_device_driver_d3d12.h
+++ b/drivers/d3d12/rendering_device_driver_d3d12.h
@@ -43,6 +43,13 @@
#pragma GCC diagnostic ignored "-Wswitch"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
+#elif defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#pragma clang diagnostic ignored "-Wstring-plus-int"
+#pragma clang diagnostic ignored "-Wswitch"
+#pragma clang diagnostic ignored "-Wmissing-field-initializers"
+#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#endif
#include "d3dx12.h"
@@ -59,12 +66,19 @@
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
+#elif defined(__clang__)
+#pragma clang diagnostic pop
#endif
using Microsoft::WRL::ComPtr;
#define D3D12_BITCODE_OFFSETS_NUM_STAGES 3
+#ifdef DEV_ENABLED
+//#define DEBUG_COUNT_BARRIERS
+#define CUSTOM_INFO_QUEUE_ENABLED 0
+#endif
+
struct dxil_validator;
class RenderingContextDriverD3D12;
@@ -257,7 +271,7 @@ private:
LocalVector<D3D12_RESOURCE_BARRIER> res_barriers;
uint32_t res_barriers_count = 0;
uint32_t res_barriers_batch = 0;
-#ifdef DEV_ENABLED
+#ifdef DEBUG_COUNT_BARRIERS
int frame_barriers_count = 0;
int frame_barriers_batches_count = 0;
uint64_t frame_barriers_cpu_time = 0;
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index a1e392cd7d..4bca42bf8b 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -161,6 +161,10 @@ String EditorFileSystemDirectory::get_file_script_class_icon_path(int p_idx) con
return files[p_idx]->script_class_icon_path;
}
+String EditorFileSystemDirectory::get_file_icon_path(int p_idx) const {
+ return files[p_idx]->icon_path;
+}
+
StringName EditorFileSystemDirectory::get_file_type(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, files.size(), "");
return files[p_idx]->type;
@@ -740,6 +744,8 @@ void EditorFileSystem::scan() {
scanning = false;
_update_pending_script_classes();
_update_pending_scene_groups();
+ // Update all icons so they are loaded for the FileSystemDock.
+ _update_files_icon_path();
emit_signal(SNAME("filesystem_changed"));
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
first_scan = false;
@@ -1298,6 +1304,8 @@ void EditorFileSystem::_notification(int p_what) {
_update_scan_actions();
_update_pending_script_classes();
_update_pending_scene_groups();
+ // Update all icons so they are loaded for the FileSystemDock.
+ _update_files_icon_path();
emit_signal(SNAME("filesystem_changed"));
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
first_scan = false;
@@ -1578,6 +1586,43 @@ String EditorFileSystem::_get_global_script_class(const String &p_type, const St
return String();
}
+void EditorFileSystem::_update_file_icon_path(EditorFileSystemDirectory::FileInfo *file_info) {
+ String icon_path;
+ if (file_info->script_class_icon_path.is_empty() && !file_info->deps.is_empty()) {
+ const String &script_path = file_info->deps[0]; // Assuming the first dependency is a script.
+ if (!script_path.is_empty()) {
+ String *cached = file_icon_cache.getptr(script_path);
+ if (cached) {
+ icon_path = *cached;
+ } else {
+ if (ClassDB::is_parent_class(ResourceLoader::get_resource_type(script_path), SNAME("Script"))) {
+ int script_file;
+ EditorFileSystemDirectory *efsd = find_file(script_path, &script_file);
+ if (efsd) {
+ icon_path = efsd->files[script_file]->script_class_icon_path;
+ }
+ }
+ file_icon_cache.insert(script_path, icon_path);
+ }
+ }
+ }
+
+ file_info->icon_path = icon_path;
+}
+
+void EditorFileSystem::_update_files_icon_path(EditorFileSystemDirectory *edp) {
+ if (!edp) {
+ edp = filesystem;
+ file_icon_cache.clear();
+ }
+ for (EditorFileSystemDirectory *sub_dir : edp->subdirs) {
+ _update_files_icon_path(sub_dir);
+ }
+ for (EditorFileSystemDirectory::FileInfo *fi : edp->files) {
+ _update_file_icon_path(fi);
+ }
+}
+
void EditorFileSystem::_update_script_classes() {
update_script_mutex.lock();
@@ -1719,6 +1764,8 @@ void EditorFileSystem::update_file(const String &p_file) {
void EditorFileSystem::update_files(const Vector<String> &p_script_paths) {
bool updated = false;
+ bool update_files_icon_cache = false;
+ Vector<EditorFileSystemDirectory::FileInfo *> files_to_update_icon_path;
for (const String &file : p_script_paths) {
ERR_CONTINUE(file.is_empty());
EditorFileSystemDirectory *fs = nullptr;
@@ -1741,6 +1788,9 @@ void EditorFileSystem::update_files(const Vector<String> &p_script_paths) {
}
if (ClassDB::is_parent_class(fs->files[cpos]->type, SNAME("Script"))) {
_queue_update_script_class(file);
+ if (!fs->files[cpos]->script_class_icon_path.is_empty()) {
+ update_files_icon_cache = true;
+ }
}
if (fs->files[cpos]->type == SNAME("PackedScene")) {
_queue_update_scene_groups(file);
@@ -1789,6 +1839,7 @@ void EditorFileSystem::update_files(const Vector<String> &p_script_paths) {
_save_late_updated_files(); //files need to be updated in the re-scan
}
+ const String old_script_class_icon_path = fs->files[cpos]->script_class_icon_path;
fs->files[cpos]->type = type;
fs->files[cpos]->resource_script_class = script_class;
fs->files[cpos]->uid = uid;
@@ -1816,6 +1867,11 @@ void EditorFileSystem::update_files(const Vector<String> &p_script_paths) {
if (fs->files[cpos]->type == SNAME("PackedScene")) {
_queue_update_scene_groups(file);
}
+ if (fs->files[cpos]->type == SNAME("Resource")) {
+ files_to_update_icon_path.push_back(fs->files[cpos]);
+ } else if (old_script_class_icon_path != fs->files[cpos]->script_class_icon_path) {
+ update_files_icon_cache = true;
+ }
updated = true;
}
}
@@ -1823,6 +1879,13 @@ void EditorFileSystem::update_files(const Vector<String> &p_script_paths) {
if (updated) {
_update_pending_script_classes();
_update_pending_scene_groups();
+ if (update_files_icon_cache) {
+ _update_files_icon_path();
+ } else {
+ for (EditorFileSystemDirectory::FileInfo *fi : files_to_update_icon_path) {
+ _update_file_icon_path(fi);
+ }
+ }
call_deferred(SNAME("emit_signal"), "filesystem_changed"); //update later
}
}
diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h
index cd95d5fb95..88cd67296b 100644
--- a/editor/editor_file_system.h
+++ b/editor/editor_file_system.h
@@ -66,6 +66,7 @@ class EditorFileSystemDirectory : public Object {
String script_class_name;
String script_class_extends;
String script_class_icon_path;
+ String icon_path;
};
Vector<FileInfo *> files;
@@ -91,6 +92,7 @@ public:
String get_file_script_class_name(int p_idx) const; //used for scripts
String get_file_script_class_extends(int p_idx) const; //used for scripts
String get_file_script_class_icon_path(int p_idx) const; //used for scripts
+ String get_file_icon_path(int p_idx) const; //used for FileSystemDock
EditorFileSystemDirectory *get_parent();
@@ -279,6 +281,7 @@ class EditorFileSystem : public Node {
void _move_group_files(EditorFileSystemDirectory *efd, const String &p_group_file, const String &p_new_location);
HashSet<String> group_file_cache;
+ HashMap<String, String> file_icon_cache;
struct ImportThreadData {
const ImportFile *reimport_files;
@@ -295,6 +298,9 @@ class EditorFileSystem : public Node {
Vector<Ref<EditorFileSystemImportFormatSupportQuery>> import_support_queries;
+ void _update_file_icon_path(EditorFileSystemDirectory::FileInfo *file_info);
+ void _update_files_icon_path(EditorFileSystemDirectory *edp = nullptr);
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 1c22ecd673..44ff95b0f9 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -200,33 +200,6 @@ Ref<Texture2D> FileSystemDock::_get_tree_item_icon(bool p_is_valid, const String
}
}
-String FileSystemDock::_get_entry_script_icon(const EditorFileSystemDirectory *p_dir, int p_file) {
- const PackedStringArray &deps = p_dir->get_file_deps(p_file);
- if (deps.is_empty()) {
- return String();
- }
-
- const String &script_path = deps[0]; // Assuming the first dependency is a script.
- if (script_path.is_empty() || !ClassDB::is_parent_class(ResourceLoader::get_resource_type(script_path), SNAME("Script"))) {
- return String();
- }
-
- String *cached = icon_cache.getptr(script_path);
- if (cached) {
- return *cached;
- }
-
- HashMap<String, String>::Iterator I;
- int script_file;
- EditorFileSystemDirectory *efsd = EditorFileSystem::get_singleton()->find_file(script_path, &script_file);
- if (efsd) {
- I = icon_cache.insert(script_path, efsd->get_file_script_class_icon_path(script_file));
- } else {
- I = icon_cache.insert(script_path, String());
- }
- return I->value;
-}
-
bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path) {
bool parent_should_expand = false;
@@ -316,7 +289,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
FileInfo fi;
fi.name = p_dir->get_file(i);
fi.type = p_dir->get_file_type(i);
- fi.icon_path = _get_entry_script_icon(p_dir, i);
+ fi.icon_path = p_dir->get_file_icon_path(i);
fi.import_broken = !p_dir->get_file_import_is_valid(i);
fi.modified_time = p_dir->get_file_modified_time(i);
@@ -414,8 +387,6 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
updating_tree = true;
TreeItem *root = tree->create_item();
- icon_cache.clear();
-
// Handles the favorites.
TreeItem *favorites_item = tree->create_item(root);
favorites_item->set_icon(0, get_editor_theme_icon(SNAME("Favorites")));
@@ -463,7 +434,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
int index;
EditorFileSystemDirectory *dir = EditorFileSystem::get_singleton()->find_file(favorite, &index);
if (dir) {
- icon = _get_tree_item_icon(dir->get_file_import_is_valid(index), dir->get_file_type(index), _get_entry_script_icon(dir, index));
+ icon = _get_tree_item_icon(dir->get_file_import_is_valid(index), dir->get_file_type(index), dir->get_file_icon_path(index));
} else {
icon = get_editor_theme_icon(SNAME("File"));
}
@@ -1017,7 +988,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
fi.path = favorite;
if (efd) {
fi.type = efd->get_file_type(index);
- fi.icon_path = _get_entry_script_icon(efd, index);
+ fi.icon_path = efd->get_file_icon_path(index);
fi.import_broken = !efd->get_file_import_is_valid(index);
fi.modified_time = efd->get_file_modified_time(index);
} else {
@@ -1110,7 +1081,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
fi.name = efd->get_file(i);
fi.path = directory.path_join(fi.name);
fi.type = efd->get_file_type(i);
- fi.icon_path = _get_entry_script_icon(efd, i);
+ fi.icon_path = efd->get_file_icon_path(i);
fi.import_broken = !efd->get_file_import_is_valid(i);
fi.modified_time = efd->get_file_modified_time(i);
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index 3fbff3ef19..959ace8eba 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -142,7 +142,6 @@ private:
FILE_NEW_SCENE,
};
- HashMap<String, String> icon_cache;
HashMap<String, Color> folder_colors;
Dictionary assigned_folder_colors;
@@ -250,7 +249,6 @@ private:
void _reselect_items_selected_on_drag_begin(bool reset = false);
Ref<Texture2D> _get_tree_item_icon(bool p_is_valid, const String &p_file_type, const String &p_icon_path);
- String _get_entry_script_icon(const EditorFileSystemDirectory *p_dir, int p_file);
bool _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path = false);
void _update_tree(const Vector<String> &p_uncollapsed_paths = Vector<String>(), bool p_uncollapse_root = false, bool p_select_in_favorites = false, bool p_unfold_path = false);
void _navigate_to_path(const String &p_path, bool p_select_in_favorites = false);
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 1f3bf60d24..d7d51d6a04 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -3043,29 +3043,45 @@ void Node3DEditorViewport::_notification(int p_what) {
preview_camera->set_icon(get_editor_theme_icon(SNAME("Camera3D")));
Control *gui_base = EditorNode::get_singleton()->get_gui_base();
+ const Ref<StyleBox> &information_3d_stylebox = gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles));
+
view_menu->begin_bulk_theme_override();
- view_menu->add_theme_style_override(CoreStringName(normal), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles)));
- view_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles)));
- view_menu->add_theme_style_override(SceneStringName(pressed), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles)));
- view_menu->add_theme_style_override("focus", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles)));
- view_menu->add_theme_style_override("disabled", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles)));
+ view_menu->add_theme_style_override(CoreStringName(normal), information_3d_stylebox);
+ view_menu->add_theme_style_override("normal_mirrored", information_3d_stylebox);
+ view_menu->add_theme_style_override("hover", information_3d_stylebox);
+ view_menu->add_theme_style_override("hover_mirrored", information_3d_stylebox);
+ view_menu->add_theme_style_override("hover_pressed", information_3d_stylebox);
+ view_menu->add_theme_style_override("hover_pressed_mirrored", information_3d_stylebox);
+ view_menu->add_theme_style_override(SceneStringName(pressed), information_3d_stylebox);
+ view_menu->add_theme_style_override("pressed_mirrored", information_3d_stylebox);
+ view_menu->add_theme_style_override("focus", information_3d_stylebox);
+ view_menu->add_theme_style_override("focus_mirrored", information_3d_stylebox);
+ view_menu->add_theme_style_override("disabled", information_3d_stylebox);
+ view_menu->add_theme_style_override("disabled_mirrored", information_3d_stylebox);
view_menu->end_bulk_theme_override();
preview_camera->begin_bulk_theme_override();
- preview_camera->add_theme_style_override(CoreStringName(normal), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles)));
- preview_camera->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles)));
- preview_camera->add_theme_style_override(SceneStringName(pressed), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles)));
- preview_camera->add_theme_style_override("focus", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles)));
- preview_camera->add_theme_style_override("disabled", gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles)));
+ preview_camera->add_theme_style_override(CoreStringName(normal), information_3d_stylebox);
+ preview_camera->add_theme_style_override("normal_mirrored", information_3d_stylebox);
+ preview_camera->add_theme_style_override("hover", information_3d_stylebox);
+ preview_camera->add_theme_style_override("hover_mirrored", information_3d_stylebox);
+ preview_camera->add_theme_style_override("hover_pressed", information_3d_stylebox);
+ preview_camera->add_theme_style_override("hover_pressed_mirrored", information_3d_stylebox);
+ preview_camera->add_theme_style_override(SceneStringName(pressed), information_3d_stylebox);
+ preview_camera->add_theme_style_override("pressed_mirrored", information_3d_stylebox);
+ preview_camera->add_theme_style_override("focus", information_3d_stylebox);
+ preview_camera->add_theme_style_override("focus_mirrored", information_3d_stylebox);
+ preview_camera->add_theme_style_override("disabled", information_3d_stylebox);
+ preview_camera->add_theme_style_override("disabled_mirrored", information_3d_stylebox);
preview_camera->end_bulk_theme_override();
frame_time_gradient->set_color(0, get_theme_color(SNAME("success_color"), EditorStringName(Editor)));
frame_time_gradient->set_color(1, get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
frame_time_gradient->set_color(2, get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
- info_label->add_theme_style_override(CoreStringName(normal), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles)));
+ info_label->add_theme_style_override(CoreStringName(normal), information_3d_stylebox);
- frame_time_panel->add_theme_style_override(SceneStringName(panel), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles)));
+ frame_time_panel->add_theme_style_override(SceneStringName(panel), information_3d_stylebox);
// Set a minimum width to prevent the width from changing all the time
// when numbers vary rapidly. This minimum width is set based on a
// GPU time of 999.99 ms in the current editor language.
@@ -3073,8 +3089,8 @@ void Node3DEditorViewport::_notification(int p_what) {
frame_time_panel->set_custom_minimum_size(Size2(min_width, 0) * EDSCALE);
frame_time_vbox->add_theme_constant_override("separation", Math::round(-1 * EDSCALE));
- cinema_label->add_theme_style_override(CoreStringName(normal), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles)));
- locked_label->add_theme_style_override(CoreStringName(normal), gui_base->get_theme_stylebox(SNAME("Information3dViewport"), EditorStringName(EditorStyles)));
+ cinema_label->add_theme_style_override(CoreStringName(normal), information_3d_stylebox);
+ locked_label->add_theme_style_override(CoreStringName(normal), information_3d_stylebox);
} break;
case NOTIFICATION_DRAG_END: {
@@ -5372,6 +5388,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
cinema_label->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
cinema_label->set_h_grow_direction(GROW_DIRECTION_END);
cinema_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ cinema_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
surface->add_child(cinema_label);
cinema_label->set_text(TTR("Cinematic Preview"));
cinema_label->hide();
@@ -5379,6 +5396,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
locked_label = memnew(Label);
locked_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ locked_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
locked_label->set_h_size_flags(SIZE_SHRINK_CENTER);
bottom_center_vbox->add_child(locked_label);
locked_label->set_text(TTR("View Rotation Locked"));
diff --git a/editor/themes/editor_theme_manager.cpp b/editor/themes/editor_theme_manager.cpp
index 169a3e2373..b6697b6d2c 100644
--- a/editor/themes/editor_theme_manager.cpp
+++ b/editor/themes/editor_theme_manager.cpp
@@ -1782,11 +1782,6 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme
style_content_panel_vp->set_content_margin_individual(p_config.border_width * 2, p_config.base_margin * EDSCALE, p_config.border_width * 2, p_config.border_width * 2);
p_theme->set_stylebox("Content", EditorStringName(EditorStyles), style_content_panel_vp);
- // 2D/CanvasItem editor
- Ref<StyleBoxFlat> style_canvas_editor_info = make_flat_stylebox(Color(0.0, 0.0, 0.0, 0.2));
- style_canvas_editor_info->set_expand_margin_all(4 * EDSCALE);
- p_theme->set_stylebox("CanvasItemInfoOverlay", EditorStringName(EditorStyles), style_canvas_editor_info);
-
// 3D/Spatial editor.
Ref<StyleBoxFlat> style_info_3d_viewport = p_config.base_style->duplicate();
style_info_3d_viewport->set_bg_color(style_info_3d_viewport->get_bg_color() * Color(1, 1, 1, 0.5));
diff --git a/modules/gdscript/tests/scripts/completion/common/identifiers.cfg b/modules/gdscript/tests/scripts/completion/common/identifiers.cfg
new file mode 100644
index 0000000000..871a404e3a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/common/identifiers.cfg
@@ -0,0 +1,21 @@
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+
+ ; GDScript: self.gd
+ {"display": "test_signal_1"},
+ {"display": "test_signal_2"},
+ {"display": "test_var_1"},
+ {"display": "test_var_2"},
+ {"display": "test_func_1"},
+ {"display": "test_func_2"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/common/identifiers.gd b/modules/gdscript/tests/scripts/completion/common/identifiers.gd
new file mode 100644
index 0000000000..efbafbee8e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/common/identifiers.gd
@@ -0,0 +1,16 @@
+extends "res://completion/class_a.notest.gd"
+
+signal test_signal_1(a)
+signal test_signal_2(a: int)
+
+var test_var_1
+var test_var_2: int
+
+func test_func_1(t):
+ pass
+
+func test_func_2(t: int) -> void:
+ pass
+
+func _init():
+ t➡
diff --git a/modules/gdscript/tests/scripts/completion/common/self.cfg b/modules/gdscript/tests/scripts/completion/common/self.cfg
new file mode 100644
index 0000000000..871a404e3a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/common/self.cfg
@@ -0,0 +1,21 @@
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+
+ ; GDScript: self.gd
+ {"display": "test_signal_1"},
+ {"display": "test_signal_2"},
+ {"display": "test_var_1"},
+ {"display": "test_var_2"},
+ {"display": "test_func_1"},
+ {"display": "test_func_2"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/common/self.gd b/modules/gdscript/tests/scripts/completion/common/self.gd
new file mode 100644
index 0000000000..9ad2fbea51
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/common/self.gd
@@ -0,0 +1,16 @@
+extends "res://completion/class_a.notest.gd"
+
+signal test_signal_1(a)
+signal test_signal_2(a: int)
+
+var test_var_1
+var test_var_2: int
+
+func test_func_1(t):
+ pass
+
+func test_func_2(t: int) -> void:
+ pass
+
+func _init():
+ self.➡
diff --git a/modules/gdscript/tests/scripts/completion/filter/organized_export.cfg b/modules/gdscript/tests/scripts/completion/filter/organized_export.cfg
new file mode 100644
index 0000000000..961a9ea58d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/filter/organized_export.cfg
@@ -0,0 +1,6 @@
+[output]
+exclude=[
+ {"display": "Test Category"},
+ {"display": "Test Group"},
+ {"display": "Test Subgroup"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/filter/organized_export.gd b/modules/gdscript/tests/scripts/completion/filter/organized_export.gd
new file mode 100644
index 0000000000..189608904c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/filter/organized_export.gd
@@ -0,0 +1,8 @@
+extends CPUParticles2D
+
+@export_category("Test Category")
+@export_group("Test Group")
+@export_subgroup("Test Subgroup")
+
+func _init():
+ ➡
diff --git a/modules/gdscript/tests/scripts/completion/filter/usage_internal.cfg b/modules/gdscript/tests/scripts/completion/filter/usage_internal.cfg
new file mode 100644
index 0000000000..8c5bff5eac
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/filter/usage_internal.cfg
@@ -0,0 +1,4 @@
+[output]
+exclude=[
+ {"display": "messages"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/filter/usage_internal.gd b/modules/gdscript/tests/scripts/completion/filter/usage_internal.gd
new file mode 100644
index 0000000000..484c1c0d10
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/filter/usage_internal.gd
@@ -0,0 +1,3 @@
+func test():
+ var trans = Translation.new()
+ trans.➡
diff --git a/modules/gdscript/tests/scripts/completion/types/local/interfered.cfg b/modules/gdscript/tests/scripts/completion/types/local/interfered.cfg
new file mode 100644
index 0000000000..8b68d51a89
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/local/interfered.cfg
@@ -0,0 +1,12 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/interfered.gd b/modules/gdscript/tests/scripts/completion/types/local/interfered.gd
new file mode 100644
index 0000000000..f003c366a4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/local/interfered.gd
@@ -0,0 +1,8 @@
+extends Node
+
+const A := preload("res://completion/class_a.notest.gd")
+
+func a():
+ var test := A.new()
+ test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/types/local/no_type.cfg b/modules/gdscript/tests/scripts/completion/types/local/no_type.cfg
new file mode 100644
index 0000000000..8b68d51a89
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/local/no_type.cfg
@@ -0,0 +1,12 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/no_type.gd b/modules/gdscript/tests/scripts/completion/types/local/no_type.gd
new file mode 100644
index 0000000000..f6b5ae3aef
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/local/no_type.gd
@@ -0,0 +1,8 @@
+extends Node
+
+const A := preload("res://completion/class_a.notest.gd")
+
+func a():
+ var test = A.new()
+ test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/types/local/typehint.cfg b/modules/gdscript/tests/scripts/completion/types/local/typehint.cfg
new file mode 100644
index 0000000000..8b68d51a89
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/local/typehint.cfg
@@ -0,0 +1,12 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/typehint.gd b/modules/gdscript/tests/scripts/completion/types/local/typehint.gd
new file mode 100644
index 0000000000..24bcfc04fc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/local/typehint.gd
@@ -0,0 +1,8 @@
+extends Node
+
+const A := preload("res://completion/class_a.notest.gd")
+
+func a():
+ var test: A
+ test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg b/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg
new file mode 100644
index 0000000000..8b68d51a89
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg
@@ -0,0 +1,12 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.gd b/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.gd
new file mode 100644
index 0000000000..88b4812c30
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.gd
@@ -0,0 +1,8 @@
+extends Node
+
+const A := preload("res://completion/class_a.notest.gd")
+
+func a():
+ var test: Node = A.new()
+ test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg b/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg
new file mode 100644
index 0000000000..8b68d51a89
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg
@@ -0,0 +1,12 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.gd b/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.gd
new file mode 100644
index 0000000000..8e226546f3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.gd
@@ -0,0 +1,8 @@
+extends Node
+
+const A := preload("res://completion/class_a.notest.gd")
+
+func a():
+ var test: A = Node.new()
+ test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/types/member/interfered.cfg b/modules/gdscript/tests/scripts/completion/types/member/interfered.cfg
new file mode 100644
index 0000000000..8b68d51a89
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/member/interfered.cfg
@@ -0,0 +1,12 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/interfered.gd b/modules/gdscript/tests/scripts/completion/types/member/interfered.gd
new file mode 100644
index 0000000000..069abd7891
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/member/interfered.gd
@@ -0,0 +1,9 @@
+extends Node
+
+const A := preload("res://completion/class_a.notest.gd")
+
+var test := A.new()
+
+func a():
+ test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/types/member/no_type.cfg b/modules/gdscript/tests/scripts/completion/types/member/no_type.cfg
new file mode 100644
index 0000000000..8b68d51a89
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/member/no_type.cfg
@@ -0,0 +1,12 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/no_type.gd b/modules/gdscript/tests/scripts/completion/types/member/no_type.gd
new file mode 100644
index 0000000000..9bb9549e97
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/member/no_type.gd
@@ -0,0 +1,9 @@
+extends Node
+
+const A := preload("res://completion/class_a.notest.gd")
+
+var test = A.new()
+
+func a():
+ test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/types/member/typehint.cfg b/modules/gdscript/tests/scripts/completion/types/member/typehint.cfg
new file mode 100644
index 0000000000..8b68d51a89
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/member/typehint.cfg
@@ -0,0 +1,12 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/typehint.gd b/modules/gdscript/tests/scripts/completion/types/member/typehint.gd
new file mode 100644
index 0000000000..7763a2e898
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/member/typehint.gd
@@ -0,0 +1,9 @@
+extends Node
+
+const A := preload("res://completion/class_a.notest.gd")
+
+var test: A
+
+func a():
+ test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg b/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg
new file mode 100644
index 0000000000..81401316ec
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg
@@ -0,0 +1,13 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+]
+exclude=[
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.gd b/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.gd
new file mode 100644
index 0000000000..a8506705a1
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.gd
@@ -0,0 +1,9 @@
+extends Node
+
+const A := preload("res://completion/class_a.notest.gd")
+
+var test: Node = A.new()
+
+func a():
+ test.➡
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg b/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg
new file mode 100644
index 0000000000..8b68d51a89
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg
@@ -0,0 +1,12 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.gd b/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.gd
new file mode 100644
index 0000000000..8b5a80cfb3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.gd
@@ -0,0 +1,9 @@
+extends Node
+
+const A := preload("res://completion/class_a.notest.gd")
+
+var test: A = Node.new()
+
+func a():
+ test.➡
+ pass
diff --git a/modules/multiplayer/multiplayer_spawner.cpp b/modules/multiplayer/multiplayer_spawner.cpp
index 2408d7231b..682d20022f 100644
--- a/modules/multiplayer/multiplayer_spawner.cpp
+++ b/modules/multiplayer/multiplayer_spawner.cpp
@@ -99,7 +99,7 @@ void MultiplayerSpawner::add_spawnable_scene(const String &p_path) {
SpawnableScene sc;
sc.path = p_path;
if (Engine::get_singleton()->is_editor_hint()) {
- ERR_FAIL_COND(!FileAccess::exists(p_path));
+ ERR_FAIL_COND(!ResourceLoader::exists(p_path));
}
spawnable_scenes.push_back(sc);
#ifdef TOOLS_ENABLED
diff --git a/platform/web/js/libs/library_godot_audio.js b/platform/web/js/libs/library_godot_audio.js
index d7baece781..4bca13d2d6 100644
--- a/platform/web/js/libs/library_godot_audio.js
+++ b/platform/web/js/libs/library_godot_audio.js
@@ -423,37 +423,32 @@ class SampleNode {
this.streamObjectId = params.streamObjectId;
/** @type {number} */
this.offset = options.offset ?? 0;
- /** @type {LoopMode} */
+ /** @type {number} */
this.startTime = options.startTime ?? 0;
+ /** @type {boolean} */
+ this.isPaused = false;
/** @type {number} */
this.pauseTime = 0;
/** @type {number} */
this._playbackRate = 44100;
/** @type {LoopMode} */
- this._loopMode = 'disabled';
+ this.loopMode = 'disabled';
/** @type {number} */
this._pitchScale = 1;
+ /** @type {number} */
+ this._sourceStartTime = 0;
/** @type {Map<Bus, SampleNodeBus>} */
this._sampleNodeBuses = new Map();
- /** @type {AudioBufferSourceNode} */
+ /** @type {AudioBufferSourceNode | null} */
this._source = GodotAudio.ctx.createBufferSource();
+ /** @type {AudioBufferSourceNode["onended"]} */
+ this._onended = null;
this.setPlaybackRate(options.playbackRate ?? 44100);
- this.setLoopMode(options.loopMode ?? this.getSample().loopMode ?? 'disabled');
+ this.loopMode = options.loopMode ?? this.getSample().loopMode ?? 'disabled';
this._source.buffer = this.getSample().getAudioBuffer();
- /** @type {SampleNode} */
- // eslint-disable-next-line consistent-this
- const self = this;
- this._source.addEventListener('ended', (_) => {
- switch (self.getSample().loopMode) {
- case 'disabled':
- GodotAudio.SampleNode.stopSampleNode(self.id);
- break;
- default:
- // do nothing
- }
- });
+ this._addEndedListener();
const bus = GodotAudio.Bus.getBus(params.busIndex);
const sampleNodeBus = this.getSampleNodeBus(bus);
@@ -461,31 +456,6 @@ class SampleNode {
}
/**
- * Gets the loop mode of the current instance.
- * @returns {LoopMode}
- */
- getLoopMode() {
- return this._loopMode;
- }
-
- /**
- * Sets the loop mode of the current instance.
- * @param {LoopMode} val Value to set.
- * @returns {void}
- */
- setLoopMode(val) {
- this._loopMode = val;
- switch (val) {
- case 'forward':
- case 'backward':
- this._source.loop = true;
- break;
- default:
- this._source.loop = false;
- }
- }
-
- /**
* Gets the playback rate.
* @returns {number}
*/
@@ -542,7 +512,8 @@ class SampleNode {
* @returns {void}
*/
start() {
- this._source.start(this.offset);
+ this._resetSourceStartTime();
+ this._source.start(this.startTime, this.offset);
}
/**
@@ -550,32 +521,31 @@ class SampleNode {
* @returns {void}
*/
stop() {
- this._source.stop();
this.clear();
}
/**
+ * Restarts the `SampleNode`.
+ */
+ restart() {
+ this.isPaused = false;
+ this.pauseTime = 0;
+ this._resetSourceStartTime();
+ this._restart();
+ }
+
+ /**
* Pauses the `SampleNode`.
* @param {boolean} [enable=true] State of the pause.
* @returns {void}
*/
pause(enable = true) {
if (enable) {
- this.pauseTime = (GodotAudio.ctx.currentTime - this.startTime) / this.playbackRate;
- this._source.stop();
- return;
- }
-
- if (this.pauseTime === 0) {
+ this._pause();
return;
}
- this._source.disconnect();
- this._source = GodotAudio.ctx.createBufferSource();
-
- this._source.buffer = this.getSample().getAudioBuffer();
- this._source.connect(this._gain);
- this._source.start(this.offset + this.pauseTime);
+ this._unpause();
}
/**
@@ -623,26 +593,114 @@ class SampleNode {
* @returns {void}
*/
clear() {
- this._source.stop();
- this._source.disconnect();
- this._source = null;
+ this.isPaused = false;
+ this.pauseTime = 0;
+
+ if (this._source != null) {
+ this._source.removeEventListener('ended', this._onended);
+ this._onended = null;
+ this._source.stop();
+ this._source.disconnect();
+ this._source = null;
+ }
for (const sampleNodeBus of this._sampleNodeBuses.values()) {
sampleNodeBus.clear();
}
this._sampleNodeBuses.clear();
- this._sampleNodeBuses = null;
GodotAudio.SampleNode.delete(this.id);
}
/**
+ * Resets the source start time
+ * @returns {void}
+ */
+ _resetSourceStartTime() {
+ this._sourceStartTime = GodotAudio.ctx.currentTime;
+ }
+
+ /**
* Syncs the `AudioNode` playback rate based on the `SampleNode` playback rate and pitch scale.
* @returns {void}
*/
_syncPlaybackRate() {
this._source.playbackRate.value = this.getPlaybackRate() * this.getPitchScale();
}
+
+ /**
+ * Restarts the `SampleNode`.
+ * Honors `isPaused` and `pauseTime`.
+ * @returns {void}
+ */
+ _restart() {
+ this._source.disconnect();
+ this._source = GodotAudio.ctx.createBufferSource();
+ this._source.buffer = this.getSample().getAudioBuffer();
+
+ // Make sure that we connect the new source to the sample node bus.
+ for (const sampleNodeBus of this._sampleNodeBuses.values()) {
+ this.connect(sampleNodeBus.getInputNode());
+ }
+
+ this._addEndedListener();
+ const pauseTime = this.isPaused
+ ? this.pauseTime
+ : 0;
+ this._source.start(this.startTime, this.offset + pauseTime);
+ }
+
+ /**
+ * Pauses the `SampleNode`.
+ * @returns {void}
+ */
+ _pause() {
+ this.isPaused = true;
+ this.pauseTime = (GodotAudio.ctx.currentTime - this._sourceStartTime) / this.getPlaybackRate();
+ this._source.stop();
+ }
+
+ /**
+ * Unpauses the `SampleNode`.
+ * @returns {void}
+ */
+ _unpause() {
+ this._restart();
+ this.isPaused = false;
+ this.pauseTime = 0;
+ }
+
+ /**
+ * Adds an "ended" listener to the source node to repeat it if necessary.
+ * @returns {void}
+ */
+ _addEndedListener() {
+ if (this._onended != null) {
+ this._source.removeEventListener('ended', this._onended);
+ }
+
+ /** @type {SampleNode} */
+ // eslint-disable-next-line consistent-this
+ const self = this;
+ this._onended = (_) => {
+ if (self.isPaused) {
+ return;
+ }
+
+ switch (self.getSample().loopMode) {
+ case 'disabled':
+ self.stop();
+ break;
+ case 'forward':
+ case 'backward':
+ self.restart();
+ break;
+ default:
+ // do nothing
+ }
+ };
+ this._source.addEventListener('ended', this._onended);
+ }
}
/**
diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h
index e2a61a9384..fc7f3ac36d 100644
--- a/thirdparty/thorvg/inc/config.h
+++ b/thirdparty/thorvg/inc/config.h
@@ -15,5 +15,5 @@
// For internal debugging:
//#define THORVG_LOG_ENABLED
-#define THORVG_VERSION_STRING "0.13.7"
+#define THORVG_VERSION_STRING "0.13.8"
#endif
diff --git a/thirdparty/thorvg/patches/pr2338-float_t.patch b/thirdparty/thorvg/patches/pr2338-float_t.patch
deleted file mode 100644
index 20b9050cbb..0000000000
--- a/thirdparty/thorvg/patches/pr2338-float_t.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
-index f59994aae6..b2ce38852c 100644
---- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
-+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
-@@ -709,7 +709,7 @@ static bool _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char**
- *ref = _idFromUrl((const char*)(str + 3));
- return true;
- } else if (len >= 10 && (str[0] == 'h' || str[0] == 'H') && (str[1] == 's' || str[1] == 'S') && (str[2] == 'l' || str[2] == 'L') && str[3] == '(' && str[len - 1] == ')') {
-- float_t th, ts, tb;
-+ float th, ts, tb;
- const char *content, *hue, *satuation, *brightness;
- content = str + 4;
- content = _skipSpace(content, nullptr);
diff --git a/thirdparty/thorvg/src/common/tvgLock.h b/thirdparty/thorvg/src/common/tvgLock.h
index 5dd3d5a624..d8bf7269f6 100644
--- a/thirdparty/thorvg/src/common/tvgLock.h
+++ b/thirdparty/thorvg/src/common/tvgLock.h
@@ -25,6 +25,8 @@
#ifdef THORVG_THREAD_SUPPORT
+#define _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR
+
#include <mutex>
namespace tvg {
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
index b2ce38852c..f29bc09b77 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
@@ -175,14 +175,14 @@ static float _toFloat(const SvgParser* svgParse, const char* str, SvgParserLengt
else if (strstr(str, "pc")) parsedValue *= PX_PER_PC;
else if (strstr(str, "in")) parsedValue *= PX_PER_IN;
else if (strstr(str, "%")) {
- if (type == SvgParserLengthType::Vertical) parsedValue = (parsedValue / 100.0) * svgParse->global.h;
- else if (type == SvgParserLengthType::Horizontal) parsedValue = (parsedValue / 100.0) * svgParse->global.w;
- else //if other then it's radius
+ if (type == SvgParserLengthType::Vertical) parsedValue = (parsedValue / 100.0f) * svgParse->global.h;
+ else if (type == SvgParserLengthType::Horizontal) parsedValue = (parsedValue / 100.0f) * svgParse->global.w;
+ else //if other than it's radius
{
float max = svgParse->global.w;
if (max < svgParse->global.h)
max = svgParse->global.h;
- parsedValue = (parsedValue / 100.0) * max;
+ parsedValue = (parsedValue / 100.0f) * max;
}
}
//TODO: Implement 'em', 'ex' attributes
@@ -580,7 +580,7 @@ static constexpr struct
};
-static bool _hslToRgb(float hue, float satuation, float brightness, uint8_t* red, uint8_t* green, uint8_t* blue)
+static bool _hslToRgb(float hue, float saturation, float brightness, uint8_t* red, uint8_t* green, uint8_t* blue)
{
if (!red || !green || !blue) return false;
@@ -588,12 +588,12 @@ static bool _hslToRgb(float hue, float satuation, float brightness, uint8_t* red
float _red = 0, _green = 0, _blue = 0;
uint32_t i = 0;
- if (mathZero(satuation)) _red = _green = _blue = brightness;
+ if (mathZero(saturation)) _red = _green = _blue = brightness;
else {
if (mathEqual(hue, 360.0)) hue = 0.0f;
hue /= 60.0f;
- v = (brightness <= 0.5f) ? (brightness * (1.0f + satuation)) : (brightness + satuation - (brightness * satuation));
+ v = (brightness <= 0.5f) ? (brightness * (1.0f + saturation)) : (brightness + saturation - (brightness * saturation));
p = brightness + brightness - v;
if (!mathZero(v)) sv = (v - p) / v;
@@ -662,7 +662,7 @@ static bool _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char**
unsigned char tr, tg, tb;
if (len == 4 && str[0] == '#') {
- //Case for "#456" should be interprete as "#445566"
+ //Case for "#456" should be interpreted as "#445566"
if (isxdigit(str[1]) && isxdigit(str[2]) && isxdigit(str[3])) {
char tmp[3] = { '\0', '\0', '\0' };
tmp[0] = str[1];
@@ -710,7 +710,7 @@ static bool _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char**
return true;
} else if (len >= 10 && (str[0] == 'h' || str[0] == 'H') && (str[1] == 's' || str[1] == 'S') && (str[2] == 'l' || str[2] == 'L') && str[3] == '(' && str[len - 1] == ')') {
float th, ts, tb;
- const char *content, *hue, *satuation, *brightness;
+ const char *content, *hue, *saturation, *brightness;
content = str + 4;
content = _skipSpace(content, nullptr);
if (_parseNumber(&content, &hue, &th) && hue) {
@@ -718,12 +718,12 @@ static bool _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char**
hue = _skipSpace(hue, nullptr);
hue = (char*)_skipComma(hue);
hue = _skipSpace(hue, nullptr);
- if (_parseNumber(&hue, &satuation, &ts) && satuation && *satuation == '%') {
+ if (_parseNumber(&hue, &saturation, &ts) && saturation && *saturation == '%') {
ts /= 100.0f;
- satuation = _skipSpace(satuation + 1, nullptr);
- satuation = (char*)_skipComma(satuation);
- satuation = _skipSpace(satuation, nullptr);
- if (_parseNumber(&satuation, &brightness, &tb) && brightness && *brightness == '%') {
+ saturation = _skipSpace(saturation + 1, nullptr);
+ saturation = (char*)_skipComma(saturation);
+ saturation = _skipSpace(saturation, nullptr);
+ if (_parseNumber(&saturation, &brightness, &tb) && brightness && *brightness == '%') {
tb /= 100.0f;
brightness = _skipSpace(brightness + 1, nullptr);
if (brightness && brightness[0] == ')' && brightness[1] == '\0') {
@@ -2119,7 +2119,72 @@ static SvgNode* _createUseNode(SvgLoaderData* loader, SvgNode* parent, const cha
}
-//TODO: Implement 'text' primitive
+static constexpr struct
+{
+ const char* tag;
+ SvgParserLengthType type;
+ int sz;
+ size_t offset;
+} textTags[] = {
+ {"x", SvgParserLengthType::Horizontal, sizeof("x"), offsetof(SvgTextNode, x)},
+ {"y", SvgParserLengthType::Vertical, sizeof("y"), offsetof(SvgTextNode, y)},
+ {"font-size", SvgParserLengthType::Vertical, sizeof("font-size"), offsetof(SvgTextNode, fontSize)}
+};
+
+
+static bool _attrParseTextNode(void* data, const char* key, const char* value)
+{
+ SvgLoaderData* loader = (SvgLoaderData*)data;
+ SvgNode* node = loader->svgParse->node;
+ SvgTextNode* text = &(node->node.text);
+
+ unsigned char* array;
+ int sz = strlen(key);
+
+ array = (unsigned char*)text;
+ for (unsigned int i = 0; i < sizeof(textTags) / sizeof(textTags[0]); i++) {
+ if (textTags[i].sz - 1 == sz && !strncmp(textTags[i].tag, key, sz)) {
+ *((float*)(array + textTags[i].offset)) = _toFloat(loader->svgParse, value, textTags[i].type);
+ return true;
+ }
+ }
+
+ if (!strcmp(key, "font-family")) {
+ if (text->fontFamily && value) free(text->fontFamily);
+ text->fontFamily = strdup(value);
+ } else if (!strcmp(key, "style")) {
+ return simpleXmlParseW3CAttribute(value, strlen(value), _parseStyleAttr, loader);
+ } else if (!strcmp(key, "clip-path")) {
+ _handleClipPathAttr(loader, node, value);
+ } else if (!strcmp(key, "mask")) {
+ _handleMaskAttr(loader, node, value);
+ } else if (!strcmp(key, "id")) {
+ if (node->id && value) free(node->id);
+ node->id = _copyId(value);
+ } else if (!strcmp(key, "class")) {
+ _handleCssClassAttr(loader, node, value);
+ } else {
+ return _parseStyleAttr(loader, key, value, false);
+ }
+ return true;
+}
+
+
+static SvgNode* _createTextNode(SvgLoaderData* loader, SvgNode* parent, const char* buf, unsigned bufLength, parseAttributes func)
+{
+ loader->svgParse->node = _createNode(parent, SvgNodeType::Text);
+ if (!loader->svgParse->node) return nullptr;
+
+ //TODO: support the def font and size as used in a system?
+ loader->svgParse->node->node.text.fontSize = 10.0f;
+ loader->svgParse->node->node.text.fontFamily = nullptr;
+
+ func(buf, bufLength, _attrParseTextNode, loader);
+
+ return loader->svgParse->node;
+}
+
+
static constexpr struct
{
const char* tag;
@@ -2134,7 +2199,8 @@ static constexpr struct
{"rect", sizeof("rect"), _createRectNode},
{"polyline", sizeof("polyline"), _createPolylineNode},
{"line", sizeof("line"), _createLineNode},
- {"image", sizeof("image"), _createImageNode}
+ {"image", sizeof("image"), _createImageNode},
+ {"text", sizeof("text"), _createTextNode}
};
@@ -3122,6 +3188,20 @@ static void _copyAttr(SvgNode* to, const SvgNode* from)
to->node.use.symbol = from->node.use.symbol;
break;
}
+ case SvgNodeType::Text: {
+ to->node.text.x = from->node.text.x;
+ to->node.text.y = from->node.text.y;
+ to->node.text.fontSize = from->node.text.fontSize;
+ if (from->node.text.text) {
+ if (to->node.text.text) free(to->node.text.text);
+ to->node.text.text = strdup(from->node.text.text);
+ }
+ if (from->node.text.fontFamily) {
+ if (to->node.text.fontFamily) free(to->node.text.fontFamily);
+ to->node.text.fontFamily = strdup(from->node.text.fontFamily);
+ }
+ break;
+ }
default: {
break;
}
@@ -3174,27 +3254,12 @@ static void _clonePostponedNodes(Array<SvgNodeIdPair>* cloneNodes, SvgNode* doc)
}
-static constexpr struct
-{
- const char* tag;
- size_t sz;
-} popArray[] = {
- {"g", sizeof("g")},
- {"svg", sizeof("svg")},
- {"defs", sizeof("defs")},
- {"mask", sizeof("mask")},
- {"clipPath", sizeof("clipPath")},
- {"style", sizeof("style")},
- {"symbol", sizeof("symbol")}
-};
-
-
static void _svgLoaderParserXmlClose(SvgLoaderData* loader, const char* content)
{
content = _skipSpace(content, nullptr);
- for (unsigned int i = 0; i < sizeof(popArray) / sizeof(popArray[0]); i++) {
- if (!strncmp(content, popArray[i].tag, popArray[i].sz - 1)) {
+ for (unsigned int i = 0; i < sizeof(groupTags) / sizeof(groupTags[0]); i++) {
+ if (!strncmp(content, groupTags[i].tag, groupTags[i].sz - 1)) {
loader->stack.pop();
break;
}
@@ -3259,7 +3324,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
node = method(loader, nullptr, attrs, attrsLength, simpleXmlParseAttributes);
loader->cssStyle = node;
loader->doc->node.doc.style = node;
- loader->style = true;
+ loader->openedTag = OpenedTagType::Style;
}
} else {
node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes);
@@ -3275,9 +3340,12 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
else parent = loader->doc;
node = method(loader, parent, attrs, attrsLength, simpleXmlParseAttributes);
if (node && !empty) {
- auto defs = _createDefsNode(loader, nullptr, nullptr, 0, nullptr);
- loader->stack.push(defs);
- loader->currentGraphicsNode = node;
+ if (!strcmp(tagName, "text")) loader->openedTag = OpenedTagType::Text;
+ else {
+ auto defs = _createDefsNode(loader, nullptr, nullptr, 0, nullptr);
+ loader->stack.push(defs);
+ loader->currentGraphicsNode = node;
+ }
}
} else if ((gradientMethod = _findGradientFactory(tagName))) {
SvgStyleGradient* gradient;
@@ -3310,6 +3378,15 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
}
+static void _svgLoaderParserText(SvgLoaderData* loader, const char* content, unsigned int length)
+{
+ auto text = &loader->svgParse->node->node.text;
+ if (text->text) free(text->text);
+ text->text = strDuplicate(content, length);
+ loader->openedTag = OpenedTagType::Other;
+}
+
+
static void _svgLoaderParserXmlCssStyle(SvgLoaderData* loader, const char* content, unsigned int length)
{
char* tag;
@@ -3342,7 +3419,7 @@ static void _svgLoaderParserXmlCssStyle(SvgLoaderData* loader, const char* conte
free(tag);
free(name);
}
- loader->style = false;
+ loader->openedTag = OpenedTagType::Other;
}
@@ -3365,7 +3442,8 @@ static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content
}
case SimpleXMLType::Data:
case SimpleXMLType::CData: {
- if (loader->style) _svgLoaderParserXmlCssStyle(loader, content, length);
+ if (loader->openedTag == OpenedTagType::Style) _svgLoaderParserXmlCssStyle(loader, content, length);
+ else if (loader->openedTag == OpenedTagType::Text) _svgLoaderParserText(loader, content, length);
break;
}
case SimpleXMLType::DoctypeChild: {
@@ -3587,6 +3665,11 @@ static void _freeNode(SvgNode* node)
free(node->node.image.href);
break;
}
+ case SvgNodeType::Text: {
+ free(node->node.text.text);
+ free(node->node.text.fontFamily);
+ break;
+ }
default: {
break;
}
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h
index 283f56561b..5661c8ae82 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h
@@ -374,6 +374,14 @@ struct SvgCssStyleNode
{
};
+struct SvgTextNode
+{
+ char* text;
+ char* fontFamily;
+ float x, y;
+ float fontSize;
+};
+
struct SvgLinearGradient
{
float x1;
@@ -518,6 +526,7 @@ struct SvgNode
SvgClipNode clip;
SvgCssStyleNode cssStyle;
SvgSymbolNode symbol;
+ SvgTextNode text;
} node;
~SvgNode();
};
@@ -545,11 +554,18 @@ struct SvgNodeIdPair
char *id;
};
+enum class OpenedTagType : uint8_t
+{
+ Other = 0,
+ Style,
+ Text
+};
+
struct SvgLoaderData
{
Array<SvgNode*> stack;
SvgNode* doc = nullptr;
- SvgNode* def = nullptr;
+ SvgNode* def = nullptr; //also used to store nested graphic nodes
SvgNode* cssStyle = nullptr;
Array<SvgStyleGradient*> gradients;
SvgStyleGradient* latestGradient = nullptr; //For stops
@@ -559,7 +575,7 @@ struct SvgLoaderData
Array<char*> images; //embedded images
int level = 0;
bool result = false;
- bool style = false;
+ OpenedTagType openedTag = OpenedTagType::Other;
SvgNode* currentGraphicsNode = nullptr;
};
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp
index 7e7efed3fc..b048695a23 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp
@@ -67,6 +67,14 @@ static Box _boundingBox(const Shape* shape)
}
+static Box _boundingBox(const Text* text)
+{
+ float x, y, w, h;
+ text->bounds(&x, &y, &w, &h, false);
+ return {x, y, w, h};
+}
+
+
static void _transformMultiply(const Matrix* mBBox, Matrix* gradTransf)
{
gradTransf->e13 = gradTransf->e13 * mBBox->e11 + mBBox->e13;
@@ -79,7 +87,7 @@ static void _transformMultiply(const Matrix* mBBox, Matrix* gradTransf)
}
-static unique_ptr<LinearGradient> _applyLinearGradientProperty(SvgStyleGradient* g, const Shape* vg, const Box& vBox, int opacity)
+static unique_ptr<LinearGradient> _applyLinearGradientProperty(SvgStyleGradient* g, const Box& vBox, int opacity)
{
Fill::ColorStop* stops;
int stopCount = 0;
@@ -134,7 +142,7 @@ static unique_ptr<LinearGradient> _applyLinearGradientProperty(SvgStyleGradient*
}
-static unique_ptr<RadialGradient> _applyRadialGradientProperty(SvgStyleGradient* g, const Shape* vg, const Box& vBox, int opacity)
+static unique_ptr<RadialGradient> _applyRadialGradientProperty(SvgStyleGradient* g, const Box& vBox, int opacity)
{
Fill::ColorStop *stops;
int stopCount = 0;
@@ -320,14 +328,15 @@ static void _applyProperty(SvgLoaderData& loaderData, SvgNode* node, Shape* vg,
if (!style->fill.paint.gradient->userSpace) bBox = _boundingBox(vg);
if (style->fill.paint.gradient->type == SvgGradientType::Linear) {
- auto linear = _applyLinearGradientProperty(style->fill.paint.gradient, vg, bBox, style->fill.opacity);
- vg->fill(std::move(linear));
+ auto linear = _applyLinearGradientProperty(style->fill.paint.gradient, bBox, style->fill.opacity);
+ vg->fill(std::move(linear));
} else if (style->fill.paint.gradient->type == SvgGradientType::Radial) {
- auto radial = _applyRadialGradientProperty(style->fill.paint.gradient, vg, bBox, style->fill.opacity);
- vg->fill(std::move(radial));
+ auto radial = _applyRadialGradientProperty(style->fill.paint.gradient, bBox, style->fill.opacity);
+ vg->fill(std::move(radial));
}
} else if (style->fill.paint.url) {
//TODO: Apply the color pointed by url
+ TVGLOG("SVG", "The fill's url not supported.");
} else if (style->fill.paint.curColor) {
//Apply the current style color
vg->fill(style->color.r, style->color.g, style->color.b, style->fill.opacity);
@@ -363,14 +372,15 @@ static void _applyProperty(SvgLoaderData& loaderData, SvgNode* node, Shape* vg,
if (!style->stroke.paint.gradient->userSpace) bBox = _boundingBox(vg);
if (style->stroke.paint.gradient->type == SvgGradientType::Linear) {
- auto linear = _applyLinearGradientProperty(style->stroke.paint.gradient, vg, bBox, style->stroke.opacity);
+ auto linear = _applyLinearGradientProperty(style->stroke.paint.gradient, bBox, style->stroke.opacity);
vg->stroke(std::move(linear));
} else if (style->stroke.paint.gradient->type == SvgGradientType::Radial) {
- auto radial = _applyRadialGradientProperty(style->stroke.paint.gradient, vg, bBox, style->stroke.opacity);
+ auto radial = _applyRadialGradientProperty(style->stroke.paint.gradient, bBox, style->stroke.opacity);
vg->stroke(std::move(radial));
}
} else if (style->stroke.paint.url) {
//TODO: Apply the color pointed by url
+ TVGLOG("SVG", "The stroke's url not supported.");
} else if (style->stroke.paint.curColor) {
//Apply the current style color
vg->stroke(style->color.r, style->color.g, style->color.b, style->stroke.opacity);
@@ -772,6 +782,61 @@ static unique_ptr<Scene> _useBuildHelper(SvgLoaderData& loaderData, const SvgNod
}
+static void _applyTextFill(SvgStyleProperty* style, Text* text, const Box& vBox)
+{
+ //If fill property is nullptr then do nothing
+ if (style->fill.paint.none) {
+ //Do nothing
+ } else if (style->fill.paint.gradient) {
+ Box bBox = vBox;
+ if (!style->fill.paint.gradient->userSpace) bBox = _boundingBox(text);
+
+ if (style->fill.paint.gradient->type == SvgGradientType::Linear) {
+ auto linear = _applyLinearGradientProperty(style->fill.paint.gradient, bBox, style->fill.opacity);
+ text->fill(std::move(linear));
+ } else if (style->fill.paint.gradient->type == SvgGradientType::Radial) {
+ auto radial = _applyRadialGradientProperty(style->fill.paint.gradient, bBox, style->fill.opacity);
+ text->fill(std::move(radial));
+ }
+ } else if (style->fill.paint.url) {
+ //TODO: Apply the color pointed by url
+ TVGLOG("SVG", "The fill's url not supported.");
+ } else if (style->fill.paint.curColor) {
+ //Apply the current style color
+ text->fill(style->color.r, style->color.g, style->color.b);
+ text->opacity(style->fill.opacity);
+ } else {
+ //Apply the fill color
+ text->fill(style->fill.paint.color.r, style->fill.paint.color.g, style->fill.paint.color.b);
+ text->opacity(style->fill.opacity);
+ }
+}
+
+
+static unique_ptr<Text> _textBuildHelper(SvgLoaderData& loaderData, const SvgNode* node, const Box& vBox, const string& svgPath)
+{
+ auto textNode = &node->node.text;
+ if (!textNode->text) return nullptr;
+ auto text = Text::gen();
+
+ Matrix textTransform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
+ if (node->transform) textTransform = *node->transform;
+ mathTranslateR(&textTransform, node->node.text.x, node->node.text.y - textNode->fontSize);
+ text->transform(textTransform);
+
+ //TODO: handle def values of font and size as used in a system?
+ const float ptPerPx = 0.75f; //1 pt = 1/72; 1 in = 96 px; -> 72/96 = 0.75
+ auto fontSizePt = textNode->fontSize * ptPerPx;
+ if (textNode->fontFamily) text->font(textNode->fontFamily, fontSizePt);
+ text->text(textNode->text);
+
+ _applyTextFill(node->style, text.get(), vBox);
+ _applyComposition(loaderData, text.get(), node, vBox, svgPath);
+
+ return text;
+}
+
+
static unique_ptr<Scene> _sceneBuildHelper(SvgLoaderData& loaderData, const SvgNode* node, const Box& vBox, const string& svgPath, bool mask, int depth, bool* isMaskWhite)
{
/* Exception handling: Prevent invalid SVG data input.
@@ -800,6 +865,9 @@ static unique_ptr<Scene> _sceneBuildHelper(SvgLoaderData& loaderData, const SvgN
scene->push(std::move(image));
if (isMaskWhite) *isMaskWhite = false;
}
+ } else if ((*child)->type == SvgNodeType::Text) {
+ auto text = _textBuildHelper(loaderData, *child, vBox, svgPath);
+ if (text) scene->push(std::move(text));
} else if ((*child)->type != SvgNodeType::Mask) {
auto shape = _shapeBuildHelper(loaderData, *child, vBox, svgPath);
if (shape) {
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h
index 3d73075a4a..231410cdac 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h
@@ -26,18 +26,6 @@
#include "tvgCommon.h"
#include "tvgRender.h"
-#include <algorithm>
-
-#if 0
-#include <sys/time.h>
-static double timeStamp()
-{
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return (tv.tv_sec + tv.tv_usec / 1000000.0);
-}
-#endif
-
#define SW_CURVE_TYPE_POINT 0
#define SW_CURVE_TYPE_CUBIC 1
#define SW_ANGLE_PI (180L << 16)
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h
index 8ec2bc0c47..bab534bba2 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h
@@ -34,14 +34,6 @@ struct AASpans
int32_t yEnd;
};
-static inline void _swap(float& a, float& b, float& tmp)
-{
- tmp = a;
- a = b;
- b = tmp;
-}
-
-
//Careful! Shared resource, No support threading
static float dudx, dvdx;
static float dxdya, dxdyb, dudya, dvdya;
@@ -85,7 +77,7 @@ static bool _rasterMaskedPolygonImageSegment(SwSurface* surface, const SwImage*
int32_t sh = image->h;
int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
int32_t vv = 0, uu = 0;
- int32_t minx = INT32_MAX, maxx = INT32_MIN;
+ int32_t minx = INT32_MAX, maxx = 0;
float dx, u, v, iptr;
SwSpan* span = nullptr; //used only when rle based.
@@ -113,7 +105,7 @@ static bool _rasterMaskedPolygonImageSegment(SwSurface* surface, const SwImage*
if (!region) {
minx = INT32_MAX;
- maxx = INT32_MIN;
+ maxx = 0;
//one single row, could be consisted of multiple spans.
while (span->y == y && spanIdx < image->rle->size) {
if (minx > span->x) minx = span->x;
@@ -278,7 +270,7 @@ static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage
int32_t dw = surface->stride;
int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
int32_t vv = 0, uu = 0;
- int32_t minx = INT32_MAX, maxx = INT32_MIN;
+ int32_t minx = INT32_MAX, maxx = 0;
float dx, u, v, iptr;
uint32_t* buf;
SwSpan* span = nullptr; //used only when rle based.
@@ -307,7 +299,7 @@ static void _rasterBlendingPolygonImageSegment(SwSurface* surface, const SwImage
if (!region) {
minx = INT32_MAX;
- maxx = INT32_MIN;
+ maxx = 0;
//one single row, could be consisted of multiple spans.
while (span->y == y && spanIdx < image->rle->size) {
if (minx > span->x) minx = span->x;
@@ -455,7 +447,7 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image,
int32_t dw = surface->stride;
int32_t x1, x2, x, y, ar, ab, iru, irv, px, ay;
int32_t vv = 0, uu = 0;
- int32_t minx = INT32_MAX, maxx = INT32_MIN;
+ int32_t minx = INT32_MAX, maxx = 0;
float dx, u, v, iptr;
uint32_t* buf;
SwSpan* span = nullptr; //used only when rle based.
@@ -489,7 +481,7 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image,
if (!region) {
minx = INT32_MAX;
- maxx = INT32_MIN;
+ maxx = 0;
//one single row, could be consisted of multiple spans.
while (span->y == y && spanIdx < image->rle->size) {
if (minx > span->x) minx = span->x;
@@ -650,28 +642,27 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const
float off_y;
float dxdy[3] = {0.0f, 0.0f, 0.0f};
- float tmp;
auto upper = false;
//Sort the vertices in ascending Y order
if (y[0] > y[1]) {
- _swap(x[0], x[1], tmp);
- _swap(y[0], y[1], tmp);
- _swap(u[0], u[1], tmp);
- _swap(v[0], v[1], tmp);
+ std::swap(x[0], x[1]);
+ std::swap(y[0], y[1]);
+ std::swap(u[0], u[1]);
+ std::swap(v[0], v[1]);
}
if (y[0] > y[2]) {
- _swap(x[0], x[2], tmp);
- _swap(y[0], y[2], tmp);
- _swap(u[0], u[2], tmp);
- _swap(v[0], v[2], tmp);
+ std::swap(x[0], x[2]);
+ std::swap(y[0], y[2]);
+ std::swap(u[0], u[2]);
+ std::swap(v[0], v[2]);
}
if (y[1] > y[2]) {
- _swap(x[1], x[2], tmp);
- _swap(y[1], y[2], tmp);
- _swap(u[1], u[2], tmp);
- _swap(v[1], v[2], tmp);
+ std::swap(x[1], x[2]);
+ std::swap(y[1], y[2]);
+ std::swap(u[1], u[2]);
+ std::swap(v[1], v[2]);
}
//Y indexes
@@ -837,7 +828,9 @@ static AASpans* _AASpans(float ymin, float ymax, const SwImage* image, const SwB
for (int32_t i = 0; i < height; i++) {
aaSpans->lines[i].x[0] = INT32_MAX;
- aaSpans->lines[i].x[1] = INT32_MIN;
+ aaSpans->lines[i].x[1] = 0;
+ aaSpans->lines[i].length[0] = 0;
+ aaSpans->lines[i].length[1] = 0;
}
return aaSpans;
}
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp
index f689179928..78108af095 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp
@@ -86,7 +86,7 @@ struct SwShapeTask : SwTask
Additionally, the stroke style should not be dashed. */
bool antialiasing(float strokeWidth)
{
- return strokeWidth < 2.0f || rshape->stroke->dashCnt > 0 || rshape->stroke->strokeFirst;
+ return strokeWidth < 2.0f || rshape->stroke->dashCnt > 0 || rshape->stroke->strokeFirst || rshape->strokeTrim();
}
float validStrokeWidth()
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp
index d8dd40d45b..4f069ece97 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp
@@ -420,6 +420,7 @@ static bool _axisAlignedRect(const SwOutline* outline)
{
//Fast Track: axis-aligned rectangle?
if (outline->pts.count != 5) return false;
+ if (outline->types[2] == SW_CURVE_TYPE_CUBIC) return false;
auto pt1 = outline->pts.data + 0;
auto pt2 = outline->pts.data + 1;
diff --git a/thirdparty/thorvg/src/renderer/tvgCommon.h b/thirdparty/thorvg/src/renderer/tvgCommon.h
index d080ea19cf..15a2cc4ef0 100644
--- a/thirdparty/thorvg/src/renderer/tvgCommon.h
+++ b/thirdparty/thorvg/src/renderer/tvgCommon.h
@@ -87,4 +87,16 @@ uint16_t THORVG_VERSION_NUMBER();
#define P(A) ((A)->pImpl) //Access to pimpl.
#define PP(A) (((Paint*)(A))->pImpl) //Access to pimpl.
+
+//for debugging
+#if 0
+#include <sys/time.h>
+static inline double THORVG_TIMESTAMP()
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (tv.tv_sec + tv.tv_usec / 1000000.0);
+}
+#endif
+
#endif //_TVG_COMMON_H_
diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.cpp b/thirdparty/thorvg/src/renderer/tvgPaint.cpp
index fcb632e2b1..ff0f75dc0f 100644
--- a/thirdparty/thorvg/src/renderer/tvgPaint.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgPaint.cpp
@@ -41,8 +41,39 @@
}
+static Result _clipRect(RenderMethod* renderer, const Point* pts, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& before)
+{
+ //sorting
+ Point tmp[4];
+ Point min = {FLT_MAX, FLT_MAX};
+ Point max = {0.0f, 0.0f};
+
+ for (int i = 0; i < 4; ++i) {
+ tmp[i] = pts[i];
+ if (rTransform) tmp[i] *= rTransform->m;
+ if (pTransform) tmp[i] *= pTransform->m;
+ if (tmp[i].x < min.x) min.x = tmp[i].x;
+ if (tmp[i].x > max.x) max.x = tmp[i].x;
+ if (tmp[i].y < min.y) min.y = tmp[i].y;
+ if (tmp[i].y > max.y) max.y = tmp[i].y;
+ }
-static Result _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& viewport)
+ float region[4] = {float(before.x), float(before.x + before.w), float(before.y), float(before.y + before.h)};
+
+ //figure out if the clipper is a superset of the current viewport(before) region
+ if (min.x <= region[0] && max.x >= region[1] && min.y <= region[2] && max.y >= region[3]) {
+ //viewport region is same, nothing to do.
+ return Result::Success;
+ //figure out if the clipper is totally outside of the viewport
+ } else if (max.x <= region[0] || min.x >= region[1] || max.y <= region[2] || min.y >= region[3]) {
+ renderer->viewport({0, 0, 0, 0});
+ return Result::Success;
+ }
+ return Result::InsufficientCondition;
+}
+
+
+static Result _compFastTrack(RenderMethod* renderer, Paint* cmpTarget, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& before)
{
/* Access Shape class by Paint is bad... but it's ok still it's an internal usage. */
auto shape = static_cast<Shape*>(cmpTarget);
@@ -58,9 +89,13 @@ static Result _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform
if (rTransform) rTransform->update();
- //No rotation and no skewing
- if (pTransform && (!mathRightAngle(&pTransform->m) || mathSkewed(&pTransform->m))) return Result::InsufficientCondition;
- if (rTransform && (!mathRightAngle(&rTransform->m) || mathSkewed(&rTransform->m))) return Result::InsufficientCondition;
+ //No rotation and no skewing, still can try out clipping the rect region.
+ auto tryClip = false;
+
+ if (pTransform && (!mathRightAngle(&pTransform->m) || mathSkewed(&pTransform->m))) tryClip = true;
+ if (rTransform && (!mathRightAngle(&rTransform->m) || mathSkewed(&rTransform->m))) tryClip = true;
+
+ if (tryClip) return _clipRect(renderer, pts, pTransform, rTransform, before);
//Perpendicular Rectangle?
auto pt1 = pts + 0;
@@ -71,6 +106,8 @@ static Result _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform
if ((mathEqual(pt1->x, pt2->x) && mathEqual(pt2->y, pt3->y) && mathEqual(pt3->x, pt4->x) && mathEqual(pt1->y, pt4->y)) ||
(mathEqual(pt2->x, pt3->x) && mathEqual(pt1->y, pt2->y) && mathEqual(pt1->x, pt4->x) && mathEqual(pt3->y, pt4->y))) {
+ RenderRegion after;
+
auto v1 = *pt1;
auto v2 = *pt3;
@@ -85,25 +122,19 @@ static Result _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform
}
//sorting
- if (v1.x > v2.x) {
- auto tmp = v2.x;
- v2.x = v1.x;
- v1.x = tmp;
- }
+ if (v1.x > v2.x) std::swap(v1.x, v2.x);
+ if (v1.y > v2.y) std::swap(v1.y, v2.y);
- if (v1.y > v2.y) {
- auto tmp = v2.y;
- v2.y = v1.y;
- v1.y = tmp;
- }
+ after.x = static_cast<int32_t>(v1.x);
+ after.y = static_cast<int32_t>(v1.y);
+ after.w = static_cast<int32_t>(ceil(v2.x - after.x));
+ after.h = static_cast<int32_t>(ceil(v2.y - after.y));
- viewport.x = static_cast<int32_t>(v1.x);
- viewport.y = static_cast<int32_t>(v1.y);
- viewport.w = static_cast<int32_t>(ceil(v2.x - viewport.x));
- viewport.h = static_cast<int32_t>(ceil(v2.y - viewport.y));
+ if (after.w < 0) after.w = 0;
+ if (after.h < 0) after.h = 0;
- if (viewport.w < 0) viewport.w = 0;
- if (viewport.h < 0) viewport.h = 0;
+ after.intersect(before);
+ renderer->viewport(after);
return Result::Success;
}
@@ -264,11 +295,8 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const RenderTransform* pT
}
}
if (tryFastTrack) {
- RenderRegion viewport2;
- if ((compFastTrack = _compFastTrack(target, pTransform, target->pImpl->rTransform, viewport2)) == Result::Success) {
- viewport = renderer->viewport();
- viewport2.intersect(viewport);
- renderer->viewport(viewport2);
+ viewport = renderer->viewport();
+ if ((compFastTrack = _compFastTrack(renderer, target, pTransform, target->pImpl->rTransform, viewport)) == Result::Success) {
target->pImpl->ctxFlag |= ContextFlag::FastTrack;
}
}
diff --git a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h
index 58918e88f0..93f8481707 100644
--- a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h
+++ b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h
@@ -23,6 +23,8 @@
#ifndef _TVG_TASK_SCHEDULER_H_
#define _TVG_TASK_SCHEDULER_H_
+#define _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR
+
#include <mutex>
#include <condition_variable>
diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh
index c0034ba888..663d685d01 100755
--- a/thirdparty/thorvg/update-thorvg.sh
+++ b/thirdparty/thorvg/update-thorvg.sh
@@ -1,6 +1,6 @@
#!/bin/bash -e
-VERSION=0.13.7
+VERSION=0.13.8
cd thirdparty/thorvg/ || true
rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/