Path: blob/master/modules/text_server_adv/text_server_adv.cpp
20854 views
/**************************************************************************/1/* text_server_adv.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "text_server_adv.h"3132#ifdef GDEXTENSION33// Headers for building as GDExtension plug-in.3435#include <godot_cpp/classes/file_access.hpp>36#include <godot_cpp/classes/os.hpp>37#include <godot_cpp/classes/project_settings.hpp>38#include <godot_cpp/classes/rendering_server.hpp>39#include <godot_cpp/classes/translation_server.hpp>40#include <godot_cpp/core/error_macros.hpp>4142using namespace godot;4344#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var)4546#elif defined(GODOT_MODULE)47// Headers for building as built-in module.4849#include "core/config/project_settings.h"50#include "core/error/error_macros.h"51#include "core/io/file_access.h"52#include "core/object/worker_thread_pool.h"53#include "core/string/translation_server.h"54#include "scene/resources/image_texture.h"55#include "servers/rendering/rendering_server.h"5657#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg.5859#endif6061// Built-in ICU data.6263#ifdef ICU_STATIC_DATA64#include <icudata.gen.h>65#endif6667// Thirdparty headers.6869#ifdef MODULE_MSDFGEN_ENABLED70GODOT_GCC_WARNING_PUSH_AND_IGNORE("-Wshadow")71GODOT_MSVC_WARNING_PUSH_AND_IGNORE(4458) // "Declaration of 'identifier' hides class member".7273#include <core/EdgeHolder.h>74#include <core/ShapeDistanceFinder.h>75#include <core/contour-combiners.h>76#include <core/edge-selectors.h>77#include <msdfgen.h>7879GODOT_GCC_WARNING_POP80GODOT_MSVC_WARNING_POP81#endif8283#ifdef MODULE_SVG_ENABLED84#ifdef MODULE_FREETYPE_ENABLED85#include "thorvg_svg_in_ot.h"86#endif87#endif8889/*************************************************************************/90/* bmp_font_t HarfBuzz Bitmap font interface */91/*************************************************************************/9293hb_font_funcs_t *TextServerAdvanced::funcs = nullptr;9495TextServerAdvanced::bmp_font_t *TextServerAdvanced::_bmp_font_create(TextServerAdvanced::FontForSizeAdvanced *p_face, bool p_unref) {96bmp_font_t *bm_font = memnew(bmp_font_t);9798if (!bm_font) {99return nullptr;100}101102bm_font->face = p_face;103bm_font->unref = p_unref;104105return bm_font;106}107108void TextServerAdvanced::_bmp_font_destroy(void *p_data) {109bmp_font_t *bm_font = static_cast<bmp_font_t *>(p_data);110memdelete(bm_font);111}112113hb_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) {114const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);115116if (!bm_font->face) {117return false;118}119120if (!bm_font->face->glyph_map.has(p_unicode)) {121if (bm_font->face->glyph_map.has(0xf000u + p_unicode)) {122*r_glyph = 0xf000u + p_unicode;123return true;124} else {125return false;126}127}128129*r_glyph = p_unicode;130return true;131}132133hb_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) {134const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);135136if (!bm_font->face) {137return 0;138}139140HashMap<int32_t, FontGlyph>::Iterator E = bm_font->face->glyph_map.find(p_glyph);141if (!E) {142return 0;143}144145return E->value.advance.x * 64;146}147148hb_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) {149const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);150151if (!bm_font->face) {152return 0;153}154155HashMap<int32_t, FontGlyph>::Iterator E = bm_font->face->glyph_map.find(p_glyph);156if (!E) {157return 0;158}159160return -E->value.advance.y * 64;161}162163hb_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) {164const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);165166if (!bm_font->face) {167return 0;168}169170if (!bm_font->face->kerning_map.has(Vector2i(p_left_glyph, p_right_glyph))) {171return 0;172}173174return bm_font->face->kerning_map[Vector2i(p_left_glyph, p_right_glyph)].x * 64;175}176177hb_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) {178const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);179180if (!bm_font->face) {181return false;182}183184HashMap<int32_t, FontGlyph>::Iterator E = bm_font->face->glyph_map.find(p_glyph);185if (!E) {186return false;187}188189*r_x = E->value.advance.x * 32;190*r_y = -bm_font->face->ascent * 64;191192return true;193}194195hb_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) {196const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);197198if (!bm_font->face) {199return false;200}201202HashMap<int32_t, FontGlyph>::Iterator E = bm_font->face->glyph_map.find(p_glyph);203if (!E) {204return false;205}206207r_extents->x_bearing = 0;208r_extents->y_bearing = 0;209r_extents->width = E->value.rect.size.x * 64;210r_extents->height = E->value.rect.size.y * 64;211212return true;213}214215hb_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) {216const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);217218if (!bm_font->face) {219return false;220}221222r_metrics->ascender = bm_font->face->ascent;223r_metrics->descender = bm_font->face->descent;224r_metrics->line_gap = 0;225226return true;227}228229void TextServerAdvanced::_bmp_create_font_funcs() {230if (funcs == nullptr) {231funcs = hb_font_funcs_create();232233hb_font_funcs_set_font_h_extents_func(funcs, _bmp_get_font_h_extents, nullptr, nullptr);234hb_font_funcs_set_nominal_glyph_func(funcs, _bmp_get_nominal_glyph, nullptr, nullptr);235hb_font_funcs_set_glyph_h_advance_func(funcs, _bmp_get_glyph_h_advance, nullptr, nullptr);236hb_font_funcs_set_glyph_v_advance_func(funcs, _bmp_get_glyph_v_advance, nullptr, nullptr);237hb_font_funcs_set_glyph_v_origin_func(funcs, _bmp_get_glyph_v_origin, nullptr, nullptr);238hb_font_funcs_set_glyph_h_kerning_func(funcs, _bmp_get_glyph_h_kerning, nullptr, nullptr);239hb_font_funcs_set_glyph_extents_func(funcs, _bmp_get_glyph_extents, nullptr, nullptr);240241hb_font_funcs_make_immutable(funcs);242}243}244245void TextServerAdvanced::_bmp_free_font_funcs() {246if (funcs != nullptr) {247hb_font_funcs_destroy(funcs);248funcs = nullptr;249}250}251252void TextServerAdvanced::_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontForSizeAdvanced *p_face, bool p_unref) {253hb_font_set_funcs(p_font, funcs, _bmp_font_create(p_face, p_unref), _bmp_font_destroy);254}255256hb_font_t *TextServerAdvanced::_bmp_font_create(TextServerAdvanced::FontForSizeAdvanced *p_face, hb_destroy_func_t p_destroy) {257hb_font_t *font;258hb_face_t *face = hb_face_create(nullptr, 0);259260font = hb_font_create(face);261hb_face_destroy(face);262_bmp_font_set_funcs(font, p_face, false);263return font;264}265266/*************************************************************************/267/* Character properties. */268/*************************************************************************/269270_FORCE_INLINE_ bool is_ain(char32_t p_chr) {271return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_AIN;272}273274_FORCE_INLINE_ bool is_alef(char32_t p_chr) {275return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_ALEF;276}277278_FORCE_INLINE_ bool is_beh(char32_t p_chr) {279int32_t prop = u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP);280return (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);281}282283_FORCE_INLINE_ bool is_dal(char32_t p_chr) {284return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_DAL;285}286287_FORCE_INLINE_ bool is_feh(char32_t p_chr) {288return (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_FEH) || (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_AFRICAN_FEH);289}290291_FORCE_INLINE_ bool is_gaf(char32_t p_chr) {292return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_GAF;293}294295_FORCE_INLINE_ bool is_heh(char32_t p_chr) {296return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_HEH;297}298299_FORCE_INLINE_ bool is_kaf(char32_t p_chr) {300return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_KAF;301}302303_FORCE_INLINE_ bool is_lam(char32_t p_chr) {304return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_LAM;305}306307_FORCE_INLINE_ bool is_qaf(char32_t p_chr) {308return (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_QAF) || (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_AFRICAN_QAF);309}310311_FORCE_INLINE_ bool is_reh(char32_t p_chr) {312return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_REH;313}314315_FORCE_INLINE_ bool is_seen_sad(char32_t p_chr) {316return (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_SAD) || (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_SEEN);317}318319_FORCE_INLINE_ bool is_tah(char32_t p_chr) {320return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_TAH;321}322323_FORCE_INLINE_ bool is_teh_marbuta(char32_t p_chr) {324return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_TEH_MARBUTA;325}326327_FORCE_INLINE_ bool is_yeh(char32_t p_chr) {328int32_t prop = u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP);329return (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);330}331332_FORCE_INLINE_ bool is_waw(char32_t p_chr) {333return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_WAW;334}335336_FORCE_INLINE_ bool is_transparent(char32_t p_chr) {337return u_getIntPropertyValue(p_chr, UCHAR_JOINING_TYPE) == U_JT_TRANSPARENT;338}339340_FORCE_INLINE_ bool is_ligature(char32_t p_chr, char32_t p_nchr) {341return (is_lam(p_chr) && is_alef(p_nchr));342}343344_FORCE_INLINE_ bool is_connected_to_prev(char32_t p_chr, char32_t p_pchr) {345int32_t prop = u_getIntPropertyValue(p_pchr, UCHAR_JOINING_TYPE);346return (prop != U_JT_RIGHT_JOINING) && (prop != U_JT_NON_JOINING) ? !is_ligature(p_pchr, p_chr) : false;347}348349/*************************************************************************/350351bool TextServerAdvanced::icu_data_loaded = false;352PackedByteArray TextServerAdvanced::icu_data;353354bool TextServerAdvanced::_has_feature(Feature p_feature) const {355switch (p_feature) {356case FEATURE_SIMPLE_LAYOUT:357case FEATURE_BIDI_LAYOUT:358case FEATURE_VERTICAL_LAYOUT:359case FEATURE_SHAPING:360case FEATURE_KASHIDA_JUSTIFICATION:361case FEATURE_BREAK_ITERATORS:362case FEATURE_FONT_BITMAP:363#ifdef MODULE_FREETYPE_ENABLED364case FEATURE_FONT_DYNAMIC:365#endif366#ifdef MODULE_MSDFGEN_ENABLED367case FEATURE_FONT_MSDF:368#endif369case FEATURE_FONT_VARIABLE:370case FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION:371case FEATURE_USE_SUPPORT_DATA:372case FEATURE_UNICODE_IDENTIFIERS:373case FEATURE_UNICODE_SECURITY:374return true;375default: {376}377}378return false;379}380381String TextServerAdvanced::_get_name() const {382#ifdef GDEXTENSION383return "ICU / HarfBuzz / Graphite (GDExtension)";384#elif defined(GODOT_MODULE)385return "ICU / HarfBuzz / Graphite (Built-in)";386#endif387}388389int64_t TextServerAdvanced::_get_features() const {390int64_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;391#ifdef MODULE_FREETYPE_ENABLED392interface_features |= FEATURE_FONT_DYNAMIC;393#endif394#ifdef MODULE_MSDFGEN_ENABLED395interface_features |= FEATURE_FONT_MSDF;396#endif397398return interface_features;399}400401void TextServerAdvanced::_free_rid(const RID &p_rid) {402_THREAD_SAFE_METHOD_403if (font_owner.owns(p_rid)) {404MutexLock ftlock(ft_mutex);405406FontAdvanced *fd = font_owner.get_or_null(p_rid);407for (const KeyValue<Vector2i, FontForSizeAdvanced *> &ffsd : fd->cache) {408OversamplingLevel *ol = oversampling_levels.getptr(ffsd.value->viewport_oversampling);409if (ol != nullptr) {410ol->fonts.erase(ffsd.value);411}412}413{414MutexLock lock(fd->mutex);415font_owner.free(p_rid);416}417memdelete(fd);418} else if (font_var_owner.owns(p_rid)) {419MutexLock ftlock(ft_mutex);420421FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(p_rid);422{423font_var_owner.free(p_rid);424}425memdelete(fdv);426} else if (shaped_owner.owns(p_rid)) {427ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_rid);428{429MutexLock lock(sd->mutex);430shaped_owner.free(p_rid);431}432memdelete(sd);433}434}435436bool TextServerAdvanced::_has(const RID &p_rid) {437_THREAD_SAFE_METHOD_438return font_owner.owns(p_rid) || font_var_owner.owns(p_rid) || shaped_owner.owns(p_rid);439}440441bool TextServerAdvanced::_load_support_data(const String &p_filename) {442_THREAD_SAFE_METHOD_443444#if defined(ICU_STATIC_DATA) || !defined(HAVE_ICU_BUILTIN)445if (!icu_data_loaded) {446UErrorCode err = U_ZERO_ERROR;447u_init(&err); // Do not check for errors, since we only load part of the data.448icu_data_loaded = true;449}450#else451if (!icu_data_loaded) {452UErrorCode err = U_ZERO_ERROR;453String filename = (p_filename.is_empty()) ? String("res://icudt_godot.dat") : p_filename;454if (FileAccess::exists(filename)) {455Ref<FileAccess> f = FileAccess::open(filename, FileAccess::READ);456if (f.is_null()) {457return false;458}459uint64_t len = f->get_length();460icu_data = f->get_buffer(len);461462udata_setCommonData(icu_data.ptr(), &err);463if (U_FAILURE(err)) {464ERR_FAIL_V_MSG(false, u_errorName(err));465}466467err = U_ZERO_ERROR;468icu_data_loaded = true;469}470471u_init(&err);472if (U_FAILURE(err)) {473ERR_FAIL_V_MSG(false, u_errorName(err));474}475}476#endif477return true;478}479480String TextServerAdvanced::_get_support_data_filename() const {481return String("icudt_godot.dat");482}483484String TextServerAdvanced::_get_support_data_info() const {485return String("ICU break iteration data (\"icudt_godot.dat\").");486}487488bool TextServerAdvanced::_save_support_data(const String &p_filename) const {489_THREAD_SAFE_METHOD_490#ifdef ICU_STATIC_DATA491492// Store data to the res file if it's available.493494Ref<FileAccess> f = FileAccess::open(p_filename, FileAccess::WRITE);495if (f.is_null()) {496return false;497}498499PackedByteArray icu_data_static;500icu_data_static.resize(U_ICUDATA_SIZE);501memcpy(icu_data_static.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);502f->store_buffer(icu_data_static);503504return true;505#else506return false;507#endif508}509510PackedByteArray TextServerAdvanced::_get_support_data() const {511_THREAD_SAFE_METHOD_512#ifdef ICU_STATIC_DATA513514PackedByteArray icu_data_static;515icu_data_static.resize(U_ICUDATA_SIZE);516memcpy(icu_data_static.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);517518return icu_data_static;519#else520return icu_data;521#endif522}523524bool TextServerAdvanced::_is_locale_using_support_data(const String &p_locale) const {525String l = p_locale.get_slicec('_', 0);526if ((l == "my") || (l == "zh") || (l == "ja") || (l == "ko") || (l == "km") || (l == "lo") || (l == "th")) {527return true;528} else {529return false;530}531}532533bool TextServerAdvanced::_is_locale_right_to_left(const String &p_locale) const {534String l = p_locale.get_slicec('_', 0);535if ((l == "ar") || (l == "dv") || (l == "he") || (l == "fa") || (l == "ff") || (l == "ku") || (l == "ur")) {536return true;537} else {538return false;539}540}541542_FORCE_INLINE_ void TextServerAdvanced::_insert_feature(const StringName &p_name, int32_t p_tag, Variant::Type p_vtype, bool p_hidden) {543FeatureInfo fi;544fi.name = p_name;545fi.vtype = p_vtype;546fi.hidden = p_hidden;547548feature_sets.insert(p_name, p_tag);549feature_sets_inv.insert(p_tag, fi);550}551552void TextServerAdvanced::_insert_feature_sets() {553// Registered OpenType feature tags.554// Name, Tag, Data Type, Hidden555_insert_feature("access_all_alternates", HB_TAG('a', 'a', 'l', 't'), Variant::Type::INT, false);556_insert_feature("above_base_forms", HB_TAG('a', 'b', 'v', 'f'), Variant::Type::INT, true);557_insert_feature("above_base_mark_positioning", HB_TAG('a', 'b', 'v', 'm'), Variant::Type::INT, true);558_insert_feature("above_base_substitutions", HB_TAG('a', 'b', 'v', 's'), Variant::Type::INT, true);559_insert_feature("alternative_fractions", HB_TAG('a', 'f', 'r', 'c'), Variant::Type::INT, false);560_insert_feature("akhands", HB_TAG('a', 'k', 'h', 'n'), Variant::Type::INT, true);561_insert_feature("below_base_forms", HB_TAG('b', 'l', 'w', 'f'), Variant::Type::INT, true);562_insert_feature("below_base_mark_positioning", HB_TAG('b', 'l', 'w', 'm'), Variant::Type::INT, true);563_insert_feature("below_base_substitutions", HB_TAG('b', 'l', 'w', 's'), Variant::Type::INT, true);564_insert_feature("contextual_alternates", HB_TAG('c', 'a', 'l', 't'), Variant::Type::BOOL, false);565_insert_feature("case_sensitive_forms", HB_TAG('c', 'a', 's', 'e'), Variant::Type::BOOL, false);566_insert_feature("glyph_composition", HB_TAG('c', 'c', 'm', 'p'), Variant::Type::INT, true);567_insert_feature("conjunct_form_after_ro", HB_TAG('c', 'f', 'a', 'r'), Variant::Type::INT, true);568_insert_feature("contextual_half_width_spacing", HB_TAG('c', 'h', 'w', 's'), Variant::Type::INT, true);569_insert_feature("conjunct_forms", HB_TAG('c', 'j', 'c', 't'), Variant::Type::INT, true);570_insert_feature("contextual_ligatures", HB_TAG('c', 'l', 'i', 'g'), Variant::Type::BOOL, false);571_insert_feature("centered_cjk_punctuation", HB_TAG('c', 'p', 'c', 't'), Variant::Type::BOOL, false);572_insert_feature("capital_spacing", HB_TAG('c', 'p', 's', 'p'), Variant::Type::BOOL, false);573_insert_feature("contextual_swash", HB_TAG('c', 's', 'w', 'h'), Variant::Type::INT, false);574_insert_feature("cursive_positioning", HB_TAG('c', 'u', 'r', 's'), Variant::Type::INT, true);575_insert_feature("character_variant_01", HB_TAG('c', 'v', '0', '1'), Variant::Type::BOOL, false);576_insert_feature("character_variant_02", HB_TAG('c', 'v', '0', '2'), Variant::Type::BOOL, false);577_insert_feature("character_variant_03", HB_TAG('c', 'v', '0', '3'), Variant::Type::BOOL, false);578_insert_feature("character_variant_04", HB_TAG('c', 'v', '0', '4'), Variant::Type::BOOL, false);579_insert_feature("character_variant_05", HB_TAG('c', 'v', '0', '5'), Variant::Type::BOOL, false);580_insert_feature("character_variant_06", HB_TAG('c', 'v', '0', '6'), Variant::Type::BOOL, false);581_insert_feature("character_variant_07", HB_TAG('c', 'v', '0', '7'), Variant::Type::BOOL, false);582_insert_feature("character_variant_08", HB_TAG('c', 'v', '0', '8'), Variant::Type::BOOL, false);583_insert_feature("character_variant_09", HB_TAG('c', 'v', '0', '9'), Variant::Type::BOOL, false);584_insert_feature("character_variant_10", HB_TAG('c', 'v', '1', '0'), Variant::Type::BOOL, false);585_insert_feature("character_variant_11", HB_TAG('c', 'v', '1', '1'), Variant::Type::BOOL, false);586_insert_feature("character_variant_12", HB_TAG('c', 'v', '1', '2'), Variant::Type::BOOL, false);587_insert_feature("character_variant_13", HB_TAG('c', 'v', '1', '3'), Variant::Type::BOOL, false);588_insert_feature("character_variant_14", HB_TAG('c', 'v', '1', '4'), Variant::Type::BOOL, false);589_insert_feature("character_variant_15", HB_TAG('c', 'v', '1', '5'), Variant::Type::BOOL, false);590_insert_feature("character_variant_16", HB_TAG('c', 'v', '1', '6'), Variant::Type::BOOL, false);591_insert_feature("character_variant_17", HB_TAG('c', 'v', '1', '7'), Variant::Type::BOOL, false);592_insert_feature("character_variant_18", HB_TAG('c', 'v', '1', '8'), Variant::Type::BOOL, false);593_insert_feature("character_variant_19", HB_TAG('c', 'v', '1', '9'), Variant::Type::BOOL, false);594_insert_feature("character_variant_20", HB_TAG('c', 'v', '2', '0'), Variant::Type::BOOL, false);595_insert_feature("character_variant_21", HB_TAG('c', 'v', '2', '1'), Variant::Type::BOOL, false);596_insert_feature("character_variant_22", HB_TAG('c', 'v', '2', '2'), Variant::Type::BOOL, false);597_insert_feature("character_variant_23", HB_TAG('c', 'v', '2', '3'), Variant::Type::BOOL, false);598_insert_feature("character_variant_24", HB_TAG('c', 'v', '2', '4'), Variant::Type::BOOL, false);599_insert_feature("character_variant_25", HB_TAG('c', 'v', '2', '5'), Variant::Type::BOOL, false);600_insert_feature("character_variant_26", HB_TAG('c', 'v', '2', '6'), Variant::Type::BOOL, false);601_insert_feature("character_variant_27", HB_TAG('c', 'v', '2', '7'), Variant::Type::BOOL, false);602_insert_feature("character_variant_28", HB_TAG('c', 'v', '2', '8'), Variant::Type::BOOL, false);603_insert_feature("character_variant_29", HB_TAG('c', 'v', '2', '9'), Variant::Type::BOOL, false);604_insert_feature("character_variant_30", HB_TAG('c', 'v', '3', '0'), Variant::Type::BOOL, false);605_insert_feature("character_variant_31", HB_TAG('c', 'v', '3', '1'), Variant::Type::BOOL, false);606_insert_feature("character_variant_32", HB_TAG('c', 'v', '3', '2'), Variant::Type::BOOL, false);607_insert_feature("character_variant_33", HB_TAG('c', 'v', '3', '3'), Variant::Type::BOOL, false);608_insert_feature("character_variant_34", HB_TAG('c', 'v', '3', '4'), Variant::Type::BOOL, false);609_insert_feature("character_variant_35", HB_TAG('c', 'v', '3', '5'), Variant::Type::BOOL, false);610_insert_feature("character_variant_36", HB_TAG('c', 'v', '3', '6'), Variant::Type::BOOL, false);611_insert_feature("character_variant_37", HB_TAG('c', 'v', '3', '7'), Variant::Type::BOOL, false);612_insert_feature("character_variant_38", HB_TAG('c', 'v', '3', '8'), Variant::Type::BOOL, false);613_insert_feature("character_variant_39", HB_TAG('c', 'v', '3', '9'), Variant::Type::BOOL, false);614_insert_feature("character_variant_40", HB_TAG('c', 'v', '4', '0'), Variant::Type::BOOL, false);615_insert_feature("character_variant_41", HB_TAG('c', 'v', '4', '1'), Variant::Type::BOOL, false);616_insert_feature("character_variant_42", HB_TAG('c', 'v', '4', '2'), Variant::Type::BOOL, false);617_insert_feature("character_variant_43", HB_TAG('c', 'v', '4', '3'), Variant::Type::BOOL, false);618_insert_feature("character_variant_44", HB_TAG('c', 'v', '4', '4'), Variant::Type::BOOL, false);619_insert_feature("character_variant_45", HB_TAG('c', 'v', '4', '5'), Variant::Type::BOOL, false);620_insert_feature("character_variant_46", HB_TAG('c', 'v', '4', '6'), Variant::Type::BOOL, false);621_insert_feature("character_variant_47", HB_TAG('c', 'v', '4', '7'), Variant::Type::BOOL, false);622_insert_feature("character_variant_48", HB_TAG('c', 'v', '4', '8'), Variant::Type::BOOL, false);623_insert_feature("character_variant_49", HB_TAG('c', 'v', '4', '9'), Variant::Type::BOOL, false);624_insert_feature("character_variant_50", HB_TAG('c', 'v', '5', '0'), Variant::Type::BOOL, false);625_insert_feature("character_variant_51", HB_TAG('c', 'v', '5', '1'), Variant::Type::BOOL, false);626_insert_feature("character_variant_52", HB_TAG('c', 'v', '5', '2'), Variant::Type::BOOL, false);627_insert_feature("character_variant_53", HB_TAG('c', 'v', '5', '3'), Variant::Type::BOOL, false);628_insert_feature("character_variant_54", HB_TAG('c', 'v', '5', '4'), Variant::Type::BOOL, false);629_insert_feature("character_variant_55", HB_TAG('c', 'v', '5', '5'), Variant::Type::BOOL, false);630_insert_feature("character_variant_56", HB_TAG('c', 'v', '5', '6'), Variant::Type::BOOL, false);631_insert_feature("character_variant_57", HB_TAG('c', 'v', '5', '7'), Variant::Type::BOOL, false);632_insert_feature("character_variant_58", HB_TAG('c', 'v', '5', '8'), Variant::Type::BOOL, false);633_insert_feature("character_variant_59", HB_TAG('c', 'v', '5', '9'), Variant::Type::BOOL, false);634_insert_feature("character_variant_60", HB_TAG('c', 'v', '6', '0'), Variant::Type::BOOL, false);635_insert_feature("character_variant_61", HB_TAG('c', 'v', '6', '1'), Variant::Type::BOOL, false);636_insert_feature("character_variant_62", HB_TAG('c', 'v', '6', '2'), Variant::Type::BOOL, false);637_insert_feature("character_variant_63", HB_TAG('c', 'v', '6', '3'), Variant::Type::BOOL, false);638_insert_feature("character_variant_64", HB_TAG('c', 'v', '6', '4'), Variant::Type::BOOL, false);639_insert_feature("character_variant_65", HB_TAG('c', 'v', '6', '5'), Variant::Type::BOOL, false);640_insert_feature("character_variant_66", HB_TAG('c', 'v', '6', '6'), Variant::Type::BOOL, false);641_insert_feature("character_variant_67", HB_TAG('c', 'v', '6', '7'), Variant::Type::BOOL, false);642_insert_feature("character_variant_68", HB_TAG('c', 'v', '6', '8'), Variant::Type::BOOL, false);643_insert_feature("character_variant_69", HB_TAG('c', 'v', '6', '9'), Variant::Type::BOOL, false);644_insert_feature("character_variant_70", HB_TAG('c', 'v', '7', '0'), Variant::Type::BOOL, false);645_insert_feature("character_variant_71", HB_TAG('c', 'v', '7', '1'), Variant::Type::BOOL, false);646_insert_feature("character_variant_72", HB_TAG('c', 'v', '7', '2'), Variant::Type::BOOL, false);647_insert_feature("character_variant_73", HB_TAG('c', 'v', '7', '3'), Variant::Type::BOOL, false);648_insert_feature("character_variant_74", HB_TAG('c', 'v', '7', '4'), Variant::Type::BOOL, false);649_insert_feature("character_variant_75", HB_TAG('c', 'v', '7', '5'), Variant::Type::BOOL, false);650_insert_feature("character_variant_76", HB_TAG('c', 'v', '7', '6'), Variant::Type::BOOL, false);651_insert_feature("character_variant_77", HB_TAG('c', 'v', '7', '7'), Variant::Type::BOOL, false);652_insert_feature("character_variant_78", HB_TAG('c', 'v', '7', '8'), Variant::Type::BOOL, false);653_insert_feature("character_variant_79", HB_TAG('c', 'v', '7', '9'), Variant::Type::BOOL, false);654_insert_feature("character_variant_80", HB_TAG('c', 'v', '8', '0'), Variant::Type::BOOL, false);655_insert_feature("character_variant_81", HB_TAG('c', 'v', '8', '1'), Variant::Type::BOOL, false);656_insert_feature("character_variant_82", HB_TAG('c', 'v', '8', '2'), Variant::Type::BOOL, false);657_insert_feature("character_variant_83", HB_TAG('c', 'v', '8', '3'), Variant::Type::BOOL, false);658_insert_feature("character_variant_84", HB_TAG('c', 'v', '8', '4'), Variant::Type::BOOL, false);659_insert_feature("character_variant_85", HB_TAG('c', 'v', '8', '5'), Variant::Type::BOOL, false);660_insert_feature("character_variant_86", HB_TAG('c', 'v', '8', '6'), Variant::Type::BOOL, false);661_insert_feature("character_variant_87", HB_TAG('c', 'v', '8', '7'), Variant::Type::BOOL, false);662_insert_feature("character_variant_88", HB_TAG('c', 'v', '8', '8'), Variant::Type::BOOL, false);663_insert_feature("character_variant_89", HB_TAG('c', 'v', '8', '9'), Variant::Type::BOOL, false);664_insert_feature("character_variant_90", HB_TAG('c', 'v', '9', '0'), Variant::Type::BOOL, false);665_insert_feature("character_variant_91", HB_TAG('c', 'v', '9', '1'), Variant::Type::BOOL, false);666_insert_feature("character_variant_92", HB_TAG('c', 'v', '9', '2'), Variant::Type::BOOL, false);667_insert_feature("character_variant_93", HB_TAG('c', 'v', '9', '3'), Variant::Type::BOOL, false);668_insert_feature("character_variant_94", HB_TAG('c', 'v', '9', '4'), Variant::Type::BOOL, false);669_insert_feature("character_variant_95", HB_TAG('c', 'v', '9', '5'), Variant::Type::BOOL, false);670_insert_feature("character_variant_96", HB_TAG('c', 'v', '9', '6'), Variant::Type::BOOL, false);671_insert_feature("character_variant_97", HB_TAG('c', 'v', '9', '7'), Variant::Type::BOOL, false);672_insert_feature("character_variant_98", HB_TAG('c', 'v', '9', '8'), Variant::Type::BOOL, false);673_insert_feature("character_variant_99", HB_TAG('c', 'v', '9', '9'), Variant::Type::BOOL, false);674_insert_feature("petite_capitals_from_capitals", HB_TAG('c', '2', 'p', 'c'), Variant::Type::BOOL, false);675_insert_feature("small_capitals_from_capitals", HB_TAG('c', '2', 's', 'c'), Variant::Type::BOOL, false);676_insert_feature("distances", HB_TAG('d', 'i', 's', 't'), Variant::Type::INT, true);677_insert_feature("discretionary_ligatures", HB_TAG('d', 'l', 'i', 'g'), Variant::Type::BOOL, false);678_insert_feature("denominators", HB_TAG('d', 'n', 'o', 'm'), Variant::Type::BOOL, false);679_insert_feature("dotless_forms", HB_TAG('d', 't', 'l', 's'), Variant::Type::INT, true);680_insert_feature("expert_forms", HB_TAG('e', 'x', 'p', 't'), Variant::Type::BOOL, true);681_insert_feature("final_glyph_on_line_alternates", HB_TAG('f', 'a', 'l', 't'), Variant::Type::INT, false);682_insert_feature("terminal_forms_2", HB_TAG('f', 'i', 'n', '2'), Variant::Type::INT, true);683_insert_feature("terminal_forms_3", HB_TAG('f', 'i', 'n', '3'), Variant::Type::INT, true);684_insert_feature("terminal_forms", HB_TAG('f', 'i', 'n', 'a'), Variant::Type::INT, true);685_insert_feature("flattened_accent_forms", HB_TAG('f', 'l', 'a', 'c'), Variant::Type::INT, true);686_insert_feature("fractions", HB_TAG('f', 'r', 'a', 'c'), Variant::Type::BOOL, false);687_insert_feature("full_widths", HB_TAG('f', 'w', 'i', 'd'), Variant::Type::BOOL, false);688_insert_feature("half_forms", HB_TAG('h', 'a', 'l', 'f'), Variant::Type::INT, true);689_insert_feature("halant_forms", HB_TAG('h', 'a', 'l', 'n'), Variant::Type::INT, true);690_insert_feature("alternate_half_widths", HB_TAG('h', 'a', 'l', 't'), Variant::Type::BOOL, false);691_insert_feature("historical_forms", HB_TAG('h', 'i', 's', 't'), Variant::Type::INT, false);692_insert_feature("horizontal_kana_alternates", HB_TAG('h', 'k', 'n', 'a'), Variant::Type::BOOL, false);693_insert_feature("historical_ligatures", HB_TAG('h', 'l', 'i', 'g'), Variant::Type::BOOL, false);694_insert_feature("hangul", HB_TAG('h', 'n', 'g', 'l'), Variant::Type::INT, false);695_insert_feature("hojo_kanji_forms", HB_TAG('h', 'o', 'j', 'o'), Variant::Type::INT, false);696_insert_feature("half_widths", HB_TAG('h', 'w', 'i', 'd'), Variant::Type::BOOL, false);697_insert_feature("initial_forms", HB_TAG('i', 'n', 'i', 't'), Variant::Type::INT, true);698_insert_feature("isolated_forms", HB_TAG('i', 's', 'o', 'l'), Variant::Type::INT, true);699_insert_feature("italics", HB_TAG('i', 't', 'a', 'l'), Variant::Type::INT, false);700_insert_feature("justification_alternates", HB_TAG('j', 'a', 'l', 't'), Variant::Type::INT, false);701_insert_feature("jis78_forms", HB_TAG('j', 'p', '7', '8'), Variant::Type::INT, false);702_insert_feature("jis83_forms", HB_TAG('j', 'p', '8', '3'), Variant::Type::INT, false);703_insert_feature("jis90_forms", HB_TAG('j', 'p', '9', '0'), Variant::Type::INT, false);704_insert_feature("jis2004_forms", HB_TAG('j', 'p', '0', '4'), Variant::Type::INT, false);705_insert_feature("kerning", HB_TAG('k', 'e', 'r', 'n'), Variant::Type::BOOL, false);706_insert_feature("left_bounds", HB_TAG('l', 'f', 'b', 'd'), Variant::Type::INT, false);707_insert_feature("standard_ligatures", HB_TAG('l', 'i', 'g', 'a'), Variant::Type::BOOL, false);708_insert_feature("leading_jamo_forms", HB_TAG('l', 'j', 'm', 'o'), Variant::Type::INT, true);709_insert_feature("lining_figures", HB_TAG('l', 'n', 'u', 'm'), Variant::Type::INT, false);710_insert_feature("localized_forms", HB_TAG('l', 'o', 'c', 'l'), Variant::Type::INT, true);711_insert_feature("left_to_right_alternates", HB_TAG('l', 't', 'r', 'a'), Variant::Type::INT, true);712_insert_feature("left_to_right_mirrored_forms", HB_TAG('l', 't', 'r', 'm'), Variant::Type::INT, true);713_insert_feature("mark_positioning", HB_TAG('m', 'a', 'r', 'k'), Variant::Type::INT, true);714_insert_feature("medial_forms_2", HB_TAG('m', 'e', 'd', '2'), Variant::Type::INT, true);715_insert_feature("medial_forms", HB_TAG('m', 'e', 'd', 'i'), Variant::Type::INT, true);716_insert_feature("mathematical_greek", HB_TAG('m', 'g', 'r', 'k'), Variant::Type::BOOL, false);717_insert_feature("mark_to_mark_positioning", HB_TAG('m', 'k', 'm', 'k'), Variant::Type::INT, true);718_insert_feature("mark_positioning_via_substitution", HB_TAG('m', 's', 'e', 't'), Variant::Type::INT, true);719_insert_feature("alternate_annotation_forms", HB_TAG('n', 'a', 'l', 't'), Variant::Type::INT, false);720_insert_feature("nlc_kanji_forms", HB_TAG('n', 'l', 'c', 'k'), Variant::Type::INT, false);721_insert_feature("nukta_forms", HB_TAG('n', 'u', 'k', 't'), Variant::Type::INT, true);722_insert_feature("numerators", HB_TAG('n', 'u', 'm', 'r'), Variant::Type::BOOL, false);723_insert_feature("oldstyle_figures", HB_TAG('o', 'n', 'u', 'm'), Variant::Type::INT, false);724_insert_feature("optical_bounds", HB_TAG('o', 'p', 'b', 'd'), Variant::Type::INT, true);725_insert_feature("ordinals", HB_TAG('o', 'r', 'd', 'n'), Variant::Type::BOOL, false);726_insert_feature("ornaments", HB_TAG('o', 'r', 'n', 'm'), Variant::Type::INT, false);727_insert_feature("proportional_alternate_widths", HB_TAG('p', 'a', 'l', 't'), Variant::Type::BOOL, false);728_insert_feature("petite_capitals", HB_TAG('p', 'c', 'a', 'p'), Variant::Type::BOOL, false);729_insert_feature("proportional_kana", HB_TAG('p', 'k', 'n', 'a'), Variant::Type::BOOL, false);730_insert_feature("proportional_figures", HB_TAG('p', 'n', 'u', 'm'), Variant::Type::BOOL, false);731_insert_feature("pre_base_forms", HB_TAG('p', 'r', 'e', 'f'), Variant::Type::INT, true);732_insert_feature("pre_base_substitutions", HB_TAG('p', 'r', 'e', 's'), Variant::Type::INT, true);733_insert_feature("post_base_forms", HB_TAG('p', 's', 't', 'f'), Variant::Type::INT, true);734_insert_feature("post_base_substitutions", HB_TAG('p', 's', 't', 's'), Variant::Type::INT, true);735_insert_feature("proportional_widths", HB_TAG('p', 'w', 'i', 'd'), Variant::Type::BOOL, false);736_insert_feature("quarter_widths", HB_TAG('q', 'w', 'i', 'd'), Variant::Type::BOOL, false);737_insert_feature("randomize", HB_TAG('r', 'a', 'n', 'd'), Variant::Type::INT, false);738_insert_feature("required_contextual_alternates", HB_TAG('r', 'c', 'l', 't'), Variant::Type::BOOL, true);739_insert_feature("rakar_forms", HB_TAG('r', 'k', 'r', 'f'), Variant::Type::INT, true);740_insert_feature("required_ligatures", HB_TAG('r', 'l', 'i', 'g'), Variant::Type::BOOL, true);741_insert_feature("reph_forms", HB_TAG('r', 'p', 'h', 'f'), Variant::Type::INT, true);742_insert_feature("right_bounds", HB_TAG('r', 't', 'b', 'd'), Variant::Type::INT, false);743_insert_feature("right_to_left_alternates", HB_TAG('r', 't', 'l', 'a'), Variant::Type::INT, true);744_insert_feature("right_to_left_mirrored_forms", HB_TAG('r', 't', 'l', 'm'), Variant::Type::INT, true);745_insert_feature("ruby_notation_forms", HB_TAG('r', 'u', 'b', 'y'), Variant::Type::INT, false);746_insert_feature("required_variation_alternates", HB_TAG('r', 'v', 'r', 'n'), Variant::Type::INT, true);747_insert_feature("stylistic_alternates", HB_TAG('s', 'a', 'l', 't'), Variant::Type::INT, false);748_insert_feature("scientific_inferiors", HB_TAG('s', 'i', 'n', 'f'), Variant::Type::BOOL, false);749_insert_feature("optical_size", HB_TAG('s', 'i', 'z', 'e'), Variant::Type::INT, false);750_insert_feature("small_capitals", HB_TAG('s', 'm', 'c', 'p'), Variant::Type::BOOL, false);751_insert_feature("simplified_forms", HB_TAG('s', 'm', 'p', 'l'), Variant::Type::INT, false);752_insert_feature("stylistic_set_01", HB_TAG('s', 's', '0', '1'), Variant::Type::BOOL, false);753_insert_feature("stylistic_set_02", HB_TAG('s', 's', '0', '2'), Variant::Type::BOOL, false);754_insert_feature("stylistic_set_03", HB_TAG('s', 's', '0', '3'), Variant::Type::BOOL, false);755_insert_feature("stylistic_set_04", HB_TAG('s', 's', '0', '4'), Variant::Type::BOOL, false);756_insert_feature("stylistic_set_05", HB_TAG('s', 's', '0', '5'), Variant::Type::BOOL, false);757_insert_feature("stylistic_set_06", HB_TAG('s', 's', '0', '6'), Variant::Type::BOOL, false);758_insert_feature("stylistic_set_07", HB_TAG('s', 's', '0', '7'), Variant::Type::BOOL, false);759_insert_feature("stylistic_set_08", HB_TAG('s', 's', '0', '8'), Variant::Type::BOOL, false);760_insert_feature("stylistic_set_09", HB_TAG('s', 's', '0', '9'), Variant::Type::BOOL, false);761_insert_feature("stylistic_set_10", HB_TAG('s', 's', '1', '0'), Variant::Type::BOOL, false);762_insert_feature("stylistic_set_11", HB_TAG('s', 's', '1', '1'), Variant::Type::BOOL, false);763_insert_feature("stylistic_set_12", HB_TAG('s', 's', '1', '2'), Variant::Type::BOOL, false);764_insert_feature("stylistic_set_13", HB_TAG('s', 's', '1', '3'), Variant::Type::BOOL, false);765_insert_feature("stylistic_set_14", HB_TAG('s', 's', '1', '4'), Variant::Type::BOOL, false);766_insert_feature("stylistic_set_15", HB_TAG('s', 's', '1', '5'), Variant::Type::BOOL, false);767_insert_feature("stylistic_set_16", HB_TAG('s', 's', '1', '6'), Variant::Type::BOOL, false);768_insert_feature("stylistic_set_17", HB_TAG('s', 's', '1', '7'), Variant::Type::BOOL, false);769_insert_feature("stylistic_set_18", HB_TAG('s', 's', '1', '8'), Variant::Type::BOOL, false);770_insert_feature("stylistic_set_19", HB_TAG('s', 's', '1', '9'), Variant::Type::BOOL, false);771_insert_feature("stylistic_set_20", HB_TAG('s', 's', '2', '0'), Variant::Type::BOOL, false);772_insert_feature("math_script_style_alternates", HB_TAG('s', 's', 't', 'y'), Variant::Type::INT, true);773_insert_feature("stretching_glyph_decomposition", HB_TAG('s', 't', 'c', 'h'), Variant::Type::INT, true);774_insert_feature("subscript", HB_TAG('s', 'u', 'b', 's'), Variant::Type::BOOL, false);775_insert_feature("superscript", HB_TAG('s', 'u', 'p', 's'), Variant::Type::BOOL, false);776_insert_feature("swash", HB_TAG('s', 'w', 's', 'h'), Variant::Type::INT, false);777_insert_feature("titling", HB_TAG('t', 'i', 't', 'l'), Variant::Type::BOOL, false);778_insert_feature("trailing_jamo_forms", HB_TAG('t', 'j', 'm', 'o'), Variant::Type::INT, true);779_insert_feature("traditional_name_forms", HB_TAG('t', 'n', 'a', 'm'), Variant::Type::INT, false);780_insert_feature("tabular_figures", HB_TAG('t', 'n', 'u', 'm'), Variant::Type::BOOL, false);781_insert_feature("traditional_forms", HB_TAG('t', 'r', 'a', 'd'), Variant::Type::INT, false);782_insert_feature("third_widths", HB_TAG('t', 'w', 'i', 'd'), Variant::Type::BOOL, false);783_insert_feature("unicase", HB_TAG('u', 'n', 'i', 'c'), Variant::Type::BOOL, false);784_insert_feature("alternate_vertical_metrics", HB_TAG('v', 'a', 'l', 't'), Variant::Type::INT, false);785_insert_feature("vattu_variants", HB_TAG('v', 'a', 't', 'u'), Variant::Type::INT, true);786_insert_feature("vertical_contextual_half_width_spacing", HB_TAG('v', 'c', 'h', 'w'), Variant::Type::BOOL, false);787_insert_feature("vertical_alternates", HB_TAG('v', 'e', 'r', 't'), Variant::Type::INT, false);788_insert_feature("alternate_vertical_half_metrics", HB_TAG('v', 'h', 'a', 'l'), Variant::Type::BOOL, false);789_insert_feature("vowel_jamo_forms", HB_TAG('v', 'j', 'm', 'o'), Variant::Type::INT, true);790_insert_feature("vertical_kana_alternates", HB_TAG('v', 'k', 'n', 'a'), Variant::Type::INT, false);791_insert_feature("vertical_kerning", HB_TAG('v', 'k', 'r', 'n'), Variant::Type::BOOL, false);792_insert_feature("proportional_alternate_vertical_metrics", HB_TAG('v', 'p', 'a', 'l'), Variant::Type::BOOL, false);793_insert_feature("vertical_alternates_and_rotation", HB_TAG('v', 'r', 't', '2'), Variant::Type::INT, false);794_insert_feature("vertical_alternates_for_rotation", HB_TAG('v', 'r', 't', 'r'), Variant::Type::INT, false);795_insert_feature("slashed_zero", HB_TAG('z', 'e', 'r', 'o'), Variant::Type::BOOL, false);796797// Registered OpenType variation tag.798_insert_feature("italic", HB_TAG('i', 't', 'a', 'l'), Variant::Type::INT, false);799_insert_feature("optical_size", HB_TAG('o', 'p', 's', 'z'), Variant::Type::INT, false);800_insert_feature("slant", HB_TAG('s', 'l', 'n', 't'), Variant::Type::INT, false);801_insert_feature("width", HB_TAG('w', 'd', 't', 'h'), Variant::Type::INT, false);802_insert_feature("weight", HB_TAG('w', 'g', 'h', 't'), Variant::Type::INT, false);803}804805int64_t TextServerAdvanced::_name_to_tag(const String &p_name) const {806if (feature_sets.has(p_name)) {807return feature_sets[p_name];808}809810// No readable name, use tag string.811return hb_tag_from_string(p_name.replace("custom_", "").ascii().get_data(), -1);812}813814Variant::Type TextServerAdvanced::_get_tag_type(int64_t p_tag) const {815if (feature_sets_inv.has(p_tag)) {816return feature_sets_inv[p_tag].vtype;817}818return Variant::Type::INT;819}820821bool TextServerAdvanced::_get_tag_hidden(int64_t p_tag) const {822if (feature_sets_inv.has(p_tag)) {823return feature_sets_inv[p_tag].hidden;824}825return false;826}827828String TextServerAdvanced::_tag_to_name(int64_t p_tag) const {829if (feature_sets_inv.has(p_tag)) {830return feature_sets_inv[p_tag].name;831}832833// No readable name, use tag string.834char name[5];835memset(name, 0, 5);836hb_tag_to_string(p_tag, name);837return String("custom_") + String(name);838}839840/*************************************************************************/841/* Font Glyph Rendering */842/*************************************************************************/843844_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 {845FontTexturePosition ret;846847int mw = p_width;848int mh = p_height;849850ShelfPackTexture *ct = p_data->textures.ptrw();851for (int32_t i = 0; i < p_data->textures.size(); i++) {852if (ct[i].image.is_null()) {853continue;854}855if (p_image_format != ct[i].image->get_format()) {856continue;857}858if (mw > ct[i].texture_w || mh > ct[i].texture_h) { // Too big for this texture.859continue;860}861862ret = ct[i].pack_rect(i, mh, mw);863if (ret.index != -1) {864break;865}866}867868if (ret.index == -1) {869// Could not find texture to fit, create one.870int texsize = MAX(p_data->size.x * 0.125, 256);871872texsize = next_power_of_2((uint32_t)texsize);873if (p_msdf) {874texsize = MIN(texsize, 2048);875} else {876texsize = MIN(texsize, 1024);877}878if (mw > texsize) { // Special case, adapt to it?879texsize = next_power_of_2((uint32_t)mw);880}881if (mh > texsize) { // Special case, adapt to it?882texsize = next_power_of_2((uint32_t)mh);883}884885ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);886tex.image = Image::create_empty(texsize, texsize, false, p_image_format);887{888// Zero texture.889uint8_t *w = tex.image->ptrw();890ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.image->get_data_size(), ret);891// Initialize the texture to all-white pixels to prevent artifacts when the892// font is displayed at a non-default scale with filtering enabled.893if (p_color_size == 2) {894for (int i = 0; i < texsize * texsize * p_color_size; i += 2) { // FORMAT_LA8, BW font.895w[i + 0] = 255;896w[i + 1] = 0;897}898} else if (p_color_size == 4) {899for (int i = 0; i < texsize * texsize * p_color_size; i += 4) { // FORMAT_RGBA8, Color font, Multichannel(+True) SDF.900if (p_msdf) {901w[i + 0] = 0;902w[i + 1] = 0;903w[i + 2] = 0;904} else {905w[i + 0] = 255;906w[i + 1] = 255;907w[i + 2] = 255;908}909w[i + 3] = 0;910}911} else {912ERR_FAIL_V(ret);913}914}915p_data->textures.push_back(tex);916917int32_t idx = p_data->textures.size() - 1;918ret = p_data->textures.write[idx].pack_rect(idx, mh, mw);919}920921return ret;922}923924#ifdef MODULE_MSDFGEN_ENABLED925926struct MSContext {927msdfgen::Point2 position;928msdfgen::Shape *shape = nullptr;929msdfgen::Contour *contour = nullptr;930};931932class DistancePixelConversion {933double invRange;934935public:936_FORCE_INLINE_ explicit DistancePixelConversion(double range) :937invRange(1 / range) {}938_FORCE_INLINE_ void operator()(float *pixels, const msdfgen::MultiAndTrueDistance &distance) const {939pixels[0] = float(invRange * distance.r + .5);940pixels[1] = float(invRange * distance.g + .5);941pixels[2] = float(invRange * distance.b + .5);942pixels[3] = float(invRange * distance.a + .5);943}944};945946struct MSDFThreadData {947msdfgen::Bitmap<float, 4> *output;948msdfgen::Shape *shape;949msdfgen::Projection *projection;950DistancePixelConversion *distancePixelConversion;951};952953static msdfgen::Point2 ft_point2(const FT_Vector &vector) {954return msdfgen::Point2(vector.x / 60.0f, vector.y / 60.0f);955}956957static int ft_move_to(const FT_Vector *to, void *user) {958MSContext *context = static_cast<MSContext *>(user);959if (!(context->contour && context->contour->edges.empty())) {960context->contour = &context->shape->addContour();961}962context->position = ft_point2(*to);963return 0;964}965966static int ft_line_to(const FT_Vector *to, void *user) {967MSContext *context = static_cast<MSContext *>(user);968msdfgen::Point2 endpoint = ft_point2(*to);969if (endpoint != context->position) {970context->contour->addEdge(new msdfgen::LinearSegment(context->position, endpoint));971context->position = endpoint;972}973return 0;974}975976static int ft_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) {977MSContext *context = static_cast<MSContext *>(user);978context->contour->addEdge(new msdfgen::QuadraticSegment(context->position, ft_point2(*control), ft_point2(*to)));979context->position = ft_point2(*to);980return 0;981}982983static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) {984MSContext *context = static_cast<MSContext *>(user);985context->contour->addEdge(new msdfgen::CubicSegment(context->position, ft_point2(*control1), ft_point2(*control2), ft_point2(*to)));986context->position = ft_point2(*to);987return 0;988}989990void TextServerAdvanced::_generateMTSDF_threaded(void *p_td, uint32_t p_y) {991MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td);992993msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape);994int row = td->shape->inverseYAxis ? td->output->height() - p_y - 1 : p_y;995for (int col = 0; col < td->output->width(); ++col) {996int x = (p_y % 2) ? td->output->width() - col - 1 : col;997msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, p_y + .5));998msdfgen::MultiAndTrueDistance distance = distanceFinder.distance(p);999td->distancePixelConversion->operator()(td->output->operator()(x, row), distance);1000}1001}10021003_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 {1004msdfgen::Shape shape;10051006shape.contours.clear();1007shape.inverseYAxis = false;10081009MSContext context = {};1010context.shape = &shape;1011FT_Outline_Funcs ft_functions;1012ft_functions.move_to = &ft_move_to;1013ft_functions.line_to = &ft_line_to;1014ft_functions.conic_to = &ft_conic_to;1015ft_functions.cubic_to = &ft_cubic_to;1016ft_functions.shift = 0;1017ft_functions.delta = 0;10181019int error = FT_Outline_Decompose(p_outline, &ft_functions, &context);1020ERR_FAIL_COND_V_MSG(error, FontGlyph(), "FreeType: Outline decomposition error: '" + String(FT_Error_String(error)) + "'.");1021if (!shape.contours.empty() && shape.contours.back().edges.empty()) {1022shape.contours.pop_back();1023}10241025if (FT_Outline_Get_Orientation(p_outline) == 1) {1026for (int i = 0; i < (int)shape.contours.size(); ++i) {1027shape.contours[i].reverse();1028}1029}10301031shape.inverseYAxis = true;1032shape.normalize();10331034msdfgen::Shape::Bounds bounds = shape.getBounds(p_pixel_range);10351036FontGlyph chr;1037chr.found = true;1038chr.advance = p_advance;10391040if (shape.validate() && shape.contours.size() > 0) {1041int w = (bounds.r - bounds.l);1042int h = (bounds.t - bounds.b);10431044if (w == 0 || h == 0) {1045chr.texture_idx = -1;1046chr.uv_rect = Rect2();1047chr.rect = Rect2();1048return chr;1049}10501051int mw = w + p_rect_margin * 4;1052int mh = h + p_rect_margin * 4;10531054ERR_FAIL_COND_V(mw > 4096, FontGlyph());1055ERR_FAIL_COND_V(mh > 4096, FontGlyph());10561057FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true);1058ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());1059ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];10601061edgeColoringSimple(shape, 3.0); // Max. angle.1062msdfgen::Bitmap<float, 4> image(w, h); // Texture size.10631064DistancePixelConversion distancePixelConversion(p_pixel_range);1065msdfgen::Projection projection(msdfgen::Vector2(1.0, 1.0), msdfgen::Vector2(-bounds.l, -bounds.b));1066msdfgen::MSDFGeneratorConfig config(true, msdfgen::ErrorCorrectionConfig());10671068MSDFThreadData td;1069td.output = ℑ1070td.shape = &shape;1071td.projection = &projection;1072td.distancePixelConversion = &distancePixelConversion;10731074WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_native_group_task(&TextServerAdvanced::_generateMTSDF_threaded, &td, h, -1, true, String("FontServerRasterizeMSDF"));1075WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);10761077msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config);10781079{1080uint8_t *wr = tex.image->ptrw();10811082for (int i = 0; i < h; i++) {1083for (int j = 0; j < w; j++) {1084int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * 4;1085ERR_FAIL_COND_V(ofs >= tex.image->get_data_size(), FontGlyph());1086wr[ofs + 0] = (uint8_t)(CLAMP(image(j, i)[0] * 256.f, 0.f, 255.f));1087wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f));1088wr[ofs + 2] = (uint8_t)(CLAMP(image(j, i)[2] * 256.f, 0.f, 255.f));1089wr[ofs + 3] = (uint8_t)(CLAMP(image(j, i)[3] * 256.f, 0.f, 255.f));1090}1091}1092}10931094tex.dirty = true;10951096chr.texture_idx = tex_pos.index;10971098chr.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);1099chr.rect.position = Vector2(bounds.l - p_rect_margin, -bounds.t - p_rect_margin);11001101chr.rect.size = chr.uv_rect.size;1102}1103return chr;1104}1105#endif11061107#ifdef MODULE_FREETYPE_ENABLED1108_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 {1109FontGlyph chr;1110chr.advance = p_advance * p_data->scale;1111chr.found = true;11121113int w = p_bitmap.width;1114int h = p_bitmap.rows;11151116if (w == 0 || h == 0) {1117chr.texture_idx = -1;1118chr.uv_rect = Rect2();1119chr.rect = Rect2();1120return chr;1121}11221123int color_size = 2;11241125switch (p_bitmap.pixel_mode) {1126case FT_PIXEL_MODE_MONO:1127case FT_PIXEL_MODE_GRAY: {1128color_size = 2;1129} break;1130case FT_PIXEL_MODE_BGRA: {1131color_size = 4;1132} break;1133case FT_PIXEL_MODE_LCD: {1134color_size = 4;1135w /= 3;1136} break;1137case FT_PIXEL_MODE_LCD_V: {1138color_size = 4;1139h /= 3;1140} break;1141}11421143int mw = w + p_rect_margin * 4;1144int mh = h + p_rect_margin * 4;11451146ERR_FAIL_COND_V(mw > 4096, FontGlyph());1147ERR_FAIL_COND_V(mh > 4096, FontGlyph());11481149Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;11501151FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh, false);1152ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());11531154// Fit character in char texture.1155ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];11561157{1158uint8_t *wr = tex.image->ptrw();11591160for (int i = 0; i < h; i++) {1161for (int j = 0; j < w; j++) {1162int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * color_size;1163ERR_FAIL_COND_V(ofs >= tex.image->get_data_size(), FontGlyph());1164switch (p_bitmap.pixel_mode) {1165case FT_PIXEL_MODE_MONO: {1166int byte = i * p_bitmap.pitch + (j >> 3);1167int bit = 1 << (7 - (j % 8));1168wr[ofs + 0] = 255; // grayscale as 11169wr[ofs + 1] = (p_bitmap.buffer[byte] & bit) ? 255 : 0;1170} break;1171case FT_PIXEL_MODE_GRAY:1172wr[ofs + 0] = 255; // grayscale as 11173wr[ofs + 1] = p_bitmap.buffer[i * p_bitmap.pitch + j];1174break;1175case FT_PIXEL_MODE_BGRA: {1176int ofs_color = i * p_bitmap.pitch + (j << 2);1177wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];1178wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];1179wr[ofs + 0] = p_bitmap.buffer[ofs_color + 2];1180wr[ofs + 3] = p_bitmap.buffer[ofs_color + 3];1181} break;1182case FT_PIXEL_MODE_LCD: {1183int ofs_color = i * p_bitmap.pitch + (j * 3);1184if (p_bgra) {1185wr[ofs + 0] = p_bitmap.buffer[ofs_color + 2];1186wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];1187wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];1188wr[ofs + 3] = 255;1189} else {1190wr[ofs + 0] = p_bitmap.buffer[ofs_color + 0];1191wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];1192wr[ofs + 2] = p_bitmap.buffer[ofs_color + 2];1193wr[ofs + 3] = 255;1194}1195} break;1196case FT_PIXEL_MODE_LCD_V: {1197int ofs_color = i * p_bitmap.pitch * 3 + j;1198if (p_bgra) {1199wr[ofs + 0] = p_bitmap.buffer[ofs_color + p_bitmap.pitch * 2];1200wr[ofs + 1] = p_bitmap.buffer[ofs_color + p_bitmap.pitch];1201wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];1202wr[ofs + 3] = 255;1203} else {1204wr[ofs + 0] = p_bitmap.buffer[ofs_color + 0];1205wr[ofs + 1] = p_bitmap.buffer[ofs_color + p_bitmap.pitch];1206wr[ofs + 2] = p_bitmap.buffer[ofs_color + p_bitmap.pitch * 2];1207wr[ofs + 3] = 255;1208}1209} break;1210default:1211ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + String::num_int64(p_bitmap.pixel_mode) + ".");1212break;1213}1214}1215}1216}12171218tex.dirty = true;12191220chr.texture_idx = tex_pos.index;12211222chr.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);1223chr.rect.position = Vector2(p_xofs - p_rect_margin, -p_yofs - p_rect_margin) * p_data->scale;1224chr.rect.size = chr.uv_rect.size * p_data->scale;1225return chr;1226}1227#endif12281229/*************************************************************************/1230/* Font Cache */1231/*************************************************************************/12321233bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph, FontGlyph &r_glyph, uint32_t p_oversampling) const {1234FontForSizeAdvanced *fd = nullptr;1235ERR_FAIL_COND_V(!_ensure_cache_for_size(p_font_data, p_size, fd, false, p_oversampling), false);12361237int32_t glyph_index = p_glyph & 0xffffff; // Remove subpixel shifts.12381239HashMap<int32_t, FontGlyph>::Iterator E = fd->glyph_map.find(p_glyph);1240if (E) {1241bool tx_valid = true;1242if (E->value.texture_idx >= 0) {1243if (E->value.texture_idx < fd->textures.size()) {1244tx_valid = fd->textures[E->value.texture_idx].image.is_valid();1245} else {1246tx_valid = false;1247}1248}1249if (tx_valid) {1250r_glyph = E->value;1251return E->value.found;1252#ifdef DEBUG_ENABLED1253} else {1254WARN_PRINT(vformat("Invalid texture cache for glyph %x in font %s, glyph will be re-rendered. Re-import this font to regenerate textures.", glyph_index, p_font_data->font_name));1255#endif1256}1257}12581259if (glyph_index == 0) { // Non graphical or invalid glyph, do not render.1260E = fd->glyph_map.insert(p_glyph, FontGlyph());1261r_glyph = E->value;1262return true;1263}12641265#ifdef MODULE_FREETYPE_ENABLED1266FontGlyph gl;1267if (p_font_data->face) {1268FT_Int32 flags = FT_LOAD_DEFAULT;12691270bool outline = p_size.y > 0;1271switch (p_font_data->hinting) {1272case TextServer::HINTING_NONE:1273flags |= FT_LOAD_NO_HINTING;1274break;1275case TextServer::HINTING_LIGHT:1276flags |= FT_LOAD_TARGET_LIGHT;1277break;1278default:1279flags |= FT_LOAD_TARGET_NORMAL;1280break;1281}1282if (p_font_data->force_autohinter) {1283flags |= FT_LOAD_FORCE_AUTOHINT;1284}1285if (outline || (p_font_data->disable_embedded_bitmaps && !FT_HAS_COLOR(p_font_data->face))) {1286flags |= FT_LOAD_NO_BITMAP;1287} else if (FT_HAS_COLOR(p_font_data->face)) {1288flags |= FT_LOAD_COLOR;1289}12901291FT_Fixed v, h;1292FT_Get_Advance(p_font_data->face, glyph_index, flags, &h);1293FT_Get_Advance(p_font_data->face, glyph_index, flags | FT_LOAD_VERTICAL_LAYOUT, &v);12941295int error = FT_Load_Glyph(p_font_data->face, glyph_index, flags);1296if (error) {1297E = fd->glyph_map.insert(p_glyph, FontGlyph());1298r_glyph = E->value;1299return false;1300}13011302if (!p_font_data->msdf) {1303if ((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)) {1304FT_Pos xshift = (int)((p_glyph >> 27) & 3) << 4;1305FT_Outline_Translate(&p_font_data->face->glyph->outline, xshift, 0);1306} 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)) {1307FT_Pos xshift = (int)((p_glyph >> 27) & 3) << 5;1308FT_Outline_Translate(&p_font_data->face->glyph->outline, xshift, 0);1309}1310}13111312if (p_font_data->embolden != 0.f) {1313FT_Pos strength = p_font_data->embolden * p_size.x / 16; // 26.6 fractional units (1 / 64).1314FT_Outline_Embolden(&p_font_data->face->glyph->outline, strength);1315}13161317if (p_font_data->transform != Transform2D()) {1318FT_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).1319FT_Outline_Transform(&p_font_data->face->glyph->outline, &mat);1320}13211322FT_Render_Mode aa_mode = FT_RENDER_MODE_NORMAL;1323bool bgra = false;1324switch (p_font_data->antialiasing) {1325case FONT_ANTIALIASING_NONE: {1326aa_mode = FT_RENDER_MODE_MONO;1327} break;1328case FONT_ANTIALIASING_GRAY: {1329aa_mode = FT_RENDER_MODE_NORMAL;1330} break;1331case FONT_ANTIALIASING_LCD: {1332int aa_layout = (int)((p_glyph >> 24) & 7);1333switch (aa_layout) {1334case FONT_LCD_SUBPIXEL_LAYOUT_HRGB: {1335aa_mode = FT_RENDER_MODE_LCD;1336bgra = false;1337} break;1338case FONT_LCD_SUBPIXEL_LAYOUT_HBGR: {1339aa_mode = FT_RENDER_MODE_LCD;1340bgra = true;1341} break;1342case FONT_LCD_SUBPIXEL_LAYOUT_VRGB: {1343aa_mode = FT_RENDER_MODE_LCD_V;1344bgra = false;1345} break;1346case FONT_LCD_SUBPIXEL_LAYOUT_VBGR: {1347aa_mode = FT_RENDER_MODE_LCD_V;1348bgra = true;1349} break;1350default: {1351aa_mode = FT_RENDER_MODE_NORMAL;1352} break;1353}1354} break;1355}13561357FT_GlyphSlot slot = p_font_data->face->glyph;1358bool from_svg = (slot->format == FT_GLYPH_FORMAT_SVG); // Need to check before FT_Render_Glyph as it will change format to bitmap.1359if (!outline) {1360if (!p_font_data->msdf) {1361error = FT_Render_Glyph(slot, aa_mode);1362}1363if (!error) {1364if (p_font_data->msdf) {1365#ifdef MODULE_MSDFGEN_ENABLED1366gl = 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);1367#else1368fd->glyph_map[p_glyph] = FontGlyph();1369ERR_FAIL_V_MSG(false, "Compiled without MSDFGEN support!");1370#endif1371} else {1372gl = 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);1373}1374}1375} else {1376FT_Stroker stroker;1377if (FT_Stroker_New(ft_library, &stroker) != 0) {1378fd->glyph_map[p_glyph] = FontGlyph();1379ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph stroker.");1380}13811382FT_Stroker_Set(stroker, (int)(fd->size.y * 16.0), FT_STROKER_LINECAP_BUTT, FT_STROKER_LINEJOIN_ROUND, 0);1383FT_Glyph glyph;1384FT_BitmapGlyph glyph_bitmap;13851386if (FT_Get_Glyph(p_font_data->face->glyph, &glyph) != 0) {1387goto cleanup_stroker;1388}1389if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0) {1390goto cleanup_glyph;1391}1392if (FT_Glyph_To_Bitmap(&glyph, aa_mode, nullptr, 1) != 0) {1393goto cleanup_glyph;1394}1395glyph_bitmap = (FT_BitmapGlyph)glyph;1396gl = rasterize_bitmap(fd, rect_range, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2(), bgra);13971398cleanup_glyph:1399FT_Done_Glyph(glyph);1400cleanup_stroker:1401FT_Stroker_Done(stroker);1402}1403gl.from_svg = from_svg;1404E = fd->glyph_map.insert(p_glyph, gl);1405r_glyph = E->value;1406return gl.found;1407}1408#endif1409E = fd->glyph_map.insert(p_glyph, FontGlyph());1410r_glyph = E->value;1411return false;1412}14131414bool 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 {1415ERR_FAIL_COND_V(p_size.x <= 0, false);14161417HashMap<Vector2i, FontForSizeAdvanced *>::Iterator E = p_font_data->cache.find(p_size);1418if (E) {1419#ifdef MODULE_FREETYPE_ENABLED1420if (E->value->fsize != nullptr) {1421FT_Activate_Size(E->value->fsize);1422}1423#endif1424r_cache_for_size = E->value;1425// Size used directly, remove from oversampling list.1426if (p_oversampling == 0 && E->value->viewport_oversampling != 0) {1427OversamplingLevel *ol = oversampling_levels.getptr(E->value->viewport_oversampling);1428if (ol) {1429ol->fonts.erase(E->value);1430}1431}1432return true;1433}14341435FontForSizeAdvanced *fd = memnew(FontForSizeAdvanced);1436fd->size = p_size;1437if (p_font_data->data_ptr && (p_font_data->data_size > 0)) {1438// Init dynamic font.1439#ifdef MODULE_FREETYPE_ENABLED1440int error = 0;1441{1442MutexLock ftlock(ft_mutex);1443if (!ft_library) {1444error = FT_Init_FreeType(&ft_library);1445if (error != 0) {1446memdelete(fd);1447if (p_silent) {1448return false;1449} else {1450ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");1451}1452}1453#ifdef MODULE_SVG_ENABLED1454FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks());1455#endif1456}14571458if (p_font_data->face == nullptr) {1459memset(&p_font_data->stream, 0, sizeof(FT_StreamRec));1460p_font_data->stream.base = (unsigned char *)p_font_data->data_ptr;1461p_font_data->stream.size = p_font_data->data_size;1462p_font_data->stream.pos = 0;14631464FT_Open_Args fargs;1465memset(&fargs, 0, sizeof(FT_Open_Args));1466fargs.memory_base = (unsigned char *)p_font_data->data_ptr;1467fargs.memory_size = p_font_data->data_size;1468fargs.flags = FT_OPEN_MEMORY;1469fargs.stream = &p_font_data->stream;14701471error = FT_Open_Face(ft_library, &fargs, p_font_data->face_index, &p_font_data->face);1472if (error) {1473if (p_font_data->face) {1474FT_Done_Face(p_font_data->face);1475p_font_data->face = nullptr;1476}1477memdelete(fd);1478if (p_silent) {1479return false;1480} else {1481ERR_FAIL_V_MSG(false, "FreeType: Error loading font: '" + String(FT_Error_String(error)) + "' (face_index=" + String::num_int64(p_font_data->face_index) + ").");1482}1483}1484}14851486FT_New_Size(p_font_data->face, &fd->fsize);1487FT_Activate_Size(fd->fsize);1488}14891490double sz = double(fd->size.x) / 64.0;1491if (p_font_data->msdf) {1492sz = p_font_data->msdf_source_size;1493}14941495if (FT_HAS_COLOR(p_font_data->face) && p_font_data->face->num_fixed_sizes > 0) {1496int best_match = 0;1497int diff = Math::abs(sz - ((int64_t)p_font_data->face->available_sizes[0].width));1498fd->scale = sz / p_font_data->face->available_sizes[0].width;1499for (int i = 1; i < p_font_data->face->num_fixed_sizes; i++) {1500int ndiff = Math::abs(sz - ((int64_t)p_font_data->face->available_sizes[i].width));1501if (ndiff < diff) {1502best_match = i;1503diff = ndiff;1504fd->scale = sz / p_font_data->face->available_sizes[i].width;1505}1506}1507FT_Select_Size(p_font_data->face, best_match);1508} else {1509FT_Size_RequestRec req;1510req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;1511req.width = MIN(2048.0, sz) * 64.0;1512req.height = MIN(2048.0, sz) * 64.0;1513req.horiResolution = 0;1514req.vertResolution = 0;15151516FT_Request_Size(p_font_data->face, &req);1517if (p_font_data->face->size->metrics.y_ppem != 0) {1518fd->scale = sz / (double)p_font_data->face->size->metrics.y_ppem;1519}1520}15211522fd->hb_handle = hb_ft_font_create(p_font_data->face, nullptr);15231524fd->ascent = (p_font_data->face->size->metrics.ascender / 64.0) * fd->scale;1525fd->descent = (-p_font_data->face->size->metrics.descender / 64.0) * fd->scale;1526fd->underline_position = (-FT_MulFix(p_font_data->face->underline_position, p_font_data->face->size->metrics.y_scale) / 64.0) * fd->scale;1527fd->underline_thickness = (FT_MulFix(p_font_data->face->underline_thickness, p_font_data->face->size->metrics.y_scale) / 64.0) * fd->scale;15281529#if HB_VERSION_ATLEAST(3, 3, 0)1530hb_font_set_synthetic_slant(fd->hb_handle, p_font_data->transform[0][1]);1531#else1532#ifndef _MSC_VER1533#warning Building with HarfBuzz < 3.3.0, synthetic slant offset correction disabled.1534#endif1535#endif15361537if (!p_font_data->face_init) {1538// When a font does not provide a `family_name`, FreeType tries to synthesize one based on other names.1539// FreeType automatically converts non-ASCII characters to "?" in the synthesized name.1540// To avoid that behavior, use the format-specific name directly if available.1541hb_face_t *hb_face = hb_font_get_face(fd->hb_handle);1542unsigned int num_entries = 0;1543const hb_ot_name_entry_t *names = hb_ot_name_list_names(hb_face, &num_entries);1544const hb_language_t english = hb_language_from_string("en", -1);1545for (unsigned int i = 0; i < num_entries; i++) {1546if (names[i].name_id != HB_OT_NAME_ID_FONT_FAMILY) {1547continue;1548}1549if (!p_font_data->font_name.is_empty() && names[i].language != english) {1550continue;1551}1552unsigned int text_size = hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, nullptr, nullptr) + 1;1553p_font_data->font_name.resize_uninitialized(text_size);1554hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, &text_size, (uint32_t *)p_font_data->font_name.ptrw());1555}1556if (p_font_data->font_name.is_empty() && p_font_data->face->family_name != nullptr) {1557p_font_data->font_name = String::utf8((const char *)p_font_data->face->family_name);1558}1559if (p_font_data->face->style_name != nullptr) {1560p_font_data->style_name = String::utf8((const char *)p_font_data->face->style_name);1561}1562p_font_data->weight = _font_get_weight_by_name(p_font_data->style_name.to_lower());1563p_font_data->stretch = _font_get_stretch_by_name(p_font_data->style_name.to_lower());1564p_font_data->style_flags = 0;1565if ((p_font_data->face->style_flags & FT_STYLE_FLAG_BOLD) || p_font_data->weight >= 700) {1566p_font_data->style_flags.set_flag(FONT_BOLD);1567}1568if ((p_font_data->face->style_flags & FT_STYLE_FLAG_ITALIC) || _is_ital_style(p_font_data->style_name.to_lower())) {1569p_font_data->style_flags.set_flag(FONT_ITALIC);1570}1571if (p_font_data->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) {1572p_font_data->style_flags.set_flag(FONT_FIXED_WIDTH);1573}15741575// Get supported scripts from OpenType font data.1576p_font_data->supported_scripts.clear();1577unsigned int count = hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, nullptr, nullptr);1578if (count != 0) {1579hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));1580hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, &count, script_tags);1581for (unsigned int i = 0; i < count; i++) {1582p_font_data->supported_scripts.insert(script_tags[i]);1583}1584memfree(script_tags);1585}1586count = hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GPOS, 0, nullptr, nullptr);1587if (count != 0) {1588hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));1589hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GPOS, 0, &count, script_tags);1590for (unsigned int i = 0; i < count; i++) {1591p_font_data->supported_scripts.insert(script_tags[i]);1592}1593memfree(script_tags);1594}15951596// Get supported scripts from OS2 table.1597TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(p_font_data->face, FT_SFNT_OS2);1598if (os2) {1599if ((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)) {1600p_font_data->supported_scripts.insert(HB_SCRIPT_COMMON);1601}1602if ((os2->ulUnicodeRange1 & 1L << 0) || (os2->ulUnicodeRange1 & 1L << 1) || (os2->ulUnicodeRange1 & 1L << 2) || (os2->ulUnicodeRange1 & 1L << 3) || (os2->ulUnicodeRange1 & 1L << 29)) {1603p_font_data->supported_scripts.insert(HB_SCRIPT_LATIN);1604}1605if ((os2->ulUnicodeRange1 & 1L << 7) || (os2->ulUnicodeRange1 & 1L << 30)) {1606p_font_data->supported_scripts.insert(HB_SCRIPT_GREEK);1607}1608if (os2->ulUnicodeRange1 & 1L << 8) {1609p_font_data->supported_scripts.insert(HB_SCRIPT_COPTIC);1610}1611if (os2->ulUnicodeRange1 & 1L << 9) {1612p_font_data->supported_scripts.insert(HB_SCRIPT_CYRILLIC);1613}1614if (os2->ulUnicodeRange1 & 1L << 10) {1615p_font_data->supported_scripts.insert(HB_SCRIPT_ARMENIAN);1616}1617if (os2->ulUnicodeRange1 & 1L << 11) {1618p_font_data->supported_scripts.insert(HB_SCRIPT_HEBREW);1619}1620if (os2->ulUnicodeRange1 & 1L << 12) {1621p_font_data->supported_scripts.insert(HB_SCRIPT_VAI);1622}1623if ((os2->ulUnicodeRange1 & 1L << 13) || (os2->ulUnicodeRange2 & 1L << 31) || (os2->ulUnicodeRange3 & 1L << 3)) {1624p_font_data->supported_scripts.insert(HB_SCRIPT_ARABIC);1625}1626if (os2->ulUnicodeRange1 & 1L << 14) {1627p_font_data->supported_scripts.insert(HB_SCRIPT_NKO);1628}1629if (os2->ulUnicodeRange1 & 1L << 15) {1630p_font_data->supported_scripts.insert(HB_SCRIPT_DEVANAGARI);1631}1632if (os2->ulUnicodeRange1 & 1L << 16) {1633p_font_data->supported_scripts.insert(HB_SCRIPT_BENGALI);1634}1635if (os2->ulUnicodeRange1 & 1L << 17) {1636p_font_data->supported_scripts.insert(HB_SCRIPT_GURMUKHI);1637}1638if (os2->ulUnicodeRange1 & 1L << 18) {1639p_font_data->supported_scripts.insert(HB_SCRIPT_GUJARATI);1640}1641if (os2->ulUnicodeRange1 & 1L << 19) {1642p_font_data->supported_scripts.insert(HB_SCRIPT_ORIYA);1643}1644if (os2->ulUnicodeRange1 & 1L << 20) {1645p_font_data->supported_scripts.insert(HB_SCRIPT_TAMIL);1646}1647if (os2->ulUnicodeRange1 & 1L << 21) {1648p_font_data->supported_scripts.insert(HB_SCRIPT_TELUGU);1649}1650if (os2->ulUnicodeRange1 & 1L << 22) {1651p_font_data->supported_scripts.insert(HB_SCRIPT_KANNADA);1652}1653if (os2->ulUnicodeRange1 & 1L << 23) {1654p_font_data->supported_scripts.insert(HB_SCRIPT_MALAYALAM);1655}1656if (os2->ulUnicodeRange1 & 1L << 24) {1657p_font_data->supported_scripts.insert(HB_SCRIPT_THAI);1658}1659if (os2->ulUnicodeRange1 & 1L << 25) {1660p_font_data->supported_scripts.insert(HB_SCRIPT_LAO);1661}1662if (os2->ulUnicodeRange1 & 1L << 26) {1663p_font_data->supported_scripts.insert(HB_SCRIPT_GEORGIAN);1664}1665if (os2->ulUnicodeRange1 & 1L << 27) {1666p_font_data->supported_scripts.insert(HB_SCRIPT_BALINESE);1667}1668if ((os2->ulUnicodeRange1 & 1L << 28) || (os2->ulUnicodeRange2 & 1L << 20) || (os2->ulUnicodeRange2 & 1L << 24)) {1669p_font_data->supported_scripts.insert(HB_SCRIPT_HANGUL);1670}1671if ((os2->ulUnicodeRange2 & 1L << 21) || (os2->ulUnicodeRange2 & 1L << 22) || (os2->ulUnicodeRange2 & 1L << 23) || (os2->ulUnicodeRange2 & 1L << 26) || (os2->ulUnicodeRange2 & 1L << 27) || (os2->ulUnicodeRange2 & 1L << 29)) {1672p_font_data->supported_scripts.insert(HB_SCRIPT_HAN);1673}1674if (os2->ulUnicodeRange2 & 1L << 17) {1675p_font_data->supported_scripts.insert(HB_SCRIPT_HIRAGANA);1676}1677if (os2->ulUnicodeRange2 & 1L << 18) {1678p_font_data->supported_scripts.insert(HB_SCRIPT_KATAKANA);1679}1680if (os2->ulUnicodeRange2 & 1L << 19) {1681p_font_data->supported_scripts.insert(HB_SCRIPT_BOPOMOFO);1682}1683if (os2->ulUnicodeRange3 & 1L << 6) {1684p_font_data->supported_scripts.insert(HB_SCRIPT_TIBETAN);1685}1686if (os2->ulUnicodeRange3 & 1L << 7) {1687p_font_data->supported_scripts.insert(HB_SCRIPT_SYRIAC);1688}1689if (os2->ulUnicodeRange3 & 1L << 8) {1690p_font_data->supported_scripts.insert(HB_SCRIPT_THAANA);1691}1692if (os2->ulUnicodeRange3 & 1L << 9) {1693p_font_data->supported_scripts.insert(HB_SCRIPT_SINHALA);1694}1695if (os2->ulUnicodeRange3 & 1L << 10) {1696p_font_data->supported_scripts.insert(HB_SCRIPT_MYANMAR);1697}1698if (os2->ulUnicodeRange3 & 1L << 11) {1699p_font_data->supported_scripts.insert(HB_SCRIPT_ETHIOPIC);1700}1701if (os2->ulUnicodeRange3 & 1L << 12) {1702p_font_data->supported_scripts.insert(HB_SCRIPT_CHEROKEE);1703}1704if (os2->ulUnicodeRange3 & 1L << 13) {1705p_font_data->supported_scripts.insert(HB_SCRIPT_CANADIAN_SYLLABICS);1706}1707if (os2->ulUnicodeRange3 & 1L << 14) {1708p_font_data->supported_scripts.insert(HB_SCRIPT_OGHAM);1709}1710if (os2->ulUnicodeRange3 & 1L << 15) {1711p_font_data->supported_scripts.insert(HB_SCRIPT_RUNIC);1712}1713if (os2->ulUnicodeRange3 & 1L << 16) {1714p_font_data->supported_scripts.insert(HB_SCRIPT_KHMER);1715}1716if (os2->ulUnicodeRange3 & 1L << 17) {1717p_font_data->supported_scripts.insert(HB_SCRIPT_MONGOLIAN);1718}1719if (os2->ulUnicodeRange3 & 1L << 19) {1720p_font_data->supported_scripts.insert(HB_SCRIPT_YI);1721}1722if (os2->ulUnicodeRange3 & 1L << 20) {1723p_font_data->supported_scripts.insert(HB_SCRIPT_HANUNOO);1724p_font_data->supported_scripts.insert(HB_SCRIPT_TAGBANWA);1725p_font_data->supported_scripts.insert(HB_SCRIPT_BUHID);1726p_font_data->supported_scripts.insert(HB_SCRIPT_TAGALOG);1727}1728if (os2->ulUnicodeRange3 & 1L << 21) {1729p_font_data->supported_scripts.insert(HB_SCRIPT_OLD_ITALIC);1730}1731if (os2->ulUnicodeRange3 & 1L << 22) {1732p_font_data->supported_scripts.insert(HB_SCRIPT_GOTHIC);1733}1734if (os2->ulUnicodeRange3 & 1L << 23) {1735p_font_data->supported_scripts.insert(HB_SCRIPT_DESERET);1736}1737if (os2->ulUnicodeRange3 & 1L << 29) {1738p_font_data->supported_scripts.insert(HB_SCRIPT_LIMBU);1739}1740if (os2->ulUnicodeRange3 & 1L << 30) {1741p_font_data->supported_scripts.insert(HB_SCRIPT_TAI_LE);1742}1743if (os2->ulUnicodeRange3 & 1L << 31) {1744p_font_data->supported_scripts.insert(HB_SCRIPT_NEW_TAI_LUE);1745}1746if (os2->ulUnicodeRange4 & 1L << 0) {1747p_font_data->supported_scripts.insert(HB_SCRIPT_BUGINESE);1748}1749if (os2->ulUnicodeRange4 & 1L << 1) {1750p_font_data->supported_scripts.insert(HB_SCRIPT_GLAGOLITIC);1751}1752if (os2->ulUnicodeRange4 & 1L << 2) {1753p_font_data->supported_scripts.insert(HB_SCRIPT_TIFINAGH);1754}1755if (os2->ulUnicodeRange4 & 1L << 4) {1756p_font_data->supported_scripts.insert(HB_SCRIPT_SYLOTI_NAGRI);1757}1758if (os2->ulUnicodeRange4 & 1L << 5) {1759p_font_data->supported_scripts.insert(HB_SCRIPT_LINEAR_B);1760}1761if (os2->ulUnicodeRange4 & 1L << 7) {1762p_font_data->supported_scripts.insert(HB_SCRIPT_UGARITIC);1763}1764if (os2->ulUnicodeRange4 & 1L << 8) {1765p_font_data->supported_scripts.insert(HB_SCRIPT_OLD_PERSIAN);1766}1767if (os2->ulUnicodeRange4 & 1L << 9) {1768p_font_data->supported_scripts.insert(HB_SCRIPT_SHAVIAN);1769}1770if (os2->ulUnicodeRange4 & 1L << 10) {1771p_font_data->supported_scripts.insert(HB_SCRIPT_OSMANYA);1772}1773if (os2->ulUnicodeRange4 & 1L << 11) {1774p_font_data->supported_scripts.insert(HB_SCRIPT_CYPRIOT);1775}1776if (os2->ulUnicodeRange4 & 1L << 12) {1777p_font_data->supported_scripts.insert(HB_SCRIPT_KHAROSHTHI);1778}1779if (os2->ulUnicodeRange4 & 1L << 13) {1780p_font_data->supported_scripts.insert(HB_SCRIPT_TAI_VIET);1781}1782if (os2->ulUnicodeRange4 & 1L << 14) {1783p_font_data->supported_scripts.insert(HB_SCRIPT_CUNEIFORM);1784}1785if (os2->ulUnicodeRange4 & 1L << 16) {1786p_font_data->supported_scripts.insert(HB_SCRIPT_SUNDANESE);1787}1788if (os2->ulUnicodeRange4 & 1L << 17) {1789p_font_data->supported_scripts.insert(HB_SCRIPT_LEPCHA);1790}1791if (os2->ulUnicodeRange4 & 1L << 18) {1792p_font_data->supported_scripts.insert(HB_SCRIPT_OL_CHIKI);1793}1794if (os2->ulUnicodeRange4 & 1L << 19) {1795p_font_data->supported_scripts.insert(HB_SCRIPT_SAURASHTRA);1796}1797if (os2->ulUnicodeRange4 & 1L << 20) {1798p_font_data->supported_scripts.insert(HB_SCRIPT_KAYAH_LI);1799}1800if (os2->ulUnicodeRange4 & 1L << 21) {1801p_font_data->supported_scripts.insert(HB_SCRIPT_REJANG);1802}1803if (os2->ulUnicodeRange4 & 1L << 22) {1804p_font_data->supported_scripts.insert(HB_SCRIPT_CHAM);1805}1806if (os2->ulUnicodeRange4 & 1L << 25) {1807p_font_data->supported_scripts.insert(HB_SCRIPT_ANATOLIAN_HIEROGLYPHS);1808}1809}18101811// Validate script sample strings.1812{1813LocalVector<uint32_t> failed_scripts;18141815Vector<UChar> sample_buf;1816sample_buf.resize(255);1817for (const uint32_t &scr_tag : p_font_data->supported_scripts) {1818if ((hb_script_t)scr_tag == HB_SCRIPT_COMMON) {1819continue;1820}1821UErrorCode icu_err = U_ZERO_ERROR;1822int32_t len = uscript_getSampleString(hb_icu_script_from_script((hb_script_t)scr_tag), sample_buf.ptrw(), 255, &icu_err);1823if (U_SUCCESS(icu_err) && len > 0) {1824String sample = String::utf16(sample_buf.ptr(), len);1825for (int ch = 0; ch < sample.length(); ch++) {1826if (FT_Get_Char_Index(p_font_data->face, sample[ch]) == 0) {1827failed_scripts.push_back(scr_tag);1828break;1829}1830}1831}1832}1833for (const uint32_t &scr_tag : failed_scripts) {1834p_font_data->supported_scripts.erase(scr_tag);1835}1836}18371838// Read OpenType feature tags.1839p_font_data->supported_features.clear();1840count = hb_ot_layout_table_get_feature_tags(hb_face, HB_OT_TAG_GSUB, 0, nullptr, nullptr);1841if (count != 0) {1842hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));1843hb_ot_layout_table_get_feature_tags(hb_face, HB_OT_TAG_GSUB, 0, &count, feature_tags);1844for (unsigned int i = 0; i < count; i++) {1845Dictionary ftr;18461847#if HB_VERSION_ATLEAST(2, 1, 0)1848hb_ot_name_id_t lbl_id;1849if (hb_ot_layout_feature_get_name_ids(hb_face, HB_OT_TAG_GSUB, i, &lbl_id, nullptr, nullptr, nullptr, nullptr)) {1850PackedInt32Array lbl;1851unsigned 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;1852lbl.resize(text_size);1853memset((uint32_t *)lbl.ptrw(), 0, sizeof(uint32_t) * text_size);1854hb_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());1855ftr["label"] = String((const char32_t *)lbl.ptr());1856}1857#else1858#ifndef _MSC_VER1859#warning Building with HarfBuzz < 2.1.0, readable OpenType feature names disabled.1860#endif1861#endif1862ftr["type"] = _get_tag_type(feature_tags[i]);1863ftr["hidden"] = _get_tag_hidden(feature_tags[i]);18641865p_font_data->supported_features[feature_tags[i]] = ftr;1866}1867memfree(feature_tags);1868}1869count = hb_ot_layout_table_get_feature_tags(hb_face, HB_OT_TAG_GPOS, 0, nullptr, nullptr);1870if (count != 0) {1871hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));1872hb_ot_layout_table_get_feature_tags(hb_face, HB_OT_TAG_GPOS, 0, &count, feature_tags);1873for (unsigned int i = 0; i < count; i++) {1874Dictionary ftr;18751876#if HB_VERSION_ATLEAST(2, 1, 0)1877hb_ot_name_id_t lbl_id;1878if (hb_ot_layout_feature_get_name_ids(hb_face, HB_OT_TAG_GPOS, i, &lbl_id, nullptr, nullptr, nullptr, nullptr)) {1879PackedInt32Array lbl;1880unsigned 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;1881lbl.resize(text_size);1882memset((uint32_t *)lbl.ptrw(), 0, sizeof(uint32_t) * text_size);1883hb_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());1884ftr["label"] = String((const char32_t *)lbl.ptr());1885}1886#else1887#ifndef _MSC_VER1888#warning Building with HarfBuzz < 2.1.0, readable OpenType feature names disabled.1889#endif1890#endif1891ftr["type"] = _get_tag_type(feature_tags[i]);1892ftr["hidden"] = _get_tag_hidden(feature_tags[i]);18931894p_font_data->supported_features[feature_tags[i]] = ftr;1895}1896memfree(feature_tags);1897}18981899// Read OpenType variations.1900p_font_data->supported_varaitions.clear();1901if (p_font_data->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {1902FT_MM_Var *amaster;1903FT_Get_MM_Var(p_font_data->face, &amaster);1904for (FT_UInt i = 0; i < amaster->num_axis; i++) {1905p_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);1906}1907FT_Done_MM_Var(ft_library, amaster);1908}1909p_font_data->face_init = true;1910}19111912#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)1913if (p_font_data->font_name == ".Apple Color Emoji UI" || p_font_data->font_name == "Apple Color Emoji") {1914// The baseline offset is missing from the Apple Color Emoji UI font data, so add it manually.1915// This issue doesn't occur with other system emoji fonts.1916if (!FT_Load_Glyph(p_font_data->face, FT_Get_Char_Index(p_font_data->face, 0x1F92E), FT_LOAD_DEFAULT | FT_LOAD_COLOR)) {1917if (p_font_data->face->glyph->metrics.horiBearingY == p_font_data->face->glyph->metrics.height) {1918p_font_data->baseline_offset = 0.15;1919}1920}1921}1922#endif19231924// Write variations.1925if (p_font_data->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {1926FT_MM_Var *amaster;19271928FT_Get_MM_Var(p_font_data->face, &amaster);19291930Vector<hb_variation_t> hb_vars;1931Vector<FT_Fixed> coords;1932coords.resize(amaster->num_axis);19331934FT_Get_Var_Design_Coordinates(p_font_data->face, coords.size(), coords.ptrw());19351936for (FT_UInt i = 0; i < amaster->num_axis; i++) {1937hb_variation_t var;19381939// Reset to default.1940var.tag = amaster->axis[i].tag;1941var.value = (double)amaster->axis[i].def / 65536.0;1942coords.write[i] = amaster->axis[i].def;19431944if (p_font_data->variation_coordinates.has(var.tag)) {1945var.value = p_font_data->variation_coordinates[var.tag];1946coords.write[i] = CLAMP(var.value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);1947}19481949if (p_font_data->variation_coordinates.has(_tag_to_name(var.tag))) {1950var.value = p_font_data->variation_coordinates[_tag_to_name(var.tag)];1951coords.write[i] = CLAMP(var.value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);1952}19531954hb_vars.push_back(var);1955}19561957FT_Set_Var_Design_Coordinates(p_font_data->face, coords.size(), coords.ptrw());1958hb_font_set_variations(fd->hb_handle, hb_vars.is_empty() ? nullptr : &hb_vars[0], hb_vars.size());1959FT_Done_MM_Var(ft_library, amaster);1960}1961#else1962memdelete(fd);1963if (p_silent) {1964return false;1965} else {1966ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!");1967}1968#endif1969} else {1970// Init bitmap font.1971fd->hb_handle = _bmp_font_create(fd, nullptr);1972}19731974fd->owner = p_font_data;1975p_font_data->cache.insert(p_size, fd);1976r_cache_for_size = fd;1977if (p_oversampling != 0) {1978OversamplingLevel *ol = oversampling_levels.getptr(p_oversampling);1979if (ol) {1980fd->viewport_oversampling = p_oversampling;1981ol->fonts.insert(fd);1982}1983}1984return true;1985}19861987void TextServerAdvanced::_reference_oversampling_level(double p_oversampling) {1988uint32_t oversampling = CLAMP(p_oversampling, 0.1, 100.0) * 64;1989if (oversampling == 64) {1990return;1991}1992OversamplingLevel *ol = oversampling_levels.getptr(oversampling);1993if (ol) {1994ol->refcount++;1995} else {1996OversamplingLevel new_ol;1997oversampling_levels.insert(oversampling, new_ol);1998}1999}20002001void TextServerAdvanced::_unreference_oversampling_level(double p_oversampling) {2002uint32_t oversampling = CLAMP(p_oversampling, 0.1, 100.0) * 64;2003if (oversampling == 64) {2004return;2005}2006OversamplingLevel *ol = oversampling_levels.getptr(oversampling);2007if (ol) {2008ol->refcount--;2009if (ol->refcount == 0) {2010for (FontForSizeAdvanced *fd : ol->fonts) {2011fd->owner->cache.erase(fd->size);2012memdelete(fd);2013}2014ol->fonts.clear();2015oversampling_levels.erase(oversampling);2016}2017}2018}20192020_FORCE_INLINE_ bool TextServerAdvanced::_font_validate(const RID &p_font_rid) const {2021FontAdvanced *fd = _get_font_data(p_font_rid);2022ERR_FAIL_NULL_V(fd, false);20232024MutexLock lock(fd->mutex);2025Vector2i size = _get_size(fd, 16);2026FontForSizeAdvanced *ffsd = nullptr;2027return _ensure_cache_for_size(fd, size, ffsd, true);2028}20292030_FORCE_INLINE_ void TextServerAdvanced::_font_clear_cache(FontAdvanced *p_font_data) {2031MutexLock ftlock(ft_mutex);20322033for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : p_font_data->cache) {2034if (E.value->viewport_oversampling != 0) {2035OversamplingLevel *ol = oversampling_levels.getptr(E.value->viewport_oversampling);2036if (ol) {2037ol->fonts.erase(E.value);2038}2039}2040memdelete(E.value);2041}2042p_font_data->cache.clear();2043p_font_data->face_init = false;2044p_font_data->supported_features.clear();2045p_font_data->supported_varaitions.clear();2046p_font_data->supported_scripts.clear();2047}20482049bool TextServerAdvanced::_font_is_color(const RID &p_font_rid) const {2050FontAdvanced *fd = _get_font_data(p_font_rid);2051ERR_FAIL_NULL_V(fd, false);20522053MutexLock lock(fd->mutex);2054Vector2i size = _get_size(fd, 16);20552056FontForSizeAdvanced *ffsd = nullptr;2057ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), false);2058#ifdef MODULE_FREETYPE_ENABLED2059return fd->face && FT_HAS_COLOR(fd->face);2060#else2061return false;2062#endif2063}20642065hb_font_t *TextServerAdvanced::_font_get_hb_handle(const RID &p_font_rid, int64_t p_size, bool &r_is_color) const {2066FontAdvanced *fd = _get_font_data(p_font_rid);2067ERR_FAIL_NULL_V(fd, nullptr);20682069MutexLock lock(fd->mutex);2070Vector2i size = _get_size(fd, p_size);20712072FontForSizeAdvanced *ffsd = nullptr;2073ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), nullptr);2074#ifdef MODULE_FREETYPE_ENABLED2075r_is_color = fd->face && FT_HAS_COLOR(fd->face);2076#else2077r_is_color = false;2078#endif20792080return ffsd->hb_handle;2081}20822083RID TextServerAdvanced::_create_font() {2084_THREAD_SAFE_METHOD_20852086FontAdvanced *fd = memnew(FontAdvanced);20872088return font_owner.make_rid(fd);2089}20902091RID TextServerAdvanced::_create_font_linked_variation(const RID &p_font_rid) {2092_THREAD_SAFE_METHOD_20932094RID rid = p_font_rid;2095FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(rid);2096if (unlikely(fdv)) {2097rid = fdv->base_font;2098}2099ERR_FAIL_COND_V(!font_owner.owns(rid), RID());21002101FontAdvancedLinkedVariation *new_fdv = memnew(FontAdvancedLinkedVariation);2102new_fdv->base_font = rid;21032104return font_var_owner.make_rid(new_fdv);2105}21062107void TextServerAdvanced::_font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) {2108FontAdvanced *fd = _get_font_data(p_font_rid);2109ERR_FAIL_NULL(fd);21102111MutexLock lock(fd->mutex);2112_font_clear_cache(fd);2113fd->data = p_data;2114fd->data_ptr = fd->data.ptr();2115fd->data_size = fd->data.size();2116}21172118void TextServerAdvanced::_font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) {2119FontAdvanced *fd = _get_font_data(p_font_rid);2120ERR_FAIL_NULL(fd);21212122MutexLock lock(fd->mutex);2123_font_clear_cache(fd);2124fd->data.resize(0);2125fd->data_ptr = p_data_ptr;2126fd->data_size = p_data_size;2127}21282129void TextServerAdvanced::_font_set_face_index(const RID &p_font_rid, int64_t p_face_index) {2130ERR_FAIL_COND(p_face_index < 0);2131ERR_FAIL_COND(p_face_index >= 0x7FFF);21322133FontAdvanced *fd = _get_font_data(p_font_rid);2134ERR_FAIL_NULL(fd);21352136MutexLock lock(fd->mutex);2137if (fd->face_index != p_face_index) {2138fd->face_index = p_face_index;2139_font_clear_cache(fd);2140}2141}21422143int64_t TextServerAdvanced::_font_get_face_index(const RID &p_font_rid) const {2144FontAdvanced *fd = _get_font_data(p_font_rid);2145ERR_FAIL_NULL_V(fd, 0);21462147MutexLock lock(fd->mutex);2148return fd->face_index;2149}21502151int64_t TextServerAdvanced::_font_get_face_count(const RID &p_font_rid) const {2152FontAdvanced *fd = _get_font_data(p_font_rid);2153ERR_FAIL_NULL_V(fd, 0);21542155MutexLock lock(fd->mutex);2156int face_count = 0;21572158if (fd->data_ptr && (fd->data_size > 0)) {2159// Init dynamic font.2160#ifdef MODULE_FREETYPE_ENABLED2161int error = 0;2162if (!ft_library) {2163error = FT_Init_FreeType(&ft_library);2164ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");2165#ifdef MODULE_SVG_ENABLED2166FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks());2167#endif2168}21692170FT_StreamRec stream;2171memset(&stream, 0, sizeof(FT_StreamRec));2172stream.base = (unsigned char *)fd->data_ptr;2173stream.size = fd->data_size;2174stream.pos = 0;21752176FT_Open_Args fargs;2177memset(&fargs, 0, sizeof(FT_Open_Args));2178fargs.memory_base = (unsigned char *)fd->data_ptr;2179fargs.memory_size = fd->data_size;2180fargs.flags = FT_OPEN_MEMORY;2181fargs.stream = &stream;21822183MutexLock ftlock(ft_mutex);21842185FT_Face tmp_face = nullptr;2186error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);2187if (error == 0) {2188face_count = tmp_face->num_faces;2189FT_Done_Face(tmp_face);2190}2191#endif2192}21932194return face_count;2195}21962197void TextServerAdvanced::_font_set_style(const RID &p_font_rid, BitField<FontStyle> p_style) {2198FontAdvanced *fd = _get_font_data(p_font_rid);2199ERR_FAIL_NULL(fd);22002201MutexLock lock(fd->mutex);2202Vector2i size = _get_size(fd, 16);2203FontForSizeAdvanced *ffsd = nullptr;2204ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2205fd->style_flags = p_style;2206}22072208BitField<TextServer::FontStyle> TextServerAdvanced::_font_get_style(const RID &p_font_rid) const {2209FontAdvanced *fd = _get_font_data(p_font_rid);2210ERR_FAIL_NULL_V(fd, 0);22112212MutexLock lock(fd->mutex);2213Vector2i size = _get_size(fd, 16);2214FontForSizeAdvanced *ffsd = nullptr;2215ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0);2216return fd->style_flags;2217}22182219void TextServerAdvanced::_font_set_style_name(const RID &p_font_rid, const String &p_name) {2220FontAdvanced *fd = _get_font_data(p_font_rid);2221ERR_FAIL_NULL(fd);22222223MutexLock lock(fd->mutex);2224Vector2i size = _get_size(fd, 16);2225FontForSizeAdvanced *ffsd = nullptr;2226ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2227fd->style_name = p_name;2228}22292230String TextServerAdvanced::_font_get_style_name(const RID &p_font_rid) const {2231FontAdvanced *fd = _get_font_data(p_font_rid);2232ERR_FAIL_NULL_V(fd, String());22332234MutexLock lock(fd->mutex);2235Vector2i size = _get_size(fd, 16);2236FontForSizeAdvanced *ffsd = nullptr;2237ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), String());2238return fd->style_name;2239}22402241void TextServerAdvanced::_font_set_weight(const RID &p_font_rid, int64_t p_weight) {2242FontAdvanced *fd = _get_font_data(p_font_rid);2243ERR_FAIL_NULL(fd);22442245MutexLock lock(fd->mutex);2246Vector2i size = _get_size(fd, 16);2247FontForSizeAdvanced *ffsd = nullptr;2248ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2249fd->weight = CLAMP(p_weight, 100, 999);2250}22512252int64_t TextServerAdvanced::_font_get_weight(const RID &p_font_rid) const {2253FontAdvanced *fd = _get_font_data(p_font_rid);2254ERR_FAIL_NULL_V(fd, 400);22552256MutexLock lock(fd->mutex);2257Vector2i size = _get_size(fd, 16);2258FontForSizeAdvanced *ffsd = nullptr;2259ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 400);2260return fd->weight;2261}22622263void TextServerAdvanced::_font_set_stretch(const RID &p_font_rid, int64_t p_stretch) {2264FontAdvanced *fd = _get_font_data(p_font_rid);2265ERR_FAIL_NULL(fd);22662267MutexLock lock(fd->mutex);2268Vector2i size = _get_size(fd, 16);2269FontForSizeAdvanced *ffsd = nullptr;2270ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2271fd->stretch = CLAMP(p_stretch, 50, 200);2272}22732274int64_t TextServerAdvanced::_font_get_stretch(const RID &p_font_rid) const {2275FontAdvanced *fd = _get_font_data(p_font_rid);2276ERR_FAIL_NULL_V(fd, 100);22772278MutexLock lock(fd->mutex);2279Vector2i size = _get_size(fd, 16);2280FontForSizeAdvanced *ffsd = nullptr;2281ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 100);2282return fd->stretch;2283}22842285void TextServerAdvanced::_font_set_name(const RID &p_font_rid, const String &p_name) {2286FontAdvanced *fd = _get_font_data(p_font_rid);2287ERR_FAIL_NULL(fd);22882289MutexLock lock(fd->mutex);2290Vector2i size = _get_size(fd, 16);2291FontForSizeAdvanced *ffsd = nullptr;2292ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2293fd->font_name = p_name;2294}22952296String TextServerAdvanced::_font_get_name(const RID &p_font_rid) const {2297FontAdvanced *fd = _get_font_data(p_font_rid);2298ERR_FAIL_NULL_V(fd, String());22992300MutexLock lock(fd->mutex);2301Vector2i size = _get_size(fd, 16);2302FontForSizeAdvanced *ffsd = nullptr;2303ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), String());2304return fd->font_name;2305}23062307Dictionary TextServerAdvanced::_font_get_ot_name_strings(const RID &p_font_rid) const {2308FontAdvanced *fd = _get_font_data(p_font_rid);2309ERR_FAIL_NULL_V(fd, Dictionary());23102311Dictionary out;2312#ifdef MODULE_FREETYPE_ENABLED2313MutexLock lock(fd->mutex);2314Vector2i size = _get_size(fd, 16);2315FontForSizeAdvanced *ffsd = nullptr;2316ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary());23172318hb_face_t *hb_face = hb_font_get_face(ffsd->hb_handle);23192320unsigned int num_entries = 0;2321const hb_ot_name_entry_t *names = hb_ot_name_list_names(hb_face, &num_entries);2322HashMap<String, Dictionary> names_for_lang;2323for (unsigned int i = 0; i < num_entries; i++) {2324String name;2325switch (names[i].name_id) {2326case HB_OT_NAME_ID_COPYRIGHT: {2327name = "copyright";2328} break;2329case HB_OT_NAME_ID_FONT_FAMILY: {2330name = "family_name";2331} break;2332case HB_OT_NAME_ID_FONT_SUBFAMILY: {2333name = "subfamily_name";2334} break;2335case HB_OT_NAME_ID_UNIQUE_ID: {2336name = "unique_identifier";2337} break;2338case HB_OT_NAME_ID_FULL_NAME: {2339name = "full_name";2340} break;2341case HB_OT_NAME_ID_VERSION_STRING: {2342name = "version";2343} break;2344case HB_OT_NAME_ID_POSTSCRIPT_NAME: {2345name = "postscript_name";2346} break;2347case HB_OT_NAME_ID_TRADEMARK: {2348name = "trademark";2349} break;2350case HB_OT_NAME_ID_MANUFACTURER: {2351name = "manufacturer";2352} break;2353case HB_OT_NAME_ID_DESIGNER: {2354name = "designer";2355} break;2356case HB_OT_NAME_ID_DESCRIPTION: {2357name = "description";2358} break;2359case HB_OT_NAME_ID_VENDOR_URL: {2360name = "vendor_url";2361} break;2362case HB_OT_NAME_ID_DESIGNER_URL: {2363name = "designer_url";2364} break;2365case HB_OT_NAME_ID_LICENSE: {2366name = "license";2367} break;2368case HB_OT_NAME_ID_LICENSE_URL: {2369name = "license_url";2370} break;2371case HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY: {2372name = "typographic_family_name";2373} break;2374case HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY: {2375name = "typographic_subfamily_name";2376} break;2377case HB_OT_NAME_ID_MAC_FULL_NAME: {2378name = "full_name_macos";2379} break;2380case HB_OT_NAME_ID_SAMPLE_TEXT: {2381name = "sample_text";2382} break;2383case HB_OT_NAME_ID_CID_FINDFONT_NAME: {2384name = "cid_findfont_name";2385} break;2386case HB_OT_NAME_ID_WWS_FAMILY: {2387name = "weight_width_slope_family_name";2388} break;2389case HB_OT_NAME_ID_WWS_SUBFAMILY: {2390name = "weight_width_slope_subfamily_name";2391} break;2392case HB_OT_NAME_ID_LIGHT_BACKGROUND: {2393name = "light_background_palette";2394} break;2395case HB_OT_NAME_ID_DARK_BACKGROUND: {2396name = "dark_background_palette";2397} break;2398case HB_OT_NAME_ID_VARIATIONS_PS_PREFIX: {2399name = "postscript_name_prefix";2400} break;2401default: {2402name = vformat("unknown_%d", names[i].name_id);2403} break;2404}2405String text;2406unsigned int text_size = hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, nullptr, nullptr) + 1;2407text.resize_uninitialized(text_size);2408hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, &text_size, (uint32_t *)text.ptrw());2409if (!text.is_empty()) {2410Dictionary &id_string = names_for_lang[String(hb_language_to_string(names[i].language))];2411id_string[name] = text;2412}2413}24142415for (const KeyValue<String, Dictionary> &E : names_for_lang) {2416out[E.key] = E.value;2417}2418#endif2419return out;2420}24212422void TextServerAdvanced::_font_set_antialiasing(const RID &p_font_rid, TextServer::FontAntialiasing p_antialiasing) {2423FontAdvanced *fd = _get_font_data(p_font_rid);2424ERR_FAIL_NULL(fd);24252426MutexLock lock(fd->mutex);2427if (fd->antialiasing != p_antialiasing) {2428_font_clear_cache(fd);2429fd->antialiasing = p_antialiasing;2430}2431}24322433TextServer::FontAntialiasing TextServerAdvanced::_font_get_antialiasing(const RID &p_font_rid) const {2434FontAdvanced *fd = _get_font_data(p_font_rid);2435ERR_FAIL_NULL_V(fd, TextServer::FONT_ANTIALIASING_NONE);24362437MutexLock lock(fd->mutex);2438return fd->antialiasing;2439}24402441void TextServerAdvanced::_font_set_disable_embedded_bitmaps(const RID &p_font_rid, bool p_disable_embedded_bitmaps) {2442FontAdvanced *fd = _get_font_data(p_font_rid);2443ERR_FAIL_NULL(fd);24442445MutexLock lock(fd->mutex);2446if (fd->disable_embedded_bitmaps != p_disable_embedded_bitmaps) {2447_font_clear_cache(fd);2448fd->disable_embedded_bitmaps = p_disable_embedded_bitmaps;2449}2450}24512452bool TextServerAdvanced::_font_get_disable_embedded_bitmaps(const RID &p_font_rid) const {2453FontAdvanced *fd = _get_font_data(p_font_rid);2454ERR_FAIL_NULL_V(fd, false);24552456MutexLock lock(fd->mutex);2457return fd->disable_embedded_bitmaps;2458}24592460void TextServerAdvanced::_font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) {2461FontAdvanced *fd = _get_font_data(p_font_rid);2462ERR_FAIL_NULL(fd);24632464MutexLock lock(fd->mutex);2465if (fd->mipmaps != p_generate_mipmaps) {2466for (KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {2467for (int i = 0; i < E.value->textures.size(); i++) {2468E.value->textures.write[i].dirty = true;2469E.value->textures.write[i].texture = Ref<ImageTexture>();2470}2471}2472fd->mipmaps = p_generate_mipmaps;2473}2474}24752476bool TextServerAdvanced::_font_get_generate_mipmaps(const RID &p_font_rid) const {2477FontAdvanced *fd = _get_font_data(p_font_rid);2478ERR_FAIL_NULL_V(fd, false);24792480MutexLock lock(fd->mutex);2481return fd->mipmaps;2482}24832484void TextServerAdvanced::_font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) {2485FontAdvanced *fd = _get_font_data(p_font_rid);2486ERR_FAIL_NULL(fd);24872488MutexLock lock(fd->mutex);2489if (fd->msdf != p_msdf) {2490_font_clear_cache(fd);2491fd->msdf = p_msdf;2492}2493}24942495bool TextServerAdvanced::_font_is_multichannel_signed_distance_field(const RID &p_font_rid) const {2496FontAdvanced *fd = _get_font_data(p_font_rid);2497ERR_FAIL_NULL_V(fd, false);24982499MutexLock lock(fd->mutex);2500return fd->msdf;2501}25022503void TextServerAdvanced::_font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) {2504FontAdvanced *fd = _get_font_data(p_font_rid);2505ERR_FAIL_NULL(fd);25062507MutexLock lock(fd->mutex);2508if (fd->msdf_range != p_msdf_pixel_range) {2509_font_clear_cache(fd);2510fd->msdf_range = p_msdf_pixel_range;2511}2512}25132514int64_t TextServerAdvanced::_font_get_msdf_pixel_range(const RID &p_font_rid) const {2515FontAdvanced *fd = _get_font_data(p_font_rid);2516ERR_FAIL_NULL_V(fd, false);25172518MutexLock lock(fd->mutex);2519return fd->msdf_range;2520}25212522void TextServerAdvanced::_font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) {2523FontAdvanced *fd = _get_font_data(p_font_rid);2524ERR_FAIL_NULL(fd);25252526MutexLock lock(fd->mutex);2527if (fd->msdf_source_size != p_msdf_size) {2528_font_clear_cache(fd);2529fd->msdf_source_size = p_msdf_size;2530}2531}25322533int64_t TextServerAdvanced::_font_get_msdf_size(const RID &p_font_rid) const {2534FontAdvanced *fd = _get_font_data(p_font_rid);2535ERR_FAIL_NULL_V(fd, 0);25362537MutexLock lock(fd->mutex);2538return fd->msdf_source_size;2539}25402541void TextServerAdvanced::_font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) {2542FontAdvanced *fd = _get_font_data(p_font_rid);2543ERR_FAIL_NULL(fd);25442545MutexLock lock(fd->mutex);2546fd->fixed_size = p_fixed_size;2547}25482549int64_t TextServerAdvanced::_font_get_fixed_size(const RID &p_font_rid) const {2550FontAdvanced *fd = _get_font_data(p_font_rid);2551ERR_FAIL_NULL_V(fd, 0);25522553MutexLock lock(fd->mutex);2554return fd->fixed_size;2555}25562557void TextServerAdvanced::_font_set_fixed_size_scale_mode(const RID &p_font_rid, TextServer::FixedSizeScaleMode p_fixed_size_scale_mode) {2558FontAdvanced *fd = _get_font_data(p_font_rid);2559ERR_FAIL_NULL(fd);25602561MutexLock lock(fd->mutex);2562fd->fixed_size_scale_mode = p_fixed_size_scale_mode;2563}25642565TextServer::FixedSizeScaleMode TextServerAdvanced::_font_get_fixed_size_scale_mode(const RID &p_font_rid) const {2566FontAdvanced *fd = _get_font_data(p_font_rid);2567ERR_FAIL_NULL_V(fd, FIXED_SIZE_SCALE_DISABLE);25682569MutexLock lock(fd->mutex);2570return fd->fixed_size_scale_mode;2571}25722573void TextServerAdvanced::_font_set_allow_system_fallback(const RID &p_font_rid, bool p_allow_system_fallback) {2574FontAdvanced *fd = _get_font_data(p_font_rid);2575ERR_FAIL_NULL(fd);25762577MutexLock lock(fd->mutex);2578fd->allow_system_fallback = p_allow_system_fallback;2579}25802581bool TextServerAdvanced::_font_is_allow_system_fallback(const RID &p_font_rid) const {2582FontAdvanced *fd = _get_font_data(p_font_rid);2583ERR_FAIL_NULL_V(fd, false);25842585MutexLock lock(fd->mutex);2586return fd->allow_system_fallback;2587}25882589void TextServerAdvanced::_font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) {2590FontAdvanced *fd = _get_font_data(p_font_rid);2591ERR_FAIL_NULL(fd);25922593MutexLock lock(fd->mutex);2594if (fd->force_autohinter != p_force_autohinter) {2595_font_clear_cache(fd);2596fd->force_autohinter = p_force_autohinter;2597}2598}25992600bool TextServerAdvanced::_font_is_force_autohinter(const RID &p_font_rid) const {2601FontAdvanced *fd = _get_font_data(p_font_rid);2602ERR_FAIL_NULL_V(fd, false);26032604MutexLock lock(fd->mutex);2605return fd->force_autohinter;2606}26072608void TextServerAdvanced::_font_set_modulate_color_glyphs(const RID &p_font_rid, bool p_modulate) {2609FontAdvanced *fd = _get_font_data(p_font_rid);2610ERR_FAIL_NULL(fd);26112612MutexLock lock(fd->mutex);2613if (fd->modulate_color_glyphs != p_modulate) {2614fd->modulate_color_glyphs = p_modulate;2615}2616}26172618bool TextServerAdvanced::_font_is_modulate_color_glyphs(const RID &p_font_rid) const {2619FontAdvanced *fd = _get_font_data(p_font_rid);2620ERR_FAIL_NULL_V(fd, false);26212622MutexLock lock(fd->mutex);2623return fd->modulate_color_glyphs;2624}26252626void TextServerAdvanced::_font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) {2627FontAdvanced *fd = _get_font_data(p_font_rid);2628ERR_FAIL_NULL(fd);26292630MutexLock lock(fd->mutex);2631if (fd->hinting != p_hinting) {2632_font_clear_cache(fd);2633fd->hinting = p_hinting;2634}2635}26362637TextServer::Hinting TextServerAdvanced::_font_get_hinting(const RID &p_font_rid) const {2638FontAdvanced *fd = _get_font_data(p_font_rid);2639ERR_FAIL_NULL_V(fd, HINTING_NONE);26402641MutexLock lock(fd->mutex);2642return fd->hinting;2643}26442645void TextServerAdvanced::_font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) {2646FontAdvanced *fd = _get_font_data(p_font_rid);2647ERR_FAIL_NULL(fd);26482649MutexLock lock(fd->mutex);2650fd->subpixel_positioning = p_subpixel;2651}26522653TextServer::SubpixelPositioning TextServerAdvanced::_font_get_subpixel_positioning(const RID &p_font_rid) const {2654FontAdvanced *fd = _get_font_data(p_font_rid);2655ERR_FAIL_NULL_V(fd, SUBPIXEL_POSITIONING_DISABLED);26562657MutexLock lock(fd->mutex);2658return fd->subpixel_positioning;2659}26602661void TextServerAdvanced::_font_set_keep_rounding_remainders(const RID &p_font_rid, bool p_keep_rounding_remainders) {2662FontAdvanced *fd = _get_font_data(p_font_rid);2663ERR_FAIL_NULL(fd);26642665MutexLock lock(fd->mutex);2666fd->keep_rounding_remainders = p_keep_rounding_remainders;2667}26682669bool TextServerAdvanced::_font_get_keep_rounding_remainders(const RID &p_font_rid) const {2670FontAdvanced *fd = _get_font_data(p_font_rid);2671ERR_FAIL_NULL_V(fd, false);26722673MutexLock lock(fd->mutex);2674return fd->keep_rounding_remainders;2675}26762677void TextServerAdvanced::_font_set_embolden(const RID &p_font_rid, double p_strength) {2678FontAdvanced *fd = _get_font_data(p_font_rid);2679ERR_FAIL_NULL(fd);26802681MutexLock lock(fd->mutex);2682if (fd->embolden != p_strength) {2683_font_clear_cache(fd);2684fd->embolden = p_strength;2685}2686}26872688double TextServerAdvanced::_font_get_embolden(const RID &p_font_rid) const {2689FontAdvanced *fd = _get_font_data(p_font_rid);2690ERR_FAIL_NULL_V(fd, 0.0);26912692MutexLock lock(fd->mutex);2693return fd->embolden;2694}26952696void TextServerAdvanced::_font_set_spacing(const RID &p_font_rid, SpacingType p_spacing, int64_t p_value) {2697ERR_FAIL_INDEX((int)p_spacing, 4);2698FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);2699if (fdv) {2700if (fdv->extra_spacing[p_spacing] != p_value) {2701fdv->extra_spacing[p_spacing] = p_value;2702}2703} else {2704FontAdvanced *fd = font_owner.get_or_null(p_font_rid);2705ERR_FAIL_NULL(fd);27062707MutexLock lock(fd->mutex);2708if (fd->extra_spacing[p_spacing] != p_value) {2709fd->extra_spacing[p_spacing] = p_value;2710}2711}2712}27132714int64_t TextServerAdvanced::_font_get_spacing(const RID &p_font_rid, SpacingType p_spacing) const {2715ERR_FAIL_INDEX_V((int)p_spacing, 4, 0);2716FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);2717if (fdv) {2718return fdv->extra_spacing[p_spacing];2719} else {2720FontAdvanced *fd = font_owner.get_or_null(p_font_rid);2721ERR_FAIL_NULL_V(fd, 0);27222723MutexLock lock(fd->mutex);2724return fd->extra_spacing[p_spacing];2725}2726}27272728void TextServerAdvanced::_font_set_baseline_offset(const RID &p_font_rid, double p_baseline_offset) {2729FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);2730if (fdv) {2731if (fdv->baseline_offset != p_baseline_offset) {2732fdv->baseline_offset = p_baseline_offset;2733}2734} else {2735FontAdvanced *fd = font_owner.get_or_null(p_font_rid);2736ERR_FAIL_NULL(fd);27372738MutexLock lock(fd->mutex);2739if (fd->baseline_offset != p_baseline_offset) {2740_font_clear_cache(fd);2741fd->baseline_offset = p_baseline_offset;2742}2743}2744}27452746double TextServerAdvanced::_font_get_baseline_offset(const RID &p_font_rid) const {2747FontAdvancedLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);2748if (fdv) {2749return fdv->baseline_offset;2750} else {2751FontAdvanced *fd = font_owner.get_or_null(p_font_rid);2752ERR_FAIL_NULL_V(fd, 0.0);27532754MutexLock lock(fd->mutex);2755return fd->baseline_offset;2756}2757}27582759void TextServerAdvanced::_font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) {2760FontAdvanced *fd = _get_font_data(p_font_rid);2761ERR_FAIL_NULL(fd);27622763MutexLock lock(fd->mutex);2764if (fd->transform != p_transform) {2765_font_clear_cache(fd);2766fd->transform = p_transform;2767}2768}27692770Transform2D TextServerAdvanced::_font_get_transform(const RID &p_font_rid) const {2771FontAdvanced *fd = _get_font_data(p_font_rid);2772ERR_FAIL_NULL_V(fd, Transform2D());27732774MutexLock lock(fd->mutex);2775return fd->transform;2776}27772778void TextServerAdvanced::_font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) {2779FontAdvanced *fd = _get_font_data(p_font_rid);2780ERR_FAIL_NULL(fd);27812782MutexLock lock(fd->mutex);2783if (!fd->variation_coordinates.recursive_equal(p_variation_coordinates, 1)) {2784_font_clear_cache(fd);2785fd->variation_coordinates = p_variation_coordinates.duplicate();2786}2787}27882789double TextServerAdvanced::_font_get_oversampling(const RID &p_font_rid) const {2790FontAdvanced *fd = _get_font_data(p_font_rid);2791ERR_FAIL_NULL_V(fd, -1.0);27922793MutexLock lock(fd->mutex);2794return fd->oversampling_override;2795}27962797void TextServerAdvanced::_font_set_oversampling(const RID &p_font_rid, double p_oversampling) {2798FontAdvanced *fd = _get_font_data(p_font_rid);2799ERR_FAIL_NULL(fd);28002801MutexLock lock(fd->mutex);2802if (fd->oversampling_override != p_oversampling) {2803_font_clear_cache(fd);2804fd->oversampling_override = p_oversampling;2805}2806}28072808Dictionary TextServerAdvanced::_font_get_variation_coordinates(const RID &p_font_rid) const {2809FontAdvanced *fd = _get_font_data(p_font_rid);2810ERR_FAIL_NULL_V(fd, Dictionary());28112812MutexLock lock(fd->mutex);2813return fd->variation_coordinates;2814}28152816TypedArray<Vector2i> TextServerAdvanced::_font_get_size_cache_list(const RID &p_font_rid) const {2817FontAdvanced *fd = _get_font_data(p_font_rid);2818ERR_FAIL_NULL_V(fd, TypedArray<Vector2i>());28192820MutexLock lock(fd->mutex);2821TypedArray<Vector2i> ret;2822for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {2823if ((E.key.x % 64 == 0) && (E.value->viewport_oversampling == 0)) {2824ret.push_back(Vector2i(E.key.x / 64, E.key.y));2825}2826}2827return ret;2828}28292830TypedArray<Dictionary> TextServerAdvanced::_font_get_size_cache_info(const RID &p_font_rid) const {2831FontAdvanced *fd = _get_font_data(p_font_rid);2832ERR_FAIL_NULL_V(fd, TypedArray<Dictionary>());28332834MutexLock lock(fd->mutex);2835TypedArray<Dictionary> ret;2836for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {2837Dictionary size_info;2838size_info["size_px"] = Vector2i(E.key.x / 64, E.key.y);2839if (E.value->viewport_oversampling) {2840size_info["viewport_oversampling"] = double(E.value->viewport_oversampling) / 64.0;2841}2842size_info["glyphs"] = E.value->glyph_map.size();2843size_info["textures"] = E.value->textures.size();2844uint64_t sz = 0;2845for (const ShelfPackTexture &tx : E.value->textures) {2846sz += tx.image->get_data_size() * 2;2847}2848size_info["textures_size"] = sz;2849ret.push_back(size_info);2850}28512852return ret;2853}28542855void TextServerAdvanced::_font_clear_size_cache(const RID &p_font_rid) {2856FontAdvanced *fd = _get_font_data(p_font_rid);2857ERR_FAIL_NULL(fd);28582859MutexLock lock(fd->mutex);2860MutexLock ftlock(ft_mutex);2861for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {2862if (E.value->viewport_oversampling != 0) {2863OversamplingLevel *ol = oversampling_levels.getptr(E.value->viewport_oversampling);2864if (ol) {2865ol->fonts.erase(E.value);2866}2867}2868memdelete(E.value);2869}2870fd->cache.clear();2871}28722873void TextServerAdvanced::_font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) {2874FontAdvanced *fd = _get_font_data(p_font_rid);2875ERR_FAIL_NULL(fd);28762877MutexLock lock(fd->mutex);2878MutexLock ftlock(ft_mutex);2879Vector2i size = Vector2i(p_size.x * 64, p_size.y);2880if (fd->cache.has(size)) {2881if (fd->cache[size]->viewport_oversampling != 0) {2882OversamplingLevel *ol = oversampling_levels.getptr(fd->cache[size]->viewport_oversampling);2883if (ol) {2884ol->fonts.erase(fd->cache[size]);2885}2886}2887memdelete(fd->cache[size]);2888fd->cache.erase(size);2889}2890}28912892void TextServerAdvanced::_font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) {2893FontAdvanced *fd = _get_font_data(p_font_rid);2894ERR_FAIL_NULL(fd);28952896MutexLock lock(fd->mutex);2897Vector2i size = _get_size(fd, p_size);28982899FontForSizeAdvanced *ffsd = nullptr;2900ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2901ffsd->ascent = p_ascent;2902}29032904double TextServerAdvanced::_font_get_ascent(const RID &p_font_rid, int64_t p_size) const {2905FontAdvanced *fd = _get_font_data(p_font_rid);2906ERR_FAIL_NULL_V(fd, 0.0);29072908MutexLock lock(fd->mutex);2909Vector2i size = _get_size(fd, p_size);29102911FontForSizeAdvanced *ffsd = nullptr;2912ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);29132914if (fd->msdf) {2915return ffsd->ascent * (double)p_size / (double)fd->msdf_source_size;2916} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {2917if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2918return ffsd->ascent * (double)p_size / (double)fd->fixed_size;2919} else {2920return ffsd->ascent * Math::round((double)p_size / (double)fd->fixed_size);2921}2922} else {2923return ffsd->ascent;2924}2925}29262927void TextServerAdvanced::_font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) {2928FontAdvanced *fd = _get_font_data(p_font_rid);2929ERR_FAIL_NULL(fd);29302931Vector2i size = _get_size(fd, p_size);29322933FontForSizeAdvanced *ffsd = nullptr;2934ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2935ffsd->descent = p_descent;2936}29372938double TextServerAdvanced::_font_get_descent(const RID &p_font_rid, int64_t p_size) const {2939FontAdvanced *fd = _get_font_data(p_font_rid);2940ERR_FAIL_NULL_V(fd, 0.0);29412942MutexLock lock(fd->mutex);2943Vector2i size = _get_size(fd, p_size);29442945FontForSizeAdvanced *ffsd = nullptr;2946ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);29472948if (fd->msdf) {2949return ffsd->descent * (double)p_size / (double)fd->msdf_source_size;2950} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {2951if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2952return ffsd->descent * (double)p_size / (double)fd->fixed_size;2953} else {2954return ffsd->descent * Math::round((double)p_size / (double)fd->fixed_size);2955}2956} else {2957return ffsd->descent;2958}2959}29602961void TextServerAdvanced::_font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) {2962FontAdvanced *fd = _get_font_data(p_font_rid);2963ERR_FAIL_NULL(fd);29642965MutexLock lock(fd->mutex);2966Vector2i size = _get_size(fd, p_size);29672968FontForSizeAdvanced *ffsd = nullptr;2969ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2970ffsd->underline_position = p_underline_position;2971}29722973double TextServerAdvanced::_font_get_underline_position(const RID &p_font_rid, int64_t p_size) const {2974FontAdvanced *fd = _get_font_data(p_font_rid);2975ERR_FAIL_NULL_V(fd, 0.0);29762977MutexLock lock(fd->mutex);2978Vector2i size = _get_size(fd, p_size);29792980FontForSizeAdvanced *ffsd = nullptr;2981ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);29822983if (fd->msdf) {2984return ffsd->underline_position * (double)p_size / (double)fd->msdf_source_size;2985} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {2986if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2987return ffsd->underline_position * (double)p_size / (double)fd->fixed_size;2988} else {2989return ffsd->underline_position * Math::round((double)p_size / (double)fd->fixed_size);2990}2991} else {2992return ffsd->underline_position;2993}2994}29952996void TextServerAdvanced::_font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) {2997FontAdvanced *fd = _get_font_data(p_font_rid);2998ERR_FAIL_NULL(fd);29993000MutexLock lock(fd->mutex);3001Vector2i size = _get_size(fd, p_size);30023003FontForSizeAdvanced *ffsd = nullptr;3004ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3005ffsd->underline_thickness = p_underline_thickness;3006}30073008double TextServerAdvanced::_font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const {3009FontAdvanced *fd = _get_font_data(p_font_rid);3010ERR_FAIL_NULL_V(fd, 0.0);30113012MutexLock lock(fd->mutex);3013Vector2i size = _get_size(fd, p_size);30143015FontForSizeAdvanced *ffsd = nullptr;3016ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);30173018if (fd->msdf) {3019return ffsd->underline_thickness * (double)p_size / (double)fd->msdf_source_size;3020} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {3021if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3022return ffsd->underline_thickness * (double)p_size / (double)fd->fixed_size;3023} else {3024return ffsd->underline_thickness * Math::round((double)p_size / (double)fd->fixed_size);3025}3026} else {3027return ffsd->underline_thickness;3028}3029}30303031void TextServerAdvanced::_font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) {3032FontAdvanced *fd = _get_font_data(p_font_rid);3033ERR_FAIL_NULL(fd);30343035MutexLock lock(fd->mutex);3036Vector2i size = _get_size(fd, p_size);30373038FontForSizeAdvanced *ffsd = nullptr;3039ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));30403041#ifdef MODULE_FREETYPE_ENABLED3042if (fd->face) {3043return; // Do not override scale for dynamic fonts, it's calculated automatically.3044}3045#endif3046ffsd->scale = p_scale;3047}30483049double TextServerAdvanced::_font_get_scale(const RID &p_font_rid, int64_t p_size) const {3050FontAdvanced *fd = _get_font_data(p_font_rid);3051ERR_FAIL_NULL_V(fd, 0.0);30523053MutexLock lock(fd->mutex);3054Vector2i size = _get_size(fd, p_size);30553056FontForSizeAdvanced *ffsd = nullptr;3057ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);30583059if (fd->msdf) {3060return ffsd->scale * (double)p_size / (double)fd->msdf_source_size;3061} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {3062if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3063return ffsd->scale * (double)p_size / (double)fd->fixed_size;3064} else {3065return ffsd->scale * Math::round((double)p_size / (double)fd->fixed_size);3066}3067} else {3068return ffsd->scale;3069}3070}30713072int64_t TextServerAdvanced::_font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const {3073FontAdvanced *fd = _get_font_data(p_font_rid);3074ERR_FAIL_NULL_V(fd, 0);30753076MutexLock lock(fd->mutex);3077Vector2i size = _get_size_outline(fd, p_size);30783079FontForSizeAdvanced *ffsd = nullptr;3080ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0);30813082return ffsd->textures.size();3083}30843085void TextServerAdvanced::_font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) {3086FontAdvanced *fd = _get_font_data(p_font_rid);3087ERR_FAIL_NULL(fd);3088MutexLock lock(fd->mutex);3089Vector2i size = _get_size_outline(fd, p_size);30903091FontForSizeAdvanced *ffsd = nullptr;3092ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3093ffsd->textures.clear();3094}30953096void TextServerAdvanced::_font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) {3097FontAdvanced *fd = _get_font_data(p_font_rid);3098ERR_FAIL_NULL(fd);30993100MutexLock lock(fd->mutex);3101Vector2i size = _get_size_outline(fd, p_size);3102FontForSizeAdvanced *ffsd = nullptr;3103ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3104ERR_FAIL_INDEX(p_texture_index, ffsd->textures.size());31053106ffsd->textures.remove_at(p_texture_index);3107}31083109void TextServerAdvanced::_font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) {3110FontAdvanced *fd = _get_font_data(p_font_rid);3111ERR_FAIL_NULL(fd);3112ERR_FAIL_COND(p_image.is_null());31133114MutexLock lock(fd->mutex);3115Vector2i size = _get_size_outline(fd, p_size);3116FontForSizeAdvanced *ffsd = nullptr;3117ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3118ERR_FAIL_COND(p_texture_index < 0);3119if (p_texture_index >= ffsd->textures.size()) {3120ffsd->textures.resize(p_texture_index + 1);3121}31223123ShelfPackTexture &tex = ffsd->textures.write[p_texture_index];31243125tex.image = p_image;3126tex.texture_w = p_image->get_width();3127tex.texture_h = p_image->get_height();31283129Ref<Image> img = p_image;3130if (fd->mipmaps && !img->has_mipmaps()) {3131img = p_image->duplicate();3132img->generate_mipmaps();3133}3134tex.texture = ImageTexture::create_from_image(img);3135tex.dirty = false;3136}31373138Ref<Image> TextServerAdvanced::_font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {3139FontAdvanced *fd = _get_font_data(p_font_rid);3140ERR_FAIL_NULL_V(fd, Ref<Image>());31413142MutexLock lock(fd->mutex);3143Vector2i size = _get_size_outline(fd, p_size);3144FontForSizeAdvanced *ffsd = nullptr;3145ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Ref<Image>());3146ERR_FAIL_INDEX_V(p_texture_index, ffsd->textures.size(), Ref<Image>());31473148const ShelfPackTexture &tex = ffsd->textures[p_texture_index];3149return tex.image;3150}31513152void TextServerAdvanced::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offsets) {3153ERR_FAIL_COND(p_offsets.size() % 4 != 0);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));3161ERR_FAIL_COND(p_texture_index < 0);3162if (p_texture_index >= ffsd->textures.size()) {3163ffsd->textures.resize(p_texture_index + 1);3164}31653166ShelfPackTexture &tex = ffsd->textures.write[p_texture_index];3167tex.shelves.clear();3168for (int32_t i = 0; i < p_offsets.size(); i += 4) {3169tex.shelves.push_back(Shelf(p_offsets[i], p_offsets[i + 1], p_offsets[i + 2], p_offsets[i + 3]));3170}3171}31723173PackedInt32Array TextServerAdvanced::_font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {3174FontAdvanced *fd = _get_font_data(p_font_rid);3175ERR_FAIL_NULL_V(fd, PackedInt32Array());31763177MutexLock lock(fd->mutex);3178Vector2i size = _get_size_outline(fd, p_size);3179FontForSizeAdvanced *ffsd = nullptr;3180ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), PackedInt32Array());3181ERR_FAIL_INDEX_V(p_texture_index, ffsd->textures.size(), PackedInt32Array());31823183const ShelfPackTexture &tex = ffsd->textures[p_texture_index];3184PackedInt32Array ret;3185ret.resize(tex.shelves.size() * 4);31863187int32_t *wr = ret.ptrw();3188int32_t i = 0;3189for (const Shelf &E : tex.shelves) {3190wr[i * 4] = E.x;3191wr[i * 4 + 1] = E.y;3192wr[i * 4 + 2] = E.w;3193wr[i * 4 + 3] = E.h;3194i++;3195}3196return ret;3197}31983199PackedInt32Array TextServerAdvanced::_font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {3200FontAdvanced *fd = _get_font_data(p_font_rid);3201ERR_FAIL_NULL_V(fd, PackedInt32Array());32023203MutexLock lock(fd->mutex);3204Vector2i size = _get_size_outline(fd, p_size);3205FontForSizeAdvanced *ffsd = nullptr;3206ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), PackedInt32Array());32073208PackedInt32Array ret;3209const HashMap<int32_t, FontGlyph> &gl = ffsd->glyph_map;3210for (const KeyValue<int32_t, FontGlyph> &E : gl) {3211ret.push_back(E.key);3212}3213return ret;3214}32153216void TextServerAdvanced::_font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) {3217FontAdvanced *fd = _get_font_data(p_font_rid);3218ERR_FAIL_NULL(fd);32193220MutexLock lock(fd->mutex);3221Vector2i size = _get_size_outline(fd, p_size);3222FontForSizeAdvanced *ffsd = nullptr;3223ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));32243225ffsd->glyph_map.clear();3226}32273228void TextServerAdvanced::_font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) {3229FontAdvanced *fd = _get_font_data(p_font_rid);3230ERR_FAIL_NULL(fd);32313232MutexLock lock(fd->mutex);3233Vector2i size = _get_size_outline(fd, p_size);3234FontForSizeAdvanced *ffsd = nullptr;3235ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));32363237ffsd->glyph_map.erase(p_glyph);3238}32393240double TextServerAdvanced::_get_extra_advance(RID p_font_rid, int p_font_size) const {3241const FontAdvanced *fd = _get_font_data(p_font_rid);3242ERR_FAIL_NULL_V(fd, 0.0);32433244MutexLock lock(fd->mutex);3245Vector2i size = _get_size(fd, p_font_size);32463247if (fd->embolden != 0.0) {3248return fd->embolden * double(size.x) / 4096.0;3249} else {3250return 0.0;3251}3252}32533254Vector2 TextServerAdvanced::_font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const {3255FontAdvanced *fd = _get_font_data(p_font_rid);3256ERR_FAIL_NULL_V(fd, Vector2());32573258MutexLock lock(fd->mutex);3259Vector2i size = _get_size(fd, p_size);32603261FontForSizeAdvanced *ffsd = nullptr;3262ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());32633264int mod = 0;3265if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3266TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3267if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3268mod = (layout << 24);3269}3270}32713272FontGlyph fgl;3273if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3274return Vector2(); // Invalid or non graphicl glyph, do not display errors.3275}32763277Vector2 ea;3278if (fd->embolden != 0.0) {3279ea.x = fd->embolden * double(size.x) / 4096.0;3280}32813282double scale = _font_get_scale(p_font_rid, p_size);3283if (fd->msdf) {3284return (fgl.advance + ea) * (double)p_size / (double)fd->msdf_source_size;3285} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {3286if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3287return (fgl.advance + ea) * (double)p_size / (double)fd->fixed_size;3288} else {3289return (fgl.advance + ea) * Math::round((double)p_size / (double)fd->fixed_size);3290}3291} 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))) {3292return (fgl.advance + ea).round();3293} else {3294return fgl.advance + ea;3295}3296}32973298void TextServerAdvanced::_font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) {3299FontAdvanced *fd = _get_font_data(p_font_rid);3300ERR_FAIL_NULL(fd);33013302MutexLock lock(fd->mutex);3303Vector2i size = _get_size(fd, p_size);33043305FontForSizeAdvanced *ffsd = nullptr;3306ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));33073308FontGlyph &fgl = ffsd->glyph_map[p_glyph];33093310fgl.advance = p_advance;3311fgl.found = true;3312}33133314Vector2 TextServerAdvanced::_font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3315FontAdvanced *fd = _get_font_data(p_font_rid);3316ERR_FAIL_NULL_V(fd, Vector2());33173318MutexLock lock(fd->mutex);3319Vector2i size = _get_size_outline(fd, p_size);33203321FontForSizeAdvanced *ffsd = nullptr;3322ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());33233324int mod = 0;3325if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3326TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3327if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3328mod = (layout << 24);3329}3330}33313332FontGlyph fgl;3333if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3334return Vector2(); // Invalid or non graphicl glyph, do not display errors.3335}33363337if (fd->msdf) {3338return fgl.rect.position * (double)p_size.x / (double)fd->msdf_source_size;3339} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size.x * 64) {3340if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3341return fgl.rect.position * (double)p_size.x / (double)fd->fixed_size;3342} else {3343return fgl.rect.position * Math::round((double)p_size.x / (double)fd->fixed_size);3344}3345} else {3346return fgl.rect.position;3347}3348}33493350void TextServerAdvanced::_font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) {3351FontAdvanced *fd = _get_font_data(p_font_rid);3352ERR_FAIL_NULL(fd);33533354MutexLock lock(fd->mutex);3355Vector2i size = _get_size_outline(fd, p_size);33563357FontForSizeAdvanced *ffsd = nullptr;3358ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));33593360FontGlyph &fgl = ffsd->glyph_map[p_glyph];33613362fgl.rect.position = p_offset;3363fgl.found = true;3364}33653366Vector2 TextServerAdvanced::_font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3367FontAdvanced *fd = _get_font_data(p_font_rid);3368ERR_FAIL_NULL_V(fd, Vector2());33693370MutexLock lock(fd->mutex);3371Vector2i size = _get_size_outline(fd, p_size);33723373FontForSizeAdvanced *ffsd = nullptr;3374ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());33753376int mod = 0;3377if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3378TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3379if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3380mod = (layout << 24);3381}3382}33833384FontGlyph fgl;3385if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3386return Vector2(); // Invalid or non graphicl glyph, do not display errors.3387}33883389if (fd->msdf) {3390return fgl.rect.size * (double)p_size.x / (double)fd->msdf_source_size;3391} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size.x * 64) {3392if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3393return fgl.rect.size * (double)p_size.x / (double)fd->fixed_size;3394} else {3395return fgl.rect.size * Math::round((double)p_size.x / (double)fd->fixed_size);3396}3397} else {3398return fgl.rect.size;3399}3400}34013402void TextServerAdvanced::_font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) {3403FontAdvanced *fd = _get_font_data(p_font_rid);3404ERR_FAIL_NULL(fd);34053406MutexLock lock(fd->mutex);3407Vector2i size = _get_size_outline(fd, p_size);34083409FontForSizeAdvanced *ffsd = nullptr;3410ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));34113412FontGlyph &fgl = ffsd->glyph_map[p_glyph];34133414fgl.rect.size = p_gl_size;3415fgl.found = true;3416}34173418Rect2 TextServerAdvanced::_font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3419FontAdvanced *fd = _get_font_data(p_font_rid);3420ERR_FAIL_NULL_V(fd, Rect2());34213422MutexLock lock(fd->mutex);3423Vector2i size = _get_size_outline(fd, p_size);34243425FontForSizeAdvanced *ffsd = nullptr;3426ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Rect2());34273428int mod = 0;3429if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3430TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3431if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3432mod = (layout << 24);3433}3434}34353436FontGlyph fgl;3437if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3438return Rect2(); // Invalid or non graphicl glyph, do not display errors.3439}34403441return fgl.uv_rect;3442}34433444void TextServerAdvanced::_font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) {3445FontAdvanced *fd = _get_font_data(p_font_rid);3446ERR_FAIL_NULL(fd);34473448MutexLock lock(fd->mutex);3449Vector2i size = _get_size_outline(fd, p_size);34503451FontForSizeAdvanced *ffsd = nullptr;3452ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));34533454FontGlyph &fgl = ffsd->glyph_map[p_glyph];34553456fgl.uv_rect = p_uv_rect;3457fgl.found = true;3458}34593460int64_t TextServerAdvanced::_font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3461FontAdvanced *fd = _get_font_data(p_font_rid);3462ERR_FAIL_NULL_V(fd, -1);34633464MutexLock lock(fd->mutex);3465Vector2i size = _get_size_outline(fd, p_size);34663467FontForSizeAdvanced *ffsd = nullptr;3468ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), -1);34693470int mod = 0;3471if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3472TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3473if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3474mod = (layout << 24);3475}3476}34773478FontGlyph fgl;3479if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3480return -1; // Invalid or non graphicl glyph, do not display errors.3481}34823483return fgl.texture_idx;3484}34853486void TextServerAdvanced::_font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) {3487FontAdvanced *fd = _get_font_data(p_font_rid);3488ERR_FAIL_NULL(fd);34893490MutexLock lock(fd->mutex);3491Vector2i size = _get_size_outline(fd, p_size);34923493FontForSizeAdvanced *ffsd = nullptr;3494ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));34953496FontGlyph &fgl = ffsd->glyph_map[p_glyph];34973498fgl.texture_idx = p_texture_idx;3499fgl.found = true;3500}35013502RID TextServerAdvanced::_font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3503FontAdvanced *fd = _get_font_data(p_font_rid);3504ERR_FAIL_NULL_V(fd, RID());35053506MutexLock lock(fd->mutex);3507Vector2i size = _get_size_outline(fd, p_size);35083509FontForSizeAdvanced *ffsd = nullptr;3510ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), RID());35113512int mod = 0;3513if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3514TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3515if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3516mod = (layout << 24);3517}3518}35193520FontGlyph fgl;3521if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3522return RID(); // Invalid or non graphicl glyph, do not display errors.3523}35243525ERR_FAIL_COND_V(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size(), RID());35263527if (RenderingServer::get_singleton() != nullptr) {3528if (fgl.texture_idx != -1) {3529if (ffsd->textures[fgl.texture_idx].dirty) {3530ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];3531Ref<Image> img = tex.image;3532if (fgl.from_svg) {3533// Same as the "fix alpha border" process option when importing SVGs3534img->fix_alpha_edges();3535}3536if (fd->mipmaps && !img->has_mipmaps()) {3537img = tex.image->duplicate();3538img->generate_mipmaps();3539}3540if (tex.texture.is_null()) {3541tex.texture = ImageTexture::create_from_image(img);3542} else {3543tex.texture->update(img);3544}3545tex.dirty = false;3546}3547return ffsd->textures[fgl.texture_idx].texture->get_rid();3548}3549}35503551return RID();3552}35533554Size2 TextServerAdvanced::_font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {3555FontAdvanced *fd = _get_font_data(p_font_rid);3556ERR_FAIL_NULL_V(fd, Size2());35573558MutexLock lock(fd->mutex);3559Vector2i size = _get_size_outline(fd, p_size);35603561FontForSizeAdvanced *ffsd = nullptr;3562ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Size2());35633564int mod = 0;3565if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3566TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3567if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3568mod = (layout << 24);3569}3570}35713572FontGlyph fgl;3573if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {3574return Size2(); // Invalid or non graphicl glyph, do not display errors.3575}35763577ERR_FAIL_COND_V(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size(), Size2());35783579if (RenderingServer::get_singleton() != nullptr) {3580if (fgl.texture_idx != -1) {3581if (ffsd->textures[fgl.texture_idx].dirty) {3582ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];3583Ref<Image> img = tex.image;3584if (fgl.from_svg) {3585// Same as the "fix alpha border" process option when importing SVGs3586img->fix_alpha_edges();3587}3588if (fd->mipmaps && !img->has_mipmaps()) {3589img = tex.image->duplicate();3590img->generate_mipmaps();3591}3592if (tex.texture.is_null()) {3593tex.texture = ImageTexture::create_from_image(img);3594} else {3595tex.texture->update(img);3596}3597tex.dirty = false;3598}3599return ffsd->textures[fgl.texture_idx].texture->get_size();3600}3601}36023603return Size2();3604}36053606Dictionary TextServerAdvanced::_font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const {3607FontAdvanced *fd = _get_font_data(p_font_rid);3608ERR_FAIL_NULL_V(fd, Dictionary());36093610MutexLock lock(fd->mutex);3611Vector2i size = _get_size(fd, p_size);36123613FontForSizeAdvanced *ffsd = nullptr;3614ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary());36153616#ifdef MODULE_FREETYPE_ENABLED3617PackedVector3Array points;3618PackedInt32Array contours;36193620int32_t index = p_index & 0xffffff; // Remove subpixel shifts.36213622int error = FT_Load_Glyph(fd->face, index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));3623ERR_FAIL_COND_V(error, Dictionary());36243625if (fd->embolden != 0.f) {3626FT_Pos strength = fd->embolden * size.x / 16; // 26.6 fractional units (1 / 64).3627FT_Outline_Embolden(&fd->face->glyph->outline, strength);3628}36293630if (fd->transform != Transform2D()) {3631FT_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).3632FT_Outline_Transform(&fd->face->glyph->outline, &mat);3633}36343635double scale = (1.0 / 64.0) * ffsd->scale;3636if (fd->msdf) {3637scale = scale * (double)p_size / (double)fd->msdf_source_size;3638} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {3639if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3640scale = scale * (double)p_size / (double)fd->fixed_size;3641} else {3642scale = scale * Math::round((double)p_size / (double)fd->fixed_size);3643}3644}3645for (short i = 0; i < fd->face->glyph->outline.n_points; i++) {3646points.push_back(Vector3(fd->face->glyph->outline.points[i].x * scale, -fd->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->face->glyph->outline.tags[i])));3647}3648for (short i = 0; i < fd->face->glyph->outline.n_contours; i++) {3649contours.push_back(fd->face->glyph->outline.contours[i]);3650}3651bool orientation = (FT_Outline_Get_Orientation(&fd->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);36523653Dictionary out;3654out["points"] = points;3655out["contours"] = contours;3656out["orientation"] = orientation;3657return out;3658#else3659return Dictionary();3660#endif3661}36623663TypedArray<Vector2i> TextServerAdvanced::_font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {3664FontAdvanced *fd = _get_font_data(p_font_rid);3665ERR_FAIL_NULL_V(fd, TypedArray<Vector2i>());36663667MutexLock lock(fd->mutex);3668Vector2i size = _get_size(fd, p_size);36693670FontForSizeAdvanced *ffsd = nullptr;3671ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), TypedArray<Vector2i>());36723673TypedArray<Vector2i> ret;3674for (const KeyValue<Vector2i, Vector2> &E : fd->cache[size]->kerning_map) {3675ret.push_back(E.key);3676}3677return ret;3678}36793680void TextServerAdvanced::_font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) {3681FontAdvanced *fd = _get_font_data(p_font_rid);3682ERR_FAIL_NULL(fd);36833684MutexLock lock(fd->mutex);3685Vector2i size = _get_size(fd, p_size);36863687FontForSizeAdvanced *ffsd = nullptr;3688ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3689ffsd->kerning_map.clear();3690}36913692void TextServerAdvanced::_font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) {3693FontAdvanced *fd = _get_font_data(p_font_rid);3694ERR_FAIL_NULL(fd);36953696MutexLock lock(fd->mutex);3697Vector2i size = _get_size(fd, p_size);36983699FontForSizeAdvanced *ffsd = nullptr;3700ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3701ffsd->kerning_map.erase(p_glyph_pair);3702}37033704void TextServerAdvanced::_font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {3705FontAdvanced *fd = _get_font_data(p_font_rid);3706ERR_FAIL_NULL(fd);37073708MutexLock lock(fd->mutex);3709Vector2i size = _get_size(fd, p_size);37103711FontForSizeAdvanced *ffsd = nullptr;3712ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3713ffsd->kerning_map[p_glyph_pair] = p_kerning;3714}37153716Vector2 TextServerAdvanced::_font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const {3717FontAdvanced *fd = _get_font_data(p_font_rid);3718ERR_FAIL_NULL_V(fd, Vector2());37193720MutexLock lock(fd->mutex);3721Vector2i size = _get_size(fd, p_size);37223723FontForSizeAdvanced *ffsd = nullptr;3724ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());37253726const HashMap<Vector2i, Vector2> &kern = ffsd->kerning_map;37273728if (kern.has(p_glyph_pair)) {3729if (fd->msdf) {3730return kern[p_glyph_pair] * (double)p_size / (double)fd->msdf_source_size;3731} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {3732if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3733return kern[p_glyph_pair] * (double)p_size / (double)fd->fixed_size;3734} else {3735return kern[p_glyph_pair] * Math::round((double)p_size / (double)fd->fixed_size);3736}3737} else {3738return kern[p_glyph_pair];3739}3740} else {3741#ifdef MODULE_FREETYPE_ENABLED3742if (fd->face) {3743FT_Vector delta;3744FT_Get_Kerning(fd->face, p_glyph_pair.x, p_glyph_pair.y, FT_KERNING_DEFAULT, &delta);3745if (fd->msdf) {3746return Vector2(delta.x, delta.y) * (double)p_size / (double)fd->msdf_source_size;3747} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {3748if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3749return Vector2(delta.x, delta.y) * (double)p_size / (double)fd->fixed_size;3750} else {3751return Vector2(delta.x, delta.y) * Math::round((double)p_size / (double)fd->fixed_size);3752}3753} else {3754return Vector2(delta.x, delta.y);3755}3756}3757#endif3758}3759return Vector2();3760}37613762int64_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 {3763FontAdvanced *fd = _get_font_data(p_font_rid);3764ERR_FAIL_NULL_V(fd, 0);3765ERR_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) + ".");3766ERR_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) + ".");37673768MutexLock lock(fd->mutex);3769Vector2i size = _get_size(fd, p_size);3770FontForSizeAdvanced *ffsd = nullptr;3771ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0);37723773#ifdef MODULE_FREETYPE_ENABLED3774if (fd->face) {3775if (p_variation_selector) {3776return FT_Face_GetCharVariantIndex(fd->face, p_char, p_variation_selector);3777} else {3778return FT_Get_Char_Index(fd->face, p_char);3779}3780} else {3781return (int64_t)p_char;3782}3783#else3784return (int64_t)p_char;3785#endif3786}37873788int64_t TextServerAdvanced::_font_get_char_from_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_glyph_index) const {3789FontAdvanced *fd = _get_font_data(p_font_rid);3790ERR_FAIL_NULL_V(fd, 0);37913792MutexLock lock(fd->mutex);3793Vector2i size = _get_size(fd, p_size);3794FontForSizeAdvanced *ffsd = nullptr;3795ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0);37963797#ifdef MODULE_FREETYPE_ENABLED3798if (ffsd->inv_glyph_map.is_empty()) {3799FT_Face face = fd->face;3800FT_UInt gindex;3801FT_ULong charcode = FT_Get_First_Char(face, &gindex);3802while (gindex != 0) {3803if (charcode != 0) {3804ffsd->inv_glyph_map[gindex] = charcode;3805}3806charcode = FT_Get_Next_Char(face, charcode, &gindex);3807}3808}38093810if (ffsd->inv_glyph_map.has(p_glyph_index)) {3811return ffsd->inv_glyph_map[p_glyph_index];3812} else {3813return 0;3814}3815#else3816return p_glyph_index;3817#endif3818}38193820bool TextServerAdvanced::_font_has_char(const RID &p_font_rid, int64_t p_char) const {3821FontAdvanced *fd = _get_font_data(p_font_rid);3822ERR_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) + ".");3823if (!fd) {3824return false;3825}38263827MutexLock lock(fd->mutex);3828FontForSizeAdvanced *ffsd = nullptr;3829if (fd->cache.is_empty()) {3830ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size * 64, 0) : Vector2i(16 * 64, 0), ffsd), false);3831} else {3832ffsd = fd->cache.begin()->value;3833}38343835#ifdef MODULE_FREETYPE_ENABLED3836if (fd->face) {3837return FT_Get_Char_Index(fd->face, p_char) != 0;3838}3839#endif3840return ffsd->glyph_map.has((int32_t)p_char);3841}38423843String TextServerAdvanced::_font_get_supported_chars(const RID &p_font_rid) const {3844FontAdvanced *fd = _get_font_data(p_font_rid);3845ERR_FAIL_NULL_V(fd, String());38463847MutexLock lock(fd->mutex);3848FontForSizeAdvanced *ffsd = nullptr;3849if (fd->cache.is_empty()) {3850ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size * 64, 0) : Vector2i(16 * 64, 0), ffsd), String());3851} else {3852ffsd = fd->cache.begin()->value;3853}38543855String chars;3856#ifdef MODULE_FREETYPE_ENABLED3857if (fd->face) {3858FT_UInt gindex;3859FT_ULong charcode = FT_Get_First_Char(fd->face, &gindex);3860while (gindex != 0) {3861if (charcode != 0) {3862chars = chars + String::chr(charcode);3863}3864charcode = FT_Get_Next_Char(fd->face, charcode, &gindex);3865}3866return chars;3867}3868#endif3869const HashMap<int32_t, FontGlyph> &gl = ffsd->glyph_map;3870for (const KeyValue<int32_t, FontGlyph> &E : gl) {3871chars = chars + String::chr(E.key);3872}3873return chars;3874}38753876PackedInt32Array TextServerAdvanced::_font_get_supported_glyphs(const RID &p_font_rid) const {3877FontAdvanced *fd = _get_font_data(p_font_rid);3878ERR_FAIL_NULL_V(fd, PackedInt32Array());38793880MutexLock lock(fd->mutex);3881FontForSizeAdvanced *at_size = nullptr;3882if (fd->cache.is_empty()) {3883ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size * 64, 0) : Vector2i(16 * 64, 0), at_size), PackedInt32Array());3884} else {3885at_size = fd->cache.begin()->value;3886}38873888PackedInt32Array glyphs;3889#ifdef MODULE_FREETYPE_ENABLED3890if (fd->face) {3891FT_UInt gindex;3892FT_ULong charcode = FT_Get_First_Char(fd->face, &gindex);3893while (gindex != 0) {3894glyphs.push_back(gindex);3895charcode = FT_Get_Next_Char(fd->face, charcode, &gindex);3896}3897return glyphs;3898}3899#endif3900if (at_size) {3901const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map;3902for (const KeyValue<int32_t, FontGlyph> &E : gl) {3903glyphs.push_back(E.key);3904}3905}3906return glyphs;3907}39083909void TextServerAdvanced::_font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) {3910FontAdvanced *fd = _get_font_data(p_font_rid);3911ERR_FAIL_NULL(fd);3912ERR_FAIL_COND_MSG((p_start >= 0xd800 && p_start <= 0xdfff) || (p_start > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_start, 16) + ".");3913ERR_FAIL_COND_MSG((p_end >= 0xd800 && p_end <= 0xdfff) || (p_end > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_end, 16) + ".");39143915MutexLock lock(fd->mutex);3916Vector2i size = _get_size_outline(fd, p_size);3917FontForSizeAdvanced *ffsd = nullptr;3918ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3919for (int64_t i = p_start; i <= p_end; i++) {3920#ifdef MODULE_FREETYPE_ENABLED3921int32_t idx = FT_Get_Char_Index(fd->face, i);3922if (fd->face) {3923FontGlyph fgl;3924if (fd->msdf) {3925_ensure_glyph(fd, size, (int32_t)idx, fgl);3926} else {3927for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {3928if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {3929_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);3930_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);3931_ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24), fgl);3932_ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24), fgl);3933} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {3934_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);3935_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);3936} else {3937_ensure_glyph(fd, size, (int32_t)idx | (aa << 24), fgl);3938}3939}3940}3941}3942#endif3943}3944}39453946void TextServerAdvanced::_font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) {3947FontAdvanced *fd = _get_font_data(p_font_rid);3948ERR_FAIL_NULL(fd);39493950MutexLock lock(fd->mutex);3951Vector2i size = _get_size_outline(fd, p_size);3952FontForSizeAdvanced *ffsd = nullptr;3953ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3954#ifdef MODULE_FREETYPE_ENABLED3955int32_t idx = p_index & 0xffffff; // Remove subpixel shifts.3956if (fd->face) {3957FontGlyph fgl;3958if (fd->msdf) {3959_ensure_glyph(fd, size, (int32_t)idx, fgl);3960} else {3961for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {3962if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {3963_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);3964_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);3965_ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24), fgl);3966_ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24), fgl);3967} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {3968_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);3969_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);3970} else {3971_ensure_glyph(fd, size, (int32_t)idx | (aa << 24), fgl);3972}3973}3974}3975}3976#endif3977}39783979void 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 {3980if (p_index == 0) {3981return; // Non visual character, skip.3982}3983FontAdvanced *fd = _get_font_data(p_font_rid);3984ERR_FAIL_NULL(fd);39853986MutexLock lock(fd->mutex);39873988// Oversampling.3989bool viewport_oversampling = false;3990float oversampling_factor = p_oversampling;3991if (p_oversampling <= 0.0) {3992if (fd->oversampling_override > 0.0) {3993oversampling_factor = fd->oversampling_override;3994} else if (vp_oversampling > 0.0) {3995oversampling_factor = vp_oversampling;3996viewport_oversampling = true;3997} else {3998oversampling_factor = 1.0;3999}4000}4001bool skip_oversampling = fd->msdf || fd->fixed_size > 0;4002if (skip_oversampling) {4003oversampling_factor = 1.0;4004} else {4005uint64_t oversampling_level = CLAMP(oversampling_factor, 0.1, 100.0) * 64;4006oversampling_factor = double(oversampling_level) / 64.0;4007}40084009Vector2i size;4010if (skip_oversampling) {4011size = _get_size(fd, p_size);4012} else {4013size = Vector2i(p_size * 64 * oversampling_factor, 0);4014}40154016FontForSizeAdvanced *ffsd = nullptr;4017ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd, false, viewport_oversampling ? 64 * oversampling_factor : 0));40184019int32_t index = p_index & 0xffffff; // Remove subpixel shifts.4020bool lcd_aa = false;40214022#ifdef MODULE_FREETYPE_ENABLED4023if (!fd->msdf && fd->face) {4024// LCD layout, bits 24, 25, 264025if (fd->antialiasing == FONT_ANTIALIASING_LCD) {4026TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();4027if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {4028lcd_aa = true;4029index = index | (layout << 24);4030}4031}4032// Subpixel X-shift, bits 27, 284033if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {4034int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));4035index = index | (xshift << 27);4036} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {4037int xshift = (int)(Math::floor(2 * (p_pos.x + 0.25)) - 2 * Math::floor(p_pos.x + 0.25));4038index = index | (xshift << 27);4039}4040}4041#endif40424043FontGlyph fgl;4044if (!_ensure_glyph(fd, size, index, fgl, viewport_oversampling ? 64 * oversampling_factor : 0)) {4045return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.4046}40474048if (fgl.found) {4049ERR_FAIL_COND(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size());40504051if (fgl.texture_idx != -1) {4052Color modulate = p_color;4053#ifdef MODULE_FREETYPE_ENABLED4054if (!fd->modulate_color_glyphs && fd->face && ffsd->textures[fgl.texture_idx].image.is_valid() && (ffsd->textures[fgl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {4055modulate.r = modulate.g = modulate.b = 1.0;4056}4057#endif4058if (RenderingServer::get_singleton() != nullptr) {4059if (ffsd->textures[fgl.texture_idx].dirty) {4060ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];4061Ref<Image> img = tex.image;4062if (fgl.from_svg) {4063// Same as the "fix alpha border" process option when importing SVGs4064img->fix_alpha_edges();4065}4066if (fd->mipmaps && !img->has_mipmaps()) {4067img = tex.image->duplicate();4068img->generate_mipmaps();4069}4070if (tex.texture.is_null()) {4071tex.texture = ImageTexture::create_from_image(img);4072} else {4073tex.texture->update(img);4074}4075tex.dirty = false;4076}4077RID texture = ffsd->textures[fgl.texture_idx].texture->get_rid();4078if (fd->msdf) {4079Point2 cpos = p_pos;4080cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size;4081Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size;4082RenderingServer::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);4083} else {4084Point2 cpos = p_pos;4085double scale = _font_get_scale(p_font_rid, p_size) / oversampling_factor;4086if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {4087cpos.x = cpos.x + 0.125;4088} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {4089cpos.x = cpos.x + 0.25;4090}4091if (scale == 1.0) {4092cpos.y = Math::floor(cpos.y);4093cpos.x = Math::floor(cpos.x);4094}4095Vector2 gpos = fgl.rect.position;4096Size2 csize = fgl.rect.size;4097if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE) {4098if (size.x != p_size * 64) {4099if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {4100double gl_scale = (double)p_size / (double)fd->fixed_size;4101gpos *= gl_scale;4102csize *= gl_scale;4103} else {4104double gl_scale = Math::round((double)p_size / (double)fd->fixed_size);4105gpos *= gl_scale;4106csize *= gl_scale;4107}4108}4109} else {4110gpos /= oversampling_factor;4111csize /= oversampling_factor;4112}4113cpos += gpos;4114if (lcd_aa) {4115RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate);4116} else {4117RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false);4118}4119}4120}4121}4122}4123}41244125void 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 {4126if (p_index == 0) {4127return; // Non visual character, skip.4128}4129FontAdvanced *fd = _get_font_data(p_font_rid);4130ERR_FAIL_NULL(fd);41314132MutexLock lock(fd->mutex);41334134// Oversampling.4135bool viewport_oversampling = false;4136float oversampling_factor = p_oversampling;4137if (p_oversampling <= 0.0) {4138if (fd->oversampling_override > 0.0) {4139oversampling_factor = fd->oversampling_override;4140} else if (vp_oversampling > 0.0) {4141oversampling_factor = vp_oversampling;4142viewport_oversampling = true;4143} else {4144oversampling_factor = 1.0;4145}4146}4147bool skip_oversampling = fd->msdf || fd->fixed_size > 0;4148if (skip_oversampling) {4149oversampling_factor = 1.0;4150} else {4151uint64_t oversampling_level = CLAMP(oversampling_factor, 0.1, 100.0) * 64;4152oversampling_factor = double(oversampling_level) / 64.0;4153}41544155Vector2i size;4156if (skip_oversampling) {4157size = _get_size_outline(fd, Vector2i(p_size, p_outline_size));4158} else {4159size = Vector2i(p_size * 64 * oversampling_factor, p_outline_size * oversampling_factor);4160}41614162FontForSizeAdvanced *ffsd = nullptr;4163ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd, false, viewport_oversampling ? 64 * oversampling_factor : 0));41644165int32_t index = p_index & 0xffffff; // Remove subpixel shifts.4166bool lcd_aa = false;41674168#ifdef MODULE_FREETYPE_ENABLED4169if (!fd->msdf && fd->face) {4170// LCD layout, bits 24, 25, 264171if (fd->antialiasing == FONT_ANTIALIASING_LCD) {4172TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();4173if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {4174lcd_aa = true;4175index = index | (layout << 24);4176}4177}4178// Subpixel X-shift, bits 27, 284179if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {4180int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));4181index = index | (xshift << 27);4182} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {4183int xshift = (int)(Math::floor(2 * (p_pos.x + 0.25)) - 2 * Math::floor(p_pos.x + 0.25));4184index = index | (xshift << 27);4185}4186}4187#endif41884189FontGlyph fgl;4190if (!_ensure_glyph(fd, size, index, fgl, viewport_oversampling ? 64 * oversampling_factor : 0)) {4191return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.4192}41934194if (fgl.found) {4195ERR_FAIL_COND(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size());41964197if (fgl.texture_idx != -1) {4198Color modulate = p_color;4199#ifdef MODULE_FREETYPE_ENABLED4200if (fd->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) {4201modulate.r = modulate.g = modulate.b = 1.0;4202}4203#endif4204if (RenderingServer::get_singleton() != nullptr) {4205if (ffsd->textures[fgl.texture_idx].dirty) {4206ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];4207Ref<Image> img = tex.image;4208if (fd->mipmaps && !img->has_mipmaps()) {4209img = tex.image->duplicate();4210img->generate_mipmaps();4211}4212if (tex.texture.is_null()) {4213tex.texture = ImageTexture::create_from_image(img);4214} else {4215tex.texture->update(img);4216}4217tex.dirty = false;4218}4219RID texture = ffsd->textures[fgl.texture_idx].texture->get_rid();4220if (fd->msdf) {4221Point2 cpos = p_pos;4222cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size;4223Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size;4224RenderingServer::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);4225} else {4226Point2 cpos = p_pos;4227double scale = _font_get_scale(p_font_rid, p_size) / oversampling_factor;4228if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {4229cpos.x = cpos.x + 0.125;4230} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {4231cpos.x = cpos.x + 0.25;4232}4233if (scale == 1.0) {4234cpos.y = Math::floor(cpos.y);4235cpos.x = Math::floor(cpos.x);4236}4237Vector2 gpos = fgl.rect.position;4238Size2 csize = fgl.rect.size;4239if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE) {4240if (size.x != p_size * 64) {4241if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {4242double gl_scale = (double)p_size / (double)fd->fixed_size;4243gpos *= gl_scale;4244csize *= gl_scale;4245} else {4246double gl_scale = Math::round((double)p_size / (double)fd->fixed_size);4247gpos *= gl_scale;4248csize *= gl_scale;4249}4250}4251} else {4252gpos /= oversampling_factor;4253csize /= oversampling_factor;4254}4255cpos += gpos;4256if (lcd_aa) {4257RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate);4258} else {4259RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false);4260}4261}4262}4263}4264}4265}42664267bool TextServerAdvanced::_font_is_language_supported(const RID &p_font_rid, const String &p_language) const {4268FontAdvanced *fd = _get_font_data(p_font_rid);4269ERR_FAIL_NULL_V(fd, false);42704271MutexLock lock(fd->mutex);4272if (fd->language_support_overrides.has(p_language)) {4273return fd->language_support_overrides[p_language];4274} else {4275if (fd->language_support_overrides.has("*")) {4276return fd->language_support_overrides["*"];4277}4278return true;4279}4280}42814282void TextServerAdvanced::_font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) {4283FontAdvanced *fd = _get_font_data(p_font_rid);4284ERR_FAIL_NULL(fd);42854286MutexLock lock(fd->mutex);4287fd->language_support_overrides[p_language] = p_supported;4288}42894290bool TextServerAdvanced::_font_get_language_support_override(const RID &p_font_rid, const String &p_language) {4291FontAdvanced *fd = _get_font_data(p_font_rid);4292ERR_FAIL_NULL_V(fd, false);42934294MutexLock lock(fd->mutex);4295return fd->language_support_overrides[p_language];4296}42974298void TextServerAdvanced::_font_remove_language_support_override(const RID &p_font_rid, const String &p_language) {4299FontAdvanced *fd = _get_font_data(p_font_rid);4300ERR_FAIL_NULL(fd);43014302MutexLock lock(fd->mutex);4303fd->language_support_overrides.erase(p_language);4304}43054306PackedStringArray TextServerAdvanced::_font_get_language_support_overrides(const RID &p_font_rid) {4307FontAdvanced *fd = _get_font_data(p_font_rid);4308ERR_FAIL_NULL_V(fd, PackedStringArray());43094310MutexLock lock(fd->mutex);4311PackedStringArray out;4312for (const KeyValue<String, bool> &E : fd->language_support_overrides) {4313out.push_back(E.key);4314}4315return out;4316}43174318bool TextServerAdvanced::_font_is_script_supported(const RID &p_font_rid, const String &p_script) const {4319FontAdvanced *fd = _get_font_data(p_font_rid);4320ERR_FAIL_NULL_V(fd, false);43214322MutexLock lock(fd->mutex);4323if (fd->script_support_overrides.has(p_script)) {4324return fd->script_support_overrides[p_script];4325} else {4326if (fd->script_support_overrides.has("*")) {4327return fd->script_support_overrides["*"];4328}4329Vector2i size = _get_size(fd, 16);4330FontForSizeAdvanced *ffsd = nullptr;4331ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), false);4332char ascii_script[] = { ' ', ' ', ' ', ' ' };4333for (int i = 0; i < MIN(4, p_script.size()); i++) {4334if (p_script[i] <= 0x7f) {4335ascii_script[i] = p_script[i];4336}4337}4338return fd->supported_scripts.has(hb_tag_from_string(ascii_script, -1));4339}4340}43414342void TextServerAdvanced::_font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) {4343FontAdvanced *fd = _get_font_data(p_font_rid);4344ERR_FAIL_NULL(fd);43454346MutexLock lock(fd->mutex);4347fd->script_support_overrides[p_script] = p_supported;4348}43494350bool TextServerAdvanced::_font_get_script_support_override(const RID &p_font_rid, const String &p_script) {4351FontAdvanced *fd = _get_font_data(p_font_rid);4352ERR_FAIL_NULL_V(fd, false);43534354MutexLock lock(fd->mutex);4355return fd->script_support_overrides[p_script];4356}43574358void TextServerAdvanced::_font_remove_script_support_override(const RID &p_font_rid, const String &p_script) {4359FontAdvanced *fd = _get_font_data(p_font_rid);4360ERR_FAIL_NULL(fd);43614362MutexLock lock(fd->mutex);4363fd->script_support_overrides.erase(p_script);4364}43654366PackedStringArray TextServerAdvanced::_font_get_script_support_overrides(const RID &p_font_rid) {4367FontAdvanced *fd = _get_font_data(p_font_rid);4368ERR_FAIL_NULL_V(fd, PackedStringArray());43694370MutexLock lock(fd->mutex);4371PackedStringArray out;4372for (const KeyValue<String, bool> &E : fd->script_support_overrides) {4373out.push_back(E.key);4374}4375return out;4376}43774378void TextServerAdvanced::_font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) {4379FontAdvanced *fd = _get_font_data(p_font_rid);4380ERR_FAIL_NULL(fd);43814382MutexLock lock(fd->mutex);4383Vector2i size = _get_size(fd, 16);4384FontForSizeAdvanced *ffsd = nullptr;4385ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));4386fd->feature_overrides = p_overrides;4387}43884389Dictionary TextServerAdvanced::_font_get_opentype_feature_overrides(const RID &p_font_rid) const {4390FontAdvanced *fd = _get_font_data(p_font_rid);4391ERR_FAIL_NULL_V(fd, Dictionary());43924393MutexLock lock(fd->mutex);4394return fd->feature_overrides;4395}43964397Dictionary TextServerAdvanced::_font_supported_feature_list(const RID &p_font_rid) const {4398FontAdvanced *fd = _get_font_data(p_font_rid);4399ERR_FAIL_NULL_V(fd, Dictionary());44004401MutexLock lock(fd->mutex);4402Vector2i size = _get_size(fd, 16);4403FontForSizeAdvanced *ffsd = nullptr;4404ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary());4405return fd->supported_features;4406}44074408Dictionary TextServerAdvanced::_font_supported_variation_list(const RID &p_font_rid) const {4409FontAdvanced *fd = _get_font_data(p_font_rid);4410ERR_FAIL_NULL_V(fd, Dictionary());44114412MutexLock lock(fd->mutex);4413Vector2i size = _get_size(fd, 16);4414FontForSizeAdvanced *ffsd = nullptr;4415ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary());4416return fd->supported_varaitions;4417}44184419/*************************************************************************/4420/* Shaped text buffer interface */4421/*************************************************************************/44224423int64_t TextServerAdvanced::_convert_pos(const String &p_utf32, const Char16String &p_utf16, int64_t p_pos) const {4424int64_t limit = p_pos;4425if (p_utf32.length() != p_utf16.length()) {4426const UChar *data = p_utf16.get_data();4427for (int i = 0; i < p_pos; i++) {4428if (U16_IS_LEAD(data[i])) {4429limit--;4430}4431}4432}4433return limit;4434}44354436int64_t TextServerAdvanced::_convert_pos(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const {4437int64_t limit = p_pos;4438if (p_sd->text.length() != p_sd->utf16.length()) {4439const UChar *data = p_sd->utf16.get_data();4440for (int i = 0; i < p_pos; i++) {4441if (U16_IS_LEAD(data[i])) {4442limit--;4443}4444}4445}4446return limit;4447}44484449int64_t TextServerAdvanced::_convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const {4450int64_t limit = p_pos;4451if (p_sd->text.length() != p_sd->utf16.length()) {4452for (int i = 0; i < p_pos; i++) {4453if (p_sd->text[i] > 0xffff) {4454limit++;4455}4456}4457}4458return limit;4459}44604461void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *p_shaped, bool p_text) {4462p_shaped->valid.clear();4463p_shaped->sort_valid = false;4464p_shaped->line_breaks_valid = false;4465p_shaped->justification_ops_valid = false;4466p_shaped->text_trimmed = false;4467p_shaped->ascent = 0.0;4468p_shaped->descent = 0.0;4469p_shaped->width = 0.0;4470p_shaped->upos = 0.0;4471p_shaped->uthk = 0.0;4472p_shaped->glyphs.clear();4473p_shaped->glyphs_logical.clear();4474p_shaped->runs.clear();4475p_shaped->runs_dirty = true;4476p_shaped->overrun_trim_data = TrimData();4477p_shaped->utf16 = Char16String();4478for (int i = 0; i < p_shaped->bidi_iter.size(); i++) {4479ubidi_close(p_shaped->bidi_iter[i]);4480}4481p_shaped->bidi_iter.clear();44824483if (p_text) {4484if (p_shaped->script_iter != nullptr) {4485memdelete(p_shaped->script_iter);4486p_shaped->script_iter = nullptr;4487}4488p_shaped->break_ops_valid = false;4489p_shaped->chars_valid = false;4490p_shaped->js_ops_valid = false;4491}4492}44934494void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) {4495ShapedTextDataAdvanced *parent = shaped_owner.get_or_null(p_shaped->parent);44964497for (const KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : parent->objects) {4498if (E.value.start >= p_shaped->start && E.value.start < p_shaped->end) {4499p_shaped->objects[E.key] = E.value;4500}4501}45024503for (int i = MAX(0, p_shaped->first_span); i <= MIN(p_shaped->last_span, parent->spans.size() - 1); i++) {4504ShapedTextDataAdvanced::Span span = parent->spans[i];4505span.start = MAX(p_shaped->start, span.start);4506span.end = MIN(p_shaped->end, span.end);4507p_shaped->spans.push_back(span);4508}4509p_shaped->first_span = 0;4510p_shaped->last_span = 0;45114512p_shaped->parent = RID();4513}45144515RID TextServerAdvanced::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {4516_THREAD_SAFE_METHOD_4517ERR_FAIL_COND_V_MSG(p_direction == DIRECTION_INHERITED, RID(), "Invalid text direction.");45184519ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced);4520sd->hb_buffer = hb_buffer_create();4521sd->direction = p_direction;4522sd->orientation = p_orientation;4523return shaped_owner.make_rid(sd);4524}45254526void TextServerAdvanced::_shaped_text_clear(const RID &p_shaped) {4527ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4528ERR_FAIL_NULL(sd);45294530MutexLock lock(sd->mutex);4531sd->parent = RID();4532sd->start = 0;4533sd->end = 0;4534sd->text = String();4535sd->spans.clear();4536sd->first_span = 0;4537sd->last_span = 0;4538sd->objects.clear();4539sd->bidi_override.clear();4540invalidate(sd, true);4541}45424543RID TextServerAdvanced::_shaped_text_duplicate(const RID &p_shaped) {4544_THREAD_SAFE_METHOD_45454546const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4547ERR_FAIL_NULL_V(sd, RID());45484549MutexLock lock(sd->mutex);45504551ShapedTextDataAdvanced *new_sd = memnew(ShapedTextDataAdvanced);4552new_sd->start = sd->start;4553new_sd->end = sd->end;4554new_sd->first_span = sd->first_span;4555new_sd->last_span = sd->last_span;4556new_sd->text = sd->text;4557new_sd->hb_buffer = hb_buffer_create();4558new_sd->utf16 = new_sd->text.utf16();4559new_sd->script_iter = memnew(ScriptIterator(new_sd->text, 0, new_sd->text.length()));4560new_sd->orientation = sd->orientation;4561new_sd->direction = sd->direction;4562new_sd->custom_punct = sd->custom_punct;4563new_sd->para_direction = sd->para_direction;4564new_sd->base_para_direction = sd->base_para_direction;4565new_sd->line_breaks_valid = sd->line_breaks_valid;4566new_sd->justification_ops_valid = sd->justification_ops_valid;4567new_sd->sort_valid = false;4568new_sd->upos = sd->upos;4569new_sd->uthk = sd->uthk;4570new_sd->runs.clear();4571new_sd->runs_dirty = true;4572for (int i = 0; i < TextServer::SPACING_MAX; i++) {4573new_sd->extra_spacing[i] = sd->extra_spacing[i];4574}4575for (const KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : sd->objects) {4576new_sd->objects[E.key] = E.value;4577}4578for (int i = 0; i < sd->spans.size(); i++) {4579new_sd->spans.push_back(sd->spans[i]);4580}4581new_sd->valid.clear();45824583return shaped_owner.make_rid(new_sd);4584}45854586void TextServerAdvanced::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {4587ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4588ERR_FAIL_COND_MSG(p_direction == DIRECTION_INHERITED, "Invalid text direction.");4589ERR_FAIL_NULL(sd);45904591MutexLock lock(sd->mutex);4592if (sd->direction != p_direction) {4593if (sd->parent != RID()) {4594full_copy(sd);4595}4596sd->direction = p_direction;4597invalidate(sd, false);4598}4599}46004601TextServer::Direction TextServerAdvanced::_shaped_text_get_direction(const RID &p_shaped) const {4602const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4603ERR_FAIL_NULL_V(sd, TextServer::DIRECTION_LTR);46044605MutexLock lock(sd->mutex);4606return sd->direction;4607}46084609TextServer::Direction TextServerAdvanced::_shaped_text_get_inferred_direction(const RID &p_shaped) const {4610const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4611ERR_FAIL_NULL_V(sd, TextServer::DIRECTION_LTR);46124613MutexLock lock(sd->mutex);4614return sd->para_direction;4615}46164617void TextServerAdvanced::_shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) {4618_THREAD_SAFE_METHOD_4619ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4620ERR_FAIL_NULL(sd);46214622if (sd->custom_punct != p_punct) {4623if (sd->parent != RID()) {4624full_copy(sd);4625}4626sd->custom_punct = p_punct;4627invalidate(sd, false);4628}4629}46304631String TextServerAdvanced::_shaped_text_get_custom_punctuation(const RID &p_shaped) const {4632_THREAD_SAFE_METHOD_4633const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4634ERR_FAIL_NULL_V(sd, String());4635return sd->custom_punct;4636}46374638void TextServerAdvanced::_shaped_text_set_custom_ellipsis(const RID &p_shaped, int64_t p_char) {4639_THREAD_SAFE_METHOD_4640ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4641ERR_FAIL_NULL(sd);4642sd->el_char = p_char;4643}46444645int64_t TextServerAdvanced::_shaped_text_get_custom_ellipsis(const RID &p_shaped) const {4646_THREAD_SAFE_METHOD_4647const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4648ERR_FAIL_NULL_V(sd, 0);4649return sd->el_char;4650}46514652void TextServerAdvanced::_shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) {4653ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4654ERR_FAIL_NULL(sd);46554656MutexLock lock(sd->mutex);4657if (sd->parent != RID()) {4658full_copy(sd);4659}4660sd->bidi_override.clear();4661for (int i = 0; i < p_override.size(); i++) {4662if (p_override[i].get_type() == Variant::VECTOR3I) {4663const Vector3i &r = p_override[i];4664sd->bidi_override.push_back(r);4665} else if (p_override[i].get_type() == Variant::VECTOR2I) {4666const Vector2i &r = p_override[i];4667sd->bidi_override.push_back(Vector3i(r.x, r.y, DIRECTION_INHERITED));4668}4669}4670invalidate(sd, false);4671}46724673void TextServerAdvanced::_shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) {4674ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4675ERR_FAIL_NULL(sd);46764677MutexLock lock(sd->mutex);4678if (sd->orientation != p_orientation) {4679if (sd->parent != RID()) {4680full_copy(sd);4681}4682sd->orientation = p_orientation;4683invalidate(sd, false);4684}4685}46864687void TextServerAdvanced::_shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) {4688ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4689ERR_FAIL_NULL(sd);46904691MutexLock lock(sd->mutex);4692ERR_FAIL_COND(sd->parent != RID());4693if (sd->preserve_invalid != p_enabled) {4694sd->preserve_invalid = p_enabled;4695invalidate(sd, false);4696}4697}46984699bool TextServerAdvanced::_shaped_text_get_preserve_invalid(const RID &p_shaped) const {4700const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4701ERR_FAIL_NULL_V(sd, false);47024703MutexLock lock(sd->mutex);4704return sd->preserve_invalid;4705}47064707void TextServerAdvanced::_shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) {4708ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4709ERR_FAIL_NULL(sd);47104711MutexLock lock(sd->mutex);4712if (sd->preserve_control != p_enabled) {4713if (sd->parent != RID()) {4714full_copy(sd);4715}4716sd->preserve_control = p_enabled;4717invalidate(sd, false);4718}4719}47204721bool TextServerAdvanced::_shaped_text_get_preserve_control(const RID &p_shaped) const {4722const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4723ERR_FAIL_NULL_V(sd, false);47244725MutexLock lock(sd->mutex);4726return sd->preserve_control;4727}47284729void TextServerAdvanced::_shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) {4730ERR_FAIL_INDEX((int)p_spacing, 4);4731ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4732ERR_FAIL_NULL(sd);47334734MutexLock lock(sd->mutex);4735if (sd->extra_spacing[p_spacing] != p_value) {4736if (sd->parent != RID()) {4737full_copy(sd);4738}4739sd->extra_spacing[p_spacing] = p_value;4740invalidate(sd, false);4741}4742}47434744int64_t TextServerAdvanced::_shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const {4745ERR_FAIL_INDEX_V((int)p_spacing, 4, 0);47464747const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4748ERR_FAIL_NULL_V(sd, 0);47494750MutexLock lock(sd->mutex);4751return sd->extra_spacing[p_spacing];4752}47534754TextServer::Orientation TextServerAdvanced::_shaped_text_get_orientation(const RID &p_shaped) const {4755const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4756ERR_FAIL_NULL_V(sd, TextServer::ORIENTATION_HORIZONTAL);47574758MutexLock lock(sd->mutex);4759return sd->orientation;4760}47614762int64_t TextServerAdvanced::_shaped_get_span_count(const RID &p_shaped) const {4763ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4764ERR_FAIL_NULL_V(sd, 0);47654766if (sd->parent != RID()) {4767return sd->last_span - sd->first_span + 1;4768} else {4769return sd->spans.size();4770}4771}47724773Variant TextServerAdvanced::_shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const {4774ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4775ERR_FAIL_NULL_V(sd, Variant());4776if (sd->parent != RID()) {4777ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);4778ERR_FAIL_COND_V(!parent_sd->valid.is_set(), Variant());4779ERR_FAIL_INDEX_V(p_index + sd->first_span, parent_sd->spans.size(), Variant());4780return parent_sd->spans[p_index + sd->first_span].meta;4781} else {4782ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant());4783return sd->spans[p_index].meta;4784}4785}47864787Variant TextServerAdvanced::_shaped_get_span_embedded_object(const RID &p_shaped, int64_t p_index) const {4788ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4789ERR_FAIL_NULL_V(sd, Variant());4790if (sd->parent != RID()) {4791ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);4792ERR_FAIL_COND_V(!parent_sd->valid.is_set(), Variant());4793ERR_FAIL_INDEX_V(p_index + sd->first_span, parent_sd->spans.size(), Variant());4794return parent_sd->spans[p_index + sd->first_span].embedded_key;4795} else {4796ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant());4797return sd->spans[p_index].embedded_key;4798}4799}48004801String TextServerAdvanced::_shaped_get_span_text(const RID &p_shaped, int64_t p_index) const {4802ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4803ERR_FAIL_NULL_V(sd, String());4804ShapedTextDataAdvanced *span_sd = sd;4805if (sd->parent.is_valid()) {4806span_sd = shaped_owner.get_or_null(sd->parent);4807ERR_FAIL_NULL_V(span_sd, String());4808}4809ERR_FAIL_INDEX_V(p_index, span_sd->spans.size(), String());4810return span_sd->text.substr(span_sd->spans[p_index].start, span_sd->spans[p_index].end - span_sd->spans[p_index].start);4811}48124813Variant TextServerAdvanced::_shaped_get_span_object(const RID &p_shaped, int64_t p_index) const {4814ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4815ERR_FAIL_NULL_V(sd, Variant());4816ShapedTextDataAdvanced *span_sd = sd;4817if (sd->parent.is_valid()) {4818span_sd = shaped_owner.get_or_null(sd->parent);4819ERR_FAIL_NULL_V(span_sd, Variant());4820}4821ERR_FAIL_INDEX_V(p_index, span_sd->spans.size(), Variant());4822return span_sd->spans[p_index].embedded_key;4823}48244825void TextServerAdvanced::_generate_runs(ShapedTextDataAdvanced *p_sd) const {4826ERR_FAIL_NULL(p_sd);4827p_sd->runs.clear();48284829ShapedTextDataAdvanced *span_sd = p_sd;4830if (p_sd->parent.is_valid()) {4831span_sd = shaped_owner.get_or_null(p_sd->parent);4832ERR_FAIL_NULL(span_sd);4833}48344835int sd_size = p_sd->glyphs.size();4836const Glyph *sd_gl = p_sd->glyphs.ptr();48374838int span_count = span_sd->spans.size();4839int span = -1;4840int span_start = -1;4841int span_end = -1;48424843TextRun run;4844for (int i = 0; i < sd_size; i += sd_gl[i].count) {4845const Glyph &gl = sd_gl[i];4846if (gl.start < 0 || gl.end < 0) {4847continue;4848}4849if (gl.start < span_start || gl.start >= span_end) {4850span = -1;4851span_start = -1;4852span_end = -1;4853for (int j = 0; j < span_count; j++) {4854if (gl.start >= span_sd->spans[j].start && gl.end <= span_sd->spans[j].end) {4855span = j;4856span_start = span_sd->spans[j].start;4857span_end = span_sd->spans[j].end;4858break;4859}4860}4861}4862if (run.font_rid != gl.font_rid || run.font_size != gl.font_size || run.span_index != span || run.rtl != bool(gl.flags & GRAPHEME_IS_RTL)) {4863if (run.span_index >= 0) {4864p_sd->runs.push_back(run);4865}4866run.range = Vector2i(gl.start, gl.end);4867run.font_rid = gl.font_rid;4868run.font_size = gl.font_size;4869run.rtl = bool(gl.flags & GRAPHEME_IS_RTL);4870run.span_index = span;4871}4872run.range.x = MIN(run.range.x, gl.start);4873run.range.y = MAX(run.range.y, gl.end);4874}4875if (run.span_index >= 0) {4876p_sd->runs.push_back(run);4877}4878p_sd->runs_dirty = false;4879}48804881int64_t TextServerAdvanced::_shaped_get_run_count(const RID &p_shaped) const {4882ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4883ERR_FAIL_NULL_V(sd, 0);4884MutexLock lock(sd->mutex);4885if (!sd->valid.is_set()) {4886const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4887}4888if (sd->runs_dirty) {4889_generate_runs(sd);4890}4891return sd->runs.size();4892}48934894String TextServerAdvanced::_shaped_get_run_text(const RID &p_shaped, int64_t p_index) const {4895ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4896ERR_FAIL_NULL_V(sd, String());4897MutexLock lock(sd->mutex);4898if (!sd->valid.is_set()) {4899const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4900}4901if (sd->runs_dirty) {4902_generate_runs(sd);4903}4904ERR_FAIL_INDEX_V(p_index, sd->runs.size(), String());4905return sd->text.substr(sd->runs[p_index].range.x - sd->start, sd->runs[p_index].range.y - sd->runs[p_index].range.x);4906}49074908Vector2i TextServerAdvanced::_shaped_get_run_range(const RID &p_shaped, int64_t p_index) const {4909ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4910ERR_FAIL_NULL_V(sd, Vector2i());4911MutexLock lock(sd->mutex);4912if (!sd->valid.is_set()) {4913const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4914}4915if (sd->runs_dirty) {4916_generate_runs(sd);4917}4918ERR_FAIL_INDEX_V(p_index, sd->runs.size(), Vector2i());4919return sd->runs[p_index].range;4920}49214922RID TextServerAdvanced::_shaped_get_run_font_rid(const RID &p_shaped, int64_t p_index) const {4923ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4924ERR_FAIL_NULL_V(sd, RID());4925MutexLock lock(sd->mutex);4926if (!sd->valid.is_set()) {4927const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4928}4929if (sd->runs_dirty) {4930_generate_runs(sd);4931}4932ERR_FAIL_INDEX_V(p_index, sd->runs.size(), RID());4933return sd->runs[p_index].font_rid;4934}49354936int TextServerAdvanced::_shaped_get_run_font_size(const RID &p_shaped, int64_t p_index) const {4937ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4938ERR_FAIL_NULL_V(sd, 0);4939MutexLock lock(sd->mutex);4940if (!sd->valid.is_set()) {4941const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4942}4943if (sd->runs_dirty) {4944_generate_runs(sd);4945}4946ERR_FAIL_INDEX_V(p_index, sd->runs.size(), 0);4947return sd->runs[p_index].font_size;4948}49494950String TextServerAdvanced::_shaped_get_run_language(const RID &p_shaped, int64_t p_index) const {4951ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4952ERR_FAIL_NULL_V(sd, String());4953MutexLock lock(sd->mutex);4954if (!sd->valid.is_set()) {4955const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4956}4957if (sd->runs_dirty) {4958_generate_runs(sd);4959}4960ERR_FAIL_INDEX_V(p_index, sd->runs.size(), String());49614962int span_idx = sd->runs[p_index].span_index;4963ShapedTextDataAdvanced *span_sd = sd;4964if (sd->parent.is_valid()) {4965span_sd = shaped_owner.get_or_null(sd->parent);4966ERR_FAIL_NULL_V(span_sd, String());4967}4968ERR_FAIL_INDEX_V(span_idx, span_sd->spans.size(), String());4969return span_sd->spans[span_idx].language;4970}49714972TextServer::Direction TextServerAdvanced::_shaped_get_run_direction(const RID &p_shaped, int64_t p_index) const {4973ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4974ERR_FAIL_NULL_V(sd, TextServer::DIRECTION_LTR);4975MutexLock lock(sd->mutex);4976if (!sd->valid.is_set()) {4977const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4978}4979if (sd->runs_dirty) {4980_generate_runs(sd);4981}4982ERR_FAIL_INDEX_V(p_index, sd->runs.size(), TextServer::DIRECTION_LTR);4983return sd->runs[p_index].rtl ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR;4984}49854986Variant TextServerAdvanced::_shaped_get_run_object(const RID &p_shaped, int64_t p_index) const {4987ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);4988ERR_FAIL_NULL_V(sd, Variant());4989MutexLock lock(sd->mutex);4990if (!sd->valid.is_set()) {4991const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);4992}4993if (sd->runs_dirty) {4994_generate_runs(sd);4995}4996ERR_FAIL_INDEX_V(p_index, sd->runs.size(), Variant());49974998int span_idx = sd->runs[p_index].span_index;4999ShapedTextDataAdvanced *span_sd = sd;5000if (sd->parent.is_valid()) {5001span_sd = shaped_owner.get_or_null(sd->parent);5002ERR_FAIL_NULL_V(span_sd, Variant());5003}5004ERR_FAIL_INDEX_V(span_idx, span_sd->spans.size(), Variant());5005return span_sd->spans[span_idx].embedded_key;5006}50075008void 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) {5009ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5010ERR_FAIL_NULL(sd);5011if (sd->parent != RID()) {5012full_copy(sd);5013}5014ERR_FAIL_INDEX(p_index, sd->spans.size());50155016ShapedTextDataAdvanced::Span &span = sd->spans.ptrw()[p_index];5017span.fonts = p_fonts;5018span.font_size = p_size;5019span.features = p_opentype_features;50205021invalidate(sd, false);5022}50235024bool 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) {5025ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5026ERR_FAIL_NULL_V(sd, false);5027ERR_FAIL_COND_V(p_size <= 0, false);50285029MutexLock lock(sd->mutex);5030for (int i = 0; i < p_fonts.size(); i++) {5031ERR_FAIL_NULL_V(_get_font_data(p_fonts[i]), false);5032}50335034if (p_text.is_empty()) {5035return true;5036}50375038if (sd->parent != RID()) {5039full_copy(sd);5040}50415042ShapedTextDataAdvanced::Span span;5043span.start = sd->text.length();5044span.end = span.start + p_text.length();5045span.fonts = p_fonts; // Do not pre-sort, spans will be divided to subruns later.5046span.font_size = p_size;5047span.language = p_language;5048span.features = p_opentype_features;5049span.meta = p_meta;50505051sd->spans.push_back(span);5052sd->text = sd->text + p_text;5053sd->end += p_text.length();5054invalidate(sd, true);50555056return true;5057}50585059bool 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) {5060_THREAD_SAFE_METHOD_5061ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5062ERR_FAIL_NULL_V(sd, false);5063ERR_FAIL_COND_V(p_key == Variant(), false);5064ERR_FAIL_COND_V(sd->objects.has(p_key), false);50655066if (sd->parent != RID()) {5067full_copy(sd);5068}50695070ShapedTextDataAdvanced::Span span;5071span.start = sd->start + sd->text.length();5072span.end = span.start + p_length;5073span.embedded_key = p_key;50745075ShapedTextDataAdvanced::EmbeddedObject obj;5076obj.inline_align = p_inline_align;5077obj.rect.size = p_size;5078obj.start = span.start;5079obj.end = span.end;5080obj.baseline = p_baseline;50815082sd->spans.push_back(span);5083sd->text = sd->text + String::chr(0xfffc).repeat(p_length);5084sd->end += p_length;5085sd->objects[p_key] = obj;5086invalidate(sd, true);50875088return true;5089}50905091String TextServerAdvanced::_shaped_get_text(const RID &p_shaped) const {5092const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5093ERR_FAIL_NULL_V(sd, String());50945095return sd->text;5096}50975098bool TextServerAdvanced::_shaped_text_has_object(const RID &p_shaped, const Variant &p_key) const {5099ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5100ERR_FAIL_NULL_V(sd, false);51015102MutexLock lock(sd->mutex);5103return sd->objects.has(p_key);5104}51055106bool TextServerAdvanced::_shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, double p_baseline) {5107ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5108ERR_FAIL_NULL_V(sd, false);51095110MutexLock lock(sd->mutex);5111ERR_FAIL_COND_V(!sd->objects.has(p_key), false);5112sd->objects[p_key].rect.size = p_size;5113sd->objects[p_key].inline_align = p_inline_align;5114sd->objects[p_key].baseline = p_baseline;5115if (sd->valid.is_set()) {5116// Recalc string metrics.5117sd->ascent = 0;5118sd->descent = 0;5119sd->width = 0;5120sd->upos = 0;5121sd->uthk = 0;51225123Vector<ShapedTextDataAdvanced::Span> &spans = sd->spans;5124if (sd->parent != RID()) {5125ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);5126ERR_FAIL_COND_V(!parent_sd->valid.is_set(), false);5127spans = parent_sd->spans;5128}51295130int sd_size = sd->glyphs.size();5131int span_size = spans.size();5132const char32_t *ch = sd->text.ptr();51335134for (int i = 0; i < sd_size; i++) {5135Glyph gl = sd->glyphs[i];5136Variant key;5137if ((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) {5138key = spans[gl.span_index + sd->first_span].embedded_key;5139}5140if (key != Variant()) {5141if (sd->orientation == ORIENTATION_HORIZONTAL) {5142sd->objects[key].rect.position.x = sd->width;5143sd->width += sd->objects[key].rect.size.x;5144sd->glyphs[i].advance = sd->objects[key].rect.size.x;5145} else {5146sd->objects[key].rect.position.y = sd->width;5147sd->width += sd->objects[key].rect.size.y;5148sd->glyphs[i].advance = sd->objects[key].rect.size.y;5149}5150} else {5151if (gl.font_rid.is_valid()) {5152if (sd->orientation == ORIENTATION_HORIZONTAL) {5153sd->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));5154sd->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));5155} else {5156sd->ascent = MAX(sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));5157sd->descent = MAX(sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));5158}5159sd->upos = MAX(sd->upos, _font_get_underline_position(gl.font_rid, gl.font_size));5160sd->uthk = MAX(sd->uthk, _font_get_underline_thickness(gl.font_rid, gl.font_size));5161} else if (sd->preserve_invalid || (sd->preserve_control && is_control(ch[gl.start - sd->start]))) {5162// Glyph not found, replace with hex code box.5163if (sd->orientation == ORIENTATION_HORIZONTAL) {5164sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.85);5165sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.15);5166} else {5167sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));5168sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));5169}5170}5171sd->width += gl.advance * gl.repeat;5172}5173}5174sd->sort_valid = false;5175sd->glyphs_logical.clear();5176_realign(sd);5177}5178return true;5179}51805181void TextServerAdvanced::_realign(ShapedTextDataAdvanced *p_sd) const {5182// Align embedded objects to baseline.5183double full_ascent = p_sd->ascent;5184double full_descent = p_sd->descent;5185for (KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : p_sd->objects) {5186if ((E.value.start >= p_sd->start) && (E.value.start < p_sd->end)) {5187if (p_sd->orientation == ORIENTATION_HORIZONTAL) {5188switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {5189case INLINE_ALIGNMENT_TO_TOP: {5190E.value.rect.position.y = -p_sd->ascent;5191} break;5192case INLINE_ALIGNMENT_TO_CENTER: {5193E.value.rect.position.y = (-p_sd->ascent + p_sd->descent) / 2;5194} break;5195case INLINE_ALIGNMENT_TO_BASELINE: {5196E.value.rect.position.y = 0;5197} break;5198case INLINE_ALIGNMENT_TO_BOTTOM: {5199E.value.rect.position.y = p_sd->descent;5200} break;5201}5202switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {5203case INLINE_ALIGNMENT_BOTTOM_TO: {5204E.value.rect.position.y -= E.value.rect.size.y;5205} break;5206case INLINE_ALIGNMENT_CENTER_TO: {5207E.value.rect.position.y -= E.value.rect.size.y / 2;5208} break;5209case INLINE_ALIGNMENT_BASELINE_TO: {5210E.value.rect.position.y -= E.value.baseline;5211} break;5212case INLINE_ALIGNMENT_TOP_TO: {5213// NOP5214} break;5215}5216full_ascent = MAX(full_ascent, -E.value.rect.position.y);5217full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y);5218} else {5219switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {5220case INLINE_ALIGNMENT_TO_TOP: {5221E.value.rect.position.x = -p_sd->ascent;5222} break;5223case INLINE_ALIGNMENT_TO_CENTER: {5224E.value.rect.position.x = (-p_sd->ascent + p_sd->descent) / 2;5225} break;5226case INLINE_ALIGNMENT_TO_BASELINE: {5227E.value.rect.position.x = 0;5228} break;5229case INLINE_ALIGNMENT_TO_BOTTOM: {5230E.value.rect.position.x = p_sd->descent;5231} break;5232}5233switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {5234case INLINE_ALIGNMENT_BOTTOM_TO: {5235E.value.rect.position.x -= E.value.rect.size.x;5236} break;5237case INLINE_ALIGNMENT_CENTER_TO: {5238E.value.rect.position.x -= E.value.rect.size.x / 2;5239} break;5240case INLINE_ALIGNMENT_BASELINE_TO: {5241E.value.rect.position.x -= E.value.baseline;5242} break;5243case INLINE_ALIGNMENT_TOP_TO: {5244// NOP5245} break;5246}5247full_ascent = MAX(full_ascent, -E.value.rect.position.x);5248full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x);5249}5250}5251}5252p_sd->ascent = full_ascent;5253p_sd->descent = full_descent;5254}52555256RID TextServerAdvanced::_shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {5257_THREAD_SAFE_METHOD_5258const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5259ERR_FAIL_NULL_V(sd, RID());52605261MutexLock lock(sd->mutex);5262if (sd->parent != RID()) {5263return _shaped_text_substr(sd->parent, p_start, p_length);5264}5265if (!sd->valid.is_set()) {5266const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);5267}5268ERR_FAIL_COND_V(p_start < 0 || p_length < 0, RID());5269ERR_FAIL_COND_V(sd->start > p_start || sd->end < p_start, RID());5270ERR_FAIL_COND_V(sd->end < p_start + p_length, RID());52715272ShapedTextDataAdvanced *new_sd = memnew(ShapedTextDataAdvanced);5273new_sd->parent = p_shaped;5274new_sd->start = p_start;5275new_sd->end = p_start + p_length;5276new_sd->orientation = sd->orientation;5277new_sd->direction = sd->direction;5278new_sd->custom_punct = sd->custom_punct;5279new_sd->para_direction = sd->para_direction;5280new_sd->base_para_direction = sd->base_para_direction;5281for (int i = 0; i < TextServer::SPACING_MAX; i++) {5282new_sd->extra_spacing[i] = sd->extra_spacing[i];5283}52845285if (!_shape_substr(new_sd, sd, p_start, p_length)) {5286memdelete(new_sd);5287return RID();5288}5289return shaped_owner.make_rid(new_sd);5290}52915292bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_length) const {5293if (p_new_sd->valid.is_set()) {5294return true;5295}52965297p_new_sd->hb_buffer = hb_buffer_create();52985299p_new_sd->line_breaks_valid = p_sd->line_breaks_valid;5300p_new_sd->justification_ops_valid = p_sd->justification_ops_valid;5301p_new_sd->sort_valid = false;5302p_new_sd->upos = p_sd->upos;5303p_new_sd->uthk = p_sd->uthk;5304p_new_sd->runs.clear();5305p_new_sd->runs_dirty = true;53065307if (p_length > 0) {5308p_new_sd->text = p_sd->text.substr(p_start - p_sd->start, p_length);5309p_new_sd->utf16 = p_new_sd->text.utf16();5310p_new_sd->script_iter = memnew(ScriptIterator(p_new_sd->text, 0, p_new_sd->text.length()));53115312int span_size = p_sd->spans.size();53135314p_new_sd->first_span = 0;5315p_new_sd->last_span = span_size - 1;5316for (int i = 0; i < span_size; i++) {5317const ShapedTextDataAdvanced::Span &span = p_sd->spans[i];5318if (span.end <= p_start) {5319p_new_sd->first_span = i + 1;5320} else if (span.start >= p_start + p_length) {5321p_new_sd->last_span = i - 1;5322break;5323}5324}53255326Vector<Vector3i> bidi_ranges;5327if (p_sd->bidi_override.is_empty()) {5328bidi_ranges.push_back(Vector3i(p_sd->start, p_sd->end, DIRECTION_INHERITED));5329} else {5330bidi_ranges = p_sd->bidi_override;5331}53325333int sd_size = p_sd->glyphs.size();5334const Glyph *sd_glyphs = p_sd->glyphs.ptr();5335const char32_t *ch = p_sd->text.ptr();5336for (int ov = 0; ov < bidi_ranges.size(); ov++) {5337UErrorCode err = U_ZERO_ERROR;53385339if (bidi_ranges[ov].x >= p_start + p_length || bidi_ranges[ov].y <= p_start) {5340continue;5341}5342int ov_start = _convert_pos_inv(p_sd, bidi_ranges[ov].x);5343int start = MAX(0, _convert_pos_inv(p_sd, p_start) - ov_start);5344int end = MIN(_convert_pos_inv(p_sd, p_start + p_length), _convert_pos_inv(p_sd, bidi_ranges[ov].y)) - ov_start;53455346ERR_FAIL_COND_V_MSG((start < 0 || end - start > p_new_sd->utf16.length()), false, "Invalid BiDi override range.");53475348// Create temporary line bidi & shape.5349UBiDi *bidi_iter = nullptr;5350if (p_sd->bidi_iter[ov]) {5351bidi_iter = ubidi_openSized(end - start, 0, &err);5352if (U_SUCCESS(err)) {5353ubidi_setLine(p_sd->bidi_iter[ov], start, end, bidi_iter, &err);5354if (U_FAILURE(err)) {5355// Line BiDi failed (string contains incompatible control characters), try full paragraph BiDi instead.5356err = U_ZERO_ERROR;5357const UChar *data = p_sd->utf16.get_data();5358switch (static_cast<TextServer::Direction>(bidi_ranges[ov].z)) {5359case DIRECTION_LTR: {5360ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err);5361} break;5362case DIRECTION_RTL: {5363ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err);5364} break;5365case DIRECTION_INHERITED: {5366ubidi_setPara(bidi_iter, data + start, end - start, p_sd->base_para_direction, nullptr, &err);5367} break;5368case DIRECTION_AUTO: {5369UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start);5370if (direction != UBIDI_NEUTRAL) {5371ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);5372} else {5373ubidi_setPara(bidi_iter, data + start, end - start, p_sd->base_para_direction, nullptr, &err);5374}5375} break;5376}5377if (U_FAILURE(err)) {5378ubidi_close(bidi_iter);5379bidi_iter = nullptr;5380ERR_PRINT(vformat("BiDi reordering for the line failed: %s", u_errorName(err)));5381}5382}5383} else {5384bidi_iter = nullptr;5385ERR_PRINT(vformat("BiDi iterator allocation for the line failed: %s", u_errorName(err)));5386}5387}5388p_new_sd->bidi_iter.push_back(bidi_iter);53895390err = U_ZERO_ERROR;5391int bidi_run_count = 1;5392if (bidi_iter) {5393bidi_run_count = ubidi_countRuns(bidi_iter, &err);5394if (U_FAILURE(err)) {5395ERR_PRINT(u_errorName(err));5396}5397}5398for (int i = 0; i < bidi_run_count; i++) {5399int32_t _bidi_run_start = 0;5400int32_t _bidi_run_length = end - start;5401if (bidi_iter) {5402ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length);5403}54045405int32_t bidi_run_start = _convert_pos(p_sd, ov_start + start + _bidi_run_start);5406int32_t bidi_run_end = _convert_pos(p_sd, ov_start + start + _bidi_run_start + _bidi_run_length);54075408bool cache_valid = false;5409int cached_font_size = -1;5410RID cached_font_rid = RID();5411double cached_font_ascent = 0;5412double cached_font_descent = 0;5413double cached_font_top_spacing = 0;5414double cached_font_bottom_spacing = 0;5415p_new_sd->glyphs.reserve(p_new_sd->glyphs.size() + MIN(sd_size, bidi_run_end - bidi_run_start));5416for (int j = 0; j < sd_size; j++) {5417int col_key_off = (sd_glyphs[j].start == sd_glyphs[j].end) ? 1 : 0;5418if ((sd_glyphs[j].start >= bidi_run_start) && (sd_glyphs[j].end <= bidi_run_end - col_key_off)) {5419// Copy glyphs.5420Glyph gl = sd_glyphs[j];5421if (gl.span_index >= 0) {5422gl.span_index -= p_new_sd->first_span;5423}5424if (gl.end == p_start + p_length && ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) == GRAPHEME_IS_SOFT_HYPHEN)) {5425uint32_t index = font_get_glyph_index(gl.font_rid, gl.font_size, 0x00ad, 0);5426if (index == 0) { // Try other fonts in the span.5427const ShapedTextDataAdvanced::Span &span = p_sd->spans[gl.span_index + p_new_sd->first_span];5428for (int k = 0; k < span.fonts.size(); k++) {5429if (span.fonts[k] != gl.font_rid) {5430index = font_get_glyph_index(span.fonts[k], gl.font_size, 0x00ad, 0);5431if (index != 0) {5432gl.font_rid = span.fonts[k];5433break;5434}5435}5436}5437}5438if (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.5439const char32_t u32str[] = { 0x00ad, 0 };5440RID rid = const_cast<TextServerAdvanced *>(this)->_find_sys_font_for_text(gl.font_rid, String(), String(), u32str);5441if (rid.is_valid()) {5442index = font_get_glyph_index(rid, gl.font_size, 0x00ad, 0);5443if (index != 0) {5444gl.font_rid = rid;5445}5446}5447}5448float w = font_get_glyph_advance(gl.font_rid, gl.font_size, index)[(p_new_sd->orientation == ORIENTATION_HORIZONTAL) ? 0 : 1];5449gl.index = index;5450gl.advance = w;5451}5452if ((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) {5453Variant key = p_sd->spans[gl.span_index + p_new_sd->first_span].embedded_key;5454if (key != Variant()) {5455ShapedTextDataAdvanced::EmbeddedObject obj = p_sd->objects[key];5456if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {5457obj.rect.position.x = p_new_sd->width;5458p_new_sd->width += obj.rect.size.x;5459} else {5460obj.rect.position.y = p_new_sd->width;5461p_new_sd->width += obj.rect.size.y;5462}5463p_new_sd->objects[key] = obj;5464}5465} else {5466if (gl.font_rid.is_valid()) {5467if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {5468if (!cache_valid || cached_font_rid != gl.font_rid || cached_font_size != gl.font_size) {5469cache_valid = true;5470cached_font_rid = gl.font_rid;5471cached_font_size = gl.font_size;5472cached_font_ascent = _font_get_ascent(gl.font_rid, gl.font_size);5473cached_font_descent = _font_get_descent(gl.font_rid, gl.font_size);5474cached_font_top_spacing = _font_get_spacing(gl.font_rid, SPACING_TOP);5475cached_font_bottom_spacing = _font_get_spacing(gl.font_rid, SPACING_BOTTOM);5476}5477p_new_sd->ascent = MAX(p_new_sd->ascent, MAX(cached_font_ascent + cached_font_top_spacing, -gl.y_off));5478p_new_sd->descent = MAX(p_new_sd->descent, MAX(cached_font_descent + cached_font_bottom_spacing, gl.y_off));5479} else {5480double glyph_advance = Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5);5481p_new_sd->ascent = MAX(p_new_sd->ascent, glyph_advance);5482p_new_sd->descent = MAX(p_new_sd->descent, glyph_advance);5483}5484} else if (p_new_sd->preserve_invalid || (p_new_sd->preserve_control && is_control(ch[gl.start - p_sd->start]))) {5485// Glyph not found, replace with hex code box.5486if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {5487double box_size = get_hex_code_box_size(gl.font_size, gl.index).y;5488p_new_sd->ascent = MAX(p_new_sd->ascent, box_size * 0.85);5489p_new_sd->descent = MAX(p_new_sd->descent, box_size * 0.15);5490} else {5491double box_size = Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5);5492p_new_sd->ascent = MAX(p_new_sd->ascent, box_size);5493p_new_sd->descent = MAX(p_new_sd->descent, box_size);5494}5495}5496p_new_sd->width += gl.advance * gl.repeat;5497}5498if (p_new_sd->glyphs.is_empty() && gl.x_off < 0.0) {5499gl.advance += -gl.x_off;5500gl.x_off = 0.0;5501}5502p_new_sd->glyphs.push_back(gl);5503}5504}5505}5506}55075508_realign(p_new_sd);5509}5510p_new_sd->valid.set();55115512return true;5513}55145515RID TextServerAdvanced::_shaped_text_get_parent(const RID &p_shaped) const {5516ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5517ERR_FAIL_NULL_V(sd, RID());55185519MutexLock lock(sd->mutex);5520return sd->parent;5521}55225523double TextServerAdvanced::_shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<TextServer::JustificationFlag> p_jst_flags) {5524ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5525ERR_FAIL_NULL_V(sd, 0.0);55265527MutexLock lock(sd->mutex);5528if (!sd->valid.is_set()) {5529_shaped_text_shape(p_shaped);5530}5531if (!sd->justification_ops_valid) {5532_shaped_text_update_justification_ops(p_shaped);5533}55345535sd->fit_width_minimum_reached = false;5536int start_pos = 0;5537int end_pos = sd->glyphs.size() - 1;55385539if (p_jst_flags.has_flag(JUSTIFICATION_AFTER_LAST_TAB)) {5540int start, end, delta;5541if (sd->para_direction == DIRECTION_LTR) {5542start = sd->glyphs.size() - 1;5543end = -1;5544delta = -1;5545} else {5546start = 0;5547end = sd->glyphs.size();5548delta = +1;5549}55505551for (int i = start; i != end; i += delta) {5552if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {5553if (sd->para_direction == DIRECTION_LTR) {5554start_pos = i;5555break;5556} else {5557end_pos = i;5558break;5559}5560}5561}5562}55635564double justification_width;5565if (p_jst_flags.has_flag(JUSTIFICATION_CONSTRAIN_ELLIPSIS)) {5566if (sd->overrun_trim_data.trim_pos >= 0) {5567if (sd->para_direction == DIRECTION_RTL) {5568start_pos = sd->overrun_trim_data.trim_pos;5569} else {5570end_pos = sd->overrun_trim_data.trim_pos;5571}5572justification_width = sd->width_trimmed;5573} else {5574return Math::ceil(sd->width);5575}5576} else {5577justification_width = sd->width;5578}55795580if (p_jst_flags.has_flag(JUSTIFICATION_TRIM_EDGE_SPACES)) {5581// Trim spaces.5582while ((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)) {5583justification_width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat;5584sd->glyphs[start_pos].advance = 0;5585start_pos += sd->glyphs[start_pos].count;5586}5587while ((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)) {5588justification_width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat;5589sd->glyphs[end_pos].advance = 0;5590end_pos -= sd->glyphs[end_pos].count;5591}5592} else {5593// Skip breaks, but do not reset size.5594while ((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)) {5595start_pos += sd->glyphs[start_pos].count;5596}5597while ((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)) {5598end_pos -= sd->glyphs[end_pos].count;5599}5600}56015602int space_count = 0;5603int elongation_count = 0;5604for (int i = start_pos; i <= end_pos; i++) {5605const Glyph &gl = sd->glyphs[i];5606if (gl.count > 0) {5607if ((gl.flags & GRAPHEME_IS_ELONGATION) == GRAPHEME_IS_ELONGATION) {5608if ((i > 0) && ((sd->glyphs[i - 1].flags & GRAPHEME_IS_ELONGATION) != GRAPHEME_IS_ELONGATION)) {5609// Expand once per elongation sequence.5610elongation_count++;5611}5612}5613if ((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) {5614space_count++;5615}5616}5617}56185619if ((elongation_count > 0) && p_jst_flags.has_flag(JUSTIFICATION_KASHIDA)) {5620double delta_width_per_kashida = (p_width - justification_width) / elongation_count;5621for (int i = start_pos; i <= end_pos; i++) {5622Glyph &gl = sd->glyphs[i];5623if (gl.count > 0) {5624if (((gl.flags & GRAPHEME_IS_ELONGATION) == GRAPHEME_IS_ELONGATION) && (gl.advance > 0)) {5625if ((i > 0) && ((sd->glyphs[i - 1].flags & GRAPHEME_IS_ELONGATION) != GRAPHEME_IS_ELONGATION)) {5626// Expand once per elongation sequence.5627int count = delta_width_per_kashida / gl.advance;5628int prev_count = gl.repeat;5629if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {5630gl.repeat = CLAMP(count, 0, 255);5631} else {5632gl.repeat = CLAMP(count + 1, 1, 255);5633}5634justification_width += (gl.repeat - prev_count) * gl.advance;5635}5636}5637}5638}5639}5640if ((space_count > 0) && p_jst_flags.has_flag(JUSTIFICATION_WORD_BOUND)) {5641double delta_width_per_space = (p_width - justification_width) / space_count;5642double adv_remain = 0;5643for (int i = start_pos; i <= end_pos; i++) {5644Glyph &gl = sd->glyphs[i];5645if (gl.count > 0) {5646if ((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) {5647double old_adv = gl.advance;5648double new_advance;5649if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {5650new_advance = MAX(gl.advance + delta_width_per_space, 0.0);5651} else {5652new_advance = MAX(gl.advance + delta_width_per_space, 0.1 * gl.font_size);5653}5654gl.advance = new_advance;5655adv_remain += (new_advance - gl.advance);5656if (adv_remain >= 1.0) {5657gl.advance++;5658adv_remain -= 1.0;5659} else if (adv_remain <= -1.0) {5660gl.advance = MAX(gl.advance - 1, 0);5661adv_remain -= 1.0;5662}5663justification_width += (gl.advance - old_adv);5664}5665}5666}5667}56685669if (Math::floor(p_width) < Math::floor(justification_width)) {5670sd->fit_width_minimum_reached = true;5671}56725673if (!p_jst_flags.has_flag(JUSTIFICATION_CONSTRAIN_ELLIPSIS)) {5674sd->width = justification_width;5675}56765677return Math::ceil(justification_width);5678}56795680double TextServerAdvanced::_shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) {5681ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);5682ERR_FAIL_NULL_V(sd, 0.0);56835684MutexLock lock(sd->mutex);5685if (!sd->valid.is_set()) {5686_shaped_text_shape(p_shaped);5687}5688if (!sd->line_breaks_valid) {5689_shaped_text_update_breaks(p_shaped);5690}56915692for (int i = 0; i < p_tab_stops.size(); i++) {5693if (p_tab_stops[i] <= 0) {5694return 0.0;5695}5696}56975698int tab_index = 0;5699double off = 0.0;57005701int start, end, delta;5702if (sd->para_direction == DIRECTION_LTR) {5703start = 0;5704end = sd->glyphs.size();5705delta = +1;5706} else {5707start = sd->glyphs.size() - 1;5708end = -1;5709delta = -1;5710}57115712Glyph *gl = sd->glyphs.ptr();57135714for (int i = start; i != end; i += delta) {5715if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {5716double tab_off = 0.0;5717while (tab_off <= off) {5718tab_off += p_tab_stops[tab_index];5719tab_index++;5720if (tab_index >= p_tab_stops.size()) {5721tab_index = 0;5722}5723}5724double old_adv = gl[i].advance;5725gl[i].advance = tab_off - off;5726sd->width += gl[i].advance - old_adv;5727off = 0;5728continue;5729}5730off += gl[i].advance * gl[i].repeat;5731}57325733return 0.0;5734}57355736RID TextServerAdvanced::_find_sys_font_for_text(const RID &p_fdef, const String &p_script_code, const String &p_language, const String &p_text) {5737RID f;5738// Try system fallback.5739String font_name = _font_get_name(p_fdef);5740BitField<FontStyle> font_style = _font_get_style(p_fdef);5741int font_weight = _font_get_weight(p_fdef);5742int font_stretch = _font_get_stretch(p_fdef);5743Dictionary dvar = _font_get_variation_coordinates(p_fdef);5744static int64_t wgth_tag = _name_to_tag("weight");5745static int64_t wdth_tag = _name_to_tag("width");5746static int64_t ital_tag = _name_to_tag("italic");5747if (dvar.has(wgth_tag)) {5748font_weight = dvar[wgth_tag].operator int();5749}5750if (dvar.has(wdth_tag)) {5751font_stretch = dvar[wdth_tag].operator int();5752}5753if (dvar.has(ital_tag) && dvar[ital_tag].operator int() == 1) {5754font_style.set_flag(TextServer::FONT_ITALIC);5755}5756if (p_script_code == "Zsye") {5757#if defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)5758font_name = "Apple Color Emoji";5759#elif defined(WINDOWS_ENABLED)5760font_name = "Segoe UI Emoji";5761#else5762font_name = "Noto Color Emoji";5763#endif5764}57655766String locale = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;5767PackedStringArray 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);5768#ifdef GDEXTENSION5769for (int fb = 0; fb < fallback_font_name.size(); fb++) {5770const String &E = fallback_font_name[fb];5771#elif defined(GODOT_MODULE)5772for (const String &E : fallback_font_name) {5773#endif5774SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, p_fdef, this);5775if (system_fonts.has(key)) {5776const SystemFontCache &sysf_cache = system_fonts[key];5777int best_score = 0;5778int best_match = -1;5779for (int face_idx = 0; face_idx < sysf_cache.var.size(); face_idx++) {5780const SystemFontCacheRec &F = sysf_cache.var[face_idx];5781if (unlikely(!_font_has_char(F.rid, p_text[0]))) {5782continue;5783}5784BitField<FontStyle> style = _font_get_style(F.rid);5785int weight = _font_get_weight(F.rid);5786int stretch = _font_get_stretch(F.rid);5787int score = (20 - Math::abs(weight - font_weight) / 50);5788score += (20 - Math::abs(stretch - font_stretch) / 10);5789if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) {5790score += 30;5791}5792if (score >= best_score) {5793best_score = score;5794best_match = face_idx;5795}5796if (best_score == 70) {5797break;5798}5799}5800if (best_match != -1) {5801f = sysf_cache.var[best_match].rid;5802}5803}5804if (!f.is_valid()) {5805if (system_fonts.has(key)) {5806const SystemFontCache &sysf_cache = system_fonts[key];5807if (sysf_cache.max_var == sysf_cache.var.size()) {5808// All subfonts already tested, skip.5809continue;5810}5811}58125813if (!system_font_data.has(E)) {5814system_font_data[E] = FileAccess::get_file_as_bytes(E);5815}58165817const PackedByteArray &font_data = system_font_data[E];58185819SystemFontCacheRec sysf;5820sysf.rid = _create_font();5821_font_set_data_ptr(sysf.rid, font_data.ptr(), font_data.size());5822if (!_font_validate(sysf.rid)) {5823_free_rid(sysf.rid);5824continue;5825}58265827Dictionary var = dvar;5828// Select matching style from collection.5829int best_score = 0;5830int best_match = -1;5831for (int face_idx = 0; face_idx < _font_get_face_count(sysf.rid); face_idx++) {5832_font_set_face_index(sysf.rid, face_idx);5833if (unlikely(!_font_has_char(sysf.rid, p_text[0]))) {5834continue;5835}5836BitField<FontStyle> style = _font_get_style(sysf.rid);5837int weight = _font_get_weight(sysf.rid);5838int stretch = _font_get_stretch(sysf.rid);5839int score = (20 - Math::abs(weight - font_weight) / 50);5840score += (20 - Math::abs(stretch - font_stretch) / 10);5841if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) {5842score += 30;5843}5844if (score >= best_score) {5845best_score = score;5846best_match = face_idx;5847}5848if (best_score == 70) {5849break;5850}5851}5852if (best_match == -1) {5853_free_rid(sysf.rid);5854continue;5855} else {5856_font_set_face_index(sysf.rid, best_match);5857}5858sysf.index = best_match;58595860// If it's a variable font, apply weight, stretch and italic coordinates to match requested style.5861if (best_score != 70) {5862Dictionary ftr = _font_supported_variation_list(sysf.rid);5863if (ftr.has(wdth_tag)) {5864var[wdth_tag] = font_stretch;5865_font_set_stretch(sysf.rid, font_stretch);5866}5867if (ftr.has(wgth_tag)) {5868var[wgth_tag] = font_weight;5869_font_set_weight(sysf.rid, font_weight);5870}5871if ((font_style & TextServer::FONT_ITALIC) && ftr.has(ital_tag)) {5872var[ital_tag] = 1;5873_font_set_style(sysf.rid, _font_get_style(sysf.rid) | TextServer::FONT_ITALIC);5874}5875}58765877bool fb_use_msdf = key.msdf;5878#ifdef MODULE_FREETYPE_ENABLED5879if (fb_use_msdf) {5880FontAdvanced *fd = _get_font_data(sysf.rid);5881if (fd) {5882MutexLock lock(fd->mutex);5883Vector2i size = _get_size(fd, 16);5884FontForSizeAdvanced *ffsd = nullptr;5885if (_ensure_cache_for_size(fd, size, ffsd)) {5886if (ffsd && (FT_HAS_COLOR(fd->face) || !FT_IS_SCALABLE(fd->face))) {5887fb_use_msdf = false;5888}5889}5890}5891}5892#endif58935894_font_set_antialiasing(sysf.rid, key.antialiasing);5895_font_set_disable_embedded_bitmaps(sysf.rid, key.disable_embedded_bitmaps);5896_font_set_generate_mipmaps(sysf.rid, key.mipmaps);5897_font_set_multichannel_signed_distance_field(sysf.rid, fb_use_msdf);5898_font_set_msdf_pixel_range(sysf.rid, key.msdf_range);5899_font_set_msdf_size(sysf.rid, key.msdf_source_size);5900_font_set_fixed_size(sysf.rid, key.fixed_size);5901_font_set_force_autohinter(sysf.rid, key.force_autohinter);5902_font_set_hinting(sysf.rid, key.hinting);5903_font_set_subpixel_positioning(sysf.rid, key.subpixel_positioning);5904_font_set_keep_rounding_remainders(sysf.rid, key.keep_rounding_remainders);5905_font_set_variation_coordinates(sysf.rid, var);5906_font_set_embolden(sysf.rid, key.embolden);5907_font_set_transform(sysf.rid, key.transform);5908_font_set_spacing(sysf.rid, SPACING_TOP, key.extra_spacing[SPACING_TOP]);5909_font_set_spacing(sysf.rid, SPACING_BOTTOM, key.extra_spacing[SPACING_BOTTOM]);5910_font_set_spacing(sysf.rid, SPACING_SPACE, key.extra_spacing[SPACING_SPACE]);5911_font_set_spacing(sysf.rid, SPACING_GLYPH, key.extra_spacing[SPACING_GLYPH]);59125913if (system_fonts.has(key)) {5914system_fonts[key].var.push_back(sysf);5915} else {5916SystemFontCache &sysf_cache = system_fonts[key];5917sysf_cache.max_var = _font_get_face_count(sysf.rid);5918sysf_cache.var.push_back(sysf);5919}5920f = sysf.rid;5921}5922break;5923}5924return f;5925}59265927void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) {5928ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped_line);5929ERR_FAIL_NULL_MSG(sd, "ShapedTextDataAdvanced invalid.");59305931MutexLock lock(sd->mutex);5932if (!sd->valid.is_set()) {5933_shaped_text_shape(p_shaped_line);5934}5935if (!sd->line_breaks_valid) {5936_shaped_text_update_breaks(p_shaped_line);5937}59385939sd->text_trimmed = false;5940sd->overrun_trim_data.ellipsis_glyph_buf.clear();59415942bool add_ellipsis = p_trim_flags.has_flag(OVERRUN_ADD_ELLIPSIS);5943bool cut_per_word = p_trim_flags.has_flag(OVERRUN_TRIM_WORD_ONLY);5944bool enforce_ellipsis = p_trim_flags.has_flag(OVERRUN_ENFORCE_ELLIPSIS);5945bool short_string_ellipsis = p_trim_flags.has_flag(OVERRUN_SHORT_STRING_ELLIPSIS);5946bool justification_aware = p_trim_flags.has_flag(OVERRUN_JUSTIFICATION_AWARE);59475948Glyph *sd_glyphs = sd->glyphs.ptr();59495950if ((p_trim_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIM || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {5951sd->overrun_trim_data.trim_pos = -1;5952sd->overrun_trim_data.ellipsis_pos = -1;5953return;5954}59555956if (justification_aware && !sd->fit_width_minimum_reached) {5957return;5958}59595960Vector<ShapedTextDataAdvanced::Span> &spans = sd->spans;5961if (sd->parent != RID()) {5962ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);5963ERR_FAIL_COND(!parent_sd->valid.is_set());5964spans = parent_sd->spans;5965}59665967int span_size = spans.size();5968if (span_size == 0) {5969return;5970}59715972int sd_size = sd->glyphs.size();5973int last_gl_font_size = sd_glyphs[sd_size - 1].font_size;5974bool found_el_char = false;59755976// Find usable fonts, if fonts from the last glyph do not have required chars.5977RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;5978if (add_ellipsis || enforce_ellipsis || short_string_ellipsis) {5979if (!_font_has_char(dot_gl_font_rid, sd->el_char)) {5980const Array &fonts = spans[span_size - 1].fonts;5981for (int i = 0; i < fonts.size(); i++) {5982if (_font_has_char(fonts[i], sd->el_char)) {5983dot_gl_font_rid = fonts[i];5984found_el_char = true;5985break;5986}5987}5988if (!found_el_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) {5989const char32_t u32str[] = { sd->el_char, 0 };5990RID rid = _find_sys_font_for_text(fonts[0], String(), spans[span_size - 1].language, u32str);5991if (rid.is_valid()) {5992dot_gl_font_rid = rid;5993found_el_char = true;5994}5995}5996} else {5997found_el_char = true;5998}5999if (!found_el_char) {6000bool found_dot_char = false;6001dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;6002if (!_font_has_char(dot_gl_font_rid, '.')) {6003const Array &fonts = spans[span_size - 1].fonts;6004for (int i = 0; i < fonts.size(); i++) {6005if (_font_has_char(fonts[i], '.')) {6006dot_gl_font_rid = fonts[i];6007found_dot_char = true;6008break;6009}6010}6011if (!found_dot_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) {6012RID rid = _find_sys_font_for_text(fonts[0], String(), spans[span_size - 1].language, ".");6013if (rid.is_valid()) {6014dot_gl_font_rid = rid;6015}6016}6017}6018}6019}6020RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;6021if (!_font_has_char(whitespace_gl_font_rid, ' ')) {6022const Array &fonts = spans[span_size - 1].fonts;6023for (int i = 0; i < fonts.size(); i++) {6024if (_font_has_char(fonts[i], ' ')) {6025whitespace_gl_font_rid = fonts[i];6026break;6027}6028}6029}60306031int32_t dot_gl_idx = ((add_ellipsis || enforce_ellipsis || short_string_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;6032Vector2 dot_adv = ((add_ellipsis || enforce_ellipsis || short_string_ellipsis) && dot_gl_font_rid.is_valid()) ? _font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2();6033int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ', 0) : -1;6034Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2();60356036int ellipsis_width = 0;6037if (add_ellipsis && whitespace_gl_font_rid.is_valid()) {6038ellipsis_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);6039}60406041int ell_min_characters = 6;6042double width = sd->width;6043double width_without_el = width;60446045bool is_rtl = sd->para_direction == DIRECTION_RTL;60466047int trim_pos = (is_rtl) ? sd_size : 0;6048int ellipsis_pos = (enforce_ellipsis || short_string_ellipsis) ? 0 : -1;60496050int last_valid_cut = -1;6051int last_valid_cut_witout_el = -1;60526053int glyphs_from = (is_rtl) ? 0 : sd_size - 1;6054int glyphs_to = (is_rtl) ? sd_size - 1 : -1;6055int glyphs_delta = (is_rtl) ? +1 : -1;60566057if ((enforce_ellipsis || short_string_ellipsis) && (width + ellipsis_width <= p_width)) {6058trim_pos = -1;6059ellipsis_pos = (is_rtl) ? 0 : sd_size;6060} else {6061for (int i = glyphs_from; i != glyphs_to; i += glyphs_delta) {6062if (!is_rtl) {6063width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;6064}6065if (sd_glyphs[i].count > 0) {6066bool above_min_char_threshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters;6067if (!above_min_char_threshold && last_valid_cut_witout_el != -1) {6068trim_pos = last_valid_cut_witout_el;6069ellipsis_pos = -1;6070width = width_without_el;6071break;6072}6073if (!(enforce_ellipsis || short_string_ellipsis) && width <= p_width && last_valid_cut_witout_el == -1) {6074if (cut_per_word && above_min_char_threshold) {6075if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {6076last_valid_cut_witout_el = i;6077width_without_el = width;6078}6079} else {6080last_valid_cut_witout_el = i;6081width_without_el = width;6082}6083}6084if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis || short_string_ellipsis) ? ellipsis_width : 0) <= p_width) {6085if (cut_per_word && above_min_char_threshold) {6086if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {6087last_valid_cut = i;6088}6089} else {6090last_valid_cut = i;6091}6092if (last_valid_cut != -1) {6093trim_pos = last_valid_cut;60946095if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis || short_string_ellipsis) && width - ellipsis_width <= p_width) {6096ellipsis_pos = trim_pos;6097}6098break;6099}6100}6101}6102if (is_rtl) {6103width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;6104}6105}6106}61076108sd->overrun_trim_data.trim_pos = trim_pos;6109sd->overrun_trim_data.ellipsis_pos = ellipsis_pos;6110if (trim_pos == 0 && (enforce_ellipsis || short_string_ellipsis) && add_ellipsis) {6111sd->overrun_trim_data.ellipsis_pos = 0;6112}61136114if ((trim_pos >= 0 && sd->width > p_width) || enforce_ellipsis || short_string_ellipsis) {6115if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis || short_string_ellipsis)) {6116// Insert an additional space when cutting word bound for aesthetics.6117if (cut_per_word && (ellipsis_pos > 0)) {6118Glyph gl;6119gl.count = 1;6120gl.advance = whitespace_adv.x;6121gl.index = whitespace_gl_idx;6122gl.font_rid = whitespace_gl_font_rid;6123gl.font_size = last_gl_font_size;6124gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);61256126sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);6127}6128// Add ellipsis dots.6129if (dot_gl_idx != 0) {6130Glyph gl;6131gl.count = 1;6132gl.repeat = (found_el_char ? 1 : 3);6133gl.advance = dot_adv.x;6134gl.index = dot_gl_idx;6135gl.font_rid = dot_gl_font_rid;6136gl.font_size = last_gl_font_size;6137gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);61386139sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);6140}6141}61426143sd->text_trimmed = true;6144sd->width_trimmed = width + ((ellipsis_pos != -1) ? ellipsis_width : 0);6145}6146}61476148int64_t TextServerAdvanced::_shaped_text_get_trim_pos(const RID &p_shaped) const {6149ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6150ERR_FAIL_NULL_V_MSG(sd, -1, "ShapedTextDataAdvanced invalid.");61516152MutexLock lock(sd->mutex);6153return sd->overrun_trim_data.trim_pos;6154}61556156int64_t TextServerAdvanced::_shaped_text_get_ellipsis_pos(const RID &p_shaped) const {6157ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6158ERR_FAIL_NULL_V_MSG(sd, -1, "ShapedTextDataAdvanced invalid.");61596160MutexLock lock(sd->mutex);6161return sd->overrun_trim_data.ellipsis_pos;6162}61636164const Glyph *TextServerAdvanced::_shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const {6165ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6166ERR_FAIL_NULL_V_MSG(sd, nullptr, "ShapedTextDataAdvanced invalid.");61676168MutexLock lock(sd->mutex);6169return sd->overrun_trim_data.ellipsis_glyph_buf.ptr();6170}61716172int64_t TextServerAdvanced::_shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const {6173ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6174ERR_FAIL_NULL_V_MSG(sd, 0, "ShapedTextDataAdvanced invalid.");61756176MutexLock lock(sd->mutex);6177return sd->overrun_trim_data.ellipsis_glyph_buf.size();6178}61796180void TextServerAdvanced::_update_chars(ShapedTextDataAdvanced *p_sd) const {6181if (!p_sd->chars_valid) {6182p_sd->chars.clear();61836184const UChar *data = p_sd->utf16.get_data();6185UErrorCode err = U_ZERO_ERROR;6186int prev = -1;6187int i = 0;61886189Vector<ShapedTextDataAdvanced::Span> &spans = p_sd->spans;6190if (p_sd->parent != RID()) {6191ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(p_sd->parent);6192ERR_FAIL_COND(!parent_sd->valid.is_set());6193spans = parent_sd->spans;6194}61956196int span_size = spans.size();6197while (i < span_size) {6198if (spans[i].start > p_sd->end) {6199break;6200}6201if (spans[i].end < p_sd->start) {6202i++;6203continue;6204}62056206int r_start = MAX(0, spans[i].start - p_sd->start);6207String language = spans[i].language;6208while (i + 1 < span_size && language == spans[i + 1].language) {6209i++;6210}6211int r_end = MIN(spans[i].end - p_sd->start, p_sd->text.length());6212UBreakIterator *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);6213if (U_SUCCESS(err)) {6214while (ubrk_next(bi) != UBRK_DONE) {6215int pos = _convert_pos(p_sd, ubrk_current(bi)) + r_start + p_sd->start;6216if (prev != pos) {6217p_sd->chars.push_back(pos);6218}6219prev = pos;6220}6221ubrk_close(bi);6222} else {6223for (int j = r_start; j < r_end; j++) {6224if (prev != j) {6225p_sd->chars.push_back(j + 1 + p_sd->start);6226}6227prev = j;6228}6229}6230i++;6231}6232p_sd->chars_valid = true;6233}6234}62356236PackedInt32Array TextServerAdvanced::_shaped_text_get_character_breaks(const RID &p_shaped) const {6237ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6238ERR_FAIL_NULL_V(sd, PackedInt32Array());62396240MutexLock lock(sd->mutex);6241if (!sd->valid.is_set()) {6242const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);6243}62446245_update_chars(sd);62466247return sd->chars;6248}62496250bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) {6251ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6252ERR_FAIL_NULL_V(sd, false);62536254MutexLock lock(sd->mutex);6255if (!sd->valid.is_set()) {6256_shaped_text_shape(p_shaped);6257}62586259if (sd->line_breaks_valid) {6260return true; // Nothing to do.6261}62626263const UChar *data = sd->utf16.get_data();62646265if (!sd->break_ops_valid) {6266sd->breaks.clear();6267sd->break_inserts = 0;6268UErrorCode err = U_ZERO_ERROR;6269int i = 0;6270int span_size = sd->spans.size();6271while (i < span_size) {6272String language = sd->spans[i].language;6273int r_start = sd->spans[i].start;6274if (r_start == sd->spans[i].end) {6275i++;6276continue;6277}6278while (i + 1 < span_size && (language == sd->spans[i + 1].language || sd->spans[i + 1].start == sd->spans[i + 1].end)) {6279i++;6280}6281int r_end = sd->spans[i].end;6282UBreakIterator *bi = _create_line_break_iterator_for_locale(language, &err);62836284if (!U_FAILURE(err) && bi) {6285ubrk_setText(bi, data + _convert_pos_inv(sd, r_start), _convert_pos_inv(sd, r_end - r_start), &err);6286}62876288if (U_FAILURE(err) || !bi) {6289// No data loaded - use fallback.6290for (int j = r_start; j < r_end; j++) {6291char32_t c = sd->text[j - sd->start];6292char32_t c_next = (j < r_end) ? sd->text[j - sd->start + 1] : 0x0000;6293if (is_whitespace(c)) {6294sd->breaks[j + 1] = false;6295}6296if (is_linebreak(c)) {6297if (c != 0x000D || c_next != 0x000A) { // Skip first hard break in CR-LF pair.6298sd->breaks[j + 1] = true;6299}6300}6301}6302} else {6303while (ubrk_next(bi) != UBRK_DONE) {6304int pos = _convert_pos(sd, ubrk_current(bi)) + r_start;6305if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_HARD) && (ubrk_getRuleStatus(bi) < UBRK_LINE_HARD_LIMIT)) {6306sd->breaks[pos] = true;6307} else if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_SOFT) && (ubrk_getRuleStatus(bi) < UBRK_LINE_SOFT_LIMIT)) {6308sd->breaks[pos] = false;6309}6310int pos_p = pos - 1 - sd->start;6311char32_t c = sd->text[pos_p];6312if (pos - sd->start != sd->end && !is_whitespace(c) && (c != 0xfffc)) {6313sd->break_inserts++;6314}6315}6316ubrk_close(bi);6317}6318i++;6319}6320sd->break_ops_valid = true;6321}63226323LocalVector<Glyph> glyphs_new;63246325bool rewrite = false;6326int sd_shift = 0;6327int sd_size = sd->glyphs.size();6328Glyph *sd_glyphs = sd->glyphs.ptr();6329Glyph *sd_glyphs_new = nullptr;63306331if (sd->break_inserts > 0) {6332glyphs_new.resize(sd->glyphs.size() + sd->break_inserts);6333sd_glyphs_new = glyphs_new.ptr();6334rewrite = true;6335} else {6336sd_glyphs_new = sd_glyphs;6337}63386339sd->sort_valid = false;6340sd->glyphs_logical.clear();6341const char32_t *ch = sd->text.ptr();63426343int c_punct_size = sd->custom_punct.length();6344const char32_t *c_punct = sd->custom_punct.ptr();63456346for (int i = 0; i < sd_size; i++) {6347if (rewrite) {6348for (int j = 0; j < sd_glyphs[i].count; j++) {6349sd_glyphs_new[sd_shift + i + j] = sd_glyphs[i + j];6350}6351}6352if (sd_glyphs[i].count > 0) {6353char32_t c = ch[sd_glyphs[i].start - sd->start];6354if (c == 0xfffc) {6355i += (sd_glyphs[i].count - 1);6356continue;6357}6358if (c == 0x0009 || c == 0x000b) {6359sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_TAB;6360}6361if (c == 0x00ad) {6362sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_SOFT_HYPHEN;6363}6364if (is_whitespace(c)) {6365sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_SPACE;6366}6367if (c_punct_size == 0) {6368if (u_ispunct(c) && c != 0x005f) {6369sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_PUNCTUATION;6370}6371} else {6372for (int j = 0; j < c_punct_size; j++) {6373if (c_punct[j] == c) {6374sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_PUNCTUATION;6375break;6376}6377}6378}6379if (is_underscore(c)) {6380sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_UNDERSCORE;6381}6382if (sd->breaks.has(sd_glyphs[i].end)) {6383if (sd->breaks[sd_glyphs[i].end] && (is_linebreak(c))) {6384sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_BREAK_HARD;6385} else if (is_whitespace(c) || c == 0x00ad) {6386sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_BREAK_SOFT;6387} else {6388int count = sd_glyphs[i].count;6389// Do not add extra space at the end of the line.6390if (sd_glyphs[i].end == sd->end) {6391i += (sd_glyphs[i].count - 1);6392continue;6393}6394// Do not add extra space after existing space.6395if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {6396if ((i + count < sd_size - 1) && ((sd_glyphs[i + count].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) {6397i += (sd_glyphs[i].count - 1);6398continue;6399}6400} else {6401if ((sd_glyphs[i].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) {6402i += (sd_glyphs[i].count - 1);6403continue;6404}6405}6406// Do not add extra space for color picker object.6407if (((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)) {6408i += (sd_glyphs[i].count - 1);6409continue;6410}6411Glyph gl;6412gl.span_index = sd_glyphs[i].span_index;6413gl.start = sd_glyphs[i].start;6414gl.end = sd_glyphs[i].end;6415gl.count = 1;6416gl.font_rid = sd_glyphs[i].font_rid;6417gl.font_size = sd_glyphs[i].font_size;6418gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | GRAPHEME_IS_SPACE;6419// Mark virtual space after punctuation as punctuation to avoid justification at this point.6420if (c_punct_size == 0) {6421if (u_ispunct(c) && c != 0x005f) {6422gl.flags |= GRAPHEME_IS_PUNCTUATION;6423}6424} else {6425for (int j = 0; j < c_punct_size; j++) {6426if (c_punct[j] == c) {6427gl.flags |= GRAPHEME_IS_PUNCTUATION;6428break;6429}6430}6431}6432if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {6433gl.flags |= GRAPHEME_IS_RTL;6434for (int j = sd_glyphs[i].count - 1; j >= 0; j--) {6435sd_glyphs_new[sd_shift + i + j + 1] = sd_glyphs_new[sd_shift + i + j];6436}6437sd_glyphs_new[sd_shift + i] = gl;6438} else {6439sd_glyphs_new[sd_shift + i + count] = gl;6440}6441sd_shift++;6442ERR_FAIL_COND_V_MSG(sd_shift > sd->break_inserts, false, "Invalid break insert count!");6443}6444}6445i += (sd_glyphs[i].count - 1);6446}6447}6448if (sd_shift < sd->break_inserts) {6449// 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).6450glyphs_new.resize(sd->glyphs.size() + sd_shift);6451}64526453if (sd->break_inserts > 0) {6454sd->glyphs = std::move(glyphs_new);6455}64566457sd->line_breaks_valid = true;64586459return sd->line_breaks_valid;6460}64616462_FORCE_INLINE_ int64_t _generate_kashida_justification_opportunities(const String &p_data, int64_t p_start, int64_t p_end) {6463int64_t kashida_pos = -1;6464int8_t priority = 100;6465int64_t i = p_start;64666467char32_t pc = 0;64686469while ((p_end > p_start) && is_transparent(p_data[p_end - 1])) {6470p_end--;6471}64726473while (i < p_end) {6474uint32_t c = p_data[i];64756476if (c == 0x0640) {6477kashida_pos = i;6478priority = 0;6479}6480if (priority >= 1 && i < p_end - 1) {6481if (is_seen_sad(c) && (p_data[i + 1] != 0x200c)) {6482kashida_pos = i;6483priority = 1;6484}6485}6486if (priority >= 2 && i > p_start) {6487if (is_teh_marbuta(c) || is_dal(c) || (is_heh(c) && i == p_end - 1)) {6488if (is_connected_to_prev(c, pc)) {6489kashida_pos = i - 1;6490priority = 2;6491}6492}6493}6494if (priority >= 3 && i > p_start) {6495if (is_alef(c) || ((is_lam(c) || is_tah(c) || is_kaf(c) || is_gaf(c)) && i == p_end - 1)) {6496if (is_connected_to_prev(c, pc)) {6497kashida_pos = i - 1;6498priority = 3;6499}6500}6501}6502if (priority >= 4 && i > p_start && i < p_end - 1) {6503if (is_beh(c)) {6504if (is_reh(p_data[i + 1]) || is_yeh(p_data[i + 1])) {6505if (is_connected_to_prev(c, pc)) {6506kashida_pos = i - 1;6507priority = 4;6508}6509}6510}6511}6512if (priority >= 5 && i > p_start) {6513if (is_waw(c) || ((is_ain(c) || is_qaf(c) || is_feh(c)) && i == p_end - 1)) {6514if (is_connected_to_prev(c, pc)) {6515kashida_pos = i - 1;6516priority = 5;6517}6518}6519}6520if (priority >= 6 && i > p_start) {6521if (is_reh(c)) {6522if (is_connected_to_prev(c, pc)) {6523kashida_pos = i - 1;6524priority = 6;6525}6526}6527}6528if (!is_transparent(c)) {6529pc = c;6530}6531i++;6532}65336534return kashida_pos;6535}65366537bool TextServerAdvanced::_shaped_text_update_justification_ops(const RID &p_shaped) {6538ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);6539ERR_FAIL_NULL_V(sd, false);65406541MutexLock lock(sd->mutex);6542if (!sd->valid.is_set()) {6543_shaped_text_shape(p_shaped);6544}6545if (!sd->line_breaks_valid) {6546_shaped_text_update_breaks(p_shaped);6547}65486549if (sd->justification_ops_valid) {6550return true; // Nothing to do.6551}65526553const UChar *data = sd->utf16.get_data();6554int data_size = sd->utf16.length();65556556if (!sd->js_ops_valid) {6557sd->jstops.clear();65586559// Use ICU word iterator and custom kashida detection.6560UErrorCode err = U_ZERO_ERROR;6561UBreakIterator *bi = ubrk_open(UBRK_WORD, "", data, data_size, &err);6562if (U_FAILURE(err)) {6563// No data - use fallback.6564int limit = 0;6565for (int i = 0; i < sd->text.length(); i++) {6566if (is_whitespace(sd->text[i])) {6567int ks = _generate_kashida_justification_opportunities(sd->text, limit, i) + sd->start;6568if (ks != -1) {6569sd->jstops[ks] = true;6570}6571limit = i + 1;6572}6573}6574int ks = _generate_kashida_justification_opportunities(sd->text, limit, sd->text.length()) + sd->start;6575if (ks != -1) {6576sd->jstops[ks] = true;6577}6578} else {6579int limit = 0;6580while (ubrk_next(bi) != UBRK_DONE) {6581if (ubrk_getRuleStatus(bi) != UBRK_WORD_NONE) {6582int i = _convert_pos(sd, ubrk_current(bi));6583sd->jstops[i + sd->start] = false;6584int ks = _generate_kashida_justification_opportunities(sd->text, limit, i);6585if (ks != -1) {6586sd->jstops[ks + sd->start] = true;6587}6588limit = i;6589}6590}6591ubrk_close(bi);6592}65936594sd->js_ops_valid = true;6595}65966597sd->sort_valid = false;6598sd->glyphs_logical.clear();65996600Glyph *sd_glyphs = sd->glyphs.ptr();6601int sd_size = sd->glyphs.size();6602if (!sd->jstops.is_empty()) {6603for (int i = 0; i < sd_size; i++) {6604if (sd_glyphs[i].count > 0) {6605char32_t c = sd->text[sd_glyphs[i].start - sd->start];6606if (c == 0x0640 && sd_glyphs[i].start == sd_glyphs[i].end - 1) {6607sd_glyphs[i].flags |= GRAPHEME_IS_ELONGATION;6608}6609if (sd->jstops.has(sd_glyphs[i].start)) {6610if (c == 0xfffc || c == 0x00ad) {6611continue;6612}6613if (sd->jstops[sd_glyphs[i].start]) {6614if (c != 0x0640) {6615if (sd_glyphs[i].font_rid != RID()) {6616Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size);6617if ((sd_glyphs[i].flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {6618#if HB_VERSION_ATLEAST(5, 1, 0)6619if ((i > 0) && ((sd_glyphs[i - 1].flags & GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL) != GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL)) {6620continue;6621}6622#endif6623gl.start = sd_glyphs[i].start;6624gl.end = sd_glyphs[i].end;6625gl.repeat = 0;6626gl.count = 1;6627if (sd->orientation == ORIENTATION_HORIZONTAL) {6628gl.y_off = sd_glyphs[i].y_off;6629} else {6630gl.x_off = sd_glyphs[i].x_off;6631}6632gl.flags |= GRAPHEME_IS_ELONGATION | GRAPHEME_IS_VIRTUAL;6633sd->glyphs.insert(i, gl);6634i++;66356636// Update write pointer and size.6637sd_size = sd->glyphs.size();6638sd_glyphs = sd->glyphs.ptr();6639continue;6640}6641}6642}6643} else if ((sd_glyphs[i].flags & GRAPHEME_IS_SPACE) != GRAPHEME_IS_SPACE && (sd_glyphs[i].flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {6644int count = sd_glyphs[i].count;6645// Do not add extra spaces at the end of the line.6646if (sd_glyphs[i].end == sd->end) {6647continue;6648}6649// Do not add extra space after existing space.6650if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {6651if ((i + count < sd_size - 1) && ((sd_glyphs[i + count].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) {6652continue;6653}6654} else {6655if ((i > 0) && ((sd_glyphs[i - 1].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) {6656continue;6657}6658}6659// Inject virtual space for alignment.6660Glyph gl;6661gl.span_index = sd_glyphs[i].span_index;6662gl.start = sd_glyphs[i].start;6663gl.end = sd_glyphs[i].end;6664gl.count = 1;6665gl.font_rid = sd_glyphs[i].font_rid;6666gl.font_size = sd_glyphs[i].font_size;6667gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_VIRTUAL;6668if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {6669gl.flags |= GRAPHEME_IS_RTL;6670sd->glyphs.insert(i, gl); // Insert before.6671} else {6672sd->glyphs.insert(i + count, gl); // Insert after.6673}6674i += count;66756676// Update write pointer and size.6677sd_size = sd->glyphs.size();6678sd_glyphs = sd->glyphs.ptr();6679continue;6680}6681}6682}6683}6684}66856686sd->justification_ops_valid = true;6687return sd->justification_ops_valid;6688}66896690Glyph 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) {6691bool color = false;6692hb_font_t *hb_font = _font_get_hb_handle(p_font, p_font_size, color);6693double scale = _font_get_scale(p_font, p_font_size);6694bool 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);6695ERR_FAIL_NULL_V(hb_font, Glyph());66966697hb_buffer_clear_contents(p_sd->hb_buffer);6698hb_buffer_set_direction(p_sd->hb_buffer, p_direction);6699hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)(HB_BUFFER_FLAG_DEFAULT));6700hb_buffer_set_script(p_sd->hb_buffer, (p_script == HB_TAG('Z', 's', 'y', 'e')) ? HB_SCRIPT_COMMON : p_script);6701hb_buffer_add_utf32(p_sd->hb_buffer, (const uint32_t *)&p_char, 1, 0, 1);67026703hb_shape(hb_font, p_sd->hb_buffer, nullptr, 0);67046705unsigned int glyph_count = 0;6706hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(p_sd->hb_buffer, &glyph_count);6707hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(p_sd->hb_buffer, &glyph_count);67086709// Process glyphs.6710Glyph gl;67116712if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {6713gl.flags |= TextServer::GRAPHEME_IS_RTL;6714}67156716gl.font_rid = p_font;6717gl.font_size = p_font_size;67186719if (glyph_count > 0) {6720if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6721if (subpos) {6722gl.advance = (double)glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size);6723} else {6724gl.advance = Math::round((double)glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size));6725}6726} else {6727gl.advance = -Math::round((double)glyph_pos[0].y_advance / (64.0 / scale));6728}6729gl.count = 1;67306731gl.index = glyph_info[0].codepoint;6732if (subpos) {6733gl.x_off = (double)glyph_pos[0].x_offset / (64.0 / scale);6734} else {6735gl.x_off = Math::round((double)glyph_pos[0].x_offset / (64.0 / scale));6736}6737gl.y_off = -Math::round((double)glyph_pos[0].y_offset / (64.0 / scale));6738if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6739gl.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));6740} else {6741gl.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));6742}67436744if ((glyph_info[0].codepoint != 0) || !u_isgraph(p_char)) {6745gl.flags |= GRAPHEME_IS_VALID;6746}6747}6748return gl;6749}67506751_FORCE_INLINE_ void TextServerAdvanced::_add_features(const Dictionary &p_source, Vector<hb_feature_t> &r_ftrs) {6752for (const KeyValue<Variant, Variant> &key_value : p_source) {6753int32_t value = key_value.value;6754if (value >= 0) {6755hb_feature_t feature;6756if (key_value.key.is_string()) {6757feature.tag = _name_to_tag(key_value.key);6758} else {6759feature.tag = key_value.key;6760}6761feature.value = value;6762feature.start = 0;6763feature.end = -1;6764r_ftrs.push_back(feature);6765}6766}6767}67686769UBreakIterator *TextServerAdvanced::_create_line_break_iterator_for_locale(const String &p_language, UErrorCode *r_err) const {6770// Creating UBreakIterator (ubrk_open) is surprisingly costly.6771// However, cloning (ubrk_clone) is cheaper, so we keep around blueprints to accelerate creating new ones.67726773String language = p_language.is_empty() ? TranslationServer::get_singleton()->get_tool_locale() : p_language;6774if (!language.contains("@")) {6775if (lb_strictness == LB_LOOSE) {6776language += "@lb=loose";6777} else if (lb_strictness == LB_NORMAL) {6778language += "@lb=normal";6779} else if (lb_strictness == LB_STRICT) {6780language += "@lb=strict";6781}6782}67836784_THREAD_SAFE_METHOD_6785const HashMap<String, UBreakIterator *>::Iterator key_value = line_break_iterators_per_language.find(language);6786if (key_value) {6787return ubrk_clone(key_value->value, r_err);6788}6789UBreakIterator *bi = ubrk_open(UBRK_LINE, language.ascii().get_data(), nullptr, 0, r_err);6790if (U_FAILURE(*r_err) || !bi) {6791return nullptr;6792}6793line_break_iterators_per_language.insert(language, bi);6794return ubrk_clone(bi, r_err);6795}67966797void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, const String &p_language, hb_script_t p_script, hb_direction_t p_direction, FontPriorityList &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) {6798RID f;6799int fs = p_sd->spans[p_span].font_size;6800if (p_fb_index >= 0 && p_fb_index < p_fonts.size()) {6801// Try font from list.6802f = p_fonts[p_fb_index];6803} 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))) {6804// Try system fallback.6805if (_font_is_allow_system_fallback(p_fonts[0])) {6806_update_chars(p_sd);68076808int64_t next = p_end;6809for (const int32_t &E : p_sd->chars) {6810if (E > p_start) {6811next = E;6812break;6813}6814}6815char scr_buffer[5] = { 0, 0, 0, 0, 0 };6816hb_tag_to_string(hb_script_to_iso15924_tag(p_script), scr_buffer);6817String script_code = String(scr_buffer);68186819String text = p_sd->text.substr(p_start, next - p_start);6820f = _find_sys_font_for_text(p_fonts[0], script_code, p_language, text);6821}6822}68236824if (!f.is_valid()) {6825// Shaping failed, try looking up raw characters or use fallback hex code boxes.6826int fb_from = (p_direction != HB_DIRECTION_RTL) ? p_start : p_end - 1;6827int fb_to = (p_direction != HB_DIRECTION_RTL) ? p_end : p_start - 1;6828int fb_delta = (p_direction != HB_DIRECTION_RTL) ? +1 : -1;68296830for (int i = fb_from; i != fb_to; i += fb_delta) {6831if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) {6832Glyph gl;6833gl.span_index = p_span;6834gl.start = i + p_sd->start;6835gl.end = i + 1 + p_sd->start;6836gl.count = 1;6837gl.font_size = fs;6838if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {6839gl.flags |= TextServer::GRAPHEME_IS_RTL;6840}68416842bool found = false;6843for (uint32_t j = 0; j <= p_fonts.size(); j++) {6844RID f_rid;6845if (j == p_fonts.size()) {6846f_rid = p_prev_font;6847} else {6848f_rid = p_fonts[j];6849}6850if (f_rid.is_valid() && _font_has_char(f_rid, p_sd->text[i])) {6851gl.font_rid = f_rid;6852gl.index = _font_get_glyph_index(gl.font_rid, fs, p_sd->text[i], 0);6853if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6854gl.advance = _font_get_glyph_advance(gl.font_rid, fs, gl.index).x;6855gl.x_off = 0;6856gl.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));6857p_sd->ascent = MAX(p_sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_TOP));6858p_sd->descent = MAX(p_sd->descent, _font_get_descent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_BOTTOM));6859} else {6860gl.advance = _font_get_glyph_advance(gl.font_rid, fs, gl.index).y;6861gl.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));6862gl.y_off = _font_get_ascent(gl.font_rid, gl.font_size);6863p_sd->ascent = MAX(p_sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));6864p_sd->descent = MAX(p_sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));6865}6866double scale = _font_get_scale(gl.font_rid, fs);6867bool 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);6868if (!subpos) {6869gl.advance = Math::round(gl.advance);6870gl.x_off = Math::round(gl.x_off);6871}6872found = true;6873break;6874}6875}6876if (!found) {6877gl.font_rid = RID();6878gl.index = p_sd->text[i];6879if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6880gl.advance = get_hex_code_box_size(fs, gl.index).x;6881p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(fs, gl.index).y * 0.85);6882p_sd->descent = MAX(p_sd->descent, get_hex_code_box_size(fs, gl.index).y * 0.15);6883} else {6884gl.advance = get_hex_code_box_size(fs, gl.index).y;6885gl.y_off = get_hex_code_box_size(fs, gl.index).y;6886gl.x_off = -Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5);6887p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5));6888p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5));6889}6890}6891bool zero_w = (p_sd->preserve_control) ? (p_sd->text[i] == 0x200B || p_sd->text[i] == 0xFEFF) : ((p_sd->text[i] >= 0x200B && p_sd->text[i] <= 0x200D) || p_sd->text[i] == 0x2060 || p_sd->text[i] == 0xFEFF);6892if (zero_w) {6893gl.index = 0;6894gl.advance = 0.0;6895}68966897p_sd->width += gl.advance;68986899p_sd->glyphs.push_back(gl);6900}6901}6902return;6903}69046905FontAdvanced *fd = _get_font_data(f);6906ERR_FAIL_NULL(fd);6907MutexLock lock(fd->mutex);6908bool color = false;69096910Vector2i fss = _get_size(fd, fs);6911hb_font_t *hb_font = _font_get_hb_handle(f, fs, color);69126913if (p_script == HB_TAG('Z', 's', 'y', 'e') && !color && _font_is_allow_system_fallback(p_fonts[0])) {6914// Color emoji is requested, skip non-color font.6915_shape_run(p_sd, p_start, p_end, p_language, p_script, p_direction, p_fonts, p_span, p_fb_index + 1, p_start, p_end, f);6916return;6917}69186919double scale = _font_get_scale(f, fs);6920double sp_sp = p_sd->extra_spacing[SPACING_SPACE] + _font_get_spacing(f, SPACING_SPACE);6921double sp_gl = p_sd->extra_spacing[SPACING_GLYPH] + _font_get_spacing(f, SPACING_GLYPH);6922bool last_run = (p_sd->end == p_end);6923double ea = _get_extra_advance(f, fs);6924bool 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);6925ERR_FAIL_NULL(hb_font);69266927hb_buffer_clear_contents(p_sd->hb_buffer);6928hb_buffer_set_direction(p_sd->hb_buffer, p_direction);6929int flags = (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0);6930if (p_sd->preserve_control) {6931flags |= HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES;6932} else {6933flags |= HB_BUFFER_FLAG_DEFAULT;6934}6935#if HB_VERSION_ATLEAST(5, 1, 0)6936flags |= HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL;6937#endif6938hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)flags);6939hb_buffer_set_script(p_sd->hb_buffer, (p_script == HB_TAG('Z', 's', 'y', 'e')) ? HB_SCRIPT_COMMON : p_script);69406941hb_language_t lang = hb_language_from_string(p_language.ascii().get_data(), -1);6942hb_buffer_set_language(p_sd->hb_buffer, lang);69436944hb_buffer_add_utf32(p_sd->hb_buffer, (const uint32_t *)p_sd->text.ptr(), p_sd->text.length(), p_start, p_end - p_start);69456946Vector<hb_feature_t> ftrs;6947_add_features(_font_get_opentype_feature_overrides(f), ftrs);6948_add_features(p_sd->spans[p_span].features, ftrs);69496950hb_shape(hb_font, p_sd->hb_buffer, ftrs.is_empty() ? nullptr : &ftrs[0], ftrs.size());69516952unsigned int glyph_count = 0;6953hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(p_sd->hb_buffer, &glyph_count);6954hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(p_sd->hb_buffer, &glyph_count);69556956int mod = 0;6957if (fd->antialiasing == FONT_ANTIALIASING_LCD) {6958TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();6959if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {6960mod = (layout << 24);6961}6962}69636964// Process glyphs.6965if (glyph_count > 0) {6966Glyph *w = (Glyph *)memalloc(glyph_count * sizeof(Glyph));69676968int end = (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) ? p_end : 0;6969uint32_t last_cluster_id = UINT32_MAX;6970unsigned int last_cluster_index = 0;6971bool last_cluster_valid = true;69726973unsigned int last_non_zero_w = glyph_count - 1;6974if (last_run) {6975for (int64_t i = glyph_count - 1; i >= 0; i--) {6976last_non_zero_w = (unsigned int)i;6977if (p_sd->orientation == ORIENTATION_HORIZONTAL) {6978if (glyph_pos[i].x_advance != 0) {6979break;6980}6981} else {6982if (glyph_pos[i].y_advance != 0) {6983break;6984}6985}6986}6987}69886989bool cache_valid = false;6990RID cached_font_rid = RID();6991int cached_font_size = 0;6992float cached_offset = 0;69936994double adv_rem = 0.0;6995for (unsigned int i = 0; i < glyph_count; i++) {6996if ((i > 0) && (last_cluster_id != glyph_info[i].cluster)) {6997if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {6998end = w[last_cluster_index].start;6999} else {7000for (unsigned int j = last_cluster_index; j < i; j++) {7001w[j].end = glyph_info[i].cluster;7002}7003}7004if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {7005w[last_cluster_index].flags |= GRAPHEME_IS_RTL;7006}7007if (last_cluster_valid) {7008w[last_cluster_index].flags |= GRAPHEME_IS_VALID;7009}7010w[last_cluster_index].count = i - last_cluster_index;7011last_cluster_index = i;7012last_cluster_valid = true;7013}70147015last_cluster_id = glyph_info[i].cluster;70167017Glyph &gl = w[i];7018gl = Glyph();70197020gl.span_index = p_span;7021gl.start = glyph_info[i].cluster;7022gl.end = end;7023gl.count = 0;70247025gl.font_rid = f;7026gl.font_size = fs;70277028if (glyph_info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK) {7029gl.flags |= GRAPHEME_IS_CONNECTED;7030}70317032#if HB_VERSION_ATLEAST(5, 1, 0)7033if (glyph_info[i].mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL) {7034gl.flags |= GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL;7035}7036#endif70377038gl.index = glyph_info[i].codepoint;7039bool zero_w = (p_sd->preserve_control) ? (p_sd->text[glyph_info[i].cluster] == 0x200B || p_sd->text[glyph_info[i].cluster] == 0xFEFF) : ((p_sd->text[glyph_info[i].cluster] >= 0x200B && p_sd->text[glyph_info[i].cluster] <= 0x200D) || p_sd->text[glyph_info[i].cluster] == 0x2060 || p_sd->text[glyph_info[i].cluster] == 0xFEFF);7040if (zero_w) {7041gl.index = 0;7042gl.advance = 0.0;7043}7044if ((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])) {7045adv_rem = 0.0; // Reset on blank.7046}7047if (gl.index != 0) {7048FontGlyph fgl;7049_ensure_glyph(fd, fss, gl.index | mod, fgl);7050if (subpos) {7051gl.x_off = (double)glyph_pos[i].x_offset / (64.0 / scale);7052} else if (p_sd->orientation == ORIENTATION_HORIZONTAL) {7053gl.x_off = Math::round(adv_rem + ((double)glyph_pos[i].x_offset / (64.0 / scale)));7054} else {7055gl.x_off = Math::round((double)glyph_pos[i].x_offset / (64.0 / scale));7056}7057if (p_sd->orientation == ORIENTATION_HORIZONTAL) {7058gl.y_off = -Math::round((double)glyph_pos[i].y_offset / (64.0 / scale));7059} else {7060gl.y_off = -Math::round(adv_rem + ((double)glyph_pos[i].y_offset / (64.0 / scale)));7061}7062if (p_sd->orientation == ORIENTATION_HORIZONTAL) {7063if (subpos) {7064gl.advance = (double)glyph_pos[i].x_advance / (64.0 / scale) + ea;7065} else {7066double full_adv = adv_rem + ((double)glyph_pos[i].x_advance / (64.0 / scale) + ea);7067gl.advance = Math::round(full_adv);7068if (fd->keep_rounding_remainders) {7069adv_rem = full_adv - gl.advance;7070}7071}7072} else {7073double full_adv = adv_rem + ((double)glyph_pos[i].y_advance / (64.0 / scale));7074gl.advance = -Math::round(full_adv);7075if (fd->keep_rounding_remainders) {7076adv_rem = full_adv + gl.advance;7077}7078}7079if (!cache_valid || cached_font_rid != gl.font_rid || cached_font_size != gl.font_size) {7080cache_valid = true;7081cached_font_size = gl.font_size;7082cached_font_rid = gl.font_rid;7083cached_offset = _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));7084}7085if (p_sd->orientation == ORIENTATION_HORIZONTAL) {7086gl.y_off += cached_offset;7087} else {7088gl.x_off += cached_offset;7089}7090}7091if ((!last_run || i < last_non_zero_w) && !Math::is_zero_approx(gl.advance)) {7092// Do not add extra spacing to the last glyph of the string and zero width glyphs.7093if (sp_sp && is_whitespace(p_sd->text[glyph_info[i].cluster])) {7094gl.advance += sp_sp;7095} else {7096gl.advance += sp_gl;7097}7098}70997100if (p_sd->preserve_control) {7101last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || zero_w || (p_sd->text[glyph_info[i].cluster] == 0x0009) || (u_isblank(p_sd->text[glyph_info[i].cluster]) && (gl.advance != 0)) || (!u_isblank(p_sd->text[glyph_info[i].cluster]) && is_linebreak(p_sd->text[glyph_info[i].cluster])));7102} else {7103last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || zero_w || (p_sd->text[glyph_info[i].cluster] == 0x0009) || (u_isblank(p_sd->text[glyph_info[i].cluster]) && (gl.advance != 0)) || (!u_isblank(p_sd->text[glyph_info[i].cluster]) && !u_isgraph(p_sd->text[glyph_info[i].cluster])));7104}7105}7106if (p_direction == HB_DIRECTION_LTR || p_direction == HB_DIRECTION_TTB) {7107for (unsigned int j = last_cluster_index; j < glyph_count; j++) {7108w[j].end = p_end;7109}7110}7111w[last_cluster_index].count = glyph_count - last_cluster_index;7112if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {7113w[last_cluster_index].flags |= GRAPHEME_IS_RTL;7114}7115if (last_cluster_valid) {7116w[last_cluster_index].flags |= GRAPHEME_IS_VALID;7117}71187119// Fallback.7120int failed_subrun_start = p_end + 1;7121int failed_subrun_end = p_start;71227123for (unsigned int i = 0; i < glyph_count; i++) {7124if ((w[i].flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {7125if (failed_subrun_start != p_end + 1) {7126_shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_language, p_script, p_direction, p_fonts, p_span, p_fb_index + 1, p_start, p_end, (p_fb_index >= p_fonts.size()) ? f : RID());7127failed_subrun_start = p_end + 1;7128failed_subrun_end = p_start;7129}7130p_sd->glyphs.reserve(p_sd->glyphs.size() + w[i].count);7131for (int j = 0; j < w[i].count; j++) {7132if (p_sd->orientation == ORIENTATION_HORIZONTAL) {7133p_sd->ascent = MAX(p_sd->ascent, -w[i + j].y_off);7134p_sd->descent = MAX(p_sd->descent, w[i + j].y_off);7135} else {7136double gla = Math::round(_font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5);7137p_sd->ascent = MAX(p_sd->ascent, gla);7138p_sd->descent = MAX(p_sd->descent, gla);7139}7140p_sd->width += w[i + j].advance;7141w[i + j].start += p_sd->start;7142w[i + j].end += p_sd->start;7143p_sd->glyphs.push_back(w[i + j]);7144}7145} else {7146if (failed_subrun_start >= w[i].start) {7147failed_subrun_start = w[i].start;7148}7149if (failed_subrun_end <= w[i].end) {7150failed_subrun_end = w[i].end;7151}7152}7153i += w[i].count - 1;7154}7155memfree(w);7156if (failed_subrun_start != p_end + 1) {7157_shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_language, p_script, p_direction, p_fonts, p_span, p_fb_index + 1, p_start, p_end, (p_fb_index >= p_fonts.size()) ? f : RID());7158}7159p_sd->ascent = MAX(p_sd->ascent, _font_get_ascent(f, fs) + _font_get_spacing(f, SPACING_TOP));7160p_sd->descent = MAX(p_sd->descent, _font_get_descent(f, fs) + _font_get_spacing(f, SPACING_BOTTOM));7161p_sd->upos = MAX(p_sd->upos, _font_get_underline_position(f, fs));7162p_sd->uthk = MAX(p_sd->uthk, _font_get_underline_thickness(f, fs));7163} else if (p_start != p_end) {7164if (p_fb_index >= p_fonts.size()) {7165Glyph gl;7166gl.start = p_start;7167gl.end = p_end;7168gl.span_index = p_span;7169gl.font_rid = f;7170gl.font_size = fs;7171gl.flags = GRAPHEME_IS_VALID;7172p_sd->glyphs.push_back(gl);71737174p_sd->ascent = MAX(p_sd->ascent, _font_get_ascent(f, fs) + _font_get_spacing(f, SPACING_TOP));7175p_sd->descent = MAX(p_sd->descent, _font_get_descent(f, fs) + _font_get_spacing(f, SPACING_BOTTOM));7176p_sd->upos = MAX(p_sd->upos, _font_get_underline_position(f, fs));7177p_sd->uthk = MAX(p_sd->uthk, _font_get_underline_thickness(f, fs));7178} else {7179_shape_run(p_sd, p_start, p_end, p_language, p_script, p_direction, p_fonts, p_span, p_fb_index + 1, p_start, p_end, f);7180}7181}7182}71837184bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {7185_THREAD_SAFE_METHOD_7186ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7187ERR_FAIL_NULL_V(sd, false);71887189MutexLock lock(sd->mutex);7190if (sd->valid.is_set()) {7191return true;7192}71937194invalidate(sd, false);7195if (sd->parent != RID()) {7196_shaped_text_shape(sd->parent);7197ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);7198ERR_FAIL_COND_V(!parent_sd->valid.is_set(), false);7199ERR_FAIL_COND_V(!_shape_substr(sd, parent_sd, sd->start, sd->end - sd->start), false);7200return true;7201}72027203if (sd->text.length() == 0) {7204sd->valid.set();7205return true;7206}72077208const String &project_locale = TranslationServer::get_singleton()->get_tool_locale();72097210sd->utf16 = sd->text.utf16();7211const UChar *data = sd->utf16.get_data();72127213// Create script iterator.7214if (sd->script_iter == nullptr) {7215sd->script_iter = memnew(ScriptIterator(sd->text, 0, sd->text.length()));7216}72177218sd->base_para_direction = UBIDI_DEFAULT_LTR;7219switch (sd->direction) {7220case DIRECTION_LTR: {7221sd->para_direction = DIRECTION_LTR;7222sd->base_para_direction = UBIDI_LTR;7223} break;7224case DIRECTION_RTL: {7225sd->para_direction = DIRECTION_RTL;7226sd->base_para_direction = UBIDI_RTL;7227} break;7228case DIRECTION_INHERITED:7229case DIRECTION_AUTO: {7230UBiDiDirection direction = ubidi_getBaseDirection(data, sd->utf16.length());7231if (direction != UBIDI_NEUTRAL) {7232sd->para_direction = (direction == UBIDI_RTL) ? DIRECTION_RTL : DIRECTION_LTR;7233sd->base_para_direction = direction;7234} else {7235const String &lang = (sd->spans.is_empty() || sd->spans[0].language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : sd->spans[0].language;7236bool lang_rtl = _is_locale_right_to_left(lang);72377238sd->para_direction = lang_rtl ? DIRECTION_RTL : DIRECTION_LTR;7239sd->base_para_direction = lang_rtl ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR;7240}7241} break;7242}72437244Vector<Vector3i> bidi_ranges;7245if (sd->bidi_override.is_empty()) {7246bidi_ranges.push_back(Vector3i(sd->start, sd->end, DIRECTION_INHERITED));7247} else {7248bidi_ranges = sd->bidi_override;7249}7250sd->runs.clear();7251sd->runs_dirty = true;72527253for (int ov = 0; ov < bidi_ranges.size(); ov++) {7254// Create BiDi iterator.7255int start = _convert_pos_inv(sd, bidi_ranges[ov].x - sd->start);7256int end = _convert_pos_inv(sd, bidi_ranges[ov].y - sd->start);72577258if (start < 0 || end - start > sd->utf16.length()) {7259continue;7260}72617262UErrorCode err = U_ZERO_ERROR;7263UBiDi *bidi_iter = ubidi_openSized(end - start, 0, &err);7264if (U_SUCCESS(err)) {7265switch (static_cast<TextServer::Direction>(bidi_ranges[ov].z)) {7266case DIRECTION_LTR: {7267ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err);7268} break;7269case DIRECTION_RTL: {7270ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err);7271} break;7272case DIRECTION_INHERITED: {7273ubidi_setPara(bidi_iter, data + start, end - start, sd->base_para_direction, nullptr, &err);7274} break;7275case DIRECTION_AUTO: {7276UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start);7277if (direction != UBIDI_NEUTRAL) {7278ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);7279} else {7280ubidi_setPara(bidi_iter, data + start, end - start, sd->base_para_direction, nullptr, &err);7281}7282} break;7283}7284if (U_FAILURE(err)) {7285ubidi_close(bidi_iter);7286bidi_iter = nullptr;7287ERR_PRINT(vformat("BiDi reordering for the paragraph failed: %s", u_errorName(err)));7288}7289} else {7290bidi_iter = nullptr;7291ERR_PRINT(vformat("BiDi iterator allocation for the paragraph failed: %s", u_errorName(err)));7292}7293sd->bidi_iter.push_back(bidi_iter);72947295err = U_ZERO_ERROR;7296int bidi_run_count = 1;7297if (bidi_iter) {7298bidi_run_count = ubidi_countRuns(bidi_iter, &err);7299if (U_FAILURE(err)) {7300ERR_PRINT(u_errorName(err));7301}7302}7303for (int i = 0; i < bidi_run_count; i++) {7304int32_t _bidi_run_start = 0;7305int32_t _bidi_run_length = end - start;7306bool is_ltr = false;7307hb_direction_t bidi_run_direction = HB_DIRECTION_INVALID;7308if (bidi_iter) {7309is_ltr = (ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length) == UBIDI_LTR);7310}7311switch (sd->orientation) {7312case ORIENTATION_HORIZONTAL: {7313if (is_ltr) {7314bidi_run_direction = HB_DIRECTION_LTR;7315} else {7316bidi_run_direction = HB_DIRECTION_RTL;7317}7318} break;7319case ORIENTATION_VERTICAL: {7320if (is_ltr) {7321bidi_run_direction = HB_DIRECTION_TTB;7322} else {7323bidi_run_direction = HB_DIRECTION_BTT;7324}7325}7326}73277328int32_t bidi_run_start = _convert_pos(sd, start + _bidi_run_start);7329int32_t bidi_run_end = _convert_pos(sd, start + _bidi_run_start + _bidi_run_length);73307331// Shape runs.73327333int scr_from = (is_ltr) ? 0 : sd->script_iter->script_ranges.size() - 1;7334int scr_to = (is_ltr) ? sd->script_iter->script_ranges.size() : -1;7335int scr_delta = (is_ltr) ? +1 : -1;73367337for (int j = scr_from; j != scr_to; j += scr_delta) {7338if ((sd->script_iter->script_ranges[j].start < bidi_run_end) && (sd->script_iter->script_ranges[j].end > bidi_run_start)) {7339int32_t script_run_start = MAX(sd->script_iter->script_ranges[j].start, bidi_run_start);7340int32_t script_run_end = MIN(sd->script_iter->script_ranges[j].end, bidi_run_end);7341char scr_buffer[5] = { 0, 0, 0, 0, 0 };7342hb_tag_to_string(hb_script_to_iso15924_tag(sd->script_iter->script_ranges[j].script), scr_buffer);7343String script_code = String(scr_buffer);73447345int spn_from = (is_ltr) ? 0 : sd->spans.size() - 1;7346int spn_to = (is_ltr) ? sd->spans.size() : -1;7347int spn_delta = (is_ltr) ? +1 : -1;73487349for (int k = spn_from; k != spn_to; k += spn_delta) {7350const ShapedTextDataAdvanced::Span &span = sd->spans[k];7351int col_key_off = (span.start == span.end) ? 1 : 0;7352if (span.start - sd->start >= script_run_end || span.end - sd->start <= script_run_start - col_key_off) {7353continue;7354}7355if (span.embedded_key != Variant()) {7356// Embedded object.7357if (sd->orientation == ORIENTATION_HORIZONTAL) {7358sd->objects[span.embedded_key].rect.position.x = sd->width;7359sd->width += sd->objects[span.embedded_key].rect.size.x;7360} else {7361sd->objects[span.embedded_key].rect.position.y = sd->width;7362sd->width += sd->objects[span.embedded_key].rect.size.y;7363}7364Glyph gl;7365gl.start = span.start;7366gl.end = span.end;7367gl.count = 1;7368gl.span_index = k;7369gl.flags = GRAPHEME_IS_VALID | GRAPHEME_IS_EMBEDDED_OBJECT;7370if (sd->orientation == ORIENTATION_HORIZONTAL) {7371gl.advance = sd->objects[span.embedded_key].rect.size.x;7372} else {7373gl.advance = sd->objects[span.embedded_key].rect.size.y;7374}7375sd->glyphs.push_back(gl);7376} else {7377// Select best matching language for the run.7378String language = span.language;7379if (!language.contains("force")) {7380if (language.is_empty() || !TranslationServer::get_singleton()->is_script_suppored_by_locale(language, script_code)) {7381language = project_locale;7382if (language.is_empty() || !TranslationServer::get_singleton()->is_script_suppored_by_locale(language, script_code)) {7383language = os_locale;7384}7385}7386}7387FontPriorityList fonts(this, span.fonts, language.left(3).remove_char('_'), script_code, sd->script_iter->script_ranges[j].script == HB_TAG('Z', 's', 'y', 'e'));7388_shape_run(sd, MAX(span.start - sd->start, script_run_start), MIN(span.end - sd->start, script_run_end), language, sd->script_iter->script_ranges[j].script, bidi_run_direction, fonts, k, 0, 0, 0, RID());7389}7390}7391}7392}7393}7394}73957396_realign(sd);7397sd->valid.set();7398return sd->valid.is_set();7399}74007401bool TextServerAdvanced::_shaped_text_is_ready(const RID &p_shaped) const {7402const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7403ERR_FAIL_NULL_V(sd, false);74047405// Atomic read is safe and faster.7406return sd->valid.is_set();7407}74087409const Glyph *TextServerAdvanced::_shaped_text_get_glyphs(const RID &p_shaped) const {7410const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7411ERR_FAIL_NULL_V(sd, nullptr);74127413MutexLock lock(sd->mutex);7414if (!sd->valid.is_set()) {7415const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7416}7417return sd->glyphs.ptr();7418}74197420int64_t TextServerAdvanced::_shaped_text_get_glyph_count(const RID &p_shaped) const {7421const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7422ERR_FAIL_NULL_V(sd, 0);74237424MutexLock lock(sd->mutex);7425if (!sd->valid.is_set()) {7426const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7427}7428return sd->glyphs.size();7429}74307431const Glyph *TextServerAdvanced::_shaped_text_sort_logical(const RID &p_shaped) {7432ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7433ERR_FAIL_NULL_V(sd, nullptr);74347435MutexLock lock(sd->mutex);7436if (!sd->valid.is_set()) {7437_shaped_text_shape(p_shaped);7438}74397440if (!sd->sort_valid) {7441sd->glyphs_logical = sd->glyphs;7442sd->glyphs_logical.sort_custom<GlyphCompare>();7443sd->sort_valid = true;7444}74457446return sd->glyphs_logical.ptr();7447}74487449Vector2i TextServerAdvanced::_shaped_text_get_range(const RID &p_shaped) const {7450const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7451ERR_FAIL_NULL_V(sd, Vector2i());74527453MutexLock lock(sd->mutex);7454return Vector2(sd->start, sd->end);7455}74567457Array TextServerAdvanced::_shaped_text_get_objects(const RID &p_shaped) const {7458Array ret;7459const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7460ERR_FAIL_NULL_V(sd, ret);74617462MutexLock lock(sd->mutex);7463for (const KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : sd->objects) {7464ret.push_back(E.key);7465}74667467return ret;7468}74697470Rect2 TextServerAdvanced::_shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const {7471const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7472ERR_FAIL_NULL_V(sd, Rect2());74737474MutexLock lock(sd->mutex);7475ERR_FAIL_COND_V(!sd->objects.has(p_key), Rect2());7476if (!sd->valid.is_set()) {7477const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7478}7479return sd->objects[p_key].rect;7480}74817482Vector2i TextServerAdvanced::_shaped_text_get_object_range(const RID &p_shaped, const Variant &p_key) const {7483const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7484ERR_FAIL_NULL_V(sd, Vector2i());74857486MutexLock lock(sd->mutex);7487ERR_FAIL_COND_V(!sd->objects.has(p_key), Vector2i());7488return Vector2i(sd->objects[p_key].start, sd->objects[p_key].end);7489}74907491int64_t TextServerAdvanced::_shaped_text_get_object_glyph(const RID &p_shaped, const Variant &p_key) const {7492const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7493ERR_FAIL_NULL_V(sd, -1);74947495MutexLock lock(sd->mutex);7496ERR_FAIL_COND_V(!sd->objects.has(p_key), -1);7497if (!sd->valid.is_set()) {7498const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7499}7500const ShapedTextDataAdvanced::EmbeddedObject &obj = sd->objects[p_key];7501int sd_size = sd->glyphs.size();7502const Glyph *sd_glyphs = sd->glyphs.ptr();7503for (int i = 0; i < sd_size; i++) {7504if (obj.start == sd_glyphs[i].start) {7505return i;7506}7507}7508return -1;7509}75107511Size2 TextServerAdvanced::_shaped_text_get_size(const RID &p_shaped) const {7512const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7513ERR_FAIL_NULL_V(sd, Size2());75147515MutexLock lock(sd->mutex);7516if (!sd->valid.is_set()) {7517const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7518}7519if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) {7520return Size2((sd->text_trimmed ? sd->width_trimmed : sd->width), sd->ascent + sd->descent + sd->extra_spacing[SPACING_TOP] + sd->extra_spacing[SPACING_BOTTOM]).ceil();7521} else {7522return Size2(sd->ascent + sd->descent + sd->extra_spacing[SPACING_TOP] + sd->extra_spacing[SPACING_BOTTOM], (sd->text_trimmed ? sd->width_trimmed : sd->width)).ceil();7523}7524}75257526double TextServerAdvanced::_shaped_text_get_ascent(const RID &p_shaped) const {7527const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7528ERR_FAIL_NULL_V(sd, 0.0);75297530MutexLock lock(sd->mutex);7531if (!sd->valid.is_set()) {7532const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7533}7534return sd->ascent + sd->extra_spacing[SPACING_TOP];7535}75367537double TextServerAdvanced::_shaped_text_get_descent(const RID &p_shaped) const {7538const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7539ERR_FAIL_NULL_V(sd, 0.0);75407541MutexLock lock(sd->mutex);7542if (!sd->valid.is_set()) {7543const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7544}7545return sd->descent + sd->extra_spacing[SPACING_BOTTOM];7546}75477548double TextServerAdvanced::_shaped_text_get_width(const RID &p_shaped) const {7549const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7550ERR_FAIL_NULL_V(sd, 0.0);75517552MutexLock lock(sd->mutex);7553if (!sd->valid.is_set()) {7554const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7555}7556return Math::ceil(sd->text_trimmed ? sd->width_trimmed : sd->width);7557}75587559double TextServerAdvanced::_shaped_text_get_underline_position(const RID &p_shaped) const {7560const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7561ERR_FAIL_NULL_V(sd, 0.0);75627563MutexLock lock(sd->mutex);7564if (!sd->valid.is_set()) {7565const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7566}75677568return sd->upos;7569}75707571double TextServerAdvanced::_shaped_text_get_underline_thickness(const RID &p_shaped) const {7572const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);7573ERR_FAIL_NULL_V(sd, 0.0);75747575MutexLock lock(sd->mutex);7576if (!sd->valid.is_set()) {7577const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);7578}75797580return sd->uthk;7581}75827583int64_t TextServerAdvanced::_is_confusable(const String &p_string, const PackedStringArray &p_dict) const {7584#ifndef ICU_STATIC_DATA7585if (!icu_data_loaded) {7586return -1;7587}7588#endif7589UErrorCode status = U_ZERO_ERROR;7590int64_t match_index = -1;75917592Char16String utf16 = p_string.utf16();7593Vector<UChar *> skeletons;7594skeletons.resize(p_dict.size());75957596if (sc_conf == nullptr) {7597sc_conf = uspoof_open(&status);7598uspoof_setChecks(sc_conf, USPOOF_CONFUSABLE, &status);7599}7600for (int i = 0; i < p_dict.size(); i++) {7601Char16String word = p_dict[i].utf16();7602int32_t len = uspoof_getSkeleton(sc_conf, 0, word.get_data(), -1, nullptr, 0, &status);7603skeletons.write[i] = (UChar *)memalloc(++len * sizeof(UChar));7604status = U_ZERO_ERROR;7605uspoof_getSkeleton(sc_conf, 0, word.get_data(), -1, skeletons.write[i], len, &status);7606}76077608int32_t len = uspoof_getSkeleton(sc_conf, 0, utf16.get_data(), -1, nullptr, 0, &status);7609UChar *skel = (UChar *)memalloc(++len * sizeof(UChar));7610status = U_ZERO_ERROR;7611uspoof_getSkeleton(sc_conf, 0, utf16.get_data(), -1, skel, len, &status);7612for (int i = 0; i < skeletons.size(); i++) {7613if (u_strcmp(skel, skeletons[i]) == 0) {7614match_index = i;7615break;7616}7617}7618memfree(skel);76197620for (int i = 0; i < skeletons.size(); i++) {7621memfree(skeletons.write[i]);7622}76237624ERR_FAIL_COND_V_MSG(U_FAILURE(status), -1, u_errorName(status));76257626return match_index;7627}76287629bool TextServerAdvanced::_spoof_check(const String &p_string) const {7630#ifndef ICU_STATIC_DATA7631if (!icu_data_loaded) {7632return false;7633}7634#endif7635UErrorCode status = U_ZERO_ERROR;7636Char16String utf16 = p_string.utf16();76377638if (allowed == nullptr) {7639allowed = uset_openEmpty();7640uset_addAll(allowed, uspoof_getRecommendedSet(&status));7641uset_addAll(allowed, uspoof_getInclusionSet(&status));7642}7643if (sc_spoof == nullptr) {7644sc_spoof = uspoof_open(&status);7645uspoof_setAllowedChars(sc_spoof, allowed, &status);7646uspoof_setRestrictionLevel(sc_spoof, USPOOF_MODERATELY_RESTRICTIVE);7647}76487649int32_t bitmask = uspoof_check(sc_spoof, utf16.get_data(), -1, nullptr, &status);7650ERR_FAIL_COND_V_MSG(U_FAILURE(status), false, u_errorName(status));76517652return (bitmask != 0);7653}76547655String TextServerAdvanced::_strip_diacritics(const String &p_string) const {7656#ifndef ICU_STATIC_DATA7657if (!icu_data_loaded) {7658return TextServer::strip_diacritics(p_string);7659}7660#endif7661UErrorCode err = U_ZERO_ERROR;76627663// Get NFKD normalizer singleton.7664const UNormalizer2 *unorm = unorm2_getNFKDInstance(&err);7665ERR_FAIL_COND_V_MSG(U_FAILURE(err), TextServer::strip_diacritics(p_string), u_errorName(err));76667667// Convert to UTF-16.7668Char16String utf16 = p_string.utf16();76697670// Normalize.7671Vector<char16_t> normalized;7672err = U_ZERO_ERROR;7673int32_t len = unorm2_normalize(unorm, utf16.get_data(), -1, nullptr, 0, &err);7674ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, TextServer::strip_diacritics(p_string), u_errorName(err));7675normalized.resize(len);7676err = U_ZERO_ERROR;7677unorm2_normalize(unorm, utf16.get_data(), -1, normalized.ptrw(), len, &err);7678ERR_FAIL_COND_V_MSG(U_FAILURE(err), TextServer::strip_diacritics(p_string), u_errorName(err));76797680// Convert back to UTF-32.7681String normalized_string = String::utf16(normalized.ptr(), len);76827683// Strip combining characters.7684String result;7685for (int i = 0; i < normalized_string.length(); i++) {7686if (u_getCombiningClass(normalized_string[i]) == 0) {7687#ifdef GDEXTENSION7688result = result + String::chr(normalized_string[i]);7689#elif defined(GODOT_MODULE)7690result = result + normalized_string[i];7691#endif7692}7693}7694return result;7695}76967697String TextServerAdvanced::_string_to_upper(const String &p_string, const String &p_language) const {7698#ifndef ICU_STATIC_DATA7699if (!icu_data_loaded) {7700return p_string.to_upper();7701}7702#endif77037704if (p_string.is_empty()) {7705return p_string;7706}7707const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;77087709// Convert to UTF-16.7710Char16String utf16 = p_string.utf16();77117712Vector<char16_t> upper;7713UErrorCode err = U_ZERO_ERROR;7714int32_t len = u_strToUpper(nullptr, 0, utf16.get_data(), -1, lang.ascii().get_data(), &err);7715ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));7716upper.resize(len);7717err = U_ZERO_ERROR;7718u_strToUpper(upper.ptrw(), len, utf16.get_data(), -1, lang.ascii().get_data(), &err);7719ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));77207721// Convert back to UTF-32.7722return String::utf16(upper.ptr(), len);7723}77247725String TextServerAdvanced::_string_to_lower(const String &p_string, const String &p_language) const {7726#ifndef ICU_STATIC_DATA7727if (!icu_data_loaded) {7728return p_string.to_lower();7729}7730#endif77317732if (p_string.is_empty()) {7733return p_string;7734}7735const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;7736// Convert to UTF-16.7737Char16String utf16 = p_string.utf16();77387739Vector<char16_t> lower;7740UErrorCode err = U_ZERO_ERROR;7741int32_t len = u_strToLower(nullptr, 0, utf16.get_data(), -1, lang.ascii().get_data(), &err);7742ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));7743lower.resize(len);7744err = U_ZERO_ERROR;7745u_strToLower(lower.ptrw(), len, utf16.get_data(), -1, lang.ascii().get_data(), &err);7746ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));77477748// Convert back to UTF-32.7749return String::utf16(lower.ptr(), len);7750}77517752String TextServerAdvanced::_string_to_title(const String &p_string, const String &p_language) const {7753#ifndef ICU_STATIC_DATA7754if (!icu_data_loaded) {7755return p_string.capitalize();7756}7757#endif77587759if (p_string.is_empty()) {7760return p_string;7761}7762const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;77637764// Convert to UTF-16.7765Char16String utf16 = p_string.utf16();77667767Vector<char16_t> upper;7768UErrorCode err = U_ZERO_ERROR;7769int32_t len = u_strToTitle(nullptr, 0, utf16.get_data(), -1, nullptr, lang.ascii().get_data(), &err);7770ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));7771upper.resize(len);7772err = U_ZERO_ERROR;7773u_strToTitle(upper.ptrw(), len, utf16.get_data(), -1, nullptr, lang.ascii().get_data(), &err);7774ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));77757776// Convert back to UTF-32.7777return String::utf16(upper.ptr(), len);7778}77797780PackedInt32Array TextServerAdvanced::_string_get_word_breaks(const String &p_string, const String &p_language, int64_t p_chars_per_line) const {7781const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;7782// Convert to UTF-16.7783Char16String utf16 = p_string.utf16();77847785HashSet<int> breaks;7786UErrorCode err = U_ZERO_ERROR;7787UBreakIterator *bi = ubrk_open(UBRK_WORD, lang.ascii().get_data(), (const UChar *)utf16.get_data(), utf16.length(), &err);7788if (U_SUCCESS(err)) {7789while (ubrk_next(bi) != UBRK_DONE) {7790int pos = _convert_pos(p_string, utf16, ubrk_current(bi));7791if (pos != p_string.length() - 1) {7792breaks.insert(pos);7793}7794}7795ubrk_close(bi);7796}77977798PackedInt32Array ret;77997800if (p_chars_per_line > 0) {7801int line_start = 0;7802int last_break = -1;7803int line_length = 0;78047805for (int i = 0; i < p_string.length(); i++) {7806const char32_t c = p_string[i];78077808bool is_lb = is_linebreak(c);7809bool is_ws = is_whitespace(c);7810bool is_p = (u_ispunct(c) && c != 0x005F) || is_underscore(c) || c == '\t' || c == 0xfffc;78117812if (is_lb) {7813if (line_length > 0) {7814ret.push_back(line_start);7815ret.push_back(i);7816}7817line_start = i;7818line_length = 0;7819last_break = -1;7820continue;7821} else if (breaks.has(i) || is_ws || is_p) {7822last_break = i;7823}78247825if (line_length == p_chars_per_line) {7826if (last_break != -1) {7827int last_break_w_spaces = last_break;7828while (last_break > line_start && is_whitespace(p_string[last_break - 1])) {7829last_break--;7830}7831if (line_start != last_break) {7832ret.push_back(line_start);7833ret.push_back(last_break);7834}7835while (last_break_w_spaces < p_string.length() && is_whitespace(p_string[last_break_w_spaces])) {7836last_break_w_spaces++;7837}7838line_start = last_break_w_spaces;7839if (last_break_w_spaces < i) {7840line_length = i - last_break_w_spaces;7841} else {7842i = last_break_w_spaces;7843line_length = 0;7844}7845} else {7846ret.push_back(line_start);7847ret.push_back(i);7848line_start = i;7849line_length = 0;7850}7851last_break = -1;7852}7853line_length++;7854}7855if (line_length > 0) {7856ret.push_back(line_start);7857ret.push_back(p_string.length());7858}7859} else {7860int word_start = 0; // -1 if no word encountered. Leading spaces are part of a word.7861int word_length = 0;78627863for (int i = 0; i < p_string.length(); i++) {7864const char32_t c = p_string[i];78657866bool is_lb = is_linebreak(c);7867bool is_ws = is_whitespace(c);7868bool is_p = (u_ispunct(c) && c != 0x005F) || is_underscore(c) || c == '\t' || c == 0xfffc;78697870if (word_start == -1) {7871if (!is_lb && !is_ws && !is_p) {7872word_start = i;7873}7874continue;7875}78767877if (is_lb) {7878if (word_start != -1 && word_length > 0) {7879ret.push_back(word_start);7880ret.push_back(i);7881}7882word_start = -1;7883word_length = 0;7884} else if (breaks.has(i) || is_ws || is_p) {7885if (word_start != -1 && word_length > 0) {7886ret.push_back(word_start);7887ret.push_back(i);7888}7889if (is_ws || is_p) {7890word_start = -1;7891} else {7892word_start = i;7893}7894word_length = 0;7895}78967897word_length++;7898}7899if (word_start != -1 && word_length > 0) {7900ret.push_back(word_start);7901ret.push_back(p_string.length());7902}7903}79047905return ret;7906}79077908PackedInt32Array TextServerAdvanced::_string_get_character_breaks(const String &p_string, const String &p_language) const {7909const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;7910// Convert to UTF-16.7911Char16String utf16 = p_string.utf16();79127913PackedInt32Array ret;79147915UErrorCode err = U_ZERO_ERROR;7916UBreakIterator *bi = ubrk_open(UBRK_CHARACTER, lang.ascii().get_data(), (const UChar *)utf16.get_data(), utf16.length(), &err);7917if (U_SUCCESS(err)) {7918while (ubrk_next(bi) != UBRK_DONE) {7919int pos = _convert_pos(p_string, utf16, ubrk_current(bi));7920ret.push_back(pos);7921}7922ubrk_close(bi);7923} else {7924return TextServer::string_get_character_breaks(p_string, p_language);7925}79267927return ret;7928}79297930bool TextServerAdvanced::_is_valid_identifier(const String &p_string) const {7931#ifndef ICU_STATIC_DATA7932if (!icu_data_loaded) {7933WARN_PRINT_ONCE("ICU data is not loaded, Unicode security and spoofing detection disabled.");7934return TextServer::is_valid_identifier(p_string);7935}7936#endif79377938enum UAX31SequenceStatus {7939SEQ_NOT_STARTED,7940SEQ_STARTED,7941SEQ_STARTED_VIR,7942SEQ_NEAR_END,7943};79447945const char32_t *str = p_string.ptr();7946int len = p_string.length();79477948if (len == 0) {7949return false; // Empty string.7950}79517952UErrorCode err = U_ZERO_ERROR;7953Char16String utf16 = p_string.utf16();7954const UNormalizer2 *norm_c = unorm2_getNFCInstance(&err);7955if (U_FAILURE(err)) {7956return false; // Failed to load normalizer.7957}7958bool isnurom = unorm2_isNormalized(norm_c, utf16.get_data(), utf16.length(), &err);7959if (U_FAILURE(err) || !isnurom) {7960return false; // Do not conform to Normalization Form C.7961}79627963UAX31SequenceStatus A1_sequence_status = SEQ_NOT_STARTED;7964UScriptCode A1_scr = USCRIPT_INHERITED;7965UAX31SequenceStatus A2_sequence_status = SEQ_NOT_STARTED;7966UScriptCode A2_scr = USCRIPT_INHERITED;7967UAX31SequenceStatus B_sequence_status = SEQ_NOT_STARTED;7968UScriptCode B_scr = USCRIPT_INHERITED;79697970for (int i = 0; i < len; i++) {7971err = U_ZERO_ERROR;7972UScriptCode scr = uscript_getScript(str[i], &err);7973if (U_FAILURE(err)) {7974return false; // Invalid script.7975}7976if (uscript_getUsage(scr) != USCRIPT_USAGE_RECOMMENDED) {7977return false; // Not a recommended script.7978}7979uint8_t cat = u_charType(str[i]);7980int32_t jt = u_getIntPropertyValue(str[i], UCHAR_JOINING_TYPE);79817982// UAX #31 section 2.3 subsections A1, A2 and B, check ZWNJ and ZWJ usage.7983switch (A1_sequence_status) {7984case SEQ_NEAR_END: {7985if ((A1_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A1_scr)) {7986return false; // Mixed script.7987}7988if (jt == U_JT_RIGHT_JOINING || jt == U_JT_DUAL_JOINING) {7989A1_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.7990} else if (jt != U_JT_TRANSPARENT) {7991return false; // Invalid end of sequence.7992}7993} break;7994case SEQ_STARTED: {7995if ((A1_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A1_scr)) {7996A1_sequence_status = SEQ_NOT_STARTED; // Reset.7997} else {7998if (jt != U_JT_TRANSPARENT) {7999if (str[i] == 0x200C /*ZWNJ*/) {8000A1_sequence_status = SEQ_NEAR_END;8001continue;8002} else {8003A1_sequence_status = SEQ_NOT_STARTED; // Reset.8004}8005}8006}8007} break;8008default:8009break;8010}8011if (A1_sequence_status == SEQ_NOT_STARTED) {8012if (jt == U_JT_LEFT_JOINING || jt == U_JT_DUAL_JOINING) {8013A1_sequence_status = SEQ_STARTED;8014A1_scr = scr;8015}8016};80178018switch (A2_sequence_status) {8019case SEQ_NEAR_END: {8020if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {8021return false; // Mixed script.8022}8023if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {8024A2_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.8025} else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {8026return false; // Invalid end of sequence.8027}8028} break;8029case SEQ_STARTED_VIR: {8030if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {8031A2_sequence_status = SEQ_NOT_STARTED; // Reset.8032} else {8033if (str[i] == 0x200C /*ZWNJ*/) {8034A2_sequence_status = SEQ_NEAR_END;8035continue;8036} else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {8037A2_sequence_status = SEQ_NOT_STARTED; // Reset.8038}8039}8040} break;8041case SEQ_STARTED: {8042if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {8043A2_sequence_status = SEQ_NOT_STARTED; // Reset.8044} else {8045if (u_getCombiningClass(str[i]) == 9 /*Virama Combining Class*/) {8046A2_sequence_status = SEQ_STARTED_VIR;8047} else if (cat != U_MODIFIER_LETTER) {8048A2_sequence_status = SEQ_NOT_STARTED; // Reset.8049}8050}8051} break;8052default:8053break;8054}8055if (A2_sequence_status == SEQ_NOT_STARTED) {8056if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {8057A2_sequence_status = SEQ_STARTED;8058A2_scr = scr;8059}8060}80618062switch (B_sequence_status) {8063case SEQ_NEAR_END: {8064if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {8065return false; // Mixed script.8066}8067if (u_getIntPropertyValue(str[i], UCHAR_INDIC_SYLLABIC_CATEGORY) != U_INSC_VOWEL_DEPENDENT) {8068B_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.8069} else {8070return false; // Invalid end of sequence.8071}8072} break;8073case SEQ_STARTED_VIR: {8074if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {8075B_sequence_status = SEQ_NOT_STARTED; // Reset.8076} else {8077if (str[i] == 0x200D /*ZWJ*/) {8078B_sequence_status = SEQ_NEAR_END;8079continue;8080} else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {8081B_sequence_status = SEQ_NOT_STARTED; // Reset.8082}8083}8084} break;8085case SEQ_STARTED: {8086if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {8087B_sequence_status = SEQ_NOT_STARTED; // Reset.8088} else {8089if (u_getCombiningClass(str[i]) == 9 /*Virama Combining Class*/) {8090B_sequence_status = SEQ_STARTED_VIR;8091} else if (cat != U_MODIFIER_LETTER) {8092B_sequence_status = SEQ_NOT_STARTED; // Reset.8093}8094}8095} break;8096default:8097break;8098}8099if (B_sequence_status == SEQ_NOT_STARTED) {8100if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {8101B_sequence_status = SEQ_STARTED;8102B_scr = scr;8103}8104}81058106if (u_hasBinaryProperty(str[i], UCHAR_PATTERN_SYNTAX) || u_hasBinaryProperty(str[i], UCHAR_PATTERN_WHITE_SPACE) || u_hasBinaryProperty(str[i], UCHAR_NONCHARACTER_CODE_POINT)) {8107return false; // Not a XID_Start or XID_Continue character.8108}8109if (i == 0) {8110if (!(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)) {8111return false; // Not a XID_Start character.8112}8113} else {8114if (!(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)) {8115return false; // Not a XID_Continue character.8116}8117}8118}8119return true;8120}81218122bool TextServerAdvanced::_is_valid_letter(uint64_t p_unicode) const {8123#ifndef ICU_STATIC_DATA8124if (!icu_data_loaded) {8125return TextServer::is_valid_letter(p_unicode);8126}8127#endif81288129return u_isalpha(p_unicode);8130}81318132void TextServerAdvanced::_update_settings() {8133lcd_subpixel_layout.set((TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"));8134lb_strictness = (LineBreakStrictness)(int)GLOBAL_GET("internationalization/locale/line_breaking_strictness");8135}81368137TextServerAdvanced::TextServerAdvanced() {8138os_locale = OS::get_singleton()->get_locale();81398140_insert_feature_sets();8141_bmp_create_font_funcs();8142_update_settings();8143ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &TextServerAdvanced::_update_settings));8144}81458146void TextServerAdvanced::_font_clear_system_fallback_cache() {8147_THREAD_SAFE_METHOD_8148for (const KeyValue<SystemFontKey, SystemFontCache> &E : system_fonts) {8149const Vector<SystemFontCacheRec> &sysf_cache = E.value.var;8150for (const SystemFontCacheRec &F : sysf_cache) {8151_free_rid(F.rid);8152}8153}8154system_fonts.clear();8155system_font_data.clear();8156}81578158void TextServerAdvanced::_cleanup() {8159font_clear_system_fallback_cache();8160}81618162TextServerAdvanced::~TextServerAdvanced() {8163_bmp_free_font_funcs();8164#ifdef MODULE_FREETYPE_ENABLED8165if (ft_library != nullptr) {8166FT_Done_FreeType(ft_library);8167}8168#endif8169if (sc_spoof != nullptr) {8170uspoof_close(sc_spoof);8171sc_spoof = nullptr;8172}8173if (sc_conf != nullptr) {8174uspoof_close(sc_conf);8175sc_conf = nullptr;8176}8177if (allowed != nullptr) {8178uset_close(allowed);8179allowed = nullptr;8180}8181for (const KeyValue<String, UBreakIterator *> &bi : line_break_iterators_per_language) {8182ubrk_close(bi.value);8183}81848185std::atexit(u_cleanup);8186}818781888189