Path: blob/master/modules/text_server_fb/text_server_fb.cpp
11352 views
/**************************************************************************/1/* text_server_fb.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_fb.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>4142#define OT_TAG(m_c1, m_c2, m_c3, m_c4) ((int32_t)((((uint32_t)(m_c1) & 0xff) << 24) | (((uint32_t)(m_c2) & 0xff) << 16) | (((uint32_t)(m_c3) & 0xff) << 8) | ((uint32_t)(m_c4) & 0xff)))4344using namespace godot;4546#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var)4748#elif defined(GODOT_MODULE)49// Headers for building as built-in module.5051#include "core/config/project_settings.h"52#include "core/error/error_macros.h"53#include "core/io/file_access.h"54#include "core/string/print_string.h"55#include "core/string/translation_server.h"5657#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg.5859#endif6061// Thirdparty headers.6263#ifdef MODULE_MSDFGEN_ENABLED64#include <core/EdgeHolder.h>65#include <core/ShapeDistanceFinder.h>66#include <core/contour-combiners.h>67#include <core/edge-selectors.h>68#include <msdfgen.h>69#endif7071#ifdef MODULE_FREETYPE_ENABLED72#include FT_SFNT_NAMES_H73#include FT_TRUETYPE_IDS_H74#ifdef MODULE_SVG_ENABLED75#include "thorvg_svg_in_ot.h"76#endif77#endif7879/*************************************************************************/8081bool TextServerFallback::_has_feature(Feature p_feature) const {82switch (p_feature) {83case FEATURE_SIMPLE_LAYOUT:84case FEATURE_FONT_BITMAP:85#ifdef MODULE_FREETYPE_ENABLED86case FEATURE_FONT_DYNAMIC:87#endif88#ifdef MODULE_MSDFGEN_ENABLED89case FEATURE_FONT_MSDF:90#endif91return true;92default: {93}94}95return false;96}9798String TextServerFallback::_get_name() const {99#ifdef GDEXTENSION100return "Fallback (GDExtension)";101#elif defined(GODOT_MODULE)102return "Fallback (Built-in)";103#endif104}105106int64_t TextServerFallback::_get_features() const {107int64_t interface_features = FEATURE_SIMPLE_LAYOUT | FEATURE_FONT_BITMAP;108#ifdef MODULE_FREETYPE_ENABLED109interface_features |= FEATURE_FONT_DYNAMIC;110#endif111#ifdef MODULE_MSDFGEN_ENABLED112interface_features |= FEATURE_FONT_MSDF;113#endif114115return interface_features;116}117118void TextServerFallback::_free_rid(const RID &p_rid) {119_THREAD_SAFE_METHOD_120if (font_owner.owns(p_rid)) {121MutexLock ftlock(ft_mutex);122123FontFallback *fd = font_owner.get_or_null(p_rid);124for (const KeyValue<Vector2i, FontForSizeFallback *> &ffsd : fd->cache) {125OversamplingLevel *ol = oversampling_levels.getptr(ffsd.value->viewport_oversampling);126if (ol != nullptr) {127ol->fonts.erase(ffsd.value);128}129}130{131MutexLock lock(fd->mutex);132font_owner.free(p_rid);133}134memdelete(fd);135} else if (font_var_owner.owns(p_rid)) {136MutexLock ftlock(ft_mutex);137138FontFallbackLinkedVariation *fdv = font_var_owner.get_or_null(p_rid);139{140font_var_owner.free(p_rid);141}142memdelete(fdv);143} else if (shaped_owner.owns(p_rid)) {144ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_rid);145{146MutexLock lock(sd->mutex);147shaped_owner.free(p_rid);148}149memdelete(sd);150}151}152153bool TextServerFallback::_has(const RID &p_rid) {154_THREAD_SAFE_METHOD_155return font_owner.owns(p_rid) || shaped_owner.owns(p_rid);156}157158String TextServerFallback::_get_support_data_filename() const {159return "";160}161162String TextServerFallback::_get_support_data_info() const {163return "Not supported";164}165166bool TextServerFallback::_load_support_data(const String &p_filename) {167return false; // No extra data used.168}169170bool TextServerFallback::_save_support_data(const String &p_filename) const {171return false; // No extra data used.172}173174PackedByteArray TextServerFallback::_get_support_data() const {175return PackedByteArray(); // No extra data used.176}177178bool TextServerFallback::_is_locale_right_to_left(const String &p_locale) const {179return false; // No RTL support.180}181182_FORCE_INLINE_ void TextServerFallback::_insert_feature(const StringName &p_name, int32_t p_tag) {183feature_sets.insert(p_name, p_tag);184feature_sets_inv.insert(p_tag, p_name);185}186187void TextServerFallback::_insert_feature_sets() {188// Registered OpenType variation tag.189_insert_feature("italic", OT_TAG('i', 't', 'a', 'l'));190_insert_feature("optical_size", OT_TAG('o', 'p', 's', 'z'));191_insert_feature("slant", OT_TAG('s', 'l', 'n', 't'));192_insert_feature("width", OT_TAG('w', 'd', 't', 'h'));193_insert_feature("weight", OT_TAG('w', 'g', 'h', 't'));194}195196_FORCE_INLINE_ int32_t ot_tag_from_string(const char *p_str, int p_len) {197char tag[4];198uint32_t i;199200if (!p_str || !p_len || !*p_str) {201return OT_TAG(0, 0, 0, 0);202}203204if (p_len < 0 || p_len > 4) {205p_len = 4;206}207for (i = 0; i < (uint32_t)p_len && p_str[i]; i++) {208tag[i] = p_str[i];209}210211for (; i < 4; i++) {212tag[i] = ' ';213}214215return OT_TAG(tag[0], tag[1], tag[2], tag[3]);216}217218int64_t TextServerFallback::_name_to_tag(const String &p_name) const {219if (feature_sets.has(p_name)) {220return feature_sets[p_name];221}222223// No readable name, use tag string.224return ot_tag_from_string(p_name.replace("custom_", "").ascii().get_data(), -1);225}226227_FORCE_INLINE_ void ot_tag_to_string(int32_t p_tag, char *p_buf) {228p_buf[0] = (char)(uint8_t)(p_tag >> 24);229p_buf[1] = (char)(uint8_t)(p_tag >> 16);230p_buf[2] = (char)(uint8_t)(p_tag >> 8);231p_buf[3] = (char)(uint8_t)(p_tag >> 0);232}233234String TextServerFallback::_tag_to_name(int64_t p_tag) const {235if (feature_sets_inv.has(p_tag)) {236return feature_sets_inv[p_tag];237}238239// No readable name, use tag string.240char name[5];241memset(name, 0, 5);242ot_tag_to_string(p_tag, name);243return String("custom_") + String(name);244}245246/*************************************************************************/247/* Font Glyph Rendering */248/*************************************************************************/249250_FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_texture_pos_for_glyph(FontForSizeFallback *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height, bool p_msdf) const {251FontTexturePosition ret;252253int mw = p_width;254int mh = p_height;255256ShelfPackTexture *ct = p_data->textures.ptrw();257for (int32_t i = 0; i < p_data->textures.size(); i++) {258if (ct[i].image.is_null()) {259continue;260}261if (p_image_format != ct[i].image->get_format()) {262continue;263}264if (mw > ct[i].texture_w || mh > ct[i].texture_h) { // Too big for this texture.265continue;266}267268ret = ct[i].pack_rect(i, mh, mw);269if (ret.index != -1) {270break;271}272}273274if (ret.index == -1) {275// Could not find texture to fit, create one.276int texsize = MAX(p_data->size.x * 0.125, 256);277278texsize = next_power_of_2((uint32_t)texsize);279280if (p_msdf) {281texsize = MIN(texsize, 2048);282} else {283texsize = MIN(texsize, 1024);284}285if (mw > texsize) { // Special case, adapt to it?286texsize = next_power_of_2((uint32_t)mw);287}288if (mh > texsize) { // Special case, adapt to it?289texsize = next_power_of_2((uint32_t)mh);290}291292ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);293tex.image = Image::create_empty(texsize, texsize, false, p_image_format);294{295// Zero texture.296uint8_t *w = tex.image->ptrw();297ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.image->get_data_size(), ret);298// Initialize the texture to all-white pixels to prevent artifacts when the299// font is displayed at a non-default scale with filtering enabled.300if (p_color_size == 2) {301for (int i = 0; i < texsize * texsize * p_color_size; i += 2) { // FORMAT_LA8, BW font.302w[i + 0] = 255;303w[i + 1] = 0;304}305} else if (p_color_size == 4) {306for (int i = 0; i < texsize * texsize * p_color_size; i += 4) { // FORMAT_RGBA8, Color font, Multichannel(+True) SDF.307if (p_msdf) {308w[i + 0] = 0;309w[i + 1] = 0;310w[i + 2] = 0;311} else {312w[i + 0] = 255;313w[i + 1] = 255;314w[i + 2] = 255;315}316w[i + 3] = 0;317}318} else {319ERR_FAIL_V(ret);320}321}322p_data->textures.push_back(tex);323324int32_t idx = p_data->textures.size() - 1;325ret = p_data->textures.write[idx].pack_rect(idx, mh, mw);326}327328return ret;329}330331#ifdef MODULE_MSDFGEN_ENABLED332333struct MSContext {334msdfgen::Point2 position;335msdfgen::Shape *shape = nullptr;336msdfgen::Contour *contour = nullptr;337};338339class DistancePixelConversion {340double invRange;341342public:343_FORCE_INLINE_ explicit DistancePixelConversion(double range) :344invRange(1 / range) {}345_FORCE_INLINE_ void operator()(float *pixels, const msdfgen::MultiAndTrueDistance &distance) const {346pixels[0] = float(invRange * distance.r + .5);347pixels[1] = float(invRange * distance.g + .5);348pixels[2] = float(invRange * distance.b + .5);349pixels[3] = float(invRange * distance.a + .5);350}351};352353struct MSDFThreadData {354msdfgen::Bitmap<float, 4> *output;355msdfgen::Shape *shape;356msdfgen::Projection *projection;357DistancePixelConversion *distancePixelConversion;358};359360static msdfgen::Point2 ft_point2(const FT_Vector &vector) {361return msdfgen::Point2(vector.x / 60.0f, vector.y / 60.0f);362}363364static int ft_move_to(const FT_Vector *to, void *user) {365MSContext *context = static_cast<MSContext *>(user);366if (!(context->contour && context->contour->edges.empty())) {367context->contour = &context->shape->addContour();368}369context->position = ft_point2(*to);370return 0;371}372373static int ft_line_to(const FT_Vector *to, void *user) {374MSContext *context = static_cast<MSContext *>(user);375msdfgen::Point2 endpoint = ft_point2(*to);376if (endpoint != context->position) {377context->contour->addEdge(new msdfgen::LinearSegment(context->position, endpoint));378context->position = endpoint;379}380return 0;381}382383static int ft_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) {384MSContext *context = static_cast<MSContext *>(user);385context->contour->addEdge(new msdfgen::QuadraticSegment(context->position, ft_point2(*control), ft_point2(*to)));386context->position = ft_point2(*to);387return 0;388}389390static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) {391MSContext *context = static_cast<MSContext *>(user);392context->contour->addEdge(new msdfgen::CubicSegment(context->position, ft_point2(*control1), ft_point2(*control2), ft_point2(*to)));393context->position = ft_point2(*to);394return 0;395}396397void TextServerFallback::_generateMTSDF_threaded(void *p_td, uint32_t p_y) {398MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td);399400msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape);401int row = td->shape->inverseYAxis ? td->output->height() - p_y - 1 : p_y;402for (int col = 0; col < td->output->width(); ++col) {403int x = (p_y % 2) ? td->output->width() - col - 1 : col;404msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, p_y + .5));405msdfgen::MultiAndTrueDistance distance = distanceFinder.distance(p);406td->distancePixelConversion->operator()(td->output->operator()(x, row), distance);407}408}409410_FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(FontFallback *p_font_data, FontForSizeFallback *p_data, int p_pixel_range, int p_rect_margin, FT_Outline *p_outline, const Vector2 &p_advance) const {411msdfgen::Shape shape;412413shape.contours.clear();414shape.inverseYAxis = false;415416MSContext context = {};417context.shape = &shape;418FT_Outline_Funcs ft_functions;419ft_functions.move_to = &ft_move_to;420ft_functions.line_to = &ft_line_to;421ft_functions.conic_to = &ft_conic_to;422ft_functions.cubic_to = &ft_cubic_to;423ft_functions.shift = 0;424ft_functions.delta = 0;425426int error = FT_Outline_Decompose(p_outline, &ft_functions, &context);427ERR_FAIL_COND_V_MSG(error, FontGlyph(), "FreeType: Outline decomposition error: '" + String(FT_Error_String(error)) + "'.");428if (!shape.contours.empty() && shape.contours.back().edges.empty()) {429shape.contours.pop_back();430}431432if (FT_Outline_Get_Orientation(p_outline) == 1) {433for (int i = 0; i < (int)shape.contours.size(); ++i) {434shape.contours[i].reverse();435}436}437438shape.inverseYAxis = true;439shape.normalize();440441msdfgen::Shape::Bounds bounds = shape.getBounds(p_pixel_range);442443FontGlyph chr;444chr.found = true;445chr.advance = p_advance;446447if (shape.validate() && shape.contours.size() > 0) {448int w = (bounds.r - bounds.l);449int h = (bounds.t - bounds.b);450451if (w == 0 || h == 0) {452chr.texture_idx = -1;453chr.uv_rect = Rect2();454chr.rect = Rect2();455return chr;456}457int mw = w + p_rect_margin * 4;458int mh = h + p_rect_margin * 4;459460ERR_FAIL_COND_V(mw > 4096, FontGlyph());461ERR_FAIL_COND_V(mh > 4096, FontGlyph());462463FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true);464ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());465ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];466467edgeColoringSimple(shape, 3.0); // Max. angle.468msdfgen::Bitmap<float, 4> image(w, h); // Texture size.469470DistancePixelConversion distancePixelConversion(p_pixel_range);471msdfgen::Projection projection(msdfgen::Vector2(1.0, 1.0), msdfgen::Vector2(-bounds.l, -bounds.b));472msdfgen::MSDFGeneratorConfig config(true, msdfgen::ErrorCorrectionConfig());473474MSDFThreadData td;475td.output = ℑ476td.shape = &shape;477td.projection = &projection;478td.distancePixelConversion = &distancePixelConversion;479480WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_native_group_task(&TextServerFallback::_generateMTSDF_threaded, &td, h, -1, true, String("TextServerFBRenderMSDF"));481WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);482483msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config);484485{486uint8_t *wr = tex.image->ptrw();487488for (int i = 0; i < h; i++) {489for (int j = 0; j < w; j++) {490int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * 4;491ERR_FAIL_COND_V(ofs >= tex.image->get_data_size(), FontGlyph());492wr[ofs + 0] = (uint8_t)(CLAMP(image(j, i)[0] * 256.f, 0.f, 255.f));493wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f));494wr[ofs + 2] = (uint8_t)(CLAMP(image(j, i)[2] * 256.f, 0.f, 255.f));495wr[ofs + 3] = (uint8_t)(CLAMP(image(j, i)[3] * 256.f, 0.f, 255.f));496}497}498}499500tex.dirty = true;501502chr.texture_idx = tex_pos.index;503504chr.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);505chr.rect.position = Vector2(bounds.l - p_rect_margin, -bounds.t - p_rect_margin);506chr.rect.size = chr.uv_rect.size;507}508return chr;509}510#endif511512#ifdef MODULE_FREETYPE_ENABLED513_FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitmap(FontForSizeFallback *p_data, int p_rect_margin, FT_Bitmap p_bitmap, int p_yofs, int p_xofs, const Vector2 &p_advance, bool p_bgra) const {514FontGlyph chr;515chr.advance = p_advance * p_data->scale;516chr.found = true;517518int w = p_bitmap.width;519int h = p_bitmap.rows;520521if (w == 0 || h == 0) {522chr.texture_idx = -1;523chr.uv_rect = Rect2();524chr.rect = Rect2();525return chr;526}527528int color_size = 2;529530switch (p_bitmap.pixel_mode) {531case FT_PIXEL_MODE_MONO:532case FT_PIXEL_MODE_GRAY: {533color_size = 2;534} break;535case FT_PIXEL_MODE_BGRA: {536color_size = 4;537} break;538case FT_PIXEL_MODE_LCD: {539color_size = 4;540w /= 3;541} break;542case FT_PIXEL_MODE_LCD_V: {543color_size = 4;544h /= 3;545} break;546}547548int mw = w + p_rect_margin * 4;549int mh = h + p_rect_margin * 4;550551ERR_FAIL_COND_V(mw > 4096, FontGlyph());552ERR_FAIL_COND_V(mh > 4096, FontGlyph());553554Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;555556FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh, false);557ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());558559// Fit character in char texture.560ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];561562{563uint8_t *wr = tex.image->ptrw();564565for (int i = 0; i < h; i++) {566for (int j = 0; j < w; j++) {567int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * color_size;568ERR_FAIL_COND_V(ofs >= tex.image->get_data_size(), FontGlyph());569switch (p_bitmap.pixel_mode) {570case FT_PIXEL_MODE_MONO: {571int byte = i * p_bitmap.pitch + (j >> 3);572int bit = 1 << (7 - (j % 8));573wr[ofs + 0] = 255; // grayscale as 1574wr[ofs + 1] = (p_bitmap.buffer[byte] & bit) ? 255 : 0;575} break;576case FT_PIXEL_MODE_GRAY:577wr[ofs + 0] = 255; // grayscale as 1578wr[ofs + 1] = p_bitmap.buffer[i * p_bitmap.pitch + j];579break;580case FT_PIXEL_MODE_BGRA: {581int ofs_color = i * p_bitmap.pitch + (j << 2);582wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];583wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];584wr[ofs + 0] = p_bitmap.buffer[ofs_color + 2];585wr[ofs + 3] = p_bitmap.buffer[ofs_color + 3];586} break;587case FT_PIXEL_MODE_LCD: {588int ofs_color = i * p_bitmap.pitch + (j * 3);589if (p_bgra) {590wr[ofs + 0] = p_bitmap.buffer[ofs_color + 2];591wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];592wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];593wr[ofs + 3] = 255;594} else {595wr[ofs + 0] = p_bitmap.buffer[ofs_color + 0];596wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];597wr[ofs + 2] = p_bitmap.buffer[ofs_color + 2];598wr[ofs + 3] = 255;599}600} break;601case FT_PIXEL_MODE_LCD_V: {602int ofs_color = i * p_bitmap.pitch * 3 + j;603if (p_bgra) {604wr[ofs + 0] = p_bitmap.buffer[ofs_color + p_bitmap.pitch * 2];605wr[ofs + 1] = p_bitmap.buffer[ofs_color + p_bitmap.pitch];606wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];607wr[ofs + 3] = 255;608} else {609wr[ofs + 0] = p_bitmap.buffer[ofs_color + 0];610wr[ofs + 1] = p_bitmap.buffer[ofs_color + p_bitmap.pitch];611wr[ofs + 2] = p_bitmap.buffer[ofs_color + p_bitmap.pitch * 2];612wr[ofs + 3] = 255;613}614} break;615default:616ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + String::num_int64(p_bitmap.pixel_mode) + ".");617break;618}619}620}621}622623tex.dirty = true;624625chr.texture_idx = tex_pos.index;626627chr.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);628chr.rect.position = Vector2(p_xofs - p_rect_margin, -p_yofs - p_rect_margin) * p_data->scale;629chr.rect.size = chr.uv_rect.size * p_data->scale;630return chr;631}632#endif633634/*************************************************************************/635/* Font Cache */636/*************************************************************************/637638bool TextServerFallback::_ensure_glyph(FontFallback *p_font_data, const Vector2i &p_size, int32_t p_glyph, FontGlyph &r_glyph, uint32_t p_oversampling) const {639FontForSizeFallback *fd = nullptr;640ERR_FAIL_COND_V(!_ensure_cache_for_size(p_font_data, p_size, fd, false, p_oversampling), false);641642int32_t glyph_index = p_glyph & 0xffffff; // Remove subpixel shifts.643644HashMap<int32_t, FontGlyph>::Iterator E = fd->glyph_map.find(p_glyph);645if (E) {646r_glyph = E->value;647return E->value.found;648}649650if (glyph_index == 0) { // Non graphical or invalid glyph, do not render.651E = fd->glyph_map.insert(p_glyph, FontGlyph());652r_glyph = E->value;653return true;654}655656#ifdef MODULE_FREETYPE_ENABLED657FontGlyph gl;658if (fd->face) {659FT_Int32 flags = FT_LOAD_DEFAULT;660661bool outline = p_size.y > 0;662switch (p_font_data->hinting) {663case TextServer::HINTING_NONE:664flags |= FT_LOAD_NO_HINTING;665break;666case TextServer::HINTING_LIGHT:667flags |= FT_LOAD_TARGET_LIGHT;668break;669default:670flags |= FT_LOAD_TARGET_NORMAL;671break;672}673if (p_font_data->force_autohinter) {674flags |= FT_LOAD_FORCE_AUTOHINT;675}676if (outline || (p_font_data->disable_embedded_bitmaps && !FT_HAS_COLOR(fd->face))) {677flags |= FT_LOAD_NO_BITMAP;678} else if (FT_HAS_COLOR(fd->face)) {679flags |= FT_LOAD_COLOR;680}681682glyph_index = FT_Get_Char_Index(fd->face, glyph_index);683684FT_Fixed v, h;685FT_Get_Advance(fd->face, glyph_index, flags, &h);686FT_Get_Advance(fd->face, glyph_index, flags | FT_LOAD_VERTICAL_LAYOUT, &v);687688int error = FT_Load_Glyph(fd->face, glyph_index, flags);689if (error) {690E = fd->glyph_map.insert(p_glyph, FontGlyph());691r_glyph = E->value;692return false;693}694695if (!p_font_data->msdf) {696if ((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)) {697FT_Pos xshift = (int)((p_glyph >> 27) & 3) << 4;698FT_Outline_Translate(&fd->face->glyph->outline, xshift, 0);699} 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)) {700FT_Pos xshift = (int)((p_glyph >> 27) & 3) << 5;701FT_Outline_Translate(&fd->face->glyph->outline, xshift, 0);702}703}704705if (p_font_data->embolden != 0.f) {706FT_Pos strength = p_font_data->embolden * p_size.x / 16; // 26.6 fractional units (1 / 64).707FT_Outline_Embolden(&fd->face->glyph->outline, strength);708}709710if (p_font_data->transform != Transform2D()) {711FT_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).712FT_Outline_Transform(&fd->face->glyph->outline, &mat);713}714715FT_Render_Mode aa_mode = FT_RENDER_MODE_NORMAL;716bool bgra = false;717switch (p_font_data->antialiasing) {718case FONT_ANTIALIASING_NONE: {719aa_mode = FT_RENDER_MODE_MONO;720} break;721case FONT_ANTIALIASING_GRAY: {722aa_mode = FT_RENDER_MODE_NORMAL;723} break;724case FONT_ANTIALIASING_LCD: {725int aa_layout = (int)((p_glyph >> 24) & 7);726switch (aa_layout) {727case FONT_LCD_SUBPIXEL_LAYOUT_HRGB: {728aa_mode = FT_RENDER_MODE_LCD;729bgra = false;730} break;731case FONT_LCD_SUBPIXEL_LAYOUT_HBGR: {732aa_mode = FT_RENDER_MODE_LCD;733bgra = true;734} break;735case FONT_LCD_SUBPIXEL_LAYOUT_VRGB: {736aa_mode = FT_RENDER_MODE_LCD_V;737bgra = false;738} break;739case FONT_LCD_SUBPIXEL_LAYOUT_VBGR: {740aa_mode = FT_RENDER_MODE_LCD_V;741bgra = true;742} break;743default: {744aa_mode = FT_RENDER_MODE_NORMAL;745} break;746}747} break;748}749750FT_GlyphSlot slot = fd->face->glyph;751bool from_svg = (slot->format == FT_GLYPH_FORMAT_SVG); // Need to check before FT_Render_Glyph as it will change format to bitmap.752if (!outline) {753if (!p_font_data->msdf) {754error = FT_Render_Glyph(slot, aa_mode);755}756if (!error) {757if (p_font_data->msdf) {758#ifdef MODULE_MSDFGEN_ENABLED759gl = 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);760#else761fd->glyph_map[p_glyph] = FontGlyph();762ERR_FAIL_V_MSG(false, "Compiled without MSDFGEN support!");763#endif764} else {765gl = 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);766}767}768} else {769FT_Stroker stroker;770if (FT_Stroker_New(ft_library, &stroker) != 0) {771fd->glyph_map[p_glyph] = FontGlyph();772ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph stroker.");773}774775FT_Stroker_Set(stroker, (int)(fd->size.y * 16.0), FT_STROKER_LINECAP_BUTT, FT_STROKER_LINEJOIN_ROUND, 0);776FT_Glyph glyph;777FT_BitmapGlyph glyph_bitmap;778779if (FT_Get_Glyph(fd->face->glyph, &glyph) != 0) {780goto cleanup_stroker;781}782if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0) {783goto cleanup_glyph;784}785if (FT_Glyph_To_Bitmap(&glyph, aa_mode, nullptr, 1) != 0) {786goto cleanup_glyph;787}788glyph_bitmap = (FT_BitmapGlyph)glyph;789gl = rasterize_bitmap(fd, rect_range, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2(), bgra);790791cleanup_glyph:792FT_Done_Glyph(glyph);793cleanup_stroker:794FT_Stroker_Done(stroker);795}796gl.from_svg = from_svg;797E = fd->glyph_map.insert(p_glyph, gl);798r_glyph = E->value;799return gl.found;800}801#endif802E = fd->glyph_map.insert(p_glyph, FontGlyph());803r_glyph = E->value;804return false;805}806807bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_font_data, const Vector2i &p_size, FontForSizeFallback *&r_cache_for_size, bool p_silent, uint32_t p_oversampling) const {808ERR_FAIL_COND_V(p_size.x <= 0, false);809810HashMap<Vector2i, FontForSizeFallback *>::Iterator E = p_font_data->cache.find(p_size);811if (E) {812r_cache_for_size = E->value;813// Size used directly, remove from oversampling list.814if (p_oversampling == 0 && E->value->viewport_oversampling != 0) {815OversamplingLevel *ol = oversampling_levels.getptr(E->value->viewport_oversampling);816if (ol) {817ol->fonts.erase(E->value);818}819}820return true;821}822823r_cache_for_size = nullptr;824FontForSizeFallback *fd = memnew(FontForSizeFallback);825fd->size = p_size;826if (p_font_data->data_ptr && (p_font_data->data_size > 0)) {827// Init dynamic font.828#ifdef MODULE_FREETYPE_ENABLED829int error = 0;830{831MutexLock ftlock(ft_mutex);832if (!ft_library) {833error = FT_Init_FreeType(&ft_library);834if (error != 0) {835memdelete(fd);836if (p_silent) {837return false;838} else {839ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");840}841}842#ifdef MODULE_SVG_ENABLED843FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks());844#endif845}846847memset(&fd->stream, 0, sizeof(FT_StreamRec));848fd->stream.base = (unsigned char *)p_font_data->data_ptr;849fd->stream.size = p_font_data->data_size;850fd->stream.pos = 0;851852FT_Open_Args fargs;853memset(&fargs, 0, sizeof(FT_Open_Args));854fargs.memory_base = (unsigned char *)p_font_data->data_ptr;855fargs.memory_size = p_font_data->data_size;856fargs.flags = FT_OPEN_MEMORY;857fargs.stream = &fd->stream;858859int max_index = 0;860FT_Face tmp_face = nullptr;861error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);862if (tmp_face && error == 0) {863max_index = tmp_face->num_faces - 1;864}865if (tmp_face) {866FT_Done_Face(tmp_face);867}868869error = FT_Open_Face(ft_library, &fargs, CLAMP(p_font_data->face_index, 0, max_index), &fd->face);870if (error) {871FT_Done_Face(fd->face);872fd->face = nullptr;873memdelete(fd);874if (p_silent) {875return false;876} else {877ERR_FAIL_V_MSG(false, "FreeType: Error loading font: '" + String(FT_Error_String(error)) + "'.");878}879}880}881882double sz = double(fd->size.x) / 64.0;883if (p_font_data->msdf) {884sz = p_font_data->msdf_source_size;885}886887if (FT_HAS_COLOR(fd->face) && fd->face->num_fixed_sizes > 0) {888int best_match = 0;889int diff = Math::abs(sz - ((int64_t)fd->face->available_sizes[0].width));890fd->scale = sz / fd->face->available_sizes[0].width;891for (int i = 1; i < fd->face->num_fixed_sizes; i++) {892int ndiff = Math::abs(sz - ((int64_t)fd->face->available_sizes[i].width));893if (ndiff < diff) {894best_match = i;895diff = ndiff;896fd->scale = sz / fd->face->available_sizes[i].width;897}898}899FT_Select_Size(fd->face, best_match);900} else {901FT_Size_RequestRec req;902req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;903req.width = sz * 64.0;904req.height = sz * 64.0;905req.horiResolution = 0;906req.vertResolution = 0;907908FT_Request_Size(fd->face, &req);909if (fd->face->size->metrics.y_ppem != 0) {910fd->scale = sz / (double)fd->face->size->metrics.y_ppem;911}912}913914fd->ascent = (fd->face->size->metrics.ascender / 64.0) * fd->scale;915fd->descent = (-fd->face->size->metrics.descender / 64.0) * fd->scale;916fd->underline_position = (-FT_MulFix(fd->face->underline_position, fd->face->size->metrics.y_scale) / 64.0) * fd->scale;917fd->underline_thickness = (FT_MulFix(fd->face->underline_thickness, fd->face->size->metrics.y_scale) / 64.0) * fd->scale;918919if (!p_font_data->face_init) {920// When a font does not provide a `family_name`, FreeType tries to synthesize one based on other names.921// FreeType automatically converts non-ASCII characters to "?" in the synthesized name.922// To avoid that behavior, use the format-specific name directly if available.923if (FT_IS_SFNT(fd->face)) {924int name_count = FT_Get_Sfnt_Name_Count(fd->face);925for (int i = 0; i < name_count; i++) {926FT_SfntName sfnt_name;927if (FT_Get_Sfnt_Name(fd->face, i, &sfnt_name) != 0) {928continue;929}930if (sfnt_name.name_id != TT_NAME_ID_FONT_FAMILY && sfnt_name.name_id != TT_NAME_ID_TYPOGRAPHIC_FAMILY) {931continue;932}933if (!p_font_data->font_name.is_empty() && sfnt_name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES) {934continue;935}936937switch (sfnt_name.platform_id) {938case TT_PLATFORM_APPLE_UNICODE: {939p_font_data->font_name.clear();940p_font_data->font_name.append_utf16((const char16_t *)sfnt_name.string, sfnt_name.string_len / 2, false);941} break;942943case TT_PLATFORM_MICROSOFT: {944if (sfnt_name.encoding_id == TT_MS_ID_UNICODE_CS || sfnt_name.encoding_id == TT_MS_ID_UCS_4) {945p_font_data->font_name.clear();946p_font_data->font_name.append_utf16((const char16_t *)sfnt_name.string, sfnt_name.string_len / 2, false);947}948} break;949}950}951}952if (p_font_data->font_name.is_empty() && fd->face->family_name != nullptr) {953p_font_data->font_name = String::utf8((const char *)fd->face->family_name);954}955if (fd->face->style_name != nullptr) {956p_font_data->style_name = String::utf8((const char *)fd->face->style_name);957}958p_font_data->weight = _font_get_weight_by_name(p_font_data->style_name.to_lower());959p_font_data->stretch = _font_get_stretch_by_name(p_font_data->style_name.to_lower());960p_font_data->style_flags = 0;961if ((fd->face->style_flags & FT_STYLE_FLAG_BOLD) || p_font_data->weight >= 700) {962p_font_data->style_flags.set_flag(FONT_BOLD);963}964if ((fd->face->style_flags & FT_STYLE_FLAG_ITALIC) || _is_ital_style(p_font_data->style_name.to_lower())) {965p_font_data->style_flags.set_flag(FONT_ITALIC);966}967if (fd->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) {968p_font_data->style_flags.set_flag(FONT_FIXED_WIDTH);969}970// Read OpenType variations.971p_font_data->supported_varaitions.clear();972if (fd->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {973FT_MM_Var *amaster;974FT_Get_MM_Var(fd->face, &amaster);975for (FT_UInt i = 0; i < amaster->num_axis; i++) {976p_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);977}978FT_Done_MM_Var(ft_library, amaster);979}980p_font_data->face_init = true;981}982983#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)984if (p_font_data->font_name == ".Apple Color Emoji UI" || p_font_data->font_name == "Apple Color Emoji") {985// The baseline offset is missing from the Apple Color Emoji UI font data, so add it manually.986// This issue doesn't occur with other system emoji fonts.987if (!FT_Load_Glyph(fd->face, FT_Get_Char_Index(fd->face, 0x1F92E), FT_LOAD_DEFAULT | FT_LOAD_COLOR)) {988if (fd->face->glyph->metrics.horiBearingY == fd->face->glyph->metrics.height) {989p_font_data->baseline_offset = 0.15;990}991}992}993#endif994995// Write variations.996if (fd->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {997FT_MM_Var *amaster;998999FT_Get_MM_Var(fd->face, &amaster);10001001Vector<FT_Fixed> coords;1002coords.resize(amaster->num_axis);10031004FT_Get_Var_Design_Coordinates(fd->face, coords.size(), coords.ptrw());10051006for (FT_UInt i = 0; i < amaster->num_axis; i++) {1007// Reset to default.1008int32_t var_tag = amaster->axis[i].tag;1009double var_value = (double)amaster->axis[i].def / 65536.0;1010coords.write[i] = amaster->axis[i].def;10111012if (p_font_data->variation_coordinates.has(var_tag)) {1013var_value = p_font_data->variation_coordinates[var_tag];1014coords.write[i] = CLAMP(var_value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);1015}10161017if (p_font_data->variation_coordinates.has(tag_to_name(var_tag))) {1018var_value = p_font_data->variation_coordinates[tag_to_name(var_tag)];1019coords.write[i] = CLAMP(var_value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);1020}1021}10221023FT_Set_Var_Design_Coordinates(fd->face, coords.size(), coords.ptrw());1024FT_Done_MM_Var(ft_library, amaster);1025}1026#else1027memdelete(fd);1028if (p_silent) {1029return false;1030} else {1031ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!");1032}1033#endif1034}10351036fd->owner = p_font_data;1037p_font_data->cache.insert(p_size, fd);1038r_cache_for_size = fd;1039if (p_oversampling != 0) {1040OversamplingLevel *ol = oversampling_levels.getptr(p_oversampling);1041if (ol) {1042fd->viewport_oversampling = p_oversampling;1043ol->fonts.insert(fd);1044}1045}1046return true;1047}10481049void TextServerFallback::_reference_oversampling_level(double p_oversampling) {1050uint32_t oversampling = CLAMP(p_oversampling, 0.1, 100.0) * 64;1051if (oversampling == 64) {1052return;1053}1054OversamplingLevel *ol = oversampling_levels.getptr(oversampling);1055if (ol) {1056ol->refcount++;1057} else {1058OversamplingLevel new_ol;1059oversampling_levels.insert(oversampling, new_ol);1060}1061}10621063void TextServerFallback::_unreference_oversampling_level(double p_oversampling) {1064uint32_t oversampling = CLAMP(p_oversampling, 0.1, 100.0) * 64;1065if (oversampling == 64) {1066return;1067}1068OversamplingLevel *ol = oversampling_levels.getptr(oversampling);1069if (ol) {1070ol->refcount--;1071if (ol->refcount == 0) {1072for (FontForSizeFallback *fd : ol->fonts) {1073fd->owner->cache.erase(fd->size);1074memdelete(fd);1075}1076ol->fonts.clear();1077oversampling_levels.erase(oversampling);1078}1079}1080}10811082_FORCE_INLINE_ bool TextServerFallback::_font_validate(const RID &p_font_rid) const {1083FontFallback *fd = _get_font_data(p_font_rid);1084ERR_FAIL_NULL_V(fd, false);10851086MutexLock lock(fd->mutex);1087Vector2i size = _get_size(fd, 16);1088FontForSizeFallback *ffsd = nullptr;1089return _ensure_cache_for_size(fd, size, ffsd, true);1090}10911092_FORCE_INLINE_ void TextServerFallback::_font_clear_cache(FontFallback *p_font_data) {1093MutexLock ftlock(ft_mutex);10941095for (const KeyValue<Vector2i, FontForSizeFallback *> &E : p_font_data->cache) {1096if (E.value->viewport_oversampling != 0) {1097OversamplingLevel *ol = oversampling_levels.getptr(E.value->viewport_oversampling);1098if (ol) {1099ol->fonts.erase(E.value);1100}1101}1102memdelete(E.value);1103}11041105p_font_data->cache.clear();1106p_font_data->face_init = false;1107p_font_data->supported_varaitions.clear();1108}11091110RID TextServerFallback::_create_font() {1111_THREAD_SAFE_METHOD_11121113FontFallback *fd = memnew(FontFallback);11141115return font_owner.make_rid(fd);1116}11171118RID TextServerFallback::_create_font_linked_variation(const RID &p_font_rid) {1119_THREAD_SAFE_METHOD_11201121RID rid = p_font_rid;1122FontFallbackLinkedVariation *fdv = font_var_owner.get_or_null(rid);1123if (unlikely(fdv)) {1124rid = fdv->base_font;1125}1126ERR_FAIL_COND_V(!font_owner.owns(rid), RID());11271128FontFallbackLinkedVariation *new_fdv = memnew(FontFallbackLinkedVariation);1129new_fdv->base_font = rid;11301131return font_var_owner.make_rid(new_fdv);1132}11331134void TextServerFallback::_font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) {1135FontFallback *fd = _get_font_data(p_font_rid);1136ERR_FAIL_NULL(fd);11371138MutexLock lock(fd->mutex);1139_font_clear_cache(fd);1140fd->data = p_data;1141fd->data_ptr = fd->data.ptr();1142fd->data_size = fd->data.size();1143}11441145void TextServerFallback::_font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) {1146FontFallback *fd = _get_font_data(p_font_rid);1147ERR_FAIL_NULL(fd);11481149MutexLock lock(fd->mutex);1150_font_clear_cache(fd);1151fd->data.resize(0);1152fd->data_ptr = p_data_ptr;1153fd->data_size = p_data_size;1154}11551156void TextServerFallback::_font_set_style(const RID &p_font_rid, BitField<FontStyle> p_style) {1157FontFallback *fd = _get_font_data(p_font_rid);1158ERR_FAIL_NULL(fd);11591160MutexLock lock(fd->mutex);1161Vector2i size = _get_size(fd, 16);1162FontForSizeFallback *ffsd = nullptr;1163ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));1164fd->style_flags = p_style;1165}11661167void TextServerFallback::_font_set_face_index(const RID &p_font_rid, int64_t p_face_index) {1168ERR_FAIL_COND(p_face_index < 0);1169ERR_FAIL_COND(p_face_index >= 0x7FFF);11701171FontFallback *fd = _get_font_data(p_font_rid);1172ERR_FAIL_NULL(fd);11731174MutexLock lock(fd->mutex);1175if (fd->face_index != p_face_index) {1176fd->face_index = p_face_index;1177_font_clear_cache(fd);1178}1179}11801181int64_t TextServerFallback::_font_get_face_index(const RID &p_font_rid) const {1182FontFallback *fd = _get_font_data(p_font_rid);1183ERR_FAIL_NULL_V(fd, 0);11841185MutexLock lock(fd->mutex);1186return fd->face_index;1187}11881189int64_t TextServerFallback::_font_get_face_count(const RID &p_font_rid) const {1190FontFallback *fd = _get_font_data(p_font_rid);1191ERR_FAIL_NULL_V(fd, 0);11921193MutexLock lock(fd->mutex);1194int face_count = 0;11951196if (fd->data_ptr && (fd->data_size > 0)) {1197// Init dynamic font.1198#ifdef MODULE_FREETYPE_ENABLED1199int error = 0;1200if (!ft_library) {1201error = FT_Init_FreeType(&ft_library);1202ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");1203#ifdef MODULE_SVG_ENABLED1204FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks());1205#endif1206}12071208FT_StreamRec stream;1209memset(&stream, 0, sizeof(FT_StreamRec));1210stream.base = (unsigned char *)fd->data_ptr;1211stream.size = fd->data_size;1212stream.pos = 0;12131214FT_Open_Args fargs;1215memset(&fargs, 0, sizeof(FT_Open_Args));1216fargs.memory_base = (unsigned char *)fd->data_ptr;1217fargs.memory_size = fd->data_size;1218fargs.flags = FT_OPEN_MEMORY;1219fargs.stream = &stream;12201221MutexLock ftlock(ft_mutex);12221223FT_Face tmp_face = nullptr;1224error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);1225if (error == 0) {1226face_count = tmp_face->num_faces;1227FT_Done_Face(tmp_face);1228}1229#endif1230}12311232return face_count;1233}12341235BitField<TextServer::FontStyle> TextServerFallback::_font_get_style(const RID &p_font_rid) const {1236FontFallback *fd = _get_font_data(p_font_rid);1237ERR_FAIL_NULL_V(fd, 0);12381239MutexLock lock(fd->mutex);1240Vector2i size = _get_size(fd, 16);1241FontForSizeFallback *ffsd = nullptr;1242ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0);1243return fd->style_flags;1244}12451246void TextServerFallback::_font_set_style_name(const RID &p_font_rid, const String &p_name) {1247FontFallback *fd = _get_font_data(p_font_rid);1248ERR_FAIL_NULL(fd);12491250MutexLock lock(fd->mutex);1251Vector2i size = _get_size(fd, 16);1252FontForSizeFallback *ffsd = nullptr;1253ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));1254fd->style_name = p_name;1255}12561257String TextServerFallback::_font_get_style_name(const RID &p_font_rid) const {1258FontFallback *fd = _get_font_data(p_font_rid);1259ERR_FAIL_NULL_V(fd, String());12601261MutexLock lock(fd->mutex);1262Vector2i size = _get_size(fd, 16);1263FontForSizeFallback *ffsd = nullptr;1264ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), String());1265return fd->style_name;1266}12671268void TextServerFallback::_font_set_weight(const RID &p_font_rid, int64_t p_weight) {1269FontFallback *fd = _get_font_data(p_font_rid);1270ERR_FAIL_NULL(fd);12711272MutexLock lock(fd->mutex);1273Vector2i size = _get_size(fd, 16);1274FontForSizeFallback *ffsd = nullptr;1275ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));1276fd->weight = CLAMP(p_weight, 100, 999);1277}12781279int64_t TextServerFallback::_font_get_weight(const RID &p_font_rid) const {1280FontFallback *fd = _get_font_data(p_font_rid);1281ERR_FAIL_NULL_V(fd, 400);12821283MutexLock lock(fd->mutex);1284Vector2i size = _get_size(fd, 16);1285FontForSizeFallback *ffsd = nullptr;1286ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 400);1287return fd->weight;1288}12891290void TextServerFallback::_font_set_stretch(const RID &p_font_rid, int64_t p_stretch) {1291FontFallback *fd = _get_font_data(p_font_rid);1292ERR_FAIL_NULL(fd);12931294MutexLock lock(fd->mutex);1295Vector2i size = _get_size(fd, 16);1296FontForSizeFallback *ffsd = nullptr;1297ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));1298fd->stretch = CLAMP(p_stretch, 50, 200);1299}13001301int64_t TextServerFallback::_font_get_stretch(const RID &p_font_rid) const {1302FontFallback *fd = _get_font_data(p_font_rid);1303ERR_FAIL_NULL_V(fd, 100);13041305MutexLock lock(fd->mutex);1306Vector2i size = _get_size(fd, 16);1307FontForSizeFallback *ffsd = nullptr;1308ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 100);1309return fd->stretch;1310}13111312void TextServerFallback::_font_set_name(const RID &p_font_rid, const String &p_name) {1313FontFallback *fd = _get_font_data(p_font_rid);1314ERR_FAIL_NULL(fd);13151316MutexLock lock(fd->mutex);1317Vector2i size = _get_size(fd, 16);1318FontForSizeFallback *ffsd = nullptr;1319ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));1320fd->font_name = p_name;1321}13221323String TextServerFallback::_font_get_name(const RID &p_font_rid) const {1324FontFallback *fd = _get_font_data(p_font_rid);1325ERR_FAIL_NULL_V(fd, String());13261327MutexLock lock(fd->mutex);1328Vector2i size = _get_size(fd, 16);1329FontForSizeFallback *ffsd = nullptr;1330ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), String());1331return fd->font_name;1332}13331334void TextServerFallback::_font_set_antialiasing(const RID &p_font_rid, TextServer::FontAntialiasing p_antialiasing) {1335FontFallback *fd = _get_font_data(p_font_rid);1336ERR_FAIL_NULL(fd);13371338MutexLock lock(fd->mutex);1339if (fd->antialiasing != p_antialiasing) {1340_font_clear_cache(fd);1341fd->antialiasing = p_antialiasing;1342}1343}13441345TextServer::FontAntialiasing TextServerFallback::_font_get_antialiasing(const RID &p_font_rid) const {1346FontFallback *fd = _get_font_data(p_font_rid);1347ERR_FAIL_NULL_V(fd, TextServer::FONT_ANTIALIASING_NONE);13481349MutexLock lock(fd->mutex);1350return fd->antialiasing;1351}13521353void TextServerFallback::_font_set_disable_embedded_bitmaps(const RID &p_font_rid, bool p_disable_embedded_bitmaps) {1354FontFallback *fd = _get_font_data(p_font_rid);1355ERR_FAIL_NULL(fd);13561357MutexLock lock(fd->mutex);1358if (fd->disable_embedded_bitmaps != p_disable_embedded_bitmaps) {1359_font_clear_cache(fd);1360fd->disable_embedded_bitmaps = p_disable_embedded_bitmaps;1361}1362}13631364bool TextServerFallback::_font_get_disable_embedded_bitmaps(const RID &p_font_rid) const {1365FontFallback *fd = _get_font_data(p_font_rid);1366ERR_FAIL_NULL_V(fd, false);13671368MutexLock lock(fd->mutex);1369return fd->disable_embedded_bitmaps;1370}13711372void TextServerFallback::_font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) {1373FontFallback *fd = _get_font_data(p_font_rid);1374ERR_FAIL_NULL(fd);13751376MutexLock lock(fd->mutex);1377if (fd->mipmaps != p_generate_mipmaps) {1378for (KeyValue<Vector2i, FontForSizeFallback *> &E : fd->cache) {1379for (int i = 0; i < E.value->textures.size(); i++) {1380E.value->textures.write[i].dirty = true;1381E.value->textures.write[i].texture = Ref<ImageTexture>();1382}1383}1384fd->mipmaps = p_generate_mipmaps;1385}1386}13871388bool TextServerFallback::_font_get_generate_mipmaps(const RID &p_font_rid) const {1389FontFallback *fd = _get_font_data(p_font_rid);1390ERR_FAIL_NULL_V(fd, false);13911392MutexLock lock(fd->mutex);1393return fd->mipmaps;1394}13951396void TextServerFallback::_font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) {1397FontFallback *fd = _get_font_data(p_font_rid);1398ERR_FAIL_NULL(fd);13991400MutexLock lock(fd->mutex);1401if (fd->msdf != p_msdf) {1402_font_clear_cache(fd);1403fd->msdf = p_msdf;1404}1405}14061407bool TextServerFallback::_font_is_multichannel_signed_distance_field(const RID &p_font_rid) const {1408FontFallback *fd = _get_font_data(p_font_rid);1409ERR_FAIL_NULL_V(fd, false);14101411MutexLock lock(fd->mutex);1412return fd->msdf;1413}14141415void TextServerFallback::_font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) {1416FontFallback *fd = _get_font_data(p_font_rid);1417ERR_FAIL_NULL(fd);14181419MutexLock lock(fd->mutex);1420if (fd->msdf_range != p_msdf_pixel_range) {1421_font_clear_cache(fd);1422fd->msdf_range = p_msdf_pixel_range;1423}1424}14251426int64_t TextServerFallback::_font_get_msdf_pixel_range(const RID &p_font_rid) const {1427FontFallback *fd = _get_font_data(p_font_rid);1428ERR_FAIL_NULL_V(fd, false);14291430MutexLock lock(fd->mutex);1431return fd->msdf_range;1432}14331434void TextServerFallback::_font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) {1435FontFallback *fd = _get_font_data(p_font_rid);1436ERR_FAIL_NULL(fd);14371438MutexLock lock(fd->mutex);1439if (fd->msdf_source_size != p_msdf_size) {1440_font_clear_cache(fd);1441fd->msdf_source_size = p_msdf_size;1442}1443}14441445int64_t TextServerFallback::_font_get_msdf_size(const RID &p_font_rid) const {1446FontFallback *fd = _get_font_data(p_font_rid);1447ERR_FAIL_NULL_V(fd, 0);14481449MutexLock lock(fd->mutex);1450return fd->msdf_source_size;1451}14521453void TextServerFallback::_font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) {1454FontFallback *fd = _get_font_data(p_font_rid);1455ERR_FAIL_NULL(fd);14561457MutexLock lock(fd->mutex);1458fd->fixed_size = p_fixed_size;1459}14601461int64_t TextServerFallback::_font_get_fixed_size(const RID &p_font_rid) const {1462FontFallback *fd = _get_font_data(p_font_rid);1463ERR_FAIL_NULL_V(fd, 0);14641465MutexLock lock(fd->mutex);1466return fd->fixed_size;1467}14681469void TextServerFallback::_font_set_fixed_size_scale_mode(const RID &p_font_rid, TextServer::FixedSizeScaleMode p_fixed_size_scale_mode) {1470FontFallback *fd = _get_font_data(p_font_rid);1471ERR_FAIL_NULL(fd);14721473MutexLock lock(fd->mutex);1474fd->fixed_size_scale_mode = p_fixed_size_scale_mode;1475}14761477TextServer::FixedSizeScaleMode TextServerFallback::_font_get_fixed_size_scale_mode(const RID &p_font_rid) const {1478FontFallback *fd = _get_font_data(p_font_rid);1479ERR_FAIL_NULL_V(fd, FIXED_SIZE_SCALE_DISABLE);14801481MutexLock lock(fd->mutex);1482return fd->fixed_size_scale_mode;1483}14841485void TextServerFallback::_font_set_allow_system_fallback(const RID &p_font_rid, bool p_allow_system_fallback) {1486FontFallback *fd = _get_font_data(p_font_rid);1487ERR_FAIL_NULL(fd);14881489MutexLock lock(fd->mutex);1490fd->allow_system_fallback = p_allow_system_fallback;1491}14921493bool TextServerFallback::_font_is_allow_system_fallback(const RID &p_font_rid) const {1494FontFallback *fd = _get_font_data(p_font_rid);1495ERR_FAIL_NULL_V(fd, false);14961497MutexLock lock(fd->mutex);1498return fd->allow_system_fallback;1499}15001501void TextServerFallback::_font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) {1502FontFallback *fd = _get_font_data(p_font_rid);1503ERR_FAIL_NULL(fd);15041505MutexLock lock(fd->mutex);1506if (fd->force_autohinter != p_force_autohinter) {1507_font_clear_cache(fd);1508fd->force_autohinter = p_force_autohinter;1509}1510}15111512bool TextServerFallback::_font_is_force_autohinter(const RID &p_font_rid) const {1513FontFallback *fd = _get_font_data(p_font_rid);1514ERR_FAIL_NULL_V(fd, false);15151516MutexLock lock(fd->mutex);1517return fd->force_autohinter;1518}15191520void TextServerFallback::_font_set_modulate_color_glyphs(const RID &p_font_rid, bool p_modulate) {1521FontFallback *fd = _get_font_data(p_font_rid);1522ERR_FAIL_NULL(fd);15231524MutexLock lock(fd->mutex);1525if (fd->modulate_color_glyphs != p_modulate) {1526fd->modulate_color_glyphs = p_modulate;1527}1528}15291530bool TextServerFallback::_font_is_modulate_color_glyphs(const RID &p_font_rid) const {1531FontFallback *fd = _get_font_data(p_font_rid);1532ERR_FAIL_NULL_V(fd, false);15331534MutexLock lock(fd->mutex);1535return fd->modulate_color_glyphs;1536}15371538void TextServerFallback::_font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) {1539FontFallback *fd = _get_font_data(p_font_rid);1540ERR_FAIL_NULL(fd);15411542MutexLock lock(fd->mutex);1543if (fd->hinting != p_hinting) {1544_font_clear_cache(fd);1545fd->hinting = p_hinting;1546}1547}15481549TextServer::Hinting TextServerFallback::_font_get_hinting(const RID &p_font_rid) const {1550FontFallback *fd = _get_font_data(p_font_rid);1551ERR_FAIL_NULL_V(fd, HINTING_NONE);15521553MutexLock lock(fd->mutex);1554return fd->hinting;1555}15561557void TextServerFallback::_font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) {1558FontFallback *fd = _get_font_data(p_font_rid);1559ERR_FAIL_NULL(fd);15601561MutexLock lock(fd->mutex);1562fd->subpixel_positioning = p_subpixel;1563}15641565TextServer::SubpixelPositioning TextServerFallback::_font_get_subpixel_positioning(const RID &p_font_rid) const {1566FontFallback *fd = _get_font_data(p_font_rid);1567ERR_FAIL_NULL_V(fd, SUBPIXEL_POSITIONING_DISABLED);15681569MutexLock lock(fd->mutex);1570return fd->subpixel_positioning;1571}15721573void TextServerFallback::_font_set_keep_rounding_remainders(const RID &p_font_rid, bool p_keep_rounding_remainders) {1574FontFallback *fd = _get_font_data(p_font_rid);1575ERR_FAIL_NULL(fd);15761577MutexLock lock(fd->mutex);1578fd->keep_rounding_remainders = p_keep_rounding_remainders;1579}15801581bool TextServerFallback::_font_get_keep_rounding_remainders(const RID &p_font_rid) const {1582FontFallback *fd = _get_font_data(p_font_rid);1583ERR_FAIL_NULL_V(fd, false);15841585MutexLock lock(fd->mutex);1586return fd->keep_rounding_remainders;1587}15881589void TextServerFallback::_font_set_embolden(const RID &p_font_rid, double p_strength) {1590FontFallback *fd = _get_font_data(p_font_rid);1591ERR_FAIL_NULL(fd);15921593MutexLock lock(fd->mutex);1594if (fd->embolden != p_strength) {1595_font_clear_cache(fd);1596fd->embolden = p_strength;1597}1598}15991600double TextServerFallback::_font_get_embolden(const RID &p_font_rid) const {1601FontFallback *fd = _get_font_data(p_font_rid);1602ERR_FAIL_NULL_V(fd, 0.0);16031604MutexLock lock(fd->mutex);1605return fd->embolden;1606}16071608void TextServerFallback::_font_set_spacing(const RID &p_font_rid, SpacingType p_spacing, int64_t p_value) {1609ERR_FAIL_INDEX((int)p_spacing, 4);1610FontFallbackLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);1611if (fdv) {1612if (fdv->extra_spacing[p_spacing] != p_value) {1613fdv->extra_spacing[p_spacing] = p_value;1614}1615} else {1616FontFallback *fd = font_owner.get_or_null(p_font_rid);1617ERR_FAIL_NULL(fd);16181619MutexLock lock(fd->mutex);1620if (fd->extra_spacing[p_spacing] != p_value) {1621_font_clear_cache(fd);1622fd->extra_spacing[p_spacing] = p_value;1623}1624}1625}16261627int64_t TextServerFallback::_font_get_spacing(const RID &p_font_rid, SpacingType p_spacing) const {1628ERR_FAIL_INDEX_V((int)p_spacing, 4, 0);1629FontFallbackLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);1630if (fdv) {1631return fdv->extra_spacing[p_spacing];1632} else {1633FontFallback *fd = font_owner.get_or_null(p_font_rid);1634ERR_FAIL_NULL_V(fd, 0);16351636MutexLock lock(fd->mutex);1637return fd->extra_spacing[p_spacing];1638}1639}16401641void TextServerFallback::_font_set_baseline_offset(const RID &p_font_rid, double p_baseline_offset) {1642FontFallbackLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);1643if (fdv) {1644if (fdv->baseline_offset != p_baseline_offset) {1645fdv->baseline_offset = p_baseline_offset;1646}1647} else {1648FontFallback *fd = font_owner.get_or_null(p_font_rid);1649ERR_FAIL_NULL(fd);16501651MutexLock lock(fd->mutex);1652if (fd->baseline_offset != p_baseline_offset) {1653_font_clear_cache(fd);1654fd->baseline_offset = p_baseline_offset;1655}1656}1657}16581659double TextServerFallback::_font_get_baseline_offset(const RID &p_font_rid) const {1660FontFallbackLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);1661if (fdv) {1662return fdv->baseline_offset;1663} else {1664FontFallback *fd = font_owner.get_or_null(p_font_rid);1665ERR_FAIL_NULL_V(fd, 0.0);16661667MutexLock lock(fd->mutex);1668return fd->baseline_offset;1669}1670}16711672void TextServerFallback::_font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) {1673FontFallback *fd = _get_font_data(p_font_rid);1674ERR_FAIL_NULL(fd);16751676MutexLock lock(fd->mutex);1677if (fd->transform != p_transform) {1678_font_clear_cache(fd);1679fd->transform = p_transform;1680}1681}16821683Transform2D TextServerFallback::_font_get_transform(const RID &p_font_rid) const {1684FontFallback *fd = _get_font_data(p_font_rid);1685ERR_FAIL_NULL_V(fd, Transform2D());16861687MutexLock lock(fd->mutex);1688return fd->transform;1689}16901691void TextServerFallback::_font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) {1692FontFallback *fd = _get_font_data(p_font_rid);1693ERR_FAIL_NULL(fd);16941695MutexLock lock(fd->mutex);1696if (!fd->variation_coordinates.recursive_equal(p_variation_coordinates, 1)) {1697_font_clear_cache(fd);1698fd->variation_coordinates = p_variation_coordinates.duplicate();1699}1700}17011702double TextServerFallback::_font_get_oversampling(const RID &p_font_rid) const {1703FontFallback *fd = _get_font_data(p_font_rid);1704ERR_FAIL_NULL_V(fd, -1.0);17051706MutexLock lock(fd->mutex);1707return fd->oversampling_override;1708}17091710void TextServerFallback::_font_set_oversampling(const RID &p_font_rid, double p_oversampling) {1711FontFallback *fd = _get_font_data(p_font_rid);1712ERR_FAIL_NULL(fd);17131714MutexLock lock(fd->mutex);1715if (fd->oversampling_override != p_oversampling) {1716_font_clear_cache(fd);1717fd->oversampling_override = p_oversampling;1718}1719}17201721Dictionary TextServerFallback::_font_get_variation_coordinates(const RID &p_font_rid) const {1722FontFallback *fd = _get_font_data(p_font_rid);1723ERR_FAIL_NULL_V(fd, Dictionary());17241725MutexLock lock(fd->mutex);1726return fd->variation_coordinates;1727}17281729TypedArray<Vector2i> TextServerFallback::_font_get_size_cache_list(const RID &p_font_rid) const {1730FontFallback *fd = _get_font_data(p_font_rid);1731ERR_FAIL_NULL_V(fd, TypedArray<Vector2i>());17321733MutexLock lock(fd->mutex);1734TypedArray<Vector2i> ret;1735for (const KeyValue<Vector2i, FontForSizeFallback *> &E : fd->cache) {1736if ((E.key.x % 64 == 0) && (E.value->viewport_oversampling == 0)) {1737ret.push_back(Vector2i(E.key.x / 64, E.key.y));1738}1739}1740return ret;1741}17421743TypedArray<Dictionary> TextServerFallback::_font_get_size_cache_info(const RID &p_font_rid) const {1744FontFallback *fd = _get_font_data(p_font_rid);1745ERR_FAIL_NULL_V(fd, TypedArray<Dictionary>());17461747MutexLock lock(fd->mutex);1748TypedArray<Dictionary> ret;1749for (const KeyValue<Vector2i, FontForSizeFallback *> &E : fd->cache) {1750Dictionary size_info;1751size_info["size_px"] = Vector2i(E.key.x / 64, E.key.y);1752if (E.value->viewport_oversampling) {1753size_info["viewport_oversampling"] = double(E.value->viewport_oversampling) / 64.0;1754}1755size_info["glyphs"] = E.value->glyph_map.size();1756size_info["textures"] = E.value->textures.size();1757uint64_t sz = 0;1758for (const ShelfPackTexture &tx : E.value->textures) {1759sz += tx.image->get_data_size() * 2;1760}1761size_info["textures_size"] = sz;1762ret.push_back(size_info);1763}17641765return ret;1766}17671768void TextServerFallback::_font_clear_size_cache(const RID &p_font_rid) {1769FontFallback *fd = _get_font_data(p_font_rid);1770ERR_FAIL_NULL(fd);17711772MutexLock lock(fd->mutex);1773MutexLock ftlock(ft_mutex);1774for (const KeyValue<Vector2i, FontForSizeFallback *> &E : fd->cache) {1775if (E.value->viewport_oversampling != 0) {1776OversamplingLevel *ol = oversampling_levels.getptr(E.value->viewport_oversampling);1777if (ol) {1778ol->fonts.erase(E.value);1779}1780}1781memdelete(E.value);1782}1783fd->cache.clear();1784}17851786void TextServerFallback::_font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) {1787FontFallback *fd = _get_font_data(p_font_rid);1788ERR_FAIL_NULL(fd);17891790MutexLock lock(fd->mutex);1791MutexLock ftlock(ft_mutex);1792Vector2i size = Vector2i(p_size.x * 64, p_size.y);1793if (fd->cache.has(size)) {1794if (fd->cache[size]->viewport_oversampling != 0) {1795OversamplingLevel *ol = oversampling_levels.getptr(fd->cache[size]->viewport_oversampling);1796if (ol) {1797ol->fonts.erase(fd->cache[size]);1798}1799}1800memdelete(fd->cache[size]);1801fd->cache.erase(size);1802}1803}18041805void TextServerFallback::_font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) {1806FontFallback *fd = _get_font_data(p_font_rid);1807ERR_FAIL_NULL(fd);18081809MutexLock lock(fd->mutex);1810Vector2i size = _get_size(fd, p_size);18111812FontForSizeFallback *ffsd = nullptr;1813ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));1814ffsd->ascent = p_ascent;1815}18161817double TextServerFallback::_font_get_ascent(const RID &p_font_rid, int64_t p_size) const {1818FontFallback *fd = _get_font_data(p_font_rid);1819ERR_FAIL_NULL_V(fd, 0.0);18201821MutexLock lock(fd->mutex);1822Vector2i size = _get_size(fd, p_size);18231824FontForSizeFallback *ffsd = nullptr;1825ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);18261827if (fd->msdf) {1828return ffsd->ascent * (double)p_size / (double)fd->msdf_source_size;1829} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {1830if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {1831return ffsd->ascent * (double)p_size / (double)fd->fixed_size;1832} else {1833return ffsd->ascent * Math::round((double)p_size / (double)fd->fixed_size);1834}1835} else {1836return ffsd->ascent;1837}1838}18391840void TextServerFallback::_font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) {1841FontFallback *fd = _get_font_data(p_font_rid);1842ERR_FAIL_NULL(fd);18431844Vector2i size = _get_size(fd, p_size);18451846FontForSizeFallback *ffsd = nullptr;1847ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));1848ffsd->descent = p_descent;1849}18501851double TextServerFallback::_font_get_descent(const RID &p_font_rid, int64_t p_size) const {1852FontFallback *fd = _get_font_data(p_font_rid);1853ERR_FAIL_NULL_V(fd, 0.0);18541855MutexLock lock(fd->mutex);1856Vector2i size = _get_size(fd, p_size);18571858FontForSizeFallback *ffsd = nullptr;1859ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);18601861if (fd->msdf) {1862return ffsd->descent * (double)p_size / (double)fd->msdf_source_size;1863} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {1864if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {1865return ffsd->descent * (double)p_size / (double)fd->fixed_size;1866} else {1867return ffsd->descent * Math::round((double)p_size / (double)fd->fixed_size);1868}1869} else {1870return ffsd->descent;1871}1872}18731874void TextServerFallback::_font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) {1875FontFallback *fd = _get_font_data(p_font_rid);1876ERR_FAIL_NULL(fd);18771878MutexLock lock(fd->mutex);1879Vector2i size = _get_size(fd, p_size);18801881FontForSizeFallback *ffsd = nullptr;1882ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));1883ffsd->underline_position = p_underline_position;1884}18851886double TextServerFallback::_font_get_underline_position(const RID &p_font_rid, int64_t p_size) const {1887FontFallback *fd = _get_font_data(p_font_rid);1888ERR_FAIL_NULL_V(fd, 0.0);18891890MutexLock lock(fd->mutex);1891Vector2i size = _get_size(fd, p_size);18921893FontForSizeFallback *ffsd = nullptr;1894ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);18951896if (fd->msdf) {1897return ffsd->underline_position * (double)p_size / (double)fd->msdf_source_size;1898} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {1899if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {1900return ffsd->underline_position * (double)p_size / (double)fd->fixed_size;1901} else {1902return ffsd->underline_position * Math::round((double)p_size / (double)fd->fixed_size);1903}1904} else {1905return ffsd->underline_position;1906}1907}19081909void TextServerFallback::_font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) {1910FontFallback *fd = _get_font_data(p_font_rid);1911ERR_FAIL_NULL(fd);19121913MutexLock lock(fd->mutex);1914Vector2i size = _get_size(fd, p_size);19151916FontForSizeFallback *ffsd = nullptr;1917ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));1918ffsd->underline_thickness = p_underline_thickness;1919}19201921double TextServerFallback::_font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const {1922FontFallback *fd = _get_font_data(p_font_rid);1923ERR_FAIL_NULL_V(fd, 0.0);19241925MutexLock lock(fd->mutex);1926Vector2i size = _get_size(fd, p_size);19271928FontForSizeFallback *ffsd = nullptr;1929ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);19301931if (fd->msdf) {1932return ffsd->underline_thickness * (double)p_size / (double)fd->msdf_source_size;1933} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {1934if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {1935return ffsd->underline_thickness * (double)p_size / (double)fd->fixed_size;1936} else {1937return ffsd->underline_thickness * Math::round((double)p_size / (double)fd->fixed_size);1938}1939} else {1940return ffsd->underline_thickness;1941}1942}19431944void TextServerFallback::_font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) {1945FontFallback *fd = _get_font_data(p_font_rid);1946ERR_FAIL_NULL(fd);19471948MutexLock lock(fd->mutex);1949Vector2i size = _get_size(fd, p_size);19501951FontForSizeFallback *ffsd = nullptr;1952ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));1953#ifdef MODULE_FREETYPE_ENABLED1954if (ffsd->face) {1955return; // Do not override scale for dynamic fonts, it's calculated automatically.1956}1957#endif1958ffsd->scale = p_scale;1959}19601961double TextServerFallback::_font_get_scale(const RID &p_font_rid, int64_t p_size) const {1962FontFallback *fd = _get_font_data(p_font_rid);1963ERR_FAIL_NULL_V(fd, 0.0);19641965MutexLock lock(fd->mutex);1966Vector2i size = _get_size(fd, p_size);19671968FontForSizeFallback *ffsd = nullptr;1969ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);19701971if (fd->msdf) {1972return ffsd->scale * (double)p_size / (double)fd->msdf_source_size;1973} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {1974if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {1975return ffsd->scale * (double)p_size / (double)fd->fixed_size;1976} else {1977return ffsd->scale * Math::round((double)p_size / (double)fd->fixed_size);1978}1979} else {1980return ffsd->scale;1981}1982}19831984int64_t TextServerFallback::_font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const {1985FontFallback *fd = _get_font_data(p_font_rid);1986ERR_FAIL_NULL_V(fd, 0);19871988MutexLock lock(fd->mutex);1989Vector2i size = _get_size_outline(fd, p_size);19901991FontForSizeFallback *ffsd = nullptr;1992ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0);19931994return ffsd->textures.size();1995}19961997void TextServerFallback::_font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) {1998FontFallback *fd = _get_font_data(p_font_rid);1999ERR_FAIL_NULL(fd);2000MutexLock lock(fd->mutex);2001Vector2i size = _get_size_outline(fd, p_size);20022003FontForSizeFallback *ffsd = nullptr;2004ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2005ffsd->textures.clear();2006}20072008void TextServerFallback::_font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) {2009FontFallback *fd = _get_font_data(p_font_rid);2010ERR_FAIL_NULL(fd);20112012MutexLock lock(fd->mutex);2013Vector2i size = _get_size_outline(fd, p_size);2014FontForSizeFallback *ffsd = nullptr;2015ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2016ERR_FAIL_INDEX(p_texture_index, ffsd->textures.size());20172018ffsd->textures.remove_at(p_texture_index);2019}20202021void TextServerFallback::_font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) {2022FontFallback *fd = _get_font_data(p_font_rid);2023ERR_FAIL_NULL(fd);2024ERR_FAIL_COND(p_image.is_null());20252026MutexLock lock(fd->mutex);2027Vector2i size = _get_size_outline(fd, p_size);2028FontForSizeFallback *ffsd = nullptr;2029ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2030ERR_FAIL_COND(p_texture_index < 0);2031if (p_texture_index >= ffsd->textures.size()) {2032ffsd->textures.resize(p_texture_index + 1);2033}20342035ShelfPackTexture &tex = ffsd->textures.write[p_texture_index];20362037tex.image = p_image;2038tex.texture_w = p_image->get_width();2039tex.texture_h = p_image->get_height();20402041Ref<Image> img = p_image;2042if (fd->mipmaps && !img->has_mipmaps()) {2043img = p_image->duplicate();2044img->generate_mipmaps();2045}2046tex.texture = ImageTexture::create_from_image(img);2047tex.dirty = false;2048}20492050Ref<Image> TextServerFallback::_font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {2051FontFallback *fd = _get_font_data(p_font_rid);2052ERR_FAIL_NULL_V(fd, Ref<Image>());20532054MutexLock lock(fd->mutex);2055Vector2i size = _get_size_outline(fd, p_size);2056FontForSizeFallback *ffsd = nullptr;2057ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Ref<Image>());2058ERR_FAIL_INDEX_V(p_texture_index, ffsd->textures.size(), Ref<Image>());20592060const ShelfPackTexture &tex = ffsd->textures[p_texture_index];2061return tex.image;2062}20632064void TextServerFallback::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offsets) {2065ERR_FAIL_COND(p_offsets.size() % 4 != 0);2066FontFallback *fd = _get_font_data(p_font_rid);2067ERR_FAIL_NULL(fd);20682069MutexLock lock(fd->mutex);2070Vector2i size = _get_size_outline(fd, p_size);2071FontForSizeFallback *ffsd = nullptr;2072ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2073ERR_FAIL_COND(p_texture_index < 0);2074if (p_texture_index >= ffsd->textures.size()) {2075ffsd->textures.resize(p_texture_index + 1);2076}20772078ShelfPackTexture &tex = ffsd->textures.write[p_texture_index];2079tex.shelves.clear();2080for (int32_t i = 0; i < p_offsets.size(); i += 4) {2081tex.shelves.push_back(Shelf(p_offsets[i], p_offsets[i + 1], p_offsets[i + 2], p_offsets[i + 3]));2082}2083}20842085PackedInt32Array TextServerFallback::_font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {2086FontFallback *fd = _get_font_data(p_font_rid);2087ERR_FAIL_NULL_V(fd, PackedInt32Array());20882089MutexLock lock(fd->mutex);2090Vector2i size = _get_size_outline(fd, p_size);2091FontForSizeFallback *ffsd = nullptr;2092ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), PackedInt32Array());2093ERR_FAIL_INDEX_V(p_texture_index, ffsd->textures.size(), PackedInt32Array());20942095const ShelfPackTexture &tex = ffsd->textures[p_texture_index];2096PackedInt32Array ret;2097ret.resize(tex.shelves.size() * 4);20982099int32_t *wr = ret.ptrw();2100int32_t i = 0;2101for (const Shelf &E : tex.shelves) {2102wr[i * 4] = E.x;2103wr[i * 4 + 1] = E.y;2104wr[i * 4 + 2] = E.w;2105wr[i * 4 + 3] = E.h;2106i++;2107}2108return ret;2109}21102111PackedInt32Array TextServerFallback::_font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {2112FontFallback *fd = _get_font_data(p_font_rid);2113ERR_FAIL_NULL_V(fd, PackedInt32Array());21142115MutexLock lock(fd->mutex);2116Vector2i size = _get_size_outline(fd, p_size);2117FontForSizeFallback *ffsd = nullptr;2118ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), PackedInt32Array());21192120PackedInt32Array ret;2121const HashMap<int32_t, FontGlyph> &gl = ffsd->glyph_map;2122for (const KeyValue<int32_t, FontGlyph> &E : gl) {2123ret.push_back(E.key);2124}2125return ret;2126}21272128void TextServerFallback::_font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) {2129FontFallback *fd = _get_font_data(p_font_rid);2130ERR_FAIL_NULL(fd);21312132MutexLock lock(fd->mutex);2133Vector2i size = _get_size_outline(fd, p_size);2134FontForSizeFallback *ffsd = nullptr;2135ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));21362137ffsd->glyph_map.clear();2138}21392140void TextServerFallback::_font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) {2141FontFallback *fd = _get_font_data(p_font_rid);2142ERR_FAIL_NULL(fd);21432144MutexLock lock(fd->mutex);2145Vector2i size = _get_size_outline(fd, p_size);2146FontForSizeFallback *ffsd = nullptr;2147ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));21482149ffsd->glyph_map.erase(p_glyph);2150}21512152Vector2 TextServerFallback::_font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const {2153FontFallback *fd = _get_font_data(p_font_rid);2154ERR_FAIL_NULL_V(fd, Vector2());21552156MutexLock lock(fd->mutex);2157Vector2i size = _get_size(fd, p_size);21582159FontForSizeFallback *ffsd = nullptr;2160ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());21612162int mod = 0;2163if (fd->antialiasing == FONT_ANTIALIASING_LCD) {2164TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();2165if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {2166mod = (layout << 24);2167}2168}21692170FontGlyph fgl;2171if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {2172return Vector2(); // Invalid or non graphicl glyph, do not display errors.2173}21742175Vector2 ea;2176if (fd->embolden != 0.0) {2177ea.x = fd->embolden * double(size.x) / 4096.0;2178}21792180double scale = _font_get_scale(p_font_rid, p_size);2181if (fd->msdf) {2182return (fgl.advance + ea) * (double)p_size / (double)fd->msdf_source_size;2183} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {2184if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2185return (fgl.advance + ea) * (double)p_size / (double)fd->fixed_size;2186} else {2187return (fgl.advance + ea) * Math::round((double)p_size / (double)fd->fixed_size);2188}2189} 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))) {2190return (fgl.advance + ea).round();2191} else {2192return fgl.advance + ea;2193}2194}21952196void TextServerFallback::_font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) {2197FontFallback *fd = _get_font_data(p_font_rid);2198ERR_FAIL_NULL(fd);21992200MutexLock lock(fd->mutex);2201Vector2i size = _get_size(fd, p_size);22022203FontForSizeFallback *ffsd = nullptr;2204ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));22052206FontGlyph &fgl = ffsd->glyph_map[p_glyph];22072208fgl.advance = p_advance;2209fgl.found = true;2210}22112212Vector2 TextServerFallback::_font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {2213FontFallback *fd = _get_font_data(p_font_rid);2214ERR_FAIL_NULL_V(fd, Vector2());22152216MutexLock lock(fd->mutex);2217Vector2i size = _get_size_outline(fd, p_size);22182219FontForSizeFallback *ffsd = nullptr;2220ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());22212222int mod = 0;2223if (fd->antialiasing == FONT_ANTIALIASING_LCD) {2224TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();2225if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {2226mod = (layout << 24);2227}2228}22292230FontGlyph fgl;2231if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {2232return Vector2(); // Invalid or non graphicl glyph, do not display errors.2233}22342235if (fd->msdf) {2236return fgl.rect.position * (double)p_size.x / (double)fd->msdf_source_size;2237} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size.x * 64) {2238if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2239return fgl.rect.position * (double)p_size.x / (double)fd->fixed_size;2240} else {2241return fgl.rect.position * Math::round((double)p_size.x / (double)fd->fixed_size);2242}2243} else {2244return fgl.rect.position;2245}2246}22472248void TextServerFallback::_font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) {2249FontFallback *fd = _get_font_data(p_font_rid);2250ERR_FAIL_NULL(fd);22512252MutexLock lock(fd->mutex);2253Vector2i size = _get_size_outline(fd, p_size);22542255FontForSizeFallback *ffsd = nullptr;2256ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));22572258FontGlyph &fgl = ffsd->glyph_map[p_glyph];22592260fgl.rect.position = p_offset;2261fgl.found = true;2262}22632264Vector2 TextServerFallback::_font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {2265FontFallback *fd = _get_font_data(p_font_rid);2266ERR_FAIL_NULL_V(fd, Vector2());22672268MutexLock lock(fd->mutex);2269Vector2i size = _get_size_outline(fd, p_size);22702271FontForSizeFallback *ffsd = nullptr;2272ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());22732274int mod = 0;2275if (fd->antialiasing == FONT_ANTIALIASING_LCD) {2276TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();2277if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {2278mod = (layout << 24);2279}2280}22812282FontGlyph fgl;2283if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {2284return Vector2(); // Invalid or non graphicl glyph, do not display errors.2285}22862287if (fd->msdf) {2288return fgl.rect.size * (double)p_size.x / (double)fd->msdf_source_size;2289} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size.x * 64) {2290if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2291return fgl.rect.size * (double)p_size.x / (double)fd->fixed_size;2292} else {2293return fgl.rect.size * Math::round((double)p_size.x / (double)fd->fixed_size);2294}2295} else {2296return fgl.rect.size;2297}2298}22992300void TextServerFallback::_font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) {2301FontFallback *fd = _get_font_data(p_font_rid);2302ERR_FAIL_NULL(fd);23032304MutexLock lock(fd->mutex);2305Vector2i size = _get_size_outline(fd, p_size);23062307FontForSizeFallback *ffsd = nullptr;2308ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));23092310FontGlyph &fgl = ffsd->glyph_map[p_glyph];23112312fgl.rect.size = p_gl_size;2313fgl.found = true;2314}23152316Rect2 TextServerFallback::_font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {2317FontFallback *fd = _get_font_data(p_font_rid);2318ERR_FAIL_NULL_V(fd, Rect2());23192320MutexLock lock(fd->mutex);2321Vector2i size = _get_size_outline(fd, p_size);23222323FontForSizeFallback *ffsd = nullptr;2324ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Rect2());23252326int mod = 0;2327if (fd->antialiasing == FONT_ANTIALIASING_LCD) {2328TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();2329if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {2330mod = (layout << 24);2331}2332}23332334FontGlyph fgl;2335if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {2336return Rect2(); // Invalid or non graphicl glyph, do not display errors.2337}23382339return fgl.uv_rect;2340}23412342void TextServerFallback::_font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) {2343FontFallback *fd = _get_font_data(p_font_rid);2344ERR_FAIL_NULL(fd);23452346MutexLock lock(fd->mutex);2347Vector2i size = _get_size_outline(fd, p_size);23482349FontForSizeFallback *ffsd = nullptr;2350ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));23512352FontGlyph &fgl = ffsd->glyph_map[p_glyph];23532354fgl.uv_rect = p_uv_rect;2355fgl.found = true;2356}23572358int64_t TextServerFallback::_font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {2359FontFallback *fd = _get_font_data(p_font_rid);2360ERR_FAIL_NULL_V(fd, -1);23612362MutexLock lock(fd->mutex);2363Vector2i size = _get_size_outline(fd, p_size);23642365FontForSizeFallback *ffsd = nullptr;2366ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), -1);23672368int mod = 0;2369if (fd->antialiasing == FONT_ANTIALIASING_LCD) {2370TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();2371if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {2372mod = (layout << 24);2373}2374}23752376FontGlyph fgl;2377if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {2378return -1; // Invalid or non graphicl glyph, do not display errors.2379}23802381return fgl.texture_idx;2382}23832384void TextServerFallback::_font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) {2385FontFallback *fd = _get_font_data(p_font_rid);2386ERR_FAIL_NULL(fd);23872388MutexLock lock(fd->mutex);2389Vector2i size = _get_size_outline(fd, p_size);23902391FontForSizeFallback *ffsd = nullptr;2392ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));23932394FontGlyph &fgl = ffsd->glyph_map[p_glyph];23952396fgl.texture_idx = p_texture_idx;2397fgl.found = true;2398}23992400RID TextServerFallback::_font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {2401FontFallback *fd = _get_font_data(p_font_rid);2402ERR_FAIL_NULL_V(fd, RID());24032404MutexLock lock(fd->mutex);2405Vector2i size = _get_size_outline(fd, p_size);24062407FontForSizeFallback *ffsd = nullptr;2408ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), RID());24092410int mod = 0;2411if (fd->antialiasing == FONT_ANTIALIASING_LCD) {2412TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();2413if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {2414mod = (layout << 24);2415}2416}24172418FontGlyph fgl;2419if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {2420return RID(); // Invalid or non graphicl glyph, do not display errors.2421}24222423ERR_FAIL_COND_V(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size(), RID());24242425if (RenderingServer::get_singleton() != nullptr) {2426if (fgl.texture_idx != -1) {2427if (ffsd->textures[fgl.texture_idx].dirty) {2428ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];2429Ref<Image> img = tex.image;2430if (fgl.from_svg) {2431// Same as the "fix alpha border" process option when importing SVGs2432img->fix_alpha_edges();2433}2434if (fd->mipmaps && !img->has_mipmaps()) {2435img = tex.image->duplicate();2436img->generate_mipmaps();2437}2438if (tex.texture.is_null()) {2439tex.texture = ImageTexture::create_from_image(img);2440} else {2441tex.texture->update(img);2442}2443tex.dirty = false;2444}2445return ffsd->textures[fgl.texture_idx].texture->get_rid();2446}2447}24482449return RID();2450}24512452Size2 TextServerFallback::_font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {2453FontFallback *fd = _get_font_data(p_font_rid);2454ERR_FAIL_NULL_V(fd, Size2());24552456MutexLock lock(fd->mutex);2457Vector2i size = _get_size_outline(fd, p_size);24582459FontForSizeFallback *ffsd = nullptr;2460ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Size2());24612462int mod = 0;2463if (fd->antialiasing == FONT_ANTIALIASING_LCD) {2464TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();2465if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {2466mod = (layout << 24);2467}2468}24692470FontGlyph fgl;2471if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {2472return Size2(); // Invalid or non graphicl glyph, do not display errors.2473}24742475ERR_FAIL_COND_V(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size(), Size2());24762477if (RenderingServer::get_singleton() != nullptr) {2478if (fgl.texture_idx != -1) {2479if (ffsd->textures[fgl.texture_idx].dirty) {2480ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];2481Ref<Image> img = tex.image;2482if (fgl.from_svg) {2483// Same as the "fix alpha border" process option when importing SVGs2484img->fix_alpha_edges();2485}2486if (fd->mipmaps && !img->has_mipmaps()) {2487img = tex.image->duplicate();2488img->generate_mipmaps();2489}2490if (tex.texture.is_null()) {2491tex.texture = ImageTexture::create_from_image(img);2492} else {2493tex.texture->update(img);2494}2495tex.dirty = false;2496}2497return ffsd->textures[fgl.texture_idx].texture->get_size();2498}2499}25002501return Size2();2502}25032504Dictionary TextServerFallback::_font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const {2505FontFallback *fd = _get_font_data(p_font_rid);2506ERR_FAIL_NULL_V(fd, Dictionary());25072508MutexLock lock(fd->mutex);2509Vector2i size = _get_size(fd, p_size);25102511FontForSizeFallback *ffsd = nullptr;2512ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary());25132514#ifdef MODULE_FREETYPE_ENABLED2515PackedVector3Array points;2516PackedInt32Array contours;25172518int32_t index = p_index & 0xffffff; // Remove subpixel shifts.25192520int error = FT_Load_Glyph(ffsd->face, FT_Get_Char_Index(ffsd->face, index), FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));2521ERR_FAIL_COND_V(error, Dictionary());25222523if (fd->embolden != 0.f) {2524FT_Pos strength = fd->embolden * size.x / 16; // 26.6 fractional units (1 / 64).2525FT_Outline_Embolden(&ffsd->face->glyph->outline, strength);2526}25272528if (fd->transform != Transform2D()) {2529FT_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).2530FT_Outline_Transform(&ffsd->face->glyph->outline, &mat);2531}25322533double scale = (1.0 / 64.0) * ffsd->scale;2534if (fd->msdf) {2535scale = scale * (double)p_size / (double)fd->msdf_source_size;2536} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {2537if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2538scale = scale * (double)p_size / (double)fd->fixed_size;2539} else {2540scale = scale * Math::round((double)p_size / (double)fd->fixed_size);2541}2542}2543for (short i = 0; i < ffsd->face->glyph->outline.n_points; i++) {2544points.push_back(Vector3(ffsd->face->glyph->outline.points[i].x * scale, -ffsd->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(ffsd->face->glyph->outline.tags[i])));2545}2546for (short i = 0; i < ffsd->face->glyph->outline.n_contours; i++) {2547contours.push_back(ffsd->face->glyph->outline.contours[i]);2548}2549bool orientation = (FT_Outline_Get_Orientation(&ffsd->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);25502551Dictionary out;2552out["points"] = points;2553out["contours"] = contours;2554out["orientation"] = orientation;2555return out;2556#else2557return Dictionary();2558#endif2559}25602561TypedArray<Vector2i> TextServerFallback::_font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {2562FontFallback *fd = _get_font_data(p_font_rid);2563ERR_FAIL_NULL_V(fd, TypedArray<Vector2i>());25642565MutexLock lock(fd->mutex);2566Vector2i size = _get_size(fd, p_size);25672568FontForSizeFallback *ffsd = nullptr;2569ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), TypedArray<Vector2i>());25702571TypedArray<Vector2i> ret;2572for (const KeyValue<Vector2i, Vector2> &E : ffsd->kerning_map) {2573ret.push_back(E.key);2574}2575return ret;2576}25772578void TextServerFallback::_font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) {2579FontFallback *fd = _get_font_data(p_font_rid);2580ERR_FAIL_NULL(fd);25812582MutexLock lock(fd->mutex);2583Vector2i size = _get_size(fd, p_size);25842585FontForSizeFallback *ffsd = nullptr;2586ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2587ffsd->kerning_map.clear();2588}25892590void TextServerFallback::_font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) {2591FontFallback *fd = _get_font_data(p_font_rid);2592ERR_FAIL_NULL(fd);25932594MutexLock lock(fd->mutex);2595Vector2i size = _get_size(fd, p_size);25962597FontForSizeFallback *ffsd = nullptr;2598ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2599ffsd->kerning_map.erase(p_glyph_pair);2600}26012602void TextServerFallback::_font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {2603FontFallback *fd = _get_font_data(p_font_rid);2604ERR_FAIL_NULL(fd);26052606MutexLock lock(fd->mutex);2607Vector2i size = _get_size(fd, p_size);26082609FontForSizeFallback *ffsd = nullptr;2610ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2611ffsd->kerning_map[p_glyph_pair] = p_kerning;2612}26132614Vector2 TextServerFallback::_font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const {2615FontFallback *fd = _get_font_data(p_font_rid);2616ERR_FAIL_NULL_V(fd, Vector2());26172618MutexLock lock(fd->mutex);2619Vector2i size = _get_size(fd, p_size);26202621FontForSizeFallback *ffsd = nullptr;2622ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());26232624const HashMap<Vector2i, Vector2> &kern = ffsd->kerning_map;26252626if (kern.has(p_glyph_pair)) {2627if (fd->msdf) {2628return kern[p_glyph_pair] * (double)p_size / (double)fd->msdf_source_size;2629} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {2630if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2631return kern[p_glyph_pair] * (double)p_size / (double)fd->fixed_size;2632} else {2633return kern[p_glyph_pair] * Math::round((double)p_size / (double)fd->fixed_size);2634}2635} else {2636return kern[p_glyph_pair];2637}2638} else {2639#ifdef MODULE_FREETYPE_ENABLED2640if (ffsd->face) {2641FT_Vector delta;2642int32_t glyph_a = FT_Get_Char_Index(ffsd->face, p_glyph_pair.x);2643int32_t glyph_b = FT_Get_Char_Index(ffsd->face, p_glyph_pair.y);2644FT_Get_Kerning(ffsd->face, glyph_a, glyph_b, FT_KERNING_DEFAULT, &delta);2645if (fd->msdf) {2646return Vector2(delta.x, delta.y) * (double)p_size / (double)fd->msdf_source_size;2647} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {2648if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2649return Vector2(delta.x, delta.y) * (double)p_size / (double)fd->fixed_size;2650} else {2651return Vector2(delta.x, delta.y) * Math::round((double)p_size / (double)fd->fixed_size);2652}2653} else {2654return Vector2(delta.x, delta.y);2655}2656}2657#endif2658}2659return Vector2();2660}26612662int64_t TextServerFallback::_font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const {2663ERR_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) + ".");2664return (int64_t)p_char;2665}26662667int64_t TextServerFallback::_font_get_char_from_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_glyph_index) const {2668return p_glyph_index;2669}26702671bool TextServerFallback::_font_has_char(const RID &p_font_rid, int64_t p_char) const {2672FontFallback *fd = _get_font_data(p_font_rid);2673ERR_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) + ".");2674if (!fd) {2675return false;2676}26772678MutexLock lock(fd->mutex);2679FontForSizeFallback *ffsd = nullptr;2680if (fd->cache.is_empty()) {2681ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size * 64, 0) : Vector2i(16 * 64, 0), ffsd), false);2682} else {2683ffsd = fd->cache.begin()->value;2684}26852686#ifdef MODULE_FREETYPE_ENABLED2687if (ffsd->face) {2688return FT_Get_Char_Index(ffsd->face, p_char) != 0;2689}2690#endif2691return ffsd->glyph_map.has((int32_t)p_char);2692}26932694String TextServerFallback::_font_get_supported_chars(const RID &p_font_rid) const {2695FontFallback *fd = _get_font_data(p_font_rid);2696ERR_FAIL_NULL_V(fd, String());26972698MutexLock lock(fd->mutex);2699FontForSizeFallback *ffsd = nullptr;2700if (fd->cache.is_empty()) {2701ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size * 64, 0) : Vector2i(16 * 64, 0), ffsd), String());2702} else {2703ffsd = fd->cache.begin()->value;2704}27052706String chars;2707#ifdef MODULE_FREETYPE_ENABLED2708if (ffsd->face) {2709FT_UInt gindex;2710FT_ULong charcode = FT_Get_First_Char(ffsd->face, &gindex);2711while (gindex != 0) {2712if (charcode != 0) {2713chars = chars + String::chr(charcode);2714}2715charcode = FT_Get_Next_Char(ffsd->face, charcode, &gindex);2716}2717return chars;2718}2719#endif2720const HashMap<int32_t, FontGlyph> &gl = ffsd->glyph_map;2721for (const KeyValue<int32_t, FontGlyph> &E : gl) {2722chars = chars + String::chr(E.key);2723}2724return chars;2725}27262727PackedInt32Array TextServerFallback::_font_get_supported_glyphs(const RID &p_font_rid) const {2728FontFallback *fd = _get_font_data(p_font_rid);2729ERR_FAIL_NULL_V(fd, PackedInt32Array());27302731MutexLock lock(fd->mutex);2732FontForSizeFallback *at_size = nullptr;2733if (fd->cache.is_empty()) {2734ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size * 64, 0) : Vector2i(16 * 64, 0), at_size), PackedInt32Array());2735} else {2736at_size = fd->cache.begin()->value;2737}27382739PackedInt32Array glyphs;2740#ifdef MODULE_FREETYPE_ENABLED2741if (at_size && at_size->face) {2742FT_UInt gindex;2743FT_ULong charcode = FT_Get_First_Char(at_size->face, &gindex);2744while (gindex != 0) {2745glyphs.push_back(gindex);2746charcode = FT_Get_Next_Char(at_size->face, charcode, &gindex);2747}2748return glyphs;2749}2750#endif2751if (at_size) {2752const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map;2753for (const KeyValue<int32_t, FontGlyph> &E : gl) {2754glyphs.push_back(E.key);2755}2756}2757return glyphs;2758}27592760void TextServerFallback::_font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) {2761FontFallback *fd = _get_font_data(p_font_rid);2762ERR_FAIL_NULL(fd);2763ERR_FAIL_COND_MSG((p_start >= 0xd800 && p_start <= 0xdfff) || (p_start > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_start, 16) + ".");2764ERR_FAIL_COND_MSG((p_end >= 0xd800 && p_end <= 0xdfff) || (p_end > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_end, 16) + ".");27652766MutexLock lock(fd->mutex);2767Vector2i size = _get_size_outline(fd, p_size);2768FontForSizeFallback *ffsd = nullptr;2769ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2770for (int64_t i = p_start; i <= p_end; i++) {2771#ifdef MODULE_FREETYPE_ENABLED2772int32_t idx = i;2773if (ffsd->face) {2774FontGlyph fgl;2775if (fd->msdf) {2776_ensure_glyph(fd, size, (int32_t)idx, fgl);2777} else {2778for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {2779if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {2780_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);2781_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);2782_ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24), fgl);2783_ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24), fgl);2784} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {2785_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);2786_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);2787} else {2788_ensure_glyph(fd, size, (int32_t)idx | (aa << 24), fgl);2789}2790}2791}2792}2793#endif2794}2795}27962797void TextServerFallback::_font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) {2798FontFallback *fd = _get_font_data(p_font_rid);2799ERR_FAIL_NULL(fd);28002801MutexLock lock(fd->mutex);2802Vector2i size = _get_size_outline(fd, p_size);2803FontForSizeFallback *ffsd = nullptr;2804ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));2805#ifdef MODULE_FREETYPE_ENABLED2806int32_t idx = p_index & 0xffffff; // Remove subpixel shifts.2807if (ffsd->face) {2808FontGlyph fgl;2809if (fd->msdf) {2810_ensure_glyph(fd, size, (int32_t)idx, fgl);2811} else {2812for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {2813if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {2814_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);2815_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);2816_ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24), fgl);2817_ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24), fgl);2818} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {2819_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);2820_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);2821} else {2822_ensure_glyph(fd, size, (int32_t)idx | (aa << 24), fgl);2823}2824}2825}2826}2827#endif2828}28292830void TextServerFallback::_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 {2831if (p_index == 0) {2832return; // Non visual character, skip.2833}2834FontFallback *fd = _get_font_data(p_font_rid);2835ERR_FAIL_NULL(fd);28362837MutexLock lock(fd->mutex);28382839// Oversampling.2840bool viewport_oversampling = false;2841float oversampling_factor = p_oversampling;2842if (p_oversampling <= 0.0) {2843if (fd->oversampling_override > 0.0) {2844oversampling_factor = fd->oversampling_override;2845} else if (vp_oversampling > 0.0) {2846oversampling_factor = vp_oversampling;2847viewport_oversampling = true;2848} else {2849oversampling_factor = 1.0;2850}2851}2852bool skip_oversampling = fd->msdf || fd->fixed_size > 0;2853if (skip_oversampling) {2854oversampling_factor = 1.0;2855} else {2856uint64_t oversampling_level = CLAMP(oversampling_factor, 0.1, 100.0) * 64;2857oversampling_factor = double(oversampling_level) / 64.0;2858}28592860Vector2i size;2861if (skip_oversampling) {2862size = _get_size(fd, p_size);2863} else {2864size = Vector2i(p_size * 64 * oversampling_factor, 0);2865}28662867FontForSizeFallback *ffsd = nullptr;2868ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd, false, viewport_oversampling ? 64 * oversampling_factor : 0));28692870int32_t index = p_index & 0xffffff; // Remove subpixel shifts.2871bool lcd_aa = false;28722873#ifdef MODULE_FREETYPE_ENABLED2874if (!fd->msdf && ffsd->face) {2875// LCD layout, bits 24, 25, 262876if (fd->antialiasing == FONT_ANTIALIASING_LCD) {2877TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();2878if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {2879lcd_aa = true;2880index = index | (layout << 24);2881}2882}2883// Subpixel X-shift, bits 27, 282884if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {2885int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));2886index = index | (xshift << 27);2887} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {2888int xshift = (int)(Math::floor(2 * (p_pos.x + 0.25)) - 2 * Math::floor(p_pos.x + 0.25));2889index = index | (xshift << 27);2890}2891}2892#endif28932894FontGlyph fgl;2895if (!_ensure_glyph(fd, size, index, fgl, viewport_oversampling ? 64 * oversampling_factor : 0)) {2896return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.2897}28982899if (fgl.found) {2900ERR_FAIL_COND(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size());29012902if (fgl.texture_idx != -1) {2903Color modulate = p_color;2904#ifdef MODULE_FREETYPE_ENABLED2905if (!fd->modulate_color_glyphs && ffsd->face && ffsd->textures[fgl.texture_idx].image.is_valid() && (ffsd->textures[fgl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {2906modulate.r = modulate.g = modulate.b = 1.0;2907}2908#endif2909if (RenderingServer::get_singleton() != nullptr) {2910if (ffsd->textures[fgl.texture_idx].dirty) {2911ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];2912Ref<Image> img = tex.image;2913if (fgl.from_svg) {2914// Same as the "fix alpha border" process option when importing SVGs2915img->fix_alpha_edges();2916}2917if (fd->mipmaps && !img->has_mipmaps()) {2918img = tex.image->duplicate();2919img->generate_mipmaps();2920}2921if (tex.texture.is_null()) {2922tex.texture = ImageTexture::create_from_image(img);2923} else {2924tex.texture->update(img);2925}2926tex.dirty = false;2927}2928RID texture = ffsd->textures[fgl.texture_idx].texture->get_rid();2929if (fd->msdf) {2930Point2 cpos = p_pos;2931cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size;2932Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size;2933RenderingServer::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);2934} else {2935Point2 cpos = p_pos;2936double scale = _font_get_scale(p_font_rid, p_size) / oversampling_factor;2937if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {2938cpos.x = cpos.x + 0.125;2939} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {2940cpos.x = cpos.x + 0.25;2941}2942if (scale == 1.0) {2943cpos.y = Math::floor(cpos.y);2944cpos.x = Math::floor(cpos.x);2945}2946Vector2 gpos = fgl.rect.position;2947Size2 csize = fgl.rect.size;2948if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE) {2949if (size.x != p_size * 64) {2950if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {2951double gl_scale = (double)p_size / (double)fd->fixed_size;2952gpos *= gl_scale;2953csize *= gl_scale;2954} else {2955double gl_scale = Math::round((double)p_size / (double)fd->fixed_size);2956gpos *= gl_scale;2957csize *= gl_scale;2958}2959}2960} else {2961gpos /= oversampling_factor;2962csize /= oversampling_factor;2963}2964cpos += gpos;2965if (lcd_aa) {2966RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate);2967} else {2968RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false);2969}2970}2971}2972}2973}2974}29752976void TextServerFallback::_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 {2977if (p_index == 0) {2978return; // Non visual character, skip.2979}2980FontFallback *fd = _get_font_data(p_font_rid);2981ERR_FAIL_NULL(fd);29822983MutexLock lock(fd->mutex);29842985// Oversampling.2986bool viewport_oversampling = false;2987float oversampling_factor = p_oversampling;2988if (p_oversampling <= 0.0) {2989if (fd->oversampling_override > 0.0) {2990oversampling_factor = fd->oversampling_override;2991} else if (vp_oversampling > 0.0) {2992oversampling_factor = vp_oversampling;2993viewport_oversampling = true;2994} else {2995oversampling_factor = 1.0;2996}2997}2998bool skip_oversampling = fd->msdf || fd->fixed_size > 0;2999if (skip_oversampling) {3000oversampling_factor = 1.0;3001} else {3002uint64_t oversampling_level = CLAMP(oversampling_factor, 0.1, 100.0) * 64;3003oversampling_factor = double(oversampling_level) / 64.0;3004}30053006Vector2i size;3007if (skip_oversampling) {3008size = _get_size_outline(fd, Vector2i(p_size, p_outline_size));3009} else {3010size = Vector2i(p_size * 64 * oversampling_factor, p_outline_size * oversampling_factor);3011}30123013FontForSizeFallback *ffsd = nullptr;3014ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd, false, viewport_oversampling ? 64 * oversampling_factor : 0));30153016int32_t index = p_index & 0xffffff; // Remove subpixel shifts.3017bool lcd_aa = false;30183019#ifdef MODULE_FREETYPE_ENABLED3020if (!fd->msdf && ffsd->face) {3021// LCD layout, bits 24, 25, 263022if (fd->antialiasing == FONT_ANTIALIASING_LCD) {3023TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();3024if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {3025lcd_aa = true;3026index = index | (layout << 24);3027}3028}3029// Subpixel X-shift, bits 27, 283030if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {3031int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));3032index = index | (xshift << 27);3033} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {3034int xshift = (int)(Math::floor(2 * (p_pos.x + 0.25)) - 2 * Math::floor(p_pos.x + 0.25));3035index = index | (xshift << 27);3036}3037}3038#endif30393040FontGlyph fgl;3041if (!_ensure_glyph(fd, size, index, fgl, viewport_oversampling ? 64 * oversampling_factor : 0)) {3042return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.3043}30443045if (fgl.found) {3046ERR_FAIL_COND(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size());30473048if (fgl.texture_idx != -1) {3049Color modulate = p_color;3050#ifdef MODULE_FREETYPE_ENABLED3051if (ffsd->face && ffsd->textures[fgl.texture_idx].image.is_valid() && (ffsd->textures[fgl.texture_idx].image->get_format() == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {3052modulate.r = modulate.g = modulate.b = 1.0;3053}3054#endif3055if (RenderingServer::get_singleton() != nullptr) {3056if (ffsd->textures[fgl.texture_idx].dirty) {3057ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];3058Ref<Image> img = tex.image;3059if (fd->mipmaps && !img->has_mipmaps()) {3060img = tex.image->duplicate();3061img->generate_mipmaps();3062}3063if (tex.texture.is_null()) {3064tex.texture = ImageTexture::create_from_image(img);3065} else {3066tex.texture->update(img);3067}3068tex.dirty = false;3069}3070RID texture = ffsd->textures[fgl.texture_idx].texture->get_rid();3071if (fd->msdf) {3072Point2 cpos = p_pos;3073cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size;3074Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size;3075RenderingServer::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);3076} else {3077Point2 cpos = p_pos;3078double scale = _font_get_scale(p_font_rid, p_size) / oversampling_factor;3079if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {3080cpos.x = cpos.x + 0.125;3081} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {3082cpos.x = cpos.x + 0.25;3083}3084if (scale == 1.0) {3085cpos.y = Math::floor(cpos.y);3086cpos.x = Math::floor(cpos.x);3087}3088Vector2 gpos = fgl.rect.position;3089Size2 csize = fgl.rect.size;3090if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE) {3091if (size.x != p_size * 64) {3092if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {3093double gl_scale = (double)p_size / (double)fd->fixed_size;3094gpos *= gl_scale;3095csize *= gl_scale;3096} else {3097double gl_scale = Math::round((double)p_size / (double)fd->fixed_size);3098gpos *= gl_scale;3099csize *= gl_scale;3100}3101}3102} else {3103gpos /= oversampling_factor;3104csize /= oversampling_factor;3105}3106cpos += gpos;3107if (lcd_aa) {3108RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate);3109} else {3110RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false);3111}3112}3113}3114}3115}3116}31173118bool TextServerFallback::_font_is_language_supported(const RID &p_font_rid, const String &p_language) const {3119FontFallback *fd = _get_font_data(p_font_rid);3120ERR_FAIL_NULL_V(fd, false);31213122MutexLock lock(fd->mutex);3123if (fd->language_support_overrides.has(p_language)) {3124return fd->language_support_overrides[p_language];3125} else {3126return true;3127}3128}31293130void TextServerFallback::_font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) {3131FontFallback *fd = _get_font_data(p_font_rid);3132ERR_FAIL_NULL(fd);31333134MutexLock lock(fd->mutex);3135fd->language_support_overrides[p_language] = p_supported;3136}31373138bool TextServerFallback::_font_get_language_support_override(const RID &p_font_rid, const String &p_language) {3139FontFallback *fd = _get_font_data(p_font_rid);3140ERR_FAIL_NULL_V(fd, false);31413142MutexLock lock(fd->mutex);3143return fd->language_support_overrides[p_language];3144}31453146void TextServerFallback::_font_remove_language_support_override(const RID &p_font_rid, const String &p_language) {3147FontFallback *fd = _get_font_data(p_font_rid);3148ERR_FAIL_NULL(fd);31493150MutexLock lock(fd->mutex);3151fd->language_support_overrides.erase(p_language);3152}31533154PackedStringArray TextServerFallback::_font_get_language_support_overrides(const RID &p_font_rid) {3155FontFallback *fd = _get_font_data(p_font_rid);3156ERR_FAIL_NULL_V(fd, PackedStringArray());31573158MutexLock lock(fd->mutex);3159PackedStringArray out;3160for (const KeyValue<String, bool> &E : fd->language_support_overrides) {3161out.push_back(E.key);3162}3163return out;3164}31653166bool TextServerFallback::_font_is_script_supported(const RID &p_font_rid, const String &p_script) const {3167FontFallback *fd = _get_font_data(p_font_rid);3168ERR_FAIL_NULL_V(fd, false);31693170MutexLock lock(fd->mutex);3171if (fd->script_support_overrides.has(p_script)) {3172return fd->script_support_overrides[p_script];3173} else {3174return true;3175}3176}31773178void TextServerFallback::_font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) {3179FontFallback *fd = _get_font_data(p_font_rid);3180ERR_FAIL_NULL(fd);31813182MutexLock lock(fd->mutex);3183fd->script_support_overrides[p_script] = p_supported;3184}31853186bool TextServerFallback::_font_get_script_support_override(const RID &p_font_rid, const String &p_script) {3187FontFallback *fd = _get_font_data(p_font_rid);3188ERR_FAIL_NULL_V(fd, false);31893190MutexLock lock(fd->mutex);3191return fd->script_support_overrides[p_script];3192}31933194void TextServerFallback::_font_remove_script_support_override(const RID &p_font_rid, const String &p_script) {3195FontFallback *fd = _get_font_data(p_font_rid);3196ERR_FAIL_NULL(fd);31973198MutexLock lock(fd->mutex);3199Vector2i size = _get_size(fd, 16);3200FontForSizeFallback *ffsd = nullptr;3201ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3202fd->script_support_overrides.erase(p_script);3203}32043205PackedStringArray TextServerFallback::_font_get_script_support_overrides(const RID &p_font_rid) {3206FontFallback *fd = _get_font_data(p_font_rid);3207ERR_FAIL_NULL_V(fd, PackedStringArray());32083209MutexLock lock(fd->mutex);3210PackedStringArray out;3211for (const KeyValue<String, bool> &E : fd->script_support_overrides) {3212out.push_back(E.key);3213}3214return out;3215}32163217void TextServerFallback::_font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) {3218FontFallback *fd = _get_font_data(p_font_rid);3219ERR_FAIL_NULL(fd);32203221MutexLock lock(fd->mutex);3222Vector2i size = _get_size(fd, 16);3223FontForSizeFallback *ffsd = nullptr;3224ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));3225fd->feature_overrides = p_overrides;3226}32273228Dictionary TextServerFallback::_font_get_opentype_feature_overrides(const RID &p_font_rid) const {3229FontFallback *fd = _get_font_data(p_font_rid);3230ERR_FAIL_NULL_V(fd, Dictionary());32313232MutexLock lock(fd->mutex);3233return fd->feature_overrides;3234}32353236Dictionary TextServerFallback::_font_supported_feature_list(const RID &p_font_rid) const {3237return Dictionary();3238}32393240Dictionary TextServerFallback::_font_supported_variation_list(const RID &p_font_rid) const {3241FontFallback *fd = _get_font_data(p_font_rid);3242ERR_FAIL_NULL_V(fd, Dictionary());32433244MutexLock lock(fd->mutex);3245Vector2i size = _get_size(fd, 16);3246FontForSizeFallback *ffsd = nullptr;3247ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary());3248return fd->supported_varaitions;3249}32503251/*************************************************************************/3252/* Shaped text buffer interface */3253/*************************************************************************/32543255void TextServerFallback::invalidate(ShapedTextDataFallback *p_shaped) {3256p_shaped->valid.clear();3257p_shaped->sort_valid = false;3258p_shaped->line_breaks_valid = false;3259p_shaped->justification_ops_valid = false;3260p_shaped->ascent = 0.0;3261p_shaped->descent = 0.0;3262p_shaped->width = 0.0;3263p_shaped->upos = 0.0;3264p_shaped->uthk = 0.0;3265p_shaped->glyphs.clear();3266p_shaped->glyphs_logical.clear();3267p_shaped->runs.clear();3268p_shaped->runs_dirty = true;3269}32703271void TextServerFallback::full_copy(ShapedTextDataFallback *p_shaped) {3272ShapedTextDataFallback *parent = shaped_owner.get_or_null(p_shaped->parent);32733274for (const KeyValue<Variant, ShapedTextDataFallback::EmbeddedObject> &E : parent->objects) {3275if (E.value.start >= p_shaped->start && E.value.start < p_shaped->end) {3276p_shaped->objects[E.key] = E.value;3277}3278}32793280for (int i = p_shaped->first_span; i <= p_shaped->last_span; i++) {3281ShapedTextDataFallback::Span span = parent->spans[i];3282span.start = MAX(p_shaped->start, span.start);3283span.end = MIN(p_shaped->end, span.end);3284p_shaped->spans.push_back(span);3285}3286p_shaped->first_span = 0;3287p_shaped->last_span = 0;32883289p_shaped->parent = RID();3290}32913292RID TextServerFallback::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {3293_THREAD_SAFE_METHOD_3294ERR_FAIL_COND_V_MSG(p_direction == DIRECTION_INHERITED, RID(), "Invalid text direction.");32953296ShapedTextDataFallback *sd = memnew(ShapedTextDataFallback);3297sd->direction = p_direction;3298sd->orientation = p_orientation;32993300return shaped_owner.make_rid(sd);3301}33023303void TextServerFallback::_shaped_text_clear(const RID &p_shaped) {3304ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3305ERR_FAIL_NULL(sd);33063307MutexLock lock(sd->mutex);3308sd->parent = RID();3309sd->start = 0;3310sd->end = 0;3311sd->text = String();3312sd->spans.clear();3313sd->first_span = 0;3314sd->last_span = 0;3315sd->objects.clear();3316invalidate(sd);3317}33183319void TextServerFallback::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {3320ERR_FAIL_COND_MSG(p_direction == DIRECTION_INHERITED, "Invalid text direction.");3321if (p_direction == DIRECTION_RTL) {3322ERR_PRINT_ONCE("Right-to-left layout is not supported by this text server.");3323}3324}33253326TextServer::Direction TextServerFallback::_shaped_text_get_direction(const RID &p_shaped) const {3327return TextServer::DIRECTION_LTR;3328}33293330TextServer::Direction TextServerFallback::_shaped_text_get_inferred_direction(const RID &p_shaped) const {3331return TextServer::DIRECTION_LTR;3332}33333334void TextServerFallback::_shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) {3335_THREAD_SAFE_METHOD_3336ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3337ERR_FAIL_NULL(sd);33383339if (sd->custom_punct != p_punct) {3340if (sd->parent != RID()) {3341full_copy(sd);3342}3343sd->custom_punct = p_punct;3344invalidate(sd);3345}3346}33473348String TextServerFallback::_shaped_text_get_custom_punctuation(const RID &p_shaped) const {3349_THREAD_SAFE_METHOD_3350const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3351ERR_FAIL_NULL_V(sd, String());3352return sd->custom_punct;3353}33543355void TextServerFallback::_shaped_text_set_custom_ellipsis(const RID &p_shaped, int64_t p_char) {3356_THREAD_SAFE_METHOD_3357ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3358ERR_FAIL_NULL(sd);3359sd->el_char = p_char;3360}33613362int64_t TextServerFallback::_shaped_text_get_custom_ellipsis(const RID &p_shaped) const {3363_THREAD_SAFE_METHOD_3364const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3365ERR_FAIL_NULL_V(sd, 0);3366return sd->el_char;3367}33683369void TextServerFallback::_shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) {3370ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3371ERR_FAIL_NULL(sd);33723373MutexLock lock(sd->mutex);3374if (sd->orientation != p_orientation) {3375if (sd->parent != RID()) {3376full_copy(sd);3377}3378sd->orientation = p_orientation;3379invalidate(sd);3380}3381}33823383void TextServerFallback::_shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) {3384// No BiDi support, ignore.3385}33863387TextServer::Orientation TextServerFallback::_shaped_text_get_orientation(const RID &p_shaped) const {3388const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3389ERR_FAIL_NULL_V(sd, TextServer::ORIENTATION_HORIZONTAL);33903391MutexLock lock(sd->mutex);3392return sd->orientation;3393}33943395void TextServerFallback::_shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) {3396ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);33973398MutexLock lock(sd->mutex);3399ERR_FAIL_NULL(sd);3400if (sd->preserve_invalid != p_enabled) {3401if (sd->parent != RID()) {3402full_copy(sd);3403}3404sd->preserve_invalid = p_enabled;3405invalidate(sd);3406}3407}34083409bool TextServerFallback::_shaped_text_get_preserve_invalid(const RID &p_shaped) const {3410const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3411ERR_FAIL_NULL_V(sd, false);34123413MutexLock lock(sd->mutex);3414return sd->preserve_invalid;3415}34163417void TextServerFallback::_shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) {3418ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3419ERR_FAIL_NULL(sd);34203421MutexLock lock(sd->mutex);3422if (sd->preserve_control != p_enabled) {3423if (sd->parent != RID()) {3424full_copy(sd);3425}3426sd->preserve_control = p_enabled;3427invalidate(sd);3428}3429}34303431bool TextServerFallback::_shaped_text_get_preserve_control(const RID &p_shaped) const {3432const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3433ERR_FAIL_NULL_V(sd, false);34343435MutexLock lock(sd->mutex);3436return sd->preserve_control;3437}34383439void TextServerFallback::_shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) {3440ERR_FAIL_INDEX((int)p_spacing, 4);3441ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3442ERR_FAIL_NULL(sd);34433444MutexLock lock(sd->mutex);3445if (sd->extra_spacing[p_spacing] != p_value) {3446if (sd->parent != RID()) {3447full_copy(sd);3448}3449sd->extra_spacing[p_spacing] = p_value;3450invalidate(sd);3451}3452}34533454int64_t TextServerFallback::_shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const {3455ERR_FAIL_INDEX_V((int)p_spacing, 4, 0);34563457const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3458ERR_FAIL_NULL_V(sd, 0);34593460MutexLock lock(sd->mutex);3461return sd->extra_spacing[p_spacing];3462}34633464int64_t TextServerFallback::_shaped_get_span_count(const RID &p_shaped) const {3465ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3466ERR_FAIL_NULL_V(sd, 0);34673468if (sd->parent != RID()) {3469return sd->last_span - sd->first_span + 1;3470} else {3471return sd->spans.size();3472}3473}34743475Variant TextServerFallback::_shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const {3476ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3477ERR_FAIL_NULL_V(sd, Variant());3478if (sd->parent != RID()) {3479ShapedTextDataFallback *parent_sd = shaped_owner.get_or_null(sd->parent);3480ERR_FAIL_COND_V(!parent_sd->valid.is_set(), Variant());3481ERR_FAIL_INDEX_V(p_index + sd->first_span, parent_sd->spans.size(), Variant());3482return parent_sd->spans[p_index + sd->first_span].meta;3483} else {3484ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant());3485return sd->spans[p_index].meta;3486}3487}34883489Variant TextServerFallback::_shaped_get_span_embedded_object(const RID &p_shaped, int64_t p_index) const {3490ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3491ERR_FAIL_NULL_V(sd, Variant());3492if (sd->parent != RID()) {3493ShapedTextDataFallback *parent_sd = shaped_owner.get_or_null(sd->parent);3494ERR_FAIL_COND_V(!parent_sd->valid.is_set(), Variant());3495ERR_FAIL_INDEX_V(p_index + sd->first_span, parent_sd->spans.size(), Variant());3496return parent_sd->spans[p_index + sd->first_span].embedded_key;3497} else {3498ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant());3499return sd->spans[p_index].embedded_key;3500}3501}35023503String TextServerFallback::_shaped_get_span_text(const RID &p_shaped, int64_t p_index) const {3504ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3505ERR_FAIL_NULL_V(sd, String());3506ShapedTextDataFallback *span_sd = sd;3507if (sd->parent.is_valid()) {3508span_sd = shaped_owner.get_or_null(sd->parent);3509ERR_FAIL_NULL_V(span_sd, String());3510}3511ERR_FAIL_INDEX_V(p_index, span_sd->spans.size(), String());3512return span_sd->text.substr(span_sd->spans[p_index].start, span_sd->spans[p_index].end - span_sd->spans[p_index].start);3513}35143515Variant TextServerFallback::_shaped_get_span_object(const RID &p_shaped, int64_t p_index) const {3516ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3517ERR_FAIL_NULL_V(sd, Variant());3518ShapedTextDataFallback *span_sd = sd;3519if (sd->parent.is_valid()) {3520span_sd = shaped_owner.get_or_null(sd->parent);3521ERR_FAIL_NULL_V(span_sd, Variant());3522}3523ERR_FAIL_INDEX_V(p_index, span_sd->spans.size(), Variant());3524return span_sd->spans[p_index].embedded_key;3525}35263527void TextServerFallback::_generate_runs(ShapedTextDataFallback *p_sd) const {3528ERR_FAIL_NULL(p_sd);3529p_sd->runs.clear();35303531ShapedTextDataFallback *span_sd = p_sd;3532if (p_sd->parent.is_valid()) {3533span_sd = shaped_owner.get_or_null(p_sd->parent);3534ERR_FAIL_NULL(span_sd);3535}35363537int sd_size = p_sd->glyphs.size();3538Glyph *sd_gl = p_sd->glyphs.ptrw();35393540int span_count = span_sd->spans.size();3541int span = -1;3542int span_start = -1;3543int span_end = -1;35443545TextRun run;3546for (int i = 0; i < sd_size; i += sd_gl[i].count) {3547const Glyph &gl = sd_gl[i];3548if (gl.start < 0 || gl.end < 0) {3549continue;3550}3551if (gl.start < span_start || gl.start >= span_end) {3552span = -1;3553span_start = -1;3554span_end = -1;3555for (int j = 0; j < span_count; j++) {3556if (gl.start >= span_sd->spans[j].start && gl.end <= span_sd->spans[j].end) {3557span = j;3558span_start = span_sd->spans[j].start;3559span_end = span_sd->spans[j].end;3560break;3561}3562}3563}3564if (run.font_rid != gl.font_rid || run.font_size != gl.font_size || run.span_index != span) {3565if (run.span_index >= 0) {3566p_sd->runs.push_back(run);3567}3568run.range = Vector2i(gl.start, gl.end);3569run.font_rid = gl.font_rid;3570run.font_size = gl.font_size;3571run.span_index = span;3572}3573run.range.x = MIN(run.range.x, gl.start);3574run.range.y = MAX(run.range.y, gl.end);3575}3576if (run.span_index >= 0) {3577p_sd->runs.push_back(run);3578}3579p_sd->runs_dirty = false;3580}35813582int64_t TextServerFallback::_shaped_get_run_count(const RID &p_shaped) const {3583ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3584ERR_FAIL_NULL_V(sd, 0);3585MutexLock lock(sd->mutex);3586if (!sd->valid.is_set()) {3587const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);3588}3589if (sd->runs_dirty) {3590_generate_runs(sd);3591}3592return sd->runs.size();3593}35943595String TextServerFallback::_shaped_get_run_text(const RID &p_shaped, int64_t p_index) const {3596ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3597ERR_FAIL_NULL_V(sd, String());3598MutexLock lock(sd->mutex);3599if (!sd->valid.is_set()) {3600const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);3601}3602if (sd->runs_dirty) {3603_generate_runs(sd);3604}3605ERR_FAIL_INDEX_V(p_index, sd->runs.size(), String());3606return sd->text.substr(sd->runs[p_index].range.x - sd->start, sd->runs[p_index].range.y - sd->runs[p_index].range.x);3607}36083609Vector2i TextServerFallback::_shaped_get_run_range(const RID &p_shaped, int64_t p_index) const {3610ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3611ERR_FAIL_NULL_V(sd, Vector2i());3612MutexLock lock(sd->mutex);3613if (!sd->valid.is_set()) {3614const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);3615}3616if (sd->runs_dirty) {3617_generate_runs(sd);3618}3619ERR_FAIL_INDEX_V(p_index, sd->runs.size(), Vector2i());3620return sd->runs[p_index].range;3621}36223623RID TextServerFallback::_shaped_get_run_font_rid(const RID &p_shaped, int64_t p_index) const {3624ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3625ERR_FAIL_NULL_V(sd, RID());3626MutexLock lock(sd->mutex);3627if (!sd->valid.is_set()) {3628const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);3629}3630if (sd->runs_dirty) {3631_generate_runs(sd);3632}3633ERR_FAIL_INDEX_V(p_index, sd->runs.size(), RID());3634return sd->runs[p_index].font_rid;3635}36363637int TextServerFallback::_shaped_get_run_font_size(const RID &p_shaped, int64_t p_index) const {3638ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3639ERR_FAIL_NULL_V(sd, 0);3640MutexLock lock(sd->mutex);3641if (!sd->valid.is_set()) {3642const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);3643}3644if (sd->runs_dirty) {3645_generate_runs(sd);3646}3647ERR_FAIL_INDEX_V(p_index, sd->runs.size(), 0);3648return sd->runs[p_index].font_size;3649}36503651String TextServerFallback::_shaped_get_run_language(const RID &p_shaped, int64_t p_index) const {3652ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3653ERR_FAIL_NULL_V(sd, String());3654MutexLock lock(sd->mutex);3655if (!sd->valid.is_set()) {3656const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);3657}3658if (sd->runs_dirty) {3659_generate_runs(sd);3660}3661ERR_FAIL_INDEX_V(p_index, sd->runs.size(), String());36623663int span_idx = sd->runs[p_index].span_index;3664ShapedTextDataFallback *span_sd = sd;3665if (sd->parent.is_valid()) {3666span_sd = shaped_owner.get_or_null(sd->parent);3667ERR_FAIL_NULL_V(span_sd, String());3668}3669ERR_FAIL_INDEX_V(span_idx, span_sd->spans.size(), String());3670return span_sd->spans[span_idx].language;3671}36723673TextServer::Direction TextServerFallback::_shaped_get_run_direction(const RID &p_shaped, int64_t p_index) const {3674ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3675ERR_FAIL_NULL_V(sd, TextServer::DIRECTION_LTR);3676MutexLock lock(sd->mutex);3677if (!sd->valid.is_set()) {3678const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);3679}3680if (sd->runs_dirty) {3681_generate_runs(sd);3682}3683ERR_FAIL_INDEX_V(p_index, sd->runs.size(), TextServer::DIRECTION_LTR);3684return TextServer::DIRECTION_LTR;3685}36863687Variant TextServerFallback::_shaped_get_run_object(const RID &p_shaped, int64_t p_index) const {3688ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3689ERR_FAIL_NULL_V(sd, Variant());3690MutexLock lock(sd->mutex);3691if (!sd->valid.is_set()) {3692const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);3693}3694if (sd->runs_dirty) {3695_generate_runs(sd);3696}3697ERR_FAIL_INDEX_V(p_index, sd->runs.size(), Variant());36983699int span_idx = sd->runs[p_index].span_index;3700ShapedTextDataFallback *span_sd = sd;3701if (sd->parent.is_valid()) {3702span_sd = shaped_owner.get_or_null(sd->parent);3703ERR_FAIL_NULL_V(span_sd, Variant());3704}3705ERR_FAIL_INDEX_V(span_idx, span_sd->spans.size(), Variant());3706return span_sd->spans[span_idx].embedded_key;3707}37083709void TextServerFallback::_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) {3710ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3711ERR_FAIL_NULL(sd);3712if (sd->parent != RID()) {3713full_copy(sd);3714}3715ERR_FAIL_INDEX(p_index, sd->spans.size());37163717ShapedTextDataFallback::Span &span = sd->spans.ptrw()[p_index];3718span.fonts.clear();3719// Pre-sort fonts, push fonts with the language support first.3720Array fonts_no_match;3721int font_count = p_fonts.size();3722for (int i = 0; i < font_count; i++) {3723if (_font_is_language_supported(p_fonts[i], span.language)) {3724span.fonts.push_back(p_fonts[i]);3725} else {3726fonts_no_match.push_back(p_fonts[i]);3727}3728}3729span.fonts.append_array(fonts_no_match);3730span.font_size = p_size;3731span.features = p_opentype_features;37323733sd->valid.clear();3734}37353736bool TextServerFallback::_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) {3737ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3738ERR_FAIL_NULL_V(sd, false);37393740MutexLock lock(sd->mutex);3741ERR_FAIL_COND_V(p_size <= 0, false);37423743for (int i = 0; i < p_fonts.size(); i++) {3744ERR_FAIL_NULL_V(_get_font_data(p_fonts[i]), false);3745}37463747if (p_text.is_empty()) {3748return true;3749}37503751if (sd->parent != RID()) {3752full_copy(sd);3753}37543755ShapedTextDataFallback::Span span;3756span.start = sd->text.length();3757span.end = span.start + p_text.length();37583759// Pre-sort fonts, push fonts with the language support first.3760Array fonts_no_match;3761int font_count = p_fonts.size();3762if (font_count > 0) {3763span.fonts.push_back(p_fonts[0]);3764}3765for (int i = 1; i < font_count; i++) {3766if (_font_is_language_supported(p_fonts[i], p_language)) {3767span.fonts.push_back(p_fonts[i]);3768} else {3769fonts_no_match.push_back(p_fonts[i]);3770}3771}3772span.fonts.append_array(fonts_no_match);37733774ERR_FAIL_COND_V(span.fonts.is_empty(), false);3775span.font_size = p_size;3776span.language = p_language;3777span.meta = p_meta;37783779sd->spans.push_back(span);3780sd->text = sd->text + p_text;3781sd->end += p_text.length();3782invalidate(sd);37833784return true;3785}37863787bool TextServerFallback::_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) {3788ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3789ERR_FAIL_NULL_V(sd, false);37903791MutexLock lock(sd->mutex);3792ERR_FAIL_COND_V(p_key == Variant(), false);3793ERR_FAIL_COND_V(sd->objects.has(p_key), false);37943795if (sd->parent != RID()) {3796full_copy(sd);3797}37983799ShapedTextDataFallback::Span span;3800span.start = sd->start + sd->text.length();3801span.end = span.start + p_length;3802span.embedded_key = p_key;38033804ShapedTextDataFallback::EmbeddedObject obj;3805obj.inline_align = p_inline_align;3806obj.rect.size = p_size;3807obj.start = span.start;3808obj.end = span.end;3809obj.baseline = p_baseline;38103811sd->spans.push_back(span);3812sd->text = sd->text + String::chr(0xfffc).repeat(p_length);3813sd->end += p_length;3814sd->objects[p_key] = obj;3815invalidate(sd);38163817return true;3818}38193820String TextServerFallback::_shaped_get_text(const RID &p_shaped) const {3821const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3822ERR_FAIL_NULL_V(sd, String());38233824return sd->text;3825}38263827bool TextServerFallback::_shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, double p_baseline) {3828ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3829ERR_FAIL_NULL_V(sd, false);38303831MutexLock lock(sd->mutex);3832ERR_FAIL_COND_V(!sd->objects.has(p_key), false);3833sd->objects[p_key].rect.size = p_size;3834sd->objects[p_key].inline_align = p_inline_align;3835sd->objects[p_key].baseline = p_baseline;3836if (sd->valid.is_set()) {3837// Recalc string metrics.3838sd->ascent = 0;3839sd->descent = 0;3840sd->width = 0;3841sd->upos = 0;3842sd->uthk = 0;38433844Vector<ShapedTextDataFallback::Span> &spans = sd->spans;3845if (sd->parent != RID()) {3846ShapedTextDataFallback *parent_sd = shaped_owner.get_or_null(sd->parent);3847ERR_FAIL_COND_V(!parent_sd->valid.is_set(), false);3848spans = parent_sd->spans;3849}38503851int sd_size = sd->glyphs.size();3852int span_size = spans.size();38533854for (int i = 0; i < sd_size; i++) {3855Glyph gl = sd->glyphs[i];3856Variant key;3857if ((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) {3858key = spans[gl.span_index + sd->first_span].embedded_key;3859}3860if (key != Variant()) {3861if (sd->orientation == ORIENTATION_HORIZONTAL) {3862sd->objects[key].rect.position.x = sd->width;3863sd->width += sd->objects[key].rect.size.x;3864sd->glyphs.write[i].advance = sd->objects[key].rect.size.x;3865} else {3866sd->objects[key].rect.position.y = sd->width;3867sd->width += sd->objects[key].rect.size.y;3868sd->glyphs.write[i].advance = sd->objects[key].rect.size.y;3869}3870} else {3871if (gl.font_rid.is_valid()) {3872if (sd->orientation == ORIENTATION_HORIZONTAL) {3873sd->ascent = MAX(sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_TOP));3874sd->descent = MAX(sd->descent, _font_get_descent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_BOTTOM));3875} else {3876sd->ascent = MAX(sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));3877sd->descent = MAX(sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));3878}3879sd->upos = MAX(sd->upos, _font_get_underline_position(gl.font_rid, gl.font_size));3880sd->uthk = MAX(sd->uthk, _font_get_underline_thickness(gl.font_rid, gl.font_size));3881} else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) {3882// Glyph not found, replace with hex code box.3883if (sd->orientation == ORIENTATION_HORIZONTAL) {3884sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.85);3885sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.15);3886} else {3887sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));3888sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));3889}3890}3891sd->width += gl.advance * gl.repeat;3892}3893}3894_realign(sd);3895}3896return true;3897}38983899void TextServerFallback::_realign(ShapedTextDataFallback *p_sd) const {3900// Align embedded objects to baseline.3901double full_ascent = p_sd->ascent;3902double full_descent = p_sd->descent;3903for (KeyValue<Variant, ShapedTextDataFallback::EmbeddedObject> &E : p_sd->objects) {3904if ((E.value.start >= p_sd->start) && (E.value.start < p_sd->end)) {3905if (p_sd->orientation == ORIENTATION_HORIZONTAL) {3906switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {3907case INLINE_ALIGNMENT_TO_TOP: {3908E.value.rect.position.y = -p_sd->ascent;3909} break;3910case INLINE_ALIGNMENT_TO_CENTER: {3911E.value.rect.position.y = (-p_sd->ascent + p_sd->descent) / 2;3912} break;3913case INLINE_ALIGNMENT_TO_BASELINE: {3914E.value.rect.position.y = 0;3915} break;3916case INLINE_ALIGNMENT_TO_BOTTOM: {3917E.value.rect.position.y = p_sd->descent;3918} break;3919}3920switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {3921case INLINE_ALIGNMENT_BOTTOM_TO: {3922E.value.rect.position.y -= E.value.rect.size.y;3923} break;3924case INLINE_ALIGNMENT_CENTER_TO: {3925E.value.rect.position.y -= E.value.rect.size.y / 2;3926} break;3927case INLINE_ALIGNMENT_BASELINE_TO: {3928E.value.rect.position.y -= E.value.baseline;3929} break;3930case INLINE_ALIGNMENT_TOP_TO: {3931// NOP3932} break;3933}3934full_ascent = MAX(full_ascent, -E.value.rect.position.y);3935full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y);3936} else {3937switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {3938case INLINE_ALIGNMENT_TO_TOP: {3939E.value.rect.position.x = -p_sd->ascent;3940} break;3941case INLINE_ALIGNMENT_TO_CENTER: {3942E.value.rect.position.x = (-p_sd->ascent + p_sd->descent) / 2;3943} break;3944case INLINE_ALIGNMENT_TO_BASELINE: {3945E.value.rect.position.x = 0;3946} break;3947case INLINE_ALIGNMENT_TO_BOTTOM: {3948E.value.rect.position.x = p_sd->descent;3949} break;3950}3951switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {3952case INLINE_ALIGNMENT_BOTTOM_TO: {3953E.value.rect.position.x -= E.value.rect.size.x;3954} break;3955case INLINE_ALIGNMENT_CENTER_TO: {3956E.value.rect.position.x -= E.value.rect.size.x / 2;3957} break;3958case INLINE_ALIGNMENT_BASELINE_TO: {3959E.value.rect.position.x -= E.value.baseline;3960} break;3961case INLINE_ALIGNMENT_TOP_TO: {3962// NOP3963} break;3964}3965full_ascent = MAX(full_ascent, -E.value.rect.position.x);3966full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x);3967}3968}3969}3970p_sd->ascent = full_ascent;3971p_sd->descent = full_descent;3972}39733974RID TextServerFallback::_shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {3975_THREAD_SAFE_METHOD_39763977const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);3978ERR_FAIL_NULL_V(sd, RID());39793980MutexLock lock(sd->mutex);3981if (sd->parent != RID()) {3982return _shaped_text_substr(sd->parent, p_start, p_length);3983}3984if (!sd->valid.is_set()) {3985const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);3986}3987ERR_FAIL_COND_V(p_start < 0 || p_length < 0, RID());3988ERR_FAIL_COND_V(sd->start > p_start || sd->end < p_start, RID());3989ERR_FAIL_COND_V(sd->end < p_start + p_length, RID());39903991ShapedTextDataFallback *new_sd = memnew(ShapedTextDataFallback);3992new_sd->parent = p_shaped;3993new_sd->start = p_start;3994new_sd->end = p_start + p_length;39953996new_sd->orientation = sd->orientation;3997new_sd->direction = sd->direction;3998new_sd->custom_punct = sd->custom_punct;3999new_sd->para_direction = sd->para_direction;4000new_sd->line_breaks_valid = sd->line_breaks_valid;4001new_sd->justification_ops_valid = sd->justification_ops_valid;4002new_sd->sort_valid = false;4003new_sd->upos = sd->upos;4004new_sd->uthk = sd->uthk;4005for (int i = 0; i < TextServer::SPACING_MAX; i++) {4006new_sd->extra_spacing[i] = sd->extra_spacing[i];4007}40084009if (p_length > 0) {4010new_sd->text = sd->text.substr(p_start - sd->start, p_length);40114012int span_size = sd->spans.size();40134014new_sd->first_span = 0;4015new_sd->last_span = span_size - 1;4016for (int i = 0; i < span_size; i++) {4017const ShapedTextDataFallback::Span &span = sd->spans[i];4018if (span.end <= p_start) {4019new_sd->first_span = i + 1;4020} else if (span.start >= p_start + p_length) {4021new_sd->last_span = i - 1;4022break;4023}4024}40254026int sd_size = sd->glyphs.size();4027const Glyph *sd_glyphs = sd->glyphs.ptr();40284029for (int i = 0; i < sd_size; i++) {4030if ((sd_glyphs[i].start >= new_sd->start) && (sd_glyphs[i].end <= new_sd->end)) {4031Glyph gl = sd_glyphs[i];4032if (gl.span_index >= 0) {4033gl.span_index -= new_sd->first_span;4034}4035if (gl.end == p_start + p_length && ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) == GRAPHEME_IS_SOFT_HYPHEN)) {4036gl.index = 0x00ad;4037gl.advance = font_get_glyph_advance(gl.font_rid, gl.font_size, 0x00ad).x;4038}4039if ((gl.flags & GRAPHEME_IS_EMBEDDED_OBJECT) == GRAPHEME_IS_EMBEDDED_OBJECT && gl.span_index + new_sd->first_span >= 0 && gl.span_index + new_sd->first_span < span_size) {4040Variant key = sd->spans[gl.span_index + new_sd->first_span].embedded_key;4041if (key != Variant()) {4042ShapedTextDataFallback::EmbeddedObject obj = sd->objects[key];4043if (new_sd->orientation == ORIENTATION_HORIZONTAL) {4044obj.rect.position.x = new_sd->width;4045new_sd->width += obj.rect.size.x;4046} else {4047obj.rect.position.y = new_sd->width;4048new_sd->width += obj.rect.size.y;4049}4050new_sd->objects[key] = obj;4051}4052} else {4053if (gl.font_rid.is_valid()) {4054if (new_sd->orientation == ORIENTATION_HORIZONTAL) {4055new_sd->ascent = MAX(new_sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_TOP));4056new_sd->descent = MAX(new_sd->descent, _font_get_descent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_BOTTOM));4057} else {4058new_sd->ascent = MAX(new_sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));4059new_sd->descent = MAX(new_sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));4060}4061} else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) {4062// Glyph not found, replace with hex code box.4063if (new_sd->orientation == ORIENTATION_HORIZONTAL) {4064new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.85);4065new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.15);4066} else {4067new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));4068new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));4069}4070}4071new_sd->width += gl.advance * gl.repeat;4072}4073new_sd->glyphs.push_back(gl);4074}4075}40764077_realign(new_sd);4078}4079new_sd->valid.set();40804081return shaped_owner.make_rid(new_sd);4082}40834084RID TextServerFallback::_shaped_text_get_parent(const RID &p_shaped) const {4085ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);4086ERR_FAIL_NULL_V(sd, RID());40874088MutexLock lock(sd->mutex);4089return sd->parent;4090}40914092double TextServerFallback::_shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<JustificationFlag> p_jst_flags) {4093ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);4094ERR_FAIL_NULL_V(sd, 0.0);40954096MutexLock lock(sd->mutex);4097if (!sd->valid.is_set()) {4098_shaped_text_shape(p_shaped);4099}4100if (!sd->justification_ops_valid) {4101_shaped_text_update_justification_ops(p_shaped);4102}41034104int start_pos = 0;4105int end_pos = sd->glyphs.size() - 1;41064107if (p_jst_flags.has_flag(JUSTIFICATION_AFTER_LAST_TAB)) {4108int start, end, delta;4109if (sd->para_direction == DIRECTION_LTR) {4110start = sd->glyphs.size() - 1;4111end = -1;4112delta = -1;4113} else {4114start = 0;4115end = sd->glyphs.size();4116delta = +1;4117}41184119for (int i = start; i != end; i += delta) {4120if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {4121if (sd->para_direction == DIRECTION_LTR) {4122start_pos = i;4123break;4124} else {4125end_pos = i;4126break;4127}4128}4129}4130}41314132double justification_width;4133if (p_jst_flags.has_flag(JUSTIFICATION_CONSTRAIN_ELLIPSIS)) {4134if (sd->overrun_trim_data.trim_pos >= 0) {4135end_pos = sd->overrun_trim_data.trim_pos;4136justification_width = sd->width_trimmed;4137} else {4138return Math::ceil(sd->width);4139}4140} else {4141justification_width = sd->width;4142}41434144if (p_jst_flags.has_flag(JUSTIFICATION_TRIM_EDGE_SPACES)) {4145// Trim spaces.4146while ((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)) {4147justification_width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat;4148sd->glyphs.write[start_pos].advance = 0;4149start_pos += sd->glyphs[start_pos].count;4150}4151while ((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)) {4152justification_width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat;4153sd->glyphs.write[end_pos].advance = 0;4154end_pos -= sd->glyphs[end_pos].count;4155}4156} else {4157// Skip breaks, but do not reset size.4158while ((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)) {4159start_pos += sd->glyphs[start_pos].count;4160}4161while ((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)) {4162end_pos -= sd->glyphs[end_pos].count;4163}4164}41654166int space_count = 0;4167for (int i = start_pos; i <= end_pos; i++) {4168const Glyph &gl = sd->glyphs[i];4169if (gl.count > 0) {4170if ((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) {4171space_count++;4172}4173}4174}41754176if ((space_count > 0) && p_jst_flags.has_flag(JUSTIFICATION_WORD_BOUND)) {4177double delta_width_per_space = (p_width - justification_width) / space_count;4178for (int i = start_pos; i <= end_pos; i++) {4179Glyph &gl = sd->glyphs.write[i];4180if (gl.count > 0) {4181if ((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) {4182double old_adv = gl.advance;4183gl.advance = MAX(gl.advance + delta_width_per_space, Math::round(0.1 * gl.font_size));4184justification_width += (gl.advance - old_adv);4185}4186}4187}4188}41894190if (Math::floor(p_width) < Math::floor(justification_width)) {4191sd->fit_width_minimum_reached = true;4192}41934194if (!p_jst_flags.has_flag(JUSTIFICATION_CONSTRAIN_ELLIPSIS)) {4195sd->width = justification_width;4196}41974198return Math::ceil(justification_width);4199}42004201double TextServerFallback::_shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) {4202ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);4203ERR_FAIL_NULL_V(sd, 0.0);42044205MutexLock lock(sd->mutex);4206if (!sd->valid.is_set()) {4207_shaped_text_shape(p_shaped);4208}4209if (!sd->line_breaks_valid) {4210_shaped_text_update_breaks(p_shaped);4211}42124213for (int i = 0; i < p_tab_stops.size(); i++) {4214if (p_tab_stops[i] <= 0) {4215return 0.0;4216}4217}42184219int tab_index = 0;4220double off = 0.0;42214222int start, end, delta;4223if (sd->para_direction == DIRECTION_LTR) {4224start = 0;4225end = sd->glyphs.size();4226delta = +1;4227} else {4228start = sd->glyphs.size() - 1;4229end = -1;4230delta = -1;4231}42324233Glyph *gl = sd->glyphs.ptrw();42344235for (int i = start; i != end; i += delta) {4236if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {4237double tab_off = 0.0;4238while (tab_off <= off) {4239tab_off += p_tab_stops[tab_index];4240tab_index++;4241if (tab_index >= p_tab_stops.size()) {4242tab_index = 0;4243}4244}4245double old_adv = gl[i].advance;4246gl[i].advance = tab_off - off;4247sd->width += gl[i].advance - old_adv;4248off = 0;4249continue;4250}4251off += gl[i].advance * gl[i].repeat;4252}42534254return 0.0;4255}42564257bool TextServerFallback::_shaped_text_update_breaks(const RID &p_shaped) {4258ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);4259ERR_FAIL_NULL_V(sd, false);42604261MutexLock lock(sd->mutex);4262if (!sd->valid.is_set()) {4263_shaped_text_shape(p_shaped);4264}42654266if (sd->line_breaks_valid) {4267return true; // Nothing to do.4268}42694270int sd_size = sd->glyphs.size();4271Glyph *sd_glyphs = sd->glyphs.ptrw();42724273int c_punct_size = sd->custom_punct.length();4274const char32_t *c_punct = sd->custom_punct.ptr();42754276for (int i = 0; i < sd_size; i++) {4277if (sd_glyphs[i].count > 0) {4278char32_t c = sd->text[sd_glyphs[i].start - sd->start];4279char32_t c_next = i < sd_size ? sd->text[sd_glyphs[i].start - sd->start + 1] : 0x0000;4280if (c_punct_size == 0) {4281if (is_punct(c) && c != 0x005F && c != ' ') {4282sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION;4283}4284} else {4285for (int j = 0; j < c_punct_size; j++) {4286if (c_punct[j] == c) {4287sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION;4288break;4289}4290}4291}4292if (is_underscore(c)) {4293sd->glyphs.write[i].flags |= GRAPHEME_IS_UNDERSCORE;4294}4295if (is_whitespace(c) && !is_linebreak(c)) {4296sd_glyphs[i].flags |= GRAPHEME_IS_SPACE;4297if (c != 0x00A0 && c != 0x202F && c != 0x2060 && c != 0x2007) { // Skip for non-breaking space variants.4298sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT;4299}4300}4301if (is_linebreak(c)) {4302sd_glyphs[i].flags |= GRAPHEME_IS_SPACE;4303if (c != 0x000D || c_next != 0x000A) { // Skip first hard break in CR-LF pair.4304sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD;4305}4306}4307if (c == 0x0009 || c == 0x000b) {4308sd_glyphs[i].flags |= GRAPHEME_IS_TAB;4309}4310if (c == 0x00ad) {4311sd_glyphs[i].flags |= GRAPHEME_IS_SOFT_HYPHEN;4312}43134314i += (sd_glyphs[i].count - 1);4315}4316}4317sd->line_breaks_valid = true;4318return sd->line_breaks_valid;4319}43204321bool TextServerFallback::_shaped_text_update_justification_ops(const RID &p_shaped) {4322ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);4323ERR_FAIL_NULL_V(sd, false);43244325MutexLock lock(sd->mutex);4326if (!sd->valid.is_set()) {4327_shaped_text_shape(p_shaped);4328}4329if (!sd->line_breaks_valid) {4330_shaped_text_update_breaks(p_shaped);4331}43324333sd->justification_ops_valid = true; // Not supported by fallback server.4334return true;4335}43364337RID TextServerFallback::_find_sys_font_for_text(const RID &p_fdef, const String &p_script_code, const String &p_language, const String &p_text) {4338RID f;4339// Try system fallback.4340if (_font_is_allow_system_fallback(p_fdef)) {4341String font_name = _font_get_name(p_fdef);4342BitField<FontStyle> font_style = _font_get_style(p_fdef);4343int font_weight = _font_get_weight(p_fdef);4344int font_stretch = _font_get_stretch(p_fdef);4345Dictionary dvar = _font_get_variation_coordinates(p_fdef);4346static int64_t wgth_tag = name_to_tag("weight");4347static int64_t wdth_tag = name_to_tag("width");4348static int64_t ital_tag = name_to_tag("italic");4349if (dvar.has(wgth_tag)) {4350font_weight = dvar[wgth_tag].operator int();4351}4352if (dvar.has(wdth_tag)) {4353font_stretch = dvar[wdth_tag].operator int();4354}4355if (dvar.has(ital_tag) && dvar[ital_tag].operator int() == 1) {4356font_style.set_flag(TextServer::FONT_ITALIC);4357}43584359String locale = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;4360PackedStringArray 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);4361#ifdef GDEXTENSION4362for (int fb = 0; fb < fallback_font_name.size(); fb++) {4363const String &E = fallback_font_name[fb];4364#elif defined(GODOT_MODULE)4365for (const String &E : fallback_font_name) {4366#endif4367SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, p_fdef, this);4368if (system_fonts.has(key)) {4369const SystemFontCache &sysf_cache = system_fonts[key];4370int best_score = 0;4371int best_match = -1;4372for (int face_idx = 0; face_idx < sysf_cache.var.size(); face_idx++) {4373const SystemFontCacheRec &F = sysf_cache.var[face_idx];4374if (unlikely(!_font_has_char(F.rid, p_text[0]))) {4375continue;4376}4377BitField<FontStyle> style = _font_get_style(F.rid);4378int weight = _font_get_weight(F.rid);4379int stretch = _font_get_stretch(F.rid);4380int score = (20 - Math::abs(weight - font_weight) / 50);4381score += (20 - Math::abs(stretch - font_stretch) / 10);4382if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) {4383score += 30;4384}4385if (score >= best_score) {4386best_score = score;4387best_match = face_idx;4388}4389if (best_score == 70) {4390break;4391}4392}4393if (best_match != -1) {4394f = sysf_cache.var[best_match].rid;4395}4396}4397if (!f.is_valid()) {4398if (system_fonts.has(key)) {4399const SystemFontCache &sysf_cache = system_fonts[key];4400if (sysf_cache.max_var == sysf_cache.var.size()) {4401// All subfonts already tested, skip.4402continue;4403}4404}44054406if (!system_font_data.has(E)) {4407system_font_data[E] = FileAccess::get_file_as_bytes(E);4408}44094410const PackedByteArray &font_data = system_font_data[E];44114412SystemFontCacheRec sysf;4413sysf.rid = _create_font();4414_font_set_data_ptr(sysf.rid, font_data.ptr(), font_data.size());4415if (!_font_validate(sysf.rid)) {4416_free_rid(sysf.rid);4417continue;4418}44194420Dictionary var = dvar;4421// Select matching style from collection.4422int best_score = 0;4423int best_match = -1;4424for (int face_idx = 0; face_idx < _font_get_face_count(sysf.rid); face_idx++) {4425_font_set_face_index(sysf.rid, face_idx);4426if (unlikely(!_font_has_char(sysf.rid, p_text[0]))) {4427continue;4428}4429BitField<FontStyle> style = _font_get_style(sysf.rid);4430int weight = _font_get_weight(sysf.rid);4431int stretch = _font_get_stretch(sysf.rid);4432int score = (20 - Math::abs(weight - font_weight) / 50);4433score += (20 - Math::abs(stretch - font_stretch) / 10);4434if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) {4435score += 30;4436}4437if (score >= best_score) {4438best_score = score;4439best_match = face_idx;4440}4441if (best_score == 70) {4442break;4443}4444}4445if (best_match == -1) {4446_free_rid(sysf.rid);4447continue;4448} else {4449_font_set_face_index(sysf.rid, best_match);4450}4451sysf.index = best_match;44524453// If it's a variable font, apply weight, stretch and italic coordinates to match requested style.4454if (best_score != 70) {4455Dictionary ftr = _font_supported_variation_list(sysf.rid);4456if (ftr.has(wdth_tag)) {4457var[wdth_tag] = font_stretch;4458_font_set_stretch(sysf.rid, font_stretch);4459}4460if (ftr.has(wgth_tag)) {4461var[wgth_tag] = font_weight;4462_font_set_weight(sysf.rid, font_weight);4463}4464if ((font_style & TextServer::FONT_ITALIC) && ftr.has(ital_tag)) {4465var[ital_tag] = 1;4466_font_set_style(sysf.rid, _font_get_style(sysf.rid) | TextServer::FONT_ITALIC);4467}4468}44694470bool fb_use_msdf = key.msdf;4471if (fb_use_msdf) {4472FontFallback *fd = _get_font_data(sysf.rid);4473if (fd) {4474MutexLock lock(fd->mutex);4475Vector2i size = _get_size(fd, 16);4476FontForSizeFallback *ffsd = nullptr;4477if (_ensure_cache_for_size(fd, size, ffsd)) {4478if (ffsd && (FT_HAS_COLOR(ffsd->face) || !FT_IS_SCALABLE(ffsd->face))) {4479fb_use_msdf = false;4480}4481}4482}4483}44844485_font_set_antialiasing(sysf.rid, key.antialiasing);4486_font_set_disable_embedded_bitmaps(sysf.rid, key.disable_embedded_bitmaps);4487_font_set_generate_mipmaps(sysf.rid, key.mipmaps);4488_font_set_multichannel_signed_distance_field(sysf.rid, fb_use_msdf);4489_font_set_msdf_pixel_range(sysf.rid, key.msdf_range);4490_font_set_msdf_size(sysf.rid, key.msdf_source_size);4491_font_set_fixed_size(sysf.rid, key.fixed_size);4492_font_set_force_autohinter(sysf.rid, key.force_autohinter);4493_font_set_hinting(sysf.rid, key.hinting);4494_font_set_subpixel_positioning(sysf.rid, key.subpixel_positioning);4495_font_set_keep_rounding_remainders(sysf.rid, key.keep_rounding_remainders);4496_font_set_variation_coordinates(sysf.rid, var);4497_font_set_embolden(sysf.rid, key.embolden);4498_font_set_transform(sysf.rid, key.transform);4499_font_set_spacing(sysf.rid, SPACING_TOP, key.extra_spacing[SPACING_TOP]);4500_font_set_spacing(sysf.rid, SPACING_BOTTOM, key.extra_spacing[SPACING_BOTTOM]);4501_font_set_spacing(sysf.rid, SPACING_SPACE, key.extra_spacing[SPACING_SPACE]);4502_font_set_spacing(sysf.rid, SPACING_GLYPH, key.extra_spacing[SPACING_GLYPH]);45034504if (system_fonts.has(key)) {4505system_fonts[key].var.push_back(sysf);4506} else {4507SystemFontCache &sysf_cache = system_fonts[key];4508sysf_cache.max_var = _font_get_face_count(sysf.rid);4509sysf_cache.var.push_back(sysf);4510}4511f = sysf.rid;4512}4513break;4514}4515}4516return f;4517}45184519void TextServerFallback::_shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) {4520ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped_line);4521ERR_FAIL_NULL_MSG(sd, "ShapedTextDataFallback invalid.");45224523MutexLock lock(sd->mutex);4524if (!sd->valid.is_set()) {4525_shaped_text_shape(p_shaped_line);4526}45274528sd->text_trimmed = false;4529sd->overrun_trim_data.ellipsis_glyph_buf.clear();45304531bool add_ellipsis = p_trim_flags.has_flag(OVERRUN_ADD_ELLIPSIS);4532bool cut_per_word = p_trim_flags.has_flag(OVERRUN_TRIM_WORD_ONLY);4533bool enforce_ellipsis = p_trim_flags.has_flag(OVERRUN_ENFORCE_ELLIPSIS);4534bool justification_aware = p_trim_flags.has_flag(OVERRUN_JUSTIFICATION_AWARE);45354536Glyph *sd_glyphs = sd->glyphs.ptrw();45374538if ((p_trim_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIM || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {4539sd->overrun_trim_data.trim_pos = -1;4540sd->overrun_trim_data.ellipsis_pos = -1;4541return;4542}45434544if (justification_aware && !sd->fit_width_minimum_reached) {4545return;4546}45474548Vector<ShapedTextDataFallback::Span> &spans = sd->spans;4549if (sd->parent != RID()) {4550ShapedTextDataFallback *parent_sd = shaped_owner.get_or_null(sd->parent);4551ERR_FAIL_COND(!parent_sd->valid.is_set());4552spans = parent_sd->spans;4553}45544555int span_size = spans.size();4556if (span_size == 0) {4557return;4558}45594560int sd_size = sd->glyphs.size();4561int last_gl_font_size = sd_glyphs[sd_size - 1].font_size;4562bool found_el_char = false;45634564// Find usable fonts, if fonts from the last glyph do not have required chars.4565RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;4566if (add_ellipsis || enforce_ellipsis) {4567if (!_font_has_char(dot_gl_font_rid, sd->el_char)) {4568const Array &fonts = spans[span_size - 1].fonts;4569for (int i = 0; i < fonts.size(); i++) {4570if (_font_has_char(fonts[i], sd->el_char)) {4571dot_gl_font_rid = fonts[i];4572found_el_char = true;4573break;4574}4575}4576if (!found_el_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) {4577const char32_t u32str[] = { sd->el_char, 0 };4578RID rid = _find_sys_font_for_text(fonts[0], String(), spans[span_size - 1].language, u32str);4579if (rid.is_valid()) {4580dot_gl_font_rid = rid;4581found_el_char = true;4582}4583}4584} else {4585found_el_char = true;4586}4587if (!found_el_char) {4588bool found_dot_char = false;4589dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;4590if (!_font_has_char(dot_gl_font_rid, '.')) {4591const Array &fonts = spans[span_size - 1].fonts;4592for (int i = 0; i < fonts.size(); i++) {4593if (_font_has_char(fonts[i], '.')) {4594dot_gl_font_rid = fonts[i];4595found_dot_char = true;4596break;4597}4598}4599if (!found_dot_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) {4600RID rid = _find_sys_font_for_text(fonts[0], String(), spans[span_size - 1].language, ".");4601if (rid.is_valid()) {4602dot_gl_font_rid = rid;4603}4604}4605}4606}4607}4608RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;4609if (!_font_has_char(whitespace_gl_font_rid, ' ')) {4610const Array &fonts = spans[span_size - 1].fonts;4611for (int i = 0; i < fonts.size(); i++) {4612if (_font_has_char(fonts[i], ' ')) {4613whitespace_gl_font_rid = fonts[i];4614break;4615}4616}4617}46184619int32_t dot_gl_idx = ((add_ellipsis || enforce_ellipsis) && dot_gl_font_rid.is_valid()) ? _font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, (found_el_char ? sd->el_char : '.'), 0) : -1;4620Vector2 dot_adv = ((add_ellipsis || enforce_ellipsis) && dot_gl_font_rid.is_valid()) ? _font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2();4621int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ', 0) : -1;4622Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2();46234624int ellipsis_width = 0;4625if (add_ellipsis && whitespace_gl_font_rid.is_valid()) {4626ellipsis_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);4627}46284629int ell_min_characters = 6;4630double width = sd->width;4631double width_without_el = width;46324633int trim_pos = 0;4634int ellipsis_pos = (enforce_ellipsis) ? 0 : -1;46354636int last_valid_cut = -1;4637int last_valid_cut_witout_el = -1;46384639if (enforce_ellipsis && (width + ellipsis_width <= p_width)) {4640trim_pos = -1;4641ellipsis_pos = sd_size;4642} else {4643for (int i = sd_size - 1; i != -1; i--) {4644width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;46454646if (sd_glyphs[i].count > 0) {4647bool above_min_char_threshold = (i >= ell_min_characters);4648if (!above_min_char_threshold && last_valid_cut_witout_el != -1) {4649trim_pos = last_valid_cut_witout_el;4650ellipsis_pos = -1;4651width = width_without_el;4652break;4653}4654if (!enforce_ellipsis && width <= p_width && last_valid_cut_witout_el == -1) {4655if (cut_per_word && above_min_char_threshold) {4656if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {4657last_valid_cut_witout_el = i;4658width_without_el = width;4659}4660} else {4661last_valid_cut_witout_el = i;4662width_without_el = width;4663}4664}4665if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {4666if (cut_per_word && above_min_char_threshold) {4667if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {4668last_valid_cut = i;4669}4670} else {4671last_valid_cut = i;4672}4673if (last_valid_cut != -1) {4674trim_pos = last_valid_cut;46754676if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {4677ellipsis_pos = trim_pos;4678}4679break;4680}4681}4682}4683}4684}46854686sd->overrun_trim_data.trim_pos = trim_pos;4687sd->overrun_trim_data.ellipsis_pos = ellipsis_pos;4688if (trim_pos == 0 && enforce_ellipsis && add_ellipsis) {4689sd->overrun_trim_data.ellipsis_pos = 0;4690}46914692if ((trim_pos >= 0 && sd->width > p_width) || enforce_ellipsis) {4693if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) {4694// Insert an additional space when cutting word bound for aesthetics.4695if (cut_per_word && (ellipsis_pos > 0)) {4696Glyph gl;4697gl.count = 1;4698gl.advance = whitespace_adv.x;4699gl.index = whitespace_gl_idx;4700gl.font_rid = whitespace_gl_font_rid;4701gl.font_size = last_gl_font_size;4702gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL;47034704sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);4705}4706// Add ellipsis dots.4707if (dot_gl_idx != 0) {4708Glyph gl;4709gl.count = 1;4710gl.repeat = (found_el_char ? 1 : 3);4711gl.advance = dot_adv.x;4712gl.index = dot_gl_idx;4713gl.font_rid = dot_gl_font_rid;4714gl.font_size = last_gl_font_size;4715gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL;47164717sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);4718}4719}47204721sd->text_trimmed = true;4722sd->width_trimmed = width + ((ellipsis_pos != -1) ? ellipsis_width : 0);4723}4724}47254726int64_t TextServerFallback::_shaped_text_get_trim_pos(const RID &p_shaped) const {4727ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);4728ERR_FAIL_NULL_V_MSG(sd, -1, "ShapedTextDataFallback invalid.");47294730MutexLock lock(sd->mutex);4731return sd->overrun_trim_data.trim_pos;4732}47334734int64_t TextServerFallback::_shaped_text_get_ellipsis_pos(const RID &p_shaped) const {4735ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);4736ERR_FAIL_NULL_V_MSG(sd, -1, "ShapedTextDataFallback invalid.");47374738MutexLock lock(sd->mutex);4739return sd->overrun_trim_data.ellipsis_pos;4740}47414742const Glyph *TextServerFallback::_shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const {4743ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);4744ERR_FAIL_NULL_V_MSG(sd, nullptr, "ShapedTextDataFallback invalid.");47454746MutexLock lock(sd->mutex);4747return sd->overrun_trim_data.ellipsis_glyph_buf.ptr();4748}47494750int64_t TextServerFallback::_shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const {4751ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);4752ERR_FAIL_NULL_V_MSG(sd, 0, "ShapedTextDataFallback invalid.");47534754MutexLock lock(sd->mutex);4755return sd->overrun_trim_data.ellipsis_glyph_buf.size();4756}47574758bool TextServerFallback::_shaped_text_shape(const RID &p_shaped) {4759ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);4760ERR_FAIL_NULL_V(sd, false);47614762MutexLock lock(sd->mutex);4763if (sd->valid.is_set()) {4764return true;4765}47664767if (sd->parent != RID()) {4768full_copy(sd);4769}47704771// Cleanup.4772sd->justification_ops_valid = false;4773sd->line_breaks_valid = false;4774sd->ascent = 0.0;4775sd->descent = 0.0;4776sd->width = 0.0;4777sd->glyphs.clear();4778sd->runs.clear();4779sd->runs_dirty = true;47804781if (sd->text.length() == 0) {4782sd->valid.set();4783return true;4784}47854786// "Shape" string.4787for (int i = 0; i < sd->spans.size(); i++) {4788const ShapedTextDataFallback::Span &span = sd->spans[i];4789if (span.embedded_key != Variant()) {4790// Embedded object.4791if (sd->orientation == ORIENTATION_HORIZONTAL) {4792sd->objects[span.embedded_key].rect.position.x = sd->width;4793sd->width += sd->objects[span.embedded_key].rect.size.x;4794} else {4795sd->objects[span.embedded_key].rect.position.y = sd->width;4796sd->width += sd->objects[span.embedded_key].rect.size.y;4797}4798Glyph gl;4799gl.span_index = i;4800gl.start = span.start;4801gl.end = span.end;4802gl.count = 1;4803gl.index = 0;4804gl.flags = GRAPHEME_IS_VALID | GRAPHEME_IS_EMBEDDED_OBJECT;4805if (sd->orientation == ORIENTATION_HORIZONTAL) {4806gl.advance = sd->objects[span.embedded_key].rect.size.x;4807} else {4808gl.advance = sd->objects[span.embedded_key].rect.size.y;4809}4810sd->glyphs.push_back(gl);4811} else {4812// Text span.4813int last_non_zero_w = sd->end - 1;4814if (i == sd->spans.size() - 1) {4815for (int j = span.end - 1; j > span.start; j--) {4816last_non_zero_w = j;4817uint32_t idx = (int32_t)sd->text[j - sd->start];4818if (!is_control(idx) && !(idx >= 0x200B && idx <= 0x200D)) {4819break;4820}4821}4822}48234824RID prev_font;4825for (int j = span.start; j < span.end; j++) {4826Glyph gl;4827gl.span_index = i;4828gl.start = j;4829gl.end = j + 1;4830gl.count = 1;4831gl.font_size = span.font_size;4832gl.index = (int32_t)sd->text[j - sd->start]; // Use codepoint.4833bool zw = (gl.index >= 0x200b && gl.index <= 0x200d);4834if (gl.index == 0x0009 || gl.index == 0x000b || zw) {4835gl.index = 0x0020;4836}4837if (!sd->preserve_control && is_control(gl.index)) {4838gl.index = 0x0020;4839}4840// Select first font which has character (font are already sorted by span language).4841for (int k = 0; k < span.fonts.size(); k++) {4842if (_font_has_char(span.fonts[k], gl.index)) {4843gl.font_rid = span.fonts[k];4844break;4845}4846}4847if (!gl.font_rid.is_valid() && prev_font.is_valid()) {4848if (_font_has_char(prev_font, gl.index)) {4849gl.font_rid = prev_font;4850}4851}4852if (!gl.font_rid.is_valid() && OS::get_singleton()->has_feature("system_fonts") && span.fonts.size() > 0) {4853// Try system fallback.4854RID fdef = span.fonts[0];4855if (_font_is_allow_system_fallback(fdef)) {4856String text = sd->text.substr(j, 1);4857gl.font_rid = _find_sys_font_for_text(fdef, String(), span.language, text);4858}4859}4860prev_font = gl.font_rid;48614862if (gl.font_rid.is_valid()) {4863double scale = _font_get_scale(gl.font_rid, gl.font_size);4864bool 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 && gl.font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);4865if (sd->text[j - sd->start] != 0 && !is_linebreak(sd->text[j - sd->start])) {4866if (sd->orientation == ORIENTATION_HORIZONTAL) {4867gl.advance = _font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x;4868gl.x_off = 0;4869gl.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));4870sd->ascent = MAX(sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_TOP));4871sd->descent = MAX(sd->descent, _font_get_descent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_BOTTOM));4872} else {4873gl.advance = _font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).y;4874gl.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));4875gl.y_off = _font_get_ascent(gl.font_rid, gl.font_size);4876sd->ascent = MAX(sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));4877sd->descent = MAX(sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));4878}4879}4880if (zw) {4881gl.advance = 0.0;4882}4883if ((j < last_non_zero_w) && !Math::is_zero_approx(gl.advance)) {4884// Do not add extra spacing to the last glyph of the string and zero width glyphs.4885if (is_whitespace(sd->text[j - sd->start])) {4886gl.advance += sd->extra_spacing[SPACING_SPACE] + _font_get_spacing(gl.font_rid, SPACING_SPACE);4887} else {4888gl.advance += sd->extra_spacing[SPACING_GLYPH] + _font_get_spacing(gl.font_rid, SPACING_GLYPH);4889}4890}4891sd->upos = MAX(sd->upos, _font_get_underline_position(gl.font_rid, gl.font_size));4892sd->uthk = MAX(sd->uthk, _font_get_underline_thickness(gl.font_rid, gl.font_size));48934894// Add kerning to previous glyph.4895if (sd->glyphs.size() > 0) {4896Glyph &prev_gl = sd->glyphs.write[sd->glyphs.size() - 1];4897if (prev_gl.font_rid == gl.font_rid && prev_gl.font_size == gl.font_size) {4898if (sd->orientation == ORIENTATION_HORIZONTAL) {4899prev_gl.advance += _font_get_kerning(gl.font_rid, gl.font_size, Vector2i(prev_gl.index, gl.index)).x;4900} else {4901prev_gl.advance += _font_get_kerning(gl.font_rid, gl.font_size, Vector2i(prev_gl.index, gl.index)).y;4902}4903}4904}4905if (sd->orientation == ORIENTATION_HORIZONTAL && !subpos) {4906gl.advance = Math::round(gl.advance);4907}4908} else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) {4909// Glyph not found, replace with hex code box.4910if (sd->orientation == ORIENTATION_HORIZONTAL) {4911gl.advance = get_hex_code_box_size(gl.font_size, gl.index).x;4912sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.85);4913sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.15);4914} else {4915gl.advance = get_hex_code_box_size(gl.font_size, gl.index).y;4916sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));4917sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));4918}4919}4920sd->width += gl.advance;4921sd->glyphs.push_back(gl);4922}4923}4924}49254926// Align embedded objects to baseline.4927_realign(sd);49284929sd->valid.set();4930return sd->valid.is_set();4931}49324933bool TextServerFallback::_shaped_text_is_ready(const RID &p_shaped) const {4934const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);4935ERR_FAIL_NULL_V(sd, false);49364937return sd->valid.is_set();4938}49394940const Glyph *TextServerFallback::_shaped_text_get_glyphs(const RID &p_shaped) const {4941const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);4942ERR_FAIL_NULL_V(sd, nullptr);49434944MutexLock lock(sd->mutex);4945if (!sd->valid.is_set()) {4946const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);4947}4948return sd->glyphs.ptr();4949}49504951int64_t TextServerFallback::_shaped_text_get_glyph_count(const RID &p_shaped) const {4952const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);4953ERR_FAIL_NULL_V(sd, 0);49544955MutexLock lock(sd->mutex);4956if (!sd->valid.is_set()) {4957const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);4958}4959return sd->glyphs.size();4960}49614962const Glyph *TextServerFallback::_shaped_text_sort_logical(const RID &p_shaped) {4963const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);4964ERR_FAIL_NULL_V(sd, nullptr);49654966MutexLock lock(sd->mutex);4967if (!sd->valid.is_set()) {4968_shaped_text_shape(p_shaped);4969}49704971return sd->glyphs.ptr(); // Already in the logical order, return as is.4972}49734974Vector2i TextServerFallback::_shaped_text_get_range(const RID &p_shaped) const {4975const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);4976ERR_FAIL_NULL_V(sd, Vector2i());49774978MutexLock lock(sd->mutex);4979return Vector2(sd->start, sd->end);4980}49814982Array TextServerFallback::_shaped_text_get_objects(const RID &p_shaped) const {4983Array ret;4984const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);4985ERR_FAIL_NULL_V(sd, ret);49864987MutexLock lock(sd->mutex);4988for (const KeyValue<Variant, ShapedTextDataFallback::EmbeddedObject> &E : sd->objects) {4989ret.push_back(E.key);4990}49914992return ret;4993}49944995Rect2 TextServerFallback::_shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const {4996const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);4997ERR_FAIL_NULL_V(sd, Rect2());49984999MutexLock lock(sd->mutex);5000ERR_FAIL_COND_V(!sd->objects.has(p_key), Rect2());5001if (!sd->valid.is_set()) {5002const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);5003}5004return sd->objects[p_key].rect;5005}50065007Vector2i TextServerFallback::_shaped_text_get_object_range(const RID &p_shaped, const Variant &p_key) const {5008const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);5009ERR_FAIL_NULL_V(sd, Vector2i());50105011MutexLock lock(sd->mutex);5012ERR_FAIL_COND_V(!sd->objects.has(p_key), Vector2i());5013return Vector2i(sd->objects[p_key].start, sd->objects[p_key].end);5014}50155016int64_t TextServerFallback::_shaped_text_get_object_glyph(const RID &p_shaped, const Variant &p_key) const {5017const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);5018ERR_FAIL_NULL_V(sd, -1);50195020MutexLock lock(sd->mutex);5021ERR_FAIL_COND_V(!sd->objects.has(p_key), -1);5022const ShapedTextDataFallback::EmbeddedObject &obj = sd->objects[p_key];5023int sd_size = sd->glyphs.size();5024const Glyph *sd_glyphs = sd->glyphs.ptr();5025for (int i = 0; i < sd_size; i++) {5026if (obj.start == sd_glyphs[i].start) {5027return i;5028}5029}5030return -1;5031}50325033Size2 TextServerFallback::_shaped_text_get_size(const RID &p_shaped) const {5034const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);5035ERR_FAIL_NULL_V(sd, Size2());50365037MutexLock lock(sd->mutex);5038if (!sd->valid.is_set()) {5039const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);5040}5041if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) {5042return Size2(sd->width, sd->ascent + sd->descent + sd->extra_spacing[SPACING_TOP] + sd->extra_spacing[SPACING_BOTTOM]).ceil();5043} else {5044return Size2(sd->ascent + sd->descent + sd->extra_spacing[SPACING_TOP] + sd->extra_spacing[SPACING_BOTTOM], sd->width).ceil();5045}5046}50475048double TextServerFallback::_shaped_text_get_ascent(const RID &p_shaped) const {5049const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);5050ERR_FAIL_NULL_V(sd, 0.0);50515052MutexLock lock(sd->mutex);5053if (!sd->valid.is_set()) {5054const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);5055}5056return sd->ascent + sd->extra_spacing[SPACING_TOP];5057}50585059double TextServerFallback::_shaped_text_get_descent(const RID &p_shaped) const {5060const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);5061ERR_FAIL_NULL_V(sd, 0.0);50625063MutexLock lock(sd->mutex);5064if (!sd->valid.is_set()) {5065const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);5066}5067return sd->descent + sd->extra_spacing[SPACING_BOTTOM];5068}50695070double TextServerFallback::_shaped_text_get_width(const RID &p_shaped) const {5071const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);5072ERR_FAIL_NULL_V(sd, 0.0);50735074MutexLock lock(sd->mutex);5075if (!sd->valid.is_set()) {5076const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);5077}5078return Math::ceil(sd->width);5079}50805081double TextServerFallback::_shaped_text_get_underline_position(const RID &p_shaped) const {5082const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);5083ERR_FAIL_NULL_V(sd, 0.0);50845085MutexLock lock(sd->mutex);5086if (!sd->valid.is_set()) {5087const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);5088}50895090return sd->upos;5091}50925093double TextServerFallback::_shaped_text_get_underline_thickness(const RID &p_shaped) const {5094const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);5095ERR_FAIL_NULL_V(sd, 0.0);50965097MutexLock lock(sd->mutex);5098if (!sd->valid.is_set()) {5099const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);5100}51015102return sd->uthk;5103}51045105PackedInt32Array TextServerFallback::_shaped_text_get_character_breaks(const RID &p_shaped) const {5106const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);5107ERR_FAIL_NULL_V(sd, PackedInt32Array());51085109MutexLock lock(sd->mutex);5110if (!sd->valid.is_set()) {5111const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);5112}51135114PackedInt32Array ret;5115int size = sd->end - sd->start;5116if (size > 0) {5117ret.resize(size);5118for (int i = 0; i < size; i++) {5119#ifdef GDEXTENSION5120ret[i] = i + 1 + sd->start;5121#else5122ret.write[i] = i + 1 + sd->start;5123#endif5124}5125}5126return ret;5127}51285129String TextServerFallback::_string_to_upper(const String &p_string, const String &p_language) const {5130return p_string.to_upper();5131}51325133String TextServerFallback::_string_to_lower(const String &p_string, const String &p_language) const {5134return p_string.to_lower();5135}51365137String TextServerFallback::_string_to_title(const String &p_string, const String &p_language) const {5138return p_string.capitalize();5139}51405141PackedInt32Array TextServerFallback::_string_get_word_breaks(const String &p_string, const String &p_language, int64_t p_chars_per_line) const {5142PackedInt32Array ret;51435144if (p_chars_per_line > 0) {5145int line_start = 0;5146int last_break = -1;5147int line_length = 0;51485149for (int i = 0; i < p_string.length(); i++) {5150const char32_t c = p_string[i];51515152bool is_lb = is_linebreak(c);5153bool is_ws = is_whitespace(c);5154bool is_p = (is_punct(c) && c != 0x005F) || is_underscore(c) || c == '\t' || c == 0xfffc;51555156if (is_lb) {5157if (line_length > 0) {5158ret.push_back(line_start);5159ret.push_back(i);5160}5161line_start = i;5162line_length = 0;5163last_break = -1;5164continue;5165} else if (is_ws || is_p) {5166last_break = i;5167}51685169if (line_length == p_chars_per_line) {5170if (last_break != -1) {5171int last_break_w_spaces = last_break;5172while (last_break > line_start && is_whitespace(p_string[last_break - 1])) {5173last_break--;5174}5175if (line_start != last_break) {5176ret.push_back(line_start);5177ret.push_back(last_break);5178}5179while (last_break_w_spaces < p_string.length() && is_whitespace(p_string[last_break_w_spaces])) {5180last_break_w_spaces++;5181}5182line_start = last_break_w_spaces;5183if (last_break_w_spaces < i) {5184line_length = i - last_break_w_spaces;5185} else {5186i = last_break_w_spaces;5187line_length = 0;5188}5189} else {5190ret.push_back(line_start);5191ret.push_back(i);5192line_start = i;5193line_length = 0;5194}5195last_break = -1;5196}5197line_length++;5198}5199if (line_length > 0) {5200ret.push_back(line_start);5201ret.push_back(p_string.length());5202}5203} else {5204int word_start = 0; // -1 if no word encountered. Leading spaces are part of a word.5205int word_length = 0;52065207for (int i = 0; i < p_string.length(); i++) {5208const char32_t c = p_string[i];52095210bool is_lb = is_linebreak(c);5211bool is_ws = is_whitespace(c);5212bool is_p = (is_punct(c) && c != 0x005F) || is_underscore(c) || c == '\t' || c == 0xfffc;52135214if (word_start == -1) {5215if (!is_lb && !is_ws && !is_p) {5216word_start = i;5217}5218continue;5219}52205221if (is_lb) {5222if (word_start != -1 && word_length > 0) {5223ret.push_back(word_start);5224ret.push_back(i);5225}5226word_start = -1;5227word_length = 0;5228} else if (is_ws || is_p) {5229if (word_start != -1 && word_length > 0) {5230ret.push_back(word_start);5231ret.push_back(i);5232}5233word_start = -1;5234word_length = 0;5235}52365237word_length++;5238}5239if (word_start != -1 && word_length > 0) {5240ret.push_back(word_start);5241ret.push_back(p_string.length());5242}5243}5244return ret;5245}52465247void TextServerFallback::_update_settings() {5248lcd_subpixel_layout.set((TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"));5249}52505251TextServerFallback::TextServerFallback() {5252_insert_feature_sets();5253ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &TextServerFallback::_update_settings));5254}52555256void TextServerFallback::_font_clear_system_fallback_cache() {5257for (const KeyValue<SystemFontKey, SystemFontCache> &E : system_fonts) {5258const Vector<SystemFontCacheRec> &sysf_cache = E.value.var;5259for (const SystemFontCacheRec &F : sysf_cache) {5260_free_rid(F.rid);5261}5262}5263system_fonts.clear();5264system_font_data.clear();5265}52665267void TextServerFallback::_cleanup() {5268font_clear_system_fallback_cache();5269}52705271TextServerFallback::~TextServerFallback() {5272#ifdef MODULE_FREETYPE_ENABLED5273if (ft_library != nullptr) {5274FT_Done_FreeType(ft_library);5275}5276#endif5277}527852795280