1/**************************************************************************/
2/* font.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 "font.h"
32#include "font.compat.inc"
33
34#include "core/io/image_loader.h"
35#include "core/io/resource_loader.h"
36#include "core/string/translation.h"
37#include "core/templates/hash_map.h"
38#include "core/templates/hashfuncs.h"
39#include "scene/resources/image_texture.h"
40#include "scene/resources/text_line.h"
41#include "scene/resources/text_paragraph.h"
42#include "scene/resources/theme.h"
43#include "scene/theme/theme_db.h"
44
45/*************************************************************************/
46/* Font */
47/*************************************************************************/
48
49void Font::_bind_methods() {
50 ClassDB::bind_method(D_METHOD("set_fallbacks", "fallbacks"), &Font::set_fallbacks);
51 ClassDB::bind_method(D_METHOD("get_fallbacks"), &Font::get_fallbacks);
52
53 // Output.
54 ClassDB::bind_method(D_METHOD("find_variation", "variation_coordinates", "face_index", "strength", "transform", "spacing_top", "spacing_bottom", "spacing_space", "spacing_glyph"), &Font::find_variation, DEFVAL(0), DEFVAL(0.0), DEFVAL(Transform2D()), DEFVAL(0), DEFVAL(0), DEFVAL(0), DEFVAL(0));
55 ClassDB::bind_method(D_METHOD("get_rids"), &Font::get_rids);
56
57 // Font metrics.
58 ClassDB::bind_method(D_METHOD("get_height", "font_size"), &Font::get_height, DEFVAL(DEFAULT_FONT_SIZE));
59 ClassDB::bind_method(D_METHOD("get_ascent", "font_size"), &Font::get_ascent, DEFVAL(DEFAULT_FONT_SIZE));
60 ClassDB::bind_method(D_METHOD("get_descent", "font_size"), &Font::get_descent, DEFVAL(DEFAULT_FONT_SIZE));
61 ClassDB::bind_method(D_METHOD("get_underline_position", "font_size"), &Font::get_underline_position, DEFVAL(DEFAULT_FONT_SIZE));
62 ClassDB::bind_method(D_METHOD("get_underline_thickness", "font_size"), &Font::get_underline_thickness, DEFVAL(DEFAULT_FONT_SIZE));
63
64 ClassDB::bind_method(D_METHOD("get_font_name"), &Font::get_font_name);
65 ClassDB::bind_method(D_METHOD("get_font_style_name"), &Font::get_font_style_name);
66 ClassDB::bind_method(D_METHOD("get_ot_name_strings"), &Font::get_ot_name_strings);
67 ClassDB::bind_method(D_METHOD("get_font_style"), &Font::get_font_style);
68 ClassDB::bind_method(D_METHOD("get_font_weight"), &Font::get_font_weight);
69 ClassDB::bind_method(D_METHOD("get_font_stretch"), &Font::get_font_stretch);
70
71 ClassDB::bind_method(D_METHOD("get_spacing", "spacing"), &Font::get_spacing);
72 ClassDB::bind_method(D_METHOD("get_opentype_features"), &Font::get_opentype_features);
73
74 // Drawing string.
75 ClassDB::bind_method(D_METHOD("set_cache_capacity", "single_line", "multi_line"), &Font::set_cache_capacity);
76
77 ClassDB::bind_method(D_METHOD("get_string_size", "text", "alignment", "width", "font_size", "justification_flags", "direction", "orientation"), &Font::get_string_size, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
78 ClassDB::bind_method(D_METHOD("get_multiline_string_size", "text", "alignment", "width", "font_size", "max_lines", "brk_flags", "justification_flags", "direction", "orientation"), &Font::get_multiline_string_size, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(-1), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
79
80 ClassDB::bind_method(D_METHOD("draw_string", "canvas_item", "pos", "text", "alignment", "width", "font_size", "modulate", "justification_flags", "direction", "orientation"), &Font::draw_string, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
81 ClassDB::bind_method(D_METHOD("draw_multiline_string", "canvas_item", "pos", "text", "alignment", "width", "font_size", "max_lines", "modulate", "brk_flags", "justification_flags", "direction", "orientation"), &Font::draw_multiline_string, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(-1), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
82
83 ClassDB::bind_method(D_METHOD("draw_string_outline", "canvas_item", "pos", "text", "alignment", "width", "font_size", "size", "modulate", "justification_flags", "direction", "orientation"), &Font::draw_string_outline, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(1), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
84 ClassDB::bind_method(D_METHOD("draw_multiline_string_outline", "canvas_item", "pos", "text", "alignment", "width", "font_size", "max_lines", "size", "modulate", "brk_flags", "justification_flags", "direction", "orientation"), &Font::draw_multiline_string_outline, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(DEFAULT_FONT_SIZE), DEFVAL(-1), DEFVAL(1), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
85
86 // Drawing char.
87 ClassDB::bind_method(D_METHOD("get_char_size", "char", "font_size"), &Font::get_char_size);
88 ClassDB::bind_method(D_METHOD("draw_char", "canvas_item", "pos", "char", "font_size", "modulate"), &Font::draw_char, DEFVAL(Color(1.0, 1.0, 1.0)));
89 ClassDB::bind_method(D_METHOD("draw_char_outline", "canvas_item", "pos", "char", "font_size", "size", "modulate"), &Font::draw_char_outline, DEFVAL(-1), DEFVAL(Color(1.0, 1.0, 1.0)));
90
91 // Helper functions.
92 ClassDB::bind_method(D_METHOD("has_char", "char"), &Font::has_char);
93 ClassDB::bind_method(D_METHOD("get_supported_chars"), &Font::get_supported_chars);
94
95 ClassDB::bind_method(D_METHOD("is_language_supported", "language"), &Font::is_language_supported);
96 ClassDB::bind_method(D_METHOD("is_script_supported", "script"), &Font::is_script_supported);
97
98 ClassDB::bind_method(D_METHOD("get_supported_feature_list"), &Font::get_supported_feature_list);
99 ClassDB::bind_method(D_METHOD("get_supported_variation_list"), &Font::get_supported_variation_list);
100 ClassDB::bind_method(D_METHOD("get_face_count"), &Font::get_face_count);
101
102 ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("Font")), "set_fallbacks", "get_fallbacks");
103}
104
105void Font::_update_rids_fb(const Ref<Font> &p_f, int p_depth) const {
106 ERR_FAIL_COND(p_depth > MAX_FALLBACK_DEPTH);
107 if (p_f.is_valid()) {
108 RID rid = p_f->_get_rid();
109 if (rid.is_valid()) {
110 rids.push_back(rid);
111 }
112 const TypedArray<Font> &_fallbacks = p_f->get_fallbacks();
113 for (int i = 0; i < _fallbacks.size(); i++) {
114 _update_rids_fb(_fallbacks[i], p_depth + 1);
115 }
116 }
117}
118
119void Font::_update_rids() const {
120 rids.clear();
121 _update_rids_fb(const_cast<Font *>(this), 0);
122 dirty_rids = false;
123}
124
125void Font::_invalidate_rids() {
126 rids.clear();
127 dirty_rids = true;
128
129 cache.clear();
130 cache_wrap.clear();
131
132 emit_changed();
133}
134
135bool Font::_is_cyclic(const Ref<Font> &p_f, int p_depth) const {
136 ERR_FAIL_COND_V(p_depth > MAX_FALLBACK_DEPTH, true);
137 if (p_f.is_null()) {
138 return false;
139 }
140 if (p_f == this) {
141 return true;
142 }
143 for (int i = 0; i < p_f->fallbacks.size(); i++) {
144 const Ref<Font> &f = p_f->fallbacks[i];
145 if (_is_cyclic(f, p_depth + 1)) {
146 return true;
147 }
148 }
149 return false;
150}
151
152void Font::reset_state() {
153 _invalidate_rids();
154}
155
156// Fallbacks.
157void Font::set_fallbacks(const TypedArray<Font> &p_fallbacks) {
158 for (int i = 0; i < p_fallbacks.size(); i++) {
159 const Ref<Font> &f = p_fallbacks[i];
160 ERR_FAIL_COND_MSG(_is_cyclic(f, 0), "Cyclic font fallback.");
161 }
162 for (int i = 0; i < fallbacks.size(); i++) {
163 Ref<Font> f = fallbacks[i];
164 if (f.is_valid()) {
165 f->disconnect_changed(callable_mp(this, &Font::_invalidate_rids));
166 }
167 }
168 fallbacks = p_fallbacks;
169 for (int i = 0; i < fallbacks.size(); i++) {
170 Ref<Font> f = fallbacks[i];
171 if (f.is_valid()) {
172 f->connect_changed(callable_mp(this, &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
173 }
174 }
175 _invalidate_rids();
176}
177
178TypedArray<Font> Font::get_fallbacks() const {
179 return fallbacks;
180}
181
182// Output.
183TypedArray<RID> Font::get_rids() const {
184 if (dirty_rids) {
185 _update_rids();
186 }
187 return rids;
188}
189
190// Drawing string.
191real_t Font::get_height(int p_font_size) const {
192 if (dirty_rids) {
193 _update_rids();
194 }
195 real_t ret = 0.f;
196 for (int i = 0; i < rids.size(); i++) {
197 ret = MAX(ret, TS->font_get_ascent(rids[i], p_font_size) + TS->font_get_descent(rids[i], p_font_size));
198 }
199 return ret + get_spacing(TextServer::SPACING_BOTTOM) + get_spacing(TextServer::SPACING_TOP);
200}
201
202real_t Font::get_ascent(int p_font_size) const {
203 if (dirty_rids) {
204 _update_rids();
205 }
206 real_t ret = 0.f;
207 for (int i = 0; i < rids.size(); i++) {
208 ret = MAX(ret, TS->font_get_ascent(rids[i], p_font_size));
209 }
210 return ret + get_spacing(TextServer::SPACING_TOP);
211}
212
213real_t Font::get_descent(int p_font_size) const {
214 if (dirty_rids) {
215 _update_rids();
216 }
217 real_t ret = 0.f;
218 for (int i = 0; i < rids.size(); i++) {
219 ret = MAX(ret, TS->font_get_descent(rids[i], p_font_size));
220 }
221 return ret + get_spacing(TextServer::SPACING_BOTTOM);
222}
223
224real_t Font::get_underline_position(int p_font_size) const {
225 if (dirty_rids) {
226 _update_rids();
227 }
228 real_t ret = 0.f;
229 for (int i = 0; i < rids.size(); i++) {
230 ret = MAX(ret, TS->font_get_underline_position(rids[i], p_font_size));
231 }
232 return ret + get_spacing(TextServer::SPACING_TOP);
233}
234
235real_t Font::get_underline_thickness(int p_font_size) const {
236 if (dirty_rids) {
237 _update_rids();
238 }
239 real_t ret = 0.f;
240 for (int i = 0; i < rids.size(); i++) {
241 ret = MAX(ret, TS->font_get_underline_thickness(rids[i], p_font_size));
242 }
243 return ret;
244}
245
246String Font::get_font_name() const {
247 return TS->font_get_name(_get_rid());
248}
249
250Dictionary Font::get_ot_name_strings() const {
251 return TS->font_get_ot_name_strings(_get_rid());
252}
253
254String Font::get_font_style_name() const {
255 return TS->font_get_style_name(_get_rid());
256}
257
258BitField<TextServer::FontStyle> Font::get_font_style() const {
259 return TS->font_get_style(_get_rid());
260}
261
262int Font::get_font_weight() const {
263 return TS->font_get_weight(_get_rid());
264}
265
266int Font::get_font_stretch() const {
267 return TS->font_get_stretch(_get_rid());
268}
269
270Dictionary Font::get_opentype_features() const {
271 return Dictionary();
272}
273
274// Drawing string.
275void Font::set_cache_capacity(int p_single_line, int p_multi_line) {
276 cache.set_capacity(p_single_line);
277 cache_wrap.set_capacity(p_multi_line);
278}
279
280Size2 Font::get_string_size(const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
281 bool fill = (p_alignment == HORIZONTAL_ALIGNMENT_FILL);
282 ShapedTextKey key = ShapedTextKey(p_text, p_font_size, fill ? p_width : 0.0, fill ? p_jst_flags : TextServer::JUSTIFICATION_NONE, TextServer::BREAK_NONE, p_direction, p_orientation);
283
284 Ref<TextLine> buffer;
285 if (cache.has(key)) {
286 buffer = cache.get(key);
287 } else {
288 buffer.instantiate();
289 buffer->set_direction(p_direction);
290 buffer->set_orientation(p_orientation);
291 buffer->add_string(p_text, Ref<Font>(this), p_font_size);
292 cache.insert(key, buffer);
293 }
294
295 buffer->set_width(p_width);
296 buffer->set_horizontal_alignment(p_alignment);
297 if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
298 buffer->set_flags(p_jst_flags);
299 }
300
301 return buffer->get_size();
302}
303
304Size2 Font::get_multiline_string_size(const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
305 ShapedTextKey key = ShapedTextKey(p_text, p_font_size, p_width, p_jst_flags, p_brk_flags, p_direction, p_orientation);
306
307 Ref<TextParagraph> lines_buffer;
308 if (cache_wrap.has(key)) {
309 lines_buffer = cache_wrap.get(key);
310 } else {
311 lines_buffer.instantiate();
312 lines_buffer->set_direction(p_direction);
313 lines_buffer->set_orientation(p_orientation);
314 lines_buffer->add_string(p_text, Ref<Font>(this), p_font_size);
315 lines_buffer->set_width(p_width);
316 lines_buffer->set_break_flags(p_brk_flags);
317 lines_buffer->set_justification_flags(p_jst_flags);
318 cache_wrap.insert(key, lines_buffer);
319 }
320
321 lines_buffer->set_alignment(p_alignment);
322 lines_buffer->set_max_lines_visible(p_max_lines);
323
324 return lines_buffer->get_size();
325}
326
327void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
328 bool fill = (p_alignment == HORIZONTAL_ALIGNMENT_FILL);
329 ShapedTextKey key = ShapedTextKey(p_text, p_font_size, fill ? p_width : 0.0, fill ? p_jst_flags : TextServer::JUSTIFICATION_NONE, TextServer::BREAK_NONE, p_direction, p_orientation);
330
331 Ref<TextLine> buffer;
332 if (cache.has(key)) {
333 buffer = cache.get(key);
334 } else {
335 buffer.instantiate();
336 buffer->set_direction(p_direction);
337 buffer->set_orientation(p_orientation);
338 buffer->add_string(p_text, Ref<Font>(this), p_font_size);
339 cache.insert(key, buffer);
340 }
341
342 Vector2 ofs = p_pos;
343 if (p_orientation == TextServer::ORIENTATION_HORIZONTAL) {
344 ofs.y -= buffer->get_line_ascent();
345 } else {
346 ofs.x -= buffer->get_line_ascent();
347 }
348
349 buffer->set_width(p_width);
350 buffer->set_horizontal_alignment(p_alignment);
351 if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
352 buffer->set_flags(p_jst_flags);
353 }
354
355 buffer->draw(p_canvas_item, ofs, p_modulate);
356}
357
358void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
359 ShapedTextKey key = ShapedTextKey(p_text, p_font_size, p_width, p_jst_flags, p_brk_flags, p_direction, p_orientation);
360
361 Ref<TextParagraph> lines_buffer;
362 if (cache_wrap.has(key)) {
363 lines_buffer = cache_wrap.get(key);
364 } else {
365 lines_buffer.instantiate();
366 lines_buffer->set_direction(p_direction);
367 lines_buffer->set_orientation(p_orientation);
368 lines_buffer->add_string(p_text, Ref<Font>(this), p_font_size);
369 lines_buffer->set_width(p_width);
370 lines_buffer->set_break_flags(p_brk_flags);
371 lines_buffer->set_justification_flags(p_jst_flags);
372 cache_wrap.insert(key, lines_buffer);
373 }
374
375 Vector2 ofs = p_pos;
376 if (p_orientation == TextServer::ORIENTATION_HORIZONTAL) {
377 ofs.y -= lines_buffer->get_line_ascent(0);
378 } else {
379 ofs.x -= lines_buffer->get_line_ascent(0);
380 }
381
382 lines_buffer->set_alignment(p_alignment);
383 lines_buffer->set_max_lines_visible(p_max_lines);
384
385 lines_buffer->draw(p_canvas_item, ofs, p_modulate);
386}
387
388void Font::draw_string_outline(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
389 bool fill = (p_alignment == HORIZONTAL_ALIGNMENT_FILL);
390 ShapedTextKey key = ShapedTextKey(p_text, p_font_size, fill ? p_width : 0.0, fill ? p_jst_flags : TextServer::JUSTIFICATION_NONE, TextServer::BREAK_NONE, p_direction, p_orientation);
391
392 Ref<TextLine> buffer;
393 if (cache.has(key)) {
394 buffer = cache.get(key);
395 } else {
396 buffer.instantiate();
397 buffer->set_direction(p_direction);
398 buffer->set_orientation(p_orientation);
399 buffer->add_string(p_text, Ref<Font>(this), p_font_size);
400 cache.insert(key, buffer);
401 }
402
403 Vector2 ofs = p_pos;
404 if (p_orientation == TextServer::ORIENTATION_HORIZONTAL) {
405 ofs.y -= buffer->get_line_ascent();
406 } else {
407 ofs.x -= buffer->get_line_ascent();
408 }
409
410 buffer->set_width(p_width);
411 buffer->set_horizontal_alignment(p_alignment);
412 if (p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
413 buffer->set_flags(p_jst_flags);
414 }
415
416 buffer->draw_outline(p_canvas_item, ofs, p_size, p_modulate);
417}
418
419void Font::draw_multiline_string_outline(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, int p_size, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
420 ShapedTextKey key = ShapedTextKey(p_text, p_font_size, p_width, p_jst_flags, p_brk_flags, p_direction, p_orientation);
421
422 Ref<TextParagraph> lines_buffer;
423 if (cache_wrap.has(key)) {
424 lines_buffer = cache_wrap.get(key);
425 } else {
426 lines_buffer.instantiate();
427 lines_buffer->set_direction(p_direction);
428 lines_buffer->set_orientation(p_orientation);
429 lines_buffer->add_string(p_text, Ref<Font>(this), p_font_size);
430 lines_buffer->set_width(p_width);
431 lines_buffer->set_break_flags(p_brk_flags);
432 lines_buffer->set_justification_flags(p_jst_flags);
433 cache_wrap.insert(key, lines_buffer);
434 }
435
436 Vector2 ofs = p_pos;
437 if (p_orientation == TextServer::ORIENTATION_HORIZONTAL) {
438 ofs.y -= lines_buffer->get_line_ascent(0);
439 } else {
440 ofs.x -= lines_buffer->get_line_ascent(0);
441 }
442
443 lines_buffer->set_alignment(p_alignment);
444 lines_buffer->set_max_lines_visible(p_max_lines);
445
446 lines_buffer->draw_outline(p_canvas_item, ofs, p_size, p_modulate);
447}
448
449// Drawing char.
450Size2 Font::get_char_size(char32_t p_char, int p_font_size) const {
451 if (dirty_rids) {
452 _update_rids();
453 }
454 for (int i = 0; i < rids.size(); i++) {
455 if (TS->font_has_char(rids[i], p_char)) {
456 int32_t glyph = TS->font_get_glyph_index(rids[i], p_font_size, p_char, 0);
457 return Size2(TS->font_get_glyph_advance(rids[i], p_font_size, glyph).x, get_height(p_font_size));
458 }
459 }
460 return Size2();
461}
462
463real_t Font::draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, int p_font_size, const Color &p_modulate) const {
464 if (dirty_rids) {
465 _update_rids();
466 }
467 for (int i = 0; i < rids.size(); i++) {
468 if (TS->font_has_char(rids[i], p_char)) {
469 int32_t glyph = TS->font_get_glyph_index(rids[i], p_font_size, p_char, 0);
470 TS->font_draw_glyph(rids[i], p_canvas_item, p_font_size, p_pos, glyph, p_modulate);
471 return TS->font_get_glyph_advance(rids[i], p_font_size, glyph).x;
472 }
473 }
474 return 0.f;
475}
476
477real_t Font::draw_char_outline(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, int p_font_size, int p_size, const Color &p_modulate) const {
478 if (dirty_rids) {
479 _update_rids();
480 }
481 for (int i = 0; i < rids.size(); i++) {
482 if (TS->font_has_char(rids[i], p_char)) {
483 int32_t glyph = TS->font_get_glyph_index(rids[i], p_font_size, p_char, 0);
484 TS->font_draw_glyph_outline(rids[i], p_canvas_item, p_font_size, p_size, p_pos, glyph, p_modulate);
485 return TS->font_get_glyph_advance(rids[i], p_font_size, glyph).x;
486 }
487 }
488 return 0.f;
489}
490
491// Helper functions.
492bool Font::has_char(char32_t p_char) const {
493 if (dirty_rids) {
494 _update_rids();
495 }
496 for (int i = 0; i < rids.size(); i++) {
497 if (TS->font_has_char(rids[i], p_char)) {
498 return true;
499 }
500 }
501 return false;
502}
503
504String Font::get_supported_chars() const {
505 if (dirty_rids) {
506 _update_rids();
507 }
508 String chars;
509 for (int i = 0; i < rids.size(); i++) {
510 String data_chars = TS->font_get_supported_chars(rids[i]);
511 for (int j = 0; j < data_chars.length(); j++) {
512 if (chars.find_char(data_chars[j]) == -1) {
513 chars += data_chars[j];
514 }
515 }
516 }
517 return chars;
518}
519
520bool Font::is_language_supported(const String &p_language) const {
521 return TS->font_is_language_supported(_get_rid(), p_language);
522}
523
524bool Font::is_script_supported(const String &p_script) const {
525 return TS->font_is_script_supported(_get_rid(), p_script);
526}
527
528Dictionary Font::get_supported_feature_list() const {
529 return TS->font_supported_feature_list(_get_rid());
530}
531
532Dictionary Font::get_supported_variation_list() const {
533 return TS->font_supported_variation_list(_get_rid());
534}
535
536int64_t Font::get_face_count() const {
537 return TS->font_get_face_count(_get_rid());
538}
539
540Font::Font() {
541 cache.set_capacity(64);
542 cache_wrap.set_capacity(16);
543}
544
545Font::~Font() {
546}
547
548/*************************************************************************/
549/* FontFile */
550/*************************************************************************/
551
552_FORCE_INLINE_ void FontFile::_clear_cache() {
553 for (int i = 0; i < cache.size(); i++) {
554 if (cache[i].is_valid()) {
555 TS->free_rid(cache[i]);
556 cache.write[i] = RID();
557 }
558 }
559}
560
561_FORCE_INLINE_ void FontFile::_ensure_rid(int p_cache_index) const {
562 if (unlikely(p_cache_index >= cache.size())) {
563 cache.resize(p_cache_index + 1);
564 }
565 if (unlikely(!cache[p_cache_index].is_valid())) {
566 cache.write[p_cache_index] = TS->create_font();
567 TS->font_set_data_ptr(cache[p_cache_index], data_ptr, data_size);
568 TS->font_set_antialiasing(cache[p_cache_index], antialiasing);
569 TS->font_set_generate_mipmaps(cache[p_cache_index], mipmaps);
570 TS->font_set_multichannel_signed_distance_field(cache[p_cache_index], msdf);
571 TS->font_set_msdf_pixel_range(cache[p_cache_index], msdf_pixel_range);
572 TS->font_set_msdf_size(cache[p_cache_index], msdf_size);
573 TS->font_set_fixed_size(cache[p_cache_index], fixed_size);
574 TS->font_set_force_autohinter(cache[p_cache_index], force_autohinter);
575 TS->font_set_allow_system_fallback(cache[p_cache_index], allow_system_fallback);
576 TS->font_set_hinting(cache[p_cache_index], hinting);
577 TS->font_set_subpixel_positioning(cache[p_cache_index], subpixel_positioning);
578 TS->font_set_oversampling(cache[p_cache_index], oversampling);
579 }
580}
581
582void FontFile::_convert_packed_8bit(Ref<Image> &p_source, int p_page, int p_sz) {
583 int w = p_source->get_width();
584 int h = p_source->get_height();
585
586 PackedByteArray imgdata = p_source->get_data();
587 const uint8_t *r = imgdata.ptr();
588
589 PackedByteArray imgdata_r;
590 imgdata_r.resize(w * h * 2);
591 uint8_t *wr = imgdata_r.ptrw();
592
593 PackedByteArray imgdata_g;
594 imgdata_g.resize(w * h * 2);
595 uint8_t *wg = imgdata_g.ptrw();
596
597 PackedByteArray imgdata_b;
598 imgdata_b.resize(w * h * 2);
599 uint8_t *wb = imgdata_b.ptrw();
600
601 PackedByteArray imgdata_a;
602 imgdata_a.resize(w * h * 2);
603 uint8_t *wa = imgdata_a.ptrw();
604
605 for (int i = 0; i < h; i++) {
606 for (int j = 0; j < w; j++) {
607 int ofs_src = (i * w + j) * 4;
608 int ofs_dst = (i * w + j) * 2;
609 wr[ofs_dst + 0] = 255;
610 wr[ofs_dst + 1] = r[ofs_src + 0];
611 wg[ofs_dst + 0] = 255;
612 wg[ofs_dst + 1] = r[ofs_src + 1];
613 wb[ofs_dst + 0] = 255;
614 wb[ofs_dst + 1] = r[ofs_src + 2];
615 wa[ofs_dst + 0] = 255;
616 wa[ofs_dst + 1] = r[ofs_src + 3];
617 }
618 }
619 Ref<Image> img_r = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_r));
620 set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 0, img_r);
621 Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_g));
622 set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 1, img_g);
623 Ref<Image> img_b = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_b));
624 set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 2, img_b);
625 Ref<Image> img_a = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_a));
626 set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 3, img_a);
627}
628
629void FontFile::_convert_packed_4bit(Ref<Image> &p_source, int p_page, int p_sz) {
630 int w = p_source->get_width();
631 int h = p_source->get_height();
632
633 PackedByteArray imgdata = p_source->get_data();
634 const uint8_t *r = imgdata.ptr();
635
636 PackedByteArray imgdata_r;
637 imgdata_r.resize(w * h * 2);
638 uint8_t *wr = imgdata_r.ptrw();
639
640 PackedByteArray imgdata_g;
641 imgdata_g.resize(w * h * 2);
642 uint8_t *wg = imgdata_g.ptrw();
643
644 PackedByteArray imgdata_b;
645 imgdata_b.resize(w * h * 2);
646 uint8_t *wb = imgdata_b.ptrw();
647
648 PackedByteArray imgdata_a;
649 imgdata_a.resize(w * h * 2);
650 uint8_t *wa = imgdata_a.ptrw();
651
652 PackedByteArray imgdata_ro;
653 imgdata_ro.resize(w * h * 2);
654 uint8_t *wro = imgdata_ro.ptrw();
655
656 PackedByteArray imgdata_go;
657 imgdata_go.resize(w * h * 2);
658 uint8_t *wgo = imgdata_go.ptrw();
659
660 PackedByteArray imgdata_bo;
661 imgdata_bo.resize(w * h * 2);
662 uint8_t *wbo = imgdata_bo.ptrw();
663
664 PackedByteArray imgdata_ao;
665 imgdata_ao.resize(w * h * 2);
666 uint8_t *wao = imgdata_ao.ptrw();
667
668 for (int i = 0; i < h; i++) {
669 for (int j = 0; j < w; j++) {
670 int ofs_src = (i * w + j) * 4;
671 int ofs_dst = (i * w + j) * 2;
672 wr[ofs_dst + 0] = 255;
673 wro[ofs_dst + 0] = 255;
674 if (r[ofs_src + 0] > 0x0F) {
675 wr[ofs_dst + 1] = (r[ofs_src + 0] - 0x0F) * 2;
676 wro[ofs_dst + 1] = 0;
677 } else {
678 wr[ofs_dst + 1] = 0;
679 wro[ofs_dst + 1] = r[ofs_src + 0] * 2;
680 }
681 wg[ofs_dst + 0] = 255;
682 wgo[ofs_dst + 0] = 255;
683 if (r[ofs_src + 1] > 0x0F) {
684 wg[ofs_dst + 1] = (r[ofs_src + 1] - 0x0F) * 2;
685 wgo[ofs_dst + 1] = 0;
686 } else {
687 wg[ofs_dst + 1] = 0;
688 wgo[ofs_dst + 1] = r[ofs_src + 1] * 2;
689 }
690 wb[ofs_dst + 0] = 255;
691 wbo[ofs_dst + 0] = 255;
692 if (r[ofs_src + 2] > 0x0F) {
693 wb[ofs_dst + 1] = (r[ofs_src + 2] - 0x0F) * 2;
694 wbo[ofs_dst + 1] = 0;
695 } else {
696 wb[ofs_dst + 1] = 0;
697 wbo[ofs_dst + 1] = r[ofs_src + 2] * 2;
698 }
699 wa[ofs_dst + 0] = 255;
700 wao[ofs_dst + 0] = 255;
701 if (r[ofs_src + 3] > 0x0F) {
702 wa[ofs_dst + 1] = (r[ofs_src + 3] - 0x0F) * 2;
703 wao[ofs_dst + 1] = 0;
704 } else {
705 wa[ofs_dst + 1] = 0;
706 wao[ofs_dst + 1] = r[ofs_src + 3] * 2;
707 }
708 }
709 }
710 Ref<Image> img_r = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_r));
711 set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 0, img_r);
712 Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_g));
713 set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 1, img_g);
714 Ref<Image> img_b = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_b));
715 set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 2, img_b);
716 Ref<Image> img_a = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_a));
717 set_texture_image(0, Vector2i(p_sz, 0), p_page * 4 + 3, img_a);
718
719 Ref<Image> img_ro = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_ro));
720 set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 0, img_ro);
721 Ref<Image> img_go = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_go));
722 set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 1, img_go);
723 Ref<Image> img_bo = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_bo));
724 set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 2, img_bo);
725 Ref<Image> img_ao = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_ao));
726 set_texture_image(0, Vector2i(p_sz, 1), p_page * 4 + 3, img_ao);
727}
728
729void FontFile::_convert_rgba_4bit(Ref<Image> &p_source, int p_page, int p_sz) {
730 int w = p_source->get_width();
731 int h = p_source->get_height();
732
733 PackedByteArray imgdata = p_source->get_data();
734 const uint8_t *r = imgdata.ptr();
735
736 PackedByteArray imgdata_g;
737 imgdata_g.resize(w * h * 4);
738 uint8_t *wg = imgdata_g.ptrw();
739
740 PackedByteArray imgdata_o;
741 imgdata_o.resize(w * h * 4);
742 uint8_t *wo = imgdata_o.ptrw();
743
744 for (int i = 0; i < h; i++) {
745 for (int j = 0; j < w; j++) {
746 int ofs = (i * w + j) * 4;
747
748 if (r[ofs + 0] > 0x7F) {
749 wg[ofs + 0] = r[ofs + 0];
750 wo[ofs + 0] = 0;
751 } else {
752 wg[ofs + 0] = 0;
753 wo[ofs + 0] = r[ofs + 0] * 2;
754 }
755 if (r[ofs + 1] > 0x7F) {
756 wg[ofs + 1] = r[ofs + 1];
757 wo[ofs + 1] = 0;
758 } else {
759 wg[ofs + 1] = 0;
760 wo[ofs + 1] = r[ofs + 1] * 2;
761 }
762 if (r[ofs + 2] > 0x7F) {
763 wg[ofs + 2] = r[ofs + 2];
764 wo[ofs + 2] = 0;
765 } else {
766 wg[ofs + 2] = 0;
767 wo[ofs + 2] = r[ofs + 2] * 2;
768 }
769 if (r[ofs + 3] > 0x7F) {
770 wg[ofs + 3] = r[ofs + 3];
771 wo[ofs + 3] = 0;
772 } else {
773 wg[ofs + 3] = 0;
774 wo[ofs + 3] = r[ofs + 3] * 2;
775 }
776 }
777 }
778 Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_RGBA8, imgdata_g));
779 set_texture_image(0, Vector2i(p_sz, 0), p_page, img_g);
780
781 Ref<Image> img_o = memnew(Image(w, h, 0, Image::FORMAT_RGBA8, imgdata_o));
782 set_texture_image(0, Vector2i(p_sz, 1), p_page, img_o);
783}
784
785void FontFile::_convert_mono_8bit(Ref<Image> &p_source, int p_page, int p_ch, int p_sz, int p_ol) {
786 int w = p_source->get_width();
787 int h = p_source->get_height();
788
789 PackedByteArray imgdata = p_source->get_data();
790 const uint8_t *r = imgdata.ptr();
791
792 int size = 4;
793 if (p_source->get_format() == Image::FORMAT_L8) {
794 size = 1;
795 p_ch = 0;
796 }
797
798 PackedByteArray imgdata_g;
799 imgdata_g.resize(w * h * 2);
800 uint8_t *wg = imgdata_g.ptrw();
801
802 for (int i = 0; i < h; i++) {
803 for (int j = 0; j < w; j++) {
804 int ofs_src = (i * w + j) * size;
805 int ofs_dst = (i * w + j) * 2;
806 wg[ofs_dst + 0] = 255;
807 wg[ofs_dst + 1] = r[ofs_src + p_ch];
808 }
809 }
810 Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_g));
811 set_texture_image(0, Vector2i(p_sz, p_ol), p_page, img_g);
812}
813
814void FontFile::_convert_mono_4bit(Ref<Image> &p_source, int p_page, int p_ch, int p_sz, int p_ol) {
815 int w = p_source->get_width();
816 int h = p_source->get_height();
817
818 PackedByteArray imgdata = p_source->get_data();
819 const uint8_t *r = imgdata.ptr();
820
821 int size = 4;
822 if (p_source->get_format() == Image::FORMAT_L8) {
823 size = 1;
824 p_ch = 0;
825 }
826
827 PackedByteArray imgdata_g;
828 imgdata_g.resize(w * h * 2);
829 uint8_t *wg = imgdata_g.ptrw();
830
831 PackedByteArray imgdata_o;
832 imgdata_o.resize(w * h * 2);
833 uint8_t *wo = imgdata_o.ptrw();
834
835 for (int i = 0; i < h; i++) {
836 for (int j = 0; j < w; j++) {
837 int ofs_src = (i * w + j) * size;
838 int ofs_dst = (i * w + j) * 2;
839 wg[ofs_dst + 0] = 255;
840 wo[ofs_dst + 0] = 255;
841 if (r[ofs_src + p_ch] > 0x7F) {
842 wg[ofs_dst + 1] = r[ofs_src + p_ch];
843 wo[ofs_dst + 1] = 0;
844 } else {
845 wg[ofs_dst + 1] = 0;
846 wo[ofs_dst + 1] = r[ofs_src + p_ch] * 2;
847 }
848 }
849 }
850 Ref<Image> img_g = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_g));
851 set_texture_image(0, Vector2i(p_sz, 0), p_page, img_g);
852
853 Ref<Image> img_o = memnew(Image(w, h, 0, Image::FORMAT_LA8, imgdata_o));
854 set_texture_image(0, Vector2i(p_sz, p_ol), p_page, img_o);
855}
856
857void FontFile::_bind_methods() {
858 ClassDB::bind_method(D_METHOD("load_bitmap_font", "path"), &FontFile::load_bitmap_font);
859 ClassDB::bind_method(D_METHOD("load_dynamic_font", "path"), &FontFile::load_dynamic_font);
860
861 ClassDB::bind_method(D_METHOD("set_data", "data"), &FontFile::set_data);
862 ClassDB::bind_method(D_METHOD("get_data"), &FontFile::get_data);
863
864 ClassDB::bind_method(D_METHOD("set_font_name", "name"), &FontFile::set_font_name);
865 ClassDB::bind_method(D_METHOD("set_font_style_name", "name"), &FontFile::set_font_style_name);
866 ClassDB::bind_method(D_METHOD("set_font_style", "style"), &FontFile::set_font_style);
867 ClassDB::bind_method(D_METHOD("set_font_weight", "weight"), &FontFile::set_font_weight);
868 ClassDB::bind_method(D_METHOD("set_font_stretch", "stretch"), &FontFile::set_font_stretch);
869
870 ClassDB::bind_method(D_METHOD("set_antialiasing", "antialiasing"), &FontFile::set_antialiasing);
871 ClassDB::bind_method(D_METHOD("get_antialiasing"), &FontFile::get_antialiasing);
872
873 ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "generate_mipmaps"), &FontFile::set_generate_mipmaps);
874 ClassDB::bind_method(D_METHOD("get_generate_mipmaps"), &FontFile::get_generate_mipmaps);
875
876 ClassDB::bind_method(D_METHOD("set_multichannel_signed_distance_field", "msdf"), &FontFile::set_multichannel_signed_distance_field);
877 ClassDB::bind_method(D_METHOD("is_multichannel_signed_distance_field"), &FontFile::is_multichannel_signed_distance_field);
878
879 ClassDB::bind_method(D_METHOD("set_msdf_pixel_range", "msdf_pixel_range"), &FontFile::set_msdf_pixel_range);
880 ClassDB::bind_method(D_METHOD("get_msdf_pixel_range"), &FontFile::get_msdf_pixel_range);
881
882 ClassDB::bind_method(D_METHOD("set_msdf_size", "msdf_size"), &FontFile::set_msdf_size);
883 ClassDB::bind_method(D_METHOD("get_msdf_size"), &FontFile::get_msdf_size);
884
885 ClassDB::bind_method(D_METHOD("set_fixed_size", "fixed_size"), &FontFile::set_fixed_size);
886 ClassDB::bind_method(D_METHOD("get_fixed_size"), &FontFile::get_fixed_size);
887
888 ClassDB::bind_method(D_METHOD("set_allow_system_fallback", "allow_system_fallback"), &FontFile::set_allow_system_fallback);
889 ClassDB::bind_method(D_METHOD("is_allow_system_fallback"), &FontFile::is_allow_system_fallback);
890
891 ClassDB::bind_method(D_METHOD("set_force_autohinter", "force_autohinter"), &FontFile::set_force_autohinter);
892 ClassDB::bind_method(D_METHOD("is_force_autohinter"), &FontFile::is_force_autohinter);
893
894 ClassDB::bind_method(D_METHOD("set_hinting", "hinting"), &FontFile::set_hinting);
895 ClassDB::bind_method(D_METHOD("get_hinting"), &FontFile::get_hinting);
896
897 ClassDB::bind_method(D_METHOD("set_subpixel_positioning", "subpixel_positioning"), &FontFile::set_subpixel_positioning);
898 ClassDB::bind_method(D_METHOD("get_subpixel_positioning"), &FontFile::get_subpixel_positioning);
899
900 ClassDB::bind_method(D_METHOD("set_oversampling", "oversampling"), &FontFile::set_oversampling);
901 ClassDB::bind_method(D_METHOD("get_oversampling"), &FontFile::get_oversampling);
902
903 ClassDB::bind_method(D_METHOD("get_cache_count"), &FontFile::get_cache_count);
904 ClassDB::bind_method(D_METHOD("clear_cache"), &FontFile::clear_cache);
905 ClassDB::bind_method(D_METHOD("remove_cache", "cache_index"), &FontFile::remove_cache);
906
907 ClassDB::bind_method(D_METHOD("get_size_cache_list", "cache_index"), &FontFile::get_size_cache_list);
908 ClassDB::bind_method(D_METHOD("clear_size_cache", "cache_index"), &FontFile::clear_size_cache);
909 ClassDB::bind_method(D_METHOD("remove_size_cache", "cache_index", "size"), &FontFile::remove_size_cache);
910
911 ClassDB::bind_method(D_METHOD("set_variation_coordinates", "cache_index", "variation_coordinates"), &FontFile::set_variation_coordinates);
912 ClassDB::bind_method(D_METHOD("get_variation_coordinates", "cache_index"), &FontFile::get_variation_coordinates);
913
914 ClassDB::bind_method(D_METHOD("set_embolden", "cache_index", "strength"), &FontFile::set_embolden);
915 ClassDB::bind_method(D_METHOD("get_embolden", "cache_index"), &FontFile::get_embolden);
916
917 ClassDB::bind_method(D_METHOD("set_transform", "cache_index", "transform"), &FontFile::set_transform);
918 ClassDB::bind_method(D_METHOD("get_transform", "cache_index"), &FontFile::get_transform);
919
920 ClassDB::bind_method(D_METHOD("set_extra_spacing", "cache_index", "spacing", "value"), &FontFile::set_extra_spacing);
921 ClassDB::bind_method(D_METHOD("get_extra_spacing", "cache_index", "spacing"), &FontFile::get_extra_spacing);
922
923 ClassDB::bind_method(D_METHOD("set_face_index", "cache_index", "face_index"), &FontFile::set_face_index);
924 ClassDB::bind_method(D_METHOD("get_face_index", "cache_index"), &FontFile::get_face_index);
925
926 ClassDB::bind_method(D_METHOD("set_cache_ascent", "cache_index", "size", "ascent"), &FontFile::set_cache_ascent);
927 ClassDB::bind_method(D_METHOD("get_cache_ascent", "cache_index", "size"), &FontFile::get_cache_ascent);
928
929 ClassDB::bind_method(D_METHOD("set_cache_descent", "cache_index", "size", "descent"), &FontFile::set_cache_descent);
930 ClassDB::bind_method(D_METHOD("get_cache_descent", "cache_index", "size"), &FontFile::get_cache_descent);
931
932 ClassDB::bind_method(D_METHOD("set_cache_underline_position", "cache_index", "size", "underline_position"), &FontFile::set_cache_underline_position);
933 ClassDB::bind_method(D_METHOD("get_cache_underline_position", "cache_index", "size"), &FontFile::get_cache_underline_position);
934
935 ClassDB::bind_method(D_METHOD("set_cache_underline_thickness", "cache_index", "size", "underline_thickness"), &FontFile::set_cache_underline_thickness);
936 ClassDB::bind_method(D_METHOD("get_cache_underline_thickness", "cache_index", "size"), &FontFile::get_cache_underline_thickness);
937
938 ClassDB::bind_method(D_METHOD("set_cache_scale", "cache_index", "size", "scale"), &FontFile::set_cache_scale);
939 ClassDB::bind_method(D_METHOD("get_cache_scale", "cache_index", "size"), &FontFile::get_cache_scale);
940
941 ClassDB::bind_method(D_METHOD("get_texture_count", "cache_index", "size"), &FontFile::get_texture_count);
942 ClassDB::bind_method(D_METHOD("clear_textures", "cache_index", "size"), &FontFile::clear_textures);
943 ClassDB::bind_method(D_METHOD("remove_texture", "cache_index", "size", "texture_index"), &FontFile::remove_texture);
944
945 ClassDB::bind_method(D_METHOD("set_texture_image", "cache_index", "size", "texture_index", "image"), &FontFile::set_texture_image);
946 ClassDB::bind_method(D_METHOD("get_texture_image", "cache_index", "size", "texture_index"), &FontFile::get_texture_image);
947
948 ClassDB::bind_method(D_METHOD("set_texture_offsets", "cache_index", "size", "texture_index", "offset"), &FontFile::set_texture_offsets);
949 ClassDB::bind_method(D_METHOD("get_texture_offsets", "cache_index", "size", "texture_index"), &FontFile::get_texture_offsets);
950
951 ClassDB::bind_method(D_METHOD("get_glyph_list", "cache_index", "size"), &FontFile::get_glyph_list);
952 ClassDB::bind_method(D_METHOD("clear_glyphs", "cache_index", "size"), &FontFile::clear_glyphs);
953 ClassDB::bind_method(D_METHOD("remove_glyph", "cache_index", "size", "glyph"), &FontFile::remove_glyph);
954
955 ClassDB::bind_method(D_METHOD("set_glyph_advance", "cache_index", "size", "glyph", "advance"), &FontFile::set_glyph_advance);
956 ClassDB::bind_method(D_METHOD("get_glyph_advance", "cache_index", "size", "glyph"), &FontFile::get_glyph_advance);
957
958 ClassDB::bind_method(D_METHOD("set_glyph_offset", "cache_index", "size", "glyph", "offset"), &FontFile::set_glyph_offset);
959 ClassDB::bind_method(D_METHOD("get_glyph_offset", "cache_index", "size", "glyph"), &FontFile::get_glyph_offset);
960
961 ClassDB::bind_method(D_METHOD("set_glyph_size", "cache_index", "size", "glyph", "gl_size"), &FontFile::set_glyph_size);
962 ClassDB::bind_method(D_METHOD("get_glyph_size", "cache_index", "size", "glyph"), &FontFile::get_glyph_size);
963
964 ClassDB::bind_method(D_METHOD("set_glyph_uv_rect", "cache_index", "size", "glyph", "uv_rect"), &FontFile::set_glyph_uv_rect);
965 ClassDB::bind_method(D_METHOD("get_glyph_uv_rect", "cache_index", "size", "glyph"), &FontFile::get_glyph_uv_rect);
966
967 ClassDB::bind_method(D_METHOD("set_glyph_texture_idx", "cache_index", "size", "glyph", "texture_idx"), &FontFile::set_glyph_texture_idx);
968 ClassDB::bind_method(D_METHOD("get_glyph_texture_idx", "cache_index", "size", "glyph"), &FontFile::get_glyph_texture_idx);
969
970 ClassDB::bind_method(D_METHOD("get_kerning_list", "cache_index", "size"), &FontFile::get_kerning_list);
971 ClassDB::bind_method(D_METHOD("clear_kerning_map", "cache_index", "size"), &FontFile::clear_kerning_map);
972 ClassDB::bind_method(D_METHOD("remove_kerning", "cache_index", "size", "glyph_pair"), &FontFile::remove_kerning);
973
974 ClassDB::bind_method(D_METHOD("set_kerning", "cache_index", "size", "glyph_pair", "kerning"), &FontFile::set_kerning);
975 ClassDB::bind_method(D_METHOD("get_kerning", "cache_index", "size", "glyph_pair"), &FontFile::get_kerning);
976
977 ClassDB::bind_method(D_METHOD("render_range", "cache_index", "size", "start", "end"), &FontFile::render_range);
978 ClassDB::bind_method(D_METHOD("render_glyph", "cache_index", "size", "index"), &FontFile::render_glyph);
979
980 ClassDB::bind_method(D_METHOD("set_language_support_override", "language", "supported"), &FontFile::set_language_support_override);
981 ClassDB::bind_method(D_METHOD("get_language_support_override", "language"), &FontFile::get_language_support_override);
982 ClassDB::bind_method(D_METHOD("remove_language_support_override", "language"), &FontFile::remove_language_support_override);
983 ClassDB::bind_method(D_METHOD("get_language_support_overrides"), &FontFile::get_language_support_overrides);
984
985 ClassDB::bind_method(D_METHOD("set_script_support_override", "script", "supported"), &FontFile::set_script_support_override);
986 ClassDB::bind_method(D_METHOD("get_script_support_override", "script"), &FontFile::get_script_support_override);
987 ClassDB::bind_method(D_METHOD("remove_script_support_override", "script"), &FontFile::remove_script_support_override);
988 ClassDB::bind_method(D_METHOD("get_script_support_overrides"), &FontFile::get_script_support_overrides);
989
990 ClassDB::bind_method(D_METHOD("set_opentype_feature_overrides", "overrides"), &FontFile::set_opentype_feature_overrides);
991 ClassDB::bind_method(D_METHOD("get_opentype_feature_overrides"), &FontFile::get_opentype_feature_overrides);
992
993 ClassDB::bind_method(D_METHOD("get_glyph_index", "size", "char", "variation_selector"), &FontFile::get_glyph_index);
994 ClassDB::bind_method(D_METHOD("get_char_from_glyph_index", "size", "glyph_index"), &FontFile::get_char_from_glyph_index);
995
996 ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_data", "get_data");
997 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_generate_mipmaps", "get_generate_mipmaps");
998 ADD_PROPERTY(PropertyInfo(Variant::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD Subpixel", PROPERTY_USAGE_STORAGE), "set_antialiasing", "get_antialiasing");
999 ADD_PROPERTY(PropertyInfo(Variant::STRING, "font_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_name", "get_font_name");
1000 ADD_PROPERTY(PropertyInfo(Variant::STRING, "style_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_style_name", "get_font_style_name");
1001 ADD_PROPERTY(PropertyInfo(Variant::INT, "font_style", PROPERTY_HINT_FLAGS, "Bold,Italic,Fixed Size", PROPERTY_USAGE_STORAGE), "set_font_style", "get_font_style");
1002 ADD_PROPERTY(PropertyInfo(Variant::INT, "font_weight", PROPERTY_HINT_RANGE, "100,999,25", PROPERTY_USAGE_STORAGE), "set_font_weight", "get_font_weight");
1003 ADD_PROPERTY(PropertyInfo(Variant::INT, "font_stretch", PROPERTY_HINT_RANGE, "50,200,25", PROPERTY_USAGE_STORAGE), "set_font_stretch", "get_font_stretch");
1004
1005 ADD_PROPERTY(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One Half of a Pixel,One Quarter of a Pixel", PROPERTY_USAGE_STORAGE), "set_subpixel_positioning", "get_subpixel_positioning");
1006 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_multichannel_signed_distance_field", "is_multichannel_signed_distance_field");
1007 ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_msdf_pixel_range", "get_msdf_pixel_range");
1008 ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_msdf_size", "get_msdf_size");
1009 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_system_fallback", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_allow_system_fallback", "is_allow_system_fallback");
1010 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_autohinter", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_force_autohinter", "is_force_autohinter");
1011 ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_STORAGE), "set_hinting", "get_hinting");
1012 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_oversampling", "get_oversampling");
1013 ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_fixed_size", "get_fixed_size");
1014 ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "opentype_feature_overrides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_opentype_feature_overrides", "get_opentype_feature_overrides");
1015}
1016
1017void FontFile::_validate_property(PropertyInfo &p_property) const {
1018 if (p_property.name == "fallbacks") {
1019 p_property.usage &= ~PROPERTY_USAGE_EDITOR;
1020 }
1021}
1022
1023bool FontFile::_set(const StringName &p_name, const Variant &p_value) {
1024 Vector<String> tokens = p_name.operator String().split("/");
1025
1026#ifndef DISABLE_DEPRECATED
1027 if (tokens.size() == 1 && tokens[0] == "font_path") {
1028 // Compatibility, DynamicFontData.
1029 load_dynamic_font(p_value);
1030 } else if (tokens.size() == 1 && tokens[0] == "override_oversampling") {
1031 set_oversampling(p_value);
1032 }
1033 if (tokens.size() == 1 && tokens[0] == "font_data") {
1034 // Compatibility, DynamicFont.
1035 Ref<Font> f = p_value;
1036 if (f.is_valid()) {
1037 fallbacks.push_back(f);
1038 return true;
1039 }
1040 return false;
1041 } else if (tokens.size() == 2 && tokens[0] == "fallback") {
1042 // Compatibility, DynamicFont.
1043 Ref<FontFile> f = p_value;
1044 if (f.is_valid()) {
1045 fallbacks.push_back(f);
1046 return true;
1047 }
1048 return false;
1049 } else if (tokens.size() == 1 && tokens[0] == "textures") {
1050 // Compatibility, BitmapFont.
1051 set_fixed_size(16);
1052 Array textures = p_value;
1053 for (int i = 0; i < textures.size(); i++) {
1054 Ref<ImageTexture> tex = textures[i];
1055 ERR_CONTINUE(!tex.is_valid());
1056 set_texture_image(0, Vector2i(16, 0), i, tex->get_image());
1057 }
1058 } else if (tokens.size() == 1 && tokens[0] == "chars") {
1059 // Compatibility, BitmapFont.
1060 set_fixed_size(16);
1061 PackedInt32Array arr = p_value;
1062 int len = arr.size();
1063 ERR_FAIL_COND_V(len % 9, false);
1064 if (!len) {
1065 return false;
1066 }
1067 int chars = len / 9;
1068 for (int i = 0; i < chars; i++) {
1069 const int32_t *char_data = &arr[i * 9];
1070 char32_t c = char_data[0];
1071 set_glyph_texture_idx(0, Vector2i(16, 0), c, char_data[1]);
1072 set_glyph_uv_rect(0, Vector2i(16, 0), c, Rect2(char_data[2], char_data[3], char_data[4], char_data[5]));
1073 set_glyph_offset(0, Vector2i(16, 0), c, Size2(char_data[6], char_data[7]));
1074 set_glyph_advance(0, 16, c, Vector2(char_data[8], 0));
1075 }
1076 } else if (tokens.size() == 1 && tokens[0] == "kernings") {
1077 // Compatibility, BitmapFont.
1078 set_fixed_size(16);
1079 PackedInt32Array arr = p_value;
1080 int len = arr.size();
1081 ERR_FAIL_COND_V(len % 3, false);
1082 if (!len) {
1083 return false;
1084 }
1085 for (int i = 0; i < len / 3; i++) {
1086 const int32_t *kern_data = &arr[i * 3];
1087 set_kerning(0, 16, Vector2i(kern_data[0], kern_data[1]), Vector2(kern_data[2], 0));
1088 }
1089 } else if (tokens.size() == 1 && tokens[0] == "height") {
1090 // Compatibility, BitmapFont.
1091 bmp_height = p_value;
1092 set_fixed_size(16);
1093 set_cache_descent(0, 16, bmp_height - bmp_ascent);
1094 } else if (tokens.size() == 1 && tokens[0] == "ascent") {
1095 // Compatibility, BitmapFont.
1096 bmp_ascent = p_value;
1097 set_fixed_size(16);
1098 set_cache_ascent(0, 16, bmp_ascent);
1099 set_cache_descent(0, 16, bmp_height - bmp_ascent);
1100 } else if (tokens.size() == 1 && tokens[0] == "fallback") {
1101 // Compatibility, BitmapFont.
1102 Ref<Font> f = p_value;
1103 if (f.is_valid()) {
1104 fallbacks.push_back(f);
1105 return true;
1106 }
1107 return false;
1108 }
1109#endif // DISABLE_DEPRECATED
1110
1111 if (tokens.size() == 2 && tokens[0] == "language_support_override") {
1112 String lang_code = tokens[1];
1113 set_language_support_override(lang_code, p_value);
1114 return true;
1115 } else if (tokens.size() == 2 && tokens[0] == "script_support_override") {
1116 String script_code = tokens[1];
1117 set_script_support_override(script_code, p_value);
1118 return true;
1119 } else if (tokens.size() >= 3 && tokens[0] == "cache") {
1120 int cache_index = tokens[1].to_int();
1121 if (tokens.size() == 3 && tokens[2] == "variation_coordinates") {
1122 set_variation_coordinates(cache_index, p_value);
1123 return true;
1124 } else if (tokens.size() == 3 && tokens[2] == "embolden") {
1125 set_embolden(cache_index, p_value);
1126 return true;
1127 } else if (tokens.size() == 3 && tokens[2] == "face_index") {
1128 set_face_index(cache_index, p_value);
1129 return true;
1130 } else if (tokens.size() == 3 && tokens[2] == "transform") {
1131 set_transform(cache_index, p_value);
1132 return true;
1133 } else if (tokens.size() == 3 && tokens[2] == "spacing_top") {
1134 set_extra_spacing(cache_index, TextServer::SPACING_TOP, p_value);
1135 return true;
1136 } else if (tokens.size() == 3 && tokens[2] == "spacing_bottom") {
1137 set_extra_spacing(cache_index, TextServer::SPACING_BOTTOM, p_value);
1138 return true;
1139 } else if (tokens.size() == 3 && tokens[2] == "spacing_space") {
1140 set_extra_spacing(cache_index, TextServer::SPACING_SPACE, p_value);
1141 return true;
1142 } else if (tokens.size() == 3 && tokens[2] == "spacing_glyph") {
1143 set_extra_spacing(cache_index, TextServer::SPACING_GLYPH, p_value);
1144 return true;
1145 }
1146 if (tokens.size() >= 5) {
1147 Vector2i sz = Vector2i(tokens[2].to_int(), tokens[3].to_int());
1148 if (tokens[4] == "ascent") {
1149 set_cache_ascent(cache_index, sz.x, p_value);
1150 return true;
1151 } else if (tokens[4] == "descent") {
1152 set_cache_descent(cache_index, sz.x, p_value);
1153 return true;
1154 } else if (tokens[4] == "underline_position") {
1155 set_cache_underline_position(cache_index, sz.x, p_value);
1156 return true;
1157 } else if (tokens[4] == "underline_thickness") {
1158 set_cache_underline_thickness(cache_index, sz.x, p_value);
1159 return true;
1160 } else if (tokens[4] == "scale") {
1161 set_cache_scale(cache_index, sz.x, p_value);
1162 return true;
1163 } else if (tokens.size() == 7 && tokens[4] == "textures") {
1164 int texture_index = tokens[5].to_int();
1165 if (tokens[6] == "image") {
1166 set_texture_image(cache_index, sz, texture_index, p_value);
1167 return true;
1168 } else if (tokens[6] == "offsets") {
1169 set_texture_offsets(cache_index, sz, texture_index, p_value);
1170 return true;
1171 }
1172 } else if (tokens.size() == 7 && tokens[4] == "glyphs") {
1173 int32_t glyph_index = tokens[5].to_int();
1174 if (tokens[6] == "advance") {
1175 set_glyph_advance(cache_index, sz.x, glyph_index, p_value);
1176 return true;
1177 } else if (tokens[6] == "offset") {
1178 set_glyph_offset(cache_index, sz, glyph_index, p_value);
1179 return true;
1180 } else if (tokens[6] == "size") {
1181 set_glyph_size(cache_index, sz, glyph_index, p_value);
1182 return true;
1183 } else if (tokens[6] == "uv_rect") {
1184 set_glyph_uv_rect(cache_index, sz, glyph_index, p_value);
1185 return true;
1186 } else if (tokens[6] == "texture_idx") {
1187 set_glyph_texture_idx(cache_index, sz, glyph_index, p_value);
1188 return true;
1189 }
1190 } else if (tokens.size() == 7 && tokens[4] == "kerning_overrides") {
1191 Vector2i gp = Vector2i(tokens[5].to_int(), tokens[6].to_int());
1192 set_kerning(cache_index, sz.x, gp, p_value);
1193 return true;
1194 }
1195 }
1196 }
1197 return false;
1198}
1199
1200bool FontFile::_get(const StringName &p_name, Variant &r_ret) const {
1201 Vector<String> tokens = p_name.operator String().split("/");
1202 if (tokens.size() == 2 && tokens[0] == "language_support_override") {
1203 String lang_code = tokens[1];
1204 r_ret = get_language_support_override(lang_code);
1205 return true;
1206 } else if (tokens.size() == 2 && tokens[0] == "script_support_override") {
1207 String script_code = tokens[1];
1208 r_ret = get_script_support_override(script_code);
1209 return true;
1210 } else if (tokens.size() >= 3 && tokens[0] == "cache") {
1211 int cache_index = tokens[1].to_int();
1212 if (tokens.size() == 3 && tokens[2] == "variation_coordinates") {
1213 r_ret = get_variation_coordinates(cache_index);
1214 return true;
1215 } else if (tokens.size() == 3 && tokens[2] == "embolden") {
1216 r_ret = get_embolden(cache_index);
1217 return true;
1218 } else if (tokens.size() == 3 && tokens[2] == "face_index") {
1219 r_ret = get_face_index(cache_index);
1220 return true;
1221 } else if (tokens.size() == 3 && tokens[2] == "transform") {
1222 r_ret = get_transform(cache_index);
1223 return true;
1224 } else if (tokens.size() == 3 && tokens[2] == "spacing_top") {
1225 r_ret = get_extra_spacing(cache_index, TextServer::SPACING_TOP);
1226 return true;
1227 } else if (tokens.size() == 3 && tokens[2] == "spacing_bottom") {
1228 r_ret = get_extra_spacing(cache_index, TextServer::SPACING_BOTTOM);
1229 return true;
1230 } else if (tokens.size() == 3 && tokens[2] == "spacing_space") {
1231 r_ret = get_extra_spacing(cache_index, TextServer::SPACING_SPACE);
1232 return true;
1233 } else if (tokens.size() == 3 && tokens[2] == "spacing_glyph") {
1234 r_ret = get_extra_spacing(cache_index, TextServer::SPACING_GLYPH);
1235 return true;
1236 }
1237 if (tokens.size() >= 5) {
1238 Vector2i sz = Vector2i(tokens[2].to_int(), tokens[3].to_int());
1239 if (tokens[4] == "ascent") {
1240 r_ret = get_cache_ascent(cache_index, sz.x);
1241 return true;
1242 } else if (tokens[4] == "descent") {
1243 r_ret = get_cache_descent(cache_index, sz.x);
1244 return true;
1245 } else if (tokens[4] == "underline_position") {
1246 r_ret = get_cache_underline_position(cache_index, sz.x);
1247 return true;
1248 } else if (tokens[4] == "underline_thickness") {
1249 r_ret = get_cache_underline_thickness(cache_index, sz.x);
1250 return true;
1251 } else if (tokens[4] == "scale") {
1252 r_ret = get_cache_scale(cache_index, sz.x);
1253 return true;
1254 } else if (tokens.size() == 7 && tokens[4] == "textures") {
1255 int texture_index = tokens[5].to_int();
1256 if (tokens[6] == "image") {
1257 r_ret = get_texture_image(cache_index, sz, texture_index);
1258 return true;
1259 } else if (tokens[6] == "offsets") {
1260 r_ret = get_texture_offsets(cache_index, sz, texture_index);
1261 return true;
1262 }
1263 } else if (tokens.size() == 7 && tokens[4] == "glyphs") {
1264 int32_t glyph_index = tokens[5].to_int();
1265 if (tokens[6] == "advance") {
1266 r_ret = get_glyph_advance(cache_index, sz.x, glyph_index);
1267 return true;
1268 } else if (tokens[6] == "offset") {
1269 r_ret = get_glyph_offset(cache_index, sz, glyph_index);
1270 return true;
1271 } else if (tokens[6] == "size") {
1272 r_ret = get_glyph_size(cache_index, sz, glyph_index);
1273 return true;
1274 } else if (tokens[6] == "uv_rect") {
1275 r_ret = get_glyph_uv_rect(cache_index, sz, glyph_index);
1276 return true;
1277 } else if (tokens[6] == "texture_idx") {
1278 r_ret = get_glyph_texture_idx(cache_index, sz, glyph_index);
1279 return true;
1280 }
1281 } else if (tokens.size() == 7 && tokens[4] == "kerning_overrides") {
1282 Vector2i gp = Vector2i(tokens[5].to_int(), tokens[6].to_int());
1283 r_ret = get_kerning(cache_index, sz.x, gp);
1284 return true;
1285 }
1286 }
1287 }
1288 return false;
1289}
1290
1291void FontFile::_get_property_list(List<PropertyInfo> *p_list) const {
1292 Vector<String> lang_over = get_language_support_overrides();
1293 for (int i = 0; i < lang_over.size(); i++) {
1294 p_list->push_back(PropertyInfo(Variant::BOOL, "language_support_override/" + lang_over[i], PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1295 }
1296 Vector<String> scr_over = get_script_support_overrides();
1297 for (int i = 0; i < scr_over.size(); i++) {
1298 p_list->push_back(PropertyInfo(Variant::BOOL, "script_support_override/" + scr_over[i], PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1299 }
1300 for (int i = 0; i < cache.size(); i++) {
1301 String prefix = "cache/" + itos(i) + "/";
1302 TypedArray<Vector2i> sizes = get_size_cache_list(i);
1303 p_list->push_back(PropertyInfo(Variant::DICTIONARY, prefix + "variation_coordinates", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1304 p_list->push_back(PropertyInfo(Variant::INT, prefix + "face_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1305 p_list->push_back(PropertyInfo(Variant::FLOAT, prefix + "embolden", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1306 p_list->push_back(PropertyInfo(Variant::TRANSFORM2D, prefix + "transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1307 p_list->push_back(PropertyInfo(Variant::INT, prefix + "spacing_top", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1308 p_list->push_back(PropertyInfo(Variant::INT, prefix + "spacing_bottom", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1309 p_list->push_back(PropertyInfo(Variant::INT, prefix + "spacing_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1310 p_list->push_back(PropertyInfo(Variant::INT, prefix + "spacing_glyph", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1311
1312 for (int j = 0; j < sizes.size(); j++) {
1313 Vector2i sz = sizes[j];
1314 String prefix_sz = prefix + itos(sz.x) + "/" + itos(sz.y) + "/";
1315 if (sz.y == 0) {
1316 p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "ascent", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1317 p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "descent", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1318 p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "underline_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1319 p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "underline_thickness", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1320 p_list->push_back(PropertyInfo(Variant::FLOAT, prefix_sz + "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1321 }
1322
1323 int tx_cnt = get_texture_count(i, sz);
1324 for (int k = 0; k < tx_cnt; k++) {
1325 p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, prefix_sz + "textures/" + itos(k) + "/offsets", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1326 p_list->push_back(PropertyInfo(Variant::OBJECT, prefix_sz + "textures/" + itos(k) + "/image", PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT));
1327 }
1328 PackedInt32Array glyphs = get_glyph_list(i, sz);
1329 for (int k = 0; k < glyphs.size(); k++) {
1330 const int32_t &gl = glyphs[k];
1331 if (sz.y == 0) {
1332 p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "glyphs/" + itos(gl) + "/advance", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1333 }
1334 p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "glyphs/" + itos(gl) + "/offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1335 p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "glyphs/" + itos(gl) + "/size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1336 p_list->push_back(PropertyInfo(Variant::RECT2, prefix_sz + "glyphs/" + itos(gl) + "/uv_rect", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1337 p_list->push_back(PropertyInfo(Variant::INT, prefix_sz + "glyphs/" + itos(gl) + "/texture_idx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1338 }
1339 if (sz.y == 0) {
1340 TypedArray<Vector2i> kerning_map = get_kerning_list(i, sz.x);
1341 for (int k = 0; k < kerning_map.size(); k++) {
1342 const Vector2i &gl_pair = kerning_map[k];
1343 p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "kerning_overrides/" + itos(gl_pair.x) + "/" + itos(gl_pair.y), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
1344 }
1345 }
1346 }
1347 }
1348}
1349
1350void FontFile::reset_state() {
1351 _clear_cache();
1352 data.clear();
1353 data_ptr = nullptr;
1354 data_size = 0;
1355 cache.clear();
1356
1357 antialiasing = TextServer::FONT_ANTIALIASING_GRAY;
1358 mipmaps = false;
1359 msdf = false;
1360 force_autohinter = false;
1361 allow_system_fallback = true;
1362 hinting = TextServer::HINTING_LIGHT;
1363 subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED;
1364 msdf_pixel_range = 14;
1365 msdf_size = 128;
1366 fixed_size = 0;
1367 oversampling = 0.f;
1368
1369 Font::reset_state();
1370}
1371
1372/*************************************************************************/
1373
1374// OEM encoding mapping for 0x80..0xFF range.
1375static const char32_t _oem_to_unicode[][129] = {
1376 U"\u20ac\ufffe\u201a\ufffe\u201e\u2026\u2020\u2021\ufffe\u2030\u0160\u2039\u015a\u0164\u017d\u0179\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffe\u2122\u0161\u203a\u015b\u0165\u017e\u017a\xa0\u02c7\u02d8\u0141\xa4\u0104\xa6\xa7\xa8\xa9\u015e\xab\xac\xad\xae\u017b\xb0\xb1\u02db\u0142\xb4\xb5\xb6\xb7\xb8\u0105\u015f\xbb\u013d\u02dd\u013e\u017c\u0154\xc1\xc2\u0102\xc4\u0139\u0106\xc7\u010c\xc9\u0118\xcb\u011a\xcd\xce\u010e\u0110\u0143\u0147\xd3\xd4\u0150\xd6\xd7\u0158\u016e\xda\u0170\xdc\xdd\u0162\xdf\u0155\xe1\xe2\u0103\xe4\u013a\u0107\xe7\u010d\xe9\u0119\xeb\u011b\xed\xee\u010f\u0111\u0144\u0148\xf3\xf4\u0151\xf6\xf7\u0159\u016f\xfa\u0171\xfc\xfd\u0163\u02d9", // 1250 - Latin 2
1377 U"\u0402\u0403\u201a\u0453\u201e\u2026\u2020\u2021\u20ac\u2030\u0409\u2039\u040a\u040c\u040b\u040f\u0452\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffe\u2122\u0459\u203a\u045a\u045c\u045b\u045f\xa0\u040e\u045e\u0408\xa4\u0490\xa6\xa7\u0401\xa9\u0404\xab\xac\xad\xae\u0407\xb0\xb1\u0406\u0456\u0491\xb5\xb6\xb7\u0451\u2116\u0454\xbb\u0458\u0405\u0455\u0457\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f", // 1251 - Cyrillic
1378 U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0160\u2039\u0152\ufffe\u017d\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\u0161\u203a\u0153\ufffe\u017e\u0178\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", // 1252 - Latin 1
1379 U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\ufffe\u2030\ufffe\u2039\ufffe\ufffe\ufffe\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffe\u2122\ufffe\u203a\ufffe\ufffe\ufffe\ufffe\xa0\u0385\u0386\xa3\xa4\xa5\xa6\xa7\xa8\xa9\ufffe\xab\xac\xad\xae\u2015\xb0\xb1\xb2\xb3\u0384\xb5\xb6\xb7\u0388\u0389\u038a\xbb\u038c\xbd\u038e\u038f\u0390\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u039a\u039b\u039c\u039d\u039e\u039f\u03a0\u03a1\ufffe\u03a3\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03aa\u03ab\u03ac\u03ad\u03ae\u03af\u03b0\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u03bd\u03be\u03bf\u03c0\u03c1\u03c2\u03c3\u03c4\u03c5\u03c6\u03c7\u03c8\u03c9\u03ca\u03cb\u03cc\u03cd\u03ce\ufffe", // 1253 - Greek
1380 U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0160\u2039\u0152\ufffe\ufffe\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\u0161\u203a\u0153\ufffe\ufffe\u0178\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\u011e\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\u0130\u015e\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\u011f\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\u0131\u015f\xff", // 1254 - Turkish
1381 U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\ufffe\u2039\ufffe\ufffe\ufffe\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\ufffe\u203a\ufffe\ufffe\ufffe\ufffe\xa0\xa1\xa2\xa3\u20aa\xa5\xa6\xa7\xa8\xa9\xd7\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xf7\xbb\xbc\xbd\xbe\xbf\u05b0\u05b1\u05b2\u05b3\u05b4\u05b5\u05b6\u05b7\u05b8\u05b9\ufffe\u05bb\u05bc\u05bd\u05be\u05bf\u05c0\u05c1\u05c2\u05c3\u05f0\u05f1\u05f2\u05f3\u05f4\ufffe\ufffe\ufffe\ufffe\ufffe\ufffe\ufffe\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\u05e3\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\ufffe\ufffe\u200e\u200f\ufffe", // 1255 - Hebrew
1382 U"\u20ac\u067e\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0679\u2039\u0152\u0686\u0698\u0688\u06af\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u06a9\u2122\u0691\u203a\u0153\u200c\u200d\u06ba\xa0\u060c\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\u06be\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\u061b\xbb\xbc\xbd\xbe\u061f\u06c1\u0621\u0622\u0623\u0624\u0625\u0626\u0627\u0628\u0629\u062a\u062b\u062c\u062d\u062e\u062f\u0630\u0631\u0632\u0633\u0634\u0635\u0636\xd7\u0637\u0638\u0639\u063a\u0640\u0641\u0642\u0643\xe0\u0644\xe2\u0645\u0646\u0647\u0648\xe7\xe8\xe9\xea\xeb\u0649\u064a\xee\xef\u064b\u064c\u064d\u064e\xf4\u064f\u0650\xf7\u0651\xf9\u0652\xfb\xfc\u200e\u200f\u06d2", // 1256 - Arabic
1383 U"\u20ac\ufffe\u201a\ufffe\u201e\u2026\u2020\u2021\ufffe\u2030\ufffe\u2039\ufffe\xa8\u02c7\xb8\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffe\u2122\ufffe\u203a\ufffe\xaf\u02db\ufffe\xa0\ufffe\xa2\xa3\xa4\ufffe\xa6\xa7\xd8\xa9\u0156\xab\xac\xad\xae\xc6\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xf8\xb9\u0157\xbb\xbc\xbd\xbe\xe6\u0104\u012e\u0100\u0106\xc4\xc5\u0118\u0112\u010c\xc9\u0179\u0116\u0122\u0136\u012a\u013b\u0160\u0143\u0145\xd3\u014c\xd5\xd6\xd7\u0172\u0141\u015a\u016a\xdc\u017b\u017d\xdf\u0105\u012f\u0101\u0107\xe4\xe5\u0119\u0113\u010d\xe9\u017a\u0117\u0123\u0137\u012b\u013c\u0161\u0144\u0146\xf3\u014d\xf5\xf6\xf7\u0173\u0142\u015b\u016b\xfc\u017c\u017e\u02d9", // 1257 - Baltic
1384 U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\ufffe\u2039\u0152\ufffe\ufffe\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\ufffe\u203a\u0153\ufffe\ufffe\u0178\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\u0102\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\u0300\xcd\xce\xcf\u0110\xd1\u0309\xd3\xd4\u01a0\xd6\xd7\xd8\xd9\xda\xdb\xdc\u01af\u0303\xdf\xe0\xe1\xe2\u0103\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\u0301\xed\xee\xef\u0111\xf1\u0323\xf3\xf4\u01a1\xf6\xf7\xf8\xf9\xfa\xfb\xfc\u01b0\u20ab\xff", // 1258 - Vietnamese
1385};
1386
1387Error FontFile::load_bitmap_font(const String &p_path) {
1388 reset_state();
1389
1390 antialiasing = TextServer::FONT_ANTIALIASING_NONE;
1391 mipmaps = false;
1392 msdf = false;
1393 force_autohinter = false;
1394 allow_system_fallback = true;
1395 hinting = TextServer::HINTING_NONE;
1396 oversampling = 1.0f;
1397
1398 Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
1399 ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_CREATE, vformat(RTR("Cannot open font from file: %s."), p_path));
1400
1401 int base_size = 16;
1402 int height = 0;
1403 int ascent = 0;
1404 int outline = 0;
1405 BitField<TextServer::FontStyle> st_flags = 0;
1406 String font_name;
1407
1408 bool packed = false;
1409 uint8_t ch[4] = { 0, 0, 0, 0 }; // RGBA
1410 int first_gl_ch = -1;
1411 int first_ol_ch = -1;
1412 int first_cm_ch = -1;
1413
1414 unsigned char magic[4];
1415 f->get_buffer((unsigned char *)&magic, 4);
1416 if (magic[0] == 'B' && magic[1] == 'M' && magic[2] == 'F') {
1417 // Binary BMFont file.
1418 ERR_FAIL_COND_V_MSG(magic[3] != 3, ERR_CANT_CREATE, vformat(RTR("Version %d of BMFont is not supported (should be 3)."), (int)magic[3]));
1419
1420 uint8_t block_type = f->get_8();
1421 uint32_t block_size = f->get_32();
1422 bool unicode = false;
1423 uint8_t encoding = 9;
1424 while (!f->eof_reached()) {
1425 uint64_t off = f->get_position();
1426 switch (block_type) {
1427 case 1: /* info */ {
1428 ERR_FAIL_COND_V_MSG(block_size < 15, ERR_CANT_CREATE, RTR("Invalid BMFont info block size."));
1429 base_size = f->get_16();
1430 if (base_size <= 0) {
1431 base_size = 16;
1432 }
1433 uint8_t flags = f->get_8();
1434 if (flags & (1 << 3)) {
1435 st_flags.set_flag(TextServer::FONT_BOLD);
1436 }
1437 if (flags & (1 << 2)) {
1438 st_flags.set_flag(TextServer::FONT_ITALIC);
1439 }
1440 unicode = (flags & 0x02);
1441 uint8_t encoding_id = f->get_8(); // non-unicode charset
1442 if (!unicode) {
1443 switch (encoding_id) {
1444 case 0x00: {
1445 encoding = 2;
1446 } break;
1447 case 0xB2: {
1448 encoding = 6;
1449 } break;
1450 case 0xBA: {
1451 encoding = 7;
1452 } break;
1453 case 0xEE: {
1454 encoding = 0;
1455 } break;
1456 case 0xA1: {
1457 encoding = 3;
1458 } break;
1459 case 0xB1: {
1460 encoding = 5;
1461 } break;
1462 case 0xCC: {
1463 encoding = 1;
1464 } break;
1465 case 0xA2: {
1466 encoding = 4;
1467 } break;
1468 case 0xA3: {
1469 encoding = 8;
1470 } break;
1471 default: {
1472 WARN_PRINT(vformat("Unknown BMFont OEM encoding %x, parsing as Unicode (should be 0x00 - Latin 1, 0xB2 - Arabic, 0xBA - Baltic, 0xEE - Latin 2, 0xA1 - Greek, 0xB1 - Hebrew, 0xCC - Cyrillic, 0xA2 - Turkish, 0xA3 - Vietnamese).", encoding_id));
1473 } break;
1474 };
1475 }
1476 f->get_16(); // stretch_h, skip
1477 f->get_8(); // aa, skip
1478 f->get_32(); // padding, skip
1479 f->get_16(); // spacing, skip
1480 outline = f->get_8();
1481 // font name
1482 PackedByteArray name_data;
1483 name_data.resize(block_size - 14);
1484 f->get_buffer(name_data.ptrw(), block_size - 14);
1485 font_name = String::utf8((const char *)name_data.ptr(), block_size - 14);
1486 set_fixed_size(base_size);
1487 } break;
1488 case 2: /* common */ {
1489 ERR_FAIL_COND_V_MSG(block_size != 15, ERR_CANT_CREATE, RTR("Invalid BMFont common block size."));
1490 height = f->get_16();
1491 ascent = f->get_16();
1492 f->get_32(); // scale, skip
1493 f->get_16(); // pages, skip
1494 uint8_t flags = f->get_8();
1495 packed = (flags & 0x01);
1496 ch[3] = f->get_8();
1497 ch[0] = f->get_8();
1498 ch[1] = f->get_8();
1499 ch[2] = f->get_8();
1500 for (int i = 0; i < 4; i++) {
1501 if (ch[i] == 0 && first_gl_ch == -1) {
1502 first_gl_ch = i;
1503 }
1504 if (ch[i] == 1 && first_ol_ch == -1) {
1505 first_ol_ch = i;
1506 if (outline == 0) {
1507 outline = 1;
1508 }
1509 }
1510 if (ch[i] == 2 && first_cm_ch == -1) {
1511 first_cm_ch = i;
1512 }
1513 }
1514 } break;
1515 case 3: /* pages */ {
1516 int page = 0;
1517 CharString cs;
1518 char32_t c = f->get_8();
1519 while (!f->eof_reached() && f->get_position() <= off + block_size) {
1520 if (c == '\0') {
1521 String base_dir = p_path.get_base_dir();
1522 String file = base_dir.path_join(String::utf8(cs.ptr(), cs.length()));
1523 if (RenderingServer::get_singleton() != nullptr) {
1524 Ref<Image> img;
1525 img.instantiate();
1526 Error err = ImageLoader::load_image(file, img);
1527 ERR_FAIL_COND_V_MSG(err != OK, ERR_FILE_CANT_READ, vformat(RTR("Can't load font texture: %s."), file));
1528
1529 if (packed) {
1530 if (ch[3] == 0) { // 4 x 8 bit monochrome, no outline
1531 outline = 0;
1532 ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, RTR("Unsupported BMFont texture format."));
1533 _convert_packed_8bit(img, page, base_size);
1534 } else if ((ch[3] == 2) && (outline > 0)) { // 4 x 4 bit monochrome, gl + outline
1535 ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, RTR("Unsupported BMFont texture format."));
1536 _convert_packed_4bit(img, page, base_size);
1537 } else {
1538 ERR_FAIL_V_MSG(ERR_CANT_CREATE, RTR("Unsupported BMFont texture format."));
1539 }
1540 } else {
1541 if ((ch[0] == 0) && (ch[1] == 0) && (ch[2] == 0) && (ch[3] == 0)) { // RGBA8 color, no outline
1542 outline = 0;
1543 ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, RTR("Unsupported BMFont texture format."));
1544 set_texture_image(0, Vector2i(base_size, 0), page, img);
1545 } else if ((ch[0] == 2) && (ch[1] == 2) && (ch[2] == 2) && (ch[3] == 2) && (outline > 0)) { // RGBA4 color, gl + outline
1546 ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, RTR("Unsupported BMFont texture format."));
1547 _convert_rgba_4bit(img, page, base_size);
1548 } else if ((first_gl_ch >= 0) && (first_ol_ch >= 0) && (outline > 0)) { // 1 x 8 bit monochrome, gl + outline
1549 ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, RTR("Unsupported BMFont texture format."));
1550 _convert_mono_8bit(img, page, first_gl_ch, base_size, 0);
1551 _convert_mono_8bit(img, page, first_ol_ch, base_size, 1);
1552 } else if ((first_cm_ch >= 0) && (outline > 0)) { // 1 x 4 bit monochrome, gl + outline
1553 ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, RTR("Unsupported BMFont texture format."));
1554 _convert_mono_4bit(img, page, first_cm_ch, base_size, 1);
1555 } else if (first_gl_ch >= 0) { // 1 x 8 bit monochrome, no outline
1556 outline = 0;
1557 ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, RTR("Unsupported BMFont texture format."));
1558 _convert_mono_8bit(img, page, first_gl_ch, base_size, 0);
1559 } else {
1560 ERR_FAIL_V_MSG(ERR_CANT_CREATE, RTR("Unsupported BMFont texture format."));
1561 }
1562 }
1563 }
1564 page++;
1565 cs = "";
1566 } else {
1567 cs += c;
1568 }
1569 c = f->get_8();
1570 }
1571 } break;
1572 case 4: /* chars */ {
1573 int char_count = block_size / 20;
1574 for (int i = 0; i < char_count; i++) {
1575 Vector2 advance;
1576 Vector2 size;
1577 Vector2 offset;
1578 Rect2 uv_rect;
1579
1580 char32_t idx = f->get_32();
1581 if (!unicode && encoding < 9) {
1582 if (idx >= 0x80 && idx <= 0xFF) {
1583 idx = _oem_to_unicode[encoding][idx - 0x80];
1584 } else if (idx > 0xFF) {
1585 WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", idx));
1586 idx = 0x00;
1587 }
1588 }
1589 uv_rect.position.x = (int16_t)f->get_16();
1590 uv_rect.position.y = (int16_t)f->get_16();
1591 uv_rect.size.width = (int16_t)f->get_16();
1592 size.width = uv_rect.size.width;
1593 uv_rect.size.height = (int16_t)f->get_16();
1594 size.height = uv_rect.size.height;
1595 offset.x = (int16_t)f->get_16();
1596 offset.y = (int16_t)f->get_16() - ascent;
1597 advance.x = (int16_t)f->get_16();
1598 if (advance.x < 0) {
1599 advance.x = size.width + 1;
1600 }
1601
1602 int texture_idx = f->get_8();
1603 uint8_t channel = f->get_8();
1604
1605 int ch_off = 0;
1606 if (packed) {
1607 switch (channel) {
1608 case 1:
1609 ch_off = 2;
1610 break; // B
1611 case 2:
1612 ch_off = 1;
1613 break; // G
1614 case 4:
1615 ch_off = 0;
1616 break; // R
1617 case 8:
1618 ch_off = 3;
1619 break; // A
1620 default:
1621 ch_off = 0;
1622 break;
1623 }
1624 }
1625 set_glyph_advance(0, base_size, idx, advance);
1626 set_glyph_offset(0, Vector2i(base_size, 0), idx, offset);
1627 set_glyph_size(0, Vector2i(base_size, 0), idx, size);
1628 set_glyph_uv_rect(0, Vector2i(base_size, 0), idx, uv_rect);
1629 set_glyph_texture_idx(0, Vector2i(base_size, 0), idx, texture_idx * (packed ? 4 : 1) + ch_off);
1630 if (outline > 0) {
1631 set_glyph_offset(0, Vector2i(base_size, 1), idx, offset);
1632 set_glyph_size(0, Vector2i(base_size, 1), idx, size);
1633 set_glyph_uv_rect(0, Vector2i(base_size, 1), idx, uv_rect);
1634 set_glyph_texture_idx(0, Vector2i(base_size, 1), idx, texture_idx * (packed ? 4 : 1) + ch_off);
1635 }
1636 }
1637 } break;
1638 case 5: /* kerning */ {
1639 int pair_count = block_size / 10;
1640 for (int i = 0; i < pair_count; i++) {
1641 Vector2i kpk;
1642 kpk.x = f->get_32();
1643 kpk.y = f->get_32();
1644 if (!unicode && encoding < 9) {
1645 if (kpk.x >= 0x80 && kpk.x <= 0xFF) {
1646 kpk.x = _oem_to_unicode[encoding][kpk.x - 0x80];
1647 } else if (kpk.x > 0xFF) {
1648 WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", kpk.x));
1649 kpk.x = 0x00;
1650 }
1651 if (kpk.y >= 0x80 && kpk.y <= 0xFF) {
1652 kpk.y = _oem_to_unicode[encoding][kpk.y - 0x80];
1653 } else if (kpk.y > 0xFF) {
1654 WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", kpk.y));
1655 kpk.y = 0x00;
1656 }
1657 }
1658 set_kerning(0, base_size, kpk, Vector2((int16_t)f->get_16(), 0));
1659 }
1660 } break;
1661 default: {
1662 ERR_FAIL_V_MSG(ERR_CANT_CREATE, RTR("Invalid BMFont block type."));
1663 } break;
1664 }
1665 f->seek(off + block_size);
1666 block_type = f->get_8();
1667 block_size = f->get_32();
1668 }
1669
1670 } else {
1671 // Text BMFont file.
1672 f->seek(0);
1673 bool unicode = false;
1674 uint8_t encoding = 9;
1675 while (true) {
1676 String line = f->get_line();
1677
1678 int delimiter = line.find(" ");
1679 String type = line.substr(0, delimiter);
1680 int pos = delimiter + 1;
1681 HashMap<String, String> keys;
1682
1683 while (pos < line.size() && line[pos] == ' ') {
1684 pos++;
1685 }
1686
1687 while (pos < line.size()) {
1688 int eq = line.find("=", pos);
1689 if (eq == -1) {
1690 break;
1691 }
1692 String key = line.substr(pos, eq - pos);
1693 int end = -1;
1694 String value;
1695 if (line[eq + 1] == '"') {
1696 end = line.find("\"", eq + 2);
1697 if (end == -1) {
1698 break;
1699 }
1700 value = line.substr(eq + 2, end - 1 - eq - 1);
1701 pos = end + 1;
1702 } else {
1703 end = line.find(" ", eq + 1);
1704 if (end == -1) {
1705 end = line.size();
1706 }
1707 value = line.substr(eq + 1, end - eq);
1708 pos = end;
1709 }
1710
1711 while (pos < line.size() && line[pos] == ' ') {
1712 pos++;
1713 }
1714
1715 keys[key] = value;
1716 }
1717
1718 if (type == "info") {
1719 if (keys.has("size")) {
1720 base_size = keys["size"].to_int();
1721 }
1722 if (keys.has("outline")) {
1723 outline = keys["outline"].to_int();
1724 }
1725 if (keys.has("bold")) {
1726 if (keys["bold"].to_int()) {
1727 st_flags.set_flag(TextServer::FONT_BOLD);
1728 }
1729 }
1730 if (keys.has("italic")) {
1731 if (keys["italic"].to_int()) {
1732 st_flags.set_flag(TextServer::FONT_ITALIC);
1733 }
1734 }
1735 if (keys.has("face")) {
1736 font_name = keys["face"];
1737 }
1738 if (keys.has("unicode")) {
1739 unicode = keys["unicode"].to_int();
1740 }
1741 if (!unicode) {
1742 if (keys.has("charset")) {
1743 String encoding_name = keys["charset"].to_upper();
1744 if (encoding_name == "" || encoding_name == "ASCII" || encoding_name == "ANSI") {
1745 encoding = 2;
1746 } else if (encoding_name == "ARABIC") {
1747 encoding = 6;
1748 } else if (encoding_name == "BALTIC") {
1749 encoding = 7;
1750 } else if (encoding_name == "EASTEUROPE") {
1751 encoding = 0;
1752 } else if (encoding_name == "GREEK") {
1753 encoding = 3;
1754 } else if (encoding_name == "HEBREW") {
1755 encoding = 5;
1756 } else if (encoding_name == "RUSSIAN") {
1757 encoding = 1;
1758 } else if (encoding_name == "TURKISH") {
1759 encoding = 4;
1760 } else if (encoding_name == "VIETNAMESE") {
1761 encoding = 8;
1762 } else {
1763 WARN_PRINT(vformat("Unknown BMFont OEM encoding %s, parsing as Unicode (should be ANSI, ASCII, ARABIC, BALTIC, EASTEUROPE, GREEK, HEBREW, RUSSIAN, TURKISH or VIETNAMESE).", encoding_name));
1764 }
1765 } else {
1766 encoding = 2;
1767 }
1768 }
1769 set_fixed_size(base_size);
1770 } else if (type == "common") {
1771 if (keys.has("lineHeight")) {
1772 height = keys["lineHeight"].to_int();
1773 }
1774 if (keys.has("base")) {
1775 ascent = keys["base"].to_int();
1776 }
1777 if (keys.has("packed")) {
1778 packed = (keys["packed"].to_int() == 1);
1779 }
1780 if (keys.has("alphaChnl")) {
1781 ch[3] = keys["alphaChnl"].to_int();
1782 }
1783 if (keys.has("redChnl")) {
1784 ch[0] = keys["redChnl"].to_int();
1785 }
1786 if (keys.has("greenChnl")) {
1787 ch[1] = keys["greenChnl"].to_int();
1788 }
1789 if (keys.has("blueChnl")) {
1790 ch[2] = keys["blueChnl"].to_int();
1791 }
1792 for (int i = 0; i < 4; i++) {
1793 if (ch[i] == 0 && first_gl_ch == -1) {
1794 first_gl_ch = i;
1795 }
1796 if (ch[i] == 1 && first_ol_ch == -1) {
1797 first_ol_ch = i;
1798 if (outline == 0) {
1799 outline = 1;
1800 }
1801 }
1802 if (ch[i] == 2 && first_cm_ch == -1) {
1803 first_cm_ch = i;
1804 }
1805 }
1806 } else if (type == "page") {
1807 int page = 0;
1808 if (keys.has("id")) {
1809 page = keys["id"].to_int();
1810 }
1811 if (keys.has("file")) {
1812 String base_dir = p_path.get_base_dir();
1813 String file = base_dir.path_join(keys["file"]);
1814 if (RenderingServer::get_singleton() != nullptr) {
1815 Ref<Image> img;
1816 img.instantiate();
1817 Error err = ImageLoader::load_image(file, img);
1818 ERR_FAIL_COND_V_MSG(err != OK, ERR_FILE_CANT_READ, vformat(RTR("Can't load font texture: %s."), file));
1819 if (packed) {
1820 if (ch[3] == 0) { // 4 x 8 bit monochrome, no outline
1821 outline = 0;
1822 ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, RTR("Unsupported BMFont texture format."));
1823 _convert_packed_8bit(img, page, base_size);
1824 } else if ((ch[3] == 2) && (outline > 0)) { // 4 x 4 bit monochrome, gl + outline
1825 ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, RTR("Unsupported BMFont texture format."));
1826 _convert_packed_4bit(img, page, base_size);
1827 } else {
1828 ERR_FAIL_V_MSG(ERR_CANT_CREATE, RTR("Unsupported BMFont texture format."));
1829 }
1830 } else {
1831 if ((ch[3] == 0) && (ch[0] == 4) && (ch[1] == 4) && (ch[2] == 4) && img->get_format() == Image::FORMAT_RGBA8) { // might be RGBA8 color, no outline (color part of the image should be sold white, but some apps designed for Godot 3 generate color fonts with this config)
1832 outline = 0;
1833 set_texture_image(0, Vector2i(base_size, 0), page, img);
1834 } else if ((ch[0] == 0) && (ch[1] == 0) && (ch[2] == 0) && (ch[3] == 0)) { // RGBA8 color, no outline
1835 outline = 0;
1836 ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, RTR("Unsupported BMFont texture format."));
1837 set_texture_image(0, Vector2i(base_size, 0), page, img);
1838 } else if ((ch[0] == 2) && (ch[1] == 2) && (ch[2] == 2) && (ch[3] == 2) && (outline > 0)) { // RGBA4 color, gl + outline
1839 ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8, ERR_FILE_CANT_READ, RTR("Unsupported BMFont texture format."));
1840 _convert_rgba_4bit(img, page, base_size);
1841 } else if ((first_gl_ch >= 0) && (first_ol_ch >= 0) && (outline > 0)) { // 1 x 8 bit monochrome, gl + outline
1842 ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, RTR("Unsupported BMFont texture format."));
1843 _convert_mono_8bit(img, page, first_gl_ch, base_size, 0);
1844 _convert_mono_8bit(img, page, first_ol_ch, base_size, 1);
1845 } else if ((first_cm_ch >= 0) && (outline > 0)) { // 1 x 4 bit monochrome, gl + outline
1846 ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, RTR("Unsupported BMFont texture format."));
1847 _convert_mono_4bit(img, page, first_cm_ch, base_size, 1);
1848 } else if (first_gl_ch >= 0) { // 1 x 8 bit monochrome, no outline
1849 outline = 0;
1850 ERR_FAIL_COND_V_MSG(img->get_format() != Image::FORMAT_RGBA8 && img->get_format() != Image::FORMAT_L8, ERR_FILE_CANT_READ, RTR("Unsupported BMFont texture format."));
1851 _convert_mono_8bit(img, page, first_gl_ch, base_size, 0);
1852 } else {
1853 ERR_FAIL_V_MSG(ERR_CANT_CREATE, RTR("Unsupported BMFont texture format."));
1854 }
1855 }
1856 }
1857 }
1858 } else if (type == "char") {
1859 char32_t idx = 0;
1860 Vector2 advance;
1861 Vector2 size;
1862 Vector2 offset;
1863 Rect2 uv_rect;
1864 int texture_idx = -1;
1865 uint8_t channel = 15;
1866
1867 if (keys.has("id")) {
1868 idx = keys["id"].to_int();
1869 if (!unicode && encoding < 9) {
1870 if (idx >= 0x80 && idx <= 0xFF) {
1871 idx = _oem_to_unicode[encoding][idx - 0x80];
1872 } else if (idx > 0xFF) {
1873 WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", idx));
1874 idx = 0x00;
1875 }
1876 }
1877 }
1878 if (keys.has("x")) {
1879 uv_rect.position.x = keys["x"].to_int();
1880 }
1881 if (keys.has("y")) {
1882 uv_rect.position.y = keys["y"].to_int();
1883 }
1884 if (keys.has("width")) {
1885 uv_rect.size.width = keys["width"].to_int();
1886 size.width = keys["width"].to_int();
1887 }
1888 if (keys.has("height")) {
1889 uv_rect.size.height = keys["height"].to_int();
1890 size.height = keys["height"].to_int();
1891 }
1892 if (keys.has("xoffset")) {
1893 offset.x = keys["xoffset"].to_int();
1894 }
1895 if (keys.has("yoffset")) {
1896 offset.y = keys["yoffset"].to_int() - ascent;
1897 }
1898 if (keys.has("page")) {
1899 texture_idx = keys["page"].to_int();
1900 }
1901 if (keys.has("xadvance")) {
1902 advance.x = keys["xadvance"].to_int();
1903 }
1904 if (advance.x < 0) {
1905 advance.x = size.width + 1;
1906 }
1907 if (keys.has("chnl")) {
1908 channel = keys["chnl"].to_int();
1909 }
1910
1911 int ch_off = 0;
1912 if (packed) {
1913 switch (channel) {
1914 case 1:
1915 ch_off = 2;
1916 break; // B
1917 case 2:
1918 ch_off = 1;
1919 break; // G
1920 case 4:
1921 ch_off = 0;
1922 break; // R
1923 case 8:
1924 ch_off = 3;
1925 break; // A
1926 default:
1927 ch_off = 0;
1928 break;
1929 }
1930 }
1931 set_glyph_advance(0, base_size, idx, advance);
1932 set_glyph_offset(0, Vector2i(base_size, 0), idx, offset);
1933 set_glyph_size(0, Vector2i(base_size, 0), idx, size);
1934 set_glyph_uv_rect(0, Vector2i(base_size, 0), idx, uv_rect);
1935 set_glyph_texture_idx(0, Vector2i(base_size, 0), idx, texture_idx * (packed ? 4 : 1) + ch_off);
1936 if (outline > 0) {
1937 set_glyph_offset(0, Vector2i(base_size, 1), idx, offset);
1938 set_glyph_size(0, Vector2i(base_size, 1), idx, size);
1939 set_glyph_uv_rect(0, Vector2i(base_size, 1), idx, uv_rect);
1940 set_glyph_texture_idx(0, Vector2i(base_size, 1), idx, texture_idx * (packed ? 4 : 1) + ch_off);
1941 }
1942 } else if (type == "kerning") {
1943 Vector2i kpk;
1944 if (keys.has("first")) {
1945 kpk.x = keys["first"].to_int();
1946 }
1947 if (keys.has("second")) {
1948 kpk.y = keys["second"].to_int();
1949 }
1950 if (!unicode && encoding < 9) {
1951 if (kpk.x >= 0x80 && kpk.x <= 0xFF) {
1952 kpk.x = _oem_to_unicode[encoding][kpk.x - 0x80];
1953 } else if (kpk.x > 0xFF) {
1954 WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", kpk.x));
1955 kpk.x = 0x00;
1956 }
1957 if (kpk.y >= 0x80 && kpk.y <= 0xFF) {
1958 kpk.y = _oem_to_unicode[encoding][kpk.y - 0x80];
1959 } else if (kpk.y > 0xFF) {
1960 WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", kpk.x));
1961 kpk.y = 0x00;
1962 }
1963 }
1964 if (keys.has("amount")) {
1965 set_kerning(0, base_size, kpk, Vector2(keys["amount"].to_int(), 0));
1966 }
1967 }
1968
1969 if (f->eof_reached()) {
1970 break;
1971 }
1972 }
1973 }
1974
1975 set_font_name(font_name);
1976 set_font_style(st_flags);
1977 if (st_flags & TextServer::FONT_BOLD) {
1978 set_font_weight(700);
1979 }
1980 set_cache_ascent(0, base_size, ascent);
1981 set_cache_descent(0, base_size, height - ascent);
1982
1983 return OK;
1984}
1985
1986Error FontFile::load_dynamic_font(const String &p_path) {
1987 reset_state();
1988
1989 Vector<uint8_t> font_data = FileAccess::get_file_as_bytes(p_path);
1990 set_data(font_data);
1991
1992 return OK;
1993}
1994
1995void FontFile::set_data_ptr(const uint8_t *p_data, size_t p_size) {
1996 data.clear();
1997 data_ptr = p_data;
1998 data_size = p_size;
1999
2000 for (int i = 0; i < cache.size(); i++) {
2001 if (cache[i].is_valid()) {
2002 TS->font_set_data_ptr(cache[i], data_ptr, data_size);
2003 }
2004 }
2005}
2006
2007void FontFile::set_data(const PackedByteArray &p_data) {
2008 data = p_data;
2009 data_ptr = data.ptr();
2010 data_size = data.size();
2011
2012 for (int i = 0; i < cache.size(); i++) {
2013 if (cache[i].is_valid()) {
2014 TS->font_set_data_ptr(cache[i], data_ptr, data_size);
2015 }
2016 }
2017}
2018
2019PackedByteArray FontFile::get_data() const {
2020 if (unlikely((size_t)data.size() != data_size)) {
2021 PackedByteArray *data_w = const_cast<PackedByteArray *>(&data);
2022 data_w->resize(data_size);
2023 memcpy(data_w->ptrw(), data_ptr, data_size);
2024 }
2025 return data;
2026}
2027
2028void FontFile::set_font_name(const String &p_name) {
2029 _ensure_rid(0);
2030 TS->font_set_name(cache[0], p_name);
2031}
2032
2033void FontFile::set_font_style_name(const String &p_name) {
2034 _ensure_rid(0);
2035 TS->font_set_style_name(cache[0], p_name);
2036}
2037
2038void FontFile::set_font_style(BitField<TextServer::FontStyle> p_style) {
2039 _ensure_rid(0);
2040 TS->font_set_style(cache[0], p_style);
2041}
2042
2043void FontFile::set_font_weight(int p_weight) {
2044 _ensure_rid(0);
2045 TS->font_set_weight(cache[0], p_weight);
2046}
2047
2048void FontFile::set_font_stretch(int p_stretch) {
2049 _ensure_rid(0);
2050 TS->font_set_stretch(cache[0], p_stretch);
2051}
2052
2053void FontFile::set_antialiasing(TextServer::FontAntialiasing p_antialiasing) {
2054 if (antialiasing != p_antialiasing) {
2055 antialiasing = p_antialiasing;
2056 for (int i = 0; i < cache.size(); i++) {
2057 _ensure_rid(i);
2058 TS->font_set_antialiasing(cache[i], antialiasing);
2059 }
2060 emit_changed();
2061 }
2062}
2063
2064TextServer::FontAntialiasing FontFile::get_antialiasing() const {
2065 return antialiasing;
2066}
2067
2068void FontFile::set_generate_mipmaps(bool p_generate_mipmaps) {
2069 if (mipmaps != p_generate_mipmaps) {
2070 mipmaps = p_generate_mipmaps;
2071 for (int i = 0; i < cache.size(); i++) {
2072 _ensure_rid(i);
2073 TS->font_set_generate_mipmaps(cache[i], mipmaps);
2074 }
2075 emit_changed();
2076 }
2077}
2078
2079bool FontFile::get_generate_mipmaps() const {
2080 return mipmaps;
2081}
2082
2083void FontFile::set_multichannel_signed_distance_field(bool p_msdf) {
2084 if (msdf != p_msdf) {
2085 msdf = p_msdf;
2086 for (int i = 0; i < cache.size(); i++) {
2087 _ensure_rid(i);
2088 TS->font_set_multichannel_signed_distance_field(cache[i], msdf);
2089 }
2090 emit_changed();
2091 }
2092}
2093
2094bool FontFile::is_multichannel_signed_distance_field() const {
2095 return msdf;
2096}
2097
2098void FontFile::set_msdf_pixel_range(int p_msdf_pixel_range) {
2099 if (msdf_pixel_range != p_msdf_pixel_range) {
2100 msdf_pixel_range = p_msdf_pixel_range;
2101 for (int i = 0; i < cache.size(); i++) {
2102 _ensure_rid(i);
2103 TS->font_set_msdf_pixel_range(cache[i], msdf_pixel_range);
2104 }
2105 emit_changed();
2106 }
2107}
2108
2109int FontFile::get_msdf_pixel_range() const {
2110 return msdf_pixel_range;
2111}
2112
2113void FontFile::set_msdf_size(int p_msdf_size) {
2114 if (msdf_size != p_msdf_size) {
2115 msdf_size = p_msdf_size;
2116 for (int i = 0; i < cache.size(); i++) {
2117 _ensure_rid(i);
2118 TS->font_set_msdf_size(cache[i], msdf_size);
2119 }
2120 emit_changed();
2121 }
2122}
2123
2124int FontFile::get_msdf_size() const {
2125 return msdf_size;
2126}
2127
2128void FontFile::set_fixed_size(int p_fixed_size) {
2129 if (fixed_size != p_fixed_size) {
2130 fixed_size = p_fixed_size;
2131 for (int i = 0; i < cache.size(); i++) {
2132 _ensure_rid(i);
2133 TS->font_set_fixed_size(cache[i], fixed_size);
2134 }
2135 emit_changed();
2136 }
2137}
2138
2139int FontFile::get_fixed_size() const {
2140 return fixed_size;
2141}
2142
2143void FontFile::set_allow_system_fallback(bool p_allow_system_fallback) {
2144 if (allow_system_fallback != p_allow_system_fallback) {
2145 allow_system_fallback = p_allow_system_fallback;
2146 for (int i = 0; i < cache.size(); i++) {
2147 _ensure_rid(i);
2148 TS->font_set_allow_system_fallback(cache[i], allow_system_fallback);
2149 }
2150 emit_changed();
2151 }
2152}
2153
2154bool FontFile::is_allow_system_fallback() const {
2155 return allow_system_fallback;
2156}
2157
2158void FontFile::set_force_autohinter(bool p_force_autohinter) {
2159 if (force_autohinter != p_force_autohinter) {
2160 force_autohinter = p_force_autohinter;
2161 for (int i = 0; i < cache.size(); i++) {
2162 _ensure_rid(i);
2163 TS->font_set_force_autohinter(cache[i], force_autohinter);
2164 }
2165 emit_changed();
2166 }
2167}
2168
2169bool FontFile::is_force_autohinter() const {
2170 return force_autohinter;
2171}
2172
2173void FontFile::set_hinting(TextServer::Hinting p_hinting) {
2174 if (hinting != p_hinting) {
2175 hinting = p_hinting;
2176 for (int i = 0; i < cache.size(); i++) {
2177 _ensure_rid(i);
2178 TS->font_set_hinting(cache[i], hinting);
2179 }
2180 emit_changed();
2181 }
2182}
2183
2184TextServer::Hinting FontFile::get_hinting() const {
2185 return hinting;
2186}
2187
2188void FontFile::set_subpixel_positioning(TextServer::SubpixelPositioning p_subpixel) {
2189 if (subpixel_positioning != p_subpixel) {
2190 subpixel_positioning = p_subpixel;
2191 for (int i = 0; i < cache.size(); i++) {
2192 _ensure_rid(i);
2193 TS->font_set_subpixel_positioning(cache[i], subpixel_positioning);
2194 }
2195 emit_changed();
2196 }
2197}
2198
2199TextServer::SubpixelPositioning FontFile::get_subpixel_positioning() const {
2200 return subpixel_positioning;
2201}
2202
2203void FontFile::set_oversampling(real_t p_oversampling) {
2204 if (oversampling != p_oversampling) {
2205 oversampling = p_oversampling;
2206 for (int i = 0; i < cache.size(); i++) {
2207 _ensure_rid(i);
2208 TS->font_set_oversampling(cache[i], oversampling);
2209 }
2210 emit_changed();
2211 }
2212}
2213
2214real_t FontFile::get_oversampling() const {
2215 return oversampling;
2216}
2217
2218RID FontFile::find_variation(const Dictionary &p_variation_coordinates, int p_face_index, float p_strength, Transform2D p_transform, int p_spacing_top, int p_spacing_bottom, int p_spacing_space, int p_spacing_glyph) const {
2219 // Find existing variation cache.
2220 const Dictionary &supported_coords = get_supported_variation_list();
2221 for (int i = 0; i < cache.size(); i++) {
2222 if (cache[i].is_valid()) {
2223 const Dictionary &cache_var = TS->font_get_variation_coordinates(cache[i]);
2224 bool match = true;
2225 match = match && (TS->font_get_face_index(cache[i]) == p_face_index);
2226 match = match && (TS->font_get_embolden(cache[i]) == p_strength);
2227 match = match && (TS->font_get_transform(cache[i]) == p_transform);
2228 match = match && (TS->font_get_spacing(cache[i], TextServer::SPACING_TOP) == p_spacing_top);
2229 match = match && (TS->font_get_spacing(cache[i], TextServer::SPACING_BOTTOM) == p_spacing_bottom);
2230 match = match && (TS->font_get_spacing(cache[i], TextServer::SPACING_SPACE) == p_spacing_space);
2231 match = match && (TS->font_get_spacing(cache[i], TextServer::SPACING_GLYPH) == p_spacing_glyph);
2232 for (const Variant *V = supported_coords.next(nullptr); V && match; V = supported_coords.next(V)) {
2233 const Vector3 &def = supported_coords[*V];
2234
2235 real_t c_v = def.z;
2236 if (cache_var.has(*V)) {
2237 real_t val = cache_var[*V];
2238 c_v = CLAMP(val, def.x, def.y);
2239 }
2240 if (cache_var.has(TS->tag_to_name(*V))) {
2241 real_t val = cache_var[TS->tag_to_name(*V)];
2242 c_v = CLAMP(val, def.x, def.y);
2243 }
2244
2245 real_t s_v = def.z;
2246 if (p_variation_coordinates.has(*V)) {
2247 real_t val = p_variation_coordinates[*V];
2248 s_v = CLAMP(val, def.x, def.y);
2249 }
2250 if (p_variation_coordinates.has(TS->tag_to_name(*V))) {
2251 real_t val = p_variation_coordinates[TS->tag_to_name(*V)];
2252 s_v = CLAMP(val, def.x, def.y);
2253 }
2254
2255 match = match && (c_v == s_v);
2256 }
2257 if (match) {
2258 return cache[i];
2259 }
2260 }
2261 }
2262
2263 // Create new variation cache.
2264 int idx = cache.size();
2265 _ensure_rid(idx);
2266 TS->font_set_variation_coordinates(cache[idx], p_variation_coordinates);
2267 TS->font_set_face_index(cache[idx], p_face_index);
2268 TS->font_set_embolden(cache[idx], p_strength);
2269 TS->font_set_transform(cache[idx], p_transform);
2270 TS->font_set_spacing(cache[idx], TextServer::SPACING_TOP, p_spacing_top);
2271 TS->font_set_spacing(cache[idx], TextServer::SPACING_BOTTOM, p_spacing_bottom);
2272 TS->font_set_spacing(cache[idx], TextServer::SPACING_SPACE, p_spacing_space);
2273 TS->font_set_spacing(cache[idx], TextServer::SPACING_GLYPH, p_spacing_glyph);
2274 return cache[idx];
2275}
2276
2277RID FontFile::_get_rid() const {
2278 _ensure_rid(0);
2279 return cache[0];
2280}
2281
2282int FontFile::get_cache_count() const {
2283 return cache.size();
2284}
2285
2286void FontFile::clear_cache() {
2287 _clear_cache();
2288 cache.clear();
2289 emit_changed();
2290}
2291
2292void FontFile::remove_cache(int p_cache_index) {
2293 ERR_FAIL_INDEX(p_cache_index, cache.size());
2294 if (cache[p_cache_index].is_valid()) {
2295 TS->free_rid(cache.write[p_cache_index]);
2296 }
2297 cache.remove_at(p_cache_index);
2298 emit_changed();
2299}
2300
2301TypedArray<Vector2i> FontFile::get_size_cache_list(int p_cache_index) const {
2302 ERR_FAIL_COND_V(p_cache_index < 0, Array());
2303 _ensure_rid(p_cache_index);
2304 return TS->font_get_size_cache_list(cache[p_cache_index]);
2305}
2306
2307void FontFile::clear_size_cache(int p_cache_index) {
2308 ERR_FAIL_COND(p_cache_index < 0);
2309 _ensure_rid(p_cache_index);
2310 TS->font_clear_size_cache(cache[p_cache_index]);
2311}
2312
2313void FontFile::remove_size_cache(int p_cache_index, const Vector2i &p_size) {
2314 ERR_FAIL_COND(p_cache_index < 0);
2315 _ensure_rid(p_cache_index);
2316 TS->font_remove_size_cache(cache[p_cache_index], p_size);
2317}
2318
2319void FontFile::set_variation_coordinates(int p_cache_index, const Dictionary &p_variation_coordinates) {
2320 ERR_FAIL_COND(p_cache_index < 0);
2321 _ensure_rid(p_cache_index);
2322 TS->font_set_variation_coordinates(cache[p_cache_index], p_variation_coordinates);
2323}
2324
2325Dictionary FontFile::get_variation_coordinates(int p_cache_index) const {
2326 ERR_FAIL_COND_V(p_cache_index < 0, Dictionary());
2327 _ensure_rid(p_cache_index);
2328 return TS->font_get_variation_coordinates(cache[p_cache_index]);
2329}
2330
2331void FontFile::set_embolden(int p_cache_index, float p_strength) {
2332 ERR_FAIL_COND(p_cache_index < 0);
2333 _ensure_rid(p_cache_index);
2334 TS->font_set_embolden(cache[p_cache_index], p_strength);
2335}
2336
2337float FontFile::get_embolden(int p_cache_index) const {
2338 ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
2339 _ensure_rid(p_cache_index);
2340 return TS->font_get_embolden(cache[p_cache_index]);
2341}
2342
2343void FontFile::set_transform(int p_cache_index, Transform2D p_transform) {
2344 ERR_FAIL_COND(p_cache_index < 0);
2345 _ensure_rid(p_cache_index);
2346 TS->font_set_transform(cache[p_cache_index], p_transform);
2347}
2348
2349Transform2D FontFile::get_transform(int p_cache_index) const {
2350 ERR_FAIL_COND_V(p_cache_index < 0, Transform2D());
2351 _ensure_rid(p_cache_index);
2352 return TS->font_get_transform(cache[p_cache_index]);
2353}
2354
2355void FontFile::set_extra_spacing(int p_cache_index, TextServer::SpacingType p_spacing, int64_t p_value) {
2356 ERR_FAIL_COND(p_cache_index < 0);
2357 _ensure_rid(p_cache_index);
2358 TS->font_set_spacing(cache[p_cache_index], p_spacing, p_value);
2359}
2360
2361int64_t FontFile::get_extra_spacing(int p_cache_index, TextServer::SpacingType p_spacing) const {
2362 ERR_FAIL_COND_V(p_cache_index < 0, 0);
2363 _ensure_rid(p_cache_index);
2364 return TS->font_get_spacing(cache[p_cache_index], p_spacing);
2365}
2366
2367void FontFile::set_face_index(int p_cache_index, int64_t p_index) {
2368 ERR_FAIL_COND(p_cache_index < 0);
2369 ERR_FAIL_COND(p_index < 0);
2370 ERR_FAIL_COND(p_index >= 0x7FFF);
2371
2372 _ensure_rid(p_cache_index);
2373 TS->font_set_face_index(cache[p_cache_index], p_index);
2374}
2375
2376int64_t FontFile::get_face_index(int p_cache_index) const {
2377 ERR_FAIL_COND_V(p_cache_index < 0, 0);
2378 _ensure_rid(p_cache_index);
2379 return TS->font_get_face_index(cache[p_cache_index]);
2380}
2381
2382void FontFile::set_cache_ascent(int p_cache_index, int p_size, real_t p_ascent) {
2383 ERR_FAIL_COND(p_cache_index < 0);
2384 _ensure_rid(p_cache_index);
2385 TS->font_set_ascent(cache[p_cache_index], p_size, p_ascent);
2386}
2387
2388real_t FontFile::get_cache_ascent(int p_cache_index, int p_size) const {
2389 ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
2390 _ensure_rid(p_cache_index);
2391 return TS->font_get_ascent(cache[p_cache_index], p_size);
2392}
2393
2394void FontFile::set_cache_descent(int p_cache_index, int p_size, real_t p_descent) {
2395 ERR_FAIL_COND(p_cache_index < 0);
2396 _ensure_rid(p_cache_index);
2397 TS->font_set_descent(cache[p_cache_index], p_size, p_descent);
2398}
2399
2400real_t FontFile::get_cache_descent(int p_cache_index, int p_size) const {
2401 ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
2402 _ensure_rid(p_cache_index);
2403 return TS->font_get_descent(cache[p_cache_index], p_size);
2404}
2405
2406void FontFile::set_cache_underline_position(int p_cache_index, int p_size, real_t p_underline_position) {
2407 ERR_FAIL_COND(p_cache_index < 0);
2408 _ensure_rid(p_cache_index);
2409 TS->font_set_underline_position(cache[p_cache_index], p_size, p_underline_position);
2410}
2411
2412real_t FontFile::get_cache_underline_position(int p_cache_index, int p_size) const {
2413 ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
2414 _ensure_rid(p_cache_index);
2415 return TS->font_get_underline_position(cache[p_cache_index], p_size);
2416}
2417
2418void FontFile::set_cache_underline_thickness(int p_cache_index, int p_size, real_t p_underline_thickness) {
2419 ERR_FAIL_COND(p_cache_index < 0);
2420 _ensure_rid(p_cache_index);
2421 TS->font_set_underline_thickness(cache[p_cache_index], p_size, p_underline_thickness);
2422}
2423
2424real_t FontFile::get_cache_underline_thickness(int p_cache_index, int p_size) const {
2425 ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
2426 _ensure_rid(p_cache_index);
2427 return TS->font_get_underline_thickness(cache[p_cache_index], p_size);
2428}
2429
2430void FontFile::set_cache_scale(int p_cache_index, int p_size, real_t p_scale) {
2431 ERR_FAIL_COND(p_cache_index < 0);
2432 _ensure_rid(p_cache_index);
2433 TS->font_set_scale(cache[p_cache_index], p_size, p_scale);
2434}
2435
2436real_t FontFile::get_cache_scale(int p_cache_index, int p_size) const {
2437 ERR_FAIL_COND_V(p_cache_index < 0, 0.f);
2438 _ensure_rid(p_cache_index);
2439 return TS->font_get_scale(cache[p_cache_index], p_size);
2440}
2441
2442int FontFile::get_texture_count(int p_cache_index, const Vector2i &p_size) const {
2443 ERR_FAIL_COND_V(p_cache_index < 0, 0);
2444 _ensure_rid(p_cache_index);
2445 return TS->font_get_texture_count(cache[p_cache_index], p_size);
2446}
2447
2448void FontFile::clear_textures(int p_cache_index, const Vector2i &p_size) {
2449 ERR_FAIL_COND(p_cache_index < 0);
2450 _ensure_rid(p_cache_index);
2451 TS->font_clear_textures(cache[p_cache_index], p_size);
2452}
2453
2454void FontFile::remove_texture(int p_cache_index, const Vector2i &p_size, int p_texture_index) {
2455 ERR_FAIL_COND(p_cache_index < 0);
2456 _ensure_rid(p_cache_index);
2457 TS->font_remove_texture(cache[p_cache_index], p_size, p_texture_index);
2458}
2459
2460void FontFile::set_texture_image(int p_cache_index, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) {
2461 ERR_FAIL_COND(p_cache_index < 0);
2462 _ensure_rid(p_cache_index);
2463 TS->font_set_texture_image(cache[p_cache_index], p_size, p_texture_index, p_image);
2464}
2465
2466Ref<Image> FontFile::get_texture_image(int p_cache_index, const Vector2i &p_size, int p_texture_index) const {
2467 ERR_FAIL_COND_V(p_cache_index < 0, Ref<Image>());
2468 _ensure_rid(p_cache_index);
2469 return TS->font_get_texture_image(cache[p_cache_index], p_size, p_texture_index);
2470}
2471
2472void FontFile::set_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) {
2473 ERR_FAIL_COND(p_cache_index < 0);
2474 _ensure_rid(p_cache_index);
2475 TS->font_set_texture_offsets(cache[p_cache_index], p_size, p_texture_index, p_offset);
2476}
2477
2478PackedInt32Array FontFile::get_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index) const {
2479 ERR_FAIL_COND_V(p_cache_index < 0, PackedInt32Array());
2480 _ensure_rid(p_cache_index);
2481 return TS->font_get_texture_offsets(cache[p_cache_index], p_size, p_texture_index);
2482}
2483
2484PackedInt32Array FontFile::get_glyph_list(int p_cache_index, const Vector2i &p_size) const {
2485 ERR_FAIL_COND_V(p_cache_index < 0, PackedInt32Array());
2486 _ensure_rid(p_cache_index);
2487 return TS->font_get_glyph_list(cache[p_cache_index], p_size);
2488}
2489
2490void FontFile::clear_glyphs(int p_cache_index, const Vector2i &p_size) {
2491 ERR_FAIL_COND(p_cache_index < 0);
2492 _ensure_rid(p_cache_index);
2493 TS->font_clear_glyphs(cache[p_cache_index], p_size);
2494}
2495
2496void FontFile::remove_glyph(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) {
2497 ERR_FAIL_COND(p_cache_index < 0);
2498 _ensure_rid(p_cache_index);
2499 TS->font_remove_glyph(cache[p_cache_index], p_size, p_glyph);
2500}
2501
2502void FontFile::set_glyph_advance(int p_cache_index, int p_size, int32_t p_glyph, const Vector2 &p_advance) {
2503 ERR_FAIL_COND(p_cache_index < 0);
2504 _ensure_rid(p_cache_index);
2505 TS->font_set_glyph_advance(cache[p_cache_index], p_size, p_glyph, p_advance);
2506}
2507
2508Vector2 FontFile::get_glyph_advance(int p_cache_index, int p_size, int32_t p_glyph) const {
2509 ERR_FAIL_COND_V(p_cache_index < 0, Vector2());
2510 _ensure_rid(p_cache_index);
2511 return TS->font_get_glyph_advance(cache[p_cache_index], p_size, p_glyph);
2512}
2513
2514void FontFile::set_glyph_offset(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) {
2515 ERR_FAIL_COND(p_cache_index < 0);
2516 _ensure_rid(p_cache_index);
2517 TS->font_set_glyph_offset(cache[p_cache_index], p_size, p_glyph, p_offset);
2518}
2519
2520Vector2 FontFile::get_glyph_offset(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
2521 ERR_FAIL_COND_V(p_cache_index < 0, Vector2());
2522 _ensure_rid(p_cache_index);
2523 return TS->font_get_glyph_offset(cache[p_cache_index], p_size, p_glyph);
2524}
2525
2526void FontFile::set_glyph_size(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) {
2527 ERR_FAIL_COND(p_cache_index < 0);
2528 _ensure_rid(p_cache_index);
2529 TS->font_set_glyph_size(cache[p_cache_index], p_size, p_glyph, p_gl_size);
2530}
2531
2532Vector2 FontFile::get_glyph_size(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
2533 ERR_FAIL_COND_V(p_cache_index < 0, Vector2());
2534 _ensure_rid(p_cache_index);
2535 return TS->font_get_glyph_size(cache[p_cache_index], p_size, p_glyph);
2536}
2537
2538void FontFile::set_glyph_uv_rect(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) {
2539 ERR_FAIL_COND(p_cache_index < 0);
2540 _ensure_rid(p_cache_index);
2541 TS->font_set_glyph_uv_rect(cache[p_cache_index], p_size, p_glyph, p_uv_rect);
2542}
2543
2544Rect2 FontFile::get_glyph_uv_rect(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
2545 ERR_FAIL_COND_V(p_cache_index < 0, Rect2());
2546 _ensure_rid(p_cache_index);
2547 return TS->font_get_glyph_uv_rect(cache[p_cache_index], p_size, p_glyph);
2548}
2549
2550void FontFile::set_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) {
2551 ERR_FAIL_COND(p_cache_index < 0);
2552 _ensure_rid(p_cache_index);
2553 TS->font_set_glyph_texture_idx(cache[p_cache_index], p_size, p_glyph, p_texture_idx);
2554}
2555
2556int FontFile::get_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const {
2557 ERR_FAIL_COND_V(p_cache_index < 0, 0);
2558 _ensure_rid(p_cache_index);
2559 return TS->font_get_glyph_texture_idx(cache[p_cache_index], p_size, p_glyph);
2560}
2561
2562TypedArray<Vector2i> FontFile::get_kerning_list(int p_cache_index, int p_size) const {
2563 ERR_FAIL_COND_V(p_cache_index < 0, Array());
2564 _ensure_rid(p_cache_index);
2565 return TS->font_get_kerning_list(cache[p_cache_index], p_size);
2566}
2567
2568void FontFile::clear_kerning_map(int p_cache_index, int p_size) {
2569 ERR_FAIL_COND(p_cache_index < 0);
2570 _ensure_rid(p_cache_index);
2571 TS->font_clear_kerning_map(cache[p_cache_index], p_size);
2572}
2573
2574void FontFile::remove_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair) {
2575 ERR_FAIL_COND(p_cache_index < 0);
2576 _ensure_rid(p_cache_index);
2577 TS->font_remove_kerning(cache[p_cache_index], p_size, p_glyph_pair);
2578}
2579
2580void FontFile::set_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
2581 ERR_FAIL_COND(p_cache_index < 0);
2582 _ensure_rid(p_cache_index);
2583 TS->font_set_kerning(cache[p_cache_index], p_size, p_glyph_pair, p_kerning);
2584}
2585
2586Vector2 FontFile::get_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair) const {
2587 ERR_FAIL_COND_V(p_cache_index < 0, Vector2());
2588 _ensure_rid(p_cache_index);
2589 return TS->font_get_kerning(cache[p_cache_index], p_size, p_glyph_pair);
2590}
2591
2592void FontFile::render_range(int p_cache_index, const Vector2i &p_size, char32_t p_start, char32_t p_end) {
2593 ERR_FAIL_COND(p_cache_index < 0);
2594 _ensure_rid(p_cache_index);
2595 TS->font_render_range(cache[p_cache_index], p_size, p_start, p_end);
2596}
2597
2598void FontFile::render_glyph(int p_cache_index, const Vector2i &p_size, int32_t p_index) {
2599 ERR_FAIL_COND(p_cache_index < 0);
2600 _ensure_rid(p_cache_index);
2601 TS->font_render_glyph(cache[p_cache_index], p_size, p_index);
2602}
2603
2604void FontFile::set_language_support_override(const String &p_language, bool p_supported) {
2605 _ensure_rid(0);
2606 TS->font_set_language_support_override(cache[0], p_language, p_supported);
2607}
2608
2609bool FontFile::get_language_support_override(const String &p_language) const {
2610 _ensure_rid(0);
2611 return TS->font_get_language_support_override(cache[0], p_language);
2612}
2613
2614void FontFile::remove_language_support_override(const String &p_language) {
2615 _ensure_rid(0);
2616 TS->font_remove_language_support_override(cache[0], p_language);
2617}
2618
2619Vector<String> FontFile::get_language_support_overrides() const {
2620 _ensure_rid(0);
2621 return TS->font_get_language_support_overrides(cache[0]);
2622}
2623
2624void FontFile::set_script_support_override(const String &p_script, bool p_supported) {
2625 _ensure_rid(0);
2626 TS->font_set_script_support_override(cache[0], p_script, p_supported);
2627}
2628
2629bool FontFile::get_script_support_override(const String &p_script) const {
2630 _ensure_rid(0);
2631 return TS->font_get_script_support_override(cache[0], p_script);
2632}
2633
2634void FontFile::remove_script_support_override(const String &p_script) {
2635 _ensure_rid(0);
2636 TS->font_remove_script_support_override(cache[0], p_script);
2637}
2638
2639Vector<String> FontFile::get_script_support_overrides() const {
2640 _ensure_rid(0);
2641 return TS->font_get_script_support_overrides(cache[0]);
2642}
2643
2644void FontFile::set_opentype_feature_overrides(const Dictionary &p_overrides) {
2645 _ensure_rid(0);
2646 TS->font_set_opentype_feature_overrides(cache[0], p_overrides);
2647}
2648
2649Dictionary FontFile::get_opentype_feature_overrides() const {
2650 _ensure_rid(0);
2651 return TS->font_get_opentype_feature_overrides(cache[0]);
2652}
2653
2654int32_t FontFile::get_glyph_index(int p_size, char32_t p_char, char32_t p_variation_selector) const {
2655 _ensure_rid(0);
2656 return TS->font_get_glyph_index(cache[0], p_size, p_char, p_variation_selector);
2657}
2658
2659char32_t FontFile::get_char_from_glyph_index(int p_size, int32_t p_glyph_index) const {
2660 _ensure_rid(0);
2661 return TS->font_get_char_from_glyph_index(cache[0], p_size, p_glyph_index);
2662}
2663
2664FontFile::FontFile() {
2665}
2666
2667FontFile::~FontFile() {
2668 _clear_cache();
2669}
2670
2671/*************************************************************************/
2672/* FontVariation */
2673/*************************************************************************/
2674
2675void FontVariation::_bind_methods() {
2676 ClassDB::bind_method(D_METHOD("set_base_font", "font"), &FontVariation::set_base_font);
2677 ClassDB::bind_method(D_METHOD("get_base_font"), &FontVariation::get_base_font);
2678
2679 ClassDB::bind_method(D_METHOD("set_variation_opentype", "coords"), &FontVariation::set_variation_opentype);
2680 ClassDB::bind_method(D_METHOD("get_variation_opentype"), &FontVariation::get_variation_opentype);
2681
2682 ClassDB::bind_method(D_METHOD("set_variation_embolden", "strength"), &FontVariation::set_variation_embolden);
2683 ClassDB::bind_method(D_METHOD("get_variation_embolden"), &FontVariation::get_variation_embolden);
2684
2685 ClassDB::bind_method(D_METHOD("set_variation_face_index", "face_index"), &FontVariation::set_variation_face_index);
2686 ClassDB::bind_method(D_METHOD("get_variation_face_index"), &FontVariation::get_variation_face_index);
2687
2688 ClassDB::bind_method(D_METHOD("set_variation_transform", "transform"), &FontVariation::set_variation_transform);
2689 ClassDB::bind_method(D_METHOD("get_variation_transform"), &FontVariation::get_variation_transform);
2690
2691 ClassDB::bind_method(D_METHOD("set_opentype_features", "features"), &FontVariation::set_opentype_features);
2692
2693 ClassDB::bind_method(D_METHOD("set_spacing", "spacing", "value"), &FontVariation::set_spacing);
2694
2695 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base_font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_base_font", "get_base_font");
2696
2697 ADD_GROUP("Variation", "variation_");
2698 ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "variation_opentype"), "set_variation_opentype", "get_variation_opentype");
2699 ADD_PROPERTY(PropertyInfo(Variant::INT, "variation_face_index"), "set_variation_face_index", "get_variation_face_index");
2700 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "variation_embolden", PROPERTY_HINT_RANGE, "-2,2,0.01"), "set_variation_embolden", "get_variation_embolden");
2701 ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "variation_transform", PROPERTY_HINT_NONE, "suffix:px"), "set_variation_transform", "get_variation_transform");
2702
2703 ADD_GROUP("OpenType Features", "opentype_");
2704 ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "opentype_features"), "set_opentype_features", "get_opentype_features");
2705
2706 ADD_GROUP("Extra Spacing", "spacing_");
2707 ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_glyph", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_GLYPH);
2708 ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_space", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_SPACE);
2709 ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_top", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_TOP);
2710 ADD_PROPERTYI(PropertyInfo(Variant::INT, "spacing_bottom", PROPERTY_HINT_NONE, "suffix:px"), "set_spacing", "get_spacing", TextServer::SPACING_BOTTOM);
2711}
2712
2713void FontVariation::_update_rids() const {
2714 Ref<Font> f = _get_base_font_or_default();
2715
2716 rids.clear();
2717 if (fallbacks.is_empty() && f.is_valid()) {
2718 RID rid = _get_rid();
2719 if (rid.is_valid()) {
2720 rids.push_back(rid);
2721 }
2722
2723 const TypedArray<Font> &base_fallbacks = f->get_fallbacks();
2724 for (int i = 0; i < base_fallbacks.size(); i++) {
2725 _update_rids_fb(base_fallbacks[i], 0);
2726 }
2727 } else {
2728 _update_rids_fb(const_cast<FontVariation *>(this), 0);
2729 }
2730 dirty_rids = false;
2731}
2732
2733void FontVariation::reset_state() {
2734 if (base_font.is_valid()) {
2735 base_font->disconnect_changed(callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
2736 base_font.unref();
2737 }
2738
2739 if (theme_font.is_valid()) {
2740 theme_font->disconnect_changed(callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
2741 theme_font.unref();
2742 }
2743
2744 variation = Variation();
2745 opentype_features = Dictionary();
2746
2747 for (int i = 0; i < TextServer::SPACING_MAX; i++) {
2748 extra_spacing[i] = 0;
2749 }
2750
2751 Font::reset_state();
2752}
2753
2754void FontVariation::set_base_font(const Ref<Font> &p_font) {
2755 if (base_font != p_font) {
2756 if (base_font.is_valid()) {
2757 base_font->disconnect_changed(callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
2758 }
2759 base_font = p_font;
2760 if (base_font.is_valid()) {
2761 base_font->connect_changed(callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
2762 }
2763 _invalidate_rids();
2764 notify_property_list_changed();
2765 }
2766}
2767
2768Ref<Font> FontVariation::get_base_font() const {
2769 return base_font;
2770}
2771
2772Ref<Font> FontVariation::_get_base_font_or_default() const {
2773 if (theme_font.is_valid()) {
2774 theme_font->disconnect_changed(callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids));
2775 theme_font.unref();
2776 }
2777
2778 if (base_font.is_valid()) {
2779 return base_font;
2780 }
2781
2782 StringName theme_name = "font";
2783 List<StringName> theme_types;
2784 ThemeDB::get_singleton()->get_native_type_dependencies(get_class_name(), &theme_types);
2785
2786 ThemeContext *global_context = ThemeDB::get_singleton()->get_default_theme_context();
2787 for (const Ref<Theme> &theme : global_context->get_themes()) {
2788 if (theme.is_null()) {
2789 continue;
2790 }
2791
2792 for (const StringName &E : theme_types) {
2793 if (!theme->has_font(theme_name, E)) {
2794 continue;
2795 }
2796
2797 Ref<Font> f = theme->get_font(theme_name, E);
2798 if (f == this) {
2799 continue;
2800 }
2801 if (f.is_valid()) {
2802 theme_font = f;
2803 theme_font->connect_changed(callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
2804 }
2805 return f;
2806 }
2807 }
2808
2809 Ref<Font> f = global_context->get_fallback_theme()->get_font(theme_name, StringName());
2810 if (f != this) {
2811 if (f.is_valid()) {
2812 theme_font = f;
2813 theme_font->connect_changed(callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
2814 }
2815 return f;
2816 }
2817
2818 return Ref<Font>();
2819}
2820
2821void FontVariation::set_variation_opentype(const Dictionary &p_coords) {
2822 if (!variation.opentype.recursive_equal(p_coords, 1)) {
2823 variation.opentype = p_coords.duplicate();
2824 _invalidate_rids();
2825 }
2826}
2827
2828Dictionary FontVariation::get_variation_opentype() const {
2829 return variation.opentype.duplicate();
2830}
2831
2832void FontVariation::set_variation_embolden(float p_strength) {
2833 if (variation.embolden != p_strength) {
2834 variation.embolden = p_strength;
2835 _invalidate_rids();
2836 }
2837}
2838
2839float FontVariation::get_variation_embolden() const {
2840 return variation.embolden;
2841}
2842
2843void FontVariation::set_variation_transform(Transform2D p_transform) {
2844 if (variation.transform != p_transform) {
2845 variation.transform = p_transform;
2846 _invalidate_rids();
2847 }
2848}
2849
2850Transform2D FontVariation::get_variation_transform() const {
2851 return variation.transform;
2852}
2853
2854void FontVariation::set_variation_face_index(int p_face_index) {
2855 if (variation.face_index != p_face_index) {
2856 variation.face_index = p_face_index;
2857 _invalidate_rids();
2858 }
2859}
2860
2861int FontVariation::get_variation_face_index() const {
2862 return variation.face_index;
2863}
2864
2865void FontVariation::set_opentype_features(const Dictionary &p_features) {
2866 if (!opentype_features.recursive_equal(p_features, 1)) {
2867 opentype_features = p_features.duplicate();
2868 _invalidate_rids();
2869 }
2870}
2871
2872Dictionary FontVariation::get_opentype_features() const {
2873 return opentype_features.duplicate();
2874}
2875
2876void FontVariation::set_spacing(TextServer::SpacingType p_spacing, int p_value) {
2877 ERR_FAIL_INDEX((int)p_spacing, TextServer::SPACING_MAX);
2878 if (extra_spacing[p_spacing] != p_value) {
2879 extra_spacing[p_spacing] = p_value;
2880 _invalidate_rids();
2881 }
2882}
2883
2884int FontVariation::get_spacing(TextServer::SpacingType p_spacing) const {
2885 ERR_FAIL_INDEX_V((int)p_spacing, TextServer::SPACING_MAX, 0);
2886 return extra_spacing[p_spacing];
2887}
2888
2889RID FontVariation::find_variation(const Dictionary &p_variation_coordinates, int p_face_index, float p_strength, Transform2D p_transform, int p_spacing_top, int p_spacing_bottom, int p_spacing_space, int p_spacing_glyph) const {
2890 Ref<Font> f = _get_base_font_or_default();
2891 if (f.is_valid()) {
2892 return f->find_variation(p_variation_coordinates, p_face_index, p_strength, p_transform, p_spacing_top, p_spacing_bottom, p_spacing_space, p_spacing_glyph);
2893 }
2894 return RID();
2895}
2896
2897RID FontVariation::_get_rid() const {
2898 Ref<Font> f = _get_base_font_or_default();
2899 if (f.is_valid()) {
2900 return f->find_variation(variation.opentype, variation.face_index, variation.embolden, variation.transform, extra_spacing[TextServer::SPACING_TOP], extra_spacing[TextServer::SPACING_BOTTOM], extra_spacing[TextServer::SPACING_SPACE], extra_spacing[TextServer::SPACING_GLYPH]);
2901 }
2902 return RID();
2903}
2904
2905FontVariation::FontVariation() {
2906 for (int i = 0; i < TextServer::SPACING_MAX; i++) {
2907 extra_spacing[i] = 0;
2908 }
2909}
2910
2911FontVariation::~FontVariation() {
2912}
2913
2914/*************************************************************************/
2915/* SystemFont */
2916/*************************************************************************/
2917
2918void SystemFont::_bind_methods() {
2919 ClassDB::bind_method(D_METHOD("set_antialiasing", "antialiasing"), &SystemFont::set_antialiasing);
2920 ClassDB::bind_method(D_METHOD("get_antialiasing"), &SystemFont::get_antialiasing);
2921
2922 ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "generate_mipmaps"), &SystemFont::set_generate_mipmaps);
2923 ClassDB::bind_method(D_METHOD("get_generate_mipmaps"), &SystemFont::get_generate_mipmaps);
2924
2925 ClassDB::bind_method(D_METHOD("set_allow_system_fallback", "allow_system_fallback"), &SystemFont::set_allow_system_fallback);
2926 ClassDB::bind_method(D_METHOD("is_allow_system_fallback"), &SystemFont::is_allow_system_fallback);
2927
2928 ClassDB::bind_method(D_METHOD("set_force_autohinter", "force_autohinter"), &SystemFont::set_force_autohinter);
2929 ClassDB::bind_method(D_METHOD("is_force_autohinter"), &SystemFont::is_force_autohinter);
2930
2931 ClassDB::bind_method(D_METHOD("set_hinting", "hinting"), &SystemFont::set_hinting);
2932 ClassDB::bind_method(D_METHOD("get_hinting"), &SystemFont::get_hinting);
2933
2934 ClassDB::bind_method(D_METHOD("set_subpixel_positioning", "subpixel_positioning"), &SystemFont::set_subpixel_positioning);
2935 ClassDB::bind_method(D_METHOD("get_subpixel_positioning"), &SystemFont::get_subpixel_positioning);
2936
2937 ClassDB::bind_method(D_METHOD("set_multichannel_signed_distance_field", "msdf"), &SystemFont::set_multichannel_signed_distance_field);
2938 ClassDB::bind_method(D_METHOD("is_multichannel_signed_distance_field"), &SystemFont::is_multichannel_signed_distance_field);
2939
2940 ClassDB::bind_method(D_METHOD("set_msdf_pixel_range", "msdf_pixel_range"), &SystemFont::set_msdf_pixel_range);
2941 ClassDB::bind_method(D_METHOD("get_msdf_pixel_range"), &SystemFont::get_msdf_pixel_range);
2942
2943 ClassDB::bind_method(D_METHOD("set_msdf_size", "msdf_size"), &SystemFont::set_msdf_size);
2944 ClassDB::bind_method(D_METHOD("get_msdf_size"), &SystemFont::get_msdf_size);
2945
2946 ClassDB::bind_method(D_METHOD("set_oversampling", "oversampling"), &SystemFont::set_oversampling);
2947 ClassDB::bind_method(D_METHOD("get_oversampling"), &SystemFont::get_oversampling);
2948
2949 ClassDB::bind_method(D_METHOD("get_font_names"), &SystemFont::get_font_names);
2950 ClassDB::bind_method(D_METHOD("set_font_names", "names"), &SystemFont::set_font_names);
2951
2952 ClassDB::bind_method(D_METHOD("get_font_italic"), &SystemFont::get_font_italic);
2953 ClassDB::bind_method(D_METHOD("set_font_italic", "italic"), &SystemFont::set_font_italic);
2954 ClassDB::bind_method(D_METHOD("set_font_weight", "weight"), &SystemFont::set_font_weight);
2955 ClassDB::bind_method(D_METHOD("set_font_stretch", "stretch"), &SystemFont::set_font_stretch);
2956
2957 ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "font_names"), "set_font_names", "get_font_names");
2958 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "font_italic"), "set_font_italic", "get_font_italic");
2959 ADD_PROPERTY(PropertyInfo(Variant::INT, "font_weight", PROPERTY_HINT_RANGE, "100,999,25"), "set_font_weight", "get_font_weight");
2960 ADD_PROPERTY(PropertyInfo(Variant::INT, "font_stretch", PROPERTY_HINT_RANGE, "50,200,25"), "set_font_stretch", "get_font_stretch");
2961 ADD_PROPERTY(PropertyInfo(Variant::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD Subpixel", PROPERTY_USAGE_STORAGE), "set_antialiasing", "get_antialiasing");
2962 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps"), "set_generate_mipmaps", "get_generate_mipmaps");
2963 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_system_fallback"), "set_allow_system_fallback", "is_allow_system_fallback");
2964 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_autohinter"), "set_force_autohinter", "is_force_autohinter");
2965 ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), "set_hinting", "get_hinting");
2966 ADD_PROPERTY(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One Half of a Pixel,One Quarter of a Pixel"), "set_subpixel_positioning", "get_subpixel_positioning");
2967 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field"), "set_multichannel_signed_distance_field", "is_multichannel_signed_distance_field");
2968 ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_pixel_range"), "set_msdf_pixel_range", "get_msdf_pixel_range");
2969 ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_size"), "set_msdf_size", "get_msdf_size");
2970 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_RANGE, "0,10,0.1"), "set_oversampling", "get_oversampling");
2971}
2972
2973void SystemFont::_update_rids() const {
2974 Ref<Font> f = _get_base_font_or_default();
2975
2976 rids.clear();
2977 if (fallbacks.is_empty() && f.is_valid()) {
2978 RID rid = _get_rid();
2979 if (rid.is_valid()) {
2980 rids.push_back(rid);
2981 }
2982
2983 const TypedArray<Font> &base_fallbacks = f->get_fallbacks();
2984 for (int i = 0; i < base_fallbacks.size(); i++) {
2985 _update_rids_fb(base_fallbacks[i], 0);
2986 }
2987 } else {
2988 _update_rids_fb(const_cast<SystemFont *>(this), 0);
2989 }
2990 dirty_rids = false;
2991}
2992
2993void SystemFont::_update_base_font() {
2994 if (base_font.is_valid()) {
2995 base_font->disconnect_changed(callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
2996 base_font.unref();
2997 }
2998
2999 face_indeces.clear();
3000 ftr_weight = 0;
3001 ftr_stretch = 0;
3002 ftr_italic = 0;
3003 for (const String &E : names) {
3004 if (E.is_empty()) {
3005 continue;
3006 }
3007
3008 String path = OS::get_singleton()->get_system_font_path(E, weight, stretch, italic);
3009 if (path.is_empty()) {
3010 continue;
3011 }
3012 Ref<FontFile> file;
3013 file.instantiate();
3014 Error err = file->load_dynamic_font(path);
3015 if (err != OK) {
3016 continue;
3017 }
3018
3019 // If it's a font collection check all faces to match requested style.
3020 int best_score = 0;
3021 for (int i = 0; i < file->get_face_count(); i++) {
3022 file->set_face_index(0, i);
3023 BitField<TextServer::FontStyle> style = file->get_font_style();
3024 int font_weight = file->get_font_weight();
3025 int font_stretch = file->get_font_stretch();
3026 int score = (20 - Math::abs(font_weight - weight) / 50);
3027 score += (20 - Math::abs(font_stretch - stretch) / 10);
3028 if (bool(style & TextServer::FONT_ITALIC) == italic) {
3029 score += 30;
3030 }
3031 if (score > best_score) {
3032 face_indeces.clear();
3033 }
3034 if (score >= best_score) {
3035 best_score = score;
3036 face_indeces.push_back(i);
3037 }
3038 }
3039 if (face_indeces.is_empty()) {
3040 face_indeces.push_back(0);
3041 }
3042 file->set_face_index(0, face_indeces[0]);
3043
3044 // If it's a variable font, apply weight, stretch and italic coordinates to match requested style.
3045 if (best_score != 50) {
3046 Dictionary ftr = file->get_supported_variation_list();
3047 if (ftr.has(TS->name_to_tag("width"))) {
3048 ftr_stretch = stretch;
3049 }
3050 if (ftr.has(TS->name_to_tag("weight"))) {
3051 ftr_weight = weight;
3052 }
3053 if (italic && ftr.has(TS->name_to_tag("italic"))) {
3054 ftr_italic = 1;
3055 }
3056 }
3057
3058 // Apply font rendering settings.
3059 file->set_antialiasing(antialiasing);
3060 file->set_generate_mipmaps(mipmaps);
3061 file->set_force_autohinter(force_autohinter);
3062 file->set_allow_system_fallback(allow_system_fallback);
3063 file->set_hinting(hinting);
3064 file->set_subpixel_positioning(subpixel_positioning);
3065 file->set_multichannel_signed_distance_field(msdf);
3066 file->set_msdf_pixel_range(msdf_pixel_range);
3067 file->set_msdf_size(msdf_size);
3068 file->set_oversampling(oversampling);
3069
3070 base_font = file;
3071
3072 break;
3073 }
3074
3075 if (base_font.is_valid()) {
3076 base_font->connect_changed(callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
3077 }
3078
3079 _invalidate_rids();
3080 notify_property_list_changed();
3081}
3082
3083void SystemFont::reset_state() {
3084 if (base_font.is_valid()) {
3085 base_font->disconnect_changed(callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
3086 base_font.unref();
3087 }
3088
3089 if (theme_font.is_valid()) {
3090 theme_font->disconnect_changed(callable_mp(reinterpret_cast<Font *>(this), &Font::_invalidate_rids));
3091 theme_font.unref();
3092 }
3093
3094 names.clear();
3095 face_indeces.clear();
3096 ftr_weight = 0;
3097 ftr_stretch = 0;
3098 ftr_italic = 0;
3099 italic = false;
3100 weight = 400;
3101 stretch = 100;
3102 antialiasing = TextServer::FONT_ANTIALIASING_GRAY;
3103 mipmaps = false;
3104 force_autohinter = false;
3105 allow_system_fallback = true;
3106 hinting = TextServer::HINTING_LIGHT;
3107 subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED;
3108 oversampling = 0.f;
3109 msdf = false;
3110
3111 Font::reset_state();
3112}
3113
3114Ref<Font> SystemFont::_get_base_font_or_default() const {
3115 if (theme_font.is_valid()) {
3116 theme_font->disconnect_changed(callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids));
3117 theme_font.unref();
3118 }
3119
3120 if (base_font.is_valid()) {
3121 return base_font;
3122 }
3123
3124 StringName theme_name = "font";
3125 List<StringName> theme_types;
3126 ThemeDB::get_singleton()->get_native_type_dependencies(get_class_name(), &theme_types);
3127
3128 ThemeContext *global_context = ThemeDB::get_singleton()->get_default_theme_context();
3129 for (const Ref<Theme> &theme : global_context->get_themes()) {
3130 if (theme.is_null()) {
3131 continue;
3132 }
3133
3134 for (const StringName &E : theme_types) {
3135 if (!theme->has_font(theme_name, E)) {
3136 continue;
3137 }
3138
3139 Ref<Font> f = theme->get_font(theme_name, E);
3140 if (f == this) {
3141 continue;
3142 }
3143 if (f.is_valid()) {
3144 theme_font = f;
3145 theme_font->connect_changed(callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
3146 }
3147 return f;
3148 }
3149 }
3150
3151 Ref<Font> f = global_context->get_fallback_theme()->get_font(theme_name, StringName());
3152 if (f != this) {
3153 if (f.is_valid()) {
3154 theme_font = f;
3155 theme_font->connect_changed(callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
3156 }
3157 return f;
3158 }
3159
3160 return Ref<Font>();
3161}
3162
3163void SystemFont::set_antialiasing(TextServer::FontAntialiasing p_antialiasing) {
3164 if (antialiasing != p_antialiasing) {
3165 antialiasing = p_antialiasing;
3166 if (base_font.is_valid()) {
3167 base_font->set_antialiasing(antialiasing);
3168 }
3169 emit_changed();
3170 }
3171}
3172
3173TextServer::FontAntialiasing SystemFont::get_antialiasing() const {
3174 return antialiasing;
3175}
3176
3177void SystemFont::set_generate_mipmaps(bool p_generate_mipmaps) {
3178 if (mipmaps != p_generate_mipmaps) {
3179 mipmaps = p_generate_mipmaps;
3180 if (base_font.is_valid()) {
3181 base_font->set_generate_mipmaps(mipmaps);
3182 }
3183 emit_changed();
3184 }
3185}
3186
3187bool SystemFont::get_generate_mipmaps() const {
3188 return mipmaps;
3189}
3190
3191void SystemFont::set_allow_system_fallback(bool p_allow_system_fallback) {
3192 if (allow_system_fallback != p_allow_system_fallback) {
3193 allow_system_fallback = p_allow_system_fallback;
3194 if (base_font.is_valid()) {
3195 base_font->set_allow_system_fallback(allow_system_fallback);
3196 }
3197 emit_changed();
3198 }
3199}
3200
3201bool SystemFont::is_allow_system_fallback() const {
3202 return allow_system_fallback;
3203}
3204
3205void SystemFont::set_force_autohinter(bool p_force_autohinter) {
3206 if (force_autohinter != p_force_autohinter) {
3207 force_autohinter = p_force_autohinter;
3208 if (base_font.is_valid()) {
3209 base_font->set_force_autohinter(force_autohinter);
3210 }
3211 emit_changed();
3212 }
3213}
3214
3215bool SystemFont::is_force_autohinter() const {
3216 return force_autohinter;
3217}
3218
3219void SystemFont::set_hinting(TextServer::Hinting p_hinting) {
3220 if (hinting != p_hinting) {
3221 hinting = p_hinting;
3222 if (base_font.is_valid()) {
3223 base_font->set_hinting(hinting);
3224 }
3225 emit_changed();
3226 }
3227}
3228
3229TextServer::Hinting SystemFont::get_hinting() const {
3230 return hinting;
3231}
3232
3233void SystemFont::set_subpixel_positioning(TextServer::SubpixelPositioning p_subpixel) {
3234 if (subpixel_positioning != p_subpixel) {
3235 subpixel_positioning = p_subpixel;
3236 if (base_font.is_valid()) {
3237 base_font->set_subpixel_positioning(subpixel_positioning);
3238 }
3239 emit_changed();
3240 }
3241}
3242
3243TextServer::SubpixelPositioning SystemFont::get_subpixel_positioning() const {
3244 return subpixel_positioning;
3245}
3246
3247void SystemFont::set_multichannel_signed_distance_field(bool p_msdf) {
3248 if (msdf != p_msdf) {
3249 msdf = p_msdf;
3250 if (base_font.is_valid()) {
3251 base_font->set_multichannel_signed_distance_field(msdf);
3252 }
3253 emit_changed();
3254 }
3255}
3256
3257bool SystemFont::is_multichannel_signed_distance_field() const {
3258 return msdf;
3259}
3260
3261void SystemFont::set_msdf_pixel_range(int p_msdf_pixel_range) {
3262 if (msdf_pixel_range != p_msdf_pixel_range) {
3263 msdf_pixel_range = p_msdf_pixel_range;
3264 if (base_font.is_valid()) {
3265 base_font->set_msdf_pixel_range(msdf_pixel_range);
3266 }
3267 emit_changed();
3268 }
3269}
3270
3271int SystemFont::get_msdf_pixel_range() const {
3272 return msdf_pixel_range;
3273}
3274
3275void SystemFont::set_msdf_size(int p_msdf_size) {
3276 if (msdf_size != p_msdf_size) {
3277 msdf_size = p_msdf_size;
3278 if (base_font.is_valid()) {
3279 base_font->set_msdf_size(msdf_size);
3280 }
3281 emit_changed();
3282 }
3283}
3284
3285int SystemFont::get_msdf_size() const {
3286 return msdf_size;
3287}
3288
3289void SystemFont::set_oversampling(real_t p_oversampling) {
3290 if (oversampling != p_oversampling) {
3291 oversampling = p_oversampling;
3292 if (base_font.is_valid()) {
3293 base_font->set_oversampling(oversampling);
3294 }
3295 emit_changed();
3296 }
3297}
3298
3299real_t SystemFont::get_oversampling() const {
3300 return oversampling;
3301}
3302
3303void SystemFont::set_font_names(const PackedStringArray &p_names) {
3304 if (names != p_names) {
3305 names = p_names;
3306 _update_base_font();
3307 }
3308}
3309
3310PackedStringArray SystemFont::get_font_names() const {
3311 return names;
3312}
3313
3314void SystemFont::set_font_italic(bool p_italic) {
3315 if (italic != p_italic) {
3316 italic = p_italic;
3317 _update_base_font();
3318 }
3319}
3320
3321bool SystemFont::get_font_italic() const {
3322 return italic;
3323}
3324
3325void SystemFont::set_font_weight(int p_weight) {
3326 if (weight != p_weight) {
3327 weight = CLAMP(p_weight, 100, 999);
3328 _update_base_font();
3329 }
3330}
3331
3332int SystemFont::get_font_weight() const {
3333 return weight;
3334}
3335
3336void SystemFont::set_font_stretch(int p_stretch) {
3337 if (stretch != p_stretch) {
3338 stretch = CLAMP(p_stretch, 50, 200);
3339 _update_base_font();
3340 }
3341}
3342
3343int SystemFont::get_font_stretch() const {
3344 return stretch;
3345}
3346
3347int SystemFont::get_spacing(TextServer::SpacingType p_spacing) const {
3348 if (base_font.is_valid()) {
3349 return base_font->get_spacing(p_spacing);
3350 } else {
3351 return 0;
3352 }
3353}
3354
3355RID SystemFont::find_variation(const Dictionary &p_variation_coordinates, int p_face_index, float p_strength, Transform2D p_transform, int p_spacing_top, int p_spacing_bottom, int p_spacing_space, int p_spacing_glyph) const {
3356 Ref<Font> f = _get_base_font_or_default();
3357 if (f.is_valid()) {
3358 Dictionary var = p_variation_coordinates;
3359 if (ftr_weight > 0 && !var.has(TS->name_to_tag("weight"))) {
3360 var[TS->name_to_tag("weight")] = ftr_weight;
3361 }
3362 if (ftr_stretch > 0 && !var.has(TS->name_to_tag("width"))) {
3363 var[TS->name_to_tag("width")] = ftr_stretch;
3364 }
3365 if (ftr_italic > 0 && !var.has(TS->name_to_tag("italic"))) {
3366 var[TS->name_to_tag("italic")] = ftr_italic;
3367 }
3368
3369 if (!face_indeces.is_empty()) {
3370 int face_index = CLAMP(p_face_index, 0, face_indeces.size() - 1);
3371 return f->find_variation(var, face_indeces[face_index], p_strength, p_transform, p_spacing_top, p_spacing_bottom, p_spacing_space, p_spacing_glyph);
3372 } else {
3373 return f->find_variation(var, 0, p_strength, p_transform, p_spacing_top, p_spacing_bottom, p_spacing_space, p_spacing_glyph);
3374 }
3375 }
3376 return RID();
3377}
3378
3379RID SystemFont::_get_rid() const {
3380 Ref<Font> f = _get_base_font_or_default();
3381 if (f.is_valid()) {
3382 if (!face_indeces.is_empty()) {
3383 Dictionary var;
3384 if (ftr_weight > 0) {
3385 var[TS->name_to_tag("weight")] = ftr_weight;
3386 }
3387 if (ftr_stretch > 0) {
3388 var[TS->name_to_tag("width")] = ftr_stretch;
3389 }
3390 if (ftr_italic > 0) {
3391 var[TS->name_to_tag("italic")] = ftr_italic;
3392 }
3393 return f->find_variation(var, face_indeces[0]);
3394 } else {
3395 return f->_get_rid();
3396 }
3397 }
3398 return RID();
3399}
3400
3401int64_t SystemFont::get_face_count() const {
3402 return face_indeces.size();
3403}
3404
3405SystemFont::SystemFont() {
3406 /* NOP */
3407}
3408
3409SystemFont::~SystemFont() {
3410}
3411