1 | /**************************************************************************/ |
2 | /* text_server.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 "servers/text_server.h" |
32 | #include "core/variant/typed_array.h" |
33 | #include "servers/rendering_server.h" |
34 | |
35 | TextServerManager *TextServerManager::singleton = nullptr; |
36 | |
37 | void TextServerManager::_bind_methods() { |
38 | ClassDB::bind_method(D_METHOD("add_interface" , "interface" ), &TextServerManager::add_interface); |
39 | ClassDB::bind_method(D_METHOD("get_interface_count" ), &TextServerManager::get_interface_count); |
40 | ClassDB::bind_method(D_METHOD("remove_interface" , "interface" ), &TextServerManager::remove_interface); |
41 | ClassDB::bind_method(D_METHOD("get_interface" , "idx" ), &TextServerManager::get_interface); |
42 | ClassDB::bind_method(D_METHOD("get_interfaces" ), &TextServerManager::get_interfaces); |
43 | ClassDB::bind_method(D_METHOD("find_interface" , "name" ), &TextServerManager::find_interface); |
44 | |
45 | ClassDB::bind_method(D_METHOD("set_primary_interface" , "index" ), &TextServerManager::set_primary_interface); |
46 | ClassDB::bind_method(D_METHOD("get_primary_interface" ), &TextServerManager::get_primary_interface); |
47 | |
48 | ADD_SIGNAL(MethodInfo("interface_added" , PropertyInfo(Variant::STRING_NAME, "interface_name" ))); |
49 | ADD_SIGNAL(MethodInfo("interface_removed" , PropertyInfo(Variant::STRING_NAME, "interface_name" ))); |
50 | } |
51 | |
52 | void TextServerManager::add_interface(const Ref<TextServer> &p_interface) { |
53 | ERR_FAIL_COND(p_interface.is_null()); |
54 | |
55 | for (int i = 0; i < interfaces.size(); i++) { |
56 | if (interfaces[i] == p_interface) { |
57 | ERR_PRINT("TextServer: Interface was already added." ); |
58 | return; |
59 | }; |
60 | }; |
61 | |
62 | interfaces.push_back(p_interface); |
63 | print_verbose("TextServer: Added interface \"" + p_interface->get_name() + "\"" ); |
64 | emit_signal(SNAME("interface_added" ), p_interface->get_name()); |
65 | } |
66 | |
67 | void TextServerManager::remove_interface(const Ref<TextServer> &p_interface) { |
68 | ERR_FAIL_COND(p_interface.is_null()); |
69 | ERR_FAIL_COND_MSG(p_interface == primary_interface, "TextServer: Can't remove primary interface." ); |
70 | |
71 | int idx = -1; |
72 | for (int i = 0; i < interfaces.size(); i++) { |
73 | if (interfaces[i] == p_interface) { |
74 | idx = i; |
75 | break; |
76 | }; |
77 | }; |
78 | |
79 | ERR_FAIL_COND_MSG(idx == -1, "Interface not found." ); |
80 | print_verbose("TextServer: Removed interface \"" + p_interface->get_name() + "\"" ); |
81 | emit_signal(SNAME("interface_removed" ), p_interface->get_name()); |
82 | interfaces.remove_at(idx); |
83 | } |
84 | |
85 | int TextServerManager::get_interface_count() const { |
86 | return interfaces.size(); |
87 | } |
88 | |
89 | Ref<TextServer> TextServerManager::get_interface(int p_index) const { |
90 | ERR_FAIL_INDEX_V(p_index, interfaces.size(), nullptr); |
91 | return interfaces[p_index]; |
92 | } |
93 | |
94 | Ref<TextServer> TextServerManager::find_interface(const String &p_name) const { |
95 | int idx = -1; |
96 | for (int i = 0; i < interfaces.size(); i++) { |
97 | if (interfaces[i]->get_name() == p_name) { |
98 | idx = i; |
99 | break; |
100 | }; |
101 | }; |
102 | |
103 | ERR_FAIL_COND_V_MSG(idx == -1, nullptr, "Interface not found." ); |
104 | return interfaces[idx]; |
105 | } |
106 | |
107 | TypedArray<Dictionary> TextServerManager::get_interfaces() const { |
108 | TypedArray<Dictionary> ret; |
109 | |
110 | for (int i = 0; i < interfaces.size(); i++) { |
111 | Dictionary iface_info; |
112 | |
113 | iface_info["id" ] = i; |
114 | iface_info["name" ] = interfaces[i]->get_name(); |
115 | |
116 | ret.push_back(iface_info); |
117 | }; |
118 | |
119 | return ret; |
120 | } |
121 | |
122 | void TextServerManager::set_primary_interface(const Ref<TextServer> &p_primary_interface) { |
123 | if (p_primary_interface.is_null()) { |
124 | print_verbose("TextServer: Clearing primary interface" ); |
125 | primary_interface.unref(); |
126 | } else { |
127 | primary_interface = p_primary_interface; |
128 | print_verbose("TextServer: Primary interface set to: \"" + primary_interface->get_name() + "\"." ); |
129 | |
130 | if (OS::get_singleton()->get_main_loop()) { |
131 | OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TEXT_SERVER_CHANGED); |
132 | } |
133 | } |
134 | } |
135 | |
136 | TextServerManager::TextServerManager() { |
137 | singleton = this; |
138 | } |
139 | |
140 | TextServerManager::~TextServerManager() { |
141 | if (primary_interface.is_valid()) { |
142 | primary_interface.unref(); |
143 | } |
144 | while (interfaces.size() > 0) { |
145 | interfaces.remove_at(0); |
146 | } |
147 | singleton = nullptr; |
148 | } |
149 | |
150 | /*************************************************************************/ |
151 | |
152 | bool Glyph::operator==(const Glyph &p_a) const { |
153 | return (p_a.index == index) && (p_a.font_rid == font_rid) && (p_a.font_size == font_size) && (p_a.start == start); |
154 | } |
155 | |
156 | bool Glyph::operator!=(const Glyph &p_a) const { |
157 | return (p_a.index != index) || (p_a.font_rid != font_rid) || (p_a.font_size != font_size) || (p_a.start != start); |
158 | } |
159 | |
160 | bool Glyph::operator<(const Glyph &p_a) const { |
161 | if (p_a.start == start) { |
162 | if (p_a.count == count) { |
163 | if ((p_a.flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL) { |
164 | return true; |
165 | } else { |
166 | return false; |
167 | } |
168 | } |
169 | return p_a.count > count; |
170 | } |
171 | return p_a.start < start; |
172 | } |
173 | |
174 | bool Glyph::operator>(const Glyph &p_a) const { |
175 | if (p_a.start == start) { |
176 | if (p_a.count == count) { |
177 | if ((p_a.flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL) { |
178 | return false; |
179 | } else { |
180 | return true; |
181 | } |
182 | } |
183 | return p_a.count < count; |
184 | } |
185 | return p_a.start > start; |
186 | } |
187 | |
188 | void TextServer::_bind_methods() { |
189 | ClassDB::bind_method(D_METHOD("has_feature" , "feature" ), &TextServer::has_feature); |
190 | ClassDB::bind_method(D_METHOD("get_name" ), &TextServer::get_name); |
191 | ClassDB::bind_method(D_METHOD("get_features" ), &TextServer::get_features); |
192 | ClassDB::bind_method(D_METHOD("load_support_data" , "filename" ), &TextServer::load_support_data); |
193 | |
194 | ClassDB::bind_method(D_METHOD("get_support_data_filename" ), &TextServer::get_support_data_filename); |
195 | ClassDB::bind_method(D_METHOD("get_support_data_info" ), &TextServer::get_support_data_info); |
196 | ClassDB::bind_method(D_METHOD("save_support_data" , "filename" ), &TextServer::save_support_data); |
197 | |
198 | ClassDB::bind_method(D_METHOD("is_locale_right_to_left" , "locale" ), &TextServer::is_locale_right_to_left); |
199 | |
200 | ClassDB::bind_method(D_METHOD("name_to_tag" , "name" ), &TextServer::name_to_tag); |
201 | ClassDB::bind_method(D_METHOD("tag_to_name" , "tag" ), &TextServer::tag_to_name); |
202 | |
203 | ClassDB::bind_method(D_METHOD("has" , "rid" ), &TextServer::has); |
204 | ClassDB::bind_method(D_METHOD("free_rid" , "rid" ), &TextServer::free_rid); |
205 | |
206 | /* Font Interface */ |
207 | |
208 | ClassDB::bind_method(D_METHOD("create_font" ), &TextServer::create_font); |
209 | |
210 | ClassDB::bind_method(D_METHOD("font_set_data" , "font_rid" , "data" ), &TextServer::font_set_data); |
211 | |
212 | ClassDB::bind_method(D_METHOD("font_set_face_index" , "font_rid" , "face_index" ), &TextServer::font_set_face_index); |
213 | ClassDB::bind_method(D_METHOD("font_get_face_index" , "font_rid" ), &TextServer::font_get_face_index); |
214 | |
215 | ClassDB::bind_method(D_METHOD("font_get_face_count" , "font_rid" ), &TextServer::font_get_face_count); |
216 | |
217 | ClassDB::bind_method(D_METHOD("font_set_style" , "font_rid" , "style" ), &TextServer::font_set_style); |
218 | ClassDB::bind_method(D_METHOD("font_get_style" , "font_rid" ), &TextServer::font_get_style); |
219 | |
220 | ClassDB::bind_method(D_METHOD("font_set_name" , "font_rid" , "name" ), &TextServer::font_set_name); |
221 | ClassDB::bind_method(D_METHOD("font_get_name" , "font_rid" ), &TextServer::font_get_name); |
222 | ClassDB::bind_method(D_METHOD("font_get_ot_name_strings" , "font_rid" ), &TextServer::font_get_ot_name_strings); |
223 | |
224 | ClassDB::bind_method(D_METHOD("font_set_style_name" , "font_rid" , "name" ), &TextServer::font_set_style_name); |
225 | ClassDB::bind_method(D_METHOD("font_get_style_name" , "font_rid" ), &TextServer::font_get_style_name); |
226 | |
227 | ClassDB::bind_method(D_METHOD("font_set_weight" , "font_rid" , "weight" ), &TextServer::font_set_weight); |
228 | ClassDB::bind_method(D_METHOD("font_get_weight" , "font_rid" ), &TextServer::font_get_weight); |
229 | |
230 | ClassDB::bind_method(D_METHOD("font_set_stretch" , "font_rid" , "weight" ), &TextServer::font_set_stretch); |
231 | ClassDB::bind_method(D_METHOD("font_get_stretch" , "font_rid" ), &TextServer::font_get_stretch); |
232 | |
233 | ClassDB::bind_method(D_METHOD("font_set_antialiasing" , "font_rid" , "antialiasing" ), &TextServer::font_set_antialiasing); |
234 | ClassDB::bind_method(D_METHOD("font_get_antialiasing" , "font_rid" ), &TextServer::font_get_antialiasing); |
235 | |
236 | ClassDB::bind_method(D_METHOD("font_set_generate_mipmaps" , "font_rid" , "generate_mipmaps" ), &TextServer::font_set_generate_mipmaps); |
237 | ClassDB::bind_method(D_METHOD("font_get_generate_mipmaps" , "font_rid" ), &TextServer::font_get_generate_mipmaps); |
238 | |
239 | ClassDB::bind_method(D_METHOD("font_set_multichannel_signed_distance_field" , "font_rid" , "msdf" ), &TextServer::font_set_multichannel_signed_distance_field); |
240 | ClassDB::bind_method(D_METHOD("font_is_multichannel_signed_distance_field" , "font_rid" ), &TextServer::font_is_multichannel_signed_distance_field); |
241 | |
242 | ClassDB::bind_method(D_METHOD("font_set_msdf_pixel_range" , "font_rid" , "msdf_pixel_range" ), &TextServer::font_set_msdf_pixel_range); |
243 | ClassDB::bind_method(D_METHOD("font_get_msdf_pixel_range" , "font_rid" ), &TextServer::font_get_msdf_pixel_range); |
244 | |
245 | ClassDB::bind_method(D_METHOD("font_set_msdf_size" , "font_rid" , "msdf_size" ), &TextServer::font_set_msdf_size); |
246 | ClassDB::bind_method(D_METHOD("font_get_msdf_size" , "font_rid" ), &TextServer::font_get_msdf_size); |
247 | |
248 | ClassDB::bind_method(D_METHOD("font_set_fixed_size" , "font_rid" , "fixed_size" ), &TextServer::font_set_fixed_size); |
249 | ClassDB::bind_method(D_METHOD("font_get_fixed_size" , "font_rid" ), &TextServer::font_get_fixed_size); |
250 | |
251 | ClassDB::bind_method(D_METHOD("font_set_allow_system_fallback" , "font_rid" , "allow_system_fallback" ), &TextServer::font_set_allow_system_fallback); |
252 | ClassDB::bind_method(D_METHOD("font_is_allow_system_fallback" , "font_rid" ), &TextServer::font_is_allow_system_fallback); |
253 | |
254 | ClassDB::bind_method(D_METHOD("font_set_force_autohinter" , "font_rid" , "force_autohinter" ), &TextServer::font_set_force_autohinter); |
255 | ClassDB::bind_method(D_METHOD("font_is_force_autohinter" , "font_rid" ), &TextServer::font_is_force_autohinter); |
256 | |
257 | ClassDB::bind_method(D_METHOD("font_set_hinting" , "font_rid" , "hinting" ), &TextServer::font_set_hinting); |
258 | ClassDB::bind_method(D_METHOD("font_get_hinting" , "font_rid" ), &TextServer::font_get_hinting); |
259 | |
260 | ClassDB::bind_method(D_METHOD("font_set_subpixel_positioning" , "font_rid" , "subpixel_positioning" ), &TextServer::font_set_subpixel_positioning); |
261 | ClassDB::bind_method(D_METHOD("font_get_subpixel_positioning" , "font_rid" ), &TextServer::font_get_subpixel_positioning); |
262 | |
263 | ClassDB::bind_method(D_METHOD("font_set_embolden" , "font_rid" , "strength" ), &TextServer::font_set_embolden); |
264 | ClassDB::bind_method(D_METHOD("font_get_embolden" , "font_rid" ), &TextServer::font_get_embolden); |
265 | |
266 | ClassDB::bind_method(D_METHOD("font_set_spacing" , "font_rid" , "spacing" , "value" ), &TextServer::font_set_spacing); |
267 | ClassDB::bind_method(D_METHOD("font_get_spacing" , "font_rid" , "spacing" ), &TextServer::font_get_spacing); |
268 | |
269 | ClassDB::bind_method(D_METHOD("font_set_transform" , "font_rid" , "transform" ), &TextServer::font_set_transform); |
270 | ClassDB::bind_method(D_METHOD("font_get_transform" , "font_rid" ), &TextServer::font_get_transform); |
271 | |
272 | ClassDB::bind_method(D_METHOD("font_set_variation_coordinates" , "font_rid" , "variation_coordinates" ), &TextServer::font_set_variation_coordinates); |
273 | ClassDB::bind_method(D_METHOD("font_get_variation_coordinates" , "font_rid" ), &TextServer::font_get_variation_coordinates); |
274 | |
275 | ClassDB::bind_method(D_METHOD("font_set_oversampling" , "font_rid" , "oversampling" ), &TextServer::font_set_oversampling); |
276 | ClassDB::bind_method(D_METHOD("font_get_oversampling" , "font_rid" ), &TextServer::font_get_oversampling); |
277 | |
278 | ClassDB::bind_method(D_METHOD("font_get_size_cache_list" , "font_rid" ), &TextServer::font_get_size_cache_list); |
279 | ClassDB::bind_method(D_METHOD("font_clear_size_cache" , "font_rid" ), &TextServer::font_clear_size_cache); |
280 | ClassDB::bind_method(D_METHOD("font_remove_size_cache" , "font_rid" , "size" ), &TextServer::font_remove_size_cache); |
281 | |
282 | ClassDB::bind_method(D_METHOD("font_set_ascent" , "font_rid" , "size" , "ascent" ), &TextServer::font_set_ascent); |
283 | ClassDB::bind_method(D_METHOD("font_get_ascent" , "font_rid" , "size" ), &TextServer::font_get_ascent); |
284 | |
285 | ClassDB::bind_method(D_METHOD("font_set_descent" , "font_rid" , "size" , "descent" ), &TextServer::font_set_descent); |
286 | ClassDB::bind_method(D_METHOD("font_get_descent" , "font_rid" , "size" ), &TextServer::font_get_descent); |
287 | |
288 | ClassDB::bind_method(D_METHOD("font_set_underline_position" , "font_rid" , "size" , "underline_position" ), &TextServer::font_set_underline_position); |
289 | ClassDB::bind_method(D_METHOD("font_get_underline_position" , "font_rid" , "size" ), &TextServer::font_get_underline_position); |
290 | |
291 | ClassDB::bind_method(D_METHOD("font_set_underline_thickness" , "font_rid" , "size" , "underline_thickness" ), &TextServer::font_set_underline_thickness); |
292 | ClassDB::bind_method(D_METHOD("font_get_underline_thickness" , "font_rid" , "size" ), &TextServer::font_get_underline_thickness); |
293 | |
294 | ClassDB::bind_method(D_METHOD("font_set_scale" , "font_rid" , "size" , "scale" ), &TextServer::font_set_scale); |
295 | ClassDB::bind_method(D_METHOD("font_get_scale" , "font_rid" , "size" ), &TextServer::font_get_scale); |
296 | |
297 | ClassDB::bind_method(D_METHOD("font_get_texture_count" , "font_rid" , "size" ), &TextServer::font_get_texture_count); |
298 | ClassDB::bind_method(D_METHOD("font_clear_textures" , "font_rid" , "size" ), &TextServer::font_clear_textures); |
299 | ClassDB::bind_method(D_METHOD("font_remove_texture" , "font_rid" , "size" , "texture_index" ), &TextServer::font_remove_texture); |
300 | |
301 | ClassDB::bind_method(D_METHOD("font_set_texture_image" , "font_rid" , "size" , "texture_index" , "image" ), &TextServer::font_set_texture_image); |
302 | ClassDB::bind_method(D_METHOD("font_get_texture_image" , "font_rid" , "size" , "texture_index" ), &TextServer::font_get_texture_image); |
303 | |
304 | ClassDB::bind_method(D_METHOD("font_set_texture_offsets" , "font_rid" , "size" , "texture_index" , "offset" ), &TextServer::font_set_texture_offsets); |
305 | ClassDB::bind_method(D_METHOD("font_get_texture_offsets" , "font_rid" , "size" , "texture_index" ), &TextServer::font_get_texture_offsets); |
306 | |
307 | ClassDB::bind_method(D_METHOD("font_get_glyph_list" , "font_rid" , "size" ), &TextServer::font_get_glyph_list); |
308 | ClassDB::bind_method(D_METHOD("font_clear_glyphs" , "font_rid" , "size" ), &TextServer::font_clear_glyphs); |
309 | ClassDB::bind_method(D_METHOD("font_remove_glyph" , "font_rid" , "size" , "glyph" ), &TextServer::font_remove_glyph); |
310 | |
311 | ClassDB::bind_method(D_METHOD("font_get_glyph_advance" , "font_rid" , "size" , "glyph" ), &TextServer::font_get_glyph_advance); |
312 | ClassDB::bind_method(D_METHOD("font_set_glyph_advance" , "font_rid" , "size" , "glyph" , "advance" ), &TextServer::font_set_glyph_advance); |
313 | |
314 | ClassDB::bind_method(D_METHOD("font_get_glyph_offset" , "font_rid" , "size" , "glyph" ), &TextServer::font_get_glyph_offset); |
315 | ClassDB::bind_method(D_METHOD("font_set_glyph_offset" , "font_rid" , "size" , "glyph" , "offset" ), &TextServer::font_set_glyph_offset); |
316 | |
317 | ClassDB::bind_method(D_METHOD("font_get_glyph_size" , "font_rid" , "size" , "glyph" ), &TextServer::font_get_glyph_size); |
318 | ClassDB::bind_method(D_METHOD("font_set_glyph_size" , "font_rid" , "size" , "glyph" , "gl_size" ), &TextServer::font_set_glyph_size); |
319 | |
320 | ClassDB::bind_method(D_METHOD("font_get_glyph_uv_rect" , "font_rid" , "size" , "glyph" ), &TextServer::font_get_glyph_uv_rect); |
321 | ClassDB::bind_method(D_METHOD("font_set_glyph_uv_rect" , "font_rid" , "size" , "glyph" , "uv_rect" ), &TextServer::font_set_glyph_uv_rect); |
322 | |
323 | ClassDB::bind_method(D_METHOD("font_get_glyph_texture_idx" , "font_rid" , "size" , "glyph" ), &TextServer::font_get_glyph_texture_idx); |
324 | ClassDB::bind_method(D_METHOD("font_set_glyph_texture_idx" , "font_rid" , "size" , "glyph" , "texture_idx" ), &TextServer::font_set_glyph_texture_idx); |
325 | |
326 | ClassDB::bind_method(D_METHOD("font_get_glyph_texture_rid" , "font_rid" , "size" , "glyph" ), &TextServer::font_get_glyph_texture_rid); |
327 | ClassDB::bind_method(D_METHOD("font_get_glyph_texture_size" , "font_rid" , "size" , "glyph" ), &TextServer::font_get_glyph_texture_size); |
328 | |
329 | ClassDB::bind_method(D_METHOD("font_get_glyph_contours" , "font" , "size" , "index" ), &TextServer::font_get_glyph_contours); |
330 | |
331 | ClassDB::bind_method(D_METHOD("font_get_kerning_list" , "font_rid" , "size" ), &TextServer::font_get_kerning_list); |
332 | ClassDB::bind_method(D_METHOD("font_clear_kerning_map" , "font_rid" , "size" ), &TextServer::font_clear_kerning_map); |
333 | ClassDB::bind_method(D_METHOD("font_remove_kerning" , "font_rid" , "size" , "glyph_pair" ), &TextServer::font_remove_kerning); |
334 | |
335 | ClassDB::bind_method(D_METHOD("font_set_kerning" , "font_rid" , "size" , "glyph_pair" , "kerning" ), &TextServer::font_set_kerning); |
336 | ClassDB::bind_method(D_METHOD("font_get_kerning" , "font_rid" , "size" , "glyph_pair" ), &TextServer::font_get_kerning); |
337 | |
338 | ClassDB::bind_method(D_METHOD("font_get_glyph_index" , "font_rid" , "size" , "char" , "variation_selector" ), &TextServer::font_get_glyph_index); |
339 | ClassDB::bind_method(D_METHOD("font_get_char_from_glyph_index" , "font_rid" , "size" , "glyph_index" ), &TextServer::font_get_char_from_glyph_index); |
340 | |
341 | ClassDB::bind_method(D_METHOD("font_has_char" , "font_rid" , "char" ), &TextServer::font_has_char); |
342 | ClassDB::bind_method(D_METHOD("font_get_supported_chars" , "font_rid" ), &TextServer::font_get_supported_chars); |
343 | |
344 | ClassDB::bind_method(D_METHOD("font_render_range" , "font_rid" , "size" , "start" , "end" ), &TextServer::font_render_range); |
345 | ClassDB::bind_method(D_METHOD("font_render_glyph" , "font_rid" , "size" , "index" ), &TextServer::font_render_glyph); |
346 | |
347 | ClassDB::bind_method(D_METHOD("font_draw_glyph" , "font_rid" , "canvas" , "size" , "pos" , "index" , "color" ), &TextServer::font_draw_glyph, DEFVAL(Color(1, 1, 1))); |
348 | ClassDB::bind_method(D_METHOD("font_draw_glyph_outline" , "font_rid" , "canvas" , "size" , "outline_size" , "pos" , "index" , "color" ), &TextServer::font_draw_glyph_outline, DEFVAL(Color(1, 1, 1))); |
349 | |
350 | ClassDB::bind_method(D_METHOD("font_is_language_supported" , "font_rid" , "language" ), &TextServer::font_is_language_supported); |
351 | ClassDB::bind_method(D_METHOD("font_set_language_support_override" , "font_rid" , "language" , "supported" ), &TextServer::font_set_language_support_override); |
352 | ClassDB::bind_method(D_METHOD("font_get_language_support_override" , "font_rid" , "language" ), &TextServer::font_get_language_support_override); |
353 | ClassDB::bind_method(D_METHOD("font_remove_language_support_override" , "font_rid" , "language" ), &TextServer::font_remove_language_support_override); |
354 | ClassDB::bind_method(D_METHOD("font_get_language_support_overrides" , "font_rid" ), &TextServer::font_get_language_support_overrides); |
355 | |
356 | ClassDB::bind_method(D_METHOD("font_is_script_supported" , "font_rid" , "script" ), &TextServer::font_is_script_supported); |
357 | ClassDB::bind_method(D_METHOD("font_set_script_support_override" , "font_rid" , "script" , "supported" ), &TextServer::font_set_script_support_override); |
358 | ClassDB::bind_method(D_METHOD("font_get_script_support_override" , "font_rid" , "script" ), &TextServer::font_get_script_support_override); |
359 | ClassDB::bind_method(D_METHOD("font_remove_script_support_override" , "font_rid" , "script" ), &TextServer::font_remove_script_support_override); |
360 | ClassDB::bind_method(D_METHOD("font_get_script_support_overrides" , "font_rid" ), &TextServer::font_get_script_support_overrides); |
361 | |
362 | ClassDB::bind_method(D_METHOD("font_set_opentype_feature_overrides" , "font_rid" , "overrides" ), &TextServer::font_set_opentype_feature_overrides); |
363 | ClassDB::bind_method(D_METHOD("font_get_opentype_feature_overrides" , "font_rid" ), &TextServer::font_get_opentype_feature_overrides); |
364 | |
365 | ClassDB::bind_method(D_METHOD("font_supported_feature_list" , "font_rid" ), &TextServer::font_supported_feature_list); |
366 | ClassDB::bind_method(D_METHOD("font_supported_variation_list" , "font_rid" ), &TextServer::font_supported_variation_list); |
367 | |
368 | ClassDB::bind_method(D_METHOD("font_get_global_oversampling" ), &TextServer::font_get_global_oversampling); |
369 | ClassDB::bind_method(D_METHOD("font_set_global_oversampling" , "oversampling" ), &TextServer::font_set_global_oversampling); |
370 | |
371 | ClassDB::bind_method(D_METHOD("get_hex_code_box_size" , "size" , "index" ), &TextServer::get_hex_code_box_size); |
372 | ClassDB::bind_method(D_METHOD("draw_hex_code_box" , "canvas" , "size" , "pos" , "index" , "color" ), &TextServer::draw_hex_code_box); |
373 | |
374 | /* Shaped text buffer interface */ |
375 | |
376 | ClassDB::bind_method(D_METHOD("create_shaped_text" , "direction" , "orientation" ), &TextServer::create_shaped_text, DEFVAL(DIRECTION_AUTO), DEFVAL(ORIENTATION_HORIZONTAL)); |
377 | |
378 | ClassDB::bind_method(D_METHOD("shaped_text_clear" , "rid" ), &TextServer::shaped_text_clear); |
379 | |
380 | ClassDB::bind_method(D_METHOD("shaped_text_set_direction" , "shaped" , "direction" ), &TextServer::shaped_text_set_direction, DEFVAL(DIRECTION_AUTO)); |
381 | ClassDB::bind_method(D_METHOD("shaped_text_get_direction" , "shaped" ), &TextServer::shaped_text_get_direction); |
382 | ClassDB::bind_method(D_METHOD("shaped_text_get_inferred_direction" , "shaped" ), &TextServer::shaped_text_get_inferred_direction); |
383 | |
384 | ClassDB::bind_method(D_METHOD("shaped_text_set_bidi_override" , "shaped" , "override" ), &TextServer::shaped_text_set_bidi_override); |
385 | |
386 | ClassDB::bind_method(D_METHOD("shaped_text_set_custom_punctuation" , "shaped" , "punct" ), &TextServer::shaped_text_set_custom_punctuation); |
387 | ClassDB::bind_method(D_METHOD("shaped_text_get_custom_punctuation" , "shaped" ), &TextServer::shaped_text_get_custom_punctuation); |
388 | |
389 | ClassDB::bind_method(D_METHOD("shaped_text_set_orientation" , "shaped" , "orientation" ), &TextServer::shaped_text_set_orientation, DEFVAL(ORIENTATION_HORIZONTAL)); |
390 | ClassDB::bind_method(D_METHOD("shaped_text_get_orientation" , "shaped" ), &TextServer::shaped_text_get_orientation); |
391 | |
392 | ClassDB::bind_method(D_METHOD("shaped_text_set_preserve_invalid" , "shaped" , "enabled" ), &TextServer::shaped_text_set_preserve_invalid); |
393 | ClassDB::bind_method(D_METHOD("shaped_text_get_preserve_invalid" , "shaped" ), &TextServer::shaped_text_get_preserve_invalid); |
394 | |
395 | ClassDB::bind_method(D_METHOD("shaped_text_set_preserve_control" , "shaped" , "enabled" ), &TextServer::shaped_text_set_preserve_control); |
396 | ClassDB::bind_method(D_METHOD("shaped_text_get_preserve_control" , "shaped" ), &TextServer::shaped_text_get_preserve_control); |
397 | |
398 | ClassDB::bind_method(D_METHOD("shaped_text_set_spacing" , "shaped" , "spacing" , "value" ), &TextServer::shaped_text_set_spacing); |
399 | ClassDB::bind_method(D_METHOD("shaped_text_get_spacing" , "shaped" , "spacing" ), &TextServer::shaped_text_get_spacing); |
400 | |
401 | ClassDB::bind_method(D_METHOD("shaped_text_add_string" , "shaped" , "text" , "fonts" , "size" , "opentype_features" , "language" , "meta" ), &TextServer::shaped_text_add_string, DEFVAL(Dictionary()), DEFVAL("" ), DEFVAL(Variant())); |
402 | ClassDB::bind_method(D_METHOD("shaped_text_add_object" , "shaped" , "key" , "size" , "inline_align" , "length" , "baseline" ), &TextServer::shaped_text_add_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(1), DEFVAL(0.0)); |
403 | ClassDB::bind_method(D_METHOD("shaped_text_resize_object" , "shaped" , "key" , "size" , "inline_align" , "baseline" ), &TextServer::shaped_text_resize_object, DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(0.0)); |
404 | |
405 | ClassDB::bind_method(D_METHOD("shaped_get_span_count" , "shaped" ), &TextServer::shaped_get_span_count); |
406 | ClassDB::bind_method(D_METHOD("shaped_get_span_meta" , "shaped" , "index" ), &TextServer::shaped_get_span_meta); |
407 | ClassDB::bind_method(D_METHOD("shaped_set_span_update_font" , "shaped" , "index" , "fonts" , "size" , "opentype_features" ), &TextServer::shaped_set_span_update_font, DEFVAL(Dictionary())); |
408 | |
409 | ClassDB::bind_method(D_METHOD("shaped_text_substr" , "shaped" , "start" , "length" ), &TextServer::shaped_text_substr); |
410 | ClassDB::bind_method(D_METHOD("shaped_text_get_parent" , "shaped" ), &TextServer::shaped_text_get_parent); |
411 | ClassDB::bind_method(D_METHOD("shaped_text_fit_to_width" , "shaped" , "width" , "justification_flags" ), &TextServer::shaped_text_fit_to_width, DEFVAL(JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA)); |
412 | ClassDB::bind_method(D_METHOD("shaped_text_tab_align" , "shaped" , "tab_stops" ), &TextServer::shaped_text_tab_align); |
413 | |
414 | ClassDB::bind_method(D_METHOD("shaped_text_shape" , "shaped" ), &TextServer::shaped_text_shape); |
415 | ClassDB::bind_method(D_METHOD("shaped_text_is_ready" , "shaped" ), &TextServer::shaped_text_is_ready); |
416 | ClassDB::bind_method(D_METHOD("shaped_text_has_visible_chars" , "shaped" ), &TextServer::shaped_text_has_visible_chars); |
417 | |
418 | ClassDB::bind_method(D_METHOD("shaped_text_get_glyphs" , "shaped" ), &TextServer::_shaped_text_get_glyphs_wrapper); |
419 | ClassDB::bind_method(D_METHOD("shaped_text_sort_logical" , "shaped" ), &TextServer::_shaped_text_sort_logical_wrapper); |
420 | ClassDB::bind_method(D_METHOD("shaped_text_get_glyph_count" , "shaped" ), &TextServer::shaped_text_get_glyph_count); |
421 | |
422 | ClassDB::bind_method(D_METHOD("shaped_text_get_range" , "shaped" ), &TextServer::shaped_text_get_range); |
423 | ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks_adv" , "shaped" , "width" , "start" , "once" , "break_flags" ), &TextServer::shaped_text_get_line_breaks_adv, DEFVAL(0), DEFVAL(true), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND)); |
424 | ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks" , "shaped" , "width" , "start" , "break_flags" ), &TextServer::shaped_text_get_line_breaks, DEFVAL(0), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND)); |
425 | ClassDB::bind_method(D_METHOD("shaped_text_get_word_breaks" , "shaped" , "grapheme_flags" ), &TextServer::shaped_text_get_word_breaks, DEFVAL(GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION)); |
426 | |
427 | ClassDB::bind_method(D_METHOD("shaped_text_get_trim_pos" , "shaped" ), &TextServer::shaped_text_get_trim_pos); |
428 | ClassDB::bind_method(D_METHOD("shaped_text_get_ellipsis_pos" , "shaped" ), &TextServer::shaped_text_get_ellipsis_pos); |
429 | ClassDB::bind_method(D_METHOD("shaped_text_get_ellipsis_glyphs" , "shaped" ), &TextServer::_shaped_text_get_ellipsis_glyphs_wrapper); |
430 | ClassDB::bind_method(D_METHOD("shaped_text_get_ellipsis_glyph_count" , "shaped" ), &TextServer::shaped_text_get_ellipsis_glyph_count); |
431 | |
432 | ClassDB::bind_method(D_METHOD("shaped_text_overrun_trim_to_width" , "shaped" , "width" , "overrun_trim_flags" ), &TextServer::shaped_text_overrun_trim_to_width, DEFVAL(0), DEFVAL(OVERRUN_NO_TRIM)); |
433 | |
434 | ClassDB::bind_method(D_METHOD("shaped_text_get_objects" , "shaped" ), &TextServer::shaped_text_get_objects); |
435 | ClassDB::bind_method(D_METHOD("shaped_text_get_object_rect" , "shaped" , "key" ), &TextServer::shaped_text_get_object_rect); |
436 | |
437 | ClassDB::bind_method(D_METHOD("shaped_text_get_size" , "shaped" ), &TextServer::shaped_text_get_size); |
438 | ClassDB::bind_method(D_METHOD("shaped_text_get_ascent" , "shaped" ), &TextServer::shaped_text_get_ascent); |
439 | ClassDB::bind_method(D_METHOD("shaped_text_get_descent" , "shaped" ), &TextServer::shaped_text_get_descent); |
440 | ClassDB::bind_method(D_METHOD("shaped_text_get_width" , "shaped" ), &TextServer::shaped_text_get_width); |
441 | ClassDB::bind_method(D_METHOD("shaped_text_get_underline_position" , "shaped" ), &TextServer::shaped_text_get_underline_position); |
442 | ClassDB::bind_method(D_METHOD("shaped_text_get_underline_thickness" , "shaped" ), &TextServer::shaped_text_get_underline_thickness); |
443 | |
444 | ClassDB::bind_method(D_METHOD("shaped_text_get_carets" , "shaped" , "position" ), &TextServer::_shaped_text_get_carets_wrapper); |
445 | ClassDB::bind_method(D_METHOD("shaped_text_get_selection" , "shaped" , "start" , "end" ), &TextServer::shaped_text_get_selection); |
446 | |
447 | ClassDB::bind_method(D_METHOD("shaped_text_hit_test_grapheme" , "shaped" , "coords" ), &TextServer::shaped_text_hit_test_grapheme); |
448 | ClassDB::bind_method(D_METHOD("shaped_text_hit_test_position" , "shaped" , "coords" ), &TextServer::shaped_text_hit_test_position); |
449 | |
450 | ClassDB::bind_method(D_METHOD("shaped_text_get_grapheme_bounds" , "shaped" , "pos" ), &TextServer::shaped_text_get_grapheme_bounds); |
451 | ClassDB::bind_method(D_METHOD("shaped_text_next_grapheme_pos" , "shaped" , "pos" ), &TextServer::shaped_text_next_grapheme_pos); |
452 | ClassDB::bind_method(D_METHOD("shaped_text_prev_grapheme_pos" , "shaped" , "pos" ), &TextServer::shaped_text_prev_grapheme_pos); |
453 | |
454 | ClassDB::bind_method(D_METHOD("shaped_text_get_character_breaks" , "shaped" ), &TextServer::shaped_text_get_character_breaks); |
455 | ClassDB::bind_method(D_METHOD("shaped_text_next_character_pos" , "shaped" , "pos" ), &TextServer::shaped_text_next_character_pos); |
456 | ClassDB::bind_method(D_METHOD("shaped_text_prev_character_pos" , "shaped" , "pos" ), &TextServer::shaped_text_prev_character_pos); |
457 | ClassDB::bind_method(D_METHOD("shaped_text_closest_character_pos" , "shaped" , "pos" ), &TextServer::shaped_text_closest_character_pos); |
458 | |
459 | ClassDB::bind_method(D_METHOD("shaped_text_draw" , "shaped" , "canvas" , "pos" , "clip_l" , "clip_r" , "color" ), &TextServer::shaped_text_draw, DEFVAL(-1), DEFVAL(-1), DEFVAL(Color(1, 1, 1))); |
460 | ClassDB::bind_method(D_METHOD("shaped_text_draw_outline" , "shaped" , "canvas" , "pos" , "clip_l" , "clip_r" , "outline_size" , "color" ), &TextServer::shaped_text_draw_outline, DEFVAL(-1), DEFVAL(-1), DEFVAL(1), DEFVAL(Color(1, 1, 1))); |
461 | |
462 | ClassDB::bind_method(D_METHOD("shaped_text_get_dominant_direction_in_range" , "shaped" , "start" , "end" ), &TextServer::shaped_text_get_dominant_direction_in_range); |
463 | |
464 | ClassDB::bind_method(D_METHOD("format_number" , "number" , "language" ), &TextServer::format_number, DEFVAL("" )); |
465 | ClassDB::bind_method(D_METHOD("parse_number" , "number" , "language" ), &TextServer::parse_number, DEFVAL("" )); |
466 | ClassDB::bind_method(D_METHOD("percent_sign" , "language" ), &TextServer::percent_sign, DEFVAL("" )); |
467 | |
468 | ClassDB::bind_method(D_METHOD("string_get_word_breaks" , "string" , "language" , "chars_per_line" ), &TextServer::string_get_word_breaks, DEFVAL("" ), DEFVAL(0)); |
469 | ClassDB::bind_method(D_METHOD("string_get_character_breaks" , "string" , "language" ), &TextServer::string_get_character_breaks, DEFVAL("" )); |
470 | |
471 | ClassDB::bind_method(D_METHOD("is_confusable" , "string" , "dict" ), &TextServer::is_confusable); |
472 | ClassDB::bind_method(D_METHOD("spoof_check" , "string" ), &TextServer::spoof_check); |
473 | |
474 | ClassDB::bind_method(D_METHOD("strip_diacritics" , "string" ), &TextServer::strip_diacritics); |
475 | ClassDB::bind_method(D_METHOD("is_valid_identifier" , "string" ), &TextServer::is_valid_identifier); |
476 | |
477 | ClassDB::bind_method(D_METHOD("string_to_upper" , "string" , "language" ), &TextServer::string_to_upper, DEFVAL("" )); |
478 | ClassDB::bind_method(D_METHOD("string_to_lower" , "string" , "language" ), &TextServer::string_to_lower, DEFVAL("" )); |
479 | |
480 | ClassDB::bind_method(D_METHOD("parse_structured_text" , "parser_type" , "args" , "text" ), &TextServer::parse_structured_text); |
481 | |
482 | /* Font AA */ |
483 | BIND_ENUM_CONSTANT(FONT_ANTIALIASING_NONE); |
484 | BIND_ENUM_CONSTANT(FONT_ANTIALIASING_GRAY); |
485 | BIND_ENUM_CONSTANT(FONT_ANTIALIASING_LCD); |
486 | |
487 | BIND_ENUM_CONSTANT(FONT_LCD_SUBPIXEL_LAYOUT_NONE); |
488 | BIND_ENUM_CONSTANT(FONT_LCD_SUBPIXEL_LAYOUT_HRGB); |
489 | BIND_ENUM_CONSTANT(FONT_LCD_SUBPIXEL_LAYOUT_HBGR); |
490 | BIND_ENUM_CONSTANT(FONT_LCD_SUBPIXEL_LAYOUT_VRGB); |
491 | BIND_ENUM_CONSTANT(FONT_LCD_SUBPIXEL_LAYOUT_VBGR); |
492 | BIND_ENUM_CONSTANT(FONT_LCD_SUBPIXEL_LAYOUT_MAX); |
493 | |
494 | /* Direction */ |
495 | BIND_ENUM_CONSTANT(DIRECTION_AUTO); |
496 | BIND_ENUM_CONSTANT(DIRECTION_LTR); |
497 | BIND_ENUM_CONSTANT(DIRECTION_RTL); |
498 | BIND_ENUM_CONSTANT(DIRECTION_INHERITED); |
499 | |
500 | /* Orientation */ |
501 | BIND_ENUM_CONSTANT(ORIENTATION_HORIZONTAL); |
502 | BIND_ENUM_CONSTANT(ORIENTATION_VERTICAL); |
503 | |
504 | /* JustificationFlag */ |
505 | BIND_BITFIELD_FLAG(JUSTIFICATION_NONE); |
506 | BIND_BITFIELD_FLAG(JUSTIFICATION_KASHIDA); |
507 | BIND_BITFIELD_FLAG(JUSTIFICATION_WORD_BOUND); |
508 | BIND_BITFIELD_FLAG(JUSTIFICATION_TRIM_EDGE_SPACES); |
509 | BIND_BITFIELD_FLAG(JUSTIFICATION_AFTER_LAST_TAB); |
510 | BIND_BITFIELD_FLAG(JUSTIFICATION_CONSTRAIN_ELLIPSIS); |
511 | BIND_BITFIELD_FLAG(JUSTIFICATION_SKIP_LAST_LINE); |
512 | BIND_BITFIELD_FLAG(JUSTIFICATION_SKIP_LAST_LINE_WITH_VISIBLE_CHARS); |
513 | BIND_BITFIELD_FLAG(JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE); |
514 | |
515 | /* AutowrapMode */ |
516 | BIND_ENUM_CONSTANT(AUTOWRAP_OFF); |
517 | BIND_ENUM_CONSTANT(AUTOWRAP_ARBITRARY); |
518 | BIND_ENUM_CONSTANT(AUTOWRAP_WORD); |
519 | BIND_ENUM_CONSTANT(AUTOWRAP_WORD_SMART); |
520 | |
521 | /* LineBreakFlag */ |
522 | BIND_BITFIELD_FLAG(BREAK_NONE); |
523 | BIND_BITFIELD_FLAG(BREAK_MANDATORY); |
524 | BIND_BITFIELD_FLAG(BREAK_WORD_BOUND); |
525 | BIND_BITFIELD_FLAG(BREAK_GRAPHEME_BOUND); |
526 | BIND_BITFIELD_FLAG(BREAK_ADAPTIVE); |
527 | BIND_BITFIELD_FLAG(BREAK_TRIM_EDGE_SPACES); |
528 | |
529 | /* VisibleCharactersBehavior */ |
530 | BIND_ENUM_CONSTANT(VC_CHARS_BEFORE_SHAPING); |
531 | BIND_ENUM_CONSTANT(VC_CHARS_AFTER_SHAPING); |
532 | BIND_ENUM_CONSTANT(VC_GLYPHS_AUTO); |
533 | BIND_ENUM_CONSTANT(VC_GLYPHS_LTR); |
534 | BIND_ENUM_CONSTANT(VC_GLYPHS_RTL); |
535 | |
536 | /* OverrunBehavior */ |
537 | BIND_ENUM_CONSTANT(OVERRUN_NO_TRIMMING); |
538 | BIND_ENUM_CONSTANT(OVERRUN_TRIM_CHAR); |
539 | BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD); |
540 | BIND_ENUM_CONSTANT(OVERRUN_TRIM_ELLIPSIS); |
541 | BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD_ELLIPSIS); |
542 | |
543 | /* TextOverrunFlag */ |
544 | BIND_BITFIELD_FLAG(OVERRUN_NO_TRIM); |
545 | BIND_BITFIELD_FLAG(OVERRUN_TRIM); |
546 | BIND_BITFIELD_FLAG(OVERRUN_TRIM_WORD_ONLY); |
547 | BIND_BITFIELD_FLAG(OVERRUN_ADD_ELLIPSIS); |
548 | BIND_BITFIELD_FLAG(OVERRUN_ENFORCE_ELLIPSIS); |
549 | BIND_BITFIELD_FLAG(OVERRUN_JUSTIFICATION_AWARE); |
550 | |
551 | /* GraphemeFlag */ |
552 | BIND_BITFIELD_FLAG(GRAPHEME_IS_VALID); |
553 | BIND_BITFIELD_FLAG(GRAPHEME_IS_RTL); |
554 | BIND_BITFIELD_FLAG(GRAPHEME_IS_VIRTUAL); |
555 | BIND_BITFIELD_FLAG(GRAPHEME_IS_SPACE); |
556 | BIND_BITFIELD_FLAG(GRAPHEME_IS_BREAK_HARD); |
557 | BIND_BITFIELD_FLAG(GRAPHEME_IS_BREAK_SOFT); |
558 | BIND_BITFIELD_FLAG(GRAPHEME_IS_TAB); |
559 | BIND_BITFIELD_FLAG(GRAPHEME_IS_ELONGATION); |
560 | BIND_BITFIELD_FLAG(GRAPHEME_IS_PUNCTUATION); |
561 | BIND_BITFIELD_FLAG(GRAPHEME_IS_UNDERSCORE); |
562 | BIND_BITFIELD_FLAG(GRAPHEME_IS_CONNECTED); |
563 | BIND_BITFIELD_FLAG(GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL); |
564 | BIND_BITFIELD_FLAG(GRAPHEME_IS_EMBEDDED_OBJECT); |
565 | |
566 | /* Hinting */ |
567 | BIND_ENUM_CONSTANT(HINTING_NONE); |
568 | BIND_ENUM_CONSTANT(HINTING_LIGHT); |
569 | BIND_ENUM_CONSTANT(HINTING_NORMAL); |
570 | |
571 | /* SubpixelPositioning */ |
572 | BIND_ENUM_CONSTANT(SUBPIXEL_POSITIONING_DISABLED); |
573 | BIND_ENUM_CONSTANT(SUBPIXEL_POSITIONING_AUTO); |
574 | BIND_ENUM_CONSTANT(SUBPIXEL_POSITIONING_ONE_HALF); |
575 | BIND_ENUM_CONSTANT(SUBPIXEL_POSITIONING_ONE_QUARTER); |
576 | BIND_ENUM_CONSTANT(SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE); |
577 | BIND_ENUM_CONSTANT(SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE); |
578 | |
579 | /* Feature */ |
580 | BIND_ENUM_CONSTANT(FEATURE_SIMPLE_LAYOUT); |
581 | BIND_ENUM_CONSTANT(FEATURE_BIDI_LAYOUT); |
582 | BIND_ENUM_CONSTANT(FEATURE_VERTICAL_LAYOUT); |
583 | BIND_ENUM_CONSTANT(FEATURE_SHAPING); |
584 | BIND_ENUM_CONSTANT(FEATURE_KASHIDA_JUSTIFICATION); |
585 | BIND_ENUM_CONSTANT(FEATURE_BREAK_ITERATORS); |
586 | BIND_ENUM_CONSTANT(FEATURE_FONT_BITMAP); |
587 | BIND_ENUM_CONSTANT(FEATURE_FONT_DYNAMIC); |
588 | BIND_ENUM_CONSTANT(FEATURE_FONT_MSDF); |
589 | BIND_ENUM_CONSTANT(FEATURE_FONT_SYSTEM); |
590 | BIND_ENUM_CONSTANT(FEATURE_FONT_VARIABLE); |
591 | BIND_ENUM_CONSTANT(FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION); |
592 | BIND_ENUM_CONSTANT(FEATURE_USE_SUPPORT_DATA); |
593 | BIND_ENUM_CONSTANT(FEATURE_UNICODE_IDENTIFIERS); |
594 | BIND_ENUM_CONSTANT(FEATURE_UNICODE_SECURITY); |
595 | |
596 | /* FT Contour Point Types */ |
597 | BIND_ENUM_CONSTANT(CONTOUR_CURVE_TAG_ON); |
598 | BIND_ENUM_CONSTANT(CONTOUR_CURVE_TAG_OFF_CONIC); |
599 | BIND_ENUM_CONSTANT(CONTOUR_CURVE_TAG_OFF_CUBIC); |
600 | |
601 | /* Font Spacing */ |
602 | BIND_ENUM_CONSTANT(SPACING_GLYPH); |
603 | BIND_ENUM_CONSTANT(SPACING_SPACE); |
604 | BIND_ENUM_CONSTANT(SPACING_TOP); |
605 | BIND_ENUM_CONSTANT(SPACING_BOTTOM); |
606 | BIND_ENUM_CONSTANT(SPACING_MAX); |
607 | |
608 | /* Font Style */ |
609 | BIND_BITFIELD_FLAG(FONT_BOLD); |
610 | BIND_BITFIELD_FLAG(FONT_ITALIC); |
611 | BIND_BITFIELD_FLAG(FONT_FIXED_WIDTH); |
612 | |
613 | /* Structured text parser */ |
614 | BIND_ENUM_CONSTANT(STRUCTURED_TEXT_DEFAULT); |
615 | BIND_ENUM_CONSTANT(STRUCTURED_TEXT_URI); |
616 | BIND_ENUM_CONSTANT(STRUCTURED_TEXT_FILE); |
617 | BIND_ENUM_CONSTANT(STRUCTURED_TEXT_EMAIL); |
618 | BIND_ENUM_CONSTANT(STRUCTURED_TEXT_LIST); |
619 | BIND_ENUM_CONSTANT(STRUCTURED_TEXT_GDSCRIPT); |
620 | BIND_ENUM_CONSTANT(STRUCTURED_TEXT_CUSTOM); |
621 | } |
622 | |
623 | Vector2 TextServer::get_hex_code_box_size(int64_t p_size, int64_t p_index) const { |
624 | int w = ((p_index <= 0xFF) ? 1 : ((p_index <= 0xFFFF) ? 2 : 3)); |
625 | int sp = MAX(0, w - 1); |
626 | int sz = MAX(1, Math::round(p_size / 15.f)); |
627 | |
628 | return Vector2(4 + 3 * w + sp + 1, 15) * sz; |
629 | } |
630 | |
631 | void TextServer::_draw_hex_code_box_number(const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, uint8_t p_index, const Color &p_color) const { |
632 | static uint8_t chars[] = { 0x7E, 0x30, 0x6D, 0x79, 0x33, 0x5B, 0x5F, 0x70, 0x7F, 0x7B, 0x77, 0x1F, 0x4E, 0x3D, 0x4F, 0x47, 0x00 }; |
633 | uint8_t x = chars[p_index]; |
634 | if (x & (1 << 6)) { |
635 | RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(p_pos, Size2(3, 1) * p_size), p_color); |
636 | } |
637 | if (x & (1 << 5)) { |
638 | RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(p_pos + Point2(2, 0) * p_size, Size2(1, 3) * p_size), p_color); |
639 | } |
640 | if (x & (1 << 4)) { |
641 | RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(p_pos + Point2(2, 2) * p_size, Size2(1, 3) * p_size), p_color); |
642 | } |
643 | if (x & (1 << 3)) { |
644 | RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(p_pos + Point2(0, 4) * p_size, Size2(3, 1) * p_size), p_color); |
645 | } |
646 | if (x & (1 << 2)) { |
647 | RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(p_pos + Point2(0, 2) * p_size, Size2(1, 3) * p_size), p_color); |
648 | } |
649 | if (x & (1 << 1)) { |
650 | RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(p_pos, Size2(1, 3) * p_size), p_color); |
651 | } |
652 | if (x & (1 << 0)) { |
653 | RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(p_pos + Point2(0, 2) * p_size, Size2(3, 1) * p_size), p_color); |
654 | } |
655 | } |
656 | |
657 | void TextServer::draw_hex_code_box(const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const { |
658 | if (p_index == 0) { |
659 | return; |
660 | } |
661 | |
662 | int w = ((p_index <= 0xFF) ? 1 : ((p_index <= 0xFFFF) ? 2 : 3)); |
663 | int sp = MAX(0, w - 1); |
664 | int sz = MAX(1, Math::round(p_size / 15.f)); |
665 | |
666 | Size2 size = Vector2(4 + 3 * w + sp, 15) * sz; |
667 | Point2 pos = p_pos - Point2i(0, size.y * 0.85); |
668 | |
669 | // Draw frame. |
670 | RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, 0), Size2(sz, size.y)), p_color); |
671 | RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(size.x - sz, 0), Size2(sz, size.y)), p_color); |
672 | RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, 0), Size2(size.x, sz)), p_color); |
673 | RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, size.y - sz), Size2(size.x, sz)), p_color); |
674 | |
675 | uint8_t a = p_index & 0x0F; |
676 | uint8_t b = (p_index >> 4) & 0x0F; |
677 | uint8_t c = (p_index >> 8) & 0x0F; |
678 | uint8_t d = (p_index >> 12) & 0x0F; |
679 | uint8_t e = (p_index >> 16) & 0x0F; |
680 | uint8_t f = (p_index >> 20) & 0x0F; |
681 | |
682 | // Draw hex code. |
683 | if (p_index <= 0xFF) { |
684 | _draw_hex_code_box_number(p_canvas, sz, pos + Point2(2, 2) * sz, b, p_color); |
685 | _draw_hex_code_box_number(p_canvas, sz, pos + Point2(2, 8) * sz, a, p_color); |
686 | } else if (p_index <= 0xFFFF) { |
687 | _draw_hex_code_box_number(p_canvas, sz, pos + Point2(2, 2) * sz, d, p_color); |
688 | _draw_hex_code_box_number(p_canvas, sz, pos + Point2(6, 2) * sz, c, p_color); |
689 | _draw_hex_code_box_number(p_canvas, sz, pos + Point2(2, 8) * sz, b, p_color); |
690 | _draw_hex_code_box_number(p_canvas, sz, pos + Point2(6, 8) * sz, a, p_color); |
691 | } else { |
692 | _draw_hex_code_box_number(p_canvas, sz, pos + Point2(2, 2) * sz, f, p_color); |
693 | _draw_hex_code_box_number(p_canvas, sz, pos + Point2(6, 2) * sz, e, p_color); |
694 | _draw_hex_code_box_number(p_canvas, sz, pos + Point2(10, 2) * sz, d, p_color); |
695 | _draw_hex_code_box_number(p_canvas, sz, pos + Point2(2, 8) * sz, c, p_color); |
696 | _draw_hex_code_box_number(p_canvas, sz, pos + Point2(6, 8) * sz, b, p_color); |
697 | _draw_hex_code_box_number(p_canvas, sz, pos + Point2(10, 8) * sz, a, p_color); |
698 | } |
699 | } |
700 | |
701 | bool TextServer::shaped_text_has_visible_chars(const RID &p_shaped) const { |
702 | int v_size = shaped_text_get_glyph_count(p_shaped); |
703 | if (v_size == 0) { |
704 | return false; |
705 | } |
706 | |
707 | const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); |
708 | for (int i = 0; i < v_size; i++) { |
709 | if (glyphs[i].index != 0 && (glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL) { |
710 | return true; |
711 | } |
712 | } |
713 | return false; |
714 | } |
715 | |
716 | PackedInt32Array TextServer::shaped_text_get_line_breaks_adv(const RID &p_shaped, const PackedFloat32Array &p_width, int64_t p_start, bool p_once, BitField<TextServer::LineBreakFlag> p_break_flags) const { |
717 | PackedInt32Array lines; |
718 | |
719 | ERR_FAIL_COND_V(p_width.is_empty(), lines); |
720 | |
721 | const_cast<TextServer *>(this)->shaped_text_update_breaks(p_shaped); |
722 | const Vector2i &range = shaped_text_get_range(p_shaped); |
723 | |
724 | real_t width = 0.f; |
725 | int line_start = MAX(p_start, range.x); |
726 | int last_end = line_start; |
727 | int prev_safe_break = 0; |
728 | int last_safe_break = -1; |
729 | int word_count = 0; |
730 | int chunk = 0; |
731 | bool trim_next = false; |
732 | |
733 | int l_size = shaped_text_get_glyph_count(p_shaped); |
734 | const Glyph *l_gl = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); |
735 | |
736 | for (int i = 0; i < l_size; i++) { |
737 | if (l_gl[i].start < p_start) { |
738 | prev_safe_break = i + 1; |
739 | continue; |
740 | } |
741 | if (l_gl[i].count > 0) { |
742 | if ((p_width[chunk] > 0) && (width + l_gl[i].advance > p_width[chunk]) && (last_safe_break >= 0)) { |
743 | if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) { |
744 | int start_pos = prev_safe_break; |
745 | int end_pos = last_safe_break; |
746 | while (trim_next && (start_pos < end_pos) && ((l_gl[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { |
747 | start_pos += l_gl[start_pos].count; |
748 | } |
749 | while ((start_pos < end_pos) && ((l_gl[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { |
750 | end_pos -= l_gl[end_pos].count; |
751 | } |
752 | if (last_end <= l_gl[start_pos].start) { |
753 | lines.push_back(l_gl[start_pos].start); |
754 | lines.push_back(l_gl[end_pos].end); |
755 | last_end = l_gl[end_pos].end; |
756 | } |
757 | trim_next = true; |
758 | } else { |
759 | if (last_end <= line_start) { |
760 | lines.push_back(line_start); |
761 | lines.push_back(l_gl[last_safe_break].end); |
762 | last_end = l_gl[last_safe_break].end; |
763 | } |
764 | } |
765 | line_start = l_gl[last_safe_break].end; |
766 | prev_safe_break = last_safe_break + 1; |
767 | i = last_safe_break; |
768 | last_safe_break = -1; |
769 | width = 0; |
770 | word_count = 0; |
771 | chunk++; |
772 | if (chunk >= p_width.size()) { |
773 | chunk = 0; |
774 | if (p_once) { |
775 | return lines; |
776 | } |
777 | } |
778 | continue; |
779 | } |
780 | if (p_break_flags.has_flag(BREAK_MANDATORY)) { |
781 | if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) { |
782 | if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) { |
783 | int start_pos = prev_safe_break; |
784 | int end_pos = i; |
785 | while (trim_next && (start_pos < end_pos) && ((l_gl[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { |
786 | start_pos += l_gl[start_pos].count; |
787 | } |
788 | while ((start_pos < end_pos) && ((l_gl[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { |
789 | end_pos -= l_gl[end_pos].count; |
790 | } |
791 | if (last_end <= l_gl[start_pos].start) { |
792 | lines.push_back(l_gl[start_pos].start); |
793 | lines.push_back(l_gl[end_pos].end); |
794 | last_end = l_gl[end_pos].end; |
795 | } |
796 | trim_next = false; |
797 | } else { |
798 | if (last_end <= line_start) { |
799 | lines.push_back(line_start); |
800 | lines.push_back(l_gl[i].end); |
801 | last_end = l_gl[i].end; |
802 | } |
803 | } |
804 | line_start = l_gl[i].end; |
805 | prev_safe_break = i + 1; |
806 | last_safe_break = -1; |
807 | width = 0; |
808 | chunk = 0; |
809 | if (p_once) { |
810 | return lines; |
811 | } |
812 | continue; |
813 | } |
814 | } |
815 | if (p_break_flags.has_flag(BREAK_WORD_BOUND)) { |
816 | if ((l_gl[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) { |
817 | last_safe_break = i; |
818 | word_count++; |
819 | } |
820 | } |
821 | if (p_break_flags.has_flag(BREAK_GRAPHEME_BOUND) && word_count == 0) { |
822 | last_safe_break = i; |
823 | } |
824 | } |
825 | width += l_gl[i].advance; |
826 | } |
827 | |
828 | if (l_size > 0) { |
829 | if (lines.size() == 0 || (lines[lines.size() - 1] < range.y && prev_safe_break < l_size)) { |
830 | if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) { |
831 | int start_pos = (prev_safe_break < l_size) ? prev_safe_break : l_size - 1; |
832 | int end_pos = l_size - 1; |
833 | while (trim_next && (start_pos < end_pos) && ((l_gl[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { |
834 | start_pos += l_gl[start_pos].count; |
835 | } |
836 | lines.push_back(l_gl[start_pos].start); |
837 | } else { |
838 | lines.push_back(line_start); |
839 | } |
840 | lines.push_back(range.y); |
841 | } |
842 | } else { |
843 | lines.push_back(0); |
844 | lines.push_back(0); |
845 | } |
846 | |
847 | return lines; |
848 | } |
849 | |
850 | PackedInt32Array TextServer::shaped_text_get_line_breaks(const RID &p_shaped, double p_width, int64_t p_start, BitField<TextServer::LineBreakFlag> p_break_flags) const { |
851 | PackedInt32Array lines; |
852 | |
853 | const_cast<TextServer *>(this)->shaped_text_update_breaks(p_shaped); |
854 | const Vector2i &range = shaped_text_get_range(p_shaped); |
855 | |
856 | double width = 0.f; |
857 | int line_start = MAX(p_start, range.x); |
858 | int last_end = line_start; |
859 | int prev_safe_break = 0; |
860 | int last_safe_break = -1; |
861 | int word_count = 0; |
862 | bool trim_next = false; |
863 | |
864 | int l_size = shaped_text_get_glyph_count(p_shaped); |
865 | const Glyph *l_gl = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); |
866 | |
867 | for (int i = 0; i < l_size; i++) { |
868 | if (l_gl[i].start < p_start) { |
869 | prev_safe_break = i + 1; |
870 | continue; |
871 | } |
872 | if (l_gl[i].count > 0) { |
873 | if ((p_width > 0) && (width + l_gl[i].advance * l_gl[i].repeat > p_width) && (last_safe_break >= 0)) { |
874 | if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) { |
875 | int start_pos = prev_safe_break; |
876 | int end_pos = last_safe_break; |
877 | while (trim_next && (start_pos < end_pos) && ((l_gl[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { |
878 | start_pos += l_gl[start_pos].count; |
879 | } |
880 | while ((start_pos < end_pos) && ((l_gl[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { |
881 | end_pos -= l_gl[end_pos].count; |
882 | } |
883 | if (last_end <= l_gl[start_pos].start) { |
884 | lines.push_back(l_gl[start_pos].start); |
885 | lines.push_back(l_gl[end_pos].end); |
886 | last_end = l_gl[end_pos].end; |
887 | } |
888 | trim_next = true; |
889 | } else { |
890 | if (last_end <= line_start) { |
891 | lines.push_back(line_start); |
892 | lines.push_back(l_gl[last_safe_break].end); |
893 | last_end = l_gl[last_safe_break].end; |
894 | } |
895 | } |
896 | line_start = l_gl[last_safe_break].end; |
897 | prev_safe_break = last_safe_break + 1; |
898 | i = last_safe_break; |
899 | last_safe_break = -1; |
900 | width = 0; |
901 | word_count = 0; |
902 | continue; |
903 | } |
904 | if (p_break_flags.has_flag(BREAK_MANDATORY)) { |
905 | if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) { |
906 | if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) { |
907 | int start_pos = prev_safe_break; |
908 | int end_pos = i; |
909 | while (trim_next && (start_pos < end_pos) && ((l_gl[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { |
910 | start_pos += l_gl[start_pos].count; |
911 | } |
912 | while ((start_pos < end_pos) && ((l_gl[end_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[end_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { |
913 | end_pos -= l_gl[end_pos].count; |
914 | } |
915 | trim_next = false; |
916 | if (last_end <= l_gl[start_pos].start) { |
917 | lines.push_back(l_gl[start_pos].start); |
918 | lines.push_back(l_gl[end_pos].end); |
919 | last_end = l_gl[end_pos].end; |
920 | } |
921 | } else { |
922 | if (last_end <= line_start) { |
923 | lines.push_back(line_start); |
924 | lines.push_back(l_gl[i].end); |
925 | last_end = l_gl[i].end; |
926 | } |
927 | } |
928 | line_start = l_gl[i].end; |
929 | prev_safe_break = i + 1; |
930 | last_safe_break = -1; |
931 | width = 0; |
932 | continue; |
933 | } |
934 | } |
935 | if (p_break_flags.has_flag(BREAK_WORD_BOUND)) { |
936 | if ((l_gl[i].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT) { |
937 | last_safe_break = i; |
938 | word_count++; |
939 | } |
940 | if (p_break_flags.has_flag(BREAK_ADAPTIVE) && word_count == 0) { |
941 | last_safe_break = i; |
942 | } |
943 | } |
944 | if (p_break_flags.has_flag(BREAK_GRAPHEME_BOUND)) { |
945 | last_safe_break = i; |
946 | } |
947 | } |
948 | width += l_gl[i].advance * l_gl[i].repeat; |
949 | } |
950 | |
951 | if (l_size > 0) { |
952 | if (lines.size() == 0 || (lines[lines.size() - 1] < range.y && prev_safe_break < l_size)) { |
953 | if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) { |
954 | int start_pos = (prev_safe_break < l_size) ? prev_safe_break : l_size - 1; |
955 | int end_pos = l_size - 1; |
956 | while (trim_next && (start_pos < end_pos) && ((l_gl[start_pos].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD || (l_gl[start_pos].flags & GRAPHEME_IS_BREAK_SOFT) == GRAPHEME_IS_BREAK_SOFT)) { |
957 | start_pos += l_gl[start_pos].count; |
958 | } |
959 | lines.push_back(l_gl[start_pos].start); |
960 | } else { |
961 | lines.push_back(line_start); |
962 | } |
963 | lines.push_back(range.y); |
964 | } |
965 | } else { |
966 | lines.push_back(0); |
967 | lines.push_back(0); |
968 | } |
969 | |
970 | return lines; |
971 | } |
972 | |
973 | PackedInt32Array TextServer::shaped_text_get_word_breaks(const RID &p_shaped, BitField<TextServer::GraphemeFlag> p_grapheme_flags) const { |
974 | PackedInt32Array words; |
975 | |
976 | const_cast<TextServer *>(this)->shaped_text_update_justification_ops(p_shaped); |
977 | const Vector2i &range = shaped_text_get_range(p_shaped); |
978 | |
979 | int word_start = range.x; |
980 | |
981 | const int l_size = shaped_text_get_glyph_count(p_shaped); |
982 | const Glyph *l_gl = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); |
983 | |
984 | for (int i = 0; i < l_size; i++) { |
985 | if (l_gl[i].count > 0) { |
986 | if ((l_gl[i].flags & p_grapheme_flags) != 0) { |
987 | if (word_start != l_gl[i].start) { |
988 | words.push_back(word_start); |
989 | words.push_back(l_gl[i].start); |
990 | } |
991 | word_start = l_gl[i].end; |
992 | } |
993 | } |
994 | } |
995 | if (l_size > 0) { |
996 | if (word_start != range.y) { |
997 | words.push_back(word_start); |
998 | words.push_back(range.y); |
999 | } |
1000 | } |
1001 | |
1002 | return words; |
1003 | } |
1004 | |
1005 | CaretInfo TextServer::shaped_text_get_carets(const RID &p_shaped, int64_t p_position) const { |
1006 | Vector<Rect2> carets; |
1007 | |
1008 | TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped); |
1009 | const Vector2 &range = shaped_text_get_range(p_shaped); |
1010 | real_t ascent = shaped_text_get_ascent(p_shaped); |
1011 | real_t descent = shaped_text_get_descent(p_shaped); |
1012 | real_t height = (ascent + descent) / 2; |
1013 | |
1014 | real_t off = 0.0f; |
1015 | CaretInfo caret; |
1016 | caret.l_dir = DIRECTION_AUTO; |
1017 | caret.t_dir = DIRECTION_AUTO; |
1018 | |
1019 | int v_size = shaped_text_get_glyph_count(p_shaped); |
1020 | const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); |
1021 | |
1022 | for (int i = 0; i < v_size; i++) { |
1023 | if (glyphs[i].count > 0) { |
1024 | // Caret before grapheme (top / left). |
1025 | if (p_position == glyphs[i].start && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) { |
1026 | real_t advance = 0.f; |
1027 | for (int j = 0; j < glyphs[i].count; j++) { |
1028 | advance += glyphs[i + j].advance * glyphs[i + j].repeat; |
1029 | } |
1030 | real_t char_adv = advance / (real_t)(glyphs[i].end - glyphs[i].start); |
1031 | Rect2 cr; |
1032 | if (orientation == ORIENTATION_HORIZONTAL) { |
1033 | if (glyphs[i].start == range.x) { |
1034 | cr.size.y = height * 2; |
1035 | } else { |
1036 | cr.size.y = height; |
1037 | } |
1038 | cr.position.y = -ascent; |
1039 | cr.position.x = off; |
1040 | if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { |
1041 | caret.t_dir = DIRECTION_RTL; |
1042 | cr.position.x += advance; |
1043 | cr.size.x = -char_adv; |
1044 | } else { |
1045 | caret.t_dir = DIRECTION_LTR; |
1046 | cr.size.x = char_adv; |
1047 | } |
1048 | } else { |
1049 | if (glyphs[i].start == range.x) { |
1050 | cr.size.x = height * 2; |
1051 | } else { |
1052 | cr.size.x = height; |
1053 | } |
1054 | cr.position.x = -ascent; |
1055 | cr.position.y = off; |
1056 | if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { |
1057 | caret.t_dir = DIRECTION_RTL; |
1058 | cr.position.y += advance; |
1059 | cr.size.y = -char_adv; |
1060 | } else { |
1061 | caret.t_dir = DIRECTION_LTR; |
1062 | cr.size.y = char_adv; |
1063 | } |
1064 | } |
1065 | caret.t_caret = cr; |
1066 | } |
1067 | // Caret after grapheme (bottom / right). |
1068 | if (p_position == glyphs[i].end && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) { |
1069 | real_t advance = 0.f; |
1070 | for (int j = 0; j < glyphs[i].count; j++) { |
1071 | advance += glyphs[i + j].advance * glyphs[i + j].repeat; |
1072 | } |
1073 | real_t char_adv = advance / (real_t)(glyphs[i].end - glyphs[i].start); |
1074 | Rect2 cr; |
1075 | if (orientation == ORIENTATION_HORIZONTAL) { |
1076 | if (glyphs[i].end == range.y) { |
1077 | cr.size.y = height * 2; |
1078 | cr.position.y = -ascent; |
1079 | } else { |
1080 | cr.size.y = height; |
1081 | cr.position.y = -ascent + height; |
1082 | } |
1083 | cr.position.x = off; |
1084 | if ((glyphs[i].flags & GRAPHEME_IS_RTL) != GRAPHEME_IS_RTL) { |
1085 | caret.l_dir = DIRECTION_LTR; |
1086 | cr.position.x += advance; |
1087 | cr.size.x = -char_adv; |
1088 | } else { |
1089 | caret.l_dir = DIRECTION_RTL; |
1090 | cr.size.x = char_adv; |
1091 | } |
1092 | } else { |
1093 | cr.size.y = 1.0f; |
1094 | if (glyphs[i].end == range.y) { |
1095 | cr.size.x = height * 2; |
1096 | cr.position.x = -ascent; |
1097 | } else { |
1098 | cr.size.x = height; |
1099 | cr.position.x = -ascent + height; |
1100 | } |
1101 | cr.position.y = off; |
1102 | if ((glyphs[i].flags & GRAPHEME_IS_RTL) != GRAPHEME_IS_RTL) { |
1103 | caret.l_dir = DIRECTION_LTR; |
1104 | cr.position.y += advance; |
1105 | cr.size.y = -char_adv; |
1106 | } else { |
1107 | caret.l_dir = DIRECTION_RTL; |
1108 | cr.position.x += advance; |
1109 | cr.size.y = char_adv; |
1110 | } |
1111 | } |
1112 | caret.l_caret = cr; |
1113 | } |
1114 | // Caret inside grapheme (middle). |
1115 | if (p_position > glyphs[i].start && p_position < glyphs[i].end && (glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL) { |
1116 | real_t advance = 0.f; |
1117 | for (int j = 0; j < glyphs[i].count; j++) { |
1118 | advance += glyphs[i + j].advance * glyphs[i + j].repeat; |
1119 | } |
1120 | real_t char_adv = advance / (real_t)(glyphs[i].end - glyphs[i].start); |
1121 | Rect2 cr; |
1122 | if (orientation == ORIENTATION_HORIZONTAL) { |
1123 | cr.size.y = height * 2; |
1124 | cr.position.y = -ascent; |
1125 | if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { |
1126 | cr.position.x = off + char_adv * (glyphs[i].end - p_position); |
1127 | cr.size.x = -char_adv; |
1128 | } else { |
1129 | cr.position.x = off + char_adv * (p_position - glyphs[i].start); |
1130 | cr.size.x = char_adv; |
1131 | } |
1132 | } else { |
1133 | cr.size.x = height * 2; |
1134 | cr.position.x = -ascent; |
1135 | if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { |
1136 | cr.position.y = off + char_adv * (glyphs[i].end - p_position); |
1137 | cr.size.y = -char_adv; |
1138 | } else { |
1139 | cr.position.y = off + char_adv * (p_position - glyphs[i].start); |
1140 | cr.size.y = char_adv; |
1141 | } |
1142 | } |
1143 | caret.t_caret = cr; |
1144 | caret.l_caret = cr; |
1145 | } |
1146 | } |
1147 | off += glyphs[i].advance * glyphs[i].repeat; |
1148 | } |
1149 | return caret; |
1150 | } |
1151 | |
1152 | Dictionary TextServer::_shaped_text_get_carets_wrapper(const RID &p_shaped, int64_t p_position) const { |
1153 | Dictionary ret; |
1154 | |
1155 | CaretInfo caret = shaped_text_get_carets(p_shaped, p_position); |
1156 | |
1157 | ret["leading_rect" ] = caret.l_caret; |
1158 | ret["leading_direction" ] = caret.l_dir; |
1159 | ret["trailing_rect" ] = caret.t_caret; |
1160 | ret["trailing_direction" ] = caret.t_dir; |
1161 | |
1162 | return ret; |
1163 | } |
1164 | |
1165 | TextServer::Direction TextServer::shaped_text_get_dominant_direction_in_range(const RID &p_shaped, int64_t p_start, int64_t p_end) const { |
1166 | if (p_start == p_end) { |
1167 | return DIRECTION_AUTO; |
1168 | } |
1169 | |
1170 | int start = MIN(p_start, p_end); |
1171 | int end = MAX(p_start, p_end); |
1172 | |
1173 | int rtl = 0; |
1174 | int ltr = 0; |
1175 | |
1176 | int v_size = shaped_text_get_glyph_count(p_shaped); |
1177 | const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); |
1178 | |
1179 | for (int i = 0; i < v_size; i++) { |
1180 | if ((glyphs[i].end > start) && (glyphs[i].start < end)) { |
1181 | if (glyphs[i].count > 0) { |
1182 | if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { |
1183 | rtl++; |
1184 | } else { |
1185 | ltr++; |
1186 | } |
1187 | } |
1188 | } |
1189 | } |
1190 | if (ltr == rtl) { |
1191 | return DIRECTION_AUTO; |
1192 | } else if (ltr > rtl) { |
1193 | return DIRECTION_LTR; |
1194 | } else { |
1195 | return DIRECTION_RTL; |
1196 | } |
1197 | } |
1198 | |
1199 | _FORCE_INLINE_ void _push_range(Vector<Vector2> &r_vector, real_t p_start, real_t p_end) { |
1200 | if (!r_vector.is_empty() && Math::is_equal_approx(r_vector[r_vector.size() - 1].y, p_start, (real_t)UNIT_EPSILON)) { |
1201 | r_vector.write[r_vector.size() - 1].y = p_end; |
1202 | } else { |
1203 | r_vector.push_back(Vector2(p_start, p_end)); |
1204 | } |
1205 | } |
1206 | |
1207 | Vector<Vector2> TextServer::shaped_text_get_selection(const RID &p_shaped, int64_t p_start, int64_t p_end) const { |
1208 | Vector<Vector2> ranges; |
1209 | |
1210 | if (p_start == p_end) { |
1211 | return ranges; |
1212 | } |
1213 | |
1214 | int start = MIN(p_start, p_end); |
1215 | int end = MAX(p_start, p_end); |
1216 | |
1217 | int v_size = shaped_text_get_glyph_count(p_shaped); |
1218 | const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); |
1219 | |
1220 | real_t off = 0.0f; |
1221 | for (int i = 0; i < v_size; i++) { |
1222 | for (int k = 0; k < glyphs[i].repeat; k++) { |
1223 | if ((glyphs[i].count > 0) && ((glyphs[i].index != 0) || ((glyphs[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE))) { |
1224 | if (glyphs[i].start < end && glyphs[i].end > start) { |
1225 | // Grapheme fully in selection range. |
1226 | if (glyphs[i].start >= start && glyphs[i].end <= end) { |
1227 | real_t advance = 0.f; |
1228 | for (int j = 0; j < glyphs[i].count; j++) { |
1229 | advance += glyphs[i + j].advance; |
1230 | } |
1231 | _push_range(ranges, off, off + advance); |
1232 | } |
1233 | // Only start of grapheme is in selection range. |
1234 | if (glyphs[i].start >= start && glyphs[i].end > end) { |
1235 | real_t advance = 0.f; |
1236 | for (int j = 0; j < glyphs[i].count; j++) { |
1237 | advance += glyphs[i + j].advance; |
1238 | } |
1239 | real_t char_adv = advance / (real_t)(glyphs[i].end - glyphs[i].start); |
1240 | if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { |
1241 | _push_range(ranges, off + char_adv * (glyphs[i].end - end), off + advance); |
1242 | } else { |
1243 | _push_range(ranges, off, off + char_adv * (end - glyphs[i].start)); |
1244 | } |
1245 | } |
1246 | // Only end of grapheme is in selection range. |
1247 | if (glyphs[i].start < start && glyphs[i].end <= end) { |
1248 | real_t advance = 0.f; |
1249 | for (int j = 0; j < glyphs[i].count; j++) { |
1250 | advance += glyphs[i + j].advance; |
1251 | } |
1252 | real_t char_adv = advance / (real_t)(glyphs[i].end - glyphs[i].start); |
1253 | if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { |
1254 | _push_range(ranges, off, off + char_adv * (glyphs[i].end - start)); |
1255 | } else { |
1256 | _push_range(ranges, off + char_adv * (start - glyphs[i].start), off + advance); |
1257 | } |
1258 | } |
1259 | // Selection range is within grapheme. |
1260 | if (glyphs[i].start < start && glyphs[i].end > end) { |
1261 | real_t advance = 0.f; |
1262 | for (int j = 0; j < glyphs[i].count; j++) { |
1263 | advance += glyphs[i + j].advance; |
1264 | } |
1265 | real_t char_adv = advance / (real_t)(glyphs[i].end - glyphs[i].start); |
1266 | if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { |
1267 | _push_range(ranges, off + char_adv * (glyphs[i].end - end), off + char_adv * (glyphs[i].end - start)); |
1268 | } else { |
1269 | _push_range(ranges, off + char_adv * (start - glyphs[i].start), off + char_adv * (end - glyphs[i].start)); |
1270 | } |
1271 | } |
1272 | } |
1273 | } |
1274 | off += glyphs[i].advance; |
1275 | } |
1276 | } |
1277 | |
1278 | return ranges; |
1279 | } |
1280 | |
1281 | int64_t TextServer::shaped_text_hit_test_grapheme(const RID &p_shaped, double p_coords) const { |
1282 | // Exact grapheme hit test, return -1 if missed. |
1283 | double off = 0.0f; |
1284 | |
1285 | int v_size = shaped_text_get_glyph_count(p_shaped); |
1286 | const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); |
1287 | |
1288 | for (int i = 0; i < v_size; i++) { |
1289 | for (int j = 0; j < glyphs[i].repeat; j++) { |
1290 | if (p_coords >= off && p_coords < off + glyphs[i].advance) { |
1291 | return i; |
1292 | } |
1293 | off += glyphs[i].advance; |
1294 | } |
1295 | } |
1296 | return -1; |
1297 | } |
1298 | |
1299 | int64_t TextServer::shaped_text_hit_test_position(const RID &p_shaped, double p_coords) const { |
1300 | int v_size = shaped_text_get_glyph_count(p_shaped); |
1301 | const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); |
1302 | |
1303 | // Cursor placement hit test. |
1304 | |
1305 | // Place caret to the left of the leftmost grapheme, or to position 0 if string is empty. |
1306 | if (p_coords <= 0) { |
1307 | if (v_size > 0) { |
1308 | if ((glyphs[0].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { |
1309 | return glyphs[0].end; |
1310 | } else { |
1311 | return glyphs[0].start; |
1312 | } |
1313 | } else { |
1314 | return 0; |
1315 | } |
1316 | } |
1317 | |
1318 | // Place caret to the right of the rightmost grapheme, or to position 0 if string is empty. |
1319 | if (p_coords >= shaped_text_get_width(p_shaped)) { |
1320 | if (v_size > 0) { |
1321 | if ((glyphs[v_size - 1].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { |
1322 | return glyphs[v_size - 1].start; |
1323 | } else { |
1324 | return glyphs[v_size - 1].end; |
1325 | } |
1326 | } else { |
1327 | return 0; |
1328 | } |
1329 | } |
1330 | |
1331 | real_t off = 0.0f; |
1332 | for (int i = 0; i < v_size; i++) { |
1333 | if (glyphs[i].count > 0) { |
1334 | real_t advance = 0.f; |
1335 | for (int j = 0; j < glyphs[i].count; j++) { |
1336 | advance += glyphs[i + j].advance * glyphs[i + j].repeat; |
1337 | } |
1338 | if (((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) && (p_coords >= off && p_coords < off + advance)) { |
1339 | if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { |
1340 | return glyphs[i].end; |
1341 | } else { |
1342 | return glyphs[i].start; |
1343 | } |
1344 | } |
1345 | // Ligature, handle mid-grapheme hit. |
1346 | if (p_coords >= off && p_coords < off + advance && glyphs[i].end > glyphs[i].start + 1) { |
1347 | int cnt = glyphs[i].end - glyphs[i].start; |
1348 | real_t char_adv = advance / (real_t)(cnt); |
1349 | real_t sub_off = off; |
1350 | for (int j = 0; j < cnt; j++) { |
1351 | // Place caret to the left of clicked sub-grapheme. |
1352 | if (p_coords >= sub_off && p_coords < sub_off + char_adv / 2) { |
1353 | if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { |
1354 | return glyphs[i].end - j; |
1355 | } else { |
1356 | return glyphs[i].start + j; |
1357 | } |
1358 | } |
1359 | // Place caret to the right of clicked sub-grapheme. |
1360 | if (p_coords >= sub_off + char_adv / 2 && p_coords < sub_off + char_adv) { |
1361 | if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { |
1362 | return glyphs[i].start + (cnt - 1) - j; |
1363 | } else { |
1364 | return glyphs[i].end - (cnt - 1) + j; |
1365 | } |
1366 | } |
1367 | sub_off += char_adv; |
1368 | } |
1369 | } |
1370 | // Place caret to the left of clicked grapheme. |
1371 | if (p_coords >= off && p_coords < off + advance / 2) { |
1372 | if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { |
1373 | return glyphs[i].end; |
1374 | } else { |
1375 | return glyphs[i].start; |
1376 | } |
1377 | } |
1378 | // Place caret to the right of clicked grapheme. |
1379 | if (p_coords >= off + advance / 2 && p_coords < off + advance) { |
1380 | if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { |
1381 | return glyphs[i].start; |
1382 | } else { |
1383 | return glyphs[i].end; |
1384 | } |
1385 | } |
1386 | } |
1387 | off += glyphs[i].advance * glyphs[i].repeat; |
1388 | } |
1389 | return 0; |
1390 | } |
1391 | |
1392 | Vector2 TextServer::shaped_text_get_grapheme_bounds(const RID &p_shaped, int64_t p_pos) const { |
1393 | int v_size = shaped_text_get_glyph_count(p_shaped); |
1394 | const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); |
1395 | |
1396 | real_t off = 0.0f; |
1397 | for (int i = 0; i < v_size; i++) { |
1398 | if ((glyphs[i].count > 0) && ((glyphs[i].index != 0) || ((glyphs[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE))) { |
1399 | if (glyphs[i].start <= p_pos && glyphs[i].end >= p_pos) { |
1400 | real_t advance = 0.f; |
1401 | for (int j = 0; j < glyphs[i].count; j++) { |
1402 | advance += glyphs[i + j].advance; |
1403 | } |
1404 | return Vector2(off, off + advance); |
1405 | } |
1406 | } |
1407 | off += glyphs[i].advance * glyphs[i].repeat; |
1408 | } |
1409 | |
1410 | return Vector2(); |
1411 | } |
1412 | |
1413 | int64_t TextServer::shaped_text_next_grapheme_pos(const RID &p_shaped, int64_t p_pos) const { |
1414 | int v_size = shaped_text_get_glyph_count(p_shaped); |
1415 | const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); |
1416 | for (int i = 0; i < v_size; i++) { |
1417 | if (p_pos >= glyphs[i].start && p_pos < glyphs[i].end) { |
1418 | return glyphs[i].end; |
1419 | } |
1420 | } |
1421 | return p_pos; |
1422 | } |
1423 | |
1424 | int64_t TextServer::shaped_text_prev_grapheme_pos(const RID &p_shaped, int64_t p_pos) const { |
1425 | int v_size = shaped_text_get_glyph_count(p_shaped); |
1426 | const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); |
1427 | for (int i = 0; i < v_size; i++) { |
1428 | if (p_pos > glyphs[i].start && p_pos <= glyphs[i].end) { |
1429 | return glyphs[i].start; |
1430 | } |
1431 | } |
1432 | |
1433 | return p_pos; |
1434 | } |
1435 | |
1436 | int64_t TextServer::shaped_text_prev_character_pos(const RID &p_shaped, int64_t p_pos) const { |
1437 | const PackedInt32Array &chars = shaped_text_get_character_breaks(p_shaped); |
1438 | int64_t prev = 0; |
1439 | for (const int32_t &E : chars) { |
1440 | if (E >= p_pos) { |
1441 | return prev; |
1442 | } |
1443 | prev = E; |
1444 | } |
1445 | return prev; |
1446 | } |
1447 | |
1448 | int64_t TextServer::shaped_text_next_character_pos(const RID &p_shaped, int64_t p_pos) const { |
1449 | const PackedInt32Array &chars = shaped_text_get_character_breaks(p_shaped); |
1450 | int64_t prev = 0; |
1451 | for (const int32_t &E : chars) { |
1452 | if (E > p_pos) { |
1453 | return E; |
1454 | } |
1455 | prev = E; |
1456 | } |
1457 | return prev; |
1458 | } |
1459 | |
1460 | int64_t TextServer::shaped_text_closest_character_pos(const RID &p_shaped, int64_t p_pos) const { |
1461 | const PackedInt32Array &chars = shaped_text_get_character_breaks(p_shaped); |
1462 | int64_t prev = 0; |
1463 | for (const int32_t &E : chars) { |
1464 | if (E == p_pos) { |
1465 | return E; |
1466 | } else if (E > p_pos) { |
1467 | if ((E - p_pos) < (p_pos - prev)) { |
1468 | return E; |
1469 | } else { |
1470 | return prev; |
1471 | } |
1472 | } |
1473 | prev = E; |
1474 | } |
1475 | return prev; |
1476 | } |
1477 | |
1478 | PackedInt32Array TextServer::string_get_character_breaks(const String &p_string, const String &p_language) const { |
1479 | PackedInt32Array ret; |
1480 | if (!p_string.is_empty()) { |
1481 | ret.resize(p_string.size() - 1); |
1482 | for (int i = 0; i < p_string.size() - 1; i++) { |
1483 | ret.write[i] = i + 1; |
1484 | } |
1485 | } |
1486 | return ret; |
1487 | } |
1488 | |
1489 | void TextServer::shaped_text_draw(const RID &p_shaped, const RID &p_canvas, const Vector2 &p_pos, double p_clip_l, double p_clip_r, const Color &p_color) const { |
1490 | TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped); |
1491 | bool hex_codes = shaped_text_get_preserve_control(p_shaped) || shaped_text_get_preserve_invalid(p_shaped); |
1492 | |
1493 | bool rtl = shaped_text_get_direction(p_shaped) == DIRECTION_RTL; |
1494 | |
1495 | int ellipsis_pos = shaped_text_get_ellipsis_pos(p_shaped); |
1496 | int trim_pos = shaped_text_get_trim_pos(p_shaped); |
1497 | |
1498 | const Glyph *ellipsis_glyphs = shaped_text_get_ellipsis_glyphs(p_shaped); |
1499 | int ellipsis_gl_size = shaped_text_get_ellipsis_glyph_count(p_shaped); |
1500 | |
1501 | int v_size = shaped_text_get_glyph_count(p_shaped); |
1502 | const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); |
1503 | |
1504 | Vector2 ofs = p_pos; |
1505 | // Draw RTL ellipsis string when needed. |
1506 | if (rtl && ellipsis_pos >= 0) { |
1507 | for (int i = ellipsis_gl_size - 1; i >= 0; i--) { |
1508 | for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) { |
1509 | font_draw_glyph(ellipsis_glyphs[i].font_rid, p_canvas, ellipsis_glyphs[i].font_size, ofs + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color); |
1510 | if (orientation == ORIENTATION_HORIZONTAL) { |
1511 | ofs.x += ellipsis_glyphs[i].advance; |
1512 | } else { |
1513 | ofs.y += ellipsis_glyphs[i].advance; |
1514 | } |
1515 | } |
1516 | } |
1517 | } |
1518 | // Draw at the baseline. |
1519 | for (int i = 0; i < v_size; i++) { |
1520 | if (trim_pos >= 0) { |
1521 | if (rtl) { |
1522 | if (i < trim_pos) { |
1523 | continue; |
1524 | } |
1525 | } else { |
1526 | if (i >= trim_pos) { |
1527 | break; |
1528 | } |
1529 | } |
1530 | } |
1531 | for (int j = 0; j < glyphs[i].repeat; j++) { |
1532 | if (p_clip_r > 0) { |
1533 | // Clip right / bottom. |
1534 | if (orientation == ORIENTATION_HORIZONTAL) { |
1535 | if (ofs.x - p_pos.x + glyphs[i].advance > p_clip_r) { |
1536 | return; |
1537 | } |
1538 | } else { |
1539 | if (ofs.y - p_pos.y + glyphs[i].advance > p_clip_r) { |
1540 | return; |
1541 | } |
1542 | } |
1543 | } |
1544 | if (p_clip_l > 0) { |
1545 | // Clip left / top. |
1546 | if (orientation == ORIENTATION_HORIZONTAL) { |
1547 | if (ofs.x - p_pos.x < p_clip_l) { |
1548 | ofs.x += glyphs[i].advance; |
1549 | continue; |
1550 | } |
1551 | } else { |
1552 | if (ofs.y - p_pos.y < p_clip_l) { |
1553 | ofs.y += glyphs[i].advance; |
1554 | continue; |
1555 | } |
1556 | } |
1557 | } |
1558 | |
1559 | if (glyphs[i].font_rid != RID()) { |
1560 | font_draw_glyph(glyphs[i].font_rid, p_canvas, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color); |
1561 | } else if (hex_codes && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL) && ((glyphs[i].flags & GRAPHEME_IS_EMBEDDED_OBJECT) != GRAPHEME_IS_EMBEDDED_OBJECT)) { |
1562 | TextServer::draw_hex_code_box(p_canvas, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color); |
1563 | } |
1564 | if (orientation == ORIENTATION_HORIZONTAL) { |
1565 | ofs.x += glyphs[i].advance; |
1566 | } else { |
1567 | ofs.y += glyphs[i].advance; |
1568 | } |
1569 | } |
1570 | } |
1571 | // Draw LTR ellipsis string when needed. |
1572 | if (!rtl && ellipsis_pos >= 0) { |
1573 | for (int i = 0; i < ellipsis_gl_size; i++) { |
1574 | for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) { |
1575 | font_draw_glyph(ellipsis_glyphs[i].font_rid, p_canvas, ellipsis_glyphs[i].font_size, ofs + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color); |
1576 | if (orientation == ORIENTATION_HORIZONTAL) { |
1577 | ofs.x += ellipsis_glyphs[i].advance; |
1578 | } else { |
1579 | ofs.y += ellipsis_glyphs[i].advance; |
1580 | } |
1581 | } |
1582 | } |
1583 | } |
1584 | } |
1585 | |
1586 | void TextServer::shaped_text_draw_outline(const RID &p_shaped, const RID &p_canvas, const Vector2 &p_pos, double p_clip_l, double p_clip_r, int64_t p_outline_size, const Color &p_color) const { |
1587 | TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped); |
1588 | |
1589 | bool rtl = (shaped_text_get_inferred_direction(p_shaped) == DIRECTION_RTL); |
1590 | |
1591 | int ellipsis_pos = shaped_text_get_ellipsis_pos(p_shaped); |
1592 | int trim_pos = shaped_text_get_trim_pos(p_shaped); |
1593 | |
1594 | const Glyph *ellipsis_glyphs = shaped_text_get_ellipsis_glyphs(p_shaped); |
1595 | int ellipsis_gl_size = shaped_text_get_ellipsis_glyph_count(p_shaped); |
1596 | |
1597 | int v_size = shaped_text_get_glyph_count(p_shaped); |
1598 | const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); |
1599 | Vector2 ofs = p_pos; |
1600 | // Draw RTL ellipsis string when needed. |
1601 | if (rtl && ellipsis_pos >= 0) { |
1602 | for (int i = ellipsis_gl_size - 1; i >= 0; i--) { |
1603 | for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) { |
1604 | font_draw_glyph_outline(ellipsis_glyphs[i].font_rid, p_canvas, ellipsis_glyphs[i].font_size, p_outline_size, ofs + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color); |
1605 | if (orientation == ORIENTATION_HORIZONTAL) { |
1606 | ofs.x += ellipsis_glyphs[i].advance; |
1607 | } else { |
1608 | ofs.y += ellipsis_glyphs[i].advance; |
1609 | } |
1610 | } |
1611 | } |
1612 | } |
1613 | // Draw at the baseline. |
1614 | for (int i = 0; i < v_size; i++) { |
1615 | if (trim_pos >= 0) { |
1616 | if (rtl) { |
1617 | if (i < trim_pos) { |
1618 | continue; |
1619 | } |
1620 | } else { |
1621 | if (i >= trim_pos) { |
1622 | break; |
1623 | } |
1624 | } |
1625 | } |
1626 | for (int j = 0; j < glyphs[i].repeat; j++) { |
1627 | if (p_clip_r > 0) { |
1628 | // Clip right / bottom. |
1629 | if (orientation == ORIENTATION_HORIZONTAL) { |
1630 | if (ofs.x - p_pos.x + glyphs[i].advance > p_clip_r) { |
1631 | return; |
1632 | } |
1633 | } else { |
1634 | if (ofs.y - p_pos.y + glyphs[i].advance > p_clip_r) { |
1635 | return; |
1636 | } |
1637 | } |
1638 | } |
1639 | if (p_clip_l > 0) { |
1640 | // Clip left / top. |
1641 | if (orientation == ORIENTATION_HORIZONTAL) { |
1642 | if (ofs.x - p_pos.x < p_clip_l) { |
1643 | ofs.x += glyphs[i].advance; |
1644 | continue; |
1645 | } |
1646 | } else { |
1647 | if (ofs.y - p_pos.y < p_clip_l) { |
1648 | ofs.y += glyphs[i].advance; |
1649 | continue; |
1650 | } |
1651 | } |
1652 | } |
1653 | if (glyphs[i].font_rid != RID()) { |
1654 | font_draw_glyph_outline(glyphs[i].font_rid, p_canvas, glyphs[i].font_size, p_outline_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, p_color); |
1655 | } |
1656 | if (orientation == ORIENTATION_HORIZONTAL) { |
1657 | ofs.x += glyphs[i].advance; |
1658 | } else { |
1659 | ofs.y += glyphs[i].advance; |
1660 | } |
1661 | } |
1662 | } |
1663 | // Draw LTR ellipsis string when needed. |
1664 | if (!rtl && ellipsis_pos >= 0) { |
1665 | for (int i = 0; i < ellipsis_gl_size; i++) { |
1666 | for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) { |
1667 | font_draw_glyph_outline(ellipsis_glyphs[i].font_rid, p_canvas, ellipsis_glyphs[i].font_size, p_outline_size, ofs + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color); |
1668 | if (orientation == ORIENTATION_HORIZONTAL) { |
1669 | ofs.x += ellipsis_glyphs[i].advance; |
1670 | } else { |
1671 | ofs.y += ellipsis_glyphs[i].advance; |
1672 | } |
1673 | } |
1674 | } |
1675 | } |
1676 | } |
1677 | |
1678 | void TextServer::_diacritics_map_add(const String &p_from, char32_t p_to) { |
1679 | for (int i = 0; i < p_from.size(); i++) { |
1680 | diacritics_map[p_from[i]] = p_to; |
1681 | } |
1682 | } |
1683 | |
1684 | void TextServer::_init_diacritics_map() { |
1685 | diacritics_map.clear(); |
1686 | |
1687 | // Latin. |
1688 | _diacritics_map_add(U"ÀÁÂÃÄÅĀĂĄǍǞǠǺȀȂȦḀẠẢẤẦẨẪẬẮẰẲẴẶ" , U'A'); |
1689 | _diacritics_map_add(U"àáâãäåāăąǎǟǡǻȁȃȧḁẚạảấầẩẫậắằẳẵặ" , U'a'); |
1690 | _diacritics_map_add(U"ǢǼ" , U'Æ'); |
1691 | _diacritics_map_add(U"ǣǽ" , U'æ'); |
1692 | _diacritics_map_add(U"ḂḄḆ" , U'B'); |
1693 | _diacritics_map_add(U"ḃḅḇ" , U'b'); |
1694 | _diacritics_map_add(U"ÇĆĈĊČḈ" , U'C'); |
1695 | _diacritics_map_add(U"çćĉċčḉ" , U'c'); |
1696 | _diacritics_map_add(U"ĎḊḌḎḐḒ" , U'D'); |
1697 | _diacritics_map_add(U"ďḋḍḏḑḓ" , U'd'); |
1698 | _diacritics_map_add(U"ÈÉÊËĒĔĖĘĚȆȨḔḖḘḚḜẸẺẼẾỀỂỄỆ" , U'E'); |
1699 | _diacritics_map_add(U"èéêëēĕėęěȇȩḕḗḙḛḝẹẻẽếềểễệ" , U'e'); |
1700 | _diacritics_map_add(U"Ḟ" , U'F'); |
1701 | _diacritics_map_add(U"ḟ" , U'f'); |
1702 | _diacritics_map_add(U"ĜĞĠĢǦǴḠ" , U'G'); |
1703 | _diacritics_map_add(U"ĝğġģǧǵḡ" , U'g'); |
1704 | _diacritics_map_add(U"ĤȞḢḤḦḨḪ" , U'H'); |
1705 | _diacritics_map_add(U"ĥȟḣḥḧḩḫẖ" , U'h'); |
1706 | _diacritics_map_add(U"ÌÍÎÏĨĪĬĮİǏȈȊḬḮỈỊ" , U'I'); |
1707 | _diacritics_map_add(U"ìíîïĩīĭįıǐȉȋḭḯỉị" , U'i'); |
1708 | _diacritics_map_add(U"Ĵ" , U'J'); |
1709 | _diacritics_map_add(U"ĵ" , U'j'); |
1710 | _diacritics_map_add(U"ĶǨḰḲḴ" , U'K'); |
1711 | _diacritics_map_add(U"ķĸǩḱḳḵ" , U'k'); |
1712 | _diacritics_map_add(U"ĹĻĽĿḶḸḺḼ" , U'L'); |
1713 | _diacritics_map_add(U"ĺļľŀḷḹḻḽ" , U'l'); |
1714 | _diacritics_map_add(U"ḾṀṂ" , U'M'); |
1715 | _diacritics_map_add(U"ḿṁṃ" , U'm'); |
1716 | _diacritics_map_add(U"ÑŃŅŇǸṄṆṈṊ" , U'N'); |
1717 | _diacritics_map_add(U"ñńņňʼnǹṅṇṉṋ" , U'n'); |
1718 | _diacritics_map_add(U"ÒÓÔÕÖŌŎŐƠǑǪǬȌȎȪȬȮȰṌṎṐṒỌỎỐỒỔỖỘỚỜỞỠỢ" , U'O'); |
1719 | _diacritics_map_add(U"òóôõöōŏőơǒǫǭȍȏȫȭȯȱṍṏṑṓọỏốồổỗộớờởỡợ" , U'o'); |
1720 | _diacritics_map_add(U"ṔṖ" , U'P'); |
1721 | _diacritics_map_add(U"ṗṕ" , U'p'); |
1722 | _diacritics_map_add(U"ŔŖŘȐȒṘṚṜṞ" , U'R'); |
1723 | _diacritics_map_add(U"ŕŗřȑȓṙṛṝṟ" , U'r'); |
1724 | _diacritics_map_add(U"ŚŜŞŠȘṠṢṤṦṨ" , U'S'); |
1725 | _diacritics_map_add(U"śŝşšſșṡṣṥṧṩẛẜẝ" , U's'); |
1726 | _diacritics_map_add(U"ŢŤȚṪṬṮṰ" , U'T'); |
1727 | _diacritics_map_add(U"ţťțṫṭṯṱẗ" , U't'); |
1728 | _diacritics_map_add(U"ÙÚÛÜŨŪŬŮŰŲƯǓǕǗǙǛȔȖṲṴṶṸṺỤỦỨỪỬỮỰ" , U'U'); |
1729 | _diacritics_map_add(U"ùúûüũūŭůűųưǔǖǘǚǜȕȗṳṵṷṹṻụủứừửữự" , U'u'); |
1730 | _diacritics_map_add(U"ṼṾ" , U'V'); |
1731 | _diacritics_map_add(U"ṽṿ" , U'v'); |
1732 | _diacritics_map_add(U"ŴẀẂẄẆẈ" , U'W'); |
1733 | _diacritics_map_add(U"ŵẁẃẅẇẉẘ" , U'w'); |
1734 | _diacritics_map_add(U"ẊẌ" , U'X'); |
1735 | _diacritics_map_add(U"ẋẍ" , U'x'); |
1736 | _diacritics_map_add(U"ÝŶẎỲỴỶỸỾ" , U'Y'); |
1737 | _diacritics_map_add(U"ýÿŷẏẙỳỵỷỹỿ" , U'y'); |
1738 | _diacritics_map_add(U"ŹŻŽẐẒẔ" , U'Z'); |
1739 | _diacritics_map_add(U"źżžẑẓẕ" , U'z'); |
1740 | |
1741 | // Greek. |
1742 | _diacritics_map_add(U"ΆἈἉἊἋἌἍἎἏᾈᾉᾊᾋᾌᾍᾎᾏᾸᾹᾺΆᾼ" , U'Α'); |
1743 | _diacritics_map_add(U"άἀἁἂἃἄἅἆἇὰάᾀᾁᾂᾃᾄᾅᾆᾇᾰᾱᾲᾳᾴᾶᾷ" , U'α'); |
1744 | _diacritics_map_add(U"ΈἘἙἚἛἜἝῈΈ" , U'Ε'); |
1745 | _diacritics_map_add(U"έἐἑἒἓἔἕὲέ" , U'ε'); |
1746 | _diacritics_map_add(U"ΉἨἩἪἫἬἭἮἯᾘᾙᾚᾛᾜᾝᾞᾟῊΉῌ" , U'Η'); |
1747 | _diacritics_map_add(U"ήἠἡἢἣἤἥἦἧὴήᾐᾑᾒᾓᾔᾕᾖᾗῂῃῄῆῇ" , U'η'); |
1748 | _diacritics_map_add(U"ΊΪἸἹἺἻἼἽἾἿῘῙῚΊ" , U'Ι'); |
1749 | _diacritics_map_add(U"ίΐϊἰἱἲἳἴἵἶἷὶίῐῑῒΐῖῗ" , U'ι'); |
1750 | _diacritics_map_add(U"ΌὈὉὊὋὌὍῸΌ" , U'Ο'); |
1751 | _diacritics_map_add(U"όὀὁὂὃὄὅὸό" , U'ο'); |
1752 | _diacritics_map_add(U"Ῥ" , U'Ρ'); |
1753 | _diacritics_map_add(U"ῤῥ" , U'ρ'); |
1754 | _diacritics_map_add(U"ΎΫϓϔὙὛὝὟῨῩῪΎ" , U'Υ'); |
1755 | _diacritics_map_add(U"ΰϋύὐὑὒὓὔὕὖὗὺύῠῡῢΰῦῧ" , U'υ'); |
1756 | _diacritics_map_add(U"ΏὨὩὪὫὬὭὮὯᾨᾩᾪᾫᾬᾭᾮᾯῺΏῼ" , U'Ω'); |
1757 | _diacritics_map_add(U"ώὠὡὢὣὤὥὦὧὼώᾠᾡᾢᾣᾤᾥᾦᾧῲῳῴῶῷ" , U'ω'); |
1758 | |
1759 | // Cyrillic. |
1760 | _diacritics_map_add(U"ӐӒ" , U'А'); |
1761 | _diacritics_map_add(U"ӑӓ" , U'а'); |
1762 | _diacritics_map_add(U"ЀЁӖ" , U'Е'); |
1763 | _diacritics_map_add(U"ѐёӗ" , U'е'); |
1764 | _diacritics_map_add(U"Ӛ" , U'Ә'); |
1765 | _diacritics_map_add(U"ӛ" , U'ә'); |
1766 | _diacritics_map_add(U"Ӝ" , U'Ж'); |
1767 | _diacritics_map_add(U"ӝ" , U'ж'); |
1768 | _diacritics_map_add(U"Ӟ" , U'З'); |
1769 | _diacritics_map_add(U"ӟ" , U'з'); |
1770 | _diacritics_map_add(U"Ѓ" , U'Г'); |
1771 | _diacritics_map_add(U"ѓ" , U'г'); |
1772 | _diacritics_map_add(U"Ї" , U'І'); |
1773 | _diacritics_map_add(U"ї" , U'і'); |
1774 | _diacritics_map_add(U"ЍӢӤЙ" , U'И'); |
1775 | _diacritics_map_add(U"ѝӣӥй" , U'и'); |
1776 | _diacritics_map_add(U"Ќ" , U'К'); |
1777 | _diacritics_map_add(U"ќ" , U'к'); |
1778 | _diacritics_map_add(U"Ӧ" , U'О'); |
1779 | _diacritics_map_add(U"ӧ" , U'о'); |
1780 | _diacritics_map_add(U"Ӫ" , U'Ө'); |
1781 | _diacritics_map_add(U"ӫ" , U'ө'); |
1782 | _diacritics_map_add(U"Ӭ" , U'Э'); |
1783 | _diacritics_map_add(U"ӭ" , U'э'); |
1784 | _diacritics_map_add(U"ЎӮӰӲ" , U'У'); |
1785 | _diacritics_map_add(U"ўӯӱӳ" , U'у'); |
1786 | _diacritics_map_add(U"Ӵ" , U'Ч'); |
1787 | _diacritics_map_add(U"ӵ" , U'ч'); |
1788 | _diacritics_map_add(U"Ӹ" , U'Ы'); |
1789 | _diacritics_map_add(U"ӹ" , U'ы'); |
1790 | } |
1791 | |
1792 | String TextServer::strip_diacritics(const String &p_string) const { |
1793 | String result; |
1794 | for (int i = 0; i < p_string.length(); i++) { |
1795 | if (p_string[i] < 0x02B0 || p_string[i] > 0x036F) { // Skip combining diacritics. |
1796 | if (diacritics_map.has(p_string[i])) { |
1797 | result += diacritics_map[p_string[i]]; |
1798 | } else { |
1799 | result += p_string[i]; |
1800 | } |
1801 | } |
1802 | } |
1803 | return result; |
1804 | } |
1805 | |
1806 | TypedArray<Vector3i> TextServer::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { |
1807 | TypedArray<Vector3i> ret; |
1808 | switch (p_parser_type) { |
1809 | case STRUCTURED_TEXT_URI: { |
1810 | int prev = 0; |
1811 | for (int i = 0; i < p_text.length(); i++) { |
1812 | if ((p_text[i] == '\\') || (p_text[i] == '/') || (p_text[i] == '.') || (p_text[i] == ':') || (p_text[i] == '&') || (p_text[i] == '=') || (p_text[i] == '@') || (p_text[i] == '?') || (p_text[i] == '#')) { |
1813 | if (prev != i) { |
1814 | ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); |
1815 | } |
1816 | ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); |
1817 | prev = i + 1; |
1818 | } |
1819 | } |
1820 | if (prev != p_text.length()) { |
1821 | ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO)); |
1822 | } |
1823 | } break; |
1824 | case STRUCTURED_TEXT_FILE: { |
1825 | int prev = 0; |
1826 | for (int i = 0; i < p_text.length(); i++) { |
1827 | if ((p_text[i] == '\\') || (p_text[i] == '/') || (p_text[i] == ':')) { |
1828 | if (prev != i) { |
1829 | ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); |
1830 | } |
1831 | ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); |
1832 | prev = i + 1; |
1833 | } |
1834 | } |
1835 | if (prev != p_text.length()) { |
1836 | ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO)); |
1837 | } |
1838 | } break; |
1839 | case STRUCTURED_TEXT_EMAIL: { |
1840 | bool local = true; |
1841 | int prev = 0; |
1842 | for (int i = 0; i < p_text.length(); i++) { |
1843 | if ((p_text[i] == '@') && local) { // Add full "local" as single context. |
1844 | local = false; |
1845 | ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); |
1846 | ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); |
1847 | prev = i + 1; |
1848 | } else if (!local && (p_text[i] == '.')) { // Add each dot separated "domain" part as context. |
1849 | if (prev != i) { |
1850 | ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); |
1851 | } |
1852 | ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); |
1853 | prev = i + 1; |
1854 | } |
1855 | } |
1856 | if (prev != p_text.length()) { |
1857 | ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO)); |
1858 | } |
1859 | } break; |
1860 | case STRUCTURED_TEXT_LIST: { |
1861 | if (p_args.size() == 1 && p_args[0].get_type() == Variant::STRING) { |
1862 | Vector<String> tags = p_text.split(String(p_args[0])); |
1863 | int prev = 0; |
1864 | for (int i = 0; i < tags.size(); i++) { |
1865 | if (prev != i) { |
1866 | ret.push_back(Vector3i(prev, prev + tags[i].length(), TextServer::DIRECTION_INHERITED)); |
1867 | } |
1868 | ret.push_back(Vector3i(prev + tags[i].length(), prev + tags[i].length() + 1, TextServer::DIRECTION_INHERITED)); |
1869 | prev = prev + tags[i].length() + 1; |
1870 | } |
1871 | } |
1872 | } break; |
1873 | case STRUCTURED_TEXT_GDSCRIPT: { |
1874 | bool in_string_literal = false; |
1875 | bool in_string_literal_single = false; |
1876 | bool in_id = false; |
1877 | |
1878 | int prev = 0; |
1879 | for (int i = 0; i < p_text.length(); i++) { |
1880 | char32_t c = p_text[i]; |
1881 | if (in_string_literal) { |
1882 | if (c == '\\') { |
1883 | i++; |
1884 | continue; // Skip escaped chars. |
1885 | } else if (c == '\"') { |
1886 | // String literal end, push string and ". |
1887 | if (prev != i) { |
1888 | ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); |
1889 | } |
1890 | prev = i + 1; |
1891 | ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); |
1892 | in_string_literal = false; |
1893 | } |
1894 | } else if (in_string_literal_single) { |
1895 | if (c == '\\') { |
1896 | i++; |
1897 | continue; // Skip escaped chars. |
1898 | } else if (c == '\'') { |
1899 | // String literal end, push string and '. |
1900 | if (prev != i) { |
1901 | ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); |
1902 | } |
1903 | prev = i + 1; |
1904 | ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); |
1905 | in_string_literal_single = false; |
1906 | } |
1907 | } else if (in_id) { |
1908 | if (!is_unicode_identifier_continue(c)) { |
1909 | // End of id, push id. |
1910 | if (prev != i) { |
1911 | ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); |
1912 | } |
1913 | prev = i; |
1914 | in_id = false; |
1915 | } |
1916 | } else if (is_unicode_identifier_start(c)) { |
1917 | // Start of new id, push prev element. |
1918 | if (prev != i) { |
1919 | ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); |
1920 | } |
1921 | prev = i; |
1922 | in_id = true; |
1923 | } else if (c == '\"') { |
1924 | // String literal start, push prev element and ". |
1925 | if (prev != i) { |
1926 | ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); |
1927 | } |
1928 | prev = i + 1; |
1929 | ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); |
1930 | in_string_literal = true; |
1931 | } else if (c == '\'') { |
1932 | // String literal start, push prev element and '. |
1933 | if (prev != i) { |
1934 | ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); |
1935 | } |
1936 | prev = i + 1; |
1937 | ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); |
1938 | in_string_literal_single = true; |
1939 | } else if (c == '#') { |
1940 | // Start of comment, push prev element and #, skip the rest of the text. |
1941 | if (prev != i) { |
1942 | ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO)); |
1943 | } |
1944 | prev = i + 1; |
1945 | ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR)); |
1946 | break; |
1947 | } |
1948 | } |
1949 | if (prev < p_text.length()) { |
1950 | ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO)); |
1951 | } |
1952 | } break; |
1953 | case STRUCTURED_TEXT_CUSTOM: |
1954 | case STRUCTURED_TEXT_DEFAULT: |
1955 | default: { |
1956 | ret.push_back(Vector3i(0, p_text.length(), TextServer::DIRECTION_INHERITED)); |
1957 | } |
1958 | } |
1959 | return ret; |
1960 | } |
1961 | |
1962 | TypedArray<Dictionary> TextServer::_shaped_text_get_glyphs_wrapper(const RID &p_shaped) const { |
1963 | TypedArray<Dictionary> ret; |
1964 | |
1965 | const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); |
1966 | int gl_size = shaped_text_get_glyph_count(p_shaped); |
1967 | for (int i = 0; i < gl_size; i++) { |
1968 | Dictionary glyph; |
1969 | |
1970 | glyph["start" ] = glyphs[i].start; |
1971 | glyph["end" ] = glyphs[i].end; |
1972 | glyph["repeat" ] = glyphs[i].repeat; |
1973 | glyph["count" ] = glyphs[i].count; |
1974 | glyph["flags" ] = glyphs[i].flags; |
1975 | glyph["offset" ] = Vector2(glyphs[i].x_off, glyphs[i].y_off); |
1976 | glyph["advance" ] = glyphs[i].advance; |
1977 | glyph["font_rid" ] = glyphs[i].font_rid; |
1978 | glyph["font_size" ] = glyphs[i].font_size; |
1979 | glyph["index" ] = glyphs[i].index; |
1980 | |
1981 | ret.push_back(glyph); |
1982 | } |
1983 | |
1984 | return ret; |
1985 | } |
1986 | |
1987 | TypedArray<Dictionary> TextServer::_shaped_text_sort_logical_wrapper(const RID &p_shaped) { |
1988 | Array ret; |
1989 | |
1990 | const Glyph *glyphs = shaped_text_sort_logical(p_shaped); |
1991 | int gl_size = shaped_text_get_glyph_count(p_shaped); |
1992 | for (int i = 0; i < gl_size; i++) { |
1993 | Dictionary glyph; |
1994 | |
1995 | glyph["start" ] = glyphs[i].start; |
1996 | glyph["end" ] = glyphs[i].end; |
1997 | glyph["repeat" ] = glyphs[i].repeat; |
1998 | glyph["count" ] = glyphs[i].count; |
1999 | glyph["flags" ] = glyphs[i].flags; |
2000 | glyph["offset" ] = Vector2(glyphs[i].x_off, glyphs[i].y_off); |
2001 | glyph["advance" ] = glyphs[i].advance; |
2002 | glyph["font_rid" ] = glyphs[i].font_rid; |
2003 | glyph["font_size" ] = glyphs[i].font_size; |
2004 | glyph["index" ] = glyphs[i].index; |
2005 | |
2006 | ret.push_back(glyph); |
2007 | } |
2008 | |
2009 | return ret; |
2010 | } |
2011 | |
2012 | TypedArray<Dictionary> TextServer::_shaped_text_get_ellipsis_glyphs_wrapper(const RID &p_shaped) const { |
2013 | TypedArray<Dictionary> ret; |
2014 | |
2015 | const Glyph *glyphs = shaped_text_get_ellipsis_glyphs(p_shaped); |
2016 | int gl_size = shaped_text_get_ellipsis_glyph_count(p_shaped); |
2017 | for (int i = 0; i < gl_size; i++) { |
2018 | Dictionary glyph; |
2019 | |
2020 | glyph["start" ] = glyphs[i].start; |
2021 | glyph["end" ] = glyphs[i].end; |
2022 | glyph["repeat" ] = glyphs[i].repeat; |
2023 | glyph["count" ] = glyphs[i].count; |
2024 | glyph["flags" ] = glyphs[i].flags; |
2025 | glyph["offset" ] = Vector2(glyphs[i].x_off, glyphs[i].y_off); |
2026 | glyph["advance" ] = glyphs[i].advance; |
2027 | glyph["font_rid" ] = glyphs[i].font_rid; |
2028 | glyph["font_size" ] = glyphs[i].font_size; |
2029 | glyph["index" ] = glyphs[i].index; |
2030 | |
2031 | ret.push_back(glyph); |
2032 | } |
2033 | |
2034 | return ret; |
2035 | } |
2036 | |
2037 | bool TextServer::is_valid_identifier(const String &p_string) const { |
2038 | const char32_t *str = p_string.ptr(); |
2039 | int len = p_string.length(); |
2040 | |
2041 | if (len == 0) { |
2042 | return false; // Empty string. |
2043 | } |
2044 | |
2045 | if (!is_unicode_identifier_start(str[0])) { |
2046 | return false; |
2047 | } |
2048 | |
2049 | for (int i = 1; i < len; i++) { |
2050 | if (!is_unicode_identifier_continue(str[i])) { |
2051 | return false; |
2052 | } |
2053 | } |
2054 | return true; |
2055 | } |
2056 | |
2057 | TextServer::TextServer() { |
2058 | _init_diacritics_map(); |
2059 | } |
2060 | |
2061 | TextServer::~TextServer() { |
2062 | } |
2063 | |