Path: blob/master/modules/text_server_adv/text_server_adv.cpp
11352 views
/**************************************************************************/1/* text_server_adv.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "text_server_adv.h"3132#ifdef GDEXTENSION33// Headers for building as GDExtension plug-in.3435#include <godot_cpp/classes/file_access.hpp>36#include <godot_cpp/classes/os.hpp>37#include <godot_cpp/classes/project_settings.hpp>38#include <godot_cpp/classes/rendering_server.hpp>39#include <godot_cpp/classes/translation_server.hpp>40#include <godot_cpp/core/error_macros.hpp>4142using namespace godot;4344#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var)4546#elif defined(GODOT_MODULE)47// Headers for building as built-in module.4849#include "core/config/project_settings.h"50#include "core/error/error_macros.h"51#include "core/io/file_access.h"52#include "core/object/worker_thread_pool.h"53#include "core/string/translation_server.h"54#include "scene/resources/image_texture.h"5556#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg.5758#endif5960// Built-in ICU data.6162#ifdef ICU_STATIC_DATA63#include <icudata.gen.h>64#endif6566// Thirdparty headers.6768#ifdef MODULE_MSDFGEN_ENABLED69#include <core/EdgeHolder.h>70#include <core/ShapeDistanceFinder.h>71#include <core/contour-combiners.h>72#include <core/edge-selectors.h>73#include <msdfgen.h>74#endif7576#ifdef MODULE_SVG_ENABLED77#ifdef MODULE_FREETYPE_ENABLED78#include "thorvg_svg_in_ot.h"79#endif80#endif8182/*************************************************************************/83/* bmp_font_t HarfBuzz Bitmap font interface */84/*************************************************************************/8586hb_font_funcs_t *TextServerAdvanced::funcs = nullptr;8788TextServerAdvanced::bmp_font_t *TextServerAdvanced::_bmp_font_create(TextServerAdvanced::FontForSizeAdvanced *p_face, bool p_unref) {89bmp_font_t *bm_font = memnew(bmp_font_t);9091if (!bm_font) {92return nullptr;93}9495bm_font->face = p_face;96bm_font->unref = p_unref;9798return bm_font;99}100101void TextServerAdvanced::_bmp_font_destroy(void *p_data) {102bmp_font_t *bm_font = static_cast<bmp_font_t *>(p_data);103memdelete(bm_font);104}105106hb_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) {107const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);108109if (!bm_font->face) {110return false;111}112113if (!bm_font->face->glyph_map.has(p_unicode)) {114if (bm_font->face->glyph_map.has(0xf000u + p_unicode)) {115*r_glyph = 0xf000u + p_unicode;116return true;117} else {118return false;119}120}121122*r_glyph = p_unicode;123return true;124}125126hb_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) {127const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);128129if (!bm_font->face) {130return 0;131}132133HashMap<int32_t, FontGlyph>::Iterator E = bm_font->face->glyph_map.find(p_glyph);134if (!E) {135return 0;136}137138return E->value.advance.x * 64;139}140141hb_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) {142const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);143144if (!bm_font->face) {145return 0;146}147148HashMap<int32_t, FontGlyph>::Iterator E = bm_font->face->glyph_map.find(p_glyph);149if (!E) {150return 0;151}152153return -E->value.advance.y * 64;154}155156hb_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) {157const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);158159if (!bm_font->face) {160return 0;161}162163if (!bm_font->face->kerning_map.has(Vector2i(p_left_glyph, p_right_glyph))) {164return 0;165}166167return bm_font->face->kerning_map[Vector2i(p_left_glyph, p_right_glyph)].x * 64;168}169170hb_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) {171const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);172173if (!bm_font->face) {174return false;175}176177HashMap<int32_t, FontGlyph>::Iterator E = bm_font->face->glyph_map.find(p_glyph);178if (!E) {179return false;180}181182*r_x = E->value.advance.x * 32;183*r_y = -bm_font->face->ascent * 64;184185return true;186}187188hb_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) {189const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);190191if (!bm_font->face) {192return false;193}194195HashMap<int32_t, FontGlyph>::Iterator E = bm_font->face->glyph_map.find(p_glyph);196if (!E) {197return false;198}199200r_extents->x_bearing = 0;201r_extents->y_bearing = 0;202r_extents->width = E->value.rect.size.x * 64;203r_extents->height = E->value.rect.size.y * 64;204205return true;206}207208hb_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) {209const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);210211if (!bm_font->face) {212return false;213}214215r_metrics->ascender = bm_font->face->ascent;216r_metrics->descender = bm_font->face->descent;217r_metrics->line_gap = 0;218219return true;220}221222void TextServerAdvanced::_bmp_create_font_funcs() {223if (funcs == nullptr) {224funcs = hb_font_funcs_create();225226hb_font_funcs_set_font_h_extents_func(funcs, _bmp_get_font_h_extents, nullptr, nullptr);227hb_font_funcs_set_nominal_glyph_func(funcs, _bmp_get_nominal_glyph, nullptr, nullptr);228hb_font_funcs_set_glyph_h_advance_func(funcs, _bmp_get_glyph_h_advance, nullptr, nullptr);229hb_font_funcs_set_glyph_v_advance_func(funcs, _bmp_get_glyph_v_advance, nullptr, nullptr);230hb_font_funcs_set_glyph_v_origin_func(funcs, _bmp_get_glyph_v_origin, nullptr, nullptr);231hb_font_funcs_set_glyph_h_kerning_func(funcs, _bmp_get_glyph_h_kerning, nullptr, nullptr);232hb_font_funcs_set_glyph_extents_func(funcs, _bmp_get_glyph_extents, nullptr, nullptr);233234hb_font_funcs_make_immutable(funcs);235}236}237238void TextServerAdvanced::_bmp_free_font_funcs() {239if (funcs != nullptr) {240hb_font_funcs_destroy(funcs);241funcs = nullptr;242}243}244245void TextServerAdvanced::_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontForSizeAdvanced *p_face, bool p_unref) {246hb_font_set_funcs(p_font, funcs, _bmp_font_create(p_face, p_unref), _bmp_font_destroy);247}248249hb_font_t *TextServerAdvanced::_bmp_font_create(TextServerAdvanced::FontForSizeAdvanced *p_face, hb_destroy_func_t p_destroy) {250hb_font_t *font;251hb_face_t *face = hb_face_create(nullptr, 0);252253font = hb_font_create(face);254hb_face_destroy(face);255_bmp_font_set_funcs(font, p_face, false);256return font;257}258259/*************************************************************************/260/* Character properties. */261/*************************************************************************/262263_FORCE_INLINE_ bool is_ain(char32_t p_chr) {264return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_AIN;265}266267_FORCE_INLINE_ bool is_alef(char32_t p_chr) {268return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_ALEF;269}270271_FORCE_INLINE_ bool is_beh(char32_t p_chr) {272int32_t prop = u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP);273return (prop == U_JG_BEH) || (prop == U_JG_NOON) || (prop == U_JG_AFRICAN_NOON) || (prop == U_JG_NYA) || (prop == U_JG_YEH) || (prop == U_JG_FARSI_YEH);274}275276_FORCE_INLINE_ bool is_dal(char32_t p_chr) {277return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_DAL;278}279280_FORCE_INLINE_ bool is_feh(char32_t p_chr) {281return (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_FEH) || (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_AFRICAN_FEH);282}283284_FORCE_INLINE_ bool is_gaf(char32_t p_chr) {285return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_GAF;286}287288_FORCE_INLINE_ bool is_heh(char32_t p_chr) {289return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_HEH;290}291292_FORCE_INLINE_ bool is_kaf(char32_t p_chr) {293return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_KAF;294}295296_FORCE_INLINE_ bool is_lam(char32_t p_chr) {297return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_LAM;298}299300_FORCE_INLINE_ bool is_qaf(char32_t p_chr) {301return (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_QAF) || (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_AFRICAN_QAF);302}303304_FORCE_INLINE_ bool is_reh(char32_t p_chr) {305return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_REH;306}307308_FORCE_INLINE_ bool is_seen_sad(char32_t p_chr) {309return (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_SAD) || (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_SEEN);310}311312_FORCE_INLINE_ bool is_tah(char32_t p_chr) {313return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_TAH;314}315316_FORCE_INLINE_ bool is_teh_marbuta(char32_t p_chr) {317return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_TEH_MARBUTA;318}319320_FORCE_INLINE_ bool is_yeh(char32_t p_chr) {321int32_t prop = u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP);322return (prop == U_JG_YEH) || (prop == U_JG_FARSI_YEH) || (prop == U_JG_YEH_BARREE) || (prop == U_JG_BURUSHASKI_YEH_BARREE) || (prop == U_JG_YEH_WITH_TAIL);323}324325_FORCE_INLINE_ bool is_waw(char32_t p_chr) {326return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_WAW;327}328329_FORCE_INLINE_ bool is_transparent(char32_t p_chr) {330return u_getIntPropertyValue(p_chr, UCHAR_JOINING_TYPE) == U_JT_TRANSPARENT;331}332333_FORCE_INLINE_ bool is_ligature(char32_t p_chr, char32_t p_nchr) {334return (is_lam(p_chr) && is_alef(p_nchr));335}336337_FORCE_INLINE_ bool is_connected_to_prev(char32_t p_chr, char32_t p_pchr) {338int32_t prop = u_getIntPropertyValue(p_pchr, UCHAR_JOINING_TYPE);339return (prop != U_JT_RIGHT_JOINING) && (prop != U_JT_NON_JOINING) ? !is_ligature(p_pchr, p_chr) : false;340}341342/*************************************************************************/343344bool TextServerAdvanced::icu_data_loaded = false;345PackedByteArray TextServerAdvanced::icu_data;346347bool TextServerAdvanced::_has_feature(Feature p_feature) const {348switch (p_feature) {349case FEATURE_SIMPLE_LAYOUT:350case FEATURE_BIDI_LAYOUT:351case FEATURE_VERTICAL_LAYOUT:352case FEATURE_SHAPING:353case FEATURE_KASHIDA_JUSTIFICATION:354case FEATURE_BREAK_ITERATORS:355case FEATURE_FONT_BITMAP:356#ifdef MODULE_FREETYPE_ENABLED357case FEATURE_FONT_DYNAMIC:358#endif359#ifdef MODULE_MSDFGEN_ENABLED360case FEATURE_FONT_MSDF:361#endif362case FEATURE_FONT_VARIABLE:363case FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION:364case FEATURE_USE_SUPPORT_DATA:365case FEATURE_UNICODE_IDENTIFIERS:366case FEATURE_UNICODE_SECURITY:367return true;368default: {369}370}371return false;372}373374String TextServerAdvanced::_get_name() const {375#ifdef GDEXTENSION376return "ICU / HarfBuzz / Graphite (GDExtension)";377#elif defined(GODOT_MODULE)378return "ICU / HarfBuzz / Graphite (Built-in)";379#endif380}381382int64_t TextServerAdvanced::_get_features() const {383int64_t interface_features = FEATURE_SIMPLE_LAYOUT | FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_FONT_BITMAP | FEATURE_FONT_VARIABLE | FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION | FEATURE_USE_SUPPORT_DATA;384#ifdef MODULE_FREETYPE_ENABLED385interface_features |= FEATURE_FONT_DYNAMIC;386#endif387#ifdef MODULE_MSDFGEN_ENABLED388interface_features |= FEATURE_FONT_MSDF;389#endif390391return interface_features;392}393394void TextServerAdvanced::_free_rid(const RID &p_rid) {395_THREAD_SAFE_METHOD_396if (font_owner.owns(p_rid)) {397MutexLock ftlock(ft_mutex);398399FontAdvanced *fd = font_owner.get_or_null(p_rid);400for (const KeyValue<Vector2i, FontForSizeAdvanced *> &ffsd : fd->cache) {401OversamplingLevel *ol = oversampling_levels.getptr(ffsd.value->viewport_oversampling);402if (ol != nullptr) {403ol->fonts.erase(ffsd.value);404}405}406{407MutexLock lock(fd->mutex);408font_owner.free(p_rid);409}410memdelete(fd);411} else if (font_var_owner.owns(p_rid)) {412MutexLock ftlock(ft_mutex);413414FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(p_rid);415{416font_var_owner.free(p_rid);417}418memdelete(fdv);419} else if (shaped_owner.owns(p_rid)) {420ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_rid);421{422MutexLock lock(sd->mutex);423shaped_owner.free(p_rid);424}425memdelete(sd);426}427}428429bool TextServerAdvanced::_has(const RID &p_rid) {430_THREAD_SAFE_METHOD_431return font_owner.owns(p_rid) || font_var_owner.owns(p_rid) || shaped_owner.owns(p_rid);432}433434bool TextServerAdvanced::_load_support_data(const String &p_filename) {435_THREAD_SAFE_METHOD_436437#if defined(ICU_STATIC_DATA) || !defined(HAVE_ICU_BUILTIN)438if (!icu_data_loaded) {439UErrorCode err = U_ZERO_ERROR;440u_init(&err); // Do not check for errors, since we only load part of the data.441icu_data_loaded = true;442}443#else444if (!icu_data_loaded) {445UErrorCode err = U_ZERO_ERROR;446String filename = (p_filename.is_empty()) ? String("res://icudt_godot.dat") : p_filename;447if (FileAccess::exists(filename)) {448Ref<FileAccess> f = FileAccess::open(filename, FileAccess::READ);449if (f.is_null()) {450return false;451}452uint64_t len = f->get_length();453icu_data = f->get_buffer(len);454455udata_setCommonData(icu_data.ptr(), &err);456if (U_FAILURE(err)) {457ERR_FAIL_V_MSG(false, u_errorName(err));458}459460err = U_ZERO_ERROR;461icu_data_loaded = true;462}463464u_init(&err);465if (U_FAILURE(err)) {466ERR_FAIL_V_MSG(false, u_errorName(err));467}468}469#endif470return true;471}472473String TextServerAdvanced::_get_support_data_filename() const {474return String("icudt_godot.dat");475}476477String TextServerAdvanced::_get_support_data_info() const {478return String("ICU break iteration data (\"icudt_godot.dat\").");479}480481bool TextServerAdvanced::_save_support_data(const String &p_filename) const {482_THREAD_SAFE_METHOD_483#ifdef ICU_STATIC_DATA484485// Store data to the res file if it's available.486487Ref<FileAccess> f = FileAccess::open(p_filename, FileAccess::WRITE);488if (f.is_null()) {489return false;490}491492PackedByteArray icu_data_static;493icu_data_static.resize(U_ICUDATA_SIZE);494memcpy(icu_data_static.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);495f->store_buffer(icu_data_static);496497return true;498#else499return false;500#endif501}502503PackedByteArray TextServerAdvanced::_get_support_data() const {504_THREAD_SAFE_METHOD_505#ifdef ICU_STATIC_DATA506507PackedByteArray icu_data_static;508icu_data_static.resize(U_ICUDATA_SIZE);509memcpy(icu_data_static.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);510511return icu_data_static;512#else513return icu_data;514#endif515}516517bool TextServerAdvanced::_is_locale_right_to_left(const String &p_locale) const {518String l = p_locale.get_slicec('_', 0);519if ((l == "ar") || (l == "dv") || (l == "he") || (l == "fa") || (l == "ff") || (l == "ku") || (l == "ur")) {520return true;521} else {522return false;523}524}525526_FORCE_INLINE_ void TextServerAdvanced::_insert_feature(const StringName &p_name, int32_t p_tag, Variant::Type p_vtype, bool p_hidden) {527FeatureInfo fi;528fi.name = p_name;529fi.vtype = p_vtype;530fi.hidden = p_hidden;531532feature_sets.insert(p_name, p_tag);533feature_sets_inv.insert(p_tag, fi);534}535536void TextServerAdvanced::_insert_feature_sets() {537// Registered OpenType feature tags.538// Name, Tag, Data Type, Hidden539_insert_feature("access_all_alternates", HB_TAG('a', 'a', 'l', 't'), Variant::Type::INT, false);540_insert_feature("above_base_forms", HB_TAG('a', 'b', 'v', 'f'), Variant::Type::INT, true);541_insert_feature("above_base_mark_positioning", HB_TAG('a', 'b', 'v', 'm'), Variant::Type::INT, true);542_insert_feature("above_base_substitutions", HB_TAG('a', 'b', 'v', 's'), Variant::Type::INT, true);543_insert_feature("alternative_fractions", HB_TAG('a', 'f', 'r', 'c'), Variant::Type::INT, false);544_insert_feature("akhands", HB_TAG('a', 'k', 'h', 'n'), Variant::Type::INT, true);545_insert_feature("below_base_forms", HB_TAG('b', 'l', 'w', 'f'), Variant::Type::INT, true);546_insert_feature("below_base_mark_positioning", HB_TAG('b', 'l', 'w', 'm'), Variant::Type::INT, true);547_insert_feature("below_base_substitutions", HB_TAG('b', 'l', 'w', 's'), Variant::Type::INT, true);548_insert_feature("contextual_alternates", HB_TAG('c', 'a', 'l', 't'), Variant::Type::BOOL, false);549_insert_feature("case_sensitive_forms", HB_TAG('c', 'a', 's', 'e'), Variant::Type::BOOL, false);550_insert_feature("glyph_composition", HB_TAG('c', 'c', 'm', 'p'), Variant::Type::INT, true);551_insert_feature("conjunct_form_after_ro", HB_TAG('c', 'f', 'a', 'r'), Variant::Type::INT, true);552_insert_feature("contextual_half_width_spacing", HB_TAG('c', 'h', 'w', 's'), Variant::Type::INT, true);553_insert_feature("conjunct_forms", HB_TAG('c', 'j', 'c', 't'), Variant::Type::INT, true);554_insert_feature("contextual_ligatures", HB_TAG('c', 'l', 'i', 'g'), Variant::Type::BOOL, false);555_insert_feature("centered_cjk_punctuation", HB_TAG('c', 'p', 'c', 't'), Variant::Type::BOOL, false);556_insert_feature("capital_spacing", HB_TAG('c', 'p', 's', 'p'), Variant::Type::BOOL, false);557_insert_feature("contextual_swash", HB_TAG('c', 's', 'w', 'h'), Variant::Type::INT, false);558_insert_feature("cursive_positioning", HB_TAG('c', 'u', 'r', 's'), Variant::Type::INT, true);559_insert_feature("character_variant_01", HB_TAG('c', 'v', '0', '1'), Variant::Type::BOOL, false);560_insert_feature("character_variant_02", HB_TAG('c', 'v', '0', '2'), Variant::Type::BOOL, false);561_insert_feature("character_variant_03", HB_TAG('c', 'v', '0', '3'), Variant::Type::BOOL, false);562_insert_feature("character_variant_04", HB_TAG('c', 'v', '0', '4'), Variant::Type::BOOL, false);563_insert_feature("character_variant_05", HB_TAG('c', 'v', '0', '5'), Variant::Type::BOOL, false);564_insert_feature("character_variant_06", HB_TAG('c', 'v', '0', '6'), Variant::Type::BOOL, false);565_insert_feature("character_variant_07", HB_TAG('c', 'v', '0', '7'), Variant::Type::BOOL, false);566_insert_feature("character_variant_08", HB_TAG('c', 'v', '0', '8'), Variant::Type::BOOL, false);567_insert_feature("character_variant_09", HB_TAG('c', 'v', '0', '9'), Variant::Type::BOOL, false);568_insert_feature("character_variant_10", HB_TAG('c', 'v', '1', '0'), Variant::Type::BOOL, false);569_insert_feature("character_variant_11", HB_TAG('c', 'v', '1', '1'), Variant::Type::BOOL, false);570_insert_feature("character_variant_12", HB_TAG('c', 'v', '1', '2'), Variant::Type::BOOL, false);571_insert_feature("character_variant_13", HB_TAG('c', 'v', '1', '3'), Variant::Type::BOOL, false);572_insert_feature("character_variant_14", HB_TAG('c', 'v', '1', '4'), Variant::Type::BOOL, false);573_insert_feature("character_variant_15", HB_TAG('c', 'v', '1', '5'), Variant::Type::BOOL, false);574_insert_feature("character_variant_16", HB_TAG('c', 'v', '1', '6'), Variant::Type::BOOL, false);575_insert_feature("character_variant_17", HB_TAG('c', 'v', '1', '7'), Variant::Type::BOOL, false);576_insert_feature("character_variant_18", HB_TAG('c', 'v', '1', '8'), Variant::Type::BOOL, false);577_insert_feature("character_variant_19", HB_TAG('c', 'v', '1', '9'), Variant::Type::BOOL, false);578_insert_feature("character_variant_20", HB_TAG('c', 'v', '2', '0'), Variant::Type::BOOL, false);579_insert_feature("character_variant_21", HB_TAG('c', 'v', '2', '1'), Variant::Type::BOOL, false);580_insert_feature("character_variant_22", HB_TAG('c', 'v', '2', '2'), Variant::Type::BOOL, false);581_insert_feature("character_variant_23", HB_TAG('c', 'v', '2', '3'), Variant::Type::BOOL, false);582_insert_feature("character_variant_24", HB_TAG('c', 'v', '2', '4'), Variant::Type::BOOL, false);583_insert_feature("character_variant_25", HB_TAG('c', 'v', '2', '5'), Variant::Type::BOOL, false);584_insert_feature("character_variant_26", HB_TAG('c', 'v', '2', '6'), Variant::Type::BOOL, false);585_insert_feature("character_variant_27", HB_TAG('c', 'v', '2', '7'), Variant::Type::BOOL, false);586_insert_feature("character_variant_28", HB_TAG('c', 'v', '2', '8'), Variant::Type::BOOL, false);587_insert_feature("character_variant_29", HB_TAG('c', 'v', '2', '9'), Variant::Type::BOOL, false);588_insert_feature("character_variant_30", HB_TAG('c', 'v', '3', '0'), Variant::Type::BOOL, false);589_insert_feature("character_variant_31", HB_TAG('c', 'v', '3', '1'), Variant::Type::BOOL, false);590_insert_feature("character_variant_32", HB_TAG('c', 'v', '3', '2'), Variant::Type::BOOL, false);591_insert_feature("character_variant_33", HB_TAG('c', 'v', '3', '3'), Variant::Type::BOOL, false);592_insert_feature("character_variant_34", HB_TAG('c', 'v', '3', '4'), Variant::Type::BOOL, false);593_insert_feature("character_variant_35", HB_TAG('c', 'v', '3', '5'), Variant::Type::BOOL, false);594_insert_feature("character_variant_36", HB_TAG('c', 'v', '3', '6'), Variant::Type::BOOL, false);595_insert_feature("character_variant_37", HB_TAG('c', 'v', '3', '7'), Variant::Type::BOOL, false);596_insert_feature("character_variant_38", HB_TAG('c', 'v', '3', '8'), Variant::Type::BOOL, false);597_insert_feature("character_variant_39", HB_TAG('c', 'v', '3', '9'), Variant::Type::BOOL, false);598_insert_feature("character_variant_40", HB_TAG('c', 'v', '4', '0'), Variant::Type::BOOL, false);599_insert_feature("character_variant_41", HB_TAG('c', 'v', '4', '1'), Variant::Type::BOOL, false);600_insert_feature("character_variant_42", HB_TAG('c', 'v', '4', '2'), Variant::Type::BOOL, false);601_insert_feature("character_variant_43", HB_TAG('c', 'v', '4', '3'), Variant::Type::BOOL, false);602_insert_feature("character_variant_44", HB_TAG('c', 'v', '4', '4'), Variant::Type::BOOL, false);603_insert_feature("character_variant_45", HB_TAG('c', 'v', '4', '5'), Variant::Type::BOOL, false);604_insert_feature("character_variant_46", HB_TAG('c', 'v', '4', '6'), Variant::Type::BOOL, false);605_insert_feature("character_variant_47", HB_TAG('c', 'v', '4', '7'), Variant::Type::BOOL, false);606_insert_feature("character_variant_48", HB_TAG('c', 'v', '4', '8'), Variant::Type::BOOL, false);607_insert_feature("character_variant_49", HB_TAG('c', 'v', '4', '9'), Variant::Type::BOOL, false);608_insert_feature("character_variant_50", HB_TAG('c', 'v', '5', '0'), Variant::Type::BOOL, false);609_insert_feature("character_variant_51", HB_TAG('c', 'v', '5', '1'), Variant::Type::BOOL, false);610_insert_feature("character_variant_52", HB_TAG('c', 'v', '5', '2'), Variant::Type::BOOL, false);611_insert_feature("character_variant_53", HB_TAG('c', 'v', '5', '3'), Variant::Type::BOOL, false);612_insert_feature("character_variant_54", HB_TAG('c', 'v', '5', '4'), Variant::Type::BOOL, false);613_insert_feature("character_variant_55", HB_TAG('c', 'v', '5', '5'), Variant::Type::BOOL, false);614_insert_feature("character_variant_56", HB_TAG('c', 'v', '5', '6'), Variant::Type::BOOL, false);615_insert_feature("character_variant_57", HB_TAG('c', 'v', '5', '7'), Variant::Type::BOOL, false);616_insert_feature("character_variant_58", HB_TAG('c', 'v', '5', '8'), Variant::Type::BOOL, false);617_insert_feature("character_variant_59", HB_TAG('c', 'v', '5', '9'), Variant::Type::BOOL, false);618_insert_feature("character_variant_60", HB_TAG('c', 'v', '6', '0'), Variant::Type::BOOL, false);619_insert_feature("character_variant_61", HB_TAG('c', 'v', '6', '1'), Variant::Type::BOOL, false);620_insert_feature("character_variant_62", HB_TAG('c', 'v', '6', '2'), Variant::Type::BOOL, false);621_insert_feature("character_variant_63", HB_TAG('c', 'v', '6', '3'), Variant::Type::BOOL, false);622_insert_feature("character_variant_64", HB_TAG('c', 'v', '6', '4'), Variant::Type::BOOL, false);623_insert_feature("character_variant_65", HB_TAG('c', 'v', '6', '5'), Variant::Type::BOOL, false);624_insert_feature("character_variant_66", HB_TAG('c', 'v', '6', '6'), Variant::Type::BOOL, false);625_insert_feature("character_variant_67", HB_TAG('c', 'v', '6', '7'), Variant::Type::BOOL, false);626_insert_feature("character_variant_68", HB_TAG('c', 'v', '6', '8'), Variant::Type::BOOL, false);627_insert_feature("character_variant_69", HB_TAG('c', 'v', '6', '9'), Variant::Type::BOOL, false);628_insert_feature("character_variant_70", HB_TAG('c', 'v', '7', '0'), Variant::Type::BOOL, false);629_insert_feature("character_variant_71", HB_TAG('c', 'v', '7', '1'), Variant::Type::BOOL, false);630_insert_feature("character_variant_72", HB_TAG('c', 'v', '7', '2'), Variant::Type::BOOL, false);631_insert_feature("character_variant_73", HB_TAG('c', 'v', '7', '3'), Variant::Type::BOOL, false);632_insert_feature("character_variant_74", HB_TAG('c', 'v', '7', '4'), Variant::Type::BOOL, false);633_insert_feature("character_variant_75", HB_TAG('c', 'v', '7', '5'), Variant::Type::BOOL, false);634_insert_feature("character_variant_76", HB_TAG('c', 'v', '7', '6'), Variant::Type::BOOL, false);635_insert_feature("character_variant_77", HB_TAG('c', 'v', '7', '7'), Variant::Type::BOOL, false);636_insert_feature("character_variant_78", HB_TAG('c', 'v', '7', '8'), Variant::Type::BOOL, false);637_insert_feature("character_variant_79", HB_TAG('c', 'v', '7', '9'), Variant::Type::BOOL, false);638_insert_feature("character_variant_80", HB_TAG('c', 'v', '8', '0'), Variant::Type::BOOL, false);639_insert_feature("character_variant_81", HB_TAG('c', 'v', '8', '1'), Variant::Type::BOOL, false);640_insert_feature("character_variant_82", HB_TAG('c', 'v', '8', '2'), Variant::Type::BOOL, false);641_insert_feature("character_variant_83", HB_TAG('c', 'v', '8', '3'), Variant::Type::BOOL, false);642_insert_feature("character_variant_84", HB_TAG('c', 'v', '8', '4'), Variant::Type::BOOL, false);643_insert_feature("character_variant_85", HB_TAG('c', 'v', '8', '5'), Variant::Type::BOOL, false);644_insert_feature("character_variant_86", HB_TAG('c', 'v', '8', '6'), Variant::Type::BOOL, false);645_insert_feature("character_variant_87", HB_TAG('c', 'v', '8', '7'), Variant::Type::BOOL, false);646_insert_feature("character_variant_88", HB_TAG('c', 'v', '8', '8'), Variant::Type::BOOL, false);647_insert_feature("character_variant_89", HB_TAG('c', 'v', '8', '9'), Variant::Type::BOOL, false);648_insert_feature("character_variant_90", HB_TAG('c', 'v', '9', '0'), Variant::Type::BOOL, false);649_insert_feature("character_variant_91", HB_TAG('c', 'v', '9', '1'), Variant::Type::BOOL, false);650_insert_feature("character_variant_92", HB_TAG('c', 'v', '9', '2'), Variant::Type::BOOL, false);651_insert_feature("character_variant_93", HB_TAG('c', 'v', '9', '3'), Variant::Type::BOOL, false);652_insert_feature("character_variant_94", HB_TAG('c', 'v', '9', '4'), Variant::Type::BOOL, false);653_insert_feature("character_variant_95", HB_TAG('c', 'v', '9', '5'), Variant::Type::BOOL, false);654_insert_feature("character_variant_96", HB_TAG('c', 'v', '9', '6'), Variant::Type::BOOL, false);655_insert_feature("character_variant_97", HB_TAG('c', 'v', '9', '7'), Variant::Type::BOOL, false);656_insert_feature("character_variant_98", HB_TAG('c', 'v', '9', '8'), Variant::Type::BOOL, false);657_insert_feature("character_variant_99", HB_TAG('c', 'v', '9', '9'), Variant::Type::BOOL, false);658_insert_feature("petite_capitals_from_capitals", HB_TAG('c', '2', 'p', 'c'), Variant::Type::BOOL, false);659_insert_feature("small_capitals_from_capitals", HB_TAG('c', '2', 's', 'c'), Variant::Type::BOOL, false);660_insert_feature("distances", HB_TAG('d', 'i', 's', 't'), Variant::Type::INT, true);661_insert_feature("discretionary_ligatures", HB_TAG('d', 'l', 'i', 'g'), Variant::Type::BOOL, false);662_insert_feature("denominators", HB_TAG('d', 'n', 'o', 'm'), Variant::Type::BOOL, false);663_insert_feature("dotless_forms", HB_TAG('d', 't', 'l', 's'), Variant::Type::INT, true);664_insert_feature("expert_forms", HB_TAG('e', 'x', 'p', 't'), Variant::Type::BOOL, true);665_insert_feature("final_glyph_on_line_alternates", HB_TAG('f', 'a', 'l', 't'), Variant::Type::INT, false);666_insert_feature("terminal_forms_2", HB_TAG('f', 'i', 'n', '2'), Variant::Type::INT, true);667_insert_feature("terminal_forms_3", HB_TAG('f', 'i', 'n', '3'), Variant::Type::INT, true);668_insert_feature("terminal_forms", HB_TAG('f', 'i', 'n', 'a'), Variant::Type::INT, true);669_insert_feature("flattened_accent_forms", HB_TAG('f', 'l', 'a', 'c'), Variant::Type::INT, true);670_insert_feature("fractions", HB_TAG('f', 'r', 'a', 'c'), Variant::Type::BOOL, false);671_insert_feature("full_widths", HB_TAG('f', 'w', 'i', 'd'), Variant::Type::BOOL, false);672_insert_feature("half_forms", HB_TAG('h', 'a', 'l', 'f'), Variant::Type::INT, true);673_insert_feature("halant_forms", HB_TAG('h', 'a', 'l', 'n'), Variant::Type::INT, true);674_insert_feature("alternate_half_widths", HB_TAG('h', 'a', 'l', 't'), Variant::Type::BOOL, false);675_insert_feature("historical_forms", HB_TAG('h', 'i', 's', 't'), Variant::Type::INT, false);676_insert_feature("horizontal_kana_alternates", HB_TAG('h', 'k', 'n', 'a'), Variant::Type::BOOL, false);677_insert_feature("historical_ligatures", HB_TAG('h', 'l', 'i', 'g'), Variant::Type::BOOL, false);678_insert_feature("hangul", HB_TAG('h', 'n', 'g', 'l'), Variant::Type::INT, false);679_insert_feature("hojo_kanji_forms", HB_TAG('h', 'o', 'j', 'o'), Variant::Type::INT, false);680_insert_feature("half_widths", HB_TAG('h', 'w', 'i', 'd'), Variant::Type::BOOL, false);681_insert_feature("initial_forms", HB_TAG('i', 'n', 'i', 't'), Variant::Type::INT, true);682_insert_feature("isolated_forms", HB_TAG('i', 's', 'o', 'l'), Variant::Type::INT, true);683_insert_feature("italics", HB_TAG('i', 't', 'a', 'l'), Variant::Type::INT, false);684_insert_feature("justification_alternates", HB_TAG('j', 'a', 'l', 't'), Variant::Type::INT, false);685_insert_feature("jis78_forms", HB_TAG('j', 'p', '7', '8'), Variant::Type::INT, false);686_insert_feature("jis83_forms", HB_TAG('j', 'p', '8', '3'), Variant::Type::INT, false);687_insert_feature("jis90_forms", HB_TAG('j', 'p', '9', '0'), Variant::Type::INT, false);688_insert_feature("jis2004_forms", HB_TAG('j', 'p', '0', '4'), Variant::Type::INT, false);689_insert_feature("kerning", HB_TAG('k', 'e', 'r', 'n'), Variant::Type::BOOL, false);690_insert_feature("left_bounds", HB_TAG('l', 'f', 'b', 'd'), Variant::Type::INT, false);691_insert_feature("standard_ligatures", HB_TAG('l', 'i', 'g', 'a'), Variant::Type::BOOL, false);692_insert_feature("leading_jamo_forms", HB_TAG('l', 'j', 'm', 'o'), Variant::Type::INT, true);693_insert_feature("lining_figures", HB_TAG('l', 'n', 'u', 'm'), Variant::Type::INT, false);694_insert_feature("localized_forms", HB_TAG('l', 'o', 'c', 'l'), Variant::Type::INT, true);695_insert_feature("left_to_right_alternates", HB_TAG('l', 't', 'r', 'a'), Variant::Type::INT, true);696_insert_feature("left_to_right_mirrored_forms", HB_TAG('l', 't', 'r', 'm'), Variant::Type::INT, true);697_insert_feature("mark_positioning", HB_TAG('m', 'a', 'r', 'k'), Variant::Type::INT, true);698_insert_feature("medial_forms_2", HB_TAG('m', 'e', 'd', '2'), Variant::Type::INT, true);699_insert_feature("medial_forms", HB_TAG('m', 'e', 'd', 'i'), Variant::Type::INT, true);700_insert_feature("mathematical_greek", HB_TAG('m', 'g', 'r', 'k'), Variant::Type::BOOL, false);701_insert_feature("mark_to_mark_positioning", HB_TAG('m', 'k', 'm', 'k'), Variant::Type::INT, true);702_insert_feature("mark_positioning_via_substitution", HB_TAG('m', 's', 'e', 't'), Variant::Type::INT, true);703_insert_feature("alternate_annotation_forms", HB_TAG('n', 'a', 'l', 't'), Variant::Type::INT, false);704_insert_feature("nlc_kanji_forms", HB_TAG('n', 'l', 'c', 'k'), Variant::Type::INT, false);705_insert_feature("nukta_forms", HB_TAG('n', 'u', 'k', 't'), Variant::Type::INT, true);706_insert_feature("numerators", HB_TAG('n', 'u', 'm', 'r'), Variant::Type::BOOL, false);707_insert_feature("oldstyle_figures", HB_TAG('o', 'n', 'u', 'm'), Variant::Type::INT, false);708_insert_feature("optical_bounds", HB_TAG('o', 'p', 'b', 'd'), Variant::Type::INT, true);709_insert_feature("ordinals", HB_TAG('o', 'r', 'd', 'n'), Variant::Type::BOOL, false);710_insert_feature("ornaments", HB_TAG('o', 'r', 'n', 'm'), Variant::Type::INT, false);711_insert_feature("proportional_alternate_widths", HB_TAG('p', 'a', 'l', 't'), Variant::Type::BOOL, false);712_insert_feature("petite_capitals", HB_TAG('p', 'c', 'a', 'p'), Variant::Type::BOOL, false);713_insert_feature("proportional_kana", HB_TAG('p', 'k', 'n', 'a'), Variant::Type::BOOL, false);714_insert_feature("proportional_figures", HB_TAG('p', 'n', 'u', 'm'), Variant::Type::BOOL, false);715_insert_feature("pre_base_forms", HB_TAG('p', 'r', 'e', 'f'), Variant::Type::INT, true);716_insert_feature("pre_base_substitutions", HB_TAG('p', 'r', 'e', 's'), Variant::Type::INT, true);717_insert_feature("post_base_forms", HB_TAG('p', 's', 't', 'f'), Variant::Type::INT, true);718_insert_feature("post_base_substitutions", HB_TAG('p', 's', 't', 's'), Variant::Type::INT, true);719_insert_feature("proportional_widths", HB_TAG('p', 'w', 'i', 'd'), Variant::Type::BOOL, false);720_insert_feature("quarter_widths", HB_TAG('q', 'w', 'i', 'd'), Variant::Type::BOOL, false);721_insert_feature("randomize", HB_TAG('r', 'a', 'n', 'd'), Variant::Type::INT, false);722_insert_feature("required_contextual_alternates", HB_TAG('r', 'c', 'l', 't'), Variant::Type::BOOL, true);723_insert_feature("rakar_forms", HB_TAG('r', 'k', 'r', 'f'), Variant::Type::INT, true);724_insert_feature("required_ligatures", HB_TAG('r', 'l', 'i', 'g'), Variant::Type::BOOL, true);725_insert_feature("reph_forms", HB_TAG('r', 'p', 'h', 'f'), Variant::Type::INT, true);726_insert_feature("right_bounds", HB_TAG('r', 't', 'b', 'd'), Variant::Type::INT, false);727_insert_feature("right_to_left_alternates", HB_TAG('r', 't', 'l', 'a'), Variant::Type::INT, true);728_insert_feature("right_to_left_mirrored_forms", HB_TAG('r', 't', 'l', 'm'), Variant::Type::INT, true);729_insert_feature("ruby_notation_forms", HB_TAG('r', 'u', 'b', 'y'), Variant::Type::INT, false);730_insert_feature("required_variation_alternates", HB_TAG('r', 'v', 'r', 'n'), Variant::Type::INT, true);731_insert_feature("stylistic_alternates", HB_TAG('s', 'a', 'l', 't'), Variant::Type::INT, false);732_insert_feature("scientific_inferiors", HB_TAG('s', 'i', 'n', 'f'), Variant::Type::BOOL, false);733_insert_feature("optical_size", HB_TAG('s', 'i', 'z', 'e'), Variant::Type::INT, false);734_insert_feature("small_capitals", HB_TAG('s', 'm', 'c', 'p'), Variant::Type::BOOL, false);735_insert_feature("simplified_forms", HB_TAG('s', 'm', 'p', 'l'), Variant::Type::INT, false);736_insert_feature("stylistic_set_01", HB_TAG('s', 's', '0', '1'), Variant::Type::BOOL, false);737_insert_feature("stylistic_set_02", HB_TAG('s', 's', '0', '2'), Variant::Type::BOOL, false);738_insert_feature("stylistic_set_03", HB_TAG('s', 's', '0', '3'), Variant::Type::BOOL, false);739_insert_feature("stylistic_set_04", HB_TAG('s', 's', '0', '4'), Variant::Type::BOOL, false);740_insert_feature("stylistic_set_05", HB_TAG('s', 's', '0', '5'), Variant::Type::BOOL, false);741_insert_feature("stylistic_set_06", HB_TAG('s', 's', '0', '6'), Variant::Type::BOOL, false);742_insert_feature("stylistic_set_07", HB_TAG('s', 's', '0', '7'), Variant::Type::BOOL, false);743_insert_feature("stylistic_set_08", HB_TAG('s', 's', '0', '8'), Variant::Type::BOOL, false);744_insert_feature("stylistic_set_09", HB_TAG('s', 's', '0', '9'), Variant::Type::BOOL, false);745_insert_feature("stylistic_set_10", HB_TAG('s', 's', '1', '0'), Variant::Type::BOOL, false);746_insert_feature("stylistic_set_11", HB_TAG('s', 's', '1', '1'), Variant::Type::BOOL, false);747_insert_feature("stylistic_set_12", HB_TAG('s', 's', '1', '2'), Variant::Type::BOOL, false);748_insert_feature("stylistic_set_13", HB_TAG('s', 's', '1', '3'), Variant::Type::BOOL, false);749_insert_feature("stylistic_set_14", HB_TAG('s', 's', '1', '4'), Variant::Type::BOOL, false);750_insert_feature("stylistic_set_15", HB_TAG('s', 's', '1', '5'), Variant::Type::BOOL, false);751_insert_feature("stylistic_set_16", HB_TAG('s', 's', '1', '6'), Variant::Type::BOOL, false);752_insert_feature("stylistic_set_17", HB_TAG('s', 's', '1', '7'), Variant::Type::BOOL, false);753_insert_feature("stylistic_set_18", HB_TAG('s', 's', '1', '8'), Variant::Type::BOOL, false);754_insert_feature("stylistic_set_19", HB_TAG('s', 's', '1', '9'), Variant::Type::BOOL, false);755_insert_feature("stylistic_set_20", HB_TAG('s', 's', '2', '0'), Variant::Type::BOOL, false);756_insert_feature("math_script_style_alternates", HB_TAG('s', 's', 't', 'y'), Variant::Type::INT, true);757_insert_feature("stretching_glyph_decomposition", HB_TAG('s', 't', 'c', 'h'), Variant::Type::INT, true);758_insert_feature("subscript", HB_TAG('s', 'u', 'b', 's'), Variant::Type::BOOL, false);759_insert_feature("superscript", HB_TAG('s', 'u', 'p', 's'), Variant::Type::BOOL, false);760_insert_feature("swash", HB_TAG('s', 'w', 's', 'h'), Variant::Type::INT, false);761_insert_feature("titling", HB_TAG('t', 'i', 't', 'l'), Variant::Type::BOOL, false);762_insert_feature("trailing_jamo_forms", HB_TAG('t', 'j', 'm', 'o'), Variant::Type::INT, true);763_insert_feature("traditional_name_forms", HB_TAG('t', 'n', 'a', 'm'), Variant::Type::INT, false);764_insert_feature("tabular_figures", HB_TAG('t', 'n', 'u', 'm'), Variant::Type::BOOL, false);765_insert_feature("traditional_forms", HB_TAG('t', 'r', 'a', 'd'), Variant::Type::INT, false);766_insert_feature("third_widths", HB_TAG('t', 'w', 'i', 'd'), Variant::Type::BOOL, false);767_insert_feature("unicase", HB_TAG('u', 'n', 'i', 'c'), Variant::Type::BOOL, false);768_insert_feature("alternate_vertical_metrics", HB_TAG('v', 'a', 'l', 't'), Variant::Type::INT, false);769_insert_feature("vattu_variants", HB_TAG('v', 'a', 't', 'u'), Variant::Type::INT, true);770_insert_feature("vertical_contextual_half_width_spacing", HB_TAG('v', 'c', 'h', 'w'), Variant::Type::BOOL, false);771_insert_feature("vertical_alternates", HB_TAG('v', 'e', 'r', 't'), Variant::Type::INT, false);772_insert_feature("alternate_vertical_half_metrics", HB_TAG('v', 'h', 'a', 'l'), Variant::Type::BOOL, false);773_insert_feature("vowel_jamo_forms", HB_TAG('v', 'j', 'm', 'o'), Variant::Type::INT, true);774_insert_feature("vertical_kana_alternates", HB_TAG('v', 'k', 'n', 'a'), Variant::Type::INT, false);775_insert_feature("vertical_kerning", HB_TAG('v', 'k', 'r', 'n'), Variant::Type::BOOL, false);776_insert_feature("proportional_alternate_vertical_metrics", HB_TAG('v', 'p', 'a', 'l'), Variant::Type::BOOL, false);777_insert_feature("vertical_alternates_and_rotation", HB_TAG('v', 'r', 't', '2'), Variant::Type::INT, false);778_insert_feature("vertical_alternates_for_rotation", HB_TAG('v', 'r', 't', 'r'), Variant::Type::INT, false);779_insert_feature("slashed_zero", HB_TAG('z', 'e', 'r', 'o'), Variant::Type::BOOL, false);780781// Registered OpenType variation tag.782_insert_feature("italic", HB_TAG('i', 't', 'a', 'l'), Variant::Type::INT, false);783_insert_feature("optical_size", HB_TAG('o', 'p', 's', 'z'), Variant::Type::INT, false);784_insert_feature("slant", HB_TAG('s', 'l', 'n', 't'), Variant::Type::INT, false);785_insert_feature("width", HB_TAG('w', 'd', 't', 'h'), Variant::Type::INT, false);786_insert_feature("weight", HB_TAG('w', 'g', 'h', 't'), Variant::Type::INT, false);787}788789int64_t TextServerAdvanced::_name_to_tag(const String &p_name) const {790if (feature_sets.has(p_name)) {791return feature_sets[p_name];792}793794// No readable name, use tag string.795return hb_tag_from_string(p_name.replace("custom_", "").ascii().get_data(), -1);796}797798Variant::Type TextServerAdvanced::_get_tag_type(int64_t p_tag) const {799if (feature_sets_inv.has(p_tag)) {800return feature_sets_inv[p_tag].vtype;801}802return Variant::Type::INT;803}804805bool TextServerAdvanced::_get_tag_hidden(int64_t p_tag) const {806if (feature_sets_inv.has(p_tag)) {807return feature_sets_inv[p_tag].hidden;808}809return false;810}811812String TextServerAdvanced::_tag_to_name(int64_t p_tag) const {813if (feature_sets_inv.has(p_tag)) {814return feature_sets_inv[p_tag].name;815}816817// No readable name, use tag string.818char name[5];819memset(name, 0, 5);820hb_tag_to_string(p_tag, name);821return String("custom_") + String(name);822}823824/*************************************************************************/825/* Font Glyph Rendering */826/*************************************************************************/827828_FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_texture_pos_for_glyph(FontForSizeAdvanced *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height, bool p_msdf) const {829FontTexturePosition ret;830831int mw = p_width;832int mh = p_height;833834ShelfPackTexture *ct = p_data->textures.ptrw();835for (int32_t i = 0; i < p_data->textures.size(); i++) {836if (ct[i].image.is_null()) {837continue;838}839if (p_image_format != ct[i].image->get_format()) {840continue;841}842if (mw > ct[i].texture_w || mh > ct[i].texture_h) { // Too big for this texture.843continue;844}845846ret = ct[i].pack_rect(i, mh, mw);847if (ret.index != -1) {848break;849}850}851852if (ret.index == -1) {853// Could not find texture to fit, create one.854int texsize = MAX(p_data->size.x * 0.125, 256);855856texsize = next_power_of_2((uint32_t)texsize);857if (p_msdf) {858texsize = MIN(texsize, 2048);859} else {860texsize = MIN(texsize, 1024);861}862if (mw > texsize) { // Special case, adapt to it?863texsize = next_power_of_2((uint32_t)mw);864}865if (mh > texsize) { // Special case, adapt to it?866texsize = next_power_of_2((uint32_t)mh);867}868869ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);870tex.image = Image::create_empty(texsize, texsize, false, p_image_format);871{872// Zero texture.873uint8_t *w = tex.image->ptrw();874ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.image->get_data_size(), ret);875// Initialize the texture to all-white pixels to prevent artifacts when the876// font is displayed at a non-default scale with filtering enabled.877if (p_color_size == 2) {878for (int i = 0; i < texsize * texsize * p_color_size; i += 2) { // FORMAT_LA8, BW font.879w[i + 0] = 255;880w[i + 1] = 0;881}882} else if (p_color_size == 4) {883for (int i = 0; i < texsize * texsize * p_color_size; i += 4) { // FORMAT_RGBA8, Color font, Multichannel(+True) SDF.884if (p_msdf) {885w[i + 0] = 0;886w[i + 1] = 0;887w[i + 2] = 0;888} else {889w[i + 0] = 255;890w[i + 1] = 255;891w[i + 2] = 255;892}893w[i + 3] = 0;894}895} else {896ERR_FAIL_V(ret);897}898}899p_data->textures.push_back(tex);900901int32_t idx = p_data->textures.size() - 1;902ret = p_data->textures.write[idx].pack_rect(idx, mh, mw);903}904905return ret;906}907908#ifdef MODULE_MSDFGEN_ENABLED909910struct MSContext {911msdfgen::Point2 position;912msdfgen::Shape *shape = nullptr;913msdfgen::Contour *contour = nullptr;914};915916class DistancePixelConversion {917double invRange;918919public:920_FORCE_INLINE_ explicit DistancePixelConversion(double range) :921invRange(1 / range) {}922_FORCE_INLINE_ void operator()(float *pixels, const msdfgen::MultiAndTrueDistance &distance) const {923pixels[0] = float(invRange * distance.r + .5);924pixels[1] = float(invRange * distance.g + .5);925pixels[2] = float(invRange * distance.b + .5);926pixels[3] = float(invRange * distance.a + .5);927}928};929930struct MSDFThreadData {931msdfgen::Bitmap<float, 4> *output;932msdfgen::Shape *shape;933msdfgen::Projection *projection;934DistancePixelConversion *distancePixelConversion;935};936937static msdfgen::Point2 ft_point2(const FT_Vector &vector) {938return msdfgen::Point2(vector.x / 60.0f, vector.y / 60.0f);939}940941static int ft_move_to(const FT_Vector *to, void *user) {942MSContext *context = static_cast<MSContext *>(user);943if (!(context->contour && context->contour->edges.empty())) {944context->contour = &context->shape->addContour();945}946context->position = ft_point2(*to);947return 0;948}949950static int ft_line_to(const FT_Vector *to, void *user) {951MSContext *context = static_cast<MSContext *>(user);952msdfgen::Point2 endpoint = ft_point2(*to);953if (endpoint != context->position) {954context->contour->addEdge(new msdfgen::LinearSegment(context->position, endpoint));955context->position = endpoint;956}957return 0;958}959960static int ft_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) {961MSContext *context = static_cast<MSContext *>(user);962context->contour->addEdge(new msdfgen::QuadraticSegment(context->position, ft_point2(*control), ft_point2(*to)));963context->position = ft_point2(*to);964return 0;965}966967static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) {968MSContext *context = static_cast<MSContext *>(user);969context->contour->addEdge(new msdfgen::CubicSegment(context->position, ft_point2(*control1), ft_point2(*control2), ft_point2(*to)));970context->position = ft_point2(*to);971return 0;972}973974void TextServerAdvanced::_generateMTSDF_threaded(void *p_td, uint32_t p_y) {975MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td);976977msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape);978int row = td->shape->inverseYAxis ? td->output->height() - p_y - 1 : p_y;979for (int col = 0; col < td->output->width(); ++col) {980int x = (p_y % 2) ? td->output->width() - col - 1 : col;981msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, p_y + .5));982msdfgen::MultiAndTrueDistance distance = distanceFinder.distance(p);983td->distancePixelConversion->operator()(td->output->operator()(x, row), distance);984}985}986987_FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(FontAdvanced *p_font_data, FontForSizeAdvanced *p_data, int p_pixel_range, int p_rect_margin, FT_Outline *p_outline, const Vector2 &p_advance) const {988msdfgen::Shape shape;989990shape.contours.clear();991shape.inverseYAxis = false;992993MSContext context = {};994context.shape = &shape;995FT_Outline_Funcs ft_functions;996ft_functions.move_to = &ft_move_to;997ft_functions.line_to = &ft_line_to;998ft_functions.conic_to = &ft_conic_to;999ft_functions.cubic_to = &ft_cubic_to;1000ft_functions.shift = 0;1001ft_functions.delta = 0;10021003int error = FT_Outline_Decompose(p_outline, &ft_functions, &context);1004ERR_FAIL_COND_V_MSG(error, FontGlyph(), "FreeType: Outline decomposition error: '" + String(FT_Error_String(error)) + "'.");1005if (!shape.contours.empty() && shape.contours.back().edges.empty()) {1006shape.contours.pop_back();1007}10081009if (FT_Outline_Get_Orientation(p_outline) == 1) {1010for (int i = 0; i < (int)shape.contours.size(); ++i) {1011shape.contours[i].reverse();1012}1013}10141015shape.inverseYAxis = true;1016shape.normalize();10171018msdfgen::Shape::Bounds bounds = shape.getBounds(p_pixel_range);10191020FontGlyph chr;1021chr.found = true;1022chr.advance = p_advance;10231024if (shape.validate() && shape.contours.size() > 0) {1025int w = (bounds.r - bounds.l);1026int h = (bounds.t - bounds.b);10271028if (w == 0 || h == 0) {1029chr.texture_idx = -1;1030chr.uv_rect = Rect2();1031chr.rect = Rect2();1032return chr;1033}10341035int mw = w + p_rect_margin * 4;1036int mh = h + p_rect_margin * 4;10371038ERR_FAIL_COND_V(mw > 4096, FontGlyph());1039ERR_FAIL_COND_V(mh > 4096, FontGlyph());10401041FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true);1042ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());1043ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];10441045edgeColoringSimple(shape, 3.0); // Max. angle.1046msdfgen::Bitmap<float, 4> image(w, h); // Texture size.10471048DistancePixelConversion distancePixelConversion(p_pixel_range);1049msdfgen::Projection projection(msdfgen::Vector2(1.0, 1.0), msdfgen::Vector2(-bounds.l, -bounds.b));1050msdfgen::MSDFGeneratorConfig config(true, msdfgen::ErrorCorrectionConfig());10511052MSDFThreadData td;1053td.output = ℑ1054td.shape = &shape;1055td.projection = &projection;1056td.distancePixelConversion = &distancePixelConversion;10571058WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_native_group_task(&TextServerAdvanced::_generateMTSDF_threaded, &td, h, -1, true, String("FontServerRasterizeMSDF"));1059WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);10601061msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config);10621063{1064uint8_t *wr = tex.image->ptrw();10651066for (int i = 0; i < h; i++) {1067for (int j = 0; j < w; j++) {1068int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * 4;1069ERR_FAIL_COND_V(ofs >= tex.image->get_data_size(), FontGlyph());1070wr[ofs + 0] = (uint8_t)(CLAMP(image(j, i)[0] * 256.f, 0.f, 255.f));1071wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f));1072wr[ofs + 2] = (uint8_t)(CLAMP(image(j, i)[2] * 256.f, 0.f, 255.f));1073wr[ofs + 3] = (uint8_t)(CLAMP(image(j, i)[3] * 256.f, 0.f, 255.f));1074}1075}1076}10771078tex.dirty = true;10791080chr.texture_idx = tex_pos.index;10811082chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2);1083chr.rect.position = Vector2(bounds.l - p_rect_margin, -bounds.t - p_rect_margin);10841085chr.rect.size = chr.uv_rect.size;1086}1087return chr;1088}1089#endif10901091#ifdef MODULE_FREETYPE_ENABLED1092_FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitmap(FontForSizeAdvanced *p_data, int p_rect_margin, FT_Bitmap p_bitmap, int p_yofs, int p_xofs, const Vector2 &p_advance, bool p_bgra) const {1093FontGlyph chr;1094chr.advance = p_advance * p_data->scale;1095chr.found = true;10961097int w = p_bitmap.width;1098int h = p_bitmap.rows;10991100if (w == 0 || h == 0) {1101chr.texture_idx = -1;1102chr.uv_rect = Rect2();1103chr.rect = Rect2();1104return chr;1105}11061107int color_size = 2;11081109switch (p_bitmap.pixel_mode) {1110case FT_PIXEL_MODE_MONO:1111case FT_PIXEL_MODE_GRAY: {1112color_size = 2;1113} break;1114case FT_PIXEL_MODE_BGRA: {1115color_size = 4;1116} break;1117case FT_PIXEL_MODE_LCD: {1118color_size = 4;1119w /= 3;1120} break;1121case FT_PIXEL_MODE_LCD_V: {1122color_size = 4;1123h /= 3;1124} break;1125}11261127int mw = w + p_rect_margin * 4;1128int mh = h + p_rect_margin * 4;11291130ERR_FAIL_COND_V(mw > 4096, FontGlyph());1131ERR_FAIL_COND_V(mh > 4096, FontGlyph());11321133Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;11341135FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh, false);1136ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());11371138// Fit character in char texture.1139ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];11401141{1142uint8_t *wr = tex.image->ptrw();11431144for (int i = 0; i < h; i++) {1145for (int j = 0; j < w; j++) {1146int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * color_size;1147ERR_FAIL_COND_V(ofs >= tex.image->get_data_size(), FontGlyph());1148switch (p_bitmap.pixel_mode) {1149case FT_PIXEL_MODE_MONO: {1150int byte = i * p_bitmap.pitch + (j >> 3);1151int bit = 1 << (7 - (j % 8));1152wr[ofs + 0] = 255; // grayscale as 11153wr[ofs + 1] = (p_bitmap.buffer[byte] & bit) ? 255 : 0;1154} break;1155case FT_PIXEL_MODE_GRAY:1156wr[ofs + 0] = 255; // grayscale as 11157wr[ofs + 1] = p_bitmap.buffer[i * p_bitmap.pitch + j];1158break;1159case FT_PIXEL_MODE_BGRA: {1160int ofs_color = i * p_bitmap.pitch + (j << 2);1161wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];1162wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];1163wr[ofs + 0] = p_bitmap.buffer[ofs_color + 2];1164wr[ofs + 3] = p_bitmap.buffer[ofs_color + 3];1165} break;1166case FT_PIXEL_MODE_LCD: {1167int ofs_color = i * p_bitmap.pitch + (j * 3);1168if (p_bgra) {1169wr[ofs + 0] = p_bitmap.buffer[ofs_color + 2];1170wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];1171wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];1172wr[ofs + 3] = 255;1173} else {1174wr[ofs + 0] = p_bitmap.buffer[ofs_color + 0];1175wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];1176wr[ofs + 2] = p_bitmap.buffer[ofs_color + 2];1177wr[ofs + 3] = 255;1178}1179} break;1180case FT_PIXEL_MODE_LCD_V: {1181int ofs_color = i * p_bitmap.pitch * 3 + j;1182if (p_bgra) {1183wr[ofs + 0] = p_bitmap.buffer[ofs_color + p_bitmap.pitch * 2];1184wr[ofs + 1] = p_bitmap.buffer[ofs_color + p_bitmap.pitch];1185wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];1186wr[ofs + 3] = 255;1187} else {1188wr[ofs + 0] = p_bitmap.buffer[ofs_color + 0];1189wr[ofs + 1] = p_bitmap.buffer[ofs_color + p_bitmap.pitch];1190wr[ofs + 2] = p_bitmap.buffer[ofs_color + p_bitmap.pitch * 2];1191wr[ofs + 3] = 255;1192}1193} break;1194default:1195ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + String::num_int64(p_bitmap.pixel_mode) + ".");1196break;1197}1198}1199}1200}12011202tex.dirty = true;12031204chr.texture_idx = tex_pos.index;12051206chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2);1207chr.rect.position = Vector2(p_xofs - p_rect_margin, -p_yofs - p_rect_margin) * p_data->scale;1208chr.rect.size = chr.uv_rect.size * p_data->scale;1209return chr;1210}1211#endif12121213/*************************************************************************/1214/* Font Cache */1215/*************************************************************************/12161217bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph, FontGlyph &r_glyph, uint32_t p_oversampling) const {1218FontForSizeAdvanced *fd = nullptr;1219ERR_FAIL_COND_V(!_ensure_cache_for_size(p_font_data, p_size, fd, false, p_oversampling), false);12201221int32_t glyph_index = p_glyph & 0xffffff; // Remove subpixel shifts.12221223HashMap<int32_t, FontGlyph>::Iterator E = fd->glyph_map.find(p_glyph);1224if (E) {1225r_glyph = E->value;1226return E->value.found;1227}12281229if (glyph_index == 0) { // Non graphical or invalid glyph, do not render.1230E = fd->glyph_map.insert(p_glyph, FontGlyph());1231r_glyph = E->value;1232return true;1233}12341235#ifdef MODULE_FREETYPE_ENABLED1236FontGlyph gl;1237if (fd->face) {1238FT_Int32 flags = FT_LOAD_DEFAULT;12391240bool outline = p_size.y > 0;1241switch (p_font_data->hinting) {1242case TextServer::HINTING_NONE:1243flags |= FT_LOAD_NO_HINTING;1244break;1245case TextServer::HINTING_LIGHT:1246flags |= FT_LOAD_TARGET_LIGHT;1247break;1248default:1249flags |= FT_LOAD_TARGET_NORMAL;1250break;1251}1252if (p_font_data->force_autohinter) {1253flags |= FT_LOAD_FORCE_AUTOHINT;1254}1255if (outline || (p_font_data->disable_embedded_bitmaps && !FT_HAS_COLOR(fd->face))) {1256flags |= FT_LOAD_NO_BITMAP;1257} else if (FT_HAS_COLOR(fd->face)) {1258flags |= FT_LOAD_COLOR;1259}12601261FT_Fixed v, h;1262FT_Get_Advance(fd->face, glyph_index, flags, &h);1263FT_Get_Advance(fd->face, glyph_index, flags | FT_LOAD_VERTICAL_LAYOUT, &v);12641265int error = FT_Load_Glyph(fd->face, glyph_index, flags);1266if (error) {1267E = fd->glyph_map.insert(p_glyph, FontGlyph());1268r_glyph = E->value;1269return false;1270}12711272if (!p_font_data->msdf) {1273if ((p_font_data->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (p_font_data->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && p_size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {1274FT_Pos xshift = (int)((p_glyph >> 27) & 3) << 4;1275FT_Outline_Translate(&fd->face->glyph->outline, xshift, 0);1276} else if ((p_font_data->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (p_font_data->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && p_size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {1277FT_Pos xshift = (int)((p_glyph >> 27) & 3) << 5;1278FT_Outline_Translate(&fd->face->glyph->outline, xshift, 0);1279}1280}12811282if (p_font_data->embolden != 0.f) {1283FT_Pos strength = p_font_data->embolden * p_size.x / 16; // 26.6 fractional units (1 / 64).1284FT_Outline_Embolden(&fd->face->glyph->outline, strength);1285}12861287if (p_font_data->transform != Transform2D()) {1288FT_Matrix mat = { FT_Fixed(p_font_data->transform[0][0] * 65536), FT_Fixed(p_font_data->transform[0][1] * 65536), FT_Fixed(p_font_data->transform[1][0] * 65536), FT_Fixed(p_font_data->transform[1][1] * 65536) }; // 16.16 fractional units (1 / 65536).1289FT_Outline_Transform(&fd->face->glyph->outline, &mat);1290}12911292FT_Render_Mode aa_mode = FT_RENDER_MODE_NORMAL;1293bool bgra = false;1294switch (p_font_data->antialiasing) {1295case FONT_ANTIALIASING_NONE: {1296aa_mode = FT_RENDER_MODE_MONO;1297} break;1298case FONT_ANTIALIASING_GRAY: {1299aa_mode = FT_RENDER_MODE_NORMAL;1300} break;1301case FONT_ANTIALIASING_LCD: {1302int aa_layout = (int)((p_glyph >> 24) & 7);1303switch (aa_layout) {1304case FONT_LCD_SUBPIXEL_LAYOUT_HRGB: {1305aa_mode = FT_RENDER_MODE_LCD;1306bgra = false;1307} break;1308case FONT_LCD_SUBPIXEL_LAYOUT_HBGR: {1309aa_mode = FT_RENDER_MODE_LCD;1310bgra = true;1311} break;1312case FONT_LCD_SUBPIXEL_LAYOUT_VRGB: {1313aa_mode = FT_RENDER_MODE_LCD_V;1314bgra = false;1315} break;1316case FONT_LCD_SUBPIXEL_LAYOUT_VBGR: {1317aa_mode = FT_RENDER_MODE_LCD_V;1318bgra = true;1319} break;1320default: {1321aa_mode = FT_RENDER_MODE_NORMAL;1322} break;1323}1324} break;1325}13261327FT_GlyphSlot slot = fd->face->glyph;1328bool from_svg = (slot->format == FT_GLYPH_FORMAT_SVG); // Need to check before FT_Render_Glyph as it will change format to bitmap.1329if (!outline) {1330if (!p_font_data->msdf) {1331error = FT_Render_Glyph(slot, aa_mode);1332}1333if (!error) {1334if (p_font_data->msdf) {1335#ifdef MODULE_MSDFGEN_ENABLED1336gl = rasterize_msdf(p_font_data, fd, p_font_data->msdf_range, rect_range, &slot->outline, Vector2((h + (1 << 9)) >> 10, (v + (1 << 9)) >> 10) / 64.0);1337#else1338fd->glyph_map[p_glyph] = FontGlyph();1339ERR_FAIL_V_MSG(false, "Compiled without MSDFGEN support!");1340#endif1341} else {1342gl = rasterize_bitmap(fd, rect_range, slot->bitmap, slot->bitmap_top, slot->bitmap_left, Vector2((h + (1 << 9)) >> 10, (v + (1 << 9)) >> 10) / 64.0, bgra);1343}1344}1345} else {1346FT_Stroker stroker;1347if (FT_Stroker_New(ft_library, &stroker) != 0) {1348fd->glyph_map[p_glyph] = FontGlyph();1349ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph stroker.");1350}13511352FT_Stroker_Set(stroker, (int)(fd->size.y * 16.0), FT_STROKER_LINECAP_BUTT, FT_STROKER_LINEJOIN_ROUND, 0);1353FT_Glyph glyph;1354FT_BitmapGlyph glyph_bitmap;13551356if (FT_Get_Glyph(fd->face->glyph, &glyph) != 0) {1357goto cleanup_stroker;1358}1359if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0) {1360goto cleanup_glyph;1361}1362if (FT_Glyph_To_Bitmap(&glyph, aa_mode, nullptr, 1) != 0) {1363goto cleanup_glyph;1364}1365glyph_bitmap = (FT_BitmapGlyph)glyph;1366gl = rasterize_bitmap(fd, rect_range, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2(), bgra);13671368cleanup_glyph:1369FT_Done_Glyph(glyph);1370cleanup_stroker:1371FT_Stroker_Done(stroker);1372}1373gl.from_svg = from_svg;1374E = fd->glyph_map.insert(p_glyph, gl);1375r_glyph = E->value;1376return gl.found;1377}1378#endif1379E = fd->glyph_map.insert(p_glyph, FontGlyph());1380r_glyph = E->value;1381return false;1382}13831384bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_font_data, const Vector2i &p_size, FontForSizeAdvanced *&r_cache_for_size, bool p_silent, uint32_t p_oversampling) const {1385ERR_FAIL_COND_V(p_size.x <= 0, false);13861387HashMap<Vector2i, FontForSizeAdvanced *>::Iterator E = p_font_data->cache.find(p_size);1388if (E) {1389r_cache_for_size = E->value;1390// Size used directly, remove from oversampling list.1391if (p_oversampling == 0 && E->value->viewport_oversampling != 0) {1392OversamplingLevel *ol = oversampling_levels.getptr(E->value->viewport_oversampling);1393if (ol) {1394ol->fonts.erase(E->value);1395}1396}1397return true;1398}13991400FontForSizeAdvanced *fd = memnew(FontForSizeAdvanced);1401fd->size = p_size;1402if (p_font_data->data_ptr && (p_font_data->data_size > 0)) {1403// Init dynamic font.1404#ifdef MODULE_FREETYPE_ENABLED1405int error = 0;1406{1407MutexLock ftlock(ft_mutex);1408if (!ft_library) {1409error = FT_Init_FreeType(&ft_library);1410if (error != 0) {1411memdelete(fd);1412if (p_silent) {1413return false;1414} else {1415ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");1416}1417}1418#ifdef MODULE_SVG_ENABLED1419FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks());1420#endif1421}14221423memset(&fd->stream, 0, sizeof(FT_StreamRec));1424fd->stream.base = (unsigned char *)p_font_data->data_ptr;1425fd->stream.size = p_font_data->data_size;1426fd->stream.pos = 0;14271428FT_Open_Args fargs;1429memset(&fargs, 0, sizeof(FT_Open_Args));1430fargs.memory_base = (unsigned char *)p_font_data->data_ptr;1431fargs.memory_size = p_font_data->data_size;1432fargs.flags = FT_OPEN_MEMORY;1433fargs.stream = &fd->stream;14341435error = FT_Open_Face(ft_library, &fargs, p_font_data->face_index, &fd->face);1436if (error) {1437if (fd->face) {1438FT_Done_Face(fd->face);1439fd->face = nullptr;1440}1441memdelete(fd);1442if (p_silent) {1443return false;1444} else {1445ERR_FAIL_V_MSG(false, "FreeType: Error loading font: '" + String(FT_Error_String(error)) + "' (face_index=" + String::num_int64(p_font_data->face_index) + ").");1446}1447}1448}14491450double sz = double(fd->size.x) / 64.0;1451if (p_font_data->msdf) {1452sz = p_font_data->msdf_source_size;1453}14541455if (FT_HAS_COLOR(fd->face) && fd->face->num_fixed_sizes > 0) {1456int best_match = 0;1457int diff = Math::abs(sz - ((int64_t)fd->face->available_sizes[0].width));1458fd->scale = sz / fd->face->available_sizes[0].width;1459for (int i = 1; i < fd->face->num_fixed_sizes; i++) {1460int ndiff = Math::abs(sz - ((int64_t)fd->face->available_sizes[i].width));1461if (ndiff < diff) {1462best_match = i;1463diff = ndiff;1464fd->scale = sz / fd->face->available_sizes[i].width;1465}1466}1467FT_Select_Size(fd->face, best_match);1468} else {1469FT_Size_RequestRec req;1470req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;1471req.width = sz * 64.0;1472req.height = sz * 64.0;1473req.horiResolution = 0;1474req.vertResolution = 0;14751476FT_Request_Size(fd->face, &req);1477if (fd->face->size->metrics.y_ppem != 0) {1478fd->scale = sz / (double)fd->face->size->metrics.y_ppem;1479}1480}14811482fd->hb_handle = hb_ft_font_create(fd->face, nullptr);14831484fd->ascent = (fd->face->size->metrics.ascender / 64.0) * fd->scale;1485fd->descent = (-fd->face->size->metrics.descender / 64.0) * fd->scale;1486fd->underline_position = (-FT_MulFix(fd->face->underline_position, fd->face->size->metrics.y_scale) / 64.0) * fd->scale;1487fd->underline_thickness = (FT_MulFix(fd->face->underline_thickness, fd->face->size->metrics.y_scale) / 64.0) * fd->scale;14881489#if HB_VERSION_ATLEAST(3, 3, 0)1490hb_font_set_synthetic_slant(fd->hb_handle, p_font_data->transform[0][1]);1491#else1492#ifndef _MSC_VER1493#warning Building with HarfBuzz < 3.3.0, synthetic slant offset correction disabled.1494#endif1495#endif14961497if (!p_font_data->face_init) {1498// When a font does not provide a `family_name`, FreeType tries to synthesize one based on other names.1499// FreeType automatically converts non-ASCII characters to "?" in the synthesized name.1500// To avoid that behavior, use the format-specific name directly if available.1501hb_face_t *hb_face = hb_font_get_face(fd->hb_handle);1502unsigned int num_entries = 0;1503const hb_ot_name_entry_t *names = hb_ot_name_list_names(hb_face, &num_entries);1504const hb_language_t english = hb_language_from_string("en", -1);1505for (unsigned int i = 0; i < num_entries; i++) {1506if (names[i].name_id != HB_OT_NAME_ID_FONT_FAMILY) {1507continue;1508}1509if (!p_font_data->font_name.is_empty() && names[i].language != english) {1510continue;1511}1512unsigned int text_size = hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, nullptr, nullptr) + 1;1513p_font_data->font_name.resize_uninitialized(text_size);1514hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, &text_size, (uint32_t *)p_font_data->font_name.ptrw());1515}1516if (p_font_data->font_name.is_empty() && fd->face->family_name != nullptr) {1517p_font_data->font_name = String::utf8((const char *)fd->face->family_name);1518}1519if (fd->face->style_name != nullptr) {1520p_font_data->style_name = String::utf8((const char *)fd->face->style_name);1521}1522p_font_data->weight = _font_get_weight_by_name(p_font_data->style_name.to_lower());1523p_font_data->stretch = _font_get_stretch_by_name(p_font_data->style_name.to_lower());1524p_font_data->style_flags = 0;1525if ((fd->face->style_flags & FT_STYLE_FLAG_BOLD) || p_font_data->weight >= 700) {1526p_font_data->style_flags.set_flag(FONT_BOLD);1527}1528if ((fd->face->style_flags & FT_STYLE_FLAG_ITALIC) || _is_ital_style(p_font_data->style_name.to_lower())) {1529p_font_data->style_flags.set_flag(FONT_ITALIC);1530}1531if (fd->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) {1532p_font_data->style_flags.set_flag(FONT_FIXED_WIDTH);1533}15341535// Get supported scripts from OpenType font data.1536p_font_data->supported_scripts.clear();1537unsigned int count = hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, nullptr, nullptr);1538if (count != 0) {1539hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));1540hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, &count, script_tags);1541for (unsigned int i = 0; i < count; i++) {1542p_font_data->supported_scripts.insert(script_tags[i]);1543}1544memfree(script_tags);1545}1546count = hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GPOS, 0, nullptr, nullptr);1547if (count != 0) {1548hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));1549hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GPOS, 0, &count, script_tags);1550for (unsigned int i = 0; i < count; i++) {1551p_font_data->supported_scripts.insert(script_tags[i]);1552}1553memfree(script_tags);1554}15551556// Get supported scripts from OS2 table.1557TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(fd->face, FT_SFNT_OS2);1558if (os2) {1559if ((os2->ulUnicodeRange1 & 1L << 4) || (os2->ulUnicodeRange1 & 1L << 5) || (os2->ulUnicodeRange1 & 1L << 6) || (os2->ulUnicodeRange1 & 1L << 31) || (os2->ulUnicodeRange2 & 1L << 0) || (os2->ulUnicodeRange2 & 1L << 1) || (os2->ulUnicodeRange2 & 1L << 2) || (os2->ulUnicodeRange2 & 1L << 3) || (os2->ulUnicodeRange2 & 1L << 4) || (os2->ulUnicodeRange2 & 1L << 5) || (os2->ulUnicodeRange2 & 1L << 6) || (os2->ulUnicodeRange2 & 1L << 7) || (os2->ulUnicodeRange2 & 1L << 8) || (os2->ulUnicodeRange2 & 1L << 9) || (os2->ulUnicodeRange2 & 1L << 10) || (os2->ulUnicodeRange2 & 1L << 11) || (os2->ulUnicodeRange2 & 1L << 12) || (os2->ulUnicodeRange2 & 1L << 13) || (os2->ulUnicodeRange2 & 1L << 14) || (os2->ulUnicodeRange2 & 1L << 15) || (os2->ulUnicodeRange2 & 1L << 30) || (os2->ulUnicodeRange3 & 1L << 0) || (os2->ulUnicodeRange3 & 1L << 1) || (os2->ulUnicodeRange3 & 1L << 2) || (os2->ulUnicodeRange3 & 1L << 4) || (os2->ulUnicodeRange3 & 1L << 5) || (os2->ulUnicodeRange3 & 1L << 18) || (os2->ulUnicodeRange3 & 1L << 24) || (os2->ulUnicodeRange3 & 1L << 25) || (os2->ulUnicodeRange3 & 1L << 26) || (os2->ulUnicodeRange3 & 1L << 27) || (os2->ulUnicodeRange3 & 1L << 28) || (os2->ulUnicodeRange4 & 1L << 3) || (os2->ulUnicodeRange4 & 1L << 6) || (os2->ulUnicodeRange4 & 1L << 15) || (os2->ulUnicodeRange4 & 1L << 23) || (os2->ulUnicodeRange4 & 1L << 24) || (os2->ulUnicodeRange4 & 1L << 26)) {1560p_font_data->supported_scripts.insert(HB_SCRIPT_COMMON);1561}1562if ((os2->ulUnicodeRange1 & 1L << 0) || (os2->ulUnicodeRange1 & 1L << 1) || (os2->ulUnicodeRange1 & 1L << 2) || (os2->ulUnicodeRange1 & 1L << 3) || (os2->ulUnicodeRange1 & 1L << 29)) {1563p_font_data->supported_scripts.insert(HB_SCRIPT_LATIN);1564}1565if ((os2->ulUnicodeRange1 & 1L << 7) || (os2->ulUnicodeRange1 & 1L << 30)) {1566p_font_data->supported_scripts.insert(HB_SCRIPT_GREEK);1567}1568if (os2->ulUnicodeRange1 & 1L << 8) {1569p_font_data->supported_scripts.insert(HB_SCRIPT_COPTIC);1570}1571if (os2->ulUnicodeRange1 & 1L << 9) {1572p_font_data->supported_scripts.insert(HB_SCRIPT_CYRILLIC);1573}1574if (os2->ulUnicodeRange1 & 1L << 10) {1575p_font_data->supported_scripts.insert(HB_SCRIPT_ARMENIAN);1576}1577if (os2->ulUnicodeRange1 & 1L << 11) {1578p_font_data->supported_scripts.insert(HB_SCRIPT_HEBREW);1579}1580if (os2->ulUnicodeRange1 & 1L << 12) {1581p_font_data->supported_scripts.insert(HB_SCRIPT_VAI);1582}1583if ((os2->ulUnicodeRange1 & 1L << 13) || (os2->ulUnicodeRange2 & 1L << 31) || (os2->ulUnicodeRange3 & 1L << 3)) {1584p_font_data->supported_scripts.insert(HB_SCRIPT_ARABIC);1585}1586if (os2->ulUnicodeRange1 & 1L << 14) {1587p_font_data->supported_scripts.insert(HB_SCRIPT_NKO);1588}1589if (os2->ulUnicodeRange1 & 1L << 15) {1590p_font_data->supported_scripts.insert(HB_SCRIPT_DEVANAGARI);1591}1592if (os2->ulUnicodeRange1 & 1L << 16) {1593p_font_data->supported_scripts.insert(HB_SCRIPT_BENGALI);1594}1595if (os2->ulUnicodeRange1 & 1L << 17) {1596p_font_data->supported_scripts.insert(HB_SCRIPT_GURMUKHI);1597}1598if (os2->ulUnicodeRange1 & 1L << 18) {1599p_font_data->supported_scripts.insert(HB_SCRIPT_GUJARATI);1600}1601if (os2->ulUnicodeRange1 & 1L << 19) {1602p_font_data->supported_scripts.insert(HB_SCRIPT_ORIYA);1603}1604if (os2->ulUnicodeRange1 & 1L << 20) {1605p_font_data->supported_scripts.insert(HB_SCRIPT_TAMIL);1606}1607if (os2->ulUnicodeRange1 & 1L << 21) {1608p_font_data->supported_scripts.insert(HB_SCRIPT_TELUGU);1609}1610if (os2->ulUnicodeRange1 & 1L << 22) {1611p_font_data->supported_scripts.insert(HB_SCRIPT_KANNADA);1612}1613if (os2->ulUnicodeRange1 & 1L << 23) {1614p_font_data->supported_scripts.insert(HB_SCRIPT_MALAYALAM);1615}1616if (os2->ulUnicodeRange1 & 1L << 24) {1617p_font_data->supported_scripts.insert(HB_SCRIPT_THAI);1618}1619if (os2->ulUnicodeRange1 & 1L << 25) {1620p_font_data->supported_scripts.insert(HB_SCRIPT_LAO);1621}1622if (os2->ulUnicodeRange1 & 1L << 26) {1623p_font_data->supported_scripts.insert(HB_SCRIPT_GEORGIAN);1624}1625if (os2->ulUnicodeRange1 & 1L << 27) {1626p_font_data->supported_scripts.insert(HB_SCRIPT_BALINESE);1627}1628if ((os2->ulUnicodeRange1 & 1L << 28) || (os2->ulUnicodeRange2 & 1L << 20) || (os2->ulUnicodeRange2 & 1L << 24)) {1629p_font_data->supported_scripts.insert(HB_SCRIPT_HANGUL);1630}1631if ((os2->ulUnicodeRange2 & 1L << 21) || (os2->ulUnicodeRange2 & 1L << 22) || (os2->ulUnicodeRange2 & 1L << 23) || (os2->ulUnicodeRange2 & 1L << 26) || (os2->ulUnicodeRange2 & 1L << 27) || (os2->ulUnicodeRange2 & 1L << 29)) {1632p_font_data->supported_scripts.insert(HB_SCRIPT_HAN);1633}1634if (os2->ulUnicodeRange2 & 1L << 17) {1635p_font_data->supported_scripts.insert(HB_SCRIPT_HIRAGANA);1636}1637if (os2->ulUnicodeRange2 & 1L << 18) {1638p_font_data->supported_scripts.insert(HB_SCRIPT_KATAKANA);1639}1640if (os2->ulUnicodeRange2 & 1L << 19) {1641p_font_data->supported_scripts.insert(HB_SCRIPT_BOPOMOFO);1642}1643if (os2->ulUnicodeRange3 & 1L << 6) {1644p_font_data->supported_scripts.insert(HB_SCRIPT_TIBETAN);1645}1646if (os2->ulUnicodeRange3 & 1L << 7) {1647p_font_data->supported_scripts.insert(HB_SCRIPT_SYRIAC);1648}1649if (os2->ulUnicodeRange3 & 1L << 8) {1650p_font_data->supported_scripts.insert(HB_SCRIPT_THAANA);1651}1652if (os2->ulUnicodeRange3 & 1L << 9) {1653p_font_data->supported_scripts.insert(HB_SCRIPT_SINHALA);1654}1655if (os2->ulUnicodeRange3 & 1L << 10) {1656p_font_data->supported_scripts.insert(HB_SCRIPT_MYANMAR);1657}1658if (os2->ulUnicodeRange3 & 1L << 11) {1659p_font_data->supported_scripts.insert(HB_SCRIPT_ETHIOPIC);1660}1661if (os2->ulUnicodeRange3 & 1L << 12) {1662p_font_data->supported_scripts.insert(HB_SCRIPT_CHEROKEE);1663}1664if (os2->ulUnicodeRange3 & 1L << 13) {1665p_font_data->supported_scripts.insert(HB_SCRIPT_CANADIAN_SYLLABICS);1666}1667if (os2->ulUnicodeRange3 & 1L << 14) {1668p_font_data->supported_scripts.insert(HB_SCRIPT_OGHAM);1669}1670if (os2->ulUnicodeRange3 & 1L << 15) {1671p_font_data->supported_scripts.insert(HB_SCRIPT_RUNIC);1672}1673if (os2->ulUnicodeRange3 & 1L << 16) {1674p_font_data->supported_scripts.insert(HB_SCRIPT_KHMER);1675}1676if (os2->ulUnicodeRange3 & 1L << 17) {1677p_font_data->supported_scripts.insert(HB_SCRIPT_MONGOLIAN);1678}1679if (os2->ulUnicodeRange3 & 1L << 19) {1680p_font_data->supported_scripts.insert(HB_SCRIPT_YI);1681}1682if (os2->ulUnicodeRange3 & 1L << 20) {1683p_font_data->supported_scripts.insert(HB_SCRIPT_HANUNOO);1684p_font_data->supported_scripts.insert(HB_SCRIPT_TAGBANWA);1685p_font_data->supported_scripts.insert(HB_SCRIPT_BUHID);1686p_font_data->supported_scripts.insert(HB_SCRIPT_TAGALOG);1687}1688if (os2->ulUnicodeRange3 & 1L << 21) {1689p_font_data->supported_scripts.insert(HB_SCRIPT_OLD_ITALIC);1690}1691if (os2->ulUnicodeRange3 & 1L << 22) {1692p_font_data->supported_scripts.insert(HB_SCRIPT_GOTHIC);1693}1694if (os2->ulUnicodeRange3 & 1L << 23) {1695p_font_data->supported_scripts.insert(HB_SCRIPT_DESERET);1696}1697if (os2->ulUnicodeRange3 & 1L << 29) {1698p_font_data->supported_scripts.insert(HB_SCRIPT_LIMBU);1699}1700if (os2->ulUnicodeRange3 & 1L << 30) {1701p_font_data->supported_scripts.insert(HB_SCRIPT_TAI_LE);1702}1703if (os2->ulUnicodeRange3 & 1L << 31) {1704p_font_data->supported_scripts.insert(HB_SCRIPT_NEW_TAI_LUE);1705}1706if (os2->ulUnicodeRange4 & 1L << 0) {1707p_font_data->supported_scripts.insert(HB_SCRIPT_BUGINESE);1708}1709if (os2->ulUnicodeRange4 & 1L << 1) {1710p_font_data->supported_scripts.insert(HB_SCRIPT_GLAGOLITIC);1711}1712if (os2->ulUnicodeRange4 & 1L << 2) {1713p_font_data->supported_scripts.insert(HB_SCRIPT_TIFINAGH);1714}1715if (os2->ulUnicodeRange4 & 1L << 4) {1716p_font_data->supported_scripts.insert(HB_SCRIPT_SYLOTI_NAGRI);1717}1718if (os2->ulUnicodeRange4 & 1L << 5) {1719p_font_data->supported_scripts.insert(HB_SCRIPT_LINEAR_B);1720}1721if (os2->ulUnicodeRange4 & 1L << 7) {1722p_font_data->supported_scripts.insert(HB_SCRIPT_UGARITIC);1723}1724if (os2->ulUnicodeRange4 & 1L << 8) {1725p_font_data->supported_scripts.insert(HB_SCRIPT_OLD_PERSIAN);1726}1727if (os2->ulUnicodeRange4 & 1L << 9) {1728p_font_data->supported_scripts.insert(HB_SCRIPT_SHAVIAN);1729}1730if (os2->ulUnicodeRange4 & 1L << 10) {1731p_font_data->supported_scripts.insert(HB_SCRIPT_OSMANYA);1732}1733if (os2->ulUnicodeRange4 & 1L << 11) {1734p_font_data->supported_scripts.insert(HB_SCRIPT_CYPRIOT);1735}1736if (os2->ulUnicodeRange4 & 1L << 12) {1737p_font_data->supported_scripts.insert(HB_SCRIPT_KHAROSHTHI);1738}1739if (os2->ulUnicodeRange4 & 1L << 13) {1740p_font_data->supported_scripts.insert(HB_SCRIPT_TAI_VIET);1741}1742if (os2->ulUnicodeRange4 & 1L << 14) {1743p_font_data->supported_scripts.insert(HB_SCRIPT_CUNEIFORM);1744}1745if (os2->ulUnicodeRange4 & 1L << 16) {1746p_font_data->supported_scripts.insert(HB_SCRIPT_SUNDANESE);1747}1748if (os2->ulUnicodeRange4 & 1L << 17) {1749p_font_data->supported_scripts.insert(HB_SCRIPT_LEPCHA);1750}1751if (os2->ulUnicodeRange4 & 1L << 18) {1752p_font_data->supported_scripts.insert(HB_SCRIPT_OL_CHIKI);1753}1754if (os2->ulUnicodeRange4 & 1L << 19) {1755p_font_data->supported_scripts.insert(HB_SCRIPT_SAURASHTRA);1756}1757if (os2->ulUnicodeRange4 & 1L << 20) {1758p_font_data->supported_scripts.insert(HB_SCRIPT_KAYAH_LI);1759}1760if (os2->ulUnicodeRange4 & 1L << 21) {1761p_font_data->supported_scripts.insert(HB_SCRIPT_REJANG);1762}1763if (os2->ulUnicodeRange4 & 1L << 22) {1764p_font_data->supported_scripts.insert(HB_SCRIPT_CHAM);1765}1766if (os2->ulUnicodeRange4 & 1L << 25) {1767p_font_data->supported_scripts.insert(HB_SCRIPT_ANATOLIAN_HIEROGLYPHS);1768}1769}17701771// Validate script sample strings.1772{1773LocalVector<uint32_t> failed_scripts;17741775Vector<UChar> sample_buf;1776sample_buf.resize(255);1777for (const uint32_t &scr_tag : p_font_data->supported_scripts) {1778if ((hb_script_t)scr_tag == HB_SCRIPT_COMMON) {1779continue;1780}1781UErrorCode icu_err = U_ZERO_ERROR;1782int32_t len = uscript_getSampleString(hb_icu_script_from_script((hb_script_t)scr_tag), sample_buf.ptrw(), 255, &icu_err);1783if (U_SUCCESS(icu_err) && len > 0) {1784String sample = String::utf16(sample_buf.ptr(), len);1785for (int ch = 0; ch < sample.length(); ch++) {1786if (FT_Get_Char_Index(fd->face, sample[ch]) == 0) {1787failed_scripts.push_back(scr_tag);1788break;1789}1790}1791}1792}1793for (const uint32_t &scr_tag : failed_scripts) {1794p_font_data->supported_scripts.erase(scr_tag);1795}1796}17971798// Read OpenType feature tags.1799p_font_data->supported_features.clear();1800count = hb_ot_layout_table_get_feature_tags(hb_face, HB_OT_TAG_GSUB, 0, nullptr, nullptr);1801if (count != 0) {1802hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));1803hb_ot_layout_table_get_feature_tags(hb_face, HB_OT_TAG_GSUB, 0, &count, feature_tags);1804for (unsigned int i = 0; i < count; i++) {1805Dictionary ftr;18061807#if HB_VERSION_ATLEAST(2, 1, 0)1808hb_ot_name_id_t lbl_id;1809if (hb_ot_layout_feature_get_name_ids(hb_face, HB_OT_TAG_GSUB, i, &lbl_id, nullptr, nullptr, nullptr, nullptr)) {1810PackedInt32Array lbl;1811unsigned int text_size = hb_ot_name_get_utf32(hb_face, lbl_id, hb_language_from_string(TranslationServer::get_singleton()->get_tool_locale().ascii().get_data(), -1), nullptr, nullptr) + 1;1812lbl.resize(text_size);1813memset((uint32_t *)lbl.ptrw(), 0, sizeof(uint32_t) * text_size);1814hb_ot_name_get_utf32(hb_face, lbl_id, hb_language_from_string(TranslationServer::get_singleton()->get_tool_locale().ascii().get_data(), -1), &text_size, (uint32_t *)lbl.ptrw());1815ftr["label"] = String((const char32_t *)lbl.ptr());1816}1817#else1818#ifndef _MSC_VER1819#warning Building with HarfBuzz < 2.1.0, readable OpenType feature names disabled.1820#endif1821#endif1822ftr["type"] = _get_tag_type(feature_tags[i]);1823ftr["hidden"] = _get_tag_hidden(feature_tags[i]);18241825p_font_data->supported_features[feature_tags[i]] = ftr;1826}1827memfree(feature_tags);1828}1829count = hb_ot_layout_table_get_feature_tags(hb_face, HB_OT_TAG_GPOS, 0, nullptr, nullptr);1830if (count != 0) {1831hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));1832hb_ot_layout_table_get_feature_tags(hb_face, HB_OT_TAG_GPOS, 0, &count, feature_tags);1833for (unsigned int i = 0; i < count; i++) {1834Dictionary ftr;18351836#if HB_VERSION_ATLEAST(2, 1, 0)1837hb_ot_name_id_t lbl_id;1838if (hb_ot_layout_feature_get_name_ids(hb_face, HB_OT_TAG_GPOS, i, &lbl_id, nullptr, nullptr, nullptr, nullptr)) {1839PackedInt32Array lbl;1840unsigned int text_size = hb_ot_name_get_utf32(hb_face, lbl_id, hb_language_from_string(TranslationServer::get_singleton()->get_tool_locale().ascii().get_data(), -1), nullptr, nullptr) + 1;1841lbl.resize(text_size);1842memset((uint32_t *)lbl.ptrw(), 0, sizeof(uint32_t) * text_size);1843hb_ot_name_get_utf32(hb_face, lbl_id, hb_language_from_string(TranslationServer::get_singleton()->get_tool_locale().ascii().get_data(), -1), &text_size, (uint32_t *)lbl.ptrw());1844ftr["label"] = String((const char32_t *)lbl.ptr());1845}1846#else1847#ifndef _MSC_VER1848#warning Building with HarfBuzz < 2.1.0, readable OpenType feature names disabled.1849#endif1850#endif1851ftr["type"] = _get_tag_type(feature_tags[i]);1852ftr["hidden"] = _get_tag_hidden(feature_tags[i]);18531854p_font_data->supported_features[feature_tags[i]] = ftr;1855}1856memfree(feature_tags);1857}18581859// Read OpenType variations.1860p_font_data->supported_varaitions.clear();1861if (fd->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {1862FT_MM_Var *amaster;1863FT_Get_MM_Var(fd->face, &amaster);1864for (FT_UInt i = 0; i < amaster->num_axis; i++) {1865p_font_data->supported_varaitions[(int32_t)amaster->axis[i].tag] = Vector3i(amaster->axis[i].minimum / 65536, amaster->axis[i].maximum / 65536, amaster->axis[i].def / 65536);1866}1867FT_Done_MM_Var(ft_library, amaster);1868}1869p_font_data->face_init = true;1870}18711872#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)1873if (p_font_data->font_name == ".Apple Color Emoji UI" || p_font_data->font_name == "Apple Color Emoji") {1874// The baseline offset is missing from the Apple Color Emoji UI font data, so add it manually.1875// This issue doesn't occur with other system emoji fonts.1876if (!FT_Load_Glyph(fd->face, FT_Get_Char_Index(fd->face, 0x1F92E), FT_LOAD_DEFAULT | FT_LOAD_COLOR)) {1877if (fd->face->glyph->metrics.horiBearingY == fd->face->glyph->metrics.height) {1878p_font_data->baseline_offset = 0.15;1879}1880}1881}1882#endif18831884// Write variations.1885if (fd->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {1886FT_MM_Var *amaster;18871888FT_Get_MM_Var(fd->face, &amaster);18891890Vector<hb_variation_t> hb_vars;1891Vector<FT_Fixed> coords;1892coords.resize(amaster->num_axis);18931894FT_Get_Var_Design_Coordinates(fd->face, coords.size(), coords.ptrw());18951896for (FT_UInt i = 0; i < amaster->num_axis; i++) {1897hb_variation_t var;18981899// Reset to default.1900var.tag = amaster->axis[i].tag;1901var.value = (double)amaster->axis[i].def / 65536.0;1902coords.write[i] = amaster->axis[i].def;19031904if (p_font_data->variation_coordinates.has(var.tag)) {1905var.value = p_font_data->variation_coordinates[var.tag];1906coords.write[i] = CLAMP(var.value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);1907}19081909if (p_font_data->variation_coordinates.has(_tag_to_name(var.tag))) {1910var.value = p_font_data->variation_coordinates[_tag_to_name(var.tag)];1911coords.write[i] = CLAMP(var.value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);1912}19131914hb_vars.push_back(var);1915}19161917FT_Set_Var_Design_Coordinates(fd->face, coords.size(), coords.ptrw());1918hb_font_set_variations(fd->hb_handle, hb_vars.is_empty() ? nullptr : &hb_vars[0], hb_vars.size());1919FT_Done_MM_Var(ft_library, amaster);1920}1921#else1922memdelete(fd);1923if (p_silent) {1924return false;1925} else {1926ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!");1927}1928#endif1929} else {1930// Init bitmap font.1931fd->hb_handle = _bmp_font_create(fd, nullptr);1932}19331934fd->owner = p_font_data;1935p_font_data->cache.insert(p_size, fd);1936r_cache_for_size = fd;1937if (p_oversampling != 0) {1938OversamplingLevel *ol = oversampling_levels.getptr(p_oversampling);1939if (ol) {1940fd->viewport_oversampling = p_oversampling;1941ol->fonts.insert(fd);1942}1943}1944return true;1945}19461947void TextServerAdvanced::_reference_oversampling_level(double p_oversampling) {1948uint32_t oversampling = CLAMP(p_oversampling, 0.1, 100.0) * 64;1949if (oversampling == 64) {1950return;1951}1952OversamplingLevel *ol = oversampling_levels.getptr(oversampling);1953if (ol) {1954ol->refcount++;1955} else {1956OversamplingLevel new_ol;1957oversampling_levels.insert(oversampling, new_ol);1958}1959}19601961void TextServerAdvanced::_unreference_oversampling_level(double p_oversampling) {1962uint32_t oversampling = CLAMP(p_oversampling, 0.1, 100.0) * 64;1963if (oversampling == 64) {1964return;1965}1966OversamplingLevel *ol = oversampling_levels.getptr(oversampling);1967if (ol) {1968ol->refcount--;1969if (ol->refcount == 0) {1970for (FontForSizeAdvanced *fd : ol->fonts) {1971fd->owner->cache.erase(fd->size);1972memdelete(fd);1973}1974ol->fonts.clear();1975oversampling_levels.erase(oversampling);1976}1977}1978}19791980_FORCE_INLINE_ bool TextServerAdvanced::_font_validate(const RID &p_font_rid) const {1981FontAdvanced *fd = _get_font_data(p_font_rid);1982ERR_FAIL_NULL_V(fd, false);19831984MutexLock lock(fd->mutex);1985Vector2i size = _get_size(fd, 16);1986FontForSizeAdvanced *ffsd = nullptr;1987return _ensure_cache_for_size(fd, size, ffsd, true);1988}19891990_FORCE_INLINE_ void TextServerAdvanced::_font_clear_cache(FontAdvanced *p_font_data) {1991MutexLock ftlock(ft_mutex);19921993for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : p_font_data->cache) {1994if (E.value->viewport_oversampling != 0) {1995OversamplingLevel *ol = oversampling_levels.getptr(E.value->viewport_oversampling);1996if (ol) {1997ol->fonts.erase(E.value);1998}1999}2000memdelete(E.value);2001}2002p_font_data->cache.clear();2003p_font_data->face_init = false;2004p_font_data->supported_features.clear();2005p_font_data->supported_varaitions.clear();2006p_font_data->supported_scripts.clear();2007}20082009hb_font_t *TextServerAdvanced::_font_get_hb_handle(const RID &p_font_rid, int64_t p_size, bool &r_is_color) const {2010FontAdvanced *fd = _get_font_data(p_font_rid);2011ERR_FAIL_NULL_V(fd, nullptr);20122013MutexLock lock(fd->mutex);2014Vector2i size = _get_size(fd, p_size);20152016FontForSizeAdvanced *ffsd = nullptr;2017ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), nullptr);2018#ifdef MODULE_FREETYPE_ENABLED2019r_is_color = ffsd->face && FT_HAS_COLOR(ffsd->face);2020#else2021r_is_color = false;2022#endif20232024return ffsd->hb_handle;2025}20262027RID TextServerAdvanced::_create_font() {2028_THREAD_SAFE_METHOD_20292030FontAdvanced *fd = memnew(FontAdvanced);20312032return font_owner.make_rid(fd);2033}20342035RID TextServerAdvanced::_create_font_linked_variation(const RID &p_font_rid) {2036_THREAD_SAFE_METHOD_20372038RID rid = p_font_rid;2039FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(rid);2040if (unlikely(fdv)) {2041rid = fdv->base_font;2042}2043ERR_FAIL_COND_V(!font_owner.owns(rid), RID());20442045FontAdvancedLinkedVariation *new_fdv = memnew(FontAdvancedLinkedVariation);2046new_fdv->base_font = rid;20472048return font_var_owner.make_rid(new_fdv);2049}20502051void TextServerAdvanced::_font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) {2052FontAdvanced *fd = _get_font_data(p_font_rid);2053ERR_FAIL_NULL(fd);20542055MutexLock lock(fd->mutex);2056_font_clear_cache(fd);2057fd->data = p_data;2058fd->data_ptr = fd->data.ptr();2059fd->data_size = fd->data.size();2060}20612062void TextServerAdvanced::_font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) {2063FontAdvanced *fd = _get_font_data(p_font_rid);2064ERR_FAIL_NULL(fd);20652066MutexLock lock(fd->mutex);2067_font_clear_cache(fd);2068fd->data.resize(0);2069fd->data_ptr = p_data_ptr;2070fd->data_size = p_data_size;2071}20722073void TextServerAdvanced::_font_set_face_index(const RID &p_font_rid, int64_t p_face_index) {2074ERR_FAIL_COND(p_face_index < 0);2075ERR_FAIL_COND(p_face_index >= 0x7FFF);20762077FontAdvanced *fd = _get_font_data(p_font_rid);2078ERR_FAIL_NULL(fd);20792080MutexLock lock(fd->mutex);2081if (fd->face_index != p_face_index) {2082fd->face_index = p_face_index;2083_font_clear_cache(fd);2084}2085}20862087int64_t TextServerAdvanced::_font_get_face_index(const RID &p_font_rid) const {2088FontAdvanced *fd = _get_font_data(p_font_rid);2089ERR_FAIL_NULL_V(fd, 0);20902091MutexLock lock(fd->mutex);2092return fd->face_index;2093}20942095int64_t TextServerAdvanced::_font_get_face_count(const RID &p_font_rid) const {2096FontAdvanced *fd = _get_font_data(p_font_rid);2097ERR_FAIL_NULL_V(fd, 0);20982099MutexLock lock(fd->mutex);2100int face_count = 0;21012102if (fd->data_ptr && (fd->data_size > 0)) {2103// Init dynamic font.2104#ifdef MODULE_FREETYPE_ENABLED2105int error = 0;2106if (!ft_library) {2107error = FT_Init_FreeType(&ft_library);2108ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");2109#ifdef MODULE_SVG_ENABLED2110FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks());2111#endif2112}21132114FT_StreamRec stream;2115memset(&stream, 0, sizeof(FT_StreamRec));2116stream.base = (unsigned char *)fd->data_ptr;2117stream.size = fd->data_size;2118stream.pos = 0;21192120FT_Open_Args fargs;2121memset(&fargs, 0, sizeof(FT_Open_Args));2122fargs.memory_base = (unsigned char *)fd->data_ptr;2123fargs.memory_size = fd->data_size;2124fargs.flags = FT_OPEN_MEMORY;2125fargs.stream = &stream;21262127MutexLock ftlock(ft_mutex);21282129FT_Face tmp_face = nullptr;2130error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);2131if (error == 0) {2132face_count = tmp_face->num_faces;2133FT_Done_Face(tmp_face);2134}2135#endif2136}21372138return face_count;2139}21402141void TextServerAdvanced::_font_set_style(const RID &p_font_rid, BitField<FontStyle> p_style) {2142FontAdvanced *fd = _get_font_data(p_font_rid);2143ERR_FAIL_NULL(fd);21442145MutexLock lock(fd->mutex);2146Vector2i size = _get_size(fd, 16);2147FontForSizeAdvanced *ffsd = nullptr;2148ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2149fd->style_flags = p_style;2150}21512152BitField<TextServer::FontStyle> TextServerAdvanced::_font_get_style(const RID &p_font_rid) const {2153FontAdvanced *fd = _get_font_data(p_font_rid);2154ERR_FAIL_NULL_V(fd, 0);21552156MutexLock lock(fd->mutex);2157Vector2i size = _get_size(fd, 16);2158FontForSizeAdvanced *ffsd = nullptr;2159ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0);2160return fd->style_flags;2161}21622163void TextServerAdvanced::_font_set_style_name(const RID &p_font_rid, const String &p_name) {2164FontAdvanced *fd = _get_font_data(p_font_rid);2165ERR_FAIL_NULL(fd);21662167MutexLock lock(fd->mutex);2168Vector2i size = _get_size(fd, 16);2169FontForSizeAdvanced *ffsd = nullptr;2170ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2171fd->style_name = p_name;2172}21732174String TextServerAdvanced::_font_get_style_name(const RID &p_font_rid) const {2175FontAdvanced *fd = _get_font_data(p_font_rid);2176ERR_FAIL_NULL_V(fd, String());21772178MutexLock lock(fd->mutex);2179Vector2i size = _get_size(fd, 16);2180FontForSizeAdvanced *ffsd = nullptr;2181ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), String());2182return fd->style_name;2183}21842185void TextServerAdvanced::_font_set_weight(const RID &p_font_rid, int64_t p_weight) {2186FontAdvanced *fd = _get_font_data(p_font_rid);2187ERR_FAIL_NULL(fd);21882189MutexLock lock(fd->mutex);2190Vector2i size = _get_size(fd, 16);2191FontForSizeAdvanced *ffsd = nullptr;2192ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2193fd->weight = CLAMP(p_weight, 100, 999);2194}21952196int64_t TextServerAdvanced::_font_get_weight(const RID &p_font_rid) const {2197FontAdvanced *fd = _get_font_data(p_font_rid);2198ERR_FAIL_NULL_V(fd, 400);21992200MutexLock lock(fd->mutex);2201Vector2i size = _get_size(fd, 16);2202FontForSizeAdvanced *ffsd = nullptr;2203ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 400);2204return fd->weight;2205}22062207void TextServerAdvanced::_font_set_stretch(const RID &p_font_rid, int64_t p_stretch) {2208FontAdvanced *fd = _get_font_data(p_font_rid);2209ERR_FAIL_NULL(fd);22102211MutexLock lock(fd->mutex);2212Vector2i size = _get_size(fd, 16);2213FontForSizeAdvanced *ffsd = nullptr;2214ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2215fd->stretch = CLAMP(p_stretch, 50, 200);2216}22172218int64_t TextServerAdvanced::_font_get_stretch(const RID &p_font_rid) const {2219FontAdvanced *fd = _get_font_data(p_font_rid);2220ERR_FAIL_NULL_V(fd, 100);22212222MutexLock lock(fd->mutex);2223Vector2i size = _get_size(fd, 16);2224FontForSizeAdvanced *ffsd = nullptr;2225ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 100);2226return fd->stretch;2227}22282229void TextServerAdvanced::_font_set_name(const RID &p_font_rid, const String &p_name) {2230FontAdvanced *fd = _get_font_data(p_font_rid);2231ERR_FAIL_NULL(fd);22322233MutexLock lock(fd->mutex);2234Vector2i size = _get_size(fd, 16);2235FontForSizeAdvanced *ffsd = nullptr;2236ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2237fd->font_name = p_name;2238}22392240String TextServerAdvanced::_font_get_name(const RID &p_font_rid) const {2241FontAdvanced *fd = _get_font_data(p_font_rid);2242ERR_FAIL_NULL_V(fd, String());22432244MutexLock lock(fd->mutex);2245Vector2i size = _get_size(fd, 16);2246FontForSizeAdvanced *ffsd = nullptr;2247ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), String());2248return fd->font_name;2249}22502251Dictionary TextServerAdvanced::_font_get_ot_name_strings(const RID &p_font_rid) const {2252FontAdvanced *fd = _get_font_data(p_font_rid);2253ERR_FAIL_NULL_V(fd, Dictionary());22542255MutexLock lock(fd->mutex);2256Vector2i size = _get_size(fd, 16);2257FontForSizeAdvanced *ffsd = nullptr;2258ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary());22592260hb_face_t *hb_face = hb_font_get_face(ffsd->hb_handle);22612262unsigned int num_entries = 0;2263const hb_ot_name_entry_t *names = hb_ot_name_list_names(hb_face, &num_entries);2264HashMap<String, Dictionary> names_for_lang;2265for (unsigned int i = 0; i < num_entries; i++) {2266String name;2267switch (names[i].name_id) {2268case HB_OT_NAME_ID_COPYRIGHT: {2269name = "copyright";2270} break;2271case HB_OT_NAME_ID_FONT_FAMILY: {2272name = "family_name";2273} break;2274case HB_OT_NAME_ID_FONT_SUBFAMILY: {2275name = "subfamily_name";2276} break;2277case HB_OT_NAME_ID_UNIQUE_ID: {2278name = "unique_identifier";2279} break;2280case HB_OT_NAME_ID_FULL_NAME: {2281name = "full_name";2282} break;2283case HB_OT_NAME_ID_VERSION_STRING: {2284name = "version";2285} break;2286case HB_OT_NAME_ID_POSTSCRIPT_NAME: {2287name = "postscript_name";2288} break;2289case HB_OT_NAME_ID_TRADEMARK: {2290name = "trademark";2291} break;2292case HB_OT_NAME_ID_MANUFACTURER: {2293name = "manufacturer";2294} break;2295case HB_OT_NAME_ID_DESIGNER: {2296name = "designer";2297} break;2298case HB_OT_NAME_ID_DESCRIPTION: {2299name = "description";2300} break;2301case HB_OT_NAME_ID_VENDOR_URL: {2302name = "vendor_url";2303} break;2304case HB_OT_NAME_ID_DESIGNER_URL: {2305name = "designer_url";2306} break;2307case HB_OT_NAME_ID_LICENSE: {2308name = "license";2309} break;2310case HB_OT_NAME_ID_LICENSE_URL: {2311name = "license_url";2312} break;2313case HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY: {2314name = "typographic_family_name";2315} break;2316case HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY: {2317name = "typographic_subfamily_name";2318} break;2319case HB_OT_NAME_ID_MAC_FULL_NAME: {2320name = "full_name_macos";2321} break;2322case HB_OT_NAME_ID_SAMPLE_TEXT: {2323name = "sample_text";2324} break;2325case HB_OT_NAME_ID_CID_FINDFONT_NAME: {2326name = "cid_findfont_name";2327} break;2328case HB_OT_NAME_ID_WWS_FAMILY: {2329name = "weight_width_slope_family_name";2330} break;2331case HB_OT_NAME_ID_WWS_SUBFAMILY: {2332name = "weight_width_slope_subfamily_name";2333} break;2334case HB_OT_NAME_ID_LIGHT_BACKGROUND: {2335name = "light_background_palette";2336} break;2337case HB_OT_NAME_ID_DARK_BACKGROUND: {2338name = "dark_background_palette";2339} break;2340case HB_OT_NAME_ID_VARIATIONS_PS_PREFIX: {2341name = "postscript_name_prefix";2342} break;2343default: {2344name = vformat("unknown_%d", names[i].name_id);2345} break;2346}2347String text;2348unsigned int text_size = hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, nullptr, nullptr) + 1;2349text.resize_uninitialized(text_size);2350hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, &text_size, (uint32_t *)text.ptrw());2351if (!text.is_empty()) {2352Dictionary &id_string = names_for_lang[String(hb_language_to_string(names[i].language))];2353id_string[name] = text;2354}2355}23562357Dictionary out;2358for (const KeyValue<String, Dictionary> &E : names_for_lang) {2359out[E.key] = E.value;2360}23612362return out;2363}23642365void TextServerAdvanced::_font_set_antialiasing(const RID &p_font_rid, TextServer::FontAntialiasing p_antialiasing) {2366FontAdvanced *fd = _get_font_data(p_font_rid);2367ERR_FAIL_NULL(fd);23682369MutexLock lock(fd->mutex);2370if (fd->antialiasing != p_antialiasing) {2371_font_clear_cache(fd);2372fd->antialiasing = p_antialiasing;2373}2374}23752376TextServer::FontAntialiasing TextServerAdvanced::_font_get_antialiasing(const RID &p_font_rid) const {2377FontAdvanced *fd = _get_font_data(p_font_rid);2378ERR_FAIL_NULL_V(fd, TextServer::FONT_ANTIALIASING_NONE);23792380MutexLock lock(fd->mutex);2381return fd->antialiasing;2382}23832384void TextServerAdvanced::_font_set_disable_embedded_bitmaps(const RID &p_font_rid, bool p_disable_embedded_bitmaps) {2385FontAdvanced *fd = _get_font_data(p_font_rid);2386ERR_FAIL_NULL(fd);23872388MutexLock lock(fd->mutex);2389if (fd->disable_embedded_bitmaps != p_disable_embedded_bitmaps) {2390_font_clear_cache(fd);2391fd->disable_embedded_bitmaps = p_disable_embedded_bitmaps;2392}2393}23942395bool TextServerAdvanced::_font_get_disable_embedded_bitmaps(const RID &p_font_rid) const {2396FontAdvanced *fd = _get_font_data(p_font_rid);2397ERR_FAIL_NULL_V(fd, false);23982399MutexLock lock(fd->mutex);2400return fd->disable_embedded_bitmaps;2401}24022403void TextServerAdvanced::_font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) {2404FontAdvanced *fd = _get_font_data(p_font_rid);2405ERR_FAIL_NULL(fd);24062407MutexLock lock(fd->mutex);2408if (fd->mipmaps != p_generate_mipmaps) {2409for (KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {2410for (int i = 0; i < E.value->textures.size(); i++) {2411E.value->textures.write[i].dirty = true;2412E.value->textures.write[i].texture = Ref<ImageTexture>();2413}2414}2415fd->mipmaps = p_generate_mipmaps;2416}2417}24182419bool TextServerAdvanced::_font_get_generate_mipmaps(const RID &p_font_rid) const {2420FontAdvanced *fd = _get_font_data(p_font_rid);2421ERR_FAIL_NULL_V(fd, false);24222423MutexLock lock(fd->mutex);2424return fd->mipmaps;2425}24262427void TextServerAdvanced::_font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) {2428FontAdvanced *fd = _get_font_data(p_font_rid);2429ERR_FAIL_NULL(fd);24302431MutexLock lock(fd->mutex);2432if (fd->msdf != p_msdf) {2433_font_clear_cache(fd);2434fd->msdf = p_msdf;2435}2436}24372438bool TextServerAdvanced::_font_is_multichannel_signed_distance_field(const RID &p_font_rid) const {2439FontAdvanced *fd = _get_font_data(p_font_rid);2440ERR_FAIL_NULL_V(fd, false);24412442MutexLock lock(fd->mutex);2443return fd->msdf;2444}24452446void TextServerAdvanced::_font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) {2447FontAdvanced *fd = _get_font_data(p_font_rid);2448ERR_FAIL_NULL(fd);24492450MutexLock lock(fd->mutex);2451if (fd->msdf_range != p_msdf_pixel_range) {2452_font_clear_cache(fd);2453fd->msdf_range = p_msdf_pixel_range;2454}2455}24562457int64_t TextServerAdvanced::_font_get_msdf_pixel_range(const RID &p_font_rid) const {2458FontAdvanced *fd = _get_font_data(p_font_rid);2459ERR_FAIL_NULL_V(fd, false);24602461MutexLock lock(fd->mutex);2462return fd->msdf_range;2463}24642465void TextServerAdvanced::_font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) {2466FontAdvanced *fd = _get_font_data(p_font_rid);2467ERR_FAIL_NULL(fd);24682469MutexLock lock(fd->mutex);2470if (fd->msdf_source_size != p_msdf_size) {2471_font_clear_cache(fd);2472fd->msdf_source_size = p_msdf_size;2473}2474}24752476int64_t TextServerAdvanced::_font_get_msdf_size(const RID &p_font_rid) const {2477FontAdvanced *fd = _get_font_data(p_font_rid);2478ERR_FAIL_NULL_V(fd, 0);24792480MutexLock lock(fd->mutex);2481return fd->msdf_source_size;2482}24832484void TextServerAdvanced::_font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) {2485FontAdvanced *fd = _get_font_data(p_font_rid);2486ERR_FAIL_NULL(fd);24872488MutexLock lock(fd->mutex);2489fd->fixed_size = p_fixed_size;2490}24912492int64_t TextServerAdvanced::_font_get_fixed_size(const RID &p_font_rid) const {2493FontAdvanced *fd = _get_font_data(p_font_rid);2494ERR_FAIL_NULL_V(fd, 0);24952496MutexLock lock(fd->mutex);2497return fd->fixed_size;2498}24992500void TextServerAdvanced::_font_set_fixed_size_scale_mode(const RID &p_font_rid, TextServer::FixedSizeScaleMode p_fixed_size_scale_mode) {2501FontAdvanced *fd = _get_font_data(p_font_rid);2502ERR_FAIL_NULL(fd);25032504MutexLock lock(fd->mutex);2505fd->fixed_size_scale_mode = p_fixed_size_scale_mode;2506}25072508TextServer::FixedSizeScaleMode TextServerAdvanced::_font_get_fixed_size_scale_mode(const RID &p_font_rid) const {2509FontAdvanced *fd = _get_font_data(p_font_rid);2510ERR_FAIL_NULL_V(fd, FIXED_SIZE_SCALE_DISABLE);25112512MutexLock lock(fd->mutex);2513return fd->fixed_size_scale_mode;2514}25152516void TextServerAdvanced::_font_set_allow_system_fallback(const RID &p_font_rid, bool p_allow_system_fallback) {2517FontAdvanced *fd = _get_font_data(p_font_rid);2518ERR_FAIL_NULL(fd);25192520MutexLock lock(fd->mutex);2521fd->allow_system_fallback = p_allow_system_fallback;2522}25232524bool TextServerAdvanced::_font_is_allow_system_fallback(const RID &p_font_rid) const {2525FontAdvanced *fd = _get_font_data(p_font_rid);2526ERR_FAIL_NULL_V(fd, false);25272528MutexLock lock(fd->mutex);2529return fd->allow_system_fallback;2530}25312532void TextServerAdvanced::_font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) {2533FontAdvanced *fd = _get_font_data(p_font_rid);2534ERR_FAIL_NULL(fd);25352536MutexLock lock(fd->mutex);2537if (fd->force_autohinter != p_force_autohinter) {2538_font_clear_cache(fd);2539fd->force_autohinter = p_force_autohinter;2540}2541}25422543bool TextServerAdvanced::_font_is_force_autohinter(const RID &p_font_rid) const {2544FontAdvanced *fd = _get_font_data(p_font_rid);2545ERR_FAIL_NULL_V(fd, false);25462547MutexLock lock(fd->mutex);2548return fd->force_autohinter;2549}25502551void TextServerAdvanced::_font_set_modulate_color_glyphs(const RID &p_font_rid, bool p_modulate) {2552FontAdvanced *fd = _get_font_data(p_font_rid);2553ERR_FAIL_NULL(fd);25542555MutexLock lock(fd->mutex);2556if (fd->modulate_color_glyphs != p_modulate) {2557fd->modulate_color_glyphs = p_modulate;2558}2559}25602561bool TextServerAdvanced::_font_is_modulate_color_glyphs(const RID &p_font_rid) const {2562FontAdvanced *fd = _get_font_data(p_font_rid);2563ERR_FAIL_NULL_V(fd, false);25642565MutexLock lock(fd->mutex);2566return fd->modulate_color_glyphs;2567}25682569void TextServerAdvanced::_font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) {2570FontAdvanced *fd = _get_font_data(p_font_rid);2571ERR_FAIL_NULL(fd);25722573MutexLock lock(fd->mutex);2574if (fd->hinting != p_hinting) {2575_font_clear_cache(fd);2576fd->hinting = p_hinting;2577}2578}25792580TextServer::Hinting TextServerAdvanced::_font_get_hinting(const RID &p_font_rid) const {2581FontAdvanced *fd = _get_font_data(p_font_rid);2582ERR_FAIL_NULL_V(fd, HINTING_NONE);25832584MutexLock lock(fd->mutex);2585return fd->hinting;2586}25872588void TextServerAdvanced::_font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) {2589FontAdvanced *fd = _get_font_data(p_font_rid);2590ERR_FAIL_NULL(fd);25912592MutexLock lock(fd->mutex);2593fd->subpixel_positioning = p_subpixel;2594}25952596TextServer::SubpixelPositioning TextServerAdvanced::_font_get_subpixel_positioning(const RID &p_font_rid) const {2597FontAdvanced *fd = _get_font_data(p_font_rid);2598ERR_FAIL_NULL_V(fd, SUBPIXEL_POSITIONING_DISABLED);25992600MutexLock lock(fd->mutex);2601return fd->subpixel_positioning;2602}26032604void TextServerAdvanced::_font_set_keep_rounding_remainders(const RID &p_font_rid, bool p_keep_rounding_remainders) {2605FontAdvanced *fd = _get_font_data(p_font_rid);2606ERR_FAIL_NULL(fd);26072608MutexLock lock(fd->mutex);2609fd->keep_rounding_remainders = p_keep_rounding_remainders;2610}26112612bool TextServerAdvanced::_font_get_keep_rounding_remainders(const RID &p_font_rid) const {2613FontAdvanced *fd = _get_font_data(p_font_rid);2614ERR_FAIL_NULL_V(fd, false);26152616MutexLock lock(fd->mutex);2617return fd->keep_rounding_remainders;2618}26192620void TextServerAdvanced::_font_set_embolden(const RID &p_font_rid, double p_strength) {2621FontAdvanced *fd = _get_font_data(p_font_rid);2622ERR_FAIL_NULL(fd);26232624MutexLock lock(fd->mutex);2625if (fd->embolden != p_strength) {2626_font_clear_cache(fd);2627fd->embolden = p_strength;2628}2629}26302631double TextServerAdvanced::_font_get_embolden(const RID &p_font_rid) const {2632FontAdvanced *fd = _get_font_data(p_font_rid);2633ERR_FAIL_NULL_V(fd, 0.0);26342635MutexLock lock(fd->mutex);2636return fd->embolden;2637}26382639void TextServerAdvanced::_font_set_spacing(const RID &p_font_rid, SpacingType p_spacing, int64_t p_value) {2640ERR_FAIL_INDEX((int)p_spacing, 4);2641FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);2642if (fdv) {2643if (fdv->extra_spacing[p_spacing] != p_value) {2644fdv->extra_spacing[p_spacing] = p_value;2645}2646} else {2647FontAdvanced *fd = font_owner.get_or_null(p_font_rid);2648ERR_FAIL_NULL(fd);26492650MutexLock lock(fd->mutex);2651if (fd->extra_spacing[p_spacing] != p_value) {2652fd->extra_spacing[p_spacing] = p_value;2653}2654}2655}26562657int64_t TextServerAdvanced::_font_get_spacing(const RID &p_font_rid, SpacingType p_spacing) const {2658ERR_FAIL_INDEX_V((int)p_spacing, 4, 0);2659FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);2660if (fdv) {2661return fdv->extra_spacing[p_spacing];2662} else {2663FontAdvanced *fd = font_owner.get_or_null(p_font_rid);2664ERR_FAIL_NULL_V(fd, 0);26652666MutexLock lock(fd->mutex);2667return fd->extra_spacing[p_spacing];2668}2669}26702671void TextServerAdvanced::_font_set_baseline_offset(const RID &p_font_rid, double p_baseline_offset) {2672FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);2673if (fdv) {2674if (fdv->baseline_offset != p_baseline_offset) {2675fdv->baseline_offset = p_baseline_offset;2676}2677} else {2678FontAdvanced *fd = font_owner.get_or_null(p_font_rid);2679ERR_FAIL_NULL(fd);26802681MutexLock lock(fd->mutex);2682if (fd->baseline_offset != p_baseline_offset) {2683_font_clear_cache(fd);2684fd->baseline_offset = p_baseline_offset;2685}2686}2687}26882689double TextServerAdvanced::_font_get_baseline_offset(const RID &p_font_rid) const {2690FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);2691if (fdv) {2692return fdv->baseline_offset;2693} else {2694FontAdvanced *fd = font_owner.get_or_null(p_font_rid);2695ERR_FAIL_NULL_V(fd, 0.0);26962697MutexLock lock(fd->mutex);2698return fd->baseline_offset;2699}2700}27012702void TextServerAdvanced::_font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) {2703FontAdvanced *fd = _get_font_data(p_font_rid);2704ERR_FAIL_NULL(fd);27052706MutexLock lock(fd->mutex);2707if (fd->transform != p_transform) {2708_font_clear_cache(fd);2709fd->transform = p_transform;2710}2711}27122713Transform2D TextServerAdvanced::_font_get_transform(const RID &p_font_rid) const {2714FontAdvanced *fd = _get_font_data(p_font_rid);2715ERR_FAIL_NULL_V(fd, Transform2D());27162717MutexLock lock(fd->mutex);2718return fd->transform;2719}27202721void TextServerAdvanced::_font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) {2722FontAdvanced *fd = _get_font_data(p_font_rid);2723ERR_FAIL_NULL(fd);27242725MutexLock lock(fd->mutex);2726if (!fd->variation_coordinates.recursive_equal(p_variation_coordinates, 1)) {2727_font_clear_cache(fd);2728fd->variation_coordinates = p_variation_coordinates.duplicate();2729}2730}27312732double TextServerAdvanced::_font_get_oversampling(const RID &p_font_rid) const {2733FontAdvanced *fd = _get_font_data(p_font_rid);2734ERR_FAIL_NULL_V(fd, -1.0);27352736MutexLock lock(fd->mutex);2737return fd->oversampling_override;2738}27392740void TextServerAdvanced::_font_set_oversampling(const RID &p_font_rid, double p_oversampling) {2741FontAdvanced *fd = _get_font_data(p_font_rid);2742ERR_FAIL_NULL(fd);27432744MutexLock lock(fd->mutex);2745if (fd->oversampling_override != p_oversampling) {2746_font_clear_cache(fd);2747fd->oversampling_override = p_oversampling;2748}2749}27502751Dictionary TextServerAdvanced::_font_get_variation_coordinates(const RID &p_font_rid) const {2752FontAdvanced *fd = _get_font_data(p_font_rid);2753ERR_FAIL_NULL_V(fd, Dictionary());27542755MutexLock lock(fd->mutex);2756return fd->variation_coordinates;2757}27582759TypedArray<Vector2i> TextServerAdvanced::_font_get_size_cache_list(const RID &p_font_rid) const {2760FontAdvanced *fd = _get_font_data(p_font_rid);2761ERR_FAIL_NULL_V(fd, TypedArray<Vector2i>());27622763MutexLock lock(fd->mutex);2764TypedArray<Vector2i> ret;2765for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {2766if ((E.key.x % 64 == 0) && (E.value->viewport_oversampling == 0)) {2767ret.push_back(Vector2i(E.key.x / 64, E.key.y));2768}2769}2770return ret;2771}27722773TypedArray<Dictionary> TextServerAdvanced::_font_get_size_cache_info(const RID &p_font_rid) const {2774FontAdvanced *fd = _get_font_data(p_font_rid);2775ERR_FAIL_NULL_V(fd, TypedArray<Dictionary>());27762777MutexLock lock(fd->mutex);2778TypedArray<Dictionary> ret;2779for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {2780Dictionary size_info;2781size_info["size_px"] = Vector2i(E.key.x / 64, E.key.y);2782if (E.value->viewport_oversampling) {2783size_info["viewport_oversampling"] = double(E.value->viewport_oversampling) / 64.0;2784}2785size_info["glyphs"] = E.value->glyph_map.size();2786size_info["textures"] = E.value->textures.size();2787uint64_t sz = 0;2788for (const ShelfPackTexture &tx : E.value->textures) {2789sz += tx.image->get_data_size() * 2;2790}2791size_info["textures_size"] = sz;2792ret.push_back(size_info);2793}27942795return ret;2796}27972798void TextServerAdvanced::_font_clear_size_cache(const RID &p_font_rid) {2799FontAdvanced *fd = _get_font_data(p_font_rid);2800ERR_FAIL_NULL(fd);28012802MutexLock lock(fd->mutex);2803MutexLock ftlock(ft_mutex);2804for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {2805if (E.value->viewport_oversampling != 0) {2806OversamplingLevel *ol = oversampling_levels.getptr(E.value->viewport_oversampling);2807if (ol) {2808ol->fonts.erase(E.value);2809}2810}2811memdelete(E.value);2812}2813fd->cache.clear();2814}28152816void TextServerAdvanced::_font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) {2817FontAdvanced *fd = _get_font_data(p_font_rid);2818ERR_FAIL_NULL(fd);28192820MutexLock lock(fd->mutex);2821MutexLock ftlock(ft_mutex);2822Vector2i size = Vector2i(p_size.x * 64, p_size.y);2823if (fd->cache.has(size)) {2824if (fd->cache[size]->viewport_oversampling != 0) {2825OversamplingLevel *ol = oversampling_levels.getptr(fd->cache[size]->viewport_oversampling);2826if (ol) {2827ol->fonts.erase(fd->cache[size]);2828}2829}2830memdelete(fd->cache[size]);2831fd->cache.erase(size);2832}2833}28342835void TextServerAdvanced::_font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) {2836FontAdvanced *fd = _get_font_data(p_font_rid);2837ERR_FAIL_NULL(fd);28382839MutexLock lock(fd->mutex);2840Vector2i size = _get_size(fd, p_size);28412842FontForSizeAdvanced *ffsd = nullptr;2843ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2844ffsd->ascent = p_ascent;2845}28462847double TextServerAdvanced::_font_get_ascent(const RID &p_font_rid, int64_t p_size) const {2848FontAdvanced *fd = _get_font_data(p_font_rid);2849ERR_FAIL_NULL_V(fd, 0.0);28502851MutexLock lock(fd->mutex);2852Vector2i size = _get_size(fd, p_size);28532854FontForSizeAdvanced *ffsd = nullptr;2855ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);28562857if (fd->msdf) {2858return ffsd->ascent * (double)p_size / (double)fd->msdf_source_size;2859} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {2860if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2861return ffsd->ascent * (double)p_size / (double)fd->fixed_size;2862} else {2863return ffsd->ascent * Math::round((double)p_size / (double)fd->fixed_size);2864}2865} else {2866return ffsd->ascent;2867}2868}28692870void TextServerAdvanced::_font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) {2871FontAdvanced *fd = _get_font_data(p_font_rid);2872ERR_FAIL_NULL(fd);28732874Vector2i size = _get_size(fd, p_size);28752876FontForSizeAdvanced *ffsd = nullptr;2877ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2878ffsd->descent = p_descent;2879}28802881double TextServerAdvanced::_font_get_descent(const RID &p_font_rid, int64_t p_size) const {2882FontAdvanced *fd = _get_font_data(p_font_rid);2883ERR_FAIL_NULL_V(fd, 0.0);28842885MutexLock lock(fd->mutex);2886Vector2i size = _get_size(fd, p_size);28872888FontForSizeAdvanced *ffsd = nullptr;2889ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);28902891if (fd->msdf) {2892return ffsd->descent * (double)p_size / (double)fd->msdf_source_size;2893} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {2894if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2895return ffsd->descent * (double)p_size / (double)fd->fixed_size;2896} else {2897return ffsd->descent * Math::round((double)p_size / (double)fd->fixed_size);2898}2899} else {2900return ffsd->descent;2901}2902}29032904void TextServerAdvanced::_font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) {2905FontAdvanced *fd = _get_font_data(p_font_rid);2906ERR_FAIL_NULL(fd);29072908MutexLock lock(fd->mutex);2909Vector2i size = _get_size(fd, p_size);29102911FontForSizeAdvanced *ffsd = nullptr;2912ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2913ffsd->underline_position = p_underline_position;2914}29152916double TextServerAdvanced::_font_get_underline_position(const RID &p_font_rid, int64_t p_size) const {2917FontAdvanced *fd = _get_font_data(p_font_rid);2918ERR_FAIL_NULL_V(fd, 0.0);29192920MutexLock lock(fd->mutex);2921Vector2i size = _get_size(fd, p_size);29222923FontForSizeAdvanced *ffsd = nullptr;2924ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);29252926if (fd->msdf) {2927return ffsd->underline_position * (double)p_size / (double)fd->msdf_source_size;2928} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {2929if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2930return ffsd->underline_position * (double)p_size / (double)fd->fixed_size;2931} else {2932return ffsd->underline_position * Math::round((double)p_size / (double)fd->fixed_size);2933}2934} else {2935return ffsd->underline_position;2936}2937}29382939void TextServerAdvanced::_font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) {2940FontAdvanced *fd = _get_font_data(p_font_rid);2941ERR_FAIL_NULL(fd);29422943MutexLock lock(fd->mutex);2944Vector2i size = _get_size(fd, p_size);29452946FontForSizeAdvanced *ffsd = nullptr;2947ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2948ffsd->underline_thickness = p_underline_thickness;2949}29502951double TextServerAdvanced::_font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const {2952FontAdvanced *fd = _get_font_data(p_font_rid);2953ERR_FAIL_NULL_V(fd, 0.0);29542955MutexLock lock(fd->mutex);2956Vector2i size = _get_size(fd, p_size);29572958FontForSizeAdvanced *ffsd = nullptr;2959ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);29602961if (fd->msdf) {2962return ffsd->underline_thickness * (double)p_size / (double)fd->msdf_source_size;2963} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {2964if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2965return ffsd->underline_thickness * (double)p_size / (double)fd->fixed_size;2966} else {2967return ffsd->underline_thickness * Math::round((double)p_size / (double)fd->fixed_size);2968}2969} else {2970return ffsd->underline_thickness;2971}2972}29732974void TextServerAdvanced::_font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) {2975FontAdvanced *fd = _get_font_data(p_font_rid);2976ERR_FAIL_NULL(fd);29772978MutexLock lock(fd->mutex);2979Vector2i size = _get_size(fd, p_size);29802981FontForSizeAdvanced *ffsd = nullptr;2982ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));29832984#ifdef MODULE_FREETYPE_ENABLED2985if (ffsd->face) {2986return; // Do not override scale for dynamic fonts, it's calculated automatically.2987}2988#endif2989ffsd->scale = p_scale;2990}29912992double TextServerAdvanced::_font_get_scale(const RID &p_font_rid, int64_t p_size) const {2993FontAdvanced *fd = _get_font_data(p_font_rid);2994ERR_FAIL_NULL_V(fd, 0.0);29952996MutexLock lock(fd->mutex);2997Vector2i size = _get_size(fd, p_size);29982999FontForSizeAdvanced *ffsd = nullptr;3000ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);30013002if (fd->msdf) {3003return ffsd->scale * (double)p_size / (double)fd->msdf_source_size;3004} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {3005if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3006return ffsd->scale * (double)p_size / (double)fd->fixed_size;3007} else {3008return ffsd->scale * Math::round((double)p_size / (double)fd->fixed_size);3009}3010} else {3011return ffsd->scale;3012}3013}30143015int64_t TextServerAdvanced::_font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const {3016FontAdvanced *fd = _get_font_data(p_font_rid);3017ERR_FAIL_NULL_V(fd, 0);30183019MutexLock lock(fd->mutex);3020Vector2i size = _get_size_outline(fd, p_size);30213022FontForSizeAdvanced *ffsd = nullptr;3023ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0);30243025return ffsd->textures.size();3026}30273028void TextServerAdvanced::_font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) {3029FontAdvanced *fd = _get_font_data(p_font_rid);3030ERR_FAIL_NULL(fd);3031MutexLock lock(fd->mutex);3032Vector2i size = _get_size_outline(fd, p_size);30333034FontForSizeAdvanced *ffsd = nullptr;3035ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3036ffsd->textures.clear();3037}30383039void TextServerAdvanced::_font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) {3040FontAdvanced *fd = _get_font_data(p_font_rid);3041ERR_FAIL_NULL(fd);30423043MutexLock lock(fd->mutex);3044Vector2i size = _get_size_outline(fd, p_size);3045FontForSizeAdvanced *ffsd = nullptr;3046ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3047ERR_FAIL_INDEX(p_texture_index, ffsd->textures.size());30483049ffsd->textures.remove_at(p_texture_index);3050}30513052void TextServerAdvanced::_font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) {3053FontAdvanced *fd = _get_font_data(p_font_rid);3054ERR_FAIL_NULL(fd);3055ERR_FAIL_COND(p_image.is_null());30563057MutexLock lock(fd->mutex);3058Vector2i size = _get_size_outline(fd, p_size);3059FontForSizeAdvanced *ffsd = nullptr;3060ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3061ERR_FAIL_COND(p_texture_index < 0);3062if (p_texture_index >= ffsd->textures.size()) {3063ffsd->textures.resize(p_texture_index + 1);3064}30653066ShelfPackTexture &tex = ffsd->textures.write[p_texture_index];30673068tex.image = p_image;3069tex.texture_w = p_image->get_width();3070tex.texture_h = p_image->get_height();30713072Ref<Image> img = p_image;3073if (fd->mipmaps && !img->has_mipmaps()) {3074img = p_image->duplicate();3075img->generate_mipmaps();3076}3077tex.texture = ImageTexture::create_from_image(img);3078tex.dirty = false;3079}30803081Ref<Image> TextServerAdvanced::_font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {3082FontAdvanced *fd = _get_font_data(p_font_rid);3083ERR_FAIL_NULL_V(fd, Ref<Image>());30843085MutexLock lock(fd->mutex);3086Vector2i size = _get_size_outline(fd, p_size);3087FontForSizeAdvanced *ffsd = nullptr;3088ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Ref<Image>());3089ERR_FAIL_INDEX_V(p_texture_index, ffsd->textures.size(), Ref<Image>());30903091const ShelfPackTexture &tex = ffsd->textures[p_texture_index];3092return tex.image;3093}30943095void TextServerAdvanced::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offsets) {3096ERR_FAIL_COND(p_offsets.size() % 4 != 0);3097FontAdvanced *fd = _get_font_data(p_font_rid);3098ERR_FAIL_NULL(fd);30993100MutexLock lock(fd->mutex);3101Vector2i size = _get_size_outline(fd, p_size);3102FontForSizeAdvanced *ffsd = nullptr;3103ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3104ERR_FAIL_COND(p_texture_index < 0);3105if (p_texture_index >= ffsd->textures.size()) {3106ffsd->textures.resize(p_texture_index + 1);3107}31083109ShelfPackTexture &tex = ffsd->textures.write[p_texture_index];3110tex.shelves.clear();3111for (int32_t i = 0; i < p_offsets.size(); i += 4) {3112tex.shelves.push_back(Shelf(p_offsets[i], p_offsets[i + 1], p_offsets[i + 2], p_offsets[i + 3]));3113}3114}31153116PackedInt32Array TextServerAdvanced::_font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {3117FontAdvanced *fd = _get_font_data(p_font_rid);3118ERR_FAIL_NULL_V(fd, PackedInt32Array());31193120MutexLock lock(fd->mutex);3121Vector2i size = _get_size_outline(fd, p_size);3122FontForSizeAdvanced *ffsd = nullptr;3123ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), PackedInt32Array());3124ERR_FAIL_INDEX_V(p_texture_index, ffsd->textures.size(), PackedInt32Array());31253126const ShelfPackTexture &tex = ffsd->textures[p_texture_index];3127PackedInt32Array ret;3128ret.resize(tex.shelves.size() * 4);31293130int32_t *wr = ret.ptrw();3131int32_t i = 0;3132for (const Shelf &E : tex.shelves) {3133wr[i * 4] = E.x;3134wr[i * 4 + 1] = E.y;3135wr[i * 4 + 2] = E.w;3136wr[i * 4 + 3] = E.h;3137i++;3138}3139return ret;3140}31413142PackedInt32Array TextServerAdvanced::_font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {3143FontAdvanced *fd = _get_font_data(p_font_rid);3144ERR_FAIL_NULL_V(fd, PackedInt32Array());31453146MutexLock lock(fd->mutex);3147Vector2i size = _get_size_outline(fd, p_size);3148FontForSizeAdvanced *ffsd = nullptr;3149ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), PackedInt32Array());31503151PackedInt32Array ret;3152const HashMap<int32_t, FontGlyph> &gl = ffsd->glyph_map;3153for (const KeyValue<int32_t, FontGlyph> &E : gl) {3154ret.push_back(E.key);3155}3156return ret;3157}31583159void TextServerAdvanced::_font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) {3160FontAdvanced *fd = _get_font_data(p_font_rid);3161ERR_FAIL_NULL(fd);31623163MutexLock lock(fd->mutex);3164Vector2i size = _get_size_outline(fd, p_size);3165FontForSizeAdvanced *ffsd = nullptr;3166ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));31673168ffsd->glyph_map.clear();3169}31703171void TextServerAdvanced::_font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) {3172FontAdvanced *fd = _get_font_data(p_font_rid);3173ERR_FAIL_NULL(fd);31743175MutexLock lock(fd->mutex);3176Vector2i size = _get_size_outline(fd, p_size);3177FontForSizeAdvanced *ffsd = nullptr;3178ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));31793180ffsd->glyph_map.erase(p_glyph);3181}31823183double TextServerAdvanced::_get_extra_advance(RID p_font_rid, int p_font_size) const {3184const FontAdvanced *fd = _get_font_data(p_font_rid);3185ERR_FAIL_NULL_V(fd, 0.0);31863187MutexLock lock(fd->mutex);3188Vector2i size = _get_size(fd, p_font_size);31893190if (fd->embolden != 0.0) {3191return fd->embolden * double(size.x) / 4096.0;3192} else {3193return 0.0;3194}3195}31963197Vector2 TextServerAdvanced::_font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const {3198FontAdvanced *fd = _get_font_data(p_font_rid);3199ERR_FAIL_NULL_V(fd, Vector2());32003201MutexLock lock(fd->mutex);3202Vector2i size = _get_size(fd, p_size);32033204FontForSizeAdvanced *ffsd = nullptr;3205ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());32063207int mod = 0;3208if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3209TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3210if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3211mod = (layout << 24);3212}3213}32143215FontGlyph fgl;3216if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3217return Vector2(); // Invalid or non graphicl glyph, do not display errors.3218}32193220Vector2 ea;3221if (fd->embolden != 0.0) {3222ea.x = fd->embolden * double(size.x) / 4096.0;3223}32243225double scale = _font_get_scale(p_font_rid, p_size);3226if (fd->msdf) {3227return (fgl.advance + ea) * (double)p_size / (double)fd->msdf_source_size;3228} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {3229if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3230return (fgl.advance + ea) * (double)p_size / (double)fd->fixed_size;3231} else {3232return (fgl.advance + ea) * Math::round((double)p_size / (double)fd->fixed_size);3233}3234} else if ((scale == 1.0) && ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_DISABLED) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x > SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64))) {3235return (fgl.advance + ea).round();3236} else {3237return fgl.advance + ea;3238}3239}32403241void TextServerAdvanced::_font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) {3242FontAdvanced *fd = _get_font_data(p_font_rid);3243ERR_FAIL_NULL(fd);32443245MutexLock lock(fd->mutex);3246Vector2i size = _get_size(fd, p_size);32473248FontForSizeAdvanced *ffsd = nullptr;3249ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));32503251FontGlyph &fgl = ffsd->glyph_map[p_glyph];32523253fgl.advance = p_advance;3254fgl.found = true;3255}32563257Vector2 TextServerAdvanced::_font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3258FontAdvanced *fd = _get_font_data(p_font_rid);3259ERR_FAIL_NULL_V(fd, Vector2());32603261MutexLock lock(fd->mutex);3262Vector2i size = _get_size_outline(fd, p_size);32633264FontForSizeAdvanced *ffsd = nullptr;3265ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());32663267int mod = 0;3268if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3269TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3270if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3271mod = (layout << 24);3272}3273}32743275FontGlyph fgl;3276if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3277return Vector2(); // Invalid or non graphicl glyph, do not display errors.3278}32793280if (fd->msdf) {3281return fgl.rect.position * (double)p_size.x / (double)fd->msdf_source_size;3282} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size.x * 64) {3283if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3284return fgl.rect.position * (double)p_size.x / (double)fd->fixed_size;3285} else {3286return fgl.rect.position * Math::round((double)p_size.x / (double)fd->fixed_size);3287}3288} else {3289return fgl.rect.position;3290}3291}32923293void TextServerAdvanced::_font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) {3294FontAdvanced *fd = _get_font_data(p_font_rid);3295ERR_FAIL_NULL(fd);32963297MutexLock lock(fd->mutex);3298Vector2i size = _get_size_outline(fd, p_size);32993300FontForSizeAdvanced *ffsd = nullptr;3301ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));33023303FontGlyph &fgl = ffsd->glyph_map[p_glyph];33043305fgl.rect.position = p_offset;3306fgl.found = true;3307}33083309Vector2 TextServerAdvanced::_font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3310FontAdvanced *fd = _get_font_data(p_font_rid);3311ERR_FAIL_NULL_V(fd, Vector2());33123313MutexLock lock(fd->mutex);3314Vector2i size = _get_size_outline(fd, p_size);33153316FontForSizeAdvanced *ffsd = nullptr;3317ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());33183319int mod = 0;3320if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3321TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3322if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3323mod = (layout << 24);3324}3325}33263327FontGlyph fgl;3328if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3329return Vector2(); // Invalid or non graphicl glyph, do not display errors.3330}33313332if (fd->msdf) {3333return fgl.rect.size * (double)p_size.x / (double)fd->msdf_source_size;3334} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size.x * 64) {3335if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3336return fgl.rect.size * (double)p_size.x / (double)fd->fixed_size;3337} else {3338return fgl.rect.size * Math::round((double)p_size.x / (double)fd->fixed_size);3339}3340} else {3341return fgl.rect.size;3342}3343}33443345void TextServerAdvanced::_font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) {3346FontAdvanced *fd = _get_font_data(p_font_rid);3347ERR_FAIL_NULL(fd);33483349MutexLock lock(fd->mutex);3350Vector2i size = _get_size_outline(fd, p_size);33513352FontForSizeAdvanced *ffsd = nullptr;3353ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));33543355FontGlyph &fgl = ffsd->glyph_map[p_glyph];33563357fgl.rect.size = p_gl_size;3358fgl.found = true;3359}33603361Rect2 TextServerAdvanced::_font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3362FontAdvanced *fd = _get_font_data(p_font_rid);3363ERR_FAIL_NULL_V(fd, Rect2());33643365MutexLock lock(fd->mutex);3366Vector2i size = _get_size_outline(fd, p_size);33673368FontForSizeAdvanced *ffsd = nullptr;3369ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Rect2());33703371int mod = 0;3372if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3373TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3374if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3375mod = (layout << 24);3376}3377}33783379FontGlyph fgl;3380if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3381return Rect2(); // Invalid or non graphicl glyph, do not display errors.3382}33833384return fgl.uv_rect;3385}33863387void TextServerAdvanced::_font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) {3388FontAdvanced *fd = _get_font_data(p_font_rid);3389ERR_FAIL_NULL(fd);33903391MutexLock lock(fd->mutex);3392Vector2i size = _get_size_outline(fd, p_size);33933394FontForSizeAdvanced *ffsd = nullptr;3395ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));33963397FontGlyph &fgl = ffsd->glyph_map[p_glyph];33983399fgl.uv_rect = p_uv_rect;3400fgl.found = true;3401}34023403int64_t TextServerAdvanced::_font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3404FontAdvanced *fd = _get_font_data(p_font_rid);3405ERR_FAIL_NULL_V(fd, -1);34063407MutexLock lock(fd->mutex);3408Vector2i size = _get_size_outline(fd, p_size);34093410FontForSizeAdvanced *ffsd = nullptr;3411ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), -1);34123413int mod = 0;3414if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3415TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3416if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3417mod = (layout << 24);3418}3419}34203421FontGlyph fgl;3422if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3423return -1; // Invalid or non graphicl glyph, do not display errors.3424}34253426return fgl.texture_idx;3427}34283429void TextServerAdvanced::_font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) {3430FontAdvanced *fd = _get_font_data(p_font_rid);3431ERR_FAIL_NULL(fd);34323433MutexLock lock(fd->mutex);3434Vector2i size = _get_size_outline(fd, p_size);34353436FontForSizeAdvanced *ffsd = nullptr;3437ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));34383439FontGlyph &fgl = ffsd->glyph_map[p_glyph];34403441fgl.texture_idx = p_texture_idx;3442fgl.found = true;3443}34443445RID TextServerAdvanced::_font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3446FontAdvanced *fd = _get_font_data(p_font_rid);3447ERR_FAIL_NULL_V(fd, RID());34483449MutexLock lock(fd->mutex);3450Vector2i size = _get_size_outline(fd, p_size);34513452FontForSizeAdvanced *ffsd = nullptr;3453ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), RID());34543455int mod = 0;3456if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3457TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3458if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3459mod = (layout << 24);3460}3461}34623463FontGlyph fgl;3464if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3465return RID(); // Invalid or non graphicl glyph, do not display errors.3466}34673468ERR_FAIL_COND_V(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size(), RID());34693470if (RenderingServer::get_singleton() != nullptr) {3471if (fgl.texture_idx != -1) {3472if (ffsd->textures[fgl.texture_idx].dirty) {3473ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];3474Ref<Image> img = tex.image;3475if (fgl.from_svg) {3476// Same as the "fix alpha border" process option when importing SVGs3477img->fix_alpha_edges();3478}3479if (fd->mipmaps && !img->has_mipmaps()) {3480img = tex.image->duplicate();3481img->generate_mipmaps();3482}3483if (tex.texture.is_null()) {3484tex.texture = ImageTexture::create_from_image(img);3485} else {3486tex.texture->update(img);3487}3488tex.dirty = false;3489}3490return ffsd->textures[fgl.texture_idx].texture->get_rid();3491}3492}34933494return RID();3495}34963497Size2 TextServerAdvanced::_font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3498FontAdvanced *fd = _get_font_data(p_font_rid);3499ERR_FAIL_NULL_V(fd, Size2());35003501MutexLock lock(fd->mutex);3502Vector2i size = _get_size_outline(fd, p_size);35033504FontForSizeAdvanced *ffsd = nullptr;3505ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Size2());35063507int mod = 0;3508if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3509TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3510if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3511mod = (layout << 24);3512}3513}35143515FontGlyph fgl;3516if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3517return Size2(); // Invalid or non graphicl glyph, do not display errors.3518}35193520ERR_FAIL_COND_V(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size(), Size2());35213522if (RenderingServer::get_singleton() != nullptr) {3523if (fgl.texture_idx != -1) {3524if (ffsd->textures[fgl.texture_idx].dirty) {3525ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];3526Ref<Image> img = tex.image;3527if (fgl.from_svg) {3528// Same as the "fix alpha border" process option when importing SVGs3529img->fix_alpha_edges();3530}3531if (fd->mipmaps && !img->has_mipmaps()) {3532img = tex.image->duplicate();3533img->generate_mipmaps();3534}3535if (tex.texture.is_null()) {3536tex.texture = ImageTexture::create_from_image(img);3537} else {3538tex.texture->update(img);3539}3540tex.dirty = false;3541}3542return ffsd->textures[fgl.texture_idx].texture->get_size();3543}3544}35453546return Size2();3547}35483549Dictionary TextServerAdvanced::_font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const {3550FontAdvanced *fd = _get_font_data(p_font_rid);3551ERR_FAIL_NULL_V(fd, Dictionary());35523553MutexLock lock(fd->mutex);3554Vector2i size = _get_size(fd, p_size);35553556FontForSizeAdvanced *ffsd = nullptr;3557ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary());35583559#ifdef MODULE_FREETYPE_ENABLED3560PackedVector3Array points;3561PackedInt32Array contours;35623563int32_t index = p_index & 0xffffff; // Remove subpixel shifts.35643565int error = FT_Load_Glyph(ffsd->face, index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));3566ERR_FAIL_COND_V(error, Dictionary());35673568if (fd->embolden != 0.f) {3569FT_Pos strength = fd->embolden * size.x / 16; // 26.6 fractional units (1 / 64).3570FT_Outline_Embolden(&ffsd->face->glyph->outline, strength);3571}35723573if (fd->transform != Transform2D()) {3574FT_Matrix mat = { FT_Fixed(fd->transform[0][0] * 65536), FT_Fixed(fd->transform[0][1] * 65536), FT_Fixed(fd->transform[1][0] * 65536), FT_Fixed(fd->transform[1][1] * 65536) }; // 16.16 fractional units (1 / 65536).3575FT_Outline_Transform(&ffsd->face->glyph->outline, &mat);3576}35773578double scale = (1.0 / 64.0) * ffsd->scale;3579if (fd->msdf) {3580scale = scale * (double)p_size / (double)fd->msdf_source_size;3581} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {3582if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3583scale = scale * (double)p_size / (double)fd->fixed_size;3584} else {3585scale = scale * Math::round((double)p_size / (double)fd->fixed_size);3586}3587}3588for (short i = 0; i < ffsd->face->glyph->outline.n_points; i++) {3589points.push_back(Vector3(ffsd->face->glyph->outline.points[i].x * scale, -ffsd->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(ffsd->face->glyph->outline.tags[i])));3590}3591for (short i = 0; i < ffsd->face->glyph->outline.n_contours; i++) {3592contours.push_back(ffsd->face->glyph->outline.contours[i]);3593}3594bool orientation = (FT_Outline_Get_Orientation(&ffsd->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);35953596Dictionary out;3597out["points"] = points;3598out["contours"] = contours;3599out["orientation"] = orientation;3600return out;3601#else3602return Dictionary();3603#endif3604}36053606TypedArray<Vector2i> TextServerAdvanced::_font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {3607FontAdvanced *fd = _get_font_data(p_font_rid);3608ERR_FAIL_NULL_V(fd, TypedArray<Vector2i>());36093610MutexLock lock(fd->mutex);3611Vector2i size = _get_size(fd, p_size);36123613FontForSizeAdvanced *ffsd = nullptr;3614ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), TypedArray<Vector2i>());36153616TypedArray<Vector2i> ret;3617for (const KeyValue<Vector2i, Vector2> &E : fd->cache[size]->kerning_map) {3618ret.push_back(E.key);3619}3620return ret;3621}36223623void TextServerAdvanced::_font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) {3624FontAdvanced *fd = _get_font_data(p_font_rid);3625ERR_FAIL_NULL(fd);36263627MutexLock lock(fd->mutex);3628Vector2i size = _get_size(fd, p_size);36293630FontForSizeAdvanced *ffsd = nullptr;3631ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3632ffsd->kerning_map.clear();3633}36343635void TextServerAdvanced::_font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) {3636FontAdvanced *fd = _get_font_data(p_font_rid);3637ERR_FAIL_NULL(fd);36383639MutexLock lock(fd->mutex);3640Vector2i size = _get_size(fd, p_size);36413642FontForSizeAdvanced *ffsd = nullptr;3643ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3644ffsd->kerning_map.erase(p_glyph_pair);3645}36463647void TextServerAdvanced::_font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {3648FontAdvanced *fd = _get_font_data(p_font_rid);3649ERR_FAIL_NULL(fd);36503651MutexLock lock(fd->mutex);3652Vector2i size = _get_size(fd, p_size);36533654FontForSizeAdvanced *ffsd = nullptr;3655ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3656ffsd->kerning_map[p_glyph_pair] = p_kerning;3657}36583659Vector2 TextServerAdvanced::_font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const {3660FontAdvanced *fd = _get_font_data(p_font_rid);3661ERR_FAIL_NULL_V(fd, Vector2());36623663MutexLock lock(fd->mutex);3664Vector2i size = _get_size(fd, p_size);36653666FontForSizeAdvanced *ffsd = nullptr;3667ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());36683669const HashMap<Vector2i, Vector2> &kern = ffsd->kerning_map;36703671if (kern.has(p_glyph_pair)) {3672if (fd->msdf) {3673return kern[p_glyph_pair] * (double)p_size / (double)fd->msdf_source_size;3674} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {3675if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3676return kern[p_glyph_pair] * (double)p_size / (double)fd->fixed_size;3677} else {3678return kern[p_glyph_pair] * Math::round((double)p_size / (double)fd->fixed_size);3679}3680} else {3681return kern[p_glyph_pair];3682}3683} else {3684#ifdef MODULE_FREETYPE_ENABLED3685if (ffsd->face) {3686FT_Vector delta;3687FT_Get_Kerning(ffsd->face, p_glyph_pair.x, p_glyph_pair.y, FT_KERNING_DEFAULT, &delta);3688if (fd->msdf) {3689return Vector2(delta.x, delta.y) * (double)p_size / (double)fd->msdf_source_size;3690} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {3691if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3692return Vector2(delta.x, delta.y) * (double)p_size / (double)fd->fixed_size;3693} else {3694return Vector2(delta.x, delta.y) * Math::round((double)p_size / (double)fd->fixed_size);3695}3696} else {3697return Vector2(delta.x, delta.y);3698}3699}3700#endif3701}3702return Vector2();3703}37043705int64_t TextServerAdvanced::_font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const {3706FontAdvanced *fd = _get_font_data(p_font_rid);3707ERR_FAIL_NULL_V(fd, 0);3708ERR_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) + ".");3709ERR_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) + ".");37103711MutexLock lock(fd->mutex);3712Vector2i size = _get_size(fd, p_size);3713FontForSizeAdvanced *ffsd = nullptr;3714ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0);37153716#ifdef MODULE_FREETYPE_ENABLED3717if (ffsd->face) {3718if (p_variation_selector) {3719return FT_Face_GetCharVariantIndex(ffsd->face, p_char, p_variation_selector);3720} else {3721return FT_Get_Char_Index(ffsd->face, p_char);3722}3723} else {3724return (int64_t)p_char;3725}3726#else3727return (int64_t)p_char;3728#endif3729}37303731int64_t TextServerAdvanced::_font_get_char_from_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_glyph_index) const {3732FontAdvanced *fd = _get_font_data(p_font_rid);3733ERR_FAIL_NULL_V(fd, 0);37343735MutexLock lock(fd->mutex);3736Vector2i size = _get_size(fd, p_size);3737FontForSizeAdvanced *ffsd = nullptr;3738ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0);37393740#ifdef MODULE_FREETYPE_ENABLED3741if (ffsd->inv_glyph_map.is_empty()) {3742FT_Face face = ffsd->face;3743FT_UInt gindex;3744FT_ULong charcode = FT_Get_First_Char(face, &gindex);3745while (gindex != 0) {3746if (charcode != 0) {3747ffsd->inv_glyph_map[gindex] = charcode;3748}3749charcode = FT_Get_Next_Char(face, charcode, &gindex);3750}3751}37523753if (ffsd->inv_glyph_map.has(p_glyph_index)) {3754return ffsd->inv_glyph_map[p_glyph_index];3755} else {3756return 0;3757}3758#else3759return p_glyph_index;3760#endif3761}37623763bool TextServerAdvanced::_font_has_char(const RID &p_font_rid, int64_t p_char) const {3764FontAdvanced *fd = _get_font_data(p_font_rid);3765ERR_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) + ".");3766if (!fd) {3767return false;3768}37693770MutexLock lock(fd->mutex);3771FontForSizeAdvanced *ffsd = nullptr;3772if (fd->cache.is_empty()) {3773ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size * 64, 0) : Vector2i(16 * 64, 0), ffsd), false);3774} else {3775ffsd = fd->cache.begin()->value;3776}37773778#ifdef MODULE_FREETYPE_ENABLED3779if (ffsd->face) {3780return FT_Get_Char_Index(ffsd->face, p_char) != 0;3781}3782#endif3783return ffsd->glyph_map.has((int32_t)p_char);3784}37853786String TextServerAdvanced::_font_get_supported_chars(const RID &p_font_rid) const {3787FontAdvanced *fd = _get_font_data(p_font_rid);3788ERR_FAIL_NULL_V(fd, String());37893790MutexLock lock(fd->mutex);3791FontForSizeAdvanced *ffsd = nullptr;3792if (fd->cache.is_empty()) {3793ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size * 64, 0) : Vector2i(16 * 64, 0), ffsd), String());3794} else {3795ffsd = fd->cache.begin()->value;3796}37973798String chars;3799#ifdef MODULE_FREETYPE_ENABLED3800if (ffsd->face) {3801FT_UInt gindex;3802FT_ULong charcode = FT_Get_First_Char(ffsd->face, &gindex);3803while (gindex != 0) {3804if (charcode != 0) {3805chars = chars + String::chr(charcode);3806}3807charcode = FT_Get_Next_Char(ffsd->face, charcode, &gindex);3808}3809return chars;3810}3811#endif3812const HashMap<int32_t, FontGlyph> &gl = ffsd->glyph_map;3813for (const KeyValue<int32_t, FontGlyph> &E : gl) {3814chars = chars + String::chr(E.key);3815}3816return chars;3817}38183819PackedInt32Array TextServerAdvanced::_font_get_supported_glyphs(const RID &p_font_rid) const {3820FontAdvanced *fd = _get_font_data(p_font_rid);3821ERR_FAIL_NULL_V(fd, PackedInt32Array());38223823MutexLock lock(fd->mutex);3824FontForSizeAdvanced *at_size = nullptr;3825if (fd->cache.is_empty()) {3826ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size * 64, 0) : Vector2i(16 * 64, 0), at_size), PackedInt32Array());3827} else {3828at_size = fd->cache.begin()->value;3829}38303831PackedInt32Array glyphs;3832#ifdef MODULE_FREETYPE_ENABLED3833if (at_size && at_size->face) {3834FT_UInt gindex;3835FT_ULong charcode = FT_Get_First_Char(at_size->face, &gindex);3836while (gindex != 0) {3837glyphs.push_back(gindex);3838charcode = FT_Get_Next_Char(at_size->face, charcode, &gindex);3839}3840return glyphs;3841}3842#endif3843if (at_size) {3844const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map;3845for (const KeyValue<int32_t, FontGlyph> &E : gl) {3846glyphs.push_back(E.key);3847}3848}3849return glyphs;3850}38513852void TextServerAdvanced::_font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) {3853FontAdvanced *fd = _get_font_data(p_font_rid);3854ERR_FAIL_NULL(fd);3855ERR_FAIL_COND_MSG((p_start >= 0xd800 && p_start <= 0xdfff) || (p_start > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_start, 16) + ".");3856ERR_FAIL_COND_MSG((p_end >= 0xd800 && p_end <= 0xdfff) || (p_end > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_end, 16) + ".");38573858MutexLock lock(fd->mutex);3859Vector2i size = _get_size_outline(fd, p_size);3860FontForSizeAdvanced *ffsd = nullptr;3861ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3862for (int64_t i = p_start; i <= p_end; i++) {3863#ifdef MODULE_FREETYPE_ENABLED3864int32_t idx = FT_Get_Char_Index(ffsd->face, i);3865if (ffsd->face) {3866FontGlyph fgl;3867if (fd->msdf) {3868_ensure_glyph(fd, size, (int32_t)idx, fgl);3869} else {3870for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {3871if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {3872_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);3873_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);3874_ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24), fgl);3875_ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24), fgl);3876} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {3877_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);3878_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);3879} else {3880_ensure_glyph(fd, size, (int32_t)idx | (aa << 24), fgl);3881}3882}3883}3884}3885#endif3886}3887}38883889void TextServerAdvanced::_font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) {3890FontAdvanced *fd = _get_font_data(p_font_rid);3891ERR_FAIL_NULL(fd);38923893MutexLock lock(fd->mutex);3894Vector2i size = _get_size_outline(fd, p_size);3895FontForSizeAdvanced *ffsd = nullptr;3896ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3897#ifdef MODULE_FREETYPE_ENABLED3898int32_t idx = p_index & 0xffffff; // Remove subpixel shifts.3899if (ffsd->face) {3900FontGlyph fgl;3901if (fd->msdf) {3902_ensure_glyph(fd, size, (int32_t)idx, fgl);3903} else {3904for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {3905if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {3906_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);3907_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);3908_ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24), fgl);3909_ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24), fgl);3910} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {3911_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);3912_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);3913} else {3914_ensure_glyph(fd, size, (int32_t)idx | (aa << 24), fgl);3915}3916}3917}3918}3919#endif3920}39213922void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {3923if (p_index == 0) {3924return; // Non visual character, skip.3925}3926FontAdvanced *fd = _get_font_data(p_font_rid);3927ERR_FAIL_NULL(fd);39283929MutexLock lock(fd->mutex);39303931// Oversampling.3932bool viewport_oversampling = false;3933float oversampling_factor = p_oversampling;3934if (p_oversampling <= 0.0) {3935if (fd->oversampling_override > 0.0) {3936oversampling_factor = fd->oversampling_override;3937} else if (vp_oversampling > 0.0) {3938oversampling_factor = vp_oversampling;3939viewport_oversampling = true;3940} else {3941oversampling_factor = 1.0;3942}3943}3944bool skip_oversampling = fd->msdf || fd->fixed_size > 0;3945if (skip_oversampling) {3946oversampling_factor = 1.0;3947} else {3948uint64_t oversampling_level = CLAMP(oversampling_factor, 0.1, 100.0) * 64;3949oversampling_factor = double(oversampling_level) / 64.0;3950}39513952Vector2i size;3953if (skip_oversampling) {3954size = _get_size(fd, p_size);3955} else {3956size = Vector2i(p_size * 64 * oversampling_factor, 0);3957}39583959FontForSizeAdvanced *ffsd = nullptr;3960ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd, false, viewport_oversampling ? 64 * oversampling_factor : 0));39613962int32_t index = p_index & 0xffffff; // Remove subpixel shifts.3963bool lcd_aa = false;39643965#ifdef MODULE_FREETYPE_ENABLED3966if (!fd->msdf && ffsd->face) {3967// LCD layout, bits 24, 25, 263968if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3969TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3970if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3971lcd_aa = true;3972index = index | (layout << 24);3973}3974}3975// Subpixel X-shift, bits 27, 283976if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {3977int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));3978index = index | (xshift << 27);3979} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {3980int xshift = (int)(Math::floor(2 * (p_pos.x + 0.25)) - 2 * Math::floor(p_pos.x + 0.25));3981index = index | (xshift << 27);3982}3983}3984#endif39853986FontGlyph fgl;3987if (!_ensure_glyph(fd, size, index, fgl, viewport_oversampling ? 64 * oversampling_factor : 0)) {3988return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.3989}39903991if (fgl.found) {3992ERR_FAIL_COND(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size());39933994if (fgl.texture_idx != -1) {3995Color modulate = p_color;3996#ifdef MODULE_FREETYPE_ENABLED3997if (!fd->modulate_color_glyphs && ffsd->face && ffsd->textures[fgl.texture_idx].image.is_valid() && (ffsd->textures[fgl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {3998modulate.r = modulate.g = modulate.b = 1.0;3999}4000#endif4001if (RenderingServer::get_singleton() != nullptr) {4002if (ffsd->textures[fgl.texture_idx].dirty) {4003ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];4004Ref<Image> img = tex.image;4005if (fgl.from_svg) {4006// Same as the "fix alpha border" process option when importing SVGs4007img->fix_alpha_edges();4008}4009if (fd->mipmaps && !img->has_mipmaps()) {4010img = tex.image->duplicate();4011img->generate_mipmaps();4012}4013if (tex.texture.is_null()) {4014tex.texture = ImageTexture::create_from_image(img);4015} else {4016tex.texture->update(img);4017}4018tex.dirty = false;4019}4020RID texture = ffsd->textures[fgl.texture_idx].texture->get_rid();4021if (fd->msdf) {4022Point2 cpos = p_pos;4023cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size;4024Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size;4025RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, 0, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size);4026} else {4027Point2 cpos = p_pos;4028double scale = _font_get_scale(p_font_rid, p_size) / oversampling_factor;4029if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {4030cpos.x = cpos.x + 0.125;4031} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {4032cpos.x = cpos.x + 0.25;4033}4034if (scale == 1.0) {4035cpos.y = Math::floor(cpos.y);4036cpos.x = Math::floor(cpos.x);4037}4038Vector2 gpos = fgl.rect.position;4039Size2 csize = fgl.rect.size;4040if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE) {4041if (size.x != p_size * 64) {4042if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {4043double gl_scale = (double)p_size / (double)fd->fixed_size;4044gpos *= gl_scale;4045csize *= gl_scale;4046} else {4047double gl_scale = Math::round((double)p_size / (double)fd->fixed_size);4048gpos *= gl_scale;4049csize *= gl_scale;4050}4051}4052} else {4053gpos /= oversampling_factor;4054csize /= oversampling_factor;4055}4056cpos += gpos;4057if (lcd_aa) {4058RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate);4059} else {4060RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false);4061}4062}4063}4064}4065}4066}40674068void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {4069if (p_index == 0) {4070return; // Non visual character, skip.4071}4072FontAdvanced *fd = _get_font_data(p_font_rid);4073ERR_FAIL_NULL(fd);40744075MutexLock lock(fd->mutex);40764077// Oversampling.4078bool viewport_oversampling = false;4079float oversampling_factor = p_oversampling;4080if (p_oversampling <= 0.0) {4081if (fd->oversampling_override > 0.0) {4082oversampling_factor = fd->oversampling_override;4083} else if (vp_oversampling > 0.0) {4084oversampling_factor = vp_oversampling;4085viewport_oversampling = true;4086} else {4087oversampling_factor = 1.0;4088}4089}4090bool skip_oversampling = fd->msdf || fd->fixed_size > 0;4091if (skip_oversampling) {4092oversampling_factor = 1.0;4093} else {4094uint64_t oversampling_level = CLAMP(oversampling_factor, 0.1, 100.0) * 64;4095oversampling_factor = double(oversampling_level) / 64.0;4096}40974098Vector2i size;4099if (skip_oversampling) {4100size = _get_size_outline(fd, Vector2i(p_size, p_outline_size));4101} else {4102size = Vector2i(p_size * 64 * oversampling_factor, p_outline_size * oversampling_factor);4103}41044105FontForSizeAdvanced *ffsd = nullptr;4106ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd, false, viewport_oversampling ? 64 * oversampling_factor : 0));41074108int32_t index = p_index & 0xffffff; // Remove subpixel shifts.4109bool lcd_aa = false;41104111#ifdef MODULE_FREETYPE_ENABLED4112if (!fd->msdf && ffsd->face) {4113// LCD layout, bits 24, 25, 264114if (fd->antialiasing == FONT_ANTIALIASING_LCD) {4115TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();4116if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {4117lcd_aa = true;4118index = index | (layout << 24);4119}4120}4121// Subpixel X-shift, bits 27, 284122if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {4123int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));4124index = index | (xshift << 27);4125} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {4126int xshift = (int)(Math::floor(2 * (p_pos.x + 0.25)) - 2 * Math::floor(p_pos.x + 0.25));4127index = index | (xshift << 27);4128}4129}4130#endif41314132FontGlyph fgl;4133if (!_ensure_glyph(fd, size, index, fgl, viewport_oversampling ? 64 * oversampling_factor : 0)) {4134return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.4135}41364137if (fgl.found) {4138ERR_FAIL_COND(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size());41394140if (fgl.texture_idx != -1) {4141Color modulate = p_color;4142#ifdef MODULE_FREETYPE_ENABLED4143if (ffsd->face && fd->cache[size]->textures[fgl.texture_idx].image.is_valid() && (ffsd->textures[fgl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {4144modulate.r = modulate.g = modulate.b = 1.0;4145}4146#endif4147if (RenderingServer::get_singleton() != nullptr) {4148if (ffsd->textures[fgl.texture_idx].dirty) {4149ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];4150Ref<Image> img = tex.image;4151if (fd->mipmaps && !img->has_mipmaps()) {4152img = tex.image->duplicate();4153img->generate_mipmaps();4154}4155if (tex.texture.is_null()) {4156tex.texture = ImageTexture::create_from_image(img);4157} else {4158tex.texture->update(img);4159}4160tex.dirty = false;4161}4162RID texture = ffsd->textures[fgl.texture_idx].texture->get_rid();4163if (fd->msdf) {4164Point2 cpos = p_pos;4165cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size;4166Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size;4167RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, p_outline_size, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size);4168} else {4169Point2 cpos = p_pos;4170double scale = _font_get_scale(p_font_rid, p_size) / oversampling_factor;4171if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {4172cpos.x = cpos.x + 0.125;4173} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {4174cpos.x = cpos.x + 0.25;4175}4176if (scale == 1.0) {4177cpos.y = Math::floor(cpos.y);4178cpos.x = Math::floor(cpos.x);4179}4180Vector2 gpos = fgl.rect.position;4181Size2 csize = fgl.rect.size;4182if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE) {4183if (size.x != p_size * 64) {4184if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {4185double gl_scale = (double)p_size / (double)fd->fixed_size;4186gpos *= gl_scale;4187csize *= gl_scale;4188} else {4189double gl_scale = Math::round((double)p_size / (double)fd->fixed_size);4190gpos *= gl_scale;4191csize *= gl_scale;4192}4193}4194} else {4195gpos /= oversampling_factor;4196csize /= oversampling_factor;4197}4198cpos += gpos;4199if (lcd_aa) {4200RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate);4201} else {4202RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false);4203}4204}4205}4206}4207}4208}42094210bool TextServerAdvanced::_font_is_language_supported(const RID &p_font_rid, const String &p_language) const {4211FontAdvanced *fd = _get_font_data(p_font_rid);4212ERR_FAIL_NULL_V(fd, false);42134214MutexLock lock(fd->mutex);4215if (fd->language_support_overrides.has(p_language)) {4216return fd->language_support_overrides[p_language];4217} else {4218return true;4219}4220}42214222void TextServerAdvanced::_font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) {4223FontAdvanced *fd = _get_font_data(p_font_rid);4224ERR_FAIL_NULL(fd);42254226MutexLock lock(fd->mutex);4227fd->language_support_overrides[p_language] = p_supported;4228}42294230bool TextServerAdvanced::_font_get_language_support_override(const RID &p_font_rid, const String &p_language) {4231FontAdvanced *fd = _get_font_data(p_font_rid);4232ERR_FAIL_NULL_V(fd, false);42334234MutexLock lock(fd->mutex);4235return fd->language_support_overrides[p_language];4236}42374238void TextServerAdvanced::_font_remove_language_support_override(const RID &p_font_rid, const String &p_language) {4239FontAdvanced *fd = _get_font_data(p_font_rid);4240ERR_FAIL_NULL(fd);42414242MutexLock lock(fd->mutex);4243fd->language_support_overrides.erase(p_language);4244}42454246PackedStringArray TextServerAdvanced::_font_get_language_support_overrides(const RID &p_font_rid) {4247FontAdvanced *fd = _get_font_data(p_font_rid);4248ERR_FAIL_NULL_V(fd, PackedStringArray());42494250MutexLock lock(fd->mutex);4251PackedStringArray out;4252for (const KeyValue<String, bool> &E : fd->language_support_overrides) {4253out.push_back(E.key);4254}4255return out;4256}42574258bool TextServerAdvanced::_font_is_script_supported(const RID &p_font_rid, const String &p_script) const {4259FontAdvanced *fd = _get_font_data(p_font_rid);4260ERR_FAIL_NULL_V(fd, false);42614262MutexLock lock(fd->mutex);4263if (fd->script_support_overrides.has(p_script)) {4264return fd->script_support_overrides[p_script];4265} else {4266Vector2i size = _get_size(fd, 16);4267FontForSizeAdvanced *ffsd = nullptr;4268ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), false);4269return fd->supported_scripts.has(hb_tag_from_string(p_script.ascii().get_data(), -1));4270}4271}42724273void TextServerAdvanced::_font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) {4274FontAdvanced *fd = _get_font_data(p_font_rid);4275ERR_FAIL_NULL(fd);42764277MutexLock lock(fd->mutex);4278fd->script_support_overrides[p_script] = p_supported;4279}42804281bool TextServerAdvanced::_font_get_script_support_override(const RID &p_font_rid, const String &p_script) {4282FontAdvanced *fd = _get_font_data(p_font_rid);4283ERR_FAIL_NULL_V(fd, false);42844285MutexLock lock(fd->mutex);4286return fd->script_support_overrides[p_script];4287}42884289void TextServerAdvanced::_font_remove_script_support_override(const RID &p_font_rid, const String &p_script) {4290FontAdvanced *fd = _get_font_data(p_font_rid);4291ERR_FAIL_NULL(fd);42924293MutexLock lock(fd->mutex);4294fd->script_support_overrides.erase(p_script);4295}42964297PackedStringArray TextServerAdvanced::_font_get_script_support_overrides(const RID &p_font_rid) {4298FontAdvanced *fd = _get_font_data(p_font_rid);4299ERR_FAIL_NULL_V(fd, PackedStringArray());43004301MutexLock lock(fd->mutex);4302PackedStringArray out;4303for (const KeyValue<String, bool> &E : fd->script_support_overrides) {4304out.push_back(E.key);4305}4306return out;4307}43084309void TextServerAdvanced::_font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) {4310FontAdvanced *fd = _get_font_data(p_font_rid);4311ERR_FAIL_NULL(fd);43124313MutexLock lock(fd->mutex);4314Vector2i size = _get_size(fd, 16);4315FontForSizeAdvanced *ffsd = nullptr;4316ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));4317fd->feature_overrides = p_overrides;4318}43194320Dictionary TextServerAdvanced::_font_get_opentype_feature_overrides(const RID &p_font_rid) const {4321FontAdvanced *fd = _get_font_data(p_font_rid);4322ERR_FAIL_NULL_V(fd, Dictionary());43234324MutexLock lock(fd->mutex);4325return fd->feature_overrides;4326}43274328Dictionary TextServerAdvanced::_font_supported_feature_list(const RID &p_font_rid) const {4329FontAdvanced *fd = _get_font_data(p_font_rid);4330ERR_FAIL_NULL_V(fd, Dictionary());43314332MutexLock lock(fd->mutex);4333Vector2i size = _get_size(fd, 16);4334FontForSizeAdvanced *ffsd = nullptr;4335ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary());4336return fd->supported_features;4337}43384339Dictionary TextServerAdvanced::_font_supported_variation_list(const RID &p_font_rid) const {4340FontAdvanced *fd = _get_font_data(p_font_rid);4341ERR_FAIL_NULL_V(fd, Dictionary());43424343MutexLock lock(fd->mutex);4344Vector2i size = _get_size(fd, 16);4345FontForSizeAdvanced *ffsd = nullptr;4346ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary());4347return fd->supported_varaitions;4348}43494350/*************************************************************************/4351/* Shaped text buffer interface */4352/*************************************************************************/43534354int64_t TextServerAdvanced::_convert_pos(const String &p_utf32, const Char16String &p_utf16, int64_t p_pos) const {4355int64_t limit = p_pos;4356if (p_utf32.length() != p_utf16.length()) {4357const UChar *data = p_utf16.get_data();4358for (int i = 0; i < p_pos; i++) {4359if (U16_IS_LEAD(data[i])) {4360limit--;4361}4362}4363}4364return limit;4365}43664367int64_t TextServerAdvanced::_convert_pos(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const {4368int64_t limit = p_pos;4369if (p_sd->text.length() != p_sd->utf16.length()) {4370const UChar *data = p_sd->utf16.get_data();4371for (int i = 0; i < p_pos; i++) {4372if (U16_IS_LEAD(data[i])) {4373limit--;4374}4375}4376}4377return limit;4378}43794380int64_t TextServerAdvanced::_convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const {4381int64_t limit = p_pos;4382if (p_sd->text.length() != p_sd->utf16.length()) {4383for (int i = 0; i < p_pos; i++) {4384if (p_sd->text[i] > 0xffff) {4385limit++;4386}4387}4388}4389return limit;4390}43914392void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *p_shaped, bool p_text) {4393p_shaped->valid.clear();4394p_shaped->sort_valid = false;4395p_shaped->line_breaks_valid = false;4396p_shaped->justification_ops_valid = false;4397p_shaped->text_trimmed = false;4398p_shaped->ascent = 0.0;4399p_shaped->descent = 0.0;4400p_shaped->width = 0.0;4401p_shaped->upos = 0.0;4402p_shaped->uthk = 0.0;4403p_shaped->glyphs.clear();4404p_shaped->glyphs_logical.clear();4405p_shaped->runs.clear();4406p_shaped->runs_dirty = true;4407p_shaped->overrun_trim_data = TrimData();4408p_shaped->utf16 = Char16String();4409for (int i = 0; i < p_shaped->bidi_iter.size(); i++) {4410ubidi_close(p_shaped->bidi_iter[i]);4411}4412p_shaped->bidi_iter.clear();44134414if (p_text) {4415if (p_shaped->script_iter != nullptr) {4416memdelete(p_shaped->script_iter);4417p_shaped->script_iter = nullptr;4418}4419p_shaped->break_ops_valid = false;4420p_shaped->chars_valid = false;4421p_shaped->js_ops_valid = false;4422}4423}44244425void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) {4426ShapedTextDataAdvanced *parent = shaped_owner.get_or_null(p_shaped->parent);44274428for (const KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : parent->objects) {4429if (E.value.start >= p_shaped->start && E.value.start < p_shaped->end) {4430p_shaped->objects[E.key] = E.value;4431}4432}44334434for (int i = p_shaped->first_span; i <= p_shaped->last_span; i++) {4435ShapedTextDataAdvanced::Span span = parent->spans[i];4436span.start = MAX(p_shaped->start, span.start);4437span.end = MIN(p_shaped->end, span.end);4438p_shaped->spans.push_back(span);4439}4440p_shaped->first_span = 0;4441p_shaped->last_span = 0;44424443p_shaped->parent = RID();4444}44454446RID TextServerAdvanced::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {4447_THREAD_SAFE_METHOD_4448ERR_FAIL_COND_V_MSG(p_direction == DIRECTION_INHERITED, RID(), "Invalid text direction.");44494450ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced);4451sd->hb_buffer = hb_buffer_create();4452sd->direction = p_direction;4453sd->orientation = p_orientation;4454return shaped_owner.make_rid(sd);4455}44564457void TextServerAdvanced::_shaped_text_clear(const RID &p_shaped) {4458ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4459ERR_FAIL_NULL(sd);44604461MutexLock lock(sd->mutex);4462sd->parent = RID();4463sd->start = 0;4464sd->end = 0;4465sd->text = String();4466sd->spans.clear();4467sd->first_span = 0;4468sd->last_span = 0;4469sd->objects.clear();4470sd->bidi_override.clear();4471invalidate(sd, true);4472}44734474void TextServerAdvanced::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {4475ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4476ERR_FAIL_COND_MSG(p_direction == DIRECTION_INHERITED, "Invalid text direction.");4477ERR_FAIL_NULL(sd);44784479MutexLock lock(sd->mutex);4480if (sd->direction != p_direction) {4481if (sd->parent != RID()) {4482full_copy(sd);4483}4484sd->direction = p_direction;4485invalidate(sd, false);4486}4487}44884489TextServer::Direction TextServerAdvanced::_shaped_text_get_direction(const RID &p_shaped) const {4490const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4491ERR_FAIL_NULL_V(sd, TextServer::DIRECTION_LTR);44924493MutexLock lock(sd->mutex);4494return sd->direction;4495}44964497TextServer::Direction TextServerAdvanced::_shaped_text_get_inferred_direction(const RID &p_shaped) const {4498const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4499ERR_FAIL_NULL_V(sd, TextServer::DIRECTION_LTR);45004501MutexLock lock(sd->mutex);4502return sd->para_direction;4503}45044505void TextServerAdvanced::_shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) {4506_THREAD_SAFE_METHOD_4507ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4508ERR_FAIL_NULL(sd);45094510if (sd->custom_punct != p_punct) {4511if (sd->parent != RID()) {4512full_copy(sd);4513}4514sd->custom_punct = p_punct;4515invalidate(sd, false);4516}4517}45184519String TextServerAdvanced::_shaped_text_get_custom_punctuation(const RID &p_shaped) const {4520_THREAD_SAFE_METHOD_4521const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4522ERR_FAIL_NULL_V(sd, String());4523return sd->custom_punct;4524}45254526void TextServerAdvanced::_shaped_text_set_custom_ellipsis(const RID &p_shaped, int64_t p_char) {4527_THREAD_SAFE_METHOD_4528ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4529ERR_FAIL_NULL(sd);4530sd->el_char = p_char;4531}45324533int64_t TextServerAdvanced::_shaped_text_get_custom_ellipsis(const RID &p_shaped) const {4534_THREAD_SAFE_METHOD_4535const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4536ERR_FAIL_NULL_V(sd, 0);4537return sd->el_char;4538}45394540void TextServerAdvanced::_shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) {4541ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4542ERR_FAIL_NULL(sd);45434544MutexLock lock(sd->mutex);4545if (sd->parent != RID()) {4546full_copy(sd);4547}4548sd->bidi_override.clear();4549for (int i = 0; i < p_override.size(); i++) {4550if (p_override[i].get_type() == Variant::VECTOR3I) {4551const Vector3i &r = p_override[i];4552sd->bidi_override.push_back(r);4553} else if (p_override[i].get_type() == Variant::VECTOR2I) {4554const Vector2i &r = p_override[i];4555sd->bidi_override.push_back(Vector3i(r.x, r.y, DIRECTION_INHERITED));4556}4557}4558invalidate(sd, false);4559}45604561void TextServerAdvanced::_shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) {4562ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4563ERR_FAIL_NULL(sd);45644565MutexLock lock(sd->mutex);4566if (sd->orientation != p_orientation) {4567if (sd->parent != RID()) {4568full_copy(sd);4569}4570sd->orientation = p_orientation;4571invalidate(sd, false);4572}4573}45744575void TextServerAdvanced::_shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) {4576ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4577ERR_FAIL_NULL(sd);45784579MutexLock lock(sd->mutex);4580ERR_FAIL_COND(sd->parent != RID());4581if (sd->preserve_invalid != p_enabled) {4582sd->preserve_invalid = p_enabled;4583invalidate(sd, false);4584}4585}45864587bool TextServerAdvanced::_shaped_text_get_preserve_invalid(const RID &p_shaped) const {4588const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4589ERR_FAIL_NULL_V(sd, false);45904591MutexLock lock(sd->mutex);4592return sd->preserve_invalid;4593}45944595void TextServerAdvanced::_shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) {4596ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4597ERR_FAIL_NULL(sd);45984599MutexLock lock(sd->mutex);4600if (sd->preserve_control != p_enabled) {4601if (sd->parent != RID()) {4602full_copy(sd);4603}4604sd->preserve_control = p_enabled;4605invalidate(sd, false);4606}4607}46084609bool TextServerAdvanced::_shaped_text_get_preserve_control(const RID &p_shaped) const {4610const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4611ERR_FAIL_NULL_V(sd, false);46124613MutexLock lock(sd->mutex);4614return sd->preserve_control;4615}46164617void TextServerAdvanced::_shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) {4618ERR_FAIL_INDEX((int)p_spacing, 4);4619ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4620ERR_FAIL_NULL(sd);46214622MutexLock lock(sd->mutex);4623if (sd->extra_spacing[p_spacing] != p_value) {4624if (sd->parent != RID()) {4625full_copy(sd);4626}4627sd->extra_spacing[p_spacing] = p_value;4628invalidate(sd, false);4629}4630}46314632int64_t TextServerAdvanced::_shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const {4633ERR_FAIL_INDEX_V((int)p_spacing, 4, 0);46344635const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4636ERR_FAIL_NULL_V(sd, 0);46374638MutexLock lock(sd->mutex);4639return sd->extra_spacing[p_spacing];4640}46414642TextServer::Orientation TextServerAdvanced::_shaped_text_get_orientation(const RID &p_shaped) const {4643const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4644ERR_FAIL_NULL_V(sd, TextServer::ORIENTATION_HORIZONTAL);46454646MutexLock lock(sd->mutex);4647return sd->orientation;4648}46494650int64_t TextServerAdvanced::_shaped_get_span_count(const RID &p_shaped) const {4651ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4652ERR_FAIL_NULL_V(sd, 0);46534654if (sd->parent != RID()) {4655return sd->last_span - sd->first_span + 1;4656} else {4657return sd->spans.size();4658}4659}46604661Variant TextServerAdvanced::_shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const {4662ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4663ERR_FAIL_NULL_V(sd, Variant());4664if (sd->parent != RID()) {4665ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);4666ERR_FAIL_COND_V(!parent_sd->valid.is_set(), Variant());4667ERR_FAIL_INDEX_V(p_index + sd->first_span, parent_sd->spans.size(), Variant());4668return parent_sd->spans[p_index + sd->first_span].meta;4669} else {4670ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant());4671return sd->spans[p_index].meta;4672}4673}46744675Variant TextServerAdvanced::_shaped_get_span_embedded_object(const RID &p_shaped, int64_t p_index) const {4676ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4677ERR_FAIL_NULL_V(sd, Variant());4678if (sd->parent != RID()) {4679ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);4680ERR_FAIL_COND_V(!parent_sd->valid.is_set(), Variant());4681ERR_FAIL_INDEX_V(p_index + sd->first_span, parent_sd->spans.size(), Variant());4682return parent_sd->spans[p_index + sd->first_span].embedded_key;4683} else {4684ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant());4685return sd->spans[p_index].embedded_key;4686}4687}46884689String TextServerAdvanced::_shaped_get_span_text(const RID &p_shaped, int64_t p_index) const {4690ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4691ERR_FAIL_NULL_V(sd, String());4692ShapedTextDataAdvanced *span_sd = sd;4693if (sd->parent.is_valid()) {4694span_sd = shaped_owner.get_or_null(sd->parent);4695ERR_FAIL_NULL_V(span_sd, String());4696}4697ERR_FAIL_INDEX_V(p_index, span_sd->spans.size(), String());4698return span_sd->text.substr(span_sd->spans[p_index].start, span_sd->spans[p_index].end - span_sd->spans[p_index].start);4699}47004701Variant TextServerAdvanced::_shaped_get_span_object(const RID &p_shaped, int64_t p_index) const {4702ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4703ERR_FAIL_NULL_V(sd, Variant());4704ShapedTextDataAdvanced *span_sd = sd;4705if (sd->parent.is_valid()) {4706span_sd = shaped_owner.get_or_null(sd->parent);4707ERR_FAIL_NULL_V(span_sd, Variant());4708}4709ERR_FAIL_INDEX_V(p_index, span_sd->spans.size(), Variant());4710return span_sd->spans[p_index].embedded_key;4711}47124713void TextServerAdvanced::_generate_runs(ShapedTextDataAdvanced *p_sd) const {4714ERR_FAIL_NULL(p_sd);4715p_sd->runs.clear();47164717ShapedTextDataAdvanced *span_sd = p_sd;4718if (p_sd->parent.is_valid()) {4719span_sd = shaped_owner.get_or_null(p_sd->parent);4720ERR_FAIL_NULL(span_sd);4721}47224723int sd_size = p_sd->glyphs.size();4724const Glyph *sd_gl = p_sd->glyphs.ptr();47254726int span_count = span_sd->spans.size();4727int span = -1;4728int span_start = -1;4729int span_end = -1;47304731TextRun run;4732for (int i = 0; i < sd_size; i += sd_gl[i].count) {4733const Glyph &gl = sd_gl[i];4734if (gl.start < 0 || gl.end < 0) {4735continue;4736}4737if (gl.start < span_start || gl.start >= span_end) {4738span = -1;4739span_start = -1;4740span_end = -1;4741for (int j = 0; j < span_count; j++) {4742if (gl.start >= span_sd->spans[j].start && gl.end <= span_sd->spans[j].end) {4743span = j;4744span_start = span_sd->spans[j].start;4745span_end = span_sd->spans[j].end;4746break;4747}4748}4749}4750if (run.font_rid != gl.font_rid || run.font_size != gl.font_size || run.span_index != span || run.rtl != bool(gl.flags & GRAPHEME_IS_RTL)) {4751if (run.span_index >= 0) {4752p_sd->runs.push_back(run);4753}4754run.range = Vector2i(gl.start, gl.end);4755run.font_rid = gl.font_rid;4756run.font_size = gl.font_size;4757run.rtl = bool(gl.flags & GRAPHEME_IS_RTL);4758run.span_index = span;4759}4760run.range.x = MIN(run.range.x, gl.start);4761run.range.y = MAX(run.range.y, gl.end);4762}4763if (run.span_index >= 0) {4764p_sd->runs.push_back(run);4765}4766p_sd->runs_dirty = false;4767}47684769int64_t TextServerAdvanced::_shaped_get_run_count(const RID &p_shaped) const {4770ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4771ERR_FAIL_NULL_V(sd, 0);4772MutexLock lock(sd->mutex);4773if (!sd->valid.is_set()) {4774const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4775}4776if (sd->runs_dirty) {4777_generate_runs(sd);4778}4779return sd->runs.size();4780}47814782String TextServerAdvanced::_shaped_get_run_text(const RID &p_shaped, int64_t p_index) const {4783ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4784ERR_FAIL_NULL_V(sd, String());4785MutexLock lock(sd->mutex);4786if (!sd->valid.is_set()) {4787const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4788}4789if (sd->runs_dirty) {4790_generate_runs(sd);4791}4792ERR_FAIL_INDEX_V(p_index, sd->runs.size(), String());4793return sd->text.substr(sd->runs[p_index].range.x - sd->start, sd->runs[p_index].range.y - sd->runs[p_index].range.x);4794}47954796Vector2i TextServerAdvanced::_shaped_get_run_range(const RID &p_shaped, int64_t p_index) const {4797ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4798ERR_FAIL_NULL_V(sd, Vector2i());4799MutexLock lock(sd->mutex);4800if (!sd->valid.is_set()) {4801const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4802}4803if (sd->runs_dirty) {4804_generate_runs(sd);4805}4806ERR_FAIL_INDEX_V(p_index, sd->runs.size(), Vector2i());4807return sd->runs[p_index].range;4808}48094810RID TextServerAdvanced::_shaped_get_run_font_rid(const RID &p_shaped, int64_t p_index) const {4811ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4812ERR_FAIL_NULL_V(sd, RID());4813MutexLock lock(sd->mutex);4814if (!sd->valid.is_set()) {4815const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4816}4817if (sd->runs_dirty) {4818_generate_runs(sd);4819}4820ERR_FAIL_INDEX_V(p_index, sd->runs.size(), RID());4821return sd->runs[p_index].font_rid;4822}48234824int TextServerAdvanced::_shaped_get_run_font_size(const RID &p_shaped, int64_t p_index) const {4825ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4826ERR_FAIL_NULL_V(sd, 0);4827MutexLock lock(sd->mutex);4828if (!sd->valid.is_set()) {4829const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4830}4831if (sd->runs_dirty) {4832_generate_runs(sd);4833}4834ERR_FAIL_INDEX_V(p_index, sd->runs.size(), 0);4835return sd->runs[p_index].font_size;4836}48374838String TextServerAdvanced::_shaped_get_run_language(const RID &p_shaped, int64_t p_index) const {4839ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4840ERR_FAIL_NULL_V(sd, String());4841MutexLock lock(sd->mutex);4842if (!sd->valid.is_set()) {4843const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4844}4845if (sd->runs_dirty) {4846_generate_runs(sd);4847}4848ERR_FAIL_INDEX_V(p_index, sd->runs.size(), String());48494850int span_idx = sd->runs[p_index].span_index;4851ShapedTextDataAdvanced *span_sd = sd;4852if (sd->parent.is_valid()) {4853span_sd = shaped_owner.get_or_null(sd->parent);4854ERR_FAIL_NULL_V(span_sd, String());4855}4856ERR_FAIL_INDEX_V(span_idx, span_sd->spans.size(), String());4857return span_sd->spans[span_idx].language;4858}48594860TextServer::Direction TextServerAdvanced::_shaped_get_run_direction(const RID &p_shaped, int64_t p_index) const {4861ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4862ERR_FAIL_NULL_V(sd, TextServer::DIRECTION_LTR);4863MutexLock lock(sd->mutex);4864if (!sd->valid.is_set()) {4865const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4866}4867if (sd->runs_dirty) {4868_generate_runs(sd);4869}4870ERR_FAIL_INDEX_V(p_index, sd->runs.size(), TextServer::DIRECTION_LTR);4871return sd->runs[p_index].rtl ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR;4872}48734874Variant TextServerAdvanced::_shaped_get_run_object(const RID &p_shaped, int64_t p_index) const {4875ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4876ERR_FAIL_NULL_V(sd, Variant());4877MutexLock lock(sd->mutex);4878if (!sd->valid.is_set()) {4879const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4880}4881if (sd->runs_dirty) {4882_generate_runs(sd);4883}4884ERR_FAIL_INDEX_V(p_index, sd->runs.size(), Variant());48854886int span_idx = sd->runs[p_index].span_index;4887ShapedTextDataAdvanced *span_sd = sd;4888if (sd->parent.is_valid()) {4889span_sd = shaped_owner.get_or_null(sd->parent);4890ERR_FAIL_NULL_V(span_sd, Variant());4891}4892ERR_FAIL_INDEX_V(span_idx, span_sd->spans.size(), Variant());4893return span_sd->spans[span_idx].embedded_key;4894}48954896void TextServerAdvanced::_shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) {4897ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4898ERR_FAIL_NULL(sd);4899if (sd->parent != RID()) {4900full_copy(sd);4901}4902ERR_FAIL_INDEX(p_index, sd->spans.size());49034904ShapedTextDataAdvanced::Span &span = sd->spans.ptrw()[p_index];4905span.fonts = p_fonts;4906span.font_size = p_size;4907span.features = p_opentype_features;49084909invalidate(sd, false);4910}49114912bool TextServerAdvanced::_shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {4913ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4914ERR_FAIL_NULL_V(sd, false);4915ERR_FAIL_COND_V(p_size <= 0, false);49164917MutexLock lock(sd->mutex);4918for (int i = 0; i < p_fonts.size(); i++) {4919ERR_FAIL_NULL_V(_get_font_data(p_fonts[i]), false);4920}49214922if (p_text.is_empty()) {4923return true;4924}49254926if (sd->parent != RID()) {4927full_copy(sd);4928}49294930ShapedTextDataAdvanced::Span span;4931span.start = sd->text.length();4932span.end = span.start + p_text.length();4933span.fonts = p_fonts; // Do not pre-sort, spans will be divided to subruns later.4934span.font_size = p_size;4935span.language = p_language;4936span.features = p_opentype_features;4937span.meta = p_meta;49384939sd->spans.push_back(span);4940sd->text = sd->text + p_text;4941sd->end += p_text.length();4942invalidate(sd, true);49434944return true;4945}49464947bool TextServerAdvanced::_shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length, double p_baseline) {4948_THREAD_SAFE_METHOD_4949ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4950ERR_FAIL_NULL_V(sd, false);4951ERR_FAIL_COND_V(p_key == Variant(), false);4952ERR_FAIL_COND_V(sd->objects.has(p_key), false);49534954if (sd->parent != RID()) {4955full_copy(sd);4956}49574958ShapedTextDataAdvanced::Span span;4959span.start = sd->start + sd->text.length();4960span.end = span.start + p_length;4961span.embedded_key = p_key;49624963ShapedTextDataAdvanced::EmbeddedObject obj;4964obj.inline_align = p_inline_align;4965obj.rect.size = p_size;4966obj.start = span.start;4967obj.end = span.end;4968obj.baseline = p_baseline;49694970sd->spans.push_back(span);4971sd->text = sd->text + String::chr(0xfffc).repeat(p_length);4972sd->end += p_length;4973sd->objects[p_key] = obj;4974invalidate(sd, true);49754976return true;4977}49784979String TextServerAdvanced::_shaped_get_text(const RID &p_shaped) const {4980const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4981ERR_FAIL_NULL_V(sd, String());49824983return sd->text;4984}49854986bool TextServerAdvanced::_shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, double p_baseline) {4987ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4988ERR_FAIL_NULL_V(sd, false);49894990MutexLock lock(sd->mutex);4991ERR_FAIL_COND_V(!sd->objects.has(p_key), false);4992sd->objects[p_key].rect.size = p_size;4993sd->objects[p_key].inline_align = p_inline_align;4994sd->objects[p_key].baseline = p_baseline;4995if (sd->valid.is_set()) {4996// Recalc string metrics.4997sd->ascent = 0;4998sd->descent = 0;4999sd->width = 0;5000sd->upos = 0;5001sd->uthk = 0;50025003Vector<ShapedTextDataAdvanced::Span> &spans = sd->spans;5004if (sd->parent != RID()) {5005ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);5006ERR_FAIL_COND_V(!parent_sd->valid.is_set(), false);5007spans = parent_sd->spans;5008}50095010int sd_size = sd->glyphs.size();5011int span_size = spans.size();5012const char32_t *ch = sd->text.ptr();50135014for (int i = 0; i < sd_size; i++) {5015Glyph gl = sd->glyphs[i];5016Variant key;5017if ((gl.flags & GRAPHEME_IS_EMBEDDED_OBJECT) == GRAPHEME_IS_EMBEDDED_OBJECT && gl.span_index + sd->first_span >= 0 && gl.span_index + sd->first_span < span_size) {5018key = spans[gl.span_index + sd->first_span].embedded_key;5019}5020if (key != Variant()) {5021if (sd->orientation == ORIENTATION_HORIZONTAL) {5022sd->objects[key].rect.position.x = sd->width;5023sd->width += sd->objects[key].rect.size.x;5024sd->glyphs[i].advance = sd->objects[key].rect.size.x;5025} else {5026sd->objects[key].rect.position.y = sd->width;5027sd->width += sd->objects[key].rect.size.y;5028sd->glyphs[i].advance = sd->objects[key].rect.size.y;5029}5030} else {5031if (gl.font_rid.is_valid()) {5032if (sd->orientation == ORIENTATION_HORIZONTAL) {5033sd->ascent = MAX(sd->ascent, MAX(_font_get_ascent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_TOP), -gl.y_off));5034sd->descent = MAX(sd->descent, MAX(_font_get_descent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_BOTTOM), gl.y_off));5035} else {5036sd->ascent = MAX(sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));5037sd->descent = MAX(sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));5038}5039sd->upos = MAX(sd->upos, _font_get_underline_position(gl.font_rid, gl.font_size));5040sd->uthk = MAX(sd->uthk, _font_get_underline_thickness(gl.font_rid, gl.font_size));5041} else if (sd->preserve_invalid || (sd->preserve_control && is_control(ch[gl.start - sd->start]))) {5042// Glyph not found, replace with hex code box.5043if (sd->orientation == ORIENTATION_HORIZONTAL) {5044sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.85);5045sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.15);5046} else {5047sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));5048sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));5049}5050}5051sd->width += gl.advance * gl.repeat;5052}5053}5054sd->sort_valid = false;5055sd->glyphs_logical.clear();5056_realign(sd);5057}5058return true;5059}50605061void TextServerAdvanced::_realign(ShapedTextDataAdvanced *p_sd) const {5062// Align embedded objects to baseline.5063double full_ascent = p_sd->ascent;5064double full_descent = p_sd->descent;5065for (KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : p_sd->objects) {5066if ((E.value.start >= p_sd->start) && (E.value.start < p_sd->end)) {5067if (p_sd->orientation == ORIENTATION_HORIZONTAL) {5068switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {5069case INLINE_ALIGNMENT_TO_TOP: {5070E.value.rect.position.y = -p_sd->ascent;5071} break;5072case INLINE_ALIGNMENT_TO_CENTER: {5073E.value.rect.position.y = (-p_sd->ascent + p_sd->descent) / 2;5074} break;5075case INLINE_ALIGNMENT_TO_BASELINE: {5076E.value.rect.position.y = 0;5077} break;5078case INLINE_ALIGNMENT_TO_BOTTOM: {5079E.value.rect.position.y = p_sd->descent;5080} break;5081}5082switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {5083case INLINE_ALIGNMENT_BOTTOM_TO: {5084E.value.rect.position.y -= E.value.rect.size.y;5085} break;5086case INLINE_ALIGNMENT_CENTER_TO: {5087E.value.rect.position.y -= E.value.rect.size.y / 2;5088} break;5089case INLINE_ALIGNMENT_BASELINE_TO: {5090E.value.rect.position.y -= E.value.baseline;5091} break;5092case INLINE_ALIGNMENT_TOP_TO: {5093// NOP5094} break;5095}5096full_ascent = MAX(full_ascent, -E.value.rect.position.y);5097full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y);5098} else {5099switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {5100case INLINE_ALIGNMENT_TO_TOP: {5101E.value.rect.position.x = -p_sd->ascent;5102} break;5103case INLINE_ALIGNMENT_TO_CENTER: {5104E.value.rect.position.x = (-p_sd->ascent + p_sd->descent) / 2;5105} break;5106case INLINE_ALIGNMENT_TO_BASELINE: {5107E.value.rect.position.x = 0;5108} break;5109case INLINE_ALIGNMENT_TO_BOTTOM: {5110E.value.rect.position.x = p_sd->descent;5111} break;5112}5113switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {5114case INLINE_ALIGNMENT_BOTTOM_TO: {5115E.value.rect.position.x -= E.value.rect.size.x;5116} break;5117case INLINE_ALIGNMENT_CENTER_TO: {5118E.value.rect.position.x -= E.value.rect.size.x / 2;5119} break;5120case INLINE_ALIGNMENT_BASELINE_TO: {5121E.value.rect.position.x -= E.value.baseline;5122} break;5123case INLINE_ALIGNMENT_TOP_TO: {5124// NOP5125} break;5126}5127full_ascent = MAX(full_ascent, -E.value.rect.position.x);5128full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x);5129}5130}5131}5132p_sd->ascent = full_ascent;5133p_sd->descent = full_descent;5134}51355136RID TextServerAdvanced::_shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {5137_THREAD_SAFE_METHOD_5138const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5139ERR_FAIL_NULL_V(sd, RID());51405141MutexLock lock(sd->mutex);5142if (sd->parent != RID()) {5143return _shaped_text_substr(sd->parent, p_start, p_length);5144}5145if (!sd->valid.is_set()) {5146const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);5147}5148ERR_FAIL_COND_V(p_start < 0 || p_length < 0, RID());5149ERR_FAIL_COND_V(sd->start > p_start || sd->end < p_start, RID());5150ERR_FAIL_COND_V(sd->end < p_start + p_length, RID());51515152ShapedTextDataAdvanced *new_sd = memnew(ShapedTextDataAdvanced);5153new_sd->parent = p_shaped;5154new_sd->start = p_start;5155new_sd->end = p_start + p_length;5156new_sd->orientation = sd->orientation;5157new_sd->direction = sd->direction;5158new_sd->custom_punct = sd->custom_punct;5159new_sd->para_direction = sd->para_direction;5160new_sd->base_para_direction = sd->base_para_direction;5161for (int i = 0; i < TextServer::SPACING_MAX; i++) {5162new_sd->extra_spacing[i] = sd->extra_spacing[i];5163}51645165if (!_shape_substr(new_sd, sd, p_start, p_length)) {5166memdelete(new_sd);5167return RID();5168}5169return shaped_owner.make_rid(new_sd);5170}51715172bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_length) const {5173if (p_new_sd->valid.is_set()) {5174return true;5175}51765177p_new_sd->hb_buffer = hb_buffer_create();51785179p_new_sd->line_breaks_valid = p_sd->line_breaks_valid;5180p_new_sd->justification_ops_valid = p_sd->justification_ops_valid;5181p_new_sd->sort_valid = false;5182p_new_sd->upos = p_sd->upos;5183p_new_sd->uthk = p_sd->uthk;5184p_new_sd->runs.clear();5185p_new_sd->runs_dirty = true;51865187if (p_length > 0) {5188p_new_sd->text = p_sd->text.substr(p_start - p_sd->start, p_length);5189p_new_sd->utf16 = p_new_sd->text.utf16();5190p_new_sd->script_iter = memnew(ScriptIterator(p_new_sd->text, 0, p_new_sd->text.length()));51915192int span_size = p_sd->spans.size();51935194p_new_sd->first_span = 0;5195p_new_sd->last_span = span_size - 1;5196for (int i = 0; i < span_size; i++) {5197const ShapedTextDataAdvanced::Span &span = p_sd->spans[i];5198if (span.end <= p_start) {5199p_new_sd->first_span = i + 1;5200} else if (span.start >= p_start + p_length) {5201p_new_sd->last_span = i - 1;5202break;5203}5204}52055206Vector<Vector3i> bidi_ranges;5207if (p_sd->bidi_override.is_empty()) {5208bidi_ranges.push_back(Vector3i(p_sd->start, p_sd->end, DIRECTION_INHERITED));5209} else {5210bidi_ranges = p_sd->bidi_override;5211}52125213int sd_size = p_sd->glyphs.size();5214const Glyph *sd_glyphs = p_sd->glyphs.ptr();5215const char32_t *ch = p_sd->text.ptr();5216for (int ov = 0; ov < bidi_ranges.size(); ov++) {5217UErrorCode err = U_ZERO_ERROR;52185219if (bidi_ranges[ov].x >= p_start + p_length || bidi_ranges[ov].y <= p_start) {5220continue;5221}5222int ov_start = _convert_pos_inv(p_sd, bidi_ranges[ov].x);5223int start = MAX(0, _convert_pos_inv(p_sd, p_start) - ov_start);5224int end = MIN(_convert_pos_inv(p_sd, p_start + p_length), _convert_pos_inv(p_sd, bidi_ranges[ov].y)) - ov_start;52255226ERR_FAIL_COND_V_MSG((start < 0 || end - start > p_new_sd->utf16.length()), false, "Invalid BiDi override range.");52275228// Create temporary line bidi & shape.5229UBiDi *bidi_iter = nullptr;5230if (p_sd->bidi_iter[ov]) {5231bidi_iter = ubidi_openSized(end - start, 0, &err);5232if (U_SUCCESS(err)) {5233ubidi_setLine(p_sd->bidi_iter[ov], start, end, bidi_iter, &err);5234if (U_FAILURE(err)) {5235// Line BiDi failed (string contains incompatible control characters), try full paragraph BiDi instead.5236err = U_ZERO_ERROR;5237const UChar *data = p_sd->utf16.get_data();5238switch (static_cast<TextServer::Direction>(bidi_ranges[ov].z)) {5239case DIRECTION_LTR: {5240ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err);5241} break;5242case DIRECTION_RTL: {5243ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err);5244} break;5245case DIRECTION_INHERITED: {5246ubidi_setPara(bidi_iter, data + start, end - start, p_sd->base_para_direction, nullptr, &err);5247} break;5248case DIRECTION_AUTO: {5249UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start);5250if (direction != UBIDI_NEUTRAL) {5251ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);5252} else {5253ubidi_setPara(bidi_iter, data + start, end - start, p_sd->base_para_direction, nullptr, &err);5254}5255} break;5256}5257if (U_FAILURE(err)) {5258ubidi_close(bidi_iter);5259bidi_iter = nullptr;5260ERR_PRINT(vformat("BiDi reordering for the line failed: %s", u_errorName(err)));5261}5262}5263} else {5264bidi_iter = nullptr;5265ERR_PRINT(vformat("BiDi iterator allocation for the line failed: %s", u_errorName(err)));5266}5267}5268p_new_sd->bidi_iter.push_back(bidi_iter);52695270err = U_ZERO_ERROR;5271int bidi_run_count = 1;5272if (bidi_iter) {5273bidi_run_count = ubidi_countRuns(bidi_iter, &err);5274if (U_FAILURE(err)) {5275ERR_PRINT(u_errorName(err));5276}5277}5278for (int i = 0; i < bidi_run_count; i++) {5279int32_t _bidi_run_start = 0;5280int32_t _bidi_run_length = end - start;5281if (bidi_iter) {5282ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length);5283}52845285int32_t bidi_run_start = _convert_pos(p_sd, ov_start + start + _bidi_run_start);5286int32_t bidi_run_end = _convert_pos(p_sd, ov_start + start + _bidi_run_start + _bidi_run_length);52875288for (int j = 0; j < sd_size; j++) {5289int col_key_off = (sd_glyphs[j].start == sd_glyphs[j].end) ? 1 : 0;5290if ((sd_glyphs[j].start >= bidi_run_start) && (sd_glyphs[j].end <= bidi_run_end - col_key_off)) {5291// Copy glyphs.5292Glyph gl = sd_glyphs[j];5293if (gl.span_index >= 0) {5294gl.span_index -= p_new_sd->first_span;5295}5296if (gl.end == p_start + p_length && ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) == GRAPHEME_IS_SOFT_HYPHEN)) {5297uint32_t index = font_get_glyph_index(gl.font_rid, gl.font_size, 0x00ad, 0);5298if (index == 0) { // Try other fonts in the span.5299const ShapedTextDataAdvanced::Span &span = p_sd->spans[gl.span_index + p_new_sd->first_span];5300for (int k = 0; k < span.fonts.size(); k++) {5301if (span.fonts[k] != gl.font_rid) {5302index = font_get_glyph_index(span.fonts[k], gl.font_size, 0x00ad, 0);5303if (index != 0) {5304gl.font_rid = span.fonts[k];5305break;5306}5307}5308}5309}5310if (index == 0 && gl.font_rid.is_valid() && OS::get_singleton()->has_feature("system_fonts") && _font_is_allow_system_fallback(gl.font_rid)) { // Try system font fallback.5311const char32_t u32str[] = { 0x00ad, 0 };5312RID rid = const_cast<TextServerAdvanced *>(this)->_find_sys_font_for_text(gl.font_rid, String(), String(), u32str);5313if (rid.is_valid()) {5314index = font_get_glyph_index(rid, gl.font_size, 0x00ad, 0);5315if (index != 0) {5316gl.font_rid = rid;5317}5318}5319}5320float w = font_get_glyph_advance(gl.font_rid, gl.font_size, index)[(p_new_sd->orientation == ORIENTATION_HORIZONTAL) ? 0 : 1];5321gl.index = index;5322gl.advance = w;5323}5324if ((gl.flags & GRAPHEME_IS_EMBEDDED_OBJECT) == GRAPHEME_IS_EMBEDDED_OBJECT && gl.span_index + p_new_sd->first_span >= 0 && gl.span_index + p_new_sd->first_span < span_size) {5325Variant key = p_sd->spans[gl.span_index + p_new_sd->first_span].embedded_key;5326if (key != Variant()) {5327ShapedTextDataAdvanced::EmbeddedObject obj = p_sd->objects[key];5328if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {5329obj.rect.position.x = p_new_sd->width;5330p_new_sd->width += obj.rect.size.x;5331} else {5332obj.rect.position.y = p_new_sd->width;5333p_new_sd->width += obj.rect.size.y;5334}5335p_new_sd->objects[key] = obj;5336}5337} else {5338if (gl.font_rid.is_valid()) {5339if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {5340p_new_sd->ascent = MAX(p_new_sd->ascent, MAX(_font_get_ascent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_TOP), -gl.y_off));5341p_new_sd->descent = MAX(p_new_sd->descent, MAX(_font_get_descent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_BOTTOM), gl.y_off));5342} else {5343p_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));5344p_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));5345}5346} else if (p_new_sd->preserve_invalid || (p_new_sd->preserve_control && is_control(ch[gl.start - p_sd->start]))) {5347// Glyph not found, replace with hex code box.5348if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {5349p_new_sd->ascent = MAX(p_new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.85);5350p_new_sd->descent = MAX(p_new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.15);5351} else {5352p_new_sd->ascent = MAX(p_new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));5353p_new_sd->descent = MAX(p_new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));5354}5355}5356p_new_sd->width += gl.advance * gl.repeat;5357}5358p_new_sd->glyphs.push_back(gl);5359}5360}5361}5362}53635364_realign(p_new_sd);5365}5366p_new_sd->valid.set();53675368return true;5369}53705371RID TextServerAdvanced::_shaped_text_get_parent(const RID &p_shaped) const {5372ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5373ERR_FAIL_NULL_V(sd, RID());53745375MutexLock lock(sd->mutex);5376return sd->parent;5377}53785379double TextServerAdvanced::_shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<TextServer::JustificationFlag> p_jst_flags) {5380ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5381ERR_FAIL_NULL_V(sd, 0.0);53825383MutexLock lock(sd->mutex);5384if (!sd->valid.is_set()) {5385_shaped_text_shape(p_shaped);5386}5387if (!sd->justification_ops_valid) {5388_shaped_text_update_justification_ops(p_shaped);5389}53905391sd->fit_width_minimum_reached = false;5392int start_pos = 0;5393int end_pos = sd->glyphs.size() - 1;53945395if (p_jst_flags.has_flag(JUSTIFICATION_AFTER_LAST_TAB)) {5396int start, end, delta;5397if (sd->para_direction == DIRECTION_LTR) {5398start = sd->glyphs.size() - 1;5399end = -1;5400delta = -1;5401} else {5402start = 0;5403end = sd->glyphs.size();5404delta = +1;5405}54065407for (int i = start; i != end; i += delta) {5408if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {5409if (sd->para_direction == DIRECTION_LTR) {5410start_pos = i;5411break;5412} else {5413end_pos = i;5414break;5415}5416}5417}5418}54195420double justification_width;5421if (p_jst_flags.has_flag(JUSTIFICATION_CONSTRAIN_ELLIPSIS)) {5422if (sd->overrun_trim_data.trim_pos >= 0) {5423if (sd->para_direction == DIRECTION_RTL) {5424start_pos = sd->overrun_trim_data.trim_pos;5425} else {5426end_pos = sd->overrun_trim_data.trim_pos;5427}5428justification_width = sd->width_trimmed;5429} else {5430return Math::ceil(sd->width);5431}5432} else {5433justification_width = sd->width;5434}54355436if (p_jst_flags.has_flag(JUSTIFICATION_TRIM_EDGE_SPACES)) {5437// Trim spaces.5438while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {5439justification_width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat;5440sd->glyphs[start_pos].advance = 0;5441start_pos += sd->glyphs[start_pos].count;5442}5443while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {5444justification_width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat;5445sd->glyphs[end_pos].advance = 0;5446end_pos -= sd->glyphs[end_pos].count;5447}5448} else {5449// Skip breaks, but do not reset size.5450while ((start_pos < end_pos) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {5451start_pos += sd->glyphs[start_pos].count;5452}5453while ((start_pos < end_pos) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN) && ((sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (sd->glyphs[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) {5454end_pos -= sd->glyphs[end_pos].count;5455}5456}54575458int space_count = 0;5459int elongation_count = 0;5460for (int i = start_pos; i <= end_pos; i++) {5461const Glyph &gl = sd->glyphs[i];5462if (gl.count > 0) {5463if ((gl.flags & GRAPHEME_IS_ELONGATION) == GRAPHEME_IS_ELONGATION) {5464if ((i > 0) && ((sd->glyphs[i - 1].flags & GRAPHEME_IS_ELONGATION) != GRAPHEME_IS_ELONGATION)) {5465// Expand once per elongation sequence.5466elongation_count++;5467}5468}5469if ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN && (gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE && (gl.flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {5470space_count++;5471}5472}5473}54745475if ((elongation_count > 0) && p_jst_flags.has_flag(JUSTIFICATION_KASHIDA)) {5476double delta_width_per_kashida = (p_width - justification_width) / elongation_count;5477for (int i = start_pos; i <= end_pos; i++) {5478Glyph &gl = sd->glyphs[i];5479if (gl.count > 0) {5480if (((gl.flags & GRAPHEME_IS_ELONGATION) == GRAPHEME_IS_ELONGATION) && (gl.advance > 0)) {5481if ((i > 0) && ((sd->glyphs[i - 1].flags & GRAPHEME_IS_ELONGATION) != GRAPHEME_IS_ELONGATION)) {5482// Expand once per elongation sequence.5483int count = delta_width_per_kashida / gl.advance;5484int prev_count = gl.repeat;5485if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {5486gl.repeat = CLAMP(count, 0, 255);5487} else {5488gl.repeat = CLAMP(count + 1, 1, 255);5489}5490justification_width += (gl.repeat - prev_count) * gl.advance;5491}5492}5493}5494}5495}5496if ((space_count > 0) && p_jst_flags.has_flag(JUSTIFICATION_WORD_BOUND)) {5497double delta_width_per_space = (p_width - justification_width) / space_count;5498double adv_remain = 0;5499for (int i = start_pos; i <= end_pos; i++) {5500Glyph &gl = sd->glyphs[i];5501if (gl.count > 0) {5502if ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) != GRAPHEME_IS_SOFT_HYPHEN && (gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE && (gl.flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {5503double old_adv = gl.advance;5504double new_advance;5505if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {5506new_advance = MAX(gl.advance + delta_width_per_space, 0.0);5507} else {5508new_advance = MAX(gl.advance + delta_width_per_space, 0.1 * gl.font_size);5509}5510gl.advance = new_advance;5511adv_remain += (new_advance - gl.advance);5512if (adv_remain >= 1.0) {5513gl.advance++;5514adv_remain -= 1.0;5515} else if (adv_remain <= -1.0) {5516gl.advance = MAX(gl.advance - 1, 0);5517adv_remain -= 1.0;5518}5519justification_width += (gl.advance - old_adv);5520}5521}5522}5523}55245525if (Math::floor(p_width) < Math::floor(justification_width)) {5526sd->fit_width_minimum_reached = true;5527}55285529if (!p_jst_flags.has_flag(JUSTIFICATION_CONSTRAIN_ELLIPSIS)) {5530sd->width = justification_width;5531}55325533return Math::ceil(justification_width);5534}55355536double TextServerAdvanced::_shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) {5537ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5538ERR_FAIL_NULL_V(sd, 0.0);55395540MutexLock lock(sd->mutex);5541if (!sd->valid.is_set()) {5542_shaped_text_shape(p_shaped);5543}5544if (!sd->line_breaks_valid) {5545_shaped_text_update_breaks(p_shaped);5546}55475548for (int i = 0; i < p_tab_stops.size(); i++) {5549if (p_tab_stops[i] <= 0) {5550return 0.0;5551}5552}55535554int tab_index = 0;5555double off = 0.0;55565557int start, end, delta;5558if (sd->para_direction == DIRECTION_LTR) {5559start = 0;5560end = sd->glyphs.size();5561delta = +1;5562} else {5563start = sd->glyphs.size() - 1;5564end = -1;5565delta = -1;5566}55675568Glyph *gl = sd->glyphs.ptr();55695570for (int i = start; i != end; i += delta) {5571if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {5572double tab_off = 0.0;5573while (tab_off <= off) {5574tab_off += p_tab_stops[tab_index];5575tab_index++;5576if (tab_index >= p_tab_stops.size()) {5577tab_index = 0;5578}5579}5580double old_adv = gl[i].advance;5581gl[i].advance = tab_off - off;5582sd->width += gl[i].advance - old_adv;5583off = 0;5584continue;5585}5586off += gl[i].advance * gl[i].repeat;5587}55885589return 0.0;5590}55915592RID TextServerAdvanced::_find_sys_font_for_text(const RID &p_fdef, const String &p_script_code, const String &p_language, const String &p_text) {5593RID f;5594// Try system fallback.5595String font_name = _font_get_name(p_fdef);5596BitField<FontStyle> font_style = _font_get_style(p_fdef);5597int font_weight = _font_get_weight(p_fdef);5598int font_stretch = _font_get_stretch(p_fdef);5599Dictionary dvar = _font_get_variation_coordinates(p_fdef);5600static int64_t wgth_tag = _name_to_tag("weight");5601static int64_t wdth_tag = _name_to_tag("width");5602static int64_t ital_tag = _name_to_tag("italic");5603if (dvar.has(wgth_tag)) {5604font_weight = dvar[wgth_tag].operator int();5605}5606if (dvar.has(wdth_tag)) {5607font_stretch = dvar[wdth_tag].operator int();5608}5609if (dvar.has(ital_tag) && dvar[ital_tag].operator int() == 1) {5610font_style.set_flag(TextServer::FONT_ITALIC);5611}56125613String locale = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;5614PackedStringArray fallback_font_name = OS::get_singleton()->get_system_font_path_for_text(font_name, p_text, locale, p_script_code, font_weight, font_stretch, font_style & TextServer::FONT_ITALIC);5615#ifdef GDEXTENSION5616for (int fb = 0; fb < fallback_font_name.size(); fb++) {5617const String &E = fallback_font_name[fb];5618#elif defined(GODOT_MODULE)5619for (const String &E : fallback_font_name) {5620#endif5621SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, p_fdef, this);5622if (system_fonts.has(key)) {5623const SystemFontCache &sysf_cache = system_fonts[key];5624int best_score = 0;5625int best_match = -1;5626for (int face_idx = 0; face_idx < sysf_cache.var.size(); face_idx++) {5627const SystemFontCacheRec &F = sysf_cache.var[face_idx];5628if (unlikely(!_font_has_char(F.rid, p_text[0]))) {5629continue;5630}5631BitField<FontStyle> style = _font_get_style(F.rid);5632int weight = _font_get_weight(F.rid);5633int stretch = _font_get_stretch(F.rid);5634int score = (20 - Math::abs(weight - font_weight) / 50);5635score += (20 - Math::abs(stretch - font_stretch) / 10);5636if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) {5637score += 30;5638}5639if (score >= best_score) {5640best_score = score;5641best_match = face_idx;5642}5643if (best_score == 70) {5644break;5645}5646}5647if (best_match != -1) {5648f = sysf_cache.var[best_match].rid;5649}5650}5651if (!f.is_valid()) {5652if (system_fonts.has(key)) {5653const SystemFontCache &sysf_cache = system_fonts[key];5654if (sysf_cache.max_var == sysf_cache.var.size()) {5655// All subfonts already tested, skip.5656continue;5657}5658}56595660if (!system_font_data.has(E)) {5661system_font_data[E] = FileAccess::get_file_as_bytes(E);5662}56635664const PackedByteArray &font_data = system_font_data[E];56655666SystemFontCacheRec sysf;5667sysf.rid = _create_font();5668_font_set_data_ptr(sysf.rid, font_data.ptr(), font_data.size());5669if (!_font_validate(sysf.rid)) {5670_free_rid(sysf.rid);5671continue;5672}56735674Dictionary var = dvar;5675// Select matching style from collection.5676int best_score = 0;5677int best_match = -1;5678for (int face_idx = 0; face_idx < _font_get_face_count(sysf.rid); face_idx++) {5679_font_set_face_index(sysf.rid, face_idx);5680if (unlikely(!_font_has_char(sysf.rid, p_text[0]))) {5681continue;5682}5683BitField<FontStyle> style = _font_get_style(sysf.rid);5684int weight = _font_get_weight(sysf.rid);5685int stretch = _font_get_stretch(sysf.rid);5686int score = (20 - Math::abs(weight - font_weight) / 50);5687score += (20 - Math::abs(stretch - font_stretch) / 10);5688if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) {5689score += 30;5690}5691if (score >= best_score) {5692best_score = score;5693best_match = face_idx;5694}5695if (best_score == 70) {5696break;5697}5698}5699if (best_match == -1) {5700_free_rid(sysf.rid);5701continue;5702} else {5703_font_set_face_index(sysf.rid, best_match);5704}5705sysf.index = best_match;57065707// If it's a variable font, apply weight, stretch and italic coordinates to match requested style.5708if (best_score != 70) {5709Dictionary ftr = _font_supported_variation_list(sysf.rid);5710if (ftr.has(wdth_tag)) {5711var[wdth_tag] = font_stretch;5712_font_set_stretch(sysf.rid, font_stretch);5713}5714if (ftr.has(wgth_tag)) {5715var[wgth_tag] = font_weight;5716_font_set_weight(sysf.rid, font_weight);5717}5718if ((font_style & TextServer::FONT_ITALIC) && ftr.has(ital_tag)) {5719var[ital_tag] = 1;5720_font_set_style(sysf.rid, _font_get_style(sysf.rid) | TextServer::FONT_ITALIC);5721}5722}57235724bool fb_use_msdf = key.msdf;5725if (fb_use_msdf) {5726FontAdvanced *fd = _get_font_data(sysf.rid);5727if (fd) {5728MutexLock lock(fd->mutex);5729Vector2i size = _get_size(fd, 16);5730FontForSizeAdvanced *ffsd = nullptr;5731if (_ensure_cache_for_size(fd, size, ffsd)) {5732if (ffsd && (FT_HAS_COLOR(ffsd->face) || !FT_IS_SCALABLE(ffsd->face))) {5733fb_use_msdf = false;5734}5735}5736}5737}57385739_font_set_antialiasing(sysf.rid, key.antialiasing);5740_font_set_disable_embedded_bitmaps(sysf.rid, key.disable_embedded_bitmaps);5741_font_set_generate_mipmaps(sysf.rid, key.mipmaps);5742_font_set_multichannel_signed_distance_field(sysf.rid, fb_use_msdf);5743_font_set_msdf_pixel_range(sysf.rid, key.msdf_range);5744_font_set_msdf_size(sysf.rid, key.msdf_source_size);5745_font_set_fixed_size(sysf.rid, key.fixed_size);5746_font_set_force_autohinter(sysf.rid, key.force_autohinter);5747_font_set_hinting(sysf.rid, key.hinting);5748_font_set_subpixel_positioning(sysf.rid, key.subpixel_positioning);5749_font_set_keep_rounding_remainders(sysf.rid, key.keep_rounding_remainders);5750_font_set_variation_coordinates(sysf.rid, var);5751_font_set_embolden(sysf.rid, key.embolden);5752_font_set_transform(sysf.rid, key.transform);5753_font_set_spacing(sysf.rid, SPACING_TOP, key.extra_spacing[SPACING_TOP]);5754_font_set_spacing(sysf.rid, SPACING_BOTTOM, key.extra_spacing[SPACING_BOTTOM]);5755_font_set_spacing(sysf.rid, SPACING_SPACE, key.extra_spacing[SPACING_SPACE]);5756_font_set_spacing(sysf.rid, SPACING_GLYPH, key.extra_spacing[SPACING_GLYPH]);57575758if (system_fonts.has(key)) {5759system_fonts[key].var.push_back(sysf);5760} else {5761SystemFontCache &sysf_cache = system_fonts[key];5762sysf_cache.max_var = _font_get_face_count(sysf.rid);5763sysf_cache.var.push_back(sysf);5764}5765f = sysf.rid;5766}5767break;5768}5769return f;5770}57715772void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) {5773ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped_line);5774ERR_FAIL_NULL_MSG(sd, "ShapedTextDataAdvanced invalid.");57755776MutexLock lock(sd->mutex);5777if (!sd->valid.is_set()) {5778_shaped_text_shape(p_shaped_line);5779}5780if (!sd->line_breaks_valid) {5781_shaped_text_update_breaks(p_shaped_line);5782}57835784sd->text_trimmed = false;5785sd->overrun_trim_data.ellipsis_glyph_buf.clear();57865787bool add_ellipsis = p_trim_flags.has_flag(OVERRUN_ADD_ELLIPSIS);5788bool cut_per_word = p_trim_flags.has_flag(OVERRUN_TRIM_WORD_ONLY);5789bool enforce_ellipsis = p_trim_flags.has_flag(OVERRUN_ENFORCE_ELLIPSIS);5790bool justification_aware = p_trim_flags.has_flag(OVERRUN_JUSTIFICATION_AWARE);57915792Glyph *sd_glyphs = sd->glyphs.ptr();57935794if ((p_trim_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIM || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {5795sd->overrun_trim_data.trim_pos = -1;5796sd->overrun_trim_data.ellipsis_pos = -1;5797return;5798}57995800if (justification_aware && !sd->fit_width_minimum_reached) {5801return;5802}58035804Vector<ShapedTextDataAdvanced::Span> &spans = sd->spans;5805if (sd->parent != RID()) {5806ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);5807ERR_FAIL_COND(!parent_sd->valid.is_set());5808spans = parent_sd->spans;5809}58105811int span_size = spans.size();5812if (span_size == 0) {5813return;5814}58155816int sd_size = sd->glyphs.size();5817int last_gl_font_size = sd_glyphs[sd_size - 1].font_size;5818bool found_el_char = false;58195820// Find usable fonts, if fonts from the last glyph do not have required chars.5821RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;5822if (add_ellipsis || enforce_ellipsis) {5823if (!_font_has_char(dot_gl_font_rid, sd->el_char)) {5824const Array &fonts = spans[span_size - 1].fonts;5825for (int i = 0; i < fonts.size(); i++) {5826if (_font_has_char(fonts[i], sd->el_char)) {5827dot_gl_font_rid = fonts[i];5828found_el_char = true;5829break;5830}5831}5832if (!found_el_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) {5833const char32_t u32str[] = { sd->el_char, 0 };5834RID rid = _find_sys_font_for_text(fonts[0], String(), spans[span_size - 1].language, u32str);5835if (rid.is_valid()) {5836dot_gl_font_rid = rid;5837found_el_char = true;5838}5839}5840} else {5841found_el_char = true;5842}5843if (!found_el_char) {5844bool found_dot_char = false;5845dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;5846if (!_font_has_char(dot_gl_font_rid, '.')) {5847const Array &fonts = spans[span_size - 1].fonts;5848for (int i = 0; i < fonts.size(); i++) {5849if (_font_has_char(fonts[i], '.')) {5850dot_gl_font_rid = fonts[i];5851found_dot_char = true;5852break;5853}5854}5855if (!found_dot_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) {5856RID rid = _find_sys_font_for_text(fonts[0], String(), spans[span_size - 1].language, ".");5857if (rid.is_valid()) {5858dot_gl_font_rid = rid;5859}5860}5861}5862}5863}5864RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;5865if (!_font_has_char(whitespace_gl_font_rid, ' ')) {5866const Array &fonts = spans[span_size - 1].fonts;5867for (int i = 0; i < fonts.size(); i++) {5868if (_font_has_char(fonts[i], ' ')) {5869whitespace_gl_font_rid = fonts[i];5870break;5871}5872}5873}58745875int32_t dot_gl_idx = ((add_ellipsis || enforce_ellipsis) && dot_gl_font_rid.is_valid()) ? _font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, (found_el_char ? sd->el_char : '.'), 0) : -1;5876Vector2 dot_adv = ((add_ellipsis || enforce_ellipsis) && dot_gl_font_rid.is_valid()) ? _font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2();5877int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ', 0) : -1;5878Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2();58795880int ellipsis_width = 0;5881if (add_ellipsis && whitespace_gl_font_rid.is_valid()) {5882ellipsis_width = (found_el_char ? 1 : 3) * dot_adv.x + sd->extra_spacing[SPACING_GLYPH] + _font_get_spacing(dot_gl_font_rid, SPACING_GLYPH) + (cut_per_word ? whitespace_adv.x : 0);5883}58845885int ell_min_characters = 6;5886double width = sd->width;5887double width_without_el = width;58885889bool is_rtl = sd->para_direction == DIRECTION_RTL;58905891int trim_pos = (is_rtl) ? sd_size : 0;5892int ellipsis_pos = (enforce_ellipsis) ? 0 : -1;58935894int last_valid_cut = -1;5895int last_valid_cut_witout_el = -1;58965897int glyphs_from = (is_rtl) ? 0 : sd_size - 1;5898int glyphs_to = (is_rtl) ? sd_size - 1 : -1;5899int glyphs_delta = (is_rtl) ? +1 : -1;59005901if (enforce_ellipsis && (width + ellipsis_width <= p_width)) {5902trim_pos = -1;5903ellipsis_pos = (is_rtl) ? 0 : sd_size;5904} else {5905for (int i = glyphs_from; i != glyphs_to; i += glyphs_delta) {5906if (!is_rtl) {5907width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;5908}5909if (sd_glyphs[i].count > 0) {5910bool above_min_char_threshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters;5911if (!above_min_char_threshold && last_valid_cut_witout_el != -1) {5912trim_pos = last_valid_cut_witout_el;5913ellipsis_pos = -1;5914width = width_without_el;5915break;5916}5917if (!enforce_ellipsis && width <= p_width && last_valid_cut_witout_el == -1) {5918if (cut_per_word && above_min_char_threshold) {5919if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {5920last_valid_cut_witout_el = i;5921width_without_el = width;5922}5923} else {5924last_valid_cut_witout_el = i;5925width_without_el = width;5926}5927}5928if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {5929if (cut_per_word && above_min_char_threshold) {5930if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {5931last_valid_cut = i;5932}5933} else {5934last_valid_cut = i;5935}5936if (last_valid_cut != -1) {5937trim_pos = last_valid_cut;59385939if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {5940ellipsis_pos = trim_pos;5941}5942break;5943}5944}5945}5946if (is_rtl) {5947width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;5948}5949}5950}59515952sd->overrun_trim_data.trim_pos = trim_pos;5953sd->overrun_trim_data.ellipsis_pos = ellipsis_pos;5954if (trim_pos == 0 && enforce_ellipsis && add_ellipsis) {5955sd->overrun_trim_data.ellipsis_pos = 0;5956}59575958if ((trim_pos >= 0 && sd->width > p_width) || enforce_ellipsis) {5959if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) {5960// Insert an additional space when cutting word bound for aesthetics.5961if (cut_per_word && (ellipsis_pos > 0)) {5962Glyph gl;5963gl.count = 1;5964gl.advance = whitespace_adv.x;5965gl.index = whitespace_gl_idx;5966gl.font_rid = whitespace_gl_font_rid;5967gl.font_size = last_gl_font_size;5968gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);59695970sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);5971}5972// Add ellipsis dots.5973if (dot_gl_idx != 0) {5974Glyph gl;5975gl.count = 1;5976gl.repeat = (found_el_char ? 1 : 3);5977gl.advance = dot_adv.x;5978gl.index = dot_gl_idx;5979gl.font_rid = dot_gl_font_rid;5980gl.font_size = last_gl_font_size;5981gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);59825983sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);5984}5985}59865987sd->text_trimmed = true;5988sd->width_trimmed = width + ((ellipsis_pos != -1) ? ellipsis_width : 0);5989}5990}59915992int64_t TextServerAdvanced::_shaped_text_get_trim_pos(const RID &p_shaped) const {5993ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5994ERR_FAIL_NULL_V_MSG(sd, -1, "ShapedTextDataAdvanced invalid.");59955996MutexLock lock(sd->mutex);5997return sd->overrun_trim_data.trim_pos;5998}59996000int64_t TextServerAdvanced::_shaped_text_get_ellipsis_pos(const RID &p_shaped) const {6001ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6002ERR_FAIL_NULL_V_MSG(sd, -1, "ShapedTextDataAdvanced invalid.");60036004MutexLock lock(sd->mutex);6005return sd->overrun_trim_data.ellipsis_pos;6006}60076008const Glyph *TextServerAdvanced::_shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const {6009ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6010ERR_FAIL_NULL_V_MSG(sd, nullptr, "ShapedTextDataAdvanced invalid.");60116012MutexLock lock(sd->mutex);6013return sd->overrun_trim_data.ellipsis_glyph_buf.ptr();6014}60156016int64_t TextServerAdvanced::_shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const {6017ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6018ERR_FAIL_NULL_V_MSG(sd, 0, "ShapedTextDataAdvanced invalid.");60196020MutexLock lock(sd->mutex);6021return sd->overrun_trim_data.ellipsis_glyph_buf.size();6022}60236024void TextServerAdvanced::_update_chars(ShapedTextDataAdvanced *p_sd) const {6025if (!p_sd->chars_valid) {6026p_sd->chars.clear();60276028const UChar *data = p_sd->utf16.get_data();6029UErrorCode err = U_ZERO_ERROR;6030int prev = -1;6031int i = 0;60326033Vector<ShapedTextDataAdvanced::Span> &spans = p_sd->spans;6034if (p_sd->parent != RID()) {6035ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(p_sd->parent);6036ERR_FAIL_COND(!parent_sd->valid.is_set());6037spans = parent_sd->spans;6038}60396040int span_size = spans.size();6041while (i < span_size) {6042if (spans[i].start > p_sd->end) {6043break;6044}6045if (spans[i].end < p_sd->start) {6046i++;6047continue;6048}60496050int r_start = MAX(0, spans[i].start - p_sd->start);6051String language = spans[i].language;6052while (i + 1 < span_size && language == spans[i + 1].language) {6053i++;6054}6055int r_end = MIN(spans[i].end - p_sd->start, p_sd->text.length());6056UBreakIterator *bi = ubrk_open(UBRK_CHARACTER, (language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale().ascii().get_data() : language.ascii().get_data(), data + _convert_pos_inv(p_sd, r_start), _convert_pos_inv(p_sd, r_end - r_start), &err);6057if (U_SUCCESS(err)) {6058while (ubrk_next(bi) != UBRK_DONE) {6059int pos = _convert_pos(p_sd, ubrk_current(bi)) + r_start + p_sd->start;6060if (prev != pos) {6061p_sd->chars.push_back(pos);6062}6063prev = pos;6064}6065ubrk_close(bi);6066} else {6067for (int j = r_start; j < r_end; j++) {6068if (prev != j) {6069p_sd->chars.push_back(j + 1 + p_sd->start);6070}6071prev = j;6072}6073}6074i++;6075}6076p_sd->chars_valid = true;6077}6078}60796080PackedInt32Array TextServerAdvanced::_shaped_text_get_character_breaks(const RID &p_shaped) const {6081ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6082ERR_FAIL_NULL_V(sd, PackedInt32Array());60836084MutexLock lock(sd->mutex);6085if (!sd->valid.is_set()) {6086const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);6087}60886089_update_chars(sd);60906091return sd->chars;6092}60936094bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) {6095ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6096ERR_FAIL_NULL_V(sd, false);60976098MutexLock lock(sd->mutex);6099if (!sd->valid.is_set()) {6100_shaped_text_shape(p_shaped);6101}61026103if (sd->line_breaks_valid) {6104return true; // Nothing to do.6105}61066107const UChar *data = sd->utf16.get_data();61086109if (!sd->break_ops_valid) {6110sd->breaks.clear();6111sd->break_inserts = 0;6112UErrorCode err = U_ZERO_ERROR;6113int i = 0;6114int span_size = sd->spans.size();6115while (i < span_size) {6116String language = sd->spans[i].language;6117int r_start = sd->spans[i].start;6118if (r_start == sd->spans[i].end) {6119i++;6120continue;6121}6122while (i + 1 < span_size && (language == sd->spans[i + 1].language || sd->spans[i + 1].start == sd->spans[i + 1].end)) {6123i++;6124}6125int r_end = sd->spans[i].end;6126UBreakIterator *bi = _create_line_break_iterator_for_locale(language, &err);61276128if (!U_FAILURE(err) && bi) {6129ubrk_setText(bi, data + _convert_pos_inv(sd, r_start), _convert_pos_inv(sd, r_end - r_start), &err);6130}61316132if (U_FAILURE(err) || !bi) {6133// No data loaded - use fallback.6134for (int j = r_start; j < r_end; j++) {6135char32_t c = sd->text[j - sd->start];6136char32_t c_next = (j < r_end) ? sd->text[j - sd->start + 1] : 0x0000;6137if (is_whitespace(c)) {6138sd->breaks[j + 1] = false;6139}6140if (is_linebreak(c)) {6141if (c != 0x000D || c_next != 0x000A) { // Skip first hard break in CR-LF pair.6142sd->breaks[j + 1] = true;6143}6144}6145}6146} else {6147while (ubrk_next(bi) != UBRK_DONE) {6148int pos = _convert_pos(sd, ubrk_current(bi)) + r_start;6149if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_HARD) && (ubrk_getRuleStatus(bi) < UBRK_LINE_HARD_LIMIT)) {6150sd->breaks[pos] = true;6151} else if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_SOFT) && (ubrk_getRuleStatus(bi) < UBRK_LINE_SOFT_LIMIT)) {6152sd->breaks[pos] = false;6153}6154int pos_p = pos - 1 - sd->start;6155char32_t c = sd->text[pos_p];6156if (pos - sd->start != sd->end && !is_whitespace(c) && (c != 0xfffc)) {6157sd->break_inserts++;6158}6159}6160ubrk_close(bi);6161}6162i++;6163}6164sd->break_ops_valid = true;6165}61666167LocalVector<Glyph> glyphs_new;61686169bool rewrite = false;6170int sd_shift = 0;6171int sd_size = sd->glyphs.size();6172Glyph *sd_glyphs = sd->glyphs.ptr();6173Glyph *sd_glyphs_new = nullptr;61746175if (sd->break_inserts > 0) {6176glyphs_new.resize(sd->glyphs.size() + sd->break_inserts);6177sd_glyphs_new = glyphs_new.ptr();6178rewrite = true;6179} else {6180sd_glyphs_new = sd_glyphs;6181}61826183sd->sort_valid = false;6184sd->glyphs_logical.clear();6185const char32_t *ch = sd->text.ptr();61866187int c_punct_size = sd->custom_punct.length();6188const char32_t *c_punct = sd->custom_punct.ptr();61896190for (int i = 0; i < sd_size; i++) {6191if (rewrite) {6192for (int j = 0; j < sd_glyphs[i].count; j++) {6193sd_glyphs_new[sd_shift + i + j] = sd_glyphs[i + j];6194}6195}6196if (sd_glyphs[i].count > 0) {6197char32_t c = ch[sd_glyphs[i].start - sd->start];6198if (c == 0xfffc) {6199i += (sd_glyphs[i].count - 1);6200continue;6201}6202if (c == 0x0009 || c == 0x000b) {6203sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_TAB;6204}6205if (c == 0x00ad) {6206sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_SOFT_HYPHEN;6207}6208if (is_whitespace(c)) {6209sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_SPACE;6210}6211if (c_punct_size == 0) {6212if (u_ispunct(c) && c != 0x005f) {6213sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_PUNCTUATION;6214}6215} else {6216for (int j = 0; j < c_punct_size; j++) {6217if (c_punct[j] == c) {6218sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_PUNCTUATION;6219break;6220}6221}6222}6223if (is_underscore(c)) {6224sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_UNDERSCORE;6225}6226if (sd->breaks.has(sd_glyphs[i].end)) {6227if (sd->breaks[sd_glyphs[i].end] && (is_linebreak(c))) {6228sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_BREAK_HARD;6229} else if (is_whitespace(c) || c == 0x00ad) {6230sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_BREAK_SOFT;6231} else {6232int count = sd_glyphs[i].count;6233// Do not add extra space at the end of the line.6234if (sd_glyphs[i].end == sd->end) {6235i += (sd_glyphs[i].count - 1);6236continue;6237}6238// Do not add extra space after existing space.6239if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {6240if ((i + count < sd_size - 1) && ((sd_glyphs[i + count].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) {6241i += (sd_glyphs[i].count - 1);6242continue;6243}6244} else {6245if ((sd_glyphs[i].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) {6246i += (sd_glyphs[i].count - 1);6247continue;6248}6249}6250// Do not add extra space for color picker object.6251if (((sd_glyphs[i].flags & GRAPHEME_IS_EMBEDDED_OBJECT) == GRAPHEME_IS_EMBEDDED_OBJECT && sd_glyphs[i].start == sd_glyphs[i].end) || (uint32_t(i + 1) < sd->glyphs.size() && (sd_glyphs[i + 1].flags & GRAPHEME_IS_EMBEDDED_OBJECT) == GRAPHEME_IS_EMBEDDED_OBJECT && sd_glyphs[i + 1].start == sd_glyphs[i + 1].end)) {6252i += (sd_glyphs[i].count - 1);6253continue;6254}6255Glyph gl;6256gl.span_index = sd_glyphs[i].span_index;6257gl.start = sd_glyphs[i].start;6258gl.end = sd_glyphs[i].end;6259gl.count = 1;6260gl.font_rid = sd_glyphs[i].font_rid;6261gl.font_size = sd_glyphs[i].font_size;6262gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | GRAPHEME_IS_SPACE;6263// Mark virtual space after punctuation as punctuation to avoid justification at this point.6264if (c_punct_size == 0) {6265if (u_ispunct(c) && c != 0x005f) {6266gl.flags |= GRAPHEME_IS_PUNCTUATION;6267}6268} else {6269for (int j = 0; j < c_punct_size; j++) {6270if (c_punct[j] == c) {6271gl.flags |= GRAPHEME_IS_PUNCTUATION;6272break;6273}6274}6275}6276if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {6277gl.flags |= GRAPHEME_IS_RTL;6278for (int j = sd_glyphs[i].count - 1; j >= 0; j--) {6279sd_glyphs_new[sd_shift + i + j + 1] = sd_glyphs_new[sd_shift + i + j];6280}6281sd_glyphs_new[sd_shift + i] = gl;6282} else {6283sd_glyphs_new[sd_shift + i + count] = gl;6284}6285sd_shift++;6286ERR_FAIL_COND_V_MSG(sd_shift > sd->break_inserts, false, "Invalid break insert count!");6287}6288}6289i += (sd_glyphs[i].count - 1);6290}6291}6292if (sd_shift < sd->break_inserts) {6293// Note: should not happen with a normal text, but might be a case with special fonts that substitute a long string (with breaks opportunities in it) with a single glyph (like Font Awesome).6294glyphs_new.resize(sd->glyphs.size() + sd_shift);6295}62966297if (sd->break_inserts > 0) {6298sd->glyphs = std::move(glyphs_new);6299}63006301sd->line_breaks_valid = true;63026303return sd->line_breaks_valid;6304}63056306_FORCE_INLINE_ int64_t _generate_kashida_justification_opportunities(const String &p_data, int64_t p_start, int64_t p_end) {6307int64_t kashida_pos = -1;6308int8_t priority = 100;6309int64_t i = p_start;63106311char32_t pc = 0;63126313while ((p_end > p_start) && is_transparent(p_data[p_end - 1])) {6314p_end--;6315}63166317while (i < p_end) {6318uint32_t c = p_data[i];63196320if (c == 0x0640) {6321kashida_pos = i;6322priority = 0;6323}6324if (priority >= 1 && i < p_end - 1) {6325if (is_seen_sad(c) && (p_data[i + 1] != 0x200c)) {6326kashida_pos = i;6327priority = 1;6328}6329}6330if (priority >= 2 && i > p_start) {6331if (is_teh_marbuta(c) || is_dal(c) || (is_heh(c) && i == p_end - 1)) {6332if (is_connected_to_prev(c, pc)) {6333kashida_pos = i - 1;6334priority = 2;6335}6336}6337}6338if (priority >= 3 && i > p_start) {6339if (is_alef(c) || ((is_lam(c) || is_tah(c) || is_kaf(c) || is_gaf(c)) && i == p_end - 1)) {6340if (is_connected_to_prev(c, pc)) {6341kashida_pos = i - 1;6342priority = 3;6343}6344}6345}6346if (priority >= 4 && i > p_start && i < p_end - 1) {6347if (is_beh(c)) {6348if (is_reh(p_data[i + 1]) || is_yeh(p_data[i + 1])) {6349if (is_connected_to_prev(c, pc)) {6350kashida_pos = i - 1;6351priority = 4;6352}6353}6354}6355}6356if (priority >= 5 && i > p_start) {6357if (is_waw(c) || ((is_ain(c) || is_qaf(c) || is_feh(c)) && i == p_end - 1)) {6358if (is_connected_to_prev(c, pc)) {6359kashida_pos = i - 1;6360priority = 5;6361}6362}6363}6364if (priority >= 6 && i > p_start) {6365if (is_reh(c)) {6366if (is_connected_to_prev(c, pc)) {6367kashida_pos = i - 1;6368priority = 6;6369}6370}6371}6372if (!is_transparent(c)) {6373pc = c;6374}6375i++;6376}63776378return kashida_pos;6379}63806381bool TextServerAdvanced::_shaped_text_update_justification_ops(const RID &p_shaped) {6382ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6383ERR_FAIL_NULL_V(sd, false);63846385MutexLock lock(sd->mutex);6386if (!sd->valid.is_set()) {6387_shaped_text_shape(p_shaped);6388}6389if (!sd->line_breaks_valid) {6390_shaped_text_update_breaks(p_shaped);6391}63926393if (sd->justification_ops_valid) {6394return true; // Nothing to do.6395}63966397const UChar *data = sd->utf16.get_data();6398int data_size = sd->utf16.length();63996400if (!sd->js_ops_valid) {6401sd->jstops.clear();64026403// Use ICU word iterator and custom kashida detection.6404UErrorCode err = U_ZERO_ERROR;6405UBreakIterator *bi = ubrk_open(UBRK_WORD, "", data, data_size, &err);6406if (U_FAILURE(err)) {6407// No data - use fallback.6408int limit = 0;6409for (int i = 0; i < sd->text.length(); i++) {6410if (is_whitespace(sd->text[i])) {6411int ks = _generate_kashida_justification_opportunities(sd->text, limit, i) + sd->start;6412if (ks != -1) {6413sd->jstops[ks] = true;6414}6415limit = i + 1;6416}6417}6418int ks = _generate_kashida_justification_opportunities(sd->text, limit, sd->text.length()) + sd->start;6419if (ks != -1) {6420sd->jstops[ks] = true;6421}6422} else {6423int limit = 0;6424while (ubrk_next(bi) != UBRK_DONE) {6425if (ubrk_getRuleStatus(bi) != UBRK_WORD_NONE) {6426int i = _convert_pos(sd, ubrk_current(bi));6427sd->jstops[i + sd->start] = false;6428int ks = _generate_kashida_justification_opportunities(sd->text, limit, i);6429if (ks != -1) {6430sd->jstops[ks + sd->start] = true;6431}6432limit = i;6433}6434}6435ubrk_close(bi);6436}64376438sd->js_ops_valid = true;6439}64406441sd->sort_valid = false;6442sd->glyphs_logical.clear();64436444Glyph *sd_glyphs = sd->glyphs.ptr();6445int sd_size = sd->glyphs.size();6446if (!sd->jstops.is_empty()) {6447for (int i = 0; i < sd_size; i++) {6448if (sd_glyphs[i].count > 0) {6449char32_t c = sd->text[sd_glyphs[i].start - sd->start];6450if (c == 0x0640 && sd_glyphs[i].start == sd_glyphs[i].end - 1) {6451sd_glyphs[i].flags |= GRAPHEME_IS_ELONGATION;6452}6453if (sd->jstops.has(sd_glyphs[i].start)) {6454if (c == 0xfffc || c == 0x00ad) {6455continue;6456}6457if (sd->jstops[sd_glyphs[i].start]) {6458if (c != 0x0640) {6459if (sd_glyphs[i].font_rid != RID()) {6460Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size);6461if ((sd_glyphs[i].flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {6462#if HB_VERSION_ATLEAST(5, 1, 0)6463if ((i > 0) && ((sd_glyphs[i - 1].flags & GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL) != GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL)) {6464continue;6465}6466#endif6467gl.start = sd_glyphs[i].start;6468gl.end = sd_glyphs[i].end;6469gl.repeat = 0;6470gl.count = 1;6471if (sd->orientation == ORIENTATION_HORIZONTAL) {6472gl.y_off = sd_glyphs[i].y_off;6473} else {6474gl.x_off = sd_glyphs[i].x_off;6475}6476gl.flags |= GRAPHEME_IS_ELONGATION | GRAPHEME_IS_VIRTUAL;6477sd->glyphs.insert(i, gl);6478i++;64796480// Update write pointer and size.6481sd_size = sd->glyphs.size();6482sd_glyphs = sd->glyphs.ptr();6483continue;6484}6485}6486}6487} else if ((sd_glyphs[i].flags & GRAPHEME_IS_SPACE) != GRAPHEME_IS_SPACE && (sd_glyphs[i].flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {6488int count = sd_glyphs[i].count;6489// Do not add extra spaces at the end of the line.6490if (sd_glyphs[i].end == sd->end) {6491continue;6492}6493// Do not add extra space after existing space.6494if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {6495if ((i + count < sd_size - 1) && ((sd_glyphs[i + count].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) {6496continue;6497}6498} else {6499if ((i > 0) && ((sd_glyphs[i - 1].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) {6500continue;6501}6502}6503// Inject virtual space for alignment.6504Glyph gl;6505gl.span_index = sd_glyphs[i].span_index;6506gl.start = sd_glyphs[i].start;6507gl.end = sd_glyphs[i].end;6508gl.count = 1;6509gl.font_rid = sd_glyphs[i].font_rid;6510gl.font_size = sd_glyphs[i].font_size;6511gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_VIRTUAL;6512if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {6513gl.flags |= GRAPHEME_IS_RTL;6514sd->glyphs.insert(i, gl); // Insert before.6515} else {6516sd->glyphs.insert(i + count, gl); // Insert after.6517}6518i += count;65196520// Update write pointer and size.6521sd_size = sd->glyphs.size();6522sd_glyphs = sd->glyphs.ptr();6523continue;6524}6525}6526}6527}6528}65296530sd->justification_ops_valid = true;6531return sd->justification_ops_valid;6532}65336534Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, const RID &p_font, int64_t p_font_size) {6535bool color = false;6536hb_font_t *hb_font = _font_get_hb_handle(p_font, p_font_size, color);6537double scale = _font_get_scale(p_font, p_font_size);6538bool subpos = (scale != 1.0) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_AUTO && p_font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);6539ERR_FAIL_NULL_V(hb_font, Glyph());65406541hb_buffer_clear_contents(p_sd->hb_buffer);6542hb_buffer_set_direction(p_sd->hb_buffer, p_direction);6543hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)(HB_BUFFER_FLAG_DEFAULT));6544hb_buffer_set_script(p_sd->hb_buffer, (p_script == HB_TAG('Z', 's', 'y', 'e')) ? HB_SCRIPT_COMMON : p_script);6545hb_buffer_add_utf32(p_sd->hb_buffer, (const uint32_t *)&p_char, 1, 0, 1);65466547hb_shape(hb_font, p_sd->hb_buffer, nullptr, 0);65486549unsigned int glyph_count = 0;6550hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(p_sd->hb_buffer, &glyph_count);6551hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(p_sd->hb_buffer, &glyph_count);65526553// Process glyphs.6554Glyph gl;65556556if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {6557gl.flags |= TextServer::GRAPHEME_IS_RTL;6558}65596560gl.font_rid = p_font;6561gl.font_size = p_font_size;65626563if (glyph_count > 0) {6564if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6565if (subpos) {6566gl.advance = (double)glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size);6567} else {6568gl.advance = Math::round((double)glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size));6569}6570} else {6571gl.advance = -Math::round((double)glyph_pos[0].y_advance / (64.0 / scale));6572}6573gl.count = 1;65746575gl.index = glyph_info[0].codepoint;6576if (subpos) {6577gl.x_off = (double)glyph_pos[0].x_offset / (64.0 / scale);6578} else {6579gl.x_off = Math::round((double)glyph_pos[0].x_offset / (64.0 / scale));6580}6581gl.y_off = -Math::round((double)glyph_pos[0].y_offset / (64.0 / scale));6582if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6583gl.y_off += _font_get_baseline_offset(gl.font_rid) * (double)(_font_get_ascent(gl.font_rid, gl.font_size) + _font_get_descent(gl.font_rid, gl.font_size));6584} else {6585gl.x_off += _font_get_baseline_offset(gl.font_rid) * (double)(_font_get_ascent(gl.font_rid, gl.font_size) + _font_get_descent(gl.font_rid, gl.font_size));6586}65876588if ((glyph_info[0].codepoint != 0) || !u_isgraph(p_char)) {6589gl.flags |= GRAPHEME_IS_VALID;6590}6591}6592return gl;6593}65946595_FORCE_INLINE_ void TextServerAdvanced::_add_features(const Dictionary &p_source, Vector<hb_feature_t> &r_ftrs) {6596for (const KeyValue<Variant, Variant> &key_value : p_source) {6597int32_t value = key_value.value;6598if (value >= 0) {6599hb_feature_t feature;6600if (key_value.key.is_string()) {6601feature.tag = _name_to_tag(key_value.key);6602} else {6603feature.tag = key_value.key;6604}6605feature.value = value;6606feature.start = 0;6607feature.end = -1;6608r_ftrs.push_back(feature);6609}6610}6611}66126613UBreakIterator *TextServerAdvanced::_create_line_break_iterator_for_locale(const String &p_language, UErrorCode *r_err) const {6614// Creating UBreakIterator (ubrk_open) is surprisingly costly.6615// However, cloning (ubrk_clone) is cheaper, so we keep around blueprints to accelerate creating new ones.66166617String language = p_language.is_empty() ? TranslationServer::get_singleton()->get_tool_locale() : p_language;6618if (!language.contains("@")) {6619if (lb_strictness == LB_LOOSE) {6620language += "@lb=loose";6621} else if (lb_strictness == LB_NORMAL) {6622language += "@lb=normal";6623} else if (lb_strictness == LB_STRICT) {6624language += "@lb=strict";6625}6626}66276628_THREAD_SAFE_METHOD_6629const HashMap<String, UBreakIterator *>::Iterator key_value = line_break_iterators_per_language.find(language);6630if (key_value) {6631return ubrk_clone(key_value->value, r_err);6632}6633UBreakIterator *bi = ubrk_open(UBRK_LINE, language.ascii().get_data(), nullptr, 0, r_err);6634if (U_FAILURE(*r_err) || !bi) {6635return nullptr;6636}6637line_break_iterators_per_language.insert(language, bi);6638return ubrk_clone(bi, r_err);6639}66406641void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, TypedArray<RID> p_fonts, int64_t p_span, int64_t p_fb_index, int64_t p_prev_start, int64_t p_prev_end, RID p_prev_font) {6642RID f;6643int fs = p_sd->spans[p_span].font_size;66446645if (p_fb_index >= 0 && p_fb_index < p_fonts.size()) {6646// Try font from list.6647f = p_fonts[p_fb_index];6648} else if (OS::get_singleton()->has_feature("system_fonts") && p_fonts.size() > 0 && ((p_fb_index == p_fonts.size()) || (p_fb_index > p_fonts.size() && p_start != p_prev_start))) {6649// Try system fallback.6650RID fdef = p_fonts[0];6651if (_font_is_allow_system_fallback(fdef)) {6652_update_chars(p_sd);66536654int64_t next = p_end;6655for (const int32_t &E : p_sd->chars) {6656if (E > p_start) {6657next = E;6658break;6659}6660}6661char scr_buffer[5] = { 0, 0, 0, 0, 0 };6662hb_tag_to_string(hb_script_to_iso15924_tag(p_script), scr_buffer);6663String script_code = String(scr_buffer);66646665String text = p_sd->text.substr(p_start, next - p_start);6666f = _find_sys_font_for_text(fdef, script_code, p_sd->spans[p_span].language, text);6667}6668}66696670if (!f.is_valid()) {6671// Shaping failed, try looking up raw characters or use fallback hex code boxes.6672int fb_from = (p_direction != HB_DIRECTION_RTL) ? p_start : p_end - 1;6673int fb_to = (p_direction != HB_DIRECTION_RTL) ? p_end : p_start - 1;6674int fb_delta = (p_direction != HB_DIRECTION_RTL) ? +1 : -1;66756676for (int i = fb_from; i != fb_to; i += fb_delta) {6677if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) {6678Glyph gl;6679gl.span_index = p_span;6680gl.start = i + p_sd->start;6681gl.end = i + 1 + p_sd->start;6682gl.count = 1;6683gl.font_size = fs;6684if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {6685gl.flags |= TextServer::GRAPHEME_IS_RTL;6686}66876688bool found = false;6689for (int j = 0; j <= p_fonts.size(); j++) {6690RID f_rid;6691if (j == p_fonts.size()) {6692f_rid = p_prev_font;6693} else {6694f_rid = p_fonts[j];6695}6696if (f_rid.is_valid() && _font_has_char(f_rid, p_sd->text[i])) {6697gl.font_rid = f_rid;6698gl.index = _font_get_glyph_index(gl.font_rid, fs, p_sd->text[i], 0);6699if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6700gl.advance = _font_get_glyph_advance(gl.font_rid, fs, gl.index).x;6701gl.x_off = 0;6702gl.y_off = _font_get_baseline_offset(gl.font_rid) * (double)(_font_get_ascent(gl.font_rid, gl.font_size) + _font_get_descent(gl.font_rid, gl.font_size));6703p_sd->ascent = MAX(p_sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_TOP));6704p_sd->descent = MAX(p_sd->descent, _font_get_descent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_BOTTOM));6705} else {6706gl.advance = _font_get_glyph_advance(gl.font_rid, fs, gl.index).y;6707gl.x_off = -Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5) + _font_get_baseline_offset(gl.font_rid) * (double)(_font_get_ascent(gl.font_rid, gl.font_size) + _font_get_descent(gl.font_rid, gl.font_size));6708gl.y_off = _font_get_ascent(gl.font_rid, gl.font_size);6709p_sd->ascent = MAX(p_sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));6710p_sd->descent = MAX(p_sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));6711}6712double scale = _font_get_scale(gl.font_rid, fs);6713bool subpos = (scale != 1.0) || (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_AUTO && fs <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);6714if (!subpos) {6715gl.advance = Math::round(gl.advance);6716gl.x_off = Math::round(gl.x_off);6717}6718found = true;6719break;6720}6721}6722if (!found) {6723gl.font_rid = RID();6724gl.index = p_sd->text[i];6725if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6726gl.advance = get_hex_code_box_size(fs, gl.index).x;6727p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(fs, gl.index).y * 0.85);6728p_sd->descent = MAX(p_sd->descent, get_hex_code_box_size(fs, gl.index).y * 0.15);6729} else {6730gl.advance = get_hex_code_box_size(fs, gl.index).y;6731gl.y_off = get_hex_code_box_size(fs, gl.index).y;6732gl.x_off = -Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5);6733p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5));6734p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5));6735}6736}67376738p_sd->width += gl.advance;67396740p_sd->glyphs.push_back(gl);6741}6742}6743return;6744}67456746FontAdvanced *fd = _get_font_data(f);6747ERR_FAIL_NULL(fd);6748MutexLock lock(fd->mutex);6749bool color = false;67506751Vector2i fss = _get_size(fd, fs);6752hb_font_t *hb_font = _font_get_hb_handle(f, fs, color);67536754if (p_script == HB_TAG('Z', 's', 'y', 'e') && !color) {6755// Color emoji is requested, skip non-color font.6756_shape_run(p_sd, p_start, p_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1, p_start, p_end, f);6757return;6758}67596760double scale = _font_get_scale(f, fs);6761double sp_sp = p_sd->extra_spacing[SPACING_SPACE] + _font_get_spacing(f, SPACING_SPACE);6762double sp_gl = p_sd->extra_spacing[SPACING_GLYPH] + _font_get_spacing(f, SPACING_GLYPH);6763bool last_run = (p_sd->end == p_end);6764double ea = _get_extra_advance(f, fs);6765bool subpos = (scale != 1.0) || (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_AUTO && fs <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);6766ERR_FAIL_NULL(hb_font);67676768hb_buffer_clear_contents(p_sd->hb_buffer);6769hb_buffer_set_direction(p_sd->hb_buffer, p_direction);6770int flags = (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0);6771if (p_sd->preserve_control) {6772flags |= HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES;6773} else {6774flags |= HB_BUFFER_FLAG_DEFAULT;6775}6776#if HB_VERSION_ATLEAST(5, 1, 0)6777flags |= HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL;6778#endif6779hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)flags);6780hb_buffer_set_script(p_sd->hb_buffer, (p_script == HB_TAG('Z', 's', 'y', 'e')) ? HB_SCRIPT_COMMON : p_script);67816782if (p_sd->spans[p_span].language.is_empty()) {6783hb_language_t lang = hb_language_from_string(TranslationServer::get_singleton()->get_tool_locale().ascii().get_data(), -1);6784hb_buffer_set_language(p_sd->hb_buffer, lang);6785} else {6786hb_language_t lang = hb_language_from_string(p_sd->spans[p_span].language.ascii().get_data(), -1);6787hb_buffer_set_language(p_sd->hb_buffer, lang);6788}67896790hb_buffer_add_utf32(p_sd->hb_buffer, (const uint32_t *)p_sd->text.ptr(), p_sd->text.length(), p_start, p_end - p_start);67916792Vector<hb_feature_t> ftrs;6793_add_features(_font_get_opentype_feature_overrides(f), ftrs);6794_add_features(p_sd->spans[p_span].features, ftrs);67956796hb_shape(hb_font, p_sd->hb_buffer, ftrs.is_empty() ? nullptr : &ftrs[0], ftrs.size());67976798unsigned int glyph_count = 0;6799hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(p_sd->hb_buffer, &glyph_count);6800hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(p_sd->hb_buffer, &glyph_count);68016802int mod = 0;6803if (fd->antialiasing == FONT_ANTIALIASING_LCD) {6804TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();6805if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {6806mod = (layout << 24);6807}6808}68096810// Process glyphs.6811if (glyph_count > 0) {6812Glyph *w = (Glyph *)memalloc(glyph_count * sizeof(Glyph));68136814int end = (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) ? p_end : 0;6815uint32_t last_cluster_id = UINT32_MAX;6816unsigned int last_cluster_index = 0;6817bool last_cluster_valid = true;68186819unsigned int last_non_zero_w = glyph_count - 1;6820if (last_run) {6821for (unsigned int i = glyph_count - 1; i > 0; i--) {6822last_non_zero_w = i;6823if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6824if (glyph_pos[i].x_advance != 0) {6825break;6826}6827} else {6828if (glyph_pos[i].y_advance != 0) {6829break;6830}6831}6832}6833}68346835double adv_rem = 0.0;6836for (unsigned int i = 0; i < glyph_count; i++) {6837if ((i > 0) && (last_cluster_id != glyph_info[i].cluster)) {6838if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {6839end = w[last_cluster_index].start;6840} else {6841for (unsigned int j = last_cluster_index; j < i; j++) {6842w[j].end = glyph_info[i].cluster;6843}6844}6845if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {6846w[last_cluster_index].flags |= GRAPHEME_IS_RTL;6847}6848if (last_cluster_valid) {6849w[last_cluster_index].flags |= GRAPHEME_IS_VALID;6850}6851w[last_cluster_index].count = i - last_cluster_index;6852last_cluster_index = i;6853last_cluster_valid = true;6854}68556856last_cluster_id = glyph_info[i].cluster;68576858Glyph &gl = w[i];6859gl = Glyph();68606861gl.span_index = p_span;6862gl.start = glyph_info[i].cluster;6863gl.end = end;6864gl.count = 0;68656866gl.font_rid = f;6867gl.font_size = fs;68686869if (glyph_info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK) {6870gl.flags |= GRAPHEME_IS_CONNECTED;6871}68726873#if HB_VERSION_ATLEAST(5, 1, 0)6874if (glyph_info[i].mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL) {6875gl.flags |= GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL;6876}6877#endif68786879gl.index = glyph_info[i].codepoint;6880bool zero_w = (p_sd->preserve_control) ? (p_sd->text[glyph_info[i].cluster] == 0x200B || p_sd->text[glyph_info[i].cluster] == 0xFEF) : (p_sd->text[glyph_info[i].cluster] >= 0x200B && p_sd->text[glyph_info[i].cluster] <= 0x200D) || p_sd->text[glyph_info[i].cluster] == 0x2060 || p_sd->text[glyph_info[i].cluster] == 0xFEFF;6881if (zero_w) {6882gl.index = 0;6883gl.advance = 0.0;6884}6885if ((p_sd->text[glyph_info[i].cluster] == 0x0009) || u_isblank(p_sd->text[glyph_info[i].cluster]) || is_linebreak(p_sd->text[glyph_info[i].cluster])) {6886adv_rem = 0.0; // Reset on blank.6887}6888if (gl.index != 0) {6889FontGlyph fgl;6890_ensure_glyph(fd, fss, gl.index | mod, fgl);6891if (subpos) {6892gl.x_off = (double)glyph_pos[i].x_offset / (64.0 / scale);6893} else if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6894gl.x_off = Math::round(adv_rem + ((double)glyph_pos[i].x_offset / (64.0 / scale)));6895} else {6896gl.x_off = Math::round((double)glyph_pos[i].x_offset / (64.0 / scale));6897}6898if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6899gl.y_off = -Math::round((double)glyph_pos[i].y_offset / (64.0 / scale));6900} else {6901gl.y_off = -Math::round(adv_rem + ((double)glyph_pos[i].y_offset / (64.0 / scale)));6902}6903if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6904if (subpos) {6905gl.advance = (double)glyph_pos[i].x_advance / (64.0 / scale) + ea;6906} else {6907double full_adv = adv_rem + ((double)glyph_pos[i].x_advance / (64.0 / scale) + ea);6908gl.advance = Math::round(full_adv);6909if (fd->keep_rounding_remainders) {6910adv_rem = full_adv - gl.advance;6911}6912}6913} else {6914double full_adv = adv_rem + ((double)glyph_pos[i].y_advance / (64.0 / scale));6915gl.advance = -Math::round(full_adv);6916if (fd->keep_rounding_remainders) {6917adv_rem = full_adv + gl.advance;6918}6919}6920if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6921gl.y_off += _font_get_baseline_offset(gl.font_rid) * (double)(_font_get_ascent(gl.font_rid, gl.font_size) + _font_get_descent(gl.font_rid, gl.font_size));6922} else {6923gl.x_off += _font_get_baseline_offset(gl.font_rid) * (double)(_font_get_ascent(gl.font_rid, gl.font_size) + _font_get_descent(gl.font_rid, gl.font_size));6924}6925}6926if ((!last_run || i < last_non_zero_w) && !Math::is_zero_approx(gl.advance)) {6927// Do not add extra spacing to the last glyph of the string and zero width glyphs.6928if (sp_sp && is_whitespace(p_sd->text[glyph_info[i].cluster])) {6929gl.advance += sp_sp;6930} else {6931gl.advance += sp_gl;6932}6933}69346935if (p_sd->preserve_control) {6936last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || zero_w || (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])));6937} else {6938last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || zero_w || (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])));6939}6940}6941if (p_direction == HB_DIRECTION_LTR || p_direction == HB_DIRECTION_TTB) {6942for (unsigned int j = last_cluster_index; j < glyph_count; j++) {6943w[j].end = p_end;6944}6945}6946w[last_cluster_index].count = glyph_count - last_cluster_index;6947if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {6948w[last_cluster_index].flags |= GRAPHEME_IS_RTL;6949}6950if (last_cluster_valid) {6951w[last_cluster_index].flags |= GRAPHEME_IS_VALID;6952}69536954// Fallback.6955int failed_subrun_start = p_end + 1;6956int failed_subrun_end = p_start;69576958for (unsigned int i = 0; i < glyph_count; i++) {6959if ((w[i].flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {6960if (failed_subrun_start != p_end + 1) {6961_shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1, p_start, p_end, (p_fb_index >= p_fonts.size()) ? f : RID());6962failed_subrun_start = p_end + 1;6963failed_subrun_end = p_start;6964}6965for (int j = 0; j < w[i].count; j++) {6966if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6967p_sd->ascent = MAX(p_sd->ascent, -w[i + j].y_off);6968p_sd->descent = MAX(p_sd->descent, w[i + j].y_off);6969} else {6970double gla = Math::round(_font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5);6971p_sd->ascent = MAX(p_sd->ascent, gla);6972p_sd->descent = MAX(p_sd->descent, gla);6973}6974p_sd->width += w[i + j].advance;6975w[i + j].start += p_sd->start;6976w[i + j].end += p_sd->start;6977p_sd->glyphs.push_back(w[i + j]);6978}6979} else {6980if (failed_subrun_start >= w[i].start) {6981failed_subrun_start = w[i].start;6982}6983if (failed_subrun_end <= w[i].end) {6984failed_subrun_end = w[i].end;6985}6986}6987i += w[i].count - 1;6988}6989memfree(w);6990if (failed_subrun_start != p_end + 1) {6991_shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1, p_start, p_end, (p_fb_index >= p_fonts.size()) ? f : RID());6992}6993p_sd->ascent = MAX(p_sd->ascent, _font_get_ascent(f, fs) + _font_get_spacing(f, SPACING_TOP));6994p_sd->descent = MAX(p_sd->descent, _font_get_descent(f, fs) + _font_get_spacing(f, SPACING_BOTTOM));6995p_sd->upos = MAX(p_sd->upos, _font_get_underline_position(f, fs));6996p_sd->uthk = MAX(p_sd->uthk, _font_get_underline_thickness(f, fs));6997} else if (p_start != p_end) {6998if (p_fb_index >= p_fonts.size()) {6999Glyph gl;7000gl.start = p_start;7001gl.end = p_end;7002gl.span_index = p_span;7003gl.font_rid = f;7004gl.font_size = fs;7005gl.flags = GRAPHEME_IS_VALID;7006p_sd->glyphs.push_back(gl);70077008p_sd->ascent = MAX(p_sd->ascent, _font_get_ascent(f, fs) + _font_get_spacing(f, SPACING_TOP));7009p_sd->descent = MAX(p_sd->descent, _font_get_descent(f, fs) + _font_get_spacing(f, SPACING_BOTTOM));7010p_sd->upos = MAX(p_sd->upos, _font_get_underline_position(f, fs));7011p_sd->uthk = MAX(p_sd->uthk, _font_get_underline_thickness(f, fs));7012} else {7013_shape_run(p_sd, p_start, p_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1, p_start, p_end, f);7014}7015}7016}70177018bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {7019_THREAD_SAFE_METHOD_7020ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7021ERR_FAIL_NULL_V(sd, false);70227023MutexLock lock(sd->mutex);7024if (sd->valid.is_set()) {7025return true;7026}70277028invalidate(sd, false);7029if (sd->parent != RID()) {7030_shaped_text_shape(sd->parent);7031ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);7032ERR_FAIL_COND_V(!parent_sd->valid.is_set(), false);7033ERR_FAIL_COND_V(!_shape_substr(sd, parent_sd, sd->start, sd->end - sd->start), false);7034return true;7035}70367037if (sd->text.length() == 0) {7038sd->valid.set();7039return true;7040}70417042sd->utf16 = sd->text.utf16();7043const UChar *data = sd->utf16.get_data();70447045// Create script iterator.7046if (sd->script_iter == nullptr) {7047sd->script_iter = memnew(ScriptIterator(sd->text, 0, sd->text.length()));7048}70497050sd->base_para_direction = UBIDI_DEFAULT_LTR;7051switch (sd->direction) {7052case DIRECTION_LTR: {7053sd->para_direction = DIRECTION_LTR;7054sd->base_para_direction = UBIDI_LTR;7055} break;7056case DIRECTION_RTL: {7057sd->para_direction = DIRECTION_RTL;7058sd->base_para_direction = UBIDI_RTL;7059} break;7060case DIRECTION_INHERITED:7061case DIRECTION_AUTO: {7062UBiDiDirection direction = ubidi_getBaseDirection(data, sd->utf16.length());7063if (direction != UBIDI_NEUTRAL) {7064sd->para_direction = (direction == UBIDI_RTL) ? DIRECTION_RTL : DIRECTION_LTR;7065sd->base_para_direction = direction;7066} else {7067const String &lang = (sd->spans.is_empty() || sd->spans[0].language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : sd->spans[0].language;7068bool lang_rtl = _is_locale_right_to_left(lang);70697070sd->para_direction = lang_rtl ? DIRECTION_RTL : DIRECTION_LTR;7071sd->base_para_direction = lang_rtl ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR;7072}7073} break;7074}70757076Vector<Vector3i> bidi_ranges;7077if (sd->bidi_override.is_empty()) {7078bidi_ranges.push_back(Vector3i(sd->start, sd->end, DIRECTION_INHERITED));7079} else {7080bidi_ranges = sd->bidi_override;7081}7082sd->runs.clear();7083sd->runs_dirty = true;70847085for (int ov = 0; ov < bidi_ranges.size(); ov++) {7086// Create BiDi iterator.7087int start = _convert_pos_inv(sd, bidi_ranges[ov].x - sd->start);7088int end = _convert_pos_inv(sd, bidi_ranges[ov].y - sd->start);70897090if (start < 0 || end - start > sd->utf16.length()) {7091continue;7092}70937094UErrorCode err = U_ZERO_ERROR;7095UBiDi *bidi_iter = ubidi_openSized(end - start, 0, &err);7096if (U_SUCCESS(err)) {7097switch (static_cast<TextServer::Direction>(bidi_ranges[ov].z)) {7098case DIRECTION_LTR: {7099ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err);7100} break;7101case DIRECTION_RTL: {7102ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err);7103} break;7104case DIRECTION_INHERITED: {7105ubidi_setPara(bidi_iter, data + start, end - start, sd->base_para_direction, nullptr, &err);7106} break;7107case DIRECTION_AUTO: {7108UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start);7109if (direction != UBIDI_NEUTRAL) {7110ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);7111} else {7112ubidi_setPara(bidi_iter, data + start, end - start, sd->base_para_direction, nullptr, &err);7113}7114} break;7115}7116if (U_FAILURE(err)) {7117ubidi_close(bidi_iter);7118bidi_iter = nullptr;7119ERR_PRINT(vformat("BiDi reordering for the paragraph failed: %s", u_errorName(err)));7120}7121} else {7122bidi_iter = nullptr;7123ERR_PRINT(vformat("BiDi iterator allocation for the paragraph failed: %s", u_errorName(err)));7124}7125sd->bidi_iter.push_back(bidi_iter);71267127err = U_ZERO_ERROR;7128int bidi_run_count = 1;7129if (bidi_iter) {7130bidi_run_count = ubidi_countRuns(bidi_iter, &err);7131if (U_FAILURE(err)) {7132ERR_PRINT(u_errorName(err));7133}7134}7135for (int i = 0; i < bidi_run_count; i++) {7136int32_t _bidi_run_start = 0;7137int32_t _bidi_run_length = end - start;7138bool is_ltr = false;7139hb_direction_t bidi_run_direction = HB_DIRECTION_INVALID;7140if (bidi_iter) {7141is_ltr = (ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length) == UBIDI_LTR);7142}7143switch (sd->orientation) {7144case ORIENTATION_HORIZONTAL: {7145if (is_ltr) {7146bidi_run_direction = HB_DIRECTION_LTR;7147} else {7148bidi_run_direction = HB_DIRECTION_RTL;7149}7150} break;7151case ORIENTATION_VERTICAL: {7152if (is_ltr) {7153bidi_run_direction = HB_DIRECTION_TTB;7154} else {7155bidi_run_direction = HB_DIRECTION_BTT;7156}7157}7158}71597160int32_t bidi_run_start = _convert_pos(sd, start + _bidi_run_start);7161int32_t bidi_run_end = _convert_pos(sd, start + _bidi_run_start + _bidi_run_length);71627163// Shape runs.71647165int scr_from = (is_ltr) ? 0 : sd->script_iter->script_ranges.size() - 1;7166int scr_to = (is_ltr) ? sd->script_iter->script_ranges.size() : -1;7167int scr_delta = (is_ltr) ? +1 : -1;71687169for (int j = scr_from; j != scr_to; j += scr_delta) {7170if ((sd->script_iter->script_ranges[j].start < bidi_run_end) && (sd->script_iter->script_ranges[j].end > bidi_run_start)) {7171int32_t script_run_start = MAX(sd->script_iter->script_ranges[j].start, bidi_run_start);7172int32_t script_run_end = MIN(sd->script_iter->script_ranges[j].end, bidi_run_end);7173char scr_buffer[5] = { 0, 0, 0, 0, 0 };7174hb_tag_to_string(hb_script_to_iso15924_tag(sd->script_iter->script_ranges[j].script), scr_buffer);7175String script_code = String(scr_buffer);71767177int spn_from = (is_ltr) ? 0 : sd->spans.size() - 1;7178int spn_to = (is_ltr) ? sd->spans.size() : -1;7179int spn_delta = (is_ltr) ? +1 : -1;71807181for (int k = spn_from; k != spn_to; k += spn_delta) {7182const ShapedTextDataAdvanced::Span &span = sd->spans[k];7183int col_key_off = (span.start == span.end) ? 1 : 0;7184if (span.start - sd->start >= script_run_end || span.end - sd->start <= script_run_start - col_key_off) {7185continue;7186}7187if (span.embedded_key != Variant()) {7188// Embedded object.7189if (sd->orientation == ORIENTATION_HORIZONTAL) {7190sd->objects[span.embedded_key].rect.position.x = sd->width;7191sd->width += sd->objects[span.embedded_key].rect.size.x;7192} else {7193sd->objects[span.embedded_key].rect.position.y = sd->width;7194sd->width += sd->objects[span.embedded_key].rect.size.y;7195}7196Glyph gl;7197gl.start = span.start;7198gl.end = span.end;7199gl.count = 1;7200gl.span_index = k;7201gl.flags = GRAPHEME_IS_VALID | GRAPHEME_IS_EMBEDDED_OBJECT;7202if (sd->orientation == ORIENTATION_HORIZONTAL) {7203gl.advance = sd->objects[span.embedded_key].rect.size.x;7204} else {7205gl.advance = sd->objects[span.embedded_key].rect.size.y;7206}7207sd->glyphs.push_back(gl);7208} else {7209Array fonts;7210Array fonts_scr_only;7211Array fonts_no_match;7212int font_count = span.fonts.size();7213if (font_count > 0) {7214fonts.push_back(sd->spans[k].fonts[0]);7215}7216for (int l = 1; l < font_count; l++) {7217if (_font_is_script_supported(span.fonts[l], script_code)) {7218if (_font_is_language_supported(span.fonts[l], span.language)) {7219fonts.push_back(sd->spans[k].fonts[l]);7220} else {7221fonts_scr_only.push_back(sd->spans[k].fonts[l]);7222}7223} else {7224fonts_no_match.push_back(sd->spans[k].fonts[l]);7225}7226}7227fonts.append_array(fonts_scr_only);7228fonts.append_array(fonts_no_match);7229_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, 0, 0, RID());7230}7231}7232}7233}7234}7235}72367237_realign(sd);7238sd->valid.set();7239return sd->valid.is_set();7240}72417242bool TextServerAdvanced::_shaped_text_is_ready(const RID &p_shaped) const {7243const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7244ERR_FAIL_NULL_V(sd, false);72457246// Atomic read is safe and faster.7247return sd->valid.is_set();7248}72497250const Glyph *TextServerAdvanced::_shaped_text_get_glyphs(const RID &p_shaped) const {7251const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7252ERR_FAIL_NULL_V(sd, nullptr);72537254MutexLock lock(sd->mutex);7255if (!sd->valid.is_set()) {7256const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7257}7258return sd->glyphs.ptr();7259}72607261int64_t TextServerAdvanced::_shaped_text_get_glyph_count(const RID &p_shaped) const {7262const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7263ERR_FAIL_NULL_V(sd, 0);72647265MutexLock lock(sd->mutex);7266if (!sd->valid.is_set()) {7267const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7268}7269return sd->glyphs.size();7270}72717272const Glyph *TextServerAdvanced::_shaped_text_sort_logical(const RID &p_shaped) {7273ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7274ERR_FAIL_NULL_V(sd, nullptr);72757276MutexLock lock(sd->mutex);7277if (!sd->valid.is_set()) {7278_shaped_text_shape(p_shaped);7279}72807281if (!sd->sort_valid) {7282sd->glyphs_logical = sd->glyphs;7283sd->glyphs_logical.sort_custom<GlyphCompare>();7284sd->sort_valid = true;7285}72867287return sd->glyphs_logical.ptr();7288}72897290Vector2i TextServerAdvanced::_shaped_text_get_range(const RID &p_shaped) const {7291const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7292ERR_FAIL_NULL_V(sd, Vector2i());72937294MutexLock lock(sd->mutex);7295return Vector2(sd->start, sd->end);7296}72977298Array TextServerAdvanced::_shaped_text_get_objects(const RID &p_shaped) const {7299Array ret;7300const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7301ERR_FAIL_NULL_V(sd, ret);73027303MutexLock lock(sd->mutex);7304for (const KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : sd->objects) {7305ret.push_back(E.key);7306}73077308return ret;7309}73107311Rect2 TextServerAdvanced::_shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const {7312const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7313ERR_FAIL_NULL_V(sd, Rect2());73147315MutexLock lock(sd->mutex);7316ERR_FAIL_COND_V(!sd->objects.has(p_key), Rect2());7317if (!sd->valid.is_set()) {7318const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7319}7320return sd->objects[p_key].rect;7321}73227323Vector2i TextServerAdvanced::_shaped_text_get_object_range(const RID &p_shaped, const Variant &p_key) const {7324const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7325ERR_FAIL_NULL_V(sd, Vector2i());73267327MutexLock lock(sd->mutex);7328ERR_FAIL_COND_V(!sd->objects.has(p_key), Vector2i());7329return Vector2i(sd->objects[p_key].start, sd->objects[p_key].end);7330}73317332int64_t TextServerAdvanced::_shaped_text_get_object_glyph(const RID &p_shaped, const Variant &p_key) const {7333const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7334ERR_FAIL_NULL_V(sd, -1);73357336MutexLock lock(sd->mutex);7337ERR_FAIL_COND_V(!sd->objects.has(p_key), -1);7338if (!sd->valid.is_set()) {7339const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7340}7341const ShapedTextDataAdvanced::EmbeddedObject &obj = sd->objects[p_key];7342int sd_size = sd->glyphs.size();7343const Glyph *sd_glyphs = sd->glyphs.ptr();7344for (int i = 0; i < sd_size; i++) {7345if (obj.start == sd_glyphs[i].start) {7346return i;7347}7348}7349return -1;7350}73517352Size2 TextServerAdvanced::_shaped_text_get_size(const RID &p_shaped) const {7353const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7354ERR_FAIL_NULL_V(sd, Size2());73557356MutexLock lock(sd->mutex);7357if (!sd->valid.is_set()) {7358const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7359}7360if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) {7361return Size2((sd->text_trimmed ? sd->width_trimmed : sd->width), sd->ascent + sd->descent + sd->extra_spacing[SPACING_TOP] + sd->extra_spacing[SPACING_BOTTOM]).ceil();7362} else {7363return Size2(sd->ascent + sd->descent + sd->extra_spacing[SPACING_TOP] + sd->extra_spacing[SPACING_BOTTOM], (sd->text_trimmed ? sd->width_trimmed : sd->width)).ceil();7364}7365}73667367double TextServerAdvanced::_shaped_text_get_ascent(const RID &p_shaped) const {7368const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7369ERR_FAIL_NULL_V(sd, 0.0);73707371MutexLock lock(sd->mutex);7372if (!sd->valid.is_set()) {7373const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7374}7375return sd->ascent + sd->extra_spacing[SPACING_TOP];7376}73777378double TextServerAdvanced::_shaped_text_get_descent(const RID &p_shaped) const {7379const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7380ERR_FAIL_NULL_V(sd, 0.0);73817382MutexLock lock(sd->mutex);7383if (!sd->valid.is_set()) {7384const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7385}7386return sd->descent + sd->extra_spacing[SPACING_BOTTOM];7387}73887389double TextServerAdvanced::_shaped_text_get_width(const RID &p_shaped) const {7390const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7391ERR_FAIL_NULL_V(sd, 0.0);73927393MutexLock lock(sd->mutex);7394if (!sd->valid.is_set()) {7395const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7396}7397return Math::ceil(sd->text_trimmed ? sd->width_trimmed : sd->width);7398}73997400double TextServerAdvanced::_shaped_text_get_underline_position(const RID &p_shaped) const {7401const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7402ERR_FAIL_NULL_V(sd, 0.0);74037404MutexLock lock(sd->mutex);7405if (!sd->valid.is_set()) {7406const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7407}74087409return sd->upos;7410}74117412double TextServerAdvanced::_shaped_text_get_underline_thickness(const RID &p_shaped) const {7413const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7414ERR_FAIL_NULL_V(sd, 0.0);74157416MutexLock lock(sd->mutex);7417if (!sd->valid.is_set()) {7418const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7419}74207421return sd->uthk;7422}74237424void TextServerAdvanced::_insert_num_systems_lang() {7425// Eastern Arabic numerals.7426{7427NumSystemData ar;7428ar.lang.insert(StringName("ar")); // Arabic7429ar.lang.insert(StringName("ar_AE"));7430ar.lang.insert(StringName("ar_BH"));7431ar.lang.insert(StringName("ar_DJ"));7432ar.lang.insert(StringName("ar_EG"));7433ar.lang.insert(StringName("ar_ER"));7434ar.lang.insert(StringName("ar_IL"));7435ar.lang.insert(StringName("ar_IQ"));7436ar.lang.insert(StringName("ar_JO"));7437ar.lang.insert(StringName("ar_KM"));7438ar.lang.insert(StringName("ar_KW"));7439ar.lang.insert(StringName("ar_LB"));7440ar.lang.insert(StringName("ar_MR"));7441ar.lang.insert(StringName("ar_OM"));7442ar.lang.insert(StringName("ar_PS"));7443ar.lang.insert(StringName("ar_QA"));7444ar.lang.insert(StringName("ar_SA"));7445ar.lang.insert(StringName("ar_SD"));7446ar.lang.insert(StringName("ar_SO"));7447ar.lang.insert(StringName("ar_SS"));7448ar.lang.insert(StringName("ar_SY"));7449ar.lang.insert(StringName("ar_TD"));7450ar.lang.insert(StringName("ar_YE"));7451ar.lang.insert(StringName("ckb")); // Central Kurdish7452ar.lang.insert(StringName("ckb_IQ"));7453ar.lang.insert(StringName("ckb_IR"));7454ar.lang.insert(StringName("sd")); // Sindhi7455ar.lang.insert(StringName("sd_PK"));7456ar.lang.insert(StringName("sd_Arab"));7457ar.lang.insert(StringName("sd_Arab_PK"));7458ar.digits = U"٠١٢٣٤٥٦٧٨٩٫";7459ar.percent_sign = U"٪";7460ar.exp_l = U"اس";7461ar.exp_u = U"اس";7462num_systems.push_back(ar);7463}74647465// Persian and Urdu numerals.7466{7467NumSystemData pr;7468pr.lang.insert(StringName("fa")); // Persian7469pr.lang.insert(StringName("fa_AF"));7470pr.lang.insert(StringName("fa_IR"));7471pr.lang.insert(StringName("ks")); // Kashmiri7472pr.lang.insert(StringName("ks_IN"));7473pr.lang.insert(StringName("ks_Arab"));7474pr.lang.insert(StringName("ks_Arab_IN"));7475pr.lang.insert(StringName("lrc")); // Northern Luri7476pr.lang.insert(StringName("lrc_IQ"));7477pr.lang.insert(StringName("lrc_IR"));7478pr.lang.insert(StringName("mzn")); // Mazanderani7479pr.lang.insert(StringName("mzn_IR"));7480pr.lang.insert(StringName("pa_PK")); // Panjabi7481pr.lang.insert(StringName("pa_Arab"));7482pr.lang.insert(StringName("pa_Arab_PK"));7483pr.lang.insert(StringName("ps")); // Pushto7484pr.lang.insert(StringName("ps_AF"));7485pr.lang.insert(StringName("ps_PK"));7486pr.lang.insert(StringName("ur_IN")); // Urdu7487pr.lang.insert(StringName("uz_AF")); // Uzbek7488pr.lang.insert(StringName("uz_Arab"));7489pr.lang.insert(StringName("uz_Arab_AF"));7490pr.digits = U"۰۱۲۳۴۵۶۷۸۹٫";7491pr.percent_sign = U"٪";7492pr.exp_l = U"اس";7493pr.exp_u = U"اس";7494num_systems.push_back(pr);7495}74967497// Bengali numerals.7498{7499NumSystemData bn;7500bn.lang.insert(StringName("as")); // Assamese7501bn.lang.insert(StringName("as_IN"));7502bn.lang.insert(StringName("bn")); // Bengali7503bn.lang.insert(StringName("bn_BD"));7504bn.lang.insert(StringName("bn_IN"));7505bn.lang.insert(StringName("mni")); // Manipuri7506bn.lang.insert(StringName("mni_IN"));7507bn.lang.insert(StringName("mni_Beng"));7508bn.lang.insert(StringName("mni_Beng_IN"));7509bn.digits = U"০১২৩৪৫৬৭৮৯.";7510bn.percent_sign = U"%";7511bn.exp_l = U"e";7512bn.exp_u = U"E";7513num_systems.push_back(bn);7514}75157516// Devanagari numerals.7517{7518NumSystemData mr;7519mr.lang.insert(StringName("mr")); // Marathi7520mr.lang.insert(StringName("mr_IN"));7521mr.lang.insert(StringName("ne")); // Nepali7522mr.lang.insert(StringName("ne_IN"));7523mr.lang.insert(StringName("ne_NP"));7524mr.lang.insert(StringName("sa")); // Sanskrit7525mr.lang.insert(StringName("sa_IN"));7526mr.digits = U"०१२३४५६७८९.";7527mr.percent_sign = U"%";7528mr.exp_l = U"e";7529mr.exp_u = U"E";7530num_systems.push_back(mr);7531}75327533// Dzongkha numerals.7534{7535NumSystemData dz;7536dz.lang.insert(StringName("dz")); // Dzongkha7537dz.lang.insert(StringName("dz_BT"));7538dz.digits = U"༠༡༢༣༤༥༦༧༨༩.";7539dz.percent_sign = U"%";7540dz.exp_l = U"e";7541dz.exp_u = U"E";7542num_systems.push_back(dz);7543}75447545// Santali numerals.7546{7547NumSystemData sat;7548sat.lang.insert(StringName("sat")); // Santali7549sat.lang.insert(StringName("sat_IN"));7550sat.lang.insert(StringName("sat_Olck"));7551sat.lang.insert(StringName("sat_Olck_IN"));7552sat.digits = U"᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙.";7553sat.percent_sign = U"%";7554sat.exp_l = U"e";7555sat.exp_u = U"E";7556num_systems.push_back(sat);7557}75587559// Burmese numerals.7560{7561NumSystemData my;7562my.lang.insert(StringName("my")); // Burmese7563my.lang.insert(StringName("my_MM"));7564my.digits = U"၀၁၂၃၄၅၆၇၈၉.";7565my.percent_sign = U"%";7566my.exp_l = U"e";7567my.exp_u = U"E";7568num_systems.push_back(my);7569}75707571// Chakma numerals.7572{7573NumSystemData ccp;7574ccp.lang.insert(StringName("ccp")); // Chakma7575ccp.lang.insert(StringName("ccp_BD"));7576ccp.lang.insert(StringName("ccp_IN"));7577ccp.digits = U"𑄶𑄷𑄸𑄹𑄺𑄻𑄼𑄽𑄾𑄿.";7578ccp.percent_sign = U"%";7579ccp.exp_l = U"e";7580ccp.exp_u = U"E";7581num_systems.push_back(ccp);7582}75837584// Adlam numerals.7585{7586NumSystemData ff;7587ff.lang.insert(StringName("ff")); // Fulah7588ff.lang.insert(StringName("ff_Adlm_BF"));7589ff.lang.insert(StringName("ff_Adlm_CM"));7590ff.lang.insert(StringName("ff_Adlm_GH"));7591ff.lang.insert(StringName("ff_Adlm_GM"));7592ff.lang.insert(StringName("ff_Adlm_GN"));7593ff.lang.insert(StringName("ff_Adlm_GW"));7594ff.lang.insert(StringName("ff_Adlm_LR"));7595ff.lang.insert(StringName("ff_Adlm_MR"));7596ff.lang.insert(StringName("ff_Adlm_NE"));7597ff.lang.insert(StringName("ff_Adlm_NG"));7598ff.lang.insert(StringName("ff_Adlm_SL"));7599ff.lang.insert(StringName("ff_Adlm_SN"));7600ff.digits = U"𞥐𞥑𞥒𞥓𞥔𞥕𞥖𞥗𞥘𞥙.";7601ff.percent_sign = U"%";7602ff.exp_l = U"𞤉";7603ff.exp_u = U"𞤉";7604num_systems.push_back(ff);7605}7606}76077608String TextServerAdvanced::_format_number(const String &p_string, const String &p_language) const {7609const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;76107611String res = p_string;7612for (int i = 0; i < num_systems.size(); i++) {7613if (num_systems[i].lang.has(lang)) {7614if (num_systems[i].digits.is_empty()) {7615return p_string;7616}7617res = res.replace("e", num_systems[i].exp_l);7618res = res.replace("E", num_systems[i].exp_u);7619char32_t *data = res.ptrw();7620for (int j = 0; j < res.length(); j++) {7621if (data[j] >= 0x30 && data[j] <= 0x39) {7622data[j] = num_systems[i].digits[data[j] - 0x30];7623} else if (data[j] == '.' || data[j] == ',') {7624data[j] = num_systems[i].digits[10];7625}7626}7627break;7628}7629}7630return res;7631}76327633String TextServerAdvanced::_parse_number(const String &p_string, const String &p_language) const {7634const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;76357636String res = p_string;7637for (int i = 0; i < num_systems.size(); i++) {7638if (num_systems[i].lang.has(lang)) {7639if (num_systems[i].digits.is_empty()) {7640return p_string;7641}7642res = res.replace(num_systems[i].exp_l, "e");7643res = res.replace(num_systems[i].exp_u, "E");7644char32_t *data = res.ptrw();7645for (int j = 0; j < res.length(); j++) {7646if (data[j] == num_systems[i].digits[10]) {7647data[j] = '.';7648} else {7649for (int k = 0; k < 10; k++) {7650if (data[j] == num_systems[i].digits[k]) {7651data[j] = 0x30 + k;7652}7653}7654}7655}7656break;7657}7658}7659return res;7660}76617662String TextServerAdvanced::_percent_sign(const String &p_language) const {7663const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;76647665for (int i = 0; i < num_systems.size(); i++) {7666if (num_systems[i].lang.has(lang)) {7667if (num_systems[i].percent_sign.is_empty()) {7668return "%";7669}7670return num_systems[i].percent_sign;7671}7672}7673return "%";7674}76757676int64_t TextServerAdvanced::_is_confusable(const String &p_string, const PackedStringArray &p_dict) const {7677#ifndef ICU_STATIC_DATA7678if (!icu_data_loaded) {7679return -1;7680}7681#endif7682UErrorCode status = U_ZERO_ERROR;7683int64_t match_index = -1;76847685Char16String utf16 = p_string.utf16();7686Vector<UChar *> skeletons;7687skeletons.resize(p_dict.size());76887689if (sc_conf == nullptr) {7690sc_conf = uspoof_open(&status);7691uspoof_setChecks(sc_conf, USPOOF_CONFUSABLE, &status);7692}7693for (int i = 0; i < p_dict.size(); i++) {7694Char16String word = p_dict[i].utf16();7695int32_t len = uspoof_getSkeleton(sc_conf, 0, word.get_data(), -1, nullptr, 0, &status);7696skeletons.write[i] = (UChar *)memalloc(++len * sizeof(UChar));7697status = U_ZERO_ERROR;7698uspoof_getSkeleton(sc_conf, 0, word.get_data(), -1, skeletons.write[i], len, &status);7699}77007701int32_t len = uspoof_getSkeleton(sc_conf, 0, utf16.get_data(), -1, nullptr, 0, &status);7702UChar *skel = (UChar *)memalloc(++len * sizeof(UChar));7703status = U_ZERO_ERROR;7704uspoof_getSkeleton(sc_conf, 0, utf16.get_data(), -1, skel, len, &status);7705for (int i = 0; i < skeletons.size(); i++) {7706if (u_strcmp(skel, skeletons[i]) == 0) {7707match_index = i;7708break;7709}7710}7711memfree(skel);77127713for (int i = 0; i < skeletons.size(); i++) {7714memfree(skeletons.write[i]);7715}77167717ERR_FAIL_COND_V_MSG(U_FAILURE(status), -1, u_errorName(status));77187719return match_index;7720}77217722bool TextServerAdvanced::_spoof_check(const String &p_string) const {7723#ifndef ICU_STATIC_DATA7724if (!icu_data_loaded) {7725return false;7726}7727#endif7728UErrorCode status = U_ZERO_ERROR;7729Char16String utf16 = p_string.utf16();77307731if (allowed == nullptr) {7732allowed = uset_openEmpty();7733uset_addAll(allowed, uspoof_getRecommendedSet(&status));7734uset_addAll(allowed, uspoof_getInclusionSet(&status));7735}7736if (sc_spoof == nullptr) {7737sc_spoof = uspoof_open(&status);7738uspoof_setAllowedChars(sc_spoof, allowed, &status);7739uspoof_setRestrictionLevel(sc_spoof, USPOOF_MODERATELY_RESTRICTIVE);7740}77417742int32_t bitmask = uspoof_check(sc_spoof, utf16.get_data(), -1, nullptr, &status);7743ERR_FAIL_COND_V_MSG(U_FAILURE(status), false, u_errorName(status));77447745return (bitmask != 0);7746}77477748String TextServerAdvanced::_strip_diacritics(const String &p_string) const {7749#ifndef ICU_STATIC_DATA7750if (!icu_data_loaded) {7751return TextServer::strip_diacritics(p_string);7752}7753#endif7754UErrorCode err = U_ZERO_ERROR;77557756// Get NFKD normalizer singleton.7757const UNormalizer2 *unorm = unorm2_getNFKDInstance(&err);7758ERR_FAIL_COND_V_MSG(U_FAILURE(err), TextServer::strip_diacritics(p_string), u_errorName(err));77597760// Convert to UTF-16.7761Char16String utf16 = p_string.utf16();77627763// Normalize.7764Vector<char16_t> normalized;7765err = U_ZERO_ERROR;7766int32_t len = unorm2_normalize(unorm, utf16.get_data(), -1, nullptr, 0, &err);7767ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, TextServer::strip_diacritics(p_string), u_errorName(err));7768normalized.resize(len);7769err = U_ZERO_ERROR;7770unorm2_normalize(unorm, utf16.get_data(), -1, normalized.ptrw(), len, &err);7771ERR_FAIL_COND_V_MSG(U_FAILURE(err), TextServer::strip_diacritics(p_string), u_errorName(err));77727773// Convert back to UTF-32.7774String normalized_string = String::utf16(normalized.ptr(), len);77757776// Strip combining characters.7777String result;7778for (int i = 0; i < normalized_string.length(); i++) {7779if (u_getCombiningClass(normalized_string[i]) == 0) {7780#ifdef GDEXTENSION7781result = result + String::chr(normalized_string[i]);7782#elif defined(GODOT_MODULE)7783result = result + normalized_string[i];7784#endif7785}7786}7787return result;7788}77897790String TextServerAdvanced::_string_to_upper(const String &p_string, const String &p_language) const {7791#ifndef ICU_STATIC_DATA7792if (!icu_data_loaded) {7793return p_string.to_upper();7794}7795#endif77967797if (p_string.is_empty()) {7798return p_string;7799}7800const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;78017802// Convert to UTF-16.7803Char16String utf16 = p_string.utf16();78047805Vector<char16_t> upper;7806UErrorCode err = U_ZERO_ERROR;7807int32_t len = u_strToUpper(nullptr, 0, utf16.get_data(), -1, lang.ascii().get_data(), &err);7808ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));7809upper.resize(len);7810err = U_ZERO_ERROR;7811u_strToUpper(upper.ptrw(), len, utf16.get_data(), -1, lang.ascii().get_data(), &err);7812ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));78137814// Convert back to UTF-32.7815return String::utf16(upper.ptr(), len);7816}78177818String TextServerAdvanced::_string_to_lower(const String &p_string, const String &p_language) const {7819#ifndef ICU_STATIC_DATA7820if (!icu_data_loaded) {7821return p_string.to_lower();7822}7823#endif78247825if (p_string.is_empty()) {7826return p_string;7827}7828const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;7829// Convert to UTF-16.7830Char16String utf16 = p_string.utf16();78317832Vector<char16_t> lower;7833UErrorCode err = U_ZERO_ERROR;7834int32_t len = u_strToLower(nullptr, 0, utf16.get_data(), -1, lang.ascii().get_data(), &err);7835ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));7836lower.resize(len);7837err = U_ZERO_ERROR;7838u_strToLower(lower.ptrw(), len, utf16.get_data(), -1, lang.ascii().get_data(), &err);7839ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));78407841// Convert back to UTF-32.7842return String::utf16(lower.ptr(), len);7843}78447845String TextServerAdvanced::_string_to_title(const String &p_string, const String &p_language) const {7846#ifndef ICU_STATIC_DATA7847if (!icu_data_loaded) {7848return p_string.capitalize();7849}7850#endif78517852if (p_string.is_empty()) {7853return p_string;7854}7855const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;78567857// Convert to UTF-16.7858Char16String utf16 = p_string.utf16();78597860Vector<char16_t> upper;7861UErrorCode err = U_ZERO_ERROR;7862int32_t len = u_strToTitle(nullptr, 0, utf16.get_data(), -1, nullptr, lang.ascii().get_data(), &err);7863ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));7864upper.resize(len);7865err = U_ZERO_ERROR;7866u_strToTitle(upper.ptrw(), len, utf16.get_data(), -1, nullptr, lang.ascii().get_data(), &err);7867ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));78687869// Convert back to UTF-32.7870return String::utf16(upper.ptr(), len);7871}78727873PackedInt32Array TextServerAdvanced::_string_get_word_breaks(const String &p_string, const String &p_language, int64_t p_chars_per_line) const {7874const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;7875// Convert to UTF-16.7876Char16String utf16 = p_string.utf16();78777878HashSet<int> breaks;7879UErrorCode err = U_ZERO_ERROR;7880UBreakIterator *bi = ubrk_open(UBRK_WORD, lang.ascii().get_data(), (const UChar *)utf16.get_data(), utf16.length(), &err);7881if (U_SUCCESS(err)) {7882while (ubrk_next(bi) != UBRK_DONE) {7883int pos = _convert_pos(p_string, utf16, ubrk_current(bi));7884if (pos != p_string.length() - 1) {7885breaks.insert(pos);7886}7887}7888ubrk_close(bi);7889}78907891PackedInt32Array ret;78927893if (p_chars_per_line > 0) {7894int line_start = 0;7895int last_break = -1;7896int line_length = 0;78977898for (int i = 0; i < p_string.length(); i++) {7899const char32_t c = p_string[i];79007901bool is_lb = is_linebreak(c);7902bool is_ws = is_whitespace(c);7903bool is_p = (u_ispunct(c) && c != 0x005F) || is_underscore(c) || c == '\t' || c == 0xfffc;79047905if (is_lb) {7906if (line_length > 0) {7907ret.push_back(line_start);7908ret.push_back(i);7909}7910line_start = i;7911line_length = 0;7912last_break = -1;7913continue;7914} else if (breaks.has(i) || is_ws || is_p) {7915last_break = i;7916}79177918if (line_length == p_chars_per_line) {7919if (last_break != -1) {7920int last_break_w_spaces = last_break;7921while (last_break > line_start && is_whitespace(p_string[last_break - 1])) {7922last_break--;7923}7924if (line_start != last_break) {7925ret.push_back(line_start);7926ret.push_back(last_break);7927}7928while (last_break_w_spaces < p_string.length() && is_whitespace(p_string[last_break_w_spaces])) {7929last_break_w_spaces++;7930}7931line_start = last_break_w_spaces;7932if (last_break_w_spaces < i) {7933line_length = i - last_break_w_spaces;7934} else {7935i = last_break_w_spaces;7936line_length = 0;7937}7938} else {7939ret.push_back(line_start);7940ret.push_back(i);7941line_start = i;7942line_length = 0;7943}7944last_break = -1;7945}7946line_length++;7947}7948if (line_length > 0) {7949ret.push_back(line_start);7950ret.push_back(p_string.length());7951}7952} else {7953int word_start = 0; // -1 if no word encountered. Leading spaces are part of a word.7954int word_length = 0;79557956for (int i = 0; i < p_string.length(); i++) {7957const char32_t c = p_string[i];79587959bool is_lb = is_linebreak(c);7960bool is_ws = is_whitespace(c);7961bool is_p = (u_ispunct(c) && c != 0x005F) || is_underscore(c) || c == '\t' || c == 0xfffc;79627963if (word_start == -1) {7964if (!is_lb && !is_ws && !is_p) {7965word_start = i;7966}7967continue;7968}79697970if (is_lb) {7971if (word_start != -1 && word_length > 0) {7972ret.push_back(word_start);7973ret.push_back(i);7974}7975word_start = -1;7976word_length = 0;7977} else if (breaks.has(i) || is_ws || is_p) {7978if (word_start != -1 && word_length > 0) {7979ret.push_back(word_start);7980ret.push_back(i);7981}7982if (is_ws || is_p) {7983word_start = -1;7984} else {7985word_start = i;7986}7987word_length = 0;7988}79897990word_length++;7991}7992if (word_start != -1 && word_length > 0) {7993ret.push_back(word_start);7994ret.push_back(p_string.length());7995}7996}79977998return ret;7999}80008001PackedInt32Array TextServerAdvanced::_string_get_character_breaks(const String &p_string, const String &p_language) const {8002const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;8003// Convert to UTF-16.8004Char16String utf16 = p_string.utf16();80058006PackedInt32Array ret;80078008UErrorCode err = U_ZERO_ERROR;8009UBreakIterator *bi = ubrk_open(UBRK_CHARACTER, lang.ascii().get_data(), (const UChar *)utf16.get_data(), utf16.length(), &err);8010if (U_SUCCESS(err)) {8011while (ubrk_next(bi) != UBRK_DONE) {8012int pos = _convert_pos(p_string, utf16, ubrk_current(bi));8013ret.push_back(pos);8014}8015ubrk_close(bi);8016} else {8017return TextServer::string_get_character_breaks(p_string, p_language);8018}80198020return ret;8021}80228023bool TextServerAdvanced::_is_valid_identifier(const String &p_string) const {8024#ifndef ICU_STATIC_DATA8025if (!icu_data_loaded) {8026WARN_PRINT_ONCE("ICU data is not loaded, Unicode security and spoofing detection disabled.");8027return TextServer::is_valid_identifier(p_string);8028}8029#endif80308031enum UAX31SequenceStatus {8032SEQ_NOT_STARTED,8033SEQ_STARTED,8034SEQ_STARTED_VIR,8035SEQ_NEAR_END,8036};80378038const char32_t *str = p_string.ptr();8039int len = p_string.length();80408041if (len == 0) {8042return false; // Empty string.8043}80448045UErrorCode err = U_ZERO_ERROR;8046Char16String utf16 = p_string.utf16();8047const UNormalizer2 *norm_c = unorm2_getNFCInstance(&err);8048if (U_FAILURE(err)) {8049return false; // Failed to load normalizer.8050}8051bool isnurom = unorm2_isNormalized(norm_c, utf16.get_data(), utf16.length(), &err);8052if (U_FAILURE(err) || !isnurom) {8053return false; // Do not conform to Normalization Form C.8054}80558056UAX31SequenceStatus A1_sequence_status = SEQ_NOT_STARTED;8057UScriptCode A1_scr = USCRIPT_INHERITED;8058UAX31SequenceStatus A2_sequence_status = SEQ_NOT_STARTED;8059UScriptCode A2_scr = USCRIPT_INHERITED;8060UAX31SequenceStatus B_sequence_status = SEQ_NOT_STARTED;8061UScriptCode B_scr = USCRIPT_INHERITED;80628063for (int i = 0; i < len; i++) {8064err = U_ZERO_ERROR;8065UScriptCode scr = uscript_getScript(str[i], &err);8066if (U_FAILURE(err)) {8067return false; // Invalid script.8068}8069if (uscript_getUsage(scr) != USCRIPT_USAGE_RECOMMENDED) {8070return false; // Not a recommended script.8071}8072uint8_t cat = u_charType(str[i]);8073int32_t jt = u_getIntPropertyValue(str[i], UCHAR_JOINING_TYPE);80748075// UAX #31 section 2.3 subsections A1, A2 and B, check ZWNJ and ZWJ usage.8076switch (A1_sequence_status) {8077case SEQ_NEAR_END: {8078if ((A1_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A1_scr)) {8079return false; // Mixed script.8080}8081if (jt == U_JT_RIGHT_JOINING || jt == U_JT_DUAL_JOINING) {8082A1_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.8083} else if (jt != U_JT_TRANSPARENT) {8084return false; // Invalid end of sequence.8085}8086} break;8087case SEQ_STARTED: {8088if ((A1_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A1_scr)) {8089A1_sequence_status = SEQ_NOT_STARTED; // Reset.8090} else {8091if (jt != U_JT_TRANSPARENT) {8092if (str[i] == 0x200C /*ZWNJ*/) {8093A1_sequence_status = SEQ_NEAR_END;8094continue;8095} else {8096A1_sequence_status = SEQ_NOT_STARTED; // Reset.8097}8098}8099}8100} break;8101default:8102break;8103}8104if (A1_sequence_status == SEQ_NOT_STARTED) {8105if (jt == U_JT_LEFT_JOINING || jt == U_JT_DUAL_JOINING) {8106A1_sequence_status = SEQ_STARTED;8107A1_scr = scr;8108}8109};81108111switch (A2_sequence_status) {8112case SEQ_NEAR_END: {8113if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {8114return false; // Mixed script.8115}8116if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {8117A2_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.8118} else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {8119return false; // Invalid end of sequence.8120}8121} break;8122case SEQ_STARTED_VIR: {8123if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {8124A2_sequence_status = SEQ_NOT_STARTED; // Reset.8125} else {8126if (str[i] == 0x200C /*ZWNJ*/) {8127A2_sequence_status = SEQ_NEAR_END;8128continue;8129} else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {8130A2_sequence_status = SEQ_NOT_STARTED; // Reset.8131}8132}8133} break;8134case SEQ_STARTED: {8135if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {8136A2_sequence_status = SEQ_NOT_STARTED; // Reset.8137} else {8138if (u_getCombiningClass(str[i]) == 9 /*Virama Combining Class*/) {8139A2_sequence_status = SEQ_STARTED_VIR;8140} else if (cat != U_MODIFIER_LETTER) {8141A2_sequence_status = SEQ_NOT_STARTED; // Reset.8142}8143}8144} break;8145default:8146break;8147}8148if (A2_sequence_status == SEQ_NOT_STARTED) {8149if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {8150A2_sequence_status = SEQ_STARTED;8151A2_scr = scr;8152}8153}81548155switch (B_sequence_status) {8156case SEQ_NEAR_END: {8157if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {8158return false; // Mixed script.8159}8160if (u_getIntPropertyValue(str[i], UCHAR_INDIC_SYLLABIC_CATEGORY) != U_INSC_VOWEL_DEPENDENT) {8161B_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.8162} else {8163return false; // Invalid end of sequence.8164}8165} break;8166case SEQ_STARTED_VIR: {8167if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {8168B_sequence_status = SEQ_NOT_STARTED; // Reset.8169} else {8170if (str[i] == 0x200D /*ZWJ*/) {8171B_sequence_status = SEQ_NEAR_END;8172continue;8173} else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {8174B_sequence_status = SEQ_NOT_STARTED; // Reset.8175}8176}8177} break;8178case SEQ_STARTED: {8179if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {8180B_sequence_status = SEQ_NOT_STARTED; // Reset.8181} else {8182if (u_getCombiningClass(str[i]) == 9 /*Virama Combining Class*/) {8183B_sequence_status = SEQ_STARTED_VIR;8184} else if (cat != U_MODIFIER_LETTER) {8185B_sequence_status = SEQ_NOT_STARTED; // Reset.8186}8187}8188} break;8189default:8190break;8191}8192if (B_sequence_status == SEQ_NOT_STARTED) {8193if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {8194B_sequence_status = SEQ_STARTED;8195B_scr = scr;8196}8197}81988199if (u_hasBinaryProperty(str[i], UCHAR_PATTERN_SYNTAX) || u_hasBinaryProperty(str[i], UCHAR_PATTERN_WHITE_SPACE) || u_hasBinaryProperty(str[i], UCHAR_NONCHARACTER_CODE_POINT)) {8200return false; // Not a XID_Start or XID_Continue character.8201}8202if (i == 0) {8203if (!(cat == U_LOWERCASE_LETTER || cat == U_UPPERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_OTHER_LETTER || cat == U_MODIFIER_LETTER || cat == U_LETTER_NUMBER || str[0] == 0x2118 || str[0] == 0x212E || str[0] == 0x309B || str[0] == 0x309C || str[0] == 0x005F)) {8204return false; // Not a XID_Start character.8205}8206} else {8207if (!(cat == U_LOWERCASE_LETTER || cat == U_UPPERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_OTHER_LETTER || cat == U_MODIFIER_LETTER || cat == U_LETTER_NUMBER || cat == U_NON_SPACING_MARK || cat == U_COMBINING_SPACING_MARK || cat == U_DECIMAL_DIGIT_NUMBER || cat == U_CONNECTOR_PUNCTUATION || str[i] == 0x2118 || str[i] == 0x212E || str[i] == 0x309B || str[i] == 0x309C || str[i] == 0x1369 || str[i] == 0x1371 || str[i] == 0x00B7 || str[i] == 0x0387 || str[i] == 0x19DA || str[i] == 0x0E33 || str[i] == 0x0EB3 || str[i] == 0xFF9E || str[i] == 0xFF9F)) {8208return false; // Not a XID_Continue character.8209}8210}8211}8212return true;8213}82148215bool TextServerAdvanced::_is_valid_letter(uint64_t p_unicode) const {8216#ifndef ICU_STATIC_DATA8217if (!icu_data_loaded) {8218return TextServer::is_valid_letter(p_unicode);8219}8220#endif82218222return u_isalpha(p_unicode);8223}82248225void TextServerAdvanced::_update_settings() {8226lcd_subpixel_layout.set((TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"));8227lb_strictness = (LineBreakStrictness)(int)GLOBAL_GET("internationalization/locale/line_breaking_strictness");8228}82298230TextServerAdvanced::TextServerAdvanced() {8231_insert_num_systems_lang();8232_insert_feature_sets();8233_bmp_create_font_funcs();8234_update_settings();8235ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &TextServerAdvanced::_update_settings));8236}82378238void TextServerAdvanced::_font_clear_system_fallback_cache() {8239_THREAD_SAFE_METHOD_8240for (const KeyValue<SystemFontKey, SystemFontCache> &E : system_fonts) {8241const Vector<SystemFontCacheRec> &sysf_cache = E.value.var;8242for (const SystemFontCacheRec &F : sysf_cache) {8243_free_rid(F.rid);8244}8245}8246system_fonts.clear();8247system_font_data.clear();8248}82498250void TextServerAdvanced::_cleanup() {8251font_clear_system_fallback_cache();8252}82538254TextServerAdvanced::~TextServerAdvanced() {8255_bmp_free_font_funcs();8256#ifdef MODULE_FREETYPE_ENABLED8257if (ft_library != nullptr) {8258FT_Done_FreeType(ft_library);8259}8260#endif8261if (sc_spoof != nullptr) {8262uspoof_close(sc_spoof);8263sc_spoof = nullptr;8264}8265if (sc_conf != nullptr) {8266uspoof_close(sc_conf);8267sc_conf = nullptr;8268}8269if (allowed != nullptr) {8270uset_close(allowed);8271allowed = nullptr;8272}8273for (const KeyValue<String, UBreakIterator *> &bi : line_break_iterators_per_language) {8274ubrk_close(bi.value);8275}82768277std::atexit(u_cleanup);8278}827982808281