diff options
Diffstat (limited to 'modules/text_server_adv')
-rw-r--r-- | modules/text_server_adv/SCsub | 7 | ||||
-rw-r--r-- | modules/text_server_adv/config.py | 10 | ||||
-rw-r--r-- | modules/text_server_adv/doc_classes/TextServerAdvanced.xml | 10 | ||||
-rw-r--r-- | modules/text_server_adv/register_types.cpp | 7 | ||||
-rw-r--r-- | modules/text_server_adv/script_iterator.cpp | 20 | ||||
-rw-r--r-- | modules/text_server_adv/script_iterator.h | 2 | ||||
-rw-r--r-- | modules/text_server_adv/text_server_adv.cpp | 2015 | ||||
-rw-r--r-- | modules/text_server_adv/text_server_adv.h | 160 |
8 files changed, 1337 insertions, 894 deletions
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub index 6691f86e60..d6a96282f3 100644 --- a/modules/text_server_adv/SCsub +++ b/modules/text_server_adv/SCsub @@ -7,7 +7,6 @@ env_text_server_adv = env_modules.Clone() def make_icu_data(target, source, env): - import os dst = target[0].srcnode().abspath @@ -24,7 +23,6 @@ def make_icu_data(target, source, env): f = open(source[0].srcnode().abspath, "rb") buf = f.read() - import os.path g.write('extern "C" U_EXPORT const size_t U_ICUDATA_SIZE = ' + str(len(buf)) + ";\n") g.write('extern "C" U_EXPORT const unsigned char U_ICUDATA_ENTRY_POINT[] = {\n') @@ -64,6 +62,7 @@ if env["builtin_harfbuzz"]: #'src/hb-gobject-structs.cc', "src/hb-icu.cc", "src/hb-map.cc", + "src/hb-ms-feature-ranges.cc", "src/hb-number.cc", "src/hb-ot-cff1-table.cc", "src/hb-ot-cff2-table.cc", @@ -271,6 +270,7 @@ if env["builtin_icu"]: "common/dictionarydata.cpp", "common/dtintrv.cpp", "common/edits.cpp", + "common/emojiprops.cpp", "common/errorcode.cpp", "common/filteredbrk.cpp", "common/filterednormalizer2.cpp", @@ -292,6 +292,7 @@ if env["builtin_icu"]: "common/locresdata.cpp", "common/locutil.cpp", "common/lsr.cpp", + "common/lstmbe.cpp", "common/messagepattern.cpp", "common/normalizer2.cpp", "common/normalizer2impl.cpp", @@ -449,7 +450,7 @@ if env["builtin_icu"]: ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - icu_data_name = "icudt69l.dat" + icu_data_name = "icudt70l.dat" if env_icu["tools"]: env_icu.Depends("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name) diff --git a/modules/text_server_adv/config.py b/modules/text_server_adv/config.py index d22f9454ed..8c8df9b05e 100644 --- a/modules/text_server_adv/config.py +++ b/modules/text_server_adv/config.py @@ -4,3 +4,13 @@ def can_build(env, platform): def configure(env): pass + + +def get_doc_classes(): + return [ + "TextServerAdvanced", + ] + + +def get_doc_path(): + return "doc_classes" diff --git a/modules/text_server_adv/doc_classes/TextServerAdvanced.xml b/modules/text_server_adv/doc_classes/TextServerAdvanced.xml new file mode 100644 index 0000000000..eff4aa5fae --- /dev/null +++ b/modules/text_server_adv/doc_classes/TextServerAdvanced.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="TextServerAdvanced" inherits="TextServer" version="4.0"> + <brief_description> + Text Server using HarfBuzz, ICU and SIL Graphite to support BiDi, complex text layouts and contextual OpenType features. + </brief_description> + <description> + </description> + <tutorials> + </tutorials> +</class> diff --git a/modules/text_server_adv/register_types.cpp b/modules/text_server_adv/register_types.cpp index abefa83b9b..b711d1561f 100644 --- a/modules/text_server_adv/register_types.cpp +++ b/modules/text_server_adv/register_types.cpp @@ -33,7 +33,12 @@ #include "text_server_adv.h" void preregister_text_server_adv_types() { - TextServerAdvanced::register_server(); + GDREGISTER_CLASS(TextServerAdvanced); + if (TextServerManager::get_singleton()) { + Ref<TextServerAdvanced> ts; + ts.instantiate(); + TextServerManager::get_singleton()->add_interface(ts); + } } void register_text_server_adv_types() { diff --git a/modules/text_server_adv/script_iterator.cpp b/modules/text_server_adv/script_iterator.cpp index f9bbd25a5f..d1e849def8 100644 --- a/modules/text_server_adv/script_iterator.cpp +++ b/modules/text_server_adv/script_iterator.cpp @@ -30,6 +30,8 @@ #include "script_iterator.h" +// This implementation is derived from ICU: icu4c/source/extra/scrptrun/scrptrun.cpp + bool ScriptIterator::same_script(int32_t p_script_one, int32_t p_script_two) { return p_script_one <= USCRIPT_INHERITED || p_script_two <= USCRIPT_INHERITED || p_script_one == p_script_two; } @@ -48,7 +50,8 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length p_start = 0; } - ParenStackEntry paren_stack[128]; + int paren_size = PAREN_STACK_DEPTH; + ParenStackEntry *paren_stack = (ParenStackEntry *)memalloc(paren_size * sizeof(ParenStackEntry)); int script_start; int script_end = p_start; @@ -64,13 +67,22 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length UChar32 ch = str[script_end]; UScriptCode sc = uscript_getScript(ch, &err); if (U_FAILURE(err)) { + memfree(paren_stack); ERR_FAIL_MSG(u_errorName(err)); } if (u_getIntPropertyValue(ch, UCHAR_BIDI_PAIRED_BRACKET_TYPE) != U_BPT_NONE) { if (u_getIntPropertyValue(ch, UCHAR_BIDI_PAIRED_BRACKET_TYPE) == U_BPT_OPEN) { - paren_stack[++paren_sp].pair_index = ch; + // If it's an open character, push it onto the stack. + paren_sp++; + if (unlikely(paren_sp >= paren_size)) { + // If the stack is full, allocate more space to handle deeply nested parentheses. This is unlikely to happen with any real text. + paren_size += PAREN_STACK_DEPTH; + paren_stack = (ParenStackEntry *)memrealloc(paren_stack, paren_size * sizeof(ParenStackEntry)); + } + paren_stack[paren_sp].pair_index = ch; paren_stack[paren_sp].script_code = script_code; } else if (paren_sp >= 0) { + // If it's a close character, find the matching open on the stack, and use that script code. Any non-matching open characters above it on the stack will be poped. UChar32 paired_ch = u_getBidiPairedBracket(ch); while (paren_sp >= 0 && paren_stack[paren_sp].pair_index != paired_ch) { paren_sp -= 1; @@ -87,11 +99,13 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length if (same_script(script_code, sc)) { if (script_code <= USCRIPT_INHERITED && sc > USCRIPT_INHERITED) { script_code = sc; + // Now that we have a final script code, fix any open characters we pushed before we knew the script code. while (start_sp < paren_sp) { paren_stack[++start_sp].script_code = script_code; } } if ((u_getIntPropertyValue(ch, UCHAR_BIDI_PAIRED_BRACKET_TYPE) == U_BPT_CLOSE) && paren_sp >= 0) { + // If this character is a close paired character pop the matching open character from the stack. paren_sp -= 1; if (start_sp >= 0) { start_sp -= 1; @@ -109,4 +123,6 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length script_ranges.push_back(rng); } while (script_end < p_length); + + memfree(paren_stack); } diff --git a/modules/text_server_adv/script_iterator.h b/modules/text_server_adv/script_iterator.h index 896a0e5c15..5efd40f7c4 100644 --- a/modules/text_server_adv/script_iterator.h +++ b/modules/text_server_adv/script_iterator.h @@ -43,6 +43,8 @@ #include <hb.h> class ScriptIterator { + static const int PAREN_STACK_DEPTH = 128; + public: struct ScriptRange { int start = 0; diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 78a87be971..cfab021e24 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -30,6 +30,7 @@ #include "text_server_adv.h" +#include "core/error/error_macros.h" #include "core/string/print_string.h" #include "core/string/translation.h" @@ -37,6 +38,8 @@ #include "thirdparty/icu4c/icudata.gen.h" #endif +#include "modules/modules_enabled.gen.h" // For freetype, msdfgen. + #ifdef MODULE_MSDFGEN_ENABLED #include "core/ShapeDistanceFinder.h" #include "core/contour-combiners.h" @@ -45,13 +48,13 @@ #endif /*************************************************************************/ -/* hb_bmp_font_t HarfBuzz Bitmap font interface */ +/* bmp_font_t HarfBuzz Bitmap font interface */ /*************************************************************************/ hb_font_funcs_t *TextServerAdvanced::funcs = nullptr; -TextServerAdvanced::hb_bmp_font_t *TextServerAdvanced::_hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) { - hb_bmp_font_t *bm_font = memnew(hb_bmp_font_t); +TextServerAdvanced::bmp_font_t *TextServerAdvanced::_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) { + bmp_font_t *bm_font = memnew(bmp_font_t); if (!bm_font) { return nullptr; @@ -63,13 +66,13 @@ TextServerAdvanced::hb_bmp_font_t *TextServerAdvanced::_hb_bmp_font_create(TextS return bm_font; } -void TextServerAdvanced::_hb_bmp_font_destroy(void *p_data) { - hb_bmp_font_t *bm_font = reinterpret_cast<hb_bmp_font_t *>(p_data); +void TextServerAdvanced::_bmp_font_destroy(void *p_data) { + bmp_font_t *bm_font = reinterpret_cast<bmp_font_t *>(p_data); memdelete(bm_font); } -hb_bool_t TextServerAdvanced::hb_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data) { - const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data); +hb_bool_t TextServerAdvanced::_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data) { + const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return false; @@ -88,8 +91,8 @@ hb_bool_t TextServerAdvanced::hb_bmp_get_nominal_glyph(hb_font_t *p_font, void * return true; } -hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) { - const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data); +hb_position_t TextServerAdvanced::_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) { + const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return 0; @@ -102,8 +105,8 @@ hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_advance(hb_font_t *p_font, return bm_font->face->glyph_map[p_glyph].advance.x * 64; } -hb_position_t TextServerAdvanced::hb_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) { - const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data); +hb_position_t TextServerAdvanced::_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) { + const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return 0; @@ -116,8 +119,8 @@ hb_position_t TextServerAdvanced::hb_bmp_get_glyph_v_advance(hb_font_t *p_font, return -bm_font->face->glyph_map[p_glyph].advance.y * 64; } -hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data) { - const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data); +hb_position_t TextServerAdvanced::_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data) { + const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return 0; @@ -130,22 +133,8 @@ hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_kerning(hb_font_t *p_font, return bm_font->face->kerning_map[Vector2i(p_left_glyph, p_right_glyph)].x * 64; } -hb_position_t TextServerAdvanced::hb_bmp_get_glyph_v_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data) { - const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data); - - if (!bm_font->face) { - return 0; - } - - if (!bm_font->face->kerning_map.has(Vector2i(p_left_glyph, p_right_glyph))) { - return 0; - } - - return bm_font->face->kerning_map[Vector2i(p_left_glyph, p_right_glyph)].y * 64; -} - -hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data) { - const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data); +hb_bool_t TextServerAdvanced::_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data) { + const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return false; @@ -161,8 +150,8 @@ hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_v_origin(hb_font_t *p_font, void return true; } -hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data) { - const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data); +hb_bool_t TextServerAdvanced::_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data) { + const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return false; @@ -180,8 +169,8 @@ hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_extents(hb_font_t *p_font, void * return true; } -hb_bool_t TextServerAdvanced::hb_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data) { - const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data); +hb_bool_t TextServerAdvanced::_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data) { + const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return false; @@ -194,41 +183,40 @@ hb_bool_t TextServerAdvanced::hb_bmp_get_font_h_extents(hb_font_t *p_font, void return true; } -void TextServerAdvanced::hb_bmp_create_font_funcs() { +void TextServerAdvanced::_bmp_create_font_funcs() { if (funcs == nullptr) { 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_nominal_glyph_func(funcs, hb_bmp_get_nominal_glyph, nullptr, nullptr); - hb_font_funcs_set_glyph_h_advance_func(funcs, hb_bmp_get_glyph_h_advance, nullptr, nullptr); - hb_font_funcs_set_glyph_v_advance_func(funcs, hb_bmp_get_glyph_v_advance, nullptr, nullptr); - hb_font_funcs_set_glyph_v_origin_func(funcs, hb_bmp_get_glyph_v_origin, nullptr, nullptr); - hb_font_funcs_set_glyph_h_kerning_func(funcs, hb_bmp_get_glyph_h_kerning, nullptr, nullptr); - hb_font_funcs_set_glyph_v_kerning_func(funcs, hb_bmp_get_glyph_v_kerning, nullptr, nullptr); - hb_font_funcs_set_glyph_extents_func(funcs, hb_bmp_get_glyph_extents, nullptr, nullptr); + hb_font_funcs_set_font_h_extents_func(funcs, _bmp_get_font_h_extents, nullptr, nullptr); + hb_font_funcs_set_nominal_glyph_func(funcs, _bmp_get_nominal_glyph, nullptr, nullptr); + hb_font_funcs_set_glyph_h_advance_func(funcs, _bmp_get_glyph_h_advance, nullptr, nullptr); + hb_font_funcs_set_glyph_v_advance_func(funcs, _bmp_get_glyph_v_advance, nullptr, nullptr); + hb_font_funcs_set_glyph_v_origin_func(funcs, _bmp_get_glyph_v_origin, nullptr, nullptr); + hb_font_funcs_set_glyph_h_kerning_func(funcs, _bmp_get_glyph_h_kerning, nullptr, nullptr); + hb_font_funcs_set_glyph_extents_func(funcs, _bmp_get_glyph_extents, nullptr, nullptr); hb_font_funcs_make_immutable(funcs); } } -void TextServerAdvanced::hb_bmp_free_font_funcs() { +void TextServerAdvanced::_bmp_free_font_funcs() { if (funcs != nullptr) { hb_font_funcs_destroy(funcs); funcs = nullptr; } } -void TextServerAdvanced::_hb_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) { - hb_font_set_funcs(p_font, funcs, _hb_bmp_font_create(p_face, p_unref), _hb_bmp_font_destroy); +void TextServerAdvanced::_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) { + hb_font_set_funcs(p_font, funcs, _bmp_font_create(p_face, p_unref), _bmp_font_destroy); } -hb_font_t *TextServerAdvanced::hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy) { +hb_font_t *TextServerAdvanced::_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy) { hb_font_t *font; hb_face_t *face = hb_face_create(nullptr, 0); font = hb_font_create(face); hb_face_destroy(face); - _hb_bmp_font_set_funcs(font, p_face, false); + _bmp_font_set_funcs(font, p_face, false); return font; } @@ -336,7 +324,7 @@ _FORCE_INLINE_ bool is_underscore(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 | FEATURE_FONT_VARIABLE; -bool TextServerAdvanced::has_feature(Feature p_feature) { +bool TextServerAdvanced::has_feature(Feature p_feature) const { return (interface_features & p_feature) == p_feature; } @@ -344,14 +332,18 @@ String TextServerAdvanced::get_name() const { return interface_name; } +uint32_t TextServerAdvanced::get_features() const { + return interface_features; +} + void TextServerAdvanced::free(RID p_rid) { _THREAD_SAFE_METHOD_ if (font_owner.owns(p_rid)) { - FontDataAdvanced *fd = font_owner.getornull(p_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_rid); font_owner.free(p_rid); memdelete(fd); } else if (shaped_owner.owns(p_rid)) { - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_rid); + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_rid); shaped_owner.free(p_rid); memdelete(sd); } @@ -408,9 +400,23 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) { return true; } -#ifdef TOOLS_ENABLED +String TextServerAdvanced::get_support_data_filename() const { +#ifdef ICU_STATIC_DATA + return _MKSTR(ICU_DATA_NAME); +#else + return String(); +#endif +} + +String TextServerAdvanced::get_support_data_info() const { +#ifdef ICU_STATIC_DATA + return String("ICU break iteration data (") + _MKSTR(ICU_DATA_NAME) + String(")."); +#else + return String(); +#endif +} -bool TextServerAdvanced::save_support_data(const String &p_filename) { +bool TextServerAdvanced::save_support_data(const String &p_filename) const { _THREAD_SAFE_METHOD_ #ifdef ICU_STATIC_DATA @@ -429,9 +435,7 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) { #endif } -#endif - -bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) { +bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) const { String l = p_locale.get_slicec('_', 0); if ((l == "ar") || (l == "dv") || (l == "he") || (l == "fa") || (l == "ff") || (l == "ku") || (l == "ur")) { return true; @@ -440,266 +444,258 @@ bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) { } } -struct FeatureInfo { - int32_t tag; - String name; -}; - -static FeatureInfo feature_set[] = { +void TextServerAdvanced::_insert_feature_sets() { // Registered OpenType feature tags. - { HB_TAG('a', 'a', 'l', 't'), "access_all_alternates" }, - { HB_TAG('a', 'b', 'v', 'f'), "above_base_forms" }, - { HB_TAG('a', 'b', 'v', 'm'), "above_base_mark_positioning" }, - { HB_TAG('a', 'b', 'v', 's'), "above_base_substitutions" }, - { HB_TAG('a', 'f', 'r', 'c'), "alternative_fractions" }, - { HB_TAG('a', 'k', 'h', 'n'), "akhands" }, - { HB_TAG('b', 'l', 'w', 'f'), "below_base_forms" }, - { HB_TAG('b', 'l', 'w', 'm'), "below_base_mark_positioning" }, - { HB_TAG('b', 'l', 'w', 's'), "below_base_substitutions" }, - { HB_TAG('c', 'a', 'l', 't'), "contextual_alternates" }, - { HB_TAG('c', 'a', 's', 'e'), "case_sensitive_forms" }, - { HB_TAG('c', 'c', 'm', 'p'), "glyph_composition" }, - { HB_TAG('c', 'f', 'a', 'r'), "conjunct_form_after_ro" }, - { HB_TAG('c', 'j', 'c', 't'), "conjunct_forms" }, - { HB_TAG('c', 'l', 'i', 'g'), "contextual_ligatures" }, - { HB_TAG('c', 'p', 'c', 't'), "centered_cjk_punctuation" }, - { HB_TAG('c', 'p', 's', 'p'), "capital_spacing" }, - { HB_TAG('c', 's', 'w', 'h'), "contextual_swash" }, - { HB_TAG('c', 'u', 'r', 's'), "cursive_positioning" }, - { HB_TAG('c', 'v', '0', '1'), "character_variant_01" }, - { HB_TAG('c', 'v', '0', '2'), "character_variant_02" }, - { HB_TAG('c', 'v', '0', '3'), "character_variant_03" }, - { HB_TAG('c', 'v', '0', '4'), "character_variant_04" }, - { HB_TAG('c', 'v', '0', '5'), "character_variant_05" }, - { HB_TAG('c', 'v', '0', '6'), "character_variant_06" }, - { HB_TAG('c', 'v', '0', '7'), "character_variant_07" }, - { HB_TAG('c', 'v', '0', '8'), "character_variant_08" }, - { HB_TAG('c', 'v', '0', '9'), "character_variant_09" }, - { HB_TAG('c', 'v', '1', '0'), "character_variant_10" }, - { HB_TAG('c', 'v', '1', '1'), "character_variant_11" }, - { HB_TAG('c', 'v', '1', '2'), "character_variant_12" }, - { HB_TAG('c', 'v', '1', '3'), "character_variant_13" }, - { HB_TAG('c', 'v', '1', '4'), "character_variant_14" }, - { HB_TAG('c', 'v', '1', '5'), "character_variant_15" }, - { HB_TAG('c', 'v', '1', '6'), "character_variant_16" }, - { HB_TAG('c', 'v', '1', '7'), "character_variant_17" }, - { HB_TAG('c', 'v', '1', '8'), "character_variant_18" }, - { HB_TAG('c', 'v', '1', '9'), "character_variant_19" }, - { HB_TAG('c', 'v', '2', '0'), "character_variant_20" }, - { HB_TAG('c', 'v', '2', '1'), "character_variant_21" }, - { HB_TAG('c', 'v', '2', '2'), "character_variant_22" }, - { HB_TAG('c', 'v', '2', '3'), "character_variant_23" }, - { HB_TAG('c', 'v', '2', '4'), "character_variant_24" }, - { HB_TAG('c', 'v', '2', '5'), "character_variant_25" }, - { HB_TAG('c', 'v', '2', '6'), "character_variant_26" }, - { HB_TAG('c', 'v', '2', '7'), "character_variant_27" }, - { HB_TAG('c', 'v', '2', '8'), "character_variant_28" }, - { HB_TAG('c', 'v', '2', '9'), "character_variant_29" }, - { HB_TAG('c', 'v', '3', '0'), "character_variant_30" }, - { HB_TAG('c', 'v', '3', '1'), "character_variant_31" }, - { HB_TAG('c', 'v', '3', '2'), "character_variant_32" }, - { HB_TAG('c', 'v', '3', '3'), "character_variant_33" }, - { HB_TAG('c', 'v', '3', '4'), "character_variant_34" }, - { HB_TAG('c', 'v', '3', '5'), "character_variant_35" }, - { HB_TAG('c', 'v', '3', '6'), "character_variant_36" }, - { HB_TAG('c', 'v', '3', '7'), "character_variant_37" }, - { HB_TAG('c', 'v', '3', '8'), "character_variant_38" }, - { HB_TAG('c', 'v', '3', '9'), "character_variant_39" }, - { HB_TAG('c', 'v', '4', '0'), "character_variant_40" }, - { HB_TAG('c', 'v', '4', '1'), "character_variant_41" }, - { HB_TAG('c', 'v', '4', '2'), "character_variant_42" }, - { HB_TAG('c', 'v', '4', '3'), "character_variant_43" }, - { HB_TAG('c', 'v', '4', '4'), "character_variant_44" }, - { HB_TAG('c', 'v', '4', '5'), "character_variant_45" }, - { HB_TAG('c', 'v', '4', '6'), "character_variant_46" }, - { HB_TAG('c', 'v', '4', '7'), "character_variant_47" }, - { HB_TAG('c', 'v', '4', '8'), "character_variant_48" }, - { HB_TAG('c', 'v', '4', '9'), "character_variant_49" }, - { HB_TAG('c', 'v', '5', '0'), "character_variant_50" }, - { HB_TAG('c', 'v', '5', '1'), "character_variant_51" }, - { HB_TAG('c', 'v', '5', '2'), "character_variant_52" }, - { HB_TAG('c', 'v', '5', '3'), "character_variant_53" }, - { HB_TAG('c', 'v', '5', '4'), "character_variant_54" }, - { HB_TAG('c', 'v', '5', '5'), "character_variant_55" }, - { HB_TAG('c', 'v', '5', '6'), "character_variant_56" }, - { HB_TAG('c', 'v', '5', '7'), "character_variant_57" }, - { HB_TAG('c', 'v', '5', '8'), "character_variant_58" }, - { HB_TAG('c', 'v', '5', '9'), "character_variant_59" }, - { HB_TAG('c', 'v', '6', '0'), "character_variant_60" }, - { HB_TAG('c', 'v', '6', '1'), "character_variant_61" }, - { HB_TAG('c', 'v', '6', '2'), "character_variant_62" }, - { HB_TAG('c', 'v', '6', '3'), "character_variant_63" }, - { HB_TAG('c', 'v', '6', '4'), "character_variant_64" }, - { HB_TAG('c', 'v', '6', '5'), "character_variant_65" }, - { HB_TAG('c', 'v', '6', '6'), "character_variant_66" }, - { HB_TAG('c', 'v', '6', '7'), "character_variant_67" }, - { HB_TAG('c', 'v', '6', '8'), "character_variant_68" }, - { HB_TAG('c', 'v', '6', '9'), "character_variant_69" }, - { HB_TAG('c', 'v', '7', '0'), "character_variant_70" }, - { HB_TAG('c', 'v', '7', '1'), "character_variant_71" }, - { HB_TAG('c', 'v', '7', '2'), "character_variant_72" }, - { HB_TAG('c', 'v', '7', '3'), "character_variant_73" }, - { HB_TAG('c', 'v', '7', '4'), "character_variant_74" }, - { HB_TAG('c', 'v', '7', '5'), "character_variant_75" }, - { HB_TAG('c', 'v', '7', '6'), "character_variant_76" }, - { HB_TAG('c', 'v', '7', '7'), "character_variant_77" }, - { HB_TAG('c', 'v', '7', '8'), "character_variant_78" }, - { HB_TAG('c', 'v', '7', '9'), "character_variant_79" }, - { HB_TAG('c', 'v', '8', '0'), "character_variant_80" }, - { HB_TAG('c', 'v', '8', '1'), "character_variant_81" }, - { HB_TAG('c', 'v', '8', '2'), "character_variant_82" }, - { HB_TAG('c', 'v', '8', '3'), "character_variant_83" }, - { HB_TAG('c', 'v', '8', '4'), "character_variant_84" }, - { HB_TAG('c', 'v', '8', '5'), "character_variant_85" }, - { HB_TAG('c', 'v', '8', '6'), "character_variant_86" }, - { HB_TAG('c', 'v', '8', '7'), "character_variant_87" }, - { HB_TAG('c', 'v', '8', '8'), "character_variant_88" }, - { HB_TAG('c', 'v', '8', '9'), "character_variant_89" }, - { HB_TAG('c', 'v', '9', '0'), "character_variant_90" }, - { HB_TAG('c', 'v', '9', '1'), "character_variant_91" }, - { HB_TAG('c', 'v', '9', '2'), "character_variant_92" }, - { HB_TAG('c', 'v', '9', '3'), "character_variant_93" }, - { HB_TAG('c', 'v', '9', '4'), "character_variant_94" }, - { HB_TAG('c', 'v', '9', '5'), "character_variant_95" }, - { HB_TAG('c', 'v', '9', '6'), "character_variant_96" }, - { HB_TAG('c', 'v', '9', '7'), "character_variant_97" }, - { HB_TAG('c', 'v', '9', '8'), "character_variant_98" }, - { HB_TAG('c', 'v', '9', '9'), "character_variant_99" }, - { HB_TAG('c', '2', 'p', 'c'), "petite_capitals_from_capitals" }, - { HB_TAG('c', '2', 's', 'c'), "small_capitals_from_capitals" }, - { HB_TAG('d', 'i', 's', 't'), "distances" }, - { HB_TAG('d', 'l', 'i', 'g'), "discretionary_ligatures" }, - { HB_TAG('d', 'n', 'o', 'm'), "denominators" }, - { HB_TAG('d', 't', 'l', 's'), "dotless_forms" }, - { HB_TAG('e', 'x', 'p', 't'), "expert_forms" }, - { HB_TAG('f', 'a', 'l', 't'), "final_glyph_on_line_alternates" }, - { HB_TAG('f', 'i', 'n', '2'), "terminal_forms_2" }, - { HB_TAG('f', 'i', 'n', '3'), "terminal_forms_3" }, - { HB_TAG('f', 'i', 'n', 'a'), "terminal_forms" }, - { HB_TAG('f', 'l', 'a', 'c'), "flattened_accent_forms" }, - { HB_TAG('f', 'r', 'a', 'c'), "fractions" }, - { HB_TAG('f', 'w', 'i', 'd'), "full_widths" }, - { HB_TAG('h', 'a', 'l', 'f'), "half_forms" }, - { HB_TAG('h', 'a', 'l', 'n'), "halant_forms" }, - { HB_TAG('h', 'a', 'l', 't'), "alternate_half_widths" }, - { HB_TAG('h', 'i', 's', 't'), "historical_forms" }, - { HB_TAG('h', 'k', 'n', 'a'), "horizontal_kana_alternates" }, - { HB_TAG('h', 'l', 'i', 'g'), "historical_ligatures" }, - { HB_TAG('h', 'n', 'g', 'l'), "hangul" }, - { HB_TAG('h', 'o', 'j', 'o'), "hojo_kanji_forms" }, - { HB_TAG('h', 'w', 'i', 'd'), "half_widths" }, - { HB_TAG('i', 'n', 'i', 't'), "initial_forms" }, - { HB_TAG('i', 's', 'o', 'l'), "isolated_forms" }, - { HB_TAG('i', 't', 'a', 'l'), "italics" }, - { HB_TAG('j', 'a', 'l', 't'), "justification_alternates" }, - { HB_TAG('j', 'p', '7', '8'), "jis78_forms" }, - { HB_TAG('j', 'p', '8', '3'), "jis83_forms" }, - { HB_TAG('j', 'p', '9', '0'), "jis90_forms" }, - { HB_TAG('j', 'p', '0', '4'), "jis2004_forms" }, - { HB_TAG('k', 'e', 'r', 'n'), "kerning" }, - { HB_TAG('l', 'f', 'b', 'd'), "left_bounds" }, - { HB_TAG('l', 'i', 'g', 'a'), "standard_ligatures" }, - { HB_TAG('l', 'j', 'm', 'o'), "leading_jamo_forms" }, - { HB_TAG('l', 'n', 'u', 'm'), "lining_figures" }, - { HB_TAG('l', 'o', 'c', 'l'), "localized_forms" }, - { HB_TAG('l', 't', 'r', 'a'), "left_to_right_alternates" }, - { HB_TAG('l', 't', 'r', 'm'), "left_to_right_mirrored_forms" }, - { HB_TAG('m', 'a', 'r', 'k'), "mark_positioning" }, - { HB_TAG('m', 'e', 'd', '2'), "medial_forms_2" }, - { HB_TAG('m', 'e', 'd', 'i'), "medial_forms" }, - { HB_TAG('m', 'g', 'r', 'k'), "mathematical_greek" }, - { HB_TAG('m', 'k', 'm', 'k'), "mark_to_mark_positioning" }, - { HB_TAG('m', 's', 'e', 't'), "mark_positioning_via_substitution" }, - { HB_TAG('n', 'a', 'l', 't'), "alternate_annotation_forms" }, - { HB_TAG('n', 'l', 'c', 'k'), "nlc_kanji_forms" }, - { HB_TAG('n', 'u', 'k', 't'), "nukta_forms" }, - { HB_TAG('n', 'u', 'm', 'r'), "numerators" }, - { HB_TAG('o', 'n', 'u', 'm'), "oldstyle_figures" }, - { HB_TAG('o', 'p', 'b', 'd'), "optical_bounds" }, - { HB_TAG('o', 'r', 'd', 'n'), "ordinals" }, - { HB_TAG('o', 'r', 'n', 'm'), "ornaments" }, - { HB_TAG('p', 'a', 'l', 't'), "proportional_alternate_widths" }, - { HB_TAG('p', 'c', 'a', 'p'), "petite_capitals" }, - { HB_TAG('p', 'k', 'n', 'a'), "proportional_kana" }, - { HB_TAG('p', 'n', 'u', 'm'), "proportional_figures" }, - { HB_TAG('p', 'r', 'e', 'f'), "pre_base_forms" }, - { HB_TAG('p', 'r', 'e', 's'), "pre_base_substitutions" }, - { HB_TAG('p', 's', 't', 'f'), "post_base_forms" }, - { HB_TAG('p', 's', 't', 's'), "post_base_substitutions" }, - { HB_TAG('p', 'w', 'i', 'd'), "proportional_widths" }, - { HB_TAG('q', 'w', 'i', 'd'), "quarter_widths" }, - { HB_TAG('r', 'a', 'n', 'd'), "randomize" }, - { HB_TAG('r', 'c', 'l', 't'), "required_contextual_alternates" }, - { HB_TAG('r', 'k', 'r', 'f'), "rakar_forms" }, - { HB_TAG('r', 'l', 'i', 'g'), "required_ligatures" }, - { HB_TAG('r', 'p', 'h', 'f'), "reph_forms" }, - { HB_TAG('r', 't', 'b', 'd'), "right_bounds" }, - { HB_TAG('r', 't', 'l', 'a'), "right_to_left_alternates" }, - { HB_TAG('r', 't', 'l', 'm'), "right_to_left_mirrored_forms" }, - { HB_TAG('r', 'u', 'b', 'y'), "ruby_notation_forms" }, - { HB_TAG('r', 'v', 'r', 'n'), "required_variation_alternates" }, - { HB_TAG('s', 'a', 'l', 't'), "stylistic_alternates" }, - { HB_TAG('s', 'i', 'n', 'f'), "scientific_inferiors" }, - { HB_TAG('s', 'i', 'z', 'e'), "optical_size" }, - { HB_TAG('s', 'm', 'c', 'p'), "small_capitals" }, - { HB_TAG('s', 'm', 'p', 'l'), "simplified_forms" }, - { HB_TAG('s', 's', '0', '1'), "stylistic_set_01" }, - { HB_TAG('s', 's', '0', '2'), "stylistic_set_02" }, - { HB_TAG('s', 's', '0', '3'), "stylistic_set_03" }, - { HB_TAG('s', 's', '0', '4'), "stylistic_set_04" }, - { HB_TAG('s', 's', '0', '5'), "stylistic_set_05" }, - { HB_TAG('s', 's', '0', '6'), "stylistic_set_06" }, - { HB_TAG('s', 's', '0', '7'), "stylistic_set_07" }, - { HB_TAG('s', 's', '0', '8'), "stylistic_set_08" }, - { HB_TAG('s', 's', '0', '9'), "stylistic_set_09" }, - { HB_TAG('s', 's', '1', '0'), "stylistic_set_10" }, - { HB_TAG('s', 's', '1', '1'), "stylistic_set_11" }, - { HB_TAG('s', 's', '1', '2'), "stylistic_set_12" }, - { HB_TAG('s', 's', '1', '3'), "stylistic_set_13" }, - { HB_TAG('s', 's', '1', '4'), "stylistic_set_14" }, - { HB_TAG('s', 's', '1', '5'), "stylistic_set_15" }, - { HB_TAG('s', 's', '1', '6'), "stylistic_set_16" }, - { HB_TAG('s', 's', '1', '7'), "stylistic_set_17" }, - { HB_TAG('s', 's', '1', '8'), "stylistic_set_18" }, - { HB_TAG('s', 's', '1', '9'), "stylistic_set_19" }, - { HB_TAG('s', 's', '2', '0'), "stylistic_set_20" }, - { HB_TAG('s', 's', 't', 'y'), "math_script_style_alternates" }, - { HB_TAG('s', 't', 'c', 'h'), "stretching_glyph_decomposition" }, - { HB_TAG('s', 'u', 'b', 's'), "subscript" }, - { HB_TAG('s', 'u', 'p', 's'), "superscript" }, - { HB_TAG('s', 'w', 's', 'h'), "swash" }, - { HB_TAG('t', 'i', 't', 'l'), "titling" }, - { HB_TAG('t', 'j', 'm', 'o'), "trailing_jamo_forms" }, - { HB_TAG('t', 'n', 'a', 'm'), "traditional_name_forms" }, - { HB_TAG('t', 'n', 'u', 'm'), "tabular_figures" }, - { HB_TAG('t', 'r', 'a', 'd'), "traditional_forms" }, - { HB_TAG('t', 'w', 'i', 'd'), "third_widths" }, - { HB_TAG('u', 'n', 'i', 'c'), "unicase" }, - { HB_TAG('v', 'a', 'l', 't'), "alternate_vertical_metrics" }, - { HB_TAG('v', 'a', 't', 'u'), "vattu_variants" }, - { HB_TAG('v', 'e', 'r', 't'), "vertical_writing" }, - { HB_TAG('v', 'h', 'a', 'l'), "alternate_vertical_half_metrics" }, - { HB_TAG('v', 'j', 'm', 'o'), "vowel_jamo_forms" }, - { HB_TAG('v', 'k', 'n', 'a'), "vertical_kana_alternates" }, - { HB_TAG('v', 'k', 'r', 'n'), "vertical_kerning" }, - { HB_TAG('v', 'p', 'a', 'l'), "proportional_alternate_vertical_metrics" }, - { HB_TAG('v', 'r', 't', '2'), "vertical_alternates_and_rotation" }, - { HB_TAG('v', 'r', 't', 'r'), "vertical_alternates_for_rotation" }, - { HB_TAG('z', 'e', 'r', 'o'), "slashed_zero" }, - // Registered OpenType variation tags. - { HB_TAG('i', 't', 'a', 'l'), "italic" }, - { HB_TAG('o', 'p', 's', 'z'), "optical_size" }, - { HB_TAG('s', 'l', 'n', 't'), "slant" }, - { HB_TAG('w', 'd', 't', 'h'), "width" }, - { HB_TAG('w', 'g', 'h', 't'), "weight" }, - { 0, String() }, -}; + feature_sets.insert("access_all_alternates", HB_TAG('a', 'a', 'l', 't')); + feature_sets.insert("above_base_forms", HB_TAG('a', 'b', 'v', 'f')); + feature_sets.insert("above_base_mark_positioning", HB_TAG('a', 'b', 'v', 'm')); + feature_sets.insert("above_base_substitutions", HB_TAG('a', 'b', 'v', 's')); + feature_sets.insert("alternative_fractions", HB_TAG('a', 'f', 'r', 'c')); + feature_sets.insert("akhands", HB_TAG('a', 'k', 'h', 'n')); + feature_sets.insert("below_base_forms", HB_TAG('b', 'l', 'w', 'f')); + feature_sets.insert("below_base_mark_positioning", HB_TAG('b', 'l', 'w', 'm')); + feature_sets.insert("below_base_substitutions", HB_TAG('b', 'l', 'w', 's')); + feature_sets.insert("contextual_alternates", HB_TAG('c', 'a', 'l', 't')); + feature_sets.insert("case_sensitive_forms", HB_TAG('c', 'a', 's', 'e')); + feature_sets.insert("glyph_composition", HB_TAG('c', 'c', 'm', 'p')); + feature_sets.insert("conjunct_form_after_ro", HB_TAG('c', 'f', 'a', 'r')); + feature_sets.insert("conjunct_forms", HB_TAG('c', 'j', 'c', 't')); + feature_sets.insert("contextual_ligatures", HB_TAG('c', 'l', 'i', 'g')); + feature_sets.insert("centered_cjk_punctuation", HB_TAG('c', 'p', 'c', 't')); + feature_sets.insert("capital_spacing", HB_TAG('c', 'p', 's', 'p')); + feature_sets.insert("contextual_swash", HB_TAG('c', 's', 'w', 'h')); + feature_sets.insert("cursive_positioning", HB_TAG('c', 'u', 'r', 's')); + feature_sets.insert("character_variant_01", HB_TAG('c', 'v', '0', '1')); + feature_sets.insert("character_variant_02", HB_TAG('c', 'v', '0', '2')); + feature_sets.insert("character_variant_03", HB_TAG('c', 'v', '0', '3')); + feature_sets.insert("character_variant_04", HB_TAG('c', 'v', '0', '4')); + feature_sets.insert("character_variant_05", HB_TAG('c', 'v', '0', '5')); + feature_sets.insert("character_variant_06", HB_TAG('c', 'v', '0', '6')); + feature_sets.insert("character_variant_07", HB_TAG('c', 'v', '0', '7')); + feature_sets.insert("character_variant_08", HB_TAG('c', 'v', '0', '8')); + feature_sets.insert("character_variant_09", HB_TAG('c', 'v', '0', '9')); + feature_sets.insert("character_variant_10", HB_TAG('c', 'v', '1', '0')); + feature_sets.insert("character_variant_11", HB_TAG('c', 'v', '1', '1')); + feature_sets.insert("character_variant_12", HB_TAG('c', 'v', '1', '2')); + feature_sets.insert("character_variant_13", HB_TAG('c', 'v', '1', '3')); + feature_sets.insert("character_variant_14", HB_TAG('c', 'v', '1', '4')); + feature_sets.insert("character_variant_15", HB_TAG('c', 'v', '1', '5')); + feature_sets.insert("character_variant_16", HB_TAG('c', 'v', '1', '6')); + feature_sets.insert("character_variant_17", HB_TAG('c', 'v', '1', '7')); + feature_sets.insert("character_variant_18", HB_TAG('c', 'v', '1', '8')); + feature_sets.insert("character_variant_19", HB_TAG('c', 'v', '1', '9')); + feature_sets.insert("character_variant_20", HB_TAG('c', 'v', '2', '0')); + feature_sets.insert("character_variant_21", HB_TAG('c', 'v', '2', '1')); + feature_sets.insert("character_variant_22", HB_TAG('c', 'v', '2', '2')); + feature_sets.insert("character_variant_23", HB_TAG('c', 'v', '2', '3')); + feature_sets.insert("character_variant_24", HB_TAG('c', 'v', '2', '4')); + feature_sets.insert("character_variant_25", HB_TAG('c', 'v', '2', '5')); + feature_sets.insert("character_variant_26", HB_TAG('c', 'v', '2', '6')); + feature_sets.insert("character_variant_27", HB_TAG('c', 'v', '2', '7')); + feature_sets.insert("character_variant_28", HB_TAG('c', 'v', '2', '8')); + feature_sets.insert("character_variant_29", HB_TAG('c', 'v', '2', '9')); + feature_sets.insert("character_variant_30", HB_TAG('c', 'v', '3', '0')); + feature_sets.insert("character_variant_31", HB_TAG('c', 'v', '3', '1')); + feature_sets.insert("character_variant_32", HB_TAG('c', 'v', '3', '2')); + feature_sets.insert("character_variant_33", HB_TAG('c', 'v', '3', '3')); + feature_sets.insert("character_variant_34", HB_TAG('c', 'v', '3', '4')); + feature_sets.insert("character_variant_35", HB_TAG('c', 'v', '3', '5')); + feature_sets.insert("character_variant_36", HB_TAG('c', 'v', '3', '6')); + feature_sets.insert("character_variant_37", HB_TAG('c', 'v', '3', '7')); + feature_sets.insert("character_variant_38", HB_TAG('c', 'v', '3', '8')); + feature_sets.insert("character_variant_39", HB_TAG('c', 'v', '3', '9')); + feature_sets.insert("character_variant_40", HB_TAG('c', 'v', '4', '0')); + feature_sets.insert("character_variant_41", HB_TAG('c', 'v', '4', '1')); + feature_sets.insert("character_variant_42", HB_TAG('c', 'v', '4', '2')); + feature_sets.insert("character_variant_43", HB_TAG('c', 'v', '4', '3')); + feature_sets.insert("character_variant_44", HB_TAG('c', 'v', '4', '4')); + feature_sets.insert("character_variant_45", HB_TAG('c', 'v', '4', '5')); + feature_sets.insert("character_variant_46", HB_TAG('c', 'v', '4', '6')); + feature_sets.insert("character_variant_47", HB_TAG('c', 'v', '4', '7')); + feature_sets.insert("character_variant_48", HB_TAG('c', 'v', '4', '8')); + feature_sets.insert("character_variant_49", HB_TAG('c', 'v', '4', '9')); + feature_sets.insert("character_variant_50", HB_TAG('c', 'v', '5', '0')); + feature_sets.insert("character_variant_51", HB_TAG('c', 'v', '5', '1')); + feature_sets.insert("character_variant_52", HB_TAG('c', 'v', '5', '2')); + feature_sets.insert("character_variant_53", HB_TAG('c', 'v', '5', '3')); + feature_sets.insert("character_variant_54", HB_TAG('c', 'v', '5', '4')); + feature_sets.insert("character_variant_55", HB_TAG('c', 'v', '5', '5')); + feature_sets.insert("character_variant_56", HB_TAG('c', 'v', '5', '6')); + feature_sets.insert("character_variant_57", HB_TAG('c', 'v', '5', '7')); + feature_sets.insert("character_variant_58", HB_TAG('c', 'v', '5', '8')); + feature_sets.insert("character_variant_59", HB_TAG('c', 'v', '5', '9')); + feature_sets.insert("character_variant_60", HB_TAG('c', 'v', '6', '0')); + feature_sets.insert("character_variant_61", HB_TAG('c', 'v', '6', '1')); + feature_sets.insert("character_variant_62", HB_TAG('c', 'v', '6', '2')); + feature_sets.insert("character_variant_63", HB_TAG('c', 'v', '6', '3')); + feature_sets.insert("character_variant_64", HB_TAG('c', 'v', '6', '4')); + feature_sets.insert("character_variant_65", HB_TAG('c', 'v', '6', '5')); + feature_sets.insert("character_variant_66", HB_TAG('c', 'v', '6', '6')); + feature_sets.insert("character_variant_67", HB_TAG('c', 'v', '6', '7')); + feature_sets.insert("character_variant_68", HB_TAG('c', 'v', '6', '8')); + feature_sets.insert("character_variant_69", HB_TAG('c', 'v', '6', '9')); + feature_sets.insert("character_variant_70", HB_TAG('c', 'v', '7', '0')); + feature_sets.insert("character_variant_71", HB_TAG('c', 'v', '7', '1')); + feature_sets.insert("character_variant_72", HB_TAG('c', 'v', '7', '2')); + feature_sets.insert("character_variant_73", HB_TAG('c', 'v', '7', '3')); + feature_sets.insert("character_variant_74", HB_TAG('c', 'v', '7', '4')); + feature_sets.insert("character_variant_75", HB_TAG('c', 'v', '7', '5')); + feature_sets.insert("character_variant_76", HB_TAG('c', 'v', '7', '6')); + feature_sets.insert("character_variant_77", HB_TAG('c', 'v', '7', '7')); + feature_sets.insert("character_variant_78", HB_TAG('c', 'v', '7', '8')); + feature_sets.insert("character_variant_79", HB_TAG('c', 'v', '7', '9')); + feature_sets.insert("character_variant_80", HB_TAG('c', 'v', '8', '0')); + feature_sets.insert("character_variant_81", HB_TAG('c', 'v', '8', '1')); + feature_sets.insert("character_variant_82", HB_TAG('c', 'v', '8', '2')); + feature_sets.insert("character_variant_83", HB_TAG('c', 'v', '8', '3')); + feature_sets.insert("character_variant_84", HB_TAG('c', 'v', '8', '4')); + feature_sets.insert("character_variant_85", HB_TAG('c', 'v', '8', '5')); + feature_sets.insert("character_variant_86", HB_TAG('c', 'v', '8', '6')); + feature_sets.insert("character_variant_87", HB_TAG('c', 'v', '8', '7')); + feature_sets.insert("character_variant_88", HB_TAG('c', 'v', '8', '8')); + feature_sets.insert("character_variant_89", HB_TAG('c', 'v', '8', '9')); + feature_sets.insert("character_variant_90", HB_TAG('c', 'v', '9', '0')); + feature_sets.insert("character_variant_91", HB_TAG('c', 'v', '9', '1')); + feature_sets.insert("character_variant_92", HB_TAG('c', 'v', '9', '2')); + feature_sets.insert("character_variant_93", HB_TAG('c', 'v', '9', '3')); + feature_sets.insert("character_variant_94", HB_TAG('c', 'v', '9', '4')); + feature_sets.insert("character_variant_95", HB_TAG('c', 'v', '9', '5')); + feature_sets.insert("character_variant_96", HB_TAG('c', 'v', '9', '6')); + feature_sets.insert("character_variant_97", HB_TAG('c', 'v', '9', '7')); + feature_sets.insert("character_variant_98", HB_TAG('c', 'v', '9', '8')); + feature_sets.insert("character_variant_99", HB_TAG('c', 'v', '9', '9')); + feature_sets.insert("petite_capitals_from_capitals", HB_TAG('c', '2', 'p', 'c')); + feature_sets.insert("small_capitals_from_capitals", HB_TAG('c', '2', 's', 'c')); + feature_sets.insert("distances", HB_TAG('d', 'i', 's', 't')); + feature_sets.insert("discretionary_ligatures", HB_TAG('d', 'l', 'i', 'g')); + feature_sets.insert("denominators", HB_TAG('d', 'n', 'o', 'm')); + feature_sets.insert("dotless_forms", HB_TAG('d', 't', 'l', 's')); + feature_sets.insert("expert_forms", HB_TAG('e', 'x', 'p', 't')); + feature_sets.insert("final_glyph_on_line_alternates", HB_TAG('f', 'a', 'l', 't')); + feature_sets.insert("terminal_forms_2", HB_TAG('f', 'i', 'n', '2')); + feature_sets.insert("terminal_forms_3", HB_TAG('f', 'i', 'n', '3')); + feature_sets.insert("terminal_forms", HB_TAG('f', 'i', 'n', 'a')); + feature_sets.insert("flattened_accent_forms", HB_TAG('f', 'l', 'a', 'c')); + feature_sets.insert("fractions", HB_TAG('f', 'r', 'a', 'c')); + feature_sets.insert("full_widths", HB_TAG('f', 'w', 'i', 'd')); + feature_sets.insert("half_forms", HB_TAG('h', 'a', 'l', 'f')); + feature_sets.insert("halant_forms", HB_TAG('h', 'a', 'l', 'n')); + feature_sets.insert("alternate_half_widths", HB_TAG('h', 'a', 'l', 't')); + feature_sets.insert("historical_forms", HB_TAG('h', 'i', 's', 't')); + feature_sets.insert("horizontal_kana_alternates", HB_TAG('h', 'k', 'n', 'a')); + feature_sets.insert("historical_ligatures", HB_TAG('h', 'l', 'i', 'g')); + feature_sets.insert("hangul", HB_TAG('h', 'n', 'g', 'l')); + feature_sets.insert("hojo_kanji_forms", HB_TAG('h', 'o', 'j', 'o')); + feature_sets.insert("half_widths", HB_TAG('h', 'w', 'i', 'd')); + feature_sets.insert("initial_forms", HB_TAG('i', 'n', 'i', 't')); + feature_sets.insert("isolated_forms", HB_TAG('i', 's', 'o', 'l')); + feature_sets.insert("italics", HB_TAG('i', 't', 'a', 'l')); + feature_sets.insert("justification_alternates", HB_TAG('j', 'a', 'l', 't')); + feature_sets.insert("jis78_forms", HB_TAG('j', 'p', '7', '8')); + feature_sets.insert("jis83_forms", HB_TAG('j', 'p', '8', '3')); + feature_sets.insert("jis90_forms", HB_TAG('j', 'p', '9', '0')); + feature_sets.insert("jis2004_forms", HB_TAG('j', 'p', '0', '4')); + feature_sets.insert("kerning", HB_TAG('k', 'e', 'r', 'n')); + feature_sets.insert("left_bounds", HB_TAG('l', 'f', 'b', 'd')); + feature_sets.insert("standard_ligatures", HB_TAG('l', 'i', 'g', 'a')); + feature_sets.insert("leading_jamo_forms", HB_TAG('l', 'j', 'm', 'o')); + feature_sets.insert("lining_figures", HB_TAG('l', 'n', 'u', 'm')); + feature_sets.insert("localized_forms", HB_TAG('l', 'o', 'c', 'l')); + feature_sets.insert("left_to_right_alternates", HB_TAG('l', 't', 'r', 'a')); + feature_sets.insert("left_to_right_mirrored_forms", HB_TAG('l', 't', 'r', 'm')); + feature_sets.insert("mark_positioning", HB_TAG('m', 'a', 'r', 'k')); + feature_sets.insert("medial_forms_2", HB_TAG('m', 'e', 'd', '2')); + feature_sets.insert("medial_forms", HB_TAG('m', 'e', 'd', 'i')); + feature_sets.insert("mathematical_greek", HB_TAG('m', 'g', 'r', 'k')); + feature_sets.insert("mark_to_mark_positioning", HB_TAG('m', 'k', 'm', 'k')); + feature_sets.insert("mark_positioning_via_substitution", HB_TAG('m', 's', 'e', 't')); + feature_sets.insert("alternate_annotation_forms", HB_TAG('n', 'a', 'l', 't')); + feature_sets.insert("nlc_kanji_forms", HB_TAG('n', 'l', 'c', 'k')); + feature_sets.insert("nukta_forms", HB_TAG('n', 'u', 'k', 't')); + feature_sets.insert("numerators", HB_TAG('n', 'u', 'm', 'r')); + feature_sets.insert("oldstyle_figures", HB_TAG('o', 'n', 'u', 'm')); + feature_sets.insert("optical_bounds", HB_TAG('o', 'p', 'b', 'd')); + feature_sets.insert("ordinals", HB_TAG('o', 'r', 'd', 'n')); + feature_sets.insert("ornaments", HB_TAG('o', 'r', 'n', 'm')); + feature_sets.insert("proportional_alternate_widths", HB_TAG('p', 'a', 'l', 't')); + feature_sets.insert("petite_capitals", HB_TAG('p', 'c', 'a', 'p')); + feature_sets.insert("proportional_kana", HB_TAG('p', 'k', 'n', 'a')); + feature_sets.insert("proportional_figures", HB_TAG('p', 'n', 'u', 'm')); + feature_sets.insert("pre_base_forms", HB_TAG('p', 'r', 'e', 'f')); + feature_sets.insert("pre_base_substitutions", HB_TAG('p', 'r', 'e', 's')); + feature_sets.insert("post_base_forms", HB_TAG('p', 's', 't', 'f')); + feature_sets.insert("post_base_substitutions", HB_TAG('p', 's', 't', 's')); + feature_sets.insert("proportional_widths", HB_TAG('p', 'w', 'i', 'd')); + feature_sets.insert("quarter_widths", HB_TAG('q', 'w', 'i', 'd')); + feature_sets.insert("randomize", HB_TAG('r', 'a', 'n', 'd')); + feature_sets.insert("required_contextual_alternates", HB_TAG('r', 'c', 'l', 't')); + feature_sets.insert("rakar_forms", HB_TAG('r', 'k', 'r', 'f')); + feature_sets.insert("required_ligatures", HB_TAG('r', 'l', 'i', 'g')); + feature_sets.insert("reph_forms", HB_TAG('r', 'p', 'h', 'f')); + feature_sets.insert("right_bounds", HB_TAG('r', 't', 'b', 'd')); + feature_sets.insert("right_to_left_alternates", HB_TAG('r', 't', 'l', 'a')); + feature_sets.insert("right_to_left_mirrored_forms", HB_TAG('r', 't', 'l', 'm')); + feature_sets.insert("ruby_notation_forms", HB_TAG('r', 'u', 'b', 'y')); + feature_sets.insert("required_variation_alternates", HB_TAG('r', 'v', 'r', 'n')); + feature_sets.insert("stylistic_alternates", HB_TAG('s', 'a', 'l', 't')); + feature_sets.insert("scientific_inferiors", HB_TAG('s', 'i', 'n', 'f')); + feature_sets.insert("optical_size", HB_TAG('s', 'i', 'z', 'e')); + feature_sets.insert("small_capitals", HB_TAG('s', 'm', 'c', 'p')); + feature_sets.insert("simplified_forms", HB_TAG('s', 'm', 'p', 'l')); + feature_sets.insert("stylistic_set_01", HB_TAG('s', 's', '0', '1')); + feature_sets.insert("stylistic_set_02", HB_TAG('s', 's', '0', '2')); + feature_sets.insert("stylistic_set_03", HB_TAG('s', 's', '0', '3')); + feature_sets.insert("stylistic_set_04", HB_TAG('s', 's', '0', '4')); + feature_sets.insert("stylistic_set_05", HB_TAG('s', 's', '0', '5')); + feature_sets.insert("stylistic_set_06", HB_TAG('s', 's', '0', '6')); + feature_sets.insert("stylistic_set_07", HB_TAG('s', 's', '0', '7')); + feature_sets.insert("stylistic_set_08", HB_TAG('s', 's', '0', '8')); + feature_sets.insert("stylistic_set_09", HB_TAG('s', 's', '0', '9')); + feature_sets.insert("stylistic_set_10", HB_TAG('s', 's', '1', '0')); + feature_sets.insert("stylistic_set_11", HB_TAG('s', 's', '1', '1')); + feature_sets.insert("stylistic_set_12", HB_TAG('s', 's', '1', '2')); + feature_sets.insert("stylistic_set_13", HB_TAG('s', 's', '1', '3')); + feature_sets.insert("stylistic_set_14", HB_TAG('s', 's', '1', '4')); + feature_sets.insert("stylistic_set_15", HB_TAG('s', 's', '1', '5')); + feature_sets.insert("stylistic_set_16", HB_TAG('s', 's', '1', '6')); + feature_sets.insert("stylistic_set_17", HB_TAG('s', 's', '1', '7')); + feature_sets.insert("stylistic_set_18", HB_TAG('s', 's', '1', '8')); + feature_sets.insert("stylistic_set_19", HB_TAG('s', 's', '1', '9')); + feature_sets.insert("stylistic_set_20", HB_TAG('s', 's', '2', '0')); + feature_sets.insert("math_script_style_alternates", HB_TAG('s', 's', 't', 'y')); + feature_sets.insert("stretching_glyph_decomposition", HB_TAG('s', 't', 'c', 'h')); + feature_sets.insert("subscript", HB_TAG('s', 'u', 'b', 's')); + feature_sets.insert("superscript", HB_TAG('s', 'u', 'p', 's')); + feature_sets.insert("swash", HB_TAG('s', 'w', 's', 'h')); + feature_sets.insert("titling", HB_TAG('t', 'i', 't', 'l')); + feature_sets.insert("trailing_jamo_forms", HB_TAG('t', 'j', 'm', 'o')); + feature_sets.insert("traditional_name_forms", HB_TAG('t', 'n', 'a', 'm')); + feature_sets.insert("tabular_figures", HB_TAG('t', 'n', 'u', 'm')); + feature_sets.insert("traditional_forms", HB_TAG('t', 'r', 'a', 'd')); + feature_sets.insert("third_widths", HB_TAG('t', 'w', 'i', 'd')); + feature_sets.insert("unicase", HB_TAG('u', 'n', 'i', 'c')); + feature_sets.insert("alternate_vertical_metrics", HB_TAG('v', 'a', 'l', 't')); + feature_sets.insert("vattu_variants", HB_TAG('v', 'a', 't', 'u')); + feature_sets.insert("vertical_writing", HB_TAG('v', 'e', 'r', 't')); + feature_sets.insert("alternate_vertical_half_metrics", HB_TAG('v', 'h', 'a', 'l')); + feature_sets.insert("vowel_jamo_forms", HB_TAG('v', 'j', 'm', 'o')); + feature_sets.insert("vertical_kana_alternates", HB_TAG('v', 'k', 'n', 'a')); + feature_sets.insert("vertical_kerning", HB_TAG('v', 'k', 'r', 'n')); + feature_sets.insert("proportional_alternate_vertical_metrics", HB_TAG('v', 'p', 'a', 'l')); + feature_sets.insert("vertical_alternates_and_rotation", HB_TAG('v', 'r', 't', '2')); + feature_sets.insert("vertical_alternates_for_rotation", HB_TAG('v', 'r', 't', 'r')); + feature_sets.insert("slashed_zero", HB_TAG('z', 'e', 'r', 'o')); + // Registered OpenType variation tag. + feature_sets.insert("italic", HB_TAG('i', 't', 'a', 'l')); + feature_sets.insert("optical_size", HB_TAG('o', 'p', 's', 'z')); + feature_sets.insert("slant", HB_TAG('s', 'l', 'n', 't')); + feature_sets.insert("width", HB_TAG('w', 'd', 't', 'h')); + feature_sets.insert("weight", HB_TAG('w', 'g', 'h', 't')); +} int32_t TextServerAdvanced::name_to_tag(const String &p_name) const { - for (int i = 0; feature_set[i].tag != 0; i++) { - if (feature_set[i].name == p_name) { - return feature_set[i].tag; - } + if (feature_sets.has(p_name)) { + return feature_sets[p_name]; } // No readable name, use tag string. @@ -707,9 +703,9 @@ int32_t TextServerAdvanced::name_to_tag(const String &p_name) const { } String TextServerAdvanced::tag_to_name(int32_t p_tag) const { - for (int i = 0; feature_set[i].tag != 0; i++) { - if (feature_set[i].tag == p_tag) { - return feature_set[i].name; + for (const KeyValue<StringName, int32_t> &E : feature_sets) { + if (E.value == p_tag) { + return E.key; } } @@ -744,6 +740,10 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_ continue; } + if (ct.offsets.size() < ct.texture_w) { + continue; + } + ret.y = 0x7FFFFFFF; ret.x = 0; @@ -942,7 +942,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf( FontGlyph chr; chr.found = true; - chr.advance = advance.round(); + chr.advance = advance; if (shape.validate() && shape.contours.size() > 0) { int w = (bounds.r - bounds.l); @@ -960,7 +960,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf( edgeColoringSimple(shape, 3.0); // Max. angle. msdfgen::Bitmap<float, 4> image(w, h); // Texture size. - //msdfgen::generateMTSDF(image, shape, p_pixel_range, 1.0, msdfgen::Vector2(-bounds.l, -bounds.b)); // Range, scale, translation. DistancePixelConversion distancePixelConversion(p_pixel_range); msdfgen::Projection projection(msdfgen::Vector2(1.0, 1.0), msdfgen::Vector2(-bounds.l, -bounds.b)); @@ -990,10 +989,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf( wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f)); wr[ofs + 2] = (uint8_t)(CLAMP(image(j, i)[2] * 256.f, 0.f, 255.f)); wr[ofs + 3] = (uint8_t)(CLAMP(image(j, i)[3] * 256.f, 0.f, 255.f)); - //wr[ofs + 0] = 100; - //wr[ofs + 1] = 100; - //wr[ofs + 2] = 100; - //wr[ofs + 3] = 100; } } } @@ -1058,13 +1053,12 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma case FT_PIXEL_MODE_MONO: { int byte = i * bitmap.pitch + (j >> 3); int bit = 1 << (7 - (j % 8)); - wr[ofs + 0] = 255; //grayscale as 1 + wr[ofs + 0] = 255; // grayscale as 1 wr[ofs + 1] = (bitmap.buffer[byte] & bit) ? 255 : 0; } break; case FT_PIXEL_MODE_GRAY: - wr[ofs + 0] = 255; //grayscale as 1 + wr[ofs + 0] = 255; // grayscale as 1 wr[ofs + 1] = bitmap.buffer[i * bitmap.pitch + j]; - //wr[ofs + 1] = 100; break; case FT_PIXEL_MODE_BGRA: { int ofs_color = i * bitmap.pitch + (j << 2); @@ -1101,12 +1095,12 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma } FontGlyph chr; - chr.advance = (advance * p_data->scale / p_data->oversampling).round(); + chr.advance = advance * p_data->scale / p_data->oversampling; chr.texture_idx = tex_pos.index; chr.found = true; chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w, h); - chr.rect.position = (Vector2(xofs, -yofs) * p_data->scale / p_data->oversampling).round(); + chr.rect.position = Vector2(xofs, -yofs) * p_data->scale / p_data->oversampling; chr.rect.size = chr.uv_rect.size * p_data->scale / p_data->oversampling; return chr; } @@ -1162,7 +1156,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontDataAdvanced *p_font_d int error = FT_Load_Glyph(fd->face, p_glyph, flags); if (error) { fd->glyph_map[p_glyph] = FontGlyph(); - ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph."); + return false; } if (!outline) { @@ -1219,19 +1213,20 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontDataAdvanced *p_font_d } _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced *p_font_data, const Vector2i &p_size) const { + ERR_FAIL_COND_V(p_size.x <= 0, false); if (p_font_data->cache.has(p_size)) { return true; } FontDataForSizeAdvanced *fd = memnew(FontDataForSizeAdvanced); fd->size = p_size; - if (p_font_data->data_ptr) { + if (p_font_data->data_ptr && (p_font_data->data_size > 0)) { // Init dynamic font. #ifdef MODULE_FREETYPE_ENABLED int error = 0; if (!library) { error = FT_Init_FreeType(&library); - ERR_FAIL_COND_V_MSG(error != 0, false, TTR("FreeType: Error initializing library:") + " '" + String(FT_Error_String(error)) + "'."); + ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'."); } memset(&fd->stream, 0, sizeof(FT_StreamRec)); @@ -1249,20 +1244,14 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced if (error) { FT_Done_Face(fd->face); fd->face = nullptr; - ERR_FAIL_V_MSG(false, TTR("FreeType: Error loading font:") + " '" + String(FT_Error_String(error)) + "'."); - } - fd->hb_handle = hb_ft_font_create(fd->face, nullptr); - if (fd->hb_handle == nullptr) { - FT_Done_Face(fd->face); - fd->face = nullptr; - ERR_FAIL_V_MSG(false, TTR("HarfBuzz: Error creating FreeType font object.")); + ERR_FAIL_V_MSG(false, "FreeType: Error loading font: '" + String(FT_Error_String(error)) + "'."); } if (p_font_data->msdf) { fd->oversampling = 1.0f; fd->size.x = p_font_data->msdf_source_size; } else if (p_font_data->oversampling <= 0.0f) { - fd->oversampling = TS->font_get_global_oversampling(); + fd->oversampling = font_get_global_oversampling(); } else { fd->oversampling = p_font_data->oversampling; } @@ -1270,26 +1259,46 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced if (FT_HAS_COLOR(fd->face) && fd->face->num_fixed_sizes > 0) { int best_match = 0; int diff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[0].width)); - fd->scale = real_t(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width; + fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width; for (int i = 1; i < fd->face->num_fixed_sizes; i++) { int ndiff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[i].width)); if (ndiff < diff) { best_match = i; diff = ndiff; - fd->scale = real_t(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width; + fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width; } } FT_Select_Size(fd->face, best_match); } else { - FT_Set_Pixel_Sizes(fd->face, 0, fd->size.x * fd->oversampling); + FT_Set_Pixel_Sizes(fd->face, 0, float(fd->size.x * fd->oversampling)); + fd->scale = ((float)fd->size.x * fd->oversampling) / (float)fd->face->size->metrics.y_ppem; } + fd->hb_handle = hb_ft_font_create(fd->face, nullptr); + fd->ascent = (fd->face->size->metrics.ascender / 64.0) / fd->oversampling * fd->scale; fd->descent = (-fd->face->size->metrics.descender / 64.0) / fd->oversampling * fd->scale; fd->underline_position = (-FT_MulFix(fd->face->underline_position, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale; fd->underline_thickness = (FT_MulFix(fd->face->underline_thickness, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale; if (!p_font_data->face_init) { + // Get style flags and name. + if (fd->face->family_name != nullptr) { + p_font_data->font_name = String::utf8((const char *)fd->face->family_name); + } + if (fd->face->style_name != nullptr) { + p_font_data->style_name = String::utf8((const char *)fd->face->style_name); + } + p_font_data->style_flags = 0; + if (fd->face->style_flags & FT_STYLE_FLAG_BOLD) { + p_font_data->style_flags |= FONT_BOLD; + } + if (fd->face->style_flags & FT_STYLE_FLAG_ITALIC) { + p_font_data->style_flags |= FONT_ITALIC; + } + if (fd->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) { + p_font_data->style_flags |= FONT_FIXED_WIDTH; + } // Get supported scripts from OpenType font data. p_font_data->supported_scripts.clear(); unsigned int count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fd->hb_handle), HB_OT_TAG_GSUB, 0, nullptr, nullptr); @@ -1598,22 +1607,19 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced FT_Done_MM_Var(library, amaster); } #else - ERR_FAIL_V_MSG(false, TTR("FreeType: Can't load dynamic font, engine is compiled without FreeType support!"); + ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!"); #endif } else { // Init bitmap font. - fd->hb_handle = hb_bmp_font_create(fd, nullptr); - if (!fd->hb_handle) { - ERR_FAIL_V_MSG(false, TTR("HarfBuzz: Error creating bitmap font object.")); - } + fd->hb_handle = _bmp_font_create(fd, nullptr); } p_font_data->cache[p_size] = fd; return true; } _FORCE_INLINE_ void TextServerAdvanced::_font_clear_cache(FontDataAdvanced *p_font_data) { - for (const Map<Vector2i, FontDataForSizeAdvanced *>::Element *E = p_font_data->cache.front(); E; E = E->next()) { - memdelete(E->get()); + for (const KeyValue<Vector2i, FontDataForSizeAdvanced *> &E : p_font_data->cache) { + memdelete(E.value); } p_font_data->cache.clear(); p_font_data->face_init = false; @@ -1623,7 +1629,7 @@ _FORCE_INLINE_ void TextServerAdvanced::_font_clear_cache(FontDataAdvanced *p_fo } hb_font_t *TextServerAdvanced::_font_get_hb_handle(RID p_font_rid, int p_size) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, nullptr); MutexLock lock(fd->mutex); @@ -1641,7 +1647,7 @@ RID TextServerAdvanced::create_font() { } void TextServerAdvanced::font_set_data(RID p_font_rid, const PackedByteArray &p_data) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1652,7 +1658,7 @@ void TextServerAdvanced::font_set_data(RID p_font_rid, const PackedByteArray &p_ } void TextServerAdvanced::font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1662,8 +1668,68 @@ void TextServerAdvanced::font_set_data_ptr(RID p_font_rid, const uint8_t *p_data fd->data_size = p_data_size; } +void TextServerAdvanced::font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p_style) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + fd->style_flags = p_style; +} + +uint32_t /*FontStyle*/ TextServerAdvanced::font_get_style(RID p_font_rid) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, 0); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0); + return fd->style_flags; +} + +void TextServerAdvanced::font_set_style_name(RID p_font_rid, const String &p_name) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + fd->style_name = p_name; +} + +String TextServerAdvanced::font_get_style_name(RID p_font_rid) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, String()); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), String()); + return fd->style_name; +} + +void TextServerAdvanced::font_set_name(RID p_font_rid, const String &p_name) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND(!fd); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + fd->font_name = p_name; +} + +String TextServerAdvanced::font_get_name(RID p_font_rid) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, String()); + + MutexLock lock(fd->mutex); + Vector2i size = _get_size(fd, 16); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), String()); + return fd->font_name; +} + void TextServerAdvanced::font_set_antialiased(RID p_font_rid, bool p_antialiased) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1674,7 +1740,7 @@ void TextServerAdvanced::font_set_antialiased(RID p_font_rid, bool p_antialiased } bool TextServerAdvanced::font_is_antialiased(RID p_font_rid) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); MutexLock lock(fd->mutex); @@ -1682,7 +1748,7 @@ bool TextServerAdvanced::font_is_antialiased(RID p_font_rid) const { } void TextServerAdvanced::font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1693,7 +1759,7 @@ void TextServerAdvanced::font_set_multichannel_signed_distance_field(RID p_font_ } bool TextServerAdvanced::font_is_multichannel_signed_distance_field(RID p_font_rid) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); MutexLock lock(fd->mutex); @@ -1701,7 +1767,7 @@ bool TextServerAdvanced::font_is_multichannel_signed_distance_field(RID p_font_r } void TextServerAdvanced::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1712,7 +1778,7 @@ void TextServerAdvanced::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pi } int TextServerAdvanced::font_get_msdf_pixel_range(RID p_font_rid) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); MutexLock lock(fd->mutex); @@ -1720,7 +1786,7 @@ int TextServerAdvanced::font_get_msdf_pixel_range(RID p_font_rid) const { } void TextServerAdvanced::font_set_msdf_size(RID p_font_rid, int p_msdf_size) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1731,7 +1797,7 @@ void TextServerAdvanced::font_set_msdf_size(RID p_font_rid, int p_msdf_size) { } int TextServerAdvanced::font_get_msdf_size(RID p_font_rid) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); MutexLock lock(fd->mutex); @@ -1739,7 +1805,7 @@ int TextServerAdvanced::font_get_msdf_size(RID p_font_rid) const { } void TextServerAdvanced::font_set_fixed_size(RID p_font_rid, int p_fixed_size) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1749,7 +1815,7 @@ void TextServerAdvanced::font_set_fixed_size(RID p_font_rid, int p_fixed_size) { } int TextServerAdvanced::font_get_fixed_size(RID p_font_rid) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); MutexLock lock(fd->mutex); @@ -1757,7 +1823,7 @@ int TextServerAdvanced::font_get_fixed_size(RID p_font_rid) const { } void TextServerAdvanced::font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1768,7 +1834,7 @@ void TextServerAdvanced::font_set_force_autohinter(RID p_font_rid, bool p_force_ } bool TextServerAdvanced::font_is_force_autohinter(RID p_font_rid) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); MutexLock lock(fd->mutex); @@ -1776,7 +1842,7 @@ bool TextServerAdvanced::font_is_force_autohinter(RID p_font_rid) const { } void TextServerAdvanced::font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1787,7 +1853,7 @@ void TextServerAdvanced::font_set_hinting(RID p_font_rid, TextServer::Hinting p_ } TextServer::Hinting TextServerAdvanced::font_get_hinting(RID p_font_rid) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, HINTING_NONE); MutexLock lock(fd->mutex); @@ -1795,7 +1861,7 @@ TextServer::Hinting TextServerAdvanced::font_get_hinting(RID p_font_rid) const { } void TextServerAdvanced::font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1806,15 +1872,15 @@ void TextServerAdvanced::font_set_variation_coordinates(RID p_font_rid, const Di } Dictionary TextServerAdvanced::font_get_variation_coordinates(RID p_font_rid) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); MutexLock lock(fd->mutex); return fd->variation_coordinates; } -void TextServerAdvanced::font_set_oversampling(RID p_font_rid, real_t p_oversampling) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); +void TextServerAdvanced::font_set_oversampling(RID p_font_rid, float p_oversampling) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1824,8 +1890,8 @@ void TextServerAdvanced::font_set_oversampling(RID p_font_rid, real_t p_oversamp } } -real_t TextServerAdvanced::font_get_oversampling(RID p_font_rid) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); +float TextServerAdvanced::font_get_oversampling(RID p_font_rid) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.f); MutexLock lock(fd->mutex); @@ -1833,7 +1899,7 @@ real_t TextServerAdvanced::font_get_oversampling(RID p_font_rid) const { } Array TextServerAdvanced::font_get_size_cache_list(RID p_font_rid) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Array()); MutexLock lock(fd->mutex); @@ -1845,18 +1911,18 @@ Array TextServerAdvanced::font_get_size_cache_list(RID p_font_rid) const { } void TextServerAdvanced::font_clear_size_cache(RID p_font_rid) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); - for (const Map<Vector2i, FontDataForSizeAdvanced *>::Element *E = fd->cache.front(); E; E = E->next()) { - memdelete(E->get()); + for (const KeyValue<Vector2i, FontDataForSizeAdvanced *> &E : fd->cache) { + memdelete(E.value); } fd->cache.clear(); } void TextServerAdvanced::font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1866,8 +1932,8 @@ void TextServerAdvanced::font_remove_size_cache(RID p_font_rid, const Vector2i & } } -void TextServerAdvanced::font_set_ascent(RID p_font_rid, int p_size, real_t p_ascent) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); +void TextServerAdvanced::font_set_ascent(RID p_font_rid, int p_size, float p_ascent) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1877,8 +1943,8 @@ void TextServerAdvanced::font_set_ascent(RID p_font_rid, int p_size, real_t p_as fd->cache[size]->ascent = p_ascent; } -real_t TextServerAdvanced::font_get_ascent(RID p_font_rid, int p_size) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); +float TextServerAdvanced::font_get_ascent(RID p_font_rid, int p_size) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.f); MutexLock lock(fd->mutex); @@ -1887,14 +1953,14 @@ real_t TextServerAdvanced::font_get_ascent(RID p_font_rid, int p_size) const { ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f); if (fd->msdf) { - return fd->cache[size]->ascent * (real_t)p_size / (real_t)fd->msdf_source_size; + return fd->cache[size]->ascent * (float)p_size / (float)fd->msdf_source_size; } else { return fd->cache[size]->ascent; } } -void TextServerAdvanced::font_set_descent(RID p_font_rid, int p_size, real_t p_descent) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); +void TextServerAdvanced::font_set_descent(RID p_font_rid, int p_size, float p_descent) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); Vector2i size = _get_size(fd, p_size); @@ -1903,8 +1969,8 @@ void TextServerAdvanced::font_set_descent(RID p_font_rid, int p_size, real_t p_d fd->cache[size]->descent = p_descent; } -real_t TextServerAdvanced::font_get_descent(RID p_font_rid, int p_size) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); +float TextServerAdvanced::font_get_descent(RID p_font_rid, int p_size) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.f); MutexLock lock(fd->mutex); @@ -1913,14 +1979,14 @@ real_t TextServerAdvanced::font_get_descent(RID p_font_rid, int p_size) const { ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f); if (fd->msdf) { - return fd->cache[size]->descent * (real_t)p_size / (real_t)fd->msdf_source_size; + return fd->cache[size]->descent * (float)p_size / (float)fd->msdf_source_size; } else { return fd->cache[size]->descent; } } -void TextServerAdvanced::font_set_underline_position(RID p_font_rid, int p_size, real_t p_underline_position) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); +void TextServerAdvanced::font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1930,8 +1996,8 @@ void TextServerAdvanced::font_set_underline_position(RID p_font_rid, int p_size, fd->cache[size]->underline_position = p_underline_position; } -real_t TextServerAdvanced::font_get_underline_position(RID p_font_rid, int p_size) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); +float TextServerAdvanced::font_get_underline_position(RID p_font_rid, int p_size) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.f); MutexLock lock(fd->mutex); @@ -1940,14 +2006,14 @@ real_t TextServerAdvanced::font_get_underline_position(RID p_font_rid, int p_siz ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f); if (fd->msdf) { - return fd->cache[size]->underline_position * (real_t)p_size / (real_t)fd->msdf_source_size; + return fd->cache[size]->underline_position * (float)p_size / (float)fd->msdf_source_size; } else { return fd->cache[size]->underline_position; } } -void TextServerAdvanced::font_set_underline_thickness(RID p_font_rid, int p_size, real_t p_underline_thickness) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); +void TextServerAdvanced::font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1957,8 +2023,8 @@ void TextServerAdvanced::font_set_underline_thickness(RID p_font_rid, int p_size fd->cache[size]->underline_thickness = p_underline_thickness; } -real_t TextServerAdvanced::font_get_underline_thickness(RID p_font_rid, int p_size) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); +float TextServerAdvanced::font_get_underline_thickness(RID p_font_rid, int p_size) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.f); MutexLock lock(fd->mutex); @@ -1967,14 +2033,14 @@ real_t TextServerAdvanced::font_get_underline_thickness(RID p_font_rid, int p_si ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f); if (fd->msdf) { - return fd->cache[size]->underline_thickness * (real_t)p_size / (real_t)fd->msdf_source_size; + return fd->cache[size]->underline_thickness * (float)p_size / (float)fd->msdf_source_size; } else { return fd->cache[size]->underline_thickness; } } -void TextServerAdvanced::font_set_scale(RID p_font_rid, int p_size, real_t p_scale) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); +void TextServerAdvanced::font_set_scale(RID p_font_rid, int p_size, float p_scale) { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -1984,8 +2050,8 @@ void TextServerAdvanced::font_set_scale(RID p_font_rid, int p_size, real_t p_sca fd->cache[size]->scale = p_scale; } -real_t TextServerAdvanced::font_get_scale(RID p_font_rid, int p_size) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); +float TextServerAdvanced::font_get_scale(RID p_font_rid, int p_size) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0.f); MutexLock lock(fd->mutex); @@ -1994,14 +2060,14 @@ real_t TextServerAdvanced::font_get_scale(RID p_font_rid, int p_size) const { ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f); if (fd->msdf) { - return fd->cache[size]->scale * (real_t)p_size / (real_t)fd->msdf_source_size; + return fd->cache[size]->scale * (float)p_size / (float)fd->msdf_source_size; } else { return fd->cache[size]->scale / fd->cache[size]->oversampling; } } void TextServerAdvanced::font_set_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing, int p_value) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2022,7 +2088,7 @@ void TextServerAdvanced::font_set_spacing(RID p_font_rid, int p_size, TextServer } int TextServerAdvanced::font_get_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); MutexLock lock(fd->mutex); @@ -2033,14 +2099,14 @@ int TextServerAdvanced::font_get_spacing(RID p_font_rid, int p_size, TextServer: switch (p_spacing) { case TextServer::SPACING_GLYPH: { if (fd->msdf) { - return fd->cache[size]->spacing_glyph * (real_t)p_size / (real_t)fd->msdf_source_size; + return fd->cache[size]->spacing_glyph * (float)p_size / (float)fd->msdf_source_size; } else { return fd->cache[size]->spacing_glyph; } } break; case TextServer::SPACING_SPACE: { if (fd->msdf) { - return fd->cache[size]->spacing_space * (real_t)p_size / (real_t)fd->msdf_source_size; + return fd->cache[size]->spacing_space * (float)p_size / (float)fd->msdf_source_size; } else { return fd->cache[size]->spacing_space; } @@ -2053,7 +2119,7 @@ int TextServerAdvanced::font_get_spacing(RID p_font_rid, int p_size, TextServer: } int TextServerAdvanced::font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); MutexLock lock(fd->mutex); @@ -2065,7 +2131,7 @@ int TextServerAdvanced::font_get_texture_count(RID p_font_rid, const Vector2i &p } void TextServerAdvanced::font_clear_textures(RID p_font_rid, const Vector2i &p_size) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); @@ -2075,7 +2141,7 @@ void TextServerAdvanced::font_clear_textures(RID p_font_rid, const Vector2i &p_s } void TextServerAdvanced::font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2083,11 +2149,11 @@ void TextServerAdvanced::font_remove_texture(RID p_font_rid, const Vector2i &p_s ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); ERR_FAIL_INDEX(p_texture_index, fd->cache[size]->textures.size()); - fd->cache[size]->textures.remove(p_texture_index); + fd->cache[size]->textures.remove_at(p_texture_index); } void TextServerAdvanced::font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); ERR_FAIL_COND(p_image.is_null()); @@ -2113,7 +2179,7 @@ void TextServerAdvanced::font_set_texture_image(RID p_font_rid, const Vector2i & } Ref<Image> TextServerAdvanced::font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Ref<Image>()); MutexLock lock(fd->mutex); @@ -2128,12 +2194,13 @@ Ref<Image> TextServerAdvanced::font_get_texture_image(RID p_font_rid, const Vect } void TextServerAdvanced::font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); + ERR_FAIL_COND(p_texture_index < 0); if (p_texture_index >= fd->cache[size]->textures.size()) { fd->cache[size]->textures.resize(p_texture_index + 1); } @@ -2143,7 +2210,7 @@ void TextServerAdvanced::font_set_texture_offsets(RID p_font_rid, const Vector2i } PackedInt32Array TextServerAdvanced::font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, PackedInt32Array()); MutexLock lock(fd->mutex); @@ -2156,7 +2223,7 @@ PackedInt32Array TextServerAdvanced::font_get_texture_offsets(RID p_font_rid, co } Array TextServerAdvanced::font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Array()); MutexLock lock(fd->mutex); @@ -2173,7 +2240,7 @@ Array TextServerAdvanced::font_get_glyph_list(RID p_font_rid, const Vector2i &p_ } void TextServerAdvanced::font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2184,7 +2251,7 @@ void TextServerAdvanced::font_clear_glyphs(RID p_font_rid, const Vector2i &p_siz } void TextServerAdvanced::font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2195,7 +2262,7 @@ void TextServerAdvanced::font_remove_glyph(RID p_font_rid, const Vector2i &p_siz } Vector2 TextServerAdvanced::font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); MutexLock lock(fd->mutex); @@ -2209,14 +2276,14 @@ Vector2 TextServerAdvanced::font_get_glyph_advance(RID p_font_rid, int p_size, i const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; if (fd->msdf) { - return gl[p_glyph].advance * (real_t)p_size / (real_t)fd->msdf_source_size; + return gl[p_glyph].advance * (float)p_size / (float)fd->msdf_source_size; } else { return gl[p_glyph].advance; } } void TextServerAdvanced::font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2231,7 +2298,7 @@ void TextServerAdvanced::font_set_glyph_advance(RID p_font_rid, int p_size, int3 } Vector2 TextServerAdvanced::font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); MutexLock lock(fd->mutex); @@ -2245,14 +2312,14 @@ Vector2 TextServerAdvanced::font_get_glyph_offset(RID p_font_rid, const Vector2i const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; if (fd->msdf) { - return gl[p_glyph].rect.position * (real_t)p_size.x / (real_t)fd->msdf_source_size; + return gl[p_glyph].rect.position * (float)p_size.x / (float)fd->msdf_source_size; } else { return gl[p_glyph].rect.position; } } void TextServerAdvanced::font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2267,7 +2334,7 @@ void TextServerAdvanced::font_set_glyph_offset(RID p_font_rid, const Vector2i &p } Vector2 TextServerAdvanced::font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); MutexLock lock(fd->mutex); @@ -2281,14 +2348,14 @@ Vector2 TextServerAdvanced::font_get_glyph_size(RID p_font_rid, const Vector2i & const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map; if (fd->msdf) { - return gl[p_glyph].rect.size * (real_t)p_size.x / (real_t)fd->msdf_source_size; + return gl[p_glyph].rect.size * (float)p_size.x / (float)fd->msdf_source_size; } else { return gl[p_glyph].rect.size; } } void TextServerAdvanced::font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2303,7 +2370,7 @@ void TextServerAdvanced::font_set_glyph_size(RID p_font_rid, const Vector2i &p_s } Rect2 TextServerAdvanced::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Rect2()); MutexLock lock(fd->mutex); @@ -2319,7 +2386,7 @@ Rect2 TextServerAdvanced::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i } void TextServerAdvanced::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2334,7 +2401,7 @@ void TextServerAdvanced::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i & } int TextServerAdvanced::font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, -1); MutexLock lock(fd->mutex); @@ -2350,7 +2417,7 @@ int TextServerAdvanced::font_get_glyph_texture_idx(RID p_font_rid, const Vector2 } void TextServerAdvanced::font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2364,42 +2431,50 @@ void TextServerAdvanced::font_set_glyph_texture_idx(RID p_font_rid, const Vector gl[p_glyph].found = true; } -bool TextServerAdvanced::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); - ERR_FAIL_COND_V(!fd, false); +Dictionary TextServerAdvanced::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index) const { + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); + ERR_FAIL_COND_V(!fd, Dictionary()); MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); - ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), false); + ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary()); + Vector<Vector3> points; + Vector<int32_t> contours; + bool orientation; #ifdef MODULE_FREETYPE_ENABLED int error = FT_Load_Glyph(fd->cache[size]->face, p_index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)); - ERR_FAIL_COND_V(error, false); + ERR_FAIL_COND_V(error, Dictionary()); - r_points.clear(); - r_contours.clear(); + points.clear(); + contours.clear(); - real_t h = fd->cache[size]->ascent; - real_t scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale; + float h = fd->cache[size]->ascent; + float scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale; if (fd->msdf) { - scale = scale * (real_t)p_size / (real_t)fd->msdf_source_size; + scale = scale * (float)p_size / (float)fd->msdf_source_size; } for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_points; i++) { - r_points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, h - fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i]))); + points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, h - fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i]))); } for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_contours; i++) { - r_contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]); + contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]); } - r_orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT); + orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT); #else - return false; + return Dictionary(); #endif - return true; + + Dictionary out; + out["points"] = points; + out["contours"] = contours; + out["orientation"] = orientation; + return out; } Array TextServerAdvanced::font_get_kerning_list(RID p_font_rid, int p_size) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Array()); MutexLock lock(fd->mutex); @@ -2415,7 +2490,7 @@ Array TextServerAdvanced::font_get_kerning_list(RID p_font_rid, int p_size) cons } void TextServerAdvanced::font_clear_kerning_map(RID p_font_rid, int p_size) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2426,7 +2501,7 @@ void TextServerAdvanced::font_clear_kerning_map(RID p_font_rid, int p_size) { } void TextServerAdvanced::font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2437,7 +2512,7 @@ void TextServerAdvanced::font_remove_kerning(RID p_font_rid, int p_size, const V } void TextServerAdvanced::font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2448,7 +2523,7 @@ void TextServerAdvanced::font_set_kerning(RID p_font_rid, int p_size, const Vect } Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector2()); MutexLock lock(fd->mutex); @@ -2460,7 +2535,7 @@ Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const V if (kern.has(p_glyph_pair)) { if (fd->msdf) { - return kern[p_glyph_pair] * (real_t)p_size / (real_t)fd->msdf_source_size; + return kern[p_glyph_pair] * (float)p_size / (float)fd->msdf_source_size; } else { return kern[p_glyph_pair]; } @@ -2470,7 +2545,7 @@ Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const V FT_Vector delta; FT_Get_Kerning(fd->cache[size]->face, p_glyph_pair.x, p_glyph_pair.y, FT_KERNING_DEFAULT, &delta); if (fd->msdf) { - return Vector2(delta.x, delta.y) * (real_t)p_size / (real_t)fd->msdf_source_size; + return Vector2(delta.x, delta.y) * (float)p_size / (float)fd->msdf_source_size; } else { return Vector2(delta.x, delta.y); } @@ -2481,8 +2556,10 @@ Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const V } int32_t TextServerAdvanced::font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, 0); + ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), 0, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + "."); + ERR_FAIL_COND_V_MSG((p_variation_selector >= 0xd800 && p_variation_selector <= 0xdfff) || (p_variation_selector > 0x10ffff), 0, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_variation_selector, 16) + "."); MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); @@ -2504,8 +2581,9 @@ int32_t TextServerAdvanced::font_get_glyph_index(RID p_font_rid, int p_size, cha } bool TextServerAdvanced::font_has_char(RID p_font_rid, char32_t p_char) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *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) + "."); MutexLock lock(fd->mutex); if (fd->cache.is_empty()) { @@ -2522,7 +2600,7 @@ bool TextServerAdvanced::font_has_char(RID p_font_rid, char32_t p_char) const { } String TextServerAdvanced::font_get_supported_chars(RID p_font_rid) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, String()); MutexLock lock(fd->mutex); @@ -2556,8 +2634,10 @@ String TextServerAdvanced::font_get_supported_chars(RID p_font_rid) const { } void TextServerAdvanced::font_render_range(RID p_font_rid, const Vector2i &p_size, char32_t p_start, char32_t p_end) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *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) + "."); + ERR_FAIL_COND_MSG((p_end >= 0xd800 && p_end <= 0xdfff) || (p_end > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_end, 16) + "."); MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, p_size); @@ -2574,7 +2654,7 @@ void TextServerAdvanced::font_render_range(RID p_font_rid, const Vector2i &p_siz } void TextServerAdvanced::font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2584,14 +2664,14 @@ void TextServerAdvanced::font_render_glyph(RID p_font_rid, const Vector2i &p_siz } void TextServerAdvanced::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); Vector2i size = _get_size(fd, p_size); ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); if (!_ensure_glyph(fd, size, p_index)) { - return; // // Invalid or non graphicl glyph, do not display errors, nothing to draw. + return; // Invalid or non-graphical glyph, do not display errors, nothing to draw. } const FontGlyph &gl = fd->cache[size]->glyph_map[p_index]; @@ -2609,13 +2689,13 @@ void TextServerAdvanced::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid(); if (fd->msdf) { Point2 cpos = p_pos; - cpos += gl.rect.position * (real_t)p_size / (real_t)fd->msdf_source_size; - Size2 csize = gl.rect.size * (real_t)p_size / (real_t)fd->msdf_source_size; + cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size; + Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size; RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range); } else { - Point2i cpos = p_pos; + Point2 cpos = p_pos.floor(); cpos += gl.rect.position; - Size2i csize = gl.rect.size; + 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); } } @@ -2624,14 +2704,14 @@ void TextServerAdvanced::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz } void TextServerAdvanced::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); Vector2i size = _get_size_outline(fd, Vector2i(p_size, p_outline_size)); ERR_FAIL_COND(!_ensure_cache_for_size(fd, size)); if (!_ensure_glyph(fd, size, p_index)) { - return; // // Invalid or non graphicl glyph, do not display errors, nothing to draw. + return; // Invalid or non-graphical glyph, do not display errors, nothing to draw. } const FontGlyph &gl = fd->cache[size]->glyph_map[p_index]; @@ -2649,13 +2729,13 @@ void TextServerAdvanced::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid(); if (fd->msdf) { Point2 cpos = p_pos; - cpos += gl.rect.position * (real_t)p_size / (real_t)fd->msdf_source_size; - Size2 csize = gl.rect.size * (real_t)p_size / (real_t)fd->msdf_source_size; + cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size; + Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size; 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 { - Point2i cpos = p_pos; + Point2 cpos = p_pos.floor(); cpos += gl.rect.position; - Size2i csize = gl.rect.size; + 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); } } @@ -2664,7 +2744,7 @@ void TextServerAdvanced::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i } bool TextServerAdvanced::font_is_language_supported(RID p_font_rid, const String &p_language) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); MutexLock lock(fd->mutex); @@ -2676,7 +2756,7 @@ bool TextServerAdvanced::font_is_language_supported(RID p_font_rid, const String } void TextServerAdvanced::font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2684,7 +2764,7 @@ void TextServerAdvanced::font_set_language_support_override(RID p_font_rid, cons } bool TextServerAdvanced::font_get_language_support_override(RID p_font_rid, const String &p_language) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); MutexLock lock(fd->mutex); @@ -2692,7 +2772,7 @@ bool TextServerAdvanced::font_get_language_support_override(RID p_font_rid, cons } void TextServerAdvanced::font_remove_language_support_override(RID p_font_rid, const String &p_language) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2700,19 +2780,19 @@ void TextServerAdvanced::font_remove_language_support_override(RID p_font_rid, c } Vector<String> TextServerAdvanced::font_get_language_support_overrides(RID p_font_rid) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector<String>()); MutexLock lock(fd->mutex); Vector<String> out; - for (const Map<String, bool>::Element *E = fd->language_support_overrides.front(); E; E = E->next()) { - out.push_back(E->key()); + for (const KeyValue<String, bool> &E : fd->language_support_overrides) { + out.push_back(E.key); } return out; } bool TextServerAdvanced::font_is_script_supported(RID p_font_rid, const String &p_script) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); MutexLock lock(fd->mutex); @@ -2721,12 +2801,12 @@ bool TextServerAdvanced::font_is_script_supported(RID p_font_rid, const String & } else { Vector2i size = _get_size(fd, 16); ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), false); - return fd->supported_scripts.has(TS->name_to_tag(p_script)); + return fd->supported_scripts.has(hb_tag_from_string(p_script.ascii().get_data(), -1)); } } void TextServerAdvanced::font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2734,7 +2814,7 @@ void TextServerAdvanced::font_set_script_support_override(RID p_font_rid, const } bool TextServerAdvanced::font_get_script_support_override(RID p_font_rid, const String &p_script) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, false); MutexLock lock(fd->mutex); @@ -2742,7 +2822,7 @@ bool TextServerAdvanced::font_get_script_support_override(RID p_font_rid, const } void TextServerAdvanced::font_remove_script_support_override(RID p_font_rid, const String &p_script) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND(!fd); MutexLock lock(fd->mutex); @@ -2750,7 +2830,7 @@ void TextServerAdvanced::font_remove_script_support_override(RID p_font_rid, con } Vector<String> TextServerAdvanced::font_get_script_support_overrides(RID p_font_rid) { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Vector<String>()); MutexLock lock(fd->mutex); @@ -2762,7 +2842,7 @@ Vector<String> TextServerAdvanced::font_get_script_support_overrides(RID p_font_ } Dictionary TextServerAdvanced::font_supported_feature_list(RID p_font_rid) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); MutexLock lock(fd->mutex); @@ -2772,7 +2852,7 @@ Dictionary TextServerAdvanced::font_supported_feature_list(RID p_font_rid) const } Dictionary TextServerAdvanced::font_supported_variation_list(RID p_font_rid) const { - FontDataAdvanced *fd = font_owner.getornull(p_font_rid); + FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid); ERR_FAIL_COND_V(!fd, Dictionary()); MutexLock lock(fd->mutex); @@ -2781,11 +2861,11 @@ Dictionary TextServerAdvanced::font_supported_variation_list(RID p_font_rid) con return fd->supported_varaitions; } -real_t TextServerAdvanced::font_get_global_oversampling() const { +float TextServerAdvanced::font_get_global_oversampling() const { return oversampling; } -void TextServerAdvanced::font_set_global_oversampling(real_t p_oversampling) { +void TextServerAdvanced::font_set_global_oversampling(float p_oversampling) { _THREAD_SAFE_METHOD_ if (oversampling != p_oversampling) { oversampling = p_oversampling; @@ -2803,7 +2883,7 @@ void TextServerAdvanced::font_set_global_oversampling(real_t p_oversampling) { List<RID> text_bufs; shaped_owner.get_owned_list(&text_bufs); for (const RID &E : text_bufs) { - invalidate(shaped_owner.getornull(E)); + invalidate(shaped_owner.get_or_null(E)); } } } @@ -2864,11 +2944,11 @@ void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced * } void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) { - ShapedTextDataAdvanced *parent = shaped_owner.getornull(p_shaped->parent); + ShapedTextDataAdvanced *parent = shaped_owner.get_or_null(p_shaped->parent); - for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = parent->objects.front(); E; E = E->next()) { - if (E->get().pos >= p_shaped->start && E->get().pos < p_shaped->end) { - p_shaped->objects[E->key()] = E->get(); + for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : parent->objects) { + if (E.value.pos >= p_shaped->start && E.value.pos < p_shaped->end) { + p_shaped->objects[E.key] = E.value; } } @@ -2895,7 +2975,7 @@ RID TextServerAdvanced::create_shaped_text(TextServer::Direction p_direction, Te } void TextServerAdvanced::shaped_text_clear(RID p_shaped) { - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); MutexLock lock(sd->mutex); @@ -2910,7 +2990,7 @@ void TextServerAdvanced::shaped_text_clear(RID p_shaped) { } void TextServerAdvanced::shaped_text_set_direction(RID p_shaped, TextServer::Direction p_direction) { - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); MutexLock lock(sd->mutex); @@ -2924,27 +3004,51 @@ void TextServerAdvanced::shaped_text_set_direction(RID p_shaped, TextServer::Dir } TextServer::Direction TextServerAdvanced::shaped_text_get_direction(RID p_shaped) const { - const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, TextServer::DIRECTION_LTR); MutexLock lock(sd->mutex); return sd->direction; } -void TextServerAdvanced::shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) { - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); +void TextServerAdvanced::shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) { + _THREAD_SAFE_METHOD_ + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND(!sd); + + if (sd->custom_punct != p_punct) { + if (sd->parent != RID()) { + full_copy(sd); + } + sd->custom_punct = p_punct; + invalidate(sd); + } +} + +String TextServerAdvanced::shaped_text_get_custom_punctuation(RID p_shaped) const { + _THREAD_SAFE_METHOD_ + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, String()); + return sd->custom_punct; +} + +void TextServerAdvanced::shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) { + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); MutexLock lock(sd->mutex); if (sd->parent != RID()) { full_copy(sd); } - sd->bidi_override = p_override; + sd->bidi_override.clear(); + for (int i = 0; i < p_override.size(); i++) { + sd->bidi_override.push_back(p_override[i]); + } invalidate(sd); } void TextServerAdvanced::shaped_text_set_orientation(RID p_shaped, TextServer::Orientation p_orientation) { - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); MutexLock lock(sd->mutex); @@ -2958,7 +3062,7 @@ void TextServerAdvanced::shaped_text_set_orientation(RID p_shaped, TextServer::O } void TextServerAdvanced::shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) { - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); MutexLock lock(sd->mutex); @@ -2970,7 +3074,7 @@ void TextServerAdvanced::shaped_text_set_preserve_invalid(RID p_shaped, bool p_e } bool TextServerAdvanced::shaped_text_get_preserve_invalid(RID p_shaped) const { - const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); @@ -2978,7 +3082,7 @@ bool TextServerAdvanced::shaped_text_get_preserve_invalid(RID p_shaped) const { } void TextServerAdvanced::shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) { - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND(!sd); MutexLock lock(sd->mutex); @@ -2992,7 +3096,7 @@ void TextServerAdvanced::shaped_text_set_preserve_control(RID p_shaped, bool p_e } bool TextServerAdvanced::shaped_text_get_preserve_control(RID p_shaped) const { - const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); @@ -3000,7 +3104,7 @@ bool TextServerAdvanced::shaped_text_get_preserve_control(RID p_shaped) const { } TextServer::Orientation TextServerAdvanced::shaped_text_get_orientation(RID p_shaped) const { - const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, TextServer::ORIENTATION_HORIZONTAL); MutexLock lock(sd->mutex); @@ -3008,13 +3112,13 @@ TextServer::Orientation TextServerAdvanced::shaped_text_get_orientation(RID p_sh } bool TextServerAdvanced::shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) { - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); ERR_FAIL_COND_V(p_size <= 0, false); MutexLock lock(sd->mutex); for (int i = 0; i < p_fonts.size(); i++) { - ERR_FAIL_COND_V(!font_owner.getornull(p_fonts[i]), false); + ERR_FAIL_COND_V(!font_owner.get_or_null(p_fonts[i]), false); } if (p_text.is_empty()) { @@ -3041,9 +3145,9 @@ bool TextServerAdvanced::shaped_text_add_string(RID p_shaped, const String &p_te return true; } -bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) { +bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align, int p_length) { _THREAD_SAFE_METHOD_ - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); ERR_FAIL_COND_V(p_key == Variant(), false); ERR_FAIL_COND_V(sd->objects.has(p_key), false); @@ -3053,7 +3157,7 @@ bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, con } ShapedTextDataAdvanced::Span span; - span.start = sd->text.length(); + span.start = sd->start + sd->text.length(); span.end = span.start + p_length; span.embedded_key = p_key; @@ -3071,8 +3175,8 @@ bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, con return true; } -bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) { - ShapedTextData *sd = shaped_owner.getornull(p_shaped); +bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align) { + ShapedTextData *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); @@ -3092,9 +3196,9 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, Glyph gl = sd->glyphs[i]; Variant key; if (gl.count == 1) { - for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) { - if (E->get().pos == gl.start) { - key = E->key(); + for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) { + if (E.value.pos == gl.start) { + key = E.key; break; } } @@ -3123,8 +3227,7 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, } 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, 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)); + sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y); } else { 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)); @@ -3135,66 +3238,66 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, } // Align embedded objects to baseline. - real_t full_ascent = sd->ascent; - real_t full_descent = sd->descent; - for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) { - if ((E->get().pos >= sd->start) && (E->get().pos < sd->end)) { + float full_ascent = sd->ascent; + float full_descent = sd->descent; + for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) { + if ((E.value.pos >= sd->start) && (E.value.pos < sd->end)) { if (sd->orientation == ORIENTATION_HORIZONTAL) { - switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { - case INLINE_ALIGN_TO_TOP: { - E->get().rect.position.y = -sd->ascent; + switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { + case INLINE_ALIGNMENT_TO_TOP: { + E.value.rect.position.y = -sd->ascent; } break; - case INLINE_ALIGN_TO_CENTER: { - E->get().rect.position.y = (-sd->ascent + sd->descent) / 2; + case INLINE_ALIGNMENT_TO_CENTER: { + E.value.rect.position.y = (-sd->ascent + sd->descent) / 2; } break; - case INLINE_ALIGN_TO_BASELINE: { - E->get().rect.position.y = 0; + case INLINE_ALIGNMENT_TO_BASELINE: { + E.value.rect.position.y = 0; } break; - case INLINE_ALIGN_TO_BOTTOM: { - E->get().rect.position.y = sd->descent; + case INLINE_ALIGNMENT_TO_BOTTOM: { + E.value.rect.position.y = sd->descent; } break; } - switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { - case INLINE_ALIGN_BOTTOM_TO: { - E->get().rect.position.y -= E->get().rect.size.y; + switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { + case INLINE_ALIGNMENT_BOTTOM_TO: { + E.value.rect.position.y -= E.value.rect.size.y; } break; - case INLINE_ALIGN_CENTER_TO: { - E->get().rect.position.y -= E->get().rect.size.y / 2; + case INLINE_ALIGNMENT_CENTER_TO: { + E.value.rect.position.y -= E.value.rect.size.y / 2; } break; - case INLINE_ALIGN_TOP_TO: { - //NOP + case INLINE_ALIGNMENT_TOP_TO: { + // NOP } break; } - full_ascent = MAX(full_ascent, -E->get().rect.position.y); - full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y); + full_ascent = MAX(full_ascent, -E.value.rect.position.y); + full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y); } else { - switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { - case INLINE_ALIGN_TO_TOP: { - E->get().rect.position.x = -sd->ascent; + switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { + case INLINE_ALIGNMENT_TO_TOP: { + E.value.rect.position.x = -sd->ascent; } break; - case INLINE_ALIGN_TO_CENTER: { - E->get().rect.position.x = (-sd->ascent + sd->descent) / 2; + case INLINE_ALIGNMENT_TO_CENTER: { + E.value.rect.position.x = (-sd->ascent + sd->descent) / 2; } break; - case INLINE_ALIGN_TO_BASELINE: { - E->get().rect.position.x = 0; + case INLINE_ALIGNMENT_TO_BASELINE: { + E.value.rect.position.x = 0; } break; - case INLINE_ALIGN_TO_BOTTOM: { - E->get().rect.position.x = sd->descent; + case INLINE_ALIGNMENT_TO_BOTTOM: { + E.value.rect.position.x = sd->descent; } break; } - switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { - case INLINE_ALIGN_BOTTOM_TO: { - E->get().rect.position.x -= E->get().rect.size.x; + switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { + case INLINE_ALIGNMENT_BOTTOM_TO: { + E.value.rect.position.x -= E.value.rect.size.x; } break; - case INLINE_ALIGN_CENTER_TO: { - E->get().rect.position.x -= E->get().rect.size.x / 2; + case INLINE_ALIGNMENT_CENTER_TO: { + E.value.rect.position.x -= E.value.rect.size.x / 2; } break; - case INLINE_ALIGN_TOP_TO: { - //NOP + case INLINE_ALIGNMENT_TOP_TO: { + // NOP } break; } - full_ascent = MAX(full_ascent, -E->get().rect.position.x); - full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x); + full_ascent = MAX(full_ascent, -E.value.rect.position.x); + full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x); } } } @@ -3205,7 +3308,7 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, } RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_length) const { - const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, RID()); MutexLock lock(sd->mutex); @@ -3220,59 +3323,72 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng ERR_FAIL_COND_V(sd->end < p_start + p_length, RID()); ShapedTextDataAdvanced *new_sd = memnew(ShapedTextDataAdvanced); - - new_sd->hb_buffer = hb_buffer_create(); new_sd->parent = p_shaped; new_sd->start = p_start; new_sd->end = p_start + p_length; - new_sd->orientation = sd->orientation; new_sd->direction = sd->direction; + new_sd->custom_punct = sd->custom_punct; new_sd->para_direction = sd->para_direction; - new_sd->line_breaks_valid = sd->line_breaks_valid; - new_sd->justification_ops_valid = sd->justification_ops_valid; - new_sd->sort_valid = false; - new_sd->upos = sd->upos; - new_sd->uthk = sd->uthk; + + if (!_shape_substr(new_sd, sd, p_start, p_length)) { + memdelete(new_sd); + return RID(); + } + return shaped_owner.make_rid(new_sd); +} + +bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int p_start, int p_length) const { + if (p_new_sd->valid) { + return true; + } + + p_new_sd->hb_buffer = hb_buffer_create(); + + p_new_sd->line_breaks_valid = p_sd->line_breaks_valid; + p_new_sd->justification_ops_valid = p_sd->justification_ops_valid; + p_new_sd->sort_valid = false; + p_new_sd->upos = p_sd->upos; + p_new_sd->uthk = p_sd->uthk; if (p_length > 0) { - new_sd->text = sd->text.substr(p_start, p_length); - new_sd->utf16 = new_sd->text.utf16(); - new_sd->script_iter = memnew(ScriptIterator(new_sd->text, 0, new_sd->text.length())); + p_new_sd->text = p_sd->text.substr(p_start - p_sd->start, p_length); + p_new_sd->utf16 = p_new_sd->text.utf16(); + p_new_sd->script_iter = memnew(ScriptIterator(p_new_sd->text, 0, p_new_sd->text.length())); - int sd_size = sd->glyphs.size(); - const Glyph *sd_glyphs = sd->glyphs.ptr(); - for (int ov = 0; ov < sd->bidi_override.size(); ov++) { + int sd_size = p_sd->glyphs.size(); + const Glyph *sd_glyphs = p_sd->glyphs.ptr(); + for (int ov = 0; ov < p_sd->bidi_override.size(); ov++) { UErrorCode err = U_ZERO_ERROR; - if (sd->bidi_override[ov].x >= p_start + p_length || sd->bidi_override[ov].y <= p_start) { + if (p_sd->bidi_override[ov].x >= p_start + p_length || p_sd->bidi_override[ov].y <= p_start) { continue; } - int start = _convert_pos_inv(sd, MAX(0, p_start - sd->bidi_override[ov].x)); - int end = _convert_pos_inv(sd, MIN(p_start + p_length, sd->bidi_override[ov].y) - sd->bidi_override[ov].x); + int start = _convert_pos_inv(p_sd, MAX(0, p_start - p_sd->bidi_override[ov].x)); + int end = _convert_pos_inv(p_sd, MIN(p_start + p_length, p_sd->bidi_override[ov].y) - p_sd->bidi_override[ov].x); - ERR_FAIL_COND_V_MSG((start < 0 || end - start > new_sd->utf16.length()), RID(), "Invalid BiDi override range."); + ERR_FAIL_COND_V_MSG((start < 0 || end - start > p_new_sd->utf16.length()), false, "Invalid BiDi override range."); // Create temporary line bidi & shape. UBiDi *bidi_iter = ubidi_openSized(end - start, 0, &err); - ERR_FAIL_COND_V_MSG(U_FAILURE(err), RID(), u_errorName(err)); - ubidi_setLine(sd->bidi_iter[ov], start, end, bidi_iter, &err); + ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err)); + ubidi_setLine(p_sd->bidi_iter[ov], start, end, bidi_iter, &err); if (U_FAILURE(err)) { ubidi_close(bidi_iter); - ERR_FAIL_V_MSG(RID(), u_errorName(err)); + ERR_FAIL_V_MSG(false, u_errorName(err)); } - new_sd->bidi_iter.push_back(bidi_iter); + p_new_sd->bidi_iter.push_back(bidi_iter); err = U_ZERO_ERROR; int bidi_run_count = ubidi_countRuns(bidi_iter, &err); - ERR_FAIL_COND_V_MSG(U_FAILURE(err), RID(), u_errorName(err)); + ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err)); for (int i = 0; i < bidi_run_count; i++) { int32_t _bidi_run_start = 0; int32_t _bidi_run_length = 0; ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length); - 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); + int32_t bidi_run_start = _convert_pos(p_sd, p_sd->bidi_override[ov].x + start + _bidi_run_start); + int32_t bidi_run_end = _convert_pos(p_sd, p_sd->bidi_override[ov].x + start + _bidi_run_start + _bidi_run_length); for (int j = 0; j < sd_size; j++) { if ((sd_glyphs[j].start >= bidi_run_start) && (sd_glyphs[j].end <= bidi_run_end)) { @@ -3281,132 +3397,131 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng 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) { + for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : p_sd->objects) { + if (E.value.pos == gl.start) { find_embedded = true; - key = E->key(); - new_sd->objects[key] = E->get(); + key = E.key; + p_new_sd->objects[key] = E.value; break; } } } 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; + if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) { + p_new_sd->objects[key].rect.position.x = p_new_sd->width; + p_new_sd->width += p_new_sd->objects[key].rect.size.x; } else { - new_sd->objects[key].rect.position.y = new_sd->width; - new_sd->width += new_sd->objects[key].rect.size.y; + p_new_sd->objects[key].rect.position.y = p_new_sd->width; + p_new_sd->width += p_new_sd->objects[key].rect.size.y; } } else { if (gl.font_rid.is_valid()) { - if (new_sd->orientation == ORIENTATION_HORIZONTAL) { - new_sd->ascent = MAX(new_sd->ascent, MAX(font_get_ascent(gl.font_rid, gl.font_size), -gl.y_off)); - new_sd->descent = MAX(new_sd->descent, MAX(font_get_descent(gl.font_rid, gl.font_size), gl.y_off)); + if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) { + p_new_sd->ascent = MAX(p_new_sd->ascent, MAX(font_get_ascent(gl.font_rid, gl.font_size), -gl.y_off)); + p_new_sd->descent = MAX(p_new_sd->descent, MAX(font_get_descent(gl.font_rid, gl.font_size), gl.y_off)); } 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)); + p_new_sd->ascent = MAX(p_new_sd->ascent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); + p_new_sd->descent = MAX(p_new_sd->descent, Math::round(font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5)); } - } else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) { + } else if (p_new_sd->preserve_invalid || (p_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, 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)); + if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) { + p_new_sd->ascent = MAX(p_new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y); } else { - 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)); + p_new_sd->ascent = MAX(p_new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f)); + p_new_sd->descent = MAX(p_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; + p_new_sd->width += gl.advance * gl.repeat; } - new_sd->glyphs.push_back(gl); + p_new_sd->glyphs.push_back(gl); } } } } // Align embedded objects to baseline. - real_t full_ascent = new_sd->ascent; - real_t full_descent = new_sd->descent; - for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = new_sd->objects.front(); E; E = E->next()) { - if ((E->get().pos >= new_sd->start) && (E->get().pos < new_sd->end)) { - if (sd->orientation == ORIENTATION_HORIZONTAL) { - switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { - case INLINE_ALIGN_TO_TOP: { - E->get().rect.position.y = -new_sd->ascent; + float full_ascent = p_new_sd->ascent; + float full_descent = p_new_sd->descent; + for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : p_new_sd->objects) { + if ((E.value.pos >= p_new_sd->start) && (E.value.pos < p_new_sd->end)) { + if (p_sd->orientation == ORIENTATION_HORIZONTAL) { + switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { + case INLINE_ALIGNMENT_TO_TOP: { + E.value.rect.position.y = -p_new_sd->ascent; } break; - case INLINE_ALIGN_TO_CENTER: { - E->get().rect.position.y = (-new_sd->ascent + new_sd->descent) / 2; + case INLINE_ALIGNMENT_TO_CENTER: { + E.value.rect.position.y = (-p_new_sd->ascent + p_new_sd->descent) / 2; } break; - case INLINE_ALIGN_TO_BASELINE: { - E->get().rect.position.y = 0; + case INLINE_ALIGNMENT_TO_BASELINE: { + E.value.rect.position.y = 0; } break; - case INLINE_ALIGN_TO_BOTTOM: { - E->get().rect.position.y = new_sd->descent; + case INLINE_ALIGNMENT_TO_BOTTOM: { + E.value.rect.position.y = p_new_sd->descent; } break; } - switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { - case INLINE_ALIGN_BOTTOM_TO: { - E->get().rect.position.y -= E->get().rect.size.y; + switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { + case INLINE_ALIGNMENT_BOTTOM_TO: { + E.value.rect.position.y -= E.value.rect.size.y; } break; - case INLINE_ALIGN_CENTER_TO: { - E->get().rect.position.y -= E->get().rect.size.y / 2; + case INLINE_ALIGNMENT_CENTER_TO: { + E.value.rect.position.y -= E.value.rect.size.y / 2; } break; - case INLINE_ALIGN_TOP_TO: { - //NOP + case INLINE_ALIGNMENT_TOP_TO: { + // NOP } break; } - full_ascent = MAX(full_ascent, -E->get().rect.position.y); - full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y); + full_ascent = MAX(full_ascent, -E.value.rect.position.y); + full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y); } else { - switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { - case INLINE_ALIGN_TO_TOP: { - E->get().rect.position.x = -new_sd->ascent; + switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { + case INLINE_ALIGNMENT_TO_TOP: { + E.value.rect.position.x = -p_new_sd->ascent; } break; - case INLINE_ALIGN_TO_CENTER: { - E->get().rect.position.x = (-new_sd->ascent + new_sd->descent) / 2; + case INLINE_ALIGNMENT_TO_CENTER: { + E.value.rect.position.x = (-p_new_sd->ascent + p_new_sd->descent) / 2; } break; - case INLINE_ALIGN_TO_BASELINE: { - E->get().rect.position.x = 0; + case INLINE_ALIGNMENT_TO_BASELINE: { + E.value.rect.position.x = 0; } break; - case INLINE_ALIGN_TO_BOTTOM: { - E->get().rect.position.x = new_sd->descent; + case INLINE_ALIGNMENT_TO_BOTTOM: { + E.value.rect.position.x = p_new_sd->descent; } break; } - switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { - case INLINE_ALIGN_BOTTOM_TO: { - E->get().rect.position.x -= E->get().rect.size.x; + switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { + case INLINE_ALIGNMENT_BOTTOM_TO: { + E.value.rect.position.x -= E.value.rect.size.x; } break; - case INLINE_ALIGN_CENTER_TO: { - E->get().rect.position.x -= E->get().rect.size.x / 2; + case INLINE_ALIGNMENT_CENTER_TO: { + E.value.rect.position.x -= E.value.rect.size.x / 2; } break; - case INLINE_ALIGN_TOP_TO: { - //NOP + case INLINE_ALIGNMENT_TOP_TO: { + // NOP } break; } - full_ascent = MAX(full_ascent, -E->get().rect.position.x); - full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x); + full_ascent = MAX(full_ascent, -E.value.rect.position.x); + full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x); } } } - new_sd->ascent = full_ascent; - new_sd->descent = full_descent; + p_new_sd->ascent = full_ascent; + p_new_sd->descent = full_descent; } - new_sd->valid = true; + p_new_sd->valid = true; - return shaped_owner.make_rid(new_sd); + return true; } RID TextServerAdvanced::shaped_text_get_parent(RID p_shaped) const { - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, RID()); MutexLock lock(sd->mutex); return sd->parent; } -real_t TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, real_t p_width, uint8_t /*JustificationFlag*/ p_jst_flags) { - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); +float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags) { + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.f); MutexLock lock(sd->mutex); @@ -3446,7 +3561,7 @@ real_t TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, real_t p_width } } - real_t justification_width; + float justification_width; if ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) == JUSTIFICATION_CONSTRAIN_ELLIPSIS) { if (sd->overrun_trim_data.trim_pos >= 0) { start_pos = sd->overrun_trim_data.trim_pos; @@ -3486,7 +3601,7 @@ real_t TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, real_t p_width } if ((elongation_count > 0) && ((p_jst_flags & JUSTIFICATION_KASHIDA) == JUSTIFICATION_KASHIDA)) { - real_t delta_width_per_kashida = (p_width - justification_width) / elongation_count; + float delta_width_per_kashida = (p_width - justification_width) / elongation_count; for (int i = start_pos; i <= end_pos; i++) { Glyph &gl = sd->glyphs.write[i]; if (gl.count > 0) { @@ -3501,15 +3616,15 @@ real_t TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, real_t p_width } } } - real_t adv_remain = 0; + float adv_remain = 0; if ((space_count > 0) && ((p_jst_flags & JUSTIFICATION_WORD_BOUND) == JUSTIFICATION_WORD_BOUND)) { - real_t delta_width_per_space = (p_width - justification_width) / space_count; + float delta_width_per_space = (p_width - justification_width) / space_count; for (int i = start_pos; i <= end_pos; i++) { Glyph &gl = sd->glyphs.write[i]; if (gl.count > 0) { if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) { - real_t old_adv = gl.advance; - real_t new_advance; + float old_adv = gl.advance; + float new_advance; if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) { new_advance = MAX(gl.advance + delta_width_per_space, 0.f); } else { @@ -3541,8 +3656,8 @@ real_t TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, real_t p_width return sd->width; } -real_t TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<real_t> &p_tab_stops) { - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); +float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) { + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.f); MutexLock lock(sd->mutex); @@ -3554,7 +3669,7 @@ real_t TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<real } int tab_index = 0; - real_t off = 0.f; + float off = 0.f; int start, end, delta; if (sd->para_direction == DIRECTION_LTR) { @@ -3571,7 +3686,7 @@ real_t TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<real for (int i = start; i != end; i += delta) { if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) { - real_t tab_off = 0.f; + float tab_off = 0.f; while (tab_off <= off) { tab_off += p_tab_stops[tab_index]; tab_index++; @@ -3579,7 +3694,7 @@ real_t TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<real tab_index = 0; } } - real_t old_adv = gl[i].advance; + float old_adv = gl[i].advance; gl[i].advance = tab_off - off; sd->width += gl[i].advance - old_adv; off = 0; @@ -3591,8 +3706,8 @@ real_t TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<real return 0.f; } -void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, real_t p_width, uint8_t p_trim_flags) { - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped_line); +void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint16_t p_trim_flags) { + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped_line); ERR_FAIL_COND_MSG(!sd, "ShapedTextDataAdvanced invalid."); MutexLock lock(sd->mutex); @@ -3600,6 +3715,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re shaped_text_shape(p_shaped_line); } + sd->text_trimmed = false; sd->overrun_trim_data.ellipsis_glyph_buf.clear(); bool add_ellipsis = (p_trim_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS; @@ -3633,7 +3749,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re } int ell_min_characters = 6; - real_t width = sd->width; + float width = sd->width; bool is_rtl = sd->direction == DIRECTION_RTL || (sd->direction == DIRECTION_AUTO && sd->para_direction == DIRECTION_RTL); @@ -3652,10 +3768,10 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re width -= sd_glyphs[i].advance * sd_glyphs[i].repeat; } if (sd_glyphs[i].count > 0) { - bool above_min_char_treshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters; + bool above_min_char_threshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters; - if (width + (((above_min_char_treshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) { - if (cut_per_word && above_min_char_treshold) { + 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; @@ -3667,7 +3783,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re if (found) { trim_pos = last_valid_cut; - if (add_ellipsis && (above_min_char_treshold || enforce_ellipsis) && width - ellipsis_width <= p_width) { + if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis) && width - ellipsis_width <= p_width) { ellipsis_pos = trim_pos; } break; @@ -3689,7 +3805,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) { // Insert an additional space when cutting word bound for aesthetics. if (cut_per_word && (ellipsis_pos > 0)) { - TextServer::Glyph gl; + Glyph gl; gl.count = 1; gl.advance = whitespace_adv.x; gl.index = whitespace_gl_idx; @@ -3700,7 +3816,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re sd->overrun_trim_data.ellipsis_glyph_buf.append(gl); } // Add ellipsis dots. - TextServer::Glyph gl; + Glyph gl; gl.count = 1; gl.repeat = 3; gl.advance = dot_adv.x; @@ -3717,16 +3833,40 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re } } -TextServer::TrimData TextServerAdvanced::shaped_text_get_trim_data(RID p_shaped) const { - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); - ERR_FAIL_COND_V_MSG(!sd, TrimData(), "ShapedTextDataAdvanced invalid."); +int TextServerAdvanced::shaped_text_get_trim_pos(RID p_shaped) const { + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid."); + + MutexLock lock(sd->mutex); + return sd->overrun_trim_data.trim_pos; +} + +int TextServerAdvanced::shaped_text_get_ellipsis_pos(RID p_shaped) const { + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid."); + + MutexLock lock(sd->mutex); + return sd->overrun_trim_data.ellipsis_pos; +} + +const Glyph *TextServerAdvanced::shaped_text_get_ellipsis_glyphs(RID p_shaped) const { + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V_MSG(!sd, nullptr, "ShapedTextDataAdvanced invalid."); + + MutexLock lock(sd->mutex); + return sd->overrun_trim_data.ellipsis_glyph_buf.ptr(); +} + +int TextServerAdvanced::shaped_text_get_ellipsis_glyph_count(RID p_shaped) const { + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V_MSG(!sd, 0, "ShapedTextDataAdvanced invalid."); MutexLock lock(sd->mutex); - return sd->overrun_trim_data; + return sd->overrun_trim_data.ellipsis_glyph_buf.size(); } bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); @@ -3784,6 +3924,9 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { const char32_t *ch = sd->text.ptr(); Glyph *sd_glyphs = sd->glyphs.ptrw(); + int c_punct_size = sd->custom_punct.length(); + const char32_t *c_punct = sd->custom_punct.ptr(); + for (i = 0; i < sd_size; i++) { if (sd_glyphs[i].count > 0) { char32_t c = ch[sd_glyphs[i].start - sd->start]; @@ -3796,12 +3939,21 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { if (is_whitespace(c)) { sd_glyphs[i].flags |= GRAPHEME_IS_SPACE; } + if (c_punct_size == 0) { + if (u_ispunct(c) && c != 0x005F) { + sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; + } + } else { + for (int j = 0; j < c_punct_size; j++) { + if (c_punct[j] == c) { + sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; + break; + } + } + } if (is_underscore(c)) { sd_glyphs[i].flags |= GRAPHEME_IS_UNDERSCORE; } - if (u_ispunct(c) && c != 0x005F) { - sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; - } if (breaks.has(sd->glyphs[i].start)) { if (breaks[sd->glyphs[i].start]) { sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD; @@ -3809,14 +3961,19 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) { if (is_whitespace(c)) { sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT; } else { - TextServer::Glyph gl; + Glyph gl; gl.start = sd_glyphs[i].start; gl.end = sd_glyphs[i].end; gl.count = 1; 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. + if (sd->glyphs[i].flags & GRAPHEME_IS_RTL) { + gl.flags |= GRAPHEME_IS_RTL; + sd->glyphs.insert(i, gl); // Insert before. + } else { + sd->glyphs.insert(i + sd_glyphs[i].count, gl); // Insert after. + } // Update write pointer and size. sd_size = sd->glyphs.size(); @@ -3913,7 +4070,7 @@ _FORCE_INLINE_ int _generate_kashida_justification_opportunies(const String &p_d } bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) { - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); @@ -3985,7 +4142,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) { sd->glyphs.write[i].flags |= GRAPHEME_IS_ELONGATION; } else { if (sd->glyphs[i].font_rid != RID()) { - TextServer::Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size); + Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size); if ((gl.flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) { gl.start = sd->glyphs[i].start; gl.end = sd->glyphs[i].end; @@ -4003,14 +4160,19 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) { } } } else if (!is_whitespace(c)) { - TextServer::Glyph gl; + Glyph gl; gl.start = sd->glyphs[i].start; gl.end = sd->glyphs[i].end; gl.count = 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; - sd->glyphs.insert(i + sd->glyphs[i].count, gl); // Insert after. + if (sd->glyphs[i].flags & GRAPHEME_IS_RTL) { + gl.flags |= GRAPHEME_IS_RTL; + sd->glyphs.insert(i, gl); // Insert before. + } else { + sd->glyphs.insert(i + sd->glyphs[i].count, gl); // Insert after. + } i += sd->glyphs[i].count; continue; } @@ -4023,9 +4185,9 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) { return sd->justification_ops_valid; } -TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size) { +Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size) { hb_font_t *hb_font = _font_get_hb_handle(p_font, p_font_size); - ERR_FAIL_COND_V(hb_font == nullptr, TextServer::Glyph()); + ERR_FAIL_COND_V(hb_font == nullptr, Glyph()); hb_buffer_clear_contents(p_sd->hb_buffer); hb_buffer_set_direction(p_sd->hb_buffer, p_direction); @@ -4040,7 +4202,7 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(p_sd->hb_buffer, &glyph_count); // Process glyphs. - TextServer::Glyph gl; + Glyph gl; if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) { gl.flags |= TextServer::GRAPHEME_IS_RTL; @@ -4050,7 +4212,7 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced gl.font_size = p_font_size; if (glyph_count > 0) { - real_t scale = font_get_scale(p_font, p_font_size); + float scale = font_get_scale(p_font, p_font_size); if (p_sd->orientation == ORIENTATION_HORIZONTAL) { gl.advance = Math::round(glyph_pos[0].x_advance / (64.0 / scale)); } else { @@ -4075,9 +4237,9 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star // 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; - gl.start = i; - gl.end = i + 1; + Glyph gl; + gl.start = i + p_sd->start; + gl.end = i + 1 + p_sd->start; gl.count = 1; gl.index = p_sd->text[i]; gl.font_size = fs; @@ -4087,8 +4249,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star } if (p_sd->orientation == ORIENTATION_HORIZONTAL) { 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)); + p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(fs, gl.index).y); } else { gl.advance = get_hex_code_box_size(fs, gl.index).y; p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f)); @@ -4104,6 +4265,9 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star RID f = p_fonts[p_fb_index]; hb_font_t *hb_font = _font_get_hb_handle(f, fs); + float scale = font_get_scale(f, fs); + float sp_sp = font_get_spacing(f, fs, SPACING_SPACE); + float sp_gl = font_get_spacing(f, fs, SPACING_GLYPH); ERR_FAIL_COND(hb_font == nullptr); hb_buffer_clear_contents(p_sd->hb_buffer); @@ -4115,7 +4279,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star } hb_buffer_set_script(p_sd->hb_buffer, p_script); - if (p_sd->spans[p_span].language != String()) { + if (!p_sd->spans[p_span].language.is_empty()) { hb_language_t lang = hb_language_from_string(p_sd->spans[p_span].language.ascii().get_data(), -1); hb_buffer_set_language(p_sd->hb_buffer, lang); } @@ -4142,7 +4306,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star // Process glyphs. if (glyph_count > 0) { - TextServer::Glyph *w = (TextServer::Glyph *)memalloc(glyph_count * sizeof(TextServer::Glyph)); + Glyph *w = (Glyph *)memalloc(glyph_count * sizeof(Glyph)); int end = (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) ? p_end : 0; uint32_t last_cluster_id = UINT32_MAX; @@ -4159,7 +4323,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star } } if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) { - w[last_cluster_index].flags |= TextServer::GRAPHEME_IS_RTL; + w[last_cluster_index].flags |= GRAPHEME_IS_RTL; } if (last_cluster_valid) { w[last_cluster_index].flags |= GRAPHEME_IS_VALID; @@ -4171,8 +4335,8 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star last_cluster_id = glyph_info[i].cluster; - TextServer::Glyph &gl = w[i]; - gl = TextServer::Glyph(); + Glyph &gl = w[i]; + gl = Glyph(); gl.start = glyph_info[i].cluster; gl.end = end; @@ -4181,9 +4345,12 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star gl.font_rid = p_fonts[p_fb_index]; gl.font_size = fs; + if (glyph_info[i].mask & HB_GLYPH_FLAG_DEFINED) { + gl.flags |= GRAPHEME_IS_CONNECTED; + } + gl.index = glyph_info[i].codepoint; if (gl.index != 0) { - real_t scale = font_get_scale(f, fs); if (p_sd->orientation == ORIENTATION_HORIZONTAL) { gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / scale)); } else { @@ -4192,16 +4359,16 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star gl.x_off = Math::round(glyph_pos[i].x_offset / (64.0 / scale)); gl.y_off = -Math::round(glyph_pos[i].y_offset / (64.0 / scale)); } - if (font_get_spacing(f, fs, SPACING_SPACE) && is_whitespace(p_sd->text[glyph_info[i].cluster])) { - gl.advance += font_get_spacing(f, fs, SPACING_SPACE); + if (sp_sp && is_whitespace(p_sd->text[glyph_info[i].cluster])) { + gl.advance += sp_sp; } else { - gl.advance += font_get_spacing(f, fs, SPACING_GLYPH); + gl.advance += sp_gl; } if (p_sd->preserve_control) { - last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || is_whitespace(p_sd->text[glyph_info[i].cluster]) || is_linebreak(p_sd->text[glyph_info[i].cluster])); + last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || (p_sd->text[glyph_info[i].cluster] == 0x0009) || (u_isblank(p_sd->text[glyph_info[i].cluster]) && (gl.advance != 0)) || (!u_isblank(p_sd->text[glyph_info[i].cluster]) && is_linebreak(p_sd->text[glyph_info[i].cluster]))); } else { - last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || !u_isgraph(p_sd->text[glyph_info[i].cluster])); + last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || (p_sd->text[glyph_info[i].cluster] == 0x0009) || (u_isblank(p_sd->text[glyph_info[i].cluster]) && (gl.advance != 0)) || (!u_isblank(p_sd->text[glyph_info[i].cluster]) && !u_isgraph(p_sd->text[glyph_info[i].cluster]))); } } if (p_direction == HB_DIRECTION_LTR || p_direction == HB_DIRECTION_TTB) { @@ -4211,7 +4378,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star } w[last_cluster_index].count = glyph_count - last_cluster_index; if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) { - w[last_cluster_index].flags |= TextServer::GRAPHEME_IS_RTL; + w[last_cluster_index].flags |= GRAPHEME_IS_RTL; } if (last_cluster_valid) { w[last_cluster_index].flags |= GRAPHEME_IS_VALID; @@ -4233,10 +4400,13 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star p_sd->ascent = MAX(p_sd->ascent, -w[i + j].y_off); p_sd->descent = MAX(p_sd->descent, w[i + j].y_off); } else { - p_sd->ascent = MAX(p_sd->ascent, Math::round(font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5)); - p_sd->descent = MAX(p_sd->descent, Math::round(font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5)); + float gla = Math::round(font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5); + p_sd->ascent = MAX(p_sd->ascent, gla); + p_sd->descent = MAX(p_sd->descent, gla); } p_sd->width += w[i + j].advance; + w[i + j].start += p_sd->start; + w[i + j].end += p_sd->start; p_sd->glyphs.push_back(w[i + j]); } } else { @@ -4261,7 +4431,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star } bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); @@ -4269,10 +4439,14 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { return true; } + invalidate(sd); if (sd->parent != RID()) { - full_copy(sd); + shaped_text_shape(sd->parent); + ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent); + ERR_FAIL_COND_V(!parent_sd->valid, false); + ERR_FAIL_COND_V(!_shape_substr(sd, parent_sd, sd->start, sd->end - sd->start), false); + return true; } - invalidate(sd); if (sd->text.length() == 0) { sd->valid = true; @@ -4288,15 +4462,17 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { } if (sd->bidi_override.is_empty()) { - sd->bidi_override.push_back(Vector2i(0, sd->end)); + sd->bidi_override.push_back(Vector2i(sd->start, sd->end)); } for (int ov = 0; ov < sd->bidi_override.size(); ov++) { // Create BiDi iterator. - int start = _convert_pos_inv(sd, sd->bidi_override[ov].x); - int end = _convert_pos_inv(sd, sd->bidi_override[ov].y); + int start = _convert_pos_inv(sd, sd->bidi_override[ov].x - sd->start); + int end = _convert_pos_inv(sd, sd->bidi_override[ov].y - sd->start); - ERR_FAIL_COND_V_MSG((start < 0 || end - start > sd->utf16.length()), false, "Invalid BiDi override range."); + if (start < 0 || end - start > sd->utf16.length()) { + continue; + } UErrorCode err = U_ZERO_ERROR; UBiDi *bidi_iter = ubidi_openSized(end, 0, &err); @@ -4350,8 +4526,8 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { } } - int32_t bidi_run_start = _convert_pos(sd, sd->bidi_override[ov].x + _bidi_run_start); - int32_t bidi_run_end = _convert_pos(sd, sd->bidi_override[ov].x + _bidi_run_start + _bidi_run_length); + int32_t bidi_run_start = _convert_pos(sd, sd->bidi_override[ov].x - sd->start + _bidi_run_start); + int32_t bidi_run_end = _convert_pos(sd, sd->bidi_override[ov].x - sd->start + _bidi_run_start + _bidi_run_length); // Shape runs. @@ -4373,7 +4549,7 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { for (int k = spn_from; k != spn_to; k += spn_delta) { const ShapedTextDataAdvanced::Span &span = sd->spans[k]; - if (span.start >= script_run_end || span.end <= script_run_start) { + if (span.start - sd->start >= script_run_end || span.end - sd->start <= script_run_start) { continue; } if (span.embedded_key != Variant()) { @@ -4414,7 +4590,7 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { } fonts.append_array(fonts_scr_only); fonts.append_array(fonts_no_match); - _shape_run(sd, MAX(sd->spans[k].start, script_run_start), MIN(sd->spans[k].end, script_run_end), sd->script_iter->script_ranges[j].script, bidi_run_direction, fonts, k, 0); + _shape_run(sd, MAX(sd->spans[k].start - sd->start, script_run_start), MIN(sd->spans[k].end - sd->start, script_run_end), sd->script_iter->script_ranges[j].script, bidi_run_direction, fonts, k, 0); } } } @@ -4423,65 +4599,65 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { } // Align embedded objects to baseline. - real_t full_ascent = sd->ascent; - real_t full_descent = sd->descent; - for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) { + float full_ascent = sd->ascent; + float full_descent = sd->descent; + for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) { if (sd->orientation == ORIENTATION_HORIZONTAL) { - switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { - case INLINE_ALIGN_TO_TOP: { - E->get().rect.position.y = -sd->ascent; + switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { + case INLINE_ALIGNMENT_TO_TOP: { + E.value.rect.position.y = -sd->ascent; } break; - case INLINE_ALIGN_TO_CENTER: { - E->get().rect.position.y = (-sd->ascent + sd->descent) / 2; + case INLINE_ALIGNMENT_TO_CENTER: { + E.value.rect.position.y = (-sd->ascent + sd->descent) / 2; } break; - case INLINE_ALIGN_TO_BASELINE: { - E->get().rect.position.y = 0; + case INLINE_ALIGNMENT_TO_BASELINE: { + E.value.rect.position.y = 0; } break; - case INLINE_ALIGN_TO_BOTTOM: { - E->get().rect.position.y = sd->descent; + case INLINE_ALIGNMENT_TO_BOTTOM: { + E.value.rect.position.y = sd->descent; } break; } - switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { - case INLINE_ALIGN_BOTTOM_TO: { - E->get().rect.position.y -= E->get().rect.size.y; + switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { + case INLINE_ALIGNMENT_BOTTOM_TO: { + E.value.rect.position.y -= E.value.rect.size.y; } break; - case INLINE_ALIGN_CENTER_TO: { - E->get().rect.position.y -= E->get().rect.size.y / 2; + case INLINE_ALIGNMENT_CENTER_TO: { + E.value.rect.position.y -= E.value.rect.size.y / 2; } break; - case INLINE_ALIGN_TOP_TO: { - //NOP + case INLINE_ALIGNMENT_TOP_TO: { + // NOP } break; } - full_ascent = MAX(full_ascent, -E->get().rect.position.y); - full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y); + full_ascent = MAX(full_ascent, -E.value.rect.position.y); + full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y); } else { - switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { - case INLINE_ALIGN_TO_TOP: { - E->get().rect.position.x = -sd->ascent; + switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) { + case INLINE_ALIGNMENT_TO_TOP: { + E.value.rect.position.x = -sd->ascent; } break; - case INLINE_ALIGN_TO_CENTER: { - E->get().rect.position.x = (-sd->ascent + sd->descent) / 2; + case INLINE_ALIGNMENT_TO_CENTER: { + E.value.rect.position.x = (-sd->ascent + sd->descent) / 2; } break; - case INLINE_ALIGN_TO_BASELINE: { - E->get().rect.position.x = 0; + case INLINE_ALIGNMENT_TO_BASELINE: { + E.value.rect.position.x = 0; } break; - case INLINE_ALIGN_TO_BOTTOM: { - E->get().rect.position.x = sd->descent; + case INLINE_ALIGNMENT_TO_BOTTOM: { + E.value.rect.position.x = sd->descent; } break; } - switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { - case INLINE_ALIGN_BOTTOM_TO: { - E->get().rect.position.x -= E->get().rect.size.x; + switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) { + case INLINE_ALIGNMENT_BOTTOM_TO: { + E.value.rect.position.x -= E.value.rect.size.x; } break; - case INLINE_ALIGN_CENTER_TO: { - E->get().rect.position.x -= E->get().rect.size.x / 2; + case INLINE_ALIGNMENT_CENTER_TO: { + E.value.rect.position.x -= E.value.rect.size.x / 2; } break; - case INLINE_ALIGN_TOP_TO: { - //NOP + case INLINE_ALIGNMENT_TOP_TO: { + // NOP } break; } - full_ascent = MAX(full_ascent, -E->get().rect.position.x); - full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x); + full_ascent = MAX(full_ascent, -E.value.rect.position.x); + full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x); } } sd->ascent = full_ascent; @@ -4491,35 +4667,38 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { } bool TextServerAdvanced::shaped_text_is_ready(RID p_shaped) const { - const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, false); MutexLock lock(sd->mutex); return sd->valid; } -Vector<TextServer::Glyph> TextServerAdvanced::shaped_text_get_glyphs(RID p_shaped) const { - const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); - ERR_FAIL_COND_V(!sd, Vector<TextServer::Glyph>()); +const Glyph *TextServerAdvanced::shaped_text_get_glyphs(RID p_shaped) const { + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, nullptr); MutexLock lock(sd->mutex); if (!sd->valid) { const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); } - return sd->glyphs; + return sd->glyphs.ptr(); } -Vector2i TextServerAdvanced::shaped_text_get_range(RID p_shaped) const { - const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); - ERR_FAIL_COND_V(!sd, Vector2i()); +int TextServerAdvanced::shaped_text_get_glyph_count(RID p_shaped) const { + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, 0); MutexLock lock(sd->mutex); - return Vector2(sd->start, sd->end); + if (!sd->valid) { + const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped); + } + return sd->glyphs.size(); } -Vector<TextServer::Glyph> TextServerAdvanced::shaped_text_sort_logical(RID p_shaped) { - ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); - ERR_FAIL_COND_V(!sd, Vector<TextServer::Glyph>()); +const Glyph *TextServerAdvanced::shaped_text_sort_logical(RID p_shaped) { + ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, nullptr); MutexLock lock(sd->mutex); if (!sd->valid) { @@ -4528,28 +4707,36 @@ Vector<TextServer::Glyph> TextServerAdvanced::shaped_text_sort_logical(RID p_sha if (!sd->sort_valid) { sd->glyphs_logical = sd->glyphs; - sd->glyphs_logical.sort_custom<TextServer::GlyphCompare>(); + sd->glyphs_logical.sort_custom<GlyphCompare>(); sd->sort_valid = true; } - return sd->glyphs_logical; + return sd->glyphs_logical.ptr(); +} + +Vector2i TextServerAdvanced::shaped_text_get_range(RID p_shaped) const { + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); + ERR_FAIL_COND_V(!sd, Vector2i()); + + MutexLock lock(sd->mutex); + return Vector2(sd->start, sd->end); } Array TextServerAdvanced::shaped_text_get_objects(RID p_shaped) const { Array ret; - const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, ret); MutexLock lock(sd->mutex); - for (const Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) { - ret.push_back(E->key()); + for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) { + ret.push_back(E.key); } return ret; } Rect2 TextServerAdvanced::shaped_text_get_object_rect(RID p_shaped, Variant p_key) const { - const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Rect2()); MutexLock lock(sd->mutex); @@ -4561,7 +4748,7 @@ Rect2 TextServerAdvanced::shaped_text_get_object_rect(RID p_shaped, Variant p_ke } Size2 TextServerAdvanced::shaped_text_get_size(RID p_shaped) const { - const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, Size2()); MutexLock lock(sd->mutex); @@ -4575,8 +4762,8 @@ Size2 TextServerAdvanced::shaped_text_get_size(RID p_shaped) const { } } -real_t TextServerAdvanced::shaped_text_get_ascent(RID p_shaped) const { - const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); +float TextServerAdvanced::shaped_text_get_ascent(RID p_shaped) const { + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.f); MutexLock lock(sd->mutex); @@ -4586,8 +4773,8 @@ real_t TextServerAdvanced::shaped_text_get_ascent(RID p_shaped) const { return sd->ascent; } -real_t TextServerAdvanced::shaped_text_get_descent(RID p_shaped) const { - const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); +float TextServerAdvanced::shaped_text_get_descent(RID p_shaped) const { + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.f); MutexLock lock(sd->mutex); @@ -4597,8 +4784,8 @@ real_t TextServerAdvanced::shaped_text_get_descent(RID p_shaped) const { return sd->descent; } -real_t TextServerAdvanced::shaped_text_get_width(RID p_shaped) const { - const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); +float TextServerAdvanced::shaped_text_get_width(RID p_shaped) const { + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.f); MutexLock lock(sd->mutex); @@ -4608,8 +4795,8 @@ real_t TextServerAdvanced::shaped_text_get_width(RID p_shaped) const { return (sd->text_trimmed ? sd->width_trimmed : sd->width); } -real_t TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) const { - const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); +float TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) const { + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.f); MutexLock lock(sd->mutex); @@ -4620,8 +4807,8 @@ real_t TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) cons return sd->upos; } -real_t TextServerAdvanced::shaped_text_get_underline_thickness(RID p_shaped) const { - const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); +float TextServerAdvanced::shaped_text_get_underline_thickness(RID p_shaped) const { + const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped); ERR_FAIL_COND_V(!sd, 0.f); MutexLock lock(sd->mutex); @@ -4632,32 +4819,188 @@ real_t TextServerAdvanced::shaped_text_get_underline_thickness(RID p_shaped) con return sd->uthk; } -struct num_system_data { - String lang; - String digits; - String percent_sign; - String exp; -}; +void TextServerAdvanced::_insert_num_systems_lang() { + // Eastern Arabic numerals. + { + NumSystemData ar; + ar.lang.insert(StringName("ar")); // Arabic + ar.lang.insert(StringName("ar_AE")); + ar.lang.insert(StringName("ar_BH")); + ar.lang.insert(StringName("ar_DJ")); + ar.lang.insert(StringName("ar_EG")); + ar.lang.insert(StringName("ar_ER")); + ar.lang.insert(StringName("ar_IL")); + ar.lang.insert(StringName("ar_IQ")); + ar.lang.insert(StringName("ar_JO")); + ar.lang.insert(StringName("ar_KM")); + ar.lang.insert(StringName("ar_KW")); + ar.lang.insert(StringName("ar_LB")); + ar.lang.insert(StringName("ar_MR")); + ar.lang.insert(StringName("ar_OM")); + ar.lang.insert(StringName("ar_PS")); + ar.lang.insert(StringName("ar_QA")); + ar.lang.insert(StringName("ar_SA")); + ar.lang.insert(StringName("ar_SD")); + ar.lang.insert(StringName("ar_SO")); + ar.lang.insert(StringName("ar_SS")); + ar.lang.insert(StringName("ar_SY")); + ar.lang.insert(StringName("ar_TD")); + ar.lang.insert(StringName("ar_YE")); + ar.lang.insert(StringName("ckb")); // Central Kurdish + ar.lang.insert(StringName("ckb_IQ")); + ar.lang.insert(StringName("ckb_IR")); + ar.lang.insert(StringName("sd")); // Sindhi + ar.lang.insert(StringName("sd_PK")); + ar.lang.insert(StringName("sd_Arab")); + ar.lang.insert(StringName("sd_Arab_PK")); + ar.digits = U"٠١٢٣٤٥٦٧٨٩٫"; + ar.percent_sign = U"٪"; + ar.exp = U"اس"; + num_systems.push_back(ar); + } + + // Persian and Urdu numerals. + { + NumSystemData pr; + pr.lang.insert(StringName("fa")); // Persian + pr.lang.insert(StringName("fa_AF")); + pr.lang.insert(StringName("fa_IR")); + pr.lang.insert(StringName("ks")); // Kashmiri + pr.lang.insert(StringName("ks_IN")); + pr.lang.insert(StringName("ks_Arab")); + pr.lang.insert(StringName("ks_Arab_IN")); + pr.lang.insert(StringName("lrc")); // Northern Luri + pr.lang.insert(StringName("lrc_IQ")); + pr.lang.insert(StringName("lrc_IR")); + pr.lang.insert(StringName("mzn")); // Mazanderani + pr.lang.insert(StringName("mzn_IR")); + pr.lang.insert(StringName("pa_PK")); // Panjabi + pr.lang.insert(StringName("pa_Arab")); + pr.lang.insert(StringName("pa_Arab_PK")); + pr.lang.insert(StringName("ps")); // Pushto + pr.lang.insert(StringName("ps_AF")); + pr.lang.insert(StringName("ps_PK")); + pr.lang.insert(StringName("ur_IN")); // Urdu + pr.lang.insert(StringName("uz_AF")); // Uzbek + pr.lang.insert(StringName("uz_Arab")); + pr.lang.insert(StringName("uz_Arab_AF")); + pr.digits = U"۰۱۲۳۴۵۶۷۸۹٫"; + pr.percent_sign = U"٪"; + pr.exp = U"اس"; + num_systems.push_back(pr); + } + + // Bengali numerals. + { + NumSystemData bn; + bn.lang.insert(StringName("as")); // Assamese + bn.lang.insert(StringName("as_IN")); + bn.lang.insert(StringName("bn")); // Bengali + bn.lang.insert(StringName("bn_BD")); + bn.lang.insert(StringName("bn_IN")); + bn.lang.insert(StringName("mni")); // Manipuri + bn.lang.insert(StringName("mni_IN")); + bn.lang.insert(StringName("mni_Beng")); + bn.lang.insert(StringName("mni_Beng_IN")); + bn.digits = U"০১২৩৪৫৬৭৮৯."; + bn.percent_sign = U"%"; + bn.exp = U"e"; + num_systems.push_back(bn); + } + + // Devanagari numerals. + { + NumSystemData mr; + mr.lang.insert(StringName("mr")); // Marathi + mr.lang.insert(StringName("mr_IN")); + mr.lang.insert(StringName("ne")); // Nepali + mr.lang.insert(StringName("ne_IN")); + mr.lang.insert(StringName("ne_NP")); + mr.lang.insert(StringName("sa")); // Sanskrit + mr.lang.insert(StringName("sa_IN")); + mr.digits = U"०१२३४५६७८९."; + mr.percent_sign = U"%"; + mr.exp = U"e"; + num_systems.push_back(mr); + } + + // Dzongkha numerals. + { + NumSystemData dz; + dz.lang.insert(StringName("dz")); // Dzongkha + dz.lang.insert(StringName("dz_BT")); + dz.digits = U"༠༡༢༣༤༥༦༧༨༩."; + dz.percent_sign = U"%"; + dz.exp = U"e"; + num_systems.push_back(dz); + } -static num_system_data num_systems[]{ - { "ar,ar_AR,ar_BH,ar_DJ,ar_EG,ar_ER,ar_IL,ar_IQ,ar_JO,ar_KM,ar_KW,ar_LB,ar_MR,ar_OM,ar_PS,ar_QA,ar_SA,ar_SD,ar_SO,ar_SS,ar_SY,ar_TD,ar_YE", U"٠١٢٣٤٥٦٧٨٩٫", U"٪", U"اس" }, - { "fa,ks,pa_Arab,ps,ug,ur_IN,ur,uz_Arab", U"۰۱۲۳۴۵۶۷۸۹٫", U"٪", U"اس" }, - { "as,bn,mni", U"০১২৩৪৫৬৭৮৯.", U"%", U"e" }, - { "mr,ne", U"०१२३४५६७८९.", U"%", U"e" }, - { "dz", U"༠༡༢༣༤༥༦༧༨༩.", U"%", U"e" }, - { "sat", U"᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙.", U"%", U"e" }, - { "my", U"၀၁၂၃၄၅၆၇၈၉.", U"%", U"e" }, - { String(), String(), String(), String() }, -}; + // Santali numerals. + { + NumSystemData sat; + sat.lang.insert(StringName("sat")); // Santali + sat.lang.insert(StringName("sat_IN")); + sat.lang.insert(StringName("sat_Olck")); + sat.lang.insert(StringName("sat_Olck_IN")); + sat.digits = U"᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙."; + sat.percent_sign = U"%"; + sat.exp = U"e"; + num_systems.push_back(sat); + } + + // Burmese numerals. + { + NumSystemData my; + my.lang.insert(StringName("my")); // Burmese + my.lang.insert(StringName("my_MM")); + my.digits = U"၀၁၂၃၄၅၆၇၈၉."; + my.percent_sign = U"%"; + my.exp = U"e"; + num_systems.push_back(my); + } + + // Chakma numerals. + { + NumSystemData ccp; + ccp.lang.insert(StringName("ccp")); // Chakma + ccp.lang.insert(StringName("ccp_BD")); + ccp.lang.insert(StringName("ccp_IN")); + ccp.digits = U"𑄶𑄷𑄸𑄹𑄺𑄻𑄼𑄽𑄾𑄿."; + ccp.percent_sign = U"%"; + ccp.exp = U"e"; + num_systems.push_back(ccp); + } + + // Adlam numerals. + { + NumSystemData ff; + ff.lang.insert(StringName("ff")); // Fulah + ff.lang.insert(StringName("ff_Adlm_BF")); + ff.lang.insert(StringName("ff_Adlm_CM")); + ff.lang.insert(StringName("ff_Adlm_GH")); + ff.lang.insert(StringName("ff_Adlm_GM")); + ff.lang.insert(StringName("ff_Adlm_GN")); + ff.lang.insert(StringName("ff_Adlm_GW")); + ff.lang.insert(StringName("ff_Adlm_LR")); + ff.lang.insert(StringName("ff_Adlm_MR")); + ff.lang.insert(StringName("ff_Adlm_NE")); + ff.lang.insert(StringName("ff_Adlm_NG")); + ff.lang.insert(StringName("ff_Adlm_SL")); + ff.lang.insert(StringName("ff_Adlm_SN")); + ff.digits = U"𞥐𞥑𞥒𞥓𞥔𞥕𞥖𞥗𞥘𞥙."; + ff.percent_sign = U"%"; + ff.exp = U"e"; + num_systems.push_back(ff); + } +} String TextServerAdvanced::format_number(const String &p_string, const String &p_language) const { - String lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language; + const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; String res = p_string; - for (int i = 0; num_systems[i].lang != String(); i++) { - Vector<String> langs = num_systems[i].lang.split(","); - if (langs.has(lang)) { - if (num_systems[i].digits == String()) { + for (int i = 0; i < num_systems.size(); i++) { + if (num_systems[i].lang.has(lang)) { + if (num_systems[i].digits.is_empty()) { return p_string; } res.replace("e", num_systems[i].exp); @@ -4677,13 +5020,12 @@ String TextServerAdvanced::format_number(const String &p_string, const String &p } String TextServerAdvanced::parse_number(const String &p_string, const String &p_language) const { - String lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language; + const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; String res = p_string; - for (int i = 0; num_systems[i].lang != String(); i++) { - Vector<String> langs = num_systems[i].lang.split(","); - if (langs.has(lang)) { - if (num_systems[i].digits == String()) { + for (int i = 0; i < num_systems.size(); i++) { + if (num_systems[i].lang.has(lang)) { + if (num_systems[i].digits.is_empty()) { return p_string; } res.replace(num_systems[i].exp, "e"); @@ -4706,12 +5048,11 @@ String TextServerAdvanced::parse_number(const String &p_string, const String &p_ } String TextServerAdvanced::percent_sign(const String &p_language) const { - String lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language; + const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language; - for (int i = 0; num_systems[i].lang != String(); i++) { - Vector<String> langs = num_systems[i].lang.split(","); - if (langs.has(lang)) { - if (num_systems[i].percent_sign == String()) { + for (int i = 0; i < num_systems.size(); i++) { + if (num_systems[i].lang.has(lang)) { + if (num_systems[i].percent_sign.is_empty()) { return "%"; } return num_systems[i].percent_sign; @@ -4720,21 +5061,47 @@ String TextServerAdvanced::percent_sign(const String &p_language) const { return "%"; } -TextServer *TextServerAdvanced::create_func(Error &r_error, void *p_user_data) { - r_error = OK; - return memnew(TextServerAdvanced()); -} +String TextServerAdvanced::strip_diacritics(const String &p_string) const { + UErrorCode err = U_ZERO_ERROR; -void TextServerAdvanced::register_server() { - TextServerManager::register_create_function(interface_name, interface_features, create_func, nullptr); + // Get NFKD normalizer singleton. + const UNormalizer2 *unorm = unorm2_getNFKDInstance(&err); + ERR_FAIL_COND_V_MSG(U_FAILURE(err), TextServer::strip_diacritics(p_string), u_errorName(err)); + + // Convert to UTF-16. + Char16String utf16 = p_string.utf16(); + + // Normalize. + Char16String normalized; + err = U_ZERO_ERROR; + int32_t len = unorm2_normalize(unorm, utf16.ptr(), -1, nullptr, 0, &err); + ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, TextServer::strip_diacritics(p_string), u_errorName(err)); + normalized.resize(len); + err = U_ZERO_ERROR; + unorm2_normalize(unorm, utf16.ptr(), -1, normalized.ptrw(), len, &err); + ERR_FAIL_COND_V_MSG(U_FAILURE(err), TextServer::strip_diacritics(p_string), u_errorName(err)); + + // Convert back to UTF-32. + String normalized_string = String::utf16(normalized.ptr(), len); + + // Strip combining characters. + String result; + for (int i = 0; i < normalized_string.length(); i++) { + if (u_getCombiningClass(normalized_string[i]) == 0) { + result += normalized_string[i]; + } + } + return result; } TextServerAdvanced::TextServerAdvanced() { - hb_bmp_create_font_funcs(); + _insert_num_systems_lang(); + _insert_feature_sets(); + _bmp_create_font_funcs(); } TextServerAdvanced::~TextServerAdvanced() { - hb_bmp_free_font_funcs(); + _bmp_free_font_funcs(); if (library != nullptr) { FT_Done_FreeType(library); } diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 5989035800..9a22180f39 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -50,11 +50,12 @@ #include <unicode/udata.h> #include <unicode/uiter.h> #include <unicode/uloc.h> +#include <unicode/unorm2.h> #include <unicode/uscript.h> #include <unicode/ustring.h> #include <unicode/utypes.h> -#include "modules/modules_enabled.gen.h" +#include "modules/modules_enabled.gen.h" // For freetype, msdfgen. #ifdef MODULE_FREETYPE_ENABLED #include <ft2build.h> @@ -79,6 +80,19 @@ class TextServerAdvanced : public TextServer { static String interface_name; static uint32_t interface_features; + struct NumSystemData { + Set<StringName> lang; + String digits; + String percent_sign; + String exp; + }; + + Vector<NumSystemData> num_systems; + Map<StringName, int32_t> feature_sets; + + void _insert_num_systems_lang(); + void _insert_feature_sets(); + // ICU support data. uint8_t *icu_data = nullptr; @@ -115,12 +129,12 @@ class TextServerAdvanced : public TextServer { }; struct FontDataForSizeAdvanced { - real_t ascent = 0.f; - real_t descent = 0.f; - real_t underline_position = 0.f; - real_t underline_thickness = 0.f; - real_t scale = 1.f; - real_t oversampling = 1.f; + float ascent = 0.f; + float descent = 0.f; + float underline_position = 0.f; + float underline_thickness = 0.f; + float scale = 1.f; + float oversampling = 1.f; int spacing_glyph = 0; int spacing_space = 0; @@ -161,7 +175,11 @@ class TextServerAdvanced : public TextServer { bool force_autohinter = false; TextServer::Hinting hinting = TextServer::HINTING_LIGHT; Dictionary variation_coordinates; - real_t oversampling = 0.f; + float oversampling = 0.f; + + uint32_t style_flags = 0; + String font_name; + String style_name; Map<Vector2i, FontDataForSizeAdvanced *> cache; @@ -245,38 +263,38 @@ class TextServerAdvanced : public TextServer { // Common data. - real_t oversampling = 1.f; + float oversampling = 1.f; mutable RID_PtrOwner<FontDataAdvanced> font_owner; mutable RID_PtrOwner<ShapedTextDataAdvanced> shaped_owner; int _convert_pos(const ShapedTextDataAdvanced *p_sd, int p_pos) const; int _convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int p_pos) const; + bool _shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int p_start, int p_length) const; void _shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_start, int32_t p_end, hb_script_t p_script, hb_direction_t p_direction, Vector<RID> p_fonts, int p_span, int p_fb_index); - TextServer::Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size); + Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size); // HarfBuzz bitmap font interface. static hb_font_funcs_t *funcs; - struct hb_bmp_font_t { + struct bmp_font_t { TextServerAdvanced::FontDataForSizeAdvanced *face = nullptr; bool unref = false; /* Whether to destroy bm_face when done. */ }; - static hb_bmp_font_t *_hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref); - static void _hb_bmp_font_destroy(void *p_data); - static hb_bool_t hb_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data); - static hb_position_t hb_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data); - static hb_position_t hb_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data); - static hb_position_t hb_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data); - static hb_position_t hb_bmp_get_glyph_v_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data); - static hb_bool_t hb_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data); - static hb_bool_t hb_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data); - static hb_bool_t hb_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data); - static void hb_bmp_create_font_funcs(); - static void hb_bmp_free_font_funcs(); - static void _hb_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref); - static hb_font_t *hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy); + static bmp_font_t *_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref); + static void _bmp_font_destroy(void *p_data); + static hb_bool_t _bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data); + static hb_position_t _bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data); + static hb_position_t _bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data); + static hb_position_t _bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data); + static hb_bool_t _bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data); + static hb_bool_t _bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data); + static hb_bool_t _bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data); + static void _bmp_create_font_funcs(); + static void _bmp_free_font_funcs(); + static void _bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref); + static hb_font_t *_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy); protected: static void _bind_methods(){}; @@ -285,20 +303,19 @@ protected: void invalidate(ShapedTextDataAdvanced *p_shaped); public: - virtual bool has_feature(Feature p_feature) override; + virtual bool has_feature(Feature p_feature) const override; virtual String get_name() const override; + virtual uint32_t get_features() const override; virtual void free(RID p_rid) override; virtual bool has(RID p_rid) override; virtual bool load_support_data(const String &p_filename) override; -#ifdef TOOLS_ENABLED - virtual String get_support_data_filename() override { return _MKSTR(ICU_DATA_NAME); }; - virtual String get_support_data_info() override { return String("ICU break iteration data (") + _MKSTR(ICU_DATA_NAME) + String(")."); }; - virtual bool save_support_data(const String &p_filename) override; -#endif + virtual String get_support_data_filename() const override; + virtual String get_support_data_info() const override; + virtual bool save_support_data(const String &p_filename) const override; - virtual bool is_locale_right_to_left(const String &p_locale) override; + virtual bool is_locale_right_to_left(const String &p_locale) const override; virtual int32_t name_to_tag(const String &p_name) const override; virtual String tag_to_name(int32_t p_tag) const override; @@ -309,6 +326,15 @@ public: virtual void font_set_data(RID p_font_rid, const PackedByteArray &p_data) override; virtual void font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) override; + virtual void font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p_style) override; + virtual uint32_t /*FontStyle*/ font_get_style(RID p_font_rid) const override; + + virtual void font_set_style_name(RID p_font_rid, const String &p_name) override; + virtual String font_get_style_name(RID p_font_rid) const override; + + virtual void font_set_name(RID p_font_rid, const String &p_name) override; + virtual String font_get_name(RID p_font_rid) const override; + virtual void font_set_antialiased(RID p_font_rid, bool p_antialiased) override; virtual bool font_is_antialiased(RID p_font_rid) const override; @@ -333,8 +359,8 @@ public: virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) override; virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const override; - virtual void font_set_oversampling(RID p_font_rid, real_t p_oversampling) override; - virtual real_t font_get_oversampling(RID p_font_rid) const override; + virtual void font_set_oversampling(RID p_font_rid, float p_oversampling) override; + virtual float font_get_oversampling(RID p_font_rid) const override; virtual Array font_get_size_cache_list(RID p_font_rid) const override; virtual void font_clear_size_cache(RID p_font_rid) override; @@ -342,20 +368,20 @@ public: hb_font_t *_font_get_hb_handle(RID p_font, int p_font_size) const; - virtual void font_set_ascent(RID p_font_rid, int p_size, real_t p_ascent) override; - virtual real_t font_get_ascent(RID p_font_rid, int p_size) const override; + virtual void font_set_ascent(RID p_font_rid, int p_size, float p_ascent) override; + virtual float font_get_ascent(RID p_font_rid, int p_size) const override; - virtual void font_set_descent(RID p_font_rid, int p_size, real_t p_descent) override; - virtual real_t font_get_descent(RID p_font_rid, int p_size) const override; + virtual void font_set_descent(RID p_font_rid, int p_size, float p_descent) override; + virtual float font_get_descent(RID p_font_rid, int p_size) const override; - virtual void font_set_underline_position(RID p_font_rid, int p_size, real_t p_underline_position) override; - virtual real_t font_get_underline_position(RID p_font_rid, int p_size) const override; + virtual void font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) override; + virtual float font_get_underline_position(RID p_font_rid, int p_size) const override; - virtual void font_set_underline_thickness(RID p_font_rid, int p_size, real_t p_underline_thickness) override; - virtual real_t font_get_underline_thickness(RID p_font_rid, int p_size) const override; + virtual void font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) override; + virtual float font_get_underline_thickness(RID p_font_rid, int p_size) const override; - virtual void font_set_scale(RID p_font_rid, int p_size, real_t p_scale) override; - virtual real_t font_get_scale(RID p_font_rid, int p_size) const override; + virtual void font_set_scale(RID p_font_rid, int p_size, float p_scale) override; + virtual float font_get_scale(RID p_font_rid, int p_size) const override; virtual void font_set_spacing(RID p_font_rid, int p_size, SpacingType p_spacing, int p_value) override; virtual int font_get_spacing(RID p_font_rid, int p_size, SpacingType p_spacing) const override; @@ -389,7 +415,7 @@ public: virtual int font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override; virtual void font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) override; - virtual bool font_get_glyph_contours(RID p_font, int p_size, int32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override; + virtual Dictionary font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const override; virtual Array font_get_kerning_list(RID p_font_rid, int p_size) const override; virtual void font_clear_kerning_map(RID p_font_rid, int p_size) override; @@ -424,8 +450,8 @@ public: virtual Dictionary font_supported_feature_list(RID p_font_rid) const override; virtual Dictionary font_supported_variation_list(RID p_font_rid) const override; - virtual real_t font_get_global_oversampling() const override; - virtual void font_set_global_oversampling(real_t p_oversampling) override; + virtual float font_get_global_oversampling() const override; + virtual void font_set_global_oversampling(float p_oversampling) override; /* Shaped text buffer interface */ @@ -436,7 +462,10 @@ public: virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override; virtual Direction shaped_text_get_direction(RID p_shaped) const override; - virtual void shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) override; + virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override; + + virtual void shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) override; + virtual String shaped_text_get_custom_punctuation(RID p_shaped) const override; virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; virtual Orientation shaped_text_get_orientation(RID p_shaped) const override; @@ -448,46 +477,49 @@ public: virtual bool shaped_text_get_preserve_control(RID p_shaped) const override; virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override; - virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) override; - virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) override; + virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER, int p_length = 1) override; + virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlignment p_inline_align = INLINE_ALIGNMENT_CENTER) override; virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override; virtual RID shaped_text_get_parent(RID p_shaped) const override; - virtual real_t shaped_text_fit_to_width(RID p_shaped, real_t p_width, uint8_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override; - virtual real_t shaped_text_tab_align(RID p_shaped, const Vector<real_t> &p_tab_stops) override; + virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override; + virtual float shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) override; virtual bool shaped_text_shape(RID p_shaped) override; virtual bool shaped_text_update_breaks(RID p_shaped) override; virtual bool shaped_text_update_justification_ops(RID p_shaped) override; - virtual void shaped_text_overrun_trim_to_width(RID p_shaped, real_t p_width, uint8_t p_trim_flags) override; - virtual TrimData shaped_text_get_trim_data(RID p_shaped) const override; + virtual int shaped_text_get_trim_pos(RID p_shaped) const override; + virtual int shaped_text_get_ellipsis_pos(RID p_shaped) const override; + virtual const Glyph *shaped_text_get_ellipsis_glyphs(RID p_shaped) const override; + virtual int shaped_text_get_ellipsis_glyph_count(RID p_shaped) const override; + + virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint16_t p_trim_flags) override; virtual bool shaped_text_is_ready(RID p_shaped) const override; - virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const override; + virtual const Glyph *shaped_text_get_glyphs(RID p_shaped) const override; + virtual const Glyph *shaped_text_sort_logical(RID p_shaped) override; + virtual int shaped_text_get_glyph_count(RID p_shaped) const override; virtual Vector2i shaped_text_get_range(RID p_shaped) const override; - virtual Vector<Glyph> shaped_text_sort_logical(RID p_shaped) override; - virtual Array shaped_text_get_objects(RID p_shaped) const override; virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const override; virtual Size2 shaped_text_get_size(RID p_shaped) const override; - virtual real_t shaped_text_get_ascent(RID p_shaped) const override; - virtual real_t shaped_text_get_descent(RID p_shaped) const override; - virtual real_t shaped_text_get_width(RID p_shaped) const override; - virtual real_t shaped_text_get_underline_position(RID p_shaped) const override; - virtual real_t shaped_text_get_underline_thickness(RID p_shaped) const override; + virtual float shaped_text_get_ascent(RID p_shaped) const override; + virtual float shaped_text_get_descent(RID p_shaped) const override; + virtual float shaped_text_get_width(RID p_shaped) const override; + virtual float shaped_text_get_underline_position(RID p_shaped) const override; + virtual float shaped_text_get_underline_thickness(RID p_shaped) const override; virtual String format_number(const String &p_string, const String &p_language = "") const override; virtual String parse_number(const String &p_string, const String &p_language = "") const override; virtual String percent_sign(const String &p_language = "") const override; - static TextServer *create_func(Error &r_error, void *p_user_data); - static void register_server(); + virtual String strip_diacritics(const String &p_string) const override; TextServerAdvanced(); ~TextServerAdvanced(); |