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