1/**************************************************************************/
2/* text_server_adv.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "text_server_adv.h"
32
33#ifdef GDEXTENSION
34// Headers for building as GDExtension plug-in.
35
36#include <godot_cpp/classes/file_access.hpp>
37#include <godot_cpp/classes/os.hpp>
38#include <godot_cpp/classes/project_settings.hpp>
39#include <godot_cpp/classes/rendering_server.hpp>
40#include <godot_cpp/classes/translation_server.hpp>
41#include <godot_cpp/core/error_macros.hpp>
42
43using namespace godot;
44
45#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var)
46
47#else
48// Headers for building as built-in module.
49
50#include "core/config/project_settings.h"
51#include "core/error/error_macros.h"
52#include "core/object/worker_thread_pool.h"
53#include "core/string/print_string.h"
54#include "core/string/translation.h"
55#include "scene/resources/image_texture.h"
56
57#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg.
58
59#endif
60
61// Built-in ICU data.
62
63#ifdef ICU_STATIC_DATA
64#include "icudata.gen.h"
65#endif
66
67// Thirdparty headers.
68
69#ifdef MODULE_MSDFGEN_ENABLED
70#include <core/ShapeDistanceFinder.h>
71#include <core/contour-combiners.h>
72#include <core/edge-selectors.h>
73#include <msdfgen.h>
74#endif
75
76#ifdef MODULE_SVG_ENABLED
77#ifdef MODULE_FREETYPE_ENABLED
78#include "thorvg_svg_in_ot.h"
79#endif
80#endif
81
82/*************************************************************************/
83/* bmp_font_t HarfBuzz Bitmap font interface */
84/*************************************************************************/
85
86hb_font_funcs_t *TextServerAdvanced::funcs = nullptr;
87
88TextServerAdvanced::bmp_font_t *TextServerAdvanced::_bmp_font_create(TextServerAdvanced::FontForSizeAdvanced *p_face, bool p_unref) {
89 bmp_font_t *bm_font = memnew(bmp_font_t);
90
91 if (!bm_font) {
92 return nullptr;
93 }
94
95 bm_font->face = p_face;
96 bm_font->unref = p_unref;
97
98 return bm_font;
99}
100
101void TextServerAdvanced::_bmp_font_destroy(void *p_data) {
102 bmp_font_t *bm_font = static_cast<bmp_font_t *>(p_data);
103 memdelete(bm_font);
104}
105
106hb_bool_t TextServerAdvanced::_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data) {
107 const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
108
109 if (!bm_font->face) {
110 return false;
111 }
112
113 if (!bm_font->face->glyph_map.has(p_unicode)) {
114 if (bm_font->face->glyph_map.has(0xf000u + p_unicode)) {
115 *r_glyph = 0xf000u + p_unicode;
116 return true;
117 } else {
118 return false;
119 }
120 }
121
122 *r_glyph = p_unicode;
123 return true;
124}
125
126hb_position_t TextServerAdvanced::_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) {
127 const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
128
129 if (!bm_font->face) {
130 return 0;
131 }
132
133 if (!bm_font->face->glyph_map.has(p_glyph)) {
134 return 0;
135 }
136
137 return bm_font->face->glyph_map[p_glyph].advance.x * 64;
138}
139
140hb_position_t TextServerAdvanced::_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) {
141 const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
142
143 if (!bm_font->face) {
144 return 0;
145 }
146
147 if (!bm_font->face->glyph_map.has(p_glyph)) {
148 return 0;
149 }
150
151 return -bm_font->face->glyph_map[p_glyph].advance.y * 64;
152}
153
154hb_position_t TextServerAdvanced::_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data) {
155 const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
156
157 if (!bm_font->face) {
158 return 0;
159 }
160
161 if (!bm_font->face->kerning_map.has(Vector2i(p_left_glyph, p_right_glyph))) {
162 return 0;
163 }
164
165 return bm_font->face->kerning_map[Vector2i(p_left_glyph, p_right_glyph)].x * 64;
166}
167
168hb_bool_t TextServerAdvanced::_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data) {
169 const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
170
171 if (!bm_font->face) {
172 return false;
173 }
174
175 if (!bm_font->face->glyph_map.has(p_glyph)) {
176 return false;
177 }
178
179 *r_x = bm_font->face->glyph_map[p_glyph].advance.x * 32;
180 *r_y = -bm_font->face->ascent * 64;
181
182 return true;
183}
184
185hb_bool_t TextServerAdvanced::_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data) {
186 const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
187
188 if (!bm_font->face) {
189 return false;
190 }
191
192 if (!bm_font->face->glyph_map.has(p_glyph)) {
193 return false;
194 }
195
196 r_extents->x_bearing = 0;
197 r_extents->y_bearing = 0;
198 r_extents->width = bm_font->face->glyph_map[p_glyph].rect.size.x * 64;
199 r_extents->height = bm_font->face->glyph_map[p_glyph].rect.size.y * 64;
200
201 return true;
202}
203
204hb_bool_t TextServerAdvanced::_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data) {
205 const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
206
207 if (!bm_font->face) {
208 return false;
209 }
210
211 r_metrics->ascender = bm_font->face->ascent;
212 r_metrics->descender = bm_font->face->descent;
213 r_metrics->line_gap = 0;
214
215 return true;
216}
217
218void TextServerAdvanced::_bmp_create_font_funcs() {
219 if (funcs == nullptr) {
220 funcs = hb_font_funcs_create();
221
222 hb_font_funcs_set_font_h_extents_func(funcs, _bmp_get_font_h_extents, nullptr, nullptr);
223 hb_font_funcs_set_nominal_glyph_func(funcs, _bmp_get_nominal_glyph, nullptr, nullptr);
224 hb_font_funcs_set_glyph_h_advance_func(funcs, _bmp_get_glyph_h_advance, nullptr, nullptr);
225 hb_font_funcs_set_glyph_v_advance_func(funcs, _bmp_get_glyph_v_advance, nullptr, nullptr);
226 hb_font_funcs_set_glyph_v_origin_func(funcs, _bmp_get_glyph_v_origin, nullptr, nullptr);
227 hb_font_funcs_set_glyph_h_kerning_func(funcs, _bmp_get_glyph_h_kerning, nullptr, nullptr);
228 hb_font_funcs_set_glyph_extents_func(funcs, _bmp_get_glyph_extents, nullptr, nullptr);
229
230 hb_font_funcs_make_immutable(funcs);
231 }
232}
233
234void TextServerAdvanced::_bmp_free_font_funcs() {
235 if (funcs != nullptr) {
236 hb_font_funcs_destroy(funcs);
237 funcs = nullptr;
238 }
239}
240
241void TextServerAdvanced::_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontForSizeAdvanced *p_face, bool p_unref) {
242 hb_font_set_funcs(p_font, funcs, _bmp_font_create(p_face, p_unref), _bmp_font_destroy);
243}
244
245hb_font_t *TextServerAdvanced::_bmp_font_create(TextServerAdvanced::FontForSizeAdvanced *p_face, hb_destroy_func_t p_destroy) {
246 hb_font_t *font;
247 hb_face_t *face = hb_face_create(nullptr, 0);
248
249 font = hb_font_create(face);
250 hb_face_destroy(face);
251 _bmp_font_set_funcs(font, p_face, false);
252 return font;
253}
254
255/*************************************************************************/
256/* Character properties. */
257/*************************************************************************/
258
259_FORCE_INLINE_ bool is_ain(char32_t p_chr) {
260 return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_AIN;
261}
262
263_FORCE_INLINE_ bool is_alef(char32_t p_chr) {
264 return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_ALEF;
265}
266
267_FORCE_INLINE_ bool is_beh(char32_t p_chr) {
268 int32_t prop = u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP);
269 return (prop == U_JG_BEH) || (prop == U_JG_NOON) || (prop == U_JG_AFRICAN_NOON) || (prop == U_JG_NYA) || (prop == U_JG_YEH) || (prop == U_JG_FARSI_YEH);
270}
271
272_FORCE_INLINE_ bool is_dal(char32_t p_chr) {
273 return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_DAL;
274}
275
276_FORCE_INLINE_ bool is_feh(char32_t p_chr) {
277 return (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_FEH) || (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_AFRICAN_FEH);
278}
279
280_FORCE_INLINE_ bool is_gaf(char32_t p_chr) {
281 return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_GAF;
282}
283
284_FORCE_INLINE_ bool is_heh(char32_t p_chr) {
285 return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_HEH;
286}
287
288_FORCE_INLINE_ bool is_kaf(char32_t p_chr) {
289 return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_KAF;
290}
291
292_FORCE_INLINE_ bool is_lam(char32_t p_chr) {
293 return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_LAM;
294}
295
296_FORCE_INLINE_ bool is_qaf(char32_t p_chr) {
297 return (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_QAF) || (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_AFRICAN_QAF);
298}
299
300_FORCE_INLINE_ bool is_reh(char32_t p_chr) {
301 return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_REH;
302}
303
304_FORCE_INLINE_ bool is_seen_sad(char32_t p_chr) {
305 return (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_SAD) || (u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_SEEN);
306}
307
308_FORCE_INLINE_ bool is_tah(char32_t p_chr) {
309 return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_TAH;
310}
311
312_FORCE_INLINE_ bool is_teh_marbuta(char32_t p_chr) {
313 return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_TEH_MARBUTA;
314}
315
316_FORCE_INLINE_ bool is_yeh(char32_t p_chr) {
317 int32_t prop = u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP);
318 return (prop == U_JG_YEH) || (prop == U_JG_FARSI_YEH) || (prop == U_JG_YEH_BARREE) || (prop == U_JG_BURUSHASKI_YEH_BARREE) || (prop == U_JG_YEH_WITH_TAIL);
319}
320
321_FORCE_INLINE_ bool is_waw(char32_t p_chr) {
322 return u_getIntPropertyValue(p_chr, UCHAR_JOINING_GROUP) == U_JG_WAW;
323}
324
325_FORCE_INLINE_ bool is_transparent(char32_t p_chr) {
326 return u_getIntPropertyValue(p_chr, UCHAR_JOINING_TYPE) == U_JT_TRANSPARENT;
327}
328
329_FORCE_INLINE_ bool is_ligature(char32_t p_chr, char32_t p_nchr) {
330 return (is_lam(p_chr) && is_alef(p_nchr));
331}
332
333_FORCE_INLINE_ bool is_connected_to_prev(char32_t p_chr, char32_t p_pchr) {
334 int32_t prop = u_getIntPropertyValue(p_pchr, UCHAR_JOINING_TYPE);
335 return (prop != U_JT_RIGHT_JOINING) && (prop != U_JT_NON_JOINING) ? !is_ligature(p_pchr, p_chr) : false;
336}
337
338/*************************************************************************/
339
340bool TextServerAdvanced::icu_data_loaded = false;
341
342bool TextServerAdvanced::_has_feature(Feature p_feature) const {
343 switch (p_feature) {
344 case FEATURE_SIMPLE_LAYOUT:
345 case FEATURE_BIDI_LAYOUT:
346 case FEATURE_VERTICAL_LAYOUT:
347 case FEATURE_SHAPING:
348 case FEATURE_KASHIDA_JUSTIFICATION:
349 case FEATURE_BREAK_ITERATORS:
350 case FEATURE_FONT_BITMAP:
351#ifdef MODULE_FREETYPE_ENABLED
352 case FEATURE_FONT_DYNAMIC:
353#endif
354#ifdef MODULE_MSDFGEN_ENABLED
355 case FEATURE_FONT_MSDF:
356#endif
357 case FEATURE_FONT_VARIABLE:
358 case FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION:
359 case FEATURE_USE_SUPPORT_DATA:
360 case FEATURE_UNICODE_IDENTIFIERS:
361 case FEATURE_UNICODE_SECURITY:
362 return true;
363 default: {
364 }
365 }
366 return false;
367}
368
369String TextServerAdvanced::_get_name() const {
370#ifdef GDEXTENSION
371 return "ICU / HarfBuzz / Graphite (GDExtension)";
372#else
373 return "ICU / HarfBuzz / Graphite (Built-in)";
374#endif
375}
376
377int64_t TextServerAdvanced::_get_features() const {
378 int64_t interface_features = FEATURE_SIMPLE_LAYOUT | FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_FONT_BITMAP | FEATURE_FONT_VARIABLE | FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION | FEATURE_USE_SUPPORT_DATA;
379#ifdef MODULE_FREETYPE_ENABLED
380 interface_features |= FEATURE_FONT_DYNAMIC;
381#endif
382#ifdef MODULE_MSDFGEN_ENABLED
383 interface_features |= FEATURE_FONT_MSDF;
384#endif
385
386 return interface_features;
387}
388
389void TextServerAdvanced::_free_rid(const RID &p_rid) {
390 _THREAD_SAFE_METHOD_
391 if (font_owner.owns(p_rid)) {
392 MutexLock ftlock(ft_mutex);
393
394 FontAdvanced *fd = font_owner.get_or_null(p_rid);
395 {
396 MutexLock lock(fd->mutex);
397 font_owner.free(p_rid);
398 }
399 memdelete(fd);
400 } else if (shaped_owner.owns(p_rid)) {
401 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_rid);
402 {
403 MutexLock lock(sd->mutex);
404 shaped_owner.free(p_rid);
405 }
406 memdelete(sd);
407 }
408}
409
410bool TextServerAdvanced::_has(const RID &p_rid) {
411 _THREAD_SAFE_METHOD_
412 return font_owner.owns(p_rid) || shaped_owner.owns(p_rid);
413}
414
415bool TextServerAdvanced::_load_support_data(const String &p_filename) {
416 _THREAD_SAFE_METHOD_
417
418#ifdef ICU_STATIC_DATA
419 if (!icu_data_loaded) {
420 UErrorCode err = U_ZERO_ERROR;
421 u_init(&err); // Do not check for errors, since we only load part of the data.
422 icu_data_loaded = true;
423 }
424#else
425 if (!icu_data_loaded) {
426 String filename = (p_filename.is_empty()) ? String("res://") + _MKSTR(ICU_DATA_NAME) : p_filename;
427
428 Ref<FileAccess> f = FileAccess::open(filename, FileAccess::READ);
429 if (f.is_null()) {
430 return false;
431 }
432 uint64_t len = f->get_length();
433 PackedByteArray icu_data = f->get_buffer(len);
434
435 UErrorCode err = U_ZERO_ERROR;
436 udata_setCommonData(icu_data.ptr(), &err);
437 if (U_FAILURE(err)) {
438 ERR_FAIL_V_MSG(false, u_errorName(err));
439 }
440
441 err = U_ZERO_ERROR;
442 u_init(&err);
443 if (U_FAILURE(err)) {
444 ERR_FAIL_V_MSG(false, u_errorName(err));
445 }
446 icu_data_loaded = true;
447 }
448#endif
449 return true;
450}
451
452String TextServerAdvanced::_get_support_data_filename() const {
453 return _MKSTR(ICU_DATA_NAME);
454}
455
456String TextServerAdvanced::_get_support_data_info() const {
457 return String("ICU break iteration data (") + _MKSTR(ICU_DATA_NAME) + String(").");
458}
459
460bool TextServerAdvanced::_save_support_data(const String &p_filename) const {
461 _THREAD_SAFE_METHOD_
462#ifdef ICU_STATIC_DATA
463
464 // Store data to the res file if it's available.
465
466 Ref<FileAccess> f = FileAccess::open(p_filename, FileAccess::WRITE);
467 if (f.is_null()) {
468 return false;
469 }
470
471 PackedByteArray icu_data;
472 icu_data.resize(U_ICUDATA_SIZE);
473 memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);
474 f->store_buffer(icu_data);
475
476 return true;
477#else
478 return false;
479#endif
480}
481
482bool TextServerAdvanced::_is_locale_right_to_left(const String &p_locale) const {
483 String l = p_locale.get_slicec('_', 0);
484 if ((l == "ar") || (l == "dv") || (l == "he") || (l == "fa") || (l == "ff") || (l == "ku") || (l == "ur")) {
485 return true;
486 } else {
487 return false;
488 }
489}
490
491_FORCE_INLINE_ void TextServerAdvanced::_insert_feature(const StringName &p_name, int32_t p_tag, Variant::Type p_vtype, bool p_hidden) {
492 FeatureInfo fi;
493 fi.name = p_name;
494 fi.vtype = p_vtype;
495 fi.hidden = p_hidden;
496
497 feature_sets.insert(p_name, p_tag);
498 feature_sets_inv.insert(p_tag, fi);
499}
500
501void TextServerAdvanced::_insert_feature_sets() {
502 // Registered OpenType feature tags.
503 // Name, Tag, Data Type, Hidden
504 _insert_feature("access_all_alternates", HB_TAG('a', 'a', 'l', 't'), Variant::Type::INT, false);
505 _insert_feature("above_base_forms", HB_TAG('a', 'b', 'v', 'f'), Variant::Type::INT, true);
506 _insert_feature("above_base_mark_positioning", HB_TAG('a', 'b', 'v', 'm'), Variant::Type::INT, true);
507 _insert_feature("above_base_substitutions", HB_TAG('a', 'b', 'v', 's'), Variant::Type::INT, true);
508 _insert_feature("alternative_fractions", HB_TAG('a', 'f', 'r', 'c'), Variant::Type::INT, false);
509 _insert_feature("akhands", HB_TAG('a', 'k', 'h', 'n'), Variant::Type::INT, true);
510 _insert_feature("below_base_forms", HB_TAG('b', 'l', 'w', 'f'), Variant::Type::INT, true);
511 _insert_feature("below_base_mark_positioning", HB_TAG('b', 'l', 'w', 'm'), Variant::Type::INT, true);
512 _insert_feature("below_base_substitutions", HB_TAG('b', 'l', 'w', 's'), Variant::Type::INT, true);
513 _insert_feature("contextual_alternates", HB_TAG('c', 'a', 'l', 't'), Variant::Type::BOOL, false);
514 _insert_feature("case_sensitive_forms", HB_TAG('c', 'a', 's', 'e'), Variant::Type::BOOL, false);
515 _insert_feature("glyph_composition", HB_TAG('c', 'c', 'm', 'p'), Variant::Type::INT, true);
516 _insert_feature("conjunct_form_after_ro", HB_TAG('c', 'f', 'a', 'r'), Variant::Type::INT, true);
517 _insert_feature("contextual_half_width_spacing", HB_TAG('c', 'h', 'w', 's'), Variant::Type::INT, true);
518 _insert_feature("conjunct_forms", HB_TAG('c', 'j', 'c', 't'), Variant::Type::INT, true);
519 _insert_feature("contextual_ligatures", HB_TAG('c', 'l', 'i', 'g'), Variant::Type::BOOL, false);
520 _insert_feature("centered_cjk_punctuation", HB_TAG('c', 'p', 'c', 't'), Variant::Type::BOOL, false);
521 _insert_feature("capital_spacing", HB_TAG('c', 'p', 's', 'p'), Variant::Type::BOOL, false);
522 _insert_feature("contextual_swash", HB_TAG('c', 's', 'w', 'h'), Variant::Type::INT, false);
523 _insert_feature("cursive_positioning", HB_TAG('c', 'u', 'r', 's'), Variant::Type::INT, true);
524 _insert_feature("character_variant_01", HB_TAG('c', 'v', '0', '1'), Variant::Type::BOOL, false);
525 _insert_feature("character_variant_02", HB_TAG('c', 'v', '0', '2'), Variant::Type::BOOL, false);
526 _insert_feature("character_variant_03", HB_TAG('c', 'v', '0', '3'), Variant::Type::BOOL, false);
527 _insert_feature("character_variant_04", HB_TAG('c', 'v', '0', '4'), Variant::Type::BOOL, false);
528 _insert_feature("character_variant_05", HB_TAG('c', 'v', '0', '5'), Variant::Type::BOOL, false);
529 _insert_feature("character_variant_06", HB_TAG('c', 'v', '0', '6'), Variant::Type::BOOL, false);
530 _insert_feature("character_variant_07", HB_TAG('c', 'v', '0', '7'), Variant::Type::BOOL, false);
531 _insert_feature("character_variant_08", HB_TAG('c', 'v', '0', '8'), Variant::Type::BOOL, false);
532 _insert_feature("character_variant_09", HB_TAG('c', 'v', '0', '9'), Variant::Type::BOOL, false);
533 _insert_feature("character_variant_10", HB_TAG('c', 'v', '1', '0'), Variant::Type::BOOL, false);
534 _insert_feature("character_variant_11", HB_TAG('c', 'v', '1', '1'), Variant::Type::BOOL, false);
535 _insert_feature("character_variant_12", HB_TAG('c', 'v', '1', '2'), Variant::Type::BOOL, false);
536 _insert_feature("character_variant_13", HB_TAG('c', 'v', '1', '3'), Variant::Type::BOOL, false);
537 _insert_feature("character_variant_14", HB_TAG('c', 'v', '1', '4'), Variant::Type::BOOL, false);
538 _insert_feature("character_variant_15", HB_TAG('c', 'v', '1', '5'), Variant::Type::BOOL, false);
539 _insert_feature("character_variant_16", HB_TAG('c', 'v', '1', '6'), Variant::Type::BOOL, false);
540 _insert_feature("character_variant_17", HB_TAG('c', 'v', '1', '7'), Variant::Type::BOOL, false);
541 _insert_feature("character_variant_18", HB_TAG('c', 'v', '1', '8'), Variant::Type::BOOL, false);
542 _insert_feature("character_variant_19", HB_TAG('c', 'v', '1', '9'), Variant::Type::BOOL, false);
543 _insert_feature("character_variant_20", HB_TAG('c', 'v', '2', '0'), Variant::Type::BOOL, false);
544 _insert_feature("character_variant_21", HB_TAG('c', 'v', '2', '1'), Variant::Type::BOOL, false);
545 _insert_feature("character_variant_22", HB_TAG('c', 'v', '2', '2'), Variant::Type::BOOL, false);
546 _insert_feature("character_variant_23", HB_TAG('c', 'v', '2', '3'), Variant::Type::BOOL, false);
547 _insert_feature("character_variant_24", HB_TAG('c', 'v', '2', '4'), Variant::Type::BOOL, false);
548 _insert_feature("character_variant_25", HB_TAG('c', 'v', '2', '5'), Variant::Type::BOOL, false);
549 _insert_feature("character_variant_26", HB_TAG('c', 'v', '2', '6'), Variant::Type::BOOL, false);
550 _insert_feature("character_variant_27", HB_TAG('c', 'v', '2', '7'), Variant::Type::BOOL, false);
551 _insert_feature("character_variant_28", HB_TAG('c', 'v', '2', '8'), Variant::Type::BOOL, false);
552 _insert_feature("character_variant_29", HB_TAG('c', 'v', '2', '9'), Variant::Type::BOOL, false);
553 _insert_feature("character_variant_30", HB_TAG('c', 'v', '3', '0'), Variant::Type::BOOL, false);
554 _insert_feature("character_variant_31", HB_TAG('c', 'v', '3', '1'), Variant::Type::BOOL, false);
555 _insert_feature("character_variant_32", HB_TAG('c', 'v', '3', '2'), Variant::Type::BOOL, false);
556 _insert_feature("character_variant_33", HB_TAG('c', 'v', '3', '3'), Variant::Type::BOOL, false);
557 _insert_feature("character_variant_34", HB_TAG('c', 'v', '3', '4'), Variant::Type::BOOL, false);
558 _insert_feature("character_variant_35", HB_TAG('c', 'v', '3', '5'), Variant::Type::BOOL, false);
559 _insert_feature("character_variant_36", HB_TAG('c', 'v', '3', '6'), Variant::Type::BOOL, false);
560 _insert_feature("character_variant_37", HB_TAG('c', 'v', '3', '7'), Variant::Type::BOOL, false);
561 _insert_feature("character_variant_38", HB_TAG('c', 'v', '3', '8'), Variant::Type::BOOL, false);
562 _insert_feature("character_variant_39", HB_TAG('c', 'v', '3', '9'), Variant::Type::BOOL, false);
563 _insert_feature("character_variant_40", HB_TAG('c', 'v', '4', '0'), Variant::Type::BOOL, false);
564 _insert_feature("character_variant_41", HB_TAG('c', 'v', '4', '1'), Variant::Type::BOOL, false);
565 _insert_feature("character_variant_42", HB_TAG('c', 'v', '4', '2'), Variant::Type::BOOL, false);
566 _insert_feature("character_variant_43", HB_TAG('c', 'v', '4', '3'), Variant::Type::BOOL, false);
567 _insert_feature("character_variant_44", HB_TAG('c', 'v', '4', '4'), Variant::Type::BOOL, false);
568 _insert_feature("character_variant_45", HB_TAG('c', 'v', '4', '5'), Variant::Type::BOOL, false);
569 _insert_feature("character_variant_46", HB_TAG('c', 'v', '4', '6'), Variant::Type::BOOL, false);
570 _insert_feature("character_variant_47", HB_TAG('c', 'v', '4', '7'), Variant::Type::BOOL, false);
571 _insert_feature("character_variant_48", HB_TAG('c', 'v', '4', '8'), Variant::Type::BOOL, false);
572 _insert_feature("character_variant_49", HB_TAG('c', 'v', '4', '9'), Variant::Type::BOOL, false);
573 _insert_feature("character_variant_50", HB_TAG('c', 'v', '5', '0'), Variant::Type::BOOL, false);
574 _insert_feature("character_variant_51", HB_TAG('c', 'v', '5', '1'), Variant::Type::BOOL, false);
575 _insert_feature("character_variant_52", HB_TAG('c', 'v', '5', '2'), Variant::Type::BOOL, false);
576 _insert_feature("character_variant_53", HB_TAG('c', 'v', '5', '3'), Variant::Type::BOOL, false);
577 _insert_feature("character_variant_54", HB_TAG('c', 'v', '5', '4'), Variant::Type::BOOL, false);
578 _insert_feature("character_variant_55", HB_TAG('c', 'v', '5', '5'), Variant::Type::BOOL, false);
579 _insert_feature("character_variant_56", HB_TAG('c', 'v', '5', '6'), Variant::Type::BOOL, false);
580 _insert_feature("character_variant_57", HB_TAG('c', 'v', '5', '7'), Variant::Type::BOOL, false);
581 _insert_feature("character_variant_58", HB_TAG('c', 'v', '5', '8'), Variant::Type::BOOL, false);
582 _insert_feature("character_variant_59", HB_TAG('c', 'v', '5', '9'), Variant::Type::BOOL, false);
583 _insert_feature("character_variant_60", HB_TAG('c', 'v', '6', '0'), Variant::Type::BOOL, false);
584 _insert_feature("character_variant_61", HB_TAG('c', 'v', '6', '1'), Variant::Type::BOOL, false);
585 _insert_feature("character_variant_62", HB_TAG('c', 'v', '6', '2'), Variant::Type::BOOL, false);
586 _insert_feature("character_variant_63", HB_TAG('c', 'v', '6', '3'), Variant::Type::BOOL, false);
587 _insert_feature("character_variant_64", HB_TAG('c', 'v', '6', '4'), Variant::Type::BOOL, false);
588 _insert_feature("character_variant_65", HB_TAG('c', 'v', '6', '5'), Variant::Type::BOOL, false);
589 _insert_feature("character_variant_66", HB_TAG('c', 'v', '6', '6'), Variant::Type::BOOL, false);
590 _insert_feature("character_variant_67", HB_TAG('c', 'v', '6', '7'), Variant::Type::BOOL, false);
591 _insert_feature("character_variant_68", HB_TAG('c', 'v', '6', '8'), Variant::Type::BOOL, false);
592 _insert_feature("character_variant_69", HB_TAG('c', 'v', '6', '9'), Variant::Type::BOOL, false);
593 _insert_feature("character_variant_70", HB_TAG('c', 'v', '7', '0'), Variant::Type::BOOL, false);
594 _insert_feature("character_variant_71", HB_TAG('c', 'v', '7', '1'), Variant::Type::BOOL, false);
595 _insert_feature("character_variant_72", HB_TAG('c', 'v', '7', '2'), Variant::Type::BOOL, false);
596 _insert_feature("character_variant_73", HB_TAG('c', 'v', '7', '3'), Variant::Type::BOOL, false);
597 _insert_feature("character_variant_74", HB_TAG('c', 'v', '7', '4'), Variant::Type::BOOL, false);
598 _insert_feature("character_variant_75", HB_TAG('c', 'v', '7', '5'), Variant::Type::BOOL, false);
599 _insert_feature("character_variant_76", HB_TAG('c', 'v', '7', '6'), Variant::Type::BOOL, false);
600 _insert_feature("character_variant_77", HB_TAG('c', 'v', '7', '7'), Variant::Type::BOOL, false);
601 _insert_feature("character_variant_78", HB_TAG('c', 'v', '7', '8'), Variant::Type::BOOL, false);
602 _insert_feature("character_variant_79", HB_TAG('c', 'v', '7', '9'), Variant::Type::BOOL, false);
603 _insert_feature("character_variant_80", HB_TAG('c', 'v', '8', '0'), Variant::Type::BOOL, false);
604 _insert_feature("character_variant_81", HB_TAG('c', 'v', '8', '1'), Variant::Type::BOOL, false);
605 _insert_feature("character_variant_82", HB_TAG('c', 'v', '8', '2'), Variant::Type::BOOL, false);
606 _insert_feature("character_variant_83", HB_TAG('c', 'v', '8', '3'), Variant::Type::BOOL, false);
607 _insert_feature("character_variant_84", HB_TAG('c', 'v', '8', '4'), Variant::Type::BOOL, false);
608 _insert_feature("character_variant_85", HB_TAG('c', 'v', '8', '5'), Variant::Type::BOOL, false);
609 _insert_feature("character_variant_86", HB_TAG('c', 'v', '8', '6'), Variant::Type::BOOL, false);
610 _insert_feature("character_variant_87", HB_TAG('c', 'v', '8', '7'), Variant::Type::BOOL, false);
611 _insert_feature("character_variant_88", HB_TAG('c', 'v', '8', '8'), Variant::Type::BOOL, false);
612 _insert_feature("character_variant_89", HB_TAG('c', 'v', '8', '9'), Variant::Type::BOOL, false);
613 _insert_feature("character_variant_90", HB_TAG('c', 'v', '9', '0'), Variant::Type::BOOL, false);
614 _insert_feature("character_variant_91", HB_TAG('c', 'v', '9', '1'), Variant::Type::BOOL, false);
615 _insert_feature("character_variant_92", HB_TAG('c', 'v', '9', '2'), Variant::Type::BOOL, false);
616 _insert_feature("character_variant_93", HB_TAG('c', 'v', '9', '3'), Variant::Type::BOOL, false);
617 _insert_feature("character_variant_94", HB_TAG('c', 'v', '9', '4'), Variant::Type::BOOL, false);
618 _insert_feature("character_variant_95", HB_TAG('c', 'v', '9', '5'), Variant::Type::BOOL, false);
619 _insert_feature("character_variant_96", HB_TAG('c', 'v', '9', '6'), Variant::Type::BOOL, false);
620 _insert_feature("character_variant_97", HB_TAG('c', 'v', '9', '7'), Variant::Type::BOOL, false);
621 _insert_feature("character_variant_98", HB_TAG('c', 'v', '9', '8'), Variant::Type::BOOL, false);
622 _insert_feature("character_variant_99", HB_TAG('c', 'v', '9', '9'), Variant::Type::BOOL, false);
623 _insert_feature("petite_capitals_from_capitals", HB_TAG('c', '2', 'p', 'c'), Variant::Type::BOOL, false);
624 _insert_feature("small_capitals_from_capitals", HB_TAG('c', '2', 's', 'c'), Variant::Type::BOOL, false);
625 _insert_feature("distances", HB_TAG('d', 'i', 's', 't'), Variant::Type::INT, true);
626 _insert_feature("discretionary_ligatures", HB_TAG('d', 'l', 'i', 'g'), Variant::Type::BOOL, false);
627 _insert_feature("denominators", HB_TAG('d', 'n', 'o', 'm'), Variant::Type::BOOL, false);
628 _insert_feature("dotless_forms", HB_TAG('d', 't', 'l', 's'), Variant::Type::INT, true);
629 _insert_feature("expert_forms", HB_TAG('e', 'x', 'p', 't'), Variant::Type::BOOL, true);
630 _insert_feature("final_glyph_on_line_alternates", HB_TAG('f', 'a', 'l', 't'), Variant::Type::INT, false);
631 _insert_feature("terminal_forms_2", HB_TAG('f', 'i', 'n', '2'), Variant::Type::INT, true);
632 _insert_feature("terminal_forms_3", HB_TAG('f', 'i', 'n', '3'), Variant::Type::INT, true);
633 _insert_feature("terminal_forms", HB_TAG('f', 'i', 'n', 'a'), Variant::Type::INT, true);
634 _insert_feature("flattened_accent_forms", HB_TAG('f', 'l', 'a', 'c'), Variant::Type::INT, true);
635 _insert_feature("fractions", HB_TAG('f', 'r', 'a', 'c'), Variant::Type::BOOL, false);
636 _insert_feature("full_widths", HB_TAG('f', 'w', 'i', 'd'), Variant::Type::BOOL, false);
637 _insert_feature("half_forms", HB_TAG('h', 'a', 'l', 'f'), Variant::Type::INT, true);
638 _insert_feature("halant_forms", HB_TAG('h', 'a', 'l', 'n'), Variant::Type::INT, true);
639 _insert_feature("alternate_half_widths", HB_TAG('h', 'a', 'l', 't'), Variant::Type::BOOL, false);
640 _insert_feature("historical_forms", HB_TAG('h', 'i', 's', 't'), Variant::Type::INT, false);
641 _insert_feature("horizontal_kana_alternates", HB_TAG('h', 'k', 'n', 'a'), Variant::Type::BOOL, false);
642 _insert_feature("historical_ligatures", HB_TAG('h', 'l', 'i', 'g'), Variant::Type::BOOL, false);
643 _insert_feature("hangul", HB_TAG('h', 'n', 'g', 'l'), Variant::Type::INT, false);
644 _insert_feature("hojo_kanji_forms", HB_TAG('h', 'o', 'j', 'o'), Variant::Type::INT, false);
645 _insert_feature("half_widths", HB_TAG('h', 'w', 'i', 'd'), Variant::Type::BOOL, false);
646 _insert_feature("initial_forms", HB_TAG('i', 'n', 'i', 't'), Variant::Type::INT, true);
647 _insert_feature("isolated_forms", HB_TAG('i', 's', 'o', 'l'), Variant::Type::INT, true);
648 _insert_feature("italics", HB_TAG('i', 't', 'a', 'l'), Variant::Type::INT, false);
649 _insert_feature("justification_alternates", HB_TAG('j', 'a', 'l', 't'), Variant::Type::INT, false);
650 _insert_feature("jis78_forms", HB_TAG('j', 'p', '7', '8'), Variant::Type::INT, false);
651 _insert_feature("jis83_forms", HB_TAG('j', 'p', '8', '3'), Variant::Type::INT, false);
652 _insert_feature("jis90_forms", HB_TAG('j', 'p', '9', '0'), Variant::Type::INT, false);
653 _insert_feature("jis2004_forms", HB_TAG('j', 'p', '0', '4'), Variant::Type::INT, false);
654 _insert_feature("kerning", HB_TAG('k', 'e', 'r', 'n'), Variant::Type::BOOL, false);
655 _insert_feature("left_bounds", HB_TAG('l', 'f', 'b', 'd'), Variant::Type::INT, false);
656 _insert_feature("standard_ligatures", HB_TAG('l', 'i', 'g', 'a'), Variant::Type::BOOL, false);
657 _insert_feature("leading_jamo_forms", HB_TAG('l', 'j', 'm', 'o'), Variant::Type::INT, true);
658 _insert_feature("lining_figures", HB_TAG('l', 'n', 'u', 'm'), Variant::Type::INT, false);
659 _insert_feature("localized_forms", HB_TAG('l', 'o', 'c', 'l'), Variant::Type::INT, true);
660 _insert_feature("left_to_right_alternates", HB_TAG('l', 't', 'r', 'a'), Variant::Type::INT, true);
661 _insert_feature("left_to_right_mirrored_forms", HB_TAG('l', 't', 'r', 'm'), Variant::Type::INT, true);
662 _insert_feature("mark_positioning", HB_TAG('m', 'a', 'r', 'k'), Variant::Type::INT, true);
663 _insert_feature("medial_forms_2", HB_TAG('m', 'e', 'd', '2'), Variant::Type::INT, true);
664 _insert_feature("medial_forms", HB_TAG('m', 'e', 'd', 'i'), Variant::Type::INT, true);
665 _insert_feature("mathematical_greek", HB_TAG('m', 'g', 'r', 'k'), Variant::Type::BOOL, false);
666 _insert_feature("mark_to_mark_positioning", HB_TAG('m', 'k', 'm', 'k'), Variant::Type::INT, true);
667 _insert_feature("mark_positioning_via_substitution", HB_TAG('m', 's', 'e', 't'), Variant::Type::INT, true);
668 _insert_feature("alternate_annotation_forms", HB_TAG('n', 'a', 'l', 't'), Variant::Type::INT, false);
669 _insert_feature("nlc_kanji_forms", HB_TAG('n', 'l', 'c', 'k'), Variant::Type::INT, false);
670 _insert_feature("nukta_forms", HB_TAG('n', 'u', 'k', 't'), Variant::Type::INT, true);
671 _insert_feature("numerators", HB_TAG('n', 'u', 'm', 'r'), Variant::Type::BOOL, false);
672 _insert_feature("oldstyle_figures", HB_TAG('o', 'n', 'u', 'm'), Variant::Type::INT, false);
673 _insert_feature("optical_bounds", HB_TAG('o', 'p', 'b', 'd'), Variant::Type::INT, true);
674 _insert_feature("ordinals", HB_TAG('o', 'r', 'd', 'n'), Variant::Type::BOOL, false);
675 _insert_feature("ornaments", HB_TAG('o', 'r', 'n', 'm'), Variant::Type::INT, false);
676 _insert_feature("proportional_alternate_widths", HB_TAG('p', 'a', 'l', 't'), Variant::Type::BOOL, false);
677 _insert_feature("petite_capitals", HB_TAG('p', 'c', 'a', 'p'), Variant::Type::BOOL, false);
678 _insert_feature("proportional_kana", HB_TAG('p', 'k', 'n', 'a'), Variant::Type::BOOL, false);
679 _insert_feature("proportional_figures", HB_TAG('p', 'n', 'u', 'm'), Variant::Type::BOOL, false);
680 _insert_feature("pre_base_forms", HB_TAG('p', 'r', 'e', 'f'), Variant::Type::INT, true);
681 _insert_feature("pre_base_substitutions", HB_TAG('p', 'r', 'e', 's'), Variant::Type::INT, true);
682 _insert_feature("post_base_forms", HB_TAG('p', 's', 't', 'f'), Variant::Type::INT, true);
683 _insert_feature("post_base_substitutions", HB_TAG('p', 's', 't', 's'), Variant::Type::INT, true);
684 _insert_feature("proportional_widths", HB_TAG('p', 'w', 'i', 'd'), Variant::Type::BOOL, false);
685 _insert_feature("quarter_widths", HB_TAG('q', 'w', 'i', 'd'), Variant::Type::BOOL, false);
686 _insert_feature("randomize", HB_TAG('r', 'a', 'n', 'd'), Variant::Type::INT, false);
687 _insert_feature("required_contextual_alternates", HB_TAG('r', 'c', 'l', 't'), Variant::Type::BOOL, true);
688 _insert_feature("rakar_forms", HB_TAG('r', 'k', 'r', 'f'), Variant::Type::INT, true);
689 _insert_feature("required_ligatures", HB_TAG('r', 'l', 'i', 'g'), Variant::Type::BOOL, true);
690 _insert_feature("reph_forms", HB_TAG('r', 'p', 'h', 'f'), Variant::Type::INT, true);
691 _insert_feature("right_bounds", HB_TAG('r', 't', 'b', 'd'), Variant::Type::INT, false);
692 _insert_feature("right_to_left_alternates", HB_TAG('r', 't', 'l', 'a'), Variant::Type::INT, true);
693 _insert_feature("right_to_left_mirrored_forms", HB_TAG('r', 't', 'l', 'm'), Variant::Type::INT, true);
694 _insert_feature("ruby_notation_forms", HB_TAG('r', 'u', 'b', 'y'), Variant::Type::INT, false);
695 _insert_feature("required_variation_alternates", HB_TAG('r', 'v', 'r', 'n'), Variant::Type::INT, true);
696 _insert_feature("stylistic_alternates", HB_TAG('s', 'a', 'l', 't'), Variant::Type::INT, false);
697 _insert_feature("scientific_inferiors", HB_TAG('s', 'i', 'n', 'f'), Variant::Type::BOOL, false);
698 _insert_feature("optical_size", HB_TAG('s', 'i', 'z', 'e'), Variant::Type::INT, false);
699 _insert_feature("small_capitals", HB_TAG('s', 'm', 'c', 'p'), Variant::Type::BOOL, false);
700 _insert_feature("simplified_forms", HB_TAG('s', 'm', 'p', 'l'), Variant::Type::INT, false);
701 _insert_feature("stylistic_set_01", HB_TAG('s', 's', '0', '1'), Variant::Type::BOOL, false);
702 _insert_feature("stylistic_set_02", HB_TAG('s', 's', '0', '2'), Variant::Type::BOOL, false);
703 _insert_feature("stylistic_set_03", HB_TAG('s', 's', '0', '3'), Variant::Type::BOOL, false);
704 _insert_feature("stylistic_set_04", HB_TAG('s', 's', '0', '4'), Variant::Type::BOOL, false);
705 _insert_feature("stylistic_set_05", HB_TAG('s', 's', '0', '5'), Variant::Type::BOOL, false);
706 _insert_feature("stylistic_set_06", HB_TAG('s', 's', '0', '6'), Variant::Type::BOOL, false);
707 _insert_feature("stylistic_set_07", HB_TAG('s', 's', '0', '7'), Variant::Type::BOOL, false);
708 _insert_feature("stylistic_set_08", HB_TAG('s', 's', '0', '8'), Variant::Type::BOOL, false);
709 _insert_feature("stylistic_set_09", HB_TAG('s', 's', '0', '9'), Variant::Type::BOOL, false);
710 _insert_feature("stylistic_set_10", HB_TAG('s', 's', '1', '0'), Variant::Type::BOOL, false);
711 _insert_feature("stylistic_set_11", HB_TAG('s', 's', '1', '1'), Variant::Type::BOOL, false);
712 _insert_feature("stylistic_set_12", HB_TAG('s', 's', '1', '2'), Variant::Type::BOOL, false);
713 _insert_feature("stylistic_set_13", HB_TAG('s', 's', '1', '3'), Variant::Type::BOOL, false);
714 _insert_feature("stylistic_set_14", HB_TAG('s', 's', '1', '4'), Variant::Type::BOOL, false);
715 _insert_feature("stylistic_set_15", HB_TAG('s', 's', '1', '5'), Variant::Type::BOOL, false);
716 _insert_feature("stylistic_set_16", HB_TAG('s', 's', '1', '6'), Variant::Type::BOOL, false);
717 _insert_feature("stylistic_set_17", HB_TAG('s', 's', '1', '7'), Variant::Type::BOOL, false);
718 _insert_feature("stylistic_set_18", HB_TAG('s', 's', '1', '8'), Variant::Type::BOOL, false);
719 _insert_feature("stylistic_set_19", HB_TAG('s', 's', '1', '9'), Variant::Type::BOOL, false);
720 _insert_feature("stylistic_set_20", HB_TAG('s', 's', '2', '0'), Variant::Type::BOOL, false);
721 _insert_feature("math_script_style_alternates", HB_TAG('s', 's', 't', 'y'), Variant::Type::INT, true);
722 _insert_feature("stretching_glyph_decomposition", HB_TAG('s', 't', 'c', 'h'), Variant::Type::INT, true);
723 _insert_feature("subscript", HB_TAG('s', 'u', 'b', 's'), Variant::Type::BOOL, false);
724 _insert_feature("superscript", HB_TAG('s', 'u', 'p', 's'), Variant::Type::BOOL, false);
725 _insert_feature("swash", HB_TAG('s', 'w', 's', 'h'), Variant::Type::INT, false);
726 _insert_feature("titling", HB_TAG('t', 'i', 't', 'l'), Variant::Type::BOOL, false);
727 _insert_feature("trailing_jamo_forms", HB_TAG('t', 'j', 'm', 'o'), Variant::Type::INT, true);
728 _insert_feature("traditional_name_forms", HB_TAG('t', 'n', 'a', 'm'), Variant::Type::INT, false);
729 _insert_feature("tabular_figures", HB_TAG('t', 'n', 'u', 'm'), Variant::Type::BOOL, false);
730 _insert_feature("traditional_forms", HB_TAG('t', 'r', 'a', 'd'), Variant::Type::INT, false);
731 _insert_feature("third_widths", HB_TAG('t', 'w', 'i', 'd'), Variant::Type::BOOL, false);
732 _insert_feature("unicase", HB_TAG('u', 'n', 'i', 'c'), Variant::Type::BOOL, false);
733 _insert_feature("alternate_vertical_metrics", HB_TAG('v', 'a', 'l', 't'), Variant::Type::INT, false);
734 _insert_feature("vattu_variants", HB_TAG('v', 'a', 't', 'u'), Variant::Type::INT, true);
735 _insert_feature("vertical_contextual_half_width_spacing", HB_TAG('v', 'c', 'h', 'w'), Variant::Type::BOOL, false);
736 _insert_feature("vertical_alternates", HB_TAG('v', 'e', 'r', 't'), Variant::Type::INT, false);
737 _insert_feature("alternate_vertical_half_metrics", HB_TAG('v', 'h', 'a', 'l'), Variant::Type::BOOL, false);
738 _insert_feature("vowel_jamo_forms", HB_TAG('v', 'j', 'm', 'o'), Variant::Type::INT, true);
739 _insert_feature("vertical_kana_alternates", HB_TAG('v', 'k', 'n', 'a'), Variant::Type::INT, false);
740 _insert_feature("vertical_kerning", HB_TAG('v', 'k', 'r', 'n'), Variant::Type::BOOL, false);
741 _insert_feature("proportional_alternate_vertical_metrics", HB_TAG('v', 'p', 'a', 'l'), Variant::Type::BOOL, false);
742 _insert_feature("vertical_alternates_and_rotation", HB_TAG('v', 'r', 't', '2'), Variant::Type::INT, false);
743 _insert_feature("vertical_alternates_for_rotation", HB_TAG('v', 'r', 't', 'r'), Variant::Type::INT, false);
744 _insert_feature("slashed_zero", HB_TAG('z', 'e', 'r', 'o'), Variant::Type::BOOL, false);
745
746 // Registered OpenType variation tag.
747 _insert_feature("italic", HB_TAG('i', 't', 'a', 'l'), Variant::Type::INT, false);
748 _insert_feature("optical_size", HB_TAG('o', 'p', 's', 'z'), Variant::Type::INT, false);
749 _insert_feature("slant", HB_TAG('s', 'l', 'n', 't'), Variant::Type::INT, false);
750 _insert_feature("width", HB_TAG('w', 'd', 't', 'h'), Variant::Type::INT, false);
751 _insert_feature("weight", HB_TAG('w', 'g', 'h', 't'), Variant::Type::INT, false);
752}
753
754int64_t TextServerAdvanced::_name_to_tag(const String &p_name) const {
755 if (feature_sets.has(p_name)) {
756 return feature_sets[p_name];
757 }
758
759 // No readable name, use tag string.
760 return hb_tag_from_string(p_name.replace("custom_", "").ascii().get_data(), -1);
761}
762
763Variant::Type TextServerAdvanced::_get_tag_type(int64_t p_tag) const {
764 if (feature_sets_inv.has(p_tag)) {
765 return feature_sets_inv[p_tag].vtype;
766 }
767 return Variant::Type::INT;
768}
769
770bool TextServerAdvanced::_get_tag_hidden(int64_t p_tag) const {
771 if (feature_sets_inv.has(p_tag)) {
772 return feature_sets_inv[p_tag].hidden;
773 }
774 return false;
775}
776
777String TextServerAdvanced::_tag_to_name(int64_t p_tag) const {
778 if (feature_sets_inv.has(p_tag)) {
779 return feature_sets_inv[p_tag].name;
780 }
781
782 // No readable name, use tag string.
783 char name[5];
784 memset(name, 0, 5);
785 hb_tag_to_string(p_tag, name);
786 return String("custom_") + String(name);
787}
788
789/*************************************************************************/
790/* Font Glyph Rendering */
791/*************************************************************************/
792
793_FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_texture_pos_for_glyph(FontForSizeAdvanced *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height, bool p_msdf) const {
794 FontTexturePosition ret;
795
796 int mw = p_width;
797 int mh = p_height;
798
799 ShelfPackTexture *ct = p_data->textures.ptrw();
800 for (int32_t i = 0; i < p_data->textures.size(); i++) {
801 if (p_image_format != ct[i].format) {
802 continue;
803 }
804 if (mw > ct[i].texture_w || mh > ct[i].texture_h) { // Too big for this texture.
805 continue;
806 }
807
808 ret = ct[i].pack_rect(i, mh, mw);
809 if (ret.index != -1) {
810 break;
811 }
812 }
813
814 if (ret.index == -1) {
815 // Could not find texture to fit, create one.
816 int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
817
818 texsize = next_power_of_2(texsize);
819 if (p_msdf) {
820 texsize = MIN(texsize, 2048);
821 } else {
822 texsize = MIN(texsize, 1024);
823 }
824 if (mw > texsize) { // Special case, adapt to it?
825 texsize = next_power_of_2(mw);
826 }
827 if (mh > texsize) { // Special case, adapt to it?
828 texsize = next_power_of_2(mh);
829 }
830
831 ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);
832 tex.format = p_image_format;
833 tex.imgdata.resize(texsize * texsize * p_color_size);
834 {
835 // Zero texture.
836 uint8_t *w = tex.imgdata.ptrw();
837 ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.imgdata.size(), ret);
838 // Initialize the texture to all-white pixels to prevent artifacts when the
839 // font is displayed at a non-default scale with filtering enabled.
840 if (p_color_size == 2) {
841 for (int i = 0; i < texsize * texsize * p_color_size; i += 2) { // FORMAT_LA8, BW font.
842 w[i + 0] = 255;
843 w[i + 1] = 0;
844 }
845 } else if (p_color_size == 4) {
846 for (int i = 0; i < texsize * texsize * p_color_size; i += 4) { // FORMAT_RGBA8, Color font, Multichannel(+True) SDF.
847 w[i + 0] = 255;
848 w[i + 1] = 255;
849 w[i + 2] = 255;
850 w[i + 3] = 0;
851 }
852 } else {
853 ERR_FAIL_V(ret);
854 }
855 }
856 p_data->textures.push_back(tex);
857
858 int32_t idx = p_data->textures.size() - 1;
859 ret = p_data->textures.write[idx].pack_rect(idx, mh, mw);
860 }
861
862 return ret;
863}
864
865#ifdef MODULE_MSDFGEN_ENABLED
866
867struct MSContext {
868 msdfgen::Point2 position;
869 msdfgen::Shape *shape = nullptr;
870 msdfgen::Contour *contour = nullptr;
871};
872
873class DistancePixelConversion {
874 double invRange;
875
876public:
877 _FORCE_INLINE_ explicit DistancePixelConversion(double range) :
878 invRange(1 / range) {}
879 _FORCE_INLINE_ void operator()(float *pixels, const msdfgen::MultiAndTrueDistance &distance) const {
880 pixels[0] = float(invRange * distance.r + .5);
881 pixels[1] = float(invRange * distance.g + .5);
882 pixels[2] = float(invRange * distance.b + .5);
883 pixels[3] = float(invRange * distance.a + .5);
884 }
885};
886
887struct MSDFThreadData {
888 msdfgen::Bitmap<float, 4> *output;
889 msdfgen::Shape *shape;
890 msdfgen::Projection *projection;
891 DistancePixelConversion *distancePixelConversion;
892};
893
894static msdfgen::Point2 ft_point2(const FT_Vector &vector) {
895 return msdfgen::Point2(vector.x / 60.0f, vector.y / 60.0f);
896}
897
898static int ft_move_to(const FT_Vector *to, void *user) {
899 MSContext *context = static_cast<MSContext *>(user);
900 if (!(context->contour && context->contour->edges.empty())) {
901 context->contour = &context->shape->addContour();
902 }
903 context->position = ft_point2(*to);
904 return 0;
905}
906
907static int ft_line_to(const FT_Vector *to, void *user) {
908 MSContext *context = static_cast<MSContext *>(user);
909 msdfgen::Point2 endpoint = ft_point2(*to);
910 if (endpoint != context->position) {
911 context->contour->addEdge(new msdfgen::LinearSegment(context->position, endpoint));
912 context->position = endpoint;
913 }
914 return 0;
915}
916
917static int ft_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) {
918 MSContext *context = static_cast<MSContext *>(user);
919 context->contour->addEdge(new msdfgen::QuadraticSegment(context->position, ft_point2(*control), ft_point2(*to)));
920 context->position = ft_point2(*to);
921 return 0;
922}
923
924static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) {
925 MSContext *context = static_cast<MSContext *>(user);
926 context->contour->addEdge(new msdfgen::CubicSegment(context->position, ft_point2(*control1), ft_point2(*control2), ft_point2(*to)));
927 context->position = ft_point2(*to);
928 return 0;
929}
930
931void TextServerAdvanced::_generateMTSDF_threaded(void *p_td, uint32_t p_y) {
932 MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td);
933
934 msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape);
935 int row = td->shape->inverseYAxis ? td->output->height() - p_y - 1 : p_y;
936 for (int col = 0; col < td->output->width(); ++col) {
937 int x = (p_y % 2) ? td->output->width() - col - 1 : col;
938 msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, p_y + .5));
939 msdfgen::MultiAndTrueDistance distance = distanceFinder.distance(p);
940 td->distancePixelConversion->operator()(td->output->operator()(x, row), distance);
941 }
942}
943
944_FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(FontAdvanced *p_font_data, FontForSizeAdvanced *p_data, int p_pixel_range, int p_rect_margin, FT_Outline *outline, const Vector2 &advance) const {
945 msdfgen::Shape shape;
946
947 shape.contours.clear();
948 shape.inverseYAxis = false;
949
950 MSContext context = {};
951 context.shape = &shape;
952 FT_Outline_Funcs ft_functions;
953 ft_functions.move_to = &ft_move_to;
954 ft_functions.line_to = &ft_line_to;
955 ft_functions.conic_to = &ft_conic_to;
956 ft_functions.cubic_to = &ft_cubic_to;
957 ft_functions.shift = 0;
958 ft_functions.delta = 0;
959
960 int error = FT_Outline_Decompose(outline, &ft_functions, &context);
961 ERR_FAIL_COND_V_MSG(error, FontGlyph(), "FreeType: Outline decomposition error: '" + String(FT_Error_String(error)) + "'.");
962 if (!shape.contours.empty() && shape.contours.back().edges.empty()) {
963 shape.contours.pop_back();
964 }
965
966 if (FT_Outline_Get_Orientation(outline) == 1) {
967 for (int i = 0; i < (int)shape.contours.size(); ++i) {
968 shape.contours[i].reverse();
969 }
970 }
971
972 shape.inverseYAxis = true;
973 shape.normalize();
974
975 msdfgen::Shape::Bounds bounds = shape.getBounds(p_pixel_range);
976
977 FontGlyph chr;
978 chr.found = true;
979 chr.advance = advance;
980
981 if (shape.validate() && shape.contours.size() > 0) {
982 int w = (bounds.r - bounds.l);
983 int h = (bounds.t - bounds.b);
984
985 int mw = w + p_rect_margin * 4;
986 int mh = h + p_rect_margin * 4;
987
988 ERR_FAIL_COND_V(mw > 4096, FontGlyph());
989 ERR_FAIL_COND_V(mh > 4096, FontGlyph());
990
991 FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true);
992 ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
993 ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];
994
995 edgeColoringSimple(shape, 3.0); // Max. angle.
996 msdfgen::Bitmap<float, 4> image(w, h); // Texture size.
997
998 DistancePixelConversion distancePixelConversion(p_pixel_range);
999 msdfgen::Projection projection(msdfgen::Vector2(1.0, 1.0), msdfgen::Vector2(-bounds.l, -bounds.b));
1000 msdfgen::MSDFGeneratorConfig config(true, msdfgen::ErrorCorrectionConfig());
1001
1002 MSDFThreadData td;
1003 td.output = &image;
1004 td.shape = &shape;
1005 td.projection = &projection;
1006 td.distancePixelConversion = &distancePixelConversion;
1007
1008 WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_native_group_task(&TextServerAdvanced::_generateMTSDF_threaded, &td, h, -1, true, String("FontServerRasterizeMSDF"));
1009 WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
1010
1011 msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config);
1012
1013 {
1014 uint8_t *wr = tex.imgdata.ptrw();
1015
1016 for (int i = 0; i < h; i++) {
1017 for (int j = 0; j < w; j++) {
1018 int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * 4;
1019 ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph());
1020 wr[ofs + 0] = (uint8_t)(CLAMP(image(j, i)[0] * 256.f, 0.f, 255.f));
1021 wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f));
1022 wr[ofs + 2] = (uint8_t)(CLAMP(image(j, i)[2] * 256.f, 0.f, 255.f));
1023 wr[ofs + 3] = (uint8_t)(CLAMP(image(j, i)[3] * 256.f, 0.f, 255.f));
1024 }
1025 }
1026 }
1027
1028 tex.dirty = true;
1029
1030 chr.texture_idx = tex_pos.index;
1031
1032 chr.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);
1033 chr.rect.position = Vector2(bounds.l - p_rect_margin, -bounds.t - p_rect_margin);
1034
1035 chr.rect.size = chr.uv_rect.size;
1036 }
1037 return chr;
1038}
1039#endif
1040
1041#ifdef MODULE_FREETYPE_ENABLED
1042_FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitmap(FontForSizeAdvanced *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance, bool p_bgra) const {
1043 int w = bitmap.width;
1044 int h = bitmap.rows;
1045 int color_size = 2;
1046
1047 switch (bitmap.pixel_mode) {
1048 case FT_PIXEL_MODE_MONO:
1049 case FT_PIXEL_MODE_GRAY: {
1050 color_size = 2;
1051 } break;
1052 case FT_PIXEL_MODE_BGRA: {
1053 color_size = 4;
1054 } break;
1055 case FT_PIXEL_MODE_LCD: {
1056 color_size = 4;
1057 w /= 3;
1058 } break;
1059 case FT_PIXEL_MODE_LCD_V: {
1060 color_size = 4;
1061 h /= 3;
1062 } break;
1063 }
1064
1065 int mw = w + p_rect_margin * 4;
1066 int mh = h + p_rect_margin * 4;
1067
1068 ERR_FAIL_COND_V(mw > 4096, FontGlyph());
1069 ERR_FAIL_COND_V(mh > 4096, FontGlyph());
1070
1071 Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;
1072
1073 FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh, false);
1074 ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
1075
1076 // Fit character in char texture.
1077 ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];
1078
1079 {
1080 uint8_t *wr = tex.imgdata.ptrw();
1081
1082 for (int i = 0; i < h; i++) {
1083 for (int j = 0; j < w; j++) {
1084 int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * color_size;
1085 ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph());
1086 switch (bitmap.pixel_mode) {
1087 case FT_PIXEL_MODE_MONO: {
1088 int byte = i * bitmap.pitch + (j >> 3);
1089 int bit = 1 << (7 - (j % 8));
1090 wr[ofs + 0] = 255; // grayscale as 1
1091 wr[ofs + 1] = (bitmap.buffer[byte] & bit) ? 255 : 0;
1092 } break;
1093 case FT_PIXEL_MODE_GRAY:
1094 wr[ofs + 0] = 255; // grayscale as 1
1095 wr[ofs + 1] = bitmap.buffer[i * bitmap.pitch + j];
1096 break;
1097 case FT_PIXEL_MODE_BGRA: {
1098 int ofs_color = i * bitmap.pitch + (j << 2);
1099 wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
1100 wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
1101 wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
1102 wr[ofs + 3] = bitmap.buffer[ofs_color + 3];
1103 } break;
1104 case FT_PIXEL_MODE_LCD: {
1105 int ofs_color = i * bitmap.pitch + (j * 3);
1106 if (p_bgra) {
1107 wr[ofs + 0] = bitmap.buffer[ofs_color + 0];
1108 wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
1109 wr[ofs + 2] = bitmap.buffer[ofs_color + 2];
1110 wr[ofs + 3] = 255;
1111 } else {
1112 wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
1113 wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
1114 wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
1115 wr[ofs + 3] = 255;
1116 }
1117 } break;
1118 case FT_PIXEL_MODE_LCD_V: {
1119 int ofs_color = i * bitmap.pitch * 3 + j;
1120 if (p_bgra) {
1121 wr[ofs + 0] = bitmap.buffer[ofs_color + bitmap.pitch * 2];
1122 wr[ofs + 1] = bitmap.buffer[ofs_color + bitmap.pitch];
1123 wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
1124 wr[ofs + 3] = 255;
1125 } else {
1126 wr[ofs + 0] = bitmap.buffer[ofs_color + 0];
1127 wr[ofs + 1] = bitmap.buffer[ofs_color + bitmap.pitch];
1128 wr[ofs + 2] = bitmap.buffer[ofs_color + bitmap.pitch * 2];
1129 wr[ofs + 3] = 255;
1130 }
1131 } break;
1132 default:
1133 ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + String::num_int64(bitmap.pixel_mode) + ".");
1134 break;
1135 }
1136 }
1137 }
1138 }
1139
1140 tex.dirty = true;
1141
1142 FontGlyph chr;
1143 chr.advance = advance * p_data->scale / p_data->oversampling;
1144 chr.texture_idx = tex_pos.index;
1145 chr.found = true;
1146
1147 chr.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);
1148 chr.rect.position = Vector2(xofs - p_rect_margin, -yofs - p_rect_margin) * p_data->scale / p_data->oversampling;
1149 chr.rect.size = chr.uv_rect.size * p_data->scale / p_data->oversampling;
1150 return chr;
1151}
1152#endif
1153
1154/*************************************************************************/
1155/* Font Cache */
1156/*************************************************************************/
1157
1158_FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph) const {
1159 ERR_FAIL_COND_V(!_ensure_cache_for_size(p_font_data, p_size), false);
1160
1161 int32_t glyph_index = p_glyph & 0xffffff; // Remove subpixel shifts.
1162
1163 FontForSizeAdvanced *fd = p_font_data->cache[p_size];
1164 if (fd->glyph_map.has(p_glyph)) {
1165 return fd->glyph_map[p_glyph].found;
1166 }
1167
1168 if (glyph_index == 0) { // Non graphical or invalid glyph, do not render.
1169 fd->glyph_map[p_glyph] = FontGlyph();
1170 return true;
1171 }
1172
1173#ifdef MODULE_FREETYPE_ENABLED
1174 FontGlyph gl;
1175 if (fd->face) {
1176 FT_Int32 flags = FT_LOAD_DEFAULT;
1177
1178 bool outline = p_size.y > 0;
1179 switch (p_font_data->hinting) {
1180 case TextServer::HINTING_NONE:
1181 flags |= FT_LOAD_NO_HINTING;
1182 break;
1183 case TextServer::HINTING_LIGHT:
1184 flags |= FT_LOAD_TARGET_LIGHT;
1185 break;
1186 default:
1187 flags |= FT_LOAD_TARGET_NORMAL;
1188 break;
1189 }
1190 if (p_font_data->force_autohinter) {
1191 flags |= FT_LOAD_FORCE_AUTOHINT;
1192 }
1193 if (outline) {
1194 flags |= FT_LOAD_NO_BITMAP;
1195 } else if (FT_HAS_COLOR(fd->face)) {
1196 flags |= FT_LOAD_COLOR;
1197 }
1198
1199 FT_Fixed v, h;
1200 FT_Get_Advance(fd->face, glyph_index, flags, &h);
1201 FT_Get_Advance(fd->face, glyph_index, flags | FT_LOAD_VERTICAL_LAYOUT, &v);
1202
1203 int error = FT_Load_Glyph(fd->face, glyph_index, flags);
1204 if (error) {
1205 fd->glyph_map[p_glyph] = FontGlyph();
1206 return false;
1207 }
1208
1209 if (!p_font_data->msdf) {
1210 if ((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)) {
1211 FT_Pos xshift = (int)((p_glyph >> 27) & 3) << 4;
1212 FT_Outline_Translate(&fd->face->glyph->outline, xshift, 0);
1213 } 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)) {
1214 FT_Pos xshift = (int)((p_glyph >> 27) & 3) << 5;
1215 FT_Outline_Translate(&fd->face->glyph->outline, xshift, 0);
1216 }
1217 }
1218
1219 if (p_font_data->embolden != 0.f) {
1220 FT_Pos strength = p_font_data->embolden * p_size.x * 4; // 26.6 fractional units (1 / 64).
1221 FT_Outline_Embolden(&fd->face->glyph->outline, strength);
1222 }
1223
1224 if (p_font_data->transform != Transform2D()) {
1225 FT_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).
1226 FT_Outline_Transform(&fd->face->glyph->outline, &mat);
1227 }
1228
1229 FT_Render_Mode aa_mode = FT_RENDER_MODE_NORMAL;
1230 bool bgra = false;
1231 switch (p_font_data->antialiasing) {
1232 case FONT_ANTIALIASING_NONE: {
1233 aa_mode = FT_RENDER_MODE_MONO;
1234 } break;
1235 case FONT_ANTIALIASING_GRAY: {
1236 aa_mode = FT_RENDER_MODE_NORMAL;
1237 } break;
1238 case FONT_ANTIALIASING_LCD: {
1239 int aa_layout = (int)((p_glyph >> 24) & 7);
1240 switch (aa_layout) {
1241 case FONT_LCD_SUBPIXEL_LAYOUT_HRGB: {
1242 aa_mode = FT_RENDER_MODE_LCD;
1243 bgra = false;
1244 } break;
1245 case FONT_LCD_SUBPIXEL_LAYOUT_HBGR: {
1246 aa_mode = FT_RENDER_MODE_LCD;
1247 bgra = true;
1248 } break;
1249 case FONT_LCD_SUBPIXEL_LAYOUT_VRGB: {
1250 aa_mode = FT_RENDER_MODE_LCD_V;
1251 bgra = false;
1252 } break;
1253 case FONT_LCD_SUBPIXEL_LAYOUT_VBGR: {
1254 aa_mode = FT_RENDER_MODE_LCD_V;
1255 bgra = true;
1256 } break;
1257 default: {
1258 aa_mode = FT_RENDER_MODE_NORMAL;
1259 } break;
1260 }
1261 } break;
1262 }
1263
1264 if (!outline) {
1265 if (!p_font_data->msdf) {
1266 error = FT_Render_Glyph(fd->face->glyph, aa_mode);
1267 }
1268 FT_GlyphSlot slot = fd->face->glyph;
1269 if (!error) {
1270 if (p_font_data->msdf) {
1271#ifdef MODULE_MSDFGEN_ENABLED
1272 gl = 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);
1273#else
1274 fd->glyph_map[p_glyph] = FontGlyph();
1275 ERR_FAIL_V_MSG(false, "Compiled without MSDFGEN support!");
1276#endif
1277 } else {
1278 gl = 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);
1279 }
1280 }
1281 } else {
1282 FT_Stroker stroker;
1283 if (FT_Stroker_New(ft_library, &stroker) != 0) {
1284 fd->glyph_map[p_glyph] = FontGlyph();
1285 ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph stroker.");
1286 }
1287
1288 FT_Stroker_Set(stroker, (int)(fd->size.y * fd->oversampling * 16.0), FT_STROKER_LINECAP_BUTT, FT_STROKER_LINEJOIN_ROUND, 0);
1289 FT_Glyph glyph;
1290 FT_BitmapGlyph glyph_bitmap;
1291
1292 if (FT_Get_Glyph(fd->face->glyph, &glyph) != 0) {
1293 goto cleanup_stroker;
1294 }
1295 if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0) {
1296 goto cleanup_glyph;
1297 }
1298 if (FT_Glyph_To_Bitmap(&glyph, aa_mode, nullptr, 1) != 0) {
1299 goto cleanup_glyph;
1300 }
1301 glyph_bitmap = (FT_BitmapGlyph)glyph;
1302 gl = rasterize_bitmap(fd, rect_range, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2(), bgra);
1303
1304 cleanup_glyph:
1305 FT_Done_Glyph(glyph);
1306 cleanup_stroker:
1307 FT_Stroker_Done(stroker);
1308 }
1309 fd->glyph_map[p_glyph] = gl;
1310 return gl.found;
1311 }
1312#endif
1313 fd->glyph_map[p_glyph] = FontGlyph();
1314 return false;
1315}
1316
1317_FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_font_data, const Vector2i &p_size) const {
1318 ERR_FAIL_COND_V(p_size.x <= 0, false);
1319 if (p_font_data->cache.has(p_size)) {
1320 return true;
1321 }
1322
1323 FontForSizeAdvanced *fd = memnew(FontForSizeAdvanced);
1324 fd->size = p_size;
1325 if (p_font_data->data_ptr && (p_font_data->data_size > 0)) {
1326 // Init dynamic font.
1327#ifdef MODULE_FREETYPE_ENABLED
1328 int error = 0;
1329 {
1330 MutexLock ftlock(ft_mutex);
1331 if (!ft_library) {
1332 error = FT_Init_FreeType(&ft_library);
1333 if (error != 0) {
1334 memdelete(fd);
1335 ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
1336 }
1337#ifdef MODULE_SVG_ENABLED
1338 FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks());
1339#endif
1340 }
1341
1342 memset(&fd->stream, 0, sizeof(FT_StreamRec));
1343 fd->stream.base = (unsigned char *)p_font_data->data_ptr;
1344 fd->stream.size = p_font_data->data_size;
1345 fd->stream.pos = 0;
1346
1347 FT_Open_Args fargs;
1348 memset(&fargs, 0, sizeof(FT_Open_Args));
1349 fargs.memory_base = (unsigned char *)p_font_data->data_ptr;
1350 fargs.memory_size = p_font_data->data_size;
1351 fargs.flags = FT_OPEN_MEMORY;
1352 fargs.stream = &fd->stream;
1353
1354 int max_index = 0;
1355 FT_Face tmp_face = nullptr;
1356 error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
1357 if (tmp_face && error == 0) {
1358 max_index = tmp_face->num_faces - 1;
1359 }
1360 if (tmp_face) {
1361 FT_Done_Face(tmp_face);
1362 }
1363
1364 error = FT_Open_Face(ft_library, &fargs, CLAMP(p_font_data->face_index, 0, max_index), &fd->face);
1365 if (error) {
1366 FT_Done_Face(fd->face);
1367 fd->face = nullptr;
1368 memdelete(fd);
1369 ERR_FAIL_V_MSG(false, "FreeType: Error loading font: '" + String(FT_Error_String(error)) + "'.");
1370 }
1371 }
1372
1373 if (p_font_data->msdf) {
1374 fd->oversampling = 1.0;
1375 fd->size.x = p_font_data->msdf_source_size;
1376 } else if (p_font_data->oversampling <= 0.0) {
1377 fd->oversampling = _font_get_global_oversampling();
1378 } else {
1379 fd->oversampling = p_font_data->oversampling;
1380 }
1381
1382 if (FT_HAS_COLOR(fd->face) && fd->face->num_fixed_sizes > 0) {
1383 int best_match = 0;
1384 int diff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[0].width));
1385 fd->scale = double(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width;
1386 for (int i = 1; i < fd->face->num_fixed_sizes; i++) {
1387 int ndiff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[i].width));
1388 if (ndiff < diff) {
1389 best_match = i;
1390 diff = ndiff;
1391 fd->scale = double(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width;
1392 }
1393 }
1394 FT_Select_Size(fd->face, best_match);
1395 } else {
1396 FT_Set_Pixel_Sizes(fd->face, 0, double(fd->size.x * fd->oversampling));
1397 if (fd->face->size->metrics.y_ppem != 0) {
1398 fd->scale = ((double)fd->size.x * fd->oversampling) / (double)fd->face->size->metrics.y_ppem;
1399 }
1400 }
1401
1402 fd->hb_handle = hb_ft_font_create(fd->face, nullptr);
1403
1404 fd->ascent = (fd->face->size->metrics.ascender / 64.0) / fd->oversampling * fd->scale;
1405 fd->descent = (-fd->face->size->metrics.descender / 64.0) / fd->oversampling * fd->scale;
1406 fd->underline_position = (-FT_MulFix(fd->face->underline_position, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale;
1407 fd->underline_thickness = (FT_MulFix(fd->face->underline_thickness, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale;
1408
1409#if HB_VERSION_ATLEAST(3, 3, 0)
1410 hb_font_set_synthetic_slant(fd->hb_handle, p_font_data->transform[0][1]);
1411#else
1412#ifndef _MSC_VER
1413#warning Building with HarfBuzz < 3.3.0, synthetic slant offset correction disabled.
1414#endif
1415#endif
1416
1417 if (!p_font_data->face_init) {
1418 // Get style flags and name.
1419 if (fd->face->family_name != nullptr) {
1420 p_font_data->font_name = String::utf8((const char *)fd->face->family_name);
1421 }
1422 if (fd->face->style_name != nullptr) {
1423 p_font_data->style_name = String::utf8((const char *)fd->face->style_name);
1424 }
1425 p_font_data->weight = _font_get_weight_by_name(p_font_data->style_name.to_lower());
1426 p_font_data->stretch = _font_get_stretch_by_name(p_font_data->style_name.to_lower());
1427 p_font_data->style_flags = 0;
1428 if ((fd->face->style_flags & FT_STYLE_FLAG_BOLD) || p_font_data->weight >= 700) {
1429 p_font_data->style_flags.set_flag(FONT_BOLD);
1430 }
1431 if ((fd->face->style_flags & FT_STYLE_FLAG_ITALIC) || _is_ital_style(p_font_data->style_name.to_lower())) {
1432 p_font_data->style_flags.set_flag(FONT_ITALIC);
1433 }
1434 if (fd->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) {
1435 p_font_data->style_flags.set_flag(FONT_FIXED_WIDTH);
1436 }
1437
1438 hb_face_t *hb_face = hb_font_get_face(fd->hb_handle);
1439 // Get supported scripts from OpenType font data.
1440 p_font_data->supported_scripts.clear();
1441 unsigned int count = hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, nullptr, nullptr);
1442 if (count != 0) {
1443 hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
1444 hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GSUB, 0, &count, script_tags);
1445 for (unsigned int i = 0; i < count; i++) {
1446 p_font_data->supported_scripts.insert(script_tags[i]);
1447 }
1448 memfree(script_tags);
1449 }
1450 count = hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GPOS, 0, nullptr, nullptr);
1451 if (count != 0) {
1452 hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
1453 hb_ot_layout_table_get_script_tags(hb_face, HB_OT_TAG_GPOS, 0, &count, script_tags);
1454 for (unsigned int i = 0; i < count; i++) {
1455 p_font_data->supported_scripts.insert(script_tags[i]);
1456 }
1457 memfree(script_tags);
1458 }
1459
1460 // Get supported scripts from OS2 table.
1461 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(fd->face, FT_SFNT_OS2);
1462 if (os2) {
1463 if ((os2->ulUnicodeRange1 & 1L << 4) || (os2->ulUnicodeRange1 & 1L << 5) || (os2->ulUnicodeRange1 & 1L << 6) || (os2->ulUnicodeRange1 & 1L << 31) || (os2->ulUnicodeRange2 & 1L << 0) || (os2->ulUnicodeRange2 & 1L << 1) || (os2->ulUnicodeRange2 & 1L << 2) || (os2->ulUnicodeRange2 & 1L << 3) || (os2->ulUnicodeRange2 & 1L << 4) || (os2->ulUnicodeRange2 & 1L << 5) || (os2->ulUnicodeRange2 & 1L << 6) || (os2->ulUnicodeRange2 & 1L << 7) || (os2->ulUnicodeRange2 & 1L << 8) || (os2->ulUnicodeRange2 & 1L << 9) || (os2->ulUnicodeRange2 & 1L << 10) || (os2->ulUnicodeRange2 & 1L << 11) || (os2->ulUnicodeRange2 & 1L << 12) || (os2->ulUnicodeRange2 & 1L << 13) || (os2->ulUnicodeRange2 & 1L << 14) || (os2->ulUnicodeRange2 & 1L << 15) || (os2->ulUnicodeRange2 & 1L << 30) || (os2->ulUnicodeRange3 & 1L << 0) || (os2->ulUnicodeRange3 & 1L << 1) || (os2->ulUnicodeRange3 & 1L << 2) || (os2->ulUnicodeRange3 & 1L << 4) || (os2->ulUnicodeRange3 & 1L << 5) || (os2->ulUnicodeRange3 & 1L << 18) || (os2->ulUnicodeRange3 & 1L << 24) || (os2->ulUnicodeRange3 & 1L << 25) || (os2->ulUnicodeRange3 & 1L << 26) || (os2->ulUnicodeRange3 & 1L << 27) || (os2->ulUnicodeRange3 & 1L << 28) || (os2->ulUnicodeRange4 & 1L << 3) || (os2->ulUnicodeRange4 & 1L << 6) || (os2->ulUnicodeRange4 & 1L << 15) || (os2->ulUnicodeRange4 & 1L << 23) || (os2->ulUnicodeRange4 & 1L << 24) || (os2->ulUnicodeRange4 & 1L << 26)) {
1464 p_font_data->supported_scripts.insert(HB_SCRIPT_COMMON);
1465 }
1466 if ((os2->ulUnicodeRange1 & 1L << 0) || (os2->ulUnicodeRange1 & 1L << 1) || (os2->ulUnicodeRange1 & 1L << 2) || (os2->ulUnicodeRange1 & 1L << 3) || (os2->ulUnicodeRange1 & 1L << 29)) {
1467 p_font_data->supported_scripts.insert(HB_SCRIPT_LATIN);
1468 }
1469 if ((os2->ulUnicodeRange1 & 1L << 7) || (os2->ulUnicodeRange1 & 1L << 30)) {
1470 p_font_data->supported_scripts.insert(HB_SCRIPT_GREEK);
1471 }
1472 if (os2->ulUnicodeRange1 & 1L << 8) {
1473 p_font_data->supported_scripts.insert(HB_SCRIPT_COPTIC);
1474 }
1475 if (os2->ulUnicodeRange1 & 1L << 9) {
1476 p_font_data->supported_scripts.insert(HB_SCRIPT_CYRILLIC);
1477 }
1478 if (os2->ulUnicodeRange1 & 1L << 10) {
1479 p_font_data->supported_scripts.insert(HB_SCRIPT_ARMENIAN);
1480 }
1481 if (os2->ulUnicodeRange1 & 1L << 11) {
1482 p_font_data->supported_scripts.insert(HB_SCRIPT_HEBREW);
1483 }
1484 if (os2->ulUnicodeRange1 & 1L << 12) {
1485 p_font_data->supported_scripts.insert(HB_SCRIPT_VAI);
1486 }
1487 if ((os2->ulUnicodeRange1 & 1L << 13) || (os2->ulUnicodeRange2 & 1L << 31) || (os2->ulUnicodeRange3 & 1L << 3)) {
1488 p_font_data->supported_scripts.insert(HB_SCRIPT_ARABIC);
1489 }
1490 if (os2->ulUnicodeRange1 & 1L << 14) {
1491 p_font_data->supported_scripts.insert(HB_SCRIPT_NKO);
1492 }
1493 if (os2->ulUnicodeRange1 & 1L << 15) {
1494 p_font_data->supported_scripts.insert(HB_SCRIPT_DEVANAGARI);
1495 }
1496 if (os2->ulUnicodeRange1 & 1L << 16) {
1497 p_font_data->supported_scripts.insert(HB_SCRIPT_BENGALI);
1498 }
1499 if (os2->ulUnicodeRange1 & 1L << 17) {
1500 p_font_data->supported_scripts.insert(HB_SCRIPT_GURMUKHI);
1501 }
1502 if (os2->ulUnicodeRange1 & 1L << 18) {
1503 p_font_data->supported_scripts.insert(HB_SCRIPT_GUJARATI);
1504 }
1505 if (os2->ulUnicodeRange1 & 1L << 19) {
1506 p_font_data->supported_scripts.insert(HB_SCRIPT_ORIYA);
1507 }
1508 if (os2->ulUnicodeRange1 & 1L << 20) {
1509 p_font_data->supported_scripts.insert(HB_SCRIPT_TAMIL);
1510 }
1511 if (os2->ulUnicodeRange1 & 1L << 21) {
1512 p_font_data->supported_scripts.insert(HB_SCRIPT_TELUGU);
1513 }
1514 if (os2->ulUnicodeRange1 & 1L << 22) {
1515 p_font_data->supported_scripts.insert(HB_SCRIPT_KANNADA);
1516 }
1517 if (os2->ulUnicodeRange1 & 1L << 23) {
1518 p_font_data->supported_scripts.insert(HB_SCRIPT_MALAYALAM);
1519 }
1520 if (os2->ulUnicodeRange1 & 1L << 24) {
1521 p_font_data->supported_scripts.insert(HB_SCRIPT_THAI);
1522 }
1523 if (os2->ulUnicodeRange1 & 1L << 25) {
1524 p_font_data->supported_scripts.insert(HB_SCRIPT_LAO);
1525 }
1526 if (os2->ulUnicodeRange1 & 1L << 26) {
1527 p_font_data->supported_scripts.insert(HB_SCRIPT_GEORGIAN);
1528 }
1529 if (os2->ulUnicodeRange1 & 1L << 27) {
1530 p_font_data->supported_scripts.insert(HB_SCRIPT_BALINESE);
1531 }
1532 if ((os2->ulUnicodeRange1 & 1L << 28) || (os2->ulUnicodeRange2 & 1L << 20) || (os2->ulUnicodeRange2 & 1L << 24)) {
1533 p_font_data->supported_scripts.insert(HB_SCRIPT_HANGUL);
1534 }
1535 if ((os2->ulUnicodeRange2 & 1L << 21) || (os2->ulUnicodeRange2 & 1L << 22) || (os2->ulUnicodeRange2 & 1L << 23) || (os2->ulUnicodeRange2 & 1L << 26) || (os2->ulUnicodeRange2 & 1L << 27) || (os2->ulUnicodeRange2 & 1L << 29)) {
1536 p_font_data->supported_scripts.insert(HB_SCRIPT_HAN);
1537 }
1538 if (os2->ulUnicodeRange2 & 1L << 17) {
1539 p_font_data->supported_scripts.insert(HB_SCRIPT_HIRAGANA);
1540 }
1541 if (os2->ulUnicodeRange2 & 1L << 18) {
1542 p_font_data->supported_scripts.insert(HB_SCRIPT_KATAKANA);
1543 }
1544 if (os2->ulUnicodeRange2 & 1L << 19) {
1545 p_font_data->supported_scripts.insert(HB_SCRIPT_BOPOMOFO);
1546 }
1547 if (os2->ulUnicodeRange3 & 1L << 6) {
1548 p_font_data->supported_scripts.insert(HB_SCRIPT_TIBETAN);
1549 }
1550 if (os2->ulUnicodeRange3 & 1L << 7) {
1551 p_font_data->supported_scripts.insert(HB_SCRIPT_SYRIAC);
1552 }
1553 if (os2->ulUnicodeRange3 & 1L << 8) {
1554 p_font_data->supported_scripts.insert(HB_SCRIPT_THAANA);
1555 }
1556 if (os2->ulUnicodeRange3 & 1L << 9) {
1557 p_font_data->supported_scripts.insert(HB_SCRIPT_SINHALA);
1558 }
1559 if (os2->ulUnicodeRange3 & 1L << 10) {
1560 p_font_data->supported_scripts.insert(HB_SCRIPT_MYANMAR);
1561 }
1562 if (os2->ulUnicodeRange3 & 1L << 11) {
1563 p_font_data->supported_scripts.insert(HB_SCRIPT_ETHIOPIC);
1564 }
1565 if (os2->ulUnicodeRange3 & 1L << 12) {
1566 p_font_data->supported_scripts.insert(HB_SCRIPT_CHEROKEE);
1567 }
1568 if (os2->ulUnicodeRange3 & 1L << 13) {
1569 p_font_data->supported_scripts.insert(HB_SCRIPT_CANADIAN_SYLLABICS);
1570 }
1571 if (os2->ulUnicodeRange3 & 1L << 14) {
1572 p_font_data->supported_scripts.insert(HB_SCRIPT_OGHAM);
1573 }
1574 if (os2->ulUnicodeRange3 & 1L << 15) {
1575 p_font_data->supported_scripts.insert(HB_SCRIPT_RUNIC);
1576 }
1577 if (os2->ulUnicodeRange3 & 1L << 16) {
1578 p_font_data->supported_scripts.insert(HB_SCRIPT_KHMER);
1579 }
1580 if (os2->ulUnicodeRange3 & 1L << 17) {
1581 p_font_data->supported_scripts.insert(HB_SCRIPT_MONGOLIAN);
1582 }
1583 if (os2->ulUnicodeRange3 & 1L << 19) {
1584 p_font_data->supported_scripts.insert(HB_SCRIPT_YI);
1585 }
1586 if (os2->ulUnicodeRange3 & 1L << 20) {
1587 p_font_data->supported_scripts.insert(HB_SCRIPT_HANUNOO);
1588 p_font_data->supported_scripts.insert(HB_SCRIPT_TAGBANWA);
1589 p_font_data->supported_scripts.insert(HB_SCRIPT_BUHID);
1590 p_font_data->supported_scripts.insert(HB_SCRIPT_TAGALOG);
1591 }
1592 if (os2->ulUnicodeRange3 & 1L << 21) {
1593 p_font_data->supported_scripts.insert(HB_SCRIPT_OLD_ITALIC);
1594 }
1595 if (os2->ulUnicodeRange3 & 1L << 22) {
1596 p_font_data->supported_scripts.insert(HB_SCRIPT_GOTHIC);
1597 }
1598 if (os2->ulUnicodeRange3 & 1L << 23) {
1599 p_font_data->supported_scripts.insert(HB_SCRIPT_DESERET);
1600 }
1601 if (os2->ulUnicodeRange3 & 1L << 29) {
1602 p_font_data->supported_scripts.insert(HB_SCRIPT_LIMBU);
1603 }
1604 if (os2->ulUnicodeRange3 & 1L << 30) {
1605 p_font_data->supported_scripts.insert(HB_SCRIPT_TAI_LE);
1606 }
1607 if (os2->ulUnicodeRange3 & 1L << 31) {
1608 p_font_data->supported_scripts.insert(HB_SCRIPT_NEW_TAI_LUE);
1609 }
1610 if (os2->ulUnicodeRange4 & 1L << 0) {
1611 p_font_data->supported_scripts.insert(HB_SCRIPT_BUGINESE);
1612 }
1613 if (os2->ulUnicodeRange4 & 1L << 1) {
1614 p_font_data->supported_scripts.insert(HB_SCRIPT_GLAGOLITIC);
1615 }
1616 if (os2->ulUnicodeRange4 & 1L << 2) {
1617 p_font_data->supported_scripts.insert(HB_SCRIPT_TIFINAGH);
1618 }
1619 if (os2->ulUnicodeRange4 & 1L << 4) {
1620 p_font_data->supported_scripts.insert(HB_SCRIPT_SYLOTI_NAGRI);
1621 }
1622 if (os2->ulUnicodeRange4 & 1L << 5) {
1623 p_font_data->supported_scripts.insert(HB_SCRIPT_LINEAR_B);
1624 }
1625 if (os2->ulUnicodeRange4 & 1L << 7) {
1626 p_font_data->supported_scripts.insert(HB_SCRIPT_UGARITIC);
1627 }
1628 if (os2->ulUnicodeRange4 & 1L << 8) {
1629 p_font_data->supported_scripts.insert(HB_SCRIPT_OLD_PERSIAN);
1630 }
1631 if (os2->ulUnicodeRange4 & 1L << 9) {
1632 p_font_data->supported_scripts.insert(HB_SCRIPT_SHAVIAN);
1633 }
1634 if (os2->ulUnicodeRange4 & 1L << 10) {
1635 p_font_data->supported_scripts.insert(HB_SCRIPT_OSMANYA);
1636 }
1637 if (os2->ulUnicodeRange4 & 1L << 11) {
1638 p_font_data->supported_scripts.insert(HB_SCRIPT_CYPRIOT);
1639 }
1640 if (os2->ulUnicodeRange4 & 1L << 12) {
1641 p_font_data->supported_scripts.insert(HB_SCRIPT_KHAROSHTHI);
1642 }
1643 if (os2->ulUnicodeRange4 & 1L << 13) {
1644 p_font_data->supported_scripts.insert(HB_SCRIPT_TAI_VIET);
1645 }
1646 if (os2->ulUnicodeRange4 & 1L << 14) {
1647 p_font_data->supported_scripts.insert(HB_SCRIPT_CUNEIFORM);
1648 }
1649 if (os2->ulUnicodeRange4 & 1L << 16) {
1650 p_font_data->supported_scripts.insert(HB_SCRIPT_SUNDANESE);
1651 }
1652 if (os2->ulUnicodeRange4 & 1L << 17) {
1653 p_font_data->supported_scripts.insert(HB_SCRIPT_LEPCHA);
1654 }
1655 if (os2->ulUnicodeRange4 & 1L << 18) {
1656 p_font_data->supported_scripts.insert(HB_SCRIPT_OL_CHIKI);
1657 }
1658 if (os2->ulUnicodeRange4 & 1L << 19) {
1659 p_font_data->supported_scripts.insert(HB_SCRIPT_SAURASHTRA);
1660 }
1661 if (os2->ulUnicodeRange4 & 1L << 20) {
1662 p_font_data->supported_scripts.insert(HB_SCRIPT_KAYAH_LI);
1663 }
1664 if (os2->ulUnicodeRange4 & 1L << 21) {
1665 p_font_data->supported_scripts.insert(HB_SCRIPT_REJANG);
1666 }
1667 if (os2->ulUnicodeRange4 & 1L << 22) {
1668 p_font_data->supported_scripts.insert(HB_SCRIPT_CHAM);
1669 }
1670 if (os2->ulUnicodeRange4 & 1L << 25) {
1671 p_font_data->supported_scripts.insert(HB_SCRIPT_ANATOLIAN_HIEROGLYPHS);
1672 }
1673 }
1674
1675 // Read OpenType feature tags.
1676 p_font_data->supported_features.clear();
1677 count = hb_ot_layout_table_get_feature_tags(hb_face, HB_OT_TAG_GSUB, 0, nullptr, nullptr);
1678 if (count != 0) {
1679 hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
1680 hb_ot_layout_table_get_feature_tags(hb_face, HB_OT_TAG_GSUB, 0, &count, feature_tags);
1681 for (unsigned int i = 0; i < count; i++) {
1682 Dictionary ftr;
1683
1684#if HB_VERSION_ATLEAST(2, 1, 0)
1685 hb_ot_name_id_t lbl_id;
1686 if (hb_ot_layout_feature_get_name_ids(hb_face, HB_OT_TAG_GSUB, i, &lbl_id, nullptr, nullptr, nullptr, nullptr)) {
1687 PackedInt32Array lbl;
1688 unsigned int text_size = hb_ot_name_get_utf32(hb_face, lbl_id, hb_language_from_string(TranslationServer::get_singleton()->get_tool_locale().ascii().get_data(), -1), nullptr, nullptr) + 1;
1689 lbl.resize(text_size);
1690 memset((uint32_t *)lbl.ptrw(), 0, sizeof(uint32_t) * text_size);
1691 hb_ot_name_get_utf32(hb_face, lbl_id, hb_language_from_string(TranslationServer::get_singleton()->get_tool_locale().ascii().get_data(), -1), &text_size, (uint32_t *)lbl.ptrw());
1692 ftr["label"] = String((const char32_t *)lbl.ptr());
1693 }
1694#else
1695#ifndef _MSC_VER
1696#warning Building with HarfBuzz < 2.1.0, readable OpenType feature names disabled.
1697#endif
1698#endif
1699 ftr["type"] = _get_tag_type(feature_tags[i]);
1700 ftr["hidden"] = _get_tag_hidden(feature_tags[i]);
1701
1702 p_font_data->supported_features[feature_tags[i]] = ftr;
1703 }
1704 memfree(feature_tags);
1705 }
1706 count = hb_ot_layout_table_get_feature_tags(hb_face, HB_OT_TAG_GPOS, 0, nullptr, nullptr);
1707 if (count != 0) {
1708 hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
1709 hb_ot_layout_table_get_feature_tags(hb_face, HB_OT_TAG_GPOS, 0, &count, feature_tags);
1710 for (unsigned int i = 0; i < count; i++) {
1711 Dictionary ftr;
1712
1713#if HB_VERSION_ATLEAST(2, 1, 0)
1714 hb_ot_name_id_t lbl_id;
1715 if (hb_ot_layout_feature_get_name_ids(hb_face, HB_OT_TAG_GPOS, i, &lbl_id, nullptr, nullptr, nullptr, nullptr)) {
1716 PackedInt32Array lbl;
1717 unsigned int text_size = hb_ot_name_get_utf32(hb_face, lbl_id, hb_language_from_string(TranslationServer::get_singleton()->get_tool_locale().ascii().get_data(), -1), nullptr, nullptr) + 1;
1718 lbl.resize(text_size);
1719 memset((uint32_t *)lbl.ptrw(), 0, sizeof(uint32_t) * text_size);
1720 hb_ot_name_get_utf32(hb_face, lbl_id, hb_language_from_string(TranslationServer::get_singleton()->get_tool_locale().ascii().get_data(), -1), &text_size, (uint32_t *)lbl.ptrw());
1721 ftr["label"] = String((const char32_t *)lbl.ptr());
1722 }
1723#else
1724#ifndef _MSC_VER
1725#warning Building with HarfBuzz < 2.1.0, readable OpenType feature names disabled.
1726#endif
1727#endif
1728 ftr["type"] = _get_tag_type(feature_tags[i]);
1729 ftr["hidden"] = _get_tag_hidden(feature_tags[i]);
1730
1731 p_font_data->supported_features[feature_tags[i]] = ftr;
1732 }
1733 memfree(feature_tags);
1734 }
1735
1736 // Read OpenType variations.
1737 p_font_data->supported_varaitions.clear();
1738 if (fd->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
1739 FT_MM_Var *amaster;
1740 FT_Get_MM_Var(fd->face, &amaster);
1741 for (FT_UInt i = 0; i < amaster->num_axis; i++) {
1742 p_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);
1743 }
1744 FT_Done_MM_Var(ft_library, amaster);
1745 }
1746 p_font_data->face_init = true;
1747 }
1748
1749 // Write variations.
1750 if (fd->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
1751 FT_MM_Var *amaster;
1752
1753 FT_Get_MM_Var(fd->face, &amaster);
1754
1755 Vector<hb_variation_t> hb_vars;
1756 Vector<FT_Fixed> coords;
1757 coords.resize(amaster->num_axis);
1758
1759 FT_Get_Var_Design_Coordinates(fd->face, coords.size(), coords.ptrw());
1760
1761 for (FT_UInt i = 0; i < amaster->num_axis; i++) {
1762 hb_variation_t var;
1763
1764 // Reset to default.
1765 var.tag = amaster->axis[i].tag;
1766 var.value = (double)amaster->axis[i].def / 65536.0;
1767 coords.write[i] = amaster->axis[i].def;
1768
1769 if (p_font_data->variation_coordinates.has(var.tag)) {
1770 var.value = p_font_data->variation_coordinates[var.tag];
1771 coords.write[i] = CLAMP(var.value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);
1772 }
1773
1774 if (p_font_data->variation_coordinates.has(_tag_to_name(var.tag))) {
1775 var.value = p_font_data->variation_coordinates[_tag_to_name(var.tag)];
1776 coords.write[i] = CLAMP(var.value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);
1777 }
1778
1779 hb_vars.push_back(var);
1780 }
1781
1782 FT_Set_Var_Design_Coordinates(fd->face, coords.size(), coords.ptrw());
1783 hb_font_set_variations(fd->hb_handle, hb_vars.is_empty() ? nullptr : &hb_vars[0], hb_vars.size());
1784 FT_Done_MM_Var(ft_library, amaster);
1785 }
1786#else
1787 memdelete(fd);
1788 ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!");
1789#endif
1790 } else {
1791 // Init bitmap font.
1792 fd->hb_handle = _bmp_font_create(fd, nullptr);
1793 }
1794 p_font_data->cache[p_size] = fd;
1795 return true;
1796}
1797
1798_FORCE_INLINE_ void TextServerAdvanced::_font_clear_cache(FontAdvanced *p_font_data) {
1799 MutexLock ftlock(ft_mutex);
1800
1801 for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : p_font_data->cache) {
1802 memdelete(E.value);
1803 }
1804 p_font_data->cache.clear();
1805 p_font_data->face_init = false;
1806 p_font_data->supported_features.clear();
1807 p_font_data->supported_varaitions.clear();
1808 p_font_data->supported_scripts.clear();
1809}
1810
1811hb_font_t *TextServerAdvanced::_font_get_hb_handle(const RID &p_font_rid, int64_t p_size) const {
1812 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
1813 ERR_FAIL_COND_V(!fd, nullptr);
1814
1815 MutexLock lock(fd->mutex);
1816 Vector2i size = _get_size(fd, p_size);
1817
1818 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), nullptr);
1819
1820 return fd->cache[size]->hb_handle;
1821}
1822
1823RID TextServerAdvanced::_create_font() {
1824 _THREAD_SAFE_METHOD_
1825
1826 FontAdvanced *fd = memnew(FontAdvanced);
1827
1828 return font_owner.make_rid(fd);
1829}
1830
1831void TextServerAdvanced::_font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) {
1832 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
1833 ERR_FAIL_COND(!fd);
1834
1835 MutexLock lock(fd->mutex);
1836 _font_clear_cache(fd);
1837 fd->data = p_data;
1838 fd->data_ptr = fd->data.ptr();
1839 fd->data_size = fd->data.size();
1840}
1841
1842void TextServerAdvanced::_font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) {
1843 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
1844 ERR_FAIL_COND(!fd);
1845
1846 MutexLock lock(fd->mutex);
1847 _font_clear_cache(fd);
1848 fd->data.resize(0);
1849 fd->data_ptr = p_data_ptr;
1850 fd->data_size = p_data_size;
1851}
1852
1853void TextServerAdvanced::_font_set_face_index(const RID &p_font_rid, int64_t p_face_index) {
1854 ERR_FAIL_COND(p_face_index < 0);
1855 ERR_FAIL_COND(p_face_index >= 0x7FFF);
1856
1857 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
1858 ERR_FAIL_COND(!fd);
1859
1860 MutexLock lock(fd->mutex);
1861 if (fd->face_index != p_face_index) {
1862 fd->face_index = p_face_index;
1863 _font_clear_cache(fd);
1864 }
1865}
1866
1867int64_t TextServerAdvanced::_font_get_face_index(const RID &p_font_rid) const {
1868 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
1869 ERR_FAIL_COND_V(!fd, 0);
1870
1871 MutexLock lock(fd->mutex);
1872 return fd->face_index;
1873}
1874
1875int64_t TextServerAdvanced::_font_get_face_count(const RID &p_font_rid) const {
1876 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
1877 ERR_FAIL_COND_V(!fd, 0);
1878
1879 MutexLock lock(fd->mutex);
1880 int face_count = 0;
1881
1882 if (fd->data_ptr && (fd->data_size > 0)) {
1883 // Init dynamic font.
1884#ifdef MODULE_FREETYPE_ENABLED
1885 int error = 0;
1886 if (!ft_library) {
1887 error = FT_Init_FreeType(&ft_library);
1888 ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
1889#ifdef MODULE_SVG_ENABLED
1890 FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks());
1891#endif
1892 }
1893
1894 FT_StreamRec stream;
1895 memset(&stream, 0, sizeof(FT_StreamRec));
1896 stream.base = (unsigned char *)fd->data_ptr;
1897 stream.size = fd->data_size;
1898 stream.pos = 0;
1899
1900 FT_Open_Args fargs;
1901 memset(&fargs, 0, sizeof(FT_Open_Args));
1902 fargs.memory_base = (unsigned char *)fd->data_ptr;
1903 fargs.memory_size = fd->data_size;
1904 fargs.flags = FT_OPEN_MEMORY;
1905 fargs.stream = &stream;
1906
1907 MutexLock ftlock(ft_mutex);
1908
1909 FT_Face tmp_face = nullptr;
1910 error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
1911 if (error == 0) {
1912 face_count = tmp_face->num_faces;
1913 FT_Done_Face(tmp_face);
1914 }
1915#endif
1916 }
1917
1918 return face_count;
1919}
1920
1921void TextServerAdvanced::_font_set_style(const RID &p_font_rid, BitField<FontStyle> p_style) {
1922 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
1923 ERR_FAIL_COND(!fd);
1924
1925 MutexLock lock(fd->mutex);
1926 Vector2i size = _get_size(fd, 16);
1927 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
1928 fd->style_flags = p_style;
1929}
1930
1931BitField<TextServer::FontStyle> TextServerAdvanced::_font_get_style(const RID &p_font_rid) const {
1932 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
1933 ERR_FAIL_COND_V(!fd, 0);
1934
1935 MutexLock lock(fd->mutex);
1936 Vector2i size = _get_size(fd, 16);
1937 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0);
1938 return fd->style_flags;
1939}
1940
1941void TextServerAdvanced::_font_set_style_name(const RID &p_font_rid, const String &p_name) {
1942 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
1943 ERR_FAIL_COND(!fd);
1944
1945 MutexLock lock(fd->mutex);
1946 Vector2i size = _get_size(fd, 16);
1947 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
1948 fd->style_name = p_name;
1949}
1950
1951String TextServerAdvanced::_font_get_style_name(const RID &p_font_rid) const {
1952 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
1953 ERR_FAIL_COND_V(!fd, String());
1954
1955 MutexLock lock(fd->mutex);
1956 Vector2i size = _get_size(fd, 16);
1957 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), String());
1958 return fd->style_name;
1959}
1960
1961void TextServerAdvanced::_font_set_weight(const RID &p_font_rid, int64_t p_weight) {
1962 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
1963 ERR_FAIL_COND(!fd);
1964
1965 MutexLock lock(fd->mutex);
1966 Vector2i size = _get_size(fd, 16);
1967 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
1968 fd->weight = CLAMP(p_weight, 100, 999);
1969}
1970
1971int64_t TextServerAdvanced::_font_get_weight(const RID &p_font_rid) const {
1972 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
1973 ERR_FAIL_COND_V(!fd, 400);
1974
1975 MutexLock lock(fd->mutex);
1976 Vector2i size = _get_size(fd, 16);
1977 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 400);
1978 return fd->weight;
1979}
1980
1981void TextServerAdvanced::_font_set_stretch(const RID &p_font_rid, int64_t p_stretch) {
1982 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
1983 ERR_FAIL_COND(!fd);
1984
1985 MutexLock lock(fd->mutex);
1986 Vector2i size = _get_size(fd, 16);
1987 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
1988 fd->stretch = CLAMP(p_stretch, 50, 200);
1989}
1990
1991int64_t TextServerAdvanced::_font_get_stretch(const RID &p_font_rid) const {
1992 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
1993 ERR_FAIL_COND_V(!fd, 100);
1994
1995 MutexLock lock(fd->mutex);
1996 Vector2i size = _get_size(fd, 16);
1997 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 100);
1998 return fd->stretch;
1999}
2000
2001void TextServerAdvanced::_font_set_name(const RID &p_font_rid, const String &p_name) {
2002 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2003 ERR_FAIL_COND(!fd);
2004
2005 MutexLock lock(fd->mutex);
2006 Vector2i size = _get_size(fd, 16);
2007 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
2008 fd->font_name = p_name;
2009}
2010
2011String TextServerAdvanced::_font_get_name(const RID &p_font_rid) const {
2012 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2013 ERR_FAIL_COND_V(!fd, String());
2014
2015 MutexLock lock(fd->mutex);
2016 Vector2i size = _get_size(fd, 16);
2017 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), String());
2018 return fd->font_name;
2019}
2020
2021Dictionary TextServerAdvanced::_font_get_ot_name_strings(const RID &p_font_rid) const {
2022 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2023 ERR_FAIL_COND_V(!fd, Dictionary());
2024
2025 MutexLock lock(fd->mutex);
2026 Vector2i size = _get_size(fd, 16);
2027 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary());
2028
2029 hb_face_t *hb_face = hb_font_get_face(fd->cache[size]->hb_handle);
2030
2031 unsigned int num_entries = 0;
2032 const hb_ot_name_entry_t *names = hb_ot_name_list_names(hb_face, &num_entries);
2033 HashMap<String, Dictionary> names_for_lang;
2034 for (unsigned int i = 0; i < num_entries; i++) {
2035 String name;
2036 switch (names[i].name_id) {
2037 case HB_OT_NAME_ID_COPYRIGHT: {
2038 name = "copyright";
2039 } break;
2040 case HB_OT_NAME_ID_FONT_FAMILY: {
2041 name = "family_name";
2042 } break;
2043 case HB_OT_NAME_ID_FONT_SUBFAMILY: {
2044 name = "subfamily_name";
2045 } break;
2046 case HB_OT_NAME_ID_UNIQUE_ID: {
2047 name = "unique_identifier";
2048 } break;
2049 case HB_OT_NAME_ID_FULL_NAME: {
2050 name = "full_name";
2051 } break;
2052 case HB_OT_NAME_ID_VERSION_STRING: {
2053 name = "version";
2054 } break;
2055 case HB_OT_NAME_ID_POSTSCRIPT_NAME: {
2056 name = "postscript_name";
2057 } break;
2058 case HB_OT_NAME_ID_TRADEMARK: {
2059 name = "trademark";
2060 } break;
2061 case HB_OT_NAME_ID_MANUFACTURER: {
2062 name = "manufacturer";
2063 } break;
2064 case HB_OT_NAME_ID_DESIGNER: {
2065 name = "designer";
2066 } break;
2067 case HB_OT_NAME_ID_DESCRIPTION: {
2068 name = "description";
2069 } break;
2070 case HB_OT_NAME_ID_VENDOR_URL: {
2071 name = "vendor_url";
2072 } break;
2073 case HB_OT_NAME_ID_DESIGNER_URL: {
2074 name = "designer_url";
2075 } break;
2076 case HB_OT_NAME_ID_LICENSE: {
2077 name = "license";
2078 } break;
2079 case HB_OT_NAME_ID_LICENSE_URL: {
2080 name = "license_url";
2081 } break;
2082 case HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY: {
2083 name = "typographic_family_name";
2084 } break;
2085 case HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY: {
2086 name = "typographic_subfamily_name";
2087 } break;
2088 case HB_OT_NAME_ID_MAC_FULL_NAME: {
2089 name = "full_name_macos";
2090 } break;
2091 case HB_OT_NAME_ID_SAMPLE_TEXT: {
2092 name = "sample_text";
2093 } break;
2094 case HB_OT_NAME_ID_CID_FINDFONT_NAME: {
2095 name = "cid_findfont_name";
2096 } break;
2097 case HB_OT_NAME_ID_WWS_FAMILY: {
2098 name = "weight_width_slope_family_name";
2099 } break;
2100 case HB_OT_NAME_ID_WWS_SUBFAMILY: {
2101 name = "weight_width_slope_subfamily_name";
2102 } break;
2103 case HB_OT_NAME_ID_LIGHT_BACKGROUND: {
2104 name = "light_background_palette";
2105 } break;
2106 case HB_OT_NAME_ID_DARK_BACKGROUND: {
2107 name = "dark_background_palette";
2108 } break;
2109 case HB_OT_NAME_ID_VARIATIONS_PS_PREFIX: {
2110 name = "postscript_name_prefix";
2111 } break;
2112 default: {
2113 name = vformat("unknown_%d", names[i].name_id);
2114 } break;
2115 }
2116 String text;
2117 unsigned int text_size = hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, nullptr, nullptr) + 1;
2118 text.resize(text_size);
2119 hb_ot_name_get_utf32(hb_face, names[i].name_id, names[i].language, &text_size, (uint32_t *)text.ptrw());
2120 if (!text.is_empty()) {
2121 Dictionary &id_string = names_for_lang[String(hb_language_to_string(names[i].language))];
2122 id_string[name] = text;
2123 }
2124 }
2125
2126 Dictionary out;
2127 for (const KeyValue<String, Dictionary> &E : names_for_lang) {
2128 out[E.key] = E.value;
2129 }
2130
2131 return out;
2132}
2133
2134void TextServerAdvanced::_font_set_antialiasing(const RID &p_font_rid, TextServer::FontAntialiasing p_antialiasing) {
2135 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2136 ERR_FAIL_COND(!fd);
2137
2138 MutexLock lock(fd->mutex);
2139 if (fd->antialiasing != p_antialiasing) {
2140 _font_clear_cache(fd);
2141 fd->antialiasing = p_antialiasing;
2142 }
2143}
2144
2145TextServer::FontAntialiasing TextServerAdvanced::_font_get_antialiasing(const RID &p_font_rid) const {
2146 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2147 ERR_FAIL_COND_V(!fd, TextServer::FONT_ANTIALIASING_NONE);
2148
2149 MutexLock lock(fd->mutex);
2150 return fd->antialiasing;
2151}
2152
2153void TextServerAdvanced::_font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) {
2154 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2155 ERR_FAIL_COND(!fd);
2156
2157 MutexLock lock(fd->mutex);
2158 if (fd->mipmaps != p_generate_mipmaps) {
2159 for (KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {
2160 for (int i = 0; i < E.value->textures.size(); i++) {
2161 E.value->textures.write[i].dirty = true;
2162 E.value->textures.write[i].texture = Ref<ImageTexture>();
2163 }
2164 }
2165 fd->mipmaps = p_generate_mipmaps;
2166 }
2167}
2168
2169bool TextServerAdvanced::_font_get_generate_mipmaps(const RID &p_font_rid) const {
2170 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2171 ERR_FAIL_COND_V(!fd, false);
2172
2173 MutexLock lock(fd->mutex);
2174 return fd->mipmaps;
2175}
2176
2177void TextServerAdvanced::_font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) {
2178 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2179 ERR_FAIL_COND(!fd);
2180
2181 MutexLock lock(fd->mutex);
2182 if (fd->msdf != p_msdf) {
2183 _font_clear_cache(fd);
2184 fd->msdf = p_msdf;
2185 }
2186}
2187
2188bool TextServerAdvanced::_font_is_multichannel_signed_distance_field(const RID &p_font_rid) const {
2189 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2190 ERR_FAIL_COND_V(!fd, false);
2191
2192 MutexLock lock(fd->mutex);
2193 return fd->msdf;
2194}
2195
2196void TextServerAdvanced::_font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) {
2197 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2198 ERR_FAIL_COND(!fd);
2199
2200 MutexLock lock(fd->mutex);
2201 if (fd->msdf_range != p_msdf_pixel_range) {
2202 _font_clear_cache(fd);
2203 fd->msdf_range = p_msdf_pixel_range;
2204 }
2205}
2206
2207int64_t TextServerAdvanced::_font_get_msdf_pixel_range(const RID &p_font_rid) const {
2208 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2209 ERR_FAIL_COND_V(!fd, false);
2210
2211 MutexLock lock(fd->mutex);
2212 return fd->msdf_range;
2213}
2214
2215void TextServerAdvanced::_font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) {
2216 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2217 ERR_FAIL_COND(!fd);
2218
2219 MutexLock lock(fd->mutex);
2220 if (fd->msdf_source_size != p_msdf_size) {
2221 _font_clear_cache(fd);
2222 fd->msdf_source_size = p_msdf_size;
2223 }
2224}
2225
2226int64_t TextServerAdvanced::_font_get_msdf_size(const RID &p_font_rid) const {
2227 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2228 ERR_FAIL_COND_V(!fd, false);
2229
2230 MutexLock lock(fd->mutex);
2231 return fd->msdf_source_size;
2232}
2233
2234void TextServerAdvanced::_font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) {
2235 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2236 ERR_FAIL_COND(!fd);
2237
2238 MutexLock lock(fd->mutex);
2239 fd->fixed_size = p_fixed_size;
2240}
2241
2242int64_t TextServerAdvanced::_font_get_fixed_size(const RID &p_font_rid) const {
2243 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2244 ERR_FAIL_COND_V(!fd, false);
2245
2246 MutexLock lock(fd->mutex);
2247 return fd->fixed_size;
2248}
2249
2250void TextServerAdvanced::_font_set_allow_system_fallback(const RID &p_font_rid, bool p_allow_system_fallback) {
2251 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2252 ERR_FAIL_COND(!fd);
2253
2254 MutexLock lock(fd->mutex);
2255 fd->allow_system_fallback = p_allow_system_fallback;
2256}
2257
2258bool TextServerAdvanced::_font_is_allow_system_fallback(const RID &p_font_rid) const {
2259 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2260 ERR_FAIL_COND_V(!fd, false);
2261
2262 MutexLock lock(fd->mutex);
2263 return fd->allow_system_fallback;
2264}
2265
2266void TextServerAdvanced::_font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) {
2267 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2268 ERR_FAIL_COND(!fd);
2269
2270 MutexLock lock(fd->mutex);
2271 if (fd->force_autohinter != p_force_autohinter) {
2272 _font_clear_cache(fd);
2273 fd->force_autohinter = p_force_autohinter;
2274 }
2275}
2276
2277bool TextServerAdvanced::_font_is_force_autohinter(const RID &p_font_rid) const {
2278 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2279 ERR_FAIL_COND_V(!fd, false);
2280
2281 MutexLock lock(fd->mutex);
2282 return fd->force_autohinter;
2283}
2284
2285void TextServerAdvanced::_font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) {
2286 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2287 ERR_FAIL_COND(!fd);
2288
2289 MutexLock lock(fd->mutex);
2290 if (fd->hinting != p_hinting) {
2291 _font_clear_cache(fd);
2292 fd->hinting = p_hinting;
2293 }
2294}
2295
2296TextServer::Hinting TextServerAdvanced::_font_get_hinting(const RID &p_font_rid) const {
2297 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2298 ERR_FAIL_COND_V(!fd, HINTING_NONE);
2299
2300 MutexLock lock(fd->mutex);
2301 return fd->hinting;
2302}
2303
2304void TextServerAdvanced::_font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) {
2305 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2306 ERR_FAIL_COND(!fd);
2307
2308 MutexLock lock(fd->mutex);
2309 fd->subpixel_positioning = p_subpixel;
2310}
2311
2312TextServer::SubpixelPositioning TextServerAdvanced::_font_get_subpixel_positioning(const RID &p_font_rid) const {
2313 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2314 ERR_FAIL_COND_V(!fd, SUBPIXEL_POSITIONING_DISABLED);
2315
2316 MutexLock lock(fd->mutex);
2317 return fd->subpixel_positioning;
2318}
2319
2320void TextServerAdvanced::_font_set_embolden(const RID &p_font_rid, double p_strength) {
2321 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2322 ERR_FAIL_COND(!fd);
2323
2324 MutexLock lock(fd->mutex);
2325 if (fd->embolden != p_strength) {
2326 _font_clear_cache(fd);
2327 fd->embolden = p_strength;
2328 }
2329}
2330
2331double TextServerAdvanced::_font_get_embolden(const RID &p_font_rid) const {
2332 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2333 ERR_FAIL_COND_V(!fd, 0.0);
2334
2335 MutexLock lock(fd->mutex);
2336 return fd->embolden;
2337}
2338
2339void TextServerAdvanced::_font_set_spacing(const RID &p_font_rid, SpacingType p_spacing, int64_t p_value) {
2340 ERR_FAIL_INDEX((int)p_spacing, 4);
2341 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2342 ERR_FAIL_COND(!fd);
2343
2344 MutexLock lock(fd->mutex);
2345 if (fd->extra_spacing[p_spacing] != p_value) {
2346 _font_clear_cache(fd);
2347 fd->extra_spacing[p_spacing] = p_value;
2348 }
2349}
2350
2351int64_t TextServerAdvanced::_font_get_spacing(const RID &p_font_rid, SpacingType p_spacing) const {
2352 ERR_FAIL_INDEX_V((int)p_spacing, 4, 0);
2353
2354 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2355 ERR_FAIL_COND_V(!fd, 0);
2356
2357 MutexLock lock(fd->mutex);
2358
2359 return fd->extra_spacing[p_spacing];
2360}
2361
2362void TextServerAdvanced::_font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) {
2363 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2364 ERR_FAIL_COND(!fd);
2365
2366 MutexLock lock(fd->mutex);
2367 if (fd->transform != p_transform) {
2368 _font_clear_cache(fd);
2369 fd->transform = p_transform;
2370 }
2371}
2372
2373Transform2D TextServerAdvanced::_font_get_transform(const RID &p_font_rid) const {
2374 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2375 ERR_FAIL_COND_V(!fd, Transform2D());
2376
2377 MutexLock lock(fd->mutex);
2378 return fd->transform;
2379}
2380
2381void TextServerAdvanced::_font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) {
2382 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2383 ERR_FAIL_COND(!fd);
2384
2385 MutexLock lock(fd->mutex);
2386 if (!fd->variation_coordinates.recursive_equal(p_variation_coordinates, 1)) {
2387 _font_clear_cache(fd);
2388 fd->variation_coordinates = p_variation_coordinates.duplicate();
2389 }
2390}
2391
2392Dictionary TextServerAdvanced::_font_get_variation_coordinates(const RID &p_font_rid) const {
2393 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2394 ERR_FAIL_COND_V(!fd, Dictionary());
2395
2396 MutexLock lock(fd->mutex);
2397 return fd->variation_coordinates;
2398}
2399
2400void TextServerAdvanced::_font_set_oversampling(const RID &p_font_rid, double p_oversampling) {
2401 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2402 ERR_FAIL_COND(!fd);
2403
2404 MutexLock lock(fd->mutex);
2405 if (fd->oversampling != p_oversampling) {
2406 _font_clear_cache(fd);
2407 fd->oversampling = p_oversampling;
2408 }
2409}
2410
2411double TextServerAdvanced::_font_get_oversampling(const RID &p_font_rid) const {
2412 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2413 ERR_FAIL_COND_V(!fd, 0.0);
2414
2415 MutexLock lock(fd->mutex);
2416 return fd->oversampling;
2417}
2418
2419TypedArray<Vector2i> TextServerAdvanced::_font_get_size_cache_list(const RID &p_font_rid) const {
2420 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2421 ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>());
2422
2423 MutexLock lock(fd->mutex);
2424 TypedArray<Vector2i> ret;
2425 for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {
2426 ret.push_back(E.key);
2427 }
2428 return ret;
2429}
2430
2431void TextServerAdvanced::_font_clear_size_cache(const RID &p_font_rid) {
2432 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2433 ERR_FAIL_COND(!fd);
2434
2435 MutexLock lock(fd->mutex);
2436 MutexLock ftlock(ft_mutex);
2437 for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {
2438 memdelete(E.value);
2439 }
2440 fd->cache.clear();
2441}
2442
2443void TextServerAdvanced::_font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) {
2444 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2445 ERR_FAIL_COND(!fd);
2446
2447 MutexLock lock(fd->mutex);
2448 MutexLock ftlock(ft_mutex);
2449 if (fd->cache.has(p_size)) {
2450 memdelete(fd->cache[p_size]);
2451 fd->cache.erase(p_size);
2452 }
2453}
2454
2455void TextServerAdvanced::_font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) {
2456 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2457 ERR_FAIL_COND(!fd);
2458
2459 MutexLock lock(fd->mutex);
2460 Vector2i size = _get_size(fd, p_size);
2461
2462 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
2463 fd->cache[size]->ascent = p_ascent;
2464}
2465
2466double TextServerAdvanced::_font_get_ascent(const RID &p_font_rid, int64_t p_size) const {
2467 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2468 ERR_FAIL_COND_V(!fd, 0.0);
2469
2470 MutexLock lock(fd->mutex);
2471 Vector2i size = _get_size(fd, p_size);
2472
2473 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0);
2474
2475 if (fd->msdf) {
2476 return fd->cache[size]->ascent * (double)p_size / (double)fd->msdf_source_size;
2477 } else {
2478 return fd->cache[size]->ascent;
2479 }
2480}
2481
2482void TextServerAdvanced::_font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) {
2483 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2484 ERR_FAIL_COND(!fd);
2485
2486 Vector2i size = _get_size(fd, p_size);
2487
2488 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
2489 fd->cache[size]->descent = p_descent;
2490}
2491
2492double TextServerAdvanced::_font_get_descent(const RID &p_font_rid, int64_t p_size) const {
2493 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2494 ERR_FAIL_COND_V(!fd, 0.0);
2495
2496 MutexLock lock(fd->mutex);
2497 Vector2i size = _get_size(fd, p_size);
2498
2499 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0);
2500
2501 if (fd->msdf) {
2502 return fd->cache[size]->descent * (double)p_size / (double)fd->msdf_source_size;
2503 } else {
2504 return fd->cache[size]->descent;
2505 }
2506}
2507
2508void TextServerAdvanced::_font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) {
2509 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2510 ERR_FAIL_COND(!fd);
2511
2512 MutexLock lock(fd->mutex);
2513 Vector2i size = _get_size(fd, p_size);
2514
2515 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
2516 fd->cache[size]->underline_position = p_underline_position;
2517}
2518
2519double TextServerAdvanced::_font_get_underline_position(const RID &p_font_rid, int64_t p_size) const {
2520 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2521 ERR_FAIL_COND_V(!fd, 0.0);
2522
2523 MutexLock lock(fd->mutex);
2524 Vector2i size = _get_size(fd, p_size);
2525
2526 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0);
2527
2528 if (fd->msdf) {
2529 return fd->cache[size]->underline_position * (double)p_size / (double)fd->msdf_source_size;
2530 } else {
2531 return fd->cache[size]->underline_position;
2532 }
2533}
2534
2535void TextServerAdvanced::_font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) {
2536 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2537 ERR_FAIL_COND(!fd);
2538
2539 MutexLock lock(fd->mutex);
2540 Vector2i size = _get_size(fd, p_size);
2541
2542 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
2543 fd->cache[size]->underline_thickness = p_underline_thickness;
2544}
2545
2546double TextServerAdvanced::_font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const {
2547 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2548 ERR_FAIL_COND_V(!fd, 0.0);
2549
2550 MutexLock lock(fd->mutex);
2551 Vector2i size = _get_size(fd, p_size);
2552
2553 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0);
2554
2555 if (fd->msdf) {
2556 return fd->cache[size]->underline_thickness * (double)p_size / (double)fd->msdf_source_size;
2557 } else {
2558 return fd->cache[size]->underline_thickness;
2559 }
2560}
2561
2562void TextServerAdvanced::_font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) {
2563 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2564 ERR_FAIL_COND(!fd);
2565
2566 MutexLock lock(fd->mutex);
2567 Vector2i size = _get_size(fd, p_size);
2568
2569 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
2570#ifdef MODULE_FREETYPE_ENABLED
2571 if (fd->cache[size]->face) {
2572 return; // Do not override scale for dynamic fonts, it's calculated automatically.
2573 }
2574#endif
2575 fd->cache[size]->scale = p_scale;
2576}
2577
2578double TextServerAdvanced::_font_get_scale(const RID &p_font_rid, int64_t p_size) const {
2579 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2580 ERR_FAIL_COND_V(!fd, 0.0);
2581
2582 MutexLock lock(fd->mutex);
2583 Vector2i size = _get_size(fd, p_size);
2584
2585 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.0);
2586
2587 if (fd->msdf) {
2588 return fd->cache[size]->scale * (double)p_size / (double)fd->msdf_source_size;
2589 } else {
2590 return fd->cache[size]->scale / fd->cache[size]->oversampling;
2591 }
2592}
2593
2594int64_t TextServerAdvanced::_font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const {
2595 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2596 ERR_FAIL_COND_V(!fd, 0);
2597
2598 MutexLock lock(fd->mutex);
2599 Vector2i size = _get_size_outline(fd, p_size);
2600
2601 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0);
2602
2603 return fd->cache[size]->textures.size();
2604}
2605
2606void TextServerAdvanced::_font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) {
2607 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2608 ERR_FAIL_COND(!fd);
2609 MutexLock lock(fd->mutex);
2610 Vector2i size = _get_size_outline(fd, p_size);
2611
2612 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
2613 fd->cache[size]->textures.clear();
2614}
2615
2616void TextServerAdvanced::_font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) {
2617 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2618 ERR_FAIL_COND(!fd);
2619
2620 MutexLock lock(fd->mutex);
2621 Vector2i size = _get_size_outline(fd, p_size);
2622 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
2623 ERR_FAIL_INDEX(p_texture_index, fd->cache[size]->textures.size());
2624
2625 fd->cache[size]->textures.remove_at(p_texture_index);
2626}
2627
2628void TextServerAdvanced::_font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) {
2629 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2630 ERR_FAIL_COND(!fd);
2631 ERR_FAIL_COND(p_image.is_null());
2632
2633 MutexLock lock(fd->mutex);
2634 Vector2i size = _get_size_outline(fd, p_size);
2635 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
2636 ERR_FAIL_COND(p_texture_index < 0);
2637 if (p_texture_index >= fd->cache[size]->textures.size()) {
2638 fd->cache[size]->textures.resize(p_texture_index + 1);
2639 }
2640
2641 ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index];
2642
2643 tex.imgdata = p_image->get_data();
2644 tex.texture_w = p_image->get_width();
2645 tex.texture_h = p_image->get_height();
2646 tex.format = p_image->get_format();
2647
2648 Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
2649 if (fd->mipmaps) {
2650 img->generate_mipmaps();
2651 }
2652
2653 tex.texture = ImageTexture::create_from_image(img);
2654 tex.dirty = false;
2655}
2656
2657Ref<Image> TextServerAdvanced::_font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
2658 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2659 ERR_FAIL_COND_V(!fd, Ref<Image>());
2660
2661 MutexLock lock(fd->mutex);
2662 Vector2i size = _get_size_outline(fd, p_size);
2663 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Ref<Image>());
2664 ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>());
2665
2666 const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index];
2667 return Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
2668}
2669
2670void TextServerAdvanced::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offsets) {
2671 ERR_FAIL_COND(p_offsets.size() % 4 != 0);
2672 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2673 ERR_FAIL_COND(!fd);
2674
2675 MutexLock lock(fd->mutex);
2676 Vector2i size = _get_size_outline(fd, p_size);
2677 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
2678 ERR_FAIL_COND(p_texture_index < 0);
2679 if (p_texture_index >= fd->cache[size]->textures.size()) {
2680 fd->cache[size]->textures.resize(p_texture_index + 1);
2681 }
2682
2683 ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index];
2684 tex.shelves.clear();
2685 for (int32_t i = 0; i < p_offsets.size(); i += 4) {
2686 tex.shelves.push_back(Shelf(p_offsets[i], p_offsets[i + 1], p_offsets[i + 2], p_offsets[i + 3]));
2687 }
2688}
2689
2690PackedInt32Array TextServerAdvanced::_font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
2691 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2692 ERR_FAIL_COND_V(!fd, PackedInt32Array());
2693
2694 MutexLock lock(fd->mutex);
2695 Vector2i size = _get_size_outline(fd, p_size);
2696 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array());
2697 ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), PackedInt32Array());
2698
2699 const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index];
2700 PackedInt32Array ret;
2701 ret.resize(tex.shelves.size() * 4);
2702
2703 int32_t *wr = ret.ptrw();
2704 int32_t i = 0;
2705 for (const Shelf &E : tex.shelves) {
2706 wr[i * 4] = E.x;
2707 wr[i * 4 + 1] = E.y;
2708 wr[i * 4 + 2] = E.w;
2709 wr[i * 4 + 3] = E.h;
2710 i++;
2711 }
2712 return ret;
2713}
2714
2715PackedInt32Array TextServerAdvanced::_font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
2716 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2717 ERR_FAIL_COND_V(!fd, PackedInt32Array());
2718
2719 MutexLock lock(fd->mutex);
2720 Vector2i size = _get_size_outline(fd, p_size);
2721 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array());
2722
2723 PackedInt32Array ret;
2724 const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
2725 for (const KeyValue<int32_t, FontGlyph> &E : gl) {
2726 ret.push_back(E.key);
2727 }
2728 return ret;
2729}
2730
2731void TextServerAdvanced::_font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) {
2732 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2733 ERR_FAIL_COND(!fd);
2734
2735 MutexLock lock(fd->mutex);
2736 Vector2i size = _get_size_outline(fd, p_size);
2737 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
2738
2739 fd->cache[size]->glyph_map.clear();
2740}
2741
2742void TextServerAdvanced::_font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) {
2743 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2744 ERR_FAIL_COND(!fd);
2745
2746 MutexLock lock(fd->mutex);
2747 Vector2i size = _get_size_outline(fd, p_size);
2748 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
2749
2750 fd->cache[size]->glyph_map.erase(p_glyph);
2751}
2752
2753double TextServerAdvanced::_get_extra_advance(RID p_font_rid, int p_font_size) const {
2754 const FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2755 ERR_FAIL_COND_V(!fd, 0.0);
2756
2757 MutexLock lock(fd->mutex);
2758 Vector2i size = _get_size(fd, p_font_size);
2759
2760 if (fd->embolden != 0.0) {
2761 return fd->embolden * double(size.x) / 64.0;
2762 } else {
2763 return 0.0;
2764 }
2765}
2766
2767Vector2 TextServerAdvanced::_font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const {
2768 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2769 ERR_FAIL_COND_V(!fd, Vector2());
2770
2771 MutexLock lock(fd->mutex);
2772 Vector2i size = _get_size(fd, p_size);
2773
2774 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
2775
2776 int mod = 0;
2777 if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
2778 TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
2779 if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
2780 mod = (layout << 24);
2781 }
2782 }
2783
2784 if (!_ensure_glyph(fd, size, p_glyph | mod)) {
2785 return Vector2(); // Invalid or non graphicl glyph, do not display errors.
2786 }
2787
2788 const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
2789
2790 Vector2 ea;
2791 if (fd->embolden != 0.0) {
2792 ea.x = fd->embolden * double(size.x) / 64.0;
2793 }
2794
2795 double scale = _font_get_scale(p_font_rid, p_size);
2796 if (fd->msdf) {
2797 return (gl[p_glyph | mod].advance + ea) * (double)p_size / (double)fd->msdf_source_size;
2798 } 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))) {
2799 return (gl[p_glyph | mod].advance + ea).round();
2800 } else {
2801 return gl[p_glyph | mod].advance + ea;
2802 }
2803}
2804
2805void TextServerAdvanced::_font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) {
2806 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2807 ERR_FAIL_COND(!fd);
2808
2809 MutexLock lock(fd->mutex);
2810 Vector2i size = _get_size(fd, p_size);
2811
2812 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
2813
2814 HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
2815
2816 gl[p_glyph].advance = p_advance;
2817 gl[p_glyph].found = true;
2818}
2819
2820Vector2 TextServerAdvanced::_font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
2821 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2822 ERR_FAIL_COND_V(!fd, Vector2());
2823
2824 MutexLock lock(fd->mutex);
2825 Vector2i size = _get_size_outline(fd, p_size);
2826
2827 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
2828
2829 int mod = 0;
2830 if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
2831 TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
2832 if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
2833 mod = (layout << 24);
2834 }
2835 }
2836
2837 if (!_ensure_glyph(fd, size, p_glyph | mod)) {
2838 return Vector2(); // Invalid or non graphicl glyph, do not display errors.
2839 }
2840
2841 const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
2842
2843 if (fd->msdf) {
2844 return gl[p_glyph | mod].rect.position * (double)p_size.x / (double)fd->msdf_source_size;
2845 } else {
2846 return gl[p_glyph | mod].rect.position;
2847 }
2848}
2849
2850void TextServerAdvanced::_font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) {
2851 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2852 ERR_FAIL_COND(!fd);
2853
2854 MutexLock lock(fd->mutex);
2855 Vector2i size = _get_size_outline(fd, p_size);
2856
2857 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
2858
2859 HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
2860
2861 gl[p_glyph].rect.position = p_offset;
2862 gl[p_glyph].found = true;
2863}
2864
2865Vector2 TextServerAdvanced::_font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
2866 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2867 ERR_FAIL_COND_V(!fd, Vector2());
2868
2869 MutexLock lock(fd->mutex);
2870 Vector2i size = _get_size_outline(fd, p_size);
2871
2872 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
2873
2874 int mod = 0;
2875 if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
2876 TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
2877 if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
2878 mod = (layout << 24);
2879 }
2880 }
2881
2882 if (!_ensure_glyph(fd, size, p_glyph | mod)) {
2883 return Vector2(); // Invalid or non graphicl glyph, do not display errors.
2884 }
2885
2886 const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
2887
2888 if (fd->msdf) {
2889 return gl[p_glyph | mod].rect.size * (double)p_size.x / (double)fd->msdf_source_size;
2890 } else {
2891 return gl[p_glyph | mod].rect.size;
2892 }
2893}
2894
2895void TextServerAdvanced::_font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) {
2896 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2897 ERR_FAIL_COND(!fd);
2898
2899 MutexLock lock(fd->mutex);
2900 Vector2i size = _get_size_outline(fd, p_size);
2901
2902 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
2903
2904 HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
2905
2906 gl[p_glyph].rect.size = p_gl_size;
2907 gl[p_glyph].found = true;
2908}
2909
2910Rect2 TextServerAdvanced::_font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
2911 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2912 ERR_FAIL_COND_V(!fd, Rect2());
2913
2914 MutexLock lock(fd->mutex);
2915 Vector2i size = _get_size_outline(fd, p_size);
2916
2917 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Rect2());
2918
2919 int mod = 0;
2920 if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
2921 TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
2922 if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
2923 mod = (layout << 24);
2924 }
2925 }
2926
2927 if (!_ensure_glyph(fd, size, p_glyph | mod)) {
2928 return Rect2(); // Invalid or non graphicl glyph, do not display errors.
2929 }
2930
2931 const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
2932 return gl[p_glyph | mod].uv_rect;
2933}
2934
2935void TextServerAdvanced::_font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) {
2936 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2937 ERR_FAIL_COND(!fd);
2938
2939 MutexLock lock(fd->mutex);
2940 Vector2i size = _get_size_outline(fd, p_size);
2941
2942 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
2943
2944 HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
2945
2946 gl[p_glyph].uv_rect = p_uv_rect;
2947 gl[p_glyph].found = true;
2948}
2949
2950int64_t TextServerAdvanced::_font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
2951 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2952 ERR_FAIL_COND_V(!fd, -1);
2953
2954 MutexLock lock(fd->mutex);
2955 Vector2i size = _get_size_outline(fd, p_size);
2956
2957 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), -1);
2958
2959 int mod = 0;
2960 if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
2961 TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
2962 if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
2963 mod = (layout << 24);
2964 }
2965 }
2966
2967 if (!_ensure_glyph(fd, size, p_glyph | mod)) {
2968 return -1; // Invalid or non graphicl glyph, do not display errors.
2969 }
2970
2971 const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
2972 return gl[p_glyph | mod].texture_idx;
2973}
2974
2975void TextServerAdvanced::_font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) {
2976 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2977 ERR_FAIL_COND(!fd);
2978
2979 MutexLock lock(fd->mutex);
2980 Vector2i size = _get_size_outline(fd, p_size);
2981
2982 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
2983
2984 HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
2985
2986 gl[p_glyph].texture_idx = p_texture_idx;
2987 gl[p_glyph].found = true;
2988}
2989
2990RID TextServerAdvanced::_font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
2991 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
2992 ERR_FAIL_COND_V(!fd, RID());
2993
2994 MutexLock lock(fd->mutex);
2995 Vector2i size = _get_size_outline(fd, p_size);
2996
2997 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), RID());
2998
2999 int mod = 0;
3000 if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
3001 TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
3002 if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
3003 mod = (layout << 24);
3004 }
3005 }
3006
3007 if (!_ensure_glyph(fd, size, p_glyph | mod)) {
3008 return RID(); // Invalid or non graphicl glyph, do not display errors.
3009 }
3010
3011 const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
3012 ERR_FAIL_COND_V(gl[p_glyph | mod].texture_idx < -1 || gl[p_glyph | mod].texture_idx >= fd->cache[size]->textures.size(), RID());
3013
3014 if (RenderingServer::get_singleton() != nullptr) {
3015 if (gl[p_glyph | mod].texture_idx != -1) {
3016 if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
3017 ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
3018 Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
3019 if (fd->mipmaps) {
3020 img->generate_mipmaps();
3021 }
3022 if (tex.texture.is_null()) {
3023 tex.texture = ImageTexture::create_from_image(img);
3024 } else {
3025 tex.texture->update(img);
3026 }
3027 tex.dirty = false;
3028 }
3029 return fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].texture->get_rid();
3030 }
3031 }
3032
3033 return RID();
3034}
3035
3036Size2 TextServerAdvanced::_font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
3037 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3038 ERR_FAIL_COND_V(!fd, Size2());
3039
3040 MutexLock lock(fd->mutex);
3041 Vector2i size = _get_size_outline(fd, p_size);
3042
3043 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Size2());
3044
3045 int mod = 0;
3046 if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
3047 TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
3048 if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
3049 mod = (layout << 24);
3050 }
3051 }
3052
3053 if (!_ensure_glyph(fd, size, p_glyph | mod)) {
3054 return Size2(); // Invalid or non graphicl glyph, do not display errors.
3055 }
3056
3057 const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
3058 ERR_FAIL_COND_V(gl[p_glyph | mod].texture_idx < -1 || gl[p_glyph | mod].texture_idx >= fd->cache[size]->textures.size(), Size2());
3059
3060 if (RenderingServer::get_singleton() != nullptr) {
3061 if (gl[p_glyph | mod].texture_idx != -1) {
3062 if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
3063 ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
3064 Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
3065 if (fd->mipmaps) {
3066 img->generate_mipmaps();
3067 }
3068 if (tex.texture.is_null()) {
3069 tex.texture = ImageTexture::create_from_image(img);
3070 } else {
3071 tex.texture->update(img);
3072 }
3073 tex.dirty = false;
3074 }
3075 return fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].texture->get_size();
3076 }
3077 }
3078
3079 return Size2();
3080}
3081
3082Dictionary TextServerAdvanced::_font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const {
3083 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3084 ERR_FAIL_COND_V(!fd, Dictionary());
3085
3086 MutexLock lock(fd->mutex);
3087 Vector2i size = _get_size(fd, p_size);
3088
3089 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary());
3090
3091#ifdef MODULE_FREETYPE_ENABLED
3092 PackedVector3Array points;
3093 PackedInt32Array contours;
3094
3095 int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
3096
3097 int error = FT_Load_Glyph(fd->cache[size]->face, index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
3098 ERR_FAIL_COND_V(error, Dictionary());
3099
3100 if (fd->embolden != 0.f) {
3101 FT_Pos strength = fd->embolden * p_size * 4; // 26.6 fractional units (1 / 64).
3102 FT_Outline_Embolden(&fd->cache[size]->face->glyph->outline, strength);
3103 }
3104
3105 if (fd->transform != Transform2D()) {
3106 FT_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).
3107 FT_Outline_Transform(&fd->cache[size]->face->glyph->outline, &mat);
3108 }
3109
3110 double scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale;
3111 if (fd->msdf) {
3112 scale = scale * (double)p_size / (double)fd->msdf_source_size;
3113 }
3114 for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_points; i++) {
3115 points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, -fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i])));
3116 }
3117 for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_contours; i++) {
3118 contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]);
3119 }
3120 bool orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
3121
3122 Dictionary out;
3123 out["points"] = points;
3124 out["contours"] = contours;
3125 out["orientation"] = orientation;
3126 return out;
3127#else
3128 return Dictionary();
3129#endif
3130}
3131
3132TypedArray<Vector2i> TextServerAdvanced::_font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {
3133 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3134 ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>());
3135
3136 MutexLock lock(fd->mutex);
3137 Vector2i size = _get_size(fd, p_size);
3138
3139 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), TypedArray<Vector2i>());
3140
3141 TypedArray<Vector2i> ret;
3142 for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {
3143 ret.push_back(E.key);
3144 }
3145 return ret;
3146}
3147
3148void TextServerAdvanced::_font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) {
3149 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3150 ERR_FAIL_COND(!fd);
3151
3152 MutexLock lock(fd->mutex);
3153 Vector2i size = _get_size(fd, p_size);
3154
3155 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
3156 fd->cache[size]->kerning_map.clear();
3157}
3158
3159void TextServerAdvanced::_font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) {
3160 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3161 ERR_FAIL_COND(!fd);
3162
3163 MutexLock lock(fd->mutex);
3164 Vector2i size = _get_size(fd, p_size);
3165
3166 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
3167 fd->cache[size]->kerning_map.erase(p_glyph_pair);
3168}
3169
3170void TextServerAdvanced::_font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
3171 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3172 ERR_FAIL_COND(!fd);
3173
3174 MutexLock lock(fd->mutex);
3175 Vector2i size = _get_size(fd, p_size);
3176
3177 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
3178 fd->cache[size]->kerning_map[p_glyph_pair] = p_kerning;
3179}
3180
3181Vector2 TextServerAdvanced::_font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const {
3182 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3183 ERR_FAIL_COND_V(!fd, Vector2());
3184
3185 MutexLock lock(fd->mutex);
3186 Vector2i size = _get_size(fd, p_size);
3187
3188 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
3189
3190 const HashMap<Vector2i, Vector2> &kern = fd->cache[size]->kerning_map;
3191
3192 if (kern.has(p_glyph_pair)) {
3193 if (fd->msdf) {
3194 return kern[p_glyph_pair] * (double)p_size / (double)fd->msdf_source_size;
3195 } else {
3196 return kern[p_glyph_pair];
3197 }
3198 } else {
3199#ifdef MODULE_FREETYPE_ENABLED
3200 if (fd->cache[size]->face) {
3201 FT_Vector delta;
3202 FT_Get_Kerning(fd->cache[size]->face, p_glyph_pair.x, p_glyph_pair.y, FT_KERNING_DEFAULT, &delta);
3203 if (fd->msdf) {
3204 return Vector2(delta.x, delta.y) * (double)p_size / (double)fd->msdf_source_size;
3205 } else {
3206 return Vector2(delta.x, delta.y);
3207 }
3208 }
3209#endif
3210 }
3211 return Vector2();
3212}
3213
3214int64_t TextServerAdvanced::_font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const {
3215 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3216 ERR_FAIL_COND_V(!fd, 0);
3217 ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), 0, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + ".");
3218 ERR_FAIL_COND_V_MSG((p_variation_selector >= 0xd800 && p_variation_selector <= 0xdfff) || (p_variation_selector > 0x10ffff), 0, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_variation_selector, 16) + ".");
3219
3220 MutexLock lock(fd->mutex);
3221 Vector2i size = _get_size(fd, p_size);
3222 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0);
3223
3224#ifdef MODULE_FREETYPE_ENABLED
3225 if (fd->cache[size]->face) {
3226 if (p_variation_selector) {
3227 return FT_Face_GetCharVariantIndex(fd->cache[size]->face, p_char, p_variation_selector);
3228 } else {
3229 return FT_Get_Char_Index(fd->cache[size]->face, p_char);
3230 }
3231 } else {
3232 return (int64_t)p_char;
3233 }
3234#else
3235 return (int64_t)p_char;
3236#endif
3237}
3238
3239int64_t TextServerAdvanced::_font_get_char_from_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_glyph_index) const {
3240 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3241 ERR_FAIL_COND_V(!fd, 0);
3242
3243 MutexLock lock(fd->mutex);
3244 Vector2i size = _get_size(fd, p_size);
3245 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0);
3246
3247#ifdef MODULE_FREETYPE_ENABLED
3248 if (fd->cache[size]->inv_glyph_map.is_empty()) {
3249 FT_Face face = fd->cache[size]->face;
3250 FT_UInt gindex;
3251 FT_ULong charcode = FT_Get_First_Char(face, &gindex);
3252 while (gindex != 0) {
3253 if (charcode != 0) {
3254 fd->cache[size]->inv_glyph_map[gindex] = charcode;
3255 }
3256 charcode = FT_Get_Next_Char(face, charcode, &gindex);
3257 }
3258 }
3259
3260 if (fd->cache[size]->inv_glyph_map.has(p_glyph_index)) {
3261 return fd->cache[size]->inv_glyph_map[p_glyph_index];
3262 } else {
3263 return 0;
3264 }
3265#else
3266 return p_glyph_index;
3267#endif
3268}
3269
3270bool TextServerAdvanced::_font_has_char(const RID &p_font_rid, int64_t p_char) const {
3271 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3272 ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), false, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + ".");
3273 if (!fd) {
3274 return false;
3275 }
3276
3277 MutexLock lock(fd->mutex);
3278 if (fd->cache.is_empty()) {
3279 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), false);
3280 }
3281 FontForSizeAdvanced *at_size = fd->cache.begin()->value;
3282
3283#ifdef MODULE_FREETYPE_ENABLED
3284 if (at_size && at_size->face) {
3285 return FT_Get_Char_Index(at_size->face, p_char) != 0;
3286 }
3287#endif
3288 return (at_size) ? at_size->glyph_map.has((int32_t)p_char) : false;
3289}
3290
3291String TextServerAdvanced::_font_get_supported_chars(const RID &p_font_rid) const {
3292 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3293 ERR_FAIL_COND_V(!fd, String());
3294
3295 MutexLock lock(fd->mutex);
3296 if (fd->cache.is_empty()) {
3297 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), String());
3298 }
3299 FontForSizeAdvanced *at_size = fd->cache.begin()->value;
3300
3301 String chars;
3302#ifdef MODULE_FREETYPE_ENABLED
3303 if (at_size && at_size->face) {
3304 FT_UInt gindex;
3305 FT_ULong charcode = FT_Get_First_Char(at_size->face, &gindex);
3306 while (gindex != 0) {
3307 if (charcode != 0) {
3308 chars = chars + String::chr(charcode);
3309 }
3310 charcode = FT_Get_Next_Char(at_size->face, charcode, &gindex);
3311 }
3312 return chars;
3313 }
3314#endif
3315 if (at_size) {
3316 const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map;
3317 for (const KeyValue<int32_t, FontGlyph> &E : gl) {
3318 chars = chars + String::chr(E.key);
3319 }
3320 }
3321 return chars;
3322}
3323
3324void TextServerAdvanced::_font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) {
3325 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3326 ERR_FAIL_COND(!fd);
3327 ERR_FAIL_COND_MSG((p_start >= 0xd800 && p_start <= 0xdfff) || (p_start > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_start, 16) + ".");
3328 ERR_FAIL_COND_MSG((p_end >= 0xd800 && p_end <= 0xdfff) || (p_end > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_end, 16) + ".");
3329
3330 MutexLock lock(fd->mutex);
3331 Vector2i size = _get_size_outline(fd, p_size);
3332 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
3333 for (int64_t i = p_start; i <= p_end; i++) {
3334#ifdef MODULE_FREETYPE_ENABLED
3335 int32_t idx = FT_Get_Char_Index(fd->cache[size]->face, i);
3336 if (fd->cache[size]->face) {
3337 if (fd->msdf) {
3338 _ensure_glyph(fd, size, (int32_t)idx);
3339 } else {
3340 for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {
3341 if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
3342 _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24));
3343 _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24));
3344 _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24));
3345 _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24));
3346 } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
3347 _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24));
3348 _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24));
3349 } else {
3350 _ensure_glyph(fd, size, (int32_t)idx | (aa << 24));
3351 }
3352 }
3353 }
3354 }
3355#endif
3356 }
3357}
3358
3359void TextServerAdvanced::_font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) {
3360 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3361 ERR_FAIL_COND(!fd);
3362
3363 MutexLock lock(fd->mutex);
3364 Vector2i size = _get_size_outline(fd, p_size);
3365 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
3366#ifdef MODULE_FREETYPE_ENABLED
3367 int32_t idx = p_index & 0xffffff; // Remove subpixel shifts.
3368 if (fd->cache[size]->face) {
3369 if (fd->msdf) {
3370 _ensure_glyph(fd, size, (int32_t)idx);
3371 } else {
3372 for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {
3373 if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
3374 _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24));
3375 _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24));
3376 _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24));
3377 _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24));
3378 } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
3379 _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24));
3380 _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24));
3381 } else {
3382 _ensure_glyph(fd, size, (int32_t)idx | (aa << 24));
3383 }
3384 }
3385 }
3386 }
3387#endif
3388}
3389
3390void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const {
3391 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3392 ERR_FAIL_COND(!fd);
3393
3394 MutexLock lock(fd->mutex);
3395 Vector2i size = _get_size(fd, p_size);
3396 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
3397
3398 int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
3399 bool lcd_aa = false;
3400
3401#ifdef MODULE_FREETYPE_ENABLED
3402 if (!fd->msdf && fd->cache[size]->face) {
3403 // LCD layout, bits 24, 25, 26
3404 if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
3405 TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
3406 if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
3407 lcd_aa = true;
3408 index = index | (layout << 24);
3409 }
3410 }
3411 // Subpixel X-shift, bits 27, 28
3412 if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
3413 int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));
3414 index = index | (xshift << 27);
3415 } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
3416 int xshift = (int)(Math::floor(2 * (p_pos.x + 0.25)) - 2 * Math::floor(p_pos.x + 0.25));
3417 index = index | (xshift << 27);
3418 }
3419 }
3420#endif
3421
3422 if (!_ensure_glyph(fd, size, index)) {
3423 return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.
3424 }
3425
3426 const FontGlyph &gl = fd->cache[size]->glyph_map[index];
3427 if (gl.found) {
3428 ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size());
3429
3430 if (gl.texture_idx != -1) {
3431 Color modulate = p_color;
3432#ifdef MODULE_FREETYPE_ENABLED
3433 if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
3434 modulate.r = modulate.g = modulate.b = 1.0;
3435 }
3436#endif
3437 if (RenderingServer::get_singleton() != nullptr) {
3438 if (fd->cache[size]->textures[gl.texture_idx].dirty) {
3439 ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
3440 Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
3441 if (fd->mipmaps) {
3442 img->generate_mipmaps();
3443 }
3444 if (tex.texture.is_null()) {
3445 tex.texture = ImageTexture::create_from_image(img);
3446 } else {
3447 tex.texture->update(img);
3448 }
3449 tex.dirty = false;
3450 }
3451 RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
3452 if (fd->msdf) {
3453 Point2 cpos = p_pos;
3454 cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size;
3455 Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size;
3456 RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size);
3457 } else {
3458 double scale = _font_get_scale(p_font_rid, p_size);
3459 Point2 cpos = p_pos;
3460 if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
3461 cpos.x = cpos.x + 0.125;
3462 } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
3463 cpos.x = cpos.x + 0.25;
3464 }
3465 if (scale == 1.0) {
3466 cpos.y = Math::floor(cpos.y);
3467 cpos.x = Math::floor(cpos.x);
3468 }
3469 cpos += gl.rect.position;
3470 Size2 csize = gl.rect.size;
3471 if (lcd_aa) {
3472 RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate);
3473 } else {
3474 RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
3475 }
3476 }
3477 }
3478 }
3479 }
3480}
3481
3482void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const {
3483 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3484 ERR_FAIL_COND(!fd);
3485
3486 MutexLock lock(fd->mutex);
3487 Vector2i size = _get_size_outline(fd, Vector2i(p_size, p_outline_size));
3488 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
3489
3490 int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
3491 bool lcd_aa = false;
3492
3493#ifdef MODULE_FREETYPE_ENABLED
3494 if (!fd->msdf && fd->cache[size]->face) {
3495 // LCD layout, bits 24, 25, 26
3496 if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
3497 TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
3498 if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
3499 lcd_aa = true;
3500 index = index | (layout << 24);
3501 }
3502 }
3503 // Subpixel X-shift, bits 27, 28
3504 if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
3505 int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));
3506 index = index | (xshift << 27);
3507 } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
3508 int xshift = (int)(Math::floor(2 * (p_pos.x + 0.25)) - 2 * Math::floor(p_pos.x + 0.25));
3509 index = index | (xshift << 27);
3510 }
3511 }
3512#endif
3513
3514 if (!_ensure_glyph(fd, size, index)) {
3515 return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.
3516 }
3517
3518 const FontGlyph &gl = fd->cache[size]->glyph_map[index];
3519 if (gl.found) {
3520 ERR_FAIL_COND(gl.texture_idx < -1 || gl.texture_idx >= fd->cache[size]->textures.size());
3521
3522 if (gl.texture_idx != -1) {
3523 Color modulate = p_color;
3524#ifdef MODULE_FREETYPE_ENABLED
3525 if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa && !fd->msdf) {
3526 modulate.r = modulate.g = modulate.b = 1.0;
3527 }
3528#endif
3529 if (RenderingServer::get_singleton() != nullptr) {
3530 if (fd->cache[size]->textures[gl.texture_idx].dirty) {
3531 ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
3532 Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
3533 if (fd->mipmaps) {
3534 img->generate_mipmaps();
3535 }
3536 if (tex.texture.is_null()) {
3537 tex.texture = ImageTexture::create_from_image(img);
3538 } else {
3539 tex.texture->update(img);
3540 }
3541 tex.dirty = false;
3542 }
3543 RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
3544 if (fd->msdf) {
3545 Point2 cpos = p_pos;
3546 cpos += gl.rect.position * (double)p_size / (double)fd->msdf_source_size;
3547 Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size;
3548 RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size, fd->msdf_range, (double)p_size / (double)fd->msdf_source_size);
3549 } else {
3550 Point2 cpos = p_pos;
3551 double scale = _font_get_scale(p_font_rid, p_size);
3552 if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
3553 cpos.x = cpos.x + 0.125;
3554 } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
3555 cpos.x = cpos.x + 0.25;
3556 }
3557 if (scale == 1.0) {
3558 cpos.y = Math::floor(cpos.y);
3559 cpos.x = Math::floor(cpos.x);
3560 }
3561 cpos += gl.rect.position;
3562 Size2 csize = gl.rect.size;
3563 if (lcd_aa) {
3564 RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate);
3565 } else {
3566 RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
3567 }
3568 }
3569 }
3570 }
3571 }
3572}
3573
3574bool TextServerAdvanced::_font_is_language_supported(const RID &p_font_rid, const String &p_language) const {
3575 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3576 ERR_FAIL_COND_V(!fd, false);
3577
3578 MutexLock lock(fd->mutex);
3579 if (fd->language_support_overrides.has(p_language)) {
3580 return fd->language_support_overrides[p_language];
3581 } else {
3582 return true;
3583 }
3584}
3585
3586void TextServerAdvanced::_font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) {
3587 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3588 ERR_FAIL_COND(!fd);
3589
3590 MutexLock lock(fd->mutex);
3591 fd->language_support_overrides[p_language] = p_supported;
3592}
3593
3594bool TextServerAdvanced::_font_get_language_support_override(const RID &p_font_rid, const String &p_language) {
3595 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3596 ERR_FAIL_COND_V(!fd, false);
3597
3598 MutexLock lock(fd->mutex);
3599 return fd->language_support_overrides[p_language];
3600}
3601
3602void TextServerAdvanced::_font_remove_language_support_override(const RID &p_font_rid, const String &p_language) {
3603 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3604 ERR_FAIL_COND(!fd);
3605
3606 MutexLock lock(fd->mutex);
3607 fd->language_support_overrides.erase(p_language);
3608}
3609
3610PackedStringArray TextServerAdvanced::_font_get_language_support_overrides(const RID &p_font_rid) {
3611 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3612 ERR_FAIL_COND_V(!fd, PackedStringArray());
3613
3614 MutexLock lock(fd->mutex);
3615 PackedStringArray out;
3616 for (const KeyValue<String, bool> &E : fd->language_support_overrides) {
3617 out.push_back(E.key);
3618 }
3619 return out;
3620}
3621
3622bool TextServerAdvanced::_font_is_script_supported(const RID &p_font_rid, const String &p_script) const {
3623 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3624 ERR_FAIL_COND_V(!fd, false);
3625
3626 MutexLock lock(fd->mutex);
3627 if (fd->script_support_overrides.has(p_script)) {
3628 return fd->script_support_overrides[p_script];
3629 } else {
3630 Vector2i size = _get_size(fd, 16);
3631 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), false);
3632 return fd->supported_scripts.has(hb_tag_from_string(p_script.ascii().get_data(), -1));
3633 }
3634}
3635
3636void TextServerAdvanced::_font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) {
3637 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3638 ERR_FAIL_COND(!fd);
3639
3640 MutexLock lock(fd->mutex);
3641 fd->script_support_overrides[p_script] = p_supported;
3642}
3643
3644bool TextServerAdvanced::_font_get_script_support_override(const RID &p_font_rid, const String &p_script) {
3645 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3646 ERR_FAIL_COND_V(!fd, false);
3647
3648 MutexLock lock(fd->mutex);
3649 return fd->script_support_overrides[p_script];
3650}
3651
3652void TextServerAdvanced::_font_remove_script_support_override(const RID &p_font_rid, const String &p_script) {
3653 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3654 ERR_FAIL_COND(!fd);
3655
3656 MutexLock lock(fd->mutex);
3657 fd->script_support_overrides.erase(p_script);
3658}
3659
3660PackedStringArray TextServerAdvanced::_font_get_script_support_overrides(const RID &p_font_rid) {
3661 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3662 ERR_FAIL_COND_V(!fd, PackedStringArray());
3663
3664 MutexLock lock(fd->mutex);
3665 PackedStringArray out;
3666 for (const KeyValue<String, bool> &E : fd->script_support_overrides) {
3667 out.push_back(E.key);
3668 }
3669 return out;
3670}
3671
3672void TextServerAdvanced::_font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) {
3673 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3674 ERR_FAIL_COND(!fd);
3675
3676 MutexLock lock(fd->mutex);
3677 Vector2i size = _get_size(fd, 16);
3678 ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
3679 fd->feature_overrides = p_overrides;
3680}
3681
3682Dictionary TextServerAdvanced::_font_get_opentype_feature_overrides(const RID &p_font_rid) const {
3683 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3684 ERR_FAIL_COND_V(!fd, Dictionary());
3685
3686 MutexLock lock(fd->mutex);
3687 return fd->feature_overrides;
3688}
3689
3690Dictionary TextServerAdvanced::_font_supported_feature_list(const RID &p_font_rid) const {
3691 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3692 ERR_FAIL_COND_V(!fd, Dictionary());
3693
3694 MutexLock lock(fd->mutex);
3695 Vector2i size = _get_size(fd, 16);
3696 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary());
3697 return fd->supported_features;
3698}
3699
3700Dictionary TextServerAdvanced::_font_supported_variation_list(const RID &p_font_rid) const {
3701 FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
3702 ERR_FAIL_COND_V(!fd, Dictionary());
3703
3704 MutexLock lock(fd->mutex);
3705 Vector2i size = _get_size(fd, 16);
3706 ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary());
3707 return fd->supported_varaitions;
3708}
3709
3710double TextServerAdvanced::_font_get_global_oversampling() const {
3711 return oversampling;
3712}
3713
3714void TextServerAdvanced::_font_set_global_oversampling(double p_oversampling) {
3715 _THREAD_SAFE_METHOD_
3716 if (oversampling != p_oversampling) {
3717 oversampling = p_oversampling;
3718 List<RID> fonts;
3719 font_owner.get_owned_list(&fonts);
3720 bool font_cleared = false;
3721 for (const RID &E : fonts) {
3722 if (!_font_is_multichannel_signed_distance_field(E) && _font_get_oversampling(E) <= 0) {
3723 _font_clear_size_cache(E);
3724 font_cleared = true;
3725 }
3726 }
3727
3728 if (font_cleared) {
3729 List<RID> text_bufs;
3730 shaped_owner.get_owned_list(&text_bufs);
3731 for (const RID &E : text_bufs) {
3732 invalidate(shaped_owner.get_or_null(E), false);
3733 }
3734 }
3735 }
3736}
3737
3738/*************************************************************************/
3739/* Shaped text buffer interface */
3740/*************************************************************************/
3741
3742int64_t TextServerAdvanced::_convert_pos(const String &p_utf32, const Char16String &p_utf16, int64_t p_pos) const {
3743 int64_t limit = p_pos;
3744 if (p_utf32.length() != p_utf16.length()) {
3745 const UChar *data = p_utf16.get_data();
3746 for (int i = 0; i < p_pos; i++) {
3747 if (U16_IS_LEAD(data[i])) {
3748 limit--;
3749 }
3750 }
3751 }
3752 return limit;
3753}
3754
3755int64_t TextServerAdvanced::_convert_pos(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const {
3756 int64_t limit = p_pos;
3757 if (p_sd->text.length() != p_sd->utf16.length()) {
3758 const UChar *data = p_sd->utf16.get_data();
3759 for (int i = 0; i < p_pos; i++) {
3760 if (U16_IS_LEAD(data[i])) {
3761 limit--;
3762 }
3763 }
3764 }
3765 return limit;
3766}
3767
3768int64_t TextServerAdvanced::_convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const {
3769 int64_t limit = p_pos;
3770 if (p_sd->text.length() != p_sd->utf16.length()) {
3771 for (int i = 0; i < p_pos; i++) {
3772 if (p_sd->text[i] > 0xffff) {
3773 limit++;
3774 }
3775 }
3776 }
3777 return limit;
3778}
3779
3780void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *p_shaped, bool p_text) {
3781 p_shaped->valid = false;
3782 p_shaped->sort_valid = false;
3783 p_shaped->line_breaks_valid = false;
3784 p_shaped->justification_ops_valid = false;
3785 p_shaped->text_trimmed = false;
3786 p_shaped->ascent = 0.0;
3787 p_shaped->descent = 0.0;
3788 p_shaped->width = 0.0;
3789 p_shaped->upos = 0.0;
3790 p_shaped->uthk = 0.0;
3791 p_shaped->glyphs.clear();
3792 p_shaped->glyphs_logical.clear();
3793 p_shaped->overrun_trim_data = TrimData();
3794 p_shaped->utf16 = Char16String();
3795 for (int i = 0; i < p_shaped->bidi_iter.size(); i++) {
3796 ubidi_close(p_shaped->bidi_iter[i]);
3797 }
3798 p_shaped->bidi_iter.clear();
3799
3800 if (p_text) {
3801 if (p_shaped->script_iter != nullptr) {
3802 memdelete(p_shaped->script_iter);
3803 p_shaped->script_iter = nullptr;
3804 }
3805 p_shaped->break_ops_valid = false;
3806 p_shaped->chars_valid = false;
3807 p_shaped->js_ops_valid = false;
3808 }
3809}
3810
3811void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) {
3812 ShapedTextDataAdvanced *parent = shaped_owner.get_or_null(p_shaped->parent);
3813
3814 for (const KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : parent->objects) {
3815 if (E.value.pos >= p_shaped->start && E.value.pos < p_shaped->end) {
3816 p_shaped->objects[E.key] = E.value;
3817 }
3818 }
3819
3820 for (int i = 0; i < parent->spans.size(); i++) {
3821 ShapedTextDataAdvanced::Span span = parent->spans[i];
3822 if (span.start >= p_shaped->end || span.end <= p_shaped->start) {
3823 continue;
3824 }
3825 span.start = MAX(p_shaped->start, span.start);
3826 span.end = MIN(p_shaped->end, span.end);
3827 p_shaped->spans.push_back(span);
3828 }
3829
3830 p_shaped->parent = RID();
3831}
3832
3833RID TextServerAdvanced::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
3834 _THREAD_SAFE_METHOD_
3835 ERR_FAIL_COND_V_MSG(p_direction == DIRECTION_INHERITED, RID(), "Invalid text direction.");
3836
3837 ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced);
3838 sd->hb_buffer = hb_buffer_create();
3839 sd->direction = p_direction;
3840 sd->orientation = p_orientation;
3841 return shaped_owner.make_rid(sd);
3842}
3843
3844void TextServerAdvanced::_shaped_text_clear(const RID &p_shaped) {
3845 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
3846 ERR_FAIL_COND(!sd);
3847
3848 MutexLock lock(sd->mutex);
3849 sd->parent = RID();
3850 sd->start = 0;
3851 sd->end = 0;
3852 sd->text = String();
3853 sd->spans.clear();
3854 sd->objects.clear();
3855 sd->bidi_override.clear();
3856 invalidate(sd, true);
3857}
3858
3859void TextServerAdvanced::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {
3860 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
3861 ERR_FAIL_COND_MSG(p_direction == DIRECTION_INHERITED, "Invalid text direction.");
3862 ERR_FAIL_COND(!sd);
3863
3864 MutexLock lock(sd->mutex);
3865 if (sd->direction != p_direction) {
3866 if (sd->parent != RID()) {
3867 full_copy(sd);
3868 }
3869 sd->direction = p_direction;
3870 invalidate(sd, false);
3871 }
3872}
3873
3874TextServer::Direction TextServerAdvanced::_shaped_text_get_direction(const RID &p_shaped) const {
3875 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
3876 ERR_FAIL_COND_V(!sd, TextServer::DIRECTION_LTR);
3877
3878 MutexLock lock(sd->mutex);
3879 return sd->direction;
3880}
3881
3882TextServer::Direction TextServerAdvanced::_shaped_text_get_inferred_direction(const RID &p_shaped) const {
3883 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
3884 ERR_FAIL_COND_V(!sd, TextServer::DIRECTION_LTR);
3885
3886 MutexLock lock(sd->mutex);
3887 return sd->para_direction;
3888}
3889
3890void TextServerAdvanced::_shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) {
3891 _THREAD_SAFE_METHOD_
3892 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
3893 ERR_FAIL_COND(!sd);
3894
3895 if (sd->custom_punct != p_punct) {
3896 if (sd->parent != RID()) {
3897 full_copy(sd);
3898 }
3899 sd->custom_punct = p_punct;
3900 invalidate(sd, false);
3901 }
3902}
3903
3904String TextServerAdvanced::_shaped_text_get_custom_punctuation(const RID &p_shaped) const {
3905 _THREAD_SAFE_METHOD_
3906 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
3907 ERR_FAIL_COND_V(!sd, String());
3908 return sd->custom_punct;
3909}
3910
3911void TextServerAdvanced::_shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) {
3912 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
3913 ERR_FAIL_COND(!sd);
3914
3915 MutexLock lock(sd->mutex);
3916 if (sd->parent != RID()) {
3917 full_copy(sd);
3918 }
3919 sd->bidi_override.clear();
3920 for (int i = 0; i < p_override.size(); i++) {
3921 if (p_override[i].get_type() == Variant::VECTOR3I) {
3922 const Vector3i &r = p_override[i];
3923 sd->bidi_override.push_back(r);
3924 } else if (p_override[i].get_type() == Variant::VECTOR2I) {
3925 const Vector2i &r = p_override[i];
3926 sd->bidi_override.push_back(Vector3i(r.x, r.y, DIRECTION_INHERITED));
3927 }
3928 }
3929 invalidate(sd, false);
3930}
3931
3932void TextServerAdvanced::_shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) {
3933 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
3934 ERR_FAIL_COND(!sd);
3935
3936 MutexLock lock(sd->mutex);
3937 if (sd->orientation != p_orientation) {
3938 if (sd->parent != RID()) {
3939 full_copy(sd);
3940 }
3941 sd->orientation = p_orientation;
3942 invalidate(sd, false);
3943 }
3944}
3945
3946void TextServerAdvanced::_shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) {
3947 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
3948 ERR_FAIL_COND(!sd);
3949
3950 MutexLock lock(sd->mutex);
3951 ERR_FAIL_COND(sd->parent != RID());
3952 if (sd->preserve_invalid != p_enabled) {
3953 sd->preserve_invalid = p_enabled;
3954 invalidate(sd, false);
3955 }
3956}
3957
3958bool TextServerAdvanced::_shaped_text_get_preserve_invalid(const RID &p_shaped) const {
3959 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
3960 ERR_FAIL_COND_V(!sd, false);
3961
3962 MutexLock lock(sd->mutex);
3963 return sd->preserve_invalid;
3964}
3965
3966void TextServerAdvanced::_shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) {
3967 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
3968 ERR_FAIL_COND(!sd);
3969
3970 MutexLock lock(sd->mutex);
3971 if (sd->preserve_control != p_enabled) {
3972 if (sd->parent != RID()) {
3973 full_copy(sd);
3974 }
3975 sd->preserve_control = p_enabled;
3976 invalidate(sd, false);
3977 }
3978}
3979
3980bool TextServerAdvanced::_shaped_text_get_preserve_control(const RID &p_shaped) const {
3981 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
3982 ERR_FAIL_COND_V(!sd, false);
3983
3984 MutexLock lock(sd->mutex);
3985 return sd->preserve_control;
3986}
3987
3988void TextServerAdvanced::_shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) {
3989 ERR_FAIL_INDEX((int)p_spacing, 4);
3990 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
3991 ERR_FAIL_COND(!sd);
3992
3993 MutexLock lock(sd->mutex);
3994 if (sd->extra_spacing[p_spacing] != p_value) {
3995 if (sd->parent != RID()) {
3996 full_copy(sd);
3997 }
3998 sd->extra_spacing[p_spacing] = p_value;
3999 invalidate(sd, false);
4000 }
4001}
4002
4003int64_t TextServerAdvanced::_shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const {
4004 ERR_FAIL_INDEX_V((int)p_spacing, 4, 0);
4005
4006 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4007 ERR_FAIL_COND_V(!sd, 0);
4008
4009 MutexLock lock(sd->mutex);
4010 return sd->extra_spacing[p_spacing];
4011}
4012
4013TextServer::Orientation TextServerAdvanced::_shaped_text_get_orientation(const RID &p_shaped) const {
4014 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4015 ERR_FAIL_COND_V(!sd, TextServer::ORIENTATION_HORIZONTAL);
4016
4017 MutexLock lock(sd->mutex);
4018 return sd->orientation;
4019}
4020
4021int64_t TextServerAdvanced::_shaped_get_span_count(const RID &p_shaped) const {
4022 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4023 ERR_FAIL_COND_V(!sd, 0);
4024 return sd->spans.size();
4025}
4026
4027Variant TextServerAdvanced::_shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const {
4028 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4029 ERR_FAIL_COND_V(!sd, Variant());
4030 ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant());
4031 return sd->spans[p_index].meta;
4032}
4033
4034void TextServerAdvanced::_shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) {
4035 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4036 ERR_FAIL_COND(!sd);
4037 ERR_FAIL_INDEX(p_index, sd->spans.size());
4038
4039 ShapedTextDataAdvanced::Span &span = sd->spans.ptrw()[p_index];
4040 span.fonts = p_fonts;
4041 span.font_size = p_size;
4042 span.features = p_opentype_features;
4043
4044 invalidate(sd, false);
4045}
4046
4047bool TextServerAdvanced::_shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
4048 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4049 ERR_FAIL_COND_V(!sd, false);
4050 ERR_FAIL_COND_V(p_size <= 0, false);
4051
4052 MutexLock lock(sd->mutex);
4053 for (int i = 0; i < p_fonts.size(); i++) {
4054 ERR_FAIL_COND_V(!font_owner.get_or_null(p_fonts[i]), false);
4055 }
4056
4057 if (p_text.is_empty()) {
4058 return true;
4059 }
4060
4061 if (sd->parent != RID()) {
4062 full_copy(sd);
4063 }
4064
4065 ShapedTextDataAdvanced::Span span;
4066 span.start = sd->text.length();
4067 span.end = span.start + p_text.length();
4068 span.fonts = p_fonts; // Do not pre-sort, spans will be divided to subruns later.
4069 span.font_size = p_size;
4070 span.language = p_language;
4071 span.features = p_opentype_features;
4072 span.meta = p_meta;
4073
4074 sd->spans.push_back(span);
4075 sd->text = sd->text + p_text;
4076 sd->end += p_text.length();
4077 invalidate(sd, true);
4078
4079 return true;
4080}
4081
4082bool TextServerAdvanced::_shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length, double p_baseline) {
4083 _THREAD_SAFE_METHOD_
4084 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4085 ERR_FAIL_COND_V(!sd, false);
4086 ERR_FAIL_COND_V(p_key == Variant(), false);
4087 ERR_FAIL_COND_V(sd->objects.has(p_key), false);
4088
4089 if (sd->parent != RID()) {
4090 full_copy(sd);
4091 }
4092
4093 ShapedTextDataAdvanced::Span span;
4094 span.start = sd->start + sd->text.length();
4095 span.end = span.start + p_length;
4096 span.embedded_key = p_key;
4097
4098 ShapedTextDataAdvanced::EmbeddedObject obj;
4099 obj.inline_align = p_inline_align;
4100 obj.rect.size = p_size;
4101 obj.pos = span.start;
4102 obj.baseline = p_baseline;
4103
4104 sd->spans.push_back(span);
4105 sd->text = sd->text + String::chr(0xfffc).repeat(p_length);
4106 sd->end += p_length;
4107 sd->objects[p_key] = obj;
4108 invalidate(sd, true);
4109
4110 return true;
4111}
4112
4113bool TextServerAdvanced::_shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, double p_baseline) {
4114 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4115 ERR_FAIL_COND_V(!sd, false);
4116
4117 MutexLock lock(sd->mutex);
4118 ERR_FAIL_COND_V(!sd->objects.has(p_key), false);
4119 sd->objects[p_key].rect.size = p_size;
4120 sd->objects[p_key].inline_align = p_inline_align;
4121 sd->objects[p_key].baseline = p_baseline;
4122 if (sd->valid) {
4123 // Recalc string metrics.
4124 sd->ascent = 0;
4125 sd->descent = 0;
4126 sd->width = 0;
4127 sd->upos = 0;
4128 sd->uthk = 0;
4129 int sd_size = sd->glyphs.size();
4130
4131 for (int i = 0; i < sd_size; i++) {
4132 Glyph gl = sd->glyphs[i];
4133 Variant key;
4134 if (gl.count == 1) {
4135 for (const KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : sd->objects) {
4136 if (E.value.pos == gl.start) {
4137 key = E.key;
4138 break;
4139 }
4140 }
4141 }
4142 if (key != Variant()) {
4143 if (sd->orientation == ORIENTATION_HORIZONTAL) {
4144 sd->objects[key].rect.position.x = sd->width;
4145 sd->width += sd->objects[key].rect.size.x;
4146 sd->glyphs.write[i].advance = sd->objects[key].rect.size.x;
4147 } else {
4148 sd->objects[key].rect.position.y = sd->width;
4149 sd->width += sd->objects[key].rect.size.y;
4150 sd->glyphs.write[i].advance = sd->objects[key].rect.size.y;
4151 }
4152 } else {
4153 if (gl.font_rid.is_valid()) {
4154 if (sd->orientation == ORIENTATION_HORIZONTAL) {
4155 sd->ascent = MAX(sd->ascent, MAX(_font_get_ascent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_TOP), -gl.y_off));
4156 sd->descent = MAX(sd->descent, MAX(_font_get_descent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_BOTTOM), gl.y_off));
4157 } else {
4158 sd->ascent = MAX(sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
4159 sd->descent = MAX(sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
4160 }
4161 sd->upos = MAX(sd->upos, _font_get_underline_position(gl.font_rid, gl.font_size));
4162 sd->uthk = MAX(sd->uthk, _font_get_underline_thickness(gl.font_rid, gl.font_size));
4163 } else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) {
4164 // Glyph not found, replace with hex code box.
4165 if (sd->orientation == ORIENTATION_HORIZONTAL) {
4166 sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
4167 } else {
4168 sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
4169 sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
4170 }
4171 }
4172 sd->width += gl.advance * gl.repeat;
4173 }
4174 }
4175 _realign(sd);
4176 }
4177 return true;
4178}
4179
4180void TextServerAdvanced::_realign(ShapedTextDataAdvanced *p_sd) const {
4181 // Align embedded objects to baseline.
4182 double full_ascent = p_sd->ascent;
4183 double full_descent = p_sd->descent;
4184 for (KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : p_sd->objects) {
4185 if ((E.value.pos >= p_sd->start) && (E.value.pos < p_sd->end)) {
4186 if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
4187 switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {
4188 case INLINE_ALIGNMENT_TO_TOP: {
4189 E.value.rect.position.y = -p_sd->ascent;
4190 } break;
4191 case INLINE_ALIGNMENT_TO_CENTER: {
4192 E.value.rect.position.y = (-p_sd->ascent + p_sd->descent) / 2;
4193 } break;
4194 case INLINE_ALIGNMENT_TO_BASELINE: {
4195 E.value.rect.position.y = 0;
4196 } break;
4197 case INLINE_ALIGNMENT_TO_BOTTOM: {
4198 E.value.rect.position.y = p_sd->descent;
4199 } break;
4200 }
4201 switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {
4202 case INLINE_ALIGNMENT_BOTTOM_TO: {
4203 E.value.rect.position.y -= E.value.rect.size.y;
4204 } break;
4205 case INLINE_ALIGNMENT_CENTER_TO: {
4206 E.value.rect.position.y -= E.value.rect.size.y / 2;
4207 } break;
4208 case INLINE_ALIGNMENT_BASELINE_TO: {
4209 E.value.rect.position.y -= E.value.baseline;
4210 } break;
4211 case INLINE_ALIGNMENT_TOP_TO: {
4212 // NOP
4213 } break;
4214 }
4215 full_ascent = MAX(full_ascent, -E.value.rect.position.y);
4216 full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y);
4217 } else {
4218 switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {
4219 case INLINE_ALIGNMENT_TO_TOP: {
4220 E.value.rect.position.x = -p_sd->ascent;
4221 } break;
4222 case INLINE_ALIGNMENT_TO_CENTER: {
4223 E.value.rect.position.x = (-p_sd->ascent + p_sd->descent) / 2;
4224 } break;
4225 case INLINE_ALIGNMENT_TO_BASELINE: {
4226 E.value.rect.position.x = 0;
4227 } break;
4228 case INLINE_ALIGNMENT_TO_BOTTOM: {
4229 E.value.rect.position.x = p_sd->descent;
4230 } break;
4231 }
4232 switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {
4233 case INLINE_ALIGNMENT_BOTTOM_TO: {
4234 E.value.rect.position.x -= E.value.rect.size.x;
4235 } break;
4236 case INLINE_ALIGNMENT_CENTER_TO: {
4237 E.value.rect.position.x -= E.value.rect.size.x / 2;
4238 } break;
4239 case INLINE_ALIGNMENT_BASELINE_TO: {
4240 E.value.rect.position.x -= E.value.baseline;
4241 } break;
4242 case INLINE_ALIGNMENT_TOP_TO: {
4243 // NOP
4244 } break;
4245 }
4246 full_ascent = MAX(full_ascent, -E.value.rect.position.x);
4247 full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x);
4248 }
4249 }
4250 }
4251 p_sd->ascent = full_ascent;
4252 p_sd->descent = full_descent;
4253}
4254
4255RID TextServerAdvanced::_shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {
4256 _THREAD_SAFE_METHOD_
4257 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4258 ERR_FAIL_COND_V(!sd, RID());
4259
4260 MutexLock lock(sd->mutex);
4261 if (sd->parent != RID()) {
4262 return _shaped_text_substr(sd->parent, p_start, p_length);
4263 }
4264 if (!sd->valid) {
4265 const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);
4266 }
4267 ERR_FAIL_COND_V(p_start < 0 || p_length < 0, RID());
4268 ERR_FAIL_COND_V(sd->start > p_start || sd->end < p_start, RID());
4269 ERR_FAIL_COND_V(sd->end < p_start + p_length, RID());
4270
4271 ShapedTextDataAdvanced *new_sd = memnew(ShapedTextDataAdvanced);
4272 new_sd->parent = p_shaped;
4273 new_sd->start = p_start;
4274 new_sd->end = p_start + p_length;
4275 new_sd->orientation = sd->orientation;
4276 new_sd->direction = sd->direction;
4277 new_sd->custom_punct = sd->custom_punct;
4278 new_sd->para_direction = sd->para_direction;
4279 new_sd->base_para_direction = sd->base_para_direction;
4280 for (int i = 0; i < TextServer::SPACING_MAX; i++) {
4281 new_sd->extra_spacing[i] = sd->extra_spacing[i];
4282 }
4283
4284 if (!_shape_substr(new_sd, sd, p_start, p_length)) {
4285 memdelete(new_sd);
4286 return RID();
4287 }
4288 return shaped_owner.make_rid(new_sd);
4289}
4290
4291bool TextServerAdvanced::_shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_length) const {
4292 if (p_new_sd->valid) {
4293 return true;
4294 }
4295
4296 p_new_sd->hb_buffer = hb_buffer_create();
4297
4298 p_new_sd->line_breaks_valid = p_sd->line_breaks_valid;
4299 p_new_sd->justification_ops_valid = p_sd->justification_ops_valid;
4300 p_new_sd->sort_valid = false;
4301 p_new_sd->upos = p_sd->upos;
4302 p_new_sd->uthk = p_sd->uthk;
4303
4304 if (p_length > 0) {
4305 p_new_sd->text = p_sd->text.substr(p_start - p_sd->start, p_length);
4306 p_new_sd->utf16 = p_new_sd->text.utf16();
4307 p_new_sd->script_iter = memnew(ScriptIterator(p_new_sd->text, 0, p_new_sd->text.length()));
4308
4309 int sd_size = p_sd->glyphs.size();
4310 const Glyph *sd_glyphs = p_sd->glyphs.ptr();
4311 for (int ov = 0; ov < p_sd->bidi_override.size(); ov++) {
4312 UErrorCode err = U_ZERO_ERROR;
4313
4314 if (p_sd->bidi_override[ov].x >= p_start + p_length || p_sd->bidi_override[ov].y <= p_start) {
4315 continue;
4316 }
4317 int ov_start = _convert_pos_inv(p_sd, p_sd->bidi_override[ov].x);
4318 int start = MAX(0, _convert_pos_inv(p_sd, p_start) - ov_start);
4319 int end = MIN(_convert_pos_inv(p_sd, p_start + p_length), _convert_pos_inv(p_sd, p_sd->bidi_override[ov].y)) - ov_start;
4320
4321 ERR_FAIL_COND_V_MSG((start < 0 || end - start > p_new_sd->utf16.length()), false, "Invalid BiDi override range.");
4322
4323 // Create temporary line bidi & shape.
4324 UBiDi *bidi_iter = nullptr;
4325 if (p_sd->bidi_iter[ov]) {
4326 bidi_iter = ubidi_openSized(end - start, 0, &err);
4327 if (U_SUCCESS(err)) {
4328 ubidi_setLine(p_sd->bidi_iter[ov], start, end, bidi_iter, &err);
4329 if (U_FAILURE(err)) {
4330 // Line BiDi failed (string contains incompatible control characters), try full paragraph BiDi instead.
4331 err = U_ZERO_ERROR;
4332 const UChar *data = p_sd->utf16.get_data();
4333 switch (static_cast<TextServer::Direction>(p_sd->bidi_override[ov].z)) {
4334 case DIRECTION_LTR: {
4335 ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err);
4336 } break;
4337 case DIRECTION_RTL: {
4338 ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err);
4339 } break;
4340 case DIRECTION_INHERITED: {
4341 ubidi_setPara(bidi_iter, data + start, end - start, p_sd->base_para_direction, nullptr, &err);
4342 } break;
4343 case DIRECTION_AUTO: {
4344 UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start);
4345 if (direction != UBIDI_NEUTRAL) {
4346 ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);
4347 } else {
4348 ubidi_setPara(bidi_iter, data + start, end - start, p_sd->base_para_direction, nullptr, &err);
4349 }
4350 } break;
4351 }
4352 if (U_FAILURE(err)) {
4353 ubidi_close(bidi_iter);
4354 bidi_iter = nullptr;
4355 ERR_PRINT(vformat("BiDi reordering for the line failed: %s", u_errorName(err)));
4356 }
4357 }
4358 } else {
4359 bidi_iter = nullptr;
4360 ERR_PRINT(vformat("BiDi iterator allocation for the line failed: %s", u_errorName(err)));
4361 }
4362 }
4363 p_new_sd->bidi_iter.push_back(bidi_iter);
4364
4365 err = U_ZERO_ERROR;
4366 int bidi_run_count = 1;
4367 if (bidi_iter) {
4368 bidi_run_count = ubidi_countRuns(bidi_iter, &err);
4369 if (U_FAILURE(err)) {
4370 ERR_PRINT(u_errorName(err));
4371 }
4372 }
4373 for (int i = 0; i < bidi_run_count; i++) {
4374 int32_t _bidi_run_start = 0;
4375 int32_t _bidi_run_length = end - start;
4376 if (bidi_iter) {
4377 ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length);
4378 }
4379
4380 int32_t bidi_run_start = _convert_pos(p_sd, ov_start + start + _bidi_run_start);
4381 int32_t bidi_run_end = _convert_pos(p_sd, ov_start + start + _bidi_run_start + _bidi_run_length);
4382
4383 for (int j = 0; j < sd_size; j++) {
4384 if ((sd_glyphs[j].start >= bidi_run_start) && (sd_glyphs[j].end <= bidi_run_end)) {
4385 // Copy glyphs.
4386 Glyph gl = sd_glyphs[j];
4387 Variant key;
4388 bool find_embedded = false;
4389 if (gl.count == 1) {
4390 for (const KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : p_sd->objects) {
4391 if (E.value.pos == gl.start) {
4392 find_embedded = true;
4393 key = E.key;
4394 p_new_sd->objects[key] = E.value;
4395 break;
4396 }
4397 }
4398 }
4399 if (find_embedded) {
4400 if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {
4401 p_new_sd->objects[key].rect.position.x = p_new_sd->width;
4402 p_new_sd->width += p_new_sd->objects[key].rect.size.x;
4403 } else {
4404 p_new_sd->objects[key].rect.position.y = p_new_sd->width;
4405 p_new_sd->width += p_new_sd->objects[key].rect.size.y;
4406 }
4407 } else {
4408 if (gl.font_rid.is_valid()) {
4409 if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {
4410 p_new_sd->ascent = MAX(p_new_sd->ascent, MAX(_font_get_ascent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_TOP), -gl.y_off));
4411 p_new_sd->descent = MAX(p_new_sd->descent, MAX(_font_get_descent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_BOTTOM), gl.y_off));
4412 } else {
4413 p_new_sd->ascent = MAX(p_new_sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
4414 p_new_sd->descent = MAX(p_new_sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
4415 }
4416 } else if (p_new_sd->preserve_invalid || (p_new_sd->preserve_control && is_control(gl.index))) {
4417 // Glyph not found, replace with hex code box.
4418 if (p_new_sd->orientation == ORIENTATION_HORIZONTAL) {
4419 p_new_sd->ascent = MAX(p_new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
4420 } else {
4421 p_new_sd->ascent = MAX(p_new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
4422 p_new_sd->descent = MAX(p_new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
4423 }
4424 }
4425 p_new_sd->width += gl.advance * gl.repeat;
4426 }
4427 p_new_sd->glyphs.push_back(gl);
4428 }
4429 }
4430 }
4431 }
4432
4433 _realign(p_new_sd);
4434 }
4435 p_new_sd->valid = true;
4436
4437 return true;
4438}
4439
4440RID TextServerAdvanced::_shaped_text_get_parent(const RID &p_shaped) const {
4441 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4442 ERR_FAIL_COND_V(!sd, RID());
4443
4444 MutexLock lock(sd->mutex);
4445 return sd->parent;
4446}
4447
4448double TextServerAdvanced::_shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<TextServer::JustificationFlag> p_jst_flags) {
4449 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4450 ERR_FAIL_COND_V(!sd, 0.0);
4451
4452 MutexLock lock(sd->mutex);
4453 if (!sd->valid) {
4454 const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);
4455 }
4456 if (!sd->justification_ops_valid) {
4457 const_cast<TextServerAdvanced *>(this)->_shaped_text_update_justification_ops(p_shaped);
4458 }
4459
4460 sd->fit_width_minimum_reached = false;
4461 int start_pos = 0;
4462 int end_pos = sd->glyphs.size() - 1;
4463
4464 if (p_jst_flags.has_flag(JUSTIFICATION_AFTER_LAST_TAB)) {
4465 int start, end, delta;
4466 if (sd->para_direction == DIRECTION_LTR) {
4467 start = sd->glyphs.size() - 1;
4468 end = -1;
4469 delta = -1;
4470 } else {
4471 start = 0;
4472 end = sd->glyphs.size();
4473 delta = +1;
4474 }
4475
4476 for (int i = start; i != end; i += delta) {
4477 if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
4478 if (sd->para_direction == DIRECTION_LTR) {
4479 start_pos = i;
4480 break;
4481 } else {
4482 end_pos = i;
4483 break;
4484 }
4485 }
4486 }
4487 }
4488
4489 double justification_width;
4490 if (p_jst_flags.has_flag(JUSTIFICATION_CONSTRAIN_ELLIPSIS)) {
4491 if (sd->overrun_trim_data.trim_pos >= 0) {
4492 if (sd->para_direction == DIRECTION_RTL) {
4493 start_pos = sd->overrun_trim_data.trim_pos;
4494 } else {
4495 end_pos = sd->overrun_trim_data.trim_pos;
4496 }
4497 justification_width = sd->width_trimmed;
4498 } else {
4499 return Math::ceil(sd->width);
4500 }
4501 } else {
4502 justification_width = sd->width;
4503 }
4504
4505 if (p_jst_flags.has_flag(JUSTIFICATION_TRIM_EDGE_SPACES)) {
4506 // Trim spaces.
4507 while ((start_pos < end_pos) && ((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)) {
4508 justification_width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat;
4509 sd->glyphs.write[start_pos].advance = 0;
4510 start_pos += sd->glyphs[start_pos].count;
4511 }
4512 while ((start_pos < end_pos) && ((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)) {
4513 justification_width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat;
4514 sd->glyphs.write[end_pos].advance = 0;
4515 end_pos -= sd->glyphs[end_pos].count;
4516 }
4517 } else {
4518 // Skip breaks, but do not reset size.
4519 while ((start_pos < end_pos) && ((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)) {
4520 start_pos += sd->glyphs[start_pos].count;
4521 }
4522 while ((start_pos < end_pos) && ((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)) {
4523 end_pos -= sd->glyphs[end_pos].count;
4524 }
4525 }
4526
4527 int space_count = 0;
4528 int elongation_count = 0;
4529 for (int i = start_pos; i <= end_pos; i++) {
4530 const Glyph &gl = sd->glyphs[i];
4531 if (gl.count > 0) {
4532 if ((gl.flags & GRAPHEME_IS_ELONGATION) == GRAPHEME_IS_ELONGATION) {
4533 if ((i > 0) && ((sd->glyphs[i - 1].flags & GRAPHEME_IS_ELONGATION) != GRAPHEME_IS_ELONGATION)) {
4534 // Expand once per elongation sequence.
4535 elongation_count++;
4536 }
4537 }
4538 if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE && (gl.flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {
4539 space_count++;
4540 }
4541 }
4542 }
4543
4544 if ((elongation_count > 0) && p_jst_flags.has_flag(JUSTIFICATION_KASHIDA)) {
4545 double delta_width_per_kashida = (p_width - justification_width) / elongation_count;
4546 for (int i = start_pos; i <= end_pos; i++) {
4547 Glyph &gl = sd->glyphs.write[i];
4548 if (gl.count > 0) {
4549 if (((gl.flags & GRAPHEME_IS_ELONGATION) == GRAPHEME_IS_ELONGATION) && (gl.advance > 0)) {
4550 if ((i > 0) && ((sd->glyphs[i - 1].flags & GRAPHEME_IS_ELONGATION) != GRAPHEME_IS_ELONGATION)) {
4551 // Expand once per elongation sequence.
4552 int count = delta_width_per_kashida / gl.advance;
4553 int prev_count = gl.repeat;
4554 if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
4555 gl.repeat = CLAMP(count, 0, 255);
4556 } else {
4557 gl.repeat = CLAMP(count + 1, 1, 255);
4558 }
4559 justification_width += (gl.repeat - prev_count) * gl.advance;
4560 }
4561 }
4562 }
4563 }
4564 }
4565 if ((space_count > 0) && p_jst_flags.has_flag(JUSTIFICATION_WORD_BOUND)) {
4566 double delta_width_per_space = (p_width - justification_width) / space_count;
4567 double adv_remain = 0;
4568 for (int i = start_pos; i <= end_pos; i++) {
4569 Glyph &gl = sd->glyphs.write[i];
4570 if (gl.count > 0) {
4571 if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE && (gl.flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {
4572 double old_adv = gl.advance;
4573 double new_advance;
4574 if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
4575 new_advance = MAX(gl.advance + delta_width_per_space, 0.0);
4576 } else {
4577 new_advance = MAX(gl.advance + delta_width_per_space, 0.1 * gl.font_size);
4578 }
4579 gl.advance = new_advance;
4580 adv_remain += (new_advance - gl.advance);
4581 if (adv_remain >= 1.0) {
4582 gl.advance++;
4583 adv_remain -= 1.0;
4584 } else if (adv_remain <= -1.0) {
4585 gl.advance = MAX(gl.advance - 1, 0);
4586 adv_remain -= 1.0;
4587 }
4588 justification_width += (gl.advance - old_adv);
4589 }
4590 }
4591 }
4592 }
4593
4594 if (Math::floor(p_width) < Math::floor(justification_width)) {
4595 sd->fit_width_minimum_reached = true;
4596 }
4597
4598 if (!p_jst_flags.has_flag(JUSTIFICATION_CONSTRAIN_ELLIPSIS)) {
4599 sd->width = justification_width;
4600 }
4601
4602 return Math::ceil(justification_width);
4603}
4604
4605double TextServerAdvanced::_shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) {
4606 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4607 ERR_FAIL_COND_V(!sd, 0.0);
4608
4609 MutexLock lock(sd->mutex);
4610 if (!sd->valid) {
4611 const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);
4612 }
4613 if (!sd->line_breaks_valid) {
4614 const_cast<TextServerAdvanced *>(this)->_shaped_text_update_breaks(p_shaped);
4615 }
4616
4617 for (int i = 0; i < p_tab_stops.size(); i++) {
4618 if (p_tab_stops[i] <= 0) {
4619 return 0.0;
4620 }
4621 }
4622
4623 int tab_index = 0;
4624 double off = 0.0;
4625
4626 int start, end, delta;
4627 if (sd->para_direction == DIRECTION_LTR) {
4628 start = 0;
4629 end = sd->glyphs.size();
4630 delta = +1;
4631 } else {
4632 start = sd->glyphs.size() - 1;
4633 end = -1;
4634 delta = -1;
4635 }
4636
4637 Glyph *gl = sd->glyphs.ptrw();
4638
4639 for (int i = start; i != end; i += delta) {
4640 if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
4641 double tab_off = 0.0;
4642 while (tab_off <= off) {
4643 tab_off += p_tab_stops[tab_index];
4644 tab_index++;
4645 if (tab_index >= p_tab_stops.size()) {
4646 tab_index = 0;
4647 }
4648 }
4649 double old_adv = gl[i].advance;
4650 gl[i].advance = tab_off - off;
4651 sd->width += gl[i].advance - old_adv;
4652 off = 0;
4653 continue;
4654 }
4655 off += gl[i].advance * gl[i].repeat;
4656 }
4657
4658 return 0.0;
4659}
4660
4661void TextServerAdvanced::_shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) {
4662 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped_line);
4663 ERR_FAIL_COND_MSG(!sd, "ShapedTextDataAdvanced invalid.");
4664
4665 MutexLock lock(sd->mutex);
4666 if (!sd->valid) {
4667 _shaped_text_shape(p_shaped_line);
4668 }
4669
4670 sd->text_trimmed = false;
4671 sd->overrun_trim_data.ellipsis_glyph_buf.clear();
4672
4673 bool add_ellipsis = p_trim_flags.has_flag(OVERRUN_ADD_ELLIPSIS);
4674 bool cut_per_word = p_trim_flags.has_flag(OVERRUN_TRIM_WORD_ONLY);
4675 bool enforce_ellipsis = p_trim_flags.has_flag(OVERRUN_ENFORCE_ELLIPSIS);
4676 bool justification_aware = p_trim_flags.has_flag(OVERRUN_JUSTIFICATION_AWARE);
4677
4678 Glyph *sd_glyphs = sd->glyphs.ptrw();
4679
4680 if ((p_trim_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIM || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {
4681 sd->overrun_trim_data.trim_pos = -1;
4682 sd->overrun_trim_data.ellipsis_pos = -1;
4683 return;
4684 }
4685
4686 if (justification_aware && !sd->fit_width_minimum_reached) {
4687 return;
4688 }
4689
4690 Vector<ShapedTextDataAdvanced::Span> &spans = sd->spans;
4691 if (sd->parent != RID()) {
4692 ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);
4693 ERR_FAIL_COND(!parent_sd->valid);
4694 spans = parent_sd->spans;
4695 }
4696
4697 if (spans.size() == 0) {
4698 return;
4699 }
4700
4701 int sd_size = sd->glyphs.size();
4702 int last_gl_font_size = sd_glyphs[sd_size - 1].font_size;
4703
4704 // Find usable fonts, if fonts from the last glyph do not have required chars.
4705 RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;
4706 if (!_font_has_char(dot_gl_font_rid, '.')) {
4707 const Array &fonts = spans[spans.size() - 1].fonts;
4708 for (int i = 0; i < fonts.size(); i++) {
4709 if (_font_has_char(fonts[i], '.')) {
4710 dot_gl_font_rid = fonts[i];
4711 break;
4712 }
4713 }
4714 }
4715 RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;
4716 if (!_font_has_char(whitespace_gl_font_rid, '.')) {
4717 const Array &fonts = spans[spans.size() - 1].fonts;
4718 for (int i = 0; i < fonts.size(); i++) {
4719 if (_font_has_char(fonts[i], ' ')) {
4720 whitespace_gl_font_rid = fonts[i];
4721 break;
4722 }
4723 }
4724 }
4725
4726 int32_t dot_gl_idx = dot_gl_font_rid.is_valid() ? _font_get_glyph_index(dot_gl_font_rid, last_gl_font_size, '.', 0) : -10;
4727 Vector2 dot_adv = dot_gl_font_rid.is_valid() ? _font_get_glyph_advance(dot_gl_font_rid, last_gl_font_size, dot_gl_idx) : Vector2();
4728 int32_t whitespace_gl_idx = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_index(whitespace_gl_font_rid, last_gl_font_size, ' ', 0) : -10;
4729 Vector2 whitespace_adv = whitespace_gl_font_rid.is_valid() ? _font_get_glyph_advance(whitespace_gl_font_rid, last_gl_font_size, whitespace_gl_idx) : Vector2();
4730
4731 int ellipsis_width = 0;
4732 if (add_ellipsis && whitespace_gl_font_rid.is_valid()) {
4733 ellipsis_width = 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);
4734 }
4735
4736 int ell_min_characters = 6;
4737 double width = sd->width;
4738
4739 bool is_rtl = sd->para_direction == DIRECTION_RTL;
4740
4741 int trim_pos = (is_rtl) ? sd_size : 0;
4742 int ellipsis_pos = (enforce_ellipsis) ? 0 : -1;
4743
4744 int last_valid_cut = 0;
4745 bool found = false;
4746
4747 int glyphs_from = (is_rtl) ? 0 : sd_size - 1;
4748 int glyphs_to = (is_rtl) ? sd_size - 1 : -1;
4749 int glyphs_delta = (is_rtl) ? +1 : -1;
4750
4751 if (enforce_ellipsis && (width + ellipsis_width <= p_width)) {
4752 trim_pos = -1;
4753 ellipsis_pos = (is_rtl) ? 0 : sd_size;
4754 } else {
4755 for (int i = glyphs_from; i != glyphs_to; i += glyphs_delta) {
4756 if (!is_rtl) {
4757 width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
4758 }
4759 if (sd_glyphs[i].count > 0) {
4760 bool above_min_char_threshold = ((is_rtl) ? sd_size - 1 - i : i) >= ell_min_characters;
4761
4762 if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis) ? ellipsis_width : 0) <= p_width) {
4763 if (cut_per_word && above_min_char_threshold) {
4764 if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
4765 last_valid_cut = i;
4766 found = true;
4767 }
4768 } else {
4769 last_valid_cut = i;
4770 found = true;
4771 }
4772 if (found) {
4773 trim_pos = last_valid_cut;
4774
4775 if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis) && width - ellipsis_width <= p_width) {
4776 ellipsis_pos = trim_pos;
4777 }
4778 break;
4779 }
4780 }
4781 }
4782 if (is_rtl) {
4783 width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
4784 }
4785 }
4786 }
4787
4788 sd->overrun_trim_data.trim_pos = trim_pos;
4789 sd->overrun_trim_data.ellipsis_pos = ellipsis_pos;
4790 if (trim_pos == 0 && enforce_ellipsis && add_ellipsis) {
4791 sd->overrun_trim_data.ellipsis_pos = 0;
4792 }
4793
4794 if ((trim_pos >= 0 && sd->width > p_width) || enforce_ellipsis) {
4795 if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) {
4796 // Insert an additional space when cutting word bound for esthetics.
4797 if (cut_per_word && (ellipsis_pos > 0)) {
4798 Glyph gl;
4799 gl.count = 1;
4800 gl.advance = whitespace_adv.x;
4801 gl.index = whitespace_gl_idx;
4802 gl.font_rid = whitespace_gl_font_rid;
4803 gl.font_size = last_gl_font_size;
4804 gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);
4805
4806 sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
4807 }
4808 // Add ellipsis dots.
4809 if (dot_gl_idx != 0) {
4810 Glyph gl;
4811 gl.count = 1;
4812 gl.repeat = 3;
4813 gl.advance = dot_adv.x;
4814 gl.index = dot_gl_idx;
4815 gl.font_rid = dot_gl_font_rid;
4816 gl.font_size = last_gl_font_size;
4817 gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL | (is_rtl ? GRAPHEME_IS_RTL : 0);
4818
4819 sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
4820 }
4821 }
4822
4823 sd->text_trimmed = true;
4824 sd->width_trimmed = width + ((ellipsis_pos != -1) ? ellipsis_width : 0);
4825 }
4826}
4827
4828int64_t TextServerAdvanced::_shaped_text_get_trim_pos(const RID &p_shaped) const {
4829 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4830 ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid.");
4831
4832 MutexLock lock(sd->mutex);
4833 return sd->overrun_trim_data.trim_pos;
4834}
4835
4836int64_t TextServerAdvanced::_shaped_text_get_ellipsis_pos(const RID &p_shaped) const {
4837 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4838 ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid.");
4839
4840 MutexLock lock(sd->mutex);
4841 return sd->overrun_trim_data.ellipsis_pos;
4842}
4843
4844const Glyph *TextServerAdvanced::_shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const {
4845 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4846 ERR_FAIL_COND_V_MSG(!sd, nullptr, "ShapedTextDataAdvanced invalid.");
4847
4848 MutexLock lock(sd->mutex);
4849 return sd->overrun_trim_data.ellipsis_glyph_buf.ptr();
4850}
4851
4852int64_t TextServerAdvanced::_shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const {
4853 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4854 ERR_FAIL_COND_V_MSG(!sd, 0, "ShapedTextDataAdvanced invalid.");
4855
4856 MutexLock lock(sd->mutex);
4857 return sd->overrun_trim_data.ellipsis_glyph_buf.size();
4858}
4859
4860void TextServerAdvanced::_update_chars(ShapedTextDataAdvanced *p_sd) const {
4861 if (!p_sd->chars_valid) {
4862 p_sd->chars.clear();
4863
4864 const UChar *data = p_sd->utf16.get_data();
4865 UErrorCode err = U_ZERO_ERROR;
4866 int prev = -1;
4867 int i = 0;
4868
4869 Vector<ShapedTextDataAdvanced::Span> &spans = p_sd->spans;
4870 if (p_sd->parent != RID()) {
4871 ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(p_sd->parent);
4872 ERR_FAIL_COND(!parent_sd->valid);
4873 spans = parent_sd->spans;
4874 }
4875
4876 while (i < spans.size()) {
4877 if (spans[i].start > p_sd->end) {
4878 break;
4879 }
4880 if (spans[i].end < p_sd->start) {
4881 i++;
4882 continue;
4883 }
4884
4885 int r_start = MAX(0, spans[i].start - p_sd->start);
4886 String language = spans[i].language;
4887 while (i + 1 < spans.size() && language == spans[i + 1].language) {
4888 i++;
4889 }
4890 int r_end = MIN(spans[i].end - p_sd->start, p_sd->text.length());
4891 UBreakIterator *bi = ubrk_open(UBRK_CHARACTER, (language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale().ascii().get_data() : language.ascii().get_data(), data + _convert_pos_inv(p_sd, r_start), _convert_pos_inv(p_sd, r_end - r_start), &err);
4892 if (U_SUCCESS(err)) {
4893 while (ubrk_next(bi) != UBRK_DONE) {
4894 int pos = _convert_pos(p_sd, ubrk_current(bi)) + r_start + p_sd->start;
4895 if (prev != pos) {
4896 p_sd->chars.push_back(pos);
4897 }
4898 prev = pos;
4899 }
4900 ubrk_close(bi);
4901 } else {
4902 for (int j = r_start; j < r_end; j++) {
4903 if (prev != j) {
4904 p_sd->chars.push_back(j + 1 + p_sd->start);
4905 }
4906 prev = j;
4907 }
4908 }
4909 i++;
4910 }
4911 p_sd->chars_valid = true;
4912 }
4913}
4914
4915PackedInt32Array TextServerAdvanced::_shaped_text_get_character_breaks(const RID &p_shaped) const {
4916 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4917 ERR_FAIL_COND_V(!sd, PackedInt32Array());
4918
4919 MutexLock lock(sd->mutex);
4920 if (!sd->valid) {
4921 const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);
4922 }
4923
4924 _update_chars(sd);
4925
4926 return sd->chars;
4927}
4928
4929bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) {
4930 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
4931 ERR_FAIL_COND_V(!sd, false);
4932
4933 MutexLock lock(sd->mutex);
4934 if (!sd->valid) {
4935 _shaped_text_shape(p_shaped);
4936 }
4937
4938 if (sd->line_breaks_valid) {
4939 return true; // Nothing to do.
4940 }
4941
4942 const UChar *data = sd->utf16.get_data();
4943
4944 if (!sd->break_ops_valid) {
4945 sd->breaks.clear();
4946 sd->break_inserts = 0;
4947 UErrorCode err = U_ZERO_ERROR;
4948 int i = 0;
4949 while (i < sd->spans.size()) {
4950 String language = sd->spans[i].language;
4951 int r_start = sd->spans[i].start;
4952 while (i + 1 < sd->spans.size() && language == sd->spans[i + 1].language) {
4953 i++;
4954 }
4955 int r_end = sd->spans[i].end;
4956 UBreakIterator *bi = ubrk_open(UBRK_LINE, (language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale().ascii().get_data() : language.ascii().get_data(), data + _convert_pos_inv(sd, r_start), _convert_pos_inv(sd, r_end - r_start), &err);
4957 if (U_FAILURE(err)) {
4958 // No data loaded - use fallback.
4959 for (int j = r_start; j < r_end; j++) {
4960 char32_t c = sd->text[j - sd->start];
4961 if (is_whitespace(c)) {
4962 sd->breaks[j + 1] = false;
4963 }
4964 if (is_linebreak(c)) {
4965 sd->breaks[j + 1] = true;
4966 }
4967 }
4968 } else {
4969 while (ubrk_next(bi) != UBRK_DONE) {
4970 int pos = _convert_pos(sd, ubrk_current(bi)) + r_start;
4971 if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_HARD) && (ubrk_getRuleStatus(bi) < UBRK_LINE_HARD_LIMIT)) {
4972 sd->breaks[pos] = true;
4973 } else if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_SOFT) && (ubrk_getRuleStatus(bi) < UBRK_LINE_SOFT_LIMIT)) {
4974 sd->breaks[pos] = false;
4975 }
4976 int pos_p = pos - 1 - sd->start;
4977 char32_t c = sd->text[pos_p];
4978 if (pos - sd->start != sd->end && !is_whitespace(c) && (c != 0xfffc)) {
4979 sd->break_inserts++;
4980 }
4981 }
4982 }
4983 ubrk_close(bi);
4984 i++;
4985 }
4986 sd->break_ops_valid = true;
4987 }
4988
4989 Vector<Glyph> glyphs_new;
4990
4991 bool rewrite = false;
4992 int sd_shift = 0;
4993 int sd_size = sd->glyphs.size();
4994 Glyph *sd_glyphs = sd->glyphs.ptrw();
4995 Glyph *sd_glyphs_new = nullptr;
4996
4997 if (sd->break_inserts > 0) {
4998 glyphs_new.resize(sd->glyphs.size() + sd->break_inserts);
4999 sd_glyphs_new = glyphs_new.ptrw();
5000 rewrite = true;
5001 } else {
5002 sd_glyphs_new = sd_glyphs;
5003 }
5004
5005 sd->sort_valid = false;
5006 sd->glyphs_logical.clear();
5007 const char32_t *ch = sd->text.ptr();
5008
5009 int c_punct_size = sd->custom_punct.length();
5010 const char32_t *c_punct = sd->custom_punct.ptr();
5011
5012 for (int i = 0; i < sd_size; i++) {
5013 if (rewrite) {
5014 for (int j = 0; j < sd_glyphs[i].count; j++) {
5015 sd_glyphs_new[sd_shift + i + j] = sd_glyphs[i + j];
5016 }
5017 }
5018 if (sd_glyphs[i].count > 0) {
5019 char32_t c = ch[sd_glyphs[i].start - sd->start];
5020 if (c == 0xfffc) {
5021 i += (sd_glyphs[i].count - 1);
5022 continue;
5023 }
5024 if (c == 0x0009 || c == 0x000b) {
5025 sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_TAB;
5026 }
5027 if (is_whitespace(c)) {
5028 sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_SPACE;
5029 }
5030 if (c_punct_size == 0) {
5031 if (u_ispunct(c) && c != 0x005f) {
5032 sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_PUNCTUATION;
5033 }
5034 } else {
5035 for (int j = 0; j < c_punct_size; j++) {
5036 if (c_punct[j] == c) {
5037 sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_PUNCTUATION;
5038 break;
5039 }
5040 }
5041 }
5042 if (is_underscore(c)) {
5043 sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_UNDERSCORE;
5044 }
5045 if (sd->breaks.has(sd_glyphs[i].end)) {
5046 if (sd->breaks[sd_glyphs[i].end] && (is_linebreak(c))) {
5047 sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_BREAK_HARD;
5048 } else if (is_whitespace(c)) {
5049 sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_BREAK_SOFT;
5050 } else {
5051 int count = sd_glyphs[i].count;
5052 // Do not add extra space at the end of the line.
5053 if (sd_glyphs[i].end == sd->end) {
5054 i += (sd_glyphs[i].count - 1);
5055 continue;
5056 }
5057 // Do not add extra space after existing space.
5058 if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {
5059 if ((i + count < sd_size - 1) && ((sd_glyphs[i + count].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) {
5060 i += (sd_glyphs[i].count - 1);
5061 continue;
5062 }
5063 } else {
5064 if ((sd_glyphs[i].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) {
5065 i += (sd_glyphs[i].count - 1);
5066 continue;
5067 }
5068 }
5069 Glyph gl;
5070 gl.start = sd_glyphs[i].start;
5071 gl.end = sd_glyphs[i].end;
5072 gl.count = 1;
5073 gl.font_rid = sd_glyphs[i].font_rid;
5074 gl.font_size = sd_glyphs[i].font_size;
5075 gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | GRAPHEME_IS_SPACE;
5076 // Mark virtual space after punctuation as punctuation to avoid justification at this point.
5077 if (c_punct_size == 0) {
5078 if (u_ispunct(c) && c != 0x005f) {
5079 gl.flags |= GRAPHEME_IS_PUNCTUATION;
5080 }
5081 } else {
5082 for (int j = 0; j < c_punct_size; j++) {
5083 if (c_punct[j] == c) {
5084 gl.flags |= GRAPHEME_IS_PUNCTUATION;
5085 break;
5086 }
5087 }
5088 }
5089 if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {
5090 gl.flags |= GRAPHEME_IS_RTL;
5091 for (int j = sd_glyphs[i].count - 1; j >= 0; j--) {
5092 sd_glyphs_new[sd_shift + i + j + 1] = sd_glyphs_new[sd_shift + i + j];
5093 }
5094 sd_glyphs_new[sd_shift + i] = gl;
5095 } else {
5096 sd_glyphs_new[sd_shift + i + count] = gl;
5097 }
5098 sd_shift++;
5099 ERR_FAIL_COND_V_MSG(sd_shift > sd->break_inserts, false, "Invalid break insert count!");
5100 }
5101 }
5102 i += (sd_glyphs[i].count - 1);
5103 }
5104 }
5105 if (sd_shift < sd->break_inserts) {
5106 // Note: should not happen with a normal text, but might be a case with special fonts that substitute a long string (with breaks opportunities in it) with a single glyph (like Font Awesome).
5107 glyphs_new.resize(sd->glyphs.size() + sd_shift);
5108 }
5109
5110 if (sd->break_inserts > 0) {
5111 sd->glyphs = glyphs_new;
5112 }
5113
5114 sd->line_breaks_valid = true;
5115
5116 return sd->line_breaks_valid;
5117}
5118
5119_FORCE_INLINE_ int64_t _generate_kashida_justification_opportunies(const String &p_data, int64_t p_start, int64_t p_end) {
5120 int64_t kashida_pos = -1;
5121 int8_t priority = 100;
5122 int64_t i = p_start;
5123
5124 char32_t pc = 0;
5125
5126 while ((p_end > p_start) && is_transparent(p_data[p_end - 1])) {
5127 p_end--;
5128 }
5129
5130 while (i < p_end) {
5131 uint32_t c = p_data[i];
5132
5133 if (c == 0x0640) {
5134 kashida_pos = i;
5135 priority = 0;
5136 }
5137 if (priority >= 1 && i < p_end - 1) {
5138 if (is_seen_sad(c) && (p_data[i + 1] != 0x200c)) {
5139 kashida_pos = i;
5140 priority = 1;
5141 }
5142 }
5143 if (priority >= 2 && i > p_start) {
5144 if (is_teh_marbuta(c) || is_dal(c) || (is_heh(c) && i == p_end - 1)) {
5145 if (is_connected_to_prev(c, pc)) {
5146 kashida_pos = i - 1;
5147 priority = 2;
5148 }
5149 }
5150 }
5151 if (priority >= 3 && i > p_start) {
5152 if (is_alef(c) || ((is_lam(c) || is_tah(c) || is_kaf(c) || is_gaf(c)) && i == p_end - 1)) {
5153 if (is_connected_to_prev(c, pc)) {
5154 kashida_pos = i - 1;
5155 priority = 3;
5156 }
5157 }
5158 }
5159 if (priority >= 4 && i > p_start && i < p_end - 1) {
5160 if (is_beh(c)) {
5161 if (is_reh(p_data[i + 1]) || is_yeh(p_data[i + 1])) {
5162 if (is_connected_to_prev(c, pc)) {
5163 kashida_pos = i - 1;
5164 priority = 4;
5165 }
5166 }
5167 }
5168 }
5169 if (priority >= 5 && i > p_start) {
5170 if (is_waw(c) || ((is_ain(c) || is_qaf(c) || is_feh(c)) && i == p_end - 1)) {
5171 if (is_connected_to_prev(c, pc)) {
5172 kashida_pos = i - 1;
5173 priority = 5;
5174 }
5175 }
5176 }
5177 if (priority >= 6 && i > p_start) {
5178 if (is_reh(c)) {
5179 if (is_connected_to_prev(c, pc)) {
5180 kashida_pos = i - 1;
5181 priority = 6;
5182 }
5183 }
5184 }
5185 if (!is_transparent(c)) {
5186 pc = c;
5187 }
5188 i++;
5189 }
5190
5191 return kashida_pos;
5192}
5193
5194bool TextServerAdvanced::_shaped_text_update_justification_ops(const RID &p_shaped) {
5195 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
5196 ERR_FAIL_COND_V(!sd, false);
5197
5198 MutexLock lock(sd->mutex);
5199 if (!sd->valid) {
5200 _shaped_text_shape(p_shaped);
5201 }
5202 if (!sd->line_breaks_valid) {
5203 _shaped_text_update_breaks(p_shaped);
5204 }
5205
5206 if (sd->justification_ops_valid) {
5207 return true; // Nothing to do.
5208 }
5209
5210 const UChar *data = sd->utf16.get_data();
5211 int data_size = sd->utf16.length();
5212
5213 if (!sd->js_ops_valid) {
5214 sd->jstops.clear();
5215
5216 // Use ICU word iterator and custom kashida detection.
5217 UErrorCode err = U_ZERO_ERROR;
5218 UBreakIterator *bi = ubrk_open(UBRK_WORD, "", data, data_size, &err);
5219 if (U_FAILURE(err)) {
5220 // No data - use fallback.
5221 int limit = 0;
5222 for (int i = 0; i < sd->text.length(); i++) {
5223 if (is_whitespace(data[i])) {
5224 int ks = _generate_kashida_justification_opportunies(sd->text, limit, i) + sd->start;
5225 if (ks != -1) {
5226 sd->jstops[ks] = true;
5227 }
5228 limit = i + 1;
5229 }
5230 }
5231 int ks = _generate_kashida_justification_opportunies(sd->text, limit, sd->text.length()) + sd->start;
5232 if (ks != -1) {
5233 sd->jstops[ks] = true;
5234 }
5235 } else {
5236 int limit = 0;
5237 while (ubrk_next(bi) != UBRK_DONE) {
5238 if (ubrk_getRuleStatus(bi) != UBRK_WORD_NONE) {
5239 int i = _convert_pos(sd, ubrk_current(bi));
5240 sd->jstops[i + sd->start] = false;
5241 int ks = _generate_kashida_justification_opportunies(sd->text, limit, i);
5242 if (ks != -1) {
5243 sd->jstops[ks + sd->start] = true;
5244 }
5245 limit = i;
5246 }
5247 }
5248 ubrk_close(bi);
5249 }
5250
5251 sd->js_ops_valid = true;
5252 }
5253
5254 sd->sort_valid = false;
5255 sd->glyphs_logical.clear();
5256
5257 Glyph *sd_glyphs = sd->glyphs.ptrw();
5258 int sd_size = sd->glyphs.size();
5259 if (!sd->jstops.is_empty()) {
5260 for (int i = 0; i < sd_size; i++) {
5261 if (sd_glyphs[i].count > 0) {
5262 char32_t c = sd->text[sd_glyphs[i].start - sd->start];
5263 if (c == 0x0640 && sd_glyphs[i].start == sd_glyphs[i].end - 1) {
5264 sd_glyphs[i].flags |= GRAPHEME_IS_ELONGATION;
5265 }
5266 if (sd->jstops.has(sd_glyphs[i].start)) {
5267 if (c == 0xfffc) {
5268 continue;
5269 }
5270 if (sd->jstops[sd_glyphs[i].start]) {
5271 if (c != 0x0640) {
5272 if (sd_glyphs[i].font_rid != RID()) {
5273 Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size);
5274 if ((sd_glyphs[i].flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {
5275#if HB_VERSION_ATLEAST(5, 1, 0)
5276 if ((i > 0) && ((sd_glyphs[i - 1].flags & GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL) != GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL)) {
5277 continue;
5278 }
5279#endif
5280 gl.start = sd_glyphs[i].start;
5281 gl.end = sd_glyphs[i].end;
5282 gl.repeat = 0;
5283 gl.count = 1;
5284 if (sd->orientation == ORIENTATION_HORIZONTAL) {
5285 gl.y_off = sd_glyphs[i].y_off;
5286 } else {
5287 gl.x_off = sd_glyphs[i].x_off;
5288 }
5289 gl.flags |= GRAPHEME_IS_ELONGATION | GRAPHEME_IS_VIRTUAL;
5290 sd->glyphs.insert(i, gl);
5291 i++;
5292
5293 // Update write pointer and size.
5294 sd_size = sd->glyphs.size();
5295 sd_glyphs = sd->glyphs.ptrw();
5296 continue;
5297 }
5298 }
5299 }
5300 } else if ((sd_glyphs[i].flags & GRAPHEME_IS_SPACE) != GRAPHEME_IS_SPACE && (sd_glyphs[i].flags & GRAPHEME_IS_PUNCTUATION) != GRAPHEME_IS_PUNCTUATION) {
5301 int count = sd_glyphs[i].count;
5302 // Do not add extra spaces at the end of the line.
5303 if (sd_glyphs[i].end == sd->end) {
5304 continue;
5305 }
5306 // Do not add extra space after existing space.
5307 if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {
5308 if ((i + count < sd_size - 1) && ((sd_glyphs[i + count].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) {
5309 continue;
5310 }
5311 } else {
5312 if ((i > 0) && ((sd_glyphs[i - 1].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) {
5313 continue;
5314 }
5315 }
5316 // Inject virtual space for alignment.
5317 Glyph gl;
5318 gl.start = sd_glyphs[i].start;
5319 gl.end = sd_glyphs[i].end;
5320 gl.count = 1;
5321 gl.font_rid = sd_glyphs[i].font_rid;
5322 gl.font_size = sd_glyphs[i].font_size;
5323 gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_VIRTUAL;
5324 if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {
5325 gl.flags |= GRAPHEME_IS_RTL;
5326 sd->glyphs.insert(i, gl); // Insert before.
5327 } else {
5328 sd->glyphs.insert(i + count, gl); // Insert after.
5329 }
5330 i += count;
5331
5332 // Update write pointer and size.
5333 sd_size = sd->glyphs.size();
5334 sd_glyphs = sd->glyphs.ptrw();
5335 continue;
5336 }
5337 }
5338 }
5339 }
5340 }
5341
5342 sd->justification_ops_valid = true;
5343 return sd->justification_ops_valid;
5344}
5345
5346Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, const RID &p_font, int64_t p_font_size) {
5347 hb_font_t *hb_font = _font_get_hb_handle(p_font, p_font_size);
5348 double scale = _font_get_scale(p_font, p_font_size);
5349 bool subpos = (scale != 1.0) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_AUTO && p_font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);
5350 ERR_FAIL_COND_V(hb_font == nullptr, Glyph());
5351
5352 hb_buffer_clear_contents(p_sd->hb_buffer);
5353 hb_buffer_set_direction(p_sd->hb_buffer, p_direction);
5354 hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)(HB_BUFFER_FLAG_DEFAULT));
5355 hb_buffer_set_script(p_sd->hb_buffer, p_script);
5356 hb_buffer_add_utf32(p_sd->hb_buffer, (const uint32_t *)&p_char, 1, 0, 1);
5357
5358 hb_shape(hb_font, p_sd->hb_buffer, nullptr, 0);
5359
5360 unsigned int glyph_count = 0;
5361 hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(p_sd->hb_buffer, &glyph_count);
5362 hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(p_sd->hb_buffer, &glyph_count);
5363
5364 // Process glyphs.
5365 Glyph gl;
5366
5367 if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
5368 gl.flags |= TextServer::GRAPHEME_IS_RTL;
5369 }
5370
5371 gl.font_rid = p_font;
5372 gl.font_size = p_font_size;
5373
5374 if (glyph_count > 0) {
5375 if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
5376 if (subpos) {
5377 gl.advance = (double)glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size);
5378 } else {
5379 gl.advance = Math::round((double)glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size));
5380 }
5381 } else {
5382 gl.advance = -Math::round((double)glyph_pos[0].y_advance / (64.0 / scale));
5383 }
5384 gl.count = 1;
5385
5386 gl.index = glyph_info[0].codepoint;
5387 if (subpos) {
5388 gl.x_off = (double)glyph_pos[0].x_offset / (64.0 / scale);
5389 } else {
5390 gl.x_off = Math::round((double)glyph_pos[0].x_offset / (64.0 / scale));
5391 }
5392 gl.y_off = -Math::round((double)glyph_pos[0].y_offset / (64.0 / scale));
5393
5394 if ((glyph_info[0].codepoint != 0) || !u_isgraph(p_char)) {
5395 gl.flags |= GRAPHEME_IS_VALID;
5396 }
5397 }
5398 return gl;
5399}
5400
5401_FORCE_INLINE_ void TextServerAdvanced::_add_featuers(const Dictionary &p_source, Vector<hb_feature_t> &r_ftrs) {
5402 Array keys = p_source.keys();
5403 Array values = p_source.values();
5404 for (int i = 0; i < keys.size(); i++) {
5405 int32_t value = values[i];
5406 if (value >= 0) {
5407 hb_feature_t feature;
5408 if (keys[i].get_type() == Variant::STRING) {
5409 feature.tag = _name_to_tag(keys[i]);
5410 } else {
5411 feature.tag = keys[i];
5412 }
5413 feature.value = value;
5414 feature.start = 0;
5415 feature.end = -1;
5416 r_ftrs.push_back(feature);
5417 }
5418 }
5419}
5420
5421void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, TypedArray<RID> p_fonts, int64_t p_span, int64_t p_fb_index, int64_t p_prev_start, int64_t p_prev_end) {
5422 RID f;
5423 int fs = p_sd->spans[p_span].font_size;
5424
5425 if (p_fb_index >= 0 && p_fb_index < p_fonts.size()) {
5426 // Try font from list.
5427 f = p_fonts[p_fb_index];
5428 } else if (OS::get_singleton()->has_feature("system_fonts") && p_fonts.size() > 0 && ((p_fb_index == p_fonts.size()) || (p_fb_index > p_fonts.size() && p_start != p_prev_start))) {
5429 // Try system fallback.
5430 RID fdef = p_fonts[0];
5431 if (_font_is_allow_system_fallback(fdef)) {
5432 _update_chars(p_sd);
5433
5434 int64_t next = p_end;
5435 for (const int32_t &E : p_sd->chars) {
5436 if (E > p_start) {
5437 next = E;
5438 break;
5439 }
5440 }
5441 String text = p_sd->text.substr(p_start, next - p_start);
5442
5443 String font_name = _font_get_name(fdef);
5444 BitField<FontStyle> font_style = _font_get_style(fdef);
5445 int font_weight = _font_get_weight(fdef);
5446 int font_stretch = _font_get_stretch(fdef);
5447 Dictionary dvar = _font_get_variation_coordinates(fdef);
5448 static int64_t wgth_tag = _name_to_tag("weight");
5449 static int64_t wdth_tag = _name_to_tag("width");
5450 static int64_t ital_tag = _name_to_tag("italic");
5451 if (dvar.has(wgth_tag)) {
5452 font_weight = dvar[wgth_tag].operator int();
5453 }
5454 if (dvar.has(wdth_tag)) {
5455 font_stretch = dvar[wdth_tag].operator int();
5456 }
5457 if (dvar.has(ital_tag) && dvar[ital_tag].operator int() == 1) {
5458 font_style.set_flag(TextServer::FONT_ITALIC);
5459 }
5460
5461 char scr_buffer[5] = { 0, 0, 0, 0, 0 };
5462 hb_tag_to_string(hb_script_to_iso15924_tag(p_script), scr_buffer);
5463 String script_code = String(scr_buffer);
5464 String locale = (p_sd->spans[p_span].language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_sd->spans[p_span].language;
5465
5466 PackedStringArray fallback_font_name = OS::get_singleton()->get_system_font_path_for_text(font_name, text, locale, script_code, font_weight, font_stretch, font_style & TextServer::FONT_ITALIC);
5467#ifdef GDEXTENSION
5468 for (int fb = 0; fb < fallback_font_name.size(); fb++) {
5469 const String &E = fallback_font_name[fb];
5470#else
5471 for (const String &E : fallback_font_name) {
5472#endif
5473 SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, fdef, this);
5474 if (system_fonts.has(key)) {
5475 const SystemFontCache &sysf_cache = system_fonts[key];
5476 int best_score = 0;
5477 int best_match = -1;
5478 for (int face_idx = 0; face_idx < sysf_cache.var.size(); face_idx++) {
5479 const SystemFontCacheRec &F = sysf_cache.var[face_idx];
5480 if (unlikely(!_font_has_char(F.rid, text[0]))) {
5481 continue;
5482 }
5483 BitField<FontStyle> style = _font_get_style(F.rid);
5484 int weight = _font_get_weight(F.rid);
5485 int stretch = _font_get_stretch(F.rid);
5486 int score = (20 - Math::abs(weight - font_weight) / 50);
5487 score += (20 - Math::abs(stretch - font_stretch) / 10);
5488 if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) {
5489 score += 30;
5490 }
5491 if (score >= best_score) {
5492 best_score = score;
5493 best_match = face_idx;
5494 }
5495 if (best_score == 70) {
5496 break;
5497 }
5498 }
5499 if (best_match != -1) {
5500 f = sysf_cache.var[best_match].rid;
5501 }
5502 }
5503 if (!f.is_valid()) {
5504 if (system_fonts.has(key)) {
5505 const SystemFontCache &sysf_cache = system_fonts[key];
5506 if (sysf_cache.max_var == sysf_cache.var.size()) {
5507 // All subfonts already tested, skip.
5508 continue;
5509 }
5510 }
5511
5512 if (!system_font_data.has(E)) {
5513 system_font_data[E] = FileAccess::get_file_as_bytes(E);
5514 }
5515
5516 const PackedByteArray &font_data = system_font_data[E];
5517
5518 SystemFontCacheRec sysf;
5519 sysf.rid = _create_font();
5520 _font_set_data_ptr(sysf.rid, font_data.ptr(), font_data.size());
5521
5522 Dictionary var = dvar;
5523 // Select matching style from collection.
5524 int best_score = 0;
5525 int best_match = -1;
5526 for (int face_idx = 0; face_idx < _font_get_face_count(sysf.rid); face_idx++) {
5527 _font_set_face_index(sysf.rid, face_idx);
5528 if (unlikely(!_font_has_char(sysf.rid, text[0]))) {
5529 continue;
5530 }
5531 BitField<FontStyle> style = _font_get_style(sysf.rid);
5532 int weight = _font_get_weight(sysf.rid);
5533 int stretch = _font_get_stretch(sysf.rid);
5534 int score = (20 - Math::abs(weight - font_weight) / 50);
5535 score += (20 - Math::abs(stretch - font_stretch) / 10);
5536 if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) {
5537 score += 30;
5538 }
5539 if (score >= best_score) {
5540 best_score = score;
5541 best_match = face_idx;
5542 }
5543 if (best_score == 70) {
5544 break;
5545 }
5546 }
5547 if (best_match == -1) {
5548 _free_rid(sysf.rid);
5549 continue;
5550 } else {
5551 _font_set_face_index(sysf.rid, best_match);
5552 }
5553 sysf.index = best_match;
5554
5555 // If it's a variable font, apply weight, stretch and italic coordinates to match requested style.
5556 if (best_score != 70) {
5557 Dictionary ftr = _font_supported_variation_list(sysf.rid);
5558 if (ftr.has(wdth_tag)) {
5559 var[wdth_tag] = font_stretch;
5560 _font_set_stretch(sysf.rid, font_stretch);
5561 }
5562 if (ftr.has(wgth_tag)) {
5563 var[wgth_tag] = font_weight;
5564 _font_set_weight(sysf.rid, font_weight);
5565 }
5566 if ((font_style & TextServer::FONT_ITALIC) && ftr.has(ital_tag)) {
5567 var[ital_tag] = 1;
5568 _font_set_style(sysf.rid, _font_get_style(sysf.rid) | TextServer::FONT_ITALIC);
5569 }
5570 }
5571
5572 _font_set_antialiasing(sysf.rid, key.antialiasing);
5573 _font_set_generate_mipmaps(sysf.rid, key.mipmaps);
5574 _font_set_multichannel_signed_distance_field(sysf.rid, key.msdf);
5575 _font_set_msdf_pixel_range(sysf.rid, key.msdf_range);
5576 _font_set_msdf_size(sysf.rid, key.msdf_source_size);
5577 _font_set_fixed_size(sysf.rid, key.fixed_size);
5578 _font_set_force_autohinter(sysf.rid, key.force_autohinter);
5579 _font_set_hinting(sysf.rid, key.hinting);
5580 _font_set_subpixel_positioning(sysf.rid, key.subpixel_positioning);
5581 _font_set_variation_coordinates(sysf.rid, var);
5582 _font_set_oversampling(sysf.rid, key.oversampling);
5583 _font_set_embolden(sysf.rid, key.embolden);
5584 _font_set_transform(sysf.rid, key.transform);
5585 _font_set_spacing(sysf.rid, SPACING_TOP, key.extra_spacing[SPACING_TOP]);
5586 _font_set_spacing(sysf.rid, SPACING_BOTTOM, key.extra_spacing[SPACING_BOTTOM]);
5587 _font_set_spacing(sysf.rid, SPACING_SPACE, key.extra_spacing[SPACING_SPACE]);
5588 _font_set_spacing(sysf.rid, SPACING_GLYPH, key.extra_spacing[SPACING_GLYPH]);
5589
5590 if (system_fonts.has(key)) {
5591 system_fonts[key].var.push_back(sysf);
5592 } else {
5593 SystemFontCache &sysf_cache = system_fonts[key];
5594 sysf_cache.max_var = _font_get_face_count(sysf.rid);
5595 sysf_cache.var.push_back(sysf);
5596 }
5597 f = sysf.rid;
5598 }
5599 break;
5600 }
5601 }
5602 }
5603
5604 if (!f.is_valid()) {
5605 // No valid font, use fallback hex code boxes.
5606 for (int i = p_start; i < p_end; i++) {
5607 if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) {
5608 Glyph gl;
5609 gl.start = i + p_sd->start;
5610 gl.end = i + 1 + p_sd->start;
5611 gl.count = 1;
5612 gl.index = p_sd->text[i];
5613 gl.font_size = fs;
5614 gl.font_rid = RID();
5615 if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
5616 gl.flags |= TextServer::GRAPHEME_IS_RTL;
5617 }
5618 if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
5619 gl.advance = get_hex_code_box_size(fs, gl.index).x;
5620 p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(fs, gl.index).y);
5621 } else {
5622 gl.advance = get_hex_code_box_size(fs, gl.index).y;
5623 gl.y_off = get_hex_code_box_size(fs, gl.index).y;
5624 gl.x_off = -Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5);
5625 p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5));
5626 p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5));
5627 }
5628 p_sd->width += gl.advance;
5629
5630 p_sd->glyphs.push_back(gl);
5631 }
5632 }
5633 return;
5634 }
5635
5636 FontAdvanced *fd = font_owner.get_or_null(f);
5637 ERR_FAIL_COND(!fd);
5638 MutexLock lock(fd->mutex);
5639
5640 Vector2i fss = _get_size(fd, fs);
5641 hb_font_t *hb_font = _font_get_hb_handle(f, fs);
5642 double scale = _font_get_scale(f, fs);
5643 double sp_sp = p_sd->extra_spacing[SPACING_SPACE] + _font_get_spacing(f, SPACING_SPACE);
5644 double sp_gl = p_sd->extra_spacing[SPACING_GLYPH] + _font_get_spacing(f, SPACING_GLYPH);
5645 bool last_run = (p_sd->end == p_end);
5646 double ea = _get_extra_advance(f, fs);
5647 bool subpos = (scale != 1.0) || (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_AUTO && fs <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);
5648 ERR_FAIL_COND(hb_font == nullptr);
5649
5650 hb_buffer_clear_contents(p_sd->hb_buffer);
5651 hb_buffer_set_direction(p_sd->hb_buffer, p_direction);
5652 int flags = (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0);
5653 if (p_sd->preserve_control) {
5654 flags |= HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES;
5655 } else {
5656 flags |= HB_BUFFER_FLAG_DEFAULT;
5657 }
5658#if HB_VERSION_ATLEAST(5, 1, 0)
5659 flags |= HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL;
5660#endif
5661 hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)flags);
5662 hb_buffer_set_script(p_sd->hb_buffer, p_script);
5663
5664 if (p_sd->spans[p_span].language.is_empty()) {
5665 hb_language_t lang = hb_language_from_string(TranslationServer::get_singleton()->get_tool_locale().ascii().get_data(), -1);
5666 hb_buffer_set_language(p_sd->hb_buffer, lang);
5667 } else {
5668 hb_language_t lang = hb_language_from_string(p_sd->spans[p_span].language.ascii().get_data(), -1);
5669 hb_buffer_set_language(p_sd->hb_buffer, lang);
5670 }
5671
5672 hb_buffer_add_utf32(p_sd->hb_buffer, (const uint32_t *)p_sd->text.ptr(), p_sd->text.length(), p_start, p_end - p_start);
5673
5674 Vector<hb_feature_t> ftrs;
5675 _add_featuers(_font_get_opentype_feature_overrides(f), ftrs);
5676 _add_featuers(p_sd->spans[p_span].features, ftrs);
5677
5678 hb_shape(hb_font, p_sd->hb_buffer, ftrs.is_empty() ? nullptr : &ftrs[0], ftrs.size());
5679
5680 unsigned int glyph_count = 0;
5681 hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(p_sd->hb_buffer, &glyph_count);
5682 hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(p_sd->hb_buffer, &glyph_count);
5683
5684 int mod = 0;
5685 if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
5686 TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
5687 if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
5688 mod = (layout << 24);
5689 }
5690 }
5691
5692 // Process glyphs.
5693 if (glyph_count > 0) {
5694 Glyph *w = (Glyph *)memalloc(glyph_count * sizeof(Glyph));
5695
5696 int end = (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) ? p_end : 0;
5697 uint32_t last_cluster_id = UINT32_MAX;
5698 unsigned int last_cluster_index = 0;
5699 bool last_cluster_valid = true;
5700
5701 for (unsigned int i = 0; i < glyph_count; i++) {
5702 if ((i > 0) && (last_cluster_id != glyph_info[i].cluster)) {
5703 if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
5704 end = w[last_cluster_index].start;
5705 } else {
5706 for (unsigned int j = last_cluster_index; j < i; j++) {
5707 w[j].end = glyph_info[i].cluster;
5708 }
5709 }
5710 if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
5711 w[last_cluster_index].flags |= GRAPHEME_IS_RTL;
5712 }
5713 if (last_cluster_valid) {
5714 w[last_cluster_index].flags |= GRAPHEME_IS_VALID;
5715 }
5716 w[last_cluster_index].count = i - last_cluster_index;
5717 last_cluster_index = i;
5718 last_cluster_valid = true;
5719 }
5720
5721 last_cluster_id = glyph_info[i].cluster;
5722
5723 Glyph &gl = w[i];
5724 gl = Glyph();
5725
5726 gl.start = glyph_info[i].cluster;
5727 gl.end = end;
5728 gl.count = 0;
5729
5730 gl.font_rid = f;
5731 gl.font_size = fs;
5732
5733 if (glyph_info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK) {
5734 gl.flags |= GRAPHEME_IS_CONNECTED;
5735 }
5736
5737#if HB_VERSION_ATLEAST(5, 1, 0)
5738 if (glyph_info[i].mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL) {
5739 gl.flags |= GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL;
5740 }
5741#endif
5742
5743 gl.index = glyph_info[i].codepoint;
5744 if (gl.index != 0) {
5745 _ensure_glyph(fd, fss, gl.index | mod);
5746 if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
5747 if (subpos) {
5748 gl.advance = (double)glyph_pos[i].x_advance / (64.0 / scale) + ea;
5749 } else {
5750 gl.advance = Math::round((double)glyph_pos[i].x_advance / (64.0 / scale) + ea);
5751 }
5752 } else {
5753 gl.advance = -Math::round((double)glyph_pos[i].y_advance / (64.0 / scale));
5754 }
5755 if (subpos) {
5756 gl.x_off = (double)glyph_pos[i].x_offset / (64.0 / scale);
5757 } else {
5758 gl.x_off = Math::round((double)glyph_pos[i].x_offset / (64.0 / scale));
5759 }
5760 gl.y_off = -Math::round((double)glyph_pos[i].y_offset / (64.0 / scale));
5761 }
5762 if (!last_run || i < glyph_count - 1) {
5763 // Do not add extra spacing to the last glyph of the string.
5764 if (sp_sp && is_whitespace(p_sd->text[glyph_info[i].cluster])) {
5765 gl.advance += sp_sp;
5766 } else {
5767 gl.advance += sp_gl;
5768 }
5769 }
5770
5771 if (p_sd->preserve_control) {
5772 last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || (p_sd->text[glyph_info[i].cluster] == 0x0009) || (u_isblank(p_sd->text[glyph_info[i].cluster]) && (gl.advance != 0)) || (!u_isblank(p_sd->text[glyph_info[i].cluster]) && is_linebreak(p_sd->text[glyph_info[i].cluster])));
5773 } else {
5774 last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || (p_sd->text[glyph_info[i].cluster] == 0x0009) || (u_isblank(p_sd->text[glyph_info[i].cluster]) && (gl.advance != 0)) || (!u_isblank(p_sd->text[glyph_info[i].cluster]) && !u_isgraph(p_sd->text[glyph_info[i].cluster])));
5775 }
5776 }
5777 if (p_direction == HB_DIRECTION_LTR || p_direction == HB_DIRECTION_TTB) {
5778 for (unsigned int j = last_cluster_index; j < glyph_count; j++) {
5779 w[j].end = p_end;
5780 }
5781 }
5782 w[last_cluster_index].count = glyph_count - last_cluster_index;
5783 if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
5784 w[last_cluster_index].flags |= GRAPHEME_IS_RTL;
5785 }
5786 if (last_cluster_valid) {
5787 w[last_cluster_index].flags |= GRAPHEME_IS_VALID;
5788 }
5789
5790 // Fallback.
5791 int failed_subrun_start = p_end + 1;
5792 int failed_subrun_end = p_start;
5793
5794 for (unsigned int i = 0; i < glyph_count; i++) {
5795 if ((w[i].flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {
5796 if (failed_subrun_start != p_end + 1) {
5797 _shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1, p_start, p_end);
5798 failed_subrun_start = p_end + 1;
5799 failed_subrun_end = p_start;
5800 }
5801 for (int j = 0; j < w[i].count; j++) {
5802 if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
5803 p_sd->ascent = MAX(p_sd->ascent, -w[i + j].y_off);
5804 p_sd->descent = MAX(p_sd->descent, w[i + j].y_off);
5805 } else {
5806 double gla = Math::round(_font_get_glyph_advance(f, fs, w[i + j].index).x * 0.5);
5807 p_sd->ascent = MAX(p_sd->ascent, gla);
5808 p_sd->descent = MAX(p_sd->descent, gla);
5809 }
5810 p_sd->width += w[i + j].advance;
5811 w[i + j].start += p_sd->start;
5812 w[i + j].end += p_sd->start;
5813 p_sd->glyphs.push_back(w[i + j]);
5814 }
5815 } else {
5816 if (failed_subrun_start >= w[i].start) {
5817 failed_subrun_start = w[i].start;
5818 }
5819 if (failed_subrun_end <= w[i].end) {
5820 failed_subrun_end = w[i].end;
5821 }
5822 }
5823 i += w[i].count - 1;
5824 }
5825 memfree(w);
5826 if (failed_subrun_start != p_end + 1) {
5827 _shape_run(p_sd, failed_subrun_start, failed_subrun_end, p_script, p_direction, p_fonts, p_span, p_fb_index + 1, p_start, p_end);
5828 }
5829 p_sd->ascent = MAX(p_sd->ascent, _font_get_ascent(f, fs) + _font_get_spacing(f, SPACING_TOP));
5830 p_sd->descent = MAX(p_sd->descent, _font_get_descent(f, fs) + _font_get_spacing(f, SPACING_BOTTOM));
5831 p_sd->upos = MAX(p_sd->upos, _font_get_underline_position(f, fs));
5832 p_sd->uthk = MAX(p_sd->uthk, _font_get_underline_thickness(f, fs));
5833 }
5834}
5835
5836bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
5837 _THREAD_SAFE_METHOD_
5838 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
5839 ERR_FAIL_COND_V(!sd, false);
5840
5841 MutexLock lock(sd->mutex);
5842 if (sd->valid) {
5843 return true;
5844 }
5845
5846 invalidate(sd, false);
5847 if (sd->parent != RID()) {
5848 _shaped_text_shape(sd->parent);
5849 ShapedTextDataAdvanced *parent_sd = shaped_owner.get_or_null(sd->parent);
5850 ERR_FAIL_COND_V(!parent_sd->valid, false);
5851 ERR_FAIL_COND_V(!_shape_substr(sd, parent_sd, sd->start, sd->end - sd->start), false);
5852 return true;
5853 }
5854
5855 if (sd->text.length() == 0) {
5856 sd->valid = true;
5857 return true;
5858 }
5859
5860 sd->utf16 = sd->text.utf16();
5861 const UChar *data = sd->utf16.get_data();
5862
5863 // Create script iterator.
5864 if (sd->script_iter == nullptr) {
5865 sd->script_iter = memnew(ScriptIterator(sd->text, 0, sd->text.length()));
5866 }
5867
5868 sd->base_para_direction = UBIDI_DEFAULT_LTR;
5869 switch (sd->direction) {
5870 case DIRECTION_LTR: {
5871 sd->para_direction = DIRECTION_LTR;
5872 sd->base_para_direction = UBIDI_LTR;
5873 } break;
5874 case DIRECTION_RTL: {
5875 sd->para_direction = DIRECTION_RTL;
5876 sd->base_para_direction = UBIDI_RTL;
5877 } break;
5878 case DIRECTION_INHERITED:
5879 case DIRECTION_AUTO: {
5880 UBiDiDirection direction = ubidi_getBaseDirection(data, sd->utf16.length());
5881 if (direction != UBIDI_NEUTRAL) {
5882 sd->para_direction = (direction == UBIDI_RTL) ? DIRECTION_RTL : DIRECTION_LTR;
5883 sd->base_para_direction = direction;
5884 } else {
5885 const String &lang = (sd->spans.is_empty() || sd->spans[0].language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : sd->spans[0].language;
5886 bool lang_rtl = _is_locale_right_to_left(lang);
5887
5888 sd->para_direction = lang_rtl ? DIRECTION_RTL : DIRECTION_LTR;
5889 sd->base_para_direction = lang_rtl ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR;
5890 }
5891 } break;
5892 }
5893
5894 if (sd->bidi_override.is_empty()) {
5895 sd->bidi_override.push_back(Vector3i(sd->start, sd->end, DIRECTION_INHERITED));
5896 }
5897
5898 for (int ov = 0; ov < sd->bidi_override.size(); ov++) {
5899 // Create BiDi iterator.
5900 int start = _convert_pos_inv(sd, sd->bidi_override[ov].x - sd->start);
5901 int end = _convert_pos_inv(sd, sd->bidi_override[ov].y - sd->start);
5902
5903 if (start < 0 || end - start > sd->utf16.length()) {
5904 continue;
5905 }
5906
5907 UErrorCode err = U_ZERO_ERROR;
5908 UBiDi *bidi_iter = ubidi_openSized(end - start, 0, &err);
5909 if (U_SUCCESS(err)) {
5910 switch (static_cast<TextServer::Direction>(sd->bidi_override[ov].z)) {
5911 case DIRECTION_LTR: {
5912 ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err);
5913 } break;
5914 case DIRECTION_RTL: {
5915 ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err);
5916 } break;
5917 case DIRECTION_INHERITED: {
5918 ubidi_setPara(bidi_iter, data + start, end - start, sd->base_para_direction, nullptr, &err);
5919 } break;
5920 case DIRECTION_AUTO: {
5921 UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start);
5922 if (direction != UBIDI_NEUTRAL) {
5923 ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);
5924 } else {
5925 ubidi_setPara(bidi_iter, data + start, end - start, sd->base_para_direction, nullptr, &err);
5926 }
5927 } break;
5928 }
5929 if (U_FAILURE(err)) {
5930 ubidi_close(bidi_iter);
5931 bidi_iter = nullptr;
5932 ERR_PRINT(vformat("BiDi reordering for the paragraph failed: %s", u_errorName(err)));
5933 }
5934 } else {
5935 bidi_iter = nullptr;
5936 ERR_PRINT(vformat("BiDi iterator allocation for the paragraph failed: %s", u_errorName(err)));
5937 }
5938 sd->bidi_iter.push_back(bidi_iter);
5939
5940 err = U_ZERO_ERROR;
5941 int bidi_run_count = 1;
5942 if (bidi_iter) {
5943 bidi_run_count = ubidi_countRuns(bidi_iter, &err);
5944 if (U_FAILURE(err)) {
5945 ERR_PRINT(u_errorName(err));
5946 }
5947 }
5948 for (int i = 0; i < bidi_run_count; i++) {
5949 int32_t _bidi_run_start = 0;
5950 int32_t _bidi_run_length = end - start;
5951 bool is_rtl = false;
5952 hb_direction_t bidi_run_direction = HB_DIRECTION_INVALID;
5953 if (bidi_iter) {
5954 is_rtl = (ubidi_getVisualRun(bidi_iter, i, &_bidi_run_start, &_bidi_run_length) == UBIDI_LTR);
5955 }
5956 switch (sd->orientation) {
5957 case ORIENTATION_HORIZONTAL: {
5958 if (is_rtl) {
5959 bidi_run_direction = HB_DIRECTION_LTR;
5960 } else {
5961 bidi_run_direction = HB_DIRECTION_RTL;
5962 }
5963 } break;
5964 case ORIENTATION_VERTICAL: {
5965 if (is_rtl) {
5966 bidi_run_direction = HB_DIRECTION_TTB;
5967 } else {
5968 bidi_run_direction = HB_DIRECTION_BTT;
5969 }
5970 }
5971 }
5972
5973 int32_t bidi_run_start = _convert_pos(sd, start + _bidi_run_start);
5974 int32_t bidi_run_end = _convert_pos(sd, start + _bidi_run_start + _bidi_run_length);
5975
5976 // Shape runs.
5977
5978 int scr_from = (is_rtl) ? 0 : sd->script_iter->script_ranges.size() - 1;
5979 int scr_to = (is_rtl) ? sd->script_iter->script_ranges.size() : -1;
5980 int scr_delta = (is_rtl) ? +1 : -1;
5981
5982 for (int j = scr_from; j != scr_to; j += scr_delta) {
5983 if ((sd->script_iter->script_ranges[j].start < bidi_run_end) && (sd->script_iter->script_ranges[j].end > bidi_run_start)) {
5984 int32_t script_run_start = MAX(sd->script_iter->script_ranges[j].start, bidi_run_start);
5985 int32_t script_run_end = MIN(sd->script_iter->script_ranges[j].end, bidi_run_end);
5986 char scr_buffer[5] = { 0, 0, 0, 0, 0 };
5987 hb_tag_to_string(hb_script_to_iso15924_tag(sd->script_iter->script_ranges[j].script), scr_buffer);
5988 String script_code = String(scr_buffer);
5989
5990 int spn_from = (is_rtl) ? 0 : sd->spans.size() - 1;
5991 int spn_to = (is_rtl) ? sd->spans.size() : -1;
5992 int spn_delta = (is_rtl) ? +1 : -1;
5993
5994 for (int k = spn_from; k != spn_to; k += spn_delta) {
5995 const ShapedTextDataAdvanced::Span &span = sd->spans[k];
5996 if (span.start - sd->start >= script_run_end || span.end - sd->start <= script_run_start) {
5997 continue;
5998 }
5999 if (span.embedded_key != Variant()) {
6000 // Embedded object.
6001 if (sd->orientation == ORIENTATION_HORIZONTAL) {
6002 sd->objects[span.embedded_key].rect.position.x = sd->width;
6003 sd->width += sd->objects[span.embedded_key].rect.size.x;
6004 } else {
6005 sd->objects[span.embedded_key].rect.position.y = sd->width;
6006 sd->width += sd->objects[span.embedded_key].rect.size.y;
6007 }
6008 Glyph gl;
6009 gl.start = span.start;
6010 gl.end = span.end;
6011 gl.count = 1;
6012 gl.flags = GRAPHEME_IS_VALID | GRAPHEME_IS_EMBEDDED_OBJECT;
6013 if (sd->orientation == ORIENTATION_HORIZONTAL) {
6014 gl.advance = sd->objects[span.embedded_key].rect.size.x;
6015 } else {
6016 gl.advance = sd->objects[span.embedded_key].rect.size.y;
6017 }
6018 sd->glyphs.push_back(gl);
6019 } else {
6020 Array fonts;
6021 Array fonts_scr_only;
6022 Array fonts_no_match;
6023 int font_count = span.fonts.size();
6024 if (font_count > 0) {
6025 fonts.push_back(sd->spans[k].fonts[0]);
6026 }
6027 for (int l = 1; l < font_count; l++) {
6028 if (_font_is_script_supported(span.fonts[l], script_code)) {
6029 if (_font_is_language_supported(span.fonts[l], span.language)) {
6030 fonts.push_back(sd->spans[k].fonts[l]);
6031 } else {
6032 fonts_scr_only.push_back(sd->spans[k].fonts[l]);
6033 }
6034 } else {
6035 fonts_no_match.push_back(sd->spans[k].fonts[l]);
6036 }
6037 }
6038 fonts.append_array(fonts_scr_only);
6039 fonts.append_array(fonts_no_match);
6040 _shape_run(sd, MAX(sd->spans[k].start - sd->start, script_run_start), MIN(sd->spans[k].end - sd->start, script_run_end), sd->script_iter->script_ranges[j].script, bidi_run_direction, fonts, k, 0, 0, 0);
6041 }
6042 }
6043 }
6044 }
6045 }
6046 }
6047
6048 _realign(sd);
6049 sd->valid = true;
6050 return sd->valid;
6051}
6052
6053bool TextServerAdvanced::_shaped_text_is_ready(const RID &p_shaped) const {
6054 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
6055 ERR_FAIL_COND_V(!sd, false);
6056
6057 MutexLock lock(sd->mutex);
6058 return sd->valid;
6059}
6060
6061const Glyph *TextServerAdvanced::_shaped_text_get_glyphs(const RID &p_shaped) const {
6062 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
6063 ERR_FAIL_COND_V(!sd, nullptr);
6064
6065 MutexLock lock(sd->mutex);
6066 if (!sd->valid) {
6067 const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);
6068 }
6069 return sd->glyphs.ptr();
6070}
6071
6072int64_t TextServerAdvanced::_shaped_text_get_glyph_count(const RID &p_shaped) const {
6073 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
6074 ERR_FAIL_COND_V(!sd, 0);
6075
6076 MutexLock lock(sd->mutex);
6077 if (!sd->valid) {
6078 const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);
6079 }
6080 return sd->glyphs.size();
6081}
6082
6083const Glyph *TextServerAdvanced::_shaped_text_sort_logical(const RID &p_shaped) {
6084 ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
6085 ERR_FAIL_COND_V(!sd, nullptr);
6086
6087 MutexLock lock(sd->mutex);
6088 if (!sd->valid) {
6089 const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);
6090 }
6091
6092 if (!sd->sort_valid) {
6093 sd->glyphs_logical = sd->glyphs;
6094 sd->glyphs_logical.sort_custom<GlyphCompare>();
6095 sd->sort_valid = true;
6096 }
6097
6098 return sd->glyphs_logical.ptr();
6099}
6100
6101Vector2i TextServerAdvanced::_shaped_text_get_range(const RID &p_shaped) const {
6102 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
6103 ERR_FAIL_COND_V(!sd, Vector2i());
6104
6105 MutexLock lock(sd->mutex);
6106 return Vector2(sd->start, sd->end);
6107}
6108
6109Array TextServerAdvanced::_shaped_text_get_objects(const RID &p_shaped) const {
6110 Array ret;
6111 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
6112 ERR_FAIL_COND_V(!sd, ret);
6113
6114 MutexLock lock(sd->mutex);
6115 for (const KeyValue<Variant, ShapedTextDataAdvanced::EmbeddedObject> &E : sd->objects) {
6116 ret.push_back(E.key);
6117 }
6118
6119 return ret;
6120}
6121
6122Rect2 TextServerAdvanced::_shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const {
6123 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
6124 ERR_FAIL_COND_V(!sd, Rect2());
6125
6126 MutexLock lock(sd->mutex);
6127 ERR_FAIL_COND_V(!sd->objects.has(p_key), Rect2());
6128 if (!sd->valid) {
6129 const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);
6130 }
6131 return sd->objects[p_key].rect;
6132}
6133
6134Size2 TextServerAdvanced::_shaped_text_get_size(const RID &p_shaped) const {
6135 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
6136 ERR_FAIL_COND_V(!sd, Size2());
6137
6138 MutexLock lock(sd->mutex);
6139 if (!sd->valid) {
6140 const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);
6141 }
6142 if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) {
6143 return Size2((sd->text_trimmed ? sd->width_trimmed : sd->width), sd->ascent + sd->descent + sd->extra_spacing[SPACING_TOP] + sd->extra_spacing[SPACING_BOTTOM]).ceil();
6144 } else {
6145 return Size2(sd->ascent + sd->descent + sd->extra_spacing[SPACING_TOP] + sd->extra_spacing[SPACING_BOTTOM], (sd->text_trimmed ? sd->width_trimmed : sd->width)).ceil();
6146 }
6147}
6148
6149double TextServerAdvanced::_shaped_text_get_ascent(const RID &p_shaped) const {
6150 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
6151 ERR_FAIL_COND_V(!sd, 0.0);
6152
6153 MutexLock lock(sd->mutex);
6154 if (!sd->valid) {
6155 const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);
6156 }
6157 return sd->ascent + sd->extra_spacing[SPACING_TOP];
6158}
6159
6160double TextServerAdvanced::_shaped_text_get_descent(const RID &p_shaped) const {
6161 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
6162 ERR_FAIL_COND_V(!sd, 0.0);
6163
6164 MutexLock lock(sd->mutex);
6165 if (!sd->valid) {
6166 const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);
6167 }
6168 return sd->descent + sd->extra_spacing[SPACING_BOTTOM];
6169}
6170
6171double TextServerAdvanced::_shaped_text_get_width(const RID &p_shaped) const {
6172 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
6173 ERR_FAIL_COND_V(!sd, 0.0);
6174
6175 MutexLock lock(sd->mutex);
6176 if (!sd->valid) {
6177 const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);
6178 }
6179 return Math::ceil(sd->text_trimmed ? sd->width_trimmed : sd->width);
6180}
6181
6182double TextServerAdvanced::_shaped_text_get_underline_position(const RID &p_shaped) const {
6183 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
6184 ERR_FAIL_COND_V(!sd, 0.0);
6185
6186 MutexLock lock(sd->mutex);
6187 if (!sd->valid) {
6188 const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);
6189 }
6190
6191 return sd->upos;
6192}
6193
6194double TextServerAdvanced::_shaped_text_get_underline_thickness(const RID &p_shaped) const {
6195 const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
6196 ERR_FAIL_COND_V(!sd, 0.0);
6197
6198 MutexLock lock(sd->mutex);
6199 if (!sd->valid) {
6200 const_cast<TextServerAdvanced *>(this)->_shaped_text_shape(p_shaped);
6201 }
6202
6203 return sd->uthk;
6204}
6205
6206void TextServerAdvanced::_insert_num_systems_lang() {
6207 // Eastern Arabic numerals.
6208 {
6209 NumSystemData ar;
6210 ar.lang.insert(StringName("ar")); // Arabic
6211 ar.lang.insert(StringName("ar_AE"));
6212 ar.lang.insert(StringName("ar_BH"));
6213 ar.lang.insert(StringName("ar_DJ"));
6214 ar.lang.insert(StringName("ar_EG"));
6215 ar.lang.insert(StringName("ar_ER"));
6216 ar.lang.insert(StringName("ar_IL"));
6217 ar.lang.insert(StringName("ar_IQ"));
6218 ar.lang.insert(StringName("ar_JO"));
6219 ar.lang.insert(StringName("ar_KM"));
6220 ar.lang.insert(StringName("ar_KW"));
6221 ar.lang.insert(StringName("ar_LB"));
6222 ar.lang.insert(StringName("ar_MR"));
6223 ar.lang.insert(StringName("ar_OM"));
6224 ar.lang.insert(StringName("ar_PS"));
6225 ar.lang.insert(StringName("ar_QA"));
6226 ar.lang.insert(StringName("ar_SA"));
6227 ar.lang.insert(StringName("ar_SD"));
6228 ar.lang.insert(StringName("ar_SO"));
6229 ar.lang.insert(StringName("ar_SS"));
6230 ar.lang.insert(StringName("ar_SY"));
6231 ar.lang.insert(StringName("ar_TD"));
6232 ar.lang.insert(StringName("ar_YE"));
6233 ar.lang.insert(StringName("ckb")); // Central Kurdish
6234 ar.lang.insert(StringName("ckb_IQ"));
6235 ar.lang.insert(StringName("ckb_IR"));
6236 ar.lang.insert(StringName("sd")); // Sindhi
6237 ar.lang.insert(StringName("sd_PK"));
6238 ar.lang.insert(StringName("sd_Arab"));
6239 ar.lang.insert(StringName("sd_Arab_PK"));
6240 ar.digits = U"٠١٢٣٤٥٦٧٨٩٫";
6241 ar.percent_sign = U"٪";
6242 ar.exp = U"اس";
6243 num_systems.push_back(ar);
6244 }
6245
6246 // Persian and Urdu numerals.
6247 {
6248 NumSystemData pr;
6249 pr.lang.insert(StringName("fa")); // Persian
6250 pr.lang.insert(StringName("fa_AF"));
6251 pr.lang.insert(StringName("fa_IR"));
6252 pr.lang.insert(StringName("ks")); // Kashmiri
6253 pr.lang.insert(StringName("ks_IN"));
6254 pr.lang.insert(StringName("ks_Arab"));
6255 pr.lang.insert(StringName("ks_Arab_IN"));
6256 pr.lang.insert(StringName("lrc")); // Northern Luri
6257 pr.lang.insert(StringName("lrc_IQ"));
6258 pr.lang.insert(StringName("lrc_IR"));
6259 pr.lang.insert(StringName("mzn")); // Mazanderani
6260 pr.lang.insert(StringName("mzn_IR"));
6261 pr.lang.insert(StringName("pa_PK")); // Panjabi
6262 pr.lang.insert(StringName("pa_Arab"));
6263 pr.lang.insert(StringName("pa_Arab_PK"));
6264 pr.lang.insert(StringName("ps")); // Pushto
6265 pr.lang.insert(StringName("ps_AF"));
6266 pr.lang.insert(StringName("ps_PK"));
6267 pr.lang.insert(StringName("ur_IN")); // Urdu
6268 pr.lang.insert(StringName("uz_AF")); // Uzbek
6269 pr.lang.insert(StringName("uz_Arab"));
6270 pr.lang.insert(StringName("uz_Arab_AF"));
6271 pr.digits = U"۰۱۲۳۴۵۶۷۸۹٫";
6272 pr.percent_sign = U"٪";
6273 pr.exp = U"اس";
6274 num_systems.push_back(pr);
6275 }
6276
6277 // Bengali numerals.
6278 {
6279 NumSystemData bn;
6280 bn.lang.insert(StringName("as")); // Assamese
6281 bn.lang.insert(StringName("as_IN"));
6282 bn.lang.insert(StringName("bn")); // Bengali
6283 bn.lang.insert(StringName("bn_BD"));
6284 bn.lang.insert(StringName("bn_IN"));
6285 bn.lang.insert(StringName("mni")); // Manipuri
6286 bn.lang.insert(StringName("mni_IN"));
6287 bn.lang.insert(StringName("mni_Beng"));
6288 bn.lang.insert(StringName("mni_Beng_IN"));
6289 bn.digits = U"০১২৩৪৫৬৭৮৯.";
6290 bn.percent_sign = U"%";
6291 bn.exp = U"e";
6292 num_systems.push_back(bn);
6293 }
6294
6295 // Devanagari numerals.
6296 {
6297 NumSystemData mr;
6298 mr.lang.insert(StringName("mr")); // Marathi
6299 mr.lang.insert(StringName("mr_IN"));
6300 mr.lang.insert(StringName("ne")); // Nepali
6301 mr.lang.insert(StringName("ne_IN"));
6302 mr.lang.insert(StringName("ne_NP"));
6303 mr.lang.insert(StringName("sa")); // Sanskrit
6304 mr.lang.insert(StringName("sa_IN"));
6305 mr.digits = U"०१२३४५६७८९.";
6306 mr.percent_sign = U"%";
6307 mr.exp = U"e";
6308 num_systems.push_back(mr);
6309 }
6310
6311 // Dzongkha numerals.
6312 {
6313 NumSystemData dz;
6314 dz.lang.insert(StringName("dz")); // Dzongkha
6315 dz.lang.insert(StringName("dz_BT"));
6316 dz.digits = U"༠༡༢༣༤༥༦༧༨༩.";
6317 dz.percent_sign = U"%";
6318 dz.exp = U"e";
6319 num_systems.push_back(dz);
6320 }
6321
6322 // Santali numerals.
6323 {
6324 NumSystemData sat;
6325 sat.lang.insert(StringName("sat")); // Santali
6326 sat.lang.insert(StringName("sat_IN"));
6327 sat.lang.insert(StringName("sat_Olck"));
6328 sat.lang.insert(StringName("sat_Olck_IN"));
6329 sat.digits = U"᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙.";
6330 sat.percent_sign = U"%";
6331 sat.exp = U"e";
6332 num_systems.push_back(sat);
6333 }
6334
6335 // Burmese numerals.
6336 {
6337 NumSystemData my;
6338 my.lang.insert(StringName("my")); // Burmese
6339 my.lang.insert(StringName("my_MM"));
6340 my.digits = U"၀၁၂၃၄၅၆၇၈၉.";
6341 my.percent_sign = U"%";
6342 my.exp = U"e";
6343 num_systems.push_back(my);
6344 }
6345
6346 // Chakma numerals.
6347 {
6348 NumSystemData ccp;
6349 ccp.lang.insert(StringName("ccp")); // Chakma
6350 ccp.lang.insert(StringName("ccp_BD"));
6351 ccp.lang.insert(StringName("ccp_IN"));
6352 ccp.digits = U"𑄶𑄷𑄸𑄹𑄺𑄻𑄼𑄽𑄾𑄿.";
6353 ccp.percent_sign = U"%";
6354 ccp.exp = U"e";
6355 num_systems.push_back(ccp);
6356 }
6357
6358 // Adlam numerals.
6359 {
6360 NumSystemData ff;
6361 ff.lang.insert(StringName("ff")); // Fulah
6362 ff.lang.insert(StringName("ff_Adlm_BF"));
6363 ff.lang.insert(StringName("ff_Adlm_CM"));
6364 ff.lang.insert(StringName("ff_Adlm_GH"));
6365 ff.lang.insert(StringName("ff_Adlm_GM"));
6366 ff.lang.insert(StringName("ff_Adlm_GN"));
6367 ff.lang.insert(StringName("ff_Adlm_GW"));
6368 ff.lang.insert(StringName("ff_Adlm_LR"));
6369 ff.lang.insert(StringName("ff_Adlm_MR"));
6370 ff.lang.insert(StringName("ff_Adlm_NE"));
6371 ff.lang.insert(StringName("ff_Adlm_NG"));
6372 ff.lang.insert(StringName("ff_Adlm_SL"));
6373 ff.lang.insert(StringName("ff_Adlm_SN"));
6374 ff.digits = U"𞥐𞥑𞥒𞥓𞥔𞥕𞥖𞥗𞥘𞥙.";
6375 ff.percent_sign = U"%";
6376 ff.exp = U"e";
6377 num_systems.push_back(ff);
6378 }
6379}
6380
6381String TextServerAdvanced::_format_number(const String &p_string, const String &p_language) const {
6382 const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
6383
6384 String res = p_string;
6385 for (int i = 0; i < num_systems.size(); i++) {
6386 if (num_systems[i].lang.has(lang)) {
6387 if (num_systems[i].digits.is_empty()) {
6388 return p_string;
6389 }
6390 res.replace("e", num_systems[i].exp);
6391 res.replace("E", num_systems[i].exp);
6392 char32_t *data = res.ptrw();
6393 for (int j = 0; j < res.length(); j++) {
6394 if (data[j] >= 0x30 && data[j] <= 0x39) {
6395 data[j] = num_systems[i].digits[data[j] - 0x30];
6396 } else if (data[j] == '.' || data[j] == ',') {
6397 data[j] = num_systems[i].digits[10];
6398 }
6399 }
6400 break;
6401 }
6402 }
6403 return res;
6404}
6405
6406String TextServerAdvanced::_parse_number(const String &p_string, const String &p_language) const {
6407 const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
6408
6409 String res = p_string;
6410 for (int i = 0; i < num_systems.size(); i++) {
6411 if (num_systems[i].lang.has(lang)) {
6412 if (num_systems[i].digits.is_empty()) {
6413 return p_string;
6414 }
6415 res.replace(num_systems[i].exp, "e");
6416 char32_t *data = res.ptrw();
6417 for (int j = 0; j < res.length(); j++) {
6418 if (data[j] == num_systems[i].digits[10]) {
6419 data[j] = '.';
6420 } else {
6421 for (int k = 0; k < 10; k++) {
6422 if (data[j] == num_systems[i].digits[k]) {
6423 data[j] = 0x30 + k;
6424 }
6425 }
6426 }
6427 }
6428 break;
6429 }
6430 }
6431 return res;
6432}
6433
6434String TextServerAdvanced::_percent_sign(const String &p_language) const {
6435 const StringName lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
6436
6437 for (int i = 0; i < num_systems.size(); i++) {
6438 if (num_systems[i].lang.has(lang)) {
6439 if (num_systems[i].percent_sign.is_empty()) {
6440 return "%";
6441 }
6442 return num_systems[i].percent_sign;
6443 }
6444 }
6445 return "%";
6446}
6447
6448int64_t TextServerAdvanced::_is_confusable(const String &p_string, const PackedStringArray &p_dict) const {
6449#ifndef ICU_STATIC_DATA
6450 if (!icu_data_loaded) {
6451 return -1;
6452 }
6453#endif
6454 UErrorCode status = U_ZERO_ERROR;
6455 int64_t match_index = -1;
6456
6457 Char16String utf16 = p_string.utf16();
6458 Vector<UChar *> skeletons;
6459 skeletons.resize(p_dict.size());
6460
6461 if (sc_conf == nullptr) {
6462 sc_conf = uspoof_open(&status);
6463 uspoof_setChecks(sc_conf, USPOOF_CONFUSABLE, &status);
6464 }
6465 for (int i = 0; i < p_dict.size(); i++) {
6466 Char16String word = p_dict[i].utf16();
6467 int32_t len = uspoof_getSkeleton(sc_conf, 0, word.get_data(), -1, NULL, 0, &status);
6468 skeletons.write[i] = (UChar *)memalloc(++len * sizeof(UChar));
6469 status = U_ZERO_ERROR;
6470 uspoof_getSkeleton(sc_conf, 0, word.get_data(), -1, skeletons.write[i], len, &status);
6471 }
6472
6473 int32_t len = uspoof_getSkeleton(sc_conf, 0, utf16.get_data(), -1, NULL, 0, &status);
6474 UChar *skel = (UChar *)memalloc(++len * sizeof(UChar));
6475 status = U_ZERO_ERROR;
6476 uspoof_getSkeleton(sc_conf, 0, utf16.get_data(), -1, skel, len, &status);
6477 for (int i = 0; i < skeletons.size(); i++) {
6478 if (u_strcmp(skel, skeletons[i]) == 0) {
6479 match_index = i;
6480 break;
6481 }
6482 }
6483 memfree(skel);
6484
6485 for (int i = 0; i < skeletons.size(); i++) {
6486 memfree(skeletons.write[i]);
6487 }
6488
6489 ERR_FAIL_COND_V_MSG(U_FAILURE(status), -1, u_errorName(status));
6490
6491 return match_index;
6492}
6493
6494bool TextServerAdvanced::_spoof_check(const String &p_string) const {
6495#ifndef ICU_STATIC_DATA
6496 if (!icu_data_loaded) {
6497 return false;
6498 }
6499#endif
6500 UErrorCode status = U_ZERO_ERROR;
6501 Char16String utf16 = p_string.utf16();
6502
6503 if (allowed == nullptr) {
6504 allowed = uset_openEmpty();
6505 uset_addAll(allowed, uspoof_getRecommendedSet(&status));
6506 uset_addAll(allowed, uspoof_getInclusionSet(&status));
6507 }
6508 if (sc_spoof == nullptr) {
6509 sc_spoof = uspoof_open(&status);
6510 uspoof_setAllowedChars(sc_spoof, allowed, &status);
6511 uspoof_setRestrictionLevel(sc_spoof, USPOOF_MODERATELY_RESTRICTIVE);
6512 }
6513
6514 int32_t bitmask = uspoof_check(sc_spoof, utf16.get_data(), -1, NULL, &status);
6515 ERR_FAIL_COND_V_MSG(U_FAILURE(status), false, u_errorName(status));
6516
6517 return (bitmask != 0);
6518}
6519
6520String TextServerAdvanced::_strip_diacritics(const String &p_string) const {
6521#ifndef ICU_STATIC_DATA
6522 if (!icu_data_loaded) {
6523 return TextServer::strip_diacritics(p_string);
6524 }
6525#endif
6526 UErrorCode err = U_ZERO_ERROR;
6527
6528 // Get NFKD normalizer singleton.
6529 const UNormalizer2 *unorm = unorm2_getNFKDInstance(&err);
6530 ERR_FAIL_COND_V_MSG(U_FAILURE(err), TextServer::strip_diacritics(p_string), u_errorName(err));
6531
6532 // Convert to UTF-16.
6533 Char16String utf16 = p_string.utf16();
6534
6535 // Normalize.
6536 Vector<char16_t> normalized;
6537 err = U_ZERO_ERROR;
6538 int32_t len = unorm2_normalize(unorm, utf16.get_data(), -1, nullptr, 0, &err);
6539 ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, TextServer::strip_diacritics(p_string), u_errorName(err));
6540 normalized.resize(len);
6541 err = U_ZERO_ERROR;
6542 unorm2_normalize(unorm, utf16.get_data(), -1, normalized.ptrw(), len, &err);
6543 ERR_FAIL_COND_V_MSG(U_FAILURE(err), TextServer::strip_diacritics(p_string), u_errorName(err));
6544
6545 // Convert back to UTF-32.
6546 String normalized_string = String::utf16(normalized.ptr(), len);
6547
6548 // Strip combining characters.
6549 String result;
6550 for (int i = 0; i < normalized_string.length(); i++) {
6551 if (u_getCombiningClass(normalized_string[i]) == 0) {
6552#ifdef GDEXTENSION
6553 result = result + String::chr(normalized_string[i]);
6554#else
6555 result = result + normalized_string[i];
6556#endif
6557 }
6558 }
6559 return result;
6560}
6561
6562String TextServerAdvanced::_string_to_upper(const String &p_string, const String &p_language) const {
6563#ifndef ICU_STATIC_DATA
6564 if (!icu_data_loaded) {
6565 return p_string.to_upper();
6566 }
6567#endif
6568
6569 if (p_string.is_empty()) {
6570 return p_string;
6571 }
6572 const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
6573
6574 // Convert to UTF-16.
6575 Char16String utf16 = p_string.utf16();
6576
6577 Vector<char16_t> upper;
6578 UErrorCode err = U_ZERO_ERROR;
6579 int32_t len = u_strToUpper(nullptr, 0, utf16.get_data(), -1, lang.ascii().get_data(), &err);
6580 ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));
6581 upper.resize(len);
6582 err = U_ZERO_ERROR;
6583 u_strToUpper(upper.ptrw(), len, utf16.get_data(), -1, lang.ascii().get_data(), &err);
6584 ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));
6585
6586 // Convert back to UTF-32.
6587 return String::utf16(upper.ptr(), len);
6588}
6589
6590String TextServerAdvanced::_string_to_lower(const String &p_string, const String &p_language) const {
6591#ifndef ICU_STATIC_DATA
6592 if (!icu_data_loaded) {
6593 return p_string.to_lower();
6594 }
6595#endif
6596
6597 if (p_string.is_empty()) {
6598 return p_string;
6599 }
6600 const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
6601 // Convert to UTF-16.
6602 Char16String utf16 = p_string.utf16();
6603
6604 Vector<char16_t> lower;
6605 UErrorCode err = U_ZERO_ERROR;
6606 int32_t len = u_strToLower(nullptr, 0, utf16.get_data(), -1, lang.ascii().get_data(), &err);
6607 ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));
6608 lower.resize(len);
6609 err = U_ZERO_ERROR;
6610 u_strToLower(lower.ptrw(), len, utf16.get_data(), -1, lang.ascii().get_data(), &err);
6611 ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));
6612
6613 // Convert back to UTF-32.
6614 return String::utf16(lower.ptr(), len);
6615}
6616
6617PackedInt32Array TextServerAdvanced::_string_get_word_breaks(const String &p_string, const String &p_language, int64_t p_chars_per_line) const {
6618 const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
6619 // Convert to UTF-16.
6620 Char16String utf16 = p_string.utf16();
6621
6622 HashSet<int> breaks;
6623 UErrorCode err = U_ZERO_ERROR;
6624 UBreakIterator *bi = ubrk_open(UBRK_LINE, lang.ascii().get_data(), (const UChar *)utf16.get_data(), utf16.length(), &err);
6625 if (U_SUCCESS(err)) {
6626 while (ubrk_next(bi) != UBRK_DONE) {
6627 int pos = _convert_pos(p_string, utf16, ubrk_current(bi)) - 1;
6628 if (pos != p_string.length() - 1) {
6629 breaks.insert(pos);
6630 }
6631 }
6632 ubrk_close(bi);
6633 }
6634
6635 PackedInt32Array ret;
6636
6637 int line_start = 0;
6638 int line_end = 0; // End of last word on current line.
6639 int word_start = 0; // -1 if no word encountered. Leading spaces are part of a word.
6640 int word_length = 0;
6641
6642 for (int i = 0; i < p_string.length(); i++) {
6643 const char32_t c = p_string[i];
6644
6645 if (is_linebreak(c)) {
6646 // Force newline.
6647 ret.push_back(line_start);
6648 ret.push_back(i);
6649 line_start = i + 1;
6650 line_end = line_start;
6651 word_start = line_start;
6652 word_length = 0;
6653 } else if (c == 0xfffc) {
6654 continue;
6655 } else if ((u_ispunct(c) && c != 0x005F) || is_underscore(c) || c == '\t' || is_whitespace(c)) {
6656 // A whitespace ends current word.
6657 if (word_length > 0) {
6658 line_end = i - 1;
6659 word_start = -1;
6660 word_length = 0;
6661 }
6662 } else if (breaks.has(i)) {
6663 // End current word, no space.
6664 if (word_length > 0) {
6665 line_end = i;
6666 word_start = i + 1;
6667 word_length = 0;
6668 }
6669 if (p_chars_per_line <= 0) {
6670 ret.push_back(line_start);
6671 ret.push_back(line_end + 1);
6672 line_start = word_start;
6673 line_end = line_start;
6674 }
6675 } else {
6676 if (word_start == -1) {
6677 word_start = i;
6678 if (p_chars_per_line <= 0) {
6679 ret.push_back(line_start);
6680 ret.push_back(line_end + 1);
6681 line_start = word_start;
6682 line_end = line_start;
6683 }
6684 }
6685 word_length += 1;
6686
6687 if (p_chars_per_line > 0) {
6688 if (word_length > p_chars_per_line) {
6689 // Word too long: wrap before current character.
6690 ret.push_back(line_start);
6691 ret.push_back(i);
6692 line_start = i;
6693 line_end = i;
6694 word_start = i;
6695 word_length = 1;
6696 } else if (i - line_start + 1 > p_chars_per_line) {
6697 // Line too long: wrap after the last word.
6698 ret.push_back(line_start);
6699 ret.push_back(line_end + 1);
6700 line_start = word_start;
6701 line_end = line_start;
6702 }
6703 }
6704 }
6705 }
6706 if (line_start < p_string.length()) {
6707 ret.push_back(line_start);
6708 ret.push_back(p_string.length());
6709 }
6710 return ret;
6711}
6712
6713PackedInt32Array TextServerAdvanced::_string_get_character_breaks(const String &p_string, const String &p_language) const {
6714 const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
6715 // Convert to UTF-16.
6716 Char16String utf16 = p_string.utf16();
6717
6718 PackedInt32Array ret;
6719
6720 UErrorCode err = U_ZERO_ERROR;
6721 UBreakIterator *bi = ubrk_open(UBRK_CHARACTER, lang.ascii().get_data(), (const UChar *)utf16.get_data(), utf16.length(), &err);
6722 if (U_SUCCESS(err)) {
6723 while (ubrk_next(bi) != UBRK_DONE) {
6724 int pos = _convert_pos(p_string, utf16, ubrk_current(bi));
6725 ret.push_back(pos);
6726 }
6727 ubrk_close(bi);
6728 } else {
6729 for (int i = 0; i <= p_string.size(); i++) {
6730 ret.push_back(i);
6731 }
6732 }
6733
6734 return ret;
6735}
6736
6737bool TextServerAdvanced::_is_valid_identifier(const String &p_string) const {
6738#ifndef ICU_STATIC_DATA
6739 if (!icu_data_loaded) {
6740 WARN_PRINT_ONCE("ICU data is not loaded, Unicode security and spoofing detection disabled.");
6741 return TextServer::is_valid_identifier(p_string);
6742 }
6743#endif
6744
6745 enum UAX31SequenceStatus {
6746 SEQ_NOT_STARTED,
6747 SEQ_STARTED,
6748 SEQ_STARTED_VIR,
6749 SEQ_NEAR_END,
6750 };
6751
6752 const char32_t *str = p_string.ptr();
6753 int len = p_string.length();
6754
6755 if (len == 0) {
6756 return false; // Empty string.
6757 }
6758
6759 UErrorCode err = U_ZERO_ERROR;
6760 Char16String utf16 = p_string.utf16();
6761 const UNormalizer2 *norm_c = unorm2_getNFCInstance(&err);
6762 if (U_FAILURE(err)) {
6763 return false; // Failed to load normalizer.
6764 }
6765 bool isnurom = unorm2_isNormalized(norm_c, utf16.get_data(), utf16.length(), &err);
6766 if (U_FAILURE(err) || !isnurom) {
6767 return false; // Do not conform to Normalization Form C.
6768 }
6769
6770 UAX31SequenceStatus A1_sequence_status = SEQ_NOT_STARTED;
6771 UScriptCode A1_scr = USCRIPT_INHERITED;
6772 UAX31SequenceStatus A2_sequence_status = SEQ_NOT_STARTED;
6773 UScriptCode A2_scr = USCRIPT_INHERITED;
6774 UAX31SequenceStatus B_sequence_status = SEQ_NOT_STARTED;
6775 UScriptCode B_scr = USCRIPT_INHERITED;
6776
6777 for (int i = 0; i < len; i++) {
6778 err = U_ZERO_ERROR;
6779 UScriptCode scr = uscript_getScript(str[i], &err);
6780 if (U_FAILURE(err)) {
6781 return false; // Invalid script.
6782 }
6783 if (uscript_getUsage(scr) != USCRIPT_USAGE_RECOMMENDED) {
6784 return false; // Not a recommended script.
6785 }
6786 uint8_t cat = u_charType(str[i]);
6787 int32_t jt = u_getIntPropertyValue(str[i], UCHAR_JOINING_TYPE);
6788
6789 // UAX #31 section 2.3 subsections A1, A2 and B, check ZWNJ and ZWJ usage.
6790 switch (A1_sequence_status) {
6791 case SEQ_NEAR_END: {
6792 if ((A1_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A1_scr)) {
6793 return false; // Mixed script.
6794 }
6795 if (jt == U_JT_RIGHT_JOINING || jt == U_JT_DUAL_JOINING) {
6796 A1_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.
6797 } else if (jt != U_JT_TRANSPARENT) {
6798 return false; // Invalid end of sequence.
6799 }
6800 } break;
6801 case SEQ_STARTED: {
6802 if ((A1_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A1_scr)) {
6803 A1_sequence_status = SEQ_NOT_STARTED; // Reset.
6804 } else {
6805 if (jt != U_JT_TRANSPARENT) {
6806 if (str[i] == 0x200C /*ZWNJ*/) {
6807 A1_sequence_status = SEQ_NEAR_END;
6808 continue;
6809 } else {
6810 A1_sequence_status = SEQ_NOT_STARTED; // Reset.
6811 }
6812 }
6813 }
6814 } break;
6815 default:
6816 break;
6817 }
6818 if (A1_sequence_status == SEQ_NOT_STARTED) {
6819 if (jt == U_JT_LEFT_JOINING || jt == U_JT_DUAL_JOINING) {
6820 A1_sequence_status = SEQ_STARTED;
6821 A1_scr = scr;
6822 }
6823 };
6824
6825 switch (A2_sequence_status) {
6826 case SEQ_NEAR_END: {
6827 if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {
6828 return false; // Mixed script.
6829 }
6830 if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {
6831 A2_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.
6832 } else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {
6833 return false; // Invalid end of sequence.
6834 }
6835 } break;
6836 case SEQ_STARTED_VIR: {
6837 if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {
6838 A2_sequence_status = SEQ_NOT_STARTED; // Reset.
6839 } else {
6840 if (str[i] == 0x200C /*ZWNJ*/) {
6841 A2_sequence_status = SEQ_NEAR_END;
6842 continue;
6843 } else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {
6844 A2_sequence_status = SEQ_NOT_STARTED; // Reset.
6845 }
6846 }
6847 } break;
6848 case SEQ_STARTED: {
6849 if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {
6850 A2_sequence_status = SEQ_NOT_STARTED; // Reset.
6851 } else {
6852 if (u_getCombiningClass(str[i]) == 9 /*Virama Combining Class*/) {
6853 A2_sequence_status = SEQ_STARTED_VIR;
6854 } else if (cat != U_MODIFIER_LETTER) {
6855 A2_sequence_status = SEQ_NOT_STARTED; // Reset.
6856 }
6857 }
6858 } break;
6859 default:
6860 break;
6861 }
6862 if (A2_sequence_status == SEQ_NOT_STARTED) {
6863 if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {
6864 A2_sequence_status = SEQ_STARTED;
6865 A2_scr = scr;
6866 }
6867 }
6868
6869 switch (B_sequence_status) {
6870 case SEQ_NEAR_END: {
6871 if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {
6872 return false; // Mixed script.
6873 }
6874 if (u_getIntPropertyValue(str[i], UCHAR_INDIC_SYLLABIC_CATEGORY) != U_INSC_VOWEL_DEPENDENT) {
6875 B_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.
6876 } else {
6877 return false; // Invalid end of sequence.
6878 }
6879 } break;
6880 case SEQ_STARTED_VIR: {
6881 if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {
6882 B_sequence_status = SEQ_NOT_STARTED; // Reset.
6883 } else {
6884 if (str[i] == 0x200D /*ZWJ*/) {
6885 B_sequence_status = SEQ_NEAR_END;
6886 continue;
6887 } else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {
6888 B_sequence_status = SEQ_NOT_STARTED; // Reset.
6889 }
6890 }
6891 } break;
6892 case SEQ_STARTED: {
6893 if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {
6894 B_sequence_status = SEQ_NOT_STARTED; // Reset.
6895 } else {
6896 if (u_getCombiningClass(str[i]) == 9 /*Virama Combining Class*/) {
6897 B_sequence_status = SEQ_STARTED_VIR;
6898 } else if (cat != U_MODIFIER_LETTER) {
6899 B_sequence_status = SEQ_NOT_STARTED; // Reset.
6900 }
6901 }
6902 } break;
6903 default:
6904 break;
6905 }
6906 if (B_sequence_status == SEQ_NOT_STARTED) {
6907 if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {
6908 B_sequence_status = SEQ_STARTED;
6909 B_scr = scr;
6910 }
6911 }
6912
6913 if (u_hasBinaryProperty(str[i], UCHAR_PATTERN_SYNTAX) || u_hasBinaryProperty(str[i], UCHAR_PATTERN_WHITE_SPACE) || u_hasBinaryProperty(str[i], UCHAR_NONCHARACTER_CODE_POINT)) {
6914 return false; // Not a XID_Start or XID_Continue character.
6915 }
6916 if (i == 0) {
6917 if (!(cat == U_LOWERCASE_LETTER || cat == U_UPPERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_OTHER_LETTER || cat == U_MODIFIER_LETTER || cat == U_LETTER_NUMBER || str[0] == 0x2118 || str[0] == 0x212E || str[0] == 0x309B || str[0] == 0x309C || str[0] == 0x005F)) {
6918 return false; // Not a XID_Start character.
6919 }
6920 } else {
6921 if (!(cat == U_LOWERCASE_LETTER || cat == U_UPPERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_OTHER_LETTER || cat == U_MODIFIER_LETTER || cat == U_LETTER_NUMBER || cat == U_NON_SPACING_MARK || cat == U_COMBINING_SPACING_MARK || cat == U_DECIMAL_DIGIT_NUMBER || cat == U_CONNECTOR_PUNCTUATION || str[i] == 0x2118 || str[i] == 0x212E || str[i] == 0x309B || str[i] == 0x309C || str[i] == 0x1369 || str[i] == 0x1371 || str[i] == 0x00B7 || str[i] == 0x0387 || str[i] == 0x19DA || str[i] == 0x0E33 || str[i] == 0x0EB3 || str[i] == 0xFF9E || str[i] == 0xFF9F)) {
6922 return false; // Not a XID_Continue character.
6923 }
6924 }
6925 }
6926 return true;
6927}
6928
6929TextServerAdvanced::TextServerAdvanced() {
6930 _insert_num_systems_lang();
6931 _insert_feature_sets();
6932 _bmp_create_font_funcs();
6933}
6934
6935void TextServerAdvanced::_cleanup() {
6936 _THREAD_SAFE_METHOD_
6937 for (const KeyValue<SystemFontKey, SystemFontCache> &E : system_fonts) {
6938 const Vector<SystemFontCacheRec> &sysf_cache = E.value.var;
6939 for (const SystemFontCacheRec &F : sysf_cache) {
6940 _free_rid(F.rid);
6941 }
6942 }
6943 system_fonts.clear();
6944 system_font_data.clear();
6945}
6946
6947TextServerAdvanced::~TextServerAdvanced() {
6948 _bmp_free_font_funcs();
6949#ifdef MODULE_FREETYPE_ENABLED
6950 if (ft_library != nullptr) {
6951 FT_Done_FreeType(ft_library);
6952 }
6953#endif
6954 if (sc_spoof != nullptr) {
6955 uspoof_close(sc_spoof);
6956 sc_spoof = nullptr;
6957 }
6958 if (sc_conf != nullptr) {
6959 uspoof_close(sc_conf);
6960 sc_conf = nullptr;
6961 }
6962 if (allowed != nullptr) {
6963 uset_close(allowed);
6964 allowed = nullptr;
6965 }
6966
6967 std::atexit(u_cleanup);
6968}
6969