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