summaryrefslogtreecommitdiff
path: root/modules/text_server_fb
diff options
context:
space:
mode:
Diffstat (limited to 'modules/text_server_fb')
-rw-r--r--modules/text_server_fb/SCsub3
-rw-r--r--modules/text_server_fb/gdextension_build/SConstruct102
-rw-r--r--modules/text_server_fb/gdextension_build/text_server_fb.gdextension24
-rw-r--r--modules/text_server_fb/text_server_fb.cpp1007
-rw-r--r--modules/text_server_fb/text_server_fb.h430
-rw-r--r--modules/text_server_fb/thorvg_bounds_iterator.cpp70
-rw-r--r--modules/text_server_fb/thorvg_bounds_iterator.h58
-rw-r--r--modules/text_server_fb/thorvg_svg_in_ot.cpp320
-rw-r--r--modules/text_server_fb/thorvg_svg_in_ot.h86
9 files changed, 1497 insertions, 603 deletions
diff --git a/modules/text_server_fb/SCsub b/modules/text_server_fb/SCsub
index 429d2e1fdc..f1d57ec4d3 100644
--- a/modules/text_server_fb/SCsub
+++ b/modules/text_server_fb/SCsub
@@ -8,6 +8,9 @@ msdfgen_enabled = "msdfgen" in env.module_list
env_text_server_fb = env_modules.Clone()
+if "svg" in env.module_list:
+ env_text_server_fb.Prepend(CPPPATH=["#thirdparty/thorvg/inc", "#thirdparty/thorvg/src/lib"])
+
if env["builtin_msdfgen"] and msdfgen_enabled:
env_text_server_fb.Prepend(CPPPATH=["#thirdparty/msdfgen"])
diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct
index de0a549900..7b4c548a21 100644
--- a/modules/text_server_fb/gdextension_build/SConstruct
+++ b/modules/text_server_fb/gdextension_build/SConstruct
@@ -19,8 +19,10 @@ env = SConscript("./godot-cpp/SConstruct")
env.__class__.disable_warnings = methods.disable_warnings
opts = Variables([], ARGUMENTS)
+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("thorvg_enabled", "Use ThorVG library (require FreeType)", True))
opts.Add(BoolVariable("verbose", "Enable verbose output for the compilation", False))
opts.Update(env)
@@ -28,6 +30,79 @@ opts.Update(env)
if not env["verbose"]:
methods.no_verbose(sys, env)
+# 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()
@@ -62,7 +137,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])
@@ -157,6 +232,25 @@ if env["freetype_enabled"]:
]
thirdparty_freetype_sources += [thirdparty_zlib_dir + file for file in thirdparty_zlib_sources]
+ if env["brotli_enabled"]:
+ thirdparty_brotli_dir = "../../../thirdparty/brotli/"
+ thirdparty_brotli_sources = [
+ "common/constants.c",
+ "common/context.c",
+ "common/dictionary.c",
+ "common/platform.c",
+ "common/shared_dictionary.c",
+ "common/transform.c",
+ "dec/bit_reader.c",
+ "dec/decode.c",
+ "dec/huffman.c",
+ "dec/state.c",
+ ]
+ thirdparty_freetype_sources += [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources]
+ env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
+ env_freetype.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"])
+ env.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
+
env_freetype.Append(CPPPATH=[thirdparty_freetype_dir + "/include", thirdparty_zlib_dir, thirdparty_png_dir])
env.Append(CPPPATH=[thirdparty_freetype_dir + "/include"])
@@ -168,13 +262,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])
@@ -197,7 +291,7 @@ if env["platform"] == "macos":
)
else:
library = env.SharedLibrary(
- f'./bin/libtextserver_fallback.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["SHLIBSUFFIX"]}',
+ f'./bin/libtextserver_fallback{env["suffix"]}{env["SHLIBSUFFIX"]}',
source=sources,
)
diff --git a/modules/text_server_fb/gdextension_build/text_server_fb.gdextension b/modules/text_server_fb/gdextension_build/text_server_fb.gdextension
index 9236555d63..58a92e403b 100644
--- a/modules/text_server_fb/gdextension_build/text_server_fb.gdextension
+++ b/modules/text_server_fb/gdextension_build/text_server_fb.gdextension
@@ -4,9 +4,21 @@ entry_symbol = "textserver_fallback_init"
[libraries]
-linux.64.debug = "bin/libtextserver_fallback.linux.debug.64.so"
-linux.64.release = "bin/libtextserver_fallback.linux.release.64.so"
-windows.64.debug = "bin/libtextserver_fallback.windows.debug.64.dll"
-windows.64.release = "bin/libtextserver_fallback.windows.release.64.dll"
-macos.debug = "bin/libtextserver_fallback.macos.debug.framework"
-macos.release = "bin/libtextserver_fallback.macos.release.framework"
+linux.x86_64.debug = "bin/libtextserver_fallback.linux.template_debug.x86_64.so"
+linux.x86_64.release = "bin/libtextserver_fallback.linux.template_release.x86_64.so"
+linux.x86_32.debug = "bin/libtextserver_fallback.linux.template_debug.x86_32.so"
+linux.x86_32.release = "bin/libtextserver_fallback.linux.template_release.x86_32.so"
+linux.arm64.debug = "bin/libtextserver_fallback.linux.template_debug.arm64.so"
+linux.arm64.release = "bin/libtextserver_fallback.linux.template_release.arm64.so"
+linux.rv64.debug = "bin/libtextserver_fallback.linux.template_debug.rv64.so"
+linux.rv64.release = "bin/libtextserver_fallback.linux.template_release.rv64.so"
+
+windows.x86_64.debug = "bin/libtextserver_fallback.windows.template_debug.x86_64.dll"
+windows.x86_64.release = "bin/libtextserver_fallback.windows.template_release.x86_64.dll"
+windows.x86_32.debug = "bin/libtextserver_fallback.windows.template_debug.x86_32.dll"
+windows.x86_32.release = "bin/libtextserver_fallback.windows.template_release.x86_32.dll"
+windows.arm64.debug = "bin/libtextserver_fallback.windows.template_debug.arm64.dll"
+windows.arm64.release = "bin/libtextserver_fallback.windows.template_release.arm64.dll"
+
+macos.debug = "bin/libtextserver_fallback.macos.template_debug.framework"
+macos.release = "bin/libtextserver_fallback.macos.template_release.framework"
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 55d912a10a..aaef9c9a3d 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -33,21 +33,25 @@
#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>
#include <godot_cpp/core/error_macros.hpp>
using namespace godot;
+#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get(m_var)
+
#else
// Headers for building as built-in module.
+#include "core/config/project_settings.h"
#include "core/error/error_macros.h"
#include "core/string/print_string.h"
#include "core/string/ucaps.h"
-#include "modules/modules_enabled.gen.h" // For freetype, msdfgen.
+#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg.
#endif
@@ -60,11 +64,15 @@ using namespace godot;
#include "msdfgen.h"
#endif
+#ifdef MODULE_SVG_ENABLED
+#include "thorvg_svg_in_ot.h"
+#endif
+
/*************************************************************************/
#define OT_TAG(c1, c2, c3, c4) ((int32_t)((((uint32_t)(c1)&0xff) << 24) | (((uint32_t)(c2)&0xff) << 16) | (((uint32_t)(c3)&0xff) << 8) | ((uint32_t)(c4)&0xff)))
-bool TextServerFallback::has_feature(Feature p_feature) const {
+bool TextServerFallback::_has_feature(Feature p_feature) const {
switch (p_feature) {
case FEATURE_SIMPLE_LAYOUT:
case FEATURE_FONT_BITMAP:
@@ -81,7 +89,7 @@ bool TextServerFallback::has_feature(Feature p_feature) const {
return false;
}
-String TextServerFallback::get_name() const {
+String TextServerFallback::_get_name() const {
#ifdef GDEXTENSION
return "Fallback (GDExtension)";
#else
@@ -89,7 +97,7 @@ String TextServerFallback::get_name() const {
#endif
}
-int64_t TextServerFallback::get_features() const {
+int64_t TextServerFallback::_get_features() const {
int64_t interface_features = FEATURE_SIMPLE_LAYOUT | FEATURE_FONT_BITMAP;
#ifdef MODULE_FREETYPE_ENABLED
interface_features |= FEATURE_FONT_DYNAMIC;
@@ -101,7 +109,7 @@ int64_t TextServerFallback::get_features() const {
return interface_features;
}
-void TextServerFallback::free_rid(const RID &p_rid) {
+void TextServerFallback::_free_rid(const RID &p_rid) {
_THREAD_SAFE_METHOD_
if (font_owner.owns(p_rid)) {
FontFallback *fd = font_owner.get_or_null(p_rid);
@@ -114,20 +122,28 @@ void TextServerFallback::free_rid(const RID &p_rid) {
}
}
-bool TextServerFallback::has(const RID &p_rid) {
+bool TextServerFallback::_has(const RID &p_rid) {
_THREAD_SAFE_METHOD_
return font_owner.owns(p_rid) || shaped_owner.owns(p_rid);
}
-bool TextServerFallback::load_support_data(const String &p_filename) {
+String TextServerFallback::_get_support_data_filename() const {
+ return "";
+};
+
+String TextServerFallback::_get_support_data_info() const {
+ return "Not supported";
+};
+
+bool TextServerFallback::_load_support_data(const String &p_filename) {
return false; // No extra data used.
}
-bool TextServerFallback::save_support_data(const String &p_filename) const {
+bool TextServerFallback::_save_support_data(const String &p_filename) const {
return false; // No extra data used.
}
-bool TextServerFallback::is_locale_right_to_left(const String &p_locale) const {
+bool TextServerFallback::_is_locale_right_to_left(const String &p_locale) const {
return false; // No RTL support.
}
@@ -167,7 +183,7 @@ _FORCE_INLINE_ int32_t ot_tag_from_string(const char *p_str, int p_len) {
return OT_TAG(tag[0], tag[1], tag[2], tag[3]);
}
-int64_t TextServerFallback::name_to_tag(const String &p_name) const {
+int64_t TextServerFallback::_name_to_tag(const String &p_name) const {
if (feature_sets.has(p_name)) {
return feature_sets[p_name];
}
@@ -183,7 +199,7 @@ _FORCE_INLINE_ void ot_tag_to_string(int32_t p_tag, char *p_buf) {
p_buf[3] = (char)(uint8_t)(p_tag >> 0);
}
-String TextServerFallback::tag_to_name(int64_t p_tag) const {
+String TextServerFallback::_tag_to_name(int64_t p_tag) const {
if (feature_sets_inv.has(p_tag)) {
return feature_sets_inv[p_tag];
}
@@ -201,54 +217,27 @@ String TextServerFallback::tag_to_name(int64_t p_tag) const {
_FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_texture_pos_for_glyph(FontForSizeFallback *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 (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture.
+ 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 (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
@@ -277,12 +266,9 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::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();
@@ -305,14 +291,10 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::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;
@@ -446,7 +428,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::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.
@@ -461,8 +443,14 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
td.projection = &projection;
td.distancePixelConversion = &distancePixelConversion;
+#ifdef GDEXTENSION
+ for (int i = 0; i < h; i++) {
+ _generateMTSDF_threaded(i, &td);
+ }
+#else
WorkerThreadPool::GroupID group_id = WorkerThreadPool::get_singleton()->add_template_group_task(this, &TextServerFallback::_generateMTSDF_threaded, &td, h, -1, true, SNAME("TextServerFBRenderMSDF"));
WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_id);
+#endif
msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config);
@@ -483,12 +471,6 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::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);
@@ -500,9 +482,28 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
#endif
#ifdef MODULE_FREETYPE_ENABLED
-_FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitmap(FontForSizeFallback *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance) const {
+_FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitmap(FontForSizeFallback *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance, bool p_bgra) const {
int w = bitmap.width;
int h = bitmap.rows;
+ int color_size = 2;
+
+ switch (bitmap.pixel_mode) {
+ case FT_PIXEL_MODE_MONO:
+ case FT_PIXEL_MODE_GRAY: {
+ color_size = 2;
+ } break;
+ case FT_PIXEL_MODE_BGRA: {
+ color_size = 4;
+ } break;
+ case FT_PIXEL_MODE_LCD: {
+ color_size = 4;
+ w /= 3;
+ } break;
+ case FT_PIXEL_MODE_LCD_V: {
+ color_size = 4;
+ h /= 3;
+ } break;
+ }
int mw = w + p_rect_margin * 4;
int mh = h + p_rect_margin * 4;
@@ -510,15 +511,13 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
ERR_FAIL_COND_V(mw > 4096, FontGlyph());
ERR_FAIL_COND_V(mh > 4096, FontGlyph());
- int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2;
Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;
FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh, false);
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();
@@ -545,6 +544,34 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
wr[ofs + 3] = bitmap.buffer[ofs_color + 3];
} break;
+ case FT_PIXEL_MODE_LCD: {
+ int ofs_color = i * bitmap.pitch + (j * 3);
+ if (p_bgra) {
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 2];
+ wr[ofs + 3] = 255;
+ } else {
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
+ wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 3] = 255;
+ }
+ } break;
+ case FT_PIXEL_MODE_LCD_V: {
+ int ofs_color = i * bitmap.pitch * 3 + j;
+ if (p_bgra) {
+ wr[ofs + 0] = bitmap.buffer[ofs_color + bitmap.pitch * 2];
+ wr[ofs + 1] = bitmap.buffer[ofs_color + bitmap.pitch];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 3] = 255;
+ } else {
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 1] = bitmap.buffer[ofs_color + bitmap.pitch];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + bitmap.pitch * 2];
+ wr[ofs + 3] = 255;
+ }
+ } break;
default:
ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + String::num_int64(bitmap.pixel_mode) + ".");
break;
@@ -555,12 +582,6 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::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;
@@ -650,9 +671,44 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontFallback *p_font_data,
FT_Outline_Transform(&fd->face->glyph->outline, &mat);
}
+ FT_Render_Mode aa_mode = FT_RENDER_MODE_NORMAL;
+ bool bgra = false;
+ switch (p_font_data->antialiasing) {
+ case FONT_ANTIALIASING_NONE: {
+ aa_mode = FT_RENDER_MODE_MONO;
+ } break;
+ case FONT_ANTIALIASING_GRAY: {
+ aa_mode = FT_RENDER_MODE_NORMAL;
+ } break;
+ case FONT_ANTIALIASING_LCD: {
+ int aa_layout = (int)((p_glyph >> 24) & 7);
+ switch (aa_layout) {
+ case FONT_LCD_SUBPIXEL_LAYOUT_HRGB: {
+ aa_mode = FT_RENDER_MODE_LCD;
+ bgra = false;
+ } break;
+ case FONT_LCD_SUBPIXEL_LAYOUT_HBGR: {
+ aa_mode = FT_RENDER_MODE_LCD;
+ bgra = true;
+ } break;
+ case FONT_LCD_SUBPIXEL_LAYOUT_VRGB: {
+ aa_mode = FT_RENDER_MODE_LCD_V;
+ bgra = false;
+ } break;
+ case FONT_LCD_SUBPIXEL_LAYOUT_VBGR: {
+ aa_mode = FT_RENDER_MODE_LCD_V;
+ bgra = true;
+ } break;
+ default: {
+ aa_mode = FT_RENDER_MODE_NORMAL;
+ } break;
+ }
+ } break;
+ }
+
if (!outline) {
if (!p_font_data->msdf) {
- error = FT_Render_Glyph(fd->face->glyph, p_font_data->antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
+ error = FT_Render_Glyph(fd->face->glyph, aa_mode);
}
FT_GlyphSlot slot = fd->face->glyph;
if (!error) {
@@ -664,7 +720,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontFallback *p_font_data,
ERR_FAIL_V_MSG(false, "Compiled without MSDFGEN support!");
#endif
} else {
- gl = rasterize_bitmap(fd, rect_range, slot->bitmap, slot->bitmap_top, slot->bitmap_left, Vector2((h + (1 << 9)) >> 10, (v + (1 << 9)) >> 10) / 64.0);
+ gl = rasterize_bitmap(fd, rect_range, slot->bitmap, slot->bitmap_top, slot->bitmap_left, Vector2((h + (1 << 9)) >> 10, (v + (1 << 9)) >> 10) / 64.0, bgra);
}
}
} else {
@@ -684,11 +740,11 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontFallback *p_font_data,
if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0) {
goto cleanup_glyph;
}
- if (FT_Glyph_To_Bitmap(&glyph, p_font_data->antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, nullptr, 1) != 0) {
+ if (FT_Glyph_To_Bitmap(&glyph, aa_mode, nullptr, 1) != 0) {
goto cleanup_glyph;
}
glyph_bitmap = (FT_BitmapGlyph)glyph;
- gl = rasterize_bitmap(fd, rect_range, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2());
+ gl = rasterize_bitmap(fd, rect_range, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2(), bgra);
cleanup_glyph:
FT_Done_Glyph(glyph);
@@ -717,7 +773,13 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *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));
@@ -733,17 +795,20 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f
fargs.stream = &fd->stream;
int max_index = 0;
- FT_Face tmp_face;
+ FT_Face tmp_face = nullptr;
error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
- if (error == 0) {
+ if (tmp_face && error == 0) {
max_index = tmp_face->num_faces - 1;
}
- FT_Done_Face(tmp_face);
+ if (tmp_face) {
+ FT_Done_Face(tmp_face);
+ }
error = FT_Open_Face(ft_library, &fargs, CLAMP(p_font_data->face_index, 0, max_index), &fd->face);
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)) + "'.");
}
@@ -751,7 +816,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *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;
}
@@ -832,8 +897,8 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *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);
}
}
@@ -842,6 +907,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *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
}
@@ -859,7 +925,7 @@ _FORCE_INLINE_ void TextServerFallback::_font_clear_cache(FontFallback *p_font_d
p_font_data->supported_varaitions.clear();
}
-RID TextServerFallback::create_font() {
+RID TextServerFallback::_create_font() {
_THREAD_SAFE_METHOD_
FontFallback *fd = memnew(FontFallback);
@@ -867,7 +933,7 @@ RID TextServerFallback::create_font() {
return font_owner.make_rid(fd);
}
-void TextServerFallback::font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) {
+void TextServerFallback::_font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -878,7 +944,7 @@ void TextServerFallback::font_set_data(const RID &p_font_rid, const PackedByteAr
fd->data_size = fd->data.size();
}
-void TextServerFallback::font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) {
+void TextServerFallback::_font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -889,7 +955,7 @@ void TextServerFallback::font_set_data_ptr(const RID &p_font_rid, const uint8_t
fd->data_size = p_data_size;
}
-void TextServerFallback::font_set_style(const RID &p_font_rid, BitField<FontStyle> p_style) {
+void TextServerFallback::_font_set_style(const RID &p_font_rid, BitField<FontStyle> p_style) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -899,7 +965,7 @@ void TextServerFallback::font_set_style(const RID &p_font_rid, BitField<FontStyl
fd->style_flags = p_style;
}
-void TextServerFallback::font_set_face_index(const RID &p_font_rid, int64_t p_face_index) {
+void TextServerFallback::_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);
@@ -913,7 +979,7 @@ void TextServerFallback::font_set_face_index(const RID &p_font_rid, int64_t p_fa
}
}
-int64_t TextServerFallback::font_get_face_index(const RID &p_font_rid) const {
+int64_t TextServerFallback::_font_get_face_index(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
@@ -921,7 +987,7 @@ int64_t TextServerFallback::font_get_face_index(const RID &p_font_rid) const {
return fd->face_index;
}
-int64_t TextServerFallback::font_get_face_count(const RID &p_font_rid) const {
+int64_t TextServerFallback::_font_get_face_count(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
@@ -935,6 +1001,9 @@ int64_t TextServerFallback::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;
@@ -950,19 +1019,19 @@ int64_t TextServerFallback::font_get_face_count(const RID &p_font_rid) const {
fargs.flags = FT_OPEN_MEMORY;
fargs.stream = &stream;
- FT_Face tmp_face;
+ FT_Face tmp_face = nullptr;
error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
if (error == 0) {
face_count = tmp_face->num_faces;
+ FT_Done_Face(tmp_face);
}
- FT_Done_Face(tmp_face);
#endif
}
return face_count;
}
-BitField<TextServer::FontStyle> TextServerFallback::font_get_style(const RID &p_font_rid) const {
+BitField<TextServer::FontStyle> TextServerFallback::_font_get_style(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
@@ -972,7 +1041,7 @@ BitField<TextServer::FontStyle> TextServerFallback::font_get_style(const RID &p_
return fd->style_flags;
}
-void TextServerFallback::font_set_style_name(const RID &p_font_rid, const String &p_name) {
+void TextServerFallback::_font_set_style_name(const RID &p_font_rid, const String &p_name) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -982,7 +1051,7 @@ void TextServerFallback::font_set_style_name(const RID &p_font_rid, const String
fd->style_name = p_name;
}
-String TextServerFallback::font_get_style_name(const RID &p_font_rid) const {
+String TextServerFallback::_font_get_style_name(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, String());
@@ -992,7 +1061,7 @@ String TextServerFallback::font_get_style_name(const RID &p_font_rid) const {
return fd->style_name;
}
-void TextServerFallback::font_set_name(const RID &p_font_rid, const String &p_name) {
+void TextServerFallback::_font_set_name(const RID &p_font_rid, const String &p_name) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1002,7 +1071,7 @@ void TextServerFallback::font_set_name(const RID &p_font_rid, const String &p_na
fd->font_name = p_name;
}
-String TextServerFallback::font_get_name(const RID &p_font_rid) const {
+String TextServerFallback::_font_get_name(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, String());
@@ -1012,26 +1081,26 @@ String TextServerFallback::font_get_name(const RID &p_font_rid) const {
return fd->font_name;
}
-void TextServerFallback::font_set_antialiased(const RID &p_font_rid, bool p_antialiased) {
+void TextServerFallback::_font_set_antialiasing(const RID &p_font_rid, TextServer::FontAntialiasing p_antialiasing) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
- if (fd->antialiased != p_antialiased) {
+ if (fd->antialiasing != p_antialiasing) {
_font_clear_cache(fd);
- fd->antialiased = p_antialiased;
+ fd->antialiasing = p_antialiasing;
}
}
-bool TextServerFallback::font_is_antialiased(const RID &p_font_rid) const {
+TextServer::FontAntialiasing TextServerFallback::_font_get_antialiasing(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, false);
+ ERR_FAIL_COND_V(!fd, TextServer::FONT_ANTIALIASING_NONE);
MutexLock lock(fd->mutex);
- return fd->antialiased;
+ return fd->antialiasing;
}
-void TextServerFallback::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) {
+void TextServerFallback::_font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1040,13 +1109,14 @@ void TextServerFallback::font_set_generate_mipmaps(const RID &p_font_rid, bool p
for (KeyValue<Vector2i, FontForSizeFallback *> &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 TextServerFallback::font_get_generate_mipmaps(const RID &p_font_rid) const {
+bool TextServerFallback::_font_get_generate_mipmaps(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -1054,7 +1124,7 @@ bool TextServerFallback::font_get_generate_mipmaps(const RID &p_font_rid) const
return fd->mipmaps;
}
-void TextServerFallback::font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) {
+void TextServerFallback::_font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1065,7 +1135,7 @@ void TextServerFallback::font_set_multichannel_signed_distance_field(const RID &
}
}
-bool TextServerFallback::font_is_multichannel_signed_distance_field(const RID &p_font_rid) const {
+bool TextServerFallback::_font_is_multichannel_signed_distance_field(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -1073,7 +1143,7 @@ bool TextServerFallback::font_is_multichannel_signed_distance_field(const RID &p
return fd->msdf;
}
-void TextServerFallback::font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) {
+void TextServerFallback::_font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1084,7 +1154,7 @@ void TextServerFallback::font_set_msdf_pixel_range(const RID &p_font_rid, int64_
}
}
-int64_t TextServerFallback::font_get_msdf_pixel_range(const RID &p_font_rid) const {
+int64_t TextServerFallback::_font_get_msdf_pixel_range(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -1092,7 +1162,7 @@ int64_t TextServerFallback::font_get_msdf_pixel_range(const RID &p_font_rid) con
return fd->msdf_range;
}
-void TextServerFallback::font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) {
+void TextServerFallback::_font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1103,7 +1173,7 @@ void TextServerFallback::font_set_msdf_size(const RID &p_font_rid, int64_t p_msd
}
}
-int64_t TextServerFallback::font_get_msdf_size(const RID &p_font_rid) const {
+int64_t TextServerFallback::_font_get_msdf_size(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -1111,7 +1181,7 @@ int64_t TextServerFallback::font_get_msdf_size(const RID &p_font_rid) const {
return fd->msdf_source_size;
}
-void TextServerFallback::font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) {
+void TextServerFallback::_font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1119,7 +1189,7 @@ void TextServerFallback::font_set_fixed_size(const RID &p_font_rid, int64_t p_fi
fd->fixed_size = p_fixed_size;
}
-int64_t TextServerFallback::font_get_fixed_size(const RID &p_font_rid) const {
+int64_t TextServerFallback::_font_get_fixed_size(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -1127,7 +1197,7 @@ int64_t TextServerFallback::font_get_fixed_size(const RID &p_font_rid) const {
return fd->fixed_size;
}
-void TextServerFallback::font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) {
+void TextServerFallback::_font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1138,7 +1208,7 @@ void TextServerFallback::font_set_force_autohinter(const RID &p_font_rid, bool p
}
}
-bool TextServerFallback::font_is_force_autohinter(const RID &p_font_rid) const {
+bool TextServerFallback::_font_is_force_autohinter(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -1146,7 +1216,7 @@ bool TextServerFallback::font_is_force_autohinter(const RID &p_font_rid) const {
return fd->force_autohinter;
}
-void TextServerFallback::font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) {
+void TextServerFallback::_font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1157,7 +1227,7 @@ void TextServerFallback::font_set_hinting(const RID &p_font_rid, TextServer::Hin
}
}
-TextServer::Hinting TextServerFallback::font_get_hinting(const RID &p_font_rid) const {
+TextServer::Hinting TextServerFallback::_font_get_hinting(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, HINTING_NONE);
@@ -1165,7 +1235,7 @@ TextServer::Hinting TextServerFallback::font_get_hinting(const RID &p_font_rid)
return fd->hinting;
}
-void TextServerFallback::font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) {
+void TextServerFallback::_font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1173,7 +1243,7 @@ void TextServerFallback::font_set_subpixel_positioning(const RID &p_font_rid, Te
fd->subpixel_positioning = p_subpixel;
}
-TextServer::SubpixelPositioning TextServerFallback::font_get_subpixel_positioning(const RID &p_font_rid) const {
+TextServer::SubpixelPositioning TextServerFallback::_font_get_subpixel_positioning(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, SUBPIXEL_POSITIONING_DISABLED);
@@ -1181,7 +1251,7 @@ TextServer::SubpixelPositioning TextServerFallback::font_get_subpixel_positionin
return fd->subpixel_positioning;
}
-void TextServerFallback::font_set_embolden(const RID &p_font_rid, double p_strength) {
+void TextServerFallback::_font_set_embolden(const RID &p_font_rid, double p_strength) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1192,7 +1262,7 @@ void TextServerFallback::font_set_embolden(const RID &p_font_rid, double p_stren
}
}
-double TextServerFallback::font_get_embolden(const RID &p_font_rid) const {
+double TextServerFallback::_font_get_embolden(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.0);
@@ -1200,7 +1270,7 @@ double TextServerFallback::font_get_embolden(const RID &p_font_rid) const {
return fd->embolden;
}
-void TextServerFallback::font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) {
+void TextServerFallback::_font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1211,7 +1281,7 @@ void TextServerFallback::font_set_transform(const RID &p_font_rid, const Transfo
}
}
-Transform2D TextServerFallback::font_get_transform(const RID &p_font_rid) const {
+Transform2D TextServerFallback::_font_get_transform(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Transform2D());
@@ -1219,7 +1289,7 @@ Transform2D TextServerFallback::font_get_transform(const RID &p_font_rid) const
return fd->transform;
}
-void TextServerFallback::font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) {
+void TextServerFallback::_font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1230,7 +1300,7 @@ void TextServerFallback::font_set_variation_coordinates(const RID &p_font_rid, c
}
}
-Dictionary TextServerFallback::font_get_variation_coordinates(const RID &p_font_rid) const {
+Dictionary TextServerFallback::_font_get_variation_coordinates(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
@@ -1238,7 +1308,7 @@ Dictionary TextServerFallback::font_get_variation_coordinates(const RID &p_font_
return fd->variation_coordinates;
}
-void TextServerFallback::font_set_oversampling(const RID &p_font_rid, double p_oversampling) {
+void TextServerFallback::_font_set_oversampling(const RID &p_font_rid, double p_oversampling) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1249,7 +1319,7 @@ void TextServerFallback::font_set_oversampling(const RID &p_font_rid, double p_o
}
}
-double TextServerFallback::font_get_oversampling(const RID &p_font_rid) const {
+double TextServerFallback::_font_get_oversampling(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.0);
@@ -1257,19 +1327,19 @@ double TextServerFallback::font_get_oversampling(const RID &p_font_rid) const {
return fd->oversampling;
}
-Array TextServerFallback::font_get_size_cache_list(const RID &p_font_rid) const {
+TypedArray<Vector2i> TextServerFallback::_font_get_size_cache_list(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, Array());
+ ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>());
MutexLock lock(fd->mutex);
- Array ret;
+ TypedArray<Vector2i> ret;
for (const KeyValue<Vector2i, FontForSizeFallback *> &E : fd->cache) {
ret.push_back(E.key);
}
return ret;
}
-void TextServerFallback::font_clear_size_cache(const RID &p_font_rid) {
+void TextServerFallback::_font_clear_size_cache(const RID &p_font_rid) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1280,7 +1350,7 @@ void TextServerFallback::font_clear_size_cache(const RID &p_font_rid) {
fd->cache.clear();
}
-void TextServerFallback::font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) {
+void TextServerFallback::_font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1291,7 +1361,7 @@ void TextServerFallback::font_remove_size_cache(const RID &p_font_rid, const Vec
}
}
-void TextServerFallback::font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) {
+void TextServerFallback::_font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1302,7 +1372,7 @@ void TextServerFallback::font_set_ascent(const RID &p_font_rid, int64_t p_size,
fd->cache[size]->ascent = p_ascent;
}
-double TextServerFallback::font_get_ascent(const RID &p_font_rid, int64_t p_size) const {
+double TextServerFallback::_font_get_ascent(const RID &p_font_rid, int64_t p_size) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.0);
@@ -1318,7 +1388,7 @@ double TextServerFallback::font_get_ascent(const RID &p_font_rid, int64_t p_size
}
}
-void TextServerFallback::font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) {
+void TextServerFallback::_font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1328,7 +1398,7 @@ void TextServerFallback::font_set_descent(const RID &p_font_rid, int64_t p_size,
fd->cache[size]->descent = p_descent;
}
-double TextServerFallback::font_get_descent(const RID &p_font_rid, int64_t p_size) const {
+double TextServerFallback::_font_get_descent(const RID &p_font_rid, int64_t p_size) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.0);
@@ -1344,7 +1414,7 @@ double TextServerFallback::font_get_descent(const RID &p_font_rid, int64_t p_siz
}
}
-void TextServerFallback::font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) {
+void TextServerFallback::_font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1355,7 +1425,7 @@ void TextServerFallback::font_set_underline_position(const RID &p_font_rid, int6
fd->cache[size]->underline_position = p_underline_position;
}
-double TextServerFallback::font_get_underline_position(const RID &p_font_rid, int64_t p_size) const {
+double TextServerFallback::_font_get_underline_position(const RID &p_font_rid, int64_t p_size) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.0);
@@ -1371,7 +1441,7 @@ double TextServerFallback::font_get_underline_position(const RID &p_font_rid, in
}
}
-void TextServerFallback::font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) {
+void TextServerFallback::_font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1382,7 +1452,7 @@ void TextServerFallback::font_set_underline_thickness(const RID &p_font_rid, int
fd->cache[size]->underline_thickness = p_underline_thickness;
}
-double TextServerFallback::font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const {
+double TextServerFallback::_font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.0);
@@ -1398,7 +1468,7 @@ double TextServerFallback::font_get_underline_thickness(const RID &p_font_rid, i
}
}
-void TextServerFallback::font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) {
+void TextServerFallback::_font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1414,7 +1484,7 @@ void TextServerFallback::font_set_scale(const RID &p_font_rid, int64_t p_size, d
fd->cache[size]->scale = p_scale;
}
-double TextServerFallback::font_get_scale(const RID &p_font_rid, int64_t p_size) const {
+double TextServerFallback::_font_get_scale(const RID &p_font_rid, int64_t p_size) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.0);
@@ -1430,7 +1500,7 @@ double TextServerFallback::font_get_scale(const RID &p_font_rid, int64_t p_size)
}
}
-int64_t TextServerFallback::font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const {
+int64_t TextServerFallback::_font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
@@ -1442,7 +1512,7 @@ int64_t TextServerFallback::font_get_texture_count(const RID &p_font_rid, const
return fd->cache[size]->textures.size();
}
-void TextServerFallback::font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) {
+void TextServerFallback::_font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1452,7 +1522,7 @@ void TextServerFallback::font_clear_textures(const RID &p_font_rid, const Vector
fd->cache[size]->textures.clear();
}
-void TextServerFallback::font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) {
+void TextServerFallback::_font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1464,7 +1534,7 @@ void TextServerFallback::font_remove_texture(const RID &p_font_rid, const Vector
fd->cache[size]->textures.remove_at(p_texture_index);
}
-void TextServerFallback::font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) {
+void TextServerFallback::_font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
ERR_FAIL_COND(p_image.is_null());
@@ -1477,16 +1547,14 @@ void TextServerFallback::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();
}
@@ -1495,7 +1563,7 @@ void TextServerFallback::font_set_texture_image(const RID &p_font_rid, const Vec
tex.dirty = false;
}
-Ref<Image> TextServerFallback::font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
+Ref<Image> TextServerFallback::_font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Ref<Image>());
@@ -1504,15 +1572,12 @@ Ref<Image> TextServerFallback::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 TextServerFallback::font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) {
+void TextServerFallback::_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);
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1524,11 +1589,14 @@ void TextServerFallback::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 TextServerFallback::font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
+PackedInt32Array TextServerFallback::_font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, PackedInt32Array());
@@ -1537,19 +1605,31 @@ PackedInt32Array TextServerFallback::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;
}
-Array TextServerFallback::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
+PackedInt32Array TextServerFallback::_font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, Array());
+ ERR_FAIL_COND_V(!fd, PackedInt32Array());
MutexLock lock(fd->mutex);
Vector2i size = _get_size_outline(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Array());
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array());
- Array ret;
+ PackedInt32Array ret;
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
for (const KeyValue<int32_t, FontGlyph> &E : gl) {
ret.push_back(E.key);
@@ -1557,7 +1637,7 @@ Array TextServerFallback::font_get_glyph_list(const RID &p_font_rid, const Vecto
return ret;
}
-void TextServerFallback::font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) {
+void TextServerFallback::_font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1568,7 +1648,7 @@ void TextServerFallback::font_clear_glyphs(const RID &p_font_rid, const Vector2i
fd->cache[size]->glyph_map.clear();
}
-void TextServerFallback::font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) {
+void TextServerFallback::_font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1579,7 +1659,7 @@ void TextServerFallback::font_remove_glyph(const RID &p_font_rid, const Vector2i
fd->cache[size]->glyph_map.erase(p_glyph);
}
-Vector2 TextServerFallback::font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const {
+Vector2 TextServerFallback::_font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
@@ -1587,7 +1667,16 @@ Vector2 TextServerFallback::font_get_glyph_advance(const RID &p_font_rid, int64_
Vector2i size = _get_size(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return Vector2(); // Invalid or non graphicl glyph, do not display errors.
}
@@ -1598,16 +1687,17 @@ Vector2 TextServerFallback::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].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)) {
- return (gl[p_glyph].advance + ea).round();
+ return (gl[p_glyph | mod].advance + ea) * (double)p_size / (double)fd->msdf_source_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].advance + ea;
+ return gl[p_glyph | mod].advance + ea;
}
}
-void TextServerFallback::font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) {
+void TextServerFallback::_font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1622,7 +1712,7 @@ void TextServerFallback::font_set_glyph_advance(const RID &p_font_rid, int64_t p
gl[p_glyph].found = true;
}
-Vector2 TextServerFallback::font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
+Vector2 TextServerFallback::_font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
@@ -1630,20 +1720,29 @@ Vector2 TextServerFallback::font_get_glyph_offset(const RID &p_font_rid, const V
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return Vector2(); // Invalid or non graphicl glyph, do not display errors.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
if (fd->msdf) {
- return gl[p_glyph].rect.position * (double)p_size.x / (double)fd->msdf_source_size;
+ return gl[p_glyph | mod].rect.position * (double)p_size.x / (double)fd->msdf_source_size;
} else {
- return gl[p_glyph].rect.position;
+ return gl[p_glyph | mod].rect.position;
}
}
-void TextServerFallback::font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) {
+void TextServerFallback::_font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1658,7 +1757,7 @@ void TextServerFallback::font_set_glyph_offset(const RID &p_font_rid, const Vect
gl[p_glyph].found = true;
}
-Vector2 TextServerFallback::font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
+Vector2 TextServerFallback::_font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
@@ -1666,20 +1765,29 @@ Vector2 TextServerFallback::font_get_glyph_size(const RID &p_font_rid, const Vec
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return Vector2(); // Invalid or non graphicl glyph, do not display errors.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
if (fd->msdf) {
- return gl[p_glyph].rect.size * (double)p_size.x / (double)fd->msdf_source_size;
+ return gl[p_glyph | mod].rect.size * (double)p_size.x / (double)fd->msdf_source_size;
} else {
- return gl[p_glyph].rect.size;
+ return gl[p_glyph | mod].rect.size;
}
}
-void TextServerFallback::font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) {
+void TextServerFallback::_font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1694,7 +1802,7 @@ void TextServerFallback::font_set_glyph_size(const RID &p_font_rid, const Vector
gl[p_glyph].found = true;
}
-Rect2 TextServerFallback::font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
+Rect2 TextServerFallback::_font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Rect2());
@@ -1702,15 +1810,24 @@ Rect2 TextServerFallback::font_get_glyph_uv_rect(const RID &p_font_rid, const Ve
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Rect2());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return Rect2(); // Invalid or non graphicl glyph, do not display errors.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
- return gl[p_glyph].uv_rect;
+ return gl[p_glyph | mod].uv_rect;
}
-void TextServerFallback::font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) {
+void TextServerFallback::_font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1725,7 +1842,7 @@ void TextServerFallback::font_set_glyph_uv_rect(const RID &p_font_rid, const Vec
gl[p_glyph].found = true;
}
-int64_t TextServerFallback::font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
+int64_t TextServerFallback::_font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, -1);
@@ -1733,15 +1850,24 @@ int64_t TextServerFallback::font_get_glyph_texture_idx(const RID &p_font_rid, co
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), -1);
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return -1; // Invalid or non graphicl glyph, do not display errors.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
- return gl[p_glyph].texture_idx;
+ return gl[p_glyph | mod].texture_idx;
}
-void TextServerFallback::font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) {
+void TextServerFallback::_font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1756,7 +1882,7 @@ void TextServerFallback::font_set_glyph_texture_idx(const RID &p_font_rid, const
gl[p_glyph].found = true;
}
-RID TextServerFallback::font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
+RID TextServerFallback::_font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, RID());
@@ -1764,20 +1890,27 @@ RID TextServerFallback::font_get_glyph_texture_rid(const RID &p_font_rid, const
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), RID());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return RID(); // Invalid or non graphicl glyph, do not display errors.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
- ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), RID());
+ ERR_FAIL_COND_V(gl[p_glyph | mod].texture_idx < -1 || gl[p_glyph | mod].texture_idx >= fd->cache[size]->textures.size(), RID());
if (RenderingServer::get_singleton() != nullptr) {
- if (gl[p_glyph].texture_idx != -1) {
- if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) {
- FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx];
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (gl[p_glyph | mod].texture_idx != -1) {
+ if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
+ 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();
}
@@ -1788,14 +1921,14 @@ RID TextServerFallback::font_get_glyph_texture_rid(const RID &p_font_rid, const
}
tex.dirty = false;
}
- return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_rid();
+ return fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].texture->get_rid();
}
}
return RID();
}
-Size2 TextServerFallback::font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
+Size2 TextServerFallback::_font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Size2());
@@ -1803,20 +1936,27 @@ Size2 TextServerFallback::font_get_glyph_texture_size(const RID &p_font_rid, con
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Size2());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return Size2(); // Invalid or non graphicl glyph, do not display errors.
}
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
- ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), Size2());
+ ERR_FAIL_COND_V(gl[p_glyph | mod].texture_idx < -1 || gl[p_glyph | mod].texture_idx >= fd->cache[size]->textures.size(), Size2());
if (RenderingServer::get_singleton() != nullptr) {
- if (gl[p_glyph].texture_idx != -1) {
- if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) {
- FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx];
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (gl[p_glyph | mod].texture_idx != -1) {
+ if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
+ 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();
}
@@ -1827,14 +1967,14 @@ Size2 TextServerFallback::font_get_glyph_texture_size(const RID &p_font_rid, con
}
tex.dirty = false;
}
- return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_size();
+ return fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].texture->get_size();
}
}
return Size2();
}
-Dictionary TextServerFallback::font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const {
+Dictionary TextServerFallback::_font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
@@ -1884,23 +2024,23 @@ Dictionary TextServerFallback::font_get_glyph_contours(const RID &p_font_rid, in
#endif
}
-Array TextServerFallback::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {
+TypedArray<Vector2i> TextServerFallback::_font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, Array());
+ ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>());
MutexLock lock(fd->mutex);
Vector2i size = _get_size(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Array());
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), TypedArray<Vector2i>());
- Array ret;
+ TypedArray<Vector2i> ret;
for (const KeyValue<Vector2i, Vector2> &E : fd->cache[size]->kerning_map) {
ret.push_back(E.key);
}
return ret;
}
-void TextServerFallback::font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) {
+void TextServerFallback::_font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1911,7 +2051,7 @@ void TextServerFallback::font_clear_kerning_map(const RID &p_font_rid, int64_t p
fd->cache[size]->kerning_map.clear();
}
-void TextServerFallback::font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) {
+void TextServerFallback::_font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1922,7 +2062,7 @@ void TextServerFallback::font_remove_kerning(const RID &p_font_rid, int64_t p_si
fd->cache[size]->kerning_map.erase(p_glyph_pair);
}
-void TextServerFallback::font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
+void TextServerFallback::_font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1933,7 +2073,7 @@ void TextServerFallback::font_set_kerning(const RID &p_font_rid, int64_t p_size,
fd->cache[size]->kerning_map[p_glyph_pair] = p_kerning;
}
-Vector2 TextServerFallback::font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const {
+Vector2 TextServerFallback::_font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
@@ -1968,15 +2108,17 @@ Vector2 TextServerFallback::font_get_kerning(const RID &p_font_rid, int64_t p_si
return Vector2();
}
-int64_t TextServerFallback::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 TextServerFallback::_font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const {
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) + ".");
return (int64_t)p_char;
}
-bool TextServerFallback::font_has_char(const RID &p_font_rid, int64_t p_char) const {
+bool TextServerFallback::_font_has_char(const RID &p_font_rid, int64_t p_char) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, false);
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) {
+ return false;
+ }
MutexLock lock(fd->mutex);
if (fd->cache.is_empty()) {
@@ -1992,7 +2134,7 @@ bool TextServerFallback::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 TextServerFallback::font_get_supported_chars(const RID &p_font_rid) const {
+String TextServerFallback::_font_get_supported_chars(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, String());
@@ -2025,7 +2167,7 @@ String TextServerFallback::font_get_supported_chars(const RID &p_font_rid) const
return chars;
}
-void TextServerFallback::font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) {
+void TextServerFallback::_font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) {
FontFallback *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) + ".");
@@ -2041,16 +2183,18 @@ void TextServerFallback::font_render_range(const RID &p_font_rid, const Vector2i
if (fd->msdf) {
_ensure_glyph(fd, size, (int32_t)idx);
} else {
- if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
- _ensure_glyph(fd, size, (int32_t)idx | (0 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (1 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (2 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (3 << 27));
- } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
- _ensure_glyph(fd, size, (int32_t)idx | (1 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (0 << 27));
- } else {
- _ensure_glyph(fd, size, (int32_t)idx);
+ for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {
+ if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
+ _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24));
+ } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
+ _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24));
+ } else {
+ _ensure_glyph(fd, size, (int32_t)idx | (aa << 24));
+ }
}
}
}
@@ -2058,7 +2202,7 @@ void TextServerFallback::font_render_range(const RID &p_font_rid, const Vector2i
}
}
-void TextServerFallback::font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) {
+void TextServerFallback::_font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2071,23 +2215,25 @@ void TextServerFallback::font_render_glyph(const RID &p_font_rid, const Vector2i
if (fd->msdf) {
_ensure_glyph(fd, size, (int32_t)idx);
} else {
- if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
- _ensure_glyph(fd, size, (int32_t)idx | (0 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (1 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (2 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (3 << 27));
- } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
- _ensure_glyph(fd, size, (int32_t)idx | (1 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (0 << 27));
- } else {
- _ensure_glyph(fd, size, (int32_t)idx);
+ for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {
+ if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
+ _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24));
+ } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
+ _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24));
+ } else {
+ _ensure_glyph(fd, size, (int32_t)idx | (aa << 24));
+ }
}
}
}
#endif
}
-void TextServerFallback::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 TextServerFallback::_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 {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2096,9 +2242,19 @@ void TextServerFallback::font_draw_glyph(const RID &p_font_rid, const RID &p_can
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
+ bool lcd_aa = false;
#ifdef MODULE_FREETYPE_ENABLED
if (!fd->msdf && fd->cache[size]->face) {
+ // LCD layout, bits 24, 25, 26
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ lcd_aa = true;
+ index = index | (layout << 24);
+ }
+ }
+ // Subpixel X-shift, bits 27, 28
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));
index = index | (xshift << 27);
@@ -2120,16 +2276,14 @@ void TextServerFallback::font_draw_glyph(const RID &p_font_rid, const RID &p_can
if (gl.texture_idx != -1) {
Color modulate = p_color;
#ifdef MODULE_FREETYPE_ENABLED
- if (fd->cache[size]->face && FT_HAS_COLOR(fd->cache[size]->face)) {
+ if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
modulate.r = modulate.g = modulate.b = 1.0;
}
#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();
}
@@ -2148,24 +2302,30 @@ void TextServerFallback::font_draw_glyph(const RID &p_font_rid, const RID &p_can
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 {
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;
Size2 csize = gl.rect.size;
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
+ if (lcd_aa) {
+ RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate);
+ } else {
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
+ }
}
}
}
}
}
-void TextServerFallback::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 TextServerFallback::_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 {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2174,9 +2334,19 @@ void TextServerFallback::font_draw_glyph_outline(const RID &p_font_rid, const RI
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
+ bool lcd_aa = false;
#ifdef MODULE_FREETYPE_ENABLED
if (!fd->msdf && fd->cache[size]->face) {
+ // LCD layout, bits 24, 25, 26
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ lcd_aa = true;
+ index = index | (layout << 24);
+ }
+ }
+ // Subpixel X-shift, bits 27, 28
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));
index = index | (xshift << 27);
@@ -2198,16 +2368,14 @@ void TextServerFallback::font_draw_glyph_outline(const RID &p_font_rid, const RI
if (gl.texture_idx != -1) {
Color modulate = p_color;
#ifdef MODULE_FREETYPE_ENABLED
- if (fd->cache[size]->face && FT_HAS_COLOR(fd->cache[size]->face)) {
+ if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
modulate.r = modulate.g = modulate.b = 1.0;
}
#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();
}
@@ -2226,24 +2394,30 @@ void TextServerFallback::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;
Size2 csize = gl.rect.size;
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
+ if (lcd_aa) {
+ RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate);
+ } else {
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
+ }
}
}
}
}
}
-bool TextServerFallback::font_is_language_supported(const RID &p_font_rid, const String &p_language) const {
+bool TextServerFallback::_font_is_language_supported(const RID &p_font_rid, const String &p_language) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -2255,7 +2429,7 @@ bool TextServerFallback::font_is_language_supported(const RID &p_font_rid, const
}
}
-void TextServerFallback::font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) {
+void TextServerFallback::_font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2263,7 +2437,7 @@ void TextServerFallback::font_set_language_support_override(const RID &p_font_ri
fd->language_support_overrides[p_language] = p_supported;
}
-bool TextServerFallback::font_get_language_support_override(const RID &p_font_rid, const String &p_language) {
+bool TextServerFallback::_font_get_language_support_override(const RID &p_font_rid, const String &p_language) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -2271,7 +2445,7 @@ bool TextServerFallback::font_get_language_support_override(const RID &p_font_ri
return fd->language_support_overrides[p_language];
}
-void TextServerFallback::font_remove_language_support_override(const RID &p_font_rid, const String &p_language) {
+void TextServerFallback::_font_remove_language_support_override(const RID &p_font_rid, const String &p_language) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2279,7 +2453,7 @@ void TextServerFallback::font_remove_language_support_override(const RID &p_font
fd->language_support_overrides.erase(p_language);
}
-PackedStringArray TextServerFallback::font_get_language_support_overrides(const RID &p_font_rid) {
+PackedStringArray TextServerFallback::_font_get_language_support_overrides(const RID &p_font_rid) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, PackedStringArray());
@@ -2291,7 +2465,7 @@ PackedStringArray TextServerFallback::font_get_language_support_overrides(const
return out;
}
-bool TextServerFallback::font_is_script_supported(const RID &p_font_rid, const String &p_script) const {
+bool TextServerFallback::_font_is_script_supported(const RID &p_font_rid, const String &p_script) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -2303,7 +2477,7 @@ bool TextServerFallback::font_is_script_supported(const RID &p_font_rid, const S
}
}
-void TextServerFallback::font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) {
+void TextServerFallback::_font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2311,7 +2485,7 @@ void TextServerFallback::font_set_script_support_override(const RID &p_font_rid,
fd->script_support_overrides[p_script] = p_supported;
}
-bool TextServerFallback::font_get_script_support_override(const RID &p_font_rid, const String &p_script) {
+bool TextServerFallback::_font_get_script_support_override(const RID &p_font_rid, const String &p_script) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
@@ -2319,7 +2493,7 @@ bool TextServerFallback::font_get_script_support_override(const RID &p_font_rid,
return fd->script_support_overrides[p_script];
}
-void TextServerFallback::font_remove_script_support_override(const RID &p_font_rid, const String &p_script) {
+void TextServerFallback::_font_remove_script_support_override(const RID &p_font_rid, const String &p_script) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2329,7 +2503,7 @@ void TextServerFallback::font_remove_script_support_override(const RID &p_font_r
fd->script_support_overrides.erase(p_script);
}
-PackedStringArray TextServerFallback::font_get_script_support_overrides(const RID &p_font_rid) {
+PackedStringArray TextServerFallback::_font_get_script_support_overrides(const RID &p_font_rid) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, PackedStringArray());
@@ -2341,7 +2515,7 @@ PackedStringArray TextServerFallback::font_get_script_support_overrides(const RI
return out;
}
-void TextServerFallback::font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) {
+void TextServerFallback::_font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2351,7 +2525,7 @@ void TextServerFallback::font_set_opentype_feature_overrides(const RID &p_font_r
fd->feature_overrides = p_overrides;
}
-Dictionary TextServerFallback::font_get_opentype_feature_overrides(const RID &p_font_rid) const {
+Dictionary TextServerFallback::_font_get_opentype_feature_overrides(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
@@ -2359,11 +2533,11 @@ Dictionary TextServerFallback::font_get_opentype_feature_overrides(const RID &p_
return fd->feature_overrides;
}
-Dictionary TextServerFallback::font_supported_feature_list(const RID &p_font_rid) const {
+Dictionary TextServerFallback::_font_supported_feature_list(const RID &p_font_rid) const {
return Dictionary();
}
-Dictionary TextServerFallback::font_supported_variation_list(const RID &p_font_rid) const {
+Dictionary TextServerFallback::_font_supported_variation_list(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
@@ -2373,11 +2547,11 @@ Dictionary TextServerFallback::font_supported_variation_list(const RID &p_font_r
return fd->supported_varaitions;
}
-double TextServerFallback::font_get_global_oversampling() const {
+double TextServerFallback::_font_get_global_oversampling() const {
return oversampling;
}
-void TextServerFallback::font_set_global_oversampling(double p_oversampling) {
+void TextServerFallback::_font_set_global_oversampling(double p_oversampling) {
_THREAD_SAFE_METHOD_
if (oversampling != p_oversampling) {
oversampling = p_oversampling;
@@ -2385,8 +2559,8 @@ void TextServerFallback::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;
}
}
@@ -2441,7 +2615,7 @@ void TextServerFallback::full_copy(ShapedTextDataFallback *p_shaped) {
p_shaped->parent = RID();
}
-RID TextServerFallback::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
+RID TextServerFallback::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
_THREAD_SAFE_METHOD_
ShapedTextDataFallback *sd = memnew(ShapedTextDataFallback);
@@ -2451,7 +2625,7 @@ RID TextServerFallback::create_shaped_text(TextServer::Direction p_direction, Te
return shaped_owner.make_rid(sd);
}
-void TextServerFallback::shaped_text_clear(const RID &p_shaped) {
+void TextServerFallback::_shaped_text_clear(const RID &p_shaped) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
@@ -2465,21 +2639,21 @@ void TextServerFallback::shaped_text_clear(const RID &p_shaped) {
invalidate(sd);
}
-void TextServerFallback::shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {
+void TextServerFallback::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {
if (p_direction == DIRECTION_RTL) {
ERR_PRINT_ONCE("Right-to-left layout is not supported by this text server.");
}
}
-TextServer::Direction TextServerFallback::shaped_text_get_direction(const RID &p_shaped) const {
+TextServer::Direction TextServerFallback::_shaped_text_get_direction(const RID &p_shaped) const {
return TextServer::DIRECTION_LTR;
}
-TextServer::Direction TextServerFallback::shaped_text_get_inferred_direction(const RID &p_shaped) const {
+TextServer::Direction TextServerFallback::_shaped_text_get_inferred_direction(const RID &p_shaped) const {
return TextServer::DIRECTION_LTR;
}
-void TextServerFallback::shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) {
+void TextServerFallback::_shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) {
_THREAD_SAFE_METHOD_
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
@@ -2493,14 +2667,14 @@ void TextServerFallback::shaped_text_set_custom_punctuation(const RID &p_shaped,
}
}
-String TextServerFallback::shaped_text_get_custom_punctuation(const RID &p_shaped) const {
+String TextServerFallback::_shaped_text_get_custom_punctuation(const RID &p_shaped) const {
_THREAD_SAFE_METHOD_
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, String());
return sd->custom_punct;
}
-void TextServerFallback::shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) {
+void TextServerFallback::_shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
@@ -2514,11 +2688,11 @@ void TextServerFallback::shaped_text_set_orientation(const RID &p_shaped, TextSe
}
}
-void TextServerFallback::shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) {
+void TextServerFallback::_shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) {
// No BiDi support, ignore.
}
-TextServer::Orientation TextServerFallback::shaped_text_get_orientation(const RID &p_shaped) const {
+TextServer::Orientation TextServerFallback::_shaped_text_get_orientation(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, TextServer::ORIENTATION_HORIZONTAL);
@@ -2526,7 +2700,7 @@ TextServer::Orientation TextServerFallback::shaped_text_get_orientation(const RI
return sd->orientation;
}
-void TextServerFallback::shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) {
+void TextServerFallback::_shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
MutexLock lock(sd->mutex);
@@ -2540,7 +2714,7 @@ void TextServerFallback::shaped_text_set_preserve_invalid(const RID &p_shaped, b
}
}
-bool TextServerFallback::shaped_text_get_preserve_invalid(const RID &p_shaped) const {
+bool TextServerFallback::_shaped_text_get_preserve_invalid(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -2548,7 +2722,7 @@ bool TextServerFallback::shaped_text_get_preserve_invalid(const RID &p_shaped) c
return sd->preserve_invalid;
}
-void TextServerFallback::shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) {
+void TextServerFallback::_shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
@@ -2562,7 +2736,7 @@ void TextServerFallback::shaped_text_set_preserve_control(const RID &p_shaped, b
}
}
-bool TextServerFallback::shaped_text_get_preserve_control(const RID &p_shaped) const {
+bool TextServerFallback::_shaped_text_get_preserve_control(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -2570,7 +2744,7 @@ bool TextServerFallback::shaped_text_get_preserve_control(const RID &p_shaped) c
return sd->preserve_control;
}
-void TextServerFallback::shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) {
+void TextServerFallback::_shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) {
ERR_FAIL_INDEX((int)p_spacing, 4);
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
@@ -2585,7 +2759,7 @@ void TextServerFallback::shaped_text_set_spacing(const RID &p_shaped, SpacingTyp
}
}
-int64_t TextServerFallback::shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const {
+int64_t TextServerFallback::_shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const {
ERR_FAIL_INDEX_V((int)p_spacing, 4, 0);
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
@@ -2595,20 +2769,20 @@ int64_t TextServerFallback::shaped_text_get_spacing(const RID &p_shaped, Spacing
return sd->extra_spacing[p_spacing];
}
-int64_t TextServerFallback::shaped_get_span_count(const RID &p_shaped) const {
+int64_t TextServerFallback::_shaped_get_span_count(const RID &p_shaped) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0);
return sd->spans.size();
}
-Variant TextServerFallback::shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const {
+Variant TextServerFallback::_shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const {
ShapedTextDataFallback *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 TextServerFallback::shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) {
+void TextServerFallback::_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) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
ERR_FAIL_INDEX(p_index, sd->spans.size());
@@ -2619,7 +2793,7 @@ void TextServerFallback::shaped_set_span_update_font(const RID &p_shaped, int64_
Array fonts_no_match;
int font_count = p_fonts.size();
for (int i = 0; i < font_count; i++) {
- if (font_is_language_supported(p_fonts[i], span.language)) {
+ if (_font_is_language_supported(p_fonts[i], span.language)) {
span.fonts.push_back(p_fonts[i]);
} else {
fonts_no_match.push_back(p_fonts[i]);
@@ -2632,7 +2806,7 @@ void TextServerFallback::shaped_set_span_update_font(const RID &p_shaped, int64_
sd->valid = false;
}
-bool TextServerFallback::shaped_text_add_string(const RID &p_shaped, const String &p_text, const Array &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
+bool TextServerFallback::_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) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -2658,8 +2832,11 @@ bool TextServerFallback::shaped_text_add_string(const RID &p_shaped, const Strin
// Pre-sort fonts, push fonts with the language support first.
Array fonts_no_match;
int font_count = p_fonts.size();
- for (int i = 0; i < font_count; i++) {
- if (font_is_language_supported(p_fonts[i], p_language)) {
+ if (font_count > 0) {
+ span.fonts.push_back(p_fonts[0]);
+ }
+ for (int i = 1; i < font_count; i++) {
+ if (_font_is_language_supported(p_fonts[i], p_language)) {
span.fonts.push_back(p_fonts[i]);
} else {
fonts_no_match.push_back(p_fonts[i]);
@@ -2680,7 +2857,7 @@ bool TextServerFallback::shaped_text_add_string(const RID &p_shaped, const Strin
return true;
}
-bool TextServerFallback::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 TextServerFallback::_shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -2711,7 +2888,7 @@ bool TextServerFallback::shaped_text_add_object(const RID &p_shaped, const Varia
return true;
}
-bool TextServerFallback::shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align) {
+bool TextServerFallback::_shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -2752,14 +2929,14 @@ bool TextServerFallback::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, font_get_ascent(gl.font_rid, gl.font_size));
- sd->descent = MAX(sd->descent, font_get_descent(gl.font_rid, gl.font_size));
+ sd->ascent = MAX(sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size));
+ sd->descent = MAX(sd->descent, _font_get_descent(gl.font_rid, gl.font_size));
} 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) {
@@ -2846,7 +3023,7 @@ void TextServerFallback::_realign(ShapedTextDataFallback *p_sd) const {
p_sd->descent = full_descent;
}
-RID TextServerFallback::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {
+RID TextServerFallback::_shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {
_THREAD_SAFE_METHOD_
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
@@ -2854,10 +3031,10 @@ RID TextServerFallback::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<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ const_cast<TextServerFallback *>(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());
@@ -2912,11 +3089,11 @@ RID TextServerFallback::shaped_text_substr(const RID &p_shaped, int64_t p_start,
} else {
if (gl.font_rid.is_valid()) {
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
- new_sd->ascent = MAX(new_sd->ascent, font_get_ascent(gl.font_rid, gl.font_size));
- new_sd->descent = MAX(new_sd->descent, font_get_descent(gl.font_rid, gl.font_size));
+ new_sd->ascent = MAX(new_sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size));
+ new_sd->descent = MAX(new_sd->descent, _font_get_descent(gl.font_rid, gl.font_size));
} else {
- new_sd->ascent = MAX(new_sd->ascent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
- new_sd->descent = MAX(new_sd->descent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
+ new_sd->descent = MAX(new_sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
}
} else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) {
// Glyph not found, replace with hex code box.
@@ -2940,7 +3117,7 @@ RID TextServerFallback::shaped_text_substr(const RID &p_shaped, int64_t p_start,
return shaped_owner.make_rid(new_sd);
}
-RID TextServerFallback::shaped_text_get_parent(const RID &p_shaped) const {
+RID TextServerFallback::_shaped_text_get_parent(const RID &p_shaped) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, RID());
@@ -2948,16 +3125,16 @@ RID TextServerFallback::shaped_text_get_parent(const RID &p_shaped) const {
return sd->parent;
}
-double TextServerFallback::shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<JustificationFlag> p_jst_flags) {
+double TextServerFallback::_shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<JustificationFlag> p_jst_flags) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
- const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
if (!sd->justification_ops_valid) {
- const_cast<TextServerFallback *>(this)->shaped_text_update_justification_ops(p_shaped);
+ const_cast<TextServerFallback *>(this)->_shaped_text_update_justification_ops(p_shaped);
}
int start_pos = 0;
@@ -3057,16 +3234,16 @@ double TextServerFallback::shaped_text_fit_to_width(const RID &p_shaped, double
return Math::ceil(justification_width);
}
-double TextServerFallback::shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) {
+double TextServerFallback::_shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
- const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
if (!sd->line_breaks_valid) {
- const_cast<TextServerFallback *>(this)->shaped_text_update_breaks(p_shaped);
+ const_cast<TextServerFallback *>(this)->_shaped_text_update_breaks(p_shaped);
}
for (int i = 0; i < p_tab_stops.size(); i++) {
@@ -3113,13 +3290,13 @@ double TextServerFallback::shaped_text_tab_align(const RID &p_shaped, const Pack
return 0.0;
}
-bool TextServerFallback::shaped_text_update_breaks(const RID &p_shaped) {
+bool TextServerFallback::_shaped_text_update_breaks(const RID &p_shaped) {
ShapedTextDataFallback *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) {
@@ -3169,29 +3346,29 @@ bool TextServerFallback::shaped_text_update_breaks(const RID &p_shaped) {
return sd->line_breaks_valid;
}
-bool TextServerFallback::shaped_text_update_justification_ops(const RID &p_shaped) {
+bool TextServerFallback::_shaped_text_update_justification_ops(const RID &p_shaped) {
ShapedTextDataFallback *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);
}
sd->justification_ops_valid = true; // Not supported by fallback server.
return true;
}
-void TextServerFallback::shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) {
+void TextServerFallback::_shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped_line);
ERR_FAIL_COND_MSG(!sd, "ShapedTextDataFallback invalid.");
MutexLock lock(sd->mutex);
if (!sd->valid) {
- shaped_text_shape(p_shaped_line);
+ _shaped_text_shape(p_shaped_line);
}
sd->text_trimmed = false;
@@ -3230,30 +3407,30 @@ void TextServerFallback::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()) {
@@ -3269,29 +3446,34 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(const RID &p_shaped_l
int last_valid_cut = 0;
bool found = false;
- for (int i = sd_size - 1; i != -1; i--) {
- width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
+ if (enforce_ellipsis && (width + ellipsis_width <= p_width)) {
+ trim_pos = -1;
+ ellipsis_pos = sd_size;
+ } else {
+ for (int i = sd_size - 1; i != -1; i--) {
+ width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
- if (sd_glyphs[i].count > 0) {
- bool above_min_char_threshold = (i >= ell_min_characters);
+ if (sd_glyphs[i].count > 0) {
+ bool above_min_char_threshold = (i >= ell_min_characters);
- if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {
- if (cut_per_word && above_min_char_threshold) {
- if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
+ if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {
+ if (cut_per_word && above_min_char_threshold) {
+ if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
+ last_valid_cut = i;
+ found = true;
+ }
+ } else {
last_valid_cut = i;
found = true;
}
- } else {
- last_valid_cut = i;
- found = true;
- }
- if (found) {
- trim_pos = last_valid_cut;
+ if (found) {
+ trim_pos = last_valid_cut;
- if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {
- ellipsis_pos = trim_pos;
+ if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {
+ ellipsis_pos = trim_pos;
+ }
+ break;
}
- break;
}
}
}
@@ -3337,7 +3519,7 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(const RID &p_shaped_l
}
}
-int64_t TextServerFallback::shaped_text_get_trim_pos(const RID &p_shaped) const {
+int64_t TextServerFallback::_shaped_text_get_trim_pos(const RID &p_shaped) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataFallback invalid.");
@@ -3345,7 +3527,7 @@ int64_t TextServerFallback::shaped_text_get_trim_pos(const RID &p_shaped) const
return sd->overrun_trim_data.trim_pos;
}
-int64_t TextServerFallback::shaped_text_get_ellipsis_pos(const RID &p_shaped) const {
+int64_t TextServerFallback::_shaped_text_get_ellipsis_pos(const RID &p_shaped) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataFallback invalid.");
@@ -3353,7 +3535,7 @@ int64_t TextServerFallback::shaped_text_get_ellipsis_pos(const RID &p_shaped) co
return sd->overrun_trim_data.ellipsis_pos;
}
-const Glyph *TextServerFallback::shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const {
+const Glyph *TextServerFallback::_shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V_MSG(!sd, nullptr, "ShapedTextDataFallback invalid.");
@@ -3361,7 +3543,7 @@ const Glyph *TextServerFallback::shaped_text_get_ellipsis_glyphs(const RID &p_sh
return sd->overrun_trim_data.ellipsis_glyph_buf.ptr();
}
-int64_t TextServerFallback::shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const {
+int64_t TextServerFallback::_shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V_MSG(!sd, 0, "ShapedTextDataFallback invalid.");
@@ -3369,7 +3551,7 @@ int64_t TextServerFallback::shaped_text_get_ellipsis_glyph_count(const RID &p_sh
return sd->overrun_trim_data.ellipsis_glyph_buf.size();
}
-bool TextServerFallback::shaped_text_shape(const RID &p_shaped) {
+bool TextServerFallback::_shaped_text_shape(const RID &p_shaped) {
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -3436,27 +3618,28 @@ bool TextServerFallback::shaped_text_shape(const RID &p_shaped) {
}
// Select first font which has character (font are already sorted by span language).
for (int k = 0; k < span.fonts.size(); k++) {
- if (font_has_char(span.fonts[k], gl.index)) {
+ if (_font_has_char(span.fonts[k], gl.index)) {
gl.font_rid = span.fonts[k];
break;
}
}
+ double scale = _font_get_scale(gl.font_rid, gl.font_size);
if (gl.font_rid.is_valid()) {
- bool subpos = (font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_HALF) || (font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_AUTO && gl.font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);
+ bool subpos = (scale != 1.0) || (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_AUTO && gl.font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);
if (sd->text[j - sd->start] != 0 && !is_linebreak(sd->text[j - sd->start])) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- gl.advance = Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x);
+ gl.advance = _font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x;
gl.x_off = 0;
gl.y_off = 0;
- sd->ascent = MAX(sd->ascent, font_get_ascent(gl.font_rid, gl.font_size));
- sd->descent = MAX(sd->descent, font_get_descent(gl.font_rid, gl.font_size));
+ sd->ascent = MAX(sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size));
+ sd->descent = MAX(sd->descent, _font_get_descent(gl.font_rid, gl.font_size));
} else {
- gl.advance = Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).y);
- gl.x_off = -Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5);
- gl.y_off = font_get_ascent(gl.font_rid, gl.font_size);
- 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));
+ gl.advance = _font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).y;
+ gl.x_off = -Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5);
+ gl.y_off = _font_get_ascent(gl.font_rid, gl.font_size);
+ 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));
}
}
if (j < sd->end - 1) {
@@ -3467,17 +3650,17 @@ bool TextServerFallback::shaped_text_shape(const RID &p_shaped) {
gl.advance += sd->extra_spacing[SPACING_GLYPH];
}
}
- 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));
// Add kerning to previous glyph.
if (sd->glyphs.size() > 0) {
Glyph &prev_gl = sd->glyphs.write[sd->glyphs.size() - 1];
if (prev_gl.font_rid == gl.font_rid && prev_gl.font_size == gl.font_size) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- prev_gl.advance += font_get_kerning(gl.font_rid, gl.font_size, Vector2i(prev_gl.index, gl.index)).x;
+ prev_gl.advance += _font_get_kerning(gl.font_rid, gl.font_size, Vector2i(prev_gl.index, gl.index)).x;
} else {
- prev_gl.advance += font_get_kerning(gl.font_rid, gl.font_size, Vector2i(prev_gl.index, gl.index)).y;
+ prev_gl.advance += _font_get_kerning(gl.font_rid, gl.font_size, Vector2i(prev_gl.index, gl.index)).y;
}
}
}
@@ -3508,7 +3691,7 @@ bool TextServerFallback::shaped_text_shape(const RID &p_shaped) {
return sd->valid;
}
-bool TextServerFallback::shaped_text_is_ready(const RID &p_shaped) const {
+bool TextServerFallback::_shaped_text_is_ready(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@@ -3516,41 +3699,41 @@ bool TextServerFallback::shaped_text_is_ready(const RID &p_shaped) const {
return sd->valid;
}
-const Glyph *TextServerFallback::shaped_text_get_glyphs(const RID &p_shaped) const {
+const Glyph *TextServerFallback::_shaped_text_get_glyphs(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, nullptr);
MutexLock lock(sd->mutex);
if (!sd->valid) {
- const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
return sd->glyphs.ptr();
}
-int64_t TextServerFallback::shaped_text_get_glyph_count(const RID &p_shaped) const {
+int64_t TextServerFallback::_shaped_text_get_glyph_count(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
- const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
return sd->glyphs.size();
}
-const Glyph *TextServerFallback::shaped_text_sort_logical(const RID &p_shaped) {
+const Glyph *TextServerFallback::_shaped_text_sort_logical(const RID &p_shaped) {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, nullptr);
MutexLock lock(sd->mutex);
if (!sd->valid) {
- const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
return sd->glyphs.ptr(); // Already in the logical order, return as is.
}
-Vector2i TextServerFallback::shaped_text_get_range(const RID &p_shaped) const {
+Vector2i TextServerFallback::_shaped_text_get_range(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, Vector2i());
@@ -3558,7 +3741,7 @@ Vector2i TextServerFallback::shaped_text_get_range(const RID &p_shaped) const {
return Vector2(sd->start, sd->end);
}
-Array TextServerFallback::shaped_text_get_objects(const RID &p_shaped) const {
+Array TextServerFallback::_shaped_text_get_objects(const RID &p_shaped) const {
Array ret;
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, ret);
@@ -3571,25 +3754,25 @@ Array TextServerFallback::shaped_text_get_objects(const RID &p_shaped) const {
return ret;
}
-Rect2 TextServerFallback::shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const {
+Rect2 TextServerFallback::_shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const {
const ShapedTextDataFallback *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<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
return sd->objects[p_key].rect;
}
-Size2 TextServerFallback::shaped_text_get_size(const RID &p_shaped) const {
+Size2 TextServerFallback::_shaped_text_get_size(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, Size2());
MutexLock lock(sd->mutex);
if (!sd->valid) {
- const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) {
return Size2(sd->width, sd->ascent + sd->descent + sd->extra_spacing[SPACING_TOP] + sd->extra_spacing[SPACING_BOTTOM]).ceil();
@@ -3598,64 +3781,64 @@ Size2 TextServerFallback::shaped_text_get_size(const RID &p_shaped) const {
}
}
-double TextServerFallback::shaped_text_get_ascent(const RID &p_shaped) const {
+double TextServerFallback::_shaped_text_get_ascent(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
- const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
return sd->ascent + sd->extra_spacing[SPACING_TOP];
}
-double TextServerFallback::shaped_text_get_descent(const RID &p_shaped) const {
+double TextServerFallback::_shaped_text_get_descent(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
- const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
return sd->descent + sd->extra_spacing[SPACING_BOTTOM];
}
-double TextServerFallback::shaped_text_get_width(const RID &p_shaped) const {
+double TextServerFallback::_shaped_text_get_width(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
- const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
return Math::ceil(sd->width);
}
-double TextServerFallback::shaped_text_get_underline_position(const RID &p_shaped) const {
+double TextServerFallback::_shaped_text_get_underline_position(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
- const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
return sd->upos;
}
-double TextServerFallback::shaped_text_get_underline_thickness(const RID &p_shaped) const {
+double TextServerFallback::_shaped_text_get_underline_thickness(const RID &p_shaped) const {
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.0);
MutexLock lock(sd->mutex);
if (!sd->valid) {
- const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
}
return sd->uthk;
}
-String TextServerFallback::string_to_upper(const String &p_string, const String &p_language) const {
+String TextServerFallback::_string_to_upper(const String &p_string, const String &p_language) const {
String upper = p_string;
for (int i = 0; i <= upper.length(); i++) {
@@ -3669,7 +3852,7 @@ String TextServerFallback::string_to_upper(const String &p_string, const String
return upper;
}
-String TextServerFallback::string_to_lower(const String &p_string, const String &p_language) const {
+String TextServerFallback::_string_to_lower(const String &p_string, const String &p_language) const {
String lower = p_string;
for (int i = 0; i <= lower.length(); i++) {
@@ -3683,7 +3866,7 @@ String TextServerFallback::string_to_lower(const String &p_string, const String
return lower;
}
-PackedInt32Array TextServerFallback::string_get_word_breaks(const String &p_string, const String &p_language) const {
+PackedInt32Array TextServerFallback::_string_get_word_breaks(const String &p_string, const String &p_language) const {
PackedInt32Array ret;
for (int i = 0; i < p_string.length(); i++) {
char32_t c = p_string[i];
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index fef19d442b..7e0bc99618 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.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>
@@ -52,6 +53,7 @@
#include <godot_cpp/variant/rect2.hpp>
#include <godot_cpp/variant/rid.hpp>
#include <godot_cpp/variant/string.hpp>
+#include <godot_cpp/variant/typed_array.hpp>
#include <godot_cpp/variant/vector2.hpp>
#include <godot_cpp/variant/vector2i.hpp>
@@ -79,12 +81,13 @@ using namespace godot;
#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 "modules/modules_enabled.gen.h" // For freetype, msdfgen.
+#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg.
#endif
@@ -98,6 +101,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.
@@ -124,20 +128,86 @@ class TextServerFallback : 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 {
@@ -158,7 +228,7 @@ class TextServerFallback : public TextServerExtension {
Vector2i size;
- Vector<FontTexture> textures;
+ Vector<ShelfPackTexture> textures;
HashMap<int32_t, FontGlyph> glyph_map;
HashMap<Vector2i, Vector2> kerning_map;
@@ -179,7 +249,7 @@ class TextServerFallback : public TextServerExtension {
struct FontFallback {
Mutex mutex;
- bool antialiased = true;
+ TextServer::FontAntialiasing antialiasing = TextServer::FONT_ANTIALIASING_GRAY;
bool mipmaps = false;
bool msdf = false;
int msdf_range = 14;
@@ -225,7 +295,7 @@ class TextServerFallback : public TextServerExtension {
_FORCE_INLINE_ FontGlyph rasterize_msdf(FontFallback *p_font_data, FontForSizeFallback *p_data, int p_pixel_range, int p_rect_margin, FT_Outline *outline, const Vector2 &advance) const;
#endif
#ifdef MODULE_FREETYPE_ENABLED
- _FORCE_INLINE_ FontGlyph rasterize_bitmap(FontForSizeFallback *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance) const;
+ _FORCE_INLINE_ FontGlyph rasterize_bitmap(FontForSizeFallback *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance, bool p_bgra) const;
#endif
_FORCE_INLINE_ bool _ensure_glyph(FontFallback *p_font_data, const Vector2i &p_size, int32_t p_glyph) const;
_FORCE_INLINE_ bool _ensure_cache_for_size(FontFallback *p_font_data, const Vector2i &p_size) const;
@@ -337,251 +407,249 @@ protected:
void invalidate(ShapedTextDataFallback *p_shaped);
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 {
- return "";
- };
- virtual String get_support_data_info() const override {
- return "Not supported";
- };
- 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);
+
+ MODBIND2(font_set_face_index, const RID &, int64_t);
+ MODBIND1RC(int64_t, font_get_face_index, const RID &);
- 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;
+ MODBIND1RC(int64_t, font_get_face_count, const RID &);
- virtual int64_t font_get_face_count(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(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_name, const RID &, const String &);
+ MODBIND1RC(String, font_get_style_name, 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_name, const RID &, const String &);
+ MODBIND1RC(String, font_get_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_antialiasing, const RID &, TextServer::FontAntialiasing);
+ MODBIND1RC(TextServer::FontAntialiasing, font_get_antialiasing, const RID &);
- virtual void font_set_antialiased(const RID &p_font_rid, bool p_antialiased) override;
- virtual bool font_is_antialiased(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_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_multichannel_signed_distance_field, const RID &, bool);
+ MODBIND1RC(bool, font_is_multichannel_signed_distance_field, 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_msdf_pixel_range, const RID &, int64_t);
+ MODBIND1RC(int64_t, font_get_msdf_pixel_range, 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_size, const RID &, int64_t);
+ MODBIND1RC(int64_t, font_get_msdf_size, 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_fixed_size, const RID &, int64_t);
+ MODBIND1RC(int64_t, font_get_fixed_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_force_autohinter, const RID &, bool);
+ MODBIND1RC(bool, font_is_force_autohinter, 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_subpixel_positioning, const RID &, SubpixelPositioning);
+ MODBIND1RC(SubpixelPositioning, font_get_subpixel_positioning, 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_embolden, const RID &, double);
+ MODBIND1RC(double, font_get_embolden, 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_transform, const RID &, const Transform2D &);
+ MODBIND1RC(Transform2D, font_get_transform, 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_variation_coordinates, const RID &, const Dictionary &);
+ MODBIND1RC(Dictionary, font_get_variation_coordinates, 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_hinting, const RID &, TextServer::Hinting);
+ MODBIND1RC(TextServer::Hinting, font_get_hinting, 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_oversampling, const RID &, double);
+ MODBIND1RC(double, font_get_oversampling, 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;
+ 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 Array 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;
+ MODBIND3(font_set_ascent, const RID &, int64_t, double);
+ MODBIND2RC(double, font_get_ascent, const RID &, int64_t);
- 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_descent, const RID &, int64_t, double);
+ MODBIND2RC(double, font_get_descent, 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_underline_position, const RID &, int64_t, double);
+ MODBIND2RC(double, font_get_underline_position, 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_thickness, const RID &, int64_t, double);
+ MODBIND2RC(double, font_get_underline_thickness, 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_scale, const RID &, int64_t, double);
+ MODBIND2RC(double, font_get_scale, 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;
+ 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 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;
+ 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_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_offsets, const RID &, const Vector2i &, int64_t, const PackedInt32Array &);
+ MODBIND3RC(PackedInt32Array, font_get_texture_offsets, 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;
+ 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 Array 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;
+ 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_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_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_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_size, const RID &, const Vector2i &, int64_t);
+ MODBIND4(font_set_glyph_size, 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(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 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(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 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;
- 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 Array 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 Array &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 Array &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 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 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 &);
TextServerFallback();
~TextServerFallback();
diff --git a/modules/text_server_fb/thorvg_bounds_iterator.cpp b/modules/text_server_fb/thorvg_bounds_iterator.cpp
new file mode 100644
index 0000000000..54a6136134
--- /dev/null
+++ b/modules/text_server_fb/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_fb/thorvg_bounds_iterator.h b/modules/text_server_fb/thorvg_bounds_iterator.h
new file mode 100644
index 0000000000..e54e30eaa2
--- /dev/null
+++ b/modules/text_server_fb/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_fb/thorvg_svg_in_ot.cpp b/modules/text_server_fb/thorvg_svg_in_ot.cpp
new file mode 100644
index 0000000000..7863ab67fa
--- /dev/null
+++ b/modules/text_server_fb/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_fb/thorvg_svg_in_ot.h b/modules/text_server_fb/thorvg_svg_in_ot.h
new file mode 100644
index 0000000000..b2816193d9
--- /dev/null
+++ b/modules/text_server_fb/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