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