Path: blob/master/modules/text_server_adv/text_server_adv.cpp
10277 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/object/worker_thread_pool.h"52#include "core/string/translation_server.h"53#include "scene/resources/image_texture.h"5455#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg.5657#endif5859// Built-in ICU data.6061#ifdef ICU_STATIC_DATA62#include <icudata.gen.h>63#endif6465// Thirdparty headers.6667#ifdef MODULE_MSDFGEN_ENABLED68#include <core/EdgeHolder.h>69#include <core/ShapeDistanceFinder.h>70#include <core/contour-combiners.h>71#include <core/edge-selectors.h>72#include <msdfgen.h>73#endif7475#ifdef MODULE_SVG_ENABLED76#ifdef MODULE_FREETYPE_ENABLED77#include "thorvg_svg_in_ot.h"78#endif79#endif8081/*************************************************************************/82/* bmp_font_t HarfBuzz Bitmap font interface */83/*************************************************************************/8485hb_font_funcs_t *TextServerAdvanced::funcs = nullptr;8687TextServerAdvanced::bmp_font_t *TextServerAdvanced::_bmp_font_create(TextServerAdvanced::FontForSizeAdvanced *p_face, bool p_unref) {88bmp_font_t *bm_font = memnew(bmp_font_t);8990if (!bm_font) {91return nullptr;92}9394bm_font->face = p_face;95bm_font->unref = p_unref;9697return bm_font;98}99100void TextServerAdvanced::_bmp_font_destroy(void *p_data) {101bmp_font_t *bm_font = static_cast<bmp_font_t *>(p_data);102memdelete(bm_font);103}104105hb_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) {106const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);107108if (!bm_font->face) {109return false;110}111112if (!bm_font->face->glyph_map.has(p_unicode)) {113if (bm_font->face->glyph_map.has(0xf000u + p_unicode)) {114*r_glyph = 0xf000u + p_unicode;115return true;116} else {117return false;118}119}120121*r_glyph = p_unicode;122return true;123}124125hb_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) {126const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);127128if (!bm_font->face) {129return 0;130}131132HashMap<int32_t, FontGlyph>::Iterator E = bm_font->face->glyph_map.find(p_glyph);133if (!E) {134return 0;135}136137return E->value.advance.x * 64;138}139140hb_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) {141const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);142143if (!bm_font->face) {144return 0;145}146147HashMap<int32_t, FontGlyph>::Iterator E = bm_font->face->glyph_map.find(p_glyph);148if (!E) {149return 0;150}151152return -E->value.advance.y * 64;153}154155hb_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) {156const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);157158if (!bm_font->face) {159return 0;160}161162if (!bm_font->face->kerning_map.has(Vector2i(p_left_glyph, p_right_glyph))) {163return 0;164}165166return bm_font->face->kerning_map[Vector2i(p_left_glyph, p_right_glyph)].x * 64;167}168169hb_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) {170const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);171172if (!bm_font->face) {173return false;174}175176HashMap<int32_t, FontGlyph>::Iterator E = bm_font->face->glyph_map.find(p_glyph);177if (!E) {178return false;179}180181*r_x = E->value.advance.x * 32;182*r_y = -bm_font->face->ascent * 64;183184return true;185}186187hb_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) {188const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);189190if (!bm_font->face) {191return false;192}193194HashMap<int32_t, FontGlyph>::Iterator E = bm_font->face->glyph_map.find(p_glyph);195if (!E) {196return false;197}198199r_extents->x_bearing = 0;200r_extents->y_bearing = 0;201r_extents->width = E->value.rect.size.x * 64;202r_extents->height = E->value.rect.size.y * 64;203204return true;205}206207hb_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) {208const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);209210if (!bm_font->face) {211return false;212}213214r_metrics->ascender = bm_font->face->ascent;215r_metrics->descender = bm_font->face->descent;216r_metrics->line_gap = 0;217218return true;219}220221void TextServerAdvanced::_bmp_create_font_funcs() {222if (funcs == nullptr) {223funcs = hb_font_funcs_create();224225hb_font_funcs_set_font_h_extents_func(funcs, _bmp_get_font_h_extents, nullptr, nullptr);226hb_font_funcs_set_nominal_glyph_func(funcs, _bmp_get_nominal_glyph, nullptr, nullptr);227hb_font_funcs_set_glyph_h_advance_func(funcs, _bmp_get_glyph_h_advance, nullptr, nullptr);228hb_font_funcs_set_glyph_v_advance_func(funcs, _bmp_get_glyph_v_advance, nullptr, nullptr);229hb_font_funcs_set_glyph_v_origin_func(funcs, _bmp_get_glyph_v_origin, nullptr, nullptr);230hb_font_funcs_set_glyph_h_kerning_func(funcs, _bmp_get_glyph_h_kerning, nullptr, nullptr);231hb_font_funcs_set_glyph_extents_func(funcs, _bmp_get_glyph_extents, nullptr, nullptr);232233hb_font_funcs_make_immutable(funcs);234}235}236237void TextServerAdvanced::_bmp_free_font_funcs() {238if (funcs != nullptr) {239hb_font_funcs_destroy(funcs);240funcs = nullptr;241}242}243244void TextServerAdvanced::_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontForSizeAdvanced *p_face, bool p_unref) {245hb_font_set_funcs(p_font, funcs, _bmp_font_create(p_face, p_unref), _bmp_font_destroy);246}247248hb_font_t *TextServerAdvanced::_bmp_font_create(TextServerAdvanced::FontForSizeAdvanced *p_face, hb_destroy_func_t p_destroy) {249hb_font_t *font;250hb_face_t *face = hb_face_create(nullptr, 0);251252font = hb_font_create(face);253hb_face_destroy(face);254_bmp_font_set_funcs(font, p_face, false);255return font;256}257258/*************************************************************************/259/* Character properties. */260/*************************************************************************/261262_FORCE_INLINE_ bool is_ain(char32_t p_chr) {263return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_AIN;264}265266_FORCE_INLINE_ bool is_alef(char32_t p_chr) {267return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_ALEF;268}269270_FORCE_INLINE_ bool is_beh(char32_t p_chr) {271int32_t prop = u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP);272return (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);273}274275_FORCE_INLINE_ bool is_dal(char32_t p_chr) {276return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_DAL;277}278279_FORCE_INLINE_ bool is_feh(char32_t p_chr) {280return (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_FEH) || (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_AFRICAN_FEH);281}282283_FORCE_INLINE_ bool is_gaf(char32_t p_chr) {284return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_GAF;285}286287_FORCE_INLINE_ bool is_heh(char32_t p_chr) {288return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_HEH;289}290291_FORCE_INLINE_ bool is_kaf(char32_t p_chr) {292return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_KAF;293}294295_FORCE_INLINE_ bool is_lam(char32_t p_chr) {296return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_LAM;297}298299_FORCE_INLINE_ bool is_qaf(char32_t p_chr) {300return (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_QAF) || (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_AFRICAN_QAF);301}302303_FORCE_INLINE_ bool is_reh(char32_t p_chr) {304return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_REH;305}306307_FORCE_INLINE_ bool is_seen_sad(char32_t p_chr) {308return (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_SAD) || (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_SEEN);309}310311_FORCE_INLINE_ bool is_tah(char32_t p_chr) {312return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_TAH;313}314315_FORCE_INLINE_ bool is_teh_marbuta(char32_t p_chr) {316return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_TEH_MARBUTA;317}318319_FORCE_INLINE_ bool is_yeh(char32_t p_chr) {320int32_t prop = u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP);321return (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);322}323324_FORCE_INLINE_ bool is_waw(char32_t p_chr) {325return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_WAW;326}327328_FORCE_INLINE_ bool is_transparent(char32_t p_chr) {329return u_getIntPropertyValue(p_chr, UCHAR_JOINING_TYPE) == U_JT_TRANSPARENT;330}331332_FORCE_INLINE_ bool is_ligature(char32_t p_chr, char32_t p_nchr) {333return (is_lam(p_chr) && is_alef(p_nchr));334}335336_FORCE_INLINE_ bool is_connected_to_prev(char32_t p_chr, char32_t p_pchr) {337int32_t prop = u_getIntPropertyValue(p_pchr, UCHAR_JOINING_TYPE);338return (prop != U_JT_RIGHT_JOINING) && (prop != U_JT_NON_JOINING) ? !is_ligature(p_pchr, p_chr) : false;339}340341/*************************************************************************/342343bool TextServerAdvanced::icu_data_loaded = false;344PackedByteArray TextServerAdvanced::icu_data;345346bool TextServerAdvanced::_has_feature(Feature p_feature) const {347switch (p_feature) {348case FEATURE_SIMPLE_LAYOUT:349case FEATURE_BIDI_LAYOUT:350case FEATURE_VERTICAL_LAYOUT:351case FEATURE_SHAPING:352case FEATURE_KASHIDA_JUSTIFICATION:353case FEATURE_BREAK_ITERATORS:354case FEATURE_FONT_BITMAP:355#ifdef MODULE_FREETYPE_ENABLED356case FEATURE_FONT_DYNAMIC:357#endif358#ifdef MODULE_MSDFGEN_ENABLED359case FEATURE_FONT_MSDF:360#endif361case FEATURE_FONT_VARIABLE:362case FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION:363case FEATURE_USE_SUPPORT_DATA:364case FEATURE_UNICODE_IDENTIFIERS:365case FEATURE_UNICODE_SECURITY:366return true;367default: {368}369}370return false;371}372373String TextServerAdvanced::_get_name() const {374#ifdef GDEXTENSION375return "ICU / HarfBuzz / Graphite (GDExtension)";376#elif defined(GODOT_MODULE)377return "ICU / HarfBuzz / Graphite (Built-in)";378#endif379}380381int64_t TextServerAdvanced::_get_features() const {382int64_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;383#ifdef MODULE_FREETYPE_ENABLED384interface_features |= FEATURE_FONT_DYNAMIC;385#endif386#ifdef MODULE_MSDFGEN_ENABLED387interface_features |= FEATURE_FONT_MSDF;388#endif389390return interface_features;391}392393void TextServerAdvanced::_free_rid(const RID &p_rid) {394_THREAD_SAFE_METHOD_395if (font_owner.owns(p_rid)) {396MutexLock ftlock(ft_mutex);397398FontAdvanced *fd = font_owner.get_or_null(p_rid);399for (const KeyValue<Vector2i, FontForSizeAdvanced *> &ffsd : fd->cache) {400OversamplingLevel *ol = oversampling_levels.getptr(ffsd.value->viewport_oversampling);401if (ol != nullptr) {402ol->fonts.erase(ffsd.value);403}404}405{406MutexLock lock(fd->mutex);407font_owner.free(p_rid);408}409memdelete(fd);410} else if (font_var_owner.owns(p_rid)) {411MutexLock ftlock(ft_mutex);412413FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(p_rid);414{415font_var_owner.free(p_rid);416}417memdelete(fdv);418} else if (shaped_owner.owns(p_rid)) {419ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_rid);420{421MutexLock lock(sd->mutex);422shaped_owner.free(p_rid);423}424memdelete(sd);425}426}427428bool TextServerAdvanced::_has(const RID &p_rid) {429_THREAD_SAFE_METHOD_430return font_owner.owns(p_rid) || font_var_owner.owns(p_rid) || shaped_owner.owns(p_rid);431}432433bool TextServerAdvanced::_load_support_data(const String &p_filename) {434_THREAD_SAFE_METHOD_435436#if defined(ICU_STATIC_DATA) || !defined(HAVE_ICU_BUILTIN)437if (!icu_data_loaded) {438UErrorCode err = U_ZERO_ERROR;439u_init(&err); // Do not check for errors, since we only load part of the data.440icu_data_loaded = true;441}442#else443if (!icu_data_loaded) {444UErrorCode err = U_ZERO_ERROR;445String filename = (p_filename.is_empty()) ? String("res://icudt_godot.dat") : p_filename;446if (FileAccess::exists(filename)) {447Ref<FileAccess> f = FileAccess::open(filename, FileAccess::READ);448if (f.is_null()) {449return false;450}451uint64_t len = f->get_length();452icu_data = f->get_buffer(len);453454udata_setCommonData(icu_data.ptr(), &err);455if (U_FAILURE(err)) {456ERR_FAIL_V_MSG(false, u_errorName(err));457}458459err = U_ZERO_ERROR;460icu_data_loaded = true;461}462463u_init(&err);464if (U_FAILURE(err)) {465ERR_FAIL_V_MSG(false, u_errorName(err));466}467}468#endif469return true;470}471472String TextServerAdvanced::_get_support_data_filename() const {473return String("icudt_godot.dat");474}475476String TextServerAdvanced::_get_support_data_info() const {477return String("ICU break iteration data (\"icudt_godot.dat\").");478}479480bool TextServerAdvanced::_save_support_data(const String &p_filename) const {481_THREAD_SAFE_METHOD_482#ifdef ICU_STATIC_DATA483484// Store data to the res file if it's available.485486Ref<FileAccess> f = FileAccess::open(p_filename, FileAccess::WRITE);487if (f.is_null()) {488return false;489}490491PackedByteArray icu_data_static;492icu_data_static.resize(U_ICUDATA_SIZE);493memcpy(icu_data_static.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);494f->store_buffer(icu_data_static);495496return true;497#else498return false;499#endif500}501502PackedByteArray TextServerAdvanced::_get_support_data() const {503_THREAD_SAFE_METHOD_504#ifdef ICU_STATIC_DATA505506PackedByteArray icu_data_static;507icu_data_static.resize(U_ICUDATA_SIZE);508memcpy(icu_data_static.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);509510return icu_data_static;511#else512return icu_data;513#endif514}515516bool TextServerAdvanced::_is_locale_right_to_left(const String &p_locale) const {517String l = p_locale.get_slicec('_', 0);518if ((l == "ar") || (l == "dv") || (l == "he") || (l == "fa") || (l == "ff") || (l == "ku") || (l == "ur")) {519return true;520} else {521return false;522}523}524525_FORCE_INLINE_ void TextServerAdvanced::_insert_feature(const StringName &p_name, int32_t p_tag, Variant::Type p_vtype, bool p_hidden) {526FeatureInfo fi;527fi.name = p_name;528fi.vtype = p_vtype;529fi.hidden = p_hidden;530531feature_sets.insert(p_name, p_tag);532feature_sets_inv.insert(p_tag, fi);533}534535void TextServerAdvanced::_insert_feature_sets() {536// Registered OpenType feature tags.537// Name, Tag, Data Type, Hidden538_insert_feature("access_all_alternates", HB_TAG('a', 'a', 'l', 't'), Variant::Type::INT, false);539_insert_feature("above_base_forms", HB_TAG('a', 'b', 'v', 'f'), Variant::Type::INT, true);540_insert_feature("above_base_mark_positioning", HB_TAG('a', 'b', 'v', 'm'), Variant::Type::INT, true);541_insert_feature("above_base_substitutions", HB_TAG('a', 'b', 'v', 's'), Variant::Type::INT, true);542_insert_feature("alternative_fractions", HB_TAG('a', 'f', 'r', 'c'), Variant::Type::INT, false);543_insert_feature("akhands", HB_TAG('a', 'k', 'h', 'n'), Variant::Type::INT, true);544_insert_feature("below_base_forms", HB_TAG('b', 'l', 'w', 'f'), Variant::Type::INT, true);545_insert_feature("below_base_mark_positioning", HB_TAG('b', 'l', 'w', 'm'), Variant::Type::INT, true);546_insert_feature("below_base_substitutions", HB_TAG('b', 'l', 'w', 's'), Variant::Type::INT, true);547_insert_feature("contextual_alternates", HB_TAG('c', 'a', 'l', 't'), Variant::Type::BOOL, false);548_insert_feature("case_sensitive_forms", HB_TAG('c', 'a', 's', 'e'), Variant::Type::BOOL, false);549_insert_feature("glyph_composition", HB_TAG('c', 'c', 'm', 'p'), Variant::Type::INT, true);550_insert_feature("conjunct_form_after_ro", HB_TAG('c', 'f', 'a', 'r'), Variant::Type::INT, true);551_insert_feature("contextual_half_width_spacing", HB_TAG('c', 'h', 'w', 's'), Variant::Type::INT, true);552_insert_feature("conjunct_forms", HB_TAG('c', 'j', 'c', 't'), Variant::Type::INT, true);553_insert_feature("contextual_ligatures", HB_TAG('c', 'l', 'i', 'g'), Variant::Type::BOOL, false);554_insert_feature("centered_cjk_punctuation", HB_TAG('c', 'p', 'c', 't'), Variant::Type::BOOL, false);555_insert_feature("capital_spacing", HB_TAG('c', 'p', 's', 'p'), Variant::Type::BOOL, false);556_insert_feature("contextual_swash", HB_TAG('c', 's', 'w', 'h'), Variant::Type::INT, false);557_insert_feature("cursive_positioning", HB_TAG('c', 'u', 'r', 's'), Variant::Type::INT, true);558_insert_feature("character_variant_01", HB_TAG('c', 'v', '0', '1'), Variant::Type::BOOL, false);559_insert_feature("character_variant_02", HB_TAG('c', 'v', '0', '2'), Variant::Type::BOOL, false);560_insert_feature("character_variant_03", HB_TAG('c', 'v', '0', '3'), Variant::Type::BOOL, false);561_insert_feature("character_variant_04", HB_TAG('c', 'v', '0', '4'), Variant::Type::BOOL, false);562_insert_feature("character_variant_05", HB_TAG('c', 'v', '0', '5'), Variant::Type::BOOL, false);563_insert_feature("character_variant_06", HB_TAG('c', 'v', '0', '6'), Variant::Type::BOOL, false);564_insert_feature("character_variant_07", HB_TAG('c', 'v', '0', '7'), Variant::Type::BOOL, false);565_insert_feature("character_variant_08", HB_TAG('c', 'v', '0', '8'), Variant::Type::BOOL, false);566_insert_feature("character_variant_09", HB_TAG('c', 'v', '0', '9'), Variant::Type::BOOL, false);567_insert_feature("character_variant_10", HB_TAG('c', 'v', '1', '0'), Variant::Type::BOOL, false);568_insert_feature("character_variant_11", HB_TAG('c', 'v', '1', '1'), Variant::Type::BOOL, false);569_insert_feature("character_variant_12", HB_TAG('c', 'v', '1', '2'), Variant::Type::BOOL, false);570_insert_feature("character_variant_13", HB_TAG('c', 'v', '1', '3'), Variant::Type::BOOL, false);571_insert_feature("character_variant_14", HB_TAG('c', 'v', '1', '4'), Variant::Type::BOOL, false);572_insert_feature("character_variant_15", HB_TAG('c', 'v', '1', '5'), Variant::Type::BOOL, false);573_insert_feature("character_variant_16", HB_TAG('c', 'v', '1', '6'), Variant::Type::BOOL, false);574_insert_feature("character_variant_17", HB_TAG('c', 'v', '1', '7'), Variant::Type::BOOL, false);575_insert_feature("character_variant_18", HB_TAG('c', 'v', '1', '8'), Variant::Type::BOOL, false);576_insert_feature("character_variant_19", HB_TAG('c', 'v', '1', '9'), Variant::Type::BOOL, false);577_insert_feature("character_variant_20", HB_TAG('c', 'v', '2', '0'), Variant::Type::BOOL, false);578_insert_feature("character_variant_21", HB_TAG('c', 'v', '2', '1'), Variant::Type::BOOL, false);579_insert_feature("character_variant_22", HB_TAG('c', 'v', '2', '2'), Variant::Type::BOOL, false);580_insert_feature("character_variant_23", HB_TAG('c', 'v', '2', '3'), Variant::Type::BOOL, false);581_insert_feature("character_variant_24", HB_TAG('c', 'v', '2', '4'), Variant::Type::BOOL, false);582_insert_feature("character_variant_25", HB_TAG('c', 'v', '2', '5'), Variant::Type::BOOL, false);583_insert_feature("character_variant_26", HB_TAG('c', 'v', '2', '6'), Variant::Type::BOOL, false);584_insert_feature("character_variant_27", HB_TAG('c', 'v', '2', '7'), Variant::Type::BOOL, false);585_insert_feature("character_variant_28", HB_TAG('c', 'v', '2', '8'), Variant::Type::BOOL, false);586_insert_feature("character_variant_29", HB_TAG('c', 'v', '2', '9'), Variant::Type::BOOL, false);587_insert_feature("character_variant_30", HB_TAG('c', 'v', '3', '0'), Variant::Type::BOOL, false);588_insert_feature("character_variant_31", HB_TAG('c', 'v', '3', '1'), Variant::Type::BOOL, false);589_insert_feature("character_variant_32", HB_TAG('c', 'v', '3', '2'), Variant::Type::BOOL, false);590_insert_feature("character_variant_33", HB_TAG('c', 'v', '3', '3'), Variant::Type::BOOL, false);591_insert_feature("character_variant_34", HB_TAG('c', 'v', '3', '4'), Variant::Type::BOOL, false);592_insert_feature("character_variant_35", HB_TAG('c', 'v', '3', '5'), Variant::Type::BOOL, false);593_insert_feature("character_variant_36", HB_TAG('c', 'v', '3', '6'), Variant::Type::BOOL, false);594_insert_feature("character_variant_37", HB_TAG('c', 'v', '3', '7'), Variant::Type::BOOL, false);595_insert_feature("character_variant_38", HB_TAG('c', 'v', '3', '8'), Variant::Type::BOOL, false);596_insert_feature("character_variant_39", HB_TAG('c', 'v', '3', '9'), Variant::Type::BOOL, false);597_insert_feature("character_variant_40", HB_TAG('c', 'v', '4', '0'), Variant::Type::BOOL, false);598_insert_feature("character_variant_41", HB_TAG('c', 'v', '4', '1'), Variant::Type::BOOL, false);599_insert_feature("character_variant_42", HB_TAG('c', 'v', '4', '2'), Variant::Type::BOOL, false);600_insert_feature("character_variant_43", HB_TAG('c', 'v', '4', '3'), Variant::Type::BOOL, false);601_insert_feature("character_variant_44", HB_TAG('c', 'v', '4', '4'), Variant::Type::BOOL, false);602_insert_feature("character_variant_45", HB_TAG('c', 'v', '4', '5'), Variant::Type::BOOL, false);603_insert_feature("character_variant_46", HB_TAG('c', 'v', '4', '6'), Variant::Type::BOOL, false);604_insert_feature("character_variant_47", HB_TAG('c', 'v', '4', '7'), Variant::Type::BOOL, false);605_insert_feature("character_variant_48", HB_TAG('c', 'v', '4', '8'), Variant::Type::BOOL, false);606_insert_feature("character_variant_49", HB_TAG('c', 'v', '4', '9'), Variant::Type::BOOL, false);607_insert_feature("character_variant_50", HB_TAG('c', 'v', '5', '0'), Variant::Type::BOOL, false);608_insert_feature("character_variant_51", HB_TAG('c', 'v', '5', '1'), Variant::Type::BOOL, false);609_insert_feature("character_variant_52", HB_TAG('c', 'v', '5', '2'), Variant::Type::BOOL, false);610_insert_feature("character_variant_53", HB_TAG('c', 'v', '5', '3'), Variant::Type::BOOL, false);611_insert_feature("character_variant_54", HB_TAG('c', 'v', '5', '4'), Variant::Type::BOOL, false);612_insert_feature("character_variant_55", HB_TAG('c', 'v', '5', '5'), Variant::Type::BOOL, false);613_insert_feature("character_variant_56", HB_TAG('c', 'v', '5', '6'), Variant::Type::BOOL, false);614_insert_feature("character_variant_57", HB_TAG('c', 'v', '5', '7'), Variant::Type::BOOL, false);615_insert_feature("character_variant_58", HB_TAG('c', 'v', '5', '8'), Variant::Type::BOOL, false);616_insert_feature("character_variant_59", HB_TAG('c', 'v', '5', '9'), Variant::Type::BOOL, false);617_insert_feature("character_variant_60", HB_TAG('c', 'v', '6', '0'), Variant::Type::BOOL, false);618_insert_feature("character_variant_61", HB_TAG('c', 'v', '6', '1'), Variant::Type::BOOL, false);619_insert_feature("character_variant_62", HB_TAG('c', 'v', '6', '2'), Variant::Type::BOOL, false);620_insert_feature("character_variant_63", HB_TAG('c', 'v', '6', '3'), Variant::Type::BOOL, false);621_insert_feature("character_variant_64", HB_TAG('c', 'v', '6', '4'), Variant::Type::BOOL, false);622_insert_feature("character_variant_65", HB_TAG('c', 'v', '6', '5'), Variant::Type::BOOL, false);623_insert_feature("character_variant_66", HB_TAG('c', 'v', '6', '6'), Variant::Type::BOOL, false);624_insert_feature("character_variant_67", HB_TAG('c', 'v', '6', '7'), Variant::Type::BOOL, false);625_insert_feature("character_variant_68", HB_TAG('c', 'v', '6', '8'), Variant::Type::BOOL, false);626_insert_feature("character_variant_69", HB_TAG('c', 'v', '6', '9'), Variant::Type::BOOL, false);627_insert_feature("character_variant_70", HB_TAG('c', 'v', '7', '0'), Variant::Type::BOOL, false);628_insert_feature("character_variant_71", HB_TAG('c', 'v', '7', '1'), Variant::Type::BOOL, false);629_insert_feature("character_variant_72", HB_TAG('c', 'v', '7', '2'), Variant::Type::BOOL, false);630_insert_feature("character_variant_73", HB_TAG('c', 'v', '7', '3'), Variant::Type::BOOL, false);631_insert_feature("character_variant_74", HB_TAG('c', 'v', '7', '4'), Variant::Type::BOOL, false);632_insert_feature("character_variant_75", HB_TAG('c', 'v', '7', '5'), Variant::Type::BOOL, false);633_insert_feature("character_variant_76", HB_TAG('c', 'v', '7', '6'), Variant::Type::BOOL, false);634_insert_feature("character_variant_77", HB_TAG('c', 'v', '7', '7'), Variant::Type::BOOL, false);635_insert_feature("character_variant_78", HB_TAG('c', 'v', '7', '8'), Variant::Type::BOOL, false);636_insert_feature("character_variant_79", HB_TAG('c', 'v', '7', '9'), Variant::Type::BOOL, false);637_insert_feature("character_variant_80", HB_TAG('c', 'v', '8', '0'), Variant::Type::BOOL, false);638_insert_feature("character_variant_81", HB_TAG('c', 'v', '8', '1'), Variant::Type::BOOL, false);639_insert_feature("character_variant_82", HB_TAG('c', 'v', '8', '2'), Variant::Type::BOOL, false);640_insert_feature("character_variant_83", HB_TAG('c', 'v', '8', '3'), Variant::Type::BOOL, false);641_insert_feature("character_variant_84", HB_TAG('c', 'v', '8', '4'), Variant::Type::BOOL, false);642_insert_feature("character_variant_85", HB_TAG('c', 'v', '8', '5'), Variant::Type::BOOL, false);643_insert_feature("character_variant_86", HB_TAG('c', 'v', '8', '6'), Variant::Type::BOOL, false);644_insert_feature("character_variant_87", HB_TAG('c', 'v', '8', '7'), Variant::Type::BOOL, false);645_insert_feature("character_variant_88", HB_TAG('c', 'v', '8', '8'), Variant::Type::BOOL, false);646_insert_feature("character_variant_89", HB_TAG('c', 'v', '8', '9'), Variant::Type::BOOL, false);647_insert_feature("character_variant_90", HB_TAG('c', 'v', '9', '0'), Variant::Type::BOOL, false);648_insert_feature("character_variant_91", HB_TAG('c', 'v', '9', '1'), Variant::Type::BOOL, false);649_insert_feature("character_variant_92", HB_TAG('c', 'v', '9', '2'), Variant::Type::BOOL, false);650_insert_feature("character_variant_93", HB_TAG('c', 'v', '9', '3'), Variant::Type::BOOL, false);651_insert_feature("character_variant_94", HB_TAG('c', 'v', '9', '4'), Variant::Type::BOOL, false);652_insert_feature("character_variant_95", HB_TAG('c', 'v', '9', '5'), Variant::Type::BOOL, false);653_insert_feature("character_variant_96", HB_TAG('c', 'v', '9', '6'), Variant::Type::BOOL, false);654_insert_feature("character_variant_97", HB_TAG('c', 'v', '9', '7'), Variant::Type::BOOL, false);655_insert_feature("character_variant_98", HB_TAG('c', 'v', '9', '8'), Variant::Type::BOOL, false);656_insert_feature("character_variant_99", HB_TAG('c', 'v', '9', '9'), Variant::Type::BOOL, false);657_insert_feature("petite_capitals_from_capitals", HB_TAG('c', '2', 'p', 'c'), Variant::Type::BOOL, false);658_insert_feature("small_capitals_from_capitals", HB_TAG('c', '2', 's', 'c'), Variant::Type::BOOL, false);659_insert_feature("distances", HB_TAG('d', 'i', 's', 't'), Variant::Type::INT, true);660_insert_feature("discretionary_ligatures", HB_TAG('d', 'l', 'i', 'g'), Variant::Type::BOOL, false);661_insert_feature("denominators", HB_TAG('d', 'n', 'o', 'm'), Variant::Type::BOOL, false);662_insert_feature("dotless_forms", HB_TAG('d', 't', 'l', 's'), Variant::Type::INT, true);663_insert_feature("expert_forms", HB_TAG('e', 'x', 'p', 't'), Variant::Type::BOOL, true);664_insert_feature("final_glyph_on_line_alternates", HB_TAG('f', 'a', 'l', 't'), Variant::Type::INT, false);665_insert_feature("terminal_forms_2", HB_TAG('f', 'i', 'n', '2'), Variant::Type::INT, true);666_insert_feature("terminal_forms_3", HB_TAG('f', 'i', 'n', '3'), Variant::Type::INT, true);667_insert_feature("terminal_forms", HB_TAG('f', 'i', 'n', 'a'), Variant::Type::INT, true);668_insert_feature("flattened_accent_forms", HB_TAG('f', 'l', 'a', 'c'), Variant::Type::INT, true);669_insert_feature("fractions", HB_TAG('f', 'r', 'a', 'c'), Variant::Type::BOOL, false);670_insert_feature("full_widths", HB_TAG('f', 'w', 'i', 'd'), Variant::Type::BOOL, false);671_insert_feature("half_forms", HB_TAG('h', 'a', 'l', 'f'), Variant::Type::INT, true);672_insert_feature("halant_forms", HB_TAG('h', 'a', 'l', 'n'), Variant::Type::INT, true);673_insert_feature("alternate_half_widths", HB_TAG('h', 'a', 'l', 't'), Variant::Type::BOOL, false);674_insert_feature("historical_forms", HB_TAG('h', 'i', 's', 't'), Variant::Type::INT, false);675_insert_feature("horizontal_kana_alternates", HB_TAG('h', 'k', 'n', 'a'), Variant::Type::BOOL, false);676_insert_feature("historical_ligatures", HB_TAG('h', 'l', 'i', 'g'), Variant::Type::BOOL, false);677_insert_feature("hangul", HB_TAG('h', 'n', 'g', 'l'), Variant::Type::INT, false);678_insert_feature("hojo_kanji_forms", HB_TAG('h', 'o', 'j', 'o'), Variant::Type::INT, false);679_insert_feature("half_widths", HB_TAG('h', 'w', 'i', 'd'), Variant::Type::BOOL, false);680_insert_feature("initial_forms", HB_TAG('i', 'n', 'i', 't'), Variant::Type::INT, true);681_insert_feature("isolated_forms", HB_TAG('i', 's', 'o', 'l'), Variant::Type::INT, true);682_insert_feature("italics", HB_TAG('i', 't', 'a', 'l'), Variant::Type::INT, false);683_insert_feature("justification_alternates", HB_TAG('j', 'a', 'l', 't'), Variant::Type::INT, false);684_insert_feature("jis78_forms", HB_TAG('j', 'p', '7', '8'), Variant::Type::INT, false);685_insert_feature("jis83_forms", HB_TAG('j', 'p', '8', '3'), Variant::Type::INT, false);686_insert_feature("jis90_forms", HB_TAG('j', 'p', '9', '0'), Variant::Type::INT, false);687_insert_feature("jis2004_forms", HB_TAG('j', 'p', '0', '4'), Variant::Type::INT, false);688_insert_feature("kerning", HB_TAG('k', 'e', 'r', 'n'), Variant::Type::BOOL, false);689_insert_feature("left_bounds", HB_TAG('l', 'f', 'b', 'd'), Variant::Type::INT, false);690_insert_feature("standard_ligatures", HB_TAG('l', 'i', 'g', 'a'), Variant::Type::BOOL, false);691_insert_feature("leading_jamo_forms", HB_TAG('l', 'j', 'm', 'o'), Variant::Type::INT, true);692_insert_feature("lining_figures", HB_TAG('l', 'n', 'u', 'm'), Variant::Type::INT, false);693_insert_feature("localized_forms", HB_TAG('l', 'o', 'c', 'l'), Variant::Type::INT, true);694_insert_feature("left_to_right_alternates", HB_TAG('l', 't', 'r', 'a'), Variant::Type::INT, true);695_insert_feature("left_to_right_mirrored_forms", HB_TAG('l', 't', 'r', 'm'), Variant::Type::INT, true);696_insert_feature("mark_positioning", HB_TAG('m', 'a', 'r', 'k'), Variant::Type::INT, true);697_insert_feature("medial_forms_2", HB_TAG('m', 'e', 'd', '2'), Variant::Type::INT, true);698_insert_feature("medial_forms", HB_TAG('m', 'e', 'd', 'i'), Variant::Type::INT, true);699_insert_feature("mathematical_greek", HB_TAG('m', 'g', 'r', 'k'), Variant::Type::BOOL, false);700_insert_feature("mark_to_mark_positioning", HB_TAG('m', 'k', 'm', 'k'), Variant::Type::INT, true);701_insert_feature("mark_positioning_via_substitution", HB_TAG('m', 's', 'e', 't'), Variant::Type::INT, true);702_insert_feature("alternate_annotation_forms", HB_TAG('n', 'a', 'l', 't'), Variant::Type::INT, false);703_insert_feature("nlc_kanji_forms", HB_TAG('n', 'l', 'c', 'k'), Variant::Type::INT, false);704_insert_feature("nukta_forms", HB_TAG('n', 'u', 'k', 't'), Variant::Type::INT, true);705_insert_feature("numerators", HB_TAG('n', 'u', 'm', 'r'), Variant::Type::BOOL, false);706_insert_feature("oldstyle_figures", HB_TAG('o', 'n', 'u', 'm'), Variant::Type::INT, false);707_insert_feature("optical_bounds", HB_TAG('o', 'p', 'b', 'd'), Variant::Type::INT, true);708_insert_feature("ordinals", HB_TAG('o', 'r', 'd', 'n'), Variant::Type::BOOL, false);709_insert_feature("ornaments", HB_TAG('o', 'r', 'n', 'm'), Variant::Type::INT, false);710_insert_feature("proportional_alternate_widths", HB_TAG('p', 'a', 'l', 't'), Variant::Type::BOOL, false);711_insert_feature("petite_capitals", HB_TAG('p', 'c', 'a', 'p'), Variant::Type::BOOL, false);712_insert_feature("proportional_kana", HB_TAG('p', 'k', 'n', 'a'), Variant::Type::BOOL, false);713_insert_feature("proportional_figures", HB_TAG('p', 'n', 'u', 'm'), Variant::Type::BOOL, false);714_insert_feature("pre_base_forms", HB_TAG('p', 'r', 'e', 'f'), Variant::Type::INT, true);715_insert_feature("pre_base_substitutions", HB_TAG('p', 'r', 'e', 's'), Variant::Type::INT, true);716_insert_feature("post_base_forms", HB_TAG('p', 's', 't', 'f'), Variant::Type::INT, true);717_insert_feature("post_base_substitutions", HB_TAG('p', 's', 't', 's'), Variant::Type::INT, true);718_insert_feature("proportional_widths", HB_TAG('p', 'w', 'i', 'd'), Variant::Type::BOOL, false);719_insert_feature("quarter_widths", HB_TAG('q', 'w', 'i', 'd'), Variant::Type::BOOL, false);720_insert_feature("randomize", HB_TAG('r', 'a', 'n', 'd'), Variant::Type::INT, false);721_insert_feature("required_contextual_alternates", HB_TAG('r', 'c', 'l', 't'), Variant::Type::BOOL, true);722_insert_feature("rakar_forms", HB_TAG('r', 'k', 'r', 'f'), Variant::Type::INT, true);723_insert_feature("required_ligatures", HB_TAG('r', 'l', 'i', 'g'), Variant::Type::BOOL, true);724_insert_feature("reph_forms", HB_TAG('r', 'p', 'h', 'f'), Variant::Type::INT, true);725_insert_feature("right_bounds", HB_TAG('r', 't', 'b', 'd'), Variant::Type::INT, false);726_insert_feature("right_to_left_alternates", HB_TAG('r', 't', 'l', 'a'), Variant::Type::INT, true);727_insert_feature("right_to_left_mirrored_forms", HB_TAG('r', 't', 'l', 'm'), Variant::Type::INT, true);728_insert_feature("ruby_notation_forms", HB_TAG('r', 'u', 'b', 'y'), Variant::Type::INT, false);729_insert_feature("required_variation_alternates", HB_TAG('r', 'v', 'r', 'n'), Variant::Type::INT, true);730_insert_feature("stylistic_alternates", HB_TAG('s', 'a', 'l', 't'), Variant::Type::INT, false);731_insert_feature("scientific_inferiors", HB_TAG('s', 'i', 'n', 'f'), Variant::Type::BOOL, false);732_insert_feature("optical_size", HB_TAG('s', 'i', 'z', 'e'), Variant::Type::INT, false);733_insert_feature("small_capitals", HB_TAG('s', 'm', 'c', 'p'), Variant::Type::BOOL, false);734_insert_feature("simplified_forms", HB_TAG('s', 'm', 'p', 'l'), Variant::Type::INT, false);735_insert_feature("stylistic_set_01", HB_TAG('s', 's', '0', '1'), Variant::Type::BOOL, false);736_insert_feature("stylistic_set_02", HB_TAG('s', 's', '0', '2'), Variant::Type::BOOL, false);737_insert_feature("stylistic_set_03", HB_TAG('s', 's', '0', '3'), Variant::Type::BOOL, false);738_insert_feature("stylistic_set_04", HB_TAG('s', 's', '0', '4'), Variant::Type::BOOL, false);739_insert_feature("stylistic_set_05", HB_TAG('s', 's', '0', '5'), Variant::Type::BOOL, false);740_insert_feature("stylistic_set_06", HB_TAG('s', 's', '0', '6'), Variant::Type::BOOL, false);741_insert_feature("stylistic_set_07", HB_TAG('s', 's', '0', '7'), Variant::Type::BOOL, false);742_insert_feature("stylistic_set_08", HB_TAG('s', 's', '0', '8'), Variant::Type::BOOL, false);743_insert_feature("stylistic_set_09", HB_TAG('s', 's', '0', '9'), Variant::Type::BOOL, false);744_insert_feature("stylistic_set_10", HB_TAG('s', 's', '1', '0'), Variant::Type::BOOL, false);745_insert_feature("stylistic_set_11", HB_TAG('s', 's', '1', '1'), Variant::Type::BOOL, false);746_insert_feature("stylistic_set_12", HB_TAG('s', 's', '1', '2'), Variant::Type::BOOL, false);747_insert_feature("stylistic_set_13", HB_TAG('s', 's', '1', '3'), Variant::Type::BOOL, false);748_insert_feature("stylistic_set_14", HB_TAG('s', 's', '1', '4'), Variant::Type::BOOL, false);749_insert_feature("stylistic_set_15", HB_TAG('s', 's', '1', '5'), Variant::Type::BOOL, false);750_insert_feature("stylistic_set_16", HB_TAG('s', 's', '1', '6'), Variant::Type::BOOL, false);751_insert_feature("stylistic_set_17", HB_TAG('s', 's', '1', '7'), Variant::Type::BOOL, false);752_insert_feature("stylistic_set_18", HB_TAG('s', 's', '1', '8'), Variant::Type::BOOL, false);753_insert_feature("stylistic_set_19", HB_TAG('s', 's', '1', '9'), Variant::Type::BOOL, false);754_insert_feature("stylistic_set_20", HB_TAG('s', 's', '2', '0'), Variant::Type::BOOL, false);755_insert_feature("math_script_style_alternates", HB_TAG('s', 's', 't', 'y'), Variant::Type::INT, true);756_insert_feature("stretching_glyph_decomposition", HB_TAG('s', 't', 'c', 'h'), Variant::Type::INT, true);757_insert_feature("subscript", HB_TAG('s', 'u', 'b', 's'), Variant::Type::BOOL, false);758_insert_feature("superscript", HB_TAG('s', 'u', 'p', 's'), Variant::Type::BOOL, false);759_insert_feature("swash", HB_TAG('s', 'w', 's', 'h'), Variant::Type::INT, false);760_insert_feature("titling", HB_TAG('t', 'i', 't', 'l'), Variant::Type::BOOL, false);761_insert_feature("trailing_jamo_forms", HB_TAG('t', 'j', 'm', 'o'), Variant::Type::INT, true);762_insert_feature("traditional_name_forms", HB_TAG('t', 'n', 'a', 'm'), Variant::Type::INT, false);763_insert_feature("tabular_figures", HB_TAG('t', 'n', 'u', 'm'), Variant::Type::BOOL, false);764_insert_feature("traditional_forms", HB_TAG('t', 'r', 'a', 'd'), Variant::Type::INT, false);765_insert_feature("third_widths", HB_TAG('t', 'w', 'i', 'd'), Variant::Type::BOOL, false);766_insert_feature("unicase", HB_TAG('u', 'n', 'i', 'c'), Variant::Type::BOOL, false);767_insert_feature("alternate_vertical_metrics", HB_TAG('v', 'a', 'l', 't'), Variant::Type::INT, false);768_insert_feature("vattu_variants", HB_TAG('v', 'a', 't', 'u'), Variant::Type::INT, true);769_insert_feature("vertical_contextual_half_width_spacing", HB_TAG('v', 'c', 'h', 'w'), Variant::Type::BOOL, false);770_insert_feature("vertical_alternates", HB_TAG('v', 'e', 'r', 't'), Variant::Type::INT, false);771_insert_feature("alternate_vertical_half_metrics", HB_TAG('v', 'h', 'a', 'l'), Variant::Type::BOOL, false);772_insert_feature("vowel_jamo_forms", HB_TAG('v', 'j', 'm', 'o'), Variant::Type::INT, true);773_insert_feature("vertical_kana_alternates", HB_TAG('v', 'k', 'n', 'a'), Variant::Type::INT, false);774_insert_feature("vertical_kerning", HB_TAG('v', 'k', 'r', 'n'), Variant::Type::BOOL, false);775_insert_feature("proportional_alternate_vertical_metrics", HB_TAG('v', 'p', 'a', 'l'), Variant::Type::BOOL, false);776_insert_feature("vertical_alternates_and_rotation", HB_TAG('v', 'r', 't', '2'), Variant::Type::INT, false);777_insert_feature("vertical_alternates_for_rotation", HB_TAG('v', 'r', 't', 'r'), Variant::Type::INT, false);778_insert_feature("slashed_zero", HB_TAG('z', 'e', 'r', 'o'), Variant::Type::BOOL, false);779780// Registered OpenType variation tag.781_insert_feature("italic", HB_TAG('i', 't', 'a', 'l'), Variant::Type::INT, false);782_insert_feature("optical_size", HB_TAG('o', 'p', 's', 'z'), Variant::Type::INT, false);783_insert_feature("slant", HB_TAG('s', 'l', 'n', 't'), Variant::Type::INT, false);784_insert_feature("width", HB_TAG('w', 'd', 't', 'h'), Variant::Type::INT, false);785_insert_feature("weight", HB_TAG('w', 'g', 'h', 't'), Variant::Type::INT, false);786}787788int64_t TextServerAdvanced::_name_to_tag(const String &p_name) const {789if (feature_sets.has(p_name)) {790return feature_sets[p_name];791}792793// No readable name, use tag string.794return hb_tag_from_string(p_name.replace("custom_", "").ascii().get_data(), -1);795}796797Variant::Type TextServerAdvanced::_get_tag_type(int64_t p_tag) const {798if (feature_sets_inv.has(p_tag)) {799return feature_sets_inv[p_tag].vtype;800}801return Variant::Type::INT;802}803804bool TextServerAdvanced::_get_tag_hidden(int64_t p_tag) const {805if (feature_sets_inv.has(p_tag)) {806return feature_sets_inv[p_tag].hidden;807}808return false;809}810811String TextServerAdvanced::_tag_to_name(int64_t p_tag) const {812if (feature_sets_inv.has(p_tag)) {813return feature_sets_inv[p_tag].name;814}815816// No readable name, use tag string.817char name[5];818memset(name, 0, 5);819hb_tag_to_string(p_tag, name);820return String("custom_") + String(name);821}822823/*************************************************************************/824/* Font Glyph Rendering */825/*************************************************************************/826827_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 {828FontTexturePosition ret;829830int mw = p_width;831int mh = p_height;832833ShelfPackTexture *ct = p_data->textures.ptrw();834for (int32_t i = 0; i < p_data->textures.size(); i++) {835if (ct[i].image.is_null()) {836continue;837}838if (p_image_format != ct[i].image->get_format()) {839continue;840}841if (mw > ct[i].texture_w || mh > ct[i].texture_h) { // Too big for this texture.842continue;843}844845ret = ct[i].pack_rect(i, mh, mw);846if (ret.index != -1) {847break;848}849}850851if (ret.index == -1) {852// Could not find texture to fit, create one.853int texsize = MAX(p_data->size.x * 0.125, 256);854855texsize = next_power_of_2((uint32_t)texsize);856if (p_msdf) {857texsize = MIN(texsize, 2048);858} else {859texsize = MIN(texsize, 1024);860}861if (mw > texsize) { // Special case, adapt to it?862texsize = next_power_of_2((uint32_t)mw);863}864if (mh > texsize) { // Special case, adapt to it?865texsize = next_power_of_2((uint32_t)mh);866}867868ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);869tex.image = Image::create_empty(texsize, texsize, false, p_image_format);870{871// Zero texture.872uint8_t *w = tex.image->ptrw();873ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.image->get_data_size(), ret);874// Initialize the texture to all-white pixels to prevent artifacts when the875// font is displayed at a non-default scale with filtering enabled.876if (p_color_size == 2) {877for (int i = 0; i < texsize * texsize * p_color_size; i += 2) { // FORMAT_LA8, BW font.878w[i + 0] = 255;879w[i + 1] = 0;880}881} else if (p_color_size == 4) {882for (int i = 0; i < texsize * texsize * p_color_size; i += 4) { // FORMAT_RGBA8, Color font, Multichannel(+True) SDF.883if (p_msdf) {884w[i + 0] = 0;885w[i + 1] = 0;886w[i + 2] = 0;887} else {888w[i + 0] = 255;889w[i + 1] = 255;890w[i + 2] = 255;891}892w[i + 3] = 0;893}894} else {895ERR_FAIL_V(ret);896}897}898p_data->textures.push_back(tex);899900int32_t idx = p_data->textures.size() - 1;901ret = p_data->textures.write[idx].pack_rect(idx, mh, mw);902}903904return ret;905}906907#ifdef MODULE_MSDFGEN_ENABLED908909struct MSContext {910msdfgen::Point2 position;911msdfgen::Shape *shape = nullptr;912msdfgen::Contour *contour = nullptr;913};914915class DistancePixelConversion {916double invRange;917918public:919_FORCE_INLINE_ explicit DistancePixelConversion(double range) :920invRange(1 / range) {}921_FORCE_INLINE_ void operator()(float *pixels, const msdfgen::MultiAndTrueDistance &distance) const {922pixels[0] = float(invRange * distance.r + .5);923pixels[1] = float(invRange * distance.g + .5);924pixels[2] = float(invRange * distance.b + .5);925pixels[3] = float(invRange * distance.a + .5);926}927};928929struct MSDFThreadData {930msdfgen::Bitmap<float, 4> *output;931msdfgen::Shape *shape;932msdfgen::Projection *projection;933DistancePixelConversion *distancePixelConversion;934};935936static msdfgen::Point2 ft_point2(const FT_Vector &vector) {937return msdfgen::Point2(vector.x / 60.0f, vector.y / 60.0f);938}939940static int ft_move_to(const FT_Vector *to, void *user) {941MSContext *context = static_cast<MSContext *>(user);942if (!(context->contour && context->contour->edges.empty())) {943context->contour = &context->shape->addContour();944}945context->position = ft_point2(*to);946return 0;947}948949static int ft_line_to(const FT_Vector *to, void *user) {950MSContext *context = static_cast<MSContext *>(user);951msdfgen::Point2 endpoint = ft_point2(*to);952if (endpoint != context->position) {953context->contour->addEdge(new msdfgen::LinearSegment(context->position, endpoint));954context->position = endpoint;955}956return 0;957}958959static int ft_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) {960MSContext *context = static_cast<MSContext *>(user);961context->contour->addEdge(new msdfgen::QuadraticSegment(context->position, ft_point2(*control), ft_point2(*to)));962context->position = ft_point2(*to);963return 0;964}965966static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) {967MSContext *context = static_cast<MSContext *>(user);968context->contour->addEdge(new msdfgen::CubicSegment(context->position, ft_point2(*control1), ft_point2(*control2), ft_point2(*to)));969context->position = ft_point2(*to);970return 0;971}972973void TextServerAdvanced::_generateMTSDF_threaded(void *p_td, uint32_t p_y) {974MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td);975976msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape);977int row = td->shape->inverseYAxis ? td->output->height() - p_y - 1 : p_y;978for (int col = 0; col < td->output->width(); ++col) {979int x = (p_y % 2) ? td->output->width() - col - 1 : col;980msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, p_y + .5));981msdfgen::MultiAndTrueDistance distance = distanceFinder.distance(p);982td->distancePixelConversion->operator()(td->output->operator()(x, row), distance);983}984}985986_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 {987msdfgen::Shape shape;988989shape.contours.clear();990shape.inverseYAxis = false;991992MSContext context = {};993context.shape = &shape;994FT_Outline_Funcs ft_functions;995ft_functions.move_to = &ft_move_to;996ft_functions.line_to = &ft_line_to;997ft_functions.conic_to = &ft_conic_to;998ft_functions.cubic_to = &ft_cubic_to;999ft_functions.shift = 0;1000ft_functions.delta = 0;10011002int error = FT_Outline_Decompose(p_outline, &ft_functions, &context);1003ERR_FAIL_COND_V_MSG(error, FontGlyph(), "FreeType: Outline decomposition error: '" + String(FT_Error_String(error)) + "'.");1004if (!shape.contours.empty() && shape.contours.back().edges.empty()) {1005shape.contours.pop_back();1006}10071008if (FT_Outline_Get_Orientation(p_outline) == 1) {1009for (int i = 0; i < (int)shape.contours.size(); ++i) {1010shape.contours[i].reverse();1011}1012}10131014shape.inverseYAxis = true;1015shape.normalize();10161017msdfgen::Shape::Bounds bounds = shape.getBounds(p_pixel_range);10181019FontGlyph chr;1020chr.found = true;1021chr.advance = p_advance;10221023if (shape.validate() && shape.contours.size() > 0) {1024int w = (bounds.r - bounds.l);1025int h = (bounds.t - bounds.b);10261027if (w == 0 || h == 0) {1028chr.texture_idx = -1;1029chr.uv_rect = Rect2();1030chr.rect = Rect2();1031return chr;1032}10331034int mw = w + p_rect_margin * 4;1035int mh = h + p_rect_margin * 4;10361037ERR_FAIL_COND_V(mw > 4096, FontGlyph());1038ERR_FAIL_COND_V(mh > 4096, FontGlyph());10391040FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true);1041ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());1042ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];10431044edgeColoringSimple(shape, 3.0); // Max. angle.1045msdfgen::Bitmap<float, 4> image(w, h); // Texture size.10461047DistancePixelConversion distancePixelConversion(p_pixel_range);1048msdfgen::Projection projection(msdfgen::Vector2(1.0, 1.0), msdfgen::Vector2(-bounds.l, -bounds.b));1049msdfgen::MSDFGeneratorConfig config(true, msdfgen::ErrorCorrectionConfig());10501051MSDFThreadData td;1052td.output = ℑ1053td.shape = &shape;1054td.projection = &projection;1055td.distancePixelConversion = &distancePixelConversion;10561057WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_native_group_task(&TextServerAdvanced::_generateMTSDF_threaded, &td, h, -1, true, String("FontServerRasterizeMSDF"));1058WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);10591060msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config);10611062{1063uint8_t *wr = tex.image->ptrw();10641065for (int i = 0; i < h; i++) {1066for (int j = 0; j < w; j++) {1067int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * 4;1068ERR_FAIL_COND_V(ofs >= tex.image->get_data_size(), FontGlyph());1069wr[ofs + 0] = (uint8_t)(CLAMP(image(j, i)[0] * 256.f, 0.f, 255.f));1070wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f));1071wr[ofs + 2] = (uint8_t)(CLAMP(image(j, i)[2] * 256.f, 0.f, 255.f));1072wr[ofs + 3] = (uint8_t)(CLAMP(image(j, i)[3] * 256.f, 0.f, 255.f));1073}1074}1075}10761077tex.dirty = true;10781079chr.texture_idx = tex_pos.index;10801081chr.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);1082chr.rect.position = Vector2(bounds.l - p_rect_margin, -bounds.t - p_rect_margin);10831084chr.rect.size = chr.uv_rect.size;1085}1086return chr;1087}1088#endif10891090#ifdef MODULE_FREETYPE_ENABLED1091_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 {1092FontGlyph chr;1093chr.advance = p_advance * p_data->scale;1094chr.found = true;10951096int w = p_bitmap.width;1097int h = p_bitmap.rows;10981099if (w == 0 || h == 0) {1100chr.texture_idx = -1;1101chr.uv_rect = Rect2();1102chr.rect = Rect2();1103return chr;1104}11051106int color_size = 2;11071108switch (p_bitmap.pixel_mode) {1109case FT_PIXEL_MODE_MONO:1110case FT_PIXEL_MODE_GRAY: {1111color_size = 2;1112} break;1113case FT_PIXEL_MODE_BGRA: {1114color_size = 4;1115} break;1116case FT_PIXEL_MODE_LCD: {1117color_size = 4;1118w /= 3;1119} break;1120case FT_PIXEL_MODE_LCD_V: {1121color_size = 4;1122h /= 3;1123} break;1124}11251126int mw = w + p_rect_margin * 4;1127int mh = h + p_rect_margin * 4;11281129ERR_FAIL_COND_V(mw > 4096, FontGlyph());1130ERR_FAIL_COND_V(mh > 4096, FontGlyph());11311132Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;11331134FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh, false);1135ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());11361137// Fit character in char texture.1138ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];11391140{1141uint8_t *wr = tex.image->ptrw();11421143for (int i = 0; i < h; i++) {1144for (int j = 0; j < w; j++) {1145int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * color_size;1146ERR_FAIL_COND_V(ofs >= tex.image->get_data_size(), FontGlyph());1147switch (p_bitmap.pixel_mode) {1148case FT_PIXEL_MODE_MONO: {1149int byte = i * p_bitmap.pitch + (j >> 3);1150int bit = 1 << (7 - (j % 8));1151wr[ofs + 0] = 255; // grayscale as 11152wr[ofs + 1] = (p_bitmap.buffer[byte] & bit) ? 255 : 0;1153} break;1154case FT_PIXEL_MODE_GRAY:1155wr[ofs + 0] = 255; // grayscale as 11156wr[ofs + 1] = p_bitmap.buffer[i * p_bitmap.pitch + j];1157break;1158case FT_PIXEL_MODE_BGRA: {1159int ofs_color = i * p_bitmap.pitch + (j << 2);1160wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];1161wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];1162wr[ofs + 0] = p_bitmap.buffer[ofs_color + 2];1163wr[ofs + 3] = p_bitmap.buffer[ofs_color + 3];1164} break;1165case FT_PIXEL_MODE_LCD: {1166int ofs_color = i * p_bitmap.pitch + (j * 3);1167if (p_bgra) {1168wr[ofs + 0] = p_bitmap.buffer[ofs_color + 2];1169wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];1170wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];1171wr[ofs + 3] = 255;1172} else {1173wr[ofs + 0] = p_bitmap.buffer[ofs_color + 0];1174wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];1175wr[ofs + 2] = p_bitmap.buffer[ofs_color + 2];1176wr[ofs + 3] = 255;1177}1178} break;1179case FT_PIXEL_MODE_LCD_V: {1180int ofs_color = i * p_bitmap.pitch * 3 + j;1181if (p_bgra) {1182wr[ofs + 0] = p_bitmap.buffer[ofs_color + p_bitmap.pitch * 2];1183wr[ofs + 1] = p_bitmap.buffer[ofs_color + p_bitmap.pitch];1184wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];1185wr[ofs + 3] = 255;1186} else {1187wr[ofs + 0] = p_bitmap.buffer[ofs_color + 0];1188wr[ofs + 1] = p_bitmap.buffer[ofs_color + p_bitmap.pitch];1189wr[ofs + 2] = p_bitmap.buffer[ofs_color + p_bitmap.pitch * 2];1190wr[ofs + 3] = 255;1191}1192} break;1193default:1194ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + String::num_int64(p_bitmap.pixel_mode) + ".");1195break;1196}1197}1198}1199}12001201tex.dirty = true;12021203chr.texture_idx = tex_pos.index;12041205chr.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);1206chr.rect.position = Vector2(p_xofs - p_rect_margin, -p_yofs - p_rect_margin) * p_data->scale;1207chr.rect.size = chr.uv_rect.size * p_data->scale;1208return chr;1209}1210#endif12111212/*************************************************************************/1213/* Font Cache */1214/*************************************************************************/12151216bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph, FontGlyph &r_glyph, uint32_t p_oversampling) const {1217FontForSizeAdvanced *fd = nullptr;1218ERR_FAIL_COND_V(!_ensure_cache_for_size(p_font_data, p_size, fd, false, p_oversampling), false);12191220int32_t glyph_index = p_glyph & 0xffffff; // Remove subpixel shifts.12211222HashMap<int32_t, FontGlyph>::Iterator E = fd->glyph_map.find(p_glyph);1223if (E) {1224r_glyph = E->value;1225return E->value.found;1226}12271228if (glyph_index == 0) { // Non graphical or invalid glyph, do not render.1229E = fd->glyph_map.insert(p_glyph, FontGlyph());1230r_glyph = E->value;1231return true;1232}12331234#ifdef MODULE_FREETYPE_ENABLED1235FontGlyph gl;1236if (fd->face) {1237FT_Int32 flags = FT_LOAD_DEFAULT;12381239bool outline = p_size.y > 0;1240switch (p_font_data->hinting) {1241case TextServer::HINTING_NONE:1242flags |= FT_LOAD_NO_HINTING;1243break;1244case TextServer::HINTING_LIGHT:1245flags |= FT_LOAD_TARGET_LIGHT;1246break;1247default:1248flags |= FT_LOAD_TARGET_NORMAL;1249break;1250}1251if (p_font_data->force_autohinter) {1252flags |= FT_LOAD_FORCE_AUTOHINT;1253}1254if (outline || (p_font_data->disable_embedded_bitmaps && !FT_HAS_COLOR(fd->face))) {1255flags |= FT_LOAD_NO_BITMAP;1256} else if (FT_HAS_COLOR(fd->face)) {1257flags |= FT_LOAD_COLOR;1258}12591260FT_Fixed v, h;1261FT_Get_Advance(fd->face, glyph_index, flags, &h);1262FT_Get_Advance(fd->face, glyph_index, flags | FT_LOAD_VERTICAL_LAYOUT, &v);12631264int error = FT_Load_Glyph(fd->face, glyph_index, flags);1265if (error) {1266E = fd->glyph_map.insert(p_glyph, FontGlyph());1267r_glyph = E->value;1268return false;1269}12701271if (!p_font_data->msdf) {1272if ((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)) {1273FT_Pos xshift = (int)((p_glyph >> 27) & 3) << 4;1274FT_Outline_Translate(&fd->face->glyph->outline, xshift, 0);1275} 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)) {1276FT_Pos xshift = (int)((p_glyph >> 27) & 3) << 5;1277FT_Outline_Translate(&fd->face->glyph->outline, xshift, 0);1278}1279}12801281if (p_font_data->embolden != 0.f) {1282FT_Pos strength = p_font_data->embolden * p_size.x / 16; // 26.6 fractional units (1 / 64).1283FT_Outline_Embolden(&fd->face->glyph->outline, strength);1284}12851286if (p_font_data->transform != Transform2D()) {1287FT_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).1288FT_Outline_Transform(&fd->face->glyph->outline, &mat);1289}12901291FT_Render_Mode aa_mode = FT_RENDER_MODE_NORMAL;1292bool bgra = false;1293switch (p_font_data->antialiasing) {1294case FONT_ANTIALIASING_NONE: {1295aa_mode = FT_RENDER_MODE_MONO;1296} break;1297case FONT_ANTIALIASING_GRAY: {1298aa_mode = FT_RENDER_MODE_NORMAL;1299} break;1300case FONT_ANTIALIASING_LCD: {1301int aa_layout = (int)((p_glyph >> 24) & 7);1302switch (aa_layout) {1303case FONT_LCD_SUBPIXEL_LAYOUT_HRGB: {1304aa_mode = FT_RENDER_MODE_LCD;1305bgra = false;1306} break;1307case FONT_LCD_SUBPIXEL_LAYOUT_HBGR: {1308aa_mode = FT_RENDER_MODE_LCD;1309bgra = true;1310} break;1311case FONT_LCD_SUBPIXEL_LAYOUT_VRGB: {1312aa_mode = FT_RENDER_MODE_LCD_V;1313bgra = false;1314} break;1315case FONT_LCD_SUBPIXEL_LAYOUT_VBGR: {1316aa_mode = FT_RENDER_MODE_LCD_V;1317bgra = true;1318} break;1319default: {1320aa_mode = FT_RENDER_MODE_NORMAL;1321} break;1322}1323} break;1324}13251326FT_GlyphSlot slot = fd->face->glyph;1327bool from_svg = (slot->format == FT_GLYPH_FORMAT_SVG); // Need to check before FT_Render_Glyph as it will change format to bitmap.1328if (!outline) {1329if (!p_font_data->msdf) {1330error = FT_Render_Glyph(slot, aa_mode);1331}1332if (!error) {1333if (p_font_data->msdf) {1334#ifdef MODULE_MSDFGEN_ENABLED1335gl = 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);1336#else1337fd->glyph_map[p_glyph] = FontGlyph();1338ERR_FAIL_V_MSG(false, "Compiled without MSDFGEN support!");1339#endif1340} else {1341gl = 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);1342}1343}1344} else {1345FT_Stroker stroker;1346if (FT_Stroker_New(ft_library, &stroker) != 0) {1347fd->glyph_map[p_glyph] = FontGlyph();1348ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph stroker.");1349}13501351FT_Stroker_Set(stroker, (int)(fd->size.y * 16.0), FT_STROKER_LINECAP_BUTT, FT_STROKER_LINEJOIN_ROUND, 0);1352FT_Glyph glyph;1353FT_BitmapGlyph glyph_bitmap;13541355if (FT_Get_Glyph(fd->face->glyph, &glyph) != 0) {1356goto cleanup_stroker;1357}1358if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0) {1359goto cleanup_glyph;1360}1361if (FT_Glyph_To_Bitmap(&glyph, aa_mode, nullptr, 1) != 0) {1362goto cleanup_glyph;1363}1364glyph_bitmap = (FT_BitmapGlyph)glyph;1365gl = rasterize_bitmap(fd, rect_range, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2(), bgra);13661367cleanup_glyph:1368FT_Done_Glyph(glyph);1369cleanup_stroker:1370FT_Stroker_Done(stroker);1371}1372gl.from_svg = from_svg;1373E = fd->glyph_map.insert(p_glyph, gl);1374r_glyph = E->value;1375return gl.found;1376}1377#endif1378E = fd->glyph_map.insert(p_glyph, FontGlyph());1379r_glyph = E->value;1380return false;1381}13821383bool 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 {1384ERR_FAIL_COND_V(p_size.x <= 0, false);13851386HashMap<Vector2i, FontForSizeAdvanced *>::Iterator E = p_font_data->cache.find(p_size);1387if (E) {1388r_cache_for_size = E->value;1389// Size used directly, remove from oversampling list.1390if (p_oversampling == 0 && E->value->viewport_oversampling != 0) {1391OversamplingLevel *ol = oversampling_levels.getptr(E->value->viewport_oversampling);1392if (ol) {1393ol->fonts.erase(E->value);1394}1395}1396return true;1397}13981399FontForSizeAdvanced *fd = memnew(FontForSizeAdvanced);1400fd->size = p_size;1401if (p_font_data->data_ptr && (p_font_data->data_size > 0)) {1402// Init dynamic font.1403#ifdef MODULE_FREETYPE_ENABLED1404int error = 0;1405{1406MutexLock ftlock(ft_mutex);1407if (!ft_library) {1408error = FT_Init_FreeType(&ft_library);1409if (error != 0) {1410memdelete(fd);1411if (p_silent) {1412return false;1413} else {1414ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");1415}1416}1417#ifdef MODULE_SVG_ENABLED1418FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks());1419#endif1420}14211422memset(&fd->stream, 0, sizeof(FT_StreamRec));1423fd->stream.base = (unsigned char *)p_font_data->data_ptr;1424fd->stream.size = p_font_data->data_size;1425fd->stream.pos = 0;14261427FT_Open_Args fargs;1428memset(&fargs, 0, sizeof(FT_Open_Args));1429fargs.memory_base = (unsigned char *)p_font_data->data_ptr;1430fargs.memory_size = p_font_data->data_size;1431fargs.flags = FT_OPEN_MEMORY;1432fargs.stream = &fd->stream;14331434error = FT_Open_Face(ft_library, &fargs, p_font_data->face_index, &fd->face);1435if (error) {1436if (fd->face) {1437FT_Done_Face(fd->face);1438fd->face = nullptr;1439}1440memdelete(fd);1441if (p_silent) {1442return false;1443} else {1444ERR_FAIL_V_MSG(false, "FreeType: Error loading font: '" + String(FT_Error_String(error)) + "' (face_index=" + String::num_int64(p_font_data->face_index) + ").");1445}1446}1447}14481449double sz = double(fd->size.x) / 64.0;1450if (p_font_data->msdf) {1451sz = p_font_data->msdf_source_size;1452}14531454if (FT_HAS_COLOR(fd->face) && fd->face->num_fixed_sizes > 0) {1455int best_match = 0;1456int diff = Math::abs(sz - ((int64_t)fd->face->available_sizes[0].width));1457fd->scale = sz / fd->face->available_sizes[0].width;1458for (int i = 1; i < fd->face->num_fixed_sizes; i++) {1459int ndiff = Math::abs(sz - ((int64_t)fd->face->available_sizes[i].width));1460if (ndiff < diff) {1461best_match = i;1462diff = ndiff;1463fd->scale = sz / fd->face->available_sizes[i].width;1464}1465}1466FT_Select_Size(fd->face, best_match);1467} else {1468FT_Size_RequestRec req;1469req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;1470req.width = sz * 64.0;1471req.height = sz * 64.0;1472req.horiResolution = 0;1473req.vertResolution = 0;14741475FT_Request_Size(fd->face, &req);1476if (fd->face->size->metrics.y_ppem != 0) {1477fd->scale = sz / (double)fd->face->size->metrics.y_ppem;1478}1479}14801481fd->hb_handle = hb_ft_font_create(fd->face, nullptr);14821483fd->ascent = (fd->face->size->metrics.ascender / 64.0) * fd->scale;1484fd->descent = (-fd->face->size->metrics.descender / 64.0) * fd->scale;1485fd->underline_position = (-FT_MulFix(fd->face->underline_position, fd->face->size->metrics.y_scale) / 64.0) * fd->scale;1486fd->underline_thickness = (FT_MulFix(fd->face->underline_thickness, fd->face->size->metrics.y_scale) / 64.0) * fd->scale;14871488#if HB_VERSION_ATLEAST(3, 3, 0)1489hb_font_set_synthetic_slant(fd->hb_handle, p_font_data->transform[0][1]);1490#else1491#ifndef _MSC_VER1492#warning Building with HarfBuzz < 3.3.0, synthetic slant offset correction disabled.1493#endif1494#endif14951496if (!p_font_data->face_init) {1497// When a font does not provide a `family_name`, FreeType tries to synthesize one based on other names.1498// FreeType automatically converts non-ASCII characters to "?" in the synthesized name.1499// To avoid that behavior, use the format-specific name directly if available.1500hb_face_t *hb_face = hb_font_get_face(fd->hb_handle);1501unsigned int num_entries = 0;1502const hb_ot_name_entry_t *names = hb_ot_name_list_names(hb_face, &num_entries);1503const hb_language_t english = hb_language_from_string("en", -1);1504for (unsigned int i = 0; i < num_entries; i++) {1505if (names[i].name_id != HB_OT_NAME_ID_FONT_FAMILY) {1506continue;1507}1508if (!p_font_data->font_name.is_empty() && names[i].language != english) {1509continue;1510}1511unsigned int text_size = hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, nullptr, nullptr) + 1;1512p_font_data->font_name.resize_uninitialized(text_size);1513hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, &text_size, (uint32_t *)p_font_data->font_name.ptrw());1514}1515if (p_font_data->font_name.is_empty() && fd->face->family_name != nullptr) {1516p_font_data->font_name = String::utf8((const char *)fd->face->family_name);1517}1518if (fd->face->style_name != nullptr) {1519p_font_data->style_name = String::utf8((const char *)fd->face->style_name);1520}1521p_font_data->weight = _font_get_weight_by_name(p_font_data->style_name.to_lower());1522p_font_data->stretch = _font_get_stretch_by_name(p_font_data->style_name.to_lower());1523p_font_data->style_flags = 0;1524if ((fd->face->style_flags & FT_STYLE_FLAG_BOLD) || p_font_data->weight >= 700) {1525p_font_data->style_flags.set_flag(FONT_BOLD);1526}1527if ((fd->face->style_flags & FT_STYLE_FLAG_ITALIC) || _is_ital_style(p_font_data->style_name.to_lower())) {1528p_font_data->style_flags.set_flag(FONT_ITALIC);1529}1530if (fd->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) {1531p_font_data->style_flags.set_flag(FONT_FIXED_WIDTH);1532}15331534// Get supported scripts from OpenType font data.1535p_font_data->supported_scripts.clear();1536unsigned int count = hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, nullptr, nullptr);1537if (count != 0) {1538hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));1539hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, &count, script_tags);1540for (unsigned int i = 0; i < count; i++) {1541p_font_data->supported_scripts.insert(script_tags[i]);1542}1543memfree(script_tags);1544}1545count = hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GPOS, 0, nullptr, nullptr);1546if (count != 0) {1547hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));1548hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GPOS, 0, &count, script_tags);1549for (unsigned int i = 0; i < count; i++) {1550p_font_data->supported_scripts.insert(script_tags[i]);1551}1552memfree(script_tags);1553}15541555// Get supported scripts from OS2 table.1556TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(fd->face, FT_SFNT_OS2);1557if (os2) {1558if ((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)) {1559p_font_data->supported_scripts.insert(HB_SCRIPT_COMMON);1560}1561if ((os2->ulUnicodeRange1 & 1L << 0) || (os2->ulUnicodeRange1 & 1L << 1) || (os2->ulUnicodeRange1 & 1L << 2) || (os2->ulUnicodeRange1 & 1L << 3) || (os2->ulUnicodeRange1 & 1L << 29)) {1562p_font_data->supported_scripts.insert(HB_SCRIPT_LATIN);1563}1564if ((os2->ulUnicodeRange1 & 1L << 7) || (os2->ulUnicodeRange1 & 1L << 30)) {1565p_font_data->supported_scripts.insert(HB_SCRIPT_GREEK);1566}1567if (os2->ulUnicodeRange1 & 1L << 8) {1568p_font_data->supported_scripts.insert(HB_SCRIPT_COPTIC);1569}1570if (os2->ulUnicodeRange1 & 1L << 9) {1571p_font_data->supported_scripts.insert(HB_SCRIPT_CYRILLIC);1572}1573if (os2->ulUnicodeRange1 & 1L << 10) {1574p_font_data->supported_scripts.insert(HB_SCRIPT_ARMENIAN);1575}1576if (os2->ulUnicodeRange1 & 1L << 11) {1577p_font_data->supported_scripts.insert(HB_SCRIPT_HEBREW);1578}1579if (os2->ulUnicodeRange1 & 1L << 12) {1580p_font_data->supported_scripts.insert(HB_SCRIPT_VAI);1581}1582if ((os2->ulUnicodeRange1 & 1L << 13) || (os2->ulUnicodeRange2 & 1L << 31) || (os2->ulUnicodeRange3 & 1L << 3)) {1583p_font_data->supported_scripts.insert(HB_SCRIPT_ARABIC);1584}1585if (os2->ulUnicodeRange1 & 1L << 14) {1586p_font_data->supported_scripts.insert(HB_SCRIPT_NKO);1587}1588if (os2->ulUnicodeRange1 & 1L << 15) {1589p_font_data->supported_scripts.insert(HB_SCRIPT_DEVANAGARI);1590}1591if (os2->ulUnicodeRange1 & 1L << 16) {1592p_font_data->supported_scripts.insert(HB_SCRIPT_BENGALI);1593}1594if (os2->ulUnicodeRange1 & 1L << 17) {1595p_font_data->supported_scripts.insert(HB_SCRIPT_GURMUKHI);1596}1597if (os2->ulUnicodeRange1 & 1L << 18) {1598p_font_data->supported_scripts.insert(HB_SCRIPT_GUJARATI);1599}1600if (os2->ulUnicodeRange1 & 1L << 19) {1601p_font_data->supported_scripts.insert(HB_SCRIPT_ORIYA);1602}1603if (os2->ulUnicodeRange1 & 1L << 20) {1604p_font_data->supported_scripts.insert(HB_SCRIPT_TAMIL);1605}1606if (os2->ulUnicodeRange1 & 1L << 21) {1607p_font_data->supported_scripts.insert(HB_SCRIPT_TELUGU);1608}1609if (os2->ulUnicodeRange1 & 1L << 22) {1610p_font_data->supported_scripts.insert(HB_SCRIPT_KANNADA);1611}1612if (os2->ulUnicodeRange1 & 1L << 23) {1613p_font_data->supported_scripts.insert(HB_SCRIPT_MALAYALAM);1614}1615if (os2->ulUnicodeRange1 & 1L << 24) {1616p_font_data->supported_scripts.insert(HB_SCRIPT_THAI);1617}1618if (os2->ulUnicodeRange1 & 1L << 25) {1619p_font_data->supported_scripts.insert(HB_SCRIPT_LAO);1620}1621if (os2->ulUnicodeRange1 & 1L << 26) {1622p_font_data->supported_scripts.insert(HB_SCRIPT_GEORGIAN);1623}1624if (os2->ulUnicodeRange1 & 1L << 27) {1625p_font_data->supported_scripts.insert(HB_SCRIPT_BALINESE);1626}1627if ((os2->ulUnicodeRange1 & 1L << 28) || (os2->ulUnicodeRange2 & 1L << 20) || (os2->ulUnicodeRange2 & 1L << 24)) {1628p_font_data->supported_scripts.insert(HB_SCRIPT_HANGUL);1629}1630if ((os2->ulUnicodeRange2 & 1L << 21) || (os2->ulUnicodeRange2 & 1L << 22) || (os2->ulUnicodeRange2 & 1L << 23) || (os2->ulUnicodeRange2 & 1L << 26) || (os2->ulUnicodeRange2 & 1L << 27) || (os2->ulUnicodeRange2 & 1L << 29)) {1631p_font_data->supported_scripts.insert(HB_SCRIPT_HAN);1632}1633if (os2->ulUnicodeRange2 & 1L << 17) {1634p_font_data->supported_scripts.insert(HB_SCRIPT_HIRAGANA);1635}1636if (os2->ulUnicodeRange2 & 1L << 18) {1637p_font_data->supported_scripts.insert(HB_SCRIPT_KATAKANA);1638}1639if (os2->ulUnicodeRange2 & 1L << 19) {1640p_font_data->supported_scripts.insert(HB_SCRIPT_BOPOMOFO);1641}1642if (os2->ulUnicodeRange3 & 1L << 6) {1643p_font_data->supported_scripts.insert(HB_SCRIPT_TIBETAN);1644}1645if (os2->ulUnicodeRange3 & 1L << 7) {1646p_font_data->supported_scripts.insert(HB_SCRIPT_SYRIAC);1647}1648if (os2->ulUnicodeRange3 & 1L << 8) {1649p_font_data->supported_scripts.insert(HB_SCRIPT_THAANA);1650}1651if (os2->ulUnicodeRange3 & 1L << 9) {1652p_font_data->supported_scripts.insert(HB_SCRIPT_SINHALA);1653}1654if (os2->ulUnicodeRange3 & 1L << 10) {1655p_font_data->supported_scripts.insert(HB_SCRIPT_MYANMAR);1656}1657if (os2->ulUnicodeRange3 & 1L << 11) {1658p_font_data->supported_scripts.insert(HB_SCRIPT_ETHIOPIC);1659}1660if (os2->ulUnicodeRange3 & 1L << 12) {1661p_font_data->supported_scripts.insert(HB_SCRIPT_CHEROKEE);1662}1663if (os2->ulUnicodeRange3 & 1L << 13) {1664p_font_data->supported_scripts.insert(HB_SCRIPT_CANADIAN_SYLLABICS);1665}1666if (os2->ulUnicodeRange3 & 1L << 14) {1667p_font_data->supported_scripts.insert(HB_SCRIPT_OGHAM);1668}1669if (os2->ulUnicodeRange3 & 1L << 15) {1670p_font_data->supported_scripts.insert(HB_SCRIPT_RUNIC);1671}1672if (os2->ulUnicodeRange3 & 1L << 16) {1673p_font_data->supported_scripts.insert(HB_SCRIPT_KHMER);1674}1675if (os2->ulUnicodeRange3 & 1L << 17) {1676p_font_data->supported_scripts.insert(HB_SCRIPT_MONGOLIAN);1677}1678if (os2->ulUnicodeRange3 & 1L << 19) {1679p_font_data->supported_scripts.insert(HB_SCRIPT_YI);1680}1681if (os2->ulUnicodeRange3 & 1L << 20) {1682p_font_data->supported_scripts.insert(HB_SCRIPT_HANUNOO);1683p_font_data->supported_scripts.insert(HB_SCRIPT_TAGBANWA);1684p_font_data->supported_scripts.insert(HB_SCRIPT_BUHID);1685p_font_data->supported_scripts.insert(HB_SCRIPT_TAGALOG);1686}1687if (os2->ulUnicodeRange3 & 1L << 21) {1688p_font_data->supported_scripts.insert(HB_SCRIPT_OLD_ITALIC);1689}1690if (os2->ulUnicodeRange3 & 1L << 22) {1691p_font_data->supported_scripts.insert(HB_SCRIPT_GOTHIC);1692}1693if (os2->ulUnicodeRange3 & 1L << 23) {1694p_font_data->supported_scripts.insert(HB_SCRIPT_DESERET);1695}1696if (os2->ulUnicodeRange3 & 1L << 29) {1697p_font_data->supported_scripts.insert(HB_SCRIPT_LIMBU);1698}1699if (os2->ulUnicodeRange3 & 1L << 30) {1700p_font_data->supported_scripts.insert(HB_SCRIPT_TAI_LE);1701}1702if (os2->ulUnicodeRange3 & 1L << 31) {1703p_font_data->supported_scripts.insert(HB_SCRIPT_NEW_TAI_LUE);1704}1705if (os2->ulUnicodeRange4 & 1L << 0) {1706p_font_data->supported_scripts.insert(HB_SCRIPT_BUGINESE);1707}1708if (os2->ulUnicodeRange4 & 1L << 1) {1709p_font_data->supported_scripts.insert(HB_SCRIPT_GLAGOLITIC);1710}1711if (os2->ulUnicodeRange4 & 1L << 2) {1712p_font_data->supported_scripts.insert(HB_SCRIPT_TIFINAGH);1713}1714if (os2->ulUnicodeRange4 & 1L << 4) {1715p_font_data->supported_scripts.insert(HB_SCRIPT_SYLOTI_NAGRI);1716}1717if (os2->ulUnicodeRange4 & 1L << 5) {1718p_font_data->supported_scripts.insert(HB_SCRIPT_LINEAR_B);1719}1720if (os2->ulUnicodeRange4 & 1L << 7) {1721p_font_data->supported_scripts.insert(HB_SCRIPT_UGARITIC);1722}1723if (os2->ulUnicodeRange4 & 1L << 8) {1724p_font_data->supported_scripts.insert(HB_SCRIPT_OLD_PERSIAN);1725}1726if (os2->ulUnicodeRange4 & 1L << 9) {1727p_font_data->supported_scripts.insert(HB_SCRIPT_SHAVIAN);1728}1729if (os2->ulUnicodeRange4 & 1L << 10) {1730p_font_data->supported_scripts.insert(HB_SCRIPT_OSMANYA);1731}1732if (os2->ulUnicodeRange4 & 1L << 11) {1733p_font_data->supported_scripts.insert(HB_SCRIPT_CYPRIOT);1734}1735if (os2->ulUnicodeRange4 & 1L << 12) {1736p_font_data->supported_scripts.insert(HB_SCRIPT_KHAROSHTHI);1737}1738if (os2->ulUnicodeRange4 & 1L << 13) {1739p_font_data->supported_scripts.insert(HB_SCRIPT_TAI_VIET);1740}1741if (os2->ulUnicodeRange4 & 1L << 14) {1742p_font_data->supported_scripts.insert(HB_SCRIPT_CUNEIFORM);1743}1744if (os2->ulUnicodeRange4 & 1L << 16) {1745p_font_data->supported_scripts.insert(HB_SCRIPT_SUNDANESE);1746}1747if (os2->ulUnicodeRange4 & 1L << 17) {1748p_font_data->supported_scripts.insert(HB_SCRIPT_LEPCHA);1749}1750if (os2->ulUnicodeRange4 & 1L << 18) {1751p_font_data->supported_scripts.insert(HB_SCRIPT_OL_CHIKI);1752}1753if (os2->ulUnicodeRange4 & 1L << 19) {1754p_font_data->supported_scripts.insert(HB_SCRIPT_SAURASHTRA);1755}1756if (os2->ulUnicodeRange4 & 1L << 20) {1757p_font_data->supported_scripts.insert(HB_SCRIPT_KAYAH_LI);1758}1759if (os2->ulUnicodeRange4 & 1L << 21) {1760p_font_data->supported_scripts.insert(HB_SCRIPT_REJANG);1761}1762if (os2->ulUnicodeRange4 & 1L << 22) {1763p_font_data->supported_scripts.insert(HB_SCRIPT_CHAM);1764}1765if (os2->ulUnicodeRange4 & 1L << 25) {1766p_font_data->supported_scripts.insert(HB_SCRIPT_ANATOLIAN_HIEROGLYPHS);1767}1768}17691770// Validate script sample strings.1771{1772LocalVector<uint32_t> failed_scripts;17731774Vector<UChar> sample_buf;1775sample_buf.resize(255);1776for (const uint32_t &scr_tag : p_font_data->supported_scripts) {1777if ((hb_script_t)scr_tag == HB_SCRIPT_COMMON) {1778continue;1779}1780UErrorCode icu_err = U_ZERO_ERROR;1781int32_t len = uscript_getSampleString(hb_icu_script_from_script((hb_script_t)scr_tag), sample_buf.ptrw(), 255, &icu_err);1782if (U_SUCCESS(icu_err) && len > 0) {1783String sample = String::utf16(sample_buf.ptr(), len);1784for (int ch = 0; ch < sample.length(); ch++) {1785if (FT_Get_Char_Index(fd->face, sample[ch]) == 0) {1786failed_scripts.push_back(scr_tag);1787break;1788}1789}1790}1791}1792for (const uint32_t &scr_tag : failed_scripts) {1793p_font_data->supported_scripts.erase(scr_tag);1794}1795}17961797// Read OpenType feature tags.1798p_font_data->supported_features.clear();1799count = hb_ot_layout_table_get_feature_tags(hb_face, HB_OT_TAG_GSUB, 0, nullptr, nullptr);1800if (count != 0) {1801hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));1802hb_ot_layout_table_get_feature_tags(hb_face, HB_OT_TAG_GSUB, 0, &count, feature_tags);1803for (unsigned int i = 0; i < count; i++) {1804Dictionary ftr;18051806#if HB_VERSION_ATLEAST(2, 1, 0)1807hb_ot_name_id_t lbl_id;1808if (hb_ot_layout_feature_get_name_ids(hb_face, HB_OT_TAG_GSUB, i, &lbl_id, nullptr, nullptr, nullptr, nullptr)) {1809PackedInt32Array lbl;1810unsigned 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;1811lbl.resize(text_size);1812memset((uint32_t *)lbl.ptrw(), 0, sizeof(uint32_t) * text_size);1813hb_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());1814ftr["label"] = String((const char32_t *)lbl.ptr());1815}1816#else1817#ifndef _MSC_VER1818#warning Building with HarfBuzz < 2.1.0, readable OpenType feature names disabled.1819#endif1820#endif1821ftr["type"] = _get_tag_type(feature_tags[i]);1822ftr["hidden"] = _get_tag_hidden(feature_tags[i]);18231824p_font_data->supported_features[feature_tags[i]] = ftr;1825}1826memfree(feature_tags);1827}1828count = hb_ot_layout_table_get_feature_tags(hb_face, HB_OT_TAG_GPOS, 0, nullptr, nullptr);1829if (count != 0) {1830hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));1831hb_ot_layout_table_get_feature_tags(hb_face, HB_OT_TAG_GPOS, 0, &count, feature_tags);1832for (unsigned int i = 0; i < count; i++) {1833Dictionary ftr;18341835#if HB_VERSION_ATLEAST(2, 1, 0)1836hb_ot_name_id_t lbl_id;1837if (hb_ot_layout_feature_get_name_ids(hb_face, HB_OT_TAG_GPOS, i, &lbl_id, nullptr, nullptr, nullptr, nullptr)) {1838PackedInt32Array lbl;1839unsigned 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;1840lbl.resize(text_size);1841memset((uint32_t *)lbl.ptrw(), 0, sizeof(uint32_t) * text_size);1842hb_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());1843ftr["label"] = String((const char32_t *)lbl.ptr());1844}1845#else1846#ifndef _MSC_VER1847#warning Building with HarfBuzz < 2.1.0, readable OpenType feature names disabled.1848#endif1849#endif1850ftr["type"] = _get_tag_type(feature_tags[i]);1851ftr["hidden"] = _get_tag_hidden(feature_tags[i]);18521853p_font_data->supported_features[feature_tags[i]] = ftr;1854}1855memfree(feature_tags);1856}18571858// Read OpenType variations.1859p_font_data->supported_varaitions.clear();1860if (fd->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {1861FT_MM_Var *amaster;1862FT_Get_MM_Var(fd->face, &amaster);1863for (FT_UInt i = 0; i < amaster->num_axis; i++) {1864p_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);1865}1866FT_Done_MM_Var(ft_library, amaster);1867}1868p_font_data->face_init = true;1869}18701871#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)1872if (p_font_data->font_name == ".Apple Color Emoji UI" || p_font_data->font_name == "Apple Color Emoji") {1873// The baseline offset is missing from the Apple Color Emoji UI font data, so add it manually.1874// This issue doesn't occur with other system emoji fonts.1875if (!FT_Load_Glyph(fd->face, FT_Get_Char_Index(fd->face, 0x1F92E), FT_LOAD_DEFAULT | FT_LOAD_COLOR)) {1876if (fd->face->glyph->metrics.horiBearingY == fd->face->glyph->metrics.height) {1877p_font_data->baseline_offset = 0.15;1878}1879}1880}1881#endif18821883// Write variations.1884if (fd->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {1885FT_MM_Var *amaster;18861887FT_Get_MM_Var(fd->face, &amaster);18881889Vector<hb_variation_t> hb_vars;1890Vector<FT_Fixed> coords;1891coords.resize(amaster->num_axis);18921893FT_Get_Var_Design_Coordinates(fd->face, coords.size(), coords.ptrw());18941895for (FT_UInt i = 0; i < amaster->num_axis; i++) {1896hb_variation_t var;18971898// Reset to default.1899var.tag = amaster->axis[i].tag;1900var.value = (double)amaster->axis[i].def / 65536.0;1901coords.write[i] = amaster->axis[i].def;19021903if (p_font_data->variation_coordinates.has(var.tag)) {1904var.value = p_font_data->variation_coordinates[var.tag];1905coords.write[i] = CLAMP(var.value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);1906}19071908if (p_font_data->variation_coordinates.has(_tag_to_name(var.tag))) {1909var.value = p_font_data->variation_coordinates[_tag_to_name(var.tag)];1910coords.write[i] = CLAMP(var.value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);1911}19121913hb_vars.push_back(var);1914}19151916FT_Set_Var_Design_Coordinates(fd->face, coords.size(), coords.ptrw());1917hb_font_set_variations(fd->hb_handle, hb_vars.is_empty() ? nullptr : &hb_vars[0], hb_vars.size());1918FT_Done_MM_Var(ft_library, amaster);1919}1920#else1921memdelete(fd);1922if (p_silent) {1923return false;1924} else {1925ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!");1926}1927#endif1928} else {1929// Init bitmap font.1930fd->hb_handle = _bmp_font_create(fd, nullptr);1931}19321933fd->owner = p_font_data;1934p_font_data->cache.insert(p_size, fd);1935r_cache_for_size = fd;1936if (p_oversampling != 0) {1937OversamplingLevel *ol = oversampling_levels.getptr(p_oversampling);1938if (ol) {1939fd->viewport_oversampling = p_oversampling;1940ol->fonts.insert(fd);1941}1942}1943return true;1944}19451946void TextServerAdvanced::_reference_oversampling_level(double p_oversampling) {1947uint32_t oversampling = CLAMP(p_oversampling, 0.1, 100.0) * 64;1948if (oversampling == 64) {1949return;1950}1951OversamplingLevel *ol = oversampling_levels.getptr(oversampling);1952if (ol) {1953ol->refcount++;1954} else {1955OversamplingLevel new_ol;1956oversampling_levels.insert(oversampling, new_ol);1957}1958}19591960void TextServerAdvanced::_unreference_oversampling_level(double p_oversampling) {1961uint32_t oversampling = CLAMP(p_oversampling, 0.1, 100.0) * 64;1962if (oversampling == 64) {1963return;1964}1965OversamplingLevel *ol = oversampling_levels.getptr(oversampling);1966if (ol) {1967ol->refcount--;1968if (ol->refcount == 0) {1969for (FontForSizeAdvanced *fd : ol->fonts) {1970fd->owner->cache.erase(fd->size);1971memdelete(fd);1972}1973ol->fonts.clear();1974oversampling_levels.erase(oversampling);1975}1976}1977}19781979_FORCE_INLINE_ bool TextServerAdvanced::_font_validate(const RID &p_font_rid) const {1980FontAdvanced *fd = _get_font_data(p_font_rid);1981ERR_FAIL_NULL_V(fd, false);19821983MutexLock lock(fd->mutex);1984Vector2i size = _get_size(fd, 16);1985FontForSizeAdvanced *ffsd = nullptr;1986return _ensure_cache_for_size(fd, size, ffsd, true);1987}19881989_FORCE_INLINE_ void TextServerAdvanced::_font_clear_cache(FontAdvanced *p_font_data) {1990MutexLock ftlock(ft_mutex);19911992for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : p_font_data->cache) {1993if (E.value->viewport_oversampling != 0) {1994OversamplingLevel *ol = oversampling_levels.getptr(E.value->viewport_oversampling);1995if (ol) {1996ol->fonts.erase(E.value);1997}1998}1999memdelete(E.value);2000}2001p_font_data->cache.clear();2002p_font_data->face_init = false;2003p_font_data->supported_features.clear();2004p_font_data->supported_varaitions.clear();2005p_font_data->supported_scripts.clear();2006}20072008hb_font_t *TextServerAdvanced::_font_get_hb_handle(const RID &p_font_rid, int64_t p_size) const {2009FontAdvanced *fd = _get_font_data(p_font_rid);2010ERR_FAIL_NULL_V(fd, nullptr);20112012MutexLock lock(fd->mutex);2013Vector2i size = _get_size(fd, p_size);20142015FontForSizeAdvanced *ffsd = nullptr;2016ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), nullptr);20172018return ffsd->hb_handle;2019}20202021RID TextServerAdvanced::_create_font() {2022_THREAD_SAFE_METHOD_20232024FontAdvanced *fd = memnew(FontAdvanced);20252026return font_owner.make_rid(fd);2027}20282029RID TextServerAdvanced::_create_font_linked_variation(const RID &p_font_rid) {2030_THREAD_SAFE_METHOD_20312032RID rid = p_font_rid;2033FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(rid);2034if (unlikely(fdv)) {2035rid = fdv->base_font;2036}2037ERR_FAIL_COND_V(!font_owner.owns(rid), RID());20382039FontAdvancedLinkedVariation *new_fdv = memnew(FontAdvancedLinkedVariation);2040new_fdv->base_font = rid;20412042return font_var_owner.make_rid(new_fdv);2043}20442045void TextServerAdvanced::_font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) {2046FontAdvanced *fd = _get_font_data(p_font_rid);2047ERR_FAIL_NULL(fd);20482049MutexLock lock(fd->mutex);2050_font_clear_cache(fd);2051fd->data = p_data;2052fd->data_ptr = fd->data.ptr();2053fd->data_size = fd->data.size();2054}20552056void TextServerAdvanced::_font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) {2057FontAdvanced *fd = _get_font_data(p_font_rid);2058ERR_FAIL_NULL(fd);20592060MutexLock lock(fd->mutex);2061_font_clear_cache(fd);2062fd->data.resize(0);2063fd->data_ptr = p_data_ptr;2064fd->data_size = p_data_size;2065}20662067void TextServerAdvanced::_font_set_face_index(const RID &p_font_rid, int64_t p_face_index) {2068ERR_FAIL_COND(p_face_index < 0);2069ERR_FAIL_COND(p_face_index >= 0x7FFF);20702071FontAdvanced *fd = _get_font_data(p_font_rid);2072ERR_FAIL_NULL(fd);20732074MutexLock lock(fd->mutex);2075if (fd->face_index != p_face_index) {2076fd->face_index = p_face_index;2077_font_clear_cache(fd);2078}2079}20802081int64_t TextServerAdvanced::_font_get_face_index(const RID &p_font_rid) const {2082FontAdvanced *fd = _get_font_data(p_font_rid);2083ERR_FAIL_NULL_V(fd, 0);20842085MutexLock lock(fd->mutex);2086return fd->face_index;2087}20882089int64_t TextServerAdvanced::_font_get_face_count(const RID &p_font_rid) const {2090FontAdvanced *fd = _get_font_data(p_font_rid);2091ERR_FAIL_NULL_V(fd, 0);20922093MutexLock lock(fd->mutex);2094int face_count = 0;20952096if (fd->data_ptr && (fd->data_size > 0)) {2097// Init dynamic font.2098#ifdef MODULE_FREETYPE_ENABLED2099int error = 0;2100if (!ft_library) {2101error = FT_Init_FreeType(&ft_library);2102ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");2103#ifdef MODULE_SVG_ENABLED2104FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks());2105#endif2106}21072108FT_StreamRec stream;2109memset(&stream, 0, sizeof(FT_StreamRec));2110stream.base = (unsigned char *)fd->data_ptr;2111stream.size = fd->data_size;2112stream.pos = 0;21132114FT_Open_Args fargs;2115memset(&fargs, 0, sizeof(FT_Open_Args));2116fargs.memory_base = (unsigned char *)fd->data_ptr;2117fargs.memory_size = fd->data_size;2118fargs.flags = FT_OPEN_MEMORY;2119fargs.stream = &stream;21202121MutexLock ftlock(ft_mutex);21222123FT_Face tmp_face = nullptr;2124error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);2125if (error == 0) {2126face_count = tmp_face->num_faces;2127FT_Done_Face(tmp_face);2128}2129#endif2130}21312132return face_count;2133}21342135void TextServerAdvanced::_font_set_style(const RID &p_font_rid, BitField<FontStyle> p_style) {2136FontAdvanced *fd = _get_font_data(p_font_rid);2137ERR_FAIL_NULL(fd);21382139MutexLock lock(fd->mutex);2140Vector2i size = _get_size(fd, 16);2141FontForSizeAdvanced *ffsd = nullptr;2142ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2143fd->style_flags = p_style;2144}21452146BitField<TextServer::FontStyle> TextServerAdvanced::_font_get_style(const RID &p_font_rid) const {2147FontAdvanced *fd = _get_font_data(p_font_rid);2148ERR_FAIL_NULL_V(fd, 0);21492150MutexLock lock(fd->mutex);2151Vector2i size = _get_size(fd, 16);2152FontForSizeAdvanced *ffsd = nullptr;2153ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0);2154return fd->style_flags;2155}21562157void TextServerAdvanced::_font_set_style_name(const RID &p_font_rid, const String &p_name) {2158FontAdvanced *fd = _get_font_data(p_font_rid);2159ERR_FAIL_NULL(fd);21602161MutexLock lock(fd->mutex);2162Vector2i size = _get_size(fd, 16);2163FontForSizeAdvanced *ffsd = nullptr;2164ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2165fd->style_name = p_name;2166}21672168String TextServerAdvanced::_font_get_style_name(const RID &p_font_rid) const {2169FontAdvanced *fd = _get_font_data(p_font_rid);2170ERR_FAIL_NULL_V(fd, String());21712172MutexLock lock(fd->mutex);2173Vector2i size = _get_size(fd, 16);2174FontForSizeAdvanced *ffsd = nullptr;2175ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), String());2176return fd->style_name;2177}21782179void TextServerAdvanced::_font_set_weight(const RID &p_font_rid, int64_t p_weight) {2180FontAdvanced *fd = _get_font_data(p_font_rid);2181ERR_FAIL_NULL(fd);21822183MutexLock lock(fd->mutex);2184Vector2i size = _get_size(fd, 16);2185FontForSizeAdvanced *ffsd = nullptr;2186ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2187fd->weight = CLAMP(p_weight, 100, 999);2188}21892190int64_t TextServerAdvanced::_font_get_weight(const RID &p_font_rid) const {2191FontAdvanced *fd = _get_font_data(p_font_rid);2192ERR_FAIL_NULL_V(fd, 400);21932194MutexLock lock(fd->mutex);2195Vector2i size = _get_size(fd, 16);2196FontForSizeAdvanced *ffsd = nullptr;2197ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 400);2198return fd->weight;2199}22002201void TextServerAdvanced::_font_set_stretch(const RID &p_font_rid, int64_t p_stretch) {2202FontAdvanced *fd = _get_font_data(p_font_rid);2203ERR_FAIL_NULL(fd);22042205MutexLock lock(fd->mutex);2206Vector2i size = _get_size(fd, 16);2207FontForSizeAdvanced *ffsd = nullptr;2208ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2209fd->stretch = CLAMP(p_stretch, 50, 200);2210}22112212int64_t TextServerAdvanced::_font_get_stretch(const RID &p_font_rid) const {2213FontAdvanced *fd = _get_font_data(p_font_rid);2214ERR_FAIL_NULL_V(fd, 100);22152216MutexLock lock(fd->mutex);2217Vector2i size = _get_size(fd, 16);2218FontForSizeAdvanced *ffsd = nullptr;2219ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 100);2220return fd->stretch;2221}22222223void TextServerAdvanced::_font_set_name(const RID &p_font_rid, const String &p_name) {2224FontAdvanced *fd = _get_font_data(p_font_rid);2225ERR_FAIL_NULL(fd);22262227MutexLock lock(fd->mutex);2228Vector2i size = _get_size(fd, 16);2229FontForSizeAdvanced *ffsd = nullptr;2230ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2231fd->font_name = p_name;2232}22332234String TextServerAdvanced::_font_get_name(const RID &p_font_rid) const {2235FontAdvanced *fd = _get_font_data(p_font_rid);2236ERR_FAIL_NULL_V(fd, String());22372238MutexLock lock(fd->mutex);2239Vector2i size = _get_size(fd, 16);2240FontForSizeAdvanced *ffsd = nullptr;2241ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), String());2242return fd->font_name;2243}22442245Dictionary TextServerAdvanced::_font_get_ot_name_strings(const RID &p_font_rid) const {2246FontAdvanced *fd = _get_font_data(p_font_rid);2247ERR_FAIL_NULL_V(fd, Dictionary());22482249MutexLock lock(fd->mutex);2250Vector2i size = _get_size(fd, 16);2251FontForSizeAdvanced *ffsd = nullptr;2252ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary());22532254hb_face_t *hb_face = hb_font_get_face(ffsd->hb_handle);22552256unsigned int num_entries = 0;2257const hb_ot_name_entry_t *names = hb_ot_name_list_names(hb_face, &num_entries);2258HashMap<String, Dictionary> names_for_lang;2259for (unsigned int i = 0; i < num_entries; i++) {2260String name;2261switch (names[i].name_id) {2262case HB_OT_NAME_ID_COPYRIGHT: {2263name = "copyright";2264} break;2265case HB_OT_NAME_ID_FONT_FAMILY: {2266name = "family_name";2267} break;2268case HB_OT_NAME_ID_FONT_SUBFAMILY: {2269name = "subfamily_name";2270} break;2271case HB_OT_NAME_ID_UNIQUE_ID: {2272name = "unique_identifier";2273} break;2274case HB_OT_NAME_ID_FULL_NAME: {2275name = "full_name";2276} break;2277case HB_OT_NAME_ID_VERSION_STRING: {2278name = "version";2279} break;2280case HB_OT_NAME_ID_POSTSCRIPT_NAME: {2281name = "postscript_name";2282} break;2283case HB_OT_NAME_ID_TRADEMARK: {2284name = "trademark";2285} break;2286case HB_OT_NAME_ID_MANUFACTURER: {2287name = "manufacturer";2288} break;2289case HB_OT_NAME_ID_DESIGNER: {2290name = "designer";2291} break;2292case HB_OT_NAME_ID_DESCRIPTION: {2293name = "description";2294} break;2295case HB_OT_NAME_ID_VENDOR_URL: {2296name = "vendor_url";2297} break;2298case HB_OT_NAME_ID_DESIGNER_URL: {2299name = "designer_url";2300} break;2301case HB_OT_NAME_ID_LICENSE: {2302name = "license";2303} break;2304case HB_OT_NAME_ID_LICENSE_URL: {2305name = "license_url";2306} break;2307case HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY: {2308name = "typographic_family_name";2309} break;2310case HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY: {2311name = "typographic_subfamily_name";2312} break;2313case HB_OT_NAME_ID_MAC_FULL_NAME: {2314name = "full_name_macos";2315} break;2316case HB_OT_NAME_ID_SAMPLE_TEXT: {2317name = "sample_text";2318} break;2319case HB_OT_NAME_ID_CID_FINDFONT_NAME: {2320name = "cid_findfont_name";2321} break;2322case HB_OT_NAME_ID_WWS_FAMILY: {2323name = "weight_width_slope_family_name";2324} break;2325case HB_OT_NAME_ID_WWS_SUBFAMILY: {2326name = "weight_width_slope_subfamily_name";2327} break;2328case HB_OT_NAME_ID_LIGHT_BACKGROUND: {2329name = "light_background_palette";2330} break;2331case HB_OT_NAME_ID_DARK_BACKGROUND: {2332name = "dark_background_palette";2333} break;2334case HB_OT_NAME_ID_VARIATIONS_PS_PREFIX: {2335name = "postscript_name_prefix";2336} break;2337default: {2338name = vformat("unknown_%d", names[i].name_id);2339} break;2340}2341String text;2342unsigned int text_size = hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, nullptr, nullptr) + 1;2343text.resize_uninitialized(text_size);2344hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, &text_size, (uint32_t *)text.ptrw());2345if (!text.is_empty()) {2346Dictionary &id_string = names_for_lang[String(hb_language_to_string(names[i].language))];2347id_string[name] = text;2348}2349}23502351Dictionary out;2352for (const KeyValue<String, Dictionary> &E : names_for_lang) {2353out[E.key] = E.value;2354}23552356return out;2357}23582359void TextServerAdvanced::_font_set_antialiasing(const RID &p_font_rid, TextServer::FontAntialiasing p_antialiasing) {2360FontAdvanced *fd = _get_font_data(p_font_rid);2361ERR_FAIL_NULL(fd);23622363MutexLock lock(fd->mutex);2364if (fd->antialiasing != p_antialiasing) {2365_font_clear_cache(fd);2366fd->antialiasing = p_antialiasing;2367}2368}23692370TextServer::FontAntialiasing TextServerAdvanced::_font_get_antialiasing(const RID &p_font_rid) const {2371FontAdvanced *fd = _get_font_data(p_font_rid);2372ERR_FAIL_NULL_V(fd, TextServer::FONT_ANTIALIASING_NONE);23732374MutexLock lock(fd->mutex);2375return fd->antialiasing;2376}23772378void TextServerAdvanced::_font_set_disable_embedded_bitmaps(const RID &p_font_rid, bool p_disable_embedded_bitmaps) {2379FontAdvanced *fd = _get_font_data(p_font_rid);2380ERR_FAIL_NULL(fd);23812382MutexLock lock(fd->mutex);2383if (fd->disable_embedded_bitmaps != p_disable_embedded_bitmaps) {2384_font_clear_cache(fd);2385fd->disable_embedded_bitmaps = p_disable_embedded_bitmaps;2386}2387}23882389bool TextServerAdvanced::_font_get_disable_embedded_bitmaps(const RID &p_font_rid) const {2390FontAdvanced *fd = _get_font_data(p_font_rid);2391ERR_FAIL_NULL_V(fd, false);23922393MutexLock lock(fd->mutex);2394return fd->disable_embedded_bitmaps;2395}23962397void TextServerAdvanced::_font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) {2398FontAdvanced *fd = _get_font_data(p_font_rid);2399ERR_FAIL_NULL(fd);24002401MutexLock lock(fd->mutex);2402if (fd->mipmaps != p_generate_mipmaps) {2403for (KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {2404for (int i = 0; i < E.value->textures.size(); i++) {2405E.value->textures.write[i].dirty = true;2406E.value->textures.write[i].texture = Ref<ImageTexture>();2407}2408}2409fd->mipmaps = p_generate_mipmaps;2410}2411}24122413bool TextServerAdvanced::_font_get_generate_mipmaps(const RID &p_font_rid) const {2414FontAdvanced *fd = _get_font_data(p_font_rid);2415ERR_FAIL_NULL_V(fd, false);24162417MutexLock lock(fd->mutex);2418return fd->mipmaps;2419}24202421void TextServerAdvanced::_font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) {2422FontAdvanced *fd = _get_font_data(p_font_rid);2423ERR_FAIL_NULL(fd);24242425MutexLock lock(fd->mutex);2426if (fd->msdf != p_msdf) {2427_font_clear_cache(fd);2428fd->msdf = p_msdf;2429}2430}24312432bool TextServerAdvanced::_font_is_multichannel_signed_distance_field(const RID &p_font_rid) const {2433FontAdvanced *fd = _get_font_data(p_font_rid);2434ERR_FAIL_NULL_V(fd, false);24352436MutexLock lock(fd->mutex);2437return fd->msdf;2438}24392440void TextServerAdvanced::_font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) {2441FontAdvanced *fd = _get_font_data(p_font_rid);2442ERR_FAIL_NULL(fd);24432444MutexLock lock(fd->mutex);2445if (fd->msdf_range != p_msdf_pixel_range) {2446_font_clear_cache(fd);2447fd->msdf_range = p_msdf_pixel_range;2448}2449}24502451int64_t TextServerAdvanced::_font_get_msdf_pixel_range(const RID &p_font_rid) const {2452FontAdvanced *fd = _get_font_data(p_font_rid);2453ERR_FAIL_NULL_V(fd, false);24542455MutexLock lock(fd->mutex);2456return fd->msdf_range;2457}24582459void TextServerAdvanced::_font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) {2460FontAdvanced *fd = _get_font_data(p_font_rid);2461ERR_FAIL_NULL(fd);24622463MutexLock lock(fd->mutex);2464if (fd->msdf_source_size != p_msdf_size) {2465_font_clear_cache(fd);2466fd->msdf_source_size = p_msdf_size;2467}2468}24692470int64_t TextServerAdvanced::_font_get_msdf_size(const RID &p_font_rid) const {2471FontAdvanced *fd = _get_font_data(p_font_rid);2472ERR_FAIL_NULL_V(fd, 0);24732474MutexLock lock(fd->mutex);2475return fd->msdf_source_size;2476}24772478void TextServerAdvanced::_font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) {2479FontAdvanced *fd = _get_font_data(p_font_rid);2480ERR_FAIL_NULL(fd);24812482MutexLock lock(fd->mutex);2483fd->fixed_size = p_fixed_size;2484}24852486int64_t TextServerAdvanced::_font_get_fixed_size(const RID &p_font_rid) const {2487FontAdvanced *fd = _get_font_data(p_font_rid);2488ERR_FAIL_NULL_V(fd, 0);24892490MutexLock lock(fd->mutex);2491return fd->fixed_size;2492}24932494void TextServerAdvanced::_font_set_fixed_size_scale_mode(const RID &p_font_rid, TextServer::FixedSizeScaleMode p_fixed_size_scale_mode) {2495FontAdvanced *fd = _get_font_data(p_font_rid);2496ERR_FAIL_NULL(fd);24972498MutexLock lock(fd->mutex);2499fd->fixed_size_scale_mode = p_fixed_size_scale_mode;2500}25012502TextServer::FixedSizeScaleMode TextServerAdvanced::_font_get_fixed_size_scale_mode(const RID &p_font_rid) const {2503FontAdvanced *fd = _get_font_data(p_font_rid);2504ERR_FAIL_NULL_V(fd, FIXED_SIZE_SCALE_DISABLE);25052506MutexLock lock(fd->mutex);2507return fd->fixed_size_scale_mode;2508}25092510void TextServerAdvanced::_font_set_allow_system_fallback(const RID &p_font_rid, bool p_allow_system_fallback) {2511FontAdvanced *fd = _get_font_data(p_font_rid);2512ERR_FAIL_NULL(fd);25132514MutexLock lock(fd->mutex);2515fd->allow_system_fallback = p_allow_system_fallback;2516}25172518bool TextServerAdvanced::_font_is_allow_system_fallback(const RID &p_font_rid) const {2519FontAdvanced *fd = _get_font_data(p_font_rid);2520ERR_FAIL_NULL_V(fd, false);25212522MutexLock lock(fd->mutex);2523return fd->allow_system_fallback;2524}25252526void TextServerAdvanced::_font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) {2527FontAdvanced *fd = _get_font_data(p_font_rid);2528ERR_FAIL_NULL(fd);25292530MutexLock lock(fd->mutex);2531if (fd->force_autohinter != p_force_autohinter) {2532_font_clear_cache(fd);2533fd->force_autohinter = p_force_autohinter;2534}2535}25362537bool TextServerAdvanced::_font_is_force_autohinter(const RID &p_font_rid) const {2538FontAdvanced *fd = _get_font_data(p_font_rid);2539ERR_FAIL_NULL_V(fd, false);25402541MutexLock lock(fd->mutex);2542return fd->force_autohinter;2543}25442545void TextServerAdvanced::_font_set_modulate_color_glyphs(const RID &p_font_rid, bool p_modulate) {2546FontAdvanced *fd = _get_font_data(p_font_rid);2547ERR_FAIL_NULL(fd);25482549MutexLock lock(fd->mutex);2550if (fd->modulate_color_glyphs != p_modulate) {2551fd->modulate_color_glyphs = p_modulate;2552}2553}25542555bool TextServerAdvanced::_font_is_modulate_color_glyphs(const RID &p_font_rid) const {2556FontAdvanced *fd = _get_font_data(p_font_rid);2557ERR_FAIL_NULL_V(fd, false);25582559MutexLock lock(fd->mutex);2560return fd->modulate_color_glyphs;2561}25622563void TextServerAdvanced::_font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) {2564FontAdvanced *fd = _get_font_data(p_font_rid);2565ERR_FAIL_NULL(fd);25662567MutexLock lock(fd->mutex);2568if (fd->hinting != p_hinting) {2569_font_clear_cache(fd);2570fd->hinting = p_hinting;2571}2572}25732574TextServer::Hinting TextServerAdvanced::_font_get_hinting(const RID &p_font_rid) const {2575FontAdvanced *fd = _get_font_data(p_font_rid);2576ERR_FAIL_NULL_V(fd, HINTING_NONE);25772578MutexLock lock(fd->mutex);2579return fd->hinting;2580}25812582void TextServerAdvanced::_font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) {2583FontAdvanced *fd = _get_font_data(p_font_rid);2584ERR_FAIL_NULL(fd);25852586MutexLock lock(fd->mutex);2587fd->subpixel_positioning = p_subpixel;2588}25892590TextServer::SubpixelPositioning TextServerAdvanced::_font_get_subpixel_positioning(const RID &p_font_rid) const {2591FontAdvanced *fd = _get_font_data(p_font_rid);2592ERR_FAIL_NULL_V(fd, SUBPIXEL_POSITIONING_DISABLED);25932594MutexLock lock(fd->mutex);2595return fd->subpixel_positioning;2596}25972598void TextServerAdvanced::_font_set_keep_rounding_remainders(const RID &p_font_rid, bool p_keep_rounding_remainders) {2599FontAdvanced *fd = _get_font_data(p_font_rid);2600ERR_FAIL_NULL(fd);26012602MutexLock lock(fd->mutex);2603fd->keep_rounding_remainders = p_keep_rounding_remainders;2604}26052606bool TextServerAdvanced::_font_get_keep_rounding_remainders(const RID &p_font_rid) const {2607FontAdvanced *fd = _get_font_data(p_font_rid);2608ERR_FAIL_NULL_V(fd, false);26092610MutexLock lock(fd->mutex);2611return fd->keep_rounding_remainders;2612}26132614void TextServerAdvanced::_font_set_embolden(const RID &p_font_rid, double p_strength) {2615FontAdvanced *fd = _get_font_data(p_font_rid);2616ERR_FAIL_NULL(fd);26172618MutexLock lock(fd->mutex);2619if (fd->embolden != p_strength) {2620_font_clear_cache(fd);2621fd->embolden = p_strength;2622}2623}26242625double TextServerAdvanced::_font_get_embolden(const RID &p_font_rid) const {2626FontAdvanced *fd = _get_font_data(p_font_rid);2627ERR_FAIL_NULL_V(fd, 0.0);26282629MutexLock lock(fd->mutex);2630return fd->embolden;2631}26322633void TextServerAdvanced::_font_set_spacing(const RID &p_font_rid, SpacingType p_spacing, int64_t p_value) {2634ERR_FAIL_INDEX((int)p_spacing, 4);2635FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);2636if (fdv) {2637if (fdv->extra_spacing[p_spacing] != p_value) {2638fdv->extra_spacing[p_spacing] = p_value;2639}2640} else {2641FontAdvanced *fd = font_owner.get_or_null(p_font_rid);2642ERR_FAIL_NULL(fd);26432644MutexLock lock(fd->mutex);2645if (fd->extra_spacing[p_spacing] != p_value) {2646fd->extra_spacing[p_spacing] = p_value;2647}2648}2649}26502651int64_t TextServerAdvanced::_font_get_spacing(const RID &p_font_rid, SpacingType p_spacing) const {2652ERR_FAIL_INDEX_V((int)p_spacing, 4, 0);2653FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);2654if (fdv) {2655return fdv->extra_spacing[p_spacing];2656} else {2657FontAdvanced *fd = font_owner.get_or_null(p_font_rid);2658ERR_FAIL_NULL_V(fd, 0);26592660MutexLock lock(fd->mutex);2661return fd->extra_spacing[p_spacing];2662}2663}26642665void TextServerAdvanced::_font_set_baseline_offset(const RID &p_font_rid, double p_baseline_offset) {2666FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);2667if (fdv) {2668if (fdv->baseline_offset != p_baseline_offset) {2669fdv->baseline_offset = p_baseline_offset;2670}2671} else {2672FontAdvanced *fd = font_owner.get_or_null(p_font_rid);2673ERR_FAIL_NULL(fd);26742675MutexLock lock(fd->mutex);2676if (fd->baseline_offset != p_baseline_offset) {2677_font_clear_cache(fd);2678fd->baseline_offset = p_baseline_offset;2679}2680}2681}26822683double TextServerAdvanced::_font_get_baseline_offset(const RID &p_font_rid) const {2684FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);2685if (fdv) {2686return fdv->baseline_offset;2687} else {2688FontAdvanced *fd = font_owner.get_or_null(p_font_rid);2689ERR_FAIL_NULL_V(fd, 0.0);26902691MutexLock lock(fd->mutex);2692return fd->baseline_offset;2693}2694}26952696void TextServerAdvanced::_font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) {2697FontAdvanced *fd = _get_font_data(p_font_rid);2698ERR_FAIL_NULL(fd);26992700MutexLock lock(fd->mutex);2701if (fd->transform != p_transform) {2702_font_clear_cache(fd);2703fd->transform = p_transform;2704}2705}27062707Transform2D TextServerAdvanced::_font_get_transform(const RID &p_font_rid) const {2708FontAdvanced *fd = _get_font_data(p_font_rid);2709ERR_FAIL_NULL_V(fd, Transform2D());27102711MutexLock lock(fd->mutex);2712return fd->transform;2713}27142715void TextServerAdvanced::_font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) {2716FontAdvanced *fd = _get_font_data(p_font_rid);2717ERR_FAIL_NULL(fd);27182719MutexLock lock(fd->mutex);2720if (!fd->variation_coordinates.recursive_equal(p_variation_coordinates, 1)) {2721_font_clear_cache(fd);2722fd->variation_coordinates = p_variation_coordinates.duplicate();2723}2724}27252726double TextServerAdvanced::_font_get_oversampling(const RID &p_font_rid) const {2727FontAdvanced *fd = _get_font_data(p_font_rid);2728ERR_FAIL_NULL_V(fd, -1.0);27292730MutexLock lock(fd->mutex);2731return fd->oversampling_override;2732}27332734void TextServerAdvanced::_font_set_oversampling(const RID &p_font_rid, double p_oversampling) {2735FontAdvanced *fd = _get_font_data(p_font_rid);2736ERR_FAIL_NULL(fd);27372738MutexLock lock(fd->mutex);2739if (fd->oversampling_override != p_oversampling) {2740_font_clear_cache(fd);2741fd->oversampling_override = p_oversampling;2742}2743}27442745Dictionary TextServerAdvanced::_font_get_variation_coordinates(const RID &p_font_rid) const {2746FontAdvanced *fd = _get_font_data(p_font_rid);2747ERR_FAIL_NULL_V(fd, Dictionary());27482749MutexLock lock(fd->mutex);2750return fd->variation_coordinates;2751}27522753TypedArray<Vector2i> TextServerAdvanced::_font_get_size_cache_list(const RID &p_font_rid) const {2754FontAdvanced *fd = _get_font_data(p_font_rid);2755ERR_FAIL_NULL_V(fd, TypedArray<Vector2i>());27562757MutexLock lock(fd->mutex);2758TypedArray<Vector2i> ret;2759for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {2760if ((E.key.x % 64 == 0) && (E.value->viewport_oversampling == 0)) {2761ret.push_back(Vector2i(E.key.x / 64, E.key.y));2762}2763}2764return ret;2765}27662767TypedArray<Dictionary> TextServerAdvanced::_font_get_size_cache_info(const RID &p_font_rid) const {2768FontAdvanced *fd = _get_font_data(p_font_rid);2769ERR_FAIL_NULL_V(fd, TypedArray<Dictionary>());27702771MutexLock lock(fd->mutex);2772TypedArray<Dictionary> ret;2773for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {2774Dictionary size_info;2775size_info["size_px"] = Vector2i(E.key.x / 64, E.key.y);2776if (E.value->viewport_oversampling) {2777size_info["viewport_oversampling"] = double(E.value->viewport_oversampling) / 64.0;2778}2779size_info["glyphs"] = E.value->glyph_map.size();2780size_info["textures"] = E.value->textures.size();2781uint64_t sz = 0;2782for (const ShelfPackTexture &tx : E.value->textures) {2783sz += tx.image->get_data_size() * 2;2784}2785size_info["textures_size"] = sz;2786ret.push_back(size_info);2787}27882789return ret;2790}27912792void TextServerAdvanced::_font_clear_size_cache(const RID &p_font_rid) {2793FontAdvanced *fd = _get_font_data(p_font_rid);2794ERR_FAIL_NULL(fd);27952796MutexLock lock(fd->mutex);2797MutexLock ftlock(ft_mutex);2798for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {2799if (E.value->viewport_oversampling != 0) {2800OversamplingLevel *ol = oversampling_levels.getptr(E.value->viewport_oversampling);2801if (ol) {2802ol->fonts.erase(E.value);2803}2804}2805memdelete(E.value);2806}2807fd->cache.clear();2808}28092810void TextServerAdvanced::_font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) {2811FontAdvanced *fd = _get_font_data(p_font_rid);2812ERR_FAIL_NULL(fd);28132814MutexLock lock(fd->mutex);2815MutexLock ftlock(ft_mutex);2816Vector2i size = Vector2i(p_size.x * 64, p_size.y);2817if (fd->cache.has(size)) {2818if (fd->cache[size]->viewport_oversampling != 0) {2819OversamplingLevel *ol = oversampling_levels.getptr(fd->cache[size]->viewport_oversampling);2820if (ol) {2821ol->fonts.erase(fd->cache[size]);2822}2823}2824memdelete(fd->cache[size]);2825fd->cache.erase(size);2826}2827}28282829void TextServerAdvanced::_font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) {2830FontAdvanced *fd = _get_font_data(p_font_rid);2831ERR_FAIL_NULL(fd);28322833MutexLock lock(fd->mutex);2834Vector2i size = _get_size(fd, p_size);28352836FontForSizeAdvanced *ffsd = nullptr;2837ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2838ffsd->ascent = p_ascent;2839}28402841double TextServerAdvanced::_font_get_ascent(const RID &p_font_rid, int64_t p_size) const {2842FontAdvanced *fd = _get_font_data(p_font_rid);2843ERR_FAIL_NULL_V(fd, 0.0);28442845MutexLock lock(fd->mutex);2846Vector2i size = _get_size(fd, p_size);28472848FontForSizeAdvanced *ffsd = nullptr;2849ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);28502851if (fd->msdf) {2852return ffsd->ascent * (double)p_size / (double)fd->msdf_source_size;2853} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {2854if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2855return ffsd->ascent * (double)p_size / (double)fd->fixed_size;2856} else {2857return ffsd->ascent * Math::round((double)p_size / (double)fd->fixed_size);2858}2859} else {2860return ffsd->ascent;2861}2862}28632864void TextServerAdvanced::_font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) {2865FontAdvanced *fd = _get_font_data(p_font_rid);2866ERR_FAIL_NULL(fd);28672868Vector2i size = _get_size(fd, p_size);28692870FontForSizeAdvanced *ffsd = nullptr;2871ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2872ffsd->descent = p_descent;2873}28742875double TextServerAdvanced::_font_get_descent(const RID &p_font_rid, int64_t p_size) const {2876FontAdvanced *fd = _get_font_data(p_font_rid);2877ERR_FAIL_NULL_V(fd, 0.0);28782879MutexLock lock(fd->mutex);2880Vector2i size = _get_size(fd, p_size);28812882FontForSizeAdvanced *ffsd = nullptr;2883ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);28842885if (fd->msdf) {2886return ffsd->descent * (double)p_size / (double)fd->msdf_source_size;2887} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {2888if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2889return ffsd->descent * (double)p_size / (double)fd->fixed_size;2890} else {2891return ffsd->descent * Math::round((double)p_size / (double)fd->fixed_size);2892}2893} else {2894return ffsd->descent;2895}2896}28972898void TextServerAdvanced::_font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) {2899FontAdvanced *fd = _get_font_data(p_font_rid);2900ERR_FAIL_NULL(fd);29012902MutexLock lock(fd->mutex);2903Vector2i size = _get_size(fd, p_size);29042905FontForSizeAdvanced *ffsd = nullptr;2906ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2907ffsd->underline_position = p_underline_position;2908}29092910double TextServerAdvanced::_font_get_underline_position(const RID &p_font_rid, int64_t p_size) const {2911FontAdvanced *fd = _get_font_data(p_font_rid);2912ERR_FAIL_NULL_V(fd, 0.0);29132914MutexLock lock(fd->mutex);2915Vector2i size = _get_size(fd, p_size);29162917FontForSizeAdvanced *ffsd = nullptr;2918ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);29192920if (fd->msdf) {2921return ffsd->underline_position * (double)p_size / (double)fd->msdf_source_size;2922} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {2923if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2924return ffsd->underline_position * (double)p_size / (double)fd->fixed_size;2925} else {2926return ffsd->underline_position * Math::round((double)p_size / (double)fd->fixed_size);2927}2928} else {2929return ffsd->underline_position;2930}2931}29322933void TextServerAdvanced::_font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) {2934FontAdvanced *fd = _get_font_data(p_font_rid);2935ERR_FAIL_NULL(fd);29362937MutexLock lock(fd->mutex);2938Vector2i size = _get_size(fd, p_size);29392940FontForSizeAdvanced *ffsd = nullptr;2941ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2942ffsd->underline_thickness = p_underline_thickness;2943}29442945double TextServerAdvanced::_font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const {2946FontAdvanced *fd = _get_font_data(p_font_rid);2947ERR_FAIL_NULL_V(fd, 0.0);29482949MutexLock lock(fd->mutex);2950Vector2i size = _get_size(fd, p_size);29512952FontForSizeAdvanced *ffsd = nullptr;2953ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);29542955if (fd->msdf) {2956return ffsd->underline_thickness * (double)p_size / (double)fd->msdf_source_size;2957} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {2958if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2959return ffsd->underline_thickness * (double)p_size / (double)fd->fixed_size;2960} else {2961return ffsd->underline_thickness * Math::round((double)p_size / (double)fd->fixed_size);2962}2963} else {2964return ffsd->underline_thickness;2965}2966}29672968void TextServerAdvanced::_font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) {2969FontAdvanced *fd = _get_font_data(p_font_rid);2970ERR_FAIL_NULL(fd);29712972MutexLock lock(fd->mutex);2973Vector2i size = _get_size(fd, p_size);29742975FontForSizeAdvanced *ffsd = nullptr;2976ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));29772978#ifdef MODULE_FREETYPE_ENABLED2979if (ffsd->face) {2980return; // Do not override scale for dynamic fonts, it's calculated automatically.2981}2982#endif2983ffsd->scale = p_scale;2984}29852986double TextServerAdvanced::_font_get_scale(const RID &p_font_rid, int64_t p_size) const {2987FontAdvanced *fd = _get_font_data(p_font_rid);2988ERR_FAIL_NULL_V(fd, 0.0);29892990MutexLock lock(fd->mutex);2991Vector2i size = _get_size(fd, p_size);29922993FontForSizeAdvanced *ffsd = nullptr;2994ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);29952996if (fd->msdf) {2997return ffsd->scale * (double)p_size / (double)fd->msdf_source_size;2998} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {2999if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3000return ffsd->scale * (double)p_size / (double)fd->fixed_size;3001} else {3002return ffsd->scale * Math::round((double)p_size / (double)fd->fixed_size);3003}3004} else {3005return ffsd->scale;3006}3007}30083009int64_t TextServerAdvanced::_font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const {3010FontAdvanced *fd = _get_font_data(p_font_rid);3011ERR_FAIL_NULL_V(fd, 0);30123013MutexLock lock(fd->mutex);3014Vector2i size = _get_size_outline(fd, p_size);30153016FontForSizeAdvanced *ffsd = nullptr;3017ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0);30183019return ffsd->textures.size();3020}30213022void TextServerAdvanced::_font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) {3023FontAdvanced *fd = _get_font_data(p_font_rid);3024ERR_FAIL_NULL(fd);3025MutexLock lock(fd->mutex);3026Vector2i size = _get_size_outline(fd, p_size);30273028FontForSizeAdvanced *ffsd = nullptr;3029ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3030ffsd->textures.clear();3031}30323033void TextServerAdvanced::_font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) {3034FontAdvanced *fd = _get_font_data(p_font_rid);3035ERR_FAIL_NULL(fd);30363037MutexLock lock(fd->mutex);3038Vector2i size = _get_size_outline(fd, p_size);3039FontForSizeAdvanced *ffsd = nullptr;3040ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3041ERR_FAIL_INDEX(p_texture_index, ffsd->textures.size());30423043ffsd->textures.remove_at(p_texture_index);3044}30453046void TextServerAdvanced::_font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) {3047FontAdvanced *fd = _get_font_data(p_font_rid);3048ERR_FAIL_NULL(fd);3049ERR_FAIL_COND(p_image.is_null());30503051MutexLock lock(fd->mutex);3052Vector2i size = _get_size_outline(fd, p_size);3053FontForSizeAdvanced *ffsd = nullptr;3054ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3055ERR_FAIL_COND(p_texture_index < 0);3056if (p_texture_index >= ffsd->textures.size()) {3057ffsd->textures.resize(p_texture_index + 1);3058}30593060ShelfPackTexture &tex = ffsd->textures.write[p_texture_index];30613062tex.image = p_image;3063tex.texture_w = p_image->get_width();3064tex.texture_h = p_image->get_height();30653066Ref<Image> img = p_image;3067if (fd->mipmaps && !img->has_mipmaps()) {3068img = p_image->duplicate();3069img->generate_mipmaps();3070}3071tex.texture = ImageTexture::create_from_image(img);3072tex.dirty = false;3073}30743075Ref<Image> TextServerAdvanced::_font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {3076FontAdvanced *fd = _get_font_data(p_font_rid);3077ERR_FAIL_NULL_V(fd, Ref<Image>());30783079MutexLock lock(fd->mutex);3080Vector2i size = _get_size_outline(fd, p_size);3081FontForSizeAdvanced *ffsd = nullptr;3082ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Ref<Image>());3083ERR_FAIL_INDEX_V(p_texture_index, ffsd->textures.size(), Ref<Image>());30843085const ShelfPackTexture &tex = ffsd->textures[p_texture_index];3086return tex.image;3087}30883089void TextServerAdvanced::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offsets) {3090ERR_FAIL_COND(p_offsets.size() % 4 != 0);3091FontAdvanced *fd = _get_font_data(p_font_rid);3092ERR_FAIL_NULL(fd);30933094MutexLock lock(fd->mutex);3095Vector2i size = _get_size_outline(fd, p_size);3096FontForSizeAdvanced *ffsd = nullptr;3097ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3098ERR_FAIL_COND(p_texture_index < 0);3099if (p_texture_index >= ffsd->textures.size()) {3100ffsd->textures.resize(p_texture_index + 1);3101}31023103ShelfPackTexture &tex = ffsd->textures.write[p_texture_index];3104tex.shelves.clear();3105for (int32_t i = 0; i < p_offsets.size(); i += 4) {3106tex.shelves.push_back(Shelf(p_offsets[i], p_offsets[i + 1], p_offsets[i + 2], p_offsets[i + 3]));3107}3108}31093110PackedInt32Array TextServerAdvanced::_font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {3111FontAdvanced *fd = _get_font_data(p_font_rid);3112ERR_FAIL_NULL_V(fd, PackedInt32Array());31133114MutexLock lock(fd->mutex);3115Vector2i size = _get_size_outline(fd, p_size);3116FontForSizeAdvanced *ffsd = nullptr;3117ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), PackedInt32Array());3118ERR_FAIL_INDEX_V(p_texture_index, ffsd->textures.size(), PackedInt32Array());31193120const ShelfPackTexture &tex = ffsd->textures[p_texture_index];3121PackedInt32Array ret;3122ret.resize(tex.shelves.size() * 4);31233124int32_t *wr = ret.ptrw();3125int32_t i = 0;3126for (const Shelf &E : tex.shelves) {3127wr[i * 4] = E.x;3128wr[i * 4 + 1] = E.y;3129wr[i * 4 + 2] = E.w;3130wr[i * 4 + 3] = E.h;3131i++;3132}3133return ret;3134}31353136PackedInt32Array TextServerAdvanced::_font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {3137FontAdvanced *fd = _get_font_data(p_font_rid);3138ERR_FAIL_NULL_V(fd, PackedInt32Array());31393140MutexLock lock(fd->mutex);3141Vector2i size = _get_size_outline(fd, p_size);3142FontForSizeAdvanced *ffsd = nullptr;3143ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), PackedInt32Array());31443145PackedInt32Array ret;3146const HashMap<int32_t, FontGlyph> &gl = ffsd->glyph_map;3147for (const KeyValue<int32_t, FontGlyph> &E : gl) {3148ret.push_back(E.key);3149}3150return ret;3151}31523153void TextServerAdvanced::_font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) {3154FontAdvanced *fd = _get_font_data(p_font_rid);3155ERR_FAIL_NULL(fd);31563157MutexLock lock(fd->mutex);3158Vector2i size = _get_size_outline(fd, p_size);3159FontForSizeAdvanced *ffsd = nullptr;3160ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));31613162ffsd->glyph_map.clear();3163}31643165void TextServerAdvanced::_font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) {3166FontAdvanced *fd = _get_font_data(p_font_rid);3167ERR_FAIL_NULL(fd);31683169MutexLock lock(fd->mutex);3170Vector2i size = _get_size_outline(fd, p_size);3171FontForSizeAdvanced *ffsd = nullptr;3172ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));31733174ffsd->glyph_map.erase(p_glyph);3175}31763177double TextServerAdvanced::_get_extra_advance(RID p_font_rid, int p_font_size) const {3178const FontAdvanced *fd = _get_font_data(p_font_rid);3179ERR_FAIL_NULL_V(fd, 0.0);31803181MutexLock lock(fd->mutex);3182Vector2i size = _get_size(fd, p_font_size);31833184if (fd->embolden != 0.0) {3185return fd->embolden * double(size.x) / 4096.0;3186} else {3187return 0.0;3188}3189}31903191Vector2 TextServerAdvanced::_font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const {3192FontAdvanced *fd = _get_font_data(p_font_rid);3193ERR_FAIL_NULL_V(fd, Vector2());31943195MutexLock lock(fd->mutex);3196Vector2i size = _get_size(fd, p_size);31973198FontForSizeAdvanced *ffsd = nullptr;3199ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());32003201int mod = 0;3202if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3203TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3204if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3205mod = (layout << 24);3206}3207}32083209FontGlyph fgl;3210if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3211return Vector2(); // Invalid or non graphicl glyph, do not display errors.3212}32133214Vector2 ea;3215if (fd->embolden != 0.0) {3216ea.x = fd->embolden * double(size.x) / 4096.0;3217}32183219double scale = _font_get_scale(p_font_rid, p_size);3220if (fd->msdf) {3221return (fgl.advance + ea) * (double)p_size / (double)fd->msdf_source_size;3222} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {3223if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3224return (fgl.advance + ea) * (double)p_size / (double)fd->fixed_size;3225} else {3226return (fgl.advance + ea) * Math::round((double)p_size / (double)fd->fixed_size);3227}3228} 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))) {3229return (fgl.advance + ea).round();3230} else {3231return fgl.advance + ea;3232}3233}32343235void TextServerAdvanced::_font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) {3236FontAdvanced *fd = _get_font_data(p_font_rid);3237ERR_FAIL_NULL(fd);32383239MutexLock lock(fd->mutex);3240Vector2i size = _get_size(fd, p_size);32413242FontForSizeAdvanced *ffsd = nullptr;3243ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));32443245FontGlyph &fgl = ffsd->glyph_map[p_glyph];32463247fgl.advance = p_advance;3248fgl.found = true;3249}32503251Vector2 TextServerAdvanced::_font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3252FontAdvanced *fd = _get_font_data(p_font_rid);3253ERR_FAIL_NULL_V(fd, Vector2());32543255MutexLock lock(fd->mutex);3256Vector2i size = _get_size_outline(fd, p_size);32573258FontForSizeAdvanced *ffsd = nullptr;3259ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());32603261int mod = 0;3262if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3263TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3264if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3265mod = (layout << 24);3266}3267}32683269FontGlyph fgl;3270if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3271return Vector2(); // Invalid or non graphicl glyph, do not display errors.3272}32733274if (fd->msdf) {3275return fgl.rect.position * (double)p_size.x / (double)fd->msdf_source_size;3276} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size.x * 64) {3277if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3278return fgl.rect.position * (double)p_size.x / (double)fd->fixed_size;3279} else {3280return fgl.rect.position * Math::round((double)p_size.x / (double)fd->fixed_size);3281}3282} else {3283return fgl.rect.position;3284}3285}32863287void TextServerAdvanced::_font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) {3288FontAdvanced *fd = _get_font_data(p_font_rid);3289ERR_FAIL_NULL(fd);32903291MutexLock lock(fd->mutex);3292Vector2i size = _get_size_outline(fd, p_size);32933294FontForSizeAdvanced *ffsd = nullptr;3295ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));32963297FontGlyph &fgl = ffsd->glyph_map[p_glyph];32983299fgl.rect.position = p_offset;3300fgl.found = true;3301}33023303Vector2 TextServerAdvanced::_font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3304FontAdvanced *fd = _get_font_data(p_font_rid);3305ERR_FAIL_NULL_V(fd, Vector2());33063307MutexLock lock(fd->mutex);3308Vector2i size = _get_size_outline(fd, p_size);33093310FontForSizeAdvanced *ffsd = nullptr;3311ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());33123313int mod = 0;3314if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3315TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3316if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3317mod = (layout << 24);3318}3319}33203321FontGlyph fgl;3322if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3323return Vector2(); // Invalid or non graphicl glyph, do not display errors.3324}33253326if (fd->msdf) {3327return fgl.rect.size * (double)p_size.x / (double)fd->msdf_source_size;3328} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size.x * 64) {3329if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3330return fgl.rect.size * (double)p_size.x / (double)fd->fixed_size;3331} else {3332return fgl.rect.size * Math::round((double)p_size.x / (double)fd->fixed_size);3333}3334} else {3335return fgl.rect.size;3336}3337}33383339void TextServerAdvanced::_font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) {3340FontAdvanced *fd = _get_font_data(p_font_rid);3341ERR_FAIL_NULL(fd);33423343MutexLock lock(fd->mutex);3344Vector2i size = _get_size_outline(fd, p_size);33453346FontForSizeAdvanced *ffsd = nullptr;3347ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));33483349FontGlyph &fgl = ffsd->glyph_map[p_glyph];33503351fgl.rect.size = p_gl_size;3352fgl.found = true;3353}33543355Rect2 TextServerAdvanced::_font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3356FontAdvanced *fd = _get_font_data(p_font_rid);3357ERR_FAIL_NULL_V(fd, Rect2());33583359MutexLock lock(fd->mutex);3360Vector2i size = _get_size_outline(fd, p_size);33613362FontForSizeAdvanced *ffsd = nullptr;3363ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Rect2());33643365int mod = 0;3366if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3367TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3368if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3369mod = (layout << 24);3370}3371}33723373FontGlyph fgl;3374if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3375return Rect2(); // Invalid or non graphicl glyph, do not display errors.3376}33773378return fgl.uv_rect;3379}33803381void TextServerAdvanced::_font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) {3382FontAdvanced *fd = _get_font_data(p_font_rid);3383ERR_FAIL_NULL(fd);33843385MutexLock lock(fd->mutex);3386Vector2i size = _get_size_outline(fd, p_size);33873388FontForSizeAdvanced *ffsd = nullptr;3389ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));33903391FontGlyph &fgl = ffsd->glyph_map[p_glyph];33923393fgl.uv_rect = p_uv_rect;3394fgl.found = true;3395}33963397int64_t TextServerAdvanced::_font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3398FontAdvanced *fd = _get_font_data(p_font_rid);3399ERR_FAIL_NULL_V(fd, -1);34003401MutexLock lock(fd->mutex);3402Vector2i size = _get_size_outline(fd, p_size);34033404FontForSizeAdvanced *ffsd = nullptr;3405ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), -1);34063407int mod = 0;3408if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3409TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3410if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3411mod = (layout << 24);3412}3413}34143415FontGlyph fgl;3416if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3417return -1; // Invalid or non graphicl glyph, do not display errors.3418}34193420return fgl.texture_idx;3421}34223423void TextServerAdvanced::_font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) {3424FontAdvanced *fd = _get_font_data(p_font_rid);3425ERR_FAIL_NULL(fd);34263427MutexLock lock(fd->mutex);3428Vector2i size = _get_size_outline(fd, p_size);34293430FontForSizeAdvanced *ffsd = nullptr;3431ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));34323433FontGlyph &fgl = ffsd->glyph_map[p_glyph];34343435fgl.texture_idx = p_texture_idx;3436fgl.found = true;3437}34383439RID TextServerAdvanced::_font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3440FontAdvanced *fd = _get_font_data(p_font_rid);3441ERR_FAIL_NULL_V(fd, RID());34423443MutexLock lock(fd->mutex);3444Vector2i size = _get_size_outline(fd, p_size);34453446FontForSizeAdvanced *ffsd = nullptr;3447ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), RID());34483449int mod = 0;3450if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3451TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3452if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3453mod = (layout << 24);3454}3455}34563457FontGlyph fgl;3458if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3459return RID(); // Invalid or non graphicl glyph, do not display errors.3460}34613462ERR_FAIL_COND_V(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size(), RID());34633464if (RenderingServer::get_singleton() != nullptr) {3465if (fgl.texture_idx != -1) {3466if (ffsd->textures[fgl.texture_idx].dirty) {3467ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];3468Ref<Image> img = tex.image;3469if (fgl.from_svg) {3470// Same as the "fix alpha border" process option when importing SVGs3471img->fix_alpha_edges();3472}3473if (fd->mipmaps && !img->has_mipmaps()) {3474img = tex.image->duplicate();3475img->generate_mipmaps();3476}3477if (tex.texture.is_null()) {3478tex.texture = ImageTexture::create_from_image(img);3479} else {3480tex.texture->update(img);3481}3482tex.dirty = false;3483}3484return ffsd->textures[fgl.texture_idx].texture->get_rid();3485}3486}34873488return RID();3489}34903491Size2 TextServerAdvanced::_font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3492FontAdvanced *fd = _get_font_data(p_font_rid);3493ERR_FAIL_NULL_V(fd, Size2());34943495MutexLock lock(fd->mutex);3496Vector2i size = _get_size_outline(fd, p_size);34973498FontForSizeAdvanced *ffsd = nullptr;3499ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Size2());35003501int mod = 0;3502if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3503TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3504if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3505mod = (layout << 24);3506}3507}35083509FontGlyph fgl;3510if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3511return Size2(); // Invalid or non graphicl glyph, do not display errors.3512}35133514ERR_FAIL_COND_V(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size(), Size2());35153516if (RenderingServer::get_singleton() != nullptr) {3517if (fgl.texture_idx != -1) {3518if (ffsd->textures[fgl.texture_idx].dirty) {3519ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];3520Ref<Image> img = tex.image;3521if (fgl.from_svg) {3522// Same as the "fix alpha border" process option when importing SVGs3523img->fix_alpha_edges();3524}3525if (fd->mipmaps && !img->has_mipmaps()) {3526img = tex.image->duplicate();3527img->generate_mipmaps();3528}3529if (tex.texture.is_null()) {3530tex.texture = ImageTexture::create_from_image(img);3531} else {3532tex.texture->update(img);3533}3534tex.dirty = false;3535}3536return ffsd->textures[fgl.texture_idx].texture->get_size();3537}3538}35393540return Size2();3541}35423543Dictionary TextServerAdvanced::_font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const {3544FontAdvanced *fd = _get_font_data(p_font_rid);3545ERR_FAIL_NULL_V(fd, Dictionary());35463547MutexLock lock(fd->mutex);3548Vector2i size = _get_size(fd, p_size);35493550FontForSizeAdvanced *ffsd = nullptr;3551ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary());35523553#ifdef MODULE_FREETYPE_ENABLED3554PackedVector3Array points;3555PackedInt32Array contours;35563557int32_t index = p_index & 0xffffff; // Remove subpixel shifts.35583559int error = FT_Load_Glyph(ffsd->face, index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));3560ERR_FAIL_COND_V(error, Dictionary());35613562if (fd->embolden != 0.f) {3563FT_Pos strength = fd->embolden * size.x / 16; // 26.6 fractional units (1 / 64).3564FT_Outline_Embolden(&ffsd->face->glyph->outline, strength);3565}35663567if (fd->transform != Transform2D()) {3568FT_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).3569FT_Outline_Transform(&ffsd->face->glyph->outline, &mat);3570}35713572double scale = (1.0 / 64.0) * ffsd->scale;3573if (fd->msdf) {3574scale = scale * (double)p_size / (double)fd->msdf_source_size;3575} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {3576if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3577scale = scale * (double)p_size / (double)fd->fixed_size;3578} else {3579scale = scale * Math::round((double)p_size / (double)fd->fixed_size);3580}3581}3582for (short i = 0; i < ffsd->face->glyph->outline.n_points; i++) {3583points.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])));3584}3585for (short i = 0; i < ffsd->face->glyph->outline.n_contours; i++) {3586contours.push_back(ffsd->face->glyph->outline.contours[i]);3587}3588bool orientation = (FT_Outline_Get_Orientation(&ffsd->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);35893590Dictionary out;3591out["points"] = points;3592out["contours"] = contours;3593out["orientation"] = orientation;3594return out;3595#else3596return Dictionary();3597#endif3598}35993600TypedArray<Vector2i> TextServerAdvanced::_font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {3601FontAdvanced *fd = _get_font_data(p_font_rid);3602ERR_FAIL_NULL_V(fd, TypedArray<Vector2i>());36033604MutexLock lock(fd->mutex);3605Vector2i size = _get_size(fd, p_size);36063607FontForSizeAdvanced *ffsd = nullptr;3608ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), TypedArray<Vector2i>());36093610TypedArray<Vector2i> ret;3611for (const KeyValue<Vector2i, Vector2> &E : fd->cache[size]->kerning_map) {3612ret.push_back(E.key);3613}3614return ret;3615}36163617void TextServerAdvanced::_font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) {3618FontAdvanced *fd = _get_font_data(p_font_rid);3619ERR_FAIL_NULL(fd);36203621MutexLock lock(fd->mutex);3622Vector2i size = _get_size(fd, p_size);36233624FontForSizeAdvanced *ffsd = nullptr;3625ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3626ffsd->kerning_map.clear();3627}36283629void TextServerAdvanced::_font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) {3630FontAdvanced *fd = _get_font_data(p_font_rid);3631ERR_FAIL_NULL(fd);36323633MutexLock lock(fd->mutex);3634Vector2i size = _get_size(fd, p_size);36353636FontForSizeAdvanced *ffsd = nullptr;3637ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3638ffsd->kerning_map.erase(p_glyph_pair);3639}36403641void TextServerAdvanced::_font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {3642FontAdvanced *fd = _get_font_data(p_font_rid);3643ERR_FAIL_NULL(fd);36443645MutexLock lock(fd->mutex);3646Vector2i size = _get_size(fd, p_size);36473648FontForSizeAdvanced *ffsd = nullptr;3649ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3650ffsd->kerning_map[p_glyph_pair] = p_kerning;3651}36523653Vector2 TextServerAdvanced::_font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const {3654FontAdvanced *fd = _get_font_data(p_font_rid);3655ERR_FAIL_NULL_V(fd, Vector2());36563657MutexLock lock(fd->mutex);3658Vector2i size = _get_size(fd, p_size);36593660FontForSizeAdvanced *ffsd = nullptr;3661ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());36623663const HashMap<Vector2i, Vector2> &kern = ffsd->kerning_map;36643665if (kern.has(p_glyph_pair)) {3666if (fd->msdf) {3667return kern[p_glyph_pair] * (double)p_size / (double)fd->msdf_source_size;3668} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {3669if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3670return kern[p_glyph_pair] * (double)p_size / (double)fd->fixed_size;3671} else {3672return kern[p_glyph_pair] * Math::round((double)p_size / (double)fd->fixed_size);3673}3674} else {3675return kern[p_glyph_pair];3676}3677} else {3678#ifdef MODULE_FREETYPE_ENABLED3679if (ffsd->face) {3680FT_Vector delta;3681FT_Get_Kerning(ffsd->face, p_glyph_pair.x, p_glyph_pair.y, FT_KERNING_DEFAULT, &delta);3682if (fd->msdf) {3683return Vector2(delta.x, delta.y) * (double)p_size / (double)fd->msdf_source_size;3684} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {3685if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3686return Vector2(delta.x, delta.y) * (double)p_size / (double)fd->fixed_size;3687} else {3688return Vector2(delta.x, delta.y) * Math::round((double)p_size / (double)fd->fixed_size);3689}3690} else {3691return Vector2(delta.x, delta.y);3692}3693}3694#endif3695}3696return Vector2();3697}36983699int64_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 {3700FontAdvanced *fd = _get_font_data(p_font_rid);3701ERR_FAIL_NULL_V(fd, 0);3702ERR_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) + ".");3703ERR_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) + ".");37043705MutexLock lock(fd->mutex);3706Vector2i size = _get_size(fd, p_size);3707FontForSizeAdvanced *ffsd = nullptr;3708ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0);37093710#ifdef MODULE_FREETYPE_ENABLED3711if (ffsd->face) {3712if (p_variation_selector) {3713return FT_Face_GetCharVariantIndex(ffsd->face, p_char, p_variation_selector);3714} else {3715return FT_Get_Char_Index(ffsd->face, p_char);3716}3717} else {3718return (int64_t)p_char;3719}3720#else3721return (int64_t)p_char;3722#endif3723}37243725int64_t TextServerAdvanced::_font_get_char_from_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_glyph_index) const {3726FontAdvanced *fd = _get_font_data(p_font_rid);3727ERR_FAIL_NULL_V(fd, 0);37283729MutexLock lock(fd->mutex);3730Vector2i size = _get_size(fd, p_size);3731FontForSizeAdvanced *ffsd = nullptr;3732ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0);37333734#ifdef MODULE_FREETYPE_ENABLED3735if (ffsd->inv_glyph_map.is_empty()) {3736FT_Face face = ffsd->face;3737FT_UInt gindex;3738FT_ULong charcode = FT_Get_First_Char(face, &gindex);3739while (gindex != 0) {3740if (charcode != 0) {3741ffsd->inv_glyph_map[gindex] = charcode;3742}3743charcode = FT_Get_Next_Char(face, charcode, &gindex);3744}3745}37463747if (ffsd->inv_glyph_map.has(p_glyph_index)) {3748return ffsd->inv_glyph_map[p_glyph_index];3749} else {3750return 0;3751}3752#else3753return p_glyph_index;3754#endif3755}37563757bool TextServerAdvanced::_font_has_char(const RID &p_font_rid, int64_t p_char) const {3758FontAdvanced *fd = _get_font_data(p_font_rid);3759ERR_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) + ".");3760if (!fd) {3761return false;3762}37633764MutexLock lock(fd->mutex);3765FontForSizeAdvanced *ffsd = nullptr;3766if (fd->cache.is_empty()) {3767ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size * 64, 0) : Vector2i(16 * 64, 0), ffsd), false);3768} else {3769ffsd = fd->cache.begin()->value;3770}37713772#ifdef MODULE_FREETYPE_ENABLED3773if (ffsd->face) {3774return FT_Get_Char_Index(ffsd->face, p_char) != 0;3775}3776#endif3777return ffsd->glyph_map.has((int32_t)p_char);3778}37793780String TextServerAdvanced::_font_get_supported_chars(const RID &p_font_rid) const {3781FontAdvanced *fd = _get_font_data(p_font_rid);3782ERR_FAIL_NULL_V(fd, String());37833784MutexLock lock(fd->mutex);3785FontForSizeAdvanced *ffsd = nullptr;3786if (fd->cache.is_empty()) {3787ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size * 64, 0) : Vector2i(16 * 64, 0), ffsd), String());3788} else {3789ffsd = fd->cache.begin()->value;3790}37913792String chars;3793#ifdef MODULE_FREETYPE_ENABLED3794if (ffsd->face) {3795FT_UInt gindex;3796FT_ULong charcode = FT_Get_First_Char(ffsd->face, &gindex);3797while (gindex != 0) {3798if (charcode != 0) {3799chars = chars + String::chr(charcode);3800}3801charcode = FT_Get_Next_Char(ffsd->face, charcode, &gindex);3802}3803return chars;3804}3805#endif3806const HashMap<int32_t, FontGlyph> &gl = ffsd->glyph_map;3807for (const KeyValue<int32_t, FontGlyph> &E : gl) {3808chars = chars + String::chr(E.key);3809}3810return chars;3811}38123813PackedInt32Array TextServerAdvanced::_font_get_supported_glyphs(const RID &p_font_rid) const {3814FontAdvanced *fd = _get_font_data(p_font_rid);3815ERR_FAIL_NULL_V(fd, PackedInt32Array());38163817MutexLock lock(fd->mutex);3818FontForSizeAdvanced *at_size = nullptr;3819if (fd->cache.is_empty()) {3820ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size * 64, 0) : Vector2i(16 * 64, 0), at_size), PackedInt32Array());3821} else {3822at_size = fd->cache.begin()->value;3823}38243825PackedInt32Array glyphs;3826#ifdef MODULE_FREETYPE_ENABLED3827if (at_size && at_size->face) {3828FT_UInt gindex;3829FT_ULong charcode = FT_Get_First_Char(at_size->face, &gindex);3830while (gindex != 0) {3831glyphs.push_back(gindex);3832charcode = FT_Get_Next_Char(at_size->face, charcode, &gindex);3833}3834return glyphs;3835}3836#endif3837if (at_size) {3838const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map;3839for (const KeyValue<int32_t, FontGlyph> &E : gl) {3840glyphs.push_back(E.key);3841}3842}3843return glyphs;3844}38453846void TextServerAdvanced::_font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) {3847FontAdvanced *fd = _get_font_data(p_font_rid);3848ERR_FAIL_NULL(fd);3849ERR_FAIL_COND_MSG((p_start >= 0xd800 && p_start <= 0xdfff) || (p_start > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_start, 16) + ".");3850ERR_FAIL_COND_MSG((p_end >= 0xd800 && p_end <= 0xdfff) || (p_end > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_end, 16) + ".");38513852MutexLock lock(fd->mutex);3853Vector2i size = _get_size_outline(fd, p_size);3854FontForSizeAdvanced *ffsd = nullptr;3855ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3856for (int64_t i = p_start; i <= p_end; i++) {3857#ifdef MODULE_FREETYPE_ENABLED3858int32_t idx = FT_Get_Char_Index(ffsd->face, i);3859if (ffsd->face) {3860FontGlyph fgl;3861if (fd->msdf) {3862_ensure_glyph(fd, size, (int32_t)idx, fgl);3863} else {3864for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {3865if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {3866_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);3867_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);3868_ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24), fgl);3869_ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24), fgl);3870} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {3871_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);3872_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);3873} else {3874_ensure_glyph(fd, size, (int32_t)idx | (aa << 24), fgl);3875}3876}3877}3878}3879#endif3880}3881}38823883void TextServerAdvanced::_font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) {3884FontAdvanced *fd = _get_font_data(p_font_rid);3885ERR_FAIL_NULL(fd);38863887MutexLock lock(fd->mutex);3888Vector2i size = _get_size_outline(fd, p_size);3889FontForSizeAdvanced *ffsd = nullptr;3890ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3891#ifdef MODULE_FREETYPE_ENABLED3892int32_t idx = p_index & 0xffffff; // Remove subpixel shifts.3893if (ffsd->face) {3894FontGlyph fgl;3895if (fd->msdf) {3896_ensure_glyph(fd, size, (int32_t)idx, fgl);3897} else {3898for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {3899if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {3900_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);3901_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);3902_ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24), fgl);3903_ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24), fgl);3904} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {3905_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);3906_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);3907} else {3908_ensure_glyph(fd, size, (int32_t)idx | (aa << 24), fgl);3909}3910}3911}3912}3913#endif3914}39153916void 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 {3917if (p_index == 0) {3918return; // Non visual character, skip.3919}3920FontAdvanced *fd = _get_font_data(p_font_rid);3921ERR_FAIL_NULL(fd);39223923MutexLock lock(fd->mutex);39243925// Oversampling.3926bool viewport_oversampling = false;3927float oversampling_factor = p_oversampling;3928if (p_oversampling <= 0.0) {3929if (fd->oversampling_override > 0.0) {3930oversampling_factor = fd->oversampling_override;3931} else if (vp_oversampling > 0.0) {3932oversampling_factor = vp_oversampling;3933viewport_oversampling = true;3934} else {3935oversampling_factor = 1.0;3936}3937}3938bool skip_oversampling = fd->msdf || fd->fixed_size > 0;3939if (skip_oversampling) {3940oversampling_factor = 1.0;3941} else {3942uint64_t oversampling_level = CLAMP(oversampling_factor, 0.1, 100.0) * 64;3943oversampling_factor = double(oversampling_level) / 64.0;3944}39453946Vector2i size;3947if (skip_oversampling) {3948size = _get_size(fd, p_size);3949} else {3950size = Vector2i(p_size * 64 * oversampling_factor, 0);3951}39523953FontForSizeAdvanced *ffsd = nullptr;3954ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd, false, viewport_oversampling ? 64 * oversampling_factor : 0));39553956int32_t index = p_index & 0xffffff; // Remove subpixel shifts.3957bool lcd_aa = false;39583959#ifdef MODULE_FREETYPE_ENABLED3960if (!fd->msdf && ffsd->face) {3961// LCD layout, bits 24, 25, 263962if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3963TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3964if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3965lcd_aa = true;3966index = index | (layout << 24);3967}3968}3969// Subpixel X-shift, bits 27, 283970if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {3971int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));3972index = index | (xshift << 27);3973} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {3974int xshift = (int)(Math::floor(2 * (p_pos.x + 0.25)) - 2 * Math::floor(p_pos.x + 0.25));3975index = index | (xshift << 27);3976}3977}3978#endif39793980FontGlyph fgl;3981if (!_ensure_glyph(fd, size, index, fgl, viewport_oversampling ? 64 * oversampling_factor : 0)) {3982return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.3983}39843985if (fgl.found) {3986ERR_FAIL_COND(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size());39873988if (fgl.texture_idx != -1) {3989Color modulate = p_color;3990#ifdef MODULE_FREETYPE_ENABLED3991if (!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) {3992modulate.r = modulate.g = modulate.b = 1.0;3993}3994#endif3995if (RenderingServer::get_singleton() != nullptr) {3996if (ffsd->textures[fgl.texture_idx].dirty) {3997ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];3998Ref<Image> img = tex.image;3999if (fgl.from_svg) {4000// Same as the "fix alpha border" process option when importing SVGs4001img->fix_alpha_edges();4002}4003if (fd->mipmaps && !img->has_mipmaps()) {4004img = tex.image->duplicate();4005img->generate_mipmaps();4006}4007if (tex.texture.is_null()) {4008tex.texture = ImageTexture::create_from_image(img);4009} else {4010tex.texture->update(img);4011}4012tex.dirty = false;4013}4014RID texture = ffsd->textures[fgl.texture_idx].texture->get_rid();4015if (fd->msdf) {4016Point2 cpos = p_pos;4017cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size;4018Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size;4019RenderingServer::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);4020} else {4021Point2 cpos = p_pos;4022double scale = _font_get_scale(p_font_rid, p_size) / oversampling_factor;4023if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {4024cpos.x = cpos.x + 0.125;4025} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {4026cpos.x = cpos.x + 0.25;4027}4028if (scale == 1.0) {4029cpos.y = Math::floor(cpos.y);4030cpos.x = Math::floor(cpos.x);4031}4032Vector2 gpos = fgl.rect.position;4033Size2 csize = fgl.rect.size;4034if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE) {4035if (size.x != p_size * 64) {4036if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {4037double gl_scale = (double)p_size / (double)fd->fixed_size;4038gpos *= gl_scale;4039csize *= gl_scale;4040} else {4041double gl_scale = Math::round((double)p_size / (double)fd->fixed_size);4042gpos *= gl_scale;4043csize *= gl_scale;4044}4045}4046} else {4047gpos /= oversampling_factor;4048csize /= oversampling_factor;4049}4050cpos += gpos;4051if (lcd_aa) {4052RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate);4053} else {4054RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false);4055}4056}4057}4058}4059}4060}40614062void 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 {4063if (p_index == 0) {4064return; // Non visual character, skip.4065}4066FontAdvanced *fd = _get_font_data(p_font_rid);4067ERR_FAIL_NULL(fd);40684069MutexLock lock(fd->mutex);40704071// Oversampling.4072bool viewport_oversampling = false;4073float oversampling_factor = p_oversampling;4074if (p_oversampling <= 0.0) {4075if (fd->oversampling_override > 0.0) {4076oversampling_factor = fd->oversampling_override;4077} else if (vp_oversampling > 0.0) {4078oversampling_factor = vp_oversampling;4079viewport_oversampling = true;4080} else {4081oversampling_factor = 1.0;4082}4083}4084bool skip_oversampling = fd->msdf || fd->fixed_size > 0;4085if (skip_oversampling) {4086oversampling_factor = 1.0;4087} else {4088uint64_t oversampling_level = CLAMP(oversampling_factor, 0.1, 100.0) * 64;4089oversampling_factor = double(oversampling_level) / 64.0;4090}40914092Vector2i size;4093if (skip_oversampling) {4094size = _get_size_outline(fd, Vector2i(p_size, p_outline_size));4095} else {4096size = Vector2i(p_size * 64 * oversampling_factor, p_outline_size * oversampling_factor);4097}40984099FontForSizeAdvanced *ffsd = nullptr;4100ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd, false, viewport_oversampling ? 64 * oversampling_factor : 0));41014102int32_t index = p_index & 0xffffff; // Remove subpixel shifts.4103bool lcd_aa = false;41044105#ifdef MODULE_FREETYPE_ENABLED4106if (!fd->msdf && ffsd->face) {4107// LCD layout, bits 24, 25, 264108if (fd->antialiasing == FONT_ANTIALIASING_LCD) {4109TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();4110if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {4111lcd_aa = true;4112index = index | (layout << 24);4113}4114}4115// Subpixel X-shift, bits 27, 284116if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {4117int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));4118index = index | (xshift << 27);4119} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {4120int xshift = (int)(Math::floor(2 * (p_pos.x + 0.25)) - 2 * Math::floor(p_pos.x + 0.25));4121index = index | (xshift << 27);4122}4123}4124#endif41254126FontGlyph fgl;4127if (!_ensure_glyph(fd, size, index, fgl, viewport_oversampling ? 64 * oversampling_factor : 0)) {4128return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.4129}41304131if (fgl.found) {4132ERR_FAIL_COND(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size());41334134if (fgl.texture_idx != -1) {4135Color modulate = p_color;4136#ifdef MODULE_FREETYPE_ENABLED4137if (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) {4138modulate.r = modulate.g = modulate.b = 1.0;4139}4140#endif4141if (RenderingServer::get_singleton() != nullptr) {4142if (ffsd->textures[fgl.texture_idx].dirty) {4143ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];4144Ref<Image> img = tex.image;4145if (fd->mipmaps && !img->has_mipmaps()) {4146img = tex.image->duplicate();4147img->generate_mipmaps();4148}4149if (tex.texture.is_null()) {4150tex.texture = ImageTexture::create_from_image(img);4151} else {4152tex.texture->update(img);4153}4154tex.dirty = false;4155}4156RID texture = ffsd->textures[fgl.texture_idx].texture->get_rid();4157if (fd->msdf) {4158Point2 cpos = p_pos;4159cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size;4160Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size;4161RenderingServer::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);4162} else {4163Point2 cpos = p_pos;4164double scale = _font_get_scale(p_font_rid, p_size) / oversampling_factor;4165if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {4166cpos.x = cpos.x + 0.125;4167} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {4168cpos.x = cpos.x + 0.25;4169}4170if (scale == 1.0) {4171cpos.y = Math::floor(cpos.y);4172cpos.x = Math::floor(cpos.x);4173}4174Vector2 gpos = fgl.rect.position;4175Size2 csize = fgl.rect.size;4176if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE) {4177if (size.x != p_size * 64) {4178if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {4179double gl_scale = (double)p_size / (double)fd->fixed_size;4180gpos *= gl_scale;4181csize *= gl_scale;4182} else {4183double gl_scale = Math::round((double)p_size / (double)fd->fixed_size);4184gpos *= gl_scale;4185csize *= gl_scale;4186}4187}4188} else {4189gpos /= oversampling_factor;4190csize /= oversampling_factor;4191}4192cpos += gpos;4193if (lcd_aa) {4194RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate);4195} else {4196RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false);4197}4198}4199}4200}4201}4202}42034204bool TextServerAdvanced::_font_is_language_supported(const RID &p_font_rid, const String &p_language) const {4205FontAdvanced *fd = _get_font_data(p_font_rid);4206ERR_FAIL_NULL_V(fd, false);42074208MutexLock lock(fd->mutex);4209if (fd->language_support_overrides.has(p_language)) {4210return fd->language_support_overrides[p_language];4211} else {4212return true;4213}4214}42154216void TextServerAdvanced::_font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) {4217FontAdvanced *fd = _get_font_data(p_font_rid);4218ERR_FAIL_NULL(fd);42194220MutexLock lock(fd->mutex);4221fd->language_support_overrides[p_language] = p_supported;4222}42234224bool TextServerAdvanced::_font_get_language_support_override(const RID &p_font_rid, const String &p_language) {4225FontAdvanced *fd = _get_font_data(p_font_rid);4226ERR_FAIL_NULL_V(fd, false);42274228MutexLock lock(fd->mutex);4229return fd->language_support_overrides[p_language];4230}42314232void TextServerAdvanced::_font_remove_language_support_override(const RID &p_font_rid, const String &p_language) {4233FontAdvanced *fd = _get_font_data(p_font_rid);4234ERR_FAIL_NULL(fd);42354236MutexLock lock(fd->mutex);4237fd->language_support_overrides.erase(p_language);4238}42394240PackedStringArray TextServerAdvanced::_font_get_language_support_overrides(const RID &p_font_rid) {4241FontAdvanced *fd = _get_font_data(p_font_rid);4242ERR_FAIL_NULL_V(fd, PackedStringArray());42434244MutexLock lock(fd->mutex);4245PackedStringArray out;4246for (const KeyValue<String, bool> &E : fd->language_support_overrides) {4247out.push_back(E.key);4248}4249return out;4250}42514252bool TextServerAdvanced::_font_is_script_supported(const RID &p_font_rid, const String &p_script) const {4253FontAdvanced *fd = _get_font_data(p_font_rid);4254ERR_FAIL_NULL_V(fd, false);42554256MutexLock lock(fd->mutex);4257if (fd->script_support_overrides.has(p_script)) {4258return fd->script_support_overrides[p_script];4259} else {4260Vector2i size = _get_size(fd, 16);4261FontForSizeAdvanced *ffsd = nullptr;4262ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), false);4263return fd->supported_scripts.has(hb_tag_from_string(p_script.ascii().get_data(), -1));4264}4265}42664267void TextServerAdvanced::_font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) {4268FontAdvanced *fd = _get_font_data(p_font_rid);4269ERR_FAIL_NULL(fd);42704271MutexLock lock(fd->mutex);4272fd->script_support_overrides[p_script] = p_supported;4273}42744275bool TextServerAdvanced::_font_get_script_support_override(const RID &p_font_rid, const String &p_script) {4276FontAdvanced *fd = _get_font_data(p_font_rid);4277ERR_FAIL_NULL_V(fd, false);42784279MutexLock lock(fd->mutex);4280return fd->script_support_overrides[p_script];4281}42824283void TextServerAdvanced::_font_remove_script_support_override(const RID &p_font_rid, const String &p_script) {4284FontAdvanced *fd = _get_font_data(p_font_rid);4285ERR_FAIL_NULL(fd);42864287MutexLock lock(fd->mutex);4288fd->script_support_overrides.erase(p_script);4289}42904291PackedStringArray TextServerAdvanced::_font_get_script_support_overrides(const RID &p_font_rid) {4292FontAdvanced *fd = _get_font_data(p_font_rid);4293ERR_FAIL_NULL_V(fd, PackedStringArray());42944295MutexLock lock(fd->mutex);4296PackedStringArray out;4297for (const KeyValue<String, bool> &E : fd->script_support_overrides) {4298out.push_back(E.key);4299}4300return out;4301}43024303void TextServerAdvanced::_font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) {4304FontAdvanced *fd = _get_font_data(p_font_rid);4305ERR_FAIL_NULL(fd);43064307MutexLock lock(fd->mutex);4308Vector2i size = _get_size(fd, 16);4309FontForSizeAdvanced *ffsd = nullptr;4310ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));4311fd->feature_overrides = p_overrides;4312}43134314Dictionary TextServerAdvanced::_font_get_opentype_feature_overrides(const RID &p_font_rid) const {4315FontAdvanced *fd = _get_font_data(p_font_rid);4316ERR_FAIL_NULL_V(fd, Dictionary());43174318MutexLock lock(fd->mutex);4319return fd->feature_overrides;4320}43214322Dictionary TextServerAdvanced::_font_supported_feature_list(const RID &p_font_rid) const {4323FontAdvanced *fd = _get_font_data(p_font_rid);4324ERR_FAIL_NULL_V(fd, Dictionary());43254326MutexLock lock(fd->mutex);4327Vector2i size = _get_size(fd, 16);4328FontForSizeAdvanced *ffsd = nullptr;4329ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary());4330return fd->supported_features;4331}43324333Dictionary TextServerAdvanced::_font_supported_variation_list(const RID &p_font_rid) const {4334FontAdvanced *fd = _get_font_data(p_font_rid);4335ERR_FAIL_NULL_V(fd, Dictionary());43364337MutexLock lock(fd->mutex);4338Vector2i size = _get_size(fd, 16);4339FontForSizeAdvanced *ffsd = nullptr;4340ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary());4341return fd->supported_varaitions;4342}43434344/*************************************************************************/4345/* Shaped text buffer interface */4346/*************************************************************************/43474348int64_t TextServerAdvanced::_convert_pos(const String &p_utf32, const Char16String &p_utf16, int64_t p_pos) const {4349int64_t limit = p_pos;4350if (p_utf32.length() != p_utf16.length()) {4351const UChar *data = p_utf16.get_data();4352for (int i = 0; i < p_pos; i++) {4353if (U16_IS_LEAD(data[i])) {4354limit--;4355}4356}4357}4358return limit;4359}43604361int64_t TextServerAdvanced::_convert_pos(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const {4362int64_t limit = p_pos;4363if (p_sd->text.length() != p_sd->utf16.length()) {4364const UChar *data = p_sd->utf16.get_data();4365for (int i = 0; i < p_pos; i++) {4366if (U16_IS_LEAD(data[i])) {4367limit--;4368}4369}4370}4371return limit;4372}43734374int64_t TextServerAdvanced::_convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const {4375int64_t limit = p_pos;4376if (p_sd->text.length() != p_sd->utf16.length()) {4377for (int i = 0; i < p_pos; i++) {4378if (p_sd->text[i] > 0xffff) {4379limit++;4380}4381}4382}4383return limit;4384}43854386void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *p_shaped, bool p_text) {4387p_shaped->valid.clear();4388p_shaped->sort_valid = false;4389p_shaped->line_breaks_valid = false;4390p_shaped->justification_ops_valid = false;4391p_shaped->text_trimmed = false;4392p_shaped->ascent = 0.0;4393p_shaped->descent = 0.0;4394p_shaped->width = 0.0;4395p_shaped->upos = 0.0;4396p_shaped->uthk = 0.0;4397p_shaped->glyphs.clear();4398p_shaped->glyphs_logical.clear();4399p_shaped->runs.clear();4400p_shaped->runs_dirty = true;4401p_shaped->overrun_trim_data = TrimData();4402p_shaped->utf16 = Char16String();4403for (int i = 0; i < p_shaped->bidi_iter.size(); i++) {4404ubidi_close(p_shaped->bidi_iter[i]);4405}4406p_shaped->bidi_iter.clear();44074408if (p_text) {4409if (p_shaped->script_iter != nullptr) {4410memdelete(p_shaped->script_iter);4411p_shaped->script_iter = nullptr;4412}4413p_shaped->break_ops_valid = false;4414p_shaped->chars_valid = false;4415p_shaped->js_ops_valid = false;4416}4417}44184419void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) {4420ShapedTextDataAdvanced *parent = shaped_owner.get_or_null(p_shaped->parent);44214422for (const KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : parent->objects) {4423if (E.value.start >= p_shaped->start && E.value.start < p_shaped->end) {4424p_shaped->objects[E.key] = E.value;4425}4426}44274428for (int i = p_shaped->first_span; i <= p_shaped->last_span; i++) {4429ShapedTextDataAdvanced::Span span = parent->spans[i];4430span.start = MAX(p_shaped->start, span.start);4431span.end = MIN(p_shaped->end, span.end);4432p_shaped->spans.push_back(span);4433}4434p_shaped->first_span = 0;4435p_shaped->last_span = 0;44364437p_shaped->parent = RID();4438}44394440RID TextServerAdvanced::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {4441_THREAD_SAFE_METHOD_4442ERR_FAIL_COND_V_MSG(p_direction == DIRECTION_INHERITED, RID(), "Invalid text direction.");44434444ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced);4445sd->hb_buffer = hb_buffer_create();4446sd->direction = p_direction;4447sd->orientation = p_orientation;4448return shaped_owner.make_rid(sd);4449}44504451void TextServerAdvanced::_shaped_text_clear(const RID &p_shaped) {4452ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4453ERR_FAIL_NULL(sd);44544455MutexLock lock(sd->mutex);4456sd->parent = RID();4457sd->start = 0;4458sd->end = 0;4459sd->text = String();4460sd->spans.clear();4461sd->first_span = 0;4462sd->last_span = 0;4463sd->objects.clear();4464sd->bidi_override.clear();4465invalidate(sd, true);4466}44674468void TextServerAdvanced::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {4469ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4470ERR_FAIL_COND_MSG(p_direction == DIRECTION_INHERITED, "Invalid text direction.");4471ERR_FAIL_NULL(sd);44724473MutexLock lock(sd->mutex);4474if (sd->direction != p_direction) {4475if (sd->parent != RID()) {4476full_copy(sd);4477}4478sd->direction = p_direction;4479invalidate(sd, false);4480}4481}44824483TextServer::Direction TextServerAdvanced::_shaped_text_get_direction(const RID &p_shaped) const {4484const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4485ERR_FAIL_NULL_V(sd, TextServer::DIRECTION_LTR);44864487MutexLock lock(sd->mutex);4488return sd->direction;4489}44904491TextServer::Direction TextServerAdvanced::_shaped_text_get_inferred_direction(const RID &p_shaped) const {4492const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4493ERR_FAIL_NULL_V(sd, TextServer::DIRECTION_LTR);44944495MutexLock lock(sd->mutex);4496return sd->para_direction;4497}44984499void TextServerAdvanced::_shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) {4500_THREAD_SAFE_METHOD_4501ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4502ERR_FAIL_NULL(sd);45034504if (sd->custom_punct != p_punct) {4505if (sd->parent != RID()) {4506full_copy(sd);4507}4508sd->custom_punct = p_punct;4509invalidate(sd, false);4510}4511}45124513String TextServerAdvanced::_shaped_text_get_custom_punctuation(const RID &p_shaped) const {4514_THREAD_SAFE_METHOD_4515const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4516ERR_FAIL_NULL_V(sd, String());4517return sd->custom_punct;4518}45194520void TextServerAdvanced::_shaped_text_set_custom_ellipsis(const RID &p_shaped, int64_t p_char) {4521_THREAD_SAFE_METHOD_4522ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4523ERR_FAIL_NULL(sd);4524sd->el_char = p_char;4525}45264527int64_t TextServerAdvanced::_shaped_text_get_custom_ellipsis(const RID &p_shaped) const {4528_THREAD_SAFE_METHOD_4529const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4530ERR_FAIL_NULL_V(sd, 0);4531return sd->el_char;4532}45334534void TextServerAdvanced::_shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) {4535ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4536ERR_FAIL_NULL(sd);45374538MutexLock lock(sd->mutex);4539if (sd->parent != RID()) {4540full_copy(sd);4541}4542sd->bidi_override.clear();4543for (int i = 0; i < p_override.size(); i++) {4544if (p_override[i].get_type() == Variant::VECTOR3I) {4545const Vector3i &r = p_override[i];4546sd->bidi_override.push_back(r);4547} else if (p_override[i].get_type() == Variant::VECTOR2I) {4548const Vector2i &r = p_override[i];4549sd->bidi_override.push_back(Vector3i(r.x, r.y, DIRECTION_INHERITED));4550}4551}4552invalidate(sd, false);4553}45544555void TextServerAdvanced::_shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) {4556ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4557ERR_FAIL_NULL(sd);45584559MutexLock lock(sd->mutex);4560if (sd->orientation != p_orientation) {4561if (sd->parent != RID()) {4562full_copy(sd);4563}4564sd->orientation = p_orientation;4565invalidate(sd, false);4566}4567}45684569void TextServerAdvanced::_shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) {4570ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4571ERR_FAIL_NULL(sd);45724573MutexLock lock(sd->mutex);4574ERR_FAIL_COND(sd->parent != RID());4575if (sd->preserve_invalid != p_enabled) {4576sd->preserve_invalid = p_enabled;4577invalidate(sd, false);4578}4579}45804581bool TextServerAdvanced::_shaped_text_get_preserve_invalid(const RID &p_shaped) const {4582const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4583ERR_FAIL_NULL_V(sd, false);45844585MutexLock lock(sd->mutex);4586return sd->preserve_invalid;4587}45884589void TextServerAdvanced::_shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) {4590ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4591ERR_FAIL_NULL(sd);45924593MutexLock lock(sd->mutex);4594if (sd->preserve_control != p_enabled) {4595if (sd->parent != RID()) {4596full_copy(sd);4597}4598sd->preserve_control = p_enabled;4599invalidate(sd, false);4600}4601}46024603bool TextServerAdvanced::_shaped_text_get_preserve_control(const RID &p_shaped) const {4604const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4605ERR_FAIL_NULL_V(sd, false);46064607MutexLock lock(sd->mutex);4608return sd->preserve_control;4609}46104611void TextServerAdvanced::_shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) {4612ERR_FAIL_INDEX((int)p_spacing, 4);4613ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4614ERR_FAIL_NULL(sd);46154616MutexLock lock(sd->mutex);4617if (sd->extra_spacing[p_spacing] != p_value) {4618if (sd->parent != RID()) {4619full_copy(sd);4620}4621sd->extra_spacing[p_spacing] = p_value;4622invalidate(sd, false);4623}4624}46254626int64_t TextServerAdvanced::_shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const {4627ERR_FAIL_INDEX_V((int)p_spacing, 4, 0);46284629const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4630ERR_FAIL_NULL_V(sd, 0);46314632MutexLock lock(sd->mutex);4633return sd->extra_spacing[p_spacing];4634}46354636TextServer::Orientation TextServerAdvanced::_shaped_text_get_orientation(const RID &p_shaped) const {4637const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4638ERR_FAIL_NULL_V(sd, TextServer::ORIENTATION_HORIZONTAL);46394640MutexLock lock(sd->mutex);4641return sd->orientation;4642}46434644int64_t TextServerAdvanced::_shaped_get_span_count(const RID &p_shaped) const {4645ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4646ERR_FAIL_NULL_V(sd, 0);46474648if (sd->parent != RID()) {4649return sd->last_span - sd->first_span + 1;4650} else {4651return sd->spans.size();4652}4653}46544655Variant TextServerAdvanced::_shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const {4656ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4657ERR_FAIL_NULL_V(sd, Variant());4658if (sd->parent != RID()) {4659ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);4660ERR_FAIL_COND_V(!parent_sd->valid.is_set(), Variant());4661ERR_FAIL_INDEX_V(p_index + sd->first_span, parent_sd->spans.size(), Variant());4662return parent_sd->spans[p_index + sd->first_span].meta;4663} else {4664ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant());4665return sd->spans[p_index].meta;4666}4667}46684669Variant TextServerAdvanced::_shaped_get_span_embedded_object(const RID &p_shaped, int64_t p_index) const {4670ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4671ERR_FAIL_NULL_V(sd, Variant());4672if (sd->parent != RID()) {4673ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);4674ERR_FAIL_COND_V(!parent_sd->valid.is_set(), Variant());4675ERR_FAIL_INDEX_V(p_index + sd->first_span, parent_sd->spans.size(), Variant());4676return parent_sd->spans[p_index + sd->first_span].embedded_key;4677} else {4678ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant());4679return sd->spans[p_index].embedded_key;4680}4681}46824683String TextServerAdvanced::_shaped_get_span_text(const RID &p_shaped, int64_t p_index) const {4684ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4685ERR_FAIL_NULL_V(sd, String());4686ShapedTextDataAdvanced *span_sd = sd;4687if (sd->parent.is_valid()) {4688span_sd = shaped_owner.get_or_null(sd->parent);4689ERR_FAIL_NULL_V(span_sd, String());4690}4691ERR_FAIL_INDEX_V(p_index, span_sd->spans.size(), String());4692return span_sd->text.substr(span_sd->spans[p_index].start, span_sd->spans[p_index].end - span_sd->spans[p_index].start);4693}46944695Variant TextServerAdvanced::_shaped_get_span_object(const RID &p_shaped, int64_t p_index) const {4696ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4697ERR_FAIL_NULL_V(sd, Variant());4698ShapedTextDataAdvanced *span_sd = sd;4699if (sd->parent.is_valid()) {4700span_sd = shaped_owner.get_or_null(sd->parent);4701ERR_FAIL_NULL_V(span_sd, Variant());4702}4703ERR_FAIL_INDEX_V(p_index, span_sd->spans.size(), Variant());4704return span_sd->spans[p_index].embedded_key;4705}47064707void TextServerAdvanced::_generate_runs(ShapedTextDataAdvanced *p_sd) const {4708ERR_FAIL_NULL(p_sd);4709p_sd->runs.clear();47104711ShapedTextDataAdvanced *span_sd = p_sd;4712if (p_sd->parent.is_valid()) {4713span_sd = shaped_owner.get_or_null(p_sd->parent);4714ERR_FAIL_NULL(span_sd);4715}47164717int sd_size = p_sd->glyphs.size();4718const Glyph *sd_gl = p_sd->glyphs.ptr();47194720int span_count = span_sd->spans.size();4721int span = -1;4722int span_start = -1;4723int span_end = -1;47244725TextRun run;4726for (int i = 0; i < sd_size; i += sd_gl[i].count) {4727const Glyph &gl = sd_gl[i];4728if (gl.start < 0 || gl.end < 0) {4729continue;4730}4731if (gl.start < span_start || gl.start >= span_end) {4732span = -1;4733span_start = -1;4734span_end = -1;4735for (int j = 0; j < span_count; j++) {4736if (gl.start >= span_sd->spans[j].start && gl.end <= span_sd->spans[j].end) {4737span = j;4738span_start = span_sd->spans[j].start;4739span_end = span_sd->spans[j].end;4740break;4741}4742}4743}4744if (run.font_rid != gl.font_rid || run.font_size != gl.font_size || run.span_index != span || run.rtl != bool(gl.flags & GRAPHEME_IS_RTL)) {4745if (run.span_index >= 0) {4746p_sd->runs.push_back(run);4747}4748run.range = Vector2i(gl.start, gl.end);4749run.font_rid = gl.font_rid;4750run.font_size = gl.font_size;4751run.rtl = bool(gl.flags & GRAPHEME_IS_RTL);4752run.span_index = span;4753}4754run.range.x = MIN(run.range.x, gl.start);4755run.range.y = MAX(run.range.y, gl.end);4756}4757if (run.span_index >= 0) {4758p_sd->runs.push_back(run);4759}4760p_sd->runs_dirty = false;4761}47624763int64_t TextServerAdvanced::_shaped_get_run_count(const RID &p_shaped) const {4764ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4765ERR_FAIL_NULL_V(sd, 0);4766MutexLock lock(sd->mutex);4767if (!sd->valid.is_set()) {4768const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4769}4770if (sd->runs_dirty) {4771_generate_runs(sd);4772}4773return sd->runs.size();4774}47754776String TextServerAdvanced::_shaped_get_run_text(const RID &p_shaped, int64_t p_index) const {4777ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4778ERR_FAIL_NULL_V(sd, String());4779MutexLock lock(sd->mutex);4780if (!sd->valid.is_set()) {4781const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4782}4783if (sd->runs_dirty) {4784_generate_runs(sd);4785}4786ERR_FAIL_INDEX_V(p_index, sd->runs.size(), String());4787return sd->text.substr(sd->runs[p_index].range.x - sd->start, sd->runs[p_index].range.y - sd->runs[p_index].range.x);4788}47894790Vector2i TextServerAdvanced::_shaped_get_run_range(const RID &p_shaped, int64_t p_index) const {4791ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4792ERR_FAIL_NULL_V(sd, Vector2i());4793MutexLock lock(sd->mutex);4794if (!sd->valid.is_set()) {4795const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4796}4797if (sd->runs_dirty) {4798_generate_runs(sd);4799}4800ERR_FAIL_INDEX_V(p_index, sd->runs.size(), Vector2i());4801return sd->runs[p_index].range;4802}48034804RID TextServerAdvanced::_shaped_get_run_font_rid(const RID &p_shaped, int64_t p_index) const {4805ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4806ERR_FAIL_NULL_V(sd, RID());4807MutexLock lock(sd->mutex);4808if (!sd->valid.is_set()) {4809const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4810}4811if (sd->runs_dirty) {4812_generate_runs(sd);4813}4814ERR_FAIL_INDEX_V(p_index, sd->runs.size(), RID());4815return sd->runs[p_index].font_rid;4816}48174818int TextServerAdvanced::_shaped_get_run_font_size(const RID &p_shaped, int64_t p_index) const {4819ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4820ERR_FAIL_NULL_V(sd, 0);4821MutexLock lock(sd->mutex);4822if (!sd->valid.is_set()) {4823const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4824}4825if (sd->runs_dirty) {4826_generate_runs(sd);4827}4828ERR_FAIL_INDEX_V(p_index, sd->runs.size(), 0);4829return sd->runs[p_index].font_size;4830}48314832String TextServerAdvanced::_shaped_get_run_language(const RID &p_shaped, int64_t p_index) const {4833ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4834ERR_FAIL_NULL_V(sd, String());4835MutexLock lock(sd->mutex);4836if (!sd->valid.is_set()) {4837const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4838}4839if (sd->runs_dirty) {4840_generate_runs(sd);4841}4842ERR_FAIL_INDEX_V(p_index, sd->runs.size(), String());48434844int span_idx = sd->runs[p_index].span_index;4845ShapedTextDataAdvanced *span_sd = sd;4846if (sd->parent.is_valid()) {4847span_sd = shaped_owner.get_or_null(sd->parent);4848ERR_FAIL_NULL_V(span_sd, String());4849}4850ERR_FAIL_INDEX_V(span_idx, span_sd->spans.size(), String());4851return span_sd->spans[span_idx].language;4852}48534854TextServer::Direction TextServerAdvanced::_shaped_get_run_direction(const RID &p_shaped, int64_t p_index) const {4855ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4856ERR_FAIL_NULL_V(sd, TextServer::DIRECTION_LTR);4857MutexLock lock(sd->mutex);4858if (!sd->valid.is_set()) {4859const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4860}4861if (sd->runs_dirty) {4862_generate_runs(sd);4863}4864ERR_FAIL_INDEX_V(p_index, sd->runs.size(), TextServer::DIRECTION_LTR);4865return sd->runs[p_index].rtl ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR;4866}48674868Variant TextServerAdvanced::_shaped_get_run_object(const RID &p_shaped, int64_t p_index) const {4869ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4870ERR_FAIL_NULL_V(sd, Variant());4871MutexLock lock(sd->mutex);4872if (!sd->valid.is_set()) {4873const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4874}4875if (sd->runs_dirty) {4876_generate_runs(sd);4877}4878ERR_FAIL_INDEX_V(p_index, sd->runs.size(), Variant());48794880int span_idx = sd->runs[p_index].span_index;4881ShapedTextDataAdvanced *span_sd = sd;4882if (sd->parent.is_valid()) {4883span_sd = shaped_owner.get_or_null(sd->parent);4884ERR_FAIL_NULL_V(span_sd, Variant());4885}4886ERR_FAIL_INDEX_V(span_idx, span_sd->spans.size(), Variant());4887return span_sd->spans[span_idx].embedded_key;4888}48894890void 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) {4891ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4892ERR_FAIL_NULL(sd);4893if (sd->parent != RID()) {4894full_copy(sd);4895}4896ERR_FAIL_INDEX(p_index, sd->spans.size());48974898ShapedTextDataAdvanced::Span &span = sd->spans.ptrw()[p_index];4899span.fonts = p_fonts;4900span.font_size = p_size;4901span.features = p_opentype_features;49024903invalidate(sd, false);4904}49054906bool 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) {4907ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4908ERR_FAIL_NULL_V(sd, false);4909ERR_FAIL_COND_V(p_size <= 0, false);49104911MutexLock lock(sd->mutex);4912for (int i = 0; i < p_fonts.size(); i++) {4913ERR_FAIL_NULL_V(_get_font_data(p_fonts[i]), false);4914}49154916if (p_text.is_empty()) {4917return true;4918}49194920if (sd->parent != RID()) {4921full_copy(sd);4922}49234924ShapedTextDataAdvanced::Span span;4925span.start = sd->text.length();4926span.end = span.start + p_text.length();4927span.fonts = p_fonts; // Do not pre-sort, spans will be divided to subruns later.4928span.font_size = p_size;4929span.language = p_language;4930span.features = p_opentype_features;4931span.meta = p_meta;49324933sd->spans.push_back(span);4934sd->text = sd->text + p_text;4935sd->end += p_text.length();4936invalidate(sd, true);49374938return true;4939}49404941bool 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) {4942_THREAD_SAFE_METHOD_4943ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4944ERR_FAIL_NULL_V(sd, false);4945ERR_FAIL_COND_V(p_key == Variant(), false);4946ERR_FAIL_COND_V(sd->objects.has(p_key), false);49474948if (sd->parent != RID()) {4949full_copy(sd);4950}49514952ShapedTextDataAdvanced::Span span;4953span.start = sd->start + sd->text.length();4954span.end = span.start + p_length;4955span.embedded_key = p_key;49564957ShapedTextDataAdvanced::EmbeddedObject obj;4958obj.inline_align = p_inline_align;4959obj.rect.size = p_size;4960obj.start = span.start;4961obj.end = span.end;4962obj.baseline = p_baseline;49634964sd->spans.push_back(span);4965sd->text = sd->text + String::chr(0xfffc).repeat(p_length);4966sd->end += p_length;4967sd->objects[p_key] = obj;4968invalidate(sd, true);49694970return true;4971}49724973String TextServerAdvanced::_shaped_get_text(const RID &p_shaped) const {4974const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4975ERR_FAIL_NULL_V(sd, String());49764977return sd->text;4978}49794980bool TextServerAdvanced::_shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, double p_baseline) {4981ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4982ERR_FAIL_NULL_V(sd, false);49834984MutexLock lock(sd->mutex);4985ERR_FAIL_COND_V(!sd->objects.has(p_key), false);4986sd->objects[p_key].rect.size = p_size;4987sd->objects[p_key].inline_align = p_inline_align;4988sd->objects[p_key].baseline = p_baseline;4989if (sd->valid.is_set()) {4990// Recalc string metrics.4991sd->ascent = 0;4992sd->descent = 0;4993sd->width = 0;4994sd->upos = 0;4995sd->uthk = 0;49964997Vector<ShapedTextDataAdvanced::Span> &spans = sd->spans;4998if (sd->parent != RID()) {4999ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);5000ERR_FAIL_COND_V(!parent_sd->valid.is_set(), false);5001spans = parent_sd->spans;5002}50035004int sd_size = sd->glyphs.size();5005int span_size = spans.size();5006const char32_t *ch = sd->text.ptr();50075008for (int i = 0; i < sd_size; i++) {5009Glyph gl = sd->glyphs[i];5010Variant key;5011if ((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) {5012key = spans[gl.span_index + sd->first_span].embedded_key;5013}5014if (key != Variant()) {5015if (sd->orientation == ORIENTATION_HORIZONTAL) {5016sd->objects[key].rect.position.x = sd->width;5017sd->width += sd->objects[key].rect.size.x;5018sd->glyphs[i].advance = sd->objects[key].rect.size.x;5019} else {5020sd->objects[key].rect.position.y = sd->width;5021sd->width += sd->objects[key].rect.size.y;5022sd->glyphs[i].advance = sd->objects[key].rect.size.y;5023}5024} else {5025if (gl.font_rid.is_valid()) {5026if (sd->orientation == ORIENTATION_HORIZONTAL) {5027sd->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));5028sd->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));5029} else {5030sd->ascent = MAX(sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));5031sd->descent = MAX(sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));5032}5033sd->upos = MAX(sd->upos, _font_get_underline_position(gl.font_rid, gl.font_size));5034sd->uthk = MAX(sd->uthk, _font_get_underline_thickness(gl.font_rid, gl.font_size));5035} else if (sd->preserve_invalid || (sd->preserve_control && is_control(ch[gl.start - sd->start]))) {5036// Glyph not found, replace with hex code box.5037if (sd->orientation == ORIENTATION_HORIZONTAL) {5038sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.85);5039sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.15);5040} else {5041sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));5042sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));5043}5044}5045sd->width += gl.advance * gl.repeat;5046}5047}5048sd->sort_valid = false;5049sd->glyphs_logical.clear();5050_realign(sd);5051}5052return true;5053}50545055void TextServerAdvanced::_realign(ShapedTextDataAdvanced *p_sd) const {5056// Align embedded objects to baseline.5057double full_ascent = p_sd->ascent;5058double full_descent = p_sd->descent;5059for (KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : p_sd->objects) {5060if ((E.value.start >= p_sd->start) && (E.value.start < p_sd->end)) {5061if (p_sd->orientation == ORIENTATION_HORIZONTAL) {5062switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {5063case INLINE_ALIGNMENT_TO_TOP: {5064E.value.rect.position.y = -p_sd->ascent;5065} break;5066case INLINE_ALIGNMENT_TO_CENTER: {5067E.value.rect.position.y = (-p_sd->ascent + p_sd->descent) / 2;5068} break;5069case INLINE_ALIGNMENT_TO_BASELINE: {5070E.value.rect.position.y = 0;5071} break;5072case INLINE_ALIGNMENT_TO_BOTTOM: {5073E.value.rect.position.y = p_sd->descent;5074} break;5075}5076switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {5077case INLINE_ALIGNMENT_BOTTOM_TO: {5078E.value.rect.position.y -= E.value.rect.size.y;5079} break;5080case INLINE_ALIGNMENT_CENTER_TO: {5081E.value.rect.position.y -= E.value.rect.size.y / 2;5082} break;5083case INLINE_ALIGNMENT_BASELINE_TO: {5084E.value.rect.position.y -= E.value.baseline;5085} break;5086case INLINE_ALIGNMENT_TOP_TO: {5087// NOP5088} break;5089}5090full_ascent = MAX(full_ascent, -E.value.rect.position.y);5091full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y);5092} else {5093switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {5094case INLINE_ALIGNMENT_TO_TOP: {5095E.value.rect.position.x = -p_sd->ascent;5096} break;5097case INLINE_ALIGNMENT_TO_CENTER: {5098E.value.rect.position.x = (-p_sd->ascent + p_sd->descent) / 2;5099} break;5100case INLINE_ALIGNMENT_TO_BASELINE: {5101E.value.rect.position.x = 0;5102} break;5103case INLINE_ALIGNMENT_TO_BOTTOM: {5104E.value.rect.position.x = p_sd->descent;5105} break;5106}5107switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {5108case INLINE_ALIGNMENT_BOTTOM_TO: {5109E.value.rect.position.x -= E.value.rect.size.x;5110} break;5111case INLINE_ALIGNMENT_CENTER_TO: {5112E.value.rect.position.x -= E.value.rect.size.x / 2;5113} break;5114case INLINE_ALIGNMENT_BASELINE_TO: {5115E.value.rect.position.x -= E.value.baseline;5116} break;5117case INLINE_ALIGNMENT_TOP_TO: {5118// NOP5119} break;5120}5121full_ascent = MAX(full_ascent, -E.value.rect.position.x);5122full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x);5123}5124}5125}5126p_sd->ascent = full_ascent;5127p_sd->descent = full_descent;5128}51295130RID TextServerAdvanced::_shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {5131_THREAD_SAFE_METHOD_5132const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5133ERR_FAIL_NULL_V(sd, RID());51345135MutexLock lock(sd->mutex);5136if (sd->parent != RID()) {5137return _shaped_text_substr(sd->parent, p_start, p_length);5138}5139if (!sd->valid.is_set()) {5140const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);5141}5142ERR_FAIL_COND_V(p_start < 0 || p_length < 0, RID());5143ERR_FAIL_COND_V(sd->start > p_start || sd->end < p_start, RID());5144ERR_FAIL_COND_V(sd->end < p_start + p_length, RID());51455146ShapedTextDataAdvanced *new_sd = memnew(ShapedTextDataAdvanced);5147new_sd->parent = p_shaped;5148new_sd->start = p_start;5149new_sd->end = p_start + p_length;5150new_sd->orientation = sd->orientation;5151new_sd->direction = sd->direction;5152new_sd->custom_punct = sd->custom_punct;5153new_sd->para_direction = sd->para_direction;5154new_sd->base_para_direction = sd->base_para_direction;5155for (int i = 0; i < TextServer::SPACING_MAX; i++) {5156new_sd->extra_spacing[i] = sd->extra_spacing[i];5157}51585159if (!_shape_substr(new_sd, sd, p_start, p_length)) {5160memdelete(new_sd);5161return RID();5162}5163return shaped_owner.make_rid(new_sd);5164}51655166bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_length) const {5167if (p_new_sd->valid.is_set()) {5168return true;5169}51705171p_new_sd->hb_buffer = hb_buffer_create();51725173p_new_sd->line_breaks_valid = p_sd->line_breaks_valid;5174p_new_sd->justification_ops_valid = p_sd->justification_ops_valid;5175p_new_sd->sort_valid = false;5176p_new_sd->upos = p_sd->upos;5177p_new_sd->uthk = p_sd->uthk;5178p_new_sd->runs.clear();5179p_new_sd->runs_dirty = true;51805181if (p_length > 0) {5182p_new_sd->text = p_sd->text.substr(p_start - p_sd->start, p_length);5183p_new_sd->utf16 = p_new_sd->text.utf16();5184p_new_sd->script_iter = memnew(ScriptIterator(p_new_sd->text, 0, p_new_sd->text.length()));51855186int span_size = p_sd->spans.size();51875188p_new_sd->first_span = 0;5189p_new_sd->last_span = span_size - 1;5190for (int i = 0; i < span_size; i++) {5191const ShapedTextDataAdvanced::Span &span = p_sd->spans[i];5192if (span.end <= p_start) {5193p_new_sd->first_span = i + 1;5194} else if (span.start >= p_start + p_length) {5195p_new_sd->last_span = i - 1;5196break;5197}5198}51995200Vector<Vector3i> bidi_ranges;5201if (p_sd->bidi_override.is_empty()) {5202bidi_ranges.push_back(Vector3i(p_sd->start, p_sd->end, DIRECTION_INHERITED));5203} else {5204bidi_ranges = p_sd->bidi_override;5205}52065207int sd_size = p_sd->glyphs.size();5208const Glyph *sd_glyphs = p_sd->glyphs.ptr();5209const char32_t *ch = p_sd->text.ptr();5210for (int ov = 0; ov < bidi_ranges.size(); ov++) {5211UErrorCode err = U_ZERO_ERROR;52125213if (bidi_ranges[ov].x >= p_start + p_length || bidi_ranges[ov].y <= p_start) {5214continue;5215}5216int ov_start = _convert_pos_inv(p_sd, bidi_ranges[ov].x);5217int start = MAX(0, _convert_pos_inv(p_sd, p_start) - ov_start);5218int end = MIN(_convert_pos_inv(p_sd, p_start + p_length), _convert_pos_inv(p_sd, bidi_ranges[ov].y)) - ov_start;52195220ERR_FAIL_COND_V_MSG((start < 0 || end - start > p_new_sd->utf16.length()), false, "Invalid BiDi override range.");52215222// Create temporary line bidi & shape.5223UBiDi *bidi_iter = nullptr;5224if (p_sd->bidi_iter[ov]) {5225bidi_iter = ubidi_openSized(end - start, 0, &err);5226if (U_SUCCESS(err)) {5227ubidi_setLine(p_sd->bidi_iter[ov], start, end, bidi_iter, &err);5228if (U_FAILURE(err)) {5229// Line BiDi failed (string contains incompatible control characters), try full paragraph BiDi instead.5230err = U_ZERO_ERROR;5231const UChar *data = p_sd->utf16.get_data();5232switch (static_cast<TextServer::Direction>(bidi_ranges[ov].z)) {5233case DIRECTION_LTR: {5234ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err);5235} break;5236case DIRECTION_RTL: {5237ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err);5238} break;5239case DIRECTION_INHERITED: {5240ubidi_setPara(bidi_iter, data + start, end - start, p_sd->base_para_direction, nullptr, &err);5241} break;5242case DIRECTION_AUTO: {5243UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start);5244if (direction != UBIDI_NEUTRAL) {5245ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);5246} else {5247ubidi_setPara(bidi_iter, data + start, end - start, p_sd->base_para_direction, nullptr, &err);5248}5249} break;5250}5251if (U_FAILURE(err)) {5252ubidi_close(bidi_iter);5253bidi_iter = nullptr;5254ERR_PRINT(vformat("BiDi reordering for the line failed: %s", u_errorName(err)));5255}5256}5257} else {5258bidi_iter = nullptr;5259ERR_PRINT(vformat("BiDi iterator allocation for the line failed: %s", u_errorName(err)));5260}5261}5262p_new_sd->bidi_iter.push_back(bidi_iter);52635264err = U_ZERO_ERROR;5265int bidi_run_count = 1;5266if (bidi_iter) {5267bidi_run_count = ubidi_countRuns(bidi_iter, &err);5268if (U_FAILURE(err)) {5269ERR_PRINT(u_errorName(err));5270}5271}5272for (int i = 0; i < bidi_run_count; i++) {5273int32_t _bidi_run_start = 0;5274int32_t _bidi_run_length = end - start;5275if (bidi_iter) {5276ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length);5277}52785279int32_t bidi_run_start = _convert_pos(p_sd, ov_start + start + _bidi_run_start);5280int32_t bidi_run_end = _convert_pos(p_sd, ov_start + start + _bidi_run_start + _bidi_run_length);52815282for (int j = 0; j < sd_size; j++) {5283int col_key_off = (sd_glyphs[j].start == sd_glyphs[j].end) ? 1 : 0;5284if ((sd_glyphs[j].start >= bidi_run_start) && (sd_glyphs[j].end <= bidi_run_end - col_key_off)) {5285// Copy glyphs.5286Glyph gl = sd_glyphs[j];5287if (gl.span_index >= 0) {5288gl.span_index -= p_new_sd->first_span;5289}5290if (gl.end == p_start + p_length && ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) == GRAPHEME_IS_SOFT_HYPHEN)) {5291uint32_t index = font_get_glyph_index(gl.font_rid, gl.font_size, 0x00ad, 0);5292if (index == 0) { // Try other fonts in the span.5293const ShapedTextDataAdvanced::Span &span = p_sd->spans[gl.span_index + p_new_sd->first_span];5294for (int k = 0; k < span.fonts.size(); k++) {5295if (span.fonts[k] != gl.font_rid) {5296index = font_get_glyph_index(span.fonts[k], gl.font_size, 0x00ad, 0);5297if (index != 0) {5298gl.font_rid = span.fonts[k];5299break;5300}5301}5302}5303}5304if (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.5305const char32_t u32str[] = { 0x00ad, 0 };5306RID rid = const_cast<TextServerAdvanced *>(this)->_find_sys_font_for_text(gl.font_rid, String(), String(), u32str);5307if (rid.is_valid()) {5308index = font_get_glyph_index(rid, gl.font_size, 0x00ad, 0);5309if (index != 0) {5310gl.font_rid = rid;5311}5312}5313}5314float w = font_get_glyph_advance(gl.font_rid, gl.font_size, index)[(p_new_sd->orientation == ORIENTATION_HORIZONTAL) ? 0 : 1];5315gl.index = index;5316gl.advance = w;5317}5318if ((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) {5319Variant key = p_sd->spans[gl.span_index + p_new_sd->first_span].embedded_key;5320if (key != Variant()) {5321ShapedTextDataAdvanced::EmbeddedObject obj = p_sd->objects[key];5322if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {5323obj.rect.position.x = p_new_sd->width;5324p_new_sd->width += obj.rect.size.x;5325} else {5326obj.rect.position.y = p_new_sd->width;5327p_new_sd->width += obj.rect.size.y;5328}5329p_new_sd->objects[key] = obj;5330}5331} else {5332if (gl.font_rid.is_valid()) {5333if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {5334p_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));5335p_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));5336} else {5337p_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));5338p_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));5339}5340} else if (p_new_sd->preserve_invalid || (p_new_sd->preserve_control && is_control(ch[gl.start - p_sd->start]))) {5341// Glyph not found, replace with hex code box.5342if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {5343p_new_sd->ascent = MAX(p_new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.85);5344p_new_sd->descent = MAX(p_new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.15);5345} else {5346p_new_sd->ascent = MAX(p_new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));5347p_new_sd->descent = MAX(p_new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));5348}5349}5350p_new_sd->width += gl.advance * gl.repeat;5351}5352p_new_sd->glyphs.push_back(gl);5353}5354}5355}5356}53575358_realign(p_new_sd);5359}5360p_new_sd->valid.set();53615362return true;5363}53645365RID TextServerAdvanced::_shaped_text_get_parent(const RID &p_shaped) const {5366ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5367ERR_FAIL_NULL_V(sd, RID());53685369MutexLock lock(sd->mutex);5370return sd->parent;5371}53725373double TextServerAdvanced::_shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<TextServer::JustificationFlag> p_jst_flags) {5374ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5375ERR_FAIL_NULL_V(sd, 0.0);53765377MutexLock lock(sd->mutex);5378if (!sd->valid.is_set()) {5379_shaped_text_shape(p_shaped);5380}5381if (!sd->justification_ops_valid) {5382_shaped_text_update_justification_ops(p_shaped);5383}53845385sd->fit_width_minimum_reached = false;5386int start_pos = 0;5387int end_pos = sd->glyphs.size() - 1;53885389if (p_jst_flags.has_flag(JUSTIFICATION_AFTER_LAST_TAB)) {5390int start, end, delta;5391if (sd->para_direction == DIRECTION_LTR) {5392start = sd->glyphs.size() - 1;5393end = -1;5394delta = -1;5395} else {5396start = 0;5397end = sd->glyphs.size();5398delta = +1;5399}54005401for (int i = start; i != end; i += delta) {5402if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {5403if (sd->para_direction == DIRECTION_LTR) {5404start_pos = i;5405break;5406} else {5407end_pos = i;5408break;5409}5410}5411}5412}54135414double justification_width;5415if (p_jst_flags.has_flag(JUSTIFICATION_CONSTRAIN_ELLIPSIS)) {5416if (sd->overrun_trim_data.trim_pos >= 0) {5417if (sd->para_direction == DIRECTION_RTL) {5418start_pos = sd->overrun_trim_data.trim_pos;5419} else {5420end_pos = sd->overrun_trim_data.trim_pos;5421}5422justification_width = sd->width_trimmed;5423} else {5424return Math::ceil(sd->width);5425}5426} else {5427justification_width = sd->width;5428}54295430if (p_jst_flags.has_flag(JUSTIFICATION_TRIM_EDGE_SPACES)) {5431// Trim spaces.5432while ((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)) {5433justification_width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat;5434sd->glyphs[start_pos].advance = 0;5435start_pos += sd->glyphs[start_pos].count;5436}5437while ((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)) {5438justification_width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat;5439sd->glyphs[end_pos].advance = 0;5440end_pos -= sd->glyphs[end_pos].count;5441}5442} else {5443// Skip breaks, but do not reset size.5444while ((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)) {5445start_pos += sd->glyphs[start_pos].count;5446}5447while ((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)) {5448end_pos -= sd->glyphs[end_pos].count;5449}5450}54515452int space_count = 0;5453int elongation_count = 0;5454for (int i = start_pos; i <= end_pos; i++) {5455const Glyph &gl = sd->glyphs[i];5456if (gl.count > 0) {5457if ((gl.flags & GRAPHEME_IS_ELONGATION) == GRAPHEME_IS_ELONGATION) {5458if ((i > 0) && ((sd->glyphs[i - 1].flags & GRAPHEME_IS_ELONGATION) != GRAPHEME_IS_ELONGATION)) {5459// Expand once per elongation sequence.5460elongation_count++;5461}5462}5463if ((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) {5464space_count++;5465}5466}5467}54685469if ((elongation_count > 0) && p_jst_flags.has_flag(JUSTIFICATION_KASHIDA)) {5470double delta_width_per_kashida = (p_width - justification_width) / elongation_count;5471for (int i = start_pos; i <= end_pos; i++) {5472Glyph &gl = sd->glyphs[i];5473if (gl.count > 0) {5474if (((gl.flags & GRAPHEME_IS_ELONGATION) == GRAPHEME_IS_ELONGATION) && (gl.advance > 0)) {5475if ((i > 0) && ((sd->glyphs[i - 1].flags & GRAPHEME_IS_ELONGATION) != GRAPHEME_IS_ELONGATION)) {5476// Expand once per elongation sequence.5477int count = delta_width_per_kashida / gl.advance;5478int prev_count = gl.repeat;5479if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {5480gl.repeat = CLAMP(count, 0, 255);5481} else {5482gl.repeat = CLAMP(count + 1, 1, 255);5483}5484justification_width += (gl.repeat - prev_count) * gl.advance;5485}5486}5487}5488}5489}5490if ((space_count > 0) && p_jst_flags.has_flag(JUSTIFICATION_WORD_BOUND)) {5491double delta_width_per_space = (p_width - justification_width) / space_count;5492double adv_remain = 0;5493for (int i = start_pos; i <= end_pos; i++) {5494Glyph &gl = sd->glyphs[i];5495if (gl.count > 0) {5496if ((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) {5497double old_adv = gl.advance;5498double new_advance;5499if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {5500new_advance = MAX(gl.advance + delta_width_per_space, 0.0);5501} else {5502new_advance = MAX(gl.advance + delta_width_per_space, 0.1 * gl.font_size);5503}5504gl.advance = new_advance;5505adv_remain += (new_advance - gl.advance);5506if (adv_remain >= 1.0) {5507gl.advance++;5508adv_remain -= 1.0;5509} else if (adv_remain <= -1.0) {5510gl.advance = MAX(gl.advance - 1, 0);5511adv_remain -= 1.0;5512}5513justification_width += (gl.advance - old_adv);5514}5515}5516}5517}55185519if (Math::floor(p_width) < Math::floor(justification_width)) {5520sd->fit_width_minimum_reached = true;5521}55225523if (!p_jst_flags.has_flag(JUSTIFICATION_CONSTRAIN_ELLIPSIS)) {5524sd->width = justification_width;5525}55265527return Math::ceil(justification_width);5528}55295530double TextServerAdvanced::_shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) {5531ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5532ERR_FAIL_NULL_V(sd, 0.0);55335534MutexLock lock(sd->mutex);5535if (!sd->valid.is_set()) {5536_shaped_text_shape(p_shaped);5537}5538if (!sd->line_breaks_valid) {5539_shaped_text_update_breaks(p_shaped);5540}55415542for (int i = 0; i < p_tab_stops.size(); i++) {5543if (p_tab_stops[i] <= 0) {5544return 0.0;5545}5546}55475548int tab_index = 0;5549double off = 0.0;55505551int start, end, delta;5552if (sd->para_direction == DIRECTION_LTR) {5553start = 0;5554end = sd->glyphs.size();5555delta = +1;5556} else {5557start = sd->glyphs.size() - 1;5558end = -1;5559delta = -1;5560}55615562Glyph *gl = sd->glyphs.ptr();55635564for (int i = start; i != end; i += delta) {5565if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {5566double tab_off = 0.0;5567while (tab_off <= off) {5568tab_off += p_tab_stops[tab_index];5569tab_index++;5570if (tab_index >= p_tab_stops.size()) {5571tab_index = 0;5572}5573}5574double old_adv = gl[i].advance;5575gl[i].advance = tab_off - off;5576sd->width += gl[i].advance - old_adv;5577off = 0;5578continue;5579}5580off += gl[i].advance * gl[i].repeat;5581}55825583return 0.0;5584}55855586RID TextServerAdvanced::_find_sys_font_for_text(const RID &p_fdef, const String &p_script_code, const String &p_language, const String &p_text) {5587RID f;5588// Try system fallback.5589String font_name = _font_get_name(p_fdef);5590BitField<FontStyle> font_style = _font_get_style(p_fdef);5591int font_weight = _font_get_weight(p_fdef);5592int font_stretch = _font_get_stretch(p_fdef);5593Dictionary dvar = _font_get_variation_coordinates(p_fdef);5594static int64_t wgth_tag = _name_to_tag("weight");5595static int64_t wdth_tag = _name_to_tag("width");5596static int64_t ital_tag = _name_to_tag("italic");5597if (dvar.has(wgth_tag)) {5598font_weight = dvar[wgth_tag].operator int();5599}5600if (dvar.has(wdth_tag)) {5601font_stretch = dvar[wdth_tag].operator int();5602}5603if (dvar.has(ital_tag) && dvar[ital_tag].operator int() == 1) {5604font_style.set_flag(TextServer::FONT_ITALIC);5605}56065607String locale = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;5608PackedStringArray 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);5609#ifdef GDEXTENSION5610for (int fb = 0; fb < fallback_font_name.size(); fb++) {5611const String &E = fallback_font_name[fb];5612#elif defined(GODOT_MODULE)5613for (const String &E : fallback_font_name) {5614#endif5615SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, p_fdef, this);5616if (system_fonts.has(key)) {5617const SystemFontCache &sysf_cache = system_fonts[key];5618int best_score = 0;5619int best_match = -1;5620for (int face_idx = 0; face_idx < sysf_cache.var.size(); face_idx++) {5621const SystemFontCacheRec &F = sysf_cache.var[face_idx];5622if (unlikely(!_font_has_char(F.rid, p_text[0]))) {5623continue;5624}5625BitField<FontStyle> style = _font_get_style(F.rid);5626int weight = _font_get_weight(F.rid);5627int stretch = _font_get_stretch(F.rid);5628int score = (20 - Math::abs(weight - font_weight) / 50);5629score += (20 - Math::abs(stretch - font_stretch) / 10);5630if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) {5631score += 30;5632}5633if (score >= best_score) {5634best_score = score;5635best_match = face_idx;5636}5637if (best_score == 70) {5638break;5639}5640}5641if (best_match != -1) {5642f = sysf_cache.var[best_match].rid;5643}5644}5645if (!f.is_valid()) {5646if (system_fonts.has(key)) {5647const SystemFontCache &sysf_cache = system_fonts[key];5648if (sysf_cache.max_var == sysf_cache.var.size()) {5649// All subfonts already tested, skip.5650continue;5651}5652}56535654if (!system_font_data.has(E)) {5655system_font_data[E] = FileAccess::get_file_as_bytes(E);5656}56575658const PackedByteArray &font_data = system_font_data[E];56595660SystemFontCacheRec sysf;5661sysf.rid = _create_font();5662_font_set_data_ptr(sysf.rid, font_data.ptr(), font_data.size());5663if (!_font_validate(sysf.rid)) {5664_free_rid(sysf.rid);5665continue;5666}56675668Dictionary var = dvar;5669// Select matching style from collection.5670int best_score = 0;5671int best_match = -1;5672for (int face_idx = 0; face_idx < _font_get_face_count(sysf.rid); face_idx++) {5673_font_set_face_index(sysf.rid, face_idx);5674if (unlikely(!_font_has_char(sysf.rid, p_text[0]))) {5675continue;5676}5677BitField<FontStyle> style = _font_get_style(sysf.rid);5678int weight = _font_get_weight(sysf.rid);5679int stretch = _font_get_stretch(sysf.rid);5680int score = (20 - Math::abs(weight - font_weight) / 50);5681score += (20 - Math::abs(stretch - font_stretch) / 10);5682if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) {5683score += 30;5684}5685if (score >= best_score) {5686best_score = score;5687best_match = face_idx;5688}5689if (best_score == 70) {5690break;5691}5692}5693if (best_match == -1) {5694_free_rid(sysf.rid);5695continue;5696} else {5697_font_set_face_index(sysf.rid, best_match);5698}5699sysf.index = best_match;57005701// If it's a variable font, apply weight, stretch and italic coordinates to match requested style.5702if (best_score != 70) {5703Dictionary ftr = _font_supported_variation_list(sysf.rid);5704if (ftr.has(wdth_tag)) {5705var[wdth_tag] = font_stretch;5706_font_set_stretch(sysf.rid, font_stretch);5707}5708if (ftr.has(wgth_tag)) {5709var[wgth_tag] = font_weight;5710_font_set_weight(sysf.rid, font_weight);5711}5712if ((font_style & TextServer::FONT_ITALIC) && ftr.has(ital_tag)) {5713var[ital_tag] = 1;5714_font_set_style(sysf.rid, _font_get_style(sysf.rid) | TextServer::FONT_ITALIC);5715}5716}57175718bool fb_use_msdf = key.msdf;5719if (fb_use_msdf) {5720FontAdvanced *fd = _get_font_data(sysf.rid);5721if (fd) {5722MutexLock lock(fd->mutex);5723Vector2i size = _get_size(fd, 16);5724FontForSizeAdvanced *ffsd = nullptr;5725if (_ensure_cache_for_size(fd, size, ffsd)) {5726if (ffsd && (FT_HAS_COLOR(ffsd->face) || !FT_IS_SCALABLE(ffsd->face))) {5727fb_use_msdf = false;5728}5729}5730}5731}57325733_font_set_antialiasing(sysf.rid, key.antialiasing);5734_font_set_disable_embedded_bitmaps(sysf.rid, key.disable_embedded_bitmaps);5735_font_set_generate_mipmaps(sysf.rid, key.mipmaps);5736_font_set_multichannel_signed_distance_field(sysf.rid, fb_use_msdf);5737_font_set_msdf_pixel_range(sysf.rid, key.msdf_range);5738_font_set_msdf_size(sysf.rid, key.msdf_source_size);5739_font_set_fixed_size(sysf.rid, key.fixed_size);5740_font_set_force_autohinter(sysf.rid, key.force_autohinter);5741_font_set_hinting(sysf.rid, key.hinting);5742_font_set_subpixel_positioning(sysf.rid, key.subpixel_positioning);5743_font_set_keep_rounding_remainders(sysf.rid, key.keep_rounding_remainders);5744_font_set_variation_coordinates(sysf.rid, var);5745_font_set_embolden(sysf.rid, key.embolden);5746_font_set_transform(sysf.rid, key.transform);5747_font_set_spacing(sysf.rid, SPACING_TOP, key.extra_spacing[SPACING_TOP]);5748_font_set_spacing(sysf.rid, SPACING_BOTTOM, key.extra_spacing[SPACING_BOTTOM]);5749_font_set_spacing(sysf.rid, SPACING_SPACE, key.extra_spacing[SPACING_SPACE]);5750_font_set_spacing(sysf.rid, SPACING_GLYPH, key.extra_spacing[SPACING_GLYPH]);57515752if (system_fonts.has(key)) {5753system_fonts[key].var.push_back(sysf);5754} else {5755SystemFontCache &sysf_cache = system_fonts[key];5756sysf_cache.max_var = _font_get_face_count(sysf.rid);5757sysf_cache.var.push_back(sysf);5758}5759f = sysf.rid;5760}5761break;5762}5763return f;5764}57655766void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) {5767ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped_line);5768ERR_FAIL_NULL_MSG(sd, "ShapedTextDataAdvanced invalid.");57695770MutexLock lock(sd->mutex);5771if (!sd->valid.is_set()) {5772_shaped_text_shape(p_shaped_line);5773}5774if (!sd->line_breaks_valid) {5775_shaped_text_update_breaks(p_shaped_line);5776}57775778sd->text_trimmed = false;5779sd->overrun_trim_data.ellipsis_glyph_buf.clear();57805781bool add_ellipsis = p_trim_flags.has_flag(OVERRUN_ADD_ELLIPSIS);5782bool cut_per_word = p_trim_flags.has_flag(OVERRUN_TRIM_WORD_ONLY);5783bool enforce_ellipsis = p_trim_flags.has_flag(OVERRUN_ENFORCE_ELLIPSIS);5784bool justification_aware = p_trim_flags.has_flag(OVERRUN_JUSTIFICATION_AWARE);57855786Glyph *sd_glyphs = sd->glyphs.ptr();57875788if ((p_trim_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIM || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {5789sd->overrun_trim_data.trim_pos = -1;5790sd->overrun_trim_data.ellipsis_pos = -1;5791return;5792}57935794if (justification_aware && !sd->fit_width_minimum_reached) {5795return;5796}57975798Vector<ShapedTextDataAdvanced::Span> &spans = sd->spans;5799if (sd->parent != RID()) {5800ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);5801ERR_FAIL_COND(!parent_sd->valid.is_set());5802spans = parent_sd->spans;5803}58045805int span_size = spans.size();5806if (span_size == 0) {5807return;5808}58095810int sd_size = sd->glyphs.size();5811int last_gl_font_size = sd_glyphs[sd_size - 1].font_size;5812bool found_el_char = false;58135814// Find usable fonts, if fonts from the last glyph do not have required chars.5815RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;5816if (add_ellipsis || enforce_ellipsis) {5817if (!_font_has_char(dot_gl_font_rid, sd->el_char)) {5818const Array &fonts = spans[span_size - 1].fonts;5819for (int i = 0; i < fonts.size(); i++) {5820if (_font_has_char(fonts[i], sd->el_char)) {5821dot_gl_font_rid = fonts[i];5822found_el_char = true;5823break;5824}5825}5826if (!found_el_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) {5827const char32_t u32str[] = { sd->el_char, 0 };5828RID rid = _find_sys_font_for_text(fonts[0], String(), spans[span_size - 1].language, u32str);5829if (rid.is_valid()) {5830dot_gl_font_rid = rid;5831found_el_char = true;5832}5833}5834} else {5835found_el_char = true;5836}5837if (!found_el_char) {5838bool found_dot_char = false;5839dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;5840if (!_font_has_char(dot_gl_font_rid, '.')) {5841const Array &fonts = spans[span_size - 1].fonts;5842for (int i = 0; i < fonts.size(); i++) {5843if (_font_has_char(fonts[i], '.')) {5844dot_gl_font_rid = fonts[i];5845found_dot_char = true;5846break;5847}5848}5849if (!found_dot_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) {5850RID rid = _find_sys_font_for_text(fonts[0], String(), spans[span_size - 1].language, ".");5851if (rid.is_valid()) {5852dot_gl_font_rid = rid;5853}5854}5855}5856}5857}5858RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;5859if (!_font_has_char(whitespace_gl_font_rid, ' ')) {5860const Array &fonts = spans[span_size - 1].fonts;5861for (int i = 0; i < fonts.size(); i++) {5862if (_font_has_char(fonts[i], ' ')) {5863whitespace_gl_font_rid = fonts[i];5864break;5865}5866}5867}58685869int32_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;5870Vector2 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();5871int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ', 0) : -1;5872Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2();58735874int ellipsis_width = 0;5875if (add_ellipsis && whitespace_gl_font_rid.is_valid()) {5876ellipsis_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);5877}58785879int ell_min_characters = 6;5880double width = sd->width;5881double width_without_el = width;58825883bool is_rtl = sd->para_direction == DIRECTION_RTL;58845885int trim_pos = (is_rtl) ? sd_size : 0;5886int ellipsis_pos = (enforce_ellipsis) ? 0 : -1;58875888int last_valid_cut = -1;5889int last_valid_cut_witout_el = -1;58905891int glyphs_from = (is_rtl) ? 0 : sd_size - 1;5892int glyphs_to = (is_rtl) ? sd_size - 1 : -1;5893int glyphs_delta = (is_rtl) ? +1 : -1;58945895if (enforce_ellipsis && (width + ellipsis_width <= p_width)) {5896trim_pos = -1;5897ellipsis_pos = (is_rtl) ? 0 : sd_size;5898} else {5899for (int i = glyphs_from; i != glyphs_to; i += glyphs_delta) {5900if (!is_rtl) {5901width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;5902}5903if (sd_glyphs[i].count > 0) {5904bool above_min_char_threshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters;5905if (!above_min_char_threshold && last_valid_cut_witout_el != -1) {5906trim_pos = last_valid_cut_witout_el;5907ellipsis_pos = -1;5908width = width_without_el;5909break;5910}5911if (!enforce_ellipsis && width <= p_width && last_valid_cut_witout_el == -1) {5912if (cut_per_word && above_min_char_threshold) {5913if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {5914last_valid_cut_witout_el = i;5915width_without_el = width;5916}5917} else {5918last_valid_cut_witout_el = i;5919width_without_el = width;5920}5921}5922if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {5923if (cut_per_word && above_min_char_threshold) {5924if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {5925last_valid_cut = i;5926}5927} else {5928last_valid_cut = i;5929}5930if (last_valid_cut != -1) {5931trim_pos = last_valid_cut;59325933if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {5934ellipsis_pos = trim_pos;5935}5936break;5937}5938}5939}5940if (is_rtl) {5941width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;5942}5943}5944}59455946sd->overrun_trim_data.trim_pos = trim_pos;5947sd->overrun_trim_data.ellipsis_pos = ellipsis_pos;5948if (trim_pos == 0 && enforce_ellipsis && add_ellipsis) {5949sd->overrun_trim_data.ellipsis_pos = 0;5950}59515952if ((trim_pos >= 0 && sd->width > p_width) || enforce_ellipsis) {5953if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) {5954// Insert an additional space when cutting word bound for aesthetics.5955if (cut_per_word && (ellipsis_pos > 0)) {5956Glyph gl;5957gl.count = 1;5958gl.advance = whitespace_adv.x;5959gl.index = whitespace_gl_idx;5960gl.font_rid = whitespace_gl_font_rid;5961gl.font_size = last_gl_font_size;5962gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);59635964sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);5965}5966// Add ellipsis dots.5967if (dot_gl_idx != 0) {5968Glyph gl;5969gl.count = 1;5970gl.repeat = (found_el_char ? 1 : 3);5971gl.advance = dot_adv.x;5972gl.index = dot_gl_idx;5973gl.font_rid = dot_gl_font_rid;5974gl.font_size = last_gl_font_size;5975gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);59765977sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);5978}5979}59805981sd->text_trimmed = true;5982sd->width_trimmed = width + ((ellipsis_pos != -1) ? ellipsis_width : 0);5983}5984}59855986int64_t TextServerAdvanced::_shaped_text_get_trim_pos(const RID &p_shaped) const {5987ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5988ERR_FAIL_NULL_V_MSG(sd, -1, "ShapedTextDataAdvanced invalid.");59895990MutexLock lock(sd->mutex);5991return sd->overrun_trim_data.trim_pos;5992}59935994int64_t TextServerAdvanced::_shaped_text_get_ellipsis_pos(const RID &p_shaped) const {5995ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5996ERR_FAIL_NULL_V_MSG(sd, -1, "ShapedTextDataAdvanced invalid.");59975998MutexLock lock(sd->mutex);5999return sd->overrun_trim_data.ellipsis_pos;6000}60016002const Glyph *TextServerAdvanced::_shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const {6003ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6004ERR_FAIL_NULL_V_MSG(sd, nullptr, "ShapedTextDataAdvanced invalid.");60056006MutexLock lock(sd->mutex);6007return sd->overrun_trim_data.ellipsis_glyph_buf.ptr();6008}60096010int64_t TextServerAdvanced::_shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const {6011ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6012ERR_FAIL_NULL_V_MSG(sd, 0, "ShapedTextDataAdvanced invalid.");60136014MutexLock lock(sd->mutex);6015return sd->overrun_trim_data.ellipsis_glyph_buf.size();6016}60176018void TextServerAdvanced::_update_chars(ShapedTextDataAdvanced *p_sd) const {6019if (!p_sd->chars_valid) {6020p_sd->chars.clear();60216022const UChar *data = p_sd->utf16.get_data();6023UErrorCode err = U_ZERO_ERROR;6024int prev = -1;6025int i = 0;60266027Vector<ShapedTextDataAdvanced::Span> &spans = p_sd->spans;6028if (p_sd->parent != RID()) {6029ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(p_sd->parent);6030ERR_FAIL_COND(!parent_sd->valid.is_set());6031spans = parent_sd->spans;6032}60336034int span_size = spans.size();6035while (i < span_size) {6036if (spans[i].start > p_sd->end) {6037break;6038}6039if (spans[i].end < p_sd->start) {6040i++;6041continue;6042}60436044int r_start = MAX(0, spans[i].start - p_sd->start);6045String language = spans[i].language;6046while (i + 1 < span_size && language == spans[i + 1].language) {6047i++;6048}6049int r_end = MIN(spans[i].end - p_sd->start, p_sd->text.length());6050UBreakIterator *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);6051if (U_SUCCESS(err)) {6052while (ubrk_next(bi) != UBRK_DONE) {6053int pos = _convert_pos(p_sd, ubrk_current(bi)) + r_start + p_sd->start;6054if (prev != pos) {6055p_sd->chars.push_back(pos);6056}6057prev = pos;6058}6059ubrk_close(bi);6060} else {6061for (int j = r_start; j < r_end; j++) {6062if (prev != j) {6063p_sd->chars.push_back(j + 1 + p_sd->start);6064}6065prev = j;6066}6067}6068i++;6069}6070p_sd->chars_valid = true;6071}6072}60736074PackedInt32Array TextServerAdvanced::_shaped_text_get_character_breaks(const RID &p_shaped) const {6075ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6076ERR_FAIL_NULL_V(sd, PackedInt32Array());60776078MutexLock lock(sd->mutex);6079if (!sd->valid.is_set()) {6080const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);6081}60826083_update_chars(sd);60846085return sd->chars;6086}60876088bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) {6089ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6090ERR_FAIL_NULL_V(sd, false);60916092MutexLock lock(sd->mutex);6093if (!sd->valid.is_set()) {6094_shaped_text_shape(p_shaped);6095}60966097if (sd->line_breaks_valid) {6098return true; // Nothing to do.6099}61006101const UChar *data = sd->utf16.get_data();61026103if (!sd->break_ops_valid) {6104sd->breaks.clear();6105sd->break_inserts = 0;6106UErrorCode err = U_ZERO_ERROR;6107int i = 0;6108int span_size = sd->spans.size();6109while (i < span_size) {6110String language = sd->spans[i].language;6111int r_start = sd->spans[i].start;6112if (r_start == sd->spans[i].end) {6113i++;6114continue;6115}6116while (i + 1 < span_size && (language == sd->spans[i + 1].language || sd->spans[i + 1].start == sd->spans[i + 1].end)) {6117i++;6118}6119int r_end = sd->spans[i].end;6120UBreakIterator *bi = _create_line_break_iterator_for_locale(language, &err);61216122if (!U_FAILURE(err) && bi) {6123ubrk_setText(bi, data + _convert_pos_inv(sd, r_start), _convert_pos_inv(sd, r_end - r_start), &err);6124}61256126if (U_FAILURE(err) || !bi) {6127// No data loaded - use fallback.6128for (int j = r_start; j < r_end; j++) {6129char32_t c = sd->text[j - sd->start];6130char32_t c_next = (j < r_end) ? sd->text[j - sd->start + 1] : 0x0000;6131if (is_whitespace(c)) {6132sd->breaks[j + 1] = false;6133}6134if (is_linebreak(c)) {6135if (c != 0x000D || c_next != 0x000A) { // Skip first hard break in CR-LF pair.6136sd->breaks[j + 1] = true;6137}6138}6139}6140} else {6141while (ubrk_next(bi) != UBRK_DONE) {6142int pos = _convert_pos(sd, ubrk_current(bi)) + r_start;6143if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_HARD) && (ubrk_getRuleStatus(bi) < UBRK_LINE_HARD_LIMIT)) {6144sd->breaks[pos] = true;6145} else if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_SOFT) && (ubrk_getRuleStatus(bi) < UBRK_LINE_SOFT_LIMIT)) {6146sd->breaks[pos] = false;6147}6148int pos_p = pos - 1 - sd->start;6149char32_t c = sd->text[pos_p];6150if (pos - sd->start != sd->end && !is_whitespace(c) && (c != 0xfffc)) {6151sd->break_inserts++;6152}6153}6154ubrk_close(bi);6155}6156i++;6157}6158sd->break_ops_valid = true;6159}61606161LocalVector<Glyph> glyphs_new;61626163bool rewrite = false;6164int sd_shift = 0;6165int sd_size = sd->glyphs.size();6166Glyph *sd_glyphs = sd->glyphs.ptr();6167Glyph *sd_glyphs_new = nullptr;61686169if (sd->break_inserts > 0) {6170glyphs_new.resize(sd->glyphs.size() + sd->break_inserts);6171sd_glyphs_new = glyphs_new.ptr();6172rewrite = true;6173} else {6174sd_glyphs_new = sd_glyphs;6175}61766177sd->sort_valid = false;6178sd->glyphs_logical.clear();6179const char32_t *ch = sd->text.ptr();61806181int c_punct_size = sd->custom_punct.length();6182const char32_t *c_punct = sd->custom_punct.ptr();61836184for (int i = 0; i < sd_size; i++) {6185if (rewrite) {6186for (int j = 0; j < sd_glyphs[i].count; j++) {6187sd_glyphs_new[sd_shift + i + j] = sd_glyphs[i + j];6188}6189}6190if (sd_glyphs[i].count > 0) {6191char32_t c = ch[sd_glyphs[i].start - sd->start];6192if (c == 0xfffc) {6193i += (sd_glyphs[i].count - 1);6194continue;6195}6196if (c == 0x0009 || c == 0x000b) {6197sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_TAB;6198}6199if (c == 0x00ad) {6200sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_SOFT_HYPHEN;6201}6202if (is_whitespace(c)) {6203sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_SPACE;6204}6205if (c_punct_size == 0) {6206if (u_ispunct(c) && c != 0x005f) {6207sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_PUNCTUATION;6208}6209} else {6210for (int j = 0; j < c_punct_size; j++) {6211if (c_punct[j] == c) {6212sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_PUNCTUATION;6213break;6214}6215}6216}6217if (is_underscore(c)) {6218sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_UNDERSCORE;6219}6220if (sd->breaks.has(sd_glyphs[i].end)) {6221if (sd->breaks[sd_glyphs[i].end] && (is_linebreak(c))) {6222sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_BREAK_HARD;6223} else if (is_whitespace(c) || c == 0x00ad) {6224sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_BREAK_SOFT;6225} else {6226int count = sd_glyphs[i].count;6227// Do not add extra space at the end of the line.6228if (sd_glyphs[i].end == sd->end) {6229i += (sd_glyphs[i].count - 1);6230continue;6231}6232// Do not add extra space after existing space.6233if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {6234if ((i + count < sd_size - 1) && ((sd_glyphs[i + count].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) {6235i += (sd_glyphs[i].count - 1);6236continue;6237}6238} else {6239if ((sd_glyphs[i].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) {6240i += (sd_glyphs[i].count - 1);6241continue;6242}6243}6244// Do not add extra space for color picker object.6245if (((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)) {6246i += (sd_glyphs[i].count - 1);6247continue;6248}6249Glyph gl;6250gl.span_index = sd_glyphs[i].span_index;6251gl.start = sd_glyphs[i].start;6252gl.end = sd_glyphs[i].end;6253gl.count = 1;6254gl.font_rid = sd_glyphs[i].font_rid;6255gl.font_size = sd_glyphs[i].font_size;6256gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | GRAPHEME_IS_SPACE;6257// Mark virtual space after punctuation as punctuation to avoid justification at this point.6258if (c_punct_size == 0) {6259if (u_ispunct(c) && c != 0x005f) {6260gl.flags |= GRAPHEME_IS_PUNCTUATION;6261}6262} else {6263for (int j = 0; j < c_punct_size; j++) {6264if (c_punct[j] == c) {6265gl.flags |= GRAPHEME_IS_PUNCTUATION;6266break;6267}6268}6269}6270if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {6271gl.flags |= GRAPHEME_IS_RTL;6272for (int j = sd_glyphs[i].count - 1; j >= 0; j--) {6273sd_glyphs_new[sd_shift + i + j + 1] = sd_glyphs_new[sd_shift + i + j];6274}6275sd_glyphs_new[sd_shift + i] = gl;6276} else {6277sd_glyphs_new[sd_shift + i + count] = gl;6278}6279sd_shift++;6280ERR_FAIL_COND_V_MSG(sd_shift > sd->break_inserts, false, "Invalid break insert count!");6281}6282}6283i += (sd_glyphs[i].count - 1);6284}6285}6286if (sd_shift < sd->break_inserts) {6287// 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).6288glyphs_new.resize(sd->glyphs.size() + sd_shift);6289}62906291if (sd->break_inserts > 0) {6292sd->glyphs = std::move(glyphs_new);6293}62946295sd->line_breaks_valid = true;62966297return sd->line_breaks_valid;6298}62996300_FORCE_INLINE_ int64_t _generate_kashida_justification_opportunities(const String &p_data, int64_t p_start, int64_t p_end) {6301int64_t kashida_pos = -1;6302int8_t priority = 100;6303int64_t i = p_start;63046305char32_t pc = 0;63066307while ((p_end > p_start) && is_transparent(p_data[p_end - 1])) {6308p_end--;6309}63106311while (i < p_end) {6312uint32_t c = p_data[i];63136314if (c == 0x0640) {6315kashida_pos = i;6316priority = 0;6317}6318if (priority >= 1 && i < p_end - 1) {6319if (is_seen_sad(c) && (p_data[i + 1] != 0x200c)) {6320kashida_pos = i;6321priority = 1;6322}6323}6324if (priority >= 2 && i > p_start) {6325if (is_teh_marbuta(c) || is_dal(c) || (is_heh(c) && i == p_end - 1)) {6326if (is_connected_to_prev(c, pc)) {6327kashida_pos = i - 1;6328priority = 2;6329}6330}6331}6332if (priority >= 3 && i > p_start) {6333if (is_alef(c) || ((is_lam(c) || is_tah(c) || is_kaf(c) || is_gaf(c)) && i == p_end - 1)) {6334if (is_connected_to_prev(c, pc)) {6335kashida_pos = i - 1;6336priority = 3;6337}6338}6339}6340if (priority >= 4 && i > p_start && i < p_end - 1) {6341if (is_beh(c)) {6342if (is_reh(p_data[i + 1]) || is_yeh(p_data[i + 1])) {6343if (is_connected_to_prev(c, pc)) {6344kashida_pos = i - 1;6345priority = 4;6346}6347}6348}6349}6350if (priority >= 5 && i > p_start) {6351if (is_waw(c) || ((is_ain(c) || is_qaf(c) || is_feh(c)) && i == p_end - 1)) {6352if (is_connected_to_prev(c, pc)) {6353kashida_pos = i - 1;6354priority = 5;6355}6356}6357}6358if (priority >= 6 && i > p_start) {6359if (is_reh(c)) {6360if (is_connected_to_prev(c, pc)) {6361kashida_pos = i - 1;6362priority = 6;6363}6364}6365}6366if (!is_transparent(c)) {6367pc = c;6368}6369i++;6370}63716372return kashida_pos;6373}63746375bool TextServerAdvanced::_shaped_text_update_justification_ops(const RID &p_shaped) {6376ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6377ERR_FAIL_NULL_V(sd, false);63786379MutexLock lock(sd->mutex);6380if (!sd->valid.is_set()) {6381_shaped_text_shape(p_shaped);6382}6383if (!sd->line_breaks_valid) {6384_shaped_text_update_breaks(p_shaped);6385}63866387if (sd->justification_ops_valid) {6388return true; // Nothing to do.6389}63906391const UChar *data = sd->utf16.get_data();6392int data_size = sd->utf16.length();63936394if (!sd->js_ops_valid) {6395sd->jstops.clear();63966397// Use ICU word iterator and custom kashida detection.6398UErrorCode err = U_ZERO_ERROR;6399UBreakIterator *bi = ubrk_open(UBRK_WORD, "", data, data_size, &err);6400if (U_FAILURE(err)) {6401// No data - use fallback.6402int limit = 0;6403for (int i = 0; i < sd->text.length(); i++) {6404if (is_whitespace(sd->text[i])) {6405int ks = _generate_kashida_justification_opportunities(sd->text, limit, i) + sd->start;6406if (ks != -1) {6407sd->jstops[ks] = true;6408}6409limit = i + 1;6410}6411}6412int ks = _generate_kashida_justification_opportunities(sd->text, limit, sd->text.length()) + sd->start;6413if (ks != -1) {6414sd->jstops[ks] = true;6415}6416} else {6417int limit = 0;6418while (ubrk_next(bi) != UBRK_DONE) {6419if (ubrk_getRuleStatus(bi) != UBRK_WORD_NONE) {6420int i = _convert_pos(sd, ubrk_current(bi));6421sd->jstops[i + sd->start] = false;6422int ks = _generate_kashida_justification_opportunities(sd->text, limit, i);6423if (ks != -1) {6424sd->jstops[ks + sd->start] = true;6425}6426limit = i;6427}6428}6429ubrk_close(bi);6430}64316432sd->js_ops_valid = true;6433}64346435sd->sort_valid = false;6436sd->glyphs_logical.clear();64376438Glyph *sd_glyphs = sd->glyphs.ptr();6439int sd_size = sd->glyphs.size();6440if (!sd->jstops.is_empty()) {6441for (int i = 0; i < sd_size; i++) {6442if (sd_glyphs[i].count > 0) {6443char32_t c = sd->text[sd_glyphs[i].start - sd->start];6444if (c == 0x0640 && sd_glyphs[i].start == sd_glyphs[i].end - 1) {6445sd_glyphs[i].flags |= GRAPHEME_IS_ELONGATION;6446}6447if (sd->jstops.has(sd_glyphs[i].start)) {6448if (c == 0xfffc || c == 0x00ad) {6449continue;6450}6451if (sd->jstops[sd_glyphs[i].start]) {6452if (c != 0x0640) {6453if (sd_glyphs[i].font_rid != RID()) {6454Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size);6455if ((sd_glyphs[i].flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {6456#if HB_VERSION_ATLEAST(5, 1, 0)6457if ((i > 0) && ((sd_glyphs[i - 1].flags & GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL) != GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL)) {6458continue;6459}6460#endif6461gl.start = sd_glyphs[i].start;6462gl.end = sd_glyphs[i].end;6463gl.repeat = 0;6464gl.count = 1;6465if (sd->orientation == ORIENTATION_HORIZONTAL) {6466gl.y_off = sd_glyphs[i].y_off;6467} else {6468gl.x_off = sd_glyphs[i].x_off;6469}6470gl.flags |= GRAPHEME_IS_ELONGATION | GRAPHEME_IS_VIRTUAL;6471sd->glyphs.insert(i, gl);6472i++;64736474// Update write pointer and size.6475sd_size = sd->glyphs.size();6476sd_glyphs = sd->glyphs.ptr();6477continue;6478}6479}6480}6481} else if ((sd_glyphs[i].flags & GRAPHEME_IS_SPACE) != GRAPHEME_IS_SPACE && (sd_glyphs[i].flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {6482int count = sd_glyphs[i].count;6483// Do not add extra spaces at the end of the line.6484if (sd_glyphs[i].end == sd->end) {6485continue;6486}6487// Do not add extra space after existing space.6488if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {6489if ((i + count < sd_size - 1) && ((sd_glyphs[i + count].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) {6490continue;6491}6492} else {6493if ((i > 0) && ((sd_glyphs[i - 1].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) {6494continue;6495}6496}6497// Inject virtual space for alignment.6498Glyph gl;6499gl.span_index = sd_glyphs[i].span_index;6500gl.start = sd_glyphs[i].start;6501gl.end = sd_glyphs[i].end;6502gl.count = 1;6503gl.font_rid = sd_glyphs[i].font_rid;6504gl.font_size = sd_glyphs[i].font_size;6505gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_VIRTUAL;6506if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {6507gl.flags |= GRAPHEME_IS_RTL;6508sd->glyphs.insert(i, gl); // Insert before.6509} else {6510sd->glyphs.insert(i + count, gl); // Insert after.6511}6512i += count;65136514// Update write pointer and size.6515sd_size = sd->glyphs.size();6516sd_glyphs = sd->glyphs.ptr();6517continue;6518}6519}6520}6521}6522}65236524sd->justification_ops_valid = true;6525return sd->justification_ops_valid;6526}65276528Glyph 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) {6529hb_font_t *hb_font = _font_get_hb_handle(p_font, p_font_size);6530double scale = _font_get_scale(p_font, p_font_size);6531bool 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);6532ERR_FAIL_NULL_V(hb_font, Glyph());65336534hb_buffer_clear_contents(p_sd->hb_buffer);6535hb_buffer_set_direction(p_sd->hb_buffer, p_direction);6536hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)(HB_BUFFER_FLAG_DEFAULT));6537hb_buffer_set_script(p_sd->hb_buffer, p_script);6538hb_buffer_add_utf32(p_sd->hb_buffer, (const uint32_t *)&p_char, 1, 0, 1);65396540hb_shape(hb_font, p_sd->hb_buffer, nullptr, 0);65416542unsigned int glyph_count = 0;6543hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(p_sd->hb_buffer, &glyph_count);6544hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(p_sd->hb_buffer, &glyph_count);65456546// Process glyphs.6547Glyph gl;65486549if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {6550gl.flags |= TextServer::GRAPHEME_IS_RTL;6551}65526553gl.font_rid = p_font;6554gl.font_size = p_font_size;65556556if (glyph_count > 0) {6557if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6558if (subpos) {6559gl.advance = (double)glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size);6560} else {6561gl.advance = Math::round((double)glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size));6562}6563} else {6564gl.advance = -Math::round((double)glyph_pos[0].y_advance / (64.0 / scale));6565}6566gl.count = 1;65676568gl.index = glyph_info[0].codepoint;6569if (subpos) {6570gl.x_off = (double)glyph_pos[0].x_offset / (64.0 / scale);6571} else {6572gl.x_off = Math::round((double)glyph_pos[0].x_offset / (64.0 / scale));6573}6574gl.y_off = -Math::round((double)glyph_pos[0].y_offset / (64.0 / scale));6575if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6576gl.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));6577} else {6578gl.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));6579}65806581if ((glyph_info[0].codepoint != 0) || !u_isgraph(p_char)) {6582gl.flags |= GRAPHEME_IS_VALID;6583}6584}6585return gl;6586}65876588_FORCE_INLINE_ void TextServerAdvanced::_add_features(const Dictionary &p_source, Vector<hb_feature_t> &r_ftrs) {6589for (const KeyValue<Variant, Variant> &key_value : p_source) {6590int32_t value = key_value.value;6591if (value >= 0) {6592hb_feature_t feature;6593if (key_value.key.is_string()) {6594feature.tag = _name_to_tag(key_value.key);6595} else {6596feature.tag = key_value.key;6597}6598feature.value = value;6599feature.start = 0;6600feature.end = -1;6601r_ftrs.push_back(feature);6602}6603}6604}66056606UBreakIterator *TextServerAdvanced::_create_line_break_iterator_for_locale(const String &p_language, UErrorCode *r_err) const {6607// Creating UBreakIterator (ubrk_open) is surprisingly costly.6608// However, cloning (ubrk_clone) is cheaper, so we keep around blueprints to accelerate creating new ones.66096610String language = p_language.is_empty() ? TranslationServer::get_singleton()->get_tool_locale() : p_language;6611if (!language.contains("@")) {6612if (lb_strictness == LB_LOOSE) {6613language += "@lb=loose";6614} else if (lb_strictness == LB_NORMAL) {6615language += "@lb=normal";6616} else if (lb_strictness == LB_STRICT) {6617language += "@lb=strict";6618}6619}66206621_THREAD_SAFE_METHOD_6622const HashMap<String, UBreakIterator *>::Iterator key_value = line_break_iterators_per_language.find(language);6623if (key_value) {6624return ubrk_clone(key_value->value, r_err);6625}6626UBreakIterator *bi = ubrk_open(UBRK_LINE, language.ascii().get_data(), nullptr, 0, r_err);6627if (U_FAILURE(*r_err) || !bi) {6628return nullptr;6629}6630line_break_iterators_per_language.insert(language, bi);6631return ubrk_clone(bi, r_err);6632}66336634void 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) {6635RID f;6636int fs = p_sd->spans[p_span].font_size;66376638if (p_fb_index >= 0 && p_fb_index < p_fonts.size()) {6639// Try font from list.6640f = p_fonts[p_fb_index];6641} 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))) {6642// Try system fallback.6643RID fdef = p_fonts[0];6644if (_font_is_allow_system_fallback(fdef)) {6645_update_chars(p_sd);66466647int64_t next = p_end;6648for (const int32_t &E : p_sd->chars) {6649if (E > p_start) {6650next = E;6651break;6652}6653}6654char scr_buffer[5] = { 0, 0, 0, 0, 0 };6655hb_tag_to_string(hb_script_to_iso15924_tag(p_script), scr_buffer);6656String script_code = String(scr_buffer);66576658String text = p_sd->text.substr(p_start, next - p_start);6659f = _find_sys_font_for_text(fdef, script_code, p_sd->spans[p_span].language, text);6660}6661}66626663if (!f.is_valid()) {6664// Shaping failed, try looking up raw characters or use fallback hex code boxes.6665int fb_from = (p_direction != HB_DIRECTION_RTL) ? p_start : p_end - 1;6666int fb_to = (p_direction != HB_DIRECTION_RTL) ? p_end : p_start - 1;6667int fb_delta = (p_direction != HB_DIRECTION_RTL) ? +1 : -1;66686669for (int i = fb_from; i != fb_to; i += fb_delta) {6670if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) {6671Glyph gl;6672gl.span_index = p_span;6673gl.start = i + p_sd->start;6674gl.end = i + 1 + p_sd->start;6675gl.count = 1;6676gl.font_size = fs;6677if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {6678gl.flags |= TextServer::GRAPHEME_IS_RTL;6679}66806681bool found = false;6682for (int j = 0; j <= p_fonts.size(); j++) {6683RID f_rid;6684if (j == p_fonts.size()) {6685f_rid = p_prev_font;6686} else {6687f_rid = p_fonts[j];6688}6689if (f_rid.is_valid() && _font_has_char(f_rid, p_sd->text[i])) {6690gl.font_rid = f_rid;6691gl.index = _font_get_glyph_index(gl.font_rid, fs, p_sd->text[i], 0);6692if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6693gl.advance = _font_get_glyph_advance(gl.font_rid, fs, gl.index).x;6694gl.x_off = 0;6695gl.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));6696p_sd->ascent = MAX(p_sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_TOP));6697p_sd->descent = MAX(p_sd->descent, _font_get_descent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_BOTTOM));6698} else {6699gl.advance = _font_get_glyph_advance(gl.font_rid, fs, gl.index).y;6700gl.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));6701gl.y_off = _font_get_ascent(gl.font_rid, gl.font_size);6702p_sd->ascent = MAX(p_sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));6703p_sd->descent = MAX(p_sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));6704}6705double scale = _font_get_scale(gl.font_rid, fs);6706bool 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);6707if (!subpos) {6708gl.advance = Math::round(gl.advance);6709gl.x_off = Math::round(gl.x_off);6710}6711found = true;6712break;6713}6714}6715if (!found) {6716gl.font_rid = RID();6717gl.index = p_sd->text[i];6718if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6719gl.advance = get_hex_code_box_size(fs, gl.index).x;6720p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(fs, gl.index).y * 0.85);6721p_sd->descent = MAX(p_sd->descent, get_hex_code_box_size(fs, gl.index).y * 0.15);6722} else {6723gl.advance = get_hex_code_box_size(fs, gl.index).y;6724gl.y_off = get_hex_code_box_size(fs, gl.index).y;6725gl.x_off = -Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5);6726p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5));6727p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5));6728}6729}67306731p_sd->width += gl.advance;67326733p_sd->glyphs.push_back(gl);6734}6735}6736return;6737}67386739FontAdvanced *fd = _get_font_data(f);6740ERR_FAIL_NULL(fd);6741MutexLock lock(fd->mutex);67426743Vector2i fss = _get_size(fd, fs);6744hb_font_t *hb_font = _font_get_hb_handle(f, fs);6745double scale = _font_get_scale(f, fs);6746double sp_sp = p_sd->extra_spacing[SPACING_SPACE] + _font_get_spacing(f, SPACING_SPACE);6747double sp_gl = p_sd->extra_spacing[SPACING_GLYPH] + _font_get_spacing(f, SPACING_GLYPH);6748bool last_run = (p_sd->end == p_end);6749double ea = _get_extra_advance(f, fs);6750bool 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);6751ERR_FAIL_NULL(hb_font);67526753hb_buffer_clear_contents(p_sd->hb_buffer);6754hb_buffer_set_direction(p_sd->hb_buffer, p_direction);6755int flags = (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0);6756if (p_sd->preserve_control) {6757flags |= HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES;6758} else {6759flags |= HB_BUFFER_FLAG_DEFAULT;6760}6761#if HB_VERSION_ATLEAST(5, 1, 0)6762flags |= HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL;6763#endif6764hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)flags);6765hb_buffer_set_script(p_sd->hb_buffer, p_script);67666767if (p_sd->spans[p_span].language.is_empty()) {6768hb_language_t lang = hb_language_from_string(TranslationServer::get_singleton()->get_tool_locale().ascii().get_data(), -1);6769hb_buffer_set_language(p_sd->hb_buffer, lang);6770} else {6771hb_language_t lang = hb_language_from_string(p_sd->spans[p_span].language.ascii().get_data(), -1);6772hb_buffer_set_language(p_sd->hb_buffer, lang);6773}67746775hb_buffer_add_utf32(p_sd->hb_buffer, (const uint32_t *)p_sd->text.ptr(), p_sd->text.length(), p_start, p_end - p_start);67766777Vector<hb_feature_t> ftrs;6778_add_features(_font_get_opentype_feature_overrides(f), ftrs);6779_add_features(p_sd->spans[p_span].features, ftrs);67806781hb_shape(hb_font, p_sd->hb_buffer, ftrs.is_empty() ? nullptr : &ftrs[0], ftrs.size());67826783unsigned int glyph_count = 0;6784hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(p_sd->hb_buffer, &glyph_count);6785hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(p_sd->hb_buffer, &glyph_count);67866787int mod = 0;6788if (fd->antialiasing == FONT_ANTIALIASING_LCD) {6789TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();6790if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {6791mod = (layout << 24);6792}6793}67946795// Process glyphs.6796if (glyph_count > 0) {6797Glyph *w = (Glyph *)memalloc(glyph_count * sizeof(Glyph));67986799int end = (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) ? p_end : 0;6800uint32_t last_cluster_id = UINT32_MAX;6801unsigned int last_cluster_index = 0;6802bool last_cluster_valid = true;68036804double adv_rem = 0.0;6805for (unsigned int i = 0; i < glyph_count; i++) {6806if ((i > 0) && (last_cluster_id != glyph_info[i].cluster)) {6807if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {6808end = w[last_cluster_index].start;6809} else {6810for (unsigned int j = last_cluster_index; j < i; j++) {6811w[j].end = glyph_info[i].cluster;6812}6813}6814if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {6815w[last_cluster_index].flags |= GRAPHEME_IS_RTL;6816}6817if (last_cluster_valid) {6818w[last_cluster_index].flags |= GRAPHEME_IS_VALID;6819}6820w[last_cluster_index].count = i - last_cluster_index;6821last_cluster_index = i;6822last_cluster_valid = true;6823}68246825last_cluster_id = glyph_info[i].cluster;68266827Glyph &gl = w[i];6828gl = Glyph();68296830gl.span_index = p_span;6831gl.start = glyph_info[i].cluster;6832gl.end = end;6833gl.count = 0;68346835gl.font_rid = f;6836gl.font_size = fs;68376838if (glyph_info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK) {6839gl.flags |= GRAPHEME_IS_CONNECTED;6840}68416842#if HB_VERSION_ATLEAST(5, 1, 0)6843if (glyph_info[i].mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL) {6844gl.flags |= GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL;6845}6846#endif68476848gl.index = glyph_info[i].codepoint;6849if ((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])) {6850adv_rem = 0.0; // Reset on blank.6851}6852if (gl.index != 0) {6853FontGlyph fgl;6854_ensure_glyph(fd, fss, gl.index | mod, fgl);6855if (subpos) {6856gl.x_off = (double)glyph_pos[i].x_offset / (64.0 / scale);6857} else if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6858gl.x_off = Math::round(adv_rem + ((double)glyph_pos[i].x_offset / (64.0 / scale)));6859} else {6860gl.x_off = Math::round((double)glyph_pos[i].x_offset / (64.0 / scale));6861}6862if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6863gl.y_off = -Math::round((double)glyph_pos[i].y_offset / (64.0 / scale));6864} else {6865gl.y_off = -Math::round(adv_rem + ((double)glyph_pos[i].y_offset / (64.0 / scale)));6866}6867if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6868if (subpos) {6869gl.advance = (double)glyph_pos[i].x_advance / (64.0 / scale) + ea;6870} else {6871double full_adv = adv_rem + ((double)glyph_pos[i].x_advance / (64.0 / scale) + ea);6872gl.advance = Math::round(full_adv);6873if (fd->keep_rounding_remainders) {6874adv_rem = full_adv - gl.advance;6875}6876}6877} else {6878double full_adv = adv_rem + ((double)glyph_pos[i].y_advance / (64.0 / scale));6879gl.advance = -Math::round(full_adv);6880if (fd->keep_rounding_remainders) {6881adv_rem = full_adv + gl.advance;6882}6883}6884if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6885gl.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));6886} else {6887gl.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));6888}6889}6890if (!last_run || i < glyph_count - 1) {6891// Do not add extra spacing to the last glyph of the string.6892if (sp_sp && is_whitespace(p_sd->text[glyph_info[i].cluster])) {6893gl.advance += sp_sp;6894} else {6895gl.advance += sp_gl;6896}6897}68986899if (p_sd->preserve_control) {6900last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || (p_sd->text[glyph_info[i].cluster] == 0x0009) || (u_isblank(p_sd->text[glyph_info[i].cluster]) && (gl.advance != 0)) || (!u_isblank(p_sd->text[glyph_info[i].cluster]) && is_linebreak(p_sd->text[glyph_info[i].cluster])));6901} else {6902last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || (p_sd->text[glyph_info[i].cluster] == 0x0009) || (u_isblank(p_sd->text[glyph_info[i].cluster]) && (gl.advance != 0)) || (!u_isblank(p_sd->text[glyph_info[i].cluster]) && !u_isgraph(p_sd->text[glyph_info[i].cluster])));6903}6904}6905if (p_direction == HB_DIRECTION_LTR || p_direction == HB_DIRECTION_TTB) {6906for (unsigned int j = last_cluster_index; j < glyph_count; j++) {6907w[j].end = p_end;6908}6909}6910w[last_cluster_index].count = glyph_count - last_cluster_index;6911if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {6912w[last_cluster_index].flags |= GRAPHEME_IS_RTL;6913}6914if (last_cluster_valid) {6915w[last_cluster_index].flags |= GRAPHEME_IS_VALID;6916}69176918// Fallback.6919int failed_subrun_start = p_end + 1;6920int failed_subrun_end = p_start;69216922for (unsigned int i = 0; i < glyph_count; i++) {6923if ((w[i].flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {6924if (failed_subrun_start != p_end + 1) {6925_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());6926failed_subrun_start = p_end + 1;6927failed_subrun_end = p_start;6928}6929for (int j = 0; j < w[i].count; j++) {6930if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6931p_sd->ascent = MAX(p_sd->ascent, -w[i + j].y_off);6932p_sd->descent = MAX(p_sd->descent, w[i + j].y_off);6933} else {6934double gla = Math::round(_font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5);6935p_sd->ascent = MAX(p_sd->ascent, gla);6936p_sd->descent = MAX(p_sd->descent, gla);6937}6938p_sd->width += w[i + j].advance;6939w[i + j].start += p_sd->start;6940w[i + j].end += p_sd->start;6941p_sd->glyphs.push_back(w[i + j]);6942}6943} else {6944if (failed_subrun_start >= w[i].start) {6945failed_subrun_start = w[i].start;6946}6947if (failed_subrun_end <= w[i].end) {6948failed_subrun_end = w[i].end;6949}6950}6951i += w[i].count - 1;6952}6953memfree(w);6954if (failed_subrun_start != p_end + 1) {6955_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());6956}6957p_sd->ascent = MAX(p_sd->ascent, _font_get_ascent(f, fs) + _font_get_spacing(f, SPACING_TOP));6958p_sd->descent = MAX(p_sd->descent, _font_get_descent(f, fs) + _font_get_spacing(f, SPACING_BOTTOM));6959p_sd->upos = MAX(p_sd->upos, _font_get_underline_position(f, fs));6960p_sd->uthk = MAX(p_sd->uthk, _font_get_underline_thickness(f, fs));6961} else if (p_start != p_end) {6962if (p_fb_index >= p_fonts.size()) {6963Glyph gl;6964gl.start = p_start;6965gl.end = p_end;6966gl.span_index = p_span;6967gl.font_rid = f;6968gl.font_size = fs;6969gl.flags = GRAPHEME_IS_VALID;6970p_sd->glyphs.push_back(gl);69716972p_sd->ascent = MAX(p_sd->ascent, _font_get_ascent(f, fs) + _font_get_spacing(f, SPACING_TOP));6973p_sd->descent = MAX(p_sd->descent, _font_get_descent(f, fs) + _font_get_spacing(f, SPACING_BOTTOM));6974p_sd->upos = MAX(p_sd->upos, _font_get_underline_position(f, fs));6975p_sd->uthk = MAX(p_sd->uthk, _font_get_underline_thickness(f, fs));6976} else {6977_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);6978}6979}6980}69816982bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {6983_THREAD_SAFE_METHOD_6984ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6985ERR_FAIL_NULL_V(sd, false);69866987MutexLock lock(sd->mutex);6988if (sd->valid.is_set()) {6989return true;6990}69916992invalidate(sd, false);6993if (sd->parent != RID()) {6994_shaped_text_shape(sd->parent);6995ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);6996ERR_FAIL_COND_V(!parent_sd->valid.is_set(), false);6997ERR_FAIL_COND_V(!_shape_substr(sd, parent_sd, sd->start, sd->end - sd->start), false);6998return true;6999}70007001if (sd->text.length() == 0) {7002sd->valid.set();7003return true;7004}70057006sd->utf16 = sd->text.utf16();7007const UChar *data = sd->utf16.get_data();70087009// Create script iterator.7010if (sd->script_iter == nullptr) {7011sd->script_iter = memnew(ScriptIterator(sd->text, 0, sd->text.length()));7012}70137014sd->base_para_direction = UBIDI_DEFAULT_LTR;7015switch (sd->direction) {7016case DIRECTION_LTR: {7017sd->para_direction = DIRECTION_LTR;7018sd->base_para_direction = UBIDI_LTR;7019} break;7020case DIRECTION_RTL: {7021sd->para_direction = DIRECTION_RTL;7022sd->base_para_direction = UBIDI_RTL;7023} break;7024case DIRECTION_INHERITED:7025case DIRECTION_AUTO: {7026UBiDiDirection direction = ubidi_getBaseDirection(data, sd->utf16.length());7027if (direction != UBIDI_NEUTRAL) {7028sd->para_direction = (direction == UBIDI_RTL) ? DIRECTION_RTL : DIRECTION_LTR;7029sd->base_para_direction = direction;7030} else {7031const String &lang = (sd->spans.is_empty() || sd->spans[0].language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : sd->spans[0].language;7032bool lang_rtl = _is_locale_right_to_left(lang);70337034sd->para_direction = lang_rtl ? DIRECTION_RTL : DIRECTION_LTR;7035sd->base_para_direction = lang_rtl ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR;7036}7037} break;7038}70397040Vector<Vector3i> bidi_ranges;7041if (sd->bidi_override.is_empty()) {7042bidi_ranges.push_back(Vector3i(sd->start, sd->end, DIRECTION_INHERITED));7043} else {7044bidi_ranges = sd->bidi_override;7045}7046sd->runs.clear();7047sd->runs_dirty = true;70487049for (int ov = 0; ov < bidi_ranges.size(); ov++) {7050// Create BiDi iterator.7051int start = _convert_pos_inv(sd, bidi_ranges[ov].x - sd->start);7052int end = _convert_pos_inv(sd, bidi_ranges[ov].y - sd->start);70537054if (start < 0 || end - start > sd->utf16.length()) {7055continue;7056}70577058UErrorCode err = U_ZERO_ERROR;7059UBiDi *bidi_iter = ubidi_openSized(end - start, 0, &err);7060if (U_SUCCESS(err)) {7061switch (static_cast<TextServer::Direction>(bidi_ranges[ov].z)) {7062case DIRECTION_LTR: {7063ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err);7064} break;7065case DIRECTION_RTL: {7066ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err);7067} break;7068case DIRECTION_INHERITED: {7069ubidi_setPara(bidi_iter, data + start, end - start, sd->base_para_direction, nullptr, &err);7070} break;7071case DIRECTION_AUTO: {7072UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start);7073if (direction != UBIDI_NEUTRAL) {7074ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);7075} else {7076ubidi_setPara(bidi_iter, data + start, end - start, sd->base_para_direction, nullptr, &err);7077}7078} break;7079}7080if (U_FAILURE(err)) {7081ubidi_close(bidi_iter);7082bidi_iter = nullptr;7083ERR_PRINT(vformat("BiDi reordering for the paragraph failed: %s", u_errorName(err)));7084}7085} else {7086bidi_iter = nullptr;7087ERR_PRINT(vformat("BiDi iterator allocation for the paragraph failed: %s", u_errorName(err)));7088}7089sd->bidi_iter.push_back(bidi_iter);70907091err = U_ZERO_ERROR;7092int bidi_run_count = 1;7093if (bidi_iter) {7094bidi_run_count = ubidi_countRuns(bidi_iter, &err);7095if (U_FAILURE(err)) {7096ERR_PRINT(u_errorName(err));7097}7098}7099for (int i = 0; i < bidi_run_count; i++) {7100int32_t _bidi_run_start = 0;7101int32_t _bidi_run_length = end - start;7102bool is_ltr = false;7103hb_direction_t bidi_run_direction = HB_DIRECTION_INVALID;7104if (bidi_iter) {7105is_ltr = (ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length) == UBIDI_LTR);7106}7107switch (sd->orientation) {7108case ORIENTATION_HORIZONTAL: {7109if (is_ltr) {7110bidi_run_direction = HB_DIRECTION_LTR;7111} else {7112bidi_run_direction = HB_DIRECTION_RTL;7113}7114} break;7115case ORIENTATION_VERTICAL: {7116if (is_ltr) {7117bidi_run_direction = HB_DIRECTION_TTB;7118} else {7119bidi_run_direction = HB_DIRECTION_BTT;7120}7121}7122}71237124int32_t bidi_run_start = _convert_pos(sd, start + _bidi_run_start);7125int32_t bidi_run_end = _convert_pos(sd, start + _bidi_run_start + _bidi_run_length);71267127// Shape runs.71287129int scr_from = (is_ltr) ? 0 : sd->script_iter->script_ranges.size() - 1;7130int scr_to = (is_ltr) ? sd->script_iter->script_ranges.size() : -1;7131int scr_delta = (is_ltr) ? +1 : -1;71327133for (int j = scr_from; j != scr_to; j += scr_delta) {7134if ((sd->script_iter->script_ranges[j].start < bidi_run_end) && (sd->script_iter->script_ranges[j].end > bidi_run_start)) {7135int32_t script_run_start = MAX(sd->script_iter->script_ranges[j].start, bidi_run_start);7136int32_t script_run_end = MIN(sd->script_iter->script_ranges[j].end, bidi_run_end);7137char scr_buffer[5] = { 0, 0, 0, 0, 0 };7138hb_tag_to_string(hb_script_to_iso15924_tag(sd->script_iter->script_ranges[j].script), scr_buffer);7139String script_code = String(scr_buffer);71407141int spn_from = (is_ltr) ? 0 : sd->spans.size() - 1;7142int spn_to = (is_ltr) ? sd->spans.size() : -1;7143int spn_delta = (is_ltr) ? +1 : -1;71447145for (int k = spn_from; k != spn_to; k += spn_delta) {7146const ShapedTextDataAdvanced::Span &span = sd->spans[k];7147int col_key_off = (span.start == span.end) ? 1 : 0;7148if (span.start - sd->start >= script_run_end || span.end - sd->start <= script_run_start - col_key_off) {7149continue;7150}7151if (span.embedded_key != Variant()) {7152// Embedded object.7153if (sd->orientation == ORIENTATION_HORIZONTAL) {7154sd->objects[span.embedded_key].rect.position.x = sd->width;7155sd->width += sd->objects[span.embedded_key].rect.size.x;7156} else {7157sd->objects[span.embedded_key].rect.position.y = sd->width;7158sd->width += sd->objects[span.embedded_key].rect.size.y;7159}7160Glyph gl;7161gl.start = span.start;7162gl.end = span.end;7163gl.count = 1;7164gl.span_index = k;7165gl.flags = GRAPHEME_IS_VALID | GRAPHEME_IS_EMBEDDED_OBJECT;7166if (sd->orientation == ORIENTATION_HORIZONTAL) {7167gl.advance = sd->objects[span.embedded_key].rect.size.x;7168} else {7169gl.advance = sd->objects[span.embedded_key].rect.size.y;7170}7171sd->glyphs.push_back(gl);7172} else {7173Array fonts;7174Array fonts_scr_only;7175Array fonts_no_match;7176int font_count = span.fonts.size();7177if (font_count > 0) {7178fonts.push_back(sd->spans[k].fonts[0]);7179}7180for (int l = 1; l < font_count; l++) {7181if (_font_is_script_supported(span.fonts[l], script_code)) {7182if (_font_is_language_supported(span.fonts[l], span.language)) {7183fonts.push_back(sd->spans[k].fonts[l]);7184} else {7185fonts_scr_only.push_back(sd->spans[k].fonts[l]);7186}7187} else {7188fonts_no_match.push_back(sd->spans[k].fonts[l]);7189}7190}7191fonts.append_array(fonts_scr_only);7192fonts.append_array(fonts_no_match);7193_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());7194}7195}7196}7197}7198}7199}72007201_realign(sd);7202sd->valid.set();7203return sd->valid.is_set();7204}72057206bool TextServerAdvanced::_shaped_text_is_ready(const RID &p_shaped) const {7207const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7208ERR_FAIL_NULL_V(sd, false);72097210// Atomic read is safe and faster.7211return sd->valid.is_set();7212}72137214const Glyph *TextServerAdvanced::_shaped_text_get_glyphs(const RID &p_shaped) const {7215const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7216ERR_FAIL_NULL_V(sd, nullptr);72177218MutexLock lock(sd->mutex);7219if (!sd->valid.is_set()) {7220const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7221}7222return sd->glyphs.ptr();7223}72247225int64_t TextServerAdvanced::_shaped_text_get_glyph_count(const RID &p_shaped) const {7226const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7227ERR_FAIL_NULL_V(sd, 0);72287229MutexLock lock(sd->mutex);7230if (!sd->valid.is_set()) {7231const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7232}7233return sd->glyphs.size();7234}72357236const Glyph *TextServerAdvanced::_shaped_text_sort_logical(const RID &p_shaped) {7237ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7238ERR_FAIL_NULL_V(sd, nullptr);72397240MutexLock lock(sd->mutex);7241if (!sd->valid.is_set()) {7242_shaped_text_shape(p_shaped);7243}72447245if (!sd->sort_valid) {7246sd->glyphs_logical = sd->glyphs;7247sd->glyphs_logical.sort_custom<GlyphCompare>();7248sd->sort_valid = true;7249}72507251return sd->glyphs_logical.ptr();7252}72537254Vector2i TextServerAdvanced::_shaped_text_get_range(const RID &p_shaped) const {7255const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7256ERR_FAIL_NULL_V(sd, Vector2i());72577258MutexLock lock(sd->mutex);7259return Vector2(sd->start, sd->end);7260}72617262Array TextServerAdvanced::_shaped_text_get_objects(const RID &p_shaped) const {7263Array ret;7264const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7265ERR_FAIL_NULL_V(sd, ret);72667267MutexLock lock(sd->mutex);7268for (const KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : sd->objects) {7269ret.push_back(E.key);7270}72717272return ret;7273}72747275Rect2 TextServerAdvanced::_shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const {7276const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7277ERR_FAIL_NULL_V(sd, Rect2());72787279MutexLock lock(sd->mutex);7280ERR_FAIL_COND_V(!sd->objects.has(p_key), Rect2());7281if (!sd->valid.is_set()) {7282const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7283}7284return sd->objects[p_key].rect;7285}72867287Vector2i TextServerAdvanced::_shaped_text_get_object_range(const RID &p_shaped, const Variant &p_key) const {7288const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7289ERR_FAIL_NULL_V(sd, Vector2i());72907291MutexLock lock(sd->mutex);7292ERR_FAIL_COND_V(!sd->objects.has(p_key), Vector2i());7293return Vector2i(sd->objects[p_key].start, sd->objects[p_key].end);7294}72957296int64_t TextServerAdvanced::_shaped_text_get_object_glyph(const RID &p_shaped, const Variant &p_key) const {7297const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7298ERR_FAIL_NULL_V(sd, -1);72997300MutexLock lock(sd->mutex);7301ERR_FAIL_COND_V(!sd->objects.has(p_key), -1);7302if (!sd->valid.is_set()) {7303const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7304}7305const ShapedTextDataAdvanced::EmbeddedObject &obj = sd->objects[p_key];7306int sd_size = sd->glyphs.size();7307const Glyph *sd_glyphs = sd->glyphs.ptr();7308for (int i = 0; i < sd_size; i++) {7309if (obj.start == sd_glyphs[i].start) {7310return i;7311}7312}7313return -1;7314}73157316Size2 TextServerAdvanced::_shaped_text_get_size(const RID &p_shaped) const {7317const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7318ERR_FAIL_NULL_V(sd, Size2());73197320MutexLock lock(sd->mutex);7321if (!sd->valid.is_set()) {7322const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7323}7324if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) {7325return Size2((sd->text_trimmed ? sd->width_trimmed : sd->width), sd->ascent + sd->descent + sd->extra_spacing[SPACING_TOP] + sd->extra_spacing[SPACING_BOTTOM]).ceil();7326} else {7327return Size2(sd->ascent + sd->descent + sd->extra_spacing[SPACING_TOP] + sd->extra_spacing[SPACING_BOTTOM], (sd->text_trimmed ? sd->width_trimmed : sd->width)).ceil();7328}7329}73307331double TextServerAdvanced::_shaped_text_get_ascent(const RID &p_shaped) const {7332const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7333ERR_FAIL_NULL_V(sd, 0.0);73347335MutexLock lock(sd->mutex);7336if (!sd->valid.is_set()) {7337const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7338}7339return sd->ascent + sd->extra_spacing[SPACING_TOP];7340}73417342double TextServerAdvanced::_shaped_text_get_descent(const RID &p_shaped) const {7343const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7344ERR_FAIL_NULL_V(sd, 0.0);73457346MutexLock lock(sd->mutex);7347if (!sd->valid.is_set()) {7348const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7349}7350return sd->descent + sd->extra_spacing[SPACING_BOTTOM];7351}73527353double TextServerAdvanced::_shaped_text_get_width(const RID &p_shaped) const {7354const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7355ERR_FAIL_NULL_V(sd, 0.0);73567357MutexLock lock(sd->mutex);7358if (!sd->valid.is_set()) {7359const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7360}7361return Math::ceil(sd->text_trimmed ? sd->width_trimmed : sd->width);7362}73637364double TextServerAdvanced::_shaped_text_get_underline_position(const RID &p_shaped) const {7365const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7366ERR_FAIL_NULL_V(sd, 0.0);73677368MutexLock lock(sd->mutex);7369if (!sd->valid.is_set()) {7370const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7371}73727373return sd->upos;7374}73757376double TextServerAdvanced::_shaped_text_get_underline_thickness(const RID &p_shaped) const {7377const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7378ERR_FAIL_NULL_V(sd, 0.0);73797380MutexLock lock(sd->mutex);7381if (!sd->valid.is_set()) {7382const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7383}73847385return sd->uthk;7386}73877388void TextServerAdvanced::_insert_num_systems_lang() {7389// Eastern Arabic numerals.7390{7391NumSystemData ar;7392ar.lang.insert(StringName("ar")); // Arabic7393ar.lang.insert(StringName("ar_AE"));7394ar.lang.insert(StringName("ar_BH"));7395ar.lang.insert(StringName("ar_DJ"));7396ar.lang.insert(StringName("ar_EG"));7397ar.lang.insert(StringName("ar_ER"));7398ar.lang.insert(StringName("ar_IL"));7399ar.lang.insert(StringName("ar_IQ"));7400ar.lang.insert(StringName("ar_JO"));7401ar.lang.insert(StringName("ar_KM"));7402ar.lang.insert(StringName("ar_KW"));7403ar.lang.insert(StringName("ar_LB"));7404ar.lang.insert(StringName("ar_MR"));7405ar.lang.insert(StringName("ar_OM"));7406ar.lang.insert(StringName("ar_PS"));7407ar.lang.insert(StringName("ar_QA"));7408ar.lang.insert(StringName("ar_SA"));7409ar.lang.insert(StringName("ar_SD"));7410ar.lang.insert(StringName("ar_SO"));7411ar.lang.insert(StringName("ar_SS"));7412ar.lang.insert(StringName("ar_SY"));7413ar.lang.insert(StringName("ar_TD"));7414ar.lang.insert(StringName("ar_YE"));7415ar.lang.insert(StringName("ckb")); // Central Kurdish7416ar.lang.insert(StringName("ckb_IQ"));7417ar.lang.insert(StringName("ckb_IR"));7418ar.lang.insert(StringName("sd")); // Sindhi7419ar.lang.insert(StringName("sd_PK"));7420ar.lang.insert(StringName("sd_Arab"));7421ar.lang.insert(StringName("sd_Arab_PK"));7422ar.digits = U"٠١٢٣٤٥٦٧٨٩٫";7423ar.percent_sign = U"٪";7424ar.exp_l = U"اس";7425ar.exp_u = U"اس";7426num_systems.push_back(ar);7427}74287429// Persian and Urdu numerals.7430{7431NumSystemData pr;7432pr.lang.insert(StringName("fa")); // Persian7433pr.lang.insert(StringName("fa_AF"));7434pr.lang.insert(StringName("fa_IR"));7435pr.lang.insert(StringName("ks")); // Kashmiri7436pr.lang.insert(StringName("ks_IN"));7437pr.lang.insert(StringName("ks_Arab"));7438pr.lang.insert(StringName("ks_Arab_IN"));7439pr.lang.insert(StringName("lrc")); // Northern Luri7440pr.lang.insert(StringName("lrc_IQ"));7441pr.lang.insert(StringName("lrc_IR"));7442pr.lang.insert(StringName("mzn")); // Mazanderani7443pr.lang.insert(StringName("mzn_IR"));7444pr.lang.insert(StringName("pa_PK")); // Panjabi7445pr.lang.insert(StringName("pa_Arab"));7446pr.lang.insert(StringName("pa_Arab_PK"));7447pr.lang.insert(StringName("ps")); // Pushto7448pr.lang.insert(StringName("ps_AF"));7449pr.lang.insert(StringName("ps_PK"));7450pr.lang.insert(StringName("ur_IN")); // Urdu7451pr.lang.insert(StringName("uz_AF")); // Uzbek7452pr.lang.insert(StringName("uz_Arab"));7453pr.lang.insert(StringName("uz_Arab_AF"));7454pr.digits = U"۰۱۲۳۴۵۶۷۸۹٫";7455pr.percent_sign = U"٪";7456pr.exp_l = U"اس";7457pr.exp_u = U"اس";7458num_systems.push_back(pr);7459}74607461// Bengali numerals.7462{7463NumSystemData bn;7464bn.lang.insert(StringName("as")); // Assamese7465bn.lang.insert(StringName("as_IN"));7466bn.lang.insert(StringName("bn")); // Bengali7467bn.lang.insert(StringName("bn_BD"));7468bn.lang.insert(StringName("bn_IN"));7469bn.lang.insert(StringName("mni")); // Manipuri7470bn.lang.insert(StringName("mni_IN"));7471bn.lang.insert(StringName("mni_Beng"));7472bn.lang.insert(StringName("mni_Beng_IN"));7473bn.digits = U"০১২৩৪৫৬৭৮৯.";7474bn.percent_sign = U"%";7475bn.exp_l = U"e";7476bn.exp_u = U"E";7477num_systems.push_back(bn);7478}74797480// Devanagari numerals.7481{7482NumSystemData mr;7483mr.lang.insert(StringName("mr")); // Marathi7484mr.lang.insert(StringName("mr_IN"));7485mr.lang.insert(StringName("ne")); // Nepali7486mr.lang.insert(StringName("ne_IN"));7487mr.lang.insert(StringName("ne_NP"));7488mr.lang.insert(StringName("sa")); // Sanskrit7489mr.lang.insert(StringName("sa_IN"));7490mr.digits = U"०१२३४५६७८९.";7491mr.percent_sign = U"%";7492mr.exp_l = U"e";7493mr.exp_u = U"E";7494num_systems.push_back(mr);7495}74967497// Dzongkha numerals.7498{7499NumSystemData dz;7500dz.lang.insert(StringName("dz")); // Dzongkha7501dz.lang.insert(StringName("dz_BT"));7502dz.digits = U"༠༡༢༣༤༥༦༧༨༩.";7503dz.percent_sign = U"%";7504dz.exp_l = U"e";7505dz.exp_u = U"E";7506num_systems.push_back(dz);7507}75087509// Santali numerals.7510{7511NumSystemData sat;7512sat.lang.insert(StringName("sat")); // Santali7513sat.lang.insert(StringName("sat_IN"));7514sat.lang.insert(StringName("sat_Olck"));7515sat.lang.insert(StringName("sat_Olck_IN"));7516sat.digits = U"᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙.";7517sat.percent_sign = U"%";7518sat.exp_l = U"e";7519sat.exp_u = U"E";7520num_systems.push_back(sat);7521}75227523// Burmese numerals.7524{7525NumSystemData my;7526my.lang.insert(StringName("my")); // Burmese7527my.lang.insert(StringName("my_MM"));7528my.digits = U"၀၁၂၃၄၅၆၇၈၉.";7529my.percent_sign = U"%";7530my.exp_l = U"e";7531my.exp_u = U"E";7532num_systems.push_back(my);7533}75347535// Chakma numerals.7536{7537NumSystemData ccp;7538ccp.lang.insert(StringName("ccp")); // Chakma7539ccp.lang.insert(StringName("ccp_BD"));7540ccp.lang.insert(StringName("ccp_IN"));7541ccp.digits = U"𑄶𑄷𑄸𑄹𑄺𑄻𑄼𑄽𑄾𑄿.";7542ccp.percent_sign = U"%";7543ccp.exp_l = U"e";7544ccp.exp_u = U"E";7545num_systems.push_back(ccp);7546}75477548// Adlam numerals.7549{7550NumSystemData ff;7551ff.lang.insert(StringName("ff")); // Fulah7552ff.lang.insert(StringName("ff_Adlm_BF"));7553ff.lang.insert(StringName("ff_Adlm_CM"));7554ff.lang.insert(StringName("ff_Adlm_GH"));7555ff.lang.insert(StringName("ff_Adlm_GM"));7556ff.lang.insert(StringName("ff_Adlm_GN"));7557ff.lang.insert(StringName("ff_Adlm_GW"));7558ff.lang.insert(StringName("ff_Adlm_LR"));7559ff.lang.insert(StringName("ff_Adlm_MR"));7560ff.lang.insert(StringName("ff_Adlm_NE"));7561ff.lang.insert(StringName("ff_Adlm_NG"));7562ff.lang.insert(StringName("ff_Adlm_SL"));7563ff.lang.insert(StringName("ff_Adlm_SN"));7564ff.digits = U"𞥐𞥑𞥒𞥓𞥔𞥕𞥖𞥗𞥘𞥙.";7565ff.percent_sign = U"%";7566ff.exp_l = U"𞤉";7567ff.exp_u = U"𞤉";7568num_systems.push_back(ff);7569}7570}75717572String TextServerAdvanced::_format_number(const String &p_string, const String &p_language) const {7573const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;75747575String res = p_string;7576for (int i = 0; i < num_systems.size(); i++) {7577if (num_systems[i].lang.has(lang)) {7578if (num_systems[i].digits.is_empty()) {7579return p_string;7580}7581res = res.replace("e", num_systems[i].exp_l);7582res = res.replace("E", num_systems[i].exp_u);7583char32_t *data = res.ptrw();7584for (int j = 0; j < res.length(); j++) {7585if (data[j] >= 0x30 && data[j] <= 0x39) {7586data[j] = num_systems[i].digits[data[j] - 0x30];7587} else if (data[j] == '.' || data[j] == ',') {7588data[j] = num_systems[i].digits[10];7589}7590}7591break;7592}7593}7594return res;7595}75967597String TextServerAdvanced::_parse_number(const String &p_string, const String &p_language) const {7598const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;75997600String res = p_string;7601for (int i = 0; i < num_systems.size(); i++) {7602if (num_systems[i].lang.has(lang)) {7603if (num_systems[i].digits.is_empty()) {7604return p_string;7605}7606res = res.replace(num_systems[i].exp_l, "e");7607res = res.replace(num_systems[i].exp_u, "E");7608char32_t *data = res.ptrw();7609for (int j = 0; j < res.length(); j++) {7610if (data[j] == num_systems[i].digits[10]) {7611data[j] = '.';7612} else {7613for (int k = 0; k < 10; k++) {7614if (data[j] == num_systems[i].digits[k]) {7615data[j] = 0x30 + k;7616}7617}7618}7619}7620break;7621}7622}7623return res;7624}76257626String TextServerAdvanced::_percent_sign(const String &p_language) const {7627const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;76287629for (int i = 0; i < num_systems.size(); i++) {7630if (num_systems[i].lang.has(lang)) {7631if (num_systems[i].percent_sign.is_empty()) {7632return "%";7633}7634return num_systems[i].percent_sign;7635}7636}7637return "%";7638}76397640int64_t TextServerAdvanced::_is_confusable(const String &p_string, const PackedStringArray &p_dict) const {7641#ifndef ICU_STATIC_DATA7642if (!icu_data_loaded) {7643return -1;7644}7645#endif7646UErrorCode status = U_ZERO_ERROR;7647int64_t match_index = -1;76487649Char16String utf16 = p_string.utf16();7650Vector<UChar *> skeletons;7651skeletons.resize(p_dict.size());76527653if (sc_conf == nullptr) {7654sc_conf = uspoof_open(&status);7655uspoof_setChecks(sc_conf, USPOOF_CONFUSABLE, &status);7656}7657for (int i = 0; i < p_dict.size(); i++) {7658Char16String word = p_dict[i].utf16();7659int32_t len = uspoof_getSkeleton(sc_conf, 0, word.get_data(), -1, nullptr, 0, &status);7660skeletons.write[i] = (UChar *)memalloc(++len * sizeof(UChar));7661status = U_ZERO_ERROR;7662uspoof_getSkeleton(sc_conf, 0, word.get_data(), -1, skeletons.write[i], len, &status);7663}76647665int32_t len = uspoof_getSkeleton(sc_conf, 0, utf16.get_data(), -1, nullptr, 0, &status);7666UChar *skel = (UChar *)memalloc(++len * sizeof(UChar));7667status = U_ZERO_ERROR;7668uspoof_getSkeleton(sc_conf, 0, utf16.get_data(), -1, skel, len, &status);7669for (int i = 0; i < skeletons.size(); i++) {7670if (u_strcmp(skel, skeletons[i]) == 0) {7671match_index = i;7672break;7673}7674}7675memfree(skel);76767677for (int i = 0; i < skeletons.size(); i++) {7678memfree(skeletons.write[i]);7679}76807681ERR_FAIL_COND_V_MSG(U_FAILURE(status), -1, u_errorName(status));76827683return match_index;7684}76857686bool TextServerAdvanced::_spoof_check(const String &p_string) const {7687#ifndef ICU_STATIC_DATA7688if (!icu_data_loaded) {7689return false;7690}7691#endif7692UErrorCode status = U_ZERO_ERROR;7693Char16String utf16 = p_string.utf16();76947695if (allowed == nullptr) {7696allowed = uset_openEmpty();7697uset_addAll(allowed, uspoof_getRecommendedSet(&status));7698uset_addAll(allowed, uspoof_getInclusionSet(&status));7699}7700if (sc_spoof == nullptr) {7701sc_spoof = uspoof_open(&status);7702uspoof_setAllowedChars(sc_spoof, allowed, &status);7703uspoof_setRestrictionLevel(sc_spoof, USPOOF_MODERATELY_RESTRICTIVE);7704}77057706int32_t bitmask = uspoof_check(sc_spoof, utf16.get_data(), -1, nullptr, &status);7707ERR_FAIL_COND_V_MSG(U_FAILURE(status), false, u_errorName(status));77087709return (bitmask != 0);7710}77117712String TextServerAdvanced::_strip_diacritics(const String &p_string) const {7713#ifndef ICU_STATIC_DATA7714if (!icu_data_loaded) {7715return TextServer::strip_diacritics(p_string);7716}7717#endif7718UErrorCode err = U_ZERO_ERROR;77197720// Get NFKD normalizer singleton.7721const UNormalizer2 *unorm = unorm2_getNFKDInstance(&err);7722ERR_FAIL_COND_V_MSG(U_FAILURE(err), TextServer::strip_diacritics(p_string), u_errorName(err));77237724// Convert to UTF-16.7725Char16String utf16 = p_string.utf16();77267727// Normalize.7728Vector<char16_t> normalized;7729err = U_ZERO_ERROR;7730int32_t len = unorm2_normalize(unorm, utf16.get_data(), -1, nullptr, 0, &err);7731ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, TextServer::strip_diacritics(p_string), u_errorName(err));7732normalized.resize(len);7733err = U_ZERO_ERROR;7734unorm2_normalize(unorm, utf16.get_data(), -1, normalized.ptrw(), len, &err);7735ERR_FAIL_COND_V_MSG(U_FAILURE(err), TextServer::strip_diacritics(p_string), u_errorName(err));77367737// Convert back to UTF-32.7738String normalized_string = String::utf16(normalized.ptr(), len);77397740// Strip combining characters.7741String result;7742for (int i = 0; i < normalized_string.length(); i++) {7743if (u_getCombiningClass(normalized_string[i]) == 0) {7744#ifdef GDEXTENSION7745result = result + String::chr(normalized_string[i]);7746#elif defined(GODOT_MODULE)7747result = result + normalized_string[i];7748#endif7749}7750}7751return result;7752}77537754String TextServerAdvanced::_string_to_upper(const String &p_string, const String &p_language) const {7755#ifndef ICU_STATIC_DATA7756if (!icu_data_loaded) {7757return p_string.to_upper();7758}7759#endif77607761if (p_string.is_empty()) {7762return p_string;7763}7764const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;77657766// Convert to UTF-16.7767Char16String utf16 = p_string.utf16();77687769Vector<char16_t> upper;7770UErrorCode err = U_ZERO_ERROR;7771int32_t len = u_strToUpper(nullptr, 0, utf16.get_data(), -1, lang.ascii().get_data(), &err);7772ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));7773upper.resize(len);7774err = U_ZERO_ERROR;7775u_strToUpper(upper.ptrw(), len, utf16.get_data(), -1, lang.ascii().get_data(), &err);7776ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));77777778// Convert back to UTF-32.7779return String::utf16(upper.ptr(), len);7780}77817782String TextServerAdvanced::_string_to_lower(const String &p_string, const String &p_language) const {7783#ifndef ICU_STATIC_DATA7784if (!icu_data_loaded) {7785return p_string.to_lower();7786}7787#endif77887789if (p_string.is_empty()) {7790return p_string;7791}7792const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;7793// Convert to UTF-16.7794Char16String utf16 = p_string.utf16();77957796Vector<char16_t> lower;7797UErrorCode err = U_ZERO_ERROR;7798int32_t len = u_strToLower(nullptr, 0, utf16.get_data(), -1, lang.ascii().get_data(), &err);7799ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));7800lower.resize(len);7801err = U_ZERO_ERROR;7802u_strToLower(lower.ptrw(), len, utf16.get_data(), -1, lang.ascii().get_data(), &err);7803ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));78047805// Convert back to UTF-32.7806return String::utf16(lower.ptr(), len);7807}78087809String TextServerAdvanced::_string_to_title(const String &p_string, const String &p_language) const {7810#ifndef ICU_STATIC_DATA7811if (!icu_data_loaded) {7812return p_string.capitalize();7813}7814#endif78157816if (p_string.is_empty()) {7817return p_string;7818}7819const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;78207821// Convert to UTF-16.7822Char16String utf16 = p_string.utf16();78237824Vector<char16_t> upper;7825UErrorCode err = U_ZERO_ERROR;7826int32_t len = u_strToTitle(nullptr, 0, utf16.get_data(), -1, nullptr, lang.ascii().get_data(), &err);7827ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));7828upper.resize(len);7829err = U_ZERO_ERROR;7830u_strToTitle(upper.ptrw(), len, utf16.get_data(), -1, nullptr, lang.ascii().get_data(), &err);7831ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));78327833// Convert back to UTF-32.7834return String::utf16(upper.ptr(), len);7835}78367837PackedInt32Array TextServerAdvanced::_string_get_word_breaks(const String &p_string, const String &p_language, int64_t p_chars_per_line) const {7838const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;7839// Convert to UTF-16.7840Char16String utf16 = p_string.utf16();78417842HashSet<int> breaks;7843UErrorCode err = U_ZERO_ERROR;7844UBreakIterator *bi = ubrk_open(UBRK_WORD, lang.ascii().get_data(), (const UChar *)utf16.get_data(), utf16.length(), &err);7845if (U_SUCCESS(err)) {7846while (ubrk_next(bi) != UBRK_DONE) {7847int pos = _convert_pos(p_string, utf16, ubrk_current(bi));7848if (pos != p_string.length() - 1) {7849breaks.insert(pos);7850}7851}7852ubrk_close(bi);7853}78547855PackedInt32Array ret;78567857if (p_chars_per_line > 0) {7858int line_start = 0;7859int last_break = -1;7860int line_length = 0;78617862for (int i = 0; i < p_string.length(); i++) {7863const char32_t c = p_string[i];78647865bool is_lb = is_linebreak(c);7866bool is_ws = is_whitespace(c);7867bool is_p = (u_ispunct(c) && c != 0x005F) || is_underscore(c) || c == '\t' || c == 0xfffc;78687869if (is_lb) {7870if (line_length > 0) {7871ret.push_back(line_start);7872ret.push_back(i);7873}7874line_start = i;7875line_length = 0;7876last_break = -1;7877continue;7878} else if (breaks.has(i) || is_ws || is_p) {7879last_break = i;7880}78817882if (line_length == p_chars_per_line) {7883if (last_break != -1) {7884int last_break_w_spaces = last_break;7885while (last_break > line_start && is_whitespace(p_string[last_break - 1])) {7886last_break--;7887}7888if (line_start != last_break) {7889ret.push_back(line_start);7890ret.push_back(last_break);7891}7892while (last_break_w_spaces < p_string.length() && is_whitespace(p_string[last_break_w_spaces])) {7893last_break_w_spaces++;7894}7895line_start = last_break_w_spaces;7896if (last_break_w_spaces < i) {7897line_length = i - last_break_w_spaces;7898} else {7899i = last_break_w_spaces;7900line_length = 0;7901}7902} else {7903ret.push_back(line_start);7904ret.push_back(i);7905line_start = i;7906line_length = 0;7907}7908last_break = -1;7909}7910line_length++;7911}7912if (line_length > 0) {7913ret.push_back(line_start);7914ret.push_back(p_string.length());7915}7916} else {7917int word_start = 0; // -1 if no word encountered. Leading spaces are part of a word.7918int word_length = 0;79197920for (int i = 0; i < p_string.length(); i++) {7921const char32_t c = p_string[i];79227923bool is_lb = is_linebreak(c);7924bool is_ws = is_whitespace(c);7925bool is_p = (u_ispunct(c) && c != 0x005F) || is_underscore(c) || c == '\t' || c == 0xfffc;79267927if (word_start == -1) {7928if (!is_lb && !is_ws && !is_p) {7929word_start = i;7930}7931continue;7932}79337934if (is_lb) {7935if (word_start != -1 && word_length > 0) {7936ret.push_back(word_start);7937ret.push_back(i);7938}7939word_start = -1;7940word_length = 0;7941} else if (breaks.has(i) || is_ws || is_p) {7942if (word_start != -1 && word_length > 0) {7943ret.push_back(word_start);7944ret.push_back(i);7945}7946if (is_ws || is_p) {7947word_start = -1;7948} else {7949word_start = i;7950}7951word_length = 0;7952}79537954word_length++;7955}7956if (word_start != -1 && word_length > 0) {7957ret.push_back(word_start);7958ret.push_back(p_string.length());7959}7960}79617962return ret;7963}79647965PackedInt32Array TextServerAdvanced::_string_get_character_breaks(const String &p_string, const String &p_language) const {7966const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;7967// Convert to UTF-16.7968Char16String utf16 = p_string.utf16();79697970PackedInt32Array ret;79717972UErrorCode err = U_ZERO_ERROR;7973UBreakIterator *bi = ubrk_open(UBRK_CHARACTER, lang.ascii().get_data(), (const UChar *)utf16.get_data(), utf16.length(), &err);7974if (U_SUCCESS(err)) {7975while (ubrk_next(bi) != UBRK_DONE) {7976int pos = _convert_pos(p_string, utf16, ubrk_current(bi));7977ret.push_back(pos);7978}7979ubrk_close(bi);7980} else {7981return TextServer::string_get_character_breaks(p_string, p_language);7982}79837984return ret;7985}79867987bool TextServerAdvanced::_is_valid_identifier(const String &p_string) const {7988#ifndef ICU_STATIC_DATA7989if (!icu_data_loaded) {7990WARN_PRINT_ONCE("ICU data is not loaded, Unicode security and spoofing detection disabled.");7991return TextServer::is_valid_identifier(p_string);7992}7993#endif79947995enum UAX31SequenceStatus {7996SEQ_NOT_STARTED,7997SEQ_STARTED,7998SEQ_STARTED_VIR,7999SEQ_NEAR_END,8000};80018002const char32_t *str = p_string.ptr();8003int len = p_string.length();80048005if (len == 0) {8006return false; // Empty string.8007}80088009UErrorCode err = U_ZERO_ERROR;8010Char16String utf16 = p_string.utf16();8011const UNormalizer2 *norm_c = unorm2_getNFCInstance(&err);8012if (U_FAILURE(err)) {8013return false; // Failed to load normalizer.8014}8015bool isnurom = unorm2_isNormalized(norm_c, utf16.get_data(), utf16.length(), &err);8016if (U_FAILURE(err) || !isnurom) {8017return false; // Do not conform to Normalization Form C.8018}80198020UAX31SequenceStatus A1_sequence_status = SEQ_NOT_STARTED;8021UScriptCode A1_scr = USCRIPT_INHERITED;8022UAX31SequenceStatus A2_sequence_status = SEQ_NOT_STARTED;8023UScriptCode A2_scr = USCRIPT_INHERITED;8024UAX31SequenceStatus B_sequence_status = SEQ_NOT_STARTED;8025UScriptCode B_scr = USCRIPT_INHERITED;80268027for (int i = 0; i < len; i++) {8028err = U_ZERO_ERROR;8029UScriptCode scr = uscript_getScript(str[i], &err);8030if (U_FAILURE(err)) {8031return false; // Invalid script.8032}8033if (uscript_getUsage(scr) != USCRIPT_USAGE_RECOMMENDED) {8034return false; // Not a recommended script.8035}8036uint8_t cat = u_charType(str[i]);8037int32_t jt = u_getIntPropertyValue(str[i], UCHAR_JOINING_TYPE);80388039// UAX #31 section 2.3 subsections A1, A2 and B, check ZWNJ and ZWJ usage.8040switch (A1_sequence_status) {8041case SEQ_NEAR_END: {8042if ((A1_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A1_scr)) {8043return false; // Mixed script.8044}8045if (jt == U_JT_RIGHT_JOINING || jt == U_JT_DUAL_JOINING) {8046A1_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.8047} else if (jt != U_JT_TRANSPARENT) {8048return false; // Invalid end of sequence.8049}8050} break;8051case SEQ_STARTED: {8052if ((A1_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A1_scr)) {8053A1_sequence_status = SEQ_NOT_STARTED; // Reset.8054} else {8055if (jt != U_JT_TRANSPARENT) {8056if (str[i] == 0x200C /*ZWNJ*/) {8057A1_sequence_status = SEQ_NEAR_END;8058continue;8059} else {8060A1_sequence_status = SEQ_NOT_STARTED; // Reset.8061}8062}8063}8064} break;8065default:8066break;8067}8068if (A1_sequence_status == SEQ_NOT_STARTED) {8069if (jt == U_JT_LEFT_JOINING || jt == U_JT_DUAL_JOINING) {8070A1_sequence_status = SEQ_STARTED;8071A1_scr = scr;8072}8073};80748075switch (A2_sequence_status) {8076case SEQ_NEAR_END: {8077if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {8078return false; // Mixed script.8079}8080if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {8081A2_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.8082} else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {8083return false; // Invalid end of sequence.8084}8085} break;8086case SEQ_STARTED_VIR: {8087if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {8088A2_sequence_status = SEQ_NOT_STARTED; // Reset.8089} else {8090if (str[i] == 0x200C /*ZWNJ*/) {8091A2_sequence_status = SEQ_NEAR_END;8092continue;8093} else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {8094A2_sequence_status = SEQ_NOT_STARTED; // Reset.8095}8096}8097} break;8098case SEQ_STARTED: {8099if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {8100A2_sequence_status = SEQ_NOT_STARTED; // Reset.8101} else {8102if (u_getCombiningClass(str[i]) == 9 /*Virama Combining Class*/) {8103A2_sequence_status = SEQ_STARTED_VIR;8104} else if (cat != U_MODIFIER_LETTER) {8105A2_sequence_status = SEQ_NOT_STARTED; // Reset.8106}8107}8108} break;8109default:8110break;8111}8112if (A2_sequence_status == SEQ_NOT_STARTED) {8113if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {8114A2_sequence_status = SEQ_STARTED;8115A2_scr = scr;8116}8117}81188119switch (B_sequence_status) {8120case SEQ_NEAR_END: {8121if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {8122return false; // Mixed script.8123}8124if (u_getIntPropertyValue(str[i], UCHAR_INDIC_SYLLABIC_CATEGORY) != U_INSC_VOWEL_DEPENDENT) {8125B_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.8126} else {8127return false; // Invalid end of sequence.8128}8129} break;8130case SEQ_STARTED_VIR: {8131if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {8132B_sequence_status = SEQ_NOT_STARTED; // Reset.8133} else {8134if (str[i] == 0x200D /*ZWJ*/) {8135B_sequence_status = SEQ_NEAR_END;8136continue;8137} else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {8138B_sequence_status = SEQ_NOT_STARTED; // Reset.8139}8140}8141} break;8142case SEQ_STARTED: {8143if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {8144B_sequence_status = SEQ_NOT_STARTED; // Reset.8145} else {8146if (u_getCombiningClass(str[i]) == 9 /*Virama Combining Class*/) {8147B_sequence_status = SEQ_STARTED_VIR;8148} else if (cat != U_MODIFIER_LETTER) {8149B_sequence_status = SEQ_NOT_STARTED; // Reset.8150}8151}8152} break;8153default:8154break;8155}8156if (B_sequence_status == SEQ_NOT_STARTED) {8157if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {8158B_sequence_status = SEQ_STARTED;8159B_scr = scr;8160}8161}81628163if (u_hasBinaryProperty(str[i], UCHAR_PATTERN_SYNTAX) || u_hasBinaryProperty(str[i], UCHAR_PATTERN_WHITE_SPACE) || u_hasBinaryProperty(str[i], UCHAR_NONCHARACTER_CODE_POINT)) {8164return false; // Not a XID_Start or XID_Continue character.8165}8166if (i == 0) {8167if (!(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)) {8168return false; // Not a XID_Start character.8169}8170} else {8171if (!(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)) {8172return false; // Not a XID_Continue character.8173}8174}8175}8176return true;8177}81788179bool TextServerAdvanced::_is_valid_letter(uint64_t p_unicode) const {8180#ifndef ICU_STATIC_DATA8181if (!icu_data_loaded) {8182return TextServer::is_valid_letter(p_unicode);8183}8184#endif81858186return u_isalpha(p_unicode);8187}81888189void TextServerAdvanced::_update_settings() {8190lcd_subpixel_layout.set((TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"));8191lb_strictness = (LineBreakStrictness)(int)GLOBAL_GET("internationalization/locale/line_breaking_strictness");8192}81938194TextServerAdvanced::TextServerAdvanced() {8195_insert_num_systems_lang();8196_insert_feature_sets();8197_bmp_create_font_funcs();8198_update_settings();8199ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &TextServerAdvanced::_update_settings));8200}82018202void TextServerAdvanced::_font_clear_system_fallback_cache() {8203_THREAD_SAFE_METHOD_8204for (const KeyValue<SystemFontKey, SystemFontCache> &E : system_fonts) {8205const Vector<SystemFontCacheRec> &sysf_cache = E.value.var;8206for (const SystemFontCacheRec &F : sysf_cache) {8207_free_rid(F.rid);8208}8209}8210system_fonts.clear();8211system_font_data.clear();8212}82138214void TextServerAdvanced::_cleanup() {8215font_clear_system_fallback_cache();8216}82178218TextServerAdvanced::~TextServerAdvanced() {8219_bmp_free_font_funcs();8220#ifdef MODULE_FREETYPE_ENABLED8221if (ft_library != nullptr) {8222FT_Done_FreeType(ft_library);8223}8224#endif8225if (sc_spoof != nullptr) {8226uspoof_close(sc_spoof);8227sc_spoof = nullptr;8228}8229if (sc_conf != nullptr) {8230uspoof_close(sc_conf);8231sc_conf = nullptr;8232}8233if (allowed != nullptr) {8234uset_close(allowed);8235allowed = nullptr;8236}8237for (const KeyValue<String, UBreakIterator *> &bi : line_break_iterators_per_language) {8238ubrk_close(bi.value);8239}82408241std::atexit(u_cleanup);8242}824382448245