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