Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/text_server_fb/text_server_fb.cpp
20957 views
1
/**************************************************************************/
2
/* text_server_fb.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_fb.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
#define OT_TAG(m_c1, m_c2, m_c3, m_c4) ((int32_t)((((uint32_t)(m_c1) & 0xff) << 24) | (((uint32_t)(m_c2) & 0xff) << 16) | (((uint32_t)(m_c3) & 0xff) << 8) | ((uint32_t)(m_c4) & 0xff)))
44
45
using namespace godot;
46
47
#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get_setting_with_override(m_var)
48
49
#elif defined(GODOT_MODULE)
50
// Headers for building as built-in module.
51
52
#include "core/config/project_settings.h"
53
#include "core/error/error_macros.h"
54
#include "core/io/file_access.h"
55
#include "core/string/print_string.h"
56
#include "core/string/translation_server.h"
57
#include "servers/rendering/rendering_server.h"
58
59
#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg.
60
61
#endif
62
63
// Thirdparty headers.
64
65
#ifdef MODULE_MSDFGEN_ENABLED
66
GODOT_GCC_WARNING_PUSH_AND_IGNORE("-Wshadow")
67
GODOT_MSVC_WARNING_PUSH_AND_IGNORE(4458) // "Declaration of 'identifier' hides class member".
68
69
#include <core/EdgeHolder.h>
70
#include <core/ShapeDistanceFinder.h>
71
#include <core/contour-combiners.h>
72
#include <core/edge-selectors.h>
73
#include <msdfgen.h>
74
75
GODOT_GCC_WARNING_POP
76
GODOT_MSVC_WARNING_POP
77
#endif
78
79
#ifdef MODULE_FREETYPE_ENABLED
80
#include FT_SFNT_NAMES_H
81
#include FT_TRUETYPE_IDS_H
82
#ifdef MODULE_SVG_ENABLED
83
#include "thorvg_svg_in_ot.h"
84
#endif
85
#endif
86
87
/*************************************************************************/
88
89
bool TextServerFallback::_has_feature(Feature p_feature) const {
90
switch (p_feature) {
91
case FEATURE_SIMPLE_LAYOUT:
92
case FEATURE_FONT_BITMAP:
93
#ifdef MODULE_FREETYPE_ENABLED
94
case FEATURE_FONT_DYNAMIC:
95
#endif
96
#ifdef MODULE_MSDFGEN_ENABLED
97
case FEATURE_FONT_MSDF:
98
#endif
99
return true;
100
default: {
101
}
102
}
103
return false;
104
}
105
106
String TextServerFallback::_get_name() const {
107
#ifdef GDEXTENSION
108
return "Fallback (GDExtension)";
109
#elif defined(GODOT_MODULE)
110
return "Fallback (Built-in)";
111
#endif
112
}
113
114
int64_t TextServerFallback::_get_features() const {
115
int64_t interface_features = FEATURE_SIMPLE_LAYOUT | FEATURE_FONT_BITMAP;
116
#ifdef MODULE_FREETYPE_ENABLED
117
interface_features |= FEATURE_FONT_DYNAMIC;
118
#endif
119
#ifdef MODULE_MSDFGEN_ENABLED
120
interface_features |= FEATURE_FONT_MSDF;
121
#endif
122
123
return interface_features;
124
}
125
126
void TextServerFallback::_free_rid(const RID &p_rid) {
127
_THREAD_SAFE_METHOD_
128
if (font_owner.owns(p_rid)) {
129
MutexLock ftlock(ft_mutex);
130
131
FontFallback *fd = font_owner.get_or_null(p_rid);
132
for (const KeyValue<Vector2i, FontForSizeFallback *> &ffsd : fd->cache) {
133
OversamplingLevel *ol = oversampling_levels.getptr(ffsd.value->viewport_oversampling);
134
if (ol != nullptr) {
135
ol->fonts.erase(ffsd.value);
136
}
137
}
138
{
139
MutexLock lock(fd->mutex);
140
font_owner.free(p_rid);
141
}
142
memdelete(fd);
143
} else if (font_var_owner.owns(p_rid)) {
144
MutexLock ftlock(ft_mutex);
145
146
FontFallbackLinkedVariation *fdv = font_var_owner.get_or_null(p_rid);
147
{
148
font_var_owner.free(p_rid);
149
}
150
memdelete(fdv);
151
} else if (shaped_owner.owns(p_rid)) {
152
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_rid);
153
{
154
MutexLock lock(sd->mutex);
155
shaped_owner.free(p_rid);
156
}
157
memdelete(sd);
158
}
159
}
160
161
bool TextServerFallback::_has(const RID &p_rid) {
162
_THREAD_SAFE_METHOD_
163
return font_owner.owns(p_rid) || shaped_owner.owns(p_rid);
164
}
165
166
String TextServerFallback::_get_support_data_filename() const {
167
return "";
168
}
169
170
String TextServerFallback::_get_support_data_info() const {
171
return "Not supported";
172
}
173
174
bool TextServerFallback::_load_support_data(const String &p_filename) {
175
return false; // No extra data used.
176
}
177
178
bool TextServerFallback::_save_support_data(const String &p_filename) const {
179
return false; // No extra data used.
180
}
181
182
PackedByteArray TextServerFallback::_get_support_data() const {
183
return PackedByteArray(); // No extra data used.
184
}
185
186
bool TextServerFallback::_is_locale_using_support_data(const String &p_locale) const {
187
return false; // No data support.
188
}
189
190
bool TextServerFallback::_is_locale_right_to_left(const String &p_locale) const {
191
return false; // No RTL support.
192
}
193
194
_FORCE_INLINE_ void TextServerFallback::_insert_feature(const StringName &p_name, int32_t p_tag) {
195
feature_sets.insert(p_name, p_tag);
196
feature_sets_inv.insert(p_tag, p_name);
197
}
198
199
void TextServerFallback::_insert_feature_sets() {
200
// Registered OpenType variation tag.
201
_insert_feature("italic", OT_TAG('i', 't', 'a', 'l'));
202
_insert_feature("optical_size", OT_TAG('o', 'p', 's', 'z'));
203
_insert_feature("slant", OT_TAG('s', 'l', 'n', 't'));
204
_insert_feature("width", OT_TAG('w', 'd', 't', 'h'));
205
_insert_feature("weight", OT_TAG('w', 'g', 'h', 't'));
206
}
207
208
_FORCE_INLINE_ int32_t ot_tag_from_string(const char *p_str, int p_len) {
209
char tag[4];
210
uint32_t i;
211
212
if (!p_str || !p_len || !*p_str) {
213
return OT_TAG(0, 0, 0, 0);
214
}
215
216
if (p_len < 0 || p_len > 4) {
217
p_len = 4;
218
}
219
for (i = 0; i < (uint32_t)p_len && p_str[i]; i++) {
220
tag[i] = p_str[i];
221
}
222
223
for (; i < 4; i++) {
224
tag[i] = ' ';
225
}
226
227
return OT_TAG(tag[0], tag[1], tag[2], tag[3]);
228
}
229
230
int64_t TextServerFallback::_name_to_tag(const String &p_name) const {
231
if (feature_sets.has(p_name)) {
232
return feature_sets[p_name];
233
}
234
235
// No readable name, use tag string.
236
return ot_tag_from_string(p_name.replace("custom_", "").ascii().get_data(), -1);
237
}
238
239
_FORCE_INLINE_ void ot_tag_to_string(int32_t p_tag, char *p_buf) {
240
p_buf[0] = (char)(uint8_t)(p_tag >> 24);
241
p_buf[1] = (char)(uint8_t)(p_tag >> 16);
242
p_buf[2] = (char)(uint8_t)(p_tag >> 8);
243
p_buf[3] = (char)(uint8_t)(p_tag >> 0);
244
}
245
246
String TextServerFallback::_tag_to_name(int64_t p_tag) const {
247
if (feature_sets_inv.has(p_tag)) {
248
return feature_sets_inv[p_tag];
249
}
250
251
// No readable name, use tag string.
252
char name[5];
253
memset(name, 0, 5);
254
ot_tag_to_string(p_tag, name);
255
return String("custom_") + String(name);
256
}
257
258
/*************************************************************************/
259
/* Font Glyph Rendering */
260
/*************************************************************************/
261
262
_FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_texture_pos_for_glyph(FontForSizeFallback *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height, bool p_msdf) const {
263
FontTexturePosition ret;
264
265
int mw = p_width;
266
int mh = p_height;
267
268
ShelfPackTexture *ct = p_data->textures.ptrw();
269
for (int32_t i = 0; i < p_data->textures.size(); i++) {
270
if (ct[i].image.is_null()) {
271
continue;
272
}
273
if (p_image_format != ct[i].image->get_format()) {
274
continue;
275
}
276
if (mw > ct[i].texture_w || mh > ct[i].texture_h) { // Too big for this texture.
277
continue;
278
}
279
280
ret = ct[i].pack_rect(i, mh, mw);
281
if (ret.index != -1) {
282
break;
283
}
284
}
285
286
if (ret.index == -1) {
287
// Could not find texture to fit, create one.
288
int texsize = MAX(p_data->size.x * 0.125, 256);
289
290
texsize = next_power_of_2((uint32_t)texsize);
291
292
if (p_msdf) {
293
texsize = MIN(texsize, 2048);
294
} else {
295
texsize = MIN(texsize, 1024);
296
}
297
if (mw > texsize) { // Special case, adapt to it?
298
texsize = next_power_of_2((uint32_t)mw);
299
}
300
if (mh > texsize) { // Special case, adapt to it?
301
texsize = next_power_of_2((uint32_t)mh);
302
}
303
304
ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);
305
tex.image = Image::create_empty(texsize, texsize, false, p_image_format);
306
{
307
// Zero texture.
308
uint8_t *w = tex.image->ptrw();
309
ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.image->get_data_size(), ret);
310
// Initialize the texture to all-white pixels to prevent artifacts when the
311
// font is displayed at a non-default scale with filtering enabled.
312
if (p_color_size == 2) {
313
for (int i = 0; i < texsize * texsize * p_color_size; i += 2) { // FORMAT_LA8, BW font.
314
w[i + 0] = 255;
315
w[i + 1] = 0;
316
}
317
} else if (p_color_size == 4) {
318
for (int i = 0; i < texsize * texsize * p_color_size; i += 4) { // FORMAT_RGBA8, Color font, Multichannel(+True) SDF.
319
if (p_msdf) {
320
w[i + 0] = 0;
321
w[i + 1] = 0;
322
w[i + 2] = 0;
323
} else {
324
w[i + 0] = 255;
325
w[i + 1] = 255;
326
w[i + 2] = 255;
327
}
328
w[i + 3] = 0;
329
}
330
} else {
331
ERR_FAIL_V(ret);
332
}
333
}
334
p_data->textures.push_back(tex);
335
336
int32_t idx = p_data->textures.size() - 1;
337
ret = p_data->textures.write[idx].pack_rect(idx, mh, mw);
338
}
339
340
return ret;
341
}
342
343
#ifdef MODULE_MSDFGEN_ENABLED
344
345
struct MSContext {
346
msdfgen::Point2 position;
347
msdfgen::Shape *shape = nullptr;
348
msdfgen::Contour *contour = nullptr;
349
};
350
351
class DistancePixelConversion {
352
double invRange;
353
354
public:
355
_FORCE_INLINE_ explicit DistancePixelConversion(double range) :
356
invRange(1 / range) {}
357
_FORCE_INLINE_ void operator()(float *pixels, const msdfgen::MultiAndTrueDistance &distance) const {
358
pixels[0] = float(invRange * distance.r + .5);
359
pixels[1] = float(invRange * distance.g + .5);
360
pixels[2] = float(invRange * distance.b + .5);
361
pixels[3] = float(invRange * distance.a + .5);
362
}
363
};
364
365
struct MSDFThreadData {
366
msdfgen::Bitmap<float, 4> *output;
367
msdfgen::Shape *shape;
368
msdfgen::Projection *projection;
369
DistancePixelConversion *distancePixelConversion;
370
};
371
372
static msdfgen::Point2 ft_point2(const FT_Vector &vector) {
373
return msdfgen::Point2(vector.x / 60.0f, vector.y / 60.0f);
374
}
375
376
static int ft_move_to(const FT_Vector *to, void *user) {
377
MSContext *context = static_cast<MSContext *>(user);
378
if (!(context->contour && context->contour->edges.empty())) {
379
context->contour = &context->shape->addContour();
380
}
381
context->position = ft_point2(*to);
382
return 0;
383
}
384
385
static int ft_line_to(const FT_Vector *to, void *user) {
386
MSContext *context = static_cast<MSContext *>(user);
387
msdfgen::Point2 endpoint = ft_point2(*to);
388
if (endpoint != context->position) {
389
context->contour->addEdge(new msdfgen::LinearSegment(context->position, endpoint));
390
context->position = endpoint;
391
}
392
return 0;
393
}
394
395
static int ft_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) {
396
MSContext *context = static_cast<MSContext *>(user);
397
context->contour->addEdge(new msdfgen::QuadraticSegment(context->position, ft_point2(*control), ft_point2(*to)));
398
context->position = ft_point2(*to);
399
return 0;
400
}
401
402
static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) {
403
MSContext *context = static_cast<MSContext *>(user);
404
context->contour->addEdge(new msdfgen::CubicSegment(context->position, ft_point2(*control1), ft_point2(*control2), ft_point2(*to)));
405
context->position = ft_point2(*to);
406
return 0;
407
}
408
409
void TextServerFallback::_generateMTSDF_threaded(void *p_td, uint32_t p_y) {
410
MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td);
411
412
msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape);
413
int row = td->shape->inverseYAxis ? td->output->height() - p_y - 1 : p_y;
414
for (int col = 0; col < td->output->width(); ++col) {
415
int x = (p_y % 2) ? td->output->width() - col - 1 : col;
416
msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, p_y + .5));
417
msdfgen::MultiAndTrueDistance distance = distanceFinder.distance(p);
418
td->distancePixelConversion->operator()(td->output->operator()(x, row), distance);
419
}
420
}
421
422
_FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(FontFallback *p_font_data, FontForSizeFallback *p_data, int p_pixel_range, int p_rect_margin, FT_Outline *p_outline, const Vector2 &p_advance) const {
423
msdfgen::Shape shape;
424
425
shape.contours.clear();
426
shape.inverseYAxis = false;
427
428
MSContext context = {};
429
context.shape = &shape;
430
FT_Outline_Funcs ft_functions;
431
ft_functions.move_to = &ft_move_to;
432
ft_functions.line_to = &ft_line_to;
433
ft_functions.conic_to = &ft_conic_to;
434
ft_functions.cubic_to = &ft_cubic_to;
435
ft_functions.shift = 0;
436
ft_functions.delta = 0;
437
438
int error = FT_Outline_Decompose(p_outline, &ft_functions, &context);
439
ERR_FAIL_COND_V_MSG(error, FontGlyph(), "FreeType: Outline decomposition error: '" + String(FT_Error_String(error)) + "'.");
440
if (!shape.contours.empty() && shape.contours.back().edges.empty()) {
441
shape.contours.pop_back();
442
}
443
444
if (FT_Outline_Get_Orientation(p_outline) == 1) {
445
for (int i = 0; i < (int)shape.contours.size(); ++i) {
446
shape.contours[i].reverse();
447
}
448
}
449
450
shape.inverseYAxis = true;
451
shape.normalize();
452
453
msdfgen::Shape::Bounds bounds = shape.getBounds(p_pixel_range);
454
455
FontGlyph chr;
456
chr.found = true;
457
chr.advance = p_advance;
458
459
if (shape.validate() && shape.contours.size() > 0) {
460
int w = (bounds.r - bounds.l);
461
int h = (bounds.t - bounds.b);
462
463
if (w == 0 || h == 0) {
464
chr.texture_idx = -1;
465
chr.uv_rect = Rect2();
466
chr.rect = Rect2();
467
return chr;
468
}
469
int mw = w + p_rect_margin * 4;
470
int mh = h + p_rect_margin * 4;
471
472
ERR_FAIL_COND_V(mw > 4096, FontGlyph());
473
ERR_FAIL_COND_V(mh > 4096, FontGlyph());
474
475
FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true);
476
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
477
ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];
478
479
edgeColoringSimple(shape, 3.0); // Max. angle.
480
msdfgen::Bitmap<float, 4> image(w, h); // Texture size.
481
482
DistancePixelConversion distancePixelConversion(p_pixel_range);
483
msdfgen::Projection projection(msdfgen::Vector2(1.0, 1.0), msdfgen::Vector2(-bounds.l, -bounds.b));
484
msdfgen::MSDFGeneratorConfig config(true, msdfgen::ErrorCorrectionConfig());
485
486
MSDFThreadData td;
487
td.output = &image;
488
td.shape = &shape;
489
td.projection = &projection;
490
td.distancePixelConversion = &distancePixelConversion;
491
492
WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_native_group_task(&TextServerFallback::_generateMTSDF_threaded, &td, h, -1, true, String("TextServerFBRenderMSDF"));
493
WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
494
495
msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config);
496
497
{
498
uint8_t *wr = tex.image->ptrw();
499
500
for (int i = 0; i < h; i++) {
501
for (int j = 0; j < w; j++) {
502
int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * 4;
503
ERR_FAIL_COND_V(ofs >= tex.image->get_data_size(), FontGlyph());
504
wr[ofs + 0] = (uint8_t)(CLAMP(image(j, i)[0] * 256.f, 0.f, 255.f));
505
wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f));
506
wr[ofs + 2] = (uint8_t)(CLAMP(image(j, i)[2] * 256.f, 0.f, 255.f));
507
wr[ofs + 3] = (uint8_t)(CLAMP(image(j, i)[3] * 256.f, 0.f, 255.f));
508
}
509
}
510
}
511
512
tex.dirty = true;
513
514
chr.texture_idx = tex_pos.index;
515
516
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);
517
chr.rect.position = Vector2(bounds.l - p_rect_margin, -bounds.t - p_rect_margin);
518
chr.rect.size = chr.uv_rect.size;
519
}
520
return chr;
521
}
522
#endif
523
524
#ifdef MODULE_FREETYPE_ENABLED
525
_FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitmap(FontForSizeFallback *p_data, int p_rect_margin, FT_Bitmap p_bitmap, int p_yofs, int p_xofs, const Vector2 &p_advance, bool p_bgra) const {
526
FontGlyph chr;
527
chr.advance = p_advance * p_data->scale;
528
chr.found = true;
529
530
int w = p_bitmap.width;
531
int h = p_bitmap.rows;
532
533
if (w == 0 || h == 0) {
534
chr.texture_idx = -1;
535
chr.uv_rect = Rect2();
536
chr.rect = Rect2();
537
return chr;
538
}
539
540
int color_size = 2;
541
542
switch (p_bitmap.pixel_mode) {
543
case FT_PIXEL_MODE_MONO:
544
case FT_PIXEL_MODE_GRAY: {
545
color_size = 2;
546
} break;
547
case FT_PIXEL_MODE_BGRA: {
548
color_size = 4;
549
} break;
550
case FT_PIXEL_MODE_LCD: {
551
color_size = 4;
552
w /= 3;
553
} break;
554
case FT_PIXEL_MODE_LCD_V: {
555
color_size = 4;
556
h /= 3;
557
} break;
558
}
559
560
int mw = w + p_rect_margin * 4;
561
int mh = h + p_rect_margin * 4;
562
563
ERR_FAIL_COND_V(mw > 4096, FontGlyph());
564
ERR_FAIL_COND_V(mh > 4096, FontGlyph());
565
566
Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;
567
568
FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh, false);
569
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
570
571
// Fit character in char texture.
572
ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];
573
574
{
575
uint8_t *wr = tex.image->ptrw();
576
577
for (int i = 0; i < h; i++) {
578
for (int j = 0; j < w; j++) {
579
int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * color_size;
580
ERR_FAIL_COND_V(ofs >= tex.image->get_data_size(), FontGlyph());
581
switch (p_bitmap.pixel_mode) {
582
case FT_PIXEL_MODE_MONO: {
583
int byte = i * p_bitmap.pitch + (j >> 3);
584
int bit = 1 << (7 - (j % 8));
585
wr[ofs + 0] = 255; // grayscale as 1
586
wr[ofs + 1] = (p_bitmap.buffer[byte] & bit) ? 255 : 0;
587
} break;
588
case FT_PIXEL_MODE_GRAY:
589
wr[ofs + 0] = 255; // grayscale as 1
590
wr[ofs + 1] = p_bitmap.buffer[i * p_bitmap.pitch + j];
591
break;
592
case FT_PIXEL_MODE_BGRA: {
593
int ofs_color = i * p_bitmap.pitch + (j << 2);
594
wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];
595
wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];
596
wr[ofs + 0] = p_bitmap.buffer[ofs_color + 2];
597
wr[ofs + 3] = p_bitmap.buffer[ofs_color + 3];
598
} break;
599
case FT_PIXEL_MODE_LCD: {
600
int ofs_color = i * p_bitmap.pitch + (j * 3);
601
if (p_bgra) {
602
wr[ofs + 0] = p_bitmap.buffer[ofs_color + 2];
603
wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];
604
wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];
605
wr[ofs + 3] = 255;
606
} else {
607
wr[ofs + 0] = p_bitmap.buffer[ofs_color + 0];
608
wr[ofs + 1] = p_bitmap.buffer[ofs_color + 1];
609
wr[ofs + 2] = p_bitmap.buffer[ofs_color + 2];
610
wr[ofs + 3] = 255;
611
}
612
} break;
613
case FT_PIXEL_MODE_LCD_V: {
614
int ofs_color = i * p_bitmap.pitch * 3 + j;
615
if (p_bgra) {
616
wr[ofs + 0] = p_bitmap.buffer[ofs_color + p_bitmap.pitch * 2];
617
wr[ofs + 1] = p_bitmap.buffer[ofs_color + p_bitmap.pitch];
618
wr[ofs + 2] = p_bitmap.buffer[ofs_color + 0];
619
wr[ofs + 3] = 255;
620
} else {
621
wr[ofs + 0] = p_bitmap.buffer[ofs_color + 0];
622
wr[ofs + 1] = p_bitmap.buffer[ofs_color + p_bitmap.pitch];
623
wr[ofs + 2] = p_bitmap.buffer[ofs_color + p_bitmap.pitch * 2];
624
wr[ofs + 3] = 255;
625
}
626
} break;
627
default:
628
ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + String::num_int64(p_bitmap.pixel_mode) + ".");
629
break;
630
}
631
}
632
}
633
}
634
635
tex.dirty = true;
636
637
chr.texture_idx = tex_pos.index;
638
639
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);
640
chr.rect.position = Vector2(p_xofs - p_rect_margin, -p_yofs - p_rect_margin) * p_data->scale;
641
chr.rect.size = chr.uv_rect.size * p_data->scale;
642
return chr;
643
}
644
#endif
645
646
/*************************************************************************/
647
/* Font Cache */
648
/*************************************************************************/
649
650
bool TextServerFallback::_ensure_glyph(FontFallback *p_font_data, const Vector2i &p_size, int32_t p_glyph, FontGlyph &r_glyph, uint32_t p_oversampling) const {
651
FontForSizeFallback *fd = nullptr;
652
ERR_FAIL_COND_V(!_ensure_cache_for_size(p_font_data, p_size, fd, false, p_oversampling), false);
653
654
int32_t glyph_index = p_glyph & 0xffffff; // Remove subpixel shifts.
655
656
HashMap<int32_t, FontGlyph>::Iterator E = fd->glyph_map.find(p_glyph);
657
if (E) {
658
bool tx_valid = true;
659
if (E->value.texture_idx >= 0) {
660
if (E->value.texture_idx < fd->textures.size()) {
661
tx_valid = fd->textures[E->value.texture_idx].image.is_valid();
662
} else {
663
tx_valid = false;
664
}
665
}
666
if (tx_valid) {
667
r_glyph = E->value;
668
return E->value.found;
669
#ifdef DEBUG_ENABLED
670
} else {
671
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));
672
#endif
673
}
674
}
675
676
if (glyph_index == 0) { // Non graphical or invalid glyph, do not render.
677
E = fd->glyph_map.insert(p_glyph, FontGlyph());
678
r_glyph = E->value;
679
return true;
680
}
681
682
#ifdef MODULE_FREETYPE_ENABLED
683
FontGlyph gl;
684
if (p_font_data->face) {
685
FT_Int32 flags = FT_LOAD_DEFAULT;
686
687
bool outline = p_size.y > 0;
688
switch (p_font_data->hinting) {
689
case TextServer::HINTING_NONE:
690
flags |= FT_LOAD_NO_HINTING;
691
break;
692
case TextServer::HINTING_LIGHT:
693
flags |= FT_LOAD_TARGET_LIGHT;
694
break;
695
default:
696
flags |= FT_LOAD_TARGET_NORMAL;
697
break;
698
}
699
if (p_font_data->force_autohinter) {
700
flags |= FT_LOAD_FORCE_AUTOHINT;
701
}
702
if (outline || (p_font_data->disable_embedded_bitmaps && !FT_HAS_COLOR(p_font_data->face))) {
703
flags |= FT_LOAD_NO_BITMAP;
704
} else if (FT_HAS_COLOR(p_font_data->face)) {
705
flags |= FT_LOAD_COLOR;
706
}
707
708
glyph_index = FT_Get_Char_Index(p_font_data->face, glyph_index);
709
710
FT_Fixed v, h;
711
FT_Get_Advance(p_font_data->face, glyph_index, flags, &h);
712
FT_Get_Advance(p_font_data->face, glyph_index, flags | FT_LOAD_VERTICAL_LAYOUT, &v);
713
714
int error = FT_Load_Glyph(p_font_data->face, glyph_index, flags);
715
if (error) {
716
E = fd->glyph_map.insert(p_glyph, FontGlyph());
717
r_glyph = E->value;
718
return false;
719
}
720
721
if (!p_font_data->msdf) {
722
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)) {
723
FT_Pos xshift = (int)((p_glyph >> 27) & 3) << 4;
724
FT_Outline_Translate(&p_font_data->face->glyph->outline, xshift, 0);
725
} 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)) {
726
FT_Pos xshift = (int)((p_glyph >> 27) & 3) << 5;
727
FT_Outline_Translate(&p_font_data->face->glyph->outline, xshift, 0);
728
}
729
}
730
731
if (p_font_data->embolden != 0.f) {
732
FT_Pos strength = p_font_data->embolden * p_size.x / 16; // 26.6 fractional units (1 / 64).
733
FT_Outline_Embolden(&p_font_data->face->glyph->outline, strength);
734
}
735
736
if (p_font_data->transform != Transform2D()) {
737
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).
738
FT_Outline_Transform(&p_font_data->face->glyph->outline, &mat);
739
}
740
741
FT_Render_Mode aa_mode = FT_RENDER_MODE_NORMAL;
742
bool bgra = false;
743
switch (p_font_data->antialiasing) {
744
case FONT_ANTIALIASING_NONE: {
745
aa_mode = FT_RENDER_MODE_MONO;
746
} break;
747
case FONT_ANTIALIASING_GRAY: {
748
aa_mode = FT_RENDER_MODE_NORMAL;
749
} break;
750
case FONT_ANTIALIASING_LCD: {
751
int aa_layout = (int)((p_glyph >> 24) & 7);
752
switch (aa_layout) {
753
case FONT_LCD_SUBPIXEL_LAYOUT_HRGB: {
754
aa_mode = FT_RENDER_MODE_LCD;
755
bgra = false;
756
} break;
757
case FONT_LCD_SUBPIXEL_LAYOUT_HBGR: {
758
aa_mode = FT_RENDER_MODE_LCD;
759
bgra = true;
760
} break;
761
case FONT_LCD_SUBPIXEL_LAYOUT_VRGB: {
762
aa_mode = FT_RENDER_MODE_LCD_V;
763
bgra = false;
764
} break;
765
case FONT_LCD_SUBPIXEL_LAYOUT_VBGR: {
766
aa_mode = FT_RENDER_MODE_LCD_V;
767
bgra = true;
768
} break;
769
default: {
770
aa_mode = FT_RENDER_MODE_NORMAL;
771
} break;
772
}
773
} break;
774
}
775
776
FT_GlyphSlot slot = p_font_data->face->glyph;
777
bool from_svg = (slot->format == FT_GLYPH_FORMAT_SVG); // Need to check before FT_Render_Glyph as it will change format to bitmap.
778
if (!outline) {
779
if (!p_font_data->msdf) {
780
error = FT_Render_Glyph(slot, aa_mode);
781
}
782
if (!error) {
783
if (p_font_data->msdf) {
784
#ifdef MODULE_MSDFGEN_ENABLED
785
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);
786
#else
787
fd->glyph_map[p_glyph] = FontGlyph();
788
ERR_FAIL_V_MSG(false, "Compiled without MSDFGEN support!");
789
#endif
790
} else {
791
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);
792
}
793
}
794
} else {
795
FT_Stroker stroker;
796
if (FT_Stroker_New(ft_library, &stroker) != 0) {
797
fd->glyph_map[p_glyph] = FontGlyph();
798
ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph stroker.");
799
}
800
801
FT_Stroker_Set(stroker, (int)(fd->size.y * 16.0), FT_STROKER_LINECAP_BUTT, FT_STROKER_LINEJOIN_ROUND, 0);
802
FT_Glyph glyph;
803
FT_BitmapGlyph glyph_bitmap;
804
805
if (FT_Get_Glyph(p_font_data->face->glyph, &glyph) != 0) {
806
goto cleanup_stroker;
807
}
808
if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0) {
809
goto cleanup_glyph;
810
}
811
if (FT_Glyph_To_Bitmap(&glyph, aa_mode, nullptr, 1) != 0) {
812
goto cleanup_glyph;
813
}
814
glyph_bitmap = (FT_BitmapGlyph)glyph;
815
gl = rasterize_bitmap(fd, rect_range, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2(), bgra);
816
817
cleanup_glyph:
818
FT_Done_Glyph(glyph);
819
cleanup_stroker:
820
FT_Stroker_Done(stroker);
821
}
822
gl.from_svg = from_svg;
823
E = fd->glyph_map.insert(p_glyph, gl);
824
r_glyph = E->value;
825
return gl.found;
826
}
827
#endif
828
E = fd->glyph_map.insert(p_glyph, FontGlyph());
829
r_glyph = E->value;
830
return false;
831
}
832
833
bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_font_data, const Vector2i &p_size, FontForSizeFallback *&r_cache_for_size, bool p_silent, uint32_t p_oversampling) const {
834
ERR_FAIL_COND_V(p_size.x <= 0, false);
835
836
HashMap<Vector2i, FontForSizeFallback *>::Iterator E = p_font_data->cache.find(p_size);
837
if (E) {
838
#ifdef MODULE_FREETYPE_ENABLED
839
if (E->value->fsize != nullptr) {
840
FT_Activate_Size(E->value->fsize);
841
}
842
#endif
843
r_cache_for_size = E->value;
844
// Size used directly, remove from oversampling list.
845
if (p_oversampling == 0 && E->value->viewport_oversampling != 0) {
846
OversamplingLevel *ol = oversampling_levels.getptr(E->value->viewport_oversampling);
847
if (ol) {
848
ol->fonts.erase(E->value);
849
}
850
}
851
return true;
852
}
853
854
r_cache_for_size = nullptr;
855
FontForSizeFallback *fd = memnew(FontForSizeFallback);
856
fd->size = p_size;
857
if (p_font_data->data_ptr && (p_font_data->data_size > 0)) {
858
// Init dynamic font.
859
#ifdef MODULE_FREETYPE_ENABLED
860
int error = 0;
861
{
862
MutexLock ftlock(ft_mutex);
863
if (!ft_library) {
864
error = FT_Init_FreeType(&ft_library);
865
if (error != 0) {
866
memdelete(fd);
867
if (p_silent) {
868
return false;
869
} else {
870
ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
871
}
872
}
873
#ifdef MODULE_SVG_ENABLED
874
FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks());
875
#endif
876
}
877
878
if (p_font_data->face == nullptr) {
879
memset(&p_font_data->stream, 0, sizeof(FT_StreamRec));
880
p_font_data->stream.base = (unsigned char *)p_font_data->data_ptr;
881
p_font_data->stream.size = p_font_data->data_size;
882
p_font_data->stream.pos = 0;
883
884
FT_Open_Args fargs;
885
memset(&fargs, 0, sizeof(FT_Open_Args));
886
fargs.memory_base = (unsigned char *)p_font_data->data_ptr;
887
fargs.memory_size = p_font_data->data_size;
888
fargs.flags = FT_OPEN_MEMORY;
889
fargs.stream = &p_font_data->stream;
890
891
int max_index = 0;
892
FT_Face tmp_face = nullptr;
893
error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
894
if (tmp_face && error == 0) {
895
max_index = tmp_face->num_faces - 1;
896
}
897
if (tmp_face) {
898
FT_Done_Face(tmp_face);
899
}
900
901
error = FT_Open_Face(ft_library, &fargs, CLAMP(p_font_data->face_index, 0, max_index), &p_font_data->face);
902
if (error) {
903
FT_Done_Face(p_font_data->face);
904
p_font_data->face = nullptr;
905
memdelete(fd);
906
if (p_silent) {
907
return false;
908
} else {
909
ERR_FAIL_V_MSG(false, "FreeType: Error loading font: '" + String(FT_Error_String(error)) + "'.");
910
}
911
}
912
}
913
914
FT_New_Size(p_font_data->face, &fd->fsize);
915
FT_Activate_Size(fd->fsize);
916
}
917
918
double sz = double(fd->size.x) / 64.0;
919
if (p_font_data->msdf) {
920
sz = p_font_data->msdf_source_size;
921
}
922
923
if (FT_HAS_COLOR(p_font_data->face) && p_font_data->face->num_fixed_sizes > 0) {
924
int best_match = 0;
925
int diff = Math::abs(sz - ((int64_t)p_font_data->face->available_sizes[0].width));
926
fd->scale = sz / p_font_data->face->available_sizes[0].width;
927
for (int i = 1; i < p_font_data->face->num_fixed_sizes; i++) {
928
int ndiff = Math::abs(sz - ((int64_t)p_font_data->face->available_sizes[i].width));
929
if (ndiff < diff) {
930
best_match = i;
931
diff = ndiff;
932
fd->scale = sz / p_font_data->face->available_sizes[i].width;
933
}
934
}
935
FT_Select_Size(p_font_data->face, best_match);
936
} else {
937
FT_Size_RequestRec req;
938
req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
939
req.width = MIN(2048.0, sz) * 64.0;
940
req.height = MIN(2048.0, sz) * 64.0;
941
req.horiResolution = 0;
942
req.vertResolution = 0;
943
944
FT_Request_Size(p_font_data->face, &req);
945
if (p_font_data->face->size->metrics.y_ppem != 0) {
946
fd->scale = sz / (double)p_font_data->face->size->metrics.y_ppem;
947
}
948
}
949
950
fd->ascent = (p_font_data->face->size->metrics.ascender / 64.0) * fd->scale;
951
fd->descent = (-p_font_data->face->size->metrics.descender / 64.0) * fd->scale;
952
fd->underline_position = (-FT_MulFix(p_font_data->face->underline_position, p_font_data->face->size->metrics.y_scale) / 64.0) * fd->scale;
953
fd->underline_thickness = (FT_MulFix(p_font_data->face->underline_thickness, p_font_data->face->size->metrics.y_scale) / 64.0) * fd->scale;
954
955
if (!p_font_data->face_init) {
956
// When a font does not provide a `family_name`, FreeType tries to synthesize one based on other names.
957
// FreeType automatically converts non-ASCII characters to "?" in the synthesized name.
958
// To avoid that behavior, use the format-specific name directly if available.
959
if (FT_IS_SFNT(p_font_data->face)) {
960
int name_count = FT_Get_Sfnt_Name_Count(p_font_data->face);
961
for (int i = 0; i < name_count; i++) {
962
FT_SfntName sfnt_name;
963
if (FT_Get_Sfnt_Name(p_font_data->face, i, &sfnt_name) != 0) {
964
continue;
965
}
966
if (sfnt_name.name_id != TT_NAME_ID_FONT_FAMILY && sfnt_name.name_id != TT_NAME_ID_TYPOGRAPHIC_FAMILY) {
967
continue;
968
}
969
if (!p_font_data->font_name.is_empty() && sfnt_name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES) {
970
continue;
971
}
972
973
switch (sfnt_name.platform_id) {
974
case TT_PLATFORM_APPLE_UNICODE: {
975
p_font_data->font_name.clear();
976
p_font_data->font_name.append_utf16((const char16_t *)sfnt_name.string, sfnt_name.string_len / 2, false);
977
} break;
978
979
case TT_PLATFORM_MICROSOFT: {
980
if (sfnt_name.encoding_id == TT_MS_ID_UNICODE_CS || sfnt_name.encoding_id == TT_MS_ID_UCS_4) {
981
p_font_data->font_name.clear();
982
p_font_data->font_name.append_utf16((const char16_t *)sfnt_name.string, sfnt_name.string_len / 2, false);
983
}
984
} break;
985
}
986
}
987
}
988
if (p_font_data->font_name.is_empty() && p_font_data->face->family_name != nullptr) {
989
p_font_data->font_name = String::utf8((const char *)p_font_data->face->family_name);
990
}
991
if (p_font_data->face->style_name != nullptr) {
992
p_font_data->style_name = String::utf8((const char *)p_font_data->face->style_name);
993
}
994
p_font_data->weight = _font_get_weight_by_name(p_font_data->style_name.to_lower());
995
p_font_data->stretch = _font_get_stretch_by_name(p_font_data->style_name.to_lower());
996
p_font_data->style_flags = 0;
997
if ((p_font_data->face->style_flags & FT_STYLE_FLAG_BOLD) || p_font_data->weight >= 700) {
998
p_font_data->style_flags.set_flag(FONT_BOLD);
999
}
1000
if ((p_font_data->face->style_flags & FT_STYLE_FLAG_ITALIC) || _is_ital_style(p_font_data->style_name.to_lower())) {
1001
p_font_data->style_flags.set_flag(FONT_ITALIC);
1002
}
1003
if (p_font_data->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) {
1004
p_font_data->style_flags.set_flag(FONT_FIXED_WIDTH);
1005
}
1006
// Read OpenType variations.
1007
p_font_data->supported_varaitions.clear();
1008
if (p_font_data->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
1009
FT_MM_Var *amaster;
1010
FT_Get_MM_Var(p_font_data->face, &amaster);
1011
for (FT_UInt i = 0; i < amaster->num_axis; i++) {
1012
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);
1013
}
1014
FT_Done_MM_Var(ft_library, amaster);
1015
}
1016
p_font_data->face_init = true;
1017
}
1018
1019
#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
1020
if (p_font_data->font_name == ".Apple Color Emoji UI" || p_font_data->font_name == "Apple Color Emoji") {
1021
// The baseline offset is missing from the Apple Color Emoji UI font data, so add it manually.
1022
// This issue doesn't occur with other system emoji fonts.
1023
if (!FT_Load_Glyph(p_font_data->face, FT_Get_Char_Index(p_font_data->face, 0x1F92E), FT_LOAD_DEFAULT | FT_LOAD_COLOR)) {
1024
if (p_font_data->face->glyph->metrics.horiBearingY == p_font_data->face->glyph->metrics.height) {
1025
p_font_data->baseline_offset = 0.15;
1026
}
1027
}
1028
}
1029
#endif
1030
1031
// Write variations.
1032
if (p_font_data->face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
1033
FT_MM_Var *amaster;
1034
1035
FT_Get_MM_Var(p_font_data->face, &amaster);
1036
1037
Vector<FT_Fixed> coords;
1038
coords.resize(amaster->num_axis);
1039
1040
FT_Get_Var_Design_Coordinates(p_font_data->face, coords.size(), coords.ptrw());
1041
1042
for (FT_UInt i = 0; i < amaster->num_axis; i++) {
1043
// Reset to default.
1044
int32_t var_tag = amaster->axis[i].tag;
1045
double var_value = (double)amaster->axis[i].def / 65536.0;
1046
coords.write[i] = amaster->axis[i].def;
1047
1048
if (p_font_data->variation_coordinates.has(var_tag)) {
1049
var_value = p_font_data->variation_coordinates[var_tag];
1050
coords.write[i] = CLAMP(var_value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);
1051
}
1052
1053
if (p_font_data->variation_coordinates.has(tag_to_name(var_tag))) {
1054
var_value = p_font_data->variation_coordinates[tag_to_name(var_tag)];
1055
coords.write[i] = CLAMP(var_value * 65536.0, amaster->axis[i].minimum, amaster->axis[i].maximum);
1056
}
1057
}
1058
1059
FT_Set_Var_Design_Coordinates(p_font_data->face, coords.size(), coords.ptrw());
1060
FT_Done_MM_Var(ft_library, amaster);
1061
}
1062
#else
1063
memdelete(fd);
1064
if (p_silent) {
1065
return false;
1066
} else {
1067
ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!");
1068
}
1069
#endif
1070
}
1071
1072
fd->owner = p_font_data;
1073
p_font_data->cache.insert(p_size, fd);
1074
r_cache_for_size = fd;
1075
if (p_oversampling != 0) {
1076
OversamplingLevel *ol = oversampling_levels.getptr(p_oversampling);
1077
if (ol) {
1078
fd->viewport_oversampling = p_oversampling;
1079
ol->fonts.insert(fd);
1080
}
1081
}
1082
return true;
1083
}
1084
1085
void TextServerFallback::_reference_oversampling_level(double p_oversampling) {
1086
uint32_t oversampling = CLAMP(p_oversampling, 0.1, 100.0) * 64;
1087
if (oversampling == 64) {
1088
return;
1089
}
1090
OversamplingLevel *ol = oversampling_levels.getptr(oversampling);
1091
if (ol) {
1092
ol->refcount++;
1093
} else {
1094
OversamplingLevel new_ol;
1095
oversampling_levels.insert(oversampling, new_ol);
1096
}
1097
}
1098
1099
void TextServerFallback::_unreference_oversampling_level(double p_oversampling) {
1100
uint32_t oversampling = CLAMP(p_oversampling, 0.1, 100.0) * 64;
1101
if (oversampling == 64) {
1102
return;
1103
}
1104
OversamplingLevel *ol = oversampling_levels.getptr(oversampling);
1105
if (ol) {
1106
ol->refcount--;
1107
if (ol->refcount == 0) {
1108
for (FontForSizeFallback *fd : ol->fonts) {
1109
fd->owner->cache.erase(fd->size);
1110
memdelete(fd);
1111
}
1112
ol->fonts.clear();
1113
oversampling_levels.erase(oversampling);
1114
}
1115
}
1116
}
1117
1118
_FORCE_INLINE_ bool TextServerFallback::_font_validate(const RID &p_font_rid) const {
1119
FontFallback *fd = _get_font_data(p_font_rid);
1120
ERR_FAIL_NULL_V(fd, false);
1121
1122
MutexLock lock(fd->mutex);
1123
Vector2i size = _get_size(fd, 16);
1124
FontForSizeFallback *ffsd = nullptr;
1125
return _ensure_cache_for_size(fd, size, ffsd, true);
1126
}
1127
1128
_FORCE_INLINE_ void TextServerFallback::_font_clear_cache(FontFallback *p_font_data) {
1129
MutexLock ftlock(ft_mutex);
1130
1131
for (const KeyValue<Vector2i, FontForSizeFallback *> &E : p_font_data->cache) {
1132
if (E.value->viewport_oversampling != 0) {
1133
OversamplingLevel *ol = oversampling_levels.getptr(E.value->viewport_oversampling);
1134
if (ol) {
1135
ol->fonts.erase(E.value);
1136
}
1137
}
1138
memdelete(E.value);
1139
}
1140
1141
p_font_data->cache.clear();
1142
p_font_data->face_init = false;
1143
p_font_data->supported_varaitions.clear();
1144
}
1145
1146
RID TextServerFallback::_create_font() {
1147
_THREAD_SAFE_METHOD_
1148
1149
FontFallback *fd = memnew(FontFallback);
1150
1151
return font_owner.make_rid(fd);
1152
}
1153
1154
RID TextServerFallback::_create_font_linked_variation(const RID &p_font_rid) {
1155
_THREAD_SAFE_METHOD_
1156
1157
RID rid = p_font_rid;
1158
FontFallbackLinkedVariation *fdv = font_var_owner.get_or_null(rid);
1159
if (unlikely(fdv)) {
1160
rid = fdv->base_font;
1161
}
1162
ERR_FAIL_COND_V(!font_owner.owns(rid), RID());
1163
1164
FontFallbackLinkedVariation *new_fdv = memnew(FontFallbackLinkedVariation);
1165
new_fdv->base_font = rid;
1166
1167
return font_var_owner.make_rid(new_fdv);
1168
}
1169
1170
void TextServerFallback::_font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) {
1171
FontFallback *fd = _get_font_data(p_font_rid);
1172
ERR_FAIL_NULL(fd);
1173
1174
MutexLock lock(fd->mutex);
1175
_font_clear_cache(fd);
1176
fd->data = p_data;
1177
fd->data_ptr = fd->data.ptr();
1178
fd->data_size = fd->data.size();
1179
}
1180
1181
void TextServerFallback::_font_set_data_ptr(const RID &p_font_rid, const uint8_t *p_data_ptr, int64_t p_data_size) {
1182
FontFallback *fd = _get_font_data(p_font_rid);
1183
ERR_FAIL_NULL(fd);
1184
1185
MutexLock lock(fd->mutex);
1186
_font_clear_cache(fd);
1187
fd->data.resize(0);
1188
fd->data_ptr = p_data_ptr;
1189
fd->data_size = p_data_size;
1190
}
1191
1192
void TextServerFallback::_font_set_style(const RID &p_font_rid, BitField<FontStyle> p_style) {
1193
FontFallback *fd = _get_font_data(p_font_rid);
1194
ERR_FAIL_NULL(fd);
1195
1196
MutexLock lock(fd->mutex);
1197
Vector2i size = _get_size(fd, 16);
1198
FontForSizeFallback *ffsd = nullptr;
1199
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
1200
fd->style_flags = p_style;
1201
}
1202
1203
void TextServerFallback::_font_set_face_index(const RID &p_font_rid, int64_t p_face_index) {
1204
ERR_FAIL_COND(p_face_index < 0);
1205
ERR_FAIL_COND(p_face_index >= 0x7FFF);
1206
1207
FontFallback *fd = _get_font_data(p_font_rid);
1208
ERR_FAIL_NULL(fd);
1209
1210
MutexLock lock(fd->mutex);
1211
if (fd->face_index != p_face_index) {
1212
fd->face_index = p_face_index;
1213
_font_clear_cache(fd);
1214
}
1215
}
1216
1217
int64_t TextServerFallback::_font_get_face_index(const RID &p_font_rid) const {
1218
FontFallback *fd = _get_font_data(p_font_rid);
1219
ERR_FAIL_NULL_V(fd, 0);
1220
1221
MutexLock lock(fd->mutex);
1222
return fd->face_index;
1223
}
1224
1225
int64_t TextServerFallback::_font_get_face_count(const RID &p_font_rid) const {
1226
FontFallback *fd = _get_font_data(p_font_rid);
1227
ERR_FAIL_NULL_V(fd, 0);
1228
1229
MutexLock lock(fd->mutex);
1230
int face_count = 0;
1231
1232
if (fd->data_ptr && (fd->data_size > 0)) {
1233
// Init dynamic font.
1234
#ifdef MODULE_FREETYPE_ENABLED
1235
int error = 0;
1236
if (!ft_library) {
1237
error = FT_Init_FreeType(&ft_library);
1238
ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
1239
#ifdef MODULE_SVG_ENABLED
1240
FT_Property_Set(ft_library, "ot-svg", "svg-hooks", get_tvg_svg_in_ot_hooks());
1241
#endif
1242
}
1243
1244
FT_StreamRec stream;
1245
memset(&stream, 0, sizeof(FT_StreamRec));
1246
stream.base = (unsigned char *)fd->data_ptr;
1247
stream.size = fd->data_size;
1248
stream.pos = 0;
1249
1250
FT_Open_Args fargs;
1251
memset(&fargs, 0, sizeof(FT_Open_Args));
1252
fargs.memory_base = (unsigned char *)fd->data_ptr;
1253
fargs.memory_size = fd->data_size;
1254
fargs.flags = FT_OPEN_MEMORY;
1255
fargs.stream = &stream;
1256
1257
MutexLock ftlock(ft_mutex);
1258
1259
FT_Face tmp_face = nullptr;
1260
error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
1261
if (error == 0) {
1262
face_count = tmp_face->num_faces;
1263
FT_Done_Face(tmp_face);
1264
}
1265
#endif
1266
}
1267
1268
return face_count;
1269
}
1270
1271
BitField<TextServer::FontStyle> TextServerFallback::_font_get_style(const RID &p_font_rid) const {
1272
FontFallback *fd = _get_font_data(p_font_rid);
1273
ERR_FAIL_NULL_V(fd, 0);
1274
1275
MutexLock lock(fd->mutex);
1276
Vector2i size = _get_size(fd, 16);
1277
FontForSizeFallback *ffsd = nullptr;
1278
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0);
1279
return fd->style_flags;
1280
}
1281
1282
void TextServerFallback::_font_set_style_name(const RID &p_font_rid, const String &p_name) {
1283
FontFallback *fd = _get_font_data(p_font_rid);
1284
ERR_FAIL_NULL(fd);
1285
1286
MutexLock lock(fd->mutex);
1287
Vector2i size = _get_size(fd, 16);
1288
FontForSizeFallback *ffsd = nullptr;
1289
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
1290
fd->style_name = p_name;
1291
}
1292
1293
String TextServerFallback::_font_get_style_name(const RID &p_font_rid) const {
1294
FontFallback *fd = _get_font_data(p_font_rid);
1295
ERR_FAIL_NULL_V(fd, String());
1296
1297
MutexLock lock(fd->mutex);
1298
Vector2i size = _get_size(fd, 16);
1299
FontForSizeFallback *ffsd = nullptr;
1300
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), String());
1301
return fd->style_name;
1302
}
1303
1304
void TextServerFallback::_font_set_weight(const RID &p_font_rid, int64_t p_weight) {
1305
FontFallback *fd = _get_font_data(p_font_rid);
1306
ERR_FAIL_NULL(fd);
1307
1308
MutexLock lock(fd->mutex);
1309
Vector2i size = _get_size(fd, 16);
1310
FontForSizeFallback *ffsd = nullptr;
1311
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
1312
fd->weight = CLAMP(p_weight, 100, 999);
1313
}
1314
1315
int64_t TextServerFallback::_font_get_weight(const RID &p_font_rid) const {
1316
FontFallback *fd = _get_font_data(p_font_rid);
1317
ERR_FAIL_NULL_V(fd, 400);
1318
1319
MutexLock lock(fd->mutex);
1320
Vector2i size = _get_size(fd, 16);
1321
FontForSizeFallback *ffsd = nullptr;
1322
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 400);
1323
return fd->weight;
1324
}
1325
1326
void TextServerFallback::_font_set_stretch(const RID &p_font_rid, int64_t p_stretch) {
1327
FontFallback *fd = _get_font_data(p_font_rid);
1328
ERR_FAIL_NULL(fd);
1329
1330
MutexLock lock(fd->mutex);
1331
Vector2i size = _get_size(fd, 16);
1332
FontForSizeFallback *ffsd = nullptr;
1333
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
1334
fd->stretch = CLAMP(p_stretch, 50, 200);
1335
}
1336
1337
int64_t TextServerFallback::_font_get_stretch(const RID &p_font_rid) const {
1338
FontFallback *fd = _get_font_data(p_font_rid);
1339
ERR_FAIL_NULL_V(fd, 100);
1340
1341
MutexLock lock(fd->mutex);
1342
Vector2i size = _get_size(fd, 16);
1343
FontForSizeFallback *ffsd = nullptr;
1344
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 100);
1345
return fd->stretch;
1346
}
1347
1348
void TextServerFallback::_font_set_name(const RID &p_font_rid, const String &p_name) {
1349
FontFallback *fd = _get_font_data(p_font_rid);
1350
ERR_FAIL_NULL(fd);
1351
1352
MutexLock lock(fd->mutex);
1353
Vector2i size = _get_size(fd, 16);
1354
FontForSizeFallback *ffsd = nullptr;
1355
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
1356
fd->font_name = p_name;
1357
}
1358
1359
String TextServerFallback::_font_get_name(const RID &p_font_rid) const {
1360
FontFallback *fd = _get_font_data(p_font_rid);
1361
ERR_FAIL_NULL_V(fd, String());
1362
1363
MutexLock lock(fd->mutex);
1364
Vector2i size = _get_size(fd, 16);
1365
FontForSizeFallback *ffsd = nullptr;
1366
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), String());
1367
return fd->font_name;
1368
}
1369
1370
void TextServerFallback::_font_set_antialiasing(const RID &p_font_rid, TextServer::FontAntialiasing p_antialiasing) {
1371
FontFallback *fd = _get_font_data(p_font_rid);
1372
ERR_FAIL_NULL(fd);
1373
1374
MutexLock lock(fd->mutex);
1375
if (fd->antialiasing != p_antialiasing) {
1376
_font_clear_cache(fd);
1377
fd->antialiasing = p_antialiasing;
1378
}
1379
}
1380
1381
TextServer::FontAntialiasing TextServerFallback::_font_get_antialiasing(const RID &p_font_rid) const {
1382
FontFallback *fd = _get_font_data(p_font_rid);
1383
ERR_FAIL_NULL_V(fd, TextServer::FONT_ANTIALIASING_NONE);
1384
1385
MutexLock lock(fd->mutex);
1386
return fd->antialiasing;
1387
}
1388
1389
void TextServerFallback::_font_set_disable_embedded_bitmaps(const RID &p_font_rid, bool p_disable_embedded_bitmaps) {
1390
FontFallback *fd = _get_font_data(p_font_rid);
1391
ERR_FAIL_NULL(fd);
1392
1393
MutexLock lock(fd->mutex);
1394
if (fd->disable_embedded_bitmaps != p_disable_embedded_bitmaps) {
1395
_font_clear_cache(fd);
1396
fd->disable_embedded_bitmaps = p_disable_embedded_bitmaps;
1397
}
1398
}
1399
1400
bool TextServerFallback::_font_get_disable_embedded_bitmaps(const RID &p_font_rid) const {
1401
FontFallback *fd = _get_font_data(p_font_rid);
1402
ERR_FAIL_NULL_V(fd, false);
1403
1404
MutexLock lock(fd->mutex);
1405
return fd->disable_embedded_bitmaps;
1406
}
1407
1408
void TextServerFallback::_font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) {
1409
FontFallback *fd = _get_font_data(p_font_rid);
1410
ERR_FAIL_NULL(fd);
1411
1412
MutexLock lock(fd->mutex);
1413
if (fd->mipmaps != p_generate_mipmaps) {
1414
for (KeyValue<Vector2i, FontForSizeFallback *> &E : fd->cache) {
1415
for (int i = 0; i < E.value->textures.size(); i++) {
1416
E.value->textures.write[i].dirty = true;
1417
E.value->textures.write[i].texture = Ref<ImageTexture>();
1418
}
1419
}
1420
fd->mipmaps = p_generate_mipmaps;
1421
}
1422
}
1423
1424
bool TextServerFallback::_font_get_generate_mipmaps(const RID &p_font_rid) const {
1425
FontFallback *fd = _get_font_data(p_font_rid);
1426
ERR_FAIL_NULL_V(fd, false);
1427
1428
MutexLock lock(fd->mutex);
1429
return fd->mipmaps;
1430
}
1431
1432
void TextServerFallback::_font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) {
1433
FontFallback *fd = _get_font_data(p_font_rid);
1434
ERR_FAIL_NULL(fd);
1435
1436
MutexLock lock(fd->mutex);
1437
if (fd->msdf != p_msdf) {
1438
_font_clear_cache(fd);
1439
fd->msdf = p_msdf;
1440
}
1441
}
1442
1443
bool TextServerFallback::_font_is_multichannel_signed_distance_field(const RID &p_font_rid) const {
1444
FontFallback *fd = _get_font_data(p_font_rid);
1445
ERR_FAIL_NULL_V(fd, false);
1446
1447
MutexLock lock(fd->mutex);
1448
return fd->msdf;
1449
}
1450
1451
void TextServerFallback::_font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) {
1452
FontFallback *fd = _get_font_data(p_font_rid);
1453
ERR_FAIL_NULL(fd);
1454
1455
MutexLock lock(fd->mutex);
1456
if (fd->msdf_range != p_msdf_pixel_range) {
1457
_font_clear_cache(fd);
1458
fd->msdf_range = p_msdf_pixel_range;
1459
}
1460
}
1461
1462
int64_t TextServerFallback::_font_get_msdf_pixel_range(const RID &p_font_rid) const {
1463
FontFallback *fd = _get_font_data(p_font_rid);
1464
ERR_FAIL_NULL_V(fd, false);
1465
1466
MutexLock lock(fd->mutex);
1467
return fd->msdf_range;
1468
}
1469
1470
void TextServerFallback::_font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) {
1471
FontFallback *fd = _get_font_data(p_font_rid);
1472
ERR_FAIL_NULL(fd);
1473
1474
MutexLock lock(fd->mutex);
1475
if (fd->msdf_source_size != p_msdf_size) {
1476
_font_clear_cache(fd);
1477
fd->msdf_source_size = p_msdf_size;
1478
}
1479
}
1480
1481
int64_t TextServerFallback::_font_get_msdf_size(const RID &p_font_rid) const {
1482
FontFallback *fd = _get_font_data(p_font_rid);
1483
ERR_FAIL_NULL_V(fd, 0);
1484
1485
MutexLock lock(fd->mutex);
1486
return fd->msdf_source_size;
1487
}
1488
1489
void TextServerFallback::_font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) {
1490
FontFallback *fd = _get_font_data(p_font_rid);
1491
ERR_FAIL_NULL(fd);
1492
1493
MutexLock lock(fd->mutex);
1494
fd->fixed_size = p_fixed_size;
1495
}
1496
1497
int64_t TextServerFallback::_font_get_fixed_size(const RID &p_font_rid) const {
1498
FontFallback *fd = _get_font_data(p_font_rid);
1499
ERR_FAIL_NULL_V(fd, 0);
1500
1501
MutexLock lock(fd->mutex);
1502
return fd->fixed_size;
1503
}
1504
1505
void TextServerFallback::_font_set_fixed_size_scale_mode(const RID &p_font_rid, TextServer::FixedSizeScaleMode p_fixed_size_scale_mode) {
1506
FontFallback *fd = _get_font_data(p_font_rid);
1507
ERR_FAIL_NULL(fd);
1508
1509
MutexLock lock(fd->mutex);
1510
fd->fixed_size_scale_mode = p_fixed_size_scale_mode;
1511
}
1512
1513
TextServer::FixedSizeScaleMode TextServerFallback::_font_get_fixed_size_scale_mode(const RID &p_font_rid) const {
1514
FontFallback *fd = _get_font_data(p_font_rid);
1515
ERR_FAIL_NULL_V(fd, FIXED_SIZE_SCALE_DISABLE);
1516
1517
MutexLock lock(fd->mutex);
1518
return fd->fixed_size_scale_mode;
1519
}
1520
1521
void TextServerFallback::_font_set_allow_system_fallback(const RID &p_font_rid, bool p_allow_system_fallback) {
1522
FontFallback *fd = _get_font_data(p_font_rid);
1523
ERR_FAIL_NULL(fd);
1524
1525
MutexLock lock(fd->mutex);
1526
fd->allow_system_fallback = p_allow_system_fallback;
1527
}
1528
1529
bool TextServerFallback::_font_is_allow_system_fallback(const RID &p_font_rid) const {
1530
FontFallback *fd = _get_font_data(p_font_rid);
1531
ERR_FAIL_NULL_V(fd, false);
1532
1533
MutexLock lock(fd->mutex);
1534
return fd->allow_system_fallback;
1535
}
1536
1537
void TextServerFallback::_font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) {
1538
FontFallback *fd = _get_font_data(p_font_rid);
1539
ERR_FAIL_NULL(fd);
1540
1541
MutexLock lock(fd->mutex);
1542
if (fd->force_autohinter != p_force_autohinter) {
1543
_font_clear_cache(fd);
1544
fd->force_autohinter = p_force_autohinter;
1545
}
1546
}
1547
1548
bool TextServerFallback::_font_is_force_autohinter(const RID &p_font_rid) const {
1549
FontFallback *fd = _get_font_data(p_font_rid);
1550
ERR_FAIL_NULL_V(fd, false);
1551
1552
MutexLock lock(fd->mutex);
1553
return fd->force_autohinter;
1554
}
1555
1556
void TextServerFallback::_font_set_modulate_color_glyphs(const RID &p_font_rid, bool p_modulate) {
1557
FontFallback *fd = _get_font_data(p_font_rid);
1558
ERR_FAIL_NULL(fd);
1559
1560
MutexLock lock(fd->mutex);
1561
if (fd->modulate_color_glyphs != p_modulate) {
1562
fd->modulate_color_glyphs = p_modulate;
1563
}
1564
}
1565
1566
bool TextServerFallback::_font_is_modulate_color_glyphs(const RID &p_font_rid) const {
1567
FontFallback *fd = _get_font_data(p_font_rid);
1568
ERR_FAIL_NULL_V(fd, false);
1569
1570
MutexLock lock(fd->mutex);
1571
return fd->modulate_color_glyphs;
1572
}
1573
1574
void TextServerFallback::_font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) {
1575
FontFallback *fd = _get_font_data(p_font_rid);
1576
ERR_FAIL_NULL(fd);
1577
1578
MutexLock lock(fd->mutex);
1579
if (fd->hinting != p_hinting) {
1580
_font_clear_cache(fd);
1581
fd->hinting = p_hinting;
1582
}
1583
}
1584
1585
TextServer::Hinting TextServerFallback::_font_get_hinting(const RID &p_font_rid) const {
1586
FontFallback *fd = _get_font_data(p_font_rid);
1587
ERR_FAIL_NULL_V(fd, HINTING_NONE);
1588
1589
MutexLock lock(fd->mutex);
1590
return fd->hinting;
1591
}
1592
1593
void TextServerFallback::_font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) {
1594
FontFallback *fd = _get_font_data(p_font_rid);
1595
ERR_FAIL_NULL(fd);
1596
1597
MutexLock lock(fd->mutex);
1598
fd->subpixel_positioning = p_subpixel;
1599
}
1600
1601
TextServer::SubpixelPositioning TextServerFallback::_font_get_subpixel_positioning(const RID &p_font_rid) const {
1602
FontFallback *fd = _get_font_data(p_font_rid);
1603
ERR_FAIL_NULL_V(fd, SUBPIXEL_POSITIONING_DISABLED);
1604
1605
MutexLock lock(fd->mutex);
1606
return fd->subpixel_positioning;
1607
}
1608
1609
void TextServerFallback::_font_set_keep_rounding_remainders(const RID &p_font_rid, bool p_keep_rounding_remainders) {
1610
FontFallback *fd = _get_font_data(p_font_rid);
1611
ERR_FAIL_NULL(fd);
1612
1613
MutexLock lock(fd->mutex);
1614
fd->keep_rounding_remainders = p_keep_rounding_remainders;
1615
}
1616
1617
bool TextServerFallback::_font_get_keep_rounding_remainders(const RID &p_font_rid) const {
1618
FontFallback *fd = _get_font_data(p_font_rid);
1619
ERR_FAIL_NULL_V(fd, false);
1620
1621
MutexLock lock(fd->mutex);
1622
return fd->keep_rounding_remainders;
1623
}
1624
1625
void TextServerFallback::_font_set_embolden(const RID &p_font_rid, double p_strength) {
1626
FontFallback *fd = _get_font_data(p_font_rid);
1627
ERR_FAIL_NULL(fd);
1628
1629
MutexLock lock(fd->mutex);
1630
if (fd->embolden != p_strength) {
1631
_font_clear_cache(fd);
1632
fd->embolden = p_strength;
1633
}
1634
}
1635
1636
double TextServerFallback::_font_get_embolden(const RID &p_font_rid) const {
1637
FontFallback *fd = _get_font_data(p_font_rid);
1638
ERR_FAIL_NULL_V(fd, 0.0);
1639
1640
MutexLock lock(fd->mutex);
1641
return fd->embolden;
1642
}
1643
1644
void TextServerFallback::_font_set_spacing(const RID &p_font_rid, SpacingType p_spacing, int64_t p_value) {
1645
ERR_FAIL_INDEX((int)p_spacing, 4);
1646
FontFallbackLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);
1647
if (fdv) {
1648
if (fdv->extra_spacing[p_spacing] != p_value) {
1649
fdv->extra_spacing[p_spacing] = p_value;
1650
}
1651
} else {
1652
FontFallback *fd = font_owner.get_or_null(p_font_rid);
1653
ERR_FAIL_NULL(fd);
1654
1655
MutexLock lock(fd->mutex);
1656
if (fd->extra_spacing[p_spacing] != p_value) {
1657
_font_clear_cache(fd);
1658
fd->extra_spacing[p_spacing] = p_value;
1659
}
1660
}
1661
}
1662
1663
int64_t TextServerFallback::_font_get_spacing(const RID &p_font_rid, SpacingType p_spacing) const {
1664
ERR_FAIL_INDEX_V((int)p_spacing, 4, 0);
1665
FontFallbackLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);
1666
if (fdv) {
1667
return fdv->extra_spacing[p_spacing];
1668
} else {
1669
FontFallback *fd = font_owner.get_or_null(p_font_rid);
1670
ERR_FAIL_NULL_V(fd, 0);
1671
1672
MutexLock lock(fd->mutex);
1673
return fd->extra_spacing[p_spacing];
1674
}
1675
}
1676
1677
void TextServerFallback::_font_set_baseline_offset(const RID &p_font_rid, double p_baseline_offset) {
1678
FontFallbackLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);
1679
if (fdv) {
1680
if (fdv->baseline_offset != p_baseline_offset) {
1681
fdv->baseline_offset = p_baseline_offset;
1682
}
1683
} else {
1684
FontFallback *fd = font_owner.get_or_null(p_font_rid);
1685
ERR_FAIL_NULL(fd);
1686
1687
MutexLock lock(fd->mutex);
1688
if (fd->baseline_offset != p_baseline_offset) {
1689
_font_clear_cache(fd);
1690
fd->baseline_offset = p_baseline_offset;
1691
}
1692
}
1693
}
1694
1695
double TextServerFallback::_font_get_baseline_offset(const RID &p_font_rid) const {
1696
FontFallbackLinkedVariation *fdv = font_var_owner.get_or_null(p_font_rid);
1697
if (fdv) {
1698
return fdv->baseline_offset;
1699
} else {
1700
FontFallback *fd = font_owner.get_or_null(p_font_rid);
1701
ERR_FAIL_NULL_V(fd, 0.0);
1702
1703
MutexLock lock(fd->mutex);
1704
return fd->baseline_offset;
1705
}
1706
}
1707
1708
void TextServerFallback::_font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) {
1709
FontFallback *fd = _get_font_data(p_font_rid);
1710
ERR_FAIL_NULL(fd);
1711
1712
MutexLock lock(fd->mutex);
1713
if (fd->transform != p_transform) {
1714
_font_clear_cache(fd);
1715
fd->transform = p_transform;
1716
}
1717
}
1718
1719
Transform2D TextServerFallback::_font_get_transform(const RID &p_font_rid) const {
1720
FontFallback *fd = _get_font_data(p_font_rid);
1721
ERR_FAIL_NULL_V(fd, Transform2D());
1722
1723
MutexLock lock(fd->mutex);
1724
return fd->transform;
1725
}
1726
1727
void TextServerFallback::_font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) {
1728
FontFallback *fd = _get_font_data(p_font_rid);
1729
ERR_FAIL_NULL(fd);
1730
1731
MutexLock lock(fd->mutex);
1732
if (!fd->variation_coordinates.recursive_equal(p_variation_coordinates, 1)) {
1733
_font_clear_cache(fd);
1734
fd->variation_coordinates = p_variation_coordinates.duplicate();
1735
}
1736
}
1737
1738
double TextServerFallback::_font_get_oversampling(const RID &p_font_rid) const {
1739
FontFallback *fd = _get_font_data(p_font_rid);
1740
ERR_FAIL_NULL_V(fd, -1.0);
1741
1742
MutexLock lock(fd->mutex);
1743
return fd->oversampling_override;
1744
}
1745
1746
void TextServerFallback::_font_set_oversampling(const RID &p_font_rid, double p_oversampling) {
1747
FontFallback *fd = _get_font_data(p_font_rid);
1748
ERR_FAIL_NULL(fd);
1749
1750
MutexLock lock(fd->mutex);
1751
if (fd->oversampling_override != p_oversampling) {
1752
_font_clear_cache(fd);
1753
fd->oversampling_override = p_oversampling;
1754
}
1755
}
1756
1757
Dictionary TextServerFallback::_font_get_variation_coordinates(const RID &p_font_rid) const {
1758
FontFallback *fd = _get_font_data(p_font_rid);
1759
ERR_FAIL_NULL_V(fd, Dictionary());
1760
1761
MutexLock lock(fd->mutex);
1762
return fd->variation_coordinates;
1763
}
1764
1765
TypedArray<Vector2i> TextServerFallback::_font_get_size_cache_list(const RID &p_font_rid) const {
1766
FontFallback *fd = _get_font_data(p_font_rid);
1767
ERR_FAIL_NULL_V(fd, TypedArray<Vector2i>());
1768
1769
MutexLock lock(fd->mutex);
1770
TypedArray<Vector2i> ret;
1771
for (const KeyValue<Vector2i, FontForSizeFallback *> &E : fd->cache) {
1772
if ((E.key.x % 64 == 0) && (E.value->viewport_oversampling == 0)) {
1773
ret.push_back(Vector2i(E.key.x / 64, E.key.y));
1774
}
1775
}
1776
return ret;
1777
}
1778
1779
TypedArray<Dictionary> TextServerFallback::_font_get_size_cache_info(const RID &p_font_rid) const {
1780
FontFallback *fd = _get_font_data(p_font_rid);
1781
ERR_FAIL_NULL_V(fd, TypedArray<Dictionary>());
1782
1783
MutexLock lock(fd->mutex);
1784
TypedArray<Dictionary> ret;
1785
for (const KeyValue<Vector2i, FontForSizeFallback *> &E : fd->cache) {
1786
Dictionary size_info;
1787
size_info["size_px"] = Vector2i(E.key.x / 64, E.key.y);
1788
if (E.value->viewport_oversampling) {
1789
size_info["viewport_oversampling"] = double(E.value->viewport_oversampling) / 64.0;
1790
}
1791
size_info["glyphs"] = E.value->glyph_map.size();
1792
size_info["textures"] = E.value->textures.size();
1793
uint64_t sz = 0;
1794
for (const ShelfPackTexture &tx : E.value->textures) {
1795
sz += tx.image->get_data_size() * 2;
1796
}
1797
size_info["textures_size"] = sz;
1798
ret.push_back(size_info);
1799
}
1800
1801
return ret;
1802
}
1803
1804
void TextServerFallback::_font_clear_size_cache(const RID &p_font_rid) {
1805
FontFallback *fd = _get_font_data(p_font_rid);
1806
ERR_FAIL_NULL(fd);
1807
1808
MutexLock lock(fd->mutex);
1809
MutexLock ftlock(ft_mutex);
1810
for (const KeyValue<Vector2i, FontForSizeFallback *> &E : fd->cache) {
1811
if (E.value->viewport_oversampling != 0) {
1812
OversamplingLevel *ol = oversampling_levels.getptr(E.value->viewport_oversampling);
1813
if (ol) {
1814
ol->fonts.erase(E.value);
1815
}
1816
}
1817
memdelete(E.value);
1818
}
1819
fd->cache.clear();
1820
}
1821
1822
void TextServerFallback::_font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) {
1823
FontFallback *fd = _get_font_data(p_font_rid);
1824
ERR_FAIL_NULL(fd);
1825
1826
MutexLock lock(fd->mutex);
1827
MutexLock ftlock(ft_mutex);
1828
Vector2i size = Vector2i(p_size.x * 64, p_size.y);
1829
if (fd->cache.has(size)) {
1830
if (fd->cache[size]->viewport_oversampling != 0) {
1831
OversamplingLevel *ol = oversampling_levels.getptr(fd->cache[size]->viewport_oversampling);
1832
if (ol) {
1833
ol->fonts.erase(fd->cache[size]);
1834
}
1835
}
1836
memdelete(fd->cache[size]);
1837
fd->cache.erase(size);
1838
}
1839
}
1840
1841
void TextServerFallback::_font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) {
1842
FontFallback *fd = _get_font_data(p_font_rid);
1843
ERR_FAIL_NULL(fd);
1844
1845
MutexLock lock(fd->mutex);
1846
Vector2i size = _get_size(fd, p_size);
1847
1848
FontForSizeFallback *ffsd = nullptr;
1849
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
1850
ffsd->ascent = p_ascent;
1851
}
1852
1853
double TextServerFallback::_font_get_ascent(const RID &p_font_rid, int64_t p_size) const {
1854
FontFallback *fd = _get_font_data(p_font_rid);
1855
ERR_FAIL_NULL_V(fd, 0.0);
1856
1857
MutexLock lock(fd->mutex);
1858
Vector2i size = _get_size(fd, p_size);
1859
1860
FontForSizeFallback *ffsd = nullptr;
1861
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);
1862
1863
if (fd->msdf) {
1864
return ffsd->ascent * (double)p_size / (double)fd->msdf_source_size;
1865
} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {
1866
if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {
1867
return ffsd->ascent * (double)p_size / (double)fd->fixed_size;
1868
} else {
1869
return ffsd->ascent * Math::round((double)p_size / (double)fd->fixed_size);
1870
}
1871
} else {
1872
return ffsd->ascent;
1873
}
1874
}
1875
1876
void TextServerFallback::_font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) {
1877
FontFallback *fd = _get_font_data(p_font_rid);
1878
ERR_FAIL_NULL(fd);
1879
1880
Vector2i size = _get_size(fd, p_size);
1881
1882
FontForSizeFallback *ffsd = nullptr;
1883
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
1884
ffsd->descent = p_descent;
1885
}
1886
1887
double TextServerFallback::_font_get_descent(const RID &p_font_rid, int64_t p_size) const {
1888
FontFallback *fd = _get_font_data(p_font_rid);
1889
ERR_FAIL_NULL_V(fd, 0.0);
1890
1891
MutexLock lock(fd->mutex);
1892
Vector2i size = _get_size(fd, p_size);
1893
1894
FontForSizeFallback *ffsd = nullptr;
1895
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);
1896
1897
if (fd->msdf) {
1898
return ffsd->descent * (double)p_size / (double)fd->msdf_source_size;
1899
} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {
1900
if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {
1901
return ffsd->descent * (double)p_size / (double)fd->fixed_size;
1902
} else {
1903
return ffsd->descent * Math::round((double)p_size / (double)fd->fixed_size);
1904
}
1905
} else {
1906
return ffsd->descent;
1907
}
1908
}
1909
1910
void TextServerFallback::_font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) {
1911
FontFallback *fd = _get_font_data(p_font_rid);
1912
ERR_FAIL_NULL(fd);
1913
1914
MutexLock lock(fd->mutex);
1915
Vector2i size = _get_size(fd, p_size);
1916
1917
FontForSizeFallback *ffsd = nullptr;
1918
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
1919
ffsd->underline_position = p_underline_position;
1920
}
1921
1922
double TextServerFallback::_font_get_underline_position(const RID &p_font_rid, int64_t p_size) const {
1923
FontFallback *fd = _get_font_data(p_font_rid);
1924
ERR_FAIL_NULL_V(fd, 0.0);
1925
1926
MutexLock lock(fd->mutex);
1927
Vector2i size = _get_size(fd, p_size);
1928
1929
FontForSizeFallback *ffsd = nullptr;
1930
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);
1931
1932
if (fd->msdf) {
1933
return ffsd->underline_position * (double)p_size / (double)fd->msdf_source_size;
1934
} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {
1935
if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {
1936
return ffsd->underline_position * (double)p_size / (double)fd->fixed_size;
1937
} else {
1938
return ffsd->underline_position * Math::round((double)p_size / (double)fd->fixed_size);
1939
}
1940
} else {
1941
return ffsd->underline_position;
1942
}
1943
}
1944
1945
void TextServerFallback::_font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) {
1946
FontFallback *fd = _get_font_data(p_font_rid);
1947
ERR_FAIL_NULL(fd);
1948
1949
MutexLock lock(fd->mutex);
1950
Vector2i size = _get_size(fd, p_size);
1951
1952
FontForSizeFallback *ffsd = nullptr;
1953
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
1954
ffsd->underline_thickness = p_underline_thickness;
1955
}
1956
1957
double TextServerFallback::_font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const {
1958
FontFallback *fd = _get_font_data(p_font_rid);
1959
ERR_FAIL_NULL_V(fd, 0.0);
1960
1961
MutexLock lock(fd->mutex);
1962
Vector2i size = _get_size(fd, p_size);
1963
1964
FontForSizeFallback *ffsd = nullptr;
1965
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);
1966
1967
if (fd->msdf) {
1968
return ffsd->underline_thickness * (double)p_size / (double)fd->msdf_source_size;
1969
} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {
1970
if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {
1971
return ffsd->underline_thickness * (double)p_size / (double)fd->fixed_size;
1972
} else {
1973
return ffsd->underline_thickness * Math::round((double)p_size / (double)fd->fixed_size);
1974
}
1975
} else {
1976
return ffsd->underline_thickness;
1977
}
1978
}
1979
1980
void TextServerFallback::_font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) {
1981
FontFallback *fd = _get_font_data(p_font_rid);
1982
ERR_FAIL_NULL(fd);
1983
1984
MutexLock lock(fd->mutex);
1985
Vector2i size = _get_size(fd, p_size);
1986
1987
FontForSizeFallback *ffsd = nullptr;
1988
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
1989
#ifdef MODULE_FREETYPE_ENABLED
1990
if (fd->face) {
1991
return; // Do not override scale for dynamic fonts, it's calculated automatically.
1992
}
1993
#endif
1994
ffsd->scale = p_scale;
1995
}
1996
1997
double TextServerFallback::_font_get_scale(const RID &p_font_rid, int64_t p_size) const {
1998
FontFallback *fd = _get_font_data(p_font_rid);
1999
ERR_FAIL_NULL_V(fd, 0.0);
2000
2001
MutexLock lock(fd->mutex);
2002
Vector2i size = _get_size(fd, p_size);
2003
2004
FontForSizeFallback *ffsd = nullptr;
2005
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0.0);
2006
2007
if (fd->msdf) {
2008
return ffsd->scale * (double)p_size / (double)fd->msdf_source_size;
2009
} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {
2010
if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {
2011
return ffsd->scale * (double)p_size / (double)fd->fixed_size;
2012
} else {
2013
return ffsd->scale * Math::round((double)p_size / (double)fd->fixed_size);
2014
}
2015
} else {
2016
return ffsd->scale;
2017
}
2018
}
2019
2020
int64_t TextServerFallback::_font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const {
2021
FontFallback *fd = _get_font_data(p_font_rid);
2022
ERR_FAIL_NULL_V(fd, 0);
2023
2024
MutexLock lock(fd->mutex);
2025
Vector2i size = _get_size_outline(fd, p_size);
2026
2027
FontForSizeFallback *ffsd = nullptr;
2028
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), 0);
2029
2030
return ffsd->textures.size();
2031
}
2032
2033
void TextServerFallback::_font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) {
2034
FontFallback *fd = _get_font_data(p_font_rid);
2035
ERR_FAIL_NULL(fd);
2036
MutexLock lock(fd->mutex);
2037
Vector2i size = _get_size_outline(fd, p_size);
2038
2039
FontForSizeFallback *ffsd = nullptr;
2040
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
2041
ffsd->textures.clear();
2042
}
2043
2044
void TextServerFallback::_font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) {
2045
FontFallback *fd = _get_font_data(p_font_rid);
2046
ERR_FAIL_NULL(fd);
2047
2048
MutexLock lock(fd->mutex);
2049
Vector2i size = _get_size_outline(fd, p_size);
2050
FontForSizeFallback *ffsd = nullptr;
2051
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
2052
ERR_FAIL_INDEX(p_texture_index, ffsd->textures.size());
2053
2054
ffsd->textures.remove_at(p_texture_index);
2055
}
2056
2057
void TextServerFallback::_font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) {
2058
FontFallback *fd = _get_font_data(p_font_rid);
2059
ERR_FAIL_NULL(fd);
2060
ERR_FAIL_COND(p_image.is_null());
2061
2062
MutexLock lock(fd->mutex);
2063
Vector2i size = _get_size_outline(fd, p_size);
2064
FontForSizeFallback *ffsd = nullptr;
2065
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
2066
ERR_FAIL_COND(p_texture_index < 0);
2067
if (p_texture_index >= ffsd->textures.size()) {
2068
ffsd->textures.resize(p_texture_index + 1);
2069
}
2070
2071
ShelfPackTexture &tex = ffsd->textures.write[p_texture_index];
2072
2073
tex.image = p_image;
2074
tex.texture_w = p_image->get_width();
2075
tex.texture_h = p_image->get_height();
2076
2077
Ref<Image> img = p_image;
2078
if (fd->mipmaps && !img->has_mipmaps()) {
2079
img = p_image->duplicate();
2080
img->generate_mipmaps();
2081
}
2082
tex.texture = ImageTexture::create_from_image(img);
2083
tex.dirty = false;
2084
}
2085
2086
Ref<Image> TextServerFallback::_font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
2087
FontFallback *fd = _get_font_data(p_font_rid);
2088
ERR_FAIL_NULL_V(fd, Ref<Image>());
2089
2090
MutexLock lock(fd->mutex);
2091
Vector2i size = _get_size_outline(fd, p_size);
2092
FontForSizeFallback *ffsd = nullptr;
2093
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Ref<Image>());
2094
ERR_FAIL_INDEX_V(p_texture_index, ffsd->textures.size(), Ref<Image>());
2095
2096
const ShelfPackTexture &tex = ffsd->textures[p_texture_index];
2097
return tex.image;
2098
}
2099
2100
void TextServerFallback::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offsets) {
2101
ERR_FAIL_COND(p_offsets.size() % 4 != 0);
2102
FontFallback *fd = _get_font_data(p_font_rid);
2103
ERR_FAIL_NULL(fd);
2104
2105
MutexLock lock(fd->mutex);
2106
Vector2i size = _get_size_outline(fd, p_size);
2107
FontForSizeFallback *ffsd = nullptr;
2108
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
2109
ERR_FAIL_COND(p_texture_index < 0);
2110
if (p_texture_index >= ffsd->textures.size()) {
2111
ffsd->textures.resize(p_texture_index + 1);
2112
}
2113
2114
ShelfPackTexture &tex = ffsd->textures.write[p_texture_index];
2115
tex.shelves.clear();
2116
for (int32_t i = 0; i < p_offsets.size(); i += 4) {
2117
tex.shelves.push_back(Shelf(p_offsets[i], p_offsets[i + 1], p_offsets[i + 2], p_offsets[i + 3]));
2118
}
2119
}
2120
2121
PackedInt32Array TextServerFallback::_font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
2122
FontFallback *fd = _get_font_data(p_font_rid);
2123
ERR_FAIL_NULL_V(fd, PackedInt32Array());
2124
2125
MutexLock lock(fd->mutex);
2126
Vector2i size = _get_size_outline(fd, p_size);
2127
FontForSizeFallback *ffsd = nullptr;
2128
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), PackedInt32Array());
2129
ERR_FAIL_INDEX_V(p_texture_index, ffsd->textures.size(), PackedInt32Array());
2130
2131
const ShelfPackTexture &tex = ffsd->textures[p_texture_index];
2132
PackedInt32Array ret;
2133
ret.resize(tex.shelves.size() * 4);
2134
2135
int32_t *wr = ret.ptrw();
2136
int32_t i = 0;
2137
for (const Shelf &E : tex.shelves) {
2138
wr[i * 4] = E.x;
2139
wr[i * 4 + 1] = E.y;
2140
wr[i * 4 + 2] = E.w;
2141
wr[i * 4 + 3] = E.h;
2142
i++;
2143
}
2144
return ret;
2145
}
2146
2147
PackedInt32Array TextServerFallback::_font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
2148
FontFallback *fd = _get_font_data(p_font_rid);
2149
ERR_FAIL_NULL_V(fd, PackedInt32Array());
2150
2151
MutexLock lock(fd->mutex);
2152
Vector2i size = _get_size_outline(fd, p_size);
2153
FontForSizeFallback *ffsd = nullptr;
2154
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), PackedInt32Array());
2155
2156
PackedInt32Array ret;
2157
const HashMap<int32_t, FontGlyph> &gl = ffsd->glyph_map;
2158
for (const KeyValue<int32_t, FontGlyph> &E : gl) {
2159
ret.push_back(E.key);
2160
}
2161
return ret;
2162
}
2163
2164
void TextServerFallback::_font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) {
2165
FontFallback *fd = _get_font_data(p_font_rid);
2166
ERR_FAIL_NULL(fd);
2167
2168
MutexLock lock(fd->mutex);
2169
Vector2i size = _get_size_outline(fd, p_size);
2170
FontForSizeFallback *ffsd = nullptr;
2171
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
2172
2173
ffsd->glyph_map.clear();
2174
}
2175
2176
void TextServerFallback::_font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) {
2177
FontFallback *fd = _get_font_data(p_font_rid);
2178
ERR_FAIL_NULL(fd);
2179
2180
MutexLock lock(fd->mutex);
2181
Vector2i size = _get_size_outline(fd, p_size);
2182
FontForSizeFallback *ffsd = nullptr;
2183
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
2184
2185
ffsd->glyph_map.erase(p_glyph);
2186
}
2187
2188
Vector2 TextServerFallback::_font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const {
2189
FontFallback *fd = _get_font_data(p_font_rid);
2190
ERR_FAIL_NULL_V(fd, Vector2());
2191
2192
MutexLock lock(fd->mutex);
2193
Vector2i size = _get_size(fd, p_size);
2194
2195
FontForSizeFallback *ffsd = nullptr;
2196
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());
2197
2198
int mod = 0;
2199
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
2200
TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();
2201
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
2202
mod = (layout << 24);
2203
}
2204
}
2205
2206
FontGlyph fgl;
2207
if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {
2208
return Vector2(); // Invalid or non graphicl glyph, do not display errors.
2209
}
2210
2211
Vector2 ea;
2212
if (fd->embolden != 0.0) {
2213
ea.x = fd->embolden * double(size.x) / 4096.0;
2214
}
2215
2216
double scale = _font_get_scale(p_font_rid, p_size);
2217
if (fd->msdf) {
2218
return (fgl.advance + ea) * (double)p_size / (double)fd->msdf_source_size;
2219
} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {
2220
if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {
2221
return (fgl.advance + ea) * (double)p_size / (double)fd->fixed_size;
2222
} else {
2223
return (fgl.advance + ea) * Math::round((double)p_size / (double)fd->fixed_size);
2224
}
2225
} 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))) {
2226
return (fgl.advance + ea).round();
2227
} else {
2228
return fgl.advance + ea;
2229
}
2230
}
2231
2232
void TextServerFallback::_font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) {
2233
FontFallback *fd = _get_font_data(p_font_rid);
2234
ERR_FAIL_NULL(fd);
2235
2236
MutexLock lock(fd->mutex);
2237
Vector2i size = _get_size(fd, p_size);
2238
2239
FontForSizeFallback *ffsd = nullptr;
2240
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
2241
2242
FontGlyph &fgl = ffsd->glyph_map[p_glyph];
2243
2244
fgl.advance = p_advance;
2245
fgl.found = true;
2246
}
2247
2248
Vector2 TextServerFallback::_font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
2249
FontFallback *fd = _get_font_data(p_font_rid);
2250
ERR_FAIL_NULL_V(fd, Vector2());
2251
2252
MutexLock lock(fd->mutex);
2253
Vector2i size = _get_size_outline(fd, p_size);
2254
2255
FontForSizeFallback *ffsd = nullptr;
2256
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());
2257
2258
int mod = 0;
2259
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
2260
TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();
2261
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
2262
mod = (layout << 24);
2263
}
2264
}
2265
2266
FontGlyph fgl;
2267
if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {
2268
return Vector2(); // Invalid or non graphicl glyph, do not display errors.
2269
}
2270
2271
if (fd->msdf) {
2272
return fgl.rect.position * (double)p_size.x / (double)fd->msdf_source_size;
2273
} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size.x * 64) {
2274
if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {
2275
return fgl.rect.position * (double)p_size.x / (double)fd->fixed_size;
2276
} else {
2277
return fgl.rect.position * Math::round((double)p_size.x / (double)fd->fixed_size);
2278
}
2279
} else {
2280
return fgl.rect.position;
2281
}
2282
}
2283
2284
void TextServerFallback::_font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) {
2285
FontFallback *fd = _get_font_data(p_font_rid);
2286
ERR_FAIL_NULL(fd);
2287
2288
MutexLock lock(fd->mutex);
2289
Vector2i size = _get_size_outline(fd, p_size);
2290
2291
FontForSizeFallback *ffsd = nullptr;
2292
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
2293
2294
FontGlyph &fgl = ffsd->glyph_map[p_glyph];
2295
2296
fgl.rect.position = p_offset;
2297
fgl.found = true;
2298
}
2299
2300
Vector2 TextServerFallback::_font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
2301
FontFallback *fd = _get_font_data(p_font_rid);
2302
ERR_FAIL_NULL_V(fd, Vector2());
2303
2304
MutexLock lock(fd->mutex);
2305
Vector2i size = _get_size_outline(fd, p_size);
2306
2307
FontForSizeFallback *ffsd = nullptr;
2308
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());
2309
2310
int mod = 0;
2311
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
2312
TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();
2313
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
2314
mod = (layout << 24);
2315
}
2316
}
2317
2318
FontGlyph fgl;
2319
if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {
2320
return Vector2(); // Invalid or non graphicl glyph, do not display errors.
2321
}
2322
2323
if (fd->msdf) {
2324
return fgl.rect.size * (double)p_size.x / (double)fd->msdf_source_size;
2325
} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size.x * 64) {
2326
if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {
2327
return fgl.rect.size * (double)p_size.x / (double)fd->fixed_size;
2328
} else {
2329
return fgl.rect.size * Math::round((double)p_size.x / (double)fd->fixed_size);
2330
}
2331
} else {
2332
return fgl.rect.size;
2333
}
2334
}
2335
2336
void TextServerFallback::_font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) {
2337
FontFallback *fd = _get_font_data(p_font_rid);
2338
ERR_FAIL_NULL(fd);
2339
2340
MutexLock lock(fd->mutex);
2341
Vector2i size = _get_size_outline(fd, p_size);
2342
2343
FontForSizeFallback *ffsd = nullptr;
2344
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
2345
2346
FontGlyph &fgl = ffsd->glyph_map[p_glyph];
2347
2348
fgl.rect.size = p_gl_size;
2349
fgl.found = true;
2350
}
2351
2352
Rect2 TextServerFallback::_font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
2353
FontFallback *fd = _get_font_data(p_font_rid);
2354
ERR_FAIL_NULL_V(fd, Rect2());
2355
2356
MutexLock lock(fd->mutex);
2357
Vector2i size = _get_size_outline(fd, p_size);
2358
2359
FontForSizeFallback *ffsd = nullptr;
2360
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Rect2());
2361
2362
int mod = 0;
2363
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
2364
TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();
2365
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
2366
mod = (layout << 24);
2367
}
2368
}
2369
2370
FontGlyph fgl;
2371
if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {
2372
return Rect2(); // Invalid or non graphicl glyph, do not display errors.
2373
}
2374
2375
return fgl.uv_rect;
2376
}
2377
2378
void TextServerFallback::_font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) {
2379
FontFallback *fd = _get_font_data(p_font_rid);
2380
ERR_FAIL_NULL(fd);
2381
2382
MutexLock lock(fd->mutex);
2383
Vector2i size = _get_size_outline(fd, p_size);
2384
2385
FontForSizeFallback *ffsd = nullptr;
2386
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
2387
2388
FontGlyph &fgl = ffsd->glyph_map[p_glyph];
2389
2390
fgl.uv_rect = p_uv_rect;
2391
fgl.found = true;
2392
}
2393
2394
int64_t TextServerFallback::_font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
2395
FontFallback *fd = _get_font_data(p_font_rid);
2396
ERR_FAIL_NULL_V(fd, -1);
2397
2398
MutexLock lock(fd->mutex);
2399
Vector2i size = _get_size_outline(fd, p_size);
2400
2401
FontForSizeFallback *ffsd = nullptr;
2402
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), -1);
2403
2404
int mod = 0;
2405
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
2406
TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();
2407
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
2408
mod = (layout << 24);
2409
}
2410
}
2411
2412
FontGlyph fgl;
2413
if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {
2414
return -1; // Invalid or non graphicl glyph, do not display errors.
2415
}
2416
2417
return fgl.texture_idx;
2418
}
2419
2420
void TextServerFallback::_font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) {
2421
FontFallback *fd = _get_font_data(p_font_rid);
2422
ERR_FAIL_NULL(fd);
2423
2424
MutexLock lock(fd->mutex);
2425
Vector2i size = _get_size_outline(fd, p_size);
2426
2427
FontForSizeFallback *ffsd = nullptr;
2428
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
2429
2430
FontGlyph &fgl = ffsd->glyph_map[p_glyph];
2431
2432
fgl.texture_idx = p_texture_idx;
2433
fgl.found = true;
2434
}
2435
2436
RID TextServerFallback::_font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
2437
FontFallback *fd = _get_font_data(p_font_rid);
2438
ERR_FAIL_NULL_V(fd, RID());
2439
2440
MutexLock lock(fd->mutex);
2441
Vector2i size = _get_size_outline(fd, p_size);
2442
2443
FontForSizeFallback *ffsd = nullptr;
2444
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), RID());
2445
2446
int mod = 0;
2447
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
2448
TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();
2449
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
2450
mod = (layout << 24);
2451
}
2452
}
2453
2454
FontGlyph fgl;
2455
if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {
2456
return RID(); // Invalid or non graphicl glyph, do not display errors.
2457
}
2458
2459
ERR_FAIL_COND_V(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size(), RID());
2460
2461
if (RenderingServer::get_singleton() != nullptr) {
2462
if (fgl.texture_idx != -1) {
2463
if (ffsd->textures[fgl.texture_idx].dirty) {
2464
ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];
2465
Ref<Image> img = tex.image;
2466
if (fgl.from_svg) {
2467
// Same as the "fix alpha border" process option when importing SVGs
2468
img->fix_alpha_edges();
2469
}
2470
if (fd->mipmaps && !img->has_mipmaps()) {
2471
img = tex.image->duplicate();
2472
img->generate_mipmaps();
2473
}
2474
if (tex.texture.is_null()) {
2475
tex.texture = ImageTexture::create_from_image(img);
2476
} else {
2477
tex.texture->update(img);
2478
}
2479
tex.dirty = false;
2480
}
2481
return ffsd->textures[fgl.texture_idx].texture->get_rid();
2482
}
2483
}
2484
2485
return RID();
2486
}
2487
2488
Size2 TextServerFallback::_font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
2489
FontFallback *fd = _get_font_data(p_font_rid);
2490
ERR_FAIL_NULL_V(fd, Size2());
2491
2492
MutexLock lock(fd->mutex);
2493
Vector2i size = _get_size_outline(fd, p_size);
2494
2495
FontForSizeFallback *ffsd = nullptr;
2496
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Size2());
2497
2498
int mod = 0;
2499
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
2500
TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();
2501
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
2502
mod = (layout << 24);
2503
}
2504
}
2505
2506
FontGlyph fgl;
2507
if (!_ensure_glyph(fd, size, p_glyph | mod, fgl)) {
2508
return Size2(); // Invalid or non graphicl glyph, do not display errors.
2509
}
2510
2511
ERR_FAIL_COND_V(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size(), Size2());
2512
2513
if (RenderingServer::get_singleton() != nullptr) {
2514
if (fgl.texture_idx != -1) {
2515
if (ffsd->textures[fgl.texture_idx].dirty) {
2516
ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];
2517
Ref<Image> img = tex.image;
2518
if (fgl.from_svg) {
2519
// Same as the "fix alpha border" process option when importing SVGs
2520
img->fix_alpha_edges();
2521
}
2522
if (fd->mipmaps && !img->has_mipmaps()) {
2523
img = tex.image->duplicate();
2524
img->generate_mipmaps();
2525
}
2526
if (tex.texture.is_null()) {
2527
tex.texture = ImageTexture::create_from_image(img);
2528
} else {
2529
tex.texture->update(img);
2530
}
2531
tex.dirty = false;
2532
}
2533
return ffsd->textures[fgl.texture_idx].texture->get_size();
2534
}
2535
}
2536
2537
return Size2();
2538
}
2539
2540
Dictionary TextServerFallback::_font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const {
2541
FontFallback *fd = _get_font_data(p_font_rid);
2542
ERR_FAIL_NULL_V(fd, Dictionary());
2543
2544
MutexLock lock(fd->mutex);
2545
Vector2i size = _get_size(fd, p_size);
2546
2547
FontForSizeFallback *ffsd = nullptr;
2548
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary());
2549
2550
#ifdef MODULE_FREETYPE_ENABLED
2551
PackedVector3Array points;
2552
PackedInt32Array contours;
2553
2554
int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
2555
2556
int error = FT_Load_Glyph(fd->face, FT_Get_Char_Index(fd->face, index), FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
2557
ERR_FAIL_COND_V(error, Dictionary());
2558
2559
if (fd->embolden != 0.f) {
2560
FT_Pos strength = fd->embolden * size.x / 16; // 26.6 fractional units (1 / 64).
2561
FT_Outline_Embolden(&fd->face->glyph->outline, strength);
2562
}
2563
2564
if (fd->transform != Transform2D()) {
2565
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).
2566
FT_Outline_Transform(&fd->face->glyph->outline, &mat);
2567
}
2568
2569
double scale = (1.0 / 64.0) * ffsd->scale;
2570
if (fd->msdf) {
2571
scale = scale * (double)p_size / (double)fd->msdf_source_size;
2572
} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {
2573
if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {
2574
scale = scale * (double)p_size / (double)fd->fixed_size;
2575
} else {
2576
scale = scale * Math::round((double)p_size / (double)fd->fixed_size);
2577
}
2578
}
2579
for (short i = 0; i < fd->face->glyph->outline.n_points; i++) {
2580
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])));
2581
}
2582
for (short i = 0; i < fd->face->glyph->outline.n_contours; i++) {
2583
contours.push_back(fd->face->glyph->outline.contours[i]);
2584
}
2585
bool orientation = (FT_Outline_Get_Orientation(&fd->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
2586
2587
Dictionary out;
2588
out["points"] = points;
2589
out["contours"] = contours;
2590
out["orientation"] = orientation;
2591
return out;
2592
#else
2593
return Dictionary();
2594
#endif
2595
}
2596
2597
TypedArray<Vector2i> TextServerFallback::_font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {
2598
FontFallback *fd = _get_font_data(p_font_rid);
2599
ERR_FAIL_NULL_V(fd, TypedArray<Vector2i>());
2600
2601
MutexLock lock(fd->mutex);
2602
Vector2i size = _get_size(fd, p_size);
2603
2604
FontForSizeFallback *ffsd = nullptr;
2605
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), TypedArray<Vector2i>());
2606
2607
TypedArray<Vector2i> ret;
2608
for (const KeyValue<Vector2i, Vector2> &E : ffsd->kerning_map) {
2609
ret.push_back(E.key);
2610
}
2611
return ret;
2612
}
2613
2614
void TextServerFallback::_font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) {
2615
FontFallback *fd = _get_font_data(p_font_rid);
2616
ERR_FAIL_NULL(fd);
2617
2618
MutexLock lock(fd->mutex);
2619
Vector2i size = _get_size(fd, p_size);
2620
2621
FontForSizeFallback *ffsd = nullptr;
2622
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
2623
ffsd->kerning_map.clear();
2624
}
2625
2626
void TextServerFallback::_font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) {
2627
FontFallback *fd = _get_font_data(p_font_rid);
2628
ERR_FAIL_NULL(fd);
2629
2630
MutexLock lock(fd->mutex);
2631
Vector2i size = _get_size(fd, p_size);
2632
2633
FontForSizeFallback *ffsd = nullptr;
2634
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
2635
ffsd->kerning_map.erase(p_glyph_pair);
2636
}
2637
2638
void TextServerFallback::_font_set_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
2639
FontFallback *fd = _get_font_data(p_font_rid);
2640
ERR_FAIL_NULL(fd);
2641
2642
MutexLock lock(fd->mutex);
2643
Vector2i size = _get_size(fd, p_size);
2644
2645
FontForSizeFallback *ffsd = nullptr;
2646
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
2647
ffsd->kerning_map[p_glyph_pair] = p_kerning;
2648
}
2649
2650
Vector2 TextServerFallback::_font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const {
2651
FontFallback *fd = _get_font_data(p_font_rid);
2652
ERR_FAIL_NULL_V(fd, Vector2());
2653
2654
MutexLock lock(fd->mutex);
2655
Vector2i size = _get_size(fd, p_size);
2656
2657
FontForSizeFallback *ffsd = nullptr;
2658
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Vector2());
2659
2660
const HashMap<Vector2i, Vector2> &kern = ffsd->kerning_map;
2661
2662
if (kern.has(p_glyph_pair)) {
2663
if (fd->msdf) {
2664
return kern[p_glyph_pair] * (double)p_size / (double)fd->msdf_source_size;
2665
} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {
2666
if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {
2667
return kern[p_glyph_pair] * (double)p_size / (double)fd->fixed_size;
2668
} else {
2669
return kern[p_glyph_pair] * Math::round((double)p_size / (double)fd->fixed_size);
2670
}
2671
} else {
2672
return kern[p_glyph_pair];
2673
}
2674
} else {
2675
#ifdef MODULE_FREETYPE_ENABLED
2676
if (fd->face) {
2677
FT_Vector delta;
2678
int32_t glyph_a = FT_Get_Char_Index(fd->face, p_glyph_pair.x);
2679
int32_t glyph_b = FT_Get_Char_Index(fd->face, p_glyph_pair.y);
2680
FT_Get_Kerning(fd->face, glyph_a, glyph_b, FT_KERNING_DEFAULT, &delta);
2681
if (fd->msdf) {
2682
return Vector2(delta.x, delta.y) * (double)p_size / (double)fd->msdf_source_size;
2683
} else if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE && size.x != p_size * 64) {
2684
if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {
2685
return Vector2(delta.x, delta.y) * (double)p_size / (double)fd->fixed_size;
2686
} else {
2687
return Vector2(delta.x, delta.y) * Math::round((double)p_size / (double)fd->fixed_size);
2688
}
2689
} else {
2690
return Vector2(delta.x, delta.y);
2691
}
2692
}
2693
#endif
2694
}
2695
return Vector2();
2696
}
2697
2698
int64_t TextServerFallback::_font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const {
2699
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) + ".");
2700
return (int64_t)p_char;
2701
}
2702
2703
int64_t TextServerFallback::_font_get_char_from_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_glyph_index) const {
2704
return p_glyph_index;
2705
}
2706
2707
bool TextServerFallback::_font_has_char(const RID &p_font_rid, int64_t p_char) const {
2708
FontFallback *fd = _get_font_data(p_font_rid);
2709
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) + ".");
2710
if (!fd) {
2711
return false;
2712
}
2713
2714
MutexLock lock(fd->mutex);
2715
FontForSizeFallback *ffsd = nullptr;
2716
if (fd->cache.is_empty()) {
2717
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size * 64, 0) : Vector2i(16 * 64, 0), ffsd), false);
2718
} else {
2719
ffsd = fd->cache.begin()->value;
2720
}
2721
2722
#ifdef MODULE_FREETYPE_ENABLED
2723
if (fd->face) {
2724
return FT_Get_Char_Index(fd->face, p_char) != 0;
2725
}
2726
#endif
2727
return ffsd->glyph_map.has((int32_t)p_char);
2728
}
2729
2730
String TextServerFallback::_font_get_supported_chars(const RID &p_font_rid) const {
2731
FontFallback *fd = _get_font_data(p_font_rid);
2732
ERR_FAIL_NULL_V(fd, String());
2733
2734
MutexLock lock(fd->mutex);
2735
FontForSizeFallback *ffsd = nullptr;
2736
if (fd->cache.is_empty()) {
2737
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size * 64, 0) : Vector2i(16 * 64, 0), ffsd), String());
2738
} else {
2739
ffsd = fd->cache.begin()->value;
2740
}
2741
2742
String chars;
2743
#ifdef MODULE_FREETYPE_ENABLED
2744
if (fd->face) {
2745
FT_UInt gindex;
2746
FT_ULong charcode = FT_Get_First_Char(fd->face, &gindex);
2747
while (gindex != 0) {
2748
if (charcode != 0) {
2749
chars = chars + String::chr(charcode);
2750
}
2751
charcode = FT_Get_Next_Char(fd->face, charcode, &gindex);
2752
}
2753
return chars;
2754
}
2755
#endif
2756
const HashMap<int32_t, FontGlyph> &gl = ffsd->glyph_map;
2757
for (const KeyValue<int32_t, FontGlyph> &E : gl) {
2758
chars = chars + String::chr(E.key);
2759
}
2760
return chars;
2761
}
2762
2763
PackedInt32Array TextServerFallback::_font_get_supported_glyphs(const RID &p_font_rid) const {
2764
FontFallback *fd = _get_font_data(p_font_rid);
2765
ERR_FAIL_NULL_V(fd, PackedInt32Array());
2766
2767
MutexLock lock(fd->mutex);
2768
FontForSizeFallback *at_size = nullptr;
2769
if (fd->cache.is_empty()) {
2770
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());
2771
} else {
2772
at_size = fd->cache.begin()->value;
2773
}
2774
2775
PackedInt32Array glyphs;
2776
#ifdef MODULE_FREETYPE_ENABLED
2777
if (fd->face) {
2778
FT_UInt gindex;
2779
FT_ULong charcode = FT_Get_First_Char(fd->face, &gindex);
2780
while (gindex != 0) {
2781
glyphs.push_back(gindex);
2782
charcode = FT_Get_Next_Char(fd->face, charcode, &gindex);
2783
}
2784
return glyphs;
2785
}
2786
#endif
2787
if (at_size) {
2788
const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map;
2789
for (const KeyValue<int32_t, FontGlyph> &E : gl) {
2790
glyphs.push_back(E.key);
2791
}
2792
}
2793
return glyphs;
2794
}
2795
2796
void TextServerFallback::_font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) {
2797
FontFallback *fd = _get_font_data(p_font_rid);
2798
ERR_FAIL_NULL(fd);
2799
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) + ".");
2800
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) + ".");
2801
2802
MutexLock lock(fd->mutex);
2803
Vector2i size = _get_size_outline(fd, p_size);
2804
FontForSizeFallback *ffsd = nullptr;
2805
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
2806
for (int64_t i = p_start; i <= p_end; i++) {
2807
#ifdef MODULE_FREETYPE_ENABLED
2808
int32_t idx = i;
2809
if (fd->face) {
2810
FontGlyph fgl;
2811
if (fd->msdf) {
2812
_ensure_glyph(fd, size, (int32_t)idx, fgl);
2813
} else {
2814
for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {
2815
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {
2816
_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);
2817
_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);
2818
_ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24), fgl);
2819
_ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24), fgl);
2820
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {
2821
_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);
2822
_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);
2823
} else {
2824
_ensure_glyph(fd, size, (int32_t)idx | (aa << 24), fgl);
2825
}
2826
}
2827
}
2828
}
2829
#endif
2830
}
2831
}
2832
2833
void TextServerFallback::_font_render_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_index) {
2834
FontFallback *fd = _get_font_data(p_font_rid);
2835
ERR_FAIL_NULL(fd);
2836
2837
MutexLock lock(fd->mutex);
2838
Vector2i size = _get_size_outline(fd, p_size);
2839
FontForSizeFallback *ffsd = nullptr;
2840
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
2841
#ifdef MODULE_FREETYPE_ENABLED
2842
int32_t idx = p_index & 0xffffff; // Remove subpixel shifts.
2843
if (fd->face) {
2844
FontGlyph fgl;
2845
if (fd->msdf) {
2846
_ensure_glyph(fd, size, (int32_t)idx, fgl);
2847
} else {
2848
for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {
2849
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {
2850
_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);
2851
_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);
2852
_ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24), fgl);
2853
_ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24), fgl);
2854
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {
2855
_ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24), fgl);
2856
_ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24), fgl);
2857
} else {
2858
_ensure_glyph(fd, size, (int32_t)idx | (aa << 24), fgl);
2859
}
2860
}
2861
}
2862
}
2863
#endif
2864
}
2865
2866
void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
2867
if (p_index == 0) {
2868
return; // Non visual character, skip.
2869
}
2870
FontFallback *fd = _get_font_data(p_font_rid);
2871
ERR_FAIL_NULL(fd);
2872
2873
MutexLock lock(fd->mutex);
2874
2875
// Oversampling.
2876
bool viewport_oversampling = false;
2877
float oversampling_factor = p_oversampling;
2878
if (p_oversampling <= 0.0) {
2879
if (fd->oversampling_override > 0.0) {
2880
oversampling_factor = fd->oversampling_override;
2881
} else if (vp_oversampling > 0.0) {
2882
oversampling_factor = vp_oversampling;
2883
viewport_oversampling = true;
2884
} else {
2885
oversampling_factor = 1.0;
2886
}
2887
}
2888
bool skip_oversampling = fd->msdf || fd->fixed_size > 0;
2889
if (skip_oversampling) {
2890
oversampling_factor = 1.0;
2891
} else {
2892
uint64_t oversampling_level = CLAMP(oversampling_factor, 0.1, 100.0) * 64;
2893
oversampling_factor = double(oversampling_level) / 64.0;
2894
}
2895
2896
Vector2i size;
2897
if (skip_oversampling) {
2898
size = _get_size(fd, p_size);
2899
} else {
2900
size = Vector2i(p_size * 64 * oversampling_factor, 0);
2901
}
2902
2903
FontForSizeFallback *ffsd = nullptr;
2904
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd, false, viewport_oversampling ? 64 * oversampling_factor : 0));
2905
2906
int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
2907
bool lcd_aa = false;
2908
2909
#ifdef MODULE_FREETYPE_ENABLED
2910
if (!fd->msdf && fd->face) {
2911
// LCD layout, bits 24, 25, 26
2912
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
2913
TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();
2914
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
2915
lcd_aa = true;
2916
index = index | (layout << 24);
2917
}
2918
}
2919
// Subpixel X-shift, bits 27, 28
2920
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {
2921
int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));
2922
index = index | (xshift << 27);
2923
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {
2924
int xshift = (int)(Math::floor(2 * (p_pos.x + 0.25)) - 2 * Math::floor(p_pos.x + 0.25));
2925
index = index | (xshift << 27);
2926
}
2927
}
2928
#endif
2929
2930
FontGlyph fgl;
2931
if (!_ensure_glyph(fd, size, index, fgl, viewport_oversampling ? 64 * oversampling_factor : 0)) {
2932
return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.
2933
}
2934
2935
if (fgl.found) {
2936
ERR_FAIL_COND(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size());
2937
2938
if (fgl.texture_idx != -1) {
2939
Color modulate = p_color;
2940
#ifdef MODULE_FREETYPE_ENABLED
2941
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) {
2942
modulate.r = modulate.g = modulate.b = 1.0;
2943
}
2944
#endif
2945
if (RenderingServer::get_singleton() != nullptr) {
2946
if (ffsd->textures[fgl.texture_idx].dirty) {
2947
ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];
2948
Ref<Image> img = tex.image;
2949
if (fgl.from_svg) {
2950
// Same as the "fix alpha border" process option when importing SVGs
2951
img->fix_alpha_edges();
2952
}
2953
if (fd->mipmaps && !img->has_mipmaps()) {
2954
img = tex.image->duplicate();
2955
img->generate_mipmaps();
2956
}
2957
if (tex.texture.is_null()) {
2958
tex.texture = ImageTexture::create_from_image(img);
2959
} else {
2960
tex.texture->update(img);
2961
}
2962
tex.dirty = false;
2963
}
2964
RID texture = ffsd->textures[fgl.texture_idx].texture->get_rid();
2965
if (fd->msdf) {
2966
Point2 cpos = p_pos;
2967
cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size;
2968
Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size;
2969
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);
2970
} else {
2971
Point2 cpos = p_pos;
2972
double scale = _font_get_scale(p_font_rid, p_size) / oversampling_factor;
2973
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
2974
cpos.x = cpos.x + 0.125;
2975
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
2976
cpos.x = cpos.x + 0.25;
2977
}
2978
if (scale == 1.0) {
2979
cpos.y = Math::floor(cpos.y);
2980
cpos.x = Math::floor(cpos.x);
2981
}
2982
Vector2 gpos = fgl.rect.position;
2983
Size2 csize = fgl.rect.size;
2984
if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE) {
2985
if (size.x != p_size * 64) {
2986
if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {
2987
double gl_scale = (double)p_size / (double)fd->fixed_size;
2988
gpos *= gl_scale;
2989
csize *= gl_scale;
2990
} else {
2991
double gl_scale = Math::round((double)p_size / (double)fd->fixed_size);
2992
gpos *= gl_scale;
2993
csize *= gl_scale;
2994
}
2995
}
2996
} else {
2997
gpos /= oversampling_factor;
2998
csize /= oversampling_factor;
2999
}
3000
cpos += gpos;
3001
if (lcd_aa) {
3002
RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate);
3003
} else {
3004
RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false);
3005
}
3006
}
3007
}
3008
}
3009
}
3010
}
3011
3012
void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color, float p_oversampling) const {
3013
if (p_index == 0) {
3014
return; // Non visual character, skip.
3015
}
3016
FontFallback *fd = _get_font_data(p_font_rid);
3017
ERR_FAIL_NULL(fd);
3018
3019
MutexLock lock(fd->mutex);
3020
3021
// Oversampling.
3022
bool viewport_oversampling = false;
3023
float oversampling_factor = p_oversampling;
3024
if (p_oversampling <= 0.0) {
3025
if (fd->oversampling_override > 0.0) {
3026
oversampling_factor = fd->oversampling_override;
3027
} else if (vp_oversampling > 0.0) {
3028
oversampling_factor = vp_oversampling;
3029
viewport_oversampling = true;
3030
} else {
3031
oversampling_factor = 1.0;
3032
}
3033
}
3034
bool skip_oversampling = fd->msdf || fd->fixed_size > 0;
3035
if (skip_oversampling) {
3036
oversampling_factor = 1.0;
3037
} else {
3038
uint64_t oversampling_level = CLAMP(oversampling_factor, 0.1, 100.0) * 64;
3039
oversampling_factor = double(oversampling_level) / 64.0;
3040
}
3041
3042
Vector2i size;
3043
if (skip_oversampling) {
3044
size = _get_size_outline(fd, Vector2i(p_size, p_outline_size));
3045
} else {
3046
size = Vector2i(p_size * 64 * oversampling_factor, p_outline_size * oversampling_factor);
3047
}
3048
3049
FontForSizeFallback *ffsd = nullptr;
3050
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd, false, viewport_oversampling ? 64 * oversampling_factor : 0));
3051
3052
int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
3053
bool lcd_aa = false;
3054
3055
#ifdef MODULE_FREETYPE_ENABLED
3056
if (!fd->msdf && fd->face) {
3057
// LCD layout, bits 24, 25, 26
3058
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
3059
TextServer::FontLCDSubpixelLayout layout = lcd_subpixel_layout.get();
3060
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
3061
lcd_aa = true;
3062
index = index | (layout << 24);
3063
}
3064
}
3065
// Subpixel X-shift, bits 27, 28
3066
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64)) {
3067
int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));
3068
index = index | (xshift << 27);
3069
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64)) {
3070
int xshift = (int)(Math::floor(2 * (p_pos.x + 0.25)) - 2 * Math::floor(p_pos.x + 0.25));
3071
index = index | (xshift << 27);
3072
}
3073
}
3074
#endif
3075
3076
FontGlyph fgl;
3077
if (!_ensure_glyph(fd, size, index, fgl, viewport_oversampling ? 64 * oversampling_factor : 0)) {
3078
return; // Invalid or non-graphical glyph, do not display errors, nothing to draw.
3079
}
3080
3081
if (fgl.found) {
3082
ERR_FAIL_COND(fgl.texture_idx < -1 || fgl.texture_idx >= ffsd->textures.size());
3083
3084
if (fgl.texture_idx != -1) {
3085
Color modulate = p_color;
3086
#ifdef MODULE_FREETYPE_ENABLED
3087
if (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) {
3088
modulate.r = modulate.g = modulate.b = 1.0;
3089
}
3090
#endif
3091
if (RenderingServer::get_singleton() != nullptr) {
3092
if (ffsd->textures[fgl.texture_idx].dirty) {
3093
ShelfPackTexture &tex = ffsd->textures.write[fgl.texture_idx];
3094
Ref<Image> img = tex.image;
3095
if (fd->mipmaps && !img->has_mipmaps()) {
3096
img = tex.image->duplicate();
3097
img->generate_mipmaps();
3098
}
3099
if (tex.texture.is_null()) {
3100
tex.texture = ImageTexture::create_from_image(img);
3101
} else {
3102
tex.texture->update(img);
3103
}
3104
tex.dirty = false;
3105
}
3106
RID texture = ffsd->textures[fgl.texture_idx].texture->get_rid();
3107
if (fd->msdf) {
3108
Point2 cpos = p_pos;
3109
cpos += fgl.rect.position * (double)p_size / (double)fd->msdf_source_size;
3110
Size2 csize = fgl.rect.size * (double)p_size / (double)fd->msdf_source_size;
3111
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);
3112
} else {
3113
Point2 cpos = p_pos;
3114
double scale = _font_get_scale(p_font_rid, p_size) / oversampling_factor;
3115
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
3116
cpos.x = cpos.x + 0.125;
3117
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
3118
cpos.x = cpos.x + 0.25;
3119
}
3120
if (scale == 1.0) {
3121
cpos.y = Math::floor(cpos.y);
3122
cpos.x = Math::floor(cpos.x);
3123
}
3124
Vector2 gpos = fgl.rect.position;
3125
Size2 csize = fgl.rect.size;
3126
if (fd->fixed_size > 0 && fd->fixed_size_scale_mode != FIXED_SIZE_SCALE_DISABLE) {
3127
if (size.x != p_size * 64) {
3128
if (fd->fixed_size_scale_mode == FIXED_SIZE_SCALE_ENABLED) {
3129
double gl_scale = (double)p_size / (double)fd->fixed_size;
3130
gpos *= gl_scale;
3131
csize *= gl_scale;
3132
} else {
3133
double gl_scale = Math::round((double)p_size / (double)fd->fixed_size);
3134
gpos *= gl_scale;
3135
csize *= gl_scale;
3136
}
3137
}
3138
} else {
3139
gpos /= oversampling_factor;
3140
csize /= oversampling_factor;
3141
}
3142
cpos += gpos;
3143
if (lcd_aa) {
3144
RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate);
3145
} else {
3146
RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, fgl.uv_rect, modulate, false, false);
3147
}
3148
}
3149
}
3150
}
3151
}
3152
}
3153
3154
bool TextServerFallback::_font_is_language_supported(const RID &p_font_rid, const String &p_language) const {
3155
FontFallback *fd = _get_font_data(p_font_rid);
3156
ERR_FAIL_NULL_V(fd, false);
3157
3158
MutexLock lock(fd->mutex);
3159
if (fd->language_support_overrides.has(p_language)) {
3160
return fd->language_support_overrides[p_language];
3161
} else {
3162
if (fd->language_support_overrides.has("*")) {
3163
return fd->language_support_overrides["*"];
3164
}
3165
return true;
3166
}
3167
}
3168
3169
void TextServerFallback::_font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) {
3170
FontFallback *fd = _get_font_data(p_font_rid);
3171
ERR_FAIL_NULL(fd);
3172
3173
MutexLock lock(fd->mutex);
3174
fd->language_support_overrides[p_language] = p_supported;
3175
}
3176
3177
bool TextServerFallback::_font_get_language_support_override(const RID &p_font_rid, const String &p_language) {
3178
FontFallback *fd = _get_font_data(p_font_rid);
3179
ERR_FAIL_NULL_V(fd, false);
3180
3181
MutexLock lock(fd->mutex);
3182
return fd->language_support_overrides[p_language];
3183
}
3184
3185
void TextServerFallback::_font_remove_language_support_override(const RID &p_font_rid, const String &p_language) {
3186
FontFallback *fd = _get_font_data(p_font_rid);
3187
ERR_FAIL_NULL(fd);
3188
3189
MutexLock lock(fd->mutex);
3190
fd->language_support_overrides.erase(p_language);
3191
}
3192
3193
PackedStringArray TextServerFallback::_font_get_language_support_overrides(const RID &p_font_rid) {
3194
FontFallback *fd = _get_font_data(p_font_rid);
3195
ERR_FAIL_NULL_V(fd, PackedStringArray());
3196
3197
MutexLock lock(fd->mutex);
3198
PackedStringArray out;
3199
for (const KeyValue<String, bool> &E : fd->language_support_overrides) {
3200
out.push_back(E.key);
3201
}
3202
return out;
3203
}
3204
3205
bool TextServerFallback::_font_is_script_supported(const RID &p_font_rid, const String &p_script) const {
3206
FontFallback *fd = _get_font_data(p_font_rid);
3207
ERR_FAIL_NULL_V(fd, false);
3208
3209
MutexLock lock(fd->mutex);
3210
if (fd->script_support_overrides.has(p_script)) {
3211
return fd->script_support_overrides[p_script];
3212
} else {
3213
if (fd->script_support_overrides.has("*")) {
3214
return fd->script_support_overrides["*"];
3215
}
3216
return true;
3217
}
3218
}
3219
3220
void TextServerFallback::_font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) {
3221
FontFallback *fd = _get_font_data(p_font_rid);
3222
ERR_FAIL_NULL(fd);
3223
3224
MutexLock lock(fd->mutex);
3225
fd->script_support_overrides[p_script] = p_supported;
3226
}
3227
3228
bool TextServerFallback::_font_get_script_support_override(const RID &p_font_rid, const String &p_script) {
3229
FontFallback *fd = _get_font_data(p_font_rid);
3230
ERR_FAIL_NULL_V(fd, false);
3231
3232
MutexLock lock(fd->mutex);
3233
return fd->script_support_overrides[p_script];
3234
}
3235
3236
void TextServerFallback::_font_remove_script_support_override(const RID &p_font_rid, const String &p_script) {
3237
FontFallback *fd = _get_font_data(p_font_rid);
3238
ERR_FAIL_NULL(fd);
3239
3240
MutexLock lock(fd->mutex);
3241
Vector2i size = _get_size(fd, 16);
3242
FontForSizeFallback *ffsd = nullptr;
3243
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
3244
fd->script_support_overrides.erase(p_script);
3245
}
3246
3247
PackedStringArray TextServerFallback::_font_get_script_support_overrides(const RID &p_font_rid) {
3248
FontFallback *fd = _get_font_data(p_font_rid);
3249
ERR_FAIL_NULL_V(fd, PackedStringArray());
3250
3251
MutexLock lock(fd->mutex);
3252
PackedStringArray out;
3253
for (const KeyValue<String, bool> &E : fd->script_support_overrides) {
3254
out.push_back(E.key);
3255
}
3256
return out;
3257
}
3258
3259
void TextServerFallback::_font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) {
3260
FontFallback *fd = _get_font_data(p_font_rid);
3261
ERR_FAIL_NULL(fd);
3262
3263
MutexLock lock(fd->mutex);
3264
Vector2i size = _get_size(fd, 16);
3265
FontForSizeFallback *ffsd = nullptr;
3266
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size, ffsd));
3267
fd->feature_overrides = p_overrides;
3268
}
3269
3270
Dictionary TextServerFallback::_font_get_opentype_feature_overrides(const RID &p_font_rid) const {
3271
FontFallback *fd = _get_font_data(p_font_rid);
3272
ERR_FAIL_NULL_V(fd, Dictionary());
3273
3274
MutexLock lock(fd->mutex);
3275
return fd->feature_overrides;
3276
}
3277
3278
Dictionary TextServerFallback::_font_supported_feature_list(const RID &p_font_rid) const {
3279
return Dictionary();
3280
}
3281
3282
Dictionary TextServerFallback::_font_supported_variation_list(const RID &p_font_rid) const {
3283
FontFallback *fd = _get_font_data(p_font_rid);
3284
ERR_FAIL_NULL_V(fd, Dictionary());
3285
3286
MutexLock lock(fd->mutex);
3287
Vector2i size = _get_size(fd, 16);
3288
FontForSizeFallback *ffsd = nullptr;
3289
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size, ffsd), Dictionary());
3290
return fd->supported_varaitions;
3291
}
3292
3293
/*************************************************************************/
3294
/* Shaped text buffer interface */
3295
/*************************************************************************/
3296
3297
void TextServerFallback::invalidate(ShapedTextDataFallback *p_shaped) {
3298
p_shaped->valid.clear();
3299
p_shaped->sort_valid = false;
3300
p_shaped->line_breaks_valid = false;
3301
p_shaped->justification_ops_valid = false;
3302
p_shaped->ascent = 0.0;
3303
p_shaped->descent = 0.0;
3304
p_shaped->width = 0.0;
3305
p_shaped->upos = 0.0;
3306
p_shaped->uthk = 0.0;
3307
p_shaped->glyphs.clear();
3308
p_shaped->glyphs_logical.clear();
3309
p_shaped->runs.clear();
3310
p_shaped->runs_dirty = true;
3311
}
3312
3313
void TextServerFallback::full_copy(ShapedTextDataFallback *p_shaped) {
3314
ShapedTextDataFallback *parent = shaped_owner.get_or_null(p_shaped->parent);
3315
3316
for (const KeyValue<Variant, ShapedTextDataFallback::EmbeddedObject> &E : parent->objects) {
3317
if (E.value.start >= p_shaped->start && E.value.start < p_shaped->end) {
3318
p_shaped->objects[E.key] = E.value;
3319
}
3320
}
3321
3322
for (int i = MAX(0, p_shaped->first_span); i <= MIN(p_shaped->last_span, parent->spans.size() - 1); i++) {
3323
ShapedTextDataFallback::Span span = parent->spans[i];
3324
span.start = MAX(p_shaped->start, span.start);
3325
span.end = MIN(p_shaped->end, span.end);
3326
p_shaped->spans.push_back(span);
3327
}
3328
p_shaped->first_span = 0;
3329
p_shaped->last_span = 0;
3330
3331
p_shaped->parent = RID();
3332
}
3333
3334
RID TextServerFallback::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
3335
_THREAD_SAFE_METHOD_
3336
ERR_FAIL_COND_V_MSG(p_direction == DIRECTION_INHERITED, RID(), "Invalid text direction.");
3337
3338
ShapedTextDataFallback *sd = memnew(ShapedTextDataFallback);
3339
sd->direction = p_direction;
3340
sd->orientation = p_orientation;
3341
3342
return shaped_owner.make_rid(sd);
3343
}
3344
3345
void TextServerFallback::_shaped_text_clear(const RID &p_shaped) {
3346
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3347
ERR_FAIL_NULL(sd);
3348
3349
MutexLock lock(sd->mutex);
3350
sd->parent = RID();
3351
sd->start = 0;
3352
sd->end = 0;
3353
sd->text = String();
3354
sd->spans.clear();
3355
sd->first_span = 0;
3356
sd->last_span = 0;
3357
sd->objects.clear();
3358
invalidate(sd);
3359
}
3360
3361
RID TextServerFallback::_shaped_text_duplicate(const RID &p_shaped) {
3362
_THREAD_SAFE_METHOD_
3363
3364
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3365
ERR_FAIL_NULL_V(sd, RID());
3366
3367
MutexLock lock(sd->mutex);
3368
3369
ShapedTextDataFallback *new_sd = memnew(ShapedTextDataFallback);
3370
new_sd->parent = p_shaped;
3371
new_sd->start = sd->start;
3372
new_sd->end = sd->end;
3373
new_sd->first_span = sd->first_span;
3374
new_sd->last_span = sd->last_span;
3375
new_sd->text = sd->text;
3376
new_sd->orientation = sd->orientation;
3377
new_sd->direction = sd->direction;
3378
new_sd->custom_punct = sd->custom_punct;
3379
new_sd->para_direction = sd->para_direction;
3380
new_sd->line_breaks_valid = sd->line_breaks_valid;
3381
new_sd->justification_ops_valid = sd->justification_ops_valid;
3382
new_sd->sort_valid = false;
3383
new_sd->upos = sd->upos;
3384
new_sd->uthk = sd->uthk;
3385
new_sd->runs.clear();
3386
new_sd->runs_dirty = true;
3387
for (int i = 0; i < TextServer::SPACING_MAX; i++) {
3388
new_sd->extra_spacing[i] = sd->extra_spacing[i];
3389
}
3390
for (const KeyValue<Variant, ShapedTextDataFallback::EmbeddedObject> &E : sd->objects) {
3391
new_sd->objects[E.key] = E.value;
3392
}
3393
for (int i = 0; i < sd->spans.size(); i++) {
3394
new_sd->spans.push_back(sd->spans[i]);
3395
}
3396
new_sd->valid.clear();
3397
3398
return shaped_owner.make_rid(new_sd);
3399
}
3400
3401
void TextServerFallback::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {
3402
ERR_FAIL_COND_MSG(p_direction == DIRECTION_INHERITED, "Invalid text direction.");
3403
if (p_direction == DIRECTION_RTL) {
3404
ERR_PRINT_ONCE("Right-to-left layout is not supported by this text server.");
3405
}
3406
}
3407
3408
TextServer::Direction TextServerFallback::_shaped_text_get_direction(const RID &p_shaped) const {
3409
return TextServer::DIRECTION_LTR;
3410
}
3411
3412
TextServer::Direction TextServerFallback::_shaped_text_get_inferred_direction(const RID &p_shaped) const {
3413
return TextServer::DIRECTION_LTR;
3414
}
3415
3416
void TextServerFallback::_shaped_text_set_custom_punctuation(const RID &p_shaped, const String &p_punct) {
3417
_THREAD_SAFE_METHOD_
3418
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3419
ERR_FAIL_NULL(sd);
3420
3421
if (sd->custom_punct != p_punct) {
3422
if (sd->parent != RID()) {
3423
full_copy(sd);
3424
}
3425
sd->custom_punct = p_punct;
3426
invalidate(sd);
3427
}
3428
}
3429
3430
String TextServerFallback::_shaped_text_get_custom_punctuation(const RID &p_shaped) const {
3431
_THREAD_SAFE_METHOD_
3432
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3433
ERR_FAIL_NULL_V(sd, String());
3434
return sd->custom_punct;
3435
}
3436
3437
void TextServerFallback::_shaped_text_set_custom_ellipsis(const RID &p_shaped, int64_t p_char) {
3438
_THREAD_SAFE_METHOD_
3439
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3440
ERR_FAIL_NULL(sd);
3441
sd->el_char = p_char;
3442
}
3443
3444
int64_t TextServerFallback::_shaped_text_get_custom_ellipsis(const RID &p_shaped) const {
3445
_THREAD_SAFE_METHOD_
3446
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3447
ERR_FAIL_NULL_V(sd, 0);
3448
return sd->el_char;
3449
}
3450
3451
void TextServerFallback::_shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) {
3452
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3453
ERR_FAIL_NULL(sd);
3454
3455
MutexLock lock(sd->mutex);
3456
if (sd->orientation != p_orientation) {
3457
if (sd->parent != RID()) {
3458
full_copy(sd);
3459
}
3460
sd->orientation = p_orientation;
3461
invalidate(sd);
3462
}
3463
}
3464
3465
void TextServerFallback::_shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) {
3466
// No BiDi support, ignore.
3467
}
3468
3469
TextServer::Orientation TextServerFallback::_shaped_text_get_orientation(const RID &p_shaped) const {
3470
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3471
ERR_FAIL_NULL_V(sd, TextServer::ORIENTATION_HORIZONTAL);
3472
3473
MutexLock lock(sd->mutex);
3474
return sd->orientation;
3475
}
3476
3477
void TextServerFallback::_shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) {
3478
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3479
3480
MutexLock lock(sd->mutex);
3481
ERR_FAIL_NULL(sd);
3482
if (sd->preserve_invalid != p_enabled) {
3483
if (sd->parent != RID()) {
3484
full_copy(sd);
3485
}
3486
sd->preserve_invalid = p_enabled;
3487
invalidate(sd);
3488
}
3489
}
3490
3491
bool TextServerFallback::_shaped_text_get_preserve_invalid(const RID &p_shaped) const {
3492
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3493
ERR_FAIL_NULL_V(sd, false);
3494
3495
MutexLock lock(sd->mutex);
3496
return sd->preserve_invalid;
3497
}
3498
3499
void TextServerFallback::_shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) {
3500
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3501
ERR_FAIL_NULL(sd);
3502
3503
MutexLock lock(sd->mutex);
3504
if (sd->preserve_control != p_enabled) {
3505
if (sd->parent != RID()) {
3506
full_copy(sd);
3507
}
3508
sd->preserve_control = p_enabled;
3509
invalidate(sd);
3510
}
3511
}
3512
3513
bool TextServerFallback::_shaped_text_get_preserve_control(const RID &p_shaped) const {
3514
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3515
ERR_FAIL_NULL_V(sd, false);
3516
3517
MutexLock lock(sd->mutex);
3518
return sd->preserve_control;
3519
}
3520
3521
void TextServerFallback::_shaped_text_set_spacing(const RID &p_shaped, SpacingType p_spacing, int64_t p_value) {
3522
ERR_FAIL_INDEX((int)p_spacing, 4);
3523
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3524
ERR_FAIL_NULL(sd);
3525
3526
MutexLock lock(sd->mutex);
3527
if (sd->extra_spacing[p_spacing] != p_value) {
3528
if (sd->parent != RID()) {
3529
full_copy(sd);
3530
}
3531
sd->extra_spacing[p_spacing] = p_value;
3532
invalidate(sd);
3533
}
3534
}
3535
3536
int64_t TextServerFallback::_shaped_text_get_spacing(const RID &p_shaped, SpacingType p_spacing) const {
3537
ERR_FAIL_INDEX_V((int)p_spacing, 4, 0);
3538
3539
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3540
ERR_FAIL_NULL_V(sd, 0);
3541
3542
MutexLock lock(sd->mutex);
3543
return sd->extra_spacing[p_spacing];
3544
}
3545
3546
int64_t TextServerFallback::_shaped_get_span_count(const RID &p_shaped) const {
3547
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3548
ERR_FAIL_NULL_V(sd, 0);
3549
3550
if (sd->parent != RID()) {
3551
return sd->last_span - sd->first_span + 1;
3552
} else {
3553
return sd->spans.size();
3554
}
3555
}
3556
3557
Variant TextServerFallback::_shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const {
3558
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3559
ERR_FAIL_NULL_V(sd, Variant());
3560
if (sd->parent != RID()) {
3561
ShapedTextDataFallback *parent_sd = shaped_owner.get_or_null(sd->parent);
3562
ERR_FAIL_COND_V(!parent_sd->valid.is_set(), Variant());
3563
ERR_FAIL_INDEX_V(p_index + sd->first_span, parent_sd->spans.size(), Variant());
3564
return parent_sd->spans[p_index + sd->first_span].meta;
3565
} else {
3566
ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant());
3567
return sd->spans[p_index].meta;
3568
}
3569
}
3570
3571
Variant TextServerFallback::_shaped_get_span_embedded_object(const RID &p_shaped, int64_t p_index) const {
3572
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3573
ERR_FAIL_NULL_V(sd, Variant());
3574
if (sd->parent != RID()) {
3575
ShapedTextDataFallback *parent_sd = shaped_owner.get_or_null(sd->parent);
3576
ERR_FAIL_COND_V(!parent_sd->valid.is_set(), Variant());
3577
ERR_FAIL_INDEX_V(p_index + sd->first_span, parent_sd->spans.size(), Variant());
3578
return parent_sd->spans[p_index + sd->first_span].embedded_key;
3579
} else {
3580
ERR_FAIL_INDEX_V(p_index, sd->spans.size(), Variant());
3581
return sd->spans[p_index].embedded_key;
3582
}
3583
}
3584
3585
String TextServerFallback::_shaped_get_span_text(const RID &p_shaped, int64_t p_index) const {
3586
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3587
ERR_FAIL_NULL_V(sd, String());
3588
ShapedTextDataFallback *span_sd = sd;
3589
if (sd->parent.is_valid()) {
3590
span_sd = shaped_owner.get_or_null(sd->parent);
3591
ERR_FAIL_NULL_V(span_sd, String());
3592
}
3593
ERR_FAIL_INDEX_V(p_index, span_sd->spans.size(), String());
3594
return span_sd->text.substr(span_sd->spans[p_index].start, span_sd->spans[p_index].end - span_sd->spans[p_index].start);
3595
}
3596
3597
Variant TextServerFallback::_shaped_get_span_object(const RID &p_shaped, int64_t p_index) const {
3598
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3599
ERR_FAIL_NULL_V(sd, Variant());
3600
ShapedTextDataFallback *span_sd = sd;
3601
if (sd->parent.is_valid()) {
3602
span_sd = shaped_owner.get_or_null(sd->parent);
3603
ERR_FAIL_NULL_V(span_sd, Variant());
3604
}
3605
ERR_FAIL_INDEX_V(p_index, span_sd->spans.size(), Variant());
3606
return span_sd->spans[p_index].embedded_key;
3607
}
3608
3609
void TextServerFallback::_generate_runs(ShapedTextDataFallback *p_sd) const {
3610
ERR_FAIL_NULL(p_sd);
3611
p_sd->runs.clear();
3612
3613
ShapedTextDataFallback *span_sd = p_sd;
3614
if (p_sd->parent.is_valid()) {
3615
span_sd = shaped_owner.get_or_null(p_sd->parent);
3616
ERR_FAIL_NULL(span_sd);
3617
}
3618
3619
int sd_size = p_sd->glyphs.size();
3620
Glyph *sd_gl = p_sd->glyphs.ptrw();
3621
3622
int span_count = span_sd->spans.size();
3623
int span = -1;
3624
int span_start = -1;
3625
int span_end = -1;
3626
3627
TextRun run;
3628
for (int i = 0; i < sd_size; i += sd_gl[i].count) {
3629
const Glyph &gl = sd_gl[i];
3630
if (gl.start < 0 || gl.end < 0) {
3631
continue;
3632
}
3633
if (gl.start < span_start || gl.start >= span_end) {
3634
span = -1;
3635
span_start = -1;
3636
span_end = -1;
3637
for (int j = 0; j < span_count; j++) {
3638
if (gl.start >= span_sd->spans[j].start && gl.end <= span_sd->spans[j].end) {
3639
span = j;
3640
span_start = span_sd->spans[j].start;
3641
span_end = span_sd->spans[j].end;
3642
break;
3643
}
3644
}
3645
}
3646
if (run.font_rid != gl.font_rid || run.font_size != gl.font_size || run.span_index != span) {
3647
if (run.span_index >= 0) {
3648
p_sd->runs.push_back(run);
3649
}
3650
run.range = Vector2i(gl.start, gl.end);
3651
run.font_rid = gl.font_rid;
3652
run.font_size = gl.font_size;
3653
run.span_index = span;
3654
}
3655
run.range.x = MIN(run.range.x, gl.start);
3656
run.range.y = MAX(run.range.y, gl.end);
3657
}
3658
if (run.span_index >= 0) {
3659
p_sd->runs.push_back(run);
3660
}
3661
p_sd->runs_dirty = false;
3662
}
3663
3664
int64_t TextServerFallback::_shaped_get_run_count(const RID &p_shaped) const {
3665
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3666
ERR_FAIL_NULL_V(sd, 0);
3667
MutexLock lock(sd->mutex);
3668
if (!sd->valid.is_set()) {
3669
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
3670
}
3671
if (sd->runs_dirty) {
3672
_generate_runs(sd);
3673
}
3674
return sd->runs.size();
3675
}
3676
3677
String TextServerFallback::_shaped_get_run_text(const RID &p_shaped, int64_t p_index) const {
3678
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3679
ERR_FAIL_NULL_V(sd, String());
3680
MutexLock lock(sd->mutex);
3681
if (!sd->valid.is_set()) {
3682
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
3683
}
3684
if (sd->runs_dirty) {
3685
_generate_runs(sd);
3686
}
3687
ERR_FAIL_INDEX_V(p_index, sd->runs.size(), String());
3688
return sd->text.substr(sd->runs[p_index].range.x - sd->start, sd->runs[p_index].range.y - sd->runs[p_index].range.x);
3689
}
3690
3691
Vector2i TextServerFallback::_shaped_get_run_range(const RID &p_shaped, int64_t p_index) const {
3692
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3693
ERR_FAIL_NULL_V(sd, Vector2i());
3694
MutexLock lock(sd->mutex);
3695
if (!sd->valid.is_set()) {
3696
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
3697
}
3698
if (sd->runs_dirty) {
3699
_generate_runs(sd);
3700
}
3701
ERR_FAIL_INDEX_V(p_index, sd->runs.size(), Vector2i());
3702
return sd->runs[p_index].range;
3703
}
3704
3705
RID TextServerFallback::_shaped_get_run_font_rid(const RID &p_shaped, int64_t p_index) const {
3706
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3707
ERR_FAIL_NULL_V(sd, RID());
3708
MutexLock lock(sd->mutex);
3709
if (!sd->valid.is_set()) {
3710
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
3711
}
3712
if (sd->runs_dirty) {
3713
_generate_runs(sd);
3714
}
3715
ERR_FAIL_INDEX_V(p_index, sd->runs.size(), RID());
3716
return sd->runs[p_index].font_rid;
3717
}
3718
3719
int TextServerFallback::_shaped_get_run_font_size(const RID &p_shaped, int64_t p_index) const {
3720
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3721
ERR_FAIL_NULL_V(sd, 0);
3722
MutexLock lock(sd->mutex);
3723
if (!sd->valid.is_set()) {
3724
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
3725
}
3726
if (sd->runs_dirty) {
3727
_generate_runs(sd);
3728
}
3729
ERR_FAIL_INDEX_V(p_index, sd->runs.size(), 0);
3730
return sd->runs[p_index].font_size;
3731
}
3732
3733
String TextServerFallback::_shaped_get_run_language(const RID &p_shaped, int64_t p_index) const {
3734
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3735
ERR_FAIL_NULL_V(sd, String());
3736
MutexLock lock(sd->mutex);
3737
if (!sd->valid.is_set()) {
3738
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
3739
}
3740
if (sd->runs_dirty) {
3741
_generate_runs(sd);
3742
}
3743
ERR_FAIL_INDEX_V(p_index, sd->runs.size(), String());
3744
3745
int span_idx = sd->runs[p_index].span_index;
3746
ShapedTextDataFallback *span_sd = sd;
3747
if (sd->parent.is_valid()) {
3748
span_sd = shaped_owner.get_or_null(sd->parent);
3749
ERR_FAIL_NULL_V(span_sd, String());
3750
}
3751
ERR_FAIL_INDEX_V(span_idx, span_sd->spans.size(), String());
3752
return span_sd->spans[span_idx].language;
3753
}
3754
3755
TextServer::Direction TextServerFallback::_shaped_get_run_direction(const RID &p_shaped, int64_t p_index) const {
3756
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3757
ERR_FAIL_NULL_V(sd, TextServer::DIRECTION_LTR);
3758
MutexLock lock(sd->mutex);
3759
if (!sd->valid.is_set()) {
3760
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
3761
}
3762
if (sd->runs_dirty) {
3763
_generate_runs(sd);
3764
}
3765
ERR_FAIL_INDEX_V(p_index, sd->runs.size(), TextServer::DIRECTION_LTR);
3766
return TextServer::DIRECTION_LTR;
3767
}
3768
3769
Variant TextServerFallback::_shaped_get_run_object(const RID &p_shaped, int64_t p_index) const {
3770
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3771
ERR_FAIL_NULL_V(sd, Variant());
3772
MutexLock lock(sd->mutex);
3773
if (!sd->valid.is_set()) {
3774
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
3775
}
3776
if (sd->runs_dirty) {
3777
_generate_runs(sd);
3778
}
3779
ERR_FAIL_INDEX_V(p_index, sd->runs.size(), Variant());
3780
3781
int span_idx = sd->runs[p_index].span_index;
3782
ShapedTextDataFallback *span_sd = sd;
3783
if (sd->parent.is_valid()) {
3784
span_sd = shaped_owner.get_or_null(sd->parent);
3785
ERR_FAIL_NULL_V(span_sd, Variant());
3786
}
3787
ERR_FAIL_INDEX_V(span_idx, span_sd->spans.size(), Variant());
3788
return span_sd->spans[span_idx].embedded_key;
3789
}
3790
3791
void TextServerFallback::_shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) {
3792
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3793
ERR_FAIL_NULL(sd);
3794
if (sd->parent != RID()) {
3795
full_copy(sd);
3796
}
3797
ERR_FAIL_INDEX(p_index, sd->spans.size());
3798
3799
ShapedTextDataFallback::Span &span = sd->spans.ptrw()[p_index];
3800
span.fonts.clear();
3801
// Pre-sort fonts, push fonts with the language support first.
3802
Array fonts_no_match;
3803
int font_count = p_fonts.size();
3804
for (int i = 0; i < font_count; i++) {
3805
if (_font_is_language_supported(p_fonts[i], span.language)) {
3806
span.fonts.push_back(p_fonts[i]);
3807
} else {
3808
fonts_no_match.push_back(p_fonts[i]);
3809
}
3810
}
3811
span.fonts.append_array(fonts_no_match);
3812
span.font_size = p_size;
3813
span.features = p_opentype_features;
3814
3815
sd->valid.clear();
3816
}
3817
3818
bool TextServerFallback::_shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
3819
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3820
ERR_FAIL_NULL_V(sd, false);
3821
3822
MutexLock lock(sd->mutex);
3823
ERR_FAIL_COND_V(p_size <= 0, false);
3824
3825
for (int i = 0; i < p_fonts.size(); i++) {
3826
ERR_FAIL_NULL_V(_get_font_data(p_fonts[i]), false);
3827
}
3828
3829
if (p_text.is_empty()) {
3830
return true;
3831
}
3832
3833
if (sd->parent != RID()) {
3834
full_copy(sd);
3835
}
3836
3837
ShapedTextDataFallback::Span span;
3838
span.start = sd->text.length();
3839
span.end = span.start + p_text.length();
3840
3841
// Pre-sort fonts, push fonts with the language support first.
3842
Array fonts_no_match;
3843
int font_count = p_fonts.size();
3844
if (font_count > 0) {
3845
span.fonts.push_back(p_fonts[0]);
3846
}
3847
for (int i = 1; i < font_count; i++) {
3848
if (_font_is_language_supported(p_fonts[i], p_language)) {
3849
span.fonts.push_back(p_fonts[i]);
3850
} else {
3851
fonts_no_match.push_back(p_fonts[i]);
3852
}
3853
}
3854
span.fonts.append_array(fonts_no_match);
3855
3856
ERR_FAIL_COND_V(span.fonts.is_empty(), false);
3857
span.font_size = p_size;
3858
span.language = p_language;
3859
span.meta = p_meta;
3860
3861
sd->spans.push_back(span);
3862
sd->text = sd->text + p_text;
3863
sd->end += p_text.length();
3864
invalidate(sd);
3865
3866
return true;
3867
}
3868
3869
bool TextServerFallback::_shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length, double p_baseline) {
3870
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3871
ERR_FAIL_NULL_V(sd, false);
3872
3873
MutexLock lock(sd->mutex);
3874
ERR_FAIL_COND_V(p_key == Variant(), false);
3875
ERR_FAIL_COND_V(sd->objects.has(p_key), false);
3876
3877
if (sd->parent != RID()) {
3878
full_copy(sd);
3879
}
3880
3881
ShapedTextDataFallback::Span span;
3882
span.start = sd->start + sd->text.length();
3883
span.end = span.start + p_length;
3884
span.embedded_key = p_key;
3885
3886
ShapedTextDataFallback::EmbeddedObject obj;
3887
obj.inline_align = p_inline_align;
3888
obj.rect.size = p_size;
3889
obj.start = span.start;
3890
obj.end = span.end;
3891
obj.baseline = p_baseline;
3892
3893
sd->spans.push_back(span);
3894
sd->text = sd->text + String::chr(0xfffc).repeat(p_length);
3895
sd->end += p_length;
3896
sd->objects[p_key] = obj;
3897
invalidate(sd);
3898
3899
return true;
3900
}
3901
3902
String TextServerFallback::_shaped_get_text(const RID &p_shaped) const {
3903
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3904
ERR_FAIL_NULL_V(sd, String());
3905
3906
return sd->text;
3907
}
3908
3909
bool TextServerFallback::_shaped_text_has_object(const RID &p_shaped, const Variant &p_key) const {
3910
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3911
ERR_FAIL_NULL_V(sd, false);
3912
3913
MutexLock lock(sd->mutex);
3914
return sd->objects.has(p_key);
3915
}
3916
3917
bool TextServerFallback::_shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, double p_baseline) {
3918
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
3919
ERR_FAIL_NULL_V(sd, false);
3920
3921
MutexLock lock(sd->mutex);
3922
ERR_FAIL_COND_V(!sd->objects.has(p_key), false);
3923
sd->objects[p_key].rect.size = p_size;
3924
sd->objects[p_key].inline_align = p_inline_align;
3925
sd->objects[p_key].baseline = p_baseline;
3926
if (sd->valid.is_set()) {
3927
// Recalc string metrics.
3928
sd->ascent = 0;
3929
sd->descent = 0;
3930
sd->width = 0;
3931
sd->upos = 0;
3932
sd->uthk = 0;
3933
3934
Vector<ShapedTextDataFallback::Span> &spans = sd->spans;
3935
if (sd->parent != RID()) {
3936
ShapedTextDataFallback *parent_sd = shaped_owner.get_or_null(sd->parent);
3937
ERR_FAIL_COND_V(!parent_sd->valid.is_set(), false);
3938
spans = parent_sd->spans;
3939
}
3940
3941
int sd_size = sd->glyphs.size();
3942
int span_size = spans.size();
3943
3944
for (int i = 0; i < sd_size; i++) {
3945
Glyph gl = sd->glyphs[i];
3946
Variant key;
3947
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) {
3948
key = spans[gl.span_index + sd->first_span].embedded_key;
3949
}
3950
if (key != Variant()) {
3951
if (sd->orientation == ORIENTATION_HORIZONTAL) {
3952
sd->objects[key].rect.position.x = sd->width;
3953
sd->width += sd->objects[key].rect.size.x;
3954
sd->glyphs.write[i].advance = sd->objects[key].rect.size.x;
3955
} else {
3956
sd->objects[key].rect.position.y = sd->width;
3957
sd->width += sd->objects[key].rect.size.y;
3958
sd->glyphs.write[i].advance = sd->objects[key].rect.size.y;
3959
}
3960
} else {
3961
if (gl.font_rid.is_valid()) {
3962
if (sd->orientation == ORIENTATION_HORIZONTAL) {
3963
sd->ascent = MAX(sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_TOP));
3964
sd->descent = MAX(sd->descent, _font_get_descent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_BOTTOM));
3965
} else {
3966
sd->ascent = MAX(sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
3967
sd->descent = MAX(sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
3968
}
3969
sd->upos = MAX(sd->upos, _font_get_underline_position(gl.font_rid, gl.font_size));
3970
sd->uthk = MAX(sd->uthk, _font_get_underline_thickness(gl.font_rid, gl.font_size));
3971
} else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) {
3972
// Glyph not found, replace with hex code box.
3973
if (sd->orientation == ORIENTATION_HORIZONTAL) {
3974
sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.85);
3975
sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.15);
3976
} else {
3977
sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
3978
sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
3979
}
3980
}
3981
sd->width += gl.advance * gl.repeat;
3982
}
3983
}
3984
_realign(sd);
3985
}
3986
return true;
3987
}
3988
3989
void TextServerFallback::_realign(ShapedTextDataFallback *p_sd) const {
3990
// Align embedded objects to baseline.
3991
double full_ascent = p_sd->ascent;
3992
double full_descent = p_sd->descent;
3993
for (KeyValue<Variant, ShapedTextDataFallback::EmbeddedObject> &E : p_sd->objects) {
3994
if ((E.value.start >= p_sd->start) && (E.value.start < p_sd->end)) {
3995
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
3996
switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {
3997
case INLINE_ALIGNMENT_TO_TOP: {
3998
E.value.rect.position.y = -p_sd->ascent;
3999
} break;
4000
case INLINE_ALIGNMENT_TO_CENTER: {
4001
E.value.rect.position.y = (-p_sd->ascent + p_sd->descent) / 2;
4002
} break;
4003
case INLINE_ALIGNMENT_TO_BASELINE: {
4004
E.value.rect.position.y = 0;
4005
} break;
4006
case INLINE_ALIGNMENT_TO_BOTTOM: {
4007
E.value.rect.position.y = p_sd->descent;
4008
} break;
4009
}
4010
switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {
4011
case INLINE_ALIGNMENT_BOTTOM_TO: {
4012
E.value.rect.position.y -= E.value.rect.size.y;
4013
} break;
4014
case INLINE_ALIGNMENT_CENTER_TO: {
4015
E.value.rect.position.y -= E.value.rect.size.y / 2;
4016
} break;
4017
case INLINE_ALIGNMENT_BASELINE_TO: {
4018
E.value.rect.position.y -= E.value.baseline;
4019
} break;
4020
case INLINE_ALIGNMENT_TOP_TO: {
4021
// NOP
4022
} break;
4023
}
4024
full_ascent = MAX(full_ascent, -E.value.rect.position.y);
4025
full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y);
4026
} else {
4027
switch (E.value.inline_align & INLINE_ALIGNMENT_TEXT_MASK) {
4028
case INLINE_ALIGNMENT_TO_TOP: {
4029
E.value.rect.position.x = -p_sd->ascent;
4030
} break;
4031
case INLINE_ALIGNMENT_TO_CENTER: {
4032
E.value.rect.position.x = (-p_sd->ascent + p_sd->descent) / 2;
4033
} break;
4034
case INLINE_ALIGNMENT_TO_BASELINE: {
4035
E.value.rect.position.x = 0;
4036
} break;
4037
case INLINE_ALIGNMENT_TO_BOTTOM: {
4038
E.value.rect.position.x = p_sd->descent;
4039
} break;
4040
}
4041
switch (E.value.inline_align & INLINE_ALIGNMENT_IMAGE_MASK) {
4042
case INLINE_ALIGNMENT_BOTTOM_TO: {
4043
E.value.rect.position.x -= E.value.rect.size.x;
4044
} break;
4045
case INLINE_ALIGNMENT_CENTER_TO: {
4046
E.value.rect.position.x -= E.value.rect.size.x / 2;
4047
} break;
4048
case INLINE_ALIGNMENT_BASELINE_TO: {
4049
E.value.rect.position.x -= E.value.baseline;
4050
} break;
4051
case INLINE_ALIGNMENT_TOP_TO: {
4052
// NOP
4053
} break;
4054
}
4055
full_ascent = MAX(full_ascent, -E.value.rect.position.x);
4056
full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x);
4057
}
4058
}
4059
}
4060
p_sd->ascent = full_ascent;
4061
p_sd->descent = full_descent;
4062
}
4063
4064
RID TextServerFallback::_shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {
4065
_THREAD_SAFE_METHOD_
4066
4067
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
4068
ERR_FAIL_NULL_V(sd, RID());
4069
4070
MutexLock lock(sd->mutex);
4071
if (sd->parent != RID()) {
4072
return _shaped_text_substr(sd->parent, p_start, p_length);
4073
}
4074
if (!sd->valid.is_set()) {
4075
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
4076
}
4077
ERR_FAIL_COND_V(p_start < 0 || p_length < 0, RID());
4078
ERR_FAIL_COND_V(sd->start > p_start || sd->end < p_start, RID());
4079
ERR_FAIL_COND_V(sd->end < p_start + p_length, RID());
4080
4081
ShapedTextDataFallback *new_sd = memnew(ShapedTextDataFallback);
4082
new_sd->parent = p_shaped;
4083
new_sd->start = p_start;
4084
new_sd->end = p_start + p_length;
4085
4086
new_sd->orientation = sd->orientation;
4087
new_sd->direction = sd->direction;
4088
new_sd->custom_punct = sd->custom_punct;
4089
new_sd->para_direction = sd->para_direction;
4090
new_sd->line_breaks_valid = sd->line_breaks_valid;
4091
new_sd->justification_ops_valid = sd->justification_ops_valid;
4092
new_sd->sort_valid = false;
4093
new_sd->upos = sd->upos;
4094
new_sd->uthk = sd->uthk;
4095
for (int i = 0; i < TextServer::SPACING_MAX; i++) {
4096
new_sd->extra_spacing[i] = sd->extra_spacing[i];
4097
}
4098
4099
if (p_length > 0) {
4100
new_sd->text = sd->text.substr(p_start - sd->start, p_length);
4101
4102
int span_size = sd->spans.size();
4103
4104
new_sd->first_span = 0;
4105
new_sd->last_span = span_size - 1;
4106
for (int i = 0; i < span_size; i++) {
4107
const ShapedTextDataFallback::Span &span = sd->spans[i];
4108
if (span.end <= p_start) {
4109
new_sd->first_span = i + 1;
4110
} else if (span.start >= p_start + p_length) {
4111
new_sd->last_span = i - 1;
4112
break;
4113
}
4114
}
4115
4116
int sd_size = sd->glyphs.size();
4117
const Glyph *sd_glyphs = sd->glyphs.ptr();
4118
4119
for (int i = 0; i < sd_size; i++) {
4120
if ((sd_glyphs[i].start >= new_sd->start) && (sd_glyphs[i].end <= new_sd->end)) {
4121
Glyph gl = sd_glyphs[i];
4122
if (gl.span_index >= 0) {
4123
gl.span_index -= new_sd->first_span;
4124
}
4125
if (gl.end == p_start + p_length && ((gl.flags & GRAPHEME_IS_SOFT_HYPHEN) == GRAPHEME_IS_SOFT_HYPHEN)) {
4126
gl.index = 0x00ad;
4127
gl.advance = font_get_glyph_advance(gl.font_rid, gl.font_size, 0x00ad).x;
4128
}
4129
if ((gl.flags & GRAPHEME_IS_EMBEDDED_OBJECT) == GRAPHEME_IS_EMBEDDED_OBJECT && gl.span_index + new_sd->first_span >= 0 && gl.span_index + new_sd->first_span < span_size) {
4130
Variant key = sd->spans[gl.span_index + new_sd->first_span].embedded_key;
4131
if (key != Variant()) {
4132
ShapedTextDataFallback::EmbeddedObject obj = sd->objects[key];
4133
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
4134
obj.rect.position.x = new_sd->width;
4135
new_sd->width += obj.rect.size.x;
4136
} else {
4137
obj.rect.position.y = new_sd->width;
4138
new_sd->width += obj.rect.size.y;
4139
}
4140
new_sd->objects[key] = obj;
4141
}
4142
} else {
4143
if (gl.font_rid.is_valid()) {
4144
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
4145
new_sd->ascent = MAX(new_sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_TOP));
4146
new_sd->descent = MAX(new_sd->descent, _font_get_descent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_BOTTOM));
4147
} else {
4148
new_sd->ascent = MAX(new_sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
4149
new_sd->descent = MAX(new_sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
4150
}
4151
} else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) {
4152
// Glyph not found, replace with hex code box.
4153
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
4154
new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.85);
4155
new_sd->descent = MAX(new_sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.15);
4156
} else {
4157
new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
4158
new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
4159
}
4160
}
4161
if (new_sd->glyphs.is_empty() && gl.x_off < 0.0) {
4162
gl.advance += -gl.x_off;
4163
gl.x_off = 0.0;
4164
}
4165
new_sd->width += gl.advance * gl.repeat;
4166
}
4167
new_sd->glyphs.push_back(gl);
4168
}
4169
}
4170
4171
_realign(new_sd);
4172
}
4173
new_sd->valid.set();
4174
4175
return shaped_owner.make_rid(new_sd);
4176
}
4177
4178
RID TextServerFallback::_shaped_text_get_parent(const RID &p_shaped) const {
4179
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
4180
ERR_FAIL_NULL_V(sd, RID());
4181
4182
MutexLock lock(sd->mutex);
4183
return sd->parent;
4184
}
4185
4186
double TextServerFallback::_shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<JustificationFlag> p_jst_flags) {
4187
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
4188
ERR_FAIL_NULL_V(sd, 0.0);
4189
4190
MutexLock lock(sd->mutex);
4191
if (!sd->valid.is_set()) {
4192
_shaped_text_shape(p_shaped);
4193
}
4194
if (!sd->justification_ops_valid) {
4195
_shaped_text_update_justification_ops(p_shaped);
4196
}
4197
4198
int start_pos = 0;
4199
int end_pos = sd->glyphs.size() - 1;
4200
4201
if (p_jst_flags.has_flag(JUSTIFICATION_AFTER_LAST_TAB)) {
4202
int start, end, delta;
4203
if (sd->para_direction == DIRECTION_LTR) {
4204
start = sd->glyphs.size() - 1;
4205
end = -1;
4206
delta = -1;
4207
} else {
4208
start = 0;
4209
end = sd->glyphs.size();
4210
delta = +1;
4211
}
4212
4213
for (int i = start; i != end; i += delta) {
4214
if ((sd->glyphs[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
4215
if (sd->para_direction == DIRECTION_LTR) {
4216
start_pos = i;
4217
break;
4218
} else {
4219
end_pos = i;
4220
break;
4221
}
4222
}
4223
}
4224
}
4225
4226
double justification_width;
4227
if (p_jst_flags.has_flag(JUSTIFICATION_CONSTRAIN_ELLIPSIS)) {
4228
if (sd->overrun_trim_data.trim_pos >= 0) {
4229
end_pos = sd->overrun_trim_data.trim_pos;
4230
justification_width = sd->width_trimmed;
4231
} else {
4232
return Math::ceil(sd->width);
4233
}
4234
} else {
4235
justification_width = sd->width;
4236
}
4237
4238
if (p_jst_flags.has_flag(JUSTIFICATION_TRIM_EDGE_SPACES)) {
4239
// Trim spaces.
4240
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)) {
4241
justification_width -= sd->glyphs[start_pos].advance * sd->glyphs[start_pos].repeat;
4242
sd->glyphs.write[start_pos].advance = 0;
4243
start_pos += sd->glyphs[start_pos].count;
4244
}
4245
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)) {
4246
justification_width -= sd->glyphs[end_pos].advance * sd->glyphs[end_pos].repeat;
4247
sd->glyphs.write[end_pos].advance = 0;
4248
end_pos -= sd->glyphs[end_pos].count;
4249
}
4250
} else {
4251
// Skip breaks, but do not reset size.
4252
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)) {
4253
start_pos += sd->glyphs[start_pos].count;
4254
}
4255
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)) {
4256
end_pos -= sd->glyphs[end_pos].count;
4257
}
4258
}
4259
4260
int space_count = 0;
4261
for (int i = start_pos; i <= end_pos; i++) {
4262
const Glyph &gl = sd->glyphs[i];
4263
if (gl.count > 0) {
4264
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) {
4265
space_count++;
4266
}
4267
}
4268
}
4269
4270
if ((space_count > 0) && p_jst_flags.has_flag(JUSTIFICATION_WORD_BOUND)) {
4271
double delta_width_per_space = (p_width - justification_width) / space_count;
4272
for (int i = start_pos; i <= end_pos; i++) {
4273
Glyph &gl = sd->glyphs.write[i];
4274
if (gl.count > 0) {
4275
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) {
4276
double old_adv = gl.advance;
4277
gl.advance = MAX(gl.advance + delta_width_per_space, Math::round(0.1 * gl.font_size));
4278
justification_width += (gl.advance - old_adv);
4279
}
4280
}
4281
}
4282
}
4283
4284
if (Math::floor(p_width) < Math::floor(justification_width)) {
4285
sd->fit_width_minimum_reached = true;
4286
}
4287
4288
if (!p_jst_flags.has_flag(JUSTIFICATION_CONSTRAIN_ELLIPSIS)) {
4289
sd->width = justification_width;
4290
}
4291
4292
return Math::ceil(justification_width);
4293
}
4294
4295
double TextServerFallback::_shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) {
4296
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
4297
ERR_FAIL_NULL_V(sd, 0.0);
4298
4299
MutexLock lock(sd->mutex);
4300
if (!sd->valid.is_set()) {
4301
_shaped_text_shape(p_shaped);
4302
}
4303
if (!sd->line_breaks_valid) {
4304
_shaped_text_update_breaks(p_shaped);
4305
}
4306
4307
for (int i = 0; i < p_tab_stops.size(); i++) {
4308
if (p_tab_stops[i] <= 0) {
4309
return 0.0;
4310
}
4311
}
4312
4313
int tab_index = 0;
4314
double off = 0.0;
4315
4316
int start, end, delta;
4317
if (sd->para_direction == DIRECTION_LTR) {
4318
start = 0;
4319
end = sd->glyphs.size();
4320
delta = +1;
4321
} else {
4322
start = sd->glyphs.size() - 1;
4323
end = -1;
4324
delta = -1;
4325
}
4326
4327
Glyph *gl = sd->glyphs.ptrw();
4328
4329
for (int i = start; i != end; i += delta) {
4330
if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
4331
double tab_off = 0.0;
4332
while (tab_off <= off) {
4333
tab_off += p_tab_stops[tab_index];
4334
tab_index++;
4335
if (tab_index >= p_tab_stops.size()) {
4336
tab_index = 0;
4337
}
4338
}
4339
double old_adv = gl[i].advance;
4340
gl[i].advance = tab_off - off;
4341
sd->width += gl[i].advance - old_adv;
4342
off = 0;
4343
continue;
4344
}
4345
off += gl[i].advance * gl[i].repeat;
4346
}
4347
4348
return 0.0;
4349
}
4350
4351
bool TextServerFallback::_shaped_text_update_breaks(const RID &p_shaped) {
4352
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
4353
ERR_FAIL_NULL_V(sd, false);
4354
4355
MutexLock lock(sd->mutex);
4356
if (!sd->valid.is_set()) {
4357
_shaped_text_shape(p_shaped);
4358
}
4359
4360
if (sd->line_breaks_valid) {
4361
return true; // Nothing to do.
4362
}
4363
4364
int sd_size = sd->glyphs.size();
4365
Glyph *sd_glyphs = sd->glyphs.ptrw();
4366
4367
int c_punct_size = sd->custom_punct.length();
4368
const char32_t *c_punct = sd->custom_punct.ptr();
4369
4370
for (int i = 0; i < sd_size; i++) {
4371
if (sd_glyphs[i].count > 0) {
4372
char32_t c = sd->text[sd_glyphs[i].start - sd->start];
4373
char32_t c_next = i < sd_size ? sd->text[sd_glyphs[i].start - sd->start + 1] : 0x0000;
4374
if (c_punct_size == 0) {
4375
if (is_punct(c) && c != 0x005F && c != ' ') {
4376
sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION;
4377
}
4378
} else {
4379
for (int j = 0; j < c_punct_size; j++) {
4380
if (c_punct[j] == c) {
4381
sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION;
4382
break;
4383
}
4384
}
4385
}
4386
if (is_underscore(c)) {
4387
sd->glyphs.write[i].flags |= GRAPHEME_IS_UNDERSCORE;
4388
}
4389
if (is_whitespace(c) && !is_linebreak(c)) {
4390
sd_glyphs[i].flags |= GRAPHEME_IS_SPACE;
4391
if (c != 0x00A0 && c != 0x202F && c != 0x2060 && c != 0x2007) { // Skip for non-breaking space variants.
4392
sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT;
4393
}
4394
}
4395
if (is_linebreak(c)) {
4396
sd_glyphs[i].flags |= GRAPHEME_IS_SPACE;
4397
if (c != 0x000D || c_next != 0x000A) { // Skip first hard break in CR-LF pair.
4398
sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD;
4399
}
4400
}
4401
if (c == 0x0009 || c == 0x000b) {
4402
sd_glyphs[i].flags |= GRAPHEME_IS_TAB;
4403
}
4404
if (c == 0x00ad) {
4405
sd_glyphs[i].flags |= GRAPHEME_IS_SOFT_HYPHEN;
4406
}
4407
4408
i += (sd_glyphs[i].count - 1);
4409
}
4410
}
4411
sd->line_breaks_valid = true;
4412
return sd->line_breaks_valid;
4413
}
4414
4415
bool TextServerFallback::_shaped_text_update_justification_ops(const RID &p_shaped) {
4416
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
4417
ERR_FAIL_NULL_V(sd, false);
4418
4419
MutexLock lock(sd->mutex);
4420
if (!sd->valid.is_set()) {
4421
_shaped_text_shape(p_shaped);
4422
}
4423
if (!sd->line_breaks_valid) {
4424
_shaped_text_update_breaks(p_shaped);
4425
}
4426
4427
sd->justification_ops_valid = true; // Not supported by fallback server.
4428
return true;
4429
}
4430
4431
RID TextServerFallback::_find_sys_font_for_text(const RID &p_fdef, const String &p_script_code, const String &p_language, const String &p_text) {
4432
RID f;
4433
// Try system fallback.
4434
if (_font_is_allow_system_fallback(p_fdef)) {
4435
String font_name = _font_get_name(p_fdef);
4436
BitField<FontStyle> font_style = _font_get_style(p_fdef);
4437
int font_weight = _font_get_weight(p_fdef);
4438
int font_stretch = _font_get_stretch(p_fdef);
4439
Dictionary dvar = _font_get_variation_coordinates(p_fdef);
4440
static int64_t wgth_tag = name_to_tag("weight");
4441
static int64_t wdth_tag = name_to_tag("width");
4442
static int64_t ital_tag = name_to_tag("italic");
4443
if (dvar.has(wgth_tag)) {
4444
font_weight = dvar[wgth_tag].operator int();
4445
}
4446
if (dvar.has(wdth_tag)) {
4447
font_stretch = dvar[wdth_tag].operator int();
4448
}
4449
if (dvar.has(ital_tag) && dvar[ital_tag].operator int() == 1) {
4450
font_style.set_flag(TextServer::FONT_ITALIC);
4451
}
4452
4453
String locale = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
4454
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);
4455
#ifdef GDEXTENSION
4456
for (int fb = 0; fb < fallback_font_name.size(); fb++) {
4457
const String &E = fallback_font_name[fb];
4458
#elif defined(GODOT_MODULE)
4459
for (const String &E : fallback_font_name) {
4460
#endif
4461
SystemFontKey key = SystemFontKey(E, font_style & TextServer::FONT_ITALIC, font_weight, font_stretch, p_fdef, this);
4462
if (system_fonts.has(key)) {
4463
const SystemFontCache &sysf_cache = system_fonts[key];
4464
int best_score = 0;
4465
int best_match = -1;
4466
for (int face_idx = 0; face_idx < sysf_cache.var.size(); face_idx++) {
4467
const SystemFontCacheRec &F = sysf_cache.var[face_idx];
4468
if (unlikely(!_font_has_char(F.rid, p_text[0]))) {
4469
continue;
4470
}
4471
BitField<FontStyle> style = _font_get_style(F.rid);
4472
int weight = _font_get_weight(F.rid);
4473
int stretch = _font_get_stretch(F.rid);
4474
int score = (20 - Math::abs(weight - font_weight) / 50);
4475
score += (20 - Math::abs(stretch - font_stretch) / 10);
4476
if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) {
4477
score += 30;
4478
}
4479
if (score >= best_score) {
4480
best_score = score;
4481
best_match = face_idx;
4482
}
4483
if (best_score == 70) {
4484
break;
4485
}
4486
}
4487
if (best_match != -1) {
4488
f = sysf_cache.var[best_match].rid;
4489
}
4490
}
4491
if (!f.is_valid()) {
4492
if (system_fonts.has(key)) {
4493
const SystemFontCache &sysf_cache = system_fonts[key];
4494
if (sysf_cache.max_var == sysf_cache.var.size()) {
4495
// All subfonts already tested, skip.
4496
continue;
4497
}
4498
}
4499
4500
if (!system_font_data.has(E)) {
4501
system_font_data[E] = FileAccess::get_file_as_bytes(E);
4502
}
4503
4504
const PackedByteArray &font_data = system_font_data[E];
4505
4506
SystemFontCacheRec sysf;
4507
sysf.rid = _create_font();
4508
_font_set_data_ptr(sysf.rid, font_data.ptr(), font_data.size());
4509
if (!_font_validate(sysf.rid)) {
4510
_free_rid(sysf.rid);
4511
continue;
4512
}
4513
4514
Dictionary var = dvar;
4515
// Select matching style from collection.
4516
int best_score = 0;
4517
int best_match = -1;
4518
for (int face_idx = 0; face_idx < _font_get_face_count(sysf.rid); face_idx++) {
4519
_font_set_face_index(sysf.rid, face_idx);
4520
if (unlikely(!_font_has_char(sysf.rid, p_text[0]))) {
4521
continue;
4522
}
4523
BitField<FontStyle> style = _font_get_style(sysf.rid);
4524
int weight = _font_get_weight(sysf.rid);
4525
int stretch = _font_get_stretch(sysf.rid);
4526
int score = (20 - Math::abs(weight - font_weight) / 50);
4527
score += (20 - Math::abs(stretch - font_stretch) / 10);
4528
if (bool(style & TextServer::FONT_ITALIC) == bool(font_style & TextServer::FONT_ITALIC)) {
4529
score += 30;
4530
}
4531
if (score >= best_score) {
4532
best_score = score;
4533
best_match = face_idx;
4534
}
4535
if (best_score == 70) {
4536
break;
4537
}
4538
}
4539
if (best_match == -1) {
4540
_free_rid(sysf.rid);
4541
continue;
4542
} else {
4543
_font_set_face_index(sysf.rid, best_match);
4544
}
4545
sysf.index = best_match;
4546
4547
// If it's a variable font, apply weight, stretch and italic coordinates to match requested style.
4548
if (best_score != 70) {
4549
Dictionary ftr = _font_supported_variation_list(sysf.rid);
4550
if (ftr.has(wdth_tag)) {
4551
var[wdth_tag] = font_stretch;
4552
_font_set_stretch(sysf.rid, font_stretch);
4553
}
4554
if (ftr.has(wgth_tag)) {
4555
var[wgth_tag] = font_weight;
4556
_font_set_weight(sysf.rid, font_weight);
4557
}
4558
if ((font_style & TextServer::FONT_ITALIC) && ftr.has(ital_tag)) {
4559
var[ital_tag] = 1;
4560
_font_set_style(sysf.rid, _font_get_style(sysf.rid) | TextServer::FONT_ITALIC);
4561
}
4562
}
4563
4564
bool fb_use_msdf = key.msdf;
4565
#ifdef MODULE_FREETYPE_ENABLED
4566
if (fb_use_msdf) {
4567
FontFallback *fd = _get_font_data(sysf.rid);
4568
if (fd) {
4569
MutexLock lock(fd->mutex);
4570
Vector2i size = _get_size(fd, 16);
4571
FontForSizeFallback *ffsd = nullptr;
4572
if (_ensure_cache_for_size(fd, size, ffsd)) {
4573
if (ffsd && (FT_HAS_COLOR(fd->face) || !FT_IS_SCALABLE(fd->face))) {
4574
fb_use_msdf = false;
4575
}
4576
}
4577
}
4578
}
4579
#endif
4580
4581
_font_set_antialiasing(sysf.rid, key.antialiasing);
4582
_font_set_disable_embedded_bitmaps(sysf.rid, key.disable_embedded_bitmaps);
4583
_font_set_generate_mipmaps(sysf.rid, key.mipmaps);
4584
_font_set_multichannel_signed_distance_field(sysf.rid, fb_use_msdf);
4585
_font_set_msdf_pixel_range(sysf.rid, key.msdf_range);
4586
_font_set_msdf_size(sysf.rid, key.msdf_source_size);
4587
_font_set_fixed_size(sysf.rid, key.fixed_size);
4588
_font_set_force_autohinter(sysf.rid, key.force_autohinter);
4589
_font_set_hinting(sysf.rid, key.hinting);
4590
_font_set_subpixel_positioning(sysf.rid, key.subpixel_positioning);
4591
_font_set_keep_rounding_remainders(sysf.rid, key.keep_rounding_remainders);
4592
_font_set_variation_coordinates(sysf.rid, var);
4593
_font_set_embolden(sysf.rid, key.embolden);
4594
_font_set_transform(sysf.rid, key.transform);
4595
_font_set_spacing(sysf.rid, SPACING_TOP, key.extra_spacing[SPACING_TOP]);
4596
_font_set_spacing(sysf.rid, SPACING_BOTTOM, key.extra_spacing[SPACING_BOTTOM]);
4597
_font_set_spacing(sysf.rid, SPACING_SPACE, key.extra_spacing[SPACING_SPACE]);
4598
_font_set_spacing(sysf.rid, SPACING_GLYPH, key.extra_spacing[SPACING_GLYPH]);
4599
4600
if (system_fonts.has(key)) {
4601
system_fonts[key].var.push_back(sysf);
4602
} else {
4603
SystemFontCache &sysf_cache = system_fonts[key];
4604
sysf_cache.max_var = _font_get_face_count(sysf.rid);
4605
sysf_cache.var.push_back(sysf);
4606
}
4607
f = sysf.rid;
4608
}
4609
break;
4610
}
4611
}
4612
return f;
4613
}
4614
4615
void TextServerFallback::_shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) {
4616
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped_line);
4617
ERR_FAIL_NULL_MSG(sd, "ShapedTextDataFallback invalid.");
4618
4619
MutexLock lock(sd->mutex);
4620
if (!sd->valid.is_set()) {
4621
_shaped_text_shape(p_shaped_line);
4622
}
4623
4624
sd->text_trimmed = false;
4625
sd->overrun_trim_data.ellipsis_glyph_buf.clear();
4626
4627
bool add_ellipsis = p_trim_flags.has_flag(OVERRUN_ADD_ELLIPSIS);
4628
bool cut_per_word = p_trim_flags.has_flag(OVERRUN_TRIM_WORD_ONLY);
4629
bool enforce_ellipsis = p_trim_flags.has_flag(OVERRUN_ENFORCE_ELLIPSIS);
4630
bool short_string_ellipsis = p_trim_flags.has_flag(OVERRUN_SHORT_STRING_ELLIPSIS);
4631
bool justification_aware = p_trim_flags.has_flag(OVERRUN_JUSTIFICATION_AWARE);
4632
4633
Glyph *sd_glyphs = sd->glyphs.ptrw();
4634
4635
if ((p_trim_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIM || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {
4636
sd->overrun_trim_data.trim_pos = -1;
4637
sd->overrun_trim_data.ellipsis_pos = -1;
4638
return;
4639
}
4640
4641
if (justification_aware && !sd->fit_width_minimum_reached) {
4642
return;
4643
}
4644
4645
Vector<ShapedTextDataFallback::Span> &spans = sd->spans;
4646
if (sd->parent != RID()) {
4647
ShapedTextDataFallback *parent_sd = shaped_owner.get_or_null(sd->parent);
4648
ERR_FAIL_COND(!parent_sd->valid.is_set());
4649
spans = parent_sd->spans;
4650
}
4651
4652
int span_size = spans.size();
4653
if (span_size == 0) {
4654
return;
4655
}
4656
4657
int sd_size = sd->glyphs.size();
4658
int last_gl_font_size = sd_glyphs[sd_size - 1].font_size;
4659
bool found_el_char = false;
4660
4661
// Find usable fonts, if fonts from the last glyph do not have required chars.
4662
RID dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;
4663
if (add_ellipsis || enforce_ellipsis || short_string_ellipsis) {
4664
if (!_font_has_char(dot_gl_font_rid, sd->el_char)) {
4665
const Array &fonts = spans[span_size - 1].fonts;
4666
for (int i = 0; i < fonts.size(); i++) {
4667
if (_font_has_char(fonts[i], sd->el_char)) {
4668
dot_gl_font_rid = fonts[i];
4669
found_el_char = true;
4670
break;
4671
}
4672
}
4673
if (!found_el_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) {
4674
const char32_t u32str[] = { sd->el_char, 0 };
4675
RID rid = _find_sys_font_for_text(fonts[0], String(), spans[span_size - 1].language, u32str);
4676
if (rid.is_valid()) {
4677
dot_gl_font_rid = rid;
4678
found_el_char = true;
4679
}
4680
}
4681
} else {
4682
found_el_char = true;
4683
}
4684
if (!found_el_char) {
4685
bool found_dot_char = false;
4686
dot_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;
4687
if (!_font_has_char(dot_gl_font_rid, '.')) {
4688
const Array &fonts = spans[span_size - 1].fonts;
4689
for (int i = 0; i < fonts.size(); i++) {
4690
if (_font_has_char(fonts[i], '.')) {
4691
dot_gl_font_rid = fonts[i];
4692
found_dot_char = true;
4693
break;
4694
}
4695
}
4696
if (!found_dot_char && OS::get_singleton()->has_feature("system_fonts") && fonts.size() > 0 && _font_is_allow_system_fallback(fonts[0])) {
4697
RID rid = _find_sys_font_for_text(fonts[0], String(), spans[span_size - 1].language, ".");
4698
if (rid.is_valid()) {
4699
dot_gl_font_rid = rid;
4700
}
4701
}
4702
}
4703
}
4704
}
4705
RID whitespace_gl_font_rid = sd_glyphs[sd_size - 1].font_rid;
4706
if (!_font_has_char(whitespace_gl_font_rid, ' ')) {
4707
const Array &fonts = spans[span_size - 1].fonts;
4708
for (int i = 0; i < fonts.size(); i++) {
4709
if (_font_has_char(fonts[i], ' ')) {
4710
whitespace_gl_font_rid = fonts[i];
4711
break;
4712
}
4713
}
4714
}
4715
4716
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;
4717
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();
4718
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;
4719
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();
4720
4721
int ellipsis_width = 0;
4722
if (add_ellipsis && whitespace_gl_font_rid.is_valid()) {
4723
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);
4724
}
4725
4726
int ell_min_characters = 6;
4727
double width = sd->width;
4728
double width_without_el = width;
4729
4730
int trim_pos = 0;
4731
int ellipsis_pos = (enforce_ellipsis || short_string_ellipsis) ? 0 : -1;
4732
4733
int last_valid_cut = -1;
4734
int last_valid_cut_witout_el = -1;
4735
4736
if ((enforce_ellipsis || short_string_ellipsis) && (width + ellipsis_width <= p_width)) {
4737
trim_pos = -1;
4738
ellipsis_pos = sd_size;
4739
} else {
4740
for (int i = sd_size - 1; i != -1; i--) {
4741
width -= sd_glyphs[i].advance * sd_glyphs[i].repeat;
4742
4743
if (sd_glyphs[i].count > 0) {
4744
bool above_min_char_threshold = (i >= ell_min_characters);
4745
if (!above_min_char_threshold && last_valid_cut_witout_el != -1) {
4746
trim_pos = last_valid_cut_witout_el;
4747
ellipsis_pos = -1;
4748
width = width_without_el;
4749
break;
4750
}
4751
if (!(enforce_ellipsis || short_string_ellipsis) && width <= p_width && last_valid_cut_witout_el == -1) {
4752
if (cut_per_word && above_min_char_threshold) {
4753
if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
4754
last_valid_cut_witout_el = i;
4755
width_without_el = width;
4756
}
4757
} else {
4758
last_valid_cut_witout_el = i;
4759
width_without_el = width;
4760
}
4761
}
4762
if (width + (((above_min_char_threshold && add_ellipsis) || enforce_ellipsis || short_string_ellipsis) ? ellipsis_width : 0) <= p_width) {
4763
if (cut_per_word && above_min_char_threshold) {
4764
if ((sd_glyphs[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) {
4765
last_valid_cut = i;
4766
}
4767
} else {
4768
last_valid_cut = i;
4769
}
4770
if (last_valid_cut != -1) {
4771
trim_pos = last_valid_cut;
4772
4773
if (add_ellipsis && (above_min_char_threshold || enforce_ellipsis || short_string_ellipsis) && width - ellipsis_width <= p_width) {
4774
ellipsis_pos = trim_pos;
4775
}
4776
break;
4777
}
4778
}
4779
}
4780
}
4781
}
4782
4783
sd->overrun_trim_data.trim_pos = trim_pos;
4784
sd->overrun_trim_data.ellipsis_pos = ellipsis_pos;
4785
if (trim_pos == 0 && (enforce_ellipsis || short_string_ellipsis) && add_ellipsis) {
4786
sd->overrun_trim_data.ellipsis_pos = 0;
4787
}
4788
4789
if ((trim_pos >= 0 && sd->width > p_width) || enforce_ellipsis || short_string_ellipsis) {
4790
if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis || short_string_ellipsis)) {
4791
// Insert an additional space when cutting word bound for aesthetics.
4792
if (cut_per_word && (ellipsis_pos > 0)) {
4793
Glyph gl;
4794
gl.count = 1;
4795
gl.advance = whitespace_adv.x;
4796
gl.index = whitespace_gl_idx;
4797
gl.font_rid = whitespace_gl_font_rid;
4798
gl.font_size = last_gl_font_size;
4799
gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL;
4800
4801
sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
4802
}
4803
// Add ellipsis dots.
4804
if (dot_gl_idx != 0) {
4805
Glyph gl;
4806
gl.count = 1;
4807
gl.repeat = (found_el_char ? 1 : 3);
4808
gl.advance = dot_adv.x;
4809
gl.index = dot_gl_idx;
4810
gl.font_rid = dot_gl_font_rid;
4811
gl.font_size = last_gl_font_size;
4812
gl.flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL;
4813
4814
sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
4815
}
4816
}
4817
4818
sd->text_trimmed = true;
4819
sd->width_trimmed = width + ((ellipsis_pos != -1) ? ellipsis_width : 0);
4820
}
4821
}
4822
4823
int64_t TextServerFallback::_shaped_text_get_trim_pos(const RID &p_shaped) const {
4824
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
4825
ERR_FAIL_NULL_V_MSG(sd, -1, "ShapedTextDataFallback invalid.");
4826
4827
MutexLock lock(sd->mutex);
4828
return sd->overrun_trim_data.trim_pos;
4829
}
4830
4831
int64_t TextServerFallback::_shaped_text_get_ellipsis_pos(const RID &p_shaped) const {
4832
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
4833
ERR_FAIL_NULL_V_MSG(sd, -1, "ShapedTextDataFallback invalid.");
4834
4835
MutexLock lock(sd->mutex);
4836
return sd->overrun_trim_data.ellipsis_pos;
4837
}
4838
4839
const Glyph *TextServerFallback::_shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const {
4840
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
4841
ERR_FAIL_NULL_V_MSG(sd, nullptr, "ShapedTextDataFallback invalid.");
4842
4843
MutexLock lock(sd->mutex);
4844
return sd->overrun_trim_data.ellipsis_glyph_buf.ptr();
4845
}
4846
4847
int64_t TextServerFallback::_shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const {
4848
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
4849
ERR_FAIL_NULL_V_MSG(sd, 0, "ShapedTextDataFallback invalid.");
4850
4851
MutexLock lock(sd->mutex);
4852
return sd->overrun_trim_data.ellipsis_glyph_buf.size();
4853
}
4854
4855
bool TextServerFallback::_shaped_text_shape(const RID &p_shaped) {
4856
ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
4857
ERR_FAIL_NULL_V(sd, false);
4858
4859
MutexLock lock(sd->mutex);
4860
if (sd->valid.is_set()) {
4861
return true;
4862
}
4863
4864
if (sd->parent != RID()) {
4865
full_copy(sd);
4866
}
4867
4868
// Cleanup.
4869
sd->justification_ops_valid = false;
4870
sd->line_breaks_valid = false;
4871
sd->ascent = 0.0;
4872
sd->descent = 0.0;
4873
sd->width = 0.0;
4874
sd->glyphs.clear();
4875
sd->runs.clear();
4876
sd->runs_dirty = true;
4877
4878
if (sd->text.length() == 0) {
4879
sd->valid.set();
4880
return true;
4881
}
4882
4883
// "Shape" string.
4884
for (int i = 0; i < sd->spans.size(); i++) {
4885
const ShapedTextDataFallback::Span &span = sd->spans[i];
4886
if (span.embedded_key != Variant()) {
4887
// Embedded object.
4888
if (sd->orientation == ORIENTATION_HORIZONTAL) {
4889
sd->objects[span.embedded_key].rect.position.x = sd->width;
4890
sd->width += sd->objects[span.embedded_key].rect.size.x;
4891
} else {
4892
sd->objects[span.embedded_key].rect.position.y = sd->width;
4893
sd->width += sd->objects[span.embedded_key].rect.size.y;
4894
}
4895
Glyph gl;
4896
gl.span_index = i;
4897
gl.start = span.start;
4898
gl.end = span.end;
4899
gl.count = 1;
4900
gl.index = 0;
4901
gl.flags = GRAPHEME_IS_VALID | GRAPHEME_IS_EMBEDDED_OBJECT;
4902
if (sd->orientation == ORIENTATION_HORIZONTAL) {
4903
gl.advance = sd->objects[span.embedded_key].rect.size.x;
4904
} else {
4905
gl.advance = sd->objects[span.embedded_key].rect.size.y;
4906
}
4907
sd->glyphs.push_back(gl);
4908
} else {
4909
// Text span.
4910
int last_non_zero_w = sd->end - 1;
4911
if (i == sd->spans.size() - 1) {
4912
for (int j = span.end - 1; j >= span.start; j--) {
4913
last_non_zero_w = j;
4914
uint32_t idx = (int32_t)sd->text[j - sd->start];
4915
if (!is_control(idx) && !(idx >= 0x200B && idx <= 0x200D)) {
4916
break;
4917
}
4918
}
4919
}
4920
4921
RID prev_font;
4922
for (int j = span.start; j < span.end; j++) {
4923
Glyph gl;
4924
gl.span_index = i;
4925
gl.start = j;
4926
gl.end = j + 1;
4927
gl.count = 1;
4928
gl.font_size = span.font_size;
4929
gl.index = (int32_t)sd->text[j - sd->start]; // Use codepoint.
4930
bool zw = (gl.index >= 0x200b && gl.index <= 0x200d);
4931
if (gl.index == 0x0009 || gl.index == 0x000b || zw) {
4932
gl.index = 0x0020;
4933
}
4934
if (!sd->preserve_control && is_control(gl.index)) {
4935
gl.index = 0x0020;
4936
}
4937
// Select first font which has character (font are already sorted by span language).
4938
for (int k = 0; k < span.fonts.size(); k++) {
4939
if (_font_has_char(span.fonts[k], gl.index)) {
4940
gl.font_rid = span.fonts[k];
4941
break;
4942
}
4943
}
4944
if (!gl.font_rid.is_valid() && prev_font.is_valid()) {
4945
if (_font_has_char(prev_font, gl.index)) {
4946
gl.font_rid = prev_font;
4947
}
4948
}
4949
if (!gl.font_rid.is_valid() && OS::get_singleton()->has_feature("system_fonts") && span.fonts.size() > 0) {
4950
// Try system fallback.
4951
RID fdef = span.fonts[0];
4952
if (_font_is_allow_system_fallback(fdef)) {
4953
String text = sd->text.substr(j, 1);
4954
gl.font_rid = _find_sys_font_for_text(fdef, String(), span.language, text);
4955
}
4956
}
4957
prev_font = gl.font_rid;
4958
4959
if (gl.font_rid.is_valid()) {
4960
double scale = _font_get_scale(gl.font_rid, gl.font_size);
4961
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 && gl.font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);
4962
if (sd->text[j - sd->start] != 0 && !is_linebreak(sd->text[j - sd->start])) {
4963
if (sd->orientation == ORIENTATION_HORIZONTAL) {
4964
gl.advance = _font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x;
4965
gl.x_off = 0;
4966
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));
4967
sd->ascent = MAX(sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_TOP));
4968
sd->descent = MAX(sd->descent, _font_get_descent(gl.font_rid, gl.font_size) + _font_get_spacing(gl.font_rid, SPACING_BOTTOM));
4969
} else {
4970
gl.advance = _font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).y;
4971
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));
4972
gl.y_off = _font_get_ascent(gl.font_rid, gl.font_size);
4973
sd->ascent = MAX(sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
4974
sd->descent = MAX(sd->descent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
4975
}
4976
}
4977
if (zw) {
4978
gl.advance = 0.0;
4979
}
4980
if ((j < last_non_zero_w) && !Math::is_zero_approx(gl.advance)) {
4981
// Do not add extra spacing to the last glyph of the string and zero width glyphs.
4982
if (is_whitespace(sd->text[j - sd->start])) {
4983
gl.advance += sd->extra_spacing[SPACING_SPACE] + _font_get_spacing(gl.font_rid, SPACING_SPACE);
4984
} else {
4985
gl.advance += sd->extra_spacing[SPACING_GLYPH] + _font_get_spacing(gl.font_rid, SPACING_GLYPH);
4986
}
4987
}
4988
sd->upos = MAX(sd->upos, _font_get_underline_position(gl.font_rid, gl.font_size));
4989
sd->uthk = MAX(sd->uthk, _font_get_underline_thickness(gl.font_rid, gl.font_size));
4990
4991
// Add kerning to previous glyph.
4992
if (sd->glyphs.size() > 0) {
4993
Glyph &prev_gl = sd->glyphs.write[sd->glyphs.size() - 1];
4994
if (prev_gl.font_rid == gl.font_rid && prev_gl.font_size == gl.font_size) {
4995
if (sd->orientation == ORIENTATION_HORIZONTAL) {
4996
prev_gl.advance += _font_get_kerning(gl.font_rid, gl.font_size, Vector2i(prev_gl.index, gl.index)).x;
4997
} else {
4998
prev_gl.advance += _font_get_kerning(gl.font_rid, gl.font_size, Vector2i(prev_gl.index, gl.index)).y;
4999
}
5000
}
5001
}
5002
if (sd->orientation == ORIENTATION_HORIZONTAL && !subpos) {
5003
gl.advance = Math::round(gl.advance);
5004
}
5005
} else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) {
5006
// Glyph not found, replace with hex code box.
5007
if (sd->orientation == ORIENTATION_HORIZONTAL) {
5008
gl.advance = get_hex_code_box_size(gl.font_size, gl.index).x;
5009
sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.85);
5010
sd->descent = MAX(sd->descent, get_hex_code_box_size(gl.font_size, gl.index).y * 0.15);
5011
} else {
5012
gl.advance = get_hex_code_box_size(gl.font_size, gl.index).y;
5013
sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
5014
sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5));
5015
}
5016
}
5017
sd->width += gl.advance;
5018
sd->glyphs.push_back(gl);
5019
}
5020
}
5021
}
5022
5023
// Align embedded objects to baseline.
5024
_realign(sd);
5025
5026
sd->valid.set();
5027
return sd->valid.is_set();
5028
}
5029
5030
bool TextServerFallback::_shaped_text_is_ready(const RID &p_shaped) const {
5031
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
5032
ERR_FAIL_NULL_V(sd, false);
5033
5034
return sd->valid.is_set();
5035
}
5036
5037
const Glyph *TextServerFallback::_shaped_text_get_glyphs(const RID &p_shaped) const {
5038
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
5039
ERR_FAIL_NULL_V(sd, nullptr);
5040
5041
MutexLock lock(sd->mutex);
5042
if (!sd->valid.is_set()) {
5043
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
5044
}
5045
return sd->glyphs.ptr();
5046
}
5047
5048
int64_t TextServerFallback::_shaped_text_get_glyph_count(const RID &p_shaped) const {
5049
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
5050
ERR_FAIL_NULL_V(sd, 0);
5051
5052
MutexLock lock(sd->mutex);
5053
if (!sd->valid.is_set()) {
5054
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
5055
}
5056
return sd->glyphs.size();
5057
}
5058
5059
const Glyph *TextServerFallback::_shaped_text_sort_logical(const RID &p_shaped) {
5060
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
5061
ERR_FAIL_NULL_V(sd, nullptr);
5062
5063
MutexLock lock(sd->mutex);
5064
if (!sd->valid.is_set()) {
5065
_shaped_text_shape(p_shaped);
5066
}
5067
5068
return sd->glyphs.ptr(); // Already in the logical order, return as is.
5069
}
5070
5071
Vector2i TextServerFallback::_shaped_text_get_range(const RID &p_shaped) const {
5072
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
5073
ERR_FAIL_NULL_V(sd, Vector2i());
5074
5075
MutexLock lock(sd->mutex);
5076
return Vector2(sd->start, sd->end);
5077
}
5078
5079
Array TextServerFallback::_shaped_text_get_objects(const RID &p_shaped) const {
5080
Array ret;
5081
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
5082
ERR_FAIL_NULL_V(sd, ret);
5083
5084
MutexLock lock(sd->mutex);
5085
for (const KeyValue<Variant, ShapedTextDataFallback::EmbeddedObject> &E : sd->objects) {
5086
ret.push_back(E.key);
5087
}
5088
5089
return ret;
5090
}
5091
5092
Rect2 TextServerFallback::_shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const {
5093
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
5094
ERR_FAIL_NULL_V(sd, Rect2());
5095
5096
MutexLock lock(sd->mutex);
5097
ERR_FAIL_COND_V(!sd->objects.has(p_key), Rect2());
5098
if (!sd->valid.is_set()) {
5099
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
5100
}
5101
return sd->objects[p_key].rect;
5102
}
5103
5104
Vector2i TextServerFallback::_shaped_text_get_object_range(const RID &p_shaped, const Variant &p_key) const {
5105
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
5106
ERR_FAIL_NULL_V(sd, Vector2i());
5107
5108
MutexLock lock(sd->mutex);
5109
ERR_FAIL_COND_V(!sd->objects.has(p_key), Vector2i());
5110
return Vector2i(sd->objects[p_key].start, sd->objects[p_key].end);
5111
}
5112
5113
int64_t TextServerFallback::_shaped_text_get_object_glyph(const RID &p_shaped, const Variant &p_key) const {
5114
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
5115
ERR_FAIL_NULL_V(sd, -1);
5116
5117
MutexLock lock(sd->mutex);
5118
ERR_FAIL_COND_V(!sd->objects.has(p_key), -1);
5119
const ShapedTextDataFallback::EmbeddedObject &obj = sd->objects[p_key];
5120
int sd_size = sd->glyphs.size();
5121
const Glyph *sd_glyphs = sd->glyphs.ptr();
5122
for (int i = 0; i < sd_size; i++) {
5123
if (obj.start == sd_glyphs[i].start) {
5124
return i;
5125
}
5126
}
5127
return -1;
5128
}
5129
5130
Size2 TextServerFallback::_shaped_text_get_size(const RID &p_shaped) const {
5131
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
5132
ERR_FAIL_NULL_V(sd, Size2());
5133
5134
MutexLock lock(sd->mutex);
5135
if (!sd->valid.is_set()) {
5136
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
5137
}
5138
if (sd->orientation == TextServer::ORIENTATION_HORIZONTAL) {
5139
return Size2(sd->width, sd->ascent + sd->descent + sd->extra_spacing[SPACING_TOP] + sd->extra_spacing[SPACING_BOTTOM]).ceil();
5140
} else {
5141
return Size2(sd->ascent + sd->descent + sd->extra_spacing[SPACING_TOP] + sd->extra_spacing[SPACING_BOTTOM], sd->width).ceil();
5142
}
5143
}
5144
5145
double TextServerFallback::_shaped_text_get_ascent(const RID &p_shaped) const {
5146
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
5147
ERR_FAIL_NULL_V(sd, 0.0);
5148
5149
MutexLock lock(sd->mutex);
5150
if (!sd->valid.is_set()) {
5151
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
5152
}
5153
return sd->ascent + sd->extra_spacing[SPACING_TOP];
5154
}
5155
5156
double TextServerFallback::_shaped_text_get_descent(const RID &p_shaped) const {
5157
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
5158
ERR_FAIL_NULL_V(sd, 0.0);
5159
5160
MutexLock lock(sd->mutex);
5161
if (!sd->valid.is_set()) {
5162
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
5163
}
5164
return sd->descent + sd->extra_spacing[SPACING_BOTTOM];
5165
}
5166
5167
double TextServerFallback::_shaped_text_get_width(const RID &p_shaped) const {
5168
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
5169
ERR_FAIL_NULL_V(sd, 0.0);
5170
5171
MutexLock lock(sd->mutex);
5172
if (!sd->valid.is_set()) {
5173
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
5174
}
5175
return Math::ceil(sd->width);
5176
}
5177
5178
double TextServerFallback::_shaped_text_get_underline_position(const RID &p_shaped) const {
5179
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
5180
ERR_FAIL_NULL_V(sd, 0.0);
5181
5182
MutexLock lock(sd->mutex);
5183
if (!sd->valid.is_set()) {
5184
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
5185
}
5186
5187
return sd->upos;
5188
}
5189
5190
double TextServerFallback::_shaped_text_get_underline_thickness(const RID &p_shaped) const {
5191
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
5192
ERR_FAIL_NULL_V(sd, 0.0);
5193
5194
MutexLock lock(sd->mutex);
5195
if (!sd->valid.is_set()) {
5196
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
5197
}
5198
5199
return sd->uthk;
5200
}
5201
5202
PackedInt32Array TextServerFallback::_shaped_text_get_character_breaks(const RID &p_shaped) const {
5203
const ShapedTextDataFallback *sd = shaped_owner.get_or_null(p_shaped);
5204
ERR_FAIL_NULL_V(sd, PackedInt32Array());
5205
5206
MutexLock lock(sd->mutex);
5207
if (!sd->valid.is_set()) {
5208
const_cast<TextServerFallback *>(this)->_shaped_text_shape(p_shaped);
5209
}
5210
5211
PackedInt32Array ret;
5212
int size = sd->end - sd->start;
5213
if (size > 0) {
5214
ret.resize(size);
5215
for (int i = 0; i < size; i++) {
5216
#ifdef GDEXTENSION
5217
ret[i] = i + 1 + sd->start;
5218
#else
5219
ret.write[i] = i + 1 + sd->start;
5220
#endif
5221
}
5222
}
5223
return ret;
5224
}
5225
5226
String TextServerFallback::_string_to_upper(const String &p_string, const String &p_language) const {
5227
return p_string.to_upper();
5228
}
5229
5230
String TextServerFallback::_string_to_lower(const String &p_string, const String &p_language) const {
5231
return p_string.to_lower();
5232
}
5233
5234
String TextServerFallback::_string_to_title(const String &p_string, const String &p_language) const {
5235
return p_string.capitalize();
5236
}
5237
5238
PackedInt32Array TextServerFallback::_string_get_word_breaks(const String &p_string, const String &p_language, int64_t p_chars_per_line) const {
5239
PackedInt32Array ret;
5240
5241
if (p_chars_per_line > 0) {
5242
int line_start = 0;
5243
int last_break = -1;
5244
int line_length = 0;
5245
5246
for (int i = 0; i < p_string.length(); i++) {
5247
const char32_t c = p_string[i];
5248
5249
bool is_lb = is_linebreak(c);
5250
bool is_ws = is_whitespace(c);
5251
bool is_p = (is_punct(c) && c != 0x005F) || is_underscore(c) || c == '\t' || c == 0xfffc;
5252
5253
if (is_lb) {
5254
if (line_length > 0) {
5255
ret.push_back(line_start);
5256
ret.push_back(i);
5257
}
5258
line_start = i;
5259
line_length = 0;
5260
last_break = -1;
5261
continue;
5262
} else if (is_ws || is_p) {
5263
last_break = i;
5264
}
5265
5266
if (line_length == p_chars_per_line) {
5267
if (last_break != -1) {
5268
int last_break_w_spaces = last_break;
5269
while (last_break > line_start && is_whitespace(p_string[last_break - 1])) {
5270
last_break--;
5271
}
5272
if (line_start != last_break) {
5273
ret.push_back(line_start);
5274
ret.push_back(last_break);
5275
}
5276
while (last_break_w_spaces < p_string.length() && is_whitespace(p_string[last_break_w_spaces])) {
5277
last_break_w_spaces++;
5278
}
5279
line_start = last_break_w_spaces;
5280
if (last_break_w_spaces < i) {
5281
line_length = i - last_break_w_spaces;
5282
} else {
5283
i = last_break_w_spaces;
5284
line_length = 0;
5285
}
5286
} else {
5287
ret.push_back(line_start);
5288
ret.push_back(i);
5289
line_start = i;
5290
line_length = 0;
5291
}
5292
last_break = -1;
5293
}
5294
line_length++;
5295
}
5296
if (line_length > 0) {
5297
ret.push_back(line_start);
5298
ret.push_back(p_string.length());
5299
}
5300
} else {
5301
int word_start = 0; // -1 if no word encountered. Leading spaces are part of a word.
5302
int word_length = 0;
5303
5304
for (int i = 0; i < p_string.length(); i++) {
5305
const char32_t c = p_string[i];
5306
5307
bool is_lb = is_linebreak(c);
5308
bool is_ws = is_whitespace(c);
5309
bool is_p = (is_punct(c) && c != 0x005F) || is_underscore(c) || c == '\t' || c == 0xfffc;
5310
5311
if (word_start == -1) {
5312
if (!is_lb && !is_ws && !is_p) {
5313
word_start = i;
5314
}
5315
continue;
5316
}
5317
5318
if (is_lb) {
5319
if (word_start != -1 && word_length > 0) {
5320
ret.push_back(word_start);
5321
ret.push_back(i);
5322
}
5323
word_start = -1;
5324
word_length = 0;
5325
} else if (is_ws || is_p) {
5326
if (word_start != -1 && word_length > 0) {
5327
ret.push_back(word_start);
5328
ret.push_back(i);
5329
}
5330
word_start = -1;
5331
word_length = 0;
5332
}
5333
5334
word_length++;
5335
}
5336
if (word_start != -1 && word_length > 0) {
5337
ret.push_back(word_start);
5338
ret.push_back(p_string.length());
5339
}
5340
}
5341
return ret;
5342
}
5343
5344
void TextServerFallback::_update_settings() {
5345
lcd_subpixel_layout.set((TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout"));
5346
}
5347
5348
TextServerFallback::TextServerFallback() {
5349
_insert_feature_sets();
5350
ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &TextServerFallback::_update_settings));
5351
}
5352
5353
void TextServerFallback::_font_clear_system_fallback_cache() {
5354
for (const KeyValue<SystemFontKey, SystemFontCache> &E : system_fonts) {
5355
const Vector<SystemFontCacheRec> &sysf_cache = E.value.var;
5356
for (const SystemFontCacheRec &F : sysf_cache) {
5357
_free_rid(F.rid);
5358
}
5359
}
5360
system_fonts.clear();
5361
system_font_data.clear();
5362
}
5363
5364
void TextServerFallback::_cleanup() {
5365
font_clear_system_fallback_cache();
5366
}
5367
5368
TextServerFallback::~TextServerFallback() {
5369
#ifdef MODULE_FREETYPE_ENABLED
5370
if (ft_library != nullptr) {
5371
FT_Done_FreeType(ft_library);
5372
}
5373
#endif
5374
}
5375
5376