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