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