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 | |
49 | void 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 | |
105 | void 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 | |
119 | void Font::_update_rids() const { |
120 | rids.clear(); |
121 | _update_rids_fb(const_cast<Font *>(this), 0); |
122 | dirty_rids = false; |
123 | } |
124 | |
125 | void Font::_invalidate_rids() { |
126 | rids.clear(); |
127 | dirty_rids = true; |
128 | |
129 | cache.clear(); |
130 | cache_wrap.clear(); |
131 | |
132 | emit_changed(); |
133 | } |
134 | |
135 | bool 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 | |
152 | void Font::reset_state() { |
153 | _invalidate_rids(); |
154 | } |
155 | |
156 | // Fallbacks. |
157 | void 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 | |
178 | TypedArray<Font> Font::get_fallbacks() const { |
179 | return fallbacks; |
180 | } |
181 | |
182 | // Output. |
183 | TypedArray<RID> Font::get_rids() const { |
184 | if (dirty_rids) { |
185 | _update_rids(); |
186 | } |
187 | return rids; |
188 | } |
189 | |
190 | // Drawing string. |
191 | real_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 | |
202 | real_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 | |
213 | real_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 | |
224 | real_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 | |
235 | real_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 | |
246 | String Font::get_font_name() const { |
247 | return TS->font_get_name(_get_rid()); |
248 | } |
249 | |
250 | Dictionary Font::get_ot_name_strings() const { |
251 | return TS->font_get_ot_name_strings(_get_rid()); |
252 | } |
253 | |
254 | String Font::get_font_style_name() const { |
255 | return TS->font_get_style_name(_get_rid()); |
256 | } |
257 | |
258 | BitField<TextServer::FontStyle> Font::get_font_style() const { |
259 | return TS->font_get_style(_get_rid()); |
260 | } |
261 | |
262 | int Font::get_font_weight() const { |
263 | return TS->font_get_weight(_get_rid()); |
264 | } |
265 | |
266 | int Font::get_font_stretch() const { |
267 | return TS->font_get_stretch(_get_rid()); |
268 | } |
269 | |
270 | Dictionary Font::get_opentype_features() const { |
271 | return Dictionary(); |
272 | } |
273 | |
274 | // Drawing string. |
275 | void 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 | |
280 | Size2 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 | |
304 | Size2 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 | |
327 | void 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 | |
358 | void 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 | |
388 | void 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 | |
419 | void 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. |
450 | Size2 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 | |
463 | real_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 | |
477 | real_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. |
492 | bool 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 | |
504 | String 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 | |
520 | bool Font::is_language_supported(const String &p_language) const { |
521 | return TS->font_is_language_supported(_get_rid(), p_language); |
522 | } |
523 | |
524 | bool Font::is_script_supported(const String &p_script) const { |
525 | return TS->font_is_script_supported(_get_rid(), p_script); |
526 | } |
527 | |
528 | Dictionary Font::get_supported_feature_list() const { |
529 | return TS->font_supported_feature_list(_get_rid()); |
530 | } |
531 | |
532 | Dictionary Font::get_supported_variation_list() const { |
533 | return TS->font_supported_variation_list(_get_rid()); |
534 | } |
535 | |
536 | int64_t Font::get_face_count() const { |
537 | return TS->font_get_face_count(_get_rid()); |
538 | } |
539 | |
540 | Font::Font() { |
541 | cache.set_capacity(64); |
542 | cache_wrap.set_capacity(16); |
543 | } |
544 | |
545 | Font::~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 | |
582 | void 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 | |
629 | void 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 | |
729 | void 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 | |
785 | void 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 | |
814 | void 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 | |
857 | void 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 | |
1017 | void FontFile::_validate_property(PropertyInfo &p_property) const { |
1018 | if (p_property.name == "fallbacks" ) { |
1019 | p_property.usage &= ~PROPERTY_USAGE_EDITOR; |
1020 | } |
1021 | } |
1022 | |
1023 | bool 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 | |
1200 | bool 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 | |
1291 | void 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 | |
1350 | void 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. |
1375 | static 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 | |
1387 | Error 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 | |
1986 | Error 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 | |
1995 | void 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 | |
2007 | void 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 | |
2019 | PackedByteArray 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 | |
2028 | void FontFile::set_font_name(const String &p_name) { |
2029 | _ensure_rid(0); |
2030 | TS->font_set_name(cache[0], p_name); |
2031 | } |
2032 | |
2033 | void 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 | |
2038 | void FontFile::set_font_style(BitField<TextServer::FontStyle> p_style) { |
2039 | _ensure_rid(0); |
2040 | TS->font_set_style(cache[0], p_style); |
2041 | } |
2042 | |
2043 | void FontFile::set_font_weight(int p_weight) { |
2044 | _ensure_rid(0); |
2045 | TS->font_set_weight(cache[0], p_weight); |
2046 | } |
2047 | |
2048 | void FontFile::set_font_stretch(int p_stretch) { |
2049 | _ensure_rid(0); |
2050 | TS->font_set_stretch(cache[0], p_stretch); |
2051 | } |
2052 | |
2053 | void 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 | |
2064 | TextServer::FontAntialiasing FontFile::get_antialiasing() const { |
2065 | return antialiasing; |
2066 | } |
2067 | |
2068 | void 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 | |
2079 | bool FontFile::get_generate_mipmaps() const { |
2080 | return mipmaps; |
2081 | } |
2082 | |
2083 | void 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 | |
2094 | bool FontFile::is_multichannel_signed_distance_field() const { |
2095 | return msdf; |
2096 | } |
2097 | |
2098 | void 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 | |
2109 | int FontFile::get_msdf_pixel_range() const { |
2110 | return msdf_pixel_range; |
2111 | } |
2112 | |
2113 | void 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 | |
2124 | int FontFile::get_msdf_size() const { |
2125 | return msdf_size; |
2126 | } |
2127 | |
2128 | void 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 | |
2139 | int FontFile::get_fixed_size() const { |
2140 | return fixed_size; |
2141 | } |
2142 | |
2143 | void 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 | |
2154 | bool FontFile::is_allow_system_fallback() const { |
2155 | return allow_system_fallback; |
2156 | } |
2157 | |
2158 | void 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 | |
2169 | bool FontFile::is_force_autohinter() const { |
2170 | return force_autohinter; |
2171 | } |
2172 | |
2173 | void 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 | |
2184 | TextServer::Hinting FontFile::get_hinting() const { |
2185 | return hinting; |
2186 | } |
2187 | |
2188 | void 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 | |
2199 | TextServer::SubpixelPositioning FontFile::get_subpixel_positioning() const { |
2200 | return subpixel_positioning; |
2201 | } |
2202 | |
2203 | void 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 | |
2214 | real_t FontFile::get_oversampling() const { |
2215 | return oversampling; |
2216 | } |
2217 | |
2218 | RID 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 | |
2277 | RID FontFile::_get_rid() const { |
2278 | _ensure_rid(0); |
2279 | return cache[0]; |
2280 | } |
2281 | |
2282 | int FontFile::get_cache_count() const { |
2283 | return cache.size(); |
2284 | } |
2285 | |
2286 | void FontFile::clear_cache() { |
2287 | _clear_cache(); |
2288 | cache.clear(); |
2289 | emit_changed(); |
2290 | } |
2291 | |
2292 | void 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 | |
2301 | TypedArray<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 | |
2307 | void 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 | |
2313 | void 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 | |
2319 | void 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 | |
2325 | Dictionary 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 | |
2331 | void 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 | |
2337 | float 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 | |
2343 | void 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 | |
2349 | Transform2D 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 | |
2355 | void FontFile::(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 | |
2361 | int64_t FontFile::(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 | |
2367 | void 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 | |
2376 | int64_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 | |
2382 | void 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 | |
2388 | real_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 | |
2394 | void 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 | |
2400 | real_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 | |
2406 | void 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 | |
2412 | real_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 | |
2418 | void 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 | |
2424 | real_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 | |
2430 | void 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 | |
2436 | real_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 | |
2442 | int 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 | |
2448 | void 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 | |
2454 | void 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 | |
2460 | void 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 | |
2466 | Ref<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 | |
2472 | void 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 | |
2478 | PackedInt32Array 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 | |
2484 | PackedInt32Array 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 | |
2490 | void 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 | |
2496 | void 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 | |
2502 | void 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 | |
2508 | Vector2 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 | |
2514 | void 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 | |
2520 | Vector2 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 | |
2526 | void 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 | |
2532 | Vector2 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 | |
2538 | void 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 | |
2544 | Rect2 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 | |
2550 | void 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 | |
2556 | int 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 | |
2562 | TypedArray<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 | |
2568 | void 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 | |
2574 | void 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 | |
2580 | void 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 | |
2586 | Vector2 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 | |
2592 | void 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 | |
2598 | void 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 | |
2604 | void 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 | |
2609 | bool 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 | |
2614 | void 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 | |
2619 | Vector<String> FontFile::get_language_support_overrides() const { |
2620 | _ensure_rid(0); |
2621 | return TS->font_get_language_support_overrides(cache[0]); |
2622 | } |
2623 | |
2624 | void 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 | |
2629 | bool 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 | |
2634 | void 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 | |
2639 | Vector<String> FontFile::get_script_support_overrides() const { |
2640 | _ensure_rid(0); |
2641 | return TS->font_get_script_support_overrides(cache[0]); |
2642 | } |
2643 | |
2644 | void 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 | |
2649 | Dictionary FontFile::get_opentype_feature_overrides() const { |
2650 | _ensure_rid(0); |
2651 | return TS->font_get_opentype_feature_overrides(cache[0]); |
2652 | } |
2653 | |
2654 | int32_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 | |
2659 | char32_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 | |
2664 | FontFile::FontFile() { |
2665 | } |
2666 | |
2667 | FontFile::~FontFile() { |
2668 | _clear_cache(); |
2669 | } |
2670 | |
2671 | /*************************************************************************/ |
2672 | /* FontVariation */ |
2673 | /*************************************************************************/ |
2674 | |
2675 | void 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 | |
2713 | void 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 | |
2733 | void 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 | |
2754 | void 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 | |
2768 | Ref<Font> FontVariation::get_base_font() const { |
2769 | return base_font; |
2770 | } |
2771 | |
2772 | Ref<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 | |
2821 | void 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 | |
2828 | Dictionary FontVariation::get_variation_opentype() const { |
2829 | return variation.opentype.duplicate(); |
2830 | } |
2831 | |
2832 | void FontVariation::set_variation_embolden(float p_strength) { |
2833 | if (variation.embolden != p_strength) { |
2834 | variation.embolden = p_strength; |
2835 | _invalidate_rids(); |
2836 | } |
2837 | } |
2838 | |
2839 | float FontVariation::get_variation_embolden() const { |
2840 | return variation.embolden; |
2841 | } |
2842 | |
2843 | void FontVariation::set_variation_transform(Transform2D p_transform) { |
2844 | if (variation.transform != p_transform) { |
2845 | variation.transform = p_transform; |
2846 | _invalidate_rids(); |
2847 | } |
2848 | } |
2849 | |
2850 | Transform2D FontVariation::get_variation_transform() const { |
2851 | return variation.transform; |
2852 | } |
2853 | |
2854 | void 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 | |
2861 | int FontVariation::get_variation_face_index() const { |
2862 | return variation.face_index; |
2863 | } |
2864 | |
2865 | void 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 | |
2872 | Dictionary FontVariation::get_opentype_features() const { |
2873 | return opentype_features.duplicate(); |
2874 | } |
2875 | |
2876 | void 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 | |
2884 | int 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 | |
2889 | RID 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 | |
2897 | RID 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 | |
2905 | FontVariation::FontVariation() { |
2906 | for (int i = 0; i < TextServer::SPACING_MAX; i++) { |
2907 | extra_spacing[i] = 0; |
2908 | } |
2909 | } |
2910 | |
2911 | FontVariation::~FontVariation() { |
2912 | } |
2913 | |
2914 | /*************************************************************************/ |
2915 | /* SystemFont */ |
2916 | /*************************************************************************/ |
2917 | |
2918 | void 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 | |
2973 | void 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 | |
2993 | void 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 | |
3083 | void 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 | |
3114 | Ref<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 | |
3163 | void 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 | |
3173 | TextServer::FontAntialiasing SystemFont::get_antialiasing() const { |
3174 | return antialiasing; |
3175 | } |
3176 | |
3177 | void 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 | |
3187 | bool SystemFont::get_generate_mipmaps() const { |
3188 | return mipmaps; |
3189 | } |
3190 | |
3191 | void 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 | |
3201 | bool SystemFont::is_allow_system_fallback() const { |
3202 | return allow_system_fallback; |
3203 | } |
3204 | |
3205 | void 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 | |
3215 | bool SystemFont::is_force_autohinter() const { |
3216 | return force_autohinter; |
3217 | } |
3218 | |
3219 | void 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 | |
3229 | TextServer::Hinting SystemFont::get_hinting() const { |
3230 | return hinting; |
3231 | } |
3232 | |
3233 | void 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 | |
3243 | TextServer::SubpixelPositioning SystemFont::get_subpixel_positioning() const { |
3244 | return subpixel_positioning; |
3245 | } |
3246 | |
3247 | void 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 | |
3257 | bool SystemFont::is_multichannel_signed_distance_field() const { |
3258 | return msdf; |
3259 | } |
3260 | |
3261 | void 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 | |
3271 | int SystemFont::get_msdf_pixel_range() const { |
3272 | return msdf_pixel_range; |
3273 | } |
3274 | |
3275 | void 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 | |
3285 | int SystemFont::get_msdf_size() const { |
3286 | return msdf_size; |
3287 | } |
3288 | |
3289 | void 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 | |
3299 | real_t SystemFont::get_oversampling() const { |
3300 | return oversampling; |
3301 | } |
3302 | |
3303 | void SystemFont::set_font_names(const PackedStringArray &p_names) { |
3304 | if (names != p_names) { |
3305 | names = p_names; |
3306 | _update_base_font(); |
3307 | } |
3308 | } |
3309 | |
3310 | PackedStringArray SystemFont::get_font_names() const { |
3311 | return names; |
3312 | } |
3313 | |
3314 | void SystemFont::set_font_italic(bool p_italic) { |
3315 | if (italic != p_italic) { |
3316 | italic = p_italic; |
3317 | _update_base_font(); |
3318 | } |
3319 | } |
3320 | |
3321 | bool SystemFont::get_font_italic() const { |
3322 | return italic; |
3323 | } |
3324 | |
3325 | void 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 | |
3332 | int SystemFont::get_font_weight() const { |
3333 | return weight; |
3334 | } |
3335 | |
3336 | void 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 | |
3343 | int SystemFont::get_font_stretch() const { |
3344 | return stretch; |
3345 | } |
3346 | |
3347 | int 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 | |
3355 | RID 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 | |
3379 | RID 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 | |
3401 | int64_t SystemFont::get_face_count() const { |
3402 | return face_indeces.size(); |
3403 | } |
3404 | |
3405 | SystemFont::SystemFont() { |
3406 | /* NOP */ |
3407 | } |
3408 | |
3409 | SystemFont::~SystemFont() { |
3410 | } |
3411 | |