summaryrefslogtreecommitdiff
path: root/modules/text_server_adv
diff options
context:
space:
mode:
Diffstat (limited to 'modules/text_server_adv')
-rw-r--r--modules/text_server_adv/SCsub62
-rw-r--r--modules/text_server_adv/bitmap_font_adv.cpp19
-rw-r--r--modules/text_server_adv/bitmap_font_adv.h7
-rw-r--r--modules/text_server_adv/dynamic_font_adv.cpp134
-rw-r--r--modules/text_server_adv/dynamic_font_adv.h15
-rw-r--r--modules/text_server_adv/font_adv.h8
-rw-r--r--modules/text_server_adv/icu_data/icudata_stub.cpp4
-rw-r--r--modules/text_server_adv/register_types.cpp4
-rw-r--r--modules/text_server_adv/register_types.h4
-rw-r--r--modules/text_server_adv/script_iterator.cpp7
-rw-r--r--modules/text_server_adv/script_iterator.h4
-rw-r--r--modules/text_server_adv/text_server_adv.cpp237
-rw-r--r--modules/text_server_adv/text_server_adv.h8
13 files changed, 313 insertions, 200 deletions
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index 7403b01a4c..3589c8546d 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -35,10 +35,14 @@ def make_icu_data(target, source, env):
g.write("#endif")
+# Thirdparty source files
+
+thirdparty_obj = []
+
if env["builtin_harfbuzz"]:
env_harfbuzz = env_modules.Clone()
+ env_harfbuzz.disable_warnings()
- # Thirdparty source files
thirdparty_dir = "#thirdparty/harfbuzz/"
thirdparty_sources = [
"src/hb-aat-layout.cc",
@@ -107,6 +111,15 @@ if env["builtin_harfbuzz"]:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+ env_harfbuzz.Append(
+ CPPPATH=[
+ "#thirdparty/harfbuzz/src",
+ "#thirdparty/freetype/include",
+ "#thirdparty/graphite/include",
+ "#thirdparty/icu4c/common/",
+ ]
+ )
+
if env["platform"] == "android" or env["platform"] == "linuxbsd" or env["platform"] == "server":
env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
@@ -117,14 +130,6 @@ if env["builtin_harfbuzz"]:
env_harfbuzz.Append(CCFLAGS=["-DHB_NO_MT"])
env_harfbuzz.Append(
- CPPPATH=[
- "#thirdparty/harfbuzz/src",
- "#thirdparty/freetype/include",
- "#thirdparty/graphite/include",
- "#thirdparty/icu4c/common/",
- ]
- )
- env_harfbuzz.Append(
CCFLAGS=[
"-DHAVE_ICU_BUILTIN",
"-DHAVE_ICU",
@@ -133,10 +138,9 @@ if env["builtin_harfbuzz"]:
"-DGRAPHITE2_STATIC",
]
)
- env_harfbuzz.disable_warnings()
- env_thirdparty = env_harfbuzz.Clone()
- env_thirdparty.disable_warnings()
- lib = env_thirdparty.add_library("harfbuzz_builtin", thirdparty_sources)
+
+ lib = env_harfbuzz.add_library("harfbuzz_builtin", thirdparty_sources)
+ thirdparty_obj += lib
# Needs to be appended to arrive after libscene in the linker call,
# but we don't want it to arrive *after* system libs, so manual hack
@@ -151,10 +155,11 @@ if env["builtin_harfbuzz"]:
if not inserted:
env.Append(LIBS=[lib])
+
if env["builtin_graphite"]:
env_graphite = env_modules.Clone()
+ env_graphite.disable_warnings()
- # Thirdparty source files
thirdparty_dir = "#thirdparty/graphite/"
thirdparty_sources = [
"src/gr_char_info.cpp",
@@ -203,10 +208,9 @@ if env["builtin_graphite"]:
"-DGRAPHITE2_NFILEFACE",
]
)
- env_graphite.disable_warnings()
- env_thirdparty = env_graphite.Clone()
- env_thirdparty.disable_warnings()
- lib = env_thirdparty.add_library("graphite_builtin", thirdparty_sources)
+
+ lib = env_graphite.add_library("graphite_builtin", thirdparty_sources)
+ thirdparty_obj += lib
# Needs to be appended to arrive after libscene in the linker call,
# but we don't want it to arrive *after* system libs, so manual hack
@@ -221,12 +225,12 @@ if env["builtin_graphite"]:
if not inserted:
env.Append(LIBS=[lib])
+
if env["builtin_icu"]:
env_icu = env_modules.Clone()
+ env_icu.disable_warnings()
- # Thirdparty source files
thirdparty_dir = "#thirdparty/icu4c/"
- # Thirdparty source files
thirdparty_sources = [
"common/appendable.cpp",
"common/bmpset.cpp",
@@ -457,10 +461,8 @@ if env["builtin_icu"]:
]
)
- env_icu.disable_warnings()
- env_thirdparty = env_icu.Clone()
- env_thirdparty.disable_warnings()
- lib = env_thirdparty.add_library("icu_builtin", thirdparty_sources)
+ lib = env_icu.add_library("icu_builtin", thirdparty_sources)
+ thirdparty_obj += lib
# Needs to be appended to arrive after libscene in the linker call,
# but we don't want it to arrive *after* system libs, so manual hack
@@ -475,6 +477,11 @@ if env["builtin_icu"]:
if not inserted:
env.Append(LIBS=[lib])
+
+# Godot source files
+
+module_obj = []
+
if env_text_server_adv["tools"]:
env_text_server_adv.Append(CXXFLAGS=["-DICU_STATIC_DATA"])
@@ -486,4 +493,9 @@ env_text_server_adv.Append(
"#thirdparty/icu4c/common/",
]
)
-env_text_server_adv.add_source_files(env.modules_sources, "*.cpp")
+
+env_text_server_adv.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/text_server_adv/bitmap_font_adv.cpp b/modules/text_server_adv/bitmap_font_adv.cpp
index 10c3732fd7..01fa94aa7c 100644
--- a/modules/text_server_adv/bitmap_font_adv.cpp
+++ b/modules/text_server_adv/bitmap_font_adv.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 */
@@ -175,8 +175,9 @@ static hb_bool_t hb_bmp_get_font_h_extents(hb_font_t *font, void *font_data, hb_
return true;
}
-static hb_font_funcs_t *_hb_bmp_get_font_funcs() {
- hb_font_funcs_t *funcs = hb_font_funcs_create();
+static hb_font_funcs_t *funcs = nullptr;
+void hb_bmp_create_font_funcs() {
+ funcs = hb_font_funcs_create();
hb_font_funcs_set_font_h_extents_func(funcs, hb_bmp_get_font_h_extents, nullptr, nullptr);
//hb_font_funcs_set_font_v_extents_func (funcs, hb_bmp_get_font_v_extents, nullptr, nullptr);
@@ -194,12 +195,17 @@ static hb_font_funcs_t *_hb_bmp_get_font_funcs() {
//hb_font_funcs_set_glyph_from_name_func (funcs, hb_bmp_get_glyph_from_name, nullptr, nullptr);
hb_font_funcs_make_immutable(funcs);
+}
- return funcs;
+void hb_bmp_free_font_funcs() {
+ if (funcs != nullptr) {
+ hb_font_funcs_destroy(funcs);
+ funcs = nullptr;
+ }
}
static void _hb_bmp_font_set_funcs(hb_font_t *p_font, BitmapFontDataAdvanced *p_face, int p_size, bool p_unref) {
- hb_font_set_funcs(p_font, _hb_bmp_get_font_funcs(), _hb_bmp_font_create(p_face, p_size, p_unref), _hb_bmp_font_destroy);
+ hb_font_set_funcs(p_font, funcs, _hb_bmp_font_create(p_face, p_size, p_unref), _hb_bmp_font_destroy);
}
hb_font_t *hb_bmp_font_create(BitmapFontDataAdvanced *p_face, int p_size, hb_destroy_func_t p_destroy) {
@@ -384,7 +390,6 @@ Error BitmapFontDataAdvanced::load_from_memory(const uint8_t *p_data, size_t p_s
chr.rect.position.y = c[2];
chr.rect.size.x = c[3];
chr.rect.size.y = c[4];
- chr.texture_idx = 0;
if (c[7] < 0) {
chr.advance.x = c[3];
} else {
diff --git a/modules/text_server_adv/bitmap_font_adv.h b/modules/text_server_adv/bitmap_font_adv.h
index b2fe7f43af..c314f1b087 100644
--- a/modules/text_server_adv/bitmap_font_adv.h
+++ b/modules/text_server_adv/bitmap_font_adv.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 */
@@ -33,6 +33,9 @@
#include "font_adv.h"
+void hb_bmp_create_font_funcs();
+void hb_bmp_free_font_funcs();
+
struct BitmapFontDataAdvanced : public FontDataAdvanced {
_THREAD_SAFE_CLASS_
diff --git a/modules/text_server_adv/dynamic_font_adv.cpp b/modules/text_server_adv/dynamic_font_adv.cpp
index 90e5cc8831..fcefa60d98 100644
--- a/modules/text_server_adv/dynamic_font_adv.cpp
+++ b/modules/text_server_adv/dynamic_font_adv.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 */
@@ -32,8 +32,7 @@
#include FT_STROKER_H
#include FT_ADVANCES_H
-
-HashMap<String, Vector<uint8_t>> DynamicFontDataAdvanced::font_mem_cache;
+#include FT_MULTIPLE_MASTERS_H
DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(int p_size, int p_outline_size) {
ERR_FAIL_COND_V(!valid, nullptr);
@@ -55,11 +54,10 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(
if (E != nullptr) {
fds = E->get();
} else {
- // FT_OPEN_STREAM is extremely slow only on Android.
- if (OS::get_singleton()->get_name() == "Android" && font_mem == nullptr && font_path != String()) {
- if (font_mem_cache.has(font_path)) {
- font_mem = font_mem_cache[font_path].ptr();
- font_mem_size = font_mem_cache[font_path].size();
+ if (font_mem == nullptr && font_path != String()) {
+ if (!font_mem_cache.is_empty()) {
+ font_mem = font_mem_cache.ptr();
+ font_mem_size = font_mem_cache.size();
} else {
FileAccess *f = FileAccess::open(font_path, FileAccess::READ);
if (!f) {
@@ -67,11 +65,9 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(
}
size_t len = f->get_len();
- font_mem_cache[font_path] = Vector<uint8_t>();
- Vector<uint8_t> &fontdata = font_mem_cache[font_path];
- fontdata.resize(len);
- f->get_buffer(fontdata.ptrw(), len);
- font_mem = fontdata.ptr();
+ font_mem_cache.resize(len);
+ f->get_buffer(font_mem_cache.ptrw(), len);
+ font_mem = font_mem_cache.ptr();
font_mem_size = len;
f->close();
}
@@ -79,27 +75,7 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(
int error = 0;
fds = memnew(DataAtSize);
- if (font_mem == nullptr && font_path != String()) {
- FileAccess *f = FileAccess::open(font_path, FileAccess::READ);
- if (!f) {
- memdelete(fds);
- ERR_FAIL_V_MSG(nullptr, "Cannot open font file '" + font_path + "'.");
- }
-
- memset(&fds->stream, 0, sizeof(FT_StreamRec));
- fds->stream.base = nullptr;
- fds->stream.size = f->get_len();
- fds->stream.pos = 0;
- fds->stream.descriptor.pointer = f;
- fds->stream.read = _ft_stream_io;
- fds->stream.close = _ft_stream_close;
-
- FT_Open_Args fargs;
- memset(&fargs, 0, sizeof(FT_Open_Args));
- fargs.flags = FT_OPEN_STREAM;
- fargs.stream = &fds->stream;
- error = FT_Open_Face(library, &fargs, 0, &fds->face);
- } else if (font_mem) {
+ if (font_mem) {
memset(&fds->stream, 0, sizeof(FT_StreamRec));
fds->stream.base = (unsigned char *)font_mem;
fds->stream.size = font_mem_size;
@@ -159,33 +135,89 @@ DynamicFontDataAdvanced::DataAtSize *DynamicFontDataAdvanced::get_data_for_size(
memdelete(fds);
ERR_FAIL_V_MSG(nullptr, "Error loading HB font.");
}
+
if (p_outline_size != 0) {
size_cache_outline[id] = fds;
} else {
size_cache[id] = fds;
}
- }
+ // Write variations.
+ if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
+ FT_MM_Var *amaster;
+
+ FT_Get_MM_Var(fds->face, &amaster);
+
+ Vector<hb_variation_t> hb_vars;
+ Vector<FT_Fixed> coords;
+ coords.resize(amaster->num_axis);
+
+ FT_Get_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw());
+
+ for (FT_UInt i = 0; i < amaster->num_axis; i++) {
+ hb_variation_t var;
+
+ // Reset to default.
+ var.tag = amaster->axis[i].tag;
+ var.value = (double)amaster->axis[i].def / 65536.f;
+ coords.write[i] = amaster->axis[i].def;
+
+ if (variations.has(var.tag)) {
+ var.value = variations[var.tag];
+ coords.write[i] = CLAMP(variations[var.tag] * 65536.f, amaster->axis[i].minimum, amaster->axis[i].maximum);
+ }
+
+ hb_vars.push_back(var);
+ }
+
+ FT_Set_Var_Design_Coordinates(fds->face, coords.size(), coords.ptrw());
+ hb_font_set_variations(fds->hb_handle, hb_vars.is_empty() ? nullptr : &hb_vars[0], hb_vars.size());
+
+ FT_Done_MM_Var(library, amaster);
+ }
+ }
return fds;
}
-unsigned long DynamicFontDataAdvanced::_ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count) {
- FileAccess *f = (FileAccess *)stream->descriptor.pointer;
-
- if (f->get_position() != offset) {
- f->seek(offset);
+Dictionary DynamicFontDataAdvanced::get_variation_list() const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
+ if (fds == nullptr) {
+ return Dictionary();
}
- if (count == 0) {
- return 0;
+
+ Dictionary ret;
+ // Read variations.
+ if (fds->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
+ FT_MM_Var *amaster;
+
+ FT_Get_MM_Var(fds->face, &amaster);
+
+ for (FT_UInt i = 0; i < amaster->num_axis; i++) {
+ ret[(int32_t)amaster->axis[i].tag] = Vector3i(amaster->axis[i].minimum / 65536, amaster->axis[i].maximum / 65536, amaster->axis[i].def / 65536);
+ }
+
+ FT_Done_MM_Var(library, amaster);
}
+ return ret;
+}
- return f->get_buffer(buffer, count);
+void DynamicFontDataAdvanced::set_variation(const String &p_name, double p_value) {
+ _THREAD_SAFE_METHOD_
+ int32_t tag = TS->name_to_tag(p_name);
+ if (!variations.has(tag) || (variations[tag] != p_value)) {
+ variations[tag] = p_value;
+ clear_cache();
+ }
}
-void DynamicFontDataAdvanced::_ft_stream_close(FT_Stream stream) {
- FileAccess *f = (FileAccess *)stream->descriptor.pointer;
- f->close();
- memdelete(f);
+double DynamicFontDataAdvanced::get_variation(const String &p_name) const {
+ _THREAD_SAFE_METHOD_
+ int32_t tag = TS->name_to_tag(p_name);
+ if (!variations.has(tag)) {
+ return 0.f;
+ }
+ return variations[tag];
}
Dictionary DynamicFontDataAdvanced::get_feature_list() const {
@@ -222,8 +254,6 @@ Dictionary DynamicFontDataAdvanced::get_feature_list() const {
DynamicFontDataAdvanced::TexturePosition DynamicFontDataAdvanced::find_texture_pos_for_glyph(DynamicFontDataAdvanced::DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height) {
TexturePosition ret;
ret.index = -1;
- ret.x = 0;
- ret.y = 0;
int mw = p_width;
int mh = p_height;
@@ -402,8 +432,8 @@ DynamicFontDataAdvanced::Character DynamicFontDataAdvanced::bitmap_to_character(
}
Character chr;
- chr.align = Vector2(xofs, -yofs) * p_data->scale_color_font / oversampling;
- chr.advance = advance * p_data->scale_color_font / oversampling;
+ chr.align = (Vector2(xofs, -yofs) * p_data->scale_color_font / oversampling).round();
+ chr.advance = (advance * p_data->scale_color_font / oversampling).round();
chr.texture_idx = tex_pos.index;
chr.found = true;
diff --git a/modules/text_server_adv/dynamic_font_adv.h b/modules/text_server_adv/dynamic_font_adv.h
index 61cff3cde9..c35dd9390b 100644
--- a/modules/text_server_adv/dynamic_font_adv.h
+++ b/modules/text_server_adv/dynamic_font_adv.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 */
@@ -116,7 +116,9 @@ private:
const uint8_t *font_mem = nullptr;
int font_mem_size = 0;
String font_path;
- static HashMap<String, Vector<uint8_t>> font_mem_cache;
+ Vector<uint8_t> font_mem_cache;
+
+ Map<int32_t, double> variations;
float rect_margin = 1.f;
int base_size = 16;
@@ -128,9 +130,6 @@ private:
Map<CacheID, DataAtSize *> size_cache;
Map<CacheID, DataAtSize *> size_cache_outline;
- static unsigned long _ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count);
- static void _ft_stream_close(FT_Stream stream);
-
DataAtSize *get_data_for_size(int p_size, int p_outline_size = 0);
TexturePosition find_texture_pos_for_glyph(DataAtSize *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height);
@@ -149,6 +148,10 @@ public:
virtual float get_descent(int p_size) const override;
virtual Dictionary get_feature_list() const override;
+ virtual Dictionary get_variation_list() const override;
+
+ virtual void set_variation(const String &p_name, double p_value) override;
+ virtual double get_variation(const String &p_name) const override;
virtual float get_underline_position(int p_size) const override;
virtual float get_underline_thickness(int p_size) const override;
diff --git a/modules/text_server_adv/font_adv.h b/modules/text_server_adv/font_adv.h
index 232d6d7d08..4bbd2dd4bf 100644
--- a/modules/text_server_adv/font_adv.h
+++ b/modules/text_server_adv/font_adv.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 */
@@ -50,6 +50,10 @@ struct FontDataAdvanced {
virtual float get_descent(int p_size) const = 0;
virtual Dictionary get_feature_list() const { return Dictionary(); };
+ virtual Dictionary get_variation_list() const { return Dictionary(); };
+
+ virtual void set_variation(const String &p_name, double p_value){};
+ virtual double get_variation(const String &p_name) const { return 0; };
virtual float get_underline_position(int p_size) const = 0;
virtual float get_underline_thickness(int p_size) const = 0;
diff --git a/modules/text_server_adv/icu_data/icudata_stub.cpp b/modules/text_server_adv/icu_data/icudata_stub.cpp
index 13f0ac0c50..187001f33a 100644
--- a/modules/text_server_adv/icu_data/icudata_stub.cpp
+++ b/modules/text_server_adv/icu_data/icudata_stub.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 */
diff --git a/modules/text_server_adv/register_types.cpp b/modules/text_server_adv/register_types.cpp
index 68117e0380..abefa83b9b 100644
--- a/modules/text_server_adv/register_types.cpp
+++ b/modules/text_server_adv/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 */
diff --git a/modules/text_server_adv/register_types.h b/modules/text_server_adv/register_types.h
index 8319ddfd5d..ddd1190f40 100644
--- a/modules/text_server_adv/register_types.h
+++ b/modules/text_server_adv/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 */
diff --git a/modules/text_server_adv/script_iterator.cpp b/modules/text_server_adv/script_iterator.cpp
index 8a2b2cced0..8f23bb9e02 100644
--- a/modules/text_server_adv/script_iterator.cpp
+++ b/modules/text_server_adv/script_iterator.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 */
@@ -56,11 +56,12 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
int paren_sp = -1;
int start_sp = paren_sp;
UErrorCode err = U_ZERO_ERROR;
+ const char32_t *str = p_string.ptr();
do {
script_code = USCRIPT_COMMON;
for (script_start = script_end; script_end < p_length; script_end++) {
- UChar32 ch = p_string[script_end];
+ UChar32 ch = str[script_end];
UScriptCode sc = uscript_getScript(ch, &err);
if (U_FAILURE(err)) {
ERR_FAIL_MSG(u_errorName(err));
diff --git a/modules/text_server_adv/script_iterator.h b/modules/text_server_adv/script_iterator.h
index 4523aa2767..ad476f7c75 100644
--- a/modules/text_server_adv/script_iterator.h
+++ b/modules/text_server_adv/script_iterator.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 */
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index e391777eea..8b05611089 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 */
@@ -132,7 +132,7 @@ _FORCE_INLINE_ bool is_linebreak(char32_t p_char) {
/*************************************************************************/
String TextServerAdvanced::interface_name = "ICU / HarfBuzz / Graphite";
-uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA;
+uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA | FEATURE_FONT_VARIABLE;
bool TextServerAdvanced::has_feature(Feature p_feature) {
return (interface_features & p_feature) == p_feature;
@@ -171,7 +171,7 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) {
}
#else
if (icu_data == nullptr) {
- String filename = (p_filename.empty()) ? String("res://") + _MKSTR(ICU_DATA_NAME) : p_filename;
+ String filename = (p_filename.is_empty()) ? String("res://") + _MKSTR(ICU_DATA_NAME) : p_filename;
FileAccess *f = FileAccess::open(filename, FileAccess::READ);
if (!f) {
@@ -622,6 +622,27 @@ bool TextServerAdvanced::font_get_antialiased(RID p_font) const {
return fd->get_antialiased();
}
+Dictionary TextServerAdvanced::font_get_variation_list(RID p_font) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, Dictionary());
+ return fd->get_variation_list();
+}
+
+void TextServerAdvanced::font_set_variation(RID p_font, const String &p_name, double p_value) {
+ _THREAD_SAFE_METHOD_
+ FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND(!fd);
+ fd->set_variation(p_name, p_value);
+}
+
+double TextServerAdvanced::font_get_variation(RID p_font, const String &p_name) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, 0);
+ return fd->get_variation(p_name);
+}
+
void TextServerAdvanced::font_set_distance_field_hint(RID p_font, bool p_distance_field) {
_THREAD_SAFE_METHOD_
FontDataAdvanced *fd = font_owner.getornull(p_font);
@@ -1040,7 +1061,7 @@ bool TextServerAdvanced::shaped_text_add_string(RID p_shaped, const String &p_te
ERR_FAIL_COND_V(!sd, false);
ERR_FAIL_COND_V(p_size <= 0, false);
- if (p_text.empty()) {
+ if (p_text.is_empty()) {
return true;
}
@@ -1108,7 +1129,9 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
sd->width = 0;
sd->upos = 0;
sd->uthk = 0;
- for (int i = 0; i < sd->glyphs.size(); i++) {
+ int sd_size = sd->glyphs.size();
+
+ for (int i = 0; i < sd_size; i++) {
Glyph gl = sd->glyphs[i];
Variant key;
if (gl.count == 1) {
@@ -1128,8 +1151,8 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y);
} break;
case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y / 2);
- sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y / 2);
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y);
@@ -1144,8 +1167,8 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x);
} break;
case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x / 2);
- sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x / 2);
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x);
@@ -1160,19 +1183,19 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
sd->ascent = MAX(sd->ascent, MAX(fd->get_ascent(gl.font_size), -gl.y_off));
sd->descent = MAX(sd->descent, MAX(fd->get_descent(gl.font_size), gl.y_off));
} else {
- sd->ascent = MAX(sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
- sd->descent = MAX(sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
+ sd->ascent = MAX(sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ sd->descent = MAX(sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).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));
} 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) {
- sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f);
- sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f);
+ sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
+ sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
} else {
- sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
- sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
+ sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
+ sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
}
}
sd->width += gl.advance * gl.repeat;
@@ -1248,6 +1271,11 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
new_sd->utf16 = new_sd->text.utf16();
new_sd->script_iter = memnew(ScriptIterator(new_sd->text, 0, new_sd->text.length()));
+ int sd_size = sd->glyphs.size();
+ const Glyph *sd_glyphs = sd->glyphs.ptr();
+ const FontDataAdvanced *fd = nullptr;
+ RID prev_rid = RID();
+
for (int ov = 0; ov < sd->bidi_override.size(); ov++) {
UErrorCode err = U_ZERO_ERROR;
@@ -1280,21 +1308,23 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
int32_t bidi_run_start = _convert_pos(sd, sd->bidi_override[ov].x + start + _bidi_run_start);
int32_t bidi_run_end = _convert_pos(sd, sd->bidi_override[ov].x + start + _bidi_run_start + _bidi_run_length);
- for (int j = 0; j < sd->glyphs.size(); j++) {
- if ((sd->glyphs[j].start >= bidi_run_start) && (sd->glyphs[j].end <= bidi_run_end)) {
+ for (int j = 0; j < sd_size; j++) {
+ if ((sd_glyphs[j].start >= bidi_run_start) && (sd_glyphs[j].end <= bidi_run_end)) {
// Copy glyphs.
- Glyph gl = sd->glyphs[j];
+ Glyph gl = sd_glyphs[j];
Variant key;
+ bool find_embedded = false;
if (gl.count == 1) {
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
if (E->get().pos == gl.start) {
+ find_embedded = true;
key = E->key();
new_sd->objects[key] = E->get();
break;
}
}
}
- if (key != Variant()) {
+ if (find_embedded) {
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
new_sd->objects[key].rect.position.x = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.x;
@@ -1303,8 +1333,8 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y);
} break;
case VALIGN_CENTER: {
- new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y / 2);
- new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y / 2);
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2));
+ new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y);
@@ -1318,8 +1348,8 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x);
} break;
case VALIGN_CENTER: {
- new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x / 2);
- new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x / 2);
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2));
+ new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x);
@@ -1327,23 +1357,26 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
}
}
} else {
- const FontDataAdvanced *fd = font_owner.getornull(gl.font_rid);
+ if (prev_rid != gl.font_rid) {
+ fd = font_owner.getornull(gl.font_rid);
+ prev_rid = gl.font_rid;
+ }
if (fd != nullptr) {
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
new_sd->ascent = MAX(new_sd->ascent, MAX(fd->get_ascent(gl.font_size), -gl.y_off));
new_sd->descent = MAX(new_sd->descent, MAX(fd->get_descent(gl.font_size), gl.y_off));
} else {
- new_sd->ascent = MAX(new_sd->ascent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
- new_sd->descent = MAX(new_sd->descent, fd->get_advance(gl.index, gl.font_size).x * 0.5);
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(fd->get_advance(gl.index, gl.font_size).x * 0.5));
+ new_sd->descent = MAX(new_sd->descent, Math::round(fd->get_advance(gl.index, gl.font_size).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.
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
- new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f);
- new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f);
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
+ new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
} else {
- new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
- new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
+ new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
+ new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
}
}
new_sd->width += gl.advance * gl.repeat;
@@ -1491,9 +1524,9 @@ float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width,
if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
float old_adv = gl.advance;
if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
- gl.advance = MAX(gl.advance + delta_width_per_space, 0.f);
+ gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.f));
} else {
- gl.advance = MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size);
+ gl.advance = Math::round(MAX(gl.advance + delta_width_per_space, 0.05 * gl.font_size));
}
sd->width += (gl.advance - old_adv);
}
@@ -1529,8 +1562,10 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<float
delta = -1;
}
+ Glyph *gl = sd->glyphs.ptrw();
+
for (int i = start; i != end; i += delta) {
- if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
+ if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
float tab_off = 0.f;
while (tab_off <= off) {
tab_off += p_tab_stops[tab_index];
@@ -1539,13 +1574,13 @@ float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<float
tab_index = 0;
}
}
- float old_adv = sd->glyphs.write[i].advance;
- sd->glyphs.write[i].advance = (tab_off - off);
- sd->width += sd->glyphs.write[i].advance - old_adv;
+ float old_adv = gl[i].advance;
+ gl[i].advance = tab_off - off;
+ sd->width += gl[i].advance - old_adv;
off = 0;
continue;
}
- off += sd->glyphs[i].advance * sd->glyphs[i].repeat;
+ off += gl[i].advance * gl[i].repeat;
}
return 0.f;
@@ -1565,8 +1600,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
const UChar *data = sd->utf16.ptr();
- Map<int, bool> breaks;
-
+ HashMap<int, bool> breaks;
UErrorCode err = U_ZERO_ERROR;
for (int i = 0; i < sd->spans.size(); i++) {
UBreakIterator *bi = ubrk_open(UBRK_LINE, sd->spans[i].language.ascii().get_data(), data + _convert_pos_inv(sd, sd->spans[i].start), _convert_pos_inv(sd, sd->spans[i].end - sd->spans[i].start), &err);
@@ -1598,40 +1632,52 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
sd->sort_valid = false;
sd->glyphs_logical.clear();
+ int sd_size = sd->glyphs.size();
+ const char32_t *ch = sd->text.ptr();
+ Glyph *sd_glyphs = sd->glyphs.ptrw();
- for (int i = 0; i < sd->glyphs.size(); i++) {
- if (sd->glyphs[i].count > 0) {
- char32_t c = sd->text[sd->glyphs[i].start - sd->start];
+ for (int i = 0; i < sd_size; i++) {
+ if (sd_glyphs[i].count > 0) {
+ char32_t c = ch[sd_glyphs[i].start - sd->start];
if (c == 0xfffc) {
continue;
}
if (c == 0x0009 || c == 0x000b) {
- sd->glyphs.write[i].flags |= GRAPHEME_IS_TAB;
+ sd_glyphs[i].flags |= GRAPHEME_IS_TAB;
+ }
+ if (is_whitespace(c)) {
+ sd_glyphs[i].flags |= GRAPHEME_IS_SPACE;
+ }
+ if (u_ispunct(c)) {
+ sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION;
}
if (breaks.has(sd->glyphs[i].start)) {
if (breaks[sd->glyphs[i].start]) {
- sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_HARD;
+ sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD;
} else {
if (is_whitespace(c)) {
- sd->glyphs.write[i].flags |= GRAPHEME_IS_BREAK_SOFT;
- sd->glyphs.write[i].flags |= GRAPHEME_IS_SPACE;
+ sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT;
} else {
TextServer::Glyph gl;
- gl.start = sd->glyphs[i].start;
- gl.end = sd->glyphs[i].end;
+ gl.start = sd_glyphs[i].start;
+ gl.end = sd_glyphs[i].end;
gl.count = 1;
- gl.repeat = 1;
- gl.font_rid = sd->glyphs[i].font_rid;
- gl.font_size = sd->glyphs[i].font_size;
+ gl.font_rid = sd_glyphs[i].font_rid;
+ gl.font_size = sd_glyphs[i].font_size;
gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL;
- sd->glyphs.insert(i + sd->glyphs[i].count, gl); // insert after
- i += sd->glyphs[i].count;
+ sd->glyphs.insert(i + sd_glyphs[i].count, gl); // insert after
+
+ // Update write pointer and size.
+ sd_size = sd->glyphs.size();
+ sd_glyphs = sd->glyphs.ptrw();
+
+ i += sd_glyphs[i].count;
continue;
}
}
}
- i += (sd->glyphs[i].count - 1);
+ i += (sd_glyphs[i].count - 1);
}
}
@@ -1725,6 +1771,10 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
shaped_text_update_breaks(p_shaped);
}
+ if (sd->justification_ops_valid) {
+ return true; // Noting to do.
+ }
+
const UChar *data = sd->utf16.ptr();
int32_t data_size = sd->utf16.length();
@@ -1755,9 +1805,9 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
if (ubrk_getRuleStatus(bi) != UBRK_WORD_NONE) {
int i = _convert_pos(sd, ubrk_current(bi));
jstops[i + sd->start] = false;
- int ks = _generate_kashida_justification_opportunies(sd->text, limit, i) + sd->start;
+ int ks = _generate_kashida_justification_opportunies(sd->text, limit, i);
if (ks != -1) {
- jstops[ks] = true;
+ jstops[ks + sd->start] = true;
}
limit = i;
}
@@ -1767,9 +1817,10 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
sd->sort_valid = false;
sd->glyphs_logical.clear();
+ int sd_size = sd->glyphs.size();
if (jstops.size() > 0) {
- for (int i = 0; i < sd->glyphs.size(); i++) {
+ for (int i = 0; i < sd_size; i++) {
if (sd->glyphs[i].count > 0) {
if (jstops.has(sd->glyphs[i].start)) {
char32_t c = sd->text[sd->glyphs[i].start - sd->start];
@@ -1803,7 +1854,6 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
gl.start = sd->glyphs[i].start;
gl.end = sd->glyphs[i].end;
gl.count = 1;
- gl.repeat = 1;
gl.font_rid = sd->glyphs[i].font_rid;
gl.font_size = sd->glyphs[i].font_size;
gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_VIRTUAL;
@@ -1838,8 +1888,6 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced
// Process glyphs.
TextServer::Glyph gl;
- gl.start = -1;
- gl.end = -1;
if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
gl.flags |= TextServer::GRAPHEME_IS_RTL;
@@ -1850,15 +1898,15 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced
if (glyph_count > 0) {
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
- gl.advance = glyph_pos[0].x_advance / (64.0 / fd->get_font_scale(p_font_size));
+ gl.advance = Math::round(glyph_pos[0].x_advance / (64.0 / fd->get_font_scale(p_font_size)));
} else {
- gl.advance = -glyph_pos[0].y_advance / (64.0 / fd->get_font_scale(p_font_size));
+ gl.advance = -Math::round(glyph_pos[0].y_advance / (64.0 / fd->get_font_scale(p_font_size)));
}
gl.count = 1;
gl.index = glyph_info[0].codepoint;
- gl.x_off = glyph_pos[0].x_offset / (64.0 / fd->get_font_scale(p_font_size));
- gl.y_off = -glyph_pos[0].y_offset / (64.0 / fd->get_font_scale(p_font_size));
+ gl.x_off = Math::round(glyph_pos[0].x_offset / (64.0 / fd->get_font_scale(p_font_size)));
+ gl.y_off = -Math::round(glyph_pos[0].y_offset / (64.0 / fd->get_font_scale(p_font_size)));
if ((glyph_info[0].codepoint != 0) || !u_isgraph(p_char)) {
gl.flags |= GRAPHEME_IS_VALID;
@@ -1873,8 +1921,9 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
fd = font_owner.getornull(p_fonts[p_fb_index]);
}
+ int fs = p_sd->spans[p_span].font_size;
if (fd == nullptr) {
- // Add fallback glyohs
+ // Add fallback glyphs
for (int i = p_start; i < p_end; i++) {
if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) {
TextServer::Glyph gl;
@@ -1882,20 +1931,19 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
gl.end = i + 1;
gl.count = 1;
gl.index = p_sd->text[i];
- gl.font_size = p_sd->spans[p_span].font_size;
+ gl.font_size = fs;
gl.font_rid = RID();
- gl.flags = 0;
if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
gl.flags |= TextServer::GRAPHEME_IS_RTL;
}
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
- gl.advance = get_hex_code_box_size(gl.font_size, gl.index).x;
- p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f);
- p_sd->descent = MAX(p_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f);
+ gl.advance = get_hex_code_box_size(fs, gl.index).x;
+ p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.75f));
+ p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.25f));
} else {
- gl.advance = get_hex_code_box_size(gl.font_size, gl.index).y;
- p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
- p_sd->descent = MAX(p_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f);
+ gl.advance = get_hex_code_box_size(fs, gl.index).y;
+ p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f));
+ p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f));
}
p_sd->width += gl.advance;
@@ -1905,7 +1953,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
return;
}
- hb_font_t *hb_font = fd->get_hb_handle(p_sd->spans[p_span].font_size);
+ hb_font_t *hb_font = fd->get_hb_handle(fs);
ERR_FAIL_COND(hb_font == nullptr);
hb_buffer_clear_contents(p_sd->hb_buffer);
@@ -1936,7 +1984,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
ftrs.push_back(feature);
}
}
- hb_shape(hb_font, p_sd->hb_buffer, ftrs.empty() ? nullptr : &ftrs[0], ftrs.size());
+ hb_shape(hb_font, p_sd->hb_buffer, ftrs.is_empty() ? nullptr : &ftrs[0], ftrs.size());
unsigned int glyph_count = 0;
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(p_sd->hb_buffer, &glyph_count);
@@ -1981,17 +2029,17 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
gl.count = 0;
gl.font_rid = p_fonts[p_fb_index];
- gl.font_size = p_sd->spans[p_span].font_size;
+ gl.font_size = fs;
gl.index = glyph_info[i].codepoint;
if (gl.index != 0) {
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
- gl.advance = glyph_pos[i].x_advance / (64.0 / fd->get_font_scale(gl.font_size));
+ gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / fd->get_font_scale(fs)));
} else {
- gl.advance = -glyph_pos[i].y_advance / (64.0 / fd->get_font_scale(gl.font_size));
+ gl.advance = -Math::round(glyph_pos[i].y_advance / (64.0 / fd->get_font_scale(fs)));
}
- gl.x_off = glyph_pos[i].x_offset / (64.0 / fd->get_font_scale(gl.font_size));
- gl.y_off = -glyph_pos[i].y_offset / (64.0 / fd->get_font_scale(gl.font_size));
+ gl.x_off = Math::round(glyph_pos[i].x_offset / (64.0 / fd->get_font_scale(fs)));
+ gl.y_off = -Math::round(glyph_pos[i].y_offset / (64.0 / fd->get_font_scale(fs)));
}
if (p_sd->preserve_control) {
@@ -2026,14 +2074,12 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
}
for (int j = 0; j < w[i].count; j++) {
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
- p_sd->ascent = MAX(p_sd->ascent, MAX(fd->get_ascent(w[i + j].font_size), w[i + j].y_off));
- p_sd->descent = MAX(p_sd->descent, MAX(fd->get_descent(w[i + j].font_size), w[i + j].y_off));
+ p_sd->ascent = MAX(p_sd->ascent, -w[i + j].y_off);
+ p_sd->descent = MAX(p_sd->descent, w[i + j].y_off);
} else {
- p_sd->ascent = MAX(p_sd->ascent, fd->get_advance(w[i + j].index, w[i + j].font_size).x * 0.5);
- p_sd->descent = MAX(p_sd->descent, fd->get_advance(w[i + j].index, w[i + j].font_size).x * 0.5);
+ p_sd->ascent = MAX(p_sd->ascent, Math::round(fd->get_advance(w[i + j].index, fs).x * 0.5));
+ p_sd->descent = MAX(p_sd->descent, Math::round(fd->get_advance(w[i + j].index, fs).x * 0.5));
}
- p_sd->upos = MAX(p_sd->upos, font_get_underline_position(w[i + j].font_rid, w[i + j].font_size));
- p_sd->uthk = MAX(p_sd->uthk, font_get_underline_thickness(w[i + j].font_rid, w[i + j].font_size));
p_sd->width += w[i + j].advance;
p_sd->glyphs.push_back(w[i + j]);
}
@@ -2051,6 +2097,10 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
if (failed_subrun_start != p_end + 1) {
_shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1);
}
+ p_sd->ascent = MAX(p_sd->ascent, fd->get_ascent(fs));
+ p_sd->descent = MAX(p_sd->descent, fd->get_descent(fs));
+ p_sd->upos = MAX(p_sd->upos, fd->get_underline_position(fs));
+ p_sd->uthk = MAX(p_sd->uthk, fd->get_underline_thickness(fs));
}
}
@@ -2081,7 +2131,7 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
sd->script_iter = memnew(ScriptIterator(sd->text, 0, sd->text.length()));
}
- if (sd->bidi_override.empty()) {
+ if (sd->bidi_override.is_empty()) {
sd->bidi_override.push_back(Vector2i(0, sd->end));
}
@@ -2180,8 +2230,8 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y);
} break;
case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y / 2);
- sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y / 2);
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y);
@@ -2195,8 +2245,8 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x);
} break;
case VALIGN_CENTER: {
- sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x / 2);
- sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x / 2);
+ sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
+ sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x);
@@ -2207,7 +2257,6 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
gl.start = span.start;
gl.end = span.end;
gl.count = 1;
- gl.index = 0;
gl.flags = GRAPHEME_IS_VALID | GRAPHEME_IS_VIRTUAL;
if (sd->orientation == ORIENTATION_HORIZONTAL) {
gl.advance = sd->objects[span.embedded_key].rect.size.x;
@@ -2507,9 +2556,11 @@ void TextServerAdvanced::register_server() {
}
TextServerAdvanced::TextServerAdvanced() {
+ hb_bmp_create_font_funcs();
}
TextServerAdvanced::~TextServerAdvanced() {
+ hb_bmp_free_font_funcs();
u_cleanup();
#ifndef ICU_STATIC_DATA
if (icu_data != nullptr) {
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index f26b87f67e..89fae477f9 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 */
@@ -138,6 +138,10 @@ public:
virtual bool font_get_antialiased(RID p_font) const override;
virtual Dictionary font_get_feature_list(RID p_font) const override;
+ virtual Dictionary font_get_variation_list(RID p_font) const override;
+
+ virtual void font_set_variation(RID p_font, const String &p_name, double p_value) override;
+ virtual double font_get_variation(RID p_font, const String &p_name) const override;
virtual void font_set_hinting(RID p_font, Hinting p_hinting) override;
virtual Hinting font_get_hinting(RID p_font) const override;