diff options
Diffstat (limited to 'modules/text_server_adv')
-rw-r--r-- | modules/text_server_adv/SCsub | 19 | ||||
-rw-r--r-- | modules/text_server_adv/gdextension_build/SConstruct | 92 | ||||
-rw-r--r-- | modules/text_server_adv/gdextension_build/text_server_adv.gdextension | 24 | ||||
-rw-r--r-- | modules/text_server_adv/text_server_adv.cpp | 757 | ||||
-rw-r--r-- | modules/text_server_adv/text_server_adv.h | 438 | ||||
-rw-r--r-- | modules/text_server_adv/thorvg_bounds_iterator.cpp | 70 | ||||
-rw-r--r-- | modules/text_server_adv/thorvg_bounds_iterator.h | 58 | ||||
-rw-r--r-- | modules/text_server_adv/thorvg_svg_in_ot.cpp | 320 | ||||
-rw-r--r-- | modules/text_server_adv/thorvg_svg_in_ot.h | 86 |
9 files changed, 1294 insertions, 570 deletions
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub index 8d0245f0f6..3c7a89b705 100644 --- a/modules/text_server_adv/SCsub +++ b/modules/text_server_adv/SCsub @@ -39,6 +39,9 @@ thirdparty_obj = [] freetype_enabled = "freetype" in env.module_list msdfgen_enabled = "msdfgen" in env.module_list +if "svg" in env.module_list: + env_text_server_adv.Prepend(CPPPATH=["#thirdparty/thorvg/inc", "#thirdparty/thorvg/src/lib"]) + if env["builtin_harfbuzz"]: env_harfbuzz = env_modules.Clone() env_harfbuzz.disable_warnings() @@ -131,9 +134,14 @@ if env["builtin_harfbuzz"]: env_harfbuzz.Append( CCFLAGS=[ "-DHAVE_FREETYPE", - "-DHAVE_GRAPHITE2", ] ) + if env["graphite"]: + env_harfbuzz.Append( + CCFLAGS=[ + "-DHAVE_GRAPHITE2", + ] + ) if env["builtin_freetype"]: env_harfbuzz.Prepend(CPPPATH=["#thirdparty/freetype/include"]) if env["builtin_graphite"] and env["graphite"]: @@ -215,6 +223,9 @@ if env["builtin_graphite"] and freetype_enabled and env["graphite"]: ] ) + if env.msvc: # Not our business to fix. + env_graphite.Append(CCFLAGS=["-D_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS"]) + lib = env_graphite.add_library("graphite_builtin", thirdparty_sources) thirdparty_obj += lib @@ -443,9 +454,9 @@ if env["builtin_icu"]: ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - icu_data_name = "icudt71l.dat" + icu_data_name = "icudt72l.dat" - if env_icu["tools"]: + if env.editor_build: env_icu.Depends("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name) env_icu.Command("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name, make_icu_data) env_text_server_adv.Prepend(CPPPATH=["#thirdparty/icu4c/"]) @@ -479,7 +490,7 @@ if env["builtin_icu"]: "-DICU_DATA_NAME=" + icu_data_name, ] ) - if env_text_server_adv["tools"]: + if env.editor_build: env_text_server_adv.Append(CXXFLAGS=["-DICU_STATIC_DATA"]) env_text_server_adv.Prepend(CPPPATH=["#thirdparty/icu4c/common/", "#thirdparty/icu4c/i18n/"]) diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct index 488d1f641b..4a363fdd7a 100644 --- a/modules/text_server_adv/gdextension_build/SConstruct +++ b/modules/text_server_adv/gdextension_build/SConstruct @@ -23,6 +23,7 @@ opts.Add(BoolVariable("brotli_enabled", "Use Brotli library", True)) opts.Add(BoolVariable("freetype_enabled", "Use FreeType library", True)) opts.Add(BoolVariable("msdfgen_enabled", "Use MSDFgen library (require FreeType)", True)) opts.Add(BoolVariable("graphite_enabled", "Use Graphite library (require FreeType)", True)) +opts.Add(BoolVariable("thorvg_enabled", "Use ThorVG library (require FreeType)", True)) opts.Add(BoolVariable("static_icu_data", "Use built-in ICU data", True)) opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", False)) @@ -34,6 +35,79 @@ if not env["verbose"]: if env["platform"] == "windows" and not env["use_mingw"]: env.AppendUnique(CCFLAGS=["/utf-8"]) # Force to use Unicode encoding. +# ThorVG +if env["thorvg_enabled"] and env["freetype_enabled"]: + env_tvg = env.Clone() + env_tvg.disable_warnings() + + thirdparty_tvg_dir = "../../../thirdparty/thorvg/" + thirdparty_tvg_sources = [ + "src/lib/sw_engine/tvgSwFill.cpp", + "src/lib/sw_engine/tvgSwImage.cpp", + "src/lib/sw_engine/tvgSwMath.cpp", + "src/lib/sw_engine/tvgSwMemPool.cpp", + "src/lib/sw_engine/tvgSwRaster.cpp", + "src/lib/sw_engine/tvgSwRenderer.cpp", + "src/lib/sw_engine/tvgSwRle.cpp", + "src/lib/sw_engine/tvgSwShape.cpp", + "src/lib/sw_engine/tvgSwStroke.cpp", + "src/lib/tvgAccessor.cpp", + "src/lib/tvgBezier.cpp", + "src/lib/tvgCanvas.cpp", + "src/lib/tvgFill.cpp", + "src/lib/tvgGlCanvas.cpp", + "src/lib/tvgInitializer.cpp", + "src/lib/tvgLinearGradient.cpp", + "src/lib/tvgLoader.cpp", + "src/lib/tvgLzw.cpp", + "src/lib/tvgPaint.cpp", + "src/lib/tvgPicture.cpp", + "src/lib/tvgRadialGradient.cpp", + "src/lib/tvgRender.cpp", + "src/lib/tvgSaver.cpp", + "src/lib/tvgScene.cpp", + "src/lib/tvgShape.cpp", + "src/lib/tvgSwCanvas.cpp", + "src/lib/tvgTaskScheduler.cpp", + "src/loaders/external_png/tvgPngLoader.cpp", + "src/loaders/jpg/tvgJpgd.cpp", + "src/loaders/jpg/tvgJpgLoader.cpp", + "src/loaders/raw/tvgRawLoader.cpp", + "src/loaders/svg/tvgSvgCssStyle.cpp", + "src/loaders/svg/tvgSvgLoader.cpp", + "src/loaders/svg/tvgSvgPath.cpp", + "src/loaders/svg/tvgSvgSceneBuilder.cpp", + "src/loaders/svg/tvgSvgUtil.cpp", + "src/loaders/svg/tvgXmlParser.cpp", + "src/loaders/tvg/tvgTvgBinInterpreter.cpp", + "src/loaders/tvg/tvgTvgLoader.cpp", + "src/savers/tvg/tvgTvgSaver.cpp", + ] + thirdparty_tvg_sources = [thirdparty_tvg_dir + file for file in thirdparty_tvg_sources] + + env_tvg.Append( + CPPPATH=[ + "../../../thirdparty/thorvg/inc", + "../../../thirdparty/thorvg/src/lib", + "../../../thirdparty/thorvg/src/lib/sw_engine", + "../../../thirdparty/thorvg/src/loaders/external_png", + "../../../thirdparty/thorvg/src/loaders/jpg", + "../../../thirdparty/thorvg/src/loaders/raw", + "../../../thirdparty/thorvg/src/loaders/svg", + "../../../thirdparty/thorvg/src/loaders/tvg", + "../../../thirdparty/thorvg/src/savers/tvg", + "../../../thirdparty/libpng", + ] + ) + env.Append(CPPPATH=["../../../thirdparty/thorvg/inc", "../../../thirdparty/thorvg/src/lib"]) + env.Append(CPPDEFINES=["MODULE_SVG_ENABLED"]) + + lib = env_tvg.Library( + f'tvg_builtin{env["suffix"]}{env["LIBSUFFIX"]}', + thirdparty_tvg_sources, + ) + env.Append(LIBS=[lib]) + # MSDFGEN if env["msdfgen_enabled"] and env["freetype_enabled"]: env_msdfgen = env.Clone() @@ -68,7 +142,7 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]: env.Append(CPPDEFINES=["MODULE_MSDFGEN_ENABLED"]) lib = env_msdfgen.Library( - f'msdfgen_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}', + f'msdfgen_builtin{env["suffix"]}{env["LIBSUFFIX"]}', thirdparty_msdfgen_sources, ) env.Append(LIBS=[lib]) @@ -193,13 +267,13 @@ if env["freetype_enabled"]: "FT_CONFIG_OPTION_SYSTEM_ZLIB", ] ) - if env["target"] == "debug": + if env.dev_build: env_freetype.Append(CPPDEFINES=["ZLIB_DEBUG"]) env.Append(CPPDEFINES=["MODULE_FREETYPE_ENABLED"]) lib = env_freetype.Library( - f'freetype_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}', + f'freetype_builtin{env["suffix"]}{env["LIBSUFFIX"]}', thirdparty_freetype_sources, ) env.Append(LIBS=[lib]) @@ -321,7 +395,7 @@ if env["freetype_enabled"]: env.Append(CPPPATH=["../../../thirdparty/harfbuzz/src"]) lib = env_harfbuzz.Library( - f'harfbuzz_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}', + f'harfbuzz_builtin{env["suffix"]}{env["LIBSUFFIX"]}', thirdparty_harfbuzz_sources, ) env.Prepend(LIBS=[lib]) @@ -381,7 +455,7 @@ if env["graphite_enabled"] and env["freetype_enabled"]: ) lib = env_graphite.Library( - f'graphite_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}', + f'graphite_builtin{env["suffix"]}{env["LIBSUFFIX"]}', thirdparty_graphite_sources, ) env.Append(LIBS=[lib]) @@ -597,7 +671,7 @@ thirdparty_icu_sources = [ ] thirdparty_icu_sources = [thirdparty_icu_dir + file for file in thirdparty_icu_sources] -icu_data_name = "icudt71l.dat" +icu_data_name = "icudt72l.dat" if env["static_icu_data"]: env_icu.Depends("../../../thirdparty/icu4c/icudata.gen.h", "../../../thirdparty/icu4c/" + icu_data_name) @@ -640,9 +714,7 @@ env.Append(CPPPATH=["../../../thirdparty/icu4c/common/", "../../../thirdparty/ic if env["platform"] == "windows": env.Append(LIBS=["advapi32"]) -lib = env_icu.Library( - f'icu_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}', thirdparty_icu_sources -) +lib = env_icu.Library(f'icu_builtin{env["suffix"]}{env["LIBSUFFIX"]}', thirdparty_icu_sources) env.Append(LIBS=[lib]) env.Append(CPPDEFINES=["GDEXTENSION"]) @@ -662,7 +734,7 @@ if env["platform"] == "macos": ) else: library = env.SharedLibrary( - f'./bin/libtextserver_advanced.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["SHLIBSUFFIX"]}', + f'./bin/libtextserver_advanced{env["suffix"]}{env["SHLIBSUFFIX"]}', source=sources, ) diff --git a/modules/text_server_adv/gdextension_build/text_server_adv.gdextension b/modules/text_server_adv/gdextension_build/text_server_adv.gdextension index 11ed271ae9..c12fcfdfdf 100644 --- a/modules/text_server_adv/gdextension_build/text_server_adv.gdextension +++ b/modules/text_server_adv/gdextension_build/text_server_adv.gdextension @@ -4,9 +4,21 @@ entry_symbol = "textserver_advanced_init" [libraries] -linux.64.debug = "bin/libtextserver_advanced.linux.debug.64.so" -linux.64.release = "bin/libtextserver_advanced.linux.release.64.so" -windows.64.debug = "bin/libtextserver_advanced.windows.debug.64.dll" -windows.64.release = "bin/libtextserver_advanced.windows.release.64.dll" -macos.debug = "bin/libtextserver_advanced.macos.debug.framework" -macos.release = "bin/libtextserver_advanced.macos.release.framework" +linux.x86_64.debug = "bin/libtextserver_advanced.linux.template_debug.x86_64.so" +linux.x86_64.release = "bin/libtextserver_advanced.linux.template_release.x86_64.so" +linux.x86_32.debug = "bin/libtextserver_advanced.linux.template_debug.x86_32.so" +linux.x86_32.release = "bin/libtextserver_advanced.linux.template_release.x86_32.so" +linux.arm64.debug = "bin/libtextserver_advanced.linux.template_debug.arm64.so" +linux.arm64.release = "bin/libtextserver_advanced.linux.template_release.arm64.so" +linux.rv64.debug = "bin/libtextserver_advanced.linux.template_debug.rv64.so" +linux.rv64.release = "bin/libtextserver_advanced.linux.template_release.rv64.so" + +windows.x86_64.debug = "bin/libtextserver_advanced.windows.template_debug.x86_64.dll" +windows.x86_64.release = "bin/libtextserver_advanced.windows.template_release.x86_64.dll" +windows.x86_32.debug = "bin/libtextserver_advanced.windows.template_debug.x86_32.dll" +windows.x86_32.release = "bin/libtextserver_advanced.windows.template_release.x86_32.dll" +windows.arm64.debug = "bin/libtextserver_advanced.windows.template_debug.arm64.dll" +windows.arm64.release = "bin/libtextserver_advanced.windows.template_release.arm64.dll" + +macos.debug = "bin/libtextserver_advanced.macos.template_debug.framework" +macos.release = "bin/libtextserver_advanced.macos.template_release.framework" diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 3565254ac7..166325c551 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -33,7 +33,7 @@ #ifdef GDEXTENSION // Headers for building as GDExtension plug-in. -#include <godot_cpp/classes/file.hpp> +#include <godot_cpp/classes/file_access.hpp> #include <godot_cpp/classes/project_settings.hpp> #include <godot_cpp/classes/rendering_server.hpp> #include <godot_cpp/classes/translation_server.hpp> @@ -41,6 +41,8 @@ using namespace godot; +#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get(m_var) + #else // Headers for building as built-in module. @@ -50,7 +52,7 @@ using namespace godot; #include "core/string/print_string.h" #include "core/string/translation.h" -#include "modules/modules_enabled.gen.h" // For freetype, msdfgen. +#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg. #endif @@ -69,6 +71,10 @@ using namespace godot; #include "msdfgen.h" #endif +#ifdef MODULE_SVG_ENABLED +#include "thorvg_svg_in_ot.h" +#endif + /*************************************************************************/ /* bmp_font_t HarfBuzz Bitmap font interface */ /*************************************************************************/ @@ -327,7 +333,7 @@ _FORCE_INLINE_ bool is_connected_to_prev(char32_t p_chr, char32_t p_pchr) { /*************************************************************************/ -bool TextServerAdvanced::has_feature(Feature p_feature) const { +bool TextServerAdvanced::_has_feature(Feature p_feature) const { switch (p_feature) { case FEATURE_SIMPLE_LAYOUT: case FEATURE_BIDI_LAYOUT: @@ -354,7 +360,7 @@ bool TextServerAdvanced::has_feature(Feature p_feature) const { return false; } -String TextServerAdvanced::get_name() const { +String TextServerAdvanced::_get_name() const { #ifdef GDEXTENSION return "ICU / HarfBuzz / Graphite (GDExtension)"; #else @@ -362,7 +368,7 @@ String TextServerAdvanced::get_name() const { #endif } -int64_t TextServerAdvanced::get_features() const { +int64_t TextServerAdvanced::_get_features() const { int64_t interface_features = FEATURE_SIMPLE_LAYOUT | FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_FONT_BITMAP | FEATURE_FONT_VARIABLE | FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION | FEATURE_USE_SUPPORT_DATA; #ifdef MODULE_FREETYPE_ENABLED interface_features |= FEATURE_FONT_DYNAMIC; @@ -374,7 +380,7 @@ int64_t TextServerAdvanced::get_features() const { return interface_features; } -void TextServerAdvanced::free_rid(const RID &p_rid) { +void TextServerAdvanced::_free_rid(const RID &p_rid) { _THREAD_SAFE_METHOD_ if (font_owner.owns(p_rid)) { FontAdvanced *fd = font_owner.get_or_null(p_rid); @@ -387,12 +393,12 @@ void TextServerAdvanced::free_rid(const RID &p_rid) { } } -bool TextServerAdvanced::has(const RID &p_rid) { +bool TextServerAdvanced::_has(const RID &p_rid) { _THREAD_SAFE_METHOD_ return font_owner.owns(p_rid) || shaped_owner.owns(p_rid); } -bool TextServerAdvanced::load_support_data(const String &p_filename) { +bool TextServerAdvanced::_load_support_data(const String &p_filename) { _THREAD_SAFE_METHOD_ #ifdef ICU_STATIC_DATA @@ -410,7 +416,11 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) { return false; } uint64_t len = f->get_length(); +#ifdef GDEXTENSION + PackedByteArray icu_data = f->get_buffer(len); +#else PackedByteArray icu_data = f->_get_buffer(len); +#endif UErrorCode err = U_ZERO_ERROR; udata_setCommonData(icu_data.ptr(), &err); @@ -429,7 +439,7 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) { return true; } -String TextServerAdvanced::get_support_data_filename() const { +String TextServerAdvanced::_get_support_data_filename() const { #ifdef ICU_STATIC_DATA return _MKSTR(ICU_DATA_NAME); #else @@ -437,7 +447,7 @@ String TextServerAdvanced::get_support_data_filename() const { #endif } -String TextServerAdvanced::get_support_data_info() const { +String TextServerAdvanced::_get_support_data_info() const { #ifdef ICU_STATIC_DATA return String("ICU break iteration data (") + _MKSTR(ICU_DATA_NAME) + String(")."); #else @@ -445,7 +455,7 @@ String TextServerAdvanced::get_support_data_info() const { #endif } -bool TextServerAdvanced::save_support_data(const String &p_filename) const { +bool TextServerAdvanced::_save_support_data(const String &p_filename) const { _THREAD_SAFE_METHOD_ #ifdef ICU_STATIC_DATA @@ -459,7 +469,11 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) const { PackedByteArray icu_data; icu_data.resize(U_ICUDATA_SIZE); memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE); +#ifdef GDEXTENSION + f->store_buffer(icu_data); +#else f->_store_buffer(icu_data); +#endif return true; #else @@ -467,7 +481,7 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) const { #endif } -bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) const { +bool TextServerAdvanced::_is_locale_right_to_left(const String &p_locale) const { String l = p_locale.get_slicec('_', 0); if ((l == "ar") || (l == "dv") || (l == "he") || (l == "fa") || (l == "ff") || (l == "ku") || (l == "ur")) { return true; @@ -739,7 +753,7 @@ void TextServerAdvanced::_insert_feature_sets() { _insert_feature("weight", HB_TAG('w', 'g', 'h', 't'), Variant::Type::INT, false); } -int64_t TextServerAdvanced::name_to_tag(const String &p_name) const { +int64_t TextServerAdvanced::_name_to_tag(const String &p_name) const { if (feature_sets.has(p_name)) { return feature_sets[p_name]; } @@ -762,7 +776,7 @@ bool TextServerAdvanced::_get_tag_hidden(int64_t p_tag) const { return false; } -String TextServerAdvanced::tag_to_name(int64_t p_tag) const { +String TextServerAdvanced::_tag_to_name(int64_t p_tag) const { if (feature_sets_inv.has(p_tag)) { return feature_sets_inv[p_tag].name; } @@ -780,58 +794,27 @@ String TextServerAdvanced::tag_to_name(int64_t p_tag) const { _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_texture_pos_for_glyph(FontForSizeAdvanced *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height, bool p_msdf) const { FontTexturePosition ret; - ret.index = -1; int mw = p_width; int mh = p_height; - for (int i = 0; i < p_data->textures.size(); i++) { - const FontTexture &ct = p_data->textures[i]; - - if (p_image_format != ct.format) { + ShelfPackTexture *ct = p_data->textures.ptrw(); + for (int32_t i = 0; i < p_data->textures.size(); i++) { + if (p_image_format != ct[i].format) { continue; } - - if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture. - continue; - } - - if (ct.offsets.size() < ct.texture_w) { + if (mw > ct[i].texture_w || mh > ct[i].texture_h) { // Too big for this texture. continue; } - ret.y = 0x7fffffff; - ret.x = 0; - - for (int j = 0; j < ct.texture_w - mw; j++) { - int max_y = 0; - - for (int k = j; k < j + mw; k++) { - int y = ct.offsets[k]; - if (y > max_y) { - max_y = y; - } - } - - if (max_y < ret.y) { - ret.y = max_y; - ret.x = j; - } - } - - if (ret.y == 0x7fffffff || ret.y + mh > ct.texture_h) { - continue; // Fail, could not fit it here. + ret = ct[i].pack_rect(i, mh, mw); + if (ret.index != -1) { + break; } - - ret.index = i; - break; } if (ret.index == -1) { // Could not find texture to fit, create one. - ret.x = 0; - ret.y = 0; - int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256); #ifdef GDEXTENSION @@ -859,12 +842,9 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_ #endif } - FontTexture tex; - tex.texture_w = texsize; - tex.texture_h = texsize; + ShelfPackTexture tex = ShelfPackTexture(texsize, texsize); tex.format = p_image_format; tex.imgdata.resize(texsize * texsize * p_color_size); - { // Zero texture. uint8_t *w = tex.imgdata.ptrw(); @@ -887,14 +867,10 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_ ERR_FAIL_V(ret); } } - tex.offsets.resize(texsize); - int32_t *offw = tex.offsets.ptrw(); - for (int i = 0; i < texsize; i++) { // Zero offsets. - offw[i] = 0; - } - p_data->textures.push_back(tex); - ret.index = p_data->textures.size() - 1; + + int32_t idx = p_data->textures.size() - 1; + ret = p_data->textures.write[idx].pack_rect(idx, mh, mw); } return ret; @@ -1028,7 +1004,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf( FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true); ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph()); - FontTexture &tex = p_data->textures.write[tex_pos.index]; + ShelfPackTexture &tex = p_data->textures.write[tex_pos.index]; edgeColoringSimple(shape, 3.0); // Max. angle. msdfgen::Bitmap<float, 4> image(w, h); // Texture size. @@ -1043,8 +1019,14 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf( td.projection = &projection; td.distancePixelConversion = &distancePixelConversion; +#ifdef GDEXTENSION + for (int i = 0; i < h; i++) { + _generateMTSDF_threaded(i, &td); + } +#else WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &TextServerAdvanced::_generateMTSDF_threaded, &td, h, -1, true, SNAME("FontServerRasterizeMSDF")); WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task); +#endif msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config); @@ -1065,12 +1047,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf( tex.dirty = true; - // Update height array. - int32_t *offw = tex.offsets.ptrw(); - for (int k = tex_pos.x; k < tex_pos.x + mw; k++) { - offw[k] = tex_pos.y + mh; - } - chr.texture_idx = tex_pos.index; chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2); @@ -1118,8 +1094,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph()); // Fit character in char texture. - - FontTexture &tex = p_data->textures.write[tex_pos.index]; + ShelfPackTexture &tex = p_data->textures.write[tex_pos.index]; { uint8_t *wr = tex.imgdata.ptrw(); @@ -1184,12 +1159,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma tex.dirty = true; - // Update height array. - int32_t *offw = tex.offsets.ptrw(); - for (int k = tex_pos.x; k < tex_pos.x + mw; k++) { - offw[k] = tex_pos.y + mh; - } - FontGlyph chr; chr.advance = advance * p_data->scale / p_data->oversampling; chr.texture_idx = tex_pos.index; @@ -1379,7 +1348,13 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f int error = 0; if (!ft_library) { error = FT_Init_FreeType(&ft_library); - ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'."); + if (error != 0) { + memdelete(fd); + ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'."); + } +#ifdef MODULE_SVG_ENABLED + FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks()); +#endif } memset(&fd->stream, 0, sizeof(FT_StreamRec)); @@ -1408,6 +1383,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f if (error) { FT_Done_Face(fd->face); fd->face = nullptr; + memdelete(fd); ERR_FAIL_V_MSG(false, "FreeType: Error loading font: '" + String(FT_Error_String(error)) + "'."); } @@ -1415,7 +1391,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f fd->oversampling = 1.0; fd->size.x = p_font_data->msdf_source_size; } else if (p_font_data->oversampling <= 0.0) { - fd->oversampling = font_get_global_oversampling(); + fd->oversampling = _font_get_global_oversampling(); } else { fd->oversampling = p_font_data->oversampling; } @@ -1808,8 +1784,8 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f coords.write[i] = CLAMP(var.value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum); } - if (p_font_data->variation_coordinates.has(tag_to_name(var.tag))) { - var.value = p_font_data->variation_coordinates[tag_to_name(var.tag)]; + if (p_font_data->variation_coordinates.has(_tag_to_name(var.tag))) { + var.value = p_font_data->variation_coordinates[_tag_to_name(var.tag)]; coords.write[i] = CLAMP(var.value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum); } @@ -1821,6 +1797,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f FT_Done_MM_Var(ft_library, amaster); } #else + memdelete(fd); ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!"); #endif } else { @@ -1854,7 +1831,7 @@ hb_font_t *TextServerAdvanced::_font_get_hb_handle(const RID &p_font_rid, int64_ return fd->cache[size]->hb_handle; } -RID TextServerAdvanced::create_font() { +RID TextServerAdvanced::_create_font() { _THREAD_SAFE_METHOD_ FontAdvanced *fd = memnew(FontAdvanced); @@ -1862,7 +1839,7 @@ RID TextServerAdvanced::create_font() { return font_owner.make_rid(fd); } -void TextServerAdvanced::font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) { +void TextServerAdvanced::_font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1873,7 +1850,7 @@ void TextServerAdvanced::font_set_data(const RID &p_font_rid, const PackedByteAr fd->data_size = fd->data.size(); } -void TextServerAdvanced::font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) { +void TextServerAdvanced::_font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1884,7 +1861,7 @@ void TextServerAdvanced::font_set_data_ptr(const RID &p_font_rid, const uint8_t fd->data_size = p_data_size; } -void TextServerAdvanced::font_set_face_index(const RID &p_font_rid, int64_t p_face_index) { +void TextServerAdvanced::_font_set_face_index(const RID &p_font_rid, int64_t p_face_index) { ERR_FAIL_COND(p_face_index < 0); ERR_FAIL_COND(p_face_index >= 0x7FFF); @@ -1898,7 +1875,7 @@ void TextServerAdvanced::font_set_face_index(const RID &p_font_rid, int64_t p_fa } } -int64_t TextServerAdvanced::font_get_face_index(const RID &p_font_rid) const { +int64_t TextServerAdvanced::_font_get_face_index(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -1906,7 +1883,7 @@ int64_t TextServerAdvanced::font_get_face_index(const RID &p_font_rid) const { return fd->face_index; } -int64_t TextServerAdvanced::font_get_face_count(const RID &p_font_rid) const { +int64_t TextServerAdvanced::_font_get_face_count(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -1920,6 +1897,9 @@ int64_t TextServerAdvanced::font_get_face_count(const RID &p_font_rid) const { if (!ft_library) { error = FT_Init_FreeType(&ft_library); ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'."); +#ifdef MODULE_SVG_ENABLED + FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks()); +#endif } FT_StreamRec stream; @@ -1947,7 +1927,7 @@ int64_t TextServerAdvanced::font_get_face_count(const RID &p_font_rid) const { return face_count; } -void TextServerAdvanced::font_set_style(const RID &p_font_rid, BitField<FontStyle> p_style) { +void TextServerAdvanced::_font_set_style(const RID &p_font_rid, BitField<FontStyle> p_style) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1957,7 +1937,7 @@ void TextServerAdvanced::font_set_style(const RID &p_font_rid, BitField<FontStyl fd->style_flags = p_style; } -BitField<TextServer::FontStyle> TextServerAdvanced::font_get_style(const RID &p_font_rid) const { +BitField<TextServer::FontStyle> TextServerAdvanced::_font_get_style(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -1967,7 +1947,7 @@ BitField<TextServer::FontStyle> TextServerAdvanced::font_get_style(const RID &p_ return fd->style_flags; } -void TextServerAdvanced::font_set_style_name(const RID &p_font_rid, const String &p_name) { +void TextServerAdvanced::_font_set_style_name(const RID &p_font_rid, const String &p_name) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1977,7 +1957,7 @@ void TextServerAdvanced::font_set_style_name(const RID &p_font_rid, const String fd->style_name = p_name; } -String TextServerAdvanced::font_get_style_name(const RID &p_font_rid) const { +String TextServerAdvanced::_font_get_style_name(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, String()); @@ -1987,7 +1967,7 @@ String TextServerAdvanced::font_get_style_name(const RID &p_font_rid) const { return fd->style_name; } -void TextServerAdvanced::font_set_name(const RID &p_font_rid, const String &p_name) { +void TextServerAdvanced::_font_set_name(const RID &p_font_rid, const String &p_name) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -1997,7 +1977,7 @@ void TextServerAdvanced::font_set_name(const RID &p_font_rid, const String &p_na fd->font_name = p_name; } -String TextServerAdvanced::font_get_name(const RID &p_font_rid) const { +String TextServerAdvanced::_font_get_name(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, String()); @@ -2007,7 +1987,7 @@ String TextServerAdvanced::font_get_name(const RID &p_font_rid) const { return fd->font_name; } -void TextServerAdvanced::font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) { +void TextServerAdvanced::_font_set_antialiasing(const RID &p_font_rid, TextServer::FontAntialiasing p_antialiasing) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2018,7 +1998,7 @@ void TextServerAdvanced::font_set_antialiasing(RID p_font_rid, TextServer::FontA } } -TextServer::FontAntialiasing TextServerAdvanced::font_get_antialiasing(RID p_font_rid) const { +TextServer::FontAntialiasing TextServerAdvanced::_font_get_antialiasing(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, TextServer::FONT_ANTIALIASING_NONE); @@ -2026,7 +2006,7 @@ TextServer::FontAntialiasing TextServerAdvanced::font_get_antialiasing(RID p_fon return fd->antialiasing; } -void TextServerAdvanced::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) { +void TextServerAdvanced::_font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2035,13 +2015,14 @@ void TextServerAdvanced::font_set_generate_mipmaps(const RID &p_font_rid, bool p for (KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) { for (int i = 0; i < E.value->textures.size(); i++) { E.value->textures.write[i].dirty = true; + E.value->textures.write[i].texture = Ref<ImageTexture>(); } } fd->mipmaps = p_generate_mipmaps; } } -bool TextServerAdvanced::font_get_generate_mipmaps(const RID &p_font_rid) const { +bool TextServerAdvanced::_font_get_generate_mipmaps(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2049,7 +2030,7 @@ bool TextServerAdvanced::font_get_generate_mipmaps(const RID &p_font_rid) const return fd->mipmaps; } -void TextServerAdvanced::font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) { +void TextServerAdvanced::_font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2060,7 +2041,7 @@ void TextServerAdvanced::font_set_multichannel_signed_distance_field(const RID & } } -bool TextServerAdvanced::font_is_multichannel_signed_distance_field(const RID &p_font_rid) const { +bool TextServerAdvanced::_font_is_multichannel_signed_distance_field(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2068,7 +2049,7 @@ bool TextServerAdvanced::font_is_multichannel_signed_distance_field(const RID &p return fd->msdf; } -void TextServerAdvanced::font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) { +void TextServerAdvanced::_font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2079,7 +2060,7 @@ void TextServerAdvanced::font_set_msdf_pixel_range(const RID &p_font_rid, int64_ } } -int64_t TextServerAdvanced::font_get_msdf_pixel_range(const RID &p_font_rid) const { +int64_t TextServerAdvanced::_font_get_msdf_pixel_range(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2087,7 +2068,7 @@ int64_t TextServerAdvanced::font_get_msdf_pixel_range(const RID &p_font_rid) con return fd->msdf_range; } -void TextServerAdvanced::font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) { +void TextServerAdvanced::_font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2098,7 +2079,7 @@ void TextServerAdvanced::font_set_msdf_size(const RID &p_font_rid, int64_t p_msd } } -int64_t TextServerAdvanced::font_get_msdf_size(const RID &p_font_rid) const { +int64_t TextServerAdvanced::_font_get_msdf_size(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2106,7 +2087,7 @@ int64_t TextServerAdvanced::font_get_msdf_size(const RID &p_font_rid) const { return fd->msdf_source_size; } -void TextServerAdvanced::font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) { +void TextServerAdvanced::_font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2114,7 +2095,7 @@ void TextServerAdvanced::font_set_fixed_size(const RID &p_font_rid, int64_t p_fi fd->fixed_size = p_fixed_size; } -int64_t TextServerAdvanced::font_get_fixed_size(const RID &p_font_rid) const { +int64_t TextServerAdvanced::_font_get_fixed_size(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2122,7 +2103,7 @@ int64_t TextServerAdvanced::font_get_fixed_size(const RID &p_font_rid) const { return fd->fixed_size; } -void TextServerAdvanced::font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) { +void TextServerAdvanced::_font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2133,7 +2114,7 @@ void TextServerAdvanced::font_set_force_autohinter(const RID &p_font_rid, bool p } } -bool TextServerAdvanced::font_is_force_autohinter(const RID &p_font_rid) const { +bool TextServerAdvanced::_font_is_force_autohinter(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -2141,7 +2122,7 @@ bool TextServerAdvanced::font_is_force_autohinter(const RID &p_font_rid) const { return fd->force_autohinter; } -void TextServerAdvanced::font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) { +void TextServerAdvanced::_font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2152,7 +2133,7 @@ void TextServerAdvanced::font_set_hinting(const RID &p_font_rid, TextServer::Hin } } -TextServer::Hinting TextServerAdvanced::font_get_hinting(const RID &p_font_rid) const { +TextServer::Hinting TextServerAdvanced::_font_get_hinting(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, HINTING_NONE); @@ -2160,7 +2141,7 @@ TextServer::Hinting TextServerAdvanced::font_get_hinting(const RID &p_font_rid) return fd->hinting; } -void TextServerAdvanced::font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) { +void TextServerAdvanced::_font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2168,7 +2149,7 @@ void TextServerAdvanced::font_set_subpixel_positioning(const RID &p_font_rid, Te fd->subpixel_positioning = p_subpixel; } -TextServer::SubpixelPositioning TextServerAdvanced::font_get_subpixel_positioning(const RID &p_font_rid) const { +TextServer::SubpixelPositioning TextServerAdvanced::_font_get_subpixel_positioning(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, SUBPIXEL_POSITIONING_DISABLED); @@ -2176,7 +2157,7 @@ TextServer::SubpixelPositioning TextServerAdvanced::font_get_subpixel_positionin return fd->subpixel_positioning; } -void TextServerAdvanced::font_set_embolden(const RID &p_font_rid, double p_strength) { +void TextServerAdvanced::_font_set_embolden(const RID &p_font_rid, double p_strength) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2187,7 +2168,7 @@ void TextServerAdvanced::font_set_embolden(const RID &p_font_rid, double p_stren } } -double TextServerAdvanced::font_get_embolden(const RID &p_font_rid) const { +double TextServerAdvanced::_font_get_embolden(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -2195,7 +2176,7 @@ double TextServerAdvanced::font_get_embolden(const RID &p_font_rid) const { return fd->embolden; } -void TextServerAdvanced::font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) { +void TextServerAdvanced::_font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2206,7 +2187,7 @@ void TextServerAdvanced::font_set_transform(const RID &p_font_rid, const Transfo } } -Transform2D TextServerAdvanced::font_get_transform(const RID &p_font_rid) const { +Transform2D TextServerAdvanced::_font_get_transform(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Transform2D()); @@ -2214,7 +2195,7 @@ Transform2D TextServerAdvanced::font_get_transform(const RID &p_font_rid) const return fd->transform; } -void TextServerAdvanced::font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) { +void TextServerAdvanced::_font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2225,7 +2206,7 @@ void TextServerAdvanced::font_set_variation_coordinates(const RID &p_font_rid, c } } -Dictionary TextServerAdvanced::font_get_variation_coordinates(const RID &p_font_rid) const { +Dictionary TextServerAdvanced::_font_get_variation_coordinates(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -2233,7 +2214,7 @@ Dictionary TextServerAdvanced::font_get_variation_coordinates(const RID &p_font_ return fd->variation_coordinates; } -void TextServerAdvanced::font_set_oversampling(const RID &p_font_rid, double p_oversampling) { +void TextServerAdvanced::_font_set_oversampling(const RID &p_font_rid, double p_oversampling) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2244,7 +2225,7 @@ void TextServerAdvanced::font_set_oversampling(const RID &p_font_rid, double p_o } } -double TextServerAdvanced::font_get_oversampling(const RID &p_font_rid) const { +double TextServerAdvanced::_font_get_oversampling(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -2252,7 +2233,7 @@ double TextServerAdvanced::font_get_oversampling(const RID &p_font_rid) const { return fd->oversampling; } -TypedArray<Vector2i> TextServerAdvanced::font_get_size_cache_list(const RID &p_font_rid) const { +TypedArray<Vector2i> TextServerAdvanced::_font_get_size_cache_list(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>()); @@ -2264,7 +2245,7 @@ TypedArray<Vector2i> TextServerAdvanced::font_get_size_cache_list(const RID &p_f return ret; } -void TextServerAdvanced::font_clear_size_cache(const RID &p_font_rid) { +void TextServerAdvanced::_font_clear_size_cache(const RID &p_font_rid) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2275,7 +2256,7 @@ void TextServerAdvanced::font_clear_size_cache(const RID &p_font_rid) { fd->cache.clear(); } -void TextServerAdvanced::font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) { +void TextServerAdvanced::_font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2286,7 +2267,7 @@ void TextServerAdvanced::font_remove_size_cache(const RID &p_font_rid, const Vec } } -void TextServerAdvanced::font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) { +void TextServerAdvanced::_font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2297,7 +2278,7 @@ void TextServerAdvanced::font_set_ascent(const RID &p_font_rid, int64_t p_size, fd->cache[size]->ascent = p_ascent; } -double TextServerAdvanced::font_get_ascent(const RID &p_font_rid, int64_t p_size) const { +double TextServerAdvanced::_font_get_ascent(const RID &p_font_rid, int64_t p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -2313,7 +2294,7 @@ double TextServerAdvanced::font_get_ascent(const RID &p_font_rid, int64_t p_size } } -void TextServerAdvanced::font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) { +void TextServerAdvanced::_font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2323,7 +2304,7 @@ void TextServerAdvanced::font_set_descent(const RID &p_font_rid, int64_t p_size, fd->cache[size]->descent = p_descent; } -double TextServerAdvanced::font_get_descent(const RID &p_font_rid, int64_t p_size) const { +double TextServerAdvanced::_font_get_descent(const RID &p_font_rid, int64_t p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -2339,7 +2320,7 @@ double TextServerAdvanced::font_get_descent(const RID &p_font_rid, int64_t p_siz } } -void TextServerAdvanced::font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) { +void TextServerAdvanced::_font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2350,7 +2331,7 @@ void TextServerAdvanced::font_set_underline_position(const RID &p_font_rid, int6 fd->cache[size]->underline_position = p_underline_position; } -double TextServerAdvanced::font_get_underline_position(const RID &p_font_rid, int64_t p_size) const { +double TextServerAdvanced::_font_get_underline_position(const RID &p_font_rid, int64_t p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -2366,7 +2347,7 @@ double TextServerAdvanced::font_get_underline_position(const RID &p_font_rid, in } } -void TextServerAdvanced::font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) { +void TextServerAdvanced::_font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2377,7 +2358,7 @@ void TextServerAdvanced::font_set_underline_thickness(const RID &p_font_rid, int fd->cache[size]->underline_thickness = p_underline_thickness; } -double TextServerAdvanced::font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const { +double TextServerAdvanced::_font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -2393,7 +2374,7 @@ double TextServerAdvanced::font_get_underline_thickness(const RID &p_font_rid, i } } -void TextServerAdvanced::font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) { +void TextServerAdvanced::_font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2409,7 +2390,7 @@ void TextServerAdvanced::font_set_scale(const RID &p_font_rid, int64_t p_size, d fd->cache[size]->scale = p_scale; } -double TextServerAdvanced::font_get_scale(const RID &p_font_rid, int64_t p_size) const { +double TextServerAdvanced::_font_get_scale(const RID &p_font_rid, int64_t p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.0); @@ -2425,7 +2406,7 @@ double TextServerAdvanced::font_get_scale(const RID &p_font_rid, int64_t p_size) } } -int64_t TextServerAdvanced::font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const { +int64_t TextServerAdvanced::_font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); @@ -2437,7 +2418,7 @@ int64_t TextServerAdvanced::font_get_texture_count(const RID &p_font_rid, const return fd->cache[size]->textures.size(); } -void TextServerAdvanced::font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) { +void TextServerAdvanced::_font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2447,7 +2428,7 @@ void TextServerAdvanced::font_clear_textures(const RID &p_font_rid, const Vector fd->cache[size]->textures.clear(); } -void TextServerAdvanced::font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) { +void TextServerAdvanced::_font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2459,7 +2440,7 @@ void TextServerAdvanced::font_remove_texture(const RID &p_font_rid, const Vector fd->cache[size]->textures.remove_at(p_texture_index); } -void TextServerAdvanced::font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) { +void TextServerAdvanced::_font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); ERR_FAIL_COND(p_image.is_null()); @@ -2472,16 +2453,14 @@ void TextServerAdvanced::font_set_texture_image(const RID &p_font_rid, const Vec fd->cache[size]->textures.resize(p_texture_index + 1); } - FontTexture &tex = fd->cache[size]->textures.write[p_texture_index]; + ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index]; tex.imgdata = p_image->get_data(); tex.texture_w = p_image->get_width(); tex.texture_h = p_image->get_height(); tex.format = p_image->get_format(); - Ref<Image> img; - img.instantiate(); - img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); if (fd->mipmaps) { img->generate_mipmaps(); } @@ -2490,7 +2469,7 @@ void TextServerAdvanced::font_set_texture_image(const RID &p_font_rid, const Vec tex.dirty = false; } -Ref<Image> TextServerAdvanced::font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const { +Ref<Image> TextServerAdvanced::_font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Ref<Image>()); @@ -2499,15 +2478,12 @@ Ref<Image> TextServerAdvanced::font_get_texture_image(const RID &p_font_rid, con ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Ref<Image>()); ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>()); - const FontTexture &tex = fd->cache[size]->textures[p_texture_index]; - Ref<Image> img; - img.instantiate(); - img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); - - return img; + const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index]; + return Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); } -void TextServerAdvanced::font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) { +void TextServerAdvanced::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offsets) { + ERR_FAIL_COND(p_offsets.size() % 4 != 0); FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2519,11 +2495,14 @@ void TextServerAdvanced::font_set_texture_offsets(const RID &p_font_rid, const V fd->cache[size]->textures.resize(p_texture_index + 1); } - FontTexture &tex = fd->cache[size]->textures.write[p_texture_index]; - tex.offsets = p_offset; + ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index]; + tex.shelves.clear(); + for (int32_t i = 0; i < p_offsets.size(); i += 4) { + tex.shelves.push_back(Shelf(p_offsets[i], p_offsets[i + 1], p_offsets[i + 2], p_offsets[i + 3])); + } } -PackedInt32Array TextServerAdvanced::font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const { +PackedInt32Array TextServerAdvanced::_font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, PackedInt32Array()); @@ -2532,11 +2511,23 @@ PackedInt32Array TextServerAdvanced::font_get_texture_offsets(const RID &p_font_ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array()); ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), PackedInt32Array()); - const FontTexture &tex = fd->cache[size]->textures[p_texture_index]; - return tex.offsets; + const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index]; + PackedInt32Array ret; + ret.resize(tex.shelves.size() * 4); + + int32_t *wr = ret.ptrw(); + int32_t i = 0; + for (const Shelf &E : tex.shelves) { + wr[i * 4] = E.x; + wr[i * 4 + 1] = E.y; + wr[i * 4 + 2] = E.w; + wr[i * 4 + 3] = E.h; + i++; + } + return ret; } -PackedInt32Array TextServerAdvanced::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const { +PackedInt32Array TextServerAdvanced::_font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, PackedInt32Array()); @@ -2552,7 +2543,7 @@ PackedInt32Array TextServerAdvanced::font_get_glyph_list(const RID &p_font_rid, return ret; } -void TextServerAdvanced::font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) { +void TextServerAdvanced::_font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2563,7 +2554,7 @@ void TextServerAdvanced::font_clear_glyphs(const RID &p_font_rid, const Vector2i fd->cache[size]->glyph_map.clear(); } -void TextServerAdvanced::font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) { +void TextServerAdvanced::_font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2588,7 +2579,7 @@ double TextServerAdvanced::_get_extra_advance(RID p_font_rid, int p_font_size) c } } -Vector2 TextServerAdvanced::font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const { +Vector2 TextServerAdvanced::_font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -2616,16 +2607,17 @@ Vector2 TextServerAdvanced::font_get_glyph_advance(const RID &p_font_rid, int64_ ea.x = fd->embolden * double(size.x) / 64.0; } + double scale = _font_get_scale(p_font_rid, p_size); if (fd->msdf) { return (gl[p_glyph | mod].advance + ea) * (double)p_size / (double)fd->msdf_source_size; - } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_DISABLED) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x > SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { + } else if ((scale == 1.0) && ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_DISABLED) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x > SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE))) { return (gl[p_glyph | mod].advance + ea).round(); } else { return gl[p_glyph | mod].advance + ea; } } -void TextServerAdvanced::font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) { +void TextServerAdvanced::_font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2640,7 +2632,7 @@ void TextServerAdvanced::font_set_glyph_advance(const RID &p_font_rid, int64_t p gl[p_glyph].found = true; } -Vector2 TextServerAdvanced::font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +Vector2 TextServerAdvanced::_font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -2670,7 +2662,7 @@ Vector2 TextServerAdvanced::font_get_glyph_offset(const RID &p_font_rid, const V } } -void TextServerAdvanced::font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) { +void TextServerAdvanced::_font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2685,7 +2677,7 @@ void TextServerAdvanced::font_set_glyph_offset(const RID &p_font_rid, const Vect gl[p_glyph].found = true; } -Vector2 TextServerAdvanced::font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +Vector2 TextServerAdvanced::_font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -2715,7 +2707,7 @@ Vector2 TextServerAdvanced::font_get_glyph_size(const RID &p_font_rid, const Vec } } -void TextServerAdvanced::font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) { +void TextServerAdvanced::_font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2730,7 +2722,7 @@ void TextServerAdvanced::font_set_glyph_size(const RID &p_font_rid, const Vector gl[p_glyph].found = true; } -Rect2 TextServerAdvanced::font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +Rect2 TextServerAdvanced::_font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Rect2()); @@ -2755,7 +2747,7 @@ Rect2 TextServerAdvanced::font_get_glyph_uv_rect(const RID &p_font_rid, const Ve return gl[p_glyph | mod].uv_rect; } -void TextServerAdvanced::font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) { +void TextServerAdvanced::_font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2770,7 +2762,7 @@ void TextServerAdvanced::font_set_glyph_uv_rect(const RID &p_font_rid, const Vec gl[p_glyph].found = true; } -int64_t TextServerAdvanced::font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +int64_t TextServerAdvanced::_font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, -1); @@ -2795,7 +2787,7 @@ int64_t TextServerAdvanced::font_get_glyph_texture_idx(const RID &p_font_rid, co return gl[p_glyph | mod].texture_idx; } -void TextServerAdvanced::font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) { +void TextServerAdvanced::_font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2810,7 +2802,7 @@ void TextServerAdvanced::font_set_glyph_texture_idx(const RID &p_font_rid, const gl[p_glyph].found = true; } -RID TextServerAdvanced::font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +RID TextServerAdvanced::_font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, RID()); @@ -2837,10 +2829,8 @@ RID TextServerAdvanced::font_get_glyph_texture_rid(const RID &p_font_rid, const if (RenderingServer::get_singleton() != nullptr) { if (gl[p_glyph | mod].texture_idx != -1) { if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) { - FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx]; - Ref<Image> img; - img.instantiate(); - img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx]; + Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); if (fd->mipmaps) { img->generate_mipmaps(); } @@ -2858,7 +2848,7 @@ RID TextServerAdvanced::font_get_glyph_texture_rid(const RID &p_font_rid, const return RID(); } -Size2 TextServerAdvanced::font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { +Size2 TextServerAdvanced::_font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Size2()); @@ -2885,10 +2875,8 @@ Size2 TextServerAdvanced::font_get_glyph_texture_size(const RID &p_font_rid, con if (RenderingServer::get_singleton() != nullptr) { if (gl[p_glyph | mod].texture_idx != -1) { if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) { - FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx]; - Ref<Image> img; - img.instantiate(); - img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx]; + Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); if (fd->mipmaps) { img->generate_mipmaps(); } @@ -2906,7 +2894,7 @@ Size2 TextServerAdvanced::font_get_glyph_texture_size(const RID &p_font_rid, con return Size2(); } -Dictionary TextServerAdvanced::font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const { +Dictionary TextServerAdvanced::_font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -2956,7 +2944,7 @@ Dictionary TextServerAdvanced::font_get_glyph_contours(const RID &p_font_rid, in #endif } -TypedArray<Vector2i> TextServerAdvanced::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const { +TypedArray<Vector2i> TextServerAdvanced::_font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>()); @@ -2972,7 +2960,7 @@ TypedArray<Vector2i> TextServerAdvanced::font_get_kerning_list(const RID &p_font return ret; } -void TextServerAdvanced::font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) { +void TextServerAdvanced::_font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2983,7 +2971,7 @@ void TextServerAdvanced::font_clear_kerning_map(const RID &p_font_rid, int64_t p fd->cache[size]->kerning_map.clear(); } -void TextServerAdvanced::font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) { +void TextServerAdvanced::_font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -2994,7 +2982,7 @@ void TextServerAdvanced::font_remove_kerning(const RID &p_font_rid, int64_t p_si fd->cache[size]->kerning_map.erase(p_glyph_pair); } -void TextServerAdvanced::font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) { +void TextServerAdvanced::_font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3005,7 +2993,7 @@ void TextServerAdvanced::font_set_kerning(const RID &p_font_rid, int64_t p_size, fd->cache[size]->kerning_map[p_glyph_pair] = p_kerning; } -Vector2 TextServerAdvanced::font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const { +Vector2 TextServerAdvanced::_font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); @@ -3038,7 +3026,7 @@ Vector2 TextServerAdvanced::font_get_kerning(const RID &p_font_rid, int64_t p_si return Vector2(); } -int64_t TextServerAdvanced::font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const { +int64_t TextServerAdvanced::_font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), 0, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + "."); @@ -3063,7 +3051,7 @@ int64_t TextServerAdvanced::font_get_glyph_index(const RID &p_font_rid, int64_t #endif } -bool TextServerAdvanced::font_has_char(const RID &p_font_rid, int64_t p_char) const { +bool TextServerAdvanced::_font_has_char(const RID &p_font_rid, int64_t p_char) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), false, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + "."); if (!fd) { @@ -3084,7 +3072,7 @@ bool TextServerAdvanced::font_has_char(const RID &p_font_rid, int64_t p_char) co return (at_size) ? at_size->glyph_map.has((int32_t)p_char) : false; } -String TextServerAdvanced::font_get_supported_chars(const RID &p_font_rid) const { +String TextServerAdvanced::_font_get_supported_chars(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, String()); @@ -3117,7 +3105,7 @@ String TextServerAdvanced::font_get_supported_chars(const RID &p_font_rid) const return chars; } -void TextServerAdvanced::font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) { +void TextServerAdvanced::_font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); ERR_FAIL_COND_MSG((p_start >= 0xd800 && p_start <= 0xdfff) || (p_start > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_start, 16) + "."); @@ -3152,7 +3140,7 @@ void TextServerAdvanced::font_render_range(const RID &p_font_rid, const Vector2i } } -void TextServerAdvanced::font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) { +void TextServerAdvanced::_font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3183,7 +3171,7 @@ void TextServerAdvanced::font_render_glyph(const RID &p_font_rid, const Vector2i #endif } -void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { +void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3232,10 +3220,8 @@ void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_can #endif if (RenderingServer::get_singleton() != nullptr) { if (fd->cache[size]->textures[gl.texture_idx].dirty) { - FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; - Ref<Image> img; - img.instantiate(); - img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; + Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); if (fd->mipmaps) { img->generate_mipmaps(); } @@ -3253,13 +3239,15 @@ void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_can Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size; RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range); } else { + double scale = _font_get_scale(p_font_rid, p_size); Point2 cpos = p_pos; - cpos.y = Math::floor(cpos.y); if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { - cpos.x = ((int)Math::floor(cpos.x + 0.125)); + cpos.x = cpos.x + 0.125; } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { - cpos.x = ((int)Math::floor(cpos.x + 0.25)); - } else { + cpos.x = cpos.x + 0.25; + } + if (scale == 1.0) { + cpos.y = Math::floor(cpos.y); cpos.x = Math::floor(cpos.x); } cpos += gl.rect.position; @@ -3275,7 +3263,7 @@ void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_can } } -void TextServerAdvanced::font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { +void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3324,10 +3312,8 @@ void TextServerAdvanced::font_draw_glyph_outline(const RID &p_font_rid, const RI #endif if (RenderingServer::get_singleton() != nullptr) { if (fd->cache[size]->textures[gl.texture_idx].dirty) { - FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; - Ref<Image> img; - img.instantiate(); - img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); + ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx]; + Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata); if (fd->mipmaps) { img->generate_mipmaps(); } @@ -3346,12 +3332,14 @@ void TextServerAdvanced::font_draw_glyph_outline(const RID &p_font_rid, const RI RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range); } else { Point2 cpos = p_pos; - cpos.y = Math::floor(cpos.y); + double scale = _font_get_scale(p_font_rid, p_size); if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) { - cpos.x = ((int)Math::floor(cpos.x + 0.125)); + cpos.x = cpos.x + 0.125; } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) { - cpos.x = ((int)Math::floor(cpos.x + 0.25)); - } else { + cpos.x = cpos.x + 0.25; + } + if (scale == 1.0) { + cpos.y = Math::floor(cpos.y); cpos.x = Math::floor(cpos.x); } cpos += gl.rect.position; @@ -3367,7 +3355,7 @@ void TextServerAdvanced::font_draw_glyph_outline(const RID &p_font_rid, const RI } } -bool TextServerAdvanced::font_is_language_supported(const RID &p_font_rid, const String &p_language) const { +bool TextServerAdvanced::_font_is_language_supported(const RID &p_font_rid, const String &p_language) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -3379,7 +3367,7 @@ bool TextServerAdvanced::font_is_language_supported(const RID &p_font_rid, const } } -void TextServerAdvanced::font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) { +void TextServerAdvanced::_font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3387,7 +3375,7 @@ void TextServerAdvanced::font_set_language_support_override(const RID &p_font_ri fd->language_support_overrides[p_language] = p_supported; } -bool TextServerAdvanced::font_get_language_support_override(const RID &p_font_rid, const String &p_language) { +bool TextServerAdvanced::_font_get_language_support_override(const RID &p_font_rid, const String &p_language) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -3395,7 +3383,7 @@ bool TextServerAdvanced::font_get_language_support_override(const RID &p_font_ri return fd->language_support_overrides[p_language]; } -void TextServerAdvanced::font_remove_language_support_override(const RID &p_font_rid, const String &p_language) { +void TextServerAdvanced::_font_remove_language_support_override(const RID &p_font_rid, const String &p_language) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3403,7 +3391,7 @@ void TextServerAdvanced::font_remove_language_support_override(const RID &p_font fd->language_support_overrides.erase(p_language); } -PackedStringArray TextServerAdvanced::font_get_language_support_overrides(const RID &p_font_rid) { +PackedStringArray TextServerAdvanced::_font_get_language_support_overrides(const RID &p_font_rid) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, PackedStringArray()); @@ -3415,7 +3403,7 @@ PackedStringArray TextServerAdvanced::font_get_language_support_overrides(const return out; } -bool TextServerAdvanced::font_is_script_supported(const RID &p_font_rid, const String &p_script) const { +bool TextServerAdvanced::_font_is_script_supported(const RID &p_font_rid, const String &p_script) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -3429,7 +3417,7 @@ bool TextServerAdvanced::font_is_script_supported(const RID &p_font_rid, const S } } -void TextServerAdvanced::font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) { +void TextServerAdvanced::_font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3437,7 +3425,7 @@ void TextServerAdvanced::font_set_script_support_override(const RID &p_font_rid, fd->script_support_overrides[p_script] = p_supported; } -bool TextServerAdvanced::font_get_script_support_override(const RID &p_font_rid, const String &p_script) { +bool TextServerAdvanced::_font_get_script_support_override(const RID &p_font_rid, const String &p_script) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); @@ -3445,7 +3433,7 @@ bool TextServerAdvanced::font_get_script_support_override(const RID &p_font_rid, return fd->script_support_overrides[p_script]; } -void TextServerAdvanced::font_remove_script_support_override(const RID &p_font_rid, const String &p_script) { +void TextServerAdvanced::_font_remove_script_support_override(const RID &p_font_rid, const String &p_script) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3453,7 +3441,7 @@ void TextServerAdvanced::font_remove_script_support_override(const RID &p_font_r fd->script_support_overrides.erase(p_script); } -PackedStringArray TextServerAdvanced::font_get_script_support_overrides(const RID &p_font_rid) { +PackedStringArray TextServerAdvanced::_font_get_script_support_overrides(const RID &p_font_rid) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, PackedStringArray()); @@ -3465,7 +3453,7 @@ PackedStringArray TextServerAdvanced::font_get_script_support_overrides(const RI return out; } -void TextServerAdvanced::font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) { +void TextServerAdvanced::_font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); @@ -3475,7 +3463,7 @@ void TextServerAdvanced::font_set_opentype_feature_overrides(const RID &p_font_r fd->feature_overrides = p_overrides; } -Dictionary TextServerAdvanced::font_get_opentype_feature_overrides(const RID &p_font_rid) const { +Dictionary TextServerAdvanced::_font_get_opentype_feature_overrides(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -3483,7 +3471,7 @@ Dictionary TextServerAdvanced::font_get_opentype_feature_overrides(const RID &p_ return fd->feature_overrides; } -Dictionary TextServerAdvanced::font_supported_feature_list(const RID &p_font_rid) const { +Dictionary TextServerAdvanced::_font_supported_feature_list(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -3493,7 +3481,7 @@ Dictionary TextServerAdvanced::font_supported_feature_list(const RID &p_font_rid return fd->supported_features; } -Dictionary TextServerAdvanced::font_supported_variation_list(const RID &p_font_rid) const { +Dictionary TextServerAdvanced::_font_supported_variation_list(const RID &p_font_rid) const { FontAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); @@ -3503,11 +3491,11 @@ Dictionary TextServerAdvanced::font_supported_variation_list(const RID &p_font_r return fd->supported_varaitions; } -double TextServerAdvanced::font_get_global_oversampling() const { +double TextServerAdvanced::_font_get_global_oversampling() const { return oversampling; } -void TextServerAdvanced::font_set_global_oversampling(double p_oversampling) { +void TextServerAdvanced::_font_set_global_oversampling(double p_oversampling) { _THREAD_SAFE_METHOD_ if (oversampling != p_oversampling) { oversampling = p_oversampling; @@ -3515,8 +3503,8 @@ void TextServerAdvanced::font_set_global_oversampling(double p_oversampling) { font_owner.get_owned_list(&fonts); bool font_cleared = false; for (const RID &E : fonts) { - if (!font_is_multichannel_signed_distance_field(E) && font_get_oversampling(E) <= 0) { - font_clear_size_cache(E); + if (!_font_is_multichannel_signed_distance_field(E) && _font_get_oversampling(E) <= 0) { + _font_clear_size_cache(E); font_cleared = true; } } @@ -3625,7 +3613,7 @@ void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) { p_shaped->parent = RID(); } -RID TextServerAdvanced::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) { +RID TextServerAdvanced::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) { _THREAD_SAFE_METHOD_ ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced); @@ -3635,7 +3623,7 @@ RID TextServerAdvanced::create_shaped_text(TextServer::Direction p_direction, Te return shaped_owner.make_rid(sd); } -void TextServerAdvanced::shaped_text_clear(const RID &p_shaped) { +void TextServerAdvanced::_shaped_text_clear(const RID &p_shaped) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3650,7 +3638,7 @@ void TextServerAdvanced::shaped_text_clear(const RID &p_shaped) { invalidate(sd, true); } -void TextServerAdvanced::shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) { +void TextServerAdvanced::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3664,7 +3652,7 @@ void TextServerAdvanced::shaped_text_set_direction(const RID &p_shaped, TextServ } } -TextServer::Direction TextServerAdvanced::shaped_text_get_direction(const RID &p_shaped) const { +TextServer::Direction TextServerAdvanced::_shaped_text_get_direction(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, TextServer::DIRECTION_LTR); @@ -3672,7 +3660,7 @@ TextServer::Direction TextServerAdvanced::shaped_text_get_direction(const RID &p return sd->direction; } -TextServer::Direction TextServerAdvanced::shaped_text_get_inferred_direction(const RID &p_shaped) const { +TextServer::Direction TextServerAdvanced::_shaped_text_get_inferred_direction(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, TextServer::DIRECTION_LTR); @@ -3680,7 +3668,7 @@ TextServer::Direction TextServerAdvanced::shaped_text_get_inferred_direction(con return sd->para_direction; } -void TextServerAdvanced::shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) { +void TextServerAdvanced::_shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) { _THREAD_SAFE_METHOD_ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3694,14 +3682,14 @@ void TextServerAdvanced::shaped_text_set_custom_punctuation(const RID &p_shaped, } } -String TextServerAdvanced::shaped_text_get_custom_punctuation(const RID &p_shaped) const { +String TextServerAdvanced::_shaped_text_get_custom_punctuation(const RID &p_shaped) const { _THREAD_SAFE_METHOD_ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, String()); return sd->custom_punct; } -void TextServerAdvanced::shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) { +void TextServerAdvanced::_shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3718,7 +3706,7 @@ void TextServerAdvanced::shaped_text_set_bidi_override(const RID &p_shaped, cons invalidate(sd, false); } -void TextServerAdvanced::shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) { +void TextServerAdvanced::_shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3732,7 +3720,7 @@ void TextServerAdvanced::shaped_text_set_orientation(const RID &p_shaped, TextSe } } -void TextServerAdvanced::shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) { +void TextServerAdvanced::_shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3744,7 +3732,7 @@ void TextServerAdvanced::shaped_text_set_preserve_invalid(const RID &p_shaped, b } } -bool TextServerAdvanced::shaped_text_get_preserve_invalid(const RID &p_shaped) const { +bool TextServerAdvanced::_shaped_text_get_preserve_invalid(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -3752,7 +3740,7 @@ bool TextServerAdvanced::shaped_text_get_preserve_invalid(const RID &p_shaped) c return sd->preserve_invalid; } -void TextServerAdvanced::shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) { +void TextServerAdvanced::_shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3766,7 +3754,7 @@ void TextServerAdvanced::shaped_text_set_preserve_control(const RID &p_shaped, b } } -bool TextServerAdvanced::shaped_text_get_preserve_control(const RID &p_shaped) const { +bool TextServerAdvanced::_shaped_text_get_preserve_control(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -3774,7 +3762,7 @@ bool TextServerAdvanced::shaped_text_get_preserve_control(const RID &p_shaped) c return sd->preserve_control; } -void TextServerAdvanced::shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) { +void TextServerAdvanced::_shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) { ERR_FAIL_INDEX((int)p_spacing, 4); ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); @@ -3789,7 +3777,7 @@ void TextServerAdvanced::shaped_text_set_spacing(const RID &p_shaped, SpacingTyp } } -int64_t TextServerAdvanced::shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const { +int64_t TextServerAdvanced::_shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const { ERR_FAIL_INDEX_V((int)p_spacing, 4, 0); const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); @@ -3799,7 +3787,7 @@ int64_t TextServerAdvanced::shaped_text_get_spacing(const RID &p_shaped, Spacing return sd->extra_spacing[p_spacing]; } -TextServer::Orientation TextServerAdvanced::shaped_text_get_orientation(const RID &p_shaped) const { +TextServer::Orientation TextServerAdvanced::_shaped_text_get_orientation(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, TextServer::ORIENTATION_HORIZONTAL); @@ -3807,20 +3795,20 @@ TextServer::Orientation TextServerAdvanced::shaped_text_get_orientation(const RI return sd->orientation; } -int64_t TextServerAdvanced::shaped_get_span_count(const RID &p_shaped) const { +int64_t TextServerAdvanced::_shaped_get_span_count(const RID &p_shaped) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0); return sd->spans.size(); } -Variant TextServerAdvanced::shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const { +Variant TextServerAdvanced::_shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Variant()); ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant()); return sd->spans[p_index].meta; } -void TextServerAdvanced::shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) { +void TextServerAdvanced::_shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); ERR_FAIL_INDEX(p_index, sd->spans.size()); @@ -3833,7 +3821,7 @@ void TextServerAdvanced::shaped_set_span_update_font(const RID &p_shaped, int64_ invalidate(sd, false); } -bool TextServerAdvanced::shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) { +bool TextServerAdvanced::_shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); ERR_FAIL_COND_V(p_size <= 0, false); @@ -3868,7 +3856,7 @@ bool TextServerAdvanced::shaped_text_add_string(const RID &p_shaped, const Strin return true; } -bool TextServerAdvanced::shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length) { +bool TextServerAdvanced::_shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length) { _THREAD_SAFE_METHOD_ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -3898,7 +3886,7 @@ bool TextServerAdvanced::shaped_text_add_object(const RID &p_shaped, const Varia return true; } -bool TextServerAdvanced::shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align) { +bool TextServerAdvanced::_shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -3939,14 +3927,14 @@ bool TextServerAdvanced::shaped_text_resize_object(const RID &p_shaped, const Va } else { if (gl.font_rid.is_valid()) { if (sd->orientation == ORIENTATION_HORIZONTAL) { - sd->ascent = MAX(sd->ascent, MAX(font_get_ascent(gl.font_rid, gl.font_size), -gl.y_off)); - sd->descent = MAX(sd->descent, MAX(font_get_descent(gl.font_rid, gl.font_size), gl.y_off)); + sd->ascent = MAX(sd->ascent, MAX(_font_get_ascent(gl.font_rid, gl.font_size), -gl.y_off)); + sd->descent = MAX(sd->descent, MAX(_font_get_descent(gl.font_rid, gl.font_size), gl.y_off)); } else { - sd->ascent = MAX(sd->ascent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); - sd->descent = MAX(sd->descent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); + sd->ascent = MAX(sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); + sd->descent = MAX(sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); } - sd->upos = MAX(sd->upos, font_get_underline_position(gl.font_rid, gl.font_size)); - sd->uthk = MAX(sd->uthk, font_get_underline_thickness(gl.font_rid, gl.font_size)); + sd->upos = MAX(sd->upos, _font_get_underline_position(gl.font_rid, gl.font_size)); + sd->uthk = MAX(sd->uthk, _font_get_underline_thickness(gl.font_rid, gl.font_size)); } else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) { // Glyph not found, replace with hex code box. if (sd->orientation == ORIENTATION_HORIZONTAL) { @@ -4033,7 +4021,7 @@ void TextServerAdvanced::_realign(ShapedTextDataAdvanced *p_sd) const { p_sd->descent = full_descent; } -RID TextServerAdvanced::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const { +RID TextServerAdvanced::_shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const { _THREAD_SAFE_METHOD_ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); @@ -4041,10 +4029,10 @@ RID TextServerAdvanced::shaped_text_substr(const RID &p_shaped, int64_t p_start, MutexLock lock(sd->mutex); if (sd->parent != RID()) { - return shaped_text_substr(sd->parent, p_start, p_length); + return _shaped_text_substr(sd->parent, p_start, p_length); } if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } ERR_FAIL_COND_V(p_start < 0 || p_length < 0, RID()); ERR_FAIL_COND_V(sd->start > p_start || sd->end < p_start, RID()); @@ -4148,11 +4136,11 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S } else { if (gl.font_rid.is_valid()) { if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) { - p_new_sd->ascent = MAX(p_new_sd->ascent, MAX(font_get_ascent(gl.font_rid, gl.font_size), -gl.y_off)); - p_new_sd->descent = MAX(p_new_sd->descent, MAX(font_get_descent(gl.font_rid, gl.font_size), gl.y_off)); + p_new_sd->ascent = MAX(p_new_sd->ascent, MAX(_font_get_ascent(gl.font_rid, gl.font_size), -gl.y_off)); + p_new_sd->descent = MAX(p_new_sd->descent, MAX(_font_get_descent(gl.font_rid, gl.font_size), gl.y_off)); } else { - p_new_sd->ascent = MAX(p_new_sd->ascent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); - p_new_sd->descent = MAX(p_new_sd->descent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); + p_new_sd->ascent = MAX(p_new_sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); + p_new_sd->descent = MAX(p_new_sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); } } else if (p_new_sd->preserve_invalid || (p_new_sd->preserve_control && is_control(gl.index))) { // Glyph not found, replace with hex code box. @@ -4178,7 +4166,7 @@ bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const S return true; } -RID TextServerAdvanced::shaped_text_get_parent(const RID &p_shaped) const { +RID TextServerAdvanced::_shaped_text_get_parent(const RID &p_shaped) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, RID()); @@ -4186,16 +4174,16 @@ RID TextServerAdvanced::shaped_text_get_parent(const RID &p_shaped) const { return sd->parent; } -double TextServerAdvanced::shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<TextServer::JustificationFlag> p_jst_flags) { +double TextServerAdvanced::_shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<TextServer::JustificationFlag> p_jst_flags) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } if (!sd->justification_ops_valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_update_justification_ops(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_update_justification_ops(p_shaped); } sd->fit_width_minimum_reached = false; @@ -4343,16 +4331,16 @@ double TextServerAdvanced::shaped_text_fit_to_width(const RID &p_shaped, double return Math::ceil(justification_width); } -double TextServerAdvanced::shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) { +double TextServerAdvanced::_shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } if (!sd->line_breaks_valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_update_breaks(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_update_breaks(p_shaped); } for (int i = 0; i < p_tab_stops.size(); i++) { @@ -4399,13 +4387,13 @@ double TextServerAdvanced::shaped_text_tab_align(const RID &p_shaped, const Pack return 0.0; } -void TextServerAdvanced::shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) { +void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped_line); ERR_FAIL_COND_MSG(!sd, "ShapedTextDataAdvanced invalid."); MutexLock lock(sd->mutex); if (!sd->valid) { - shaped_text_shape(p_shaped_line); + _shaped_text_shape(p_shaped_line); } sd->text_trimmed = false; @@ -4444,30 +4432,30 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(const RID &p_shaped_l // Find usable fonts, if fonts from the last glyph do not have required chars. RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; - if (!font_has_char(dot_gl_font_rid, '.')) { + if (!_font_has_char(dot_gl_font_rid, '.')) { const Array &fonts = spans[spans.size() - 1].fonts; for (int i = 0; i < fonts.size(); i++) { - if (font_has_char(fonts[i], '.')) { + if (_font_has_char(fonts[i], '.')) { dot_gl_font_rid = fonts[i]; break; } } } RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid; - if (!font_has_char(whitespace_gl_font_rid, '.')) { + if (!_font_has_char(whitespace_gl_font_rid, '.')) { const Array &fonts = spans[spans.size() - 1].fonts; for (int i = 0; i < fonts.size(); i++) { - if (font_has_char(fonts[i], ' ')) { + if (_font_has_char(fonts[i], ' ')) { whitespace_gl_font_rid = fonts[i]; break; } } } - int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, '.') : -10; - Vector2 dot_adv = dot_gl_font_rid.is_valid() ? font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2(); - int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ') : -10; - Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2(); + int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? _font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, '.', 0) : -10; + Vector2 dot_adv = dot_gl_font_rid.is_valid() ? _font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2(); + int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ', 0) : -10; + Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2(); int ellipsis_width = 0; if (add_ellipsis && whitespace_gl_font_rid.is_valid()) { @@ -4566,7 +4554,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(const RID &p_shaped_l } } -int64_t TextServerAdvanced::shaped_text_get_trim_pos(const RID &p_shaped) const { +int64_t TextServerAdvanced::_shaped_text_get_trim_pos(const RID &p_shaped) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid."); @@ -4574,7 +4562,7 @@ int64_t TextServerAdvanced::shaped_text_get_trim_pos(const RID &p_shaped) const return sd->overrun_trim_data.trim_pos; } -int64_t TextServerAdvanced::shaped_text_get_ellipsis_pos(const RID &p_shaped) const { +int64_t TextServerAdvanced::_shaped_text_get_ellipsis_pos(const RID &p_shaped) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid."); @@ -4582,7 +4570,7 @@ int64_t TextServerAdvanced::shaped_text_get_ellipsis_pos(const RID &p_shaped) co return sd->overrun_trim_data.ellipsis_pos; } -const Glyph *TextServerAdvanced::shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const { +const Glyph *TextServerAdvanced::_shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V_MSG(!sd, nullptr, "ShapedTextDataAdvanced invalid."); @@ -4590,7 +4578,7 @@ const Glyph *TextServerAdvanced::shaped_text_get_ellipsis_glyphs(const RID &p_sh return sd->overrun_trim_data.ellipsis_glyph_buf.ptr(); } -int64_t TextServerAdvanced::shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const { +int64_t TextServerAdvanced::_shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V_MSG(!sd, 0, "ShapedTextDataAdvanced invalid."); @@ -4598,13 +4586,13 @@ int64_t TextServerAdvanced::shaped_text_get_ellipsis_glyph_count(const RID &p_sh return sd->overrun_trim_data.ellipsis_glyph_buf.size(); } -bool TextServerAdvanced::shaped_text_update_breaks(const RID &p_shaped) { +bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); if (!sd->valid) { - shaped_text_shape(p_shaped); + _shaped_text_shape(p_shaped); } if (sd->line_breaks_valid) { @@ -4615,6 +4603,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(const RID &p_shaped) { if (!sd->break_ops_valid) { sd->breaks.clear(); + sd->break_inserts = 0; UErrorCode err = U_ZERO_ERROR; int i = 0; while (i < sd->spans.size()) { @@ -4643,6 +4632,12 @@ bool TextServerAdvanced::shaped_text_update_breaks(const RID &p_shaped) { sd->breaks[pos] = true; } else if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_SOFT) && (ubrk_getRuleStatus(bi) < UBRK_LINE_SOFT_LIMIT)) { sd->breaks[pos] = false; + + int pos_p = pos - 1 - sd->start; + char32_t c = sd->text[pos_p]; + if (pos - sd->start != sd->end && !is_whitespace(c) && (c != 0xfffc)) { + sd->break_inserts++; + } } } } @@ -4652,60 +4647,83 @@ bool TextServerAdvanced::shaped_text_update_breaks(const RID &p_shaped) { sd->break_ops_valid = true; } + Vector<Glyph> glyphs_new; + + bool rewrite = false; + int sd_shift = 0; + int sd_size = sd->glyphs.size(); + Glyph *sd_glyphs = sd->glyphs.ptrw(); + Glyph *sd_glyphs_new = nullptr; + + if (sd->break_inserts > 0) { + glyphs_new.resize(sd->glyphs.size() + sd->break_inserts); + sd_glyphs_new = glyphs_new.ptrw(); + rewrite = true; + } else { + sd_glyphs_new = sd_glyphs; + } + sd->sort_valid = false; sd->glyphs_logical.clear(); - int sd_size = sd->glyphs.size(); const char32_t *ch = sd->text.ptr(); - Glyph *sd_glyphs = sd->glyphs.ptrw(); int c_punct_size = sd->custom_punct.length(); const char32_t *c_punct = sd->custom_punct.ptr(); for (int i = 0; i < sd_size; i++) { + if (rewrite) { + for (int j = 0; j < sd_glyphs[i].count; j++) { + sd_glyphs_new[sd_shift + i + j] = sd_glyphs[i + j]; + } + } if (sd_glyphs[i].count > 0) { char32_t c = ch[sd_glyphs[i].start - sd->start]; if (c == 0xfffc) { + i += (sd_glyphs[i].count - 1); continue; } if (c == 0x0009 || c == 0x000b) { - sd_glyphs[i].flags |= GRAPHEME_IS_TAB; + sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_TAB; } if (is_whitespace(c)) { - sd_glyphs[i].flags |= GRAPHEME_IS_SPACE; + sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_SPACE; } if (c_punct_size == 0) { if (u_ispunct(c) && c != 0x005f) { - sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; + sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_PUNCTUATION; } } else { for (int j = 0; j < c_punct_size; j++) { if (c_punct[j] == c) { - sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; + sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_PUNCTUATION; break; } } } if (is_underscore(c)) { - sd_glyphs[i].flags |= GRAPHEME_IS_UNDERSCORE; + sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_UNDERSCORE; } if (sd->breaks.has(sd_glyphs[i].end)) { if (sd->breaks[sd_glyphs[i].end] && (is_linebreak(c))) { - sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD; + sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_BREAK_HARD; } else if (is_whitespace(c)) { - sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT; + sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_BREAK_SOFT; } else { int count = sd_glyphs[i].count; // Do not add extra space at the end of the line. if (sd_glyphs[i].end == sd->end) { + i += (sd_glyphs[i].count - 1); continue; } // Do not add extra space after existing space. if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) { if ((i + count < sd_size - 1) && ((sd_glyphs[i + count].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) { + i += (sd_glyphs[i].count - 1); continue; } } else { - if ((i > 0) && ((sd_glyphs[i - 1].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) { + if ((sd_glyphs[i].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) { + i += (sd_glyphs[i].count - 1); continue; } } @@ -4718,22 +4736,25 @@ bool TextServerAdvanced::shaped_text_update_breaks(const RID &p_shaped) { gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | GRAPHEME_IS_SPACE; if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) { gl.flags |= GRAPHEME_IS_RTL; - sd->glyphs.insert(i, gl); // Insert before. + for (int j = sd_glyphs[i].count - 1; j >= 0; j--) { + sd_glyphs_new[sd_shift + i + j + 1] = sd_glyphs_new[sd_shift + i + j]; + } + sd_glyphs_new[sd_shift + i] = gl; } else { - sd->glyphs.insert(i + count, gl); // Insert after. + sd_glyphs_new[sd_shift + i + count] = gl; } - i += count; - - // Update write pointer and size. - sd_size = sd->glyphs.size(); - sd_glyphs = sd->glyphs.ptrw(); - continue; + sd_shift++; + ERR_FAIL_COND_V_MSG(sd_shift > sd->break_inserts, false, "Invalid break insert count!"); } } - i += (sd_glyphs[i].count - 1); } } + ERR_FAIL_COND_V_MSG(sd_shift != sd->break_inserts, false, "Invalid break insert count!"); + + if (sd->break_inserts > 0) { + sd->glyphs = glyphs_new; + } sd->line_breaks_valid = true; @@ -4815,16 +4836,16 @@ _FORCE_INLINE_ int64_t _generate_kashida_justification_opportunies(const String return kashida_pos; } -bool TextServerAdvanced::shaped_text_update_justification_ops(const RID &p_shaped) { +bool TextServerAdvanced::_shaped_text_update_justification_ops(const RID &p_shaped) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); if (!sd->valid) { - shaped_text_shape(p_shaped); + _shaped_text_shape(p_shaped); } if (!sd->line_breaks_valid) { - shaped_text_update_breaks(p_shaped); + _shaped_text_update_breaks(p_shaped); } if (sd->justification_ops_valid) { @@ -4969,7 +4990,8 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(const RID &p_shape Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, const RID &p_font, int64_t p_font_size) { hb_font_t *hb_font = _font_get_hb_handle(p_font, p_font_size); - bool subpos = (font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_HALF) || (font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_AUTO && p_font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE); + double scale = _font_get_scale(p_font, p_font_size); + bool subpos = (scale != 1.0) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_AUTO && p_font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE); ERR_FAIL_COND_V(hb_font == nullptr, Glyph()); hb_buffer_clear_contents(p_sd->hb_buffer); @@ -4995,25 +5017,24 @@ Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char gl.font_size = p_font_size; if (glyph_count > 0) { - double scale = font_get_scale(p_font, p_font_size); if (p_sd->orientation == ORIENTATION_HORIZONTAL) { if (subpos) { - gl.advance = glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size); + gl.advance = (double)glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size); } else { - gl.advance = Math::round(glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size)); + gl.advance = Math::round((double)glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size)); } } else { - gl.advance = -Math::round(glyph_pos[0].y_advance / (64.0 / scale)); + gl.advance = -Math::round((double)glyph_pos[0].y_advance / (64.0 / scale)); } gl.count = 1; gl.index = glyph_info[0].codepoint; if (subpos) { - gl.x_off = glyph_pos[0].x_offset / (64.0 / scale); + gl.x_off = (double)glyph_pos[0].x_offset / (64.0 / scale); } else { - gl.x_off = Math::round(glyph_pos[0].x_offset / (64.0 / scale)); + gl.x_off = Math::round((double)glyph_pos[0].x_offset / (64.0 / scale)); } - gl.y_off = -Math::round(glyph_pos[0].y_offset / (64.0 / scale)); + gl.y_off = -Math::round((double)glyph_pos[0].y_offset / (64.0 / scale)); if ((glyph_info[0].codepoint != 0) || !u_isgraph(p_char)) { gl.flags |= GRAPHEME_IS_VALID; @@ -5030,7 +5051,7 @@ _FORCE_INLINE_ void TextServerAdvanced::_add_featuers(const Dictionary &p_source if (value >= 0) { hb_feature_t feature; if (keys[i].get_type() == Variant::STRING) { - feature.tag = name_to_tag(keys[i]); + feature.tag = _name_to_tag(keys[i]); } else { feature.tag = keys[i]; } @@ -5063,6 +5084,8 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(fs, gl.index).y); } else { gl.advance = get_hex_code_box_size(fs, gl.index).y; + gl.y_off = get_hex_code_box_size(fs, gl.index).y; + gl.x_off = -Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5); p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5)); p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5)); } @@ -5081,12 +5104,12 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star Vector2i fss = _get_size(fd, fs); hb_font_t *hb_font = _font_get_hb_handle(f, fs); - double scale = font_get_scale(f, fs); + double scale = _font_get_scale(f, fs); double sp_sp = p_sd->extra_spacing[SPACING_SPACE]; double sp_gl = p_sd->extra_spacing[SPACING_GLYPH]; bool last_run = (p_sd->end == p_end); double ea = _get_extra_advance(f, fs); - bool subpos = (font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_HALF) || (font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_AUTO && fs <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE); + bool subpos = (scale != 1.0) || (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_AUTO && fs <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE); ERR_FAIL_COND(hb_font == nullptr); hb_buffer_clear_contents(p_sd->hb_buffer); @@ -5114,7 +5137,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star hb_buffer_add_utf32(p_sd->hb_buffer, (const uint32_t *)p_sd->text.ptr(), p_sd->text.length(), p_start, p_end - p_start); Vector<hb_feature_t> ftrs; - _add_featuers(font_get_opentype_feature_overrides(f), ftrs); + _add_featuers(_font_get_opentype_feature_overrides(f), ftrs); _add_featuers(p_sd->spans[p_span].features, ftrs); hb_shape(hb_font, p_sd->hb_buffer, ftrs.is_empty() ? nullptr : &ftrs[0], ftrs.size()); @@ -5187,19 +5210,19 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star _ensure_glyph(fd, fss, gl.index | mod); if (p_sd->orientation == ORIENTATION_HORIZONTAL) { if (subpos) { - gl.advance = glyph_pos[i].x_advance / (64.0 / scale) + ea; + gl.advance = (double)glyph_pos[i].x_advance / (64.0 / scale) + ea; } else { - gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / scale) + ea); + gl.advance = Math::round((double)glyph_pos[i].x_advance / (64.0 / scale) + ea); } } else { - gl.advance = -Math::round(glyph_pos[i].y_advance / (64.0 / scale)); + gl.advance = -Math::round((double)glyph_pos[i].y_advance / (64.0 / scale)); } if (subpos) { - gl.x_off = glyph_pos[i].x_offset / (64.0 / scale); + gl.x_off = (double)glyph_pos[i].x_offset / (64.0 / scale); } else { - gl.x_off = Math::round(glyph_pos[i].x_offset / (64.0 / scale)); + gl.x_off = Math::round((double)glyph_pos[i].x_offset / (64.0 / scale)); } - gl.y_off = -Math::round(glyph_pos[i].y_offset / (64.0 / scale)); + gl.y_off = -Math::round((double)glyph_pos[i].y_offset / (64.0 / scale)); } if (!last_run || i < glyph_count - 1) { // Do not add extra spacing to the last glyph of the string. @@ -5245,7 +5268,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star p_sd->ascent = MAX(p_sd->ascent, -w[i + j].y_off); p_sd->descent = MAX(p_sd->descent, w[i + j].y_off); } else { - double gla = Math::round(font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5); + double gla = Math::round(_font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5); p_sd->ascent = MAX(p_sd->ascent, gla); p_sd->descent = MAX(p_sd->descent, gla); } @@ -5268,14 +5291,14 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star if (failed_subrun_start != p_end + 1) { _shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1); } - p_sd->ascent = MAX(p_sd->ascent, font_get_ascent(f, fs)); - p_sd->descent = MAX(p_sd->descent, font_get_descent(f, fs)); - p_sd->upos = MAX(p_sd->upos, font_get_underline_position(f, fs)); - p_sd->uthk = MAX(p_sd->uthk, font_get_underline_thickness(f, fs)); + p_sd->ascent = MAX(p_sd->ascent, _font_get_ascent(f, fs)); + p_sd->descent = MAX(p_sd->descent, _font_get_descent(f, fs)); + p_sd->upos = MAX(p_sd->upos, _font_get_underline_position(f, fs)); + p_sd->uthk = MAX(p_sd->uthk, _font_get_underline_thickness(f, fs)); } } -bool TextServerAdvanced::shaped_text_shape(const RID &p_shaped) { +bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -5286,7 +5309,7 @@ bool TextServerAdvanced::shaped_text_shape(const RID &p_shaped) { invalidate(sd, false); if (sd->parent != RID()) { - shaped_text_shape(sd->parent); + _shaped_text_shape(sd->parent); ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent); ERR_FAIL_COND_V(!parent_sd->valid, false); ERR_FAIL_COND_V(!_shape_substr(sd, parent_sd, sd->start, sd->end - sd->start), false); @@ -5386,7 +5409,7 @@ bool TextServerAdvanced::shaped_text_shape(const RID &p_shaped) { int32_t script_run_end = MIN(sd->script_iter->script_ranges[j].end, bidi_run_end); char scr_buffer[5] = { 0, 0, 0, 0, 0 }; hb_tag_to_string(hb_script_to_iso15924_tag(sd->script_iter->script_ranges[j].script), scr_buffer); - String script = String(scr_buffer); + String script_code = String(scr_buffer); int spn_from = (is_rtl) ? 0 : sd->spans.size() - 1; int spn_to = (is_rtl) ? sd->spans.size() : -1; @@ -5426,8 +5449,8 @@ bool TextServerAdvanced::shaped_text_shape(const RID &p_shaped) { fonts.push_back(sd->spans[k].fonts[0]); } for (int l = 1; l < font_count; l++) { - if (font_is_script_supported(span.fonts[l], script)) { - if (font_is_language_supported(span.fonts[l], span.language)) { + if (_font_is_script_supported(span.fonts[l], script_code)) { + if (_font_is_language_supported(span.fonts[l], span.language)) { fonts.push_back(sd->spans[k].fonts[l]); } else { fonts_scr_only.push_back(sd->spans[k].fonts[l]); @@ -5451,7 +5474,7 @@ bool TextServerAdvanced::shaped_text_shape(const RID &p_shaped) { return sd->valid; } -bool TextServerAdvanced::shaped_text_is_ready(const RID &p_shaped) const { +bool TextServerAdvanced::_shaped_text_is_ready(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -5459,35 +5482,35 @@ bool TextServerAdvanced::shaped_text_is_ready(const RID &p_shaped) const { return sd->valid; } -const Glyph *TextServerAdvanced::shaped_text_get_glyphs(const RID &p_shaped) const { +const Glyph *TextServerAdvanced::_shaped_text_get_glyphs(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, nullptr); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->glyphs.ptr(); } -int64_t TextServerAdvanced::shaped_text_get_glyph_count(const RID &p_shaped) const { +int64_t TextServerAdvanced::_shaped_text_get_glyph_count(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->glyphs.size(); } -const Glyph *TextServerAdvanced::shaped_text_sort_logical(const RID &p_shaped) { +const Glyph *TextServerAdvanced::_shaped_text_sort_logical(const RID &p_shaped) { ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, nullptr); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } if (!sd->sort_valid) { @@ -5499,7 +5522,7 @@ const Glyph *TextServerAdvanced::shaped_text_sort_logical(const RID &p_shaped) { return sd->glyphs_logical.ptr(); } -Vector2i TextServerAdvanced::shaped_text_get_range(const RID &p_shaped) const { +Vector2i TextServerAdvanced::_shaped_text_get_range(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Vector2i()); @@ -5507,7 +5530,7 @@ Vector2i TextServerAdvanced::shaped_text_get_range(const RID &p_shaped) const { return Vector2(sd->start, sd->end); } -Array TextServerAdvanced::shaped_text_get_objects(const RID &p_shaped) const { +Array TextServerAdvanced::_shaped_text_get_objects(const RID &p_shaped) const { Array ret; const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, ret); @@ -5520,25 +5543,25 @@ Array TextServerAdvanced::shaped_text_get_objects(const RID &p_shaped) const { return ret; } -Rect2 TextServerAdvanced::shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const { +Rect2 TextServerAdvanced::_shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Rect2()); MutexLock lock(sd->mutex); ERR_FAIL_COND_V(!sd->objects.has(p_key), Rect2()); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->objects[p_key].rect; } -Size2 TextServerAdvanced::shaped_text_get_size(const RID &p_shaped) const { +Size2 TextServerAdvanced::_shaped_text_get_size(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Size2()); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) { return Size2((sd->text_trimmed ? sd->width_trimmed : sd->width), sd->ascent + sd->descent + sd->extra_spacing[SPACING_TOP] + sd->extra_spacing[SPACING_BOTTOM]).ceil(); @@ -5547,58 +5570,58 @@ Size2 TextServerAdvanced::shaped_text_get_size(const RID &p_shaped) const { } } -double TextServerAdvanced::shaped_text_get_ascent(const RID &p_shaped) const { +double TextServerAdvanced::_shaped_text_get_ascent(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->ascent + sd->extra_spacing[SPACING_TOP]; } -double TextServerAdvanced::shaped_text_get_descent(const RID &p_shaped) const { +double TextServerAdvanced::_shaped_text_get_descent(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->descent + sd->extra_spacing[SPACING_BOTTOM]; } -double TextServerAdvanced::shaped_text_get_width(const RID &p_shaped) const { +double TextServerAdvanced::_shaped_text_get_width(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return Math::ceil(sd->text_trimmed ? sd->width_trimmed : sd->width); } -double TextServerAdvanced::shaped_text_get_underline_position(const RID &p_shaped) const { +double TextServerAdvanced::_shaped_text_get_underline_position(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->upos; } -double TextServerAdvanced::shaped_text_get_underline_thickness(const RID &p_shaped) const { +double TextServerAdvanced::_shaped_text_get_underline_thickness(const RID &p_shaped) const { const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.0); MutexLock lock(sd->mutex); if (!sd->valid) { - const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped); } return sd->uthk; @@ -5779,7 +5802,7 @@ void TextServerAdvanced::_insert_num_systems_lang() { } } -String TextServerAdvanced::format_number(const String &p_string, const String &p_language) const { +String TextServerAdvanced::_format_number(const String &p_string, const String &p_language) const { const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; String res = p_string; @@ -5804,7 +5827,7 @@ String TextServerAdvanced::format_number(const String &p_string, const String &p return res; } -String TextServerAdvanced::parse_number(const String &p_string, const String &p_language) const { +String TextServerAdvanced::_parse_number(const String &p_string, const String &p_language) const { const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; String res = p_string; @@ -5832,7 +5855,7 @@ String TextServerAdvanced::parse_number(const String &p_string, const String &p_ return res; } -String TextServerAdvanced::percent_sign(const String &p_language) const { +String TextServerAdvanced::_percent_sign(const String &p_language) const { const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; for (int i = 0; i < num_systems.size(); i++) { @@ -5846,7 +5869,7 @@ String TextServerAdvanced::percent_sign(const String &p_language) const { return "%"; } -int64_t TextServerAdvanced::is_confusable(const String &p_string, const PackedStringArray &p_dict) const { +int64_t TextServerAdvanced::_is_confusable(const String &p_string, const PackedStringArray &p_dict) const { UErrorCode status = U_ZERO_ERROR; int64_t match_index = -1; @@ -5886,7 +5909,7 @@ int64_t TextServerAdvanced::is_confusable(const String &p_string, const PackedSt return match_index; } -bool TextServerAdvanced::spoof_check(const String &p_string) const { +bool TextServerAdvanced::_spoof_check(const String &p_string) const { UErrorCode status = U_ZERO_ERROR; Char16String utf16 = p_string.utf16(); @@ -5908,7 +5931,7 @@ bool TextServerAdvanced::spoof_check(const String &p_string) const { return (bitmask != 0); } -String TextServerAdvanced::strip_diacritics(const String &p_string) const { +String TextServerAdvanced::_strip_diacritics(const String &p_string) const { UErrorCode err = U_ZERO_ERROR; // Get NFKD normalizer singleton. @@ -5941,7 +5964,7 @@ String TextServerAdvanced::strip_diacritics(const String &p_string) const { return result; } -String TextServerAdvanced::string_to_upper(const String &p_string, const String &p_language) const { +String TextServerAdvanced::_string_to_upper(const String &p_string, const String &p_language) const { const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; // Convert to UTF-16. @@ -5960,7 +5983,7 @@ String TextServerAdvanced::string_to_upper(const String &p_string, const String return String::utf16(upper.ptr(), len); } -String TextServerAdvanced::string_to_lower(const String &p_string, const String &p_language) const { +String TextServerAdvanced::_string_to_lower(const String &p_string, const String &p_language) const { const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; // Convert to UTF-16. Char16String utf16 = p_string.utf16(); @@ -5978,7 +6001,7 @@ String TextServerAdvanced::string_to_lower(const String &p_string, const String return String::utf16(lower.ptr(), len); } -PackedInt32Array TextServerAdvanced::string_get_word_breaks(const String &p_string, const String &p_language) const { +PackedInt32Array TextServerAdvanced::_string_get_word_breaks(const String &p_string, const String &p_language) const { const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; // Convert to UTF-16. Char16String utf16 = p_string.utf16(); @@ -6026,7 +6049,7 @@ PackedInt32Array TextServerAdvanced::string_get_word_breaks(const String &p_stri return ret; } -bool TextServerAdvanced::is_valid_identifier(const String &p_string) const { +bool TextServerAdvanced::_is_valid_identifier(const String &p_string) const { enum UAX31SequenceStatus { SEQ_NOT_STARTED, SEQ_STARTED, @@ -6047,7 +6070,7 @@ bool TextServerAdvanced::is_valid_identifier(const String &p_string) const { if (U_FAILURE(err)) { return false; // Failed to load normalizer. } - bool isnurom = unorm2_isNormalized(norm_c, utf16.ptr(), utf16.length(), &err); + bool isnurom = unorm2_isNormalized(norm_c, utf16.get_data(), utf16.length(), &err); if (U_FAILURE(err) || !isnurom) { return false; // Do not conform to Normalization Form C. } diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index b9633a9b71..10fe3c2316 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -42,6 +42,7 @@ #include <godot_cpp/godot.hpp> #include <godot_cpp/core/class_db.hpp> +#include <godot_cpp/core/ext_wrappers.gen.inc> #include <godot_cpp/core/mutex_lock.hpp> #include <godot_cpp/variant/array.hpp> @@ -79,13 +80,15 @@ using namespace godot; #else // Headers for building as built-in module. +#include "servers/text/text_server_extension.h" + +#include "core/extension/ext_wrappers.gen.inc" #include "core/object/worker_thread_pool.h" #include "core/templates/hash_map.h" #include "core/templates/rid_owner.h" #include "scene/resources/texture.h" -#include "servers/text/text_server_extension.h" -#include "modules/modules_enabled.gen.h" // For freetype, msdfgen. +#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg. #endif @@ -114,6 +117,7 @@ using namespace godot; #include FT_ADVANCES_H #include FT_MULTIPLE_MASTERS_H #include FT_BBOX_H +#include FT_MODULE_H #include FT_CONFIG_OPTIONS_H #if !defined(FT_CONFIG_OPTION_USE_BROTLI) && !defined(_MSC_VER) #warning FreeType is configured without Brotli support, built-in fonts will not be available. @@ -165,20 +169,86 @@ class TextServerAdvanced : public TextServerExtension { const int rect_range = 1; - struct FontTexture { + struct FontTexturePosition { + int32_t index = -1; + int32_t x = 0; + int32_t y = 0; + + FontTexturePosition() {} + FontTexturePosition(int32_t p_id, int32_t p_x, int32_t p_y) : + index(p_id), x(p_x), y(p_y) {} + }; + + struct Shelf { + int32_t x = 0; + int32_t y = 0; + int32_t w = 0; + int32_t h = 0; + + FontTexturePosition alloc_shelf(int32_t p_id, int32_t p_w, int32_t p_h) { + if (p_w > w || p_h > h) { + return FontTexturePosition(-1, 0, 0); + } + int32_t xx = x; + x += p_w; + w -= p_w; + return FontTexturePosition(p_id, xx, y); + } + + Shelf() {} + Shelf(int32_t p_x, int32_t p_y, int32_t p_w, int32_t p_h) : + x(p_x), y(p_y), w(p_w), h(p_h) {} + }; + + struct ShelfPackTexture { + int32_t texture_w = 1024; + int32_t texture_h = 1024; + Image::Format format; PackedByteArray imgdata; - int texture_w = 0; - int texture_h = 0; - PackedInt32Array offsets; Ref<ImageTexture> texture; bool dirty = true; - }; - struct FontTexturePosition { - int index = 0; - int x = 0; - int y = 0; + List<Shelf> shelves; + + FontTexturePosition pack_rect(int32_t p_id, int32_t p_h, int32_t p_w) { + int32_t y = 0; + int32_t waste = 0; + Shelf *best_shelf = nullptr; + int32_t best_waste = std::numeric_limits<std::int32_t>::max(); + + for (Shelf &E : shelves) { + y += E.h; + if (p_w > E.w) { + continue; + } + if (p_h == E.h) { + return E.alloc_shelf(p_id, p_w, p_h); + } + if (p_h > E.h) { + continue; + } + if (p_h < E.h) { + waste = (E.h - p_h) * p_w; + if (waste < best_waste) { + best_waste = waste; + best_shelf = &E; + } + } + } + if (best_shelf) { + return best_shelf->alloc_shelf(p_id, p_w, p_h); + } + if (p_h <= (texture_h - y) && p_w <= texture_w) { + List<Shelf>::Element *E = shelves.push_back(Shelf(0, y, texture_w, p_h)); + return E->get().alloc_shelf(p_id, p_w, p_h); + } + return FontTexturePosition(-1, 0, 0); + } + + ShelfPackTexture() {} + ShelfPackTexture(int32_t p_w, int32_t p_h) : + texture_w(p_w), texture_h(p_h) {} }; struct FontGlyph { @@ -199,7 +269,7 @@ class TextServerAdvanced : public TextServerExtension { Vector2i size; - Vector<FontTexture> textures; + Vector<ShelfPackTexture> textures; HashMap<int32_t, FontGlyph> glyph_map; HashMap<Vector2i, Vector2> kerning_map; hb_font_t *hb_handle = nullptr; @@ -381,6 +451,7 @@ class TextServerAdvanced : public TextServerExtension { HashMap<int, bool> jstops; HashMap<int, bool> breaks; + int break_inserts = 0; bool break_ops_valid = false; bool js_ops_valid = false; @@ -462,258 +533,259 @@ protected: void invalidate(ShapedTextDataAdvanced *p_shaped, bool p_text = false); public: - virtual bool has_feature(Feature p_feature) const override; - virtual String get_name() const override; - virtual int64_t get_features() const override; + MODBIND1RC(bool, has_feature, Feature); + MODBIND0RC(String, get_name); + MODBIND0RC(int64_t, get_features); - virtual void free_rid(const RID &p_rid) override; - virtual bool has(const RID &p_rid) override; - virtual bool load_support_data(const String &p_filename) override; + MODBIND1(free_rid, const RID &); + MODBIND1R(bool, has, const RID &); + MODBIND1R(bool, load_support_data, const String &); - virtual String get_support_data_filename() const override; - virtual String get_support_data_info() const override; - virtual bool save_support_data(const String &p_filename) const override; + MODBIND0RC(String, get_support_data_filename); + MODBIND0RC(String, get_support_data_info); + MODBIND1RC(bool, save_support_data, const String &); - virtual bool is_locale_right_to_left(const String &p_locale) const override; + MODBIND1RC(bool, is_locale_right_to_left, const String &); - virtual int64_t name_to_tag(const String &p_name) const override; - virtual String tag_to_name(int64_t p_tag) const override; + MODBIND1RC(int64_t, name_to_tag, const String &); + MODBIND1RC(String, tag_to_name, int64_t); /* Font interface */ - virtual RID create_font() override; - virtual void font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) override; - virtual void font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) override; + MODBIND0R(RID, create_font); + + MODBIND2(font_set_data, const RID &, const PackedByteArray &); + MODBIND3(font_set_data_ptr, const RID &, const uint8_t *, int64_t); - virtual void font_set_face_index(const RID &p_font_rid, int64_t p_index) override; - virtual int64_t font_get_face_index(const RID &p_font_rid) const override; + MODBIND2(font_set_face_index, const RID &, int64_t); + MODBIND1RC(int64_t, font_get_face_index, const RID &); - virtual int64_t font_get_face_count(const RID &p_font_rid) const override; + MODBIND1RC(int64_t, font_get_face_count, const RID &); - virtual void font_set_style(const RID &p_font_rid, BitField<FontStyle> p_style) override; - virtual BitField<FontStyle> font_get_style(const RID &p_font_rid) const override; + MODBIND2(font_set_style, const RID &, BitField<FontStyle>); + MODBIND1RC(BitField<FontStyle>, font_get_style, const RID &); - virtual void font_set_style_name(const RID &p_font_rid, const String &p_name) override; - virtual String font_get_style_name(const RID &p_font_rid) const override; + MODBIND2(font_set_style_name, const RID &, const String &); + MODBIND1RC(String, font_get_style_name, const RID &); - virtual void font_set_name(const RID &p_font_rid, const String &p_name) override; - virtual String font_get_name(const RID &p_font_rid) const override; + MODBIND2(font_set_name, const RID &, const String &); + MODBIND1RC(String, font_get_name, const RID &); - virtual void font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) override; - virtual TextServer::FontAntialiasing font_get_antialiasing(RID p_font_rid) const override; + MODBIND2(font_set_antialiasing, const RID &, TextServer::FontAntialiasing); + MODBIND1RC(TextServer::FontAntialiasing, font_get_antialiasing, const RID &); - virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) override; - virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const override; + MODBIND2(font_set_generate_mipmaps, const RID &, bool); + MODBIND1RC(bool, font_get_generate_mipmaps, const RID &); - virtual void font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) override; - virtual bool font_is_multichannel_signed_distance_field(const RID &p_font_rid) const override; + MODBIND2(font_set_multichannel_signed_distance_field, const RID &, bool); + MODBIND1RC(bool, font_is_multichannel_signed_distance_field, const RID &); - virtual void font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) override; - virtual int64_t font_get_msdf_pixel_range(const RID &p_font_rid) const override; + MODBIND2(font_set_msdf_pixel_range, const RID &, int64_t); + MODBIND1RC(int64_t, font_get_msdf_pixel_range, const RID &); - virtual void font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) override; - virtual int64_t font_get_msdf_size(const RID &p_font_rid) const override; + MODBIND2(font_set_msdf_size, const RID &, int64_t); + MODBIND1RC(int64_t, font_get_msdf_size, const RID &); - virtual void font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) override; - virtual int64_t font_get_fixed_size(const RID &p_font_rid) const override; + MODBIND2(font_set_fixed_size, const RID &, int64_t); + MODBIND1RC(int64_t, font_get_fixed_size, const RID &); - virtual void font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) override; - virtual bool font_is_force_autohinter(const RID &p_font_rid) const override; + MODBIND2(font_set_force_autohinter, const RID &, bool); + MODBIND1RC(bool, font_is_force_autohinter, const RID &); - virtual void font_set_subpixel_positioning(const RID &p_font_rid, SubpixelPositioning p_subpixel) override; - virtual SubpixelPositioning font_get_subpixel_positioning(const RID &p_font_rid) const override; + MODBIND2(font_set_subpixel_positioning, const RID &, SubpixelPositioning); + MODBIND1RC(SubpixelPositioning, font_get_subpixel_positioning, const RID &); - virtual void font_set_embolden(const RID &p_font_rid, double p_strength) override; - virtual double font_get_embolden(const RID &p_font_rid) const override; + MODBIND2(font_set_embolden, const RID &, double); + MODBIND1RC(double, font_get_embolden, const RID &); - virtual void font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) override; - virtual Transform2D font_get_transform(const RID &p_font_rid) const override; + MODBIND2(font_set_transform, const RID &, const Transform2D &); + MODBIND1RC(Transform2D, font_get_transform, const RID &); - virtual void font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) override; - virtual Dictionary font_get_variation_coordinates(const RID &p_font_rid) const override; + MODBIND2(font_set_variation_coordinates, const RID &, const Dictionary &); + MODBIND1RC(Dictionary, font_get_variation_coordinates, const RID &); - virtual void font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) override; - virtual TextServer::Hinting font_get_hinting(const RID &p_font_rid) const override; + MODBIND2(font_set_hinting, const RID &, TextServer::Hinting); + MODBIND1RC(TextServer::Hinting, font_get_hinting, const RID &); - virtual void font_set_oversampling(const RID &p_font_rid, double p_oversampling) override; - virtual double font_get_oversampling(const RID &p_font_rid) const override; + MODBIND2(font_set_oversampling, const RID &, double); + MODBIND1RC(double, font_get_oversampling, const RID &); - virtual TypedArray<Vector2i> font_get_size_cache_list(const RID &p_font_rid) const override; - virtual void font_clear_size_cache(const RID &p_font_rid) override; - virtual void font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) override; + MODBIND1RC(TypedArray<Vector2i>, font_get_size_cache_list, const RID &); + MODBIND1(font_clear_size_cache, const RID &); + MODBIND2(font_remove_size_cache, const RID &, const Vector2i &); - virtual void font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) override; - virtual double font_get_ascent(const RID &p_font_rid, int64_t p_size) const override; + MODBIND3(font_set_ascent, const RID &, int64_t, double); + MODBIND2RC(double, font_get_ascent, const RID &, int64_t); - virtual void font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) override; - virtual double font_get_descent(const RID &p_font_rid, int64_t p_size) const override; + MODBIND3(font_set_descent, const RID &, int64_t, double); + MODBIND2RC(double, font_get_descent, const RID &, int64_t); - virtual void font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) override; - virtual double font_get_underline_position(const RID &p_font_rid, int64_t p_size) const override; + MODBIND3(font_set_underline_position, const RID &, int64_t, double); + MODBIND2RC(double, font_get_underline_position, const RID &, int64_t); - virtual void font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) override; - virtual double font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const override; + MODBIND3(font_set_underline_thickness, const RID &, int64_t, double); + MODBIND2RC(double, font_get_underline_thickness, const RID &, int64_t); - virtual void font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) override; - virtual double font_get_scale(const RID &p_font_rid, int64_t p_size) const override; + MODBIND3(font_set_scale, const RID &, int64_t, double); + MODBIND2RC(double, font_get_scale, const RID &, int64_t); - virtual int64_t font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const override; - virtual void font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) override; - virtual void font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) override; + MODBIND2RC(int64_t, font_get_texture_count, const RID &, const Vector2i &); + MODBIND2(font_clear_textures, const RID &, const Vector2i &); + MODBIND3(font_remove_texture, const RID &, const Vector2i &, int64_t); - virtual void font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) override; - virtual Ref<Image> font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override; + MODBIND4(font_set_texture_image, const RID &, const Vector2i &, int64_t, const Ref<Image> &); + MODBIND3RC(Ref<Image>, font_get_texture_image, const RID &, const Vector2i &, int64_t); - virtual void font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) override; - virtual PackedInt32Array font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override; + MODBIND4(font_set_texture_offsets, const RID &, const Vector2i &, int64_t, const PackedInt32Array &); + MODBIND3RC(PackedInt32Array, font_get_texture_offsets, const RID &, const Vector2i &, int64_t); - virtual PackedInt32Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override; - virtual void font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) override; - virtual void font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) override; + MODBIND2RC(PackedInt32Array, font_get_glyph_list, const RID &, const Vector2i &); + MODBIND2(font_clear_glyphs, const RID &, const Vector2i &); + MODBIND3(font_remove_glyph, const RID &, const Vector2i &, int64_t); - virtual Vector2 font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const override; - virtual void font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) override; + MODBIND3RC(Vector2, font_get_glyph_advance, const RID &, int64_t, int64_t); + MODBIND4(font_set_glyph_advance, const RID &, int64_t, int64_t, const Vector2 &); - virtual Vector2 font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; - virtual void font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) override; + MODBIND3RC(Vector2, font_get_glyph_offset, const RID &, const Vector2i &, int64_t); + MODBIND4(font_set_glyph_offset, const RID &, const Vector2i &, int64_t, const Vector2 &); - virtual Vector2 font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; - virtual void font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) override; + MODBIND3RC(Vector2, font_get_glyph_size, const RID &, const Vector2i &, int64_t); + MODBIND4(font_set_glyph_size, const RID &, const Vector2i &, int64_t, const Vector2 &); - virtual Rect2 font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; - virtual void font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) override; + MODBIND3RC(Rect2, font_get_glyph_uv_rect, const RID &, const Vector2i &, int64_t); + MODBIND4(font_set_glyph_uv_rect, const RID &, const Vector2i &, int64_t, const Rect2 &); - virtual int64_t font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; - virtual void font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) override; + MODBIND3RC(int64_t, font_get_glyph_texture_idx, const RID &, const Vector2i &, int64_t); + MODBIND4(font_set_glyph_texture_idx, const RID &, const Vector2i &, int64_t, int64_t); - virtual RID font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; - virtual Size2 font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override; + MODBIND3RC(RID, font_get_glyph_texture_rid, const RID &, const Vector2i &, int64_t); + MODBIND3RC(Size2, font_get_glyph_texture_size, const RID &, const Vector2i &, int64_t); - virtual Dictionary font_get_glyph_contours(const RID &p_font, int64_t p_size, int64_t p_index) const override; + MODBIND3RC(Dictionary, font_get_glyph_contours, const RID &, int64_t, int64_t); - virtual TypedArray<Vector2i> font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override; - virtual void font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) override; - virtual void font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) override; + MODBIND2RC(TypedArray<Vector2i>, font_get_kerning_list, const RID &, int64_t); + MODBIND2(font_clear_kerning_map, const RID &, int64_t); + MODBIND3(font_remove_kerning, const RID &, int64_t, const Vector2i &); - virtual void font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) override; - virtual Vector2 font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const override; + MODBIND4(font_set_kerning, const RID &, int64_t, const Vector2i &, const Vector2 &); + MODBIND3RC(Vector2, font_get_kerning, const RID &, int64_t, const Vector2i &); - virtual int64_t font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector = 0) const override; + MODBIND4RC(int64_t, font_get_glyph_index, const RID &, int64_t, int64_t, int64_t); - virtual bool font_has_char(const RID &p_font_rid, int64_t p_char) const override; - virtual String font_get_supported_chars(const RID &p_font_rid) const override; + MODBIND2RC(bool, font_has_char, const RID &, int64_t); + MODBIND1RC(String, font_get_supported_chars, const RID &); - virtual void font_render_range(const RID &p_font, const Vector2i &p_size, int64_t p_start, int64_t p_end) override; - virtual void font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) override; + MODBIND4(font_render_range, const RID &, const Vector2i &, int64_t, int64_t); + MODBIND3(font_render_glyph, const RID &, const Vector2i &, int64_t); - virtual void font_draw_glyph(const RID &p_font, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1)) const override; - virtual void font_draw_glyph_outline(const RID &p_font, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color = Color(1, 1, 1)) const override; + MODBIND6C(font_draw_glyph, const RID &, const RID &, int64_t, const Vector2 &, int64_t, const Color &); + MODBIND7C(font_draw_glyph_outline, const RID &, const RID &, int64_t, int64_t, const Vector2 &, int64_t, const Color &); - virtual bool font_is_language_supported(const RID &p_font_rid, const String &p_language) const override; - virtual void font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) override; - virtual bool font_get_language_support_override(const RID &p_font_rid, const String &p_language) override; - virtual void font_remove_language_support_override(const RID &p_font_rid, const String &p_language) override; - virtual PackedStringArray font_get_language_support_overrides(const RID &p_font_rid) override; + MODBIND2RC(bool, font_is_language_supported, const RID &, const String &); + MODBIND3(font_set_language_support_override, const RID &, const String &, bool); + MODBIND2R(bool, font_get_language_support_override, const RID &, const String &); + MODBIND2(font_remove_language_support_override, const RID &, const String &); + MODBIND1R(PackedStringArray, font_get_language_support_overrides, const RID &); - virtual bool font_is_script_supported(const RID &p_font_rid, const String &p_script) const override; - virtual void font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) override; - virtual bool font_get_script_support_override(const RID &p_font_rid, const String &p_script) override; - virtual void font_remove_script_support_override(const RID &p_font_rid, const String &p_script) override; - virtual PackedStringArray font_get_script_support_overrides(const RID &p_font_rid) override; + MODBIND2RC(bool, font_is_script_supported, const RID &, const String &); + MODBIND3(font_set_script_support_override, const RID &, const String &, bool); + MODBIND2R(bool, font_get_script_support_override, const RID &, const String &); + MODBIND2(font_remove_script_support_override, const RID &, const String &); + MODBIND1R(PackedStringArray, font_get_script_support_overrides, const RID &); - virtual void font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) override; - virtual Dictionary font_get_opentype_feature_overrides(const RID &p_font_rid) const override; + MODBIND2(font_set_opentype_feature_overrides, const RID &, const Dictionary &); + MODBIND1RC(Dictionary, font_get_opentype_feature_overrides, const RID &); - virtual Dictionary font_supported_feature_list(const RID &p_font_rid) const override; - virtual Dictionary font_supported_variation_list(const RID &p_font_rid) const override; + MODBIND1RC(Dictionary, font_supported_feature_list, const RID &); + MODBIND1RC(Dictionary, font_supported_variation_list, const RID &); - virtual double font_get_global_oversampling() const override; - virtual void font_set_global_oversampling(double p_oversampling) override; + MODBIND0RC(double, font_get_global_oversampling); + MODBIND1(font_set_global_oversampling, double); /* Shaped text buffer interface */ - virtual RID create_shaped_text(Direction p_direction = DIRECTION_AUTO, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; + MODBIND2R(RID, create_shaped_text, Direction, Orientation); - virtual void shaped_text_clear(const RID &p_shaped) override; + MODBIND1(shaped_text_clear, const RID &); - virtual void shaped_text_set_direction(const RID &p_shaped, Direction p_direction = DIRECTION_AUTO) override; - virtual Direction shaped_text_get_direction(const RID &p_shaped) const override; - virtual Direction shaped_text_get_inferred_direction(const RID &p_shaped) const override; + MODBIND2(shaped_text_set_direction, const RID &, Direction); + MODBIND1RC(Direction, shaped_text_get_direction, const RID &); + MODBIND1RC(Direction, shaped_text_get_inferred_direction, const RID &); - virtual void shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) override; + MODBIND2(shaped_text_set_bidi_override, const RID &, const Array &); - virtual void shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) override; - virtual String shaped_text_get_custom_punctuation(const RID &p_shaped) const override; + MODBIND2(shaped_text_set_custom_punctuation, const RID &, const String &); + MODBIND1RC(String, shaped_text_get_custom_punctuation, const RID &); - virtual void shaped_text_set_orientation(const RID &p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; - virtual Orientation shaped_text_get_orientation(const RID &p_shaped) const override; + MODBIND2(shaped_text_set_orientation, const RID &, Orientation); + MODBIND1RC(Orientation, shaped_text_get_orientation, const RID &); - virtual void shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) override; - virtual bool shaped_text_get_preserve_invalid(const RID &p_shaped) const override; + MODBIND2(shaped_text_set_preserve_invalid, const RID &, bool); + MODBIND1RC(bool, shaped_text_get_preserve_invalid, const RID &); - virtual void shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) override; - virtual bool shaped_text_get_preserve_control(const RID &p_shaped) const override; + MODBIND2(shaped_text_set_preserve_control, const RID &, bool); + MODBIND1RC(bool, shaped_text_get_preserve_control, const RID &); - virtual void shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) override; - virtual int64_t shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const override; + MODBIND3(shaped_text_set_spacing, const RID &, SpacingType, int64_t); + MODBIND2RC(int64_t, shaped_text_get_spacing, const RID &, SpacingType); - virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", const Variant &p_meta = Variant()) override; - virtual bool shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int64_t p_length = 1) override; - virtual bool shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override; + MODBIND7R(bool, shaped_text_add_string, const RID &, const String &, const TypedArray<RID> &, int64_t, const Dictionary &, const String &, const Variant &); + MODBIND5R(bool, shaped_text_add_object, const RID &, const Variant &, const Size2 &, InlineAlignment, int64_t); + MODBIND4R(bool, shaped_text_resize_object, const RID &, const Variant &, const Size2 &, InlineAlignment); - virtual int64_t shaped_get_span_count(const RID &p_shaped) const override; - virtual Variant shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const override; - virtual void shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features = Dictionary()) override; + MODBIND1RC(int64_t, shaped_get_span_count, const RID &); + MODBIND2RC(Variant, shaped_get_span_meta, const RID &, int64_t); + MODBIND5(shaped_set_span_update_font, const RID &, int64_t, const TypedArray<RID> &, int64_t, const Dictionary &); - virtual RID shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const override; - virtual RID shaped_text_get_parent(const RID &p_shaped) const override; + MODBIND3RC(RID, shaped_text_substr, const RID &, int64_t, int64_t); + MODBIND1RC(RID, shaped_text_get_parent, const RID &); - virtual double shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<TextServer::JustificationFlag> p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override; - virtual double shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) override; + MODBIND3R(double, shaped_text_fit_to_width, const RID &, double, BitField<TextServer::JustificationFlag>); + MODBIND2R(double, shaped_text_tab_align, const RID &, const PackedFloat32Array &); - virtual bool shaped_text_shape(const RID &p_shaped) override; - virtual bool shaped_text_update_breaks(const RID &p_shaped) override; - virtual bool shaped_text_update_justification_ops(const RID &p_shaped) override; + MODBIND1R(bool, shaped_text_shape, const RID &); + MODBIND1R(bool, shaped_text_update_breaks, const RID &); + MODBIND1R(bool, shaped_text_update_justification_ops, const RID &); - virtual int64_t shaped_text_get_trim_pos(const RID &p_shaped) const override; - virtual int64_t shaped_text_get_ellipsis_pos(const RID &p_shaped) const override; - virtual const Glyph *shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const override; - virtual int64_t shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const override; + MODBIND1RC(int64_t, shaped_text_get_trim_pos, const RID &); + MODBIND1RC(int64_t, shaped_text_get_ellipsis_pos, const RID &); + MODBIND1RC(const Glyph *, shaped_text_get_ellipsis_glyphs, const RID &); + MODBIND1RC(int64_t, shaped_text_get_ellipsis_glyph_count, const RID &); - virtual void shaped_text_overrun_trim_to_width(const RID &p_shaped, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) override; + MODBIND3(shaped_text_overrun_trim_to_width, const RID &, double, BitField<TextServer::TextOverrunFlag>); - virtual bool shaped_text_is_ready(const RID &p_shaped) const override; + MODBIND1RC(bool, shaped_text_is_ready, const RID &); - virtual const Glyph *shaped_text_get_glyphs(const RID &p_shaped) const override; - virtual const Glyph *shaped_text_sort_logical(const RID &p_shaped) override; - virtual int64_t shaped_text_get_glyph_count(const RID &p_shaped) const override; + MODBIND1RC(const Glyph *, shaped_text_get_glyphs, const RID &); + MODBIND1R(const Glyph *, shaped_text_sort_logical, const RID &); + MODBIND1RC(int64_t, shaped_text_get_glyph_count, const RID &); - virtual Vector2i shaped_text_get_range(const RID &p_shaped) const override; + MODBIND1RC(Vector2i, shaped_text_get_range, const RID &); - virtual Array shaped_text_get_objects(const RID &p_shaped) const override; - virtual Rect2 shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const override; + MODBIND1RC(Array, shaped_text_get_objects, const RID &); + MODBIND2RC(Rect2, shaped_text_get_object_rect, const RID &, const Variant &); - virtual Size2 shaped_text_get_size(const RID &p_shaped) const override; - virtual double shaped_text_get_ascent(const RID &p_shaped) const override; - virtual double shaped_text_get_descent(const RID &p_shaped) const override; - virtual double shaped_text_get_width(const RID &p_shaped) const override; - virtual double shaped_text_get_underline_position(const RID &p_shaped) const override; - virtual double shaped_text_get_underline_thickness(const RID &p_shaped) const override; + MODBIND1RC(Size2, shaped_text_get_size, const RID &); + MODBIND1RC(double, shaped_text_get_ascent, const RID &); + MODBIND1RC(double, shaped_text_get_descent, const RID &); + MODBIND1RC(double, shaped_text_get_width, const RID &); + MODBIND1RC(double, shaped_text_get_underline_position, const RID &); + MODBIND1RC(double, shaped_text_get_underline_thickness, const RID &); - virtual String format_number(const String &p_string, const String &p_language = "") const override; - virtual String parse_number(const String &p_string, const String &p_language = "") const override; - virtual String percent_sign(const String &p_language = "") const override; + MODBIND2RC(String, format_number, const String &, const String &); + MODBIND2RC(String, parse_number, const String &, const String &); + MODBIND1RC(String, percent_sign, const String &); - virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const override; + MODBIND2RC(PackedInt32Array, string_get_word_breaks, const String &, const String &); - virtual int64_t is_confusable(const String &p_string, const PackedStringArray &p_dict) const override; - virtual bool spoof_check(const String &p_string) const override; + MODBIND2RC(int64_t, is_confusable, const String &, const PackedStringArray &); + MODBIND1RC(bool, spoof_check, const String &); - virtual String strip_diacritics(const String &p_string) const override; - virtual bool is_valid_identifier(const String &p_string) const override; + MODBIND1RC(String, strip_diacritics, const String &); + MODBIND1RC(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; + MODBIND2RC(String, string_to_upper, const String &, const String &); + MODBIND2RC(String, string_to_lower, const String &, const String &); TextServerAdvanced(); ~TextServerAdvanced(); diff --git a/modules/text_server_adv/thorvg_bounds_iterator.cpp b/modules/text_server_adv/thorvg_bounds_iterator.cpp new file mode 100644 index 0000000000..54a6136134 --- /dev/null +++ b/modules/text_server_adv/thorvg_bounds_iterator.cpp @@ -0,0 +1,70 @@ +/*************************************************************************/ +/* thorvg_bounds_iterator.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. */ +/*************************************************************************/ + +#ifdef GDEXTENSION +// Headers for building as GDExtension plug-in. + +#include <godot_cpp/godot.hpp> + +using namespace godot; + +#else +// Headers for building as built-in module. + +#include "core/typedefs.h" + +#include "modules/modules_enabled.gen.h" // For svg. +#endif + +#ifdef MODULE_SVG_ENABLED + +#include "thorvg_bounds_iterator.h" + +#include <tvgIteratorAccessor.h> +#include <tvgPaint.h> + +// This function uses private ThorVG API to get bounding box of top level children elements. + +void tvg_get_bounds(tvg::Picture *p_picture, float &r_min_x, float &r_min_y, float &r_max_x, float &r_max_y) { + tvg::IteratorAccessor itrAccessor; + if (tvg::Iterator *it = itrAccessor.iterator(p_picture)) { + while (const tvg::Paint *child = it->next()) { + float x = 0, y = 0, w = 0, h = 0; + child->bounds(&x, &y, &w, &h, true); + r_min_x = MIN(x, r_min_x); + r_min_y = MIN(y, r_min_y); + r_max_x = MAX(x + w, r_max_x); + r_max_y = MAX(y + h, r_max_y); + } + delete (it); + } +} + +#endif // MODULE_SVG_ENABLED diff --git a/modules/text_server_adv/thorvg_bounds_iterator.h b/modules/text_server_adv/thorvg_bounds_iterator.h new file mode 100644 index 0000000000..e54e30eaa2 --- /dev/null +++ b/modules/text_server_adv/thorvg_bounds_iterator.h @@ -0,0 +1,58 @@ +/*************************************************************************/ +/* thorvg_bounds_iterator.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 THORVG_BOUNDS_ITERATOR_H +#define THORVG_BOUNDS_ITERATOR_H + +#ifdef GDEXTENSION +// Headers for building as GDExtension plug-in. + +#include <godot_cpp/core/mutex_lock.hpp> +#include <godot_cpp/godot.hpp> + +using namespace godot; + +#else +// Headers for building as built-in module. + +#include "core/typedefs.h" + +#include "modules/modules_enabled.gen.h" // For svg. +#endif + +#ifdef MODULE_SVG_ENABLED + +#include <thorvg.h> + +void tvg_get_bounds(tvg::Picture *p_picture, float &r_min_x, float &r_min_y, float &r_max_x, float &r_max_y); + +#endif // MODULE_SVG_ENABLED + +#endif // THORVG_BOUNDS_ITERATOR_H diff --git a/modules/text_server_adv/thorvg_svg_in_ot.cpp b/modules/text_server_adv/thorvg_svg_in_ot.cpp new file mode 100644 index 0000000000..7863ab67fa --- /dev/null +++ b/modules/text_server_adv/thorvg_svg_in_ot.cpp @@ -0,0 +1,320 @@ +/*************************************************************************/ +/* thorvg_svg_in_ot.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. */ +/*************************************************************************/ + +#ifdef GDEXTENSION +// Headers for building as GDExtension plug-in. + +#include <godot_cpp/classes/xml_parser.hpp> +#include <godot_cpp/core/mutex_lock.hpp> +#include <godot_cpp/godot.hpp> +#include <godot_cpp/templates/vector.hpp> + +using namespace godot; + +#else +// Headers for building as built-in module. + +#include "core/error/error_macros.h" +#include "core/io/xml_parser.h" +#include "core/os/memory.h" +#include "core/os/os.h" +#include "core/string/ustring.h" +#include "core/typedefs.h" +#include "core/variant/variant.h" + +#include "modules/modules_enabled.gen.h" // For svg. +#endif + +#ifdef MODULE_SVG_ENABLED + +#include "thorvg_bounds_iterator.h" +#include "thorvg_svg_in_ot.h" + +#include <freetype/otsvg.h> +#include <ft2build.h> + +#include <math.h> +#include <stdlib.h> + +FT_Error tvg_svg_in_ot_init(FT_Pointer *p_state) { + *p_state = memnew(TVG_State); + + return FT_Err_Ok; +} + +void tvg_svg_in_ot_free(FT_Pointer *p_state) { + TVG_State *state = *reinterpret_cast<TVG_State **>(p_state); + memdelete(state); +} + +FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Pointer *p_state) { + TVG_State *state = *reinterpret_cast<TVG_State **>(p_state); + if (!state) { + ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "SVG in OT state not initialized."); + } + MutexLock lock(state->mutex); + + FT_SVG_Document document = (FT_SVG_Document)p_slot->other; + FT_Size_Metrics metrics = document->metrics; + + GL_State &gl_state = state->glyph_map[p_slot->glyph_index]; + if (!gl_state.ready) { + Ref<XMLParser> parser; + parser.instantiate(); +#ifdef GDEXTENSION + PackedByteArray data; + data.resize(document->svg_document_length); + memcpy(data.ptrw(), document->svg_document, document->svg_document_length); + parser->open_buffer(data); +#else + parser->_open_buffer((const uint8_t *)document->svg_document, document->svg_document_length); +#endif + + float aspect = 1.0f; + String xml_body; + while (parser->read() == OK) { + if (parser->has_attribute("id")) { +#ifdef GDEXTENSION + const String &gl_name = parser->get_named_attribute_value("id"); +#else + const String &gl_name = parser->get_attribute_value("id"); +#endif + if (gl_name.begins_with("glyph")) { + int dot_pos = gl_name.find("."); + int64_t gl_idx = gl_name.substr(5, (dot_pos > 0) ? dot_pos - 5 : -1).to_int(); + if (p_slot->glyph_index != gl_idx) { + parser->skip_section(); + continue; + } + } + } + if (parser->get_node_type() == XMLParser::NODE_ELEMENT && parser->get_node_name() == "svg") { + if (parser->has_attribute("viewBox")) { +#ifdef GDEXTENSION + PackedStringArray vb = parser->get_named_attribute_value("viewBox").split(" "); +#else + Vector<String> vb = parser->get_attribute_value("viewBox").split(" "); +#endif + + if (vb.size() == 4) { + aspect = vb[2].to_float() / vb[3].to_float(); + } + } + continue; + } +#ifdef GDEXTENSION + if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { + xml_body = xml_body + "<" + parser->get_node_name(); + for (int i = 0; i < parser->get_attribute_count(); i++) { + xml_body = xml_body + " " + parser->get_attribute_name(i) + "=\"" + parser->get_attribute_value(i) + "\""; + } + xml_body = xml_body + ">"; + } else if (parser->get_node_type() == XMLParser::NODE_TEXT) { + xml_body = xml_body + parser->get_node_data(); + } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) { + xml_body = xml_body + "</" + parser->get_node_name() + ">"; + } +#else + if (parser->get_node_type() == XMLParser::NODE_ELEMENT) { + xml_body += vformat("<%s", parser->get_node_name()); + for (int i = 0; i < parser->get_attribute_count(); i++) { + xml_body += vformat(" %s=\"%s\"", parser->get_attribute_name(i), parser->get_attribute_value(i)); + } + xml_body += ">"; + } else if (parser->get_node_type() == XMLParser::NODE_TEXT) { + xml_body += parser->get_node_data(); + } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) { + xml_body += vformat("</%s>", parser->get_node_name()); + } +#endif + } + String temp_xml = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 0 0\">" + xml_body; + + std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen(); + tvg::Result result = picture->load(temp_xml.utf8().get_data(), temp_xml.utf8().length(), "svg+xml", false); + if (result != tvg::Result::Success) { + ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (bounds detection)."); + } + + float min_x = INFINITY, min_y = INFINITY, max_x = -INFINITY, max_y = -INFINITY; + tvg_get_bounds(picture.get(), min_x, min_y, max_x, max_y); + + float new_h = (max_y - min_y); + float new_w = (max_x - min_x); + + if (new_h * aspect >= new_w) { + new_w = (new_h * aspect); + } else { + new_h = (new_w / aspect); + } + +#ifdef GDEXTENSION + gl_state.xml_code = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"" + rtos(min_x) + " " + rtos(min_y) + " " + rtos(new_w) + " " + rtos(new_h) + "\">" + xml_body; +#else + gl_state.xml_code = vformat("<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"%f %f %f %f\">", min_x, min_y, new_w, new_h) + xml_body; +#endif + + picture = tvg::Picture::gen(); + result = picture->load(gl_state.xml_code.utf8().get_data(), gl_state.xml_code.utf8().length(), "svg+xml", false); + if (result != tvg::Result::Success) { + ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (glyph metrics)."); + } + + float x_svg_to_out, y_svg_to_out; + x_svg_to_out = (float)metrics.x_ppem / new_w; + y_svg_to_out = (float)metrics.y_ppem / new_h; + + gl_state.m.e11 = (double)document->transform.xx / (1 << 16) * x_svg_to_out; + gl_state.m.e12 = -(double)document->transform.xy / (1 << 16) * x_svg_to_out; + gl_state.m.e21 = -(double)document->transform.yx / (1 << 16) * y_svg_to_out; + gl_state.m.e22 = (double)document->transform.yy / (1 << 16) * y_svg_to_out; + gl_state.m.e13 = (double)document->delta.x / 64 * new_w / metrics.x_ppem; + gl_state.m.e23 = -(double)document->delta.y / 64 * new_h / metrics.y_ppem; + gl_state.m.e31 = 0; + gl_state.m.e32 = 0; + gl_state.m.e33 = 1; + + result = picture->transform(gl_state.m); + if (result != tvg::Result::Success) { + ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to apply transform to SVG document."); + } + + result = picture->bounds(&gl_state.x, &gl_state.y, &gl_state.w, &gl_state.h, true); + if (result != tvg::Result::Success) { + ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to get SVG bounds."); + } + + gl_state.bmp_y = -min_y * gl_state.h / new_h; + gl_state.bmp_x = min_x * gl_state.w / new_w; + + gl_state.ready = true; + } + + p_slot->bitmap_left = (FT_Int)gl_state.bmp_x; + p_slot->bitmap_top = (FT_Int)gl_state.bmp_y; + + float tmp = ceil(gl_state.h); + p_slot->bitmap.rows = (unsigned int)tmp; + tmp = ceil(gl_state.w); + p_slot->bitmap.width = (unsigned int)tmp; + p_slot->bitmap.pitch = (int)p_slot->bitmap.width * 4; + p_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA; + + float metrics_width, metrics_height; + float horiBearingX, horiBearingY; + float vertBearingX, vertBearingY; + + metrics_width = (float)gl_state.w; + metrics_height = (float)gl_state.h; + horiBearingX = (float)gl_state.x; + horiBearingY = (float)-gl_state.y; + vertBearingX = p_slot->metrics.horiBearingX / 64.0f - p_slot->metrics.horiAdvance / 64.0f / 2; + vertBearingY = (p_slot->metrics.vertAdvance / 64.0f - p_slot->metrics.height / 64.0f) / 2; + + tmp = roundf(metrics_width * 64); + p_slot->metrics.width = (FT_Pos)tmp; + tmp = roundf(metrics_height * 64); + p_slot->metrics.height = (FT_Pos)tmp; + + p_slot->metrics.horiBearingX = (FT_Pos)(horiBearingX * 64); + p_slot->metrics.horiBearingY = (FT_Pos)(horiBearingY * 64); + p_slot->metrics.vertBearingX = (FT_Pos)(vertBearingX * 64); + p_slot->metrics.vertBearingY = (FT_Pos)(vertBearingY * 64); + + if (p_slot->metrics.vertAdvance == 0) { + p_slot->metrics.vertAdvance = (FT_Pos)(metrics_height * 1.2f * 64); + } + + return FT_Err_Ok; +} + +FT_Error tvg_svg_in_ot_render(FT_GlyphSlot p_slot, FT_Pointer *p_state) { + TVG_State *state = *reinterpret_cast<TVG_State **>(p_state); + if (!state) { + ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "SVG in OT state not initialized."); + } + MutexLock lock(state->mutex); + + if (!state->glyph_map.has(p_slot->glyph_index)) { + ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "SVG glyph not loaded."); + } + + GL_State &gl_state = state->glyph_map[p_slot->glyph_index]; + ERR_FAIL_COND_V_MSG(!gl_state.ready, FT_Err_Invalid_SVG_Document, "SVG glyph not ready."); + + std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen(); + tvg::Result res = picture->load(gl_state.xml_code.utf8().get_data(), gl_state.xml_code.utf8().length(), "svg+xml", false); + if (res != tvg::Result::Success) { + ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (glyph rendering)."); + } + res = picture->transform(gl_state.m); + if (res != tvg::Result::Success) { + ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to apply transform to SVG document."); + } + + std::unique_ptr<tvg::SwCanvas> sw_canvas = tvg::SwCanvas::gen(); + res = sw_canvas->target((uint32_t *)p_slot->bitmap.buffer, (int)p_slot->bitmap.width, (int)p_slot->bitmap.width, (int)p_slot->bitmap.rows, tvg::SwCanvas::ARGB8888_STRAIGHT); + if (res != tvg::Result::Success) { + ERR_FAIL_V_MSG(FT_Err_Invalid_Outline, "Failed to create SVG canvas."); + } + res = sw_canvas->push(std::move(picture)); + if (res != tvg::Result::Success) { + ERR_FAIL_V_MSG(FT_Err_Invalid_Outline, "Failed to set SVG canvas source."); + } + res = sw_canvas->draw(); + if (res != tvg::Result::Success) { + ERR_FAIL_V_MSG(FT_Err_Invalid_Outline, "Failed to draw to SVG canvas."); + } + res = sw_canvas->sync(); + if (res != tvg::Result::Success) { + ERR_FAIL_V_MSG(FT_Err_Invalid_Outline, "Failed to sync SVG canvas."); + } + + state->glyph_map.erase(p_slot->glyph_index); + + p_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA; + p_slot->bitmap.num_grays = 256; + p_slot->format = FT_GLYPH_FORMAT_BITMAP; + + return FT_Err_Ok; +} + +SVG_RendererHooks tvg_svg_in_ot_hooks = { + (SVG_Lib_Init_Func)tvg_svg_in_ot_init, + (SVG_Lib_Free_Func)tvg_svg_in_ot_free, + (SVG_Lib_Render_Func)tvg_svg_in_ot_render, + (SVG_Lib_Preset_Slot_Func)tvg_svg_in_ot_preset_slot, +}; + +SVG_RendererHooks *get_tvg_svg_in_ot_hooks() { + return &tvg_svg_in_ot_hooks; +} + +#endif // MODULE_SVG_ENABLED diff --git a/modules/text_server_adv/thorvg_svg_in_ot.h b/modules/text_server_adv/thorvg_svg_in_ot.h new file mode 100644 index 0000000000..b2816193d9 --- /dev/null +++ b/modules/text_server_adv/thorvg_svg_in_ot.h @@ -0,0 +1,86 @@ +/*************************************************************************/ +/* thorvg_svg_in_ot.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 THORVG_SVG_IN_OT_H +#define THORVG_SVG_IN_OT_H + +#ifdef GDEXTENSION +// Headers for building as GDExtension plug-in. + +#include <godot_cpp/core/mutex_lock.hpp> +#include <godot_cpp/godot.hpp> +#include <godot_cpp/templates/hash_map.hpp> + +using namespace godot; + +#else +// Headers for building as built-in module. + +#include "core/os/mutex.h" +#include "core/templates/hash_map.h" +#include "core/typedefs.h" + +#include "modules/modules_enabled.gen.h" // For svg. +#endif + +#ifdef MODULE_SVG_ENABLED + +#include <freetype/freetype.h> +#include <freetype/otsvg.h> +#include <ft2build.h> +#include <thorvg.h> + +struct GL_State { + bool ready = false; + float bmp_x = 0; + float bmp_y = 0; + float x = 0; + float y = 0; + float w = 0; + float h = 0; + String xml_code; + tvg::Matrix m; +}; + +struct TVG_State { + Mutex mutex; + HashMap<uint32_t, GL_State> glyph_map; +}; + +FT_Error tvg_svg_in_ot_init(FT_Pointer *p_state); +void tvg_svg_in_ot_free(FT_Pointer *p_state); +FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Pointer *p_state); +FT_Error tvg_svg_in_ot_render(FT_GlyphSlot p_slot, FT_Pointer *p_state); + +SVG_RendererHooks *get_tvg_svg_in_ot_hooks(); + +#endif // MODULE_SVG_ENABLED + +#endif // THORVG_SVG_IN_OT_H |