2020-08-05 09:25:28 +03:00
/**************************************************************************/
/* text_server.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
# include "servers/text_server.h"
2024-04-15 22:14:41 +03:00
# include "text_server.compat.inc"
2025-06-12 14:34:42 +03:00
# include "core/config/project_settings.h"
2022-08-05 03:41:48 +02:00
# include "core/variant/typed_array.h"
2021-10-02 22:06:20 +03:00
# include "servers/rendering_server.h"
2020-08-05 09:25:28 +03:00
TextServerManager * TextServerManager : : singleton = nullptr ;
void TextServerManager : : _bind_methods ( ) {
2021-08-28 00:19:51 +03:00
ClassDB : : bind_method ( D_METHOD ( " add_interface " , " interface " ) , & TextServerManager : : add_interface ) ;
ClassDB : : bind_method ( D_METHOD ( " get_interface_count " ) , & TextServerManager : : get_interface_count ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_interface " , " interface " ) , & TextServerManager : : remove_interface ) ;
ClassDB : : bind_method ( D_METHOD ( " get_interface " , " idx " ) , & TextServerManager : : get_interface ) ;
ClassDB : : bind_method ( D_METHOD ( " get_interfaces " ) , & TextServerManager : : get_interfaces ) ;
ClassDB : : bind_method ( D_METHOD ( " find_interface " , " name " ) , & TextServerManager : : find_interface ) ;
ClassDB : : bind_method ( D_METHOD ( " set_primary_interface " , " index " ) , & TextServerManager : : set_primary_interface ) ;
2021-10-12 21:36:08 +03:00
ClassDB : : bind_method ( D_METHOD ( " get_primary_interface " ) , & TextServerManager : : get_primary_interface ) ;
2020-08-05 09:25:28 +03:00
2021-08-28 00:19:51 +03:00
ADD_SIGNAL ( MethodInfo ( " interface_added " , PropertyInfo ( Variant : : STRING_NAME , " interface_name " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " interface_removed " , PropertyInfo ( Variant : : STRING_NAME , " interface_name " ) ) ) ;
2020-08-05 09:25:28 +03:00
}
2021-08-28 00:19:51 +03:00
void TextServerManager : : add_interface ( const Ref < TextServer > & p_interface ) {
ERR_FAIL_COND ( p_interface . is_null ( ) ) ;
2020-08-05 09:25:28 +03:00
2021-08-28 00:19:51 +03:00
for ( int i = 0 ; i < interfaces . size ( ) ; i + + ) {
if ( interfaces [ i ] = = p_interface ) {
ERR_PRINT ( " TextServer: Interface was already added. " ) ;
return ;
} ;
} ;
2020-08-05 09:25:28 +03:00
2021-08-28 00:19:51 +03:00
interfaces . push_back ( p_interface ) ;
print_verbose ( " TextServer: Added interface \" " + p_interface - > get_name ( ) + " \" " ) ;
emit_signal ( SNAME ( " interface_added " ) , p_interface - > get_name ( ) ) ;
2020-08-05 09:25:28 +03:00
}
2021-08-28 00:19:51 +03:00
void TextServerManager : : remove_interface ( const Ref < TextServer > & p_interface ) {
ERR_FAIL_COND ( p_interface . is_null ( ) ) ;
ERR_FAIL_COND_MSG ( p_interface = = primary_interface , " TextServer: Can't remove primary interface. " ) ;
2020-08-05 09:25:28 +03:00
2021-08-28 00:19:51 +03:00
int idx = - 1 ;
for ( int i = 0 ; i < interfaces . size ( ) ; i + + ) {
if ( interfaces [ i ] = = p_interface ) {
idx = i ;
break ;
} ;
} ;
2020-08-05 09:25:28 +03:00
2022-05-25 11:39:00 -05:00
ERR_FAIL_COND_MSG ( idx = = - 1 , " Interface not found. " ) ;
2021-08-28 00:19:51 +03:00
print_verbose ( " TextServer: Removed interface \" " + p_interface - > get_name ( ) + " \" " ) ;
emit_signal ( SNAME ( " interface_removed " ) , p_interface - > get_name ( ) ) ;
2021-07-03 16:17:03 -06:00
interfaces . remove_at ( idx ) ;
2020-08-05 09:25:28 +03:00
}
2021-08-28 00:19:51 +03:00
int TextServerManager : : get_interface_count ( ) const {
return interfaces . size ( ) ;
2020-08-05 09:25:28 +03:00
}
2021-08-28 00:19:51 +03:00
Ref < TextServer > TextServerManager : : get_interface ( int p_index ) const {
ERR_FAIL_INDEX_V ( p_index , interfaces . size ( ) , nullptr ) ;
return interfaces [ p_index ] ;
2020-08-05 09:25:28 +03:00
}
2021-08-28 00:19:51 +03:00
Ref < TextServer > TextServerManager : : find_interface ( const String & p_name ) const {
int idx = - 1 ;
for ( int i = 0 ; i < interfaces . size ( ) ; i + + ) {
if ( interfaces [ i ] - > get_name ( ) = = p_name ) {
idx = i ;
break ;
} ;
} ;
2020-08-05 09:25:28 +03:00
2022-05-25 11:39:00 -05:00
ERR_FAIL_COND_V_MSG ( idx = = - 1 , nullptr , " Interface not found. " ) ;
2021-08-28 00:19:51 +03:00
return interfaces [ idx ] ;
2020-08-05 09:25:28 +03:00
}
2022-08-08 00:52:20 +02:00
TypedArray < Dictionary > TextServerManager : : get_interfaces ( ) const {
TypedArray < Dictionary > ret ;
2020-08-05 09:25:28 +03:00
2021-08-28 00:19:51 +03:00
for ( int i = 0 ; i < interfaces . size ( ) ; i + + ) {
2020-08-05 09:25:28 +03:00
Dictionary iface_info ;
iface_info [ " id " ] = i ;
2021-08-28 00:19:51 +03:00
iface_info [ " name " ] = interfaces [ i ] - > get_name ( ) ;
2020-08-05 09:25:28 +03:00
ret . push_back ( iface_info ) ;
} ;
return ret ;
2021-08-28 00:19:51 +03:00
}
2020-08-05 09:25:28 +03:00
2021-08-28 00:19:51 +03:00
void TextServerManager : : set_primary_interface ( const Ref < TextServer > & p_primary_interface ) {
if ( p_primary_interface . is_null ( ) ) {
print_verbose ( " TextServer: Clearing primary interface " ) ;
primary_interface . unref ( ) ;
} else {
primary_interface = p_primary_interface ;
print_verbose ( " TextServer: Primary interface set to: \" " + primary_interface - > get_name ( ) + " \" . " ) ;
if ( OS : : get_singleton ( ) - > get_main_loop ( ) ) {
OS : : get_singleton ( ) - > get_main_loop ( ) - > notification ( MainLoop : : NOTIFICATION_TEXT_SERVER_CHANGED ) ;
}
}
2020-08-05 09:25:28 +03:00
}
TextServerManager : : TextServerManager ( ) {
singleton = this ;
}
TextServerManager : : ~ TextServerManager ( ) {
2021-08-28 00:19:51 +03:00
if ( primary_interface . is_valid ( ) ) {
primary_interface . unref ( ) ;
2020-08-05 09:25:28 +03:00
}
2021-08-28 00:19:51 +03:00
while ( interfaces . size ( ) > 0 ) {
2021-07-03 16:17:03 -06:00
interfaces . remove_at ( 0 ) ;
2021-08-28 00:19:51 +03:00
}
singleton = nullptr ;
2020-08-05 09:25:28 +03:00
}
/*************************************************************************/
2021-08-28 00:19:51 +03:00
bool Glyph : : operator = = ( const Glyph & p_a ) const {
2020-08-05 09:25:28 +03:00
return ( p_a . index = = index ) & & ( p_a . font_rid = = font_rid ) & & ( p_a . font_size = = font_size ) & & ( p_a . start = = start ) ;
}
2021-08-28 00:19:51 +03:00
bool Glyph : : operator ! = ( const Glyph & p_a ) const {
2020-08-05 09:25:28 +03:00
return ( p_a . index ! = index ) | | ( p_a . font_rid ! = font_rid ) | | ( p_a . font_size ! = font_size ) | | ( p_a . start ! = start ) ;
}
2021-08-28 00:19:51 +03:00
bool Glyph : : operator < ( const Glyph & p_a ) const {
2020-08-05 09:25:28 +03:00
if ( p_a . start = = start ) {
if ( p_a . count = = count ) {
2021-08-28 00:19:51 +03:00
if ( ( p_a . flags & TextServer : : GRAPHEME_IS_VIRTUAL ) = = TextServer : : GRAPHEME_IS_VIRTUAL ) {
2020-08-05 09:25:28 +03:00
return true ;
} else {
return false ;
}
}
return p_a . count > count ;
}
return p_a . start < start ;
}
2021-08-28 00:19:51 +03:00
bool Glyph : : operator > ( const Glyph & p_a ) const {
2020-08-05 09:25:28 +03:00
if ( p_a . start = = start ) {
if ( p_a . count = = count ) {
2021-08-28 00:19:51 +03:00
if ( ( p_a . flags & TextServer : : GRAPHEME_IS_VIRTUAL ) = = TextServer : : GRAPHEME_IS_VIRTUAL ) {
2020-08-05 09:25:28 +03:00
return false ;
} else {
return true ;
}
}
return p_a . count < count ;
}
return p_a . start > start ;
}
void TextServer : : _bind_methods ( ) {
ClassDB : : bind_method ( D_METHOD ( " has_feature " , " feature " ) , & TextServer : : has_feature ) ;
ClassDB : : bind_method ( D_METHOD ( " get_name " ) , & TextServer : : get_name ) ;
2021-08-28 00:19:51 +03:00
ClassDB : : bind_method ( D_METHOD ( " get_features " ) , & TextServer : : get_features ) ;
2020-08-05 09:25:28 +03:00
ClassDB : : bind_method ( D_METHOD ( " load_support_data " , " filename " ) , & TextServer : : load_support_data ) ;
2021-08-28 00:19:51 +03:00
ClassDB : : bind_method ( D_METHOD ( " get_support_data_filename " ) , & TextServer : : get_support_data_filename ) ;
ClassDB : : bind_method ( D_METHOD ( " get_support_data_info " ) , & TextServer : : get_support_data_info ) ;
ClassDB : : bind_method ( D_METHOD ( " save_support_data " , " filename " ) , & TextServer : : save_support_data ) ;
2024-11-13 08:03:40 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_support_data " ) , & TextServer : : get_support_data ) ;
2021-08-28 00:19:51 +03:00
2020-08-05 09:25:28 +03:00
ClassDB : : bind_method ( D_METHOD ( " is_locale_right_to_left " , " locale " ) , & TextServer : : is_locale_right_to_left ) ;
ClassDB : : bind_method ( D_METHOD ( " name_to_tag " , " name " ) , & TextServer : : name_to_tag ) ;
ClassDB : : bind_method ( D_METHOD ( " tag_to_name " , " tag " ) , & TextServer : : tag_to_name ) ;
ClassDB : : bind_method ( D_METHOD ( " has " , " rid " ) , & TextServer : : has ) ;
2022-02-13 14:41:29 +02:00
ClassDB : : bind_method ( D_METHOD ( " free_rid " , " rid " ) , & TextServer : : free_rid ) ;
2020-08-05 09:25:28 +03:00
/* Font Interface */
2021-02-06 16:34:06 +02:00
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " create_font " ) , & TextServer : : create_font ) ;
2023-09-28 10:45:09 +03:00
ClassDB : : bind_method ( D_METHOD ( " create_font_linked_variation " , " font_rid " ) , & TextServer : : create_font_linked_variation ) ;
2020-08-05 09:25:28 +03:00
2021-08-28 00:19:51 +03:00
ClassDB : : bind_method ( D_METHOD ( " font_set_data " , " font_rid " , " data " ) , & TextServer : : font_set_data ) ;
2020-08-05 09:25:28 +03:00
2022-06-07 11:35:59 +03:00
ClassDB : : bind_method ( D_METHOD ( " font_set_face_index " , " font_rid " , " face_index " ) , & TextServer : : font_set_face_index ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_face_index " , " font_rid " ) , & TextServer : : font_get_face_index ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_face_count " , " font_rid " ) , & TextServer : : font_get_face_count ) ;
2021-10-26 09:40:11 +03:00
ClassDB : : bind_method ( D_METHOD ( " font_set_style " , " font_rid " , " style " ) , & TextServer : : font_set_style ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_style " , " font_rid " ) , & TextServer : : font_get_style ) ;
ClassDB : : bind_method ( D_METHOD ( " font_set_name " , " font_rid " , " name " ) , & TextServer : : font_set_name ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_name " , " font_rid " ) , & TextServer : : font_get_name ) ;
2023-04-05 12:49:38 +03:00
ClassDB : : bind_method ( D_METHOD ( " font_get_ot_name_strings " , " font_rid " ) , & TextServer : : font_get_ot_name_strings ) ;
2021-10-26 09:40:11 +03:00
ClassDB : : bind_method ( D_METHOD ( " font_set_style_name " , " font_rid " , " name " ) , & TextServer : : font_set_style_name ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_style_name " , " font_rid " ) , & TextServer : : font_get_style_name ) ;
2022-11-21 15:04:01 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_weight " , " font_rid " , " weight " ) , & TextServer : : font_set_weight ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_weight " , " font_rid " ) , & TextServer : : font_get_weight ) ;
ClassDB : : bind_method ( D_METHOD ( " font_set_stretch " , " font_rid " , " weight " ) , & TextServer : : font_set_stretch ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_stretch " , " font_rid " ) , & TextServer : : font_get_stretch ) ;
2022-08-12 14:03:28 +03:00
ClassDB : : bind_method ( D_METHOD ( " font_set_antialiasing " , " font_rid " , " antialiasing " ) , & TextServer : : font_set_antialiasing ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_antialiasing " , " font_rid " ) , & TextServer : : font_get_antialiasing ) ;
2020-08-05 09:25:28 +03:00
2024-03-11 13:42:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_disable_embedded_bitmaps " , " font_rid " , " disable_embedded_bitmaps " ) , & TextServer : : font_set_disable_embedded_bitmaps ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_disable_embedded_bitmaps " , " font_rid " ) , & TextServer : : font_get_disable_embedded_bitmaps ) ;
2022-04-19 13:27:18 +03:00
ClassDB : : bind_method ( D_METHOD ( " font_set_generate_mipmaps " , " font_rid " , " generate_mipmaps " ) , & TextServer : : font_set_generate_mipmaps ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_generate_mipmaps " , " font_rid " ) , & TextServer : : font_get_generate_mipmaps ) ;
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_multichannel_signed_distance_field " , " font_rid " , " msdf " ) , & TextServer : : font_set_multichannel_signed_distance_field ) ;
ClassDB : : bind_method ( D_METHOD ( " font_is_multichannel_signed_distance_field " , " font_rid " ) , & TextServer : : font_is_multichannel_signed_distance_field ) ;
2021-02-15 10:46:23 +02:00
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_msdf_pixel_range " , " font_rid " , " msdf_pixel_range " ) , & TextServer : : font_set_msdf_pixel_range ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_msdf_pixel_range " , " font_rid " ) , & TextServer : : font_get_msdf_pixel_range ) ;
2021-02-15 10:46:23 +02:00
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_msdf_size " , " font_rid " , " msdf_size " ) , & TextServer : : font_set_msdf_size ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_msdf_size " , " font_rid " ) , & TextServer : : font_get_msdf_size ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_fixed_size " , " font_rid " , " fixed_size " ) , & TextServer : : font_set_fixed_size ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_fixed_size " , " font_rid " ) , & TextServer : : font_get_fixed_size ) ;
2020-10-22 19:40:18 +03:00
2023-08-14 10:42:49 +03:00
ClassDB : : bind_method ( D_METHOD ( " font_set_fixed_size_scale_mode " , " font_rid " , " fixed_size_scale_mode " ) , & TextServer : : font_set_fixed_size_scale_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_fixed_size_scale_mode " , " font_rid " ) , & TextServer : : font_get_fixed_size_scale_mode ) ;
2022-11-21 15:04:01 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_allow_system_fallback " , " font_rid " , " allow_system_fallback " ) , & TextServer : : font_set_allow_system_fallback ) ;
ClassDB : : bind_method ( D_METHOD ( " font_is_allow_system_fallback " , " font_rid " ) , & TextServer : : font_is_allow_system_fallback ) ;
2025-03-30 14:20:25 +03:00
ClassDB : : bind_method ( D_METHOD ( " font_clear_system_fallback_cache " ) , & TextServer : : font_clear_system_fallback_cache ) ;
2022-11-21 15:04:01 +02:00
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_force_autohinter " , " font_rid " , " force_autohinter " ) , & TextServer : : font_set_force_autohinter ) ;
ClassDB : : bind_method ( D_METHOD ( " font_is_force_autohinter " , " font_rid " ) , & TextServer : : font_is_force_autohinter ) ;
2020-08-05 09:25:28 +03:00
2025-04-01 13:36:10 +03:00
ClassDB : : bind_method ( D_METHOD ( " font_set_modulate_color_glyphs " , " font_rid " , " force_autohinter " ) , & TextServer : : font_set_modulate_color_glyphs ) ;
ClassDB : : bind_method ( D_METHOD ( " font_is_modulate_color_glyphs " , " font_rid " ) , & TextServer : : font_is_modulate_color_glyphs ) ;
2022-01-10 10:13:22 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_hinting " , " font_rid " , " hinting " ) , & TextServer : : font_set_hinting ) ;
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_get_hinting " , " font_rid " ) , & TextServer : : font_get_hinting ) ;
2020-08-05 09:25:28 +03:00
2022-01-10 10:13:22 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_subpixel_positioning " , " font_rid " , " subpixel_positioning " ) , & TextServer : : font_set_subpixel_positioning ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_subpixel_positioning " , " font_rid " ) , & TextServer : : font_get_subpixel_positioning ) ;
2024-10-30 11:14:11 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_keep_rounding_remainders " , " font_rid " , " keep_rounding_remainders " ) , & TextServer : : font_set_keep_rounding_remainders ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_keep_rounding_remainders " , " font_rid " ) , & TextServer : : font_get_keep_rounding_remainders ) ;
2022-03-11 09:31:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_embolden " , " font_rid " , " strength " ) , & TextServer : : font_set_embolden ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_embolden " , " font_rid " ) , & TextServer : : font_get_embolden ) ;
2023-08-24 11:56:50 +03:00
ClassDB : : bind_method ( D_METHOD ( " font_set_spacing " , " font_rid " , " spacing " , " value " ) , & TextServer : : font_set_spacing ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_spacing " , " font_rid " , " spacing " ) , & TextServer : : font_get_spacing ) ;
2024-01-28 12:34:56 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_baseline_offset " , " font_rid " , " baseline_offset " ) , & TextServer : : font_set_baseline_offset ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_baseline_offset " , " font_rid " ) , & TextServer : : font_get_baseline_offset ) ;
2022-03-11 09:31:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_transform " , " font_rid " , " transform " ) , & TextServer : : font_set_transform ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_transform " , " font_rid " ) , & TextServer : : font_get_transform ) ;
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_variation_coordinates " , " font_rid " , " variation_coordinates " ) , & TextServer : : font_set_variation_coordinates ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_variation_coordinates " , " font_rid " ) , & TextServer : : font_get_variation_coordinates ) ;
2020-08-05 09:25:28 +03:00
2025-03-30 14:20:25 +03:00
# ifndef DISABLE_DEPRECATED
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_oversampling " , " font_rid " , " oversampling " ) , & TextServer : : font_set_oversampling ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_oversampling " , " font_rid " ) , & TextServer : : font_get_oversampling ) ;
2025-03-30 14:20:25 +03:00
# endif
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_get_size_cache_list " , " font_rid " ) , & TextServer : : font_get_size_cache_list ) ;
ClassDB : : bind_method ( D_METHOD ( " font_clear_size_cache " , " font_rid " ) , & TextServer : : font_clear_size_cache ) ;
ClassDB : : bind_method ( D_METHOD ( " font_remove_size_cache " , " font_rid " , " size " ) , & TextServer : : font_remove_size_cache ) ;
2025-03-30 14:20:25 +03:00
ClassDB : : bind_method ( D_METHOD ( " font_get_size_cache_info " , " font_rid " ) , & TextServer : : font_get_size_cache_info ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_ascent " , " font_rid " , " size " , " ascent " ) , & TextServer : : font_set_ascent ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_ascent " , " font_rid " , " size " ) , & TextServer : : font_get_ascent ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_descent " , " font_rid " , " size " , " descent " ) , & TextServer : : font_set_descent ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_descent " , " font_rid " , " size " ) , & TextServer : : font_get_descent ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_underline_position " , " font_rid " , " size " , " underline_position " ) , & TextServer : : font_set_underline_position ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_underline_position " , " font_rid " , " size " ) , & TextServer : : font_get_underline_position ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_underline_thickness " , " font_rid " , " size " , " underline_thickness " ) , & TextServer : : font_set_underline_thickness ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_underline_thickness " , " font_rid " , " size " ) , & TextServer : : font_get_underline_thickness ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_scale " , " font_rid " , " size " , " scale " ) , & TextServer : : font_set_scale ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_scale " , " font_rid " , " size " ) , & TextServer : : font_get_scale ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_get_texture_count " , " font_rid " , " size " ) , & TextServer : : font_get_texture_count ) ;
ClassDB : : bind_method ( D_METHOD ( " font_clear_textures " , " font_rid " , " size " ) , & TextServer : : font_clear_textures ) ;
ClassDB : : bind_method ( D_METHOD ( " font_remove_texture " , " font_rid " , " size " , " texture_index " ) , & TextServer : : font_remove_texture ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_texture_image " , " font_rid " , " size " , " texture_index " , " image " ) , & TextServer : : font_set_texture_image ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_texture_image " , " font_rid " , " size " , " texture_index " ) , & TextServer : : font_get_texture_image ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_texture_offsets " , " font_rid " , " size " , " texture_index " , " offset " ) , & TextServer : : font_set_texture_offsets ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_texture_offsets " , " font_rid " , " size " , " texture_index " ) , & TextServer : : font_get_texture_offsets ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_get_glyph_list " , " font_rid " , " size " ) , & TextServer : : font_get_glyph_list ) ;
ClassDB : : bind_method ( D_METHOD ( " font_clear_glyphs " , " font_rid " , " size " ) , & TextServer : : font_clear_glyphs ) ;
ClassDB : : bind_method ( D_METHOD ( " font_remove_glyph " , " font_rid " , " size " , " glyph " ) , & TextServer : : font_remove_glyph ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_glyph_advance " , " font_rid " , " size " , " glyph " ) , & TextServer : : font_get_glyph_advance ) ;
ClassDB : : bind_method ( D_METHOD ( " font_set_glyph_advance " , " font_rid " , " size " , " glyph " , " advance " ) , & TextServer : : font_set_glyph_advance ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_glyph_offset " , " font_rid " , " size " , " glyph " ) , & TextServer : : font_get_glyph_offset ) ;
ClassDB : : bind_method ( D_METHOD ( " font_set_glyph_offset " , " font_rid " , " size " , " glyph " , " offset " ) , & TextServer : : font_set_glyph_offset ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_glyph_size " , " font_rid " , " size " , " glyph " ) , & TextServer : : font_get_glyph_size ) ;
2021-08-28 13:30:32 +10:00
ClassDB : : bind_method ( D_METHOD ( " font_set_glyph_size " , " font_rid " , " size " , " glyph " , " gl_size " ) , & TextServer : : font_set_glyph_size ) ;
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_get_glyph_uv_rect " , " font_rid " , " size " , " glyph " ) , & TextServer : : font_get_glyph_uv_rect ) ;
ClassDB : : bind_method ( D_METHOD ( " font_set_glyph_uv_rect " , " font_rid " , " size " , " glyph " , " uv_rect " ) , & TextServer : : font_set_glyph_uv_rect ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_glyph_texture_idx " , " font_rid " , " size " , " glyph " ) , & TextServer : : font_get_glyph_texture_idx ) ;
ClassDB : : bind_method ( D_METHOD ( " font_set_glyph_texture_idx " , " font_rid " , " size " , " glyph " , " texture_idx " ) , & TextServer : : font_set_glyph_texture_idx ) ;
2020-08-05 09:25:28 +03:00
2022-04-19 13:27:18 +03:00
ClassDB : : bind_method ( D_METHOD ( " font_get_glyph_texture_rid " , " font_rid " , " size " , " glyph " ) , & TextServer : : font_get_glyph_texture_rid ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_glyph_texture_size " , " font_rid " , " size " , " glyph " ) , & TextServer : : font_get_glyph_texture_size ) ;
2021-08-28 00:19:51 +03:00
ClassDB : : bind_method ( D_METHOD ( " font_get_glyph_contours " , " font " , " size " , " index " ) , & TextServer : : font_get_glyph_contours ) ;
2020-12-10 17:30:25 +02:00
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_get_kerning_list " , " font_rid " , " size " ) , & TextServer : : font_get_kerning_list ) ;
ClassDB : : bind_method ( D_METHOD ( " font_clear_kerning_map " , " font_rid " , " size " ) , & TextServer : : font_clear_kerning_map ) ;
ClassDB : : bind_method ( D_METHOD ( " font_remove_kerning " , " font_rid " , " size " , " glyph_pair " ) , & TextServer : : font_remove_kerning ) ;
ClassDB : : bind_method ( D_METHOD ( " font_set_kerning " , " font_rid " , " size " , " glyph_pair " , " kerning " ) , & TextServer : : font_set_kerning ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_kerning " , " font_rid " , " size " , " glyph_pair " ) , & TextServer : : font_get_kerning ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_glyph_index " , " font_rid " , " size " , " char " , " variation_selector " ) , & TextServer : : font_get_glyph_index ) ;
2023-02-27 16:21:28 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_get_char_from_glyph_index " , " font_rid " , " size " , " glyph_index " ) , & TextServer : : font_get_char_from_glyph_index ) ;
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_has_char " , " font_rid " , " char " ) , & TextServer : : font_has_char ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_supported_chars " , " font_rid " ) , & TextServer : : font_get_supported_chars ) ;
2024-07-22 10:12:00 +03:00
ClassDB : : bind_method ( D_METHOD ( " font_get_supported_glyphs " , " font_rid " ) , & TextServer : : font_get_supported_glyphs ) ;
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_render_range " , " font_rid " , " size " , " start " , " end " ) , & TextServer : : font_render_range ) ;
ClassDB : : bind_method ( D_METHOD ( " font_render_glyph " , " font_rid " , " size " , " index " ) , & TextServer : : font_render_glyph ) ;
2025-03-30 14:20:25 +03:00
ClassDB : : bind_method ( D_METHOD ( " font_draw_glyph " , " font_rid " , " canvas " , " size " , " pos " , " index " , " color " , " oversampling " ) , & TextServer : : font_draw_glyph , DEFVAL ( Color ( 1 , 1 , 1 ) ) , DEFVAL ( 0.0 ) ) ;
ClassDB : : bind_method ( D_METHOD ( " font_draw_glyph_outline " , " font_rid " , " canvas " , " size " , " outline_size " , " pos " , " index " , " color " , " oversampling " ) , & TextServer : : font_draw_glyph_outline , DEFVAL ( Color ( 1 , 1 , 1 ) ) , DEFVAL ( 0.0 ) ) ;
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_is_language_supported " , " font_rid " , " language " ) , & TextServer : : font_is_language_supported ) ;
ClassDB : : bind_method ( D_METHOD ( " font_set_language_support_override " , " font_rid " , " language " , " supported " ) , & TextServer : : font_set_language_support_override ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_language_support_override " , " font_rid " , " language " ) , & TextServer : : font_get_language_support_override ) ;
ClassDB : : bind_method ( D_METHOD ( " font_remove_language_support_override " , " font_rid " , " language " ) , & TextServer : : font_remove_language_support_override ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_language_support_overrides " , " font_rid " ) , & TextServer : : font_get_language_support_overrides ) ;
ClassDB : : bind_method ( D_METHOD ( " font_is_script_supported " , " font_rid " , " script " ) , & TextServer : : font_is_script_supported ) ;
ClassDB : : bind_method ( D_METHOD ( " font_set_script_support_override " , " font_rid " , " script " , " supported " ) , & TextServer : : font_set_script_support_override ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_script_support_override " , " font_rid " , " script " ) , & TextServer : : font_get_script_support_override ) ;
ClassDB : : bind_method ( D_METHOD ( " font_remove_script_support_override " , " font_rid " , " script " ) , & TextServer : : font_remove_script_support_override ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_script_support_overrides " , " font_rid " ) , & TextServer : : font_get_script_support_overrides ) ;
2021-11-18 23:36:22 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_set_opentype_feature_overrides " , " font_rid " , " overrides " ) , & TextServer : : font_set_opentype_feature_overrides ) ;
ClassDB : : bind_method ( D_METHOD ( " font_get_opentype_feature_overrides " , " font_rid " ) , & TextServer : : font_get_opentype_feature_overrides ) ;
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_supported_feature_list " , " font_rid " ) , & TextServer : : font_supported_feature_list ) ;
ClassDB : : bind_method ( D_METHOD ( " font_supported_variation_list " , " font_rid " ) , & TextServer : : font_supported_variation_list ) ;
2025-03-30 14:20:25 +03:00
# ifndef DISABLE_DEPRECATED
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " font_get_global_oversampling " ) , & TextServer : : font_get_global_oversampling ) ;
ClassDB : : bind_method ( D_METHOD ( " font_set_global_oversampling " , " oversampling " ) , & TextServer : : font_set_global_oversampling ) ;
2025-03-30 14:20:25 +03:00
# endif
2020-12-27 15:30:33 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_hex_code_box_size " , " size " , " index " ) , & TextServer : : get_hex_code_box_size ) ;
ClassDB : : bind_method ( D_METHOD ( " draw_hex_code_box " , " canvas " , " size " , " pos " , " index " , " color " ) , & TextServer : : draw_hex_code_box ) ;
2020-08-05 09:25:28 +03:00
/* Shaped text buffer interface */
ClassDB : : bind_method ( D_METHOD ( " create_shaped_text " , " direction " , " orientation " ) , & TextServer : : create_shaped_text , DEFVAL ( DIRECTION_AUTO ) , DEFVAL ( ORIENTATION_HORIZONTAL ) ) ;
2021-02-19 13:35:31 +01:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_clear " , " rid " ) , & TextServer : : shaped_text_clear ) ;
2020-08-05 09:25:28 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_set_direction " , " shaped " , " direction " ) , & TextServer : : shaped_text_set_direction , DEFVAL ( DIRECTION_AUTO ) ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_direction " , " shaped " ) , & TextServer : : shaped_text_get_direction ) ;
2022-01-10 17:24:03 +02:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_inferred_direction " , " shaped " ) , & TextServer : : shaped_text_get_inferred_direction ) ;
2020-08-05 09:25:28 +03:00
2021-08-28 00:19:51 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_set_bidi_override " , " shaped " , " override " ) , & TextServer : : shaped_text_set_bidi_override ) ;
2020-08-05 09:25:28 +03:00
2021-03-06 11:52:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_set_custom_punctuation " , " shaped " , " punct " ) , & TextServer : : shaped_text_set_custom_punctuation ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_custom_punctuation " , " shaped " ) , & TextServer : : shaped_text_get_custom_punctuation ) ;
2023-10-01 13:39:13 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_set_custom_ellipsis " , " shaped " , " char " ) , & TextServer : : shaped_text_set_custom_ellipsis ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_custom_ellipsis " , " shaped " ) , & TextServer : : shaped_text_get_custom_ellipsis ) ;
2020-08-05 09:25:28 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_set_orientation " , " shaped " , " orientation " ) , & TextServer : : shaped_text_set_orientation , DEFVAL ( ORIENTATION_HORIZONTAL ) ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_orientation " , " shaped " ) , & TextServer : : shaped_text_get_orientation ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_set_preserve_invalid " , " shaped " , " enabled " ) , & TextServer : : shaped_text_set_preserve_invalid ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_preserve_invalid " , " shaped " ) , & TextServer : : shaped_text_get_preserve_invalid ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_set_preserve_control " , " shaped " , " enabled " ) , & TextServer : : shaped_text_set_preserve_control ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_preserve_control " , " shaped " ) , & TextServer : : shaped_text_get_preserve_control ) ;
2022-05-09 12:47:10 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_set_spacing " , " shaped " , " spacing " , " value " ) , & TextServer : : shaped_text_set_spacing ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_spacing " , " shaped " , " spacing " ) , & TextServer : : shaped_text_get_spacing ) ;
2022-01-20 09:30:42 +02:00
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 ( ) ) ) ;
2022-12-08 22:01:07 +02:00
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 ) ) ;
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 ) ) ;
2025-03-21 16:42:23 +02:00
ClassDB : : bind_method ( D_METHOD ( " shaped_get_text " , " shaped " ) , & TextServer : : shaped_get_text ) ;
2020-08-05 09:25:28 +03:00
2022-01-20 09:30:42 +02:00
ClassDB : : bind_method ( D_METHOD ( " shaped_get_span_count " , " shaped " ) , & TextServer : : shaped_get_span_count ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_get_span_meta " , " shaped " , " index " ) , & TextServer : : shaped_get_span_meta ) ;
2024-09-26 09:37:47 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_get_span_embedded_object " , " shaped " , " index " ) , & TextServer : : shaped_get_span_embedded_object ) ;
2025-03-21 16:42:23 +02:00
ClassDB : : bind_method ( D_METHOD ( " shaped_get_span_text " , " shaped " , " index " ) , & TextServer : : shaped_get_span_text ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_get_span_object " , " shaped " , " index " ) , & TextServer : : shaped_get_span_object ) ;
2022-01-20 09:30:42 +02:00
ClassDB : : bind_method ( D_METHOD ( " shaped_set_span_update_font " , " shaped " , " index " , " fonts " , " size " , " opentype_features " ) , & TextServer : : shaped_set_span_update_font , DEFVAL ( Dictionary ( ) ) ) ;
2025-03-21 16:42:23 +02:00
ClassDB : : bind_method ( D_METHOD ( " shaped_get_run_count " , " shaped " ) , & TextServer : : shaped_get_run_count ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_get_run_text " , " shaped " , " index " ) , & TextServer : : shaped_get_run_text ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_get_run_range " , " shaped " , " index " ) , & TextServer : : shaped_get_run_range ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_get_run_font_rid " , " shaped " , " index " ) , & TextServer : : shaped_get_run_font_rid ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_get_run_font_size " , " shaped " , " index " ) , & TextServer : : shaped_get_run_font_size ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_get_run_language " , " shaped " , " index " ) , & TextServer : : shaped_get_run_language ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_get_run_direction " , " shaped " , " index " ) , & TextServer : : shaped_get_run_direction ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_get_run_object " , " shaped " , " index " ) , & TextServer : : shaped_get_run_object ) ;
2020-08-05 09:25:28 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_substr " , " shaped " , " start " , " length " ) , & TextServer : : shaped_text_substr ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_parent " , " shaped " ) , & TextServer : : shaped_text_get_parent ) ;
2023-03-23 11:22:37 +02:00
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 ) ) ;
2020-08-05 09:25:28 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_tab_align " , " shaped " , " tab_stops " ) , & TextServer : : shaped_text_tab_align ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_shape " , " shaped " ) , & TextServer : : shaped_text_shape ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_is_ready " , " shaped " ) , & TextServer : : shaped_text_is_ready ) ;
2023-03-23 11:22:37 +02:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_has_visible_chars " , " shaped " ) , & TextServer : : shaped_text_has_visible_chars ) ;
2020-08-05 09:25:28 +03:00
2021-08-28 00:19:51 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_glyphs " , " shaped " ) , & TextServer : : _shaped_text_get_glyphs_wrapper ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_sort_logical " , " shaped " ) , & TextServer : : _shaped_text_sort_logical_wrapper ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_glyph_count " , " shaped " ) , & TextServer : : shaped_text_get_glyph_count ) ;
2020-08-05 09:25:28 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_range " , " shaped " ) , & TextServer : : shaped_text_get_range ) ;
2021-08-28 00:19:51 +03:00
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 ) ) ;
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 ) ) ;
2024-04-15 22:14:41 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_word_breaks " , " shaped " , " grapheme_flags " , " skip_grapheme_flags " ) , & TextServer : : shaped_text_get_word_breaks , DEFVAL ( GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION ) , DEFVAL ( GRAPHEME_IS_VIRTUAL ) ) ;
2021-08-28 00:19:51 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_trim_pos " , " shaped " ) , & TextServer : : shaped_text_get_trim_pos ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_ellipsis_pos " , " shaped " ) , & TextServer : : shaped_text_get_ellipsis_pos ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_ellipsis_glyphs " , " shaped " ) , & TextServer : : _shaped_text_get_ellipsis_glyphs_wrapper ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_ellipsis_glyph_count " , " shaped " ) , & TextServer : : shaped_text_get_ellipsis_glyph_count ) ;
2021-07-04 16:43:55 +02:00
2022-06-15 11:01:45 +03:00
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 ) ) ;
2021-07-04 16:43:55 +02:00
2020-08-05 09:25:28 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_objects " , " shaped " ) , & TextServer : : shaped_text_get_objects ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_object_rect " , " shaped " , " key " ) , & TextServer : : shaped_text_get_object_rect ) ;
2024-03-11 16:28:58 +02:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_object_range " , " shaped " , " key " ) , & TextServer : : shaped_text_get_object_range ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_object_glyph " , " shaped " , " key " ) , & TextServer : : shaped_text_get_object_glyph ) ;
2020-08-05 09:25:28 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_size " , " shaped " ) , & TextServer : : shaped_text_get_size ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_ascent " , " shaped " ) , & TextServer : : shaped_text_get_ascent ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_descent " , " shaped " ) , & TextServer : : shaped_text_get_descent ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_width " , " shaped " ) , & TextServer : : shaped_text_get_width ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_underline_position " , " shaped " ) , & TextServer : : shaped_text_get_underline_position ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_underline_thickness " , " shaped " ) , & TextServer : : shaped_text_get_underline_thickness ) ;
2021-08-28 00:19:51 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_carets " , " shaped " , " position " ) , & TextServer : : _shaped_text_get_carets_wrapper ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_selection " , " shaped " , " start " , " end " ) , & TextServer : : shaped_text_get_selection ) ;
2020-08-05 09:25:28 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_hit_test_grapheme " , " shaped " , " coords " ) , & TextServer : : shaped_text_hit_test_grapheme ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_hit_test_position " , " shaped " , " coords " ) , & TextServer : : shaped_text_hit_test_position ) ;
2021-11-18 18:55:43 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_grapheme_bounds " , " shaped " , " pos " ) , & TextServer : : shaped_text_get_grapheme_bounds ) ;
2020-08-05 09:25:28 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_next_grapheme_pos " , " shaped " , " pos " ) , & TextServer : : shaped_text_next_grapheme_pos ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_prev_grapheme_pos " , " shaped " , " pos " ) , & TextServer : : shaped_text_prev_grapheme_pos ) ;
2023-08-15 11:42:40 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_character_breaks " , " shaped " ) , & TextServer : : shaped_text_get_character_breaks ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_next_character_pos " , " shaped " , " pos " ) , & TextServer : : shaped_text_next_character_pos ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_prev_character_pos " , " shaped " , " pos " ) , & TextServer : : shaped_text_prev_character_pos ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_closest_character_pos " , " shaped " , " pos " ) , & TextServer : : shaped_text_closest_character_pos ) ;
2025-03-30 14:20:25 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_draw " , " shaped " , " canvas " , " pos " , " clip_l " , " clip_r " , " color " , " oversampling " ) , & TextServer : : shaped_text_draw , DEFVAL ( - 1 ) , DEFVAL ( - 1 ) , DEFVAL ( Color ( 1 , 1 , 1 ) ) , DEFVAL ( 0.0 ) ) ;
ClassDB : : bind_method ( D_METHOD ( " shaped_text_draw_outline " , " shaped " , " canvas " , " pos " , " clip_l " , " clip_r " , " outline_size " , " color " , " oversampling " ) , & TextServer : : shaped_text_draw_outline , DEFVAL ( - 1 ) , DEFVAL ( - 1 ) , DEFVAL ( 1 ) , DEFVAL ( Color ( 1 , 1 , 1 ) ) , DEFVAL ( 0.0 ) ) ;
2020-08-05 09:25:28 +03:00
2021-08-28 00:19:51 +03:00
ClassDB : : bind_method ( D_METHOD ( " shaped_text_get_dominant_direction_in_range " , " shaped " , " start " , " end " ) , & TextServer : : shaped_text_get_dominant_direction_in_range ) ;
2020-08-05 09:25:28 +03:00
ClassDB : : bind_method ( D_METHOD ( " format_number " , " number " , " language " ) , & TextServer : : format_number , DEFVAL ( " " ) ) ;
ClassDB : : bind_method ( D_METHOD ( " parse_number " , " number " , " language " ) , & TextServer : : parse_number , DEFVAL ( " " ) ) ;
ClassDB : : bind_method ( D_METHOD ( " percent_sign " , " language " ) , & TextServer : : percent_sign , DEFVAL ( " " ) ) ;
2022-08-18 16:20:20 +08:00
ClassDB : : bind_method ( D_METHOD ( " string_get_word_breaks " , " string " , " language " , " chars_per_line " ) , & TextServer : : string_get_word_breaks , DEFVAL ( " " ) , DEFVAL ( 0 ) ) ;
2023-08-15 11:42:40 +03:00
ClassDB : : bind_method ( D_METHOD ( " string_get_character_breaks " , " string " , " language " ) , & TextServer : : string_get_character_breaks , DEFVAL ( " " ) ) ;
2021-11-04 14:33:37 +02:00
2021-11-12 10:12:37 +02:00
ClassDB : : bind_method ( D_METHOD ( " is_confusable " , " string " , " dict " ) , & TextServer : : is_confusable ) ;
ClassDB : : bind_method ( D_METHOD ( " spoof_check " , " string " ) , & TextServer : : spoof_check ) ;
2021-10-12 21:36:08 +03:00
ClassDB : : bind_method ( D_METHOD ( " strip_diacritics " , " string " ) , & TextServer : : strip_diacritics ) ;
2021-10-18 15:07:11 +03:00
ClassDB : : bind_method ( D_METHOD ( " is_valid_identifier " , " string " ) , & TextServer : : is_valid_identifier ) ;
2024-05-02 21:32:20 +02:00
ClassDB : : bind_method ( D_METHOD ( " is_valid_letter " , " unicode " ) , & TextServer : : is_valid_letter ) ;
2021-10-12 21:36:08 +03:00
2022-01-17 10:54:45 +02:00
ClassDB : : bind_method ( D_METHOD ( " string_to_upper " , " string " , " language " ) , & TextServer : : string_to_upper , DEFVAL ( " " ) ) ;
ClassDB : : bind_method ( D_METHOD ( " string_to_lower " , " string " , " language " ) , & TextServer : : string_to_lower , DEFVAL ( " " ) ) ;
2024-04-04 10:56:49 +03:00
ClassDB : : bind_method ( D_METHOD ( " string_to_title " , " string " , " language " ) , & TextServer : : string_to_title , DEFVAL ( " " ) ) ;
2022-01-17 10:54:45 +02:00
2022-04-19 13:27:18 +03:00
ClassDB : : bind_method ( D_METHOD ( " parse_structured_text " , " parser_type " , " args " , " text " ) , & TextServer : : parse_structured_text ) ;
2022-08-12 14:03:28 +03:00
/* Font AA */
BIND_ENUM_CONSTANT ( FONT_ANTIALIASING_NONE ) ;
BIND_ENUM_CONSTANT ( FONT_ANTIALIASING_GRAY ) ;
BIND_ENUM_CONSTANT ( FONT_ANTIALIASING_LCD ) ;
BIND_ENUM_CONSTANT ( FONT_LCD_SUBPIXEL_LAYOUT_NONE ) ;
BIND_ENUM_CONSTANT ( FONT_LCD_SUBPIXEL_LAYOUT_HRGB ) ;
BIND_ENUM_CONSTANT ( FONT_LCD_SUBPIXEL_LAYOUT_HBGR ) ;
BIND_ENUM_CONSTANT ( FONT_LCD_SUBPIXEL_LAYOUT_VRGB ) ;
BIND_ENUM_CONSTANT ( FONT_LCD_SUBPIXEL_LAYOUT_VBGR ) ;
2022-09-27 11:23:34 +03:00
BIND_ENUM_CONSTANT ( FONT_LCD_SUBPIXEL_LAYOUT_MAX ) ;
2022-08-12 14:03:28 +03:00
2020-08-05 09:25:28 +03:00
/* Direction */
BIND_ENUM_CONSTANT ( DIRECTION_AUTO ) ;
BIND_ENUM_CONSTANT ( DIRECTION_LTR ) ;
BIND_ENUM_CONSTANT ( DIRECTION_RTL ) ;
2023-01-18 09:33:35 +02:00
BIND_ENUM_CONSTANT ( DIRECTION_INHERITED ) ;
2020-08-05 09:25:28 +03:00
/* Orientation */
BIND_ENUM_CONSTANT ( ORIENTATION_HORIZONTAL ) ;
BIND_ENUM_CONSTANT ( ORIENTATION_VERTICAL ) ;
/* JustificationFlag */
2022-07-11 12:40:31 +03:00
BIND_BITFIELD_FLAG ( JUSTIFICATION_NONE ) ;
BIND_BITFIELD_FLAG ( JUSTIFICATION_KASHIDA ) ;
BIND_BITFIELD_FLAG ( JUSTIFICATION_WORD_BOUND ) ;
BIND_BITFIELD_FLAG ( JUSTIFICATION_TRIM_EDGE_SPACES ) ;
BIND_BITFIELD_FLAG ( JUSTIFICATION_AFTER_LAST_TAB ) ;
BIND_BITFIELD_FLAG ( JUSTIFICATION_CONSTRAIN_ELLIPSIS ) ;
2023-03-23 11:22:37 +02:00
BIND_BITFIELD_FLAG ( JUSTIFICATION_SKIP_LAST_LINE ) ;
BIND_BITFIELD_FLAG ( JUSTIFICATION_SKIP_LAST_LINE_WITH_VISIBLE_CHARS ) ;
BIND_BITFIELD_FLAG ( JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE ) ;
2020-08-05 09:25:28 +03:00
2022-06-15 11:01:45 +03:00
/* AutowrapMode */
BIND_ENUM_CONSTANT ( AUTOWRAP_OFF ) ;
BIND_ENUM_CONSTANT ( AUTOWRAP_ARBITRARY ) ;
BIND_ENUM_CONSTANT ( AUTOWRAP_WORD ) ;
BIND_ENUM_CONSTANT ( AUTOWRAP_WORD_SMART ) ;
2020-08-05 09:25:28 +03:00
/* LineBreakFlag */
2022-07-11 12:40:31 +03:00
BIND_BITFIELD_FLAG ( BREAK_NONE ) ;
BIND_BITFIELD_FLAG ( BREAK_MANDATORY ) ;
BIND_BITFIELD_FLAG ( BREAK_WORD_BOUND ) ;
BIND_BITFIELD_FLAG ( BREAK_GRAPHEME_BOUND ) ;
BIND_BITFIELD_FLAG ( BREAK_ADAPTIVE ) ;
2025-03-16 13:57:01 +02:00
# ifndef DISABLE_DEPRECATED
2022-08-30 11:56:17 +03:00
BIND_BITFIELD_FLAG ( BREAK_TRIM_EDGE_SPACES ) ;
2025-03-16 13:57:01 +02:00
# endif
2024-02-19 13:41:12 +02:00
BIND_BITFIELD_FLAG ( BREAK_TRIM_INDENT ) ;
2025-03-16 13:57:01 +02:00
BIND_BITFIELD_FLAG ( BREAK_TRIM_START_EDGE_SPACES ) ;
BIND_BITFIELD_FLAG ( BREAK_TRIM_END_EDGE_SPACES ) ;
2020-08-05 09:25:28 +03:00
2022-06-15 11:01:45 +03:00
/* VisibleCharactersBehavior */
BIND_ENUM_CONSTANT ( VC_CHARS_BEFORE_SHAPING ) ;
BIND_ENUM_CONSTANT ( VC_CHARS_AFTER_SHAPING ) ;
BIND_ENUM_CONSTANT ( VC_GLYPHS_AUTO ) ;
BIND_ENUM_CONSTANT ( VC_GLYPHS_LTR ) ;
BIND_ENUM_CONSTANT ( VC_GLYPHS_RTL ) ;
/* OverrunBehavior */
2021-07-04 16:43:55 +02:00
BIND_ENUM_CONSTANT ( OVERRUN_NO_TRIMMING ) ;
2022-06-15 11:01:45 +03:00
BIND_ENUM_CONSTANT ( OVERRUN_TRIM_CHAR ) ;
BIND_ENUM_CONSTANT ( OVERRUN_TRIM_WORD ) ;
BIND_ENUM_CONSTANT ( OVERRUN_TRIM_ELLIPSIS ) ;
BIND_ENUM_CONSTANT ( OVERRUN_TRIM_WORD_ELLIPSIS ) ;
2025-02-10 08:41:31 +02:00
BIND_ENUM_CONSTANT ( OVERRUN_TRIM_ELLIPSIS_FORCE ) ;
BIND_ENUM_CONSTANT ( OVERRUN_TRIM_WORD_ELLIPSIS_FORCE ) ;
2022-06-15 11:01:45 +03:00
/* TextOverrunFlag */
2022-07-11 12:40:31 +03:00
BIND_BITFIELD_FLAG ( OVERRUN_NO_TRIM ) ;
BIND_BITFIELD_FLAG ( OVERRUN_TRIM ) ;
BIND_BITFIELD_FLAG ( OVERRUN_TRIM_WORD_ONLY ) ;
BIND_BITFIELD_FLAG ( OVERRUN_ADD_ELLIPSIS ) ;
BIND_BITFIELD_FLAG ( OVERRUN_ENFORCE_ELLIPSIS ) ;
BIND_BITFIELD_FLAG ( OVERRUN_JUSTIFICATION_AWARE ) ;
2021-07-04 16:43:55 +02:00
2020-08-05 09:25:28 +03:00
/* GraphemeFlag */
2022-07-11 12:40:31 +03:00
BIND_BITFIELD_FLAG ( GRAPHEME_IS_VALID ) ;
BIND_BITFIELD_FLAG ( GRAPHEME_IS_RTL ) ;
BIND_BITFIELD_FLAG ( GRAPHEME_IS_VIRTUAL ) ;
BIND_BITFIELD_FLAG ( GRAPHEME_IS_SPACE ) ;
BIND_BITFIELD_FLAG ( GRAPHEME_IS_BREAK_HARD ) ;
BIND_BITFIELD_FLAG ( GRAPHEME_IS_BREAK_SOFT ) ;
BIND_BITFIELD_FLAG ( GRAPHEME_IS_TAB ) ;
BIND_BITFIELD_FLAG ( GRAPHEME_IS_ELONGATION ) ;
BIND_BITFIELD_FLAG ( GRAPHEME_IS_PUNCTUATION ) ;
BIND_BITFIELD_FLAG ( GRAPHEME_IS_UNDERSCORE ) ;
BIND_BITFIELD_FLAG ( GRAPHEME_IS_CONNECTED ) ;
2022-08-04 08:16:56 +03:00
BIND_BITFIELD_FLAG ( GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL ) ;
2023-04-12 10:08:51 +03:00
BIND_BITFIELD_FLAG ( GRAPHEME_IS_EMBEDDED_OBJECT ) ;
2023-12-08 12:30:56 +02:00
BIND_BITFIELD_FLAG ( GRAPHEME_IS_SOFT_HYPHEN ) ;
2020-08-05 09:25:28 +03:00
/* Hinting */
BIND_ENUM_CONSTANT ( HINTING_NONE ) ;
BIND_ENUM_CONSTANT ( HINTING_LIGHT ) ;
BIND_ENUM_CONSTANT ( HINTING_NORMAL ) ;
2022-01-10 10:13:22 +02:00
/* SubpixelPositioning */
BIND_ENUM_CONSTANT ( SUBPIXEL_POSITIONING_DISABLED ) ;
BIND_ENUM_CONSTANT ( SUBPIXEL_POSITIONING_AUTO ) ;
BIND_ENUM_CONSTANT ( SUBPIXEL_POSITIONING_ONE_HALF ) ;
BIND_ENUM_CONSTANT ( SUBPIXEL_POSITIONING_ONE_QUARTER ) ;
2022-02-13 14:41:29 +02:00
BIND_ENUM_CONSTANT ( SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE ) ;
BIND_ENUM_CONSTANT ( SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE ) ;
2022-01-10 10:13:22 +02:00
2020-08-05 09:25:28 +03:00
/* Feature */
2022-02-13 14:41:29 +02:00
BIND_ENUM_CONSTANT ( FEATURE_SIMPLE_LAYOUT ) ;
2020-08-05 09:25:28 +03:00
BIND_ENUM_CONSTANT ( FEATURE_BIDI_LAYOUT ) ;
BIND_ENUM_CONSTANT ( FEATURE_VERTICAL_LAYOUT ) ;
BIND_ENUM_CONSTANT ( FEATURE_SHAPING ) ;
BIND_ENUM_CONSTANT ( FEATURE_KASHIDA_JUSTIFICATION ) ;
BIND_ENUM_CONSTANT ( FEATURE_BREAK_ITERATORS ) ;
2022-02-13 14:41:29 +02:00
BIND_ENUM_CONSTANT ( FEATURE_FONT_BITMAP ) ;
BIND_ENUM_CONSTANT ( FEATURE_FONT_DYNAMIC ) ;
BIND_ENUM_CONSTANT ( FEATURE_FONT_MSDF ) ;
2020-08-05 09:25:28 +03:00
BIND_ENUM_CONSTANT ( FEATURE_FONT_SYSTEM ) ;
2020-10-22 19:40:18 +03:00
BIND_ENUM_CONSTANT ( FEATURE_FONT_VARIABLE ) ;
2022-01-17 10:54:45 +02:00
BIND_ENUM_CONSTANT ( FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION ) ;
2020-08-05 09:25:28 +03:00
BIND_ENUM_CONSTANT ( FEATURE_USE_SUPPORT_DATA ) ;
2021-10-18 15:07:11 +03:00
BIND_ENUM_CONSTANT ( FEATURE_UNICODE_IDENTIFIERS ) ;
2021-11-12 10:12:37 +02:00
BIND_ENUM_CONSTANT ( FEATURE_UNICODE_SECURITY ) ;
2020-12-10 17:30:25 +02:00
/* FT Contour Point Types */
BIND_ENUM_CONSTANT ( CONTOUR_CURVE_TAG_ON ) ;
BIND_ENUM_CONSTANT ( CONTOUR_CURVE_TAG_OFF_CONIC ) ;
BIND_ENUM_CONSTANT ( CONTOUR_CURVE_TAG_OFF_CUBIC ) ;
2020-12-27 15:30:33 +02:00
2021-10-26 09:40:11 +03:00
/* Font Spacing */
2020-12-27 15:30:33 +02:00
BIND_ENUM_CONSTANT ( SPACING_GLYPH ) ;
BIND_ENUM_CONSTANT ( SPACING_SPACE ) ;
BIND_ENUM_CONSTANT ( SPACING_TOP ) ;
BIND_ENUM_CONSTANT ( SPACING_BOTTOM ) ;
2022-07-11 12:40:31 +03:00
BIND_ENUM_CONSTANT ( SPACING_MAX ) ;
2021-10-26 09:40:11 +03:00
/* Font Style */
2022-07-11 12:40:31 +03:00
BIND_BITFIELD_FLAG ( FONT_BOLD ) ;
BIND_BITFIELD_FLAG ( FONT_ITALIC ) ;
BIND_BITFIELD_FLAG ( FONT_FIXED_WIDTH ) ;
2022-04-19 13:27:18 +03:00
/* Structured text parser */
BIND_ENUM_CONSTANT ( STRUCTURED_TEXT_DEFAULT ) ;
BIND_ENUM_CONSTANT ( STRUCTURED_TEXT_URI ) ;
BIND_ENUM_CONSTANT ( STRUCTURED_TEXT_FILE ) ;
BIND_ENUM_CONSTANT ( STRUCTURED_TEXT_EMAIL ) ;
BIND_ENUM_CONSTANT ( STRUCTURED_TEXT_LIST ) ;
2023-01-18 09:33:35 +02:00
BIND_ENUM_CONSTANT ( STRUCTURED_TEXT_GDSCRIPT ) ;
2022-04-19 13:27:18 +03:00
BIND_ENUM_CONSTANT ( STRUCTURED_TEXT_CUSTOM ) ;
2023-08-14 10:42:49 +03:00
/* Fixed size scale mode */
BIND_ENUM_CONSTANT ( FIXED_SIZE_SCALE_DISABLE ) ;
BIND_ENUM_CONSTANT ( FIXED_SIZE_SCALE_INTEGER_ONLY ) ;
BIND_ENUM_CONSTANT ( FIXED_SIZE_SCALE_ENABLED ) ;
2020-08-05 09:25:28 +03:00
}
2024-02-22 12:10:37 +02:00
_FORCE_INLINE_ int32_t ot_tag_from_string ( const char * p_str , int p_len ) {
char tag [ 4 ] ;
uint32_t i ;
if ( ! p_str | | ! p_len | | ! * p_str ) {
return OT_TAG ( 0 , 0 , 0 , 0 ) ;
}
if ( p_len < 0 | | p_len > 4 ) {
p_len = 4 ;
}
for ( i = 0 ; i < ( uint32_t ) p_len & & p_str [ i ] ; i + + ) {
tag [ i ] = p_str [ i ] ;
}
for ( ; i < 4 ; i + + ) {
tag [ i ] = ' ' ;
}
return OT_TAG ( tag [ 0 ] , tag [ 1 ] , tag [ 2 ] , tag [ 3 ] ) ;
}
int64_t TextServer : : name_to_tag ( const String & p_name ) const {
// No readable name, use tag string.
return ot_tag_from_string ( p_name . replace ( " custom_ " , " " ) . ascii ( ) . get_data ( ) , - 1 ) ;
}
_FORCE_INLINE_ void ot_tag_to_string ( int32_t p_tag , char * p_buf ) {
p_buf [ 0 ] = ( char ) ( uint8_t ) ( p_tag > > 24 ) ;
p_buf [ 1 ] = ( char ) ( uint8_t ) ( p_tag > > 16 ) ;
p_buf [ 2 ] = ( char ) ( uint8_t ) ( p_tag > > 8 ) ;
p_buf [ 3 ] = ( char ) ( uint8_t ) ( p_tag > > 0 ) ;
}
String TextServer : : tag_to_name ( int64_t p_tag ) const {
// No readable name, use tag string.
char name [ 5 ] ;
memset ( name , 0 , 5 ) ;
ot_tag_to_string ( p_tag , name ) ;
return String ( " custom_ " ) + String ( name ) ;
}
2022-02-13 14:41:29 +02:00
Vector2 TextServer : : get_hex_code_box_size ( int64_t p_size , int64_t p_index ) const {
2021-10-02 22:06:20 +03:00
int w = ( ( p_index < = 0xFF ) ? 1 : ( ( p_index < = 0xFFFF ) ? 2 : 3 ) ) ;
int sp = MAX ( 0 , w - 1 ) ;
2021-10-18 11:02:49 +03:00
int sz = MAX ( 1 , Math : : round ( p_size / 15.f ) ) ;
2020-08-05 09:25:28 +03:00
2021-10-02 22:06:20 +03:00
return Vector2 ( 4 + 3 * w + sp + 1 , 15 ) * sz ;
2020-08-05 09:25:28 +03:00
}
2022-02-13 14:41:29 +02:00
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 {
2021-10-02 22:06:20 +03:00
static uint8_t chars [ ] = { 0x7E , 0x30 , 0x6D , 0x79 , 0x33 , 0x5B , 0x5F , 0x70 , 0x7F , 0x7B , 0x77 , 0x1F , 0x4E , 0x3D , 0x4F , 0x47 , 0x00 } ;
uint8_t x = chars [ p_index ] ;
if ( x & ( 1 < < 6 ) ) {
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( p_canvas , Rect2 ( p_pos , Size2 ( 3 , 1 ) * p_size ) , p_color ) ;
2020-08-05 09:25:28 +03:00
}
2021-10-02 22:06:20 +03:00
if ( x & ( 1 < < 5 ) ) {
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( p_canvas , Rect2 ( p_pos + Point2 ( 2 , 0 ) * p_size , Size2 ( 1 , 3 ) * p_size ) , p_color ) ;
}
if ( x & ( 1 < < 4 ) ) {
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( p_canvas , Rect2 ( p_pos + Point2 ( 2 , 2 ) * p_size , Size2 ( 1 , 3 ) * p_size ) , p_color ) ;
}
if ( x & ( 1 < < 3 ) ) {
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( p_canvas , Rect2 ( p_pos + Point2 ( 0 , 4 ) * p_size , Size2 ( 3 , 1 ) * p_size ) , p_color ) ;
}
if ( x & ( 1 < < 2 ) ) {
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( p_canvas , Rect2 ( p_pos + Point2 ( 0 , 2 ) * p_size , Size2 ( 1 , 3 ) * p_size ) , p_color ) ;
}
if ( x & ( 1 < < 1 ) ) {
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( p_canvas , Rect2 ( p_pos , Size2 ( 1 , 3 ) * p_size ) , p_color ) ;
}
if ( x & ( 1 < < 0 ) ) {
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( p_canvas , Rect2 ( p_pos + Point2 ( 0 , 2 ) * p_size , Size2 ( 3 , 1 ) * p_size ) , p_color ) ;
2020-08-05 09:25:28 +03:00
}
}
2022-02-13 14:41:29 +02:00
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 {
2021-08-28 00:19:51 +03:00
if ( p_index = = 0 ) {
return ;
}
2020-08-05 09:25:28 +03:00
2021-10-02 22:06:20 +03:00
int w = ( ( p_index < = 0xFF ) ? 1 : ( ( p_index < = 0xFFFF ) ? 2 : 3 ) ) ;
int sp = MAX ( 0 , w - 1 ) ;
2021-10-18 11:02:49 +03:00
int sz = MAX ( 1 , Math : : round ( p_size / 15.f ) ) ;
2021-10-02 22:06:20 +03:00
Size2 size = Vector2 ( 4 + 3 * w + sp , 15 ) * sz ;
Point2 pos = p_pos - Point2i ( 0 , size . y * 0.85 ) ;
// Draw frame.
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( p_canvas , Rect2 ( pos + Point2 ( 0 , 0 ) , Size2 ( sz , size . y ) ) , p_color ) ;
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( p_canvas , Rect2 ( pos + Point2 ( size . x - sz , 0 ) , Size2 ( sz , size . y ) ) , p_color ) ;
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( p_canvas , Rect2 ( pos + Point2 ( 0 , 0 ) , Size2 ( size . x , sz ) ) , p_color ) ;
RenderingServer : : get_singleton ( ) - > canvas_item_add_rect ( p_canvas , Rect2 ( pos + Point2 ( 0 , size . y - sz ) , Size2 ( size . x , sz ) ) , p_color ) ;
2020-08-05 09:25:28 +03:00
uint8_t a = p_index & 0x0F ;
uint8_t b = ( p_index > > 4 ) & 0x0F ;
uint8_t c = ( p_index > > 8 ) & 0x0F ;
uint8_t d = ( p_index > > 12 ) & 0x0F ;
uint8_t e = ( p_index > > 16 ) & 0x0F ;
uint8_t f = ( p_index > > 20 ) & 0x0F ;
2021-10-02 22:06:20 +03:00
// Draw hex code.
2020-08-05 09:25:28 +03:00
if ( p_index < = 0xFF ) {
2021-10-02 22:06:20 +03:00
_draw_hex_code_box_number ( p_canvas , sz , pos + Point2 ( 2 , 2 ) * sz , b , p_color ) ;
_draw_hex_code_box_number ( p_canvas , sz , pos + Point2 ( 2 , 8 ) * sz , a , p_color ) ;
2020-08-05 09:25:28 +03:00
} else if ( p_index < = 0xFFFF ) {
2021-10-02 22:06:20 +03:00
_draw_hex_code_box_number ( p_canvas , sz , pos + Point2 ( 2 , 2 ) * sz , d , p_color ) ;
_draw_hex_code_box_number ( p_canvas , sz , pos + Point2 ( 6 , 2 ) * sz , c , p_color ) ;
_draw_hex_code_box_number ( p_canvas , sz , pos + Point2 ( 2 , 8 ) * sz , b , p_color ) ;
_draw_hex_code_box_number ( p_canvas , sz , pos + Point2 ( 6 , 8 ) * sz , a , p_color ) ;
2020-08-05 09:25:28 +03:00
} else {
2021-10-02 22:06:20 +03:00
_draw_hex_code_box_number ( p_canvas , sz , pos + Point2 ( 2 , 2 ) * sz , f , p_color ) ;
_draw_hex_code_box_number ( p_canvas , sz , pos + Point2 ( 6 , 2 ) * sz , e , p_color ) ;
_draw_hex_code_box_number ( p_canvas , sz , pos + Point2 ( 10 , 2 ) * sz , d , p_color ) ;
_draw_hex_code_box_number ( p_canvas , sz , pos + Point2 ( 2 , 8 ) * sz , c , p_color ) ;
_draw_hex_code_box_number ( p_canvas , sz , pos + Point2 ( 6 , 8 ) * sz , b , p_color ) ;
_draw_hex_code_box_number ( p_canvas , sz , pos + Point2 ( 10 , 8 ) * sz , a , p_color ) ;
2020-08-05 09:25:28 +03:00
}
}
2023-03-23 11:22:37 +02:00
bool TextServer : : shaped_text_has_visible_chars ( const RID & p_shaped ) const {
int v_size = shaped_text_get_glyph_count ( p_shaped ) ;
if ( v_size = = 0 ) {
return false ;
}
const Glyph * glyphs = shaped_text_get_glyphs ( p_shaped ) ;
for ( int i = 0 ; i < v_size ; i + + ) {
if ( glyphs [ i ] . index ! = 0 & & ( glyphs [ i ] . flags & GRAPHEME_IS_VIRTUAL ) ! = GRAPHEME_IS_VIRTUAL ) {
return true ;
}
}
return false ;
}
2022-07-11 12:40:31 +03:00
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 {
2021-08-28 00:19:51 +03:00
PackedInt32Array lines ;
2020-08-05 09:25:28 +03:00
2020-12-15 12:04:21 +00:00
ERR_FAIL_COND_V ( p_width . is_empty ( ) , lines ) ;
2020-08-05 09:25:28 +03:00
2023-12-08 12:30:56 +02:00
TextServer : : Orientation orientation = shaped_text_get_orientation ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
const_cast < TextServer * > ( this ) - > shaped_text_update_breaks ( p_shaped ) ;
const Vector2i & range = shaped_text_get_range ( p_shaped ) ;
2020-12-27 15:30:33 +02:00
real_t width = 0.f ;
2020-08-05 09:25:28 +03:00
int line_start = MAX ( p_start , range . x ) ;
2023-05-26 16:18:26 +03:00
int last_end = line_start ;
2022-08-30 11:56:17 +03:00
int prev_safe_break = 0 ;
2020-08-05 09:25:28 +03:00
int last_safe_break = - 1 ;
2022-09-01 21:31:26 +03:00
int word_count = 0 ;
2020-08-05 09:25:28 +03:00
int chunk = 0 ;
2025-02-07 08:25:44 +02:00
int prev_chunk = - 1 ;
2022-09-01 21:31:26 +03:00
bool trim_next = false ;
2020-12-01 15:03:31 +02:00
2025-03-16 13:57:01 +02:00
# ifndef DISABLE_DEPRECATED
if ( p_break_flags . has_flag ( BREAK_TRIM_EDGE_SPACES ) ) {
p_break_flags = p_break_flags | BREAK_TRIM_START_EDGE_SPACES | BREAK_TRIM_END_EDGE_SPACES ;
}
# endif
2021-08-28 00:19:51 +03:00
int l_size = shaped_text_get_glyph_count ( p_shaped ) ;
const Glyph * l_gl = const_cast < TextServer * > ( this ) - > shaped_text_sort_logical ( p_shaped ) ;
2020-12-01 15:03:31 +02:00
2025-02-07 08:25:44 +02:00
int indent_end = 0 ;
2024-02-19 13:41:12 +02:00
double indent = 0.0 ;
2020-12-01 15:03:31 +02:00
for ( int i = 0 ; i < l_size ; i + + ) {
2024-02-19 13:41:12 +02:00
double l_width = p_width [ chunk ] ;
2025-02-07 08:25:44 +02:00
if ( p_break_flags . has_flag ( BREAK_TRIM_INDENT ) & & chunk ! = prev_chunk ) {
indent = 0.0 ;
for ( int j = indent_end ; j < l_size ; j + + ) {
if ( ( l_gl [ j ] . flags & GRAPHEME_IS_TAB ) = = GRAPHEME_IS_TAB | | ( l_gl [ j ] . flags & GRAPHEME_IS_SPACE ) = = GRAPHEME_IS_SPACE ) {
if ( indent + l_gl [ j ] . advance * l_gl [ j ] . repeat > l_width ) {
indent = 0.0 ;
}
indent + = l_gl [ j ] . advance * l_gl [ j ] . repeat ;
indent_end = l_gl [ j ] . end ;
} else {
break ;
}
}
indent = MIN ( indent , 0.6 * l_width ) ;
prev_chunk = chunk ;
}
if ( l_width > indent & & i > indent_end ) {
2024-02-19 13:41:12 +02:00
l_width - = indent ;
}
2020-12-01 15:03:31 +02:00
if ( l_gl [ i ] . start < p_start ) {
2022-08-30 11:56:17 +03:00
prev_safe_break = i + 1 ;
2020-08-05 09:25:28 +03:00
continue ;
}
2020-12-01 15:03:31 +02:00
if ( l_gl [ i ] . count > 0 ) {
2024-11-21 10:57:07 +02:00
float adv = 0.0 ;
for ( int j = i ; j < l_size & & l_gl [ i ] . end = = l_gl [ j ] . end & & l_gl [ i ] . start = = l_gl [ j ] . start ; j + + ) {
adv + = l_gl [ j ] . advance * l_gl [ j ] . repeat ;
}
if ( ( l_width > 0 ) & & ( width + adv > l_width ) & & ( last_safe_break > = 0 ) ) {
int cur_safe_brk = last_safe_break ;
2025-03-16 13:57:01 +02:00
if ( p_break_flags . has_flag ( BREAK_TRIM_START_EDGE_SPACES ) | | p_break_flags . has_flag ( BREAK_TRIM_END_EDGE_SPACES ) ) {
2022-08-30 11:56:17 +03:00
int start_pos = prev_safe_break ;
int end_pos = last_safe_break ;
2025-03-16 13:57:01 +02:00
while ( p_break_flags . has_flag ( BREAK_TRIM_START_EDGE_SPACES ) & & trim_next & & ( start_pos < end_pos ) & & ( ( l_gl [ start_pos ] . flags & GRAPHEME_IS_SOFT_HYPHEN ) ! = GRAPHEME_IS_SOFT_HYPHEN ) & & ( ( 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 ) ) {
2022-08-30 11:56:17 +03:00
start_pos + = l_gl [ start_pos ] . count ;
}
2025-03-16 13:57:01 +02:00
while ( p_break_flags . has_flag ( BREAK_TRIM_END_EDGE_SPACES ) & & ( start_pos < end_pos ) & & ( ( l_gl [ end_pos ] . flags & GRAPHEME_IS_SOFT_HYPHEN ) ! = GRAPHEME_IS_SOFT_HYPHEN ) & & ( ( 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 ) ) {
2022-08-30 11:56:17 +03:00
end_pos - = l_gl [ end_pos ] . count ;
}
2023-05-26 16:18:26 +03:00
if ( last_end < = l_gl [ start_pos ] . start ) {
lines . push_back ( l_gl [ start_pos ] . start ) ;
lines . push_back ( l_gl [ end_pos ] . end ) ;
2025-02-14 14:40:37 +02:00
cur_safe_brk = last_safe_break ;
2023-05-26 16:18:26 +03:00
last_end = l_gl [ end_pos ] . end ;
}
2022-09-01 21:31:26 +03:00
trim_next = true ;
2022-08-30 11:56:17 +03:00
} else {
2023-05-26 16:18:26 +03:00
if ( last_end < = line_start ) {
lines . push_back ( line_start ) ;
lines . push_back ( l_gl [ last_safe_break ] . end ) ;
last_end = l_gl [ last_safe_break ] . end ;
}
2022-08-30 11:56:17 +03:00
}
2024-11-21 10:57:07 +02:00
line_start = l_gl [ cur_safe_brk ] . end ;
prev_safe_break = cur_safe_brk + 1 ;
while ( prev_safe_break < l_size & & l_gl [ prev_safe_break ] . end = = line_start ) {
prev_safe_break + + ;
}
i = cur_safe_brk ;
2020-08-05 09:25:28 +03:00
last_safe_break = - 1 ;
width = 0 ;
2022-09-01 21:31:26 +03:00
word_count = 0 ;
2020-08-05 09:25:28 +03:00
chunk + + ;
if ( chunk > = p_width . size ( ) ) {
chunk = 0 ;
if ( p_once ) {
return lines ;
}
}
continue ;
}
2022-07-11 12:40:31 +03:00
if ( p_break_flags . has_flag ( BREAK_MANDATORY ) ) {
2020-12-01 15:03:31 +02:00
if ( ( l_gl [ i ] . flags & GRAPHEME_IS_BREAK_HARD ) = = GRAPHEME_IS_BREAK_HARD ) {
2024-11-21 10:57:07 +02:00
int cur_safe_brk = i ;
2025-03-16 13:57:01 +02:00
if ( p_break_flags . has_flag ( BREAK_TRIM_START_EDGE_SPACES ) | | p_break_flags . has_flag ( BREAK_TRIM_END_EDGE_SPACES ) ) {
2022-08-30 11:56:17 +03:00
int start_pos = prev_safe_break ;
int end_pos = i ;
2025-03-16 13:57:01 +02:00
while ( p_break_flags . has_flag ( BREAK_TRIM_START_EDGE_SPACES ) & & 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 ) ) {
2022-08-30 11:56:17 +03:00
start_pos + = l_gl [ start_pos ] . count ;
}
2025-03-16 13:57:01 +02:00
while ( p_break_flags . has_flag ( BREAK_TRIM_END_EDGE_SPACES ) & & ( 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 ) ) {
2022-08-30 11:56:17 +03:00
end_pos - = l_gl [ end_pos ] . count ;
}
2023-05-26 16:18:26 +03:00
if ( last_end < = l_gl [ start_pos ] . start ) {
lines . push_back ( l_gl [ start_pos ] . start ) ;
lines . push_back ( l_gl [ end_pos ] . end ) ;
2024-12-16 23:37:26 +02:00
last_end = l_gl [ i ] . end ;
cur_safe_brk = i ;
2023-05-26 16:18:26 +03:00
}
2024-12-16 23:37:26 +02:00
trim_next = true ;
2022-08-30 11:56:17 +03:00
} else {
2023-05-26 16:18:26 +03:00
if ( last_end < = line_start ) {
lines . push_back ( line_start ) ;
lines . push_back ( l_gl [ i ] . end ) ;
last_end = l_gl [ i ] . end ;
}
2022-08-30 11:56:17 +03:00
}
2024-11-21 10:57:07 +02:00
line_start = l_gl [ cur_safe_brk ] . end ;
prev_safe_break = cur_safe_brk + 1 ;
while ( prev_safe_break < l_size & & l_gl [ prev_safe_break ] . end = = line_start ) {
prev_safe_break + + ;
}
2020-08-05 09:25:28 +03:00
last_safe_break = - 1 ;
width = 0 ;
chunk = 0 ;
if ( p_once ) {
return lines ;
}
continue ;
}
}
2022-07-11 12:40:31 +03:00
if ( p_break_flags . has_flag ( BREAK_WORD_BOUND ) ) {
2020-12-01 15:03:31 +02:00
if ( ( l_gl [ i ] . flags & GRAPHEME_IS_BREAK_SOFT ) = = GRAPHEME_IS_BREAK_SOFT ) {
2023-12-08 12:30:56 +02:00
if ( ( l_gl [ i ] . flags & GRAPHEME_IS_SOFT_HYPHEN ) = = GRAPHEME_IS_SOFT_HYPHEN ) {
uint32_t gl = font_get_glyph_index ( l_gl [ i ] . font_rid , l_gl [ i ] . font_size , 0x00ad , 0 ) ;
float w = font_get_glyph_advance ( l_gl [ i ] . font_rid , l_gl [ i ] . font_size , gl ) [ ( orientation = = ORIENTATION_HORIZONTAL ) ? 0 : 1 ] ;
2024-11-21 10:57:07 +02:00
if ( width + adv + w < = p_width [ chunk ] ) {
2023-12-08 12:30:56 +02:00
last_safe_break = i ;
word_count + + ;
}
} else {
last_safe_break = i ;
word_count + + ;
}
2020-08-05 09:25:28 +03:00
}
}
2022-09-01 21:31:26 +03:00
if ( p_break_flags . has_flag ( BREAK_GRAPHEME_BOUND ) & & word_count = = 0 ) {
2020-08-05 09:25:28 +03:00
last_safe_break = i ;
}
}
2024-11-21 10:57:07 +02:00
width + = l_gl [ i ] . advance * l_gl [ i ] . repeat ;
2020-08-05 09:25:28 +03:00
}
2020-12-01 15:03:31 +02:00
if ( l_size > 0 ) {
2025-03-20 00:07:31 +08:00
if ( lines . is_empty ( ) | | ( lines [ lines . size ( ) - 1 ] < range . y & & prev_safe_break < l_size ) ) {
2025-03-16 13:57:01 +02:00
if ( p_break_flags . has_flag ( BREAK_TRIM_START_EDGE_SPACES ) ) {
2022-08-30 11:56:17 +03:00
int start_pos = ( prev_safe_break < l_size ) ? prev_safe_break : l_size - 1 ;
2024-11-21 10:57:07 +02:00
if ( last_end < = l_gl [ start_pos ] . start ) {
int end_pos = l_size - 1 ;
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 ) ) {
start_pos + = l_gl [ start_pos ] . count ;
}
lines . push_back ( l_gl [ start_pos ] . start ) ;
} else {
lines . push_back ( last_end ) ;
2022-08-30 11:56:17 +03:00
}
} else {
2024-11-21 10:57:07 +02:00
lines . push_back ( MAX ( last_end , line_start ) ) ;
2022-08-30 11:56:17 +03:00
}
2022-09-01 21:31:26 +03:00
lines . push_back ( range . y ) ;
2021-08-28 00:19:51 +03:00
}
2020-08-05 09:25:28 +03:00
} else {
2021-08-28 00:19:51 +03:00
lines . push_back ( 0 ) ;
lines . push_back ( 0 ) ;
2020-08-05 09:25:28 +03:00
}
return lines ;
}
2022-07-11 12:40:31 +03:00
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 {
2021-08-28 00:19:51 +03:00
PackedInt32Array lines ;
2020-08-05 09:25:28 +03:00
const_cast < TextServer * > ( this ) - > shaped_text_update_breaks ( p_shaped ) ;
const Vector2i & range = shaped_text_get_range ( p_shaped ) ;
2022-02-13 14:41:29 +02:00
double width = 0.f ;
2020-08-05 09:25:28 +03:00
int line_start = MAX ( p_start , range . x ) ;
2023-05-26 16:18:26 +03:00
int last_end = line_start ;
2022-08-30 11:56:17 +03:00
int prev_safe_break = 0 ;
2020-08-05 09:25:28 +03:00
int last_safe_break = - 1 ;
2021-07-04 16:43:55 +02:00
int word_count = 0 ;
2022-09-01 21:31:26 +03:00
bool trim_next = false ;
2021-08-28 00:19:51 +03:00
2025-03-16 13:57:01 +02:00
# ifndef DISABLE_DEPRECATED
if ( p_break_flags . has_flag ( BREAK_TRIM_EDGE_SPACES ) ) {
p_break_flags = p_break_flags | BREAK_TRIM_START_EDGE_SPACES | BREAK_TRIM_END_EDGE_SPACES ;
}
# endif
2023-12-08 12:30:56 +02:00
TextServer : : Orientation orientation = shaped_text_get_orientation ( p_shaped ) ;
2021-08-28 00:19:51 +03:00
int l_size = shaped_text_get_glyph_count ( p_shaped ) ;
const Glyph * l_gl = const_cast < TextServer * > ( this ) - > shaped_text_sort_logical ( p_shaped ) ;
2020-12-01 15:03:31 +02:00
2025-02-07 08:25:44 +02:00
int indent_end = 0 ;
2024-02-19 13:41:12 +02:00
double indent = 0.0 ;
if ( p_break_flags . has_flag ( BREAK_TRIM_INDENT ) ) {
for ( int i = 0 ; i < l_size ; i + + ) {
if ( ( l_gl [ i ] . flags & GRAPHEME_IS_TAB ) = = GRAPHEME_IS_TAB | | ( l_gl [ i ] . flags & GRAPHEME_IS_SPACE ) = = GRAPHEME_IS_SPACE ) {
2025-02-07 08:25:44 +02:00
if ( indent + l_gl [ i ] . advance * l_gl [ i ] . repeat > p_width ) {
indent = 0.0 ;
}
2024-02-19 13:41:12 +02:00
indent + = l_gl [ i ] . advance * l_gl [ i ] . repeat ;
2025-02-07 08:25:44 +02:00
indent_end = l_gl [ i ] . end ;
2024-02-19 13:41:12 +02:00
} else {
break ;
}
}
2025-02-07 08:25:44 +02:00
indent = MIN ( indent , 0.6 * p_width ) ;
2024-02-19 13:41:12 +02:00
}
double l_width = p_width ;
2020-12-01 15:03:31 +02:00
for ( int i = 0 ; i < l_size ; i + + ) {
if ( l_gl [ i ] . start < p_start ) {
2022-08-30 11:56:17 +03:00
prev_safe_break = i + 1 ;
2020-08-05 09:25:28 +03:00
continue ;
}
2020-12-01 15:03:31 +02:00
if ( l_gl [ i ] . count > 0 ) {
2024-11-21 10:57:07 +02:00
float adv = 0.0 ;
for ( int j = i ; j < l_size & & l_gl [ i ] . end = = l_gl [ j ] . end & & l_gl [ i ] . start = = l_gl [ j ] . start ; j + + ) {
adv + = l_gl [ j ] . advance * l_gl [ j ] . repeat ;
}
if ( ( l_width > 0 ) & & ( width + adv > l_width ) & & ( last_safe_break > = 0 ) ) {
int cur_safe_brk = last_safe_break ;
2025-03-16 13:57:01 +02:00
if ( p_break_flags . has_flag ( BREAK_TRIM_START_EDGE_SPACES ) | | p_break_flags . has_flag ( BREAK_TRIM_END_EDGE_SPACES ) ) {
2022-08-30 11:56:17 +03:00
int start_pos = prev_safe_break ;
int end_pos = last_safe_break ;
2025-03-16 13:57:01 +02:00
while ( p_break_flags . has_flag ( BREAK_TRIM_START_EDGE_SPACES ) & & trim_next & & ( start_pos < end_pos ) & & ( ( l_gl [ start_pos ] . flags & GRAPHEME_IS_SOFT_HYPHEN ) ! = GRAPHEME_IS_SOFT_HYPHEN ) & & ( ( 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 ) ) {
2022-08-30 11:56:17 +03:00
start_pos + = l_gl [ start_pos ] . count ;
}
2025-03-16 13:57:01 +02:00
while ( p_break_flags . has_flag ( BREAK_TRIM_END_EDGE_SPACES ) & & ( start_pos < end_pos ) & & ( ( l_gl [ end_pos ] . flags & GRAPHEME_IS_SOFT_HYPHEN ) ! = GRAPHEME_IS_SOFT_HYPHEN ) & & ( ( 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 ) ) {
2022-08-30 11:56:17 +03:00
end_pos - = l_gl [ end_pos ] . count ;
}
2023-05-26 16:18:26 +03:00
if ( last_end < = l_gl [ start_pos ] . start ) {
lines . push_back ( l_gl [ start_pos ] . start ) ;
lines . push_back ( l_gl [ end_pos ] . end ) ;
2025-02-07 08:25:44 +02:00
if ( p_width > indent & & i > indent_end ) {
2024-02-19 13:41:12 +02:00
l_width = p_width - indent ;
}
2025-02-14 14:40:37 +02:00
cur_safe_brk = last_safe_break ;
2023-05-26 16:18:26 +03:00
last_end = l_gl [ end_pos ] . end ;
}
2022-09-01 21:31:26 +03:00
trim_next = true ;
2022-08-30 11:56:17 +03:00
} else {
2023-05-26 16:18:26 +03:00
if ( last_end < = line_start ) {
lines . push_back ( line_start ) ;
lines . push_back ( l_gl [ last_safe_break ] . end ) ;
2025-02-07 08:25:44 +02:00
if ( p_width > indent & & i > indent_end ) {
2024-02-19 13:41:12 +02:00
l_width = p_width - indent ;
}
2023-05-26 16:18:26 +03:00
last_end = l_gl [ last_safe_break ] . end ;
}
2022-08-30 11:56:17 +03:00
}
2024-11-21 10:57:07 +02:00
line_start = l_gl [ cur_safe_brk ] . end ;
prev_safe_break = cur_safe_brk + 1 ;
while ( prev_safe_break < l_size & & l_gl [ prev_safe_break ] . end = = line_start ) {
prev_safe_break + + ;
}
i = cur_safe_brk ;
2020-08-05 09:25:28 +03:00
last_safe_break = - 1 ;
width = 0 ;
2021-07-04 16:43:55 +02:00
word_count = 0 ;
2020-08-05 09:25:28 +03:00
continue ;
}
2022-07-11 12:40:31 +03:00
if ( p_break_flags . has_flag ( BREAK_MANDATORY ) ) {
2020-12-01 15:03:31 +02:00
if ( ( l_gl [ i ] . flags & GRAPHEME_IS_BREAK_HARD ) = = GRAPHEME_IS_BREAK_HARD ) {
2024-11-21 10:57:07 +02:00
int cur_safe_brk = i ;
2025-03-16 13:57:01 +02:00
if ( p_break_flags . has_flag ( BREAK_TRIM_START_EDGE_SPACES ) | | p_break_flags . has_flag ( BREAK_TRIM_END_EDGE_SPACES ) ) {
2022-08-30 11:56:17 +03:00
int start_pos = prev_safe_break ;
int end_pos = i ;
2025-03-16 13:57:01 +02:00
while ( p_break_flags . has_flag ( BREAK_TRIM_START_EDGE_SPACES ) & & 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 ) ) {
2022-08-30 11:56:17 +03:00
start_pos + = l_gl [ start_pos ] . count ;
}
2025-03-16 13:57:01 +02:00
while ( p_break_flags . has_flag ( BREAK_TRIM_END_EDGE_SPACES ) & & ( 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 ) ) {
2022-08-30 11:56:17 +03:00
end_pos - = l_gl [ end_pos ] . count ;
}
2024-12-16 23:37:26 +02:00
trim_next = true ;
2023-05-26 16:18:26 +03:00
if ( last_end < = l_gl [ start_pos ] . start ) {
lines . push_back ( l_gl [ start_pos ] . start ) ;
lines . push_back ( l_gl [ end_pos ] . end ) ;
2025-02-07 08:25:44 +02:00
if ( p_width > indent & & i > indent_end ) {
2024-02-19 13:41:12 +02:00
l_width = p_width - indent ;
}
2024-12-16 23:37:26 +02:00
last_end = l_gl [ i ] . end ;
cur_safe_brk = i ;
2023-05-26 16:18:26 +03:00
}
2022-08-30 11:56:17 +03:00
} else {
2023-05-26 16:18:26 +03:00
if ( last_end < = line_start ) {
lines . push_back ( line_start ) ;
lines . push_back ( l_gl [ i ] . end ) ;
2025-02-07 08:25:44 +02:00
if ( p_width > indent & & i > indent_end ) {
2024-02-19 13:41:12 +02:00
l_width = p_width - indent ;
}
2023-05-26 16:18:26 +03:00
last_end = l_gl [ i ] . end ;
}
2022-08-30 11:56:17 +03:00
}
2024-11-21 10:57:07 +02:00
line_start = l_gl [ cur_safe_brk ] . end ;
prev_safe_break = cur_safe_brk + 1 ;
while ( prev_safe_break < l_size & & l_gl [ prev_safe_break ] . end = = line_start ) {
prev_safe_break + + ;
}
2020-08-05 09:25:28 +03:00
last_safe_break = - 1 ;
width = 0 ;
continue ;
}
}
2022-07-11 12:40:31 +03:00
if ( p_break_flags . has_flag ( BREAK_WORD_BOUND ) ) {
2020-12-01 15:03:31 +02:00
if ( ( l_gl [ i ] . flags & GRAPHEME_IS_BREAK_SOFT ) = = GRAPHEME_IS_BREAK_SOFT ) {
2023-12-08 12:30:56 +02:00
if ( ( l_gl [ i ] . flags & GRAPHEME_IS_SOFT_HYPHEN ) = = GRAPHEME_IS_SOFT_HYPHEN ) {
uint32_t gl = font_get_glyph_index ( l_gl [ i ] . font_rid , l_gl [ i ] . font_size , 0x00AD , 0 ) ;
float w = font_get_glyph_advance ( l_gl [ i ] . font_rid , l_gl [ i ] . font_size , gl ) [ ( orientation = = ORIENTATION_HORIZONTAL ) ? 0 : 1 ] ;
2024-11-21 10:57:07 +02:00
if ( width + adv + w < = p_width ) {
2023-12-08 12:30:56 +02:00
last_safe_break = i ;
word_count + + ;
}
} else {
last_safe_break = i ;
word_count + + ;
}
2020-08-05 09:25:28 +03:00
}
2022-07-11 12:40:31 +03:00
if ( p_break_flags . has_flag ( BREAK_ADAPTIVE ) & & word_count = = 0 ) {
last_safe_break = i ;
}
2020-08-05 09:25:28 +03:00
}
2022-07-11 12:40:31 +03:00
if ( p_break_flags . has_flag ( BREAK_GRAPHEME_BOUND ) ) {
2020-08-05 09:25:28 +03:00
last_safe_break = i ;
}
}
2021-08-21 00:22:09 +02:00
width + = l_gl [ i ] . advance * l_gl [ i ] . repeat ;
2020-08-05 09:25:28 +03:00
}
2020-12-01 15:03:31 +02:00
if ( l_size > 0 ) {
2025-03-20 00:07:31 +08:00
if ( lines . is_empty ( ) | | ( lines [ lines . size ( ) - 1 ] < range . y & & prev_safe_break < l_size ) ) {
2025-03-16 13:57:01 +02:00
if ( p_break_flags . has_flag ( BREAK_TRIM_START_EDGE_SPACES ) ) {
2022-08-30 11:56:17 +03:00
int start_pos = ( prev_safe_break < l_size ) ? prev_safe_break : l_size - 1 ;
2024-11-21 10:57:07 +02:00
if ( last_end < = l_gl [ start_pos ] . start ) {
int end_pos = l_size - 1 ;
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 ) ) {
start_pos + = l_gl [ start_pos ] . count ;
}
lines . push_back ( l_gl [ start_pos ] . start ) ;
} else {
lines . push_back ( last_end ) ;
2022-08-30 11:56:17 +03:00
}
} else {
2024-11-21 10:57:07 +02:00
lines . push_back ( MAX ( last_end , line_start ) ) ;
2022-08-30 11:56:17 +03:00
}
2022-09-01 21:31:26 +03:00
lines . push_back ( range . y ) ;
2020-08-05 09:25:28 +03:00
}
} else {
2021-08-28 00:19:51 +03:00
lines . push_back ( 0 ) ;
lines . push_back ( 0 ) ;
2020-08-05 09:25:28 +03:00
}
return lines ;
}
2024-04-15 22:14:41 +03:00
PackedInt32Array TextServer : : shaped_text_get_word_breaks ( const RID & p_shaped , BitField < TextServer : : GraphemeFlag > p_grapheme_flags , BitField < TextServer : : GraphemeFlag > p_skip_grapheme_flags ) const {
2021-08-28 00:19:51 +03:00
PackedInt32Array words ;
2020-08-05 09:25:28 +03:00
2020-12-14 10:30:32 +02:00
const_cast < TextServer * > ( this ) - > shaped_text_update_justification_ops ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
const Vector2i & range = shaped_text_get_range ( p_shaped ) ;
int word_start = range . x ;
2020-12-01 15:03:31 +02:00
2022-02-21 22:32:24 +01:00
const int l_size = shaped_text_get_glyph_count ( p_shaped ) ;
2021-08-28 00:19:51 +03:00
const Glyph * l_gl = const_cast < TextServer * > ( this ) - > shaped_text_sort_logical ( p_shaped ) ;
2020-12-01 15:03:31 +02:00
for ( int i = 0 ; i < l_size ; i + + ) {
if ( l_gl [ i ] . count > 0 ) {
2024-04-15 22:14:41 +03:00
if ( ( l_gl [ i ] . flags & p_grapheme_flags ) ! = 0 & & ( l_gl [ i ] . flags & p_skip_grapheme_flags ) = = 0 ) {
int next = ( i = = 0 ) ? l_gl [ i ] . start : l_gl [ i - 1 ] . end ;
if ( word_start < next ) {
2022-03-05 22:31:58 +02:00
words . push_back ( word_start ) ;
2024-04-15 22:14:41 +03:00
words . push_back ( next ) ;
2022-03-05 22:31:58 +02:00
}
2020-12-01 15:03:31 +02:00
word_start = l_gl [ i ] . end ;
2020-08-05 09:25:28 +03:00
}
}
}
2020-12-01 15:03:31 +02:00
if ( l_size > 0 ) {
2022-03-05 22:31:58 +02:00
if ( word_start ! = range . y ) {
words . push_back ( word_start ) ;
words . push_back ( range . y ) ;
}
2020-08-05 09:25:28 +03:00
}
return words ;
}
2022-02-13 14:41:29 +02:00
CaretInfo TextServer : : shaped_text_get_carets ( const RID & p_shaped , int64_t p_position ) const {
2020-08-05 09:25:28 +03:00
Vector < Rect2 > carets ;
2021-08-28 00:19:51 +03:00
2020-08-05 09:25:28 +03:00
TextServer : : Orientation orientation = shaped_text_get_orientation ( p_shaped ) ;
const Vector2 & range = shaped_text_get_range ( p_shaped ) ;
2020-12-27 15:30:33 +02:00
real_t ascent = shaped_text_get_ascent ( p_shaped ) ;
real_t descent = shaped_text_get_descent ( p_shaped ) ;
real_t height = ( ascent + descent ) / 2 ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
real_t off = 0.0f ;
2025-04-23 21:44:01 -04:00
real_t obj_off = - 1.0f ;
2021-08-28 00:19:51 +03:00
CaretInfo caret ;
caret . l_dir = DIRECTION_AUTO ;
caret . t_dir = DIRECTION_AUTO ;
2020-12-01 15:03:31 +02:00
2021-08-28 00:19:51 +03:00
int v_size = shaped_text_get_glyph_count ( p_shaped ) ;
const Glyph * glyphs = shaped_text_get_glyphs ( p_shaped ) ;
2020-12-01 15:03:31 +02:00
for ( int i = 0 ; i < v_size ; i + + ) {
2020-08-05 09:25:28 +03:00
if ( glyphs [ i ] . count > 0 ) {
2025-04-23 21:44:01 -04:00
// Skip inline objects.
if ( ( glyphs [ i ] . flags & GRAPHEME_IS_EMBEDDED_OBJECT ) = = GRAPHEME_IS_EMBEDDED_OBJECT & & glyphs [ i ] . start = = glyphs [ i ] . end ) {
obj_off = glyphs [ i ] . advance ;
continue ;
}
2020-08-05 09:25:28 +03:00
// Caret before grapheme (top / left).
if ( p_position = = glyphs [ i ] . start & & ( ( glyphs [ i ] . flags & GRAPHEME_IS_VIRTUAL ) ! = GRAPHEME_IS_VIRTUAL ) ) {
2022-10-06 14:30:50 +03:00
real_t advance = 0.f ;
for ( int j = 0 ; j < glyphs [ i ] . count ; j + + ) {
advance + = glyphs [ i + j ] . advance * glyphs [ i + j ] . repeat ;
}
real_t char_adv = advance / ( real_t ) ( glyphs [ i ] . end - glyphs [ i ] . start ) ;
2020-08-05 09:25:28 +03:00
Rect2 cr ;
if ( orientation = = ORIENTATION_HORIZONTAL ) {
if ( glyphs [ i ] . start = = range . x ) {
cr . size . y = height * 2 ;
} else {
cr . size . y = height ;
}
cr . position . y = - ascent ;
cr . position . x = off ;
if ( ( glyphs [ i ] . flags & GRAPHEME_IS_RTL ) = = GRAPHEME_IS_RTL ) {
2021-08-28 00:19:51 +03:00
caret . t_dir = DIRECTION_RTL ;
2022-10-06 14:30:50 +03:00
cr . position . x + = advance ;
cr . size . x = - char_adv ;
2020-08-05 09:25:28 +03:00
} else {
2021-08-28 00:19:51 +03:00
caret . t_dir = DIRECTION_LTR ;
2022-10-06 14:30:50 +03:00
cr . size . x = char_adv ;
2020-08-05 09:25:28 +03:00
}
} else {
if ( glyphs [ i ] . start = = range . x ) {
cr . size . x = height * 2 ;
} else {
cr . size . x = height ;
}
cr . position . x = - ascent ;
cr . position . y = off ;
if ( ( glyphs [ i ] . flags & GRAPHEME_IS_RTL ) = = GRAPHEME_IS_RTL ) {
2021-08-28 00:19:51 +03:00
caret . t_dir = DIRECTION_RTL ;
2022-10-06 14:30:50 +03:00
cr . position . y + = advance ;
cr . size . y = - char_adv ;
2020-08-05 09:25:28 +03:00
} else {
2021-08-28 00:19:51 +03:00
caret . t_dir = DIRECTION_LTR ;
2022-10-06 14:30:50 +03:00
cr . size . y = char_adv ;
2020-08-05 09:25:28 +03:00
}
}
2021-08-28 00:19:51 +03:00
caret . t_caret = cr ;
2020-08-05 09:25:28 +03:00
}
// Caret after grapheme (bottom / right).
if ( p_position = = glyphs [ i ] . end & & ( ( glyphs [ i ] . flags & GRAPHEME_IS_VIRTUAL ) ! = GRAPHEME_IS_VIRTUAL ) ) {
2022-10-06 14:30:50 +03:00
real_t advance = 0.f ;
for ( int j = 0 ; j < glyphs [ i ] . count ; j + + ) {
advance + = glyphs [ i + j ] . advance * glyphs [ i + j ] . repeat ;
}
real_t char_adv = advance / ( real_t ) ( glyphs [ i ] . end - glyphs [ i ] . start ) ;
2020-08-05 09:25:28 +03:00
Rect2 cr ;
if ( orientation = = ORIENTATION_HORIZONTAL ) {
if ( glyphs [ i ] . end = = range . y ) {
cr . size . y = height * 2 ;
cr . position . y = - ascent ;
} else {
cr . size . y = height ;
cr . position . y = - ascent + height ;
}
cr . position . x = off ;
if ( ( glyphs [ i ] . flags & GRAPHEME_IS_RTL ) ! = GRAPHEME_IS_RTL ) {
2021-08-28 00:19:51 +03:00
caret . l_dir = DIRECTION_LTR ;
2022-10-06 14:30:50 +03:00
cr . position . x + = advance ;
cr . size . x = - char_adv ;
2020-08-05 09:25:28 +03:00
} else {
2021-08-28 00:19:51 +03:00
caret . l_dir = DIRECTION_RTL ;
2022-10-06 14:30:50 +03:00
cr . size . x = char_adv ;
2020-08-05 09:25:28 +03:00
}
} else {
cr . size . y = 1.0f ;
if ( glyphs [ i ] . end = = range . y ) {
cr . size . x = height * 2 ;
cr . position . x = - ascent ;
} else {
cr . size . x = height ;
cr . position . x = - ascent + height ;
}
cr . position . y = off ;
if ( ( glyphs [ i ] . flags & GRAPHEME_IS_RTL ) ! = GRAPHEME_IS_RTL ) {
2021-08-28 00:19:51 +03:00
caret . l_dir = DIRECTION_LTR ;
2022-10-06 14:30:50 +03:00
cr . position . y + = advance ;
cr . size . y = - char_adv ;
2020-08-05 09:25:28 +03:00
} else {
2021-08-28 00:19:51 +03:00
caret . l_dir = DIRECTION_RTL ;
2022-10-06 14:30:50 +03:00
cr . position . x + = advance ;
cr . size . y = char_adv ;
2020-08-05 09:25:28 +03:00
}
}
2025-04-23 21:44:01 -04:00
cr . position . x + = MAX ( 0.0 , obj_off ) ; // Prevent split caret when on an inline object.
2021-08-28 00:19:51 +03:00
caret . l_caret = cr ;
2020-08-05 09:25:28 +03:00
}
// Caret inside grapheme (middle).
if ( p_position > glyphs [ i ] . start & & p_position < glyphs [ i ] . end & & ( glyphs [ i ] . flags & GRAPHEME_IS_VIRTUAL ) ! = GRAPHEME_IS_VIRTUAL ) {
2020-12-27 15:30:33 +02:00
real_t advance = 0.f ;
2020-08-05 09:25:28 +03:00
for ( int j = 0 ; j < glyphs [ i ] . count ; j + + ) {
advance + = glyphs [ i + j ] . advance * glyphs [ i + j ] . repeat ;
}
2020-12-27 15:30:33 +02:00
real_t char_adv = advance / ( real_t ) ( glyphs [ i ] . end - glyphs [ i ] . start ) ;
2020-08-05 09:25:28 +03:00
Rect2 cr ;
if ( orientation = = ORIENTATION_HORIZONTAL ) {
cr . size . y = height * 2 ;
cr . position . y = - ascent ;
if ( ( glyphs [ i ] . flags & GRAPHEME_IS_RTL ) = = GRAPHEME_IS_RTL ) {
cr . position . x = off + char_adv * ( glyphs [ i ] . end - p_position ) ;
2022-10-06 14:30:50 +03:00
cr . size . x = - char_adv ;
2020-08-05 09:25:28 +03:00
} else {
cr . position . x = off + char_adv * ( p_position - glyphs [ i ] . start ) ;
2022-10-06 14:30:50 +03:00
cr . size . x = char_adv ;
2020-08-05 09:25:28 +03:00
}
} else {
cr . size . x = height * 2 ;
cr . position . x = - ascent ;
if ( ( glyphs [ i ] . flags & GRAPHEME_IS_RTL ) = = GRAPHEME_IS_RTL ) {
cr . position . y = off + char_adv * ( glyphs [ i ] . end - p_position ) ;
2022-10-06 14:30:50 +03:00
cr . size . y = - char_adv ;
2020-08-05 09:25:28 +03:00
} else {
cr . position . y = off + char_adv * ( p_position - glyphs [ i ] . start ) ;
2022-10-06 14:30:50 +03:00
cr . size . y = char_adv ;
2020-08-05 09:25:28 +03:00
}
}
2021-08-28 00:19:51 +03:00
caret . t_caret = cr ;
caret . l_caret = cr ;
2020-08-05 09:25:28 +03:00
}
}
off + = glyphs [ i ] . advance * glyphs [ i ] . repeat ;
2025-04-23 21:44:01 -04:00
if ( obj_off > = 0.0 ) {
off + = obj_off ;
obj_off = - 1.0 ;
}
2020-08-05 09:25:28 +03:00
}
2021-08-28 00:19:51 +03:00
return caret ;
2020-08-05 09:25:28 +03:00
}
2022-02-13 14:41:29 +02:00
Dictionary TextServer : : _shaped_text_get_carets_wrapper ( const RID & p_shaped , int64_t p_position ) const {
2021-08-28 00:19:51 +03:00
Dictionary ret ;
CaretInfo caret = shaped_text_get_carets ( p_shaped , p_position ) ;
ret [ " leading_rect " ] = caret . l_caret ;
ret [ " leading_direction " ] = caret . l_dir ;
ret [ " trailing_rect " ] = caret . t_caret ;
ret [ " trailing_direction " ] = caret . t_dir ;
return ret ;
}
2020-08-05 09:25:28 +03:00
2022-02-13 14:41:29 +02:00
TextServer : : Direction TextServer : : shaped_text_get_dominant_direction_in_range ( const RID & p_shaped , int64_t p_start , int64_t p_end ) const {
2020-08-05 09:25:28 +03:00
if ( p_start = = p_end ) {
return DIRECTION_AUTO ;
}
int start = MIN ( p_start , p_end ) ;
int end = MAX ( p_start , p_end ) ;
int rtl = 0 ;
int ltr = 0 ;
2021-08-28 00:19:51 +03:00
int v_size = shaped_text_get_glyph_count ( p_shaped ) ;
const Glyph * glyphs = shaped_text_get_glyphs ( p_shaped ) ;
2020-12-01 15:03:31 +02:00
for ( int i = 0 ; i < v_size ; i + + ) {
2020-08-05 09:25:28 +03:00
if ( ( glyphs [ i ] . end > start ) & & ( glyphs [ i ] . start < end ) ) {
if ( glyphs [ i ] . count > 0 ) {
if ( ( glyphs [ i ] . flags & GRAPHEME_IS_RTL ) = = GRAPHEME_IS_RTL ) {
rtl + + ;
} else {
ltr + + ;
}
}
}
}
if ( ltr = = rtl ) {
return DIRECTION_AUTO ;
} else if ( ltr > rtl ) {
return DIRECTION_LTR ;
} else {
return DIRECTION_RTL ;
}
}
2022-04-11 11:37:38 +03:00
_FORCE_INLINE_ void _push_range ( Vector < Vector2 > & r_vector , real_t p_start , real_t p_end ) {
if ( ! r_vector . is_empty ( ) & & Math : : is_equal_approx ( r_vector [ r_vector . size ( ) - 1 ] . y , p_start , ( real_t ) UNIT_EPSILON ) ) {
r_vector . write [ r_vector . size ( ) - 1 ] . y = p_end ;
} else {
r_vector . push_back ( Vector2 ( p_start , p_end ) ) ;
}
}
2022-02-13 14:41:29 +02:00
Vector < Vector2 > TextServer : : shaped_text_get_selection ( const RID & p_shaped , int64_t p_start , int64_t p_end ) const {
2020-08-05 09:25:28 +03:00
Vector < Vector2 > ranges ;
if ( p_start = = p_end ) {
return ranges ;
}
int start = MIN ( p_start , p_end ) ;
int end = MAX ( p_start , p_end ) ;
2021-08-28 00:19:51 +03:00
int v_size = shaped_text_get_glyph_count ( p_shaped ) ;
const Glyph * glyphs = shaped_text_get_glyphs ( p_shaped ) ;
2020-12-01 15:03:31 +02:00
2020-12-27 15:30:33 +02:00
real_t off = 0.0f ;
2020-12-01 15:03:31 +02:00
for ( int i = 0 ; i < v_size ; i + + ) {
2020-08-05 09:25:28 +03:00
for ( int k = 0 ; k < glyphs [ i ] . repeat ; k + + ) {
2020-12-17 23:38:55 +02:00
if ( ( glyphs [ i ] . count > 0 ) & & ( ( glyphs [ i ] . index ! = 0 ) | | ( ( glyphs [ i ] . flags & GRAPHEME_IS_SPACE ) = = GRAPHEME_IS_SPACE ) ) ) {
2020-08-05 09:25:28 +03:00
if ( glyphs [ i ] . start < end & & glyphs [ i ] . end > start ) {
// Grapheme fully in selection range.
if ( glyphs [ i ] . start > = start & & glyphs [ i ] . end < = end ) {
2020-12-27 15:30:33 +02:00
real_t advance = 0.f ;
2020-08-05 09:25:28 +03:00
for ( int j = 0 ; j < glyphs [ i ] . count ; j + + ) {
advance + = glyphs [ i + j ] . advance ;
}
2022-04-11 11:37:38 +03:00
_push_range ( ranges , off , off + advance ) ;
2020-08-05 09:25:28 +03:00
}
// Only start of grapheme is in selection range.
if ( glyphs [ i ] . start > = start & & glyphs [ i ] . end > end ) {
2020-12-27 15:30:33 +02:00
real_t advance = 0.f ;
2020-08-05 09:25:28 +03:00
for ( int j = 0 ; j < glyphs [ i ] . count ; j + + ) {
advance + = glyphs [ i + j ] . advance ;
}
2020-12-27 15:30:33 +02:00
real_t char_adv = advance / ( real_t ) ( glyphs [ i ] . end - glyphs [ i ] . start ) ;
2020-08-05 09:25:28 +03:00
if ( ( glyphs [ i ] . flags & GRAPHEME_IS_RTL ) = = GRAPHEME_IS_RTL ) {
2022-04-11 11:37:38 +03:00
_push_range ( ranges , off + char_adv * ( glyphs [ i ] . end - end ) , off + advance ) ;
2020-08-05 09:25:28 +03:00
} else {
2022-04-11 11:37:38 +03:00
_push_range ( ranges , off , off + char_adv * ( end - glyphs [ i ] . start ) ) ;
2020-08-05 09:25:28 +03:00
}
}
// Only end of grapheme is in selection range.
if ( glyphs [ i ] . start < start & & glyphs [ i ] . end < = end ) {
2020-12-27 15:30:33 +02:00
real_t advance = 0.f ;
2020-08-05 09:25:28 +03:00
for ( int j = 0 ; j < glyphs [ i ] . count ; j + + ) {
advance + = glyphs [ i + j ] . advance ;
}
2020-12-27 15:30:33 +02:00
real_t char_adv = advance / ( real_t ) ( glyphs [ i ] . end - glyphs [ i ] . start ) ;
2020-08-05 09:25:28 +03:00
if ( ( glyphs [ i ] . flags & GRAPHEME_IS_RTL ) = = GRAPHEME_IS_RTL ) {
2022-04-11 11:37:38 +03:00
_push_range ( ranges , off , off + char_adv * ( glyphs [ i ] . end - start ) ) ;
2020-08-05 09:25:28 +03:00
} else {
2022-04-11 11:37:38 +03:00
_push_range ( ranges , off + char_adv * ( start - glyphs [ i ] . start ) , off + advance ) ;
2020-08-05 09:25:28 +03:00
}
}
2021-08-11 00:09:48 +02:00
// Selection range is within grapheme.
2020-08-05 09:25:28 +03:00
if ( glyphs [ i ] . start < start & & glyphs [ i ] . end > end ) {
2020-12-27 15:30:33 +02:00
real_t advance = 0.f ;
2020-08-05 09:25:28 +03:00
for ( int j = 0 ; j < glyphs [ i ] . count ; j + + ) {
advance + = glyphs [ i + j ] . advance ;
}
2020-12-27 15:30:33 +02:00
real_t char_adv = advance / ( real_t ) ( glyphs [ i ] . end - glyphs [ i ] . start ) ;
2020-08-05 09:25:28 +03:00
if ( ( glyphs [ i ] . flags & GRAPHEME_IS_RTL ) = = GRAPHEME_IS_RTL ) {
2022-04-11 11:37:38 +03:00
_push_range ( ranges , off + char_adv * ( glyphs [ i ] . end - end ) , off + char_adv * ( glyphs [ i ] . end - start ) ) ;
2020-08-05 09:25:28 +03:00
} else {
2022-04-11 11:37:38 +03:00
_push_range ( ranges , off + char_adv * ( start - glyphs [ i ] . start ) , off + char_adv * ( end - glyphs [ i ] . start ) ) ;
2020-08-05 09:25:28 +03:00
}
}
}
}
off + = glyphs [ i ] . advance ;
}
}
return ranges ;
}
2022-02-13 14:41:29 +02:00
int64_t TextServer : : shaped_text_hit_test_grapheme ( const RID & p_shaped , double p_coords ) const {
2020-08-05 09:25:28 +03:00
// Exact grapheme hit test, return -1 if missed.
2022-02-13 14:41:29 +02:00
double off = 0.0f ;
2020-12-01 15:03:31 +02:00
2021-08-28 00:19:51 +03:00
int v_size = shaped_text_get_glyph_count ( p_shaped ) ;
const Glyph * glyphs = shaped_text_get_glyphs ( p_shaped ) ;
2020-12-01 15:03:31 +02:00
for ( int i = 0 ; i < v_size ; i + + ) {
2020-08-05 09:25:28 +03:00
for ( int j = 0 ; j < glyphs [ i ] . repeat ; j + + ) {
if ( p_coords > = off & & p_coords < off + glyphs [ i ] . advance ) {
return i ;
}
off + = glyphs [ i ] . advance ;
}
}
return - 1 ;
}
2022-02-13 14:41:29 +02:00
int64_t TextServer : : shaped_text_hit_test_position ( const RID & p_shaped , double p_coords ) const {
2021-08-28 00:19:51 +03:00
int v_size = shaped_text_get_glyph_count ( p_shaped ) ;
const Glyph * glyphs = shaped_text_get_glyphs ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
// Cursor placement hit test.
// Place caret to the left of the leftmost grapheme, or to position 0 if string is empty.
if ( p_coords < = 0 ) {
2020-12-01 15:03:31 +02:00
if ( v_size > 0 ) {
2020-08-05 09:25:28 +03:00
if ( ( glyphs [ 0 ] . flags & GRAPHEME_IS_RTL ) = = GRAPHEME_IS_RTL ) {
return glyphs [ 0 ] . end ;
} else {
return glyphs [ 0 ] . start ;
}
} else {
return 0 ;
}
}
// Place caret to the right of the rightmost grapheme, or to position 0 if string is empty.
if ( p_coords > = shaped_text_get_width ( p_shaped ) ) {
2020-12-01 15:03:31 +02:00
if ( v_size > 0 ) {
if ( ( glyphs [ v_size - 1 ] . flags & GRAPHEME_IS_RTL ) = = GRAPHEME_IS_RTL ) {
return glyphs [ v_size - 1 ] . start ;
2020-08-05 09:25:28 +03:00
} else {
2020-12-01 15:03:31 +02:00
return glyphs [ v_size - 1 ] . end ;
2020-08-05 09:25:28 +03:00
}
} else {
return 0 ;
}
}
2020-12-27 15:30:33 +02:00
real_t off = 0.0f ;
2020-12-01 15:03:31 +02:00
for ( int i = 0 ; i < v_size ; i + + ) {
2020-12-21 11:57:35 +02:00
if ( glyphs [ i ] . count > 0 ) {
2020-12-27 15:30:33 +02:00
real_t advance = 0.f ;
2020-12-21 11:57:35 +02:00
for ( int j = 0 ; j < glyphs [ i ] . count ; j + + ) {
advance + = glyphs [ i + j ] . advance * glyphs [ i + j ] . repeat ;
}
if ( ( ( glyphs [ i ] . flags & GRAPHEME_IS_VIRTUAL ) = = GRAPHEME_IS_VIRTUAL ) & & ( p_coords > = off & & p_coords < off + advance ) ) {
if ( ( glyphs [ i ] . flags & GRAPHEME_IS_RTL ) = = GRAPHEME_IS_RTL ) {
return glyphs [ i ] . end ;
} else {
return glyphs [ i ] . start ;
2020-08-05 09:25:28 +03:00
}
2020-12-21 11:57:35 +02:00
}
2021-11-18 23:36:22 +02:00
// Ligature, handle mid-grapheme hit.
if ( p_coords > = off & & p_coords < off + advance & & glyphs [ i ] . end > glyphs [ i ] . start + 1 ) {
int cnt = glyphs [ i ] . end - glyphs [ i ] . start ;
real_t char_adv = advance / ( real_t ) ( cnt ) ;
real_t sub_off = off ;
for ( int j = 0 ; j < cnt ; j + + ) {
// Place caret to the left of clicked sub-grapheme.
if ( p_coords > = sub_off & & p_coords < sub_off + char_adv / 2 ) {
if ( ( glyphs [ i ] . flags & GRAPHEME_IS_RTL ) = = GRAPHEME_IS_RTL ) {
return glyphs [ i ] . end - j ;
} else {
return glyphs [ i ] . start + j ;
}
}
// Place caret to the right of clicked sub-grapheme.
if ( p_coords > = sub_off + char_adv / 2 & & p_coords < sub_off + char_adv ) {
if ( ( glyphs [ i ] . flags & GRAPHEME_IS_RTL ) = = GRAPHEME_IS_RTL ) {
return glyphs [ i ] . start + ( cnt - 1 ) - j ;
} else {
return glyphs [ i ] . end - ( cnt - 1 ) + j ;
}
}
sub_off + = char_adv ;
}
}
2020-12-21 11:57:35 +02:00
// Place caret to the left of clicked grapheme.
if ( p_coords > = off & & p_coords < off + advance / 2 ) {
if ( ( glyphs [ i ] . flags & GRAPHEME_IS_RTL ) = = GRAPHEME_IS_RTL ) {
return glyphs [ i ] . end ;
} else {
return glyphs [ i ] . start ;
2020-08-05 09:25:28 +03:00
}
2020-12-21 11:57:35 +02:00
}
// Place caret to the right of clicked grapheme.
if ( p_coords > = off + advance / 2 & & p_coords < off + advance ) {
if ( ( glyphs [ i ] . flags & GRAPHEME_IS_RTL ) = = GRAPHEME_IS_RTL ) {
return glyphs [ i ] . start ;
} else {
return glyphs [ i ] . end ;
2020-08-05 09:25:28 +03:00
}
}
}
2020-12-21 11:57:35 +02:00
off + = glyphs [ i ] . advance * glyphs [ i ] . repeat ;
2020-08-05 09:25:28 +03:00
}
return 0 ;
}
2022-02-13 14:41:29 +02:00
Vector2 TextServer : : shaped_text_get_grapheme_bounds ( const RID & p_shaped , int64_t p_pos ) const {
2021-11-18 18:55:43 +03:00
int v_size = shaped_text_get_glyph_count ( p_shaped ) ;
const Glyph * glyphs = shaped_text_get_glyphs ( p_shaped ) ;
real_t off = 0.0f ;
for ( int i = 0 ; i < v_size ; i + + ) {
if ( ( glyphs [ i ] . count > 0 ) & & ( ( glyphs [ i ] . index ! = 0 ) | | ( ( glyphs [ i ] . flags & GRAPHEME_IS_SPACE ) = = GRAPHEME_IS_SPACE ) ) ) {
if ( glyphs [ i ] . start < = p_pos & & glyphs [ i ] . end > = p_pos ) {
real_t advance = 0.f ;
for ( int j = 0 ; j < glyphs [ i ] . count ; j + + ) {
advance + = glyphs [ i + j ] . advance ;
}
return Vector2 ( off , off + advance ) ;
}
}
off + = glyphs [ i ] . advance * glyphs [ i ] . repeat ;
}
return Vector2 ( ) ;
}
2022-02-13 14:41:29 +02:00
int64_t TextServer : : shaped_text_next_grapheme_pos ( const RID & p_shaped , int64_t p_pos ) const {
2021-08-28 00:19:51 +03:00
int v_size = shaped_text_get_glyph_count ( p_shaped ) ;
const Glyph * glyphs = shaped_text_get_glyphs ( p_shaped ) ;
2020-12-01 15:03:31 +02:00
for ( int i = 0 ; i < v_size ; i + + ) {
2020-08-05 09:25:28 +03:00
if ( p_pos > = glyphs [ i ] . start & & p_pos < glyphs [ i ] . end ) {
return glyphs [ i ] . end ;
}
}
return p_pos ;
}
2022-02-13 14:41:29 +02:00
int64_t TextServer : : shaped_text_prev_grapheme_pos ( const RID & p_shaped , int64_t p_pos ) const {
2021-08-28 00:19:51 +03:00
int v_size = shaped_text_get_glyph_count ( p_shaped ) ;
const Glyph * glyphs = shaped_text_get_glyphs ( p_shaped ) ;
2020-12-01 15:03:31 +02:00
for ( int i = 0 ; i < v_size ; i + + ) {
2020-08-05 09:25:28 +03:00
if ( p_pos > glyphs [ i ] . start & & p_pos < = glyphs [ i ] . end ) {
return glyphs [ i ] . start ;
}
}
return p_pos ;
}
2023-08-15 11:42:40 +03:00
int64_t TextServer : : shaped_text_prev_character_pos ( const RID & p_shaped , int64_t p_pos ) const {
const PackedInt32Array & chars = shaped_text_get_character_breaks ( p_shaped ) ;
2024-08-09 00:03:00 +03:00
int64_t prev = shaped_text_get_range ( p_shaped ) . x ;
2023-08-15 11:42:40 +03:00
for ( const int32_t & E : chars ) {
if ( E > = p_pos ) {
return prev ;
}
prev = E ;
}
return prev ;
}
int64_t TextServer : : shaped_text_next_character_pos ( const RID & p_shaped , int64_t p_pos ) const {
const PackedInt32Array & chars = shaped_text_get_character_breaks ( p_shaped ) ;
2024-08-09 00:03:00 +03:00
int64_t prev = shaped_text_get_range ( p_shaped ) . x ;
2023-08-15 11:42:40 +03:00
for ( const int32_t & E : chars ) {
if ( E > p_pos ) {
return E ;
}
prev = E ;
}
return prev ;
}
int64_t TextServer : : shaped_text_closest_character_pos ( const RID & p_shaped , int64_t p_pos ) const {
const PackedInt32Array & chars = shaped_text_get_character_breaks ( p_shaped ) ;
2024-08-09 00:03:00 +03:00
int64_t prev = shaped_text_get_range ( p_shaped ) . x ;
2023-08-15 11:42:40 +03:00
for ( const int32_t & E : chars ) {
if ( E = = p_pos ) {
return E ;
} else if ( E > p_pos ) {
if ( ( E - p_pos ) < ( p_pos - prev ) ) {
return E ;
} else {
return prev ;
}
}
prev = E ;
}
return prev ;
}
PackedInt32Array TextServer : : string_get_character_breaks ( const String & p_string , const String & p_language ) const {
PackedInt32Array ret ;
2023-08-19 11:19:09 +03:00
if ( ! p_string . is_empty ( ) ) {
ret . resize ( p_string . size ( ) - 1 ) ;
for ( int i = 0 ; i < p_string . size ( ) - 1 ; i + + ) {
ret . write [ i ] = i + 1 ;
}
2023-08-15 11:42:40 +03:00
}
return ret ;
}
2025-03-30 14:20:25 +03:00
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 , float p_oversampling ) const {
2020-08-05 09:25:28 +03:00
TextServer : : Orientation orientation = shaped_text_get_orientation ( p_shaped ) ;
bool hex_codes = shaped_text_get_preserve_control ( p_shaped ) | | shaped_text_get_preserve_invalid ( p_shaped ) ;
2021-08-11 00:09:48 +02:00
bool rtl = shaped_text_get_direction ( p_shaped ) = = DIRECTION_RTL ;
2021-08-28 00:19:51 +03:00
int ellipsis_pos = shaped_text_get_ellipsis_pos ( p_shaped ) ;
int trim_pos = shaped_text_get_trim_pos ( p_shaped ) ;
const Glyph * ellipsis_glyphs = shaped_text_get_ellipsis_glyphs ( p_shaped ) ;
int ellipsis_gl_size = shaped_text_get_ellipsis_glyph_count ( p_shaped ) ;
int v_size = shaped_text_get_glyph_count ( p_shaped ) ;
const Glyph * glyphs = shaped_text_get_glyphs ( p_shaped ) ;
2020-12-01 15:03:31 +02:00
2024-01-18 15:31:48 +02:00
Vector2 ofs ;
2021-08-11 00:09:48 +02:00
// Draw RTL ellipsis string when needed.
2021-08-28 00:19:51 +03:00
if ( rtl & & ellipsis_pos > = 0 ) {
for ( int i = ellipsis_gl_size - 1 ; i > = 0 ; i - - ) {
for ( int j = 0 ; j < ellipsis_glyphs [ i ] . repeat ; j + + ) {
2025-03-30 14:20:25 +03:00
font_draw_glyph ( ellipsis_glyphs [ i ] . font_rid , p_canvas , ellipsis_glyphs [ i ] . font_size , ofs + p_pos + Vector2 ( ellipsis_glyphs [ i ] . x_off , ellipsis_glyphs [ i ] . y_off ) , ellipsis_glyphs [ i ] . index , p_color , p_oversampling ) ;
2021-08-11 00:09:48 +02:00
if ( orientation = = ORIENTATION_HORIZONTAL ) {
2021-08-28 00:19:51 +03:00
ofs . x + = ellipsis_glyphs [ i ] . advance ;
2021-08-11 00:09:48 +02:00
} else {
2021-08-28 00:19:51 +03:00
ofs . y + = ellipsis_glyphs [ i ] . advance ;
2021-08-11 00:09:48 +02:00
}
}
}
}
2020-08-05 09:25:28 +03:00
// Draw at the baseline.
2020-12-01 15:03:31 +02:00
for ( int i = 0 ; i < v_size ; i + + ) {
2022-01-10 17:24:03 +02:00
if ( trim_pos > = 0 ) {
if ( rtl ) {
if ( i < trim_pos ) {
continue ;
}
} else {
if ( i > = trim_pos ) {
break ;
}
}
}
2020-08-05 09:25:28 +03:00
for ( int j = 0 ; j < glyphs [ i ] . repeat ; j + + ) {
if ( p_clip_r > 0 ) {
// Clip right / bottom.
if ( orientation = = ORIENTATION_HORIZONTAL ) {
2024-01-18 15:31:48 +02:00
if ( ofs . x + glyphs [ i ] . advance > p_clip_r ) {
2020-08-05 09:25:28 +03:00
return ;
}
} else {
2024-01-18 15:31:48 +02:00
if ( ofs . y + glyphs [ i ] . advance > p_clip_r ) {
2020-08-05 09:25:28 +03:00
return ;
}
}
}
if ( p_clip_l > 0 ) {
// Clip left / top.
if ( orientation = = ORIENTATION_HORIZONTAL ) {
2024-01-18 15:31:48 +02:00
if ( ofs . x < p_clip_l ) {
2020-08-05 09:25:28 +03:00
ofs . x + = glyphs [ i ] . advance ;
continue ;
}
} else {
2024-01-18 15:31:48 +02:00
if ( ofs . y < p_clip_l ) {
2020-08-05 09:25:28 +03:00
ofs . y + = glyphs [ i ] . advance ;
continue ;
}
}
}
2021-08-11 00:09:48 +02:00
2020-08-05 09:25:28 +03:00
if ( glyphs [ i ] . font_rid ! = RID ( ) ) {
2025-03-30 14:20:25 +03:00
font_draw_glyph ( glyphs [ i ] . font_rid , p_canvas , glyphs [ i ] . font_size , ofs + p_pos + Vector2 ( glyphs [ i ] . x_off , glyphs [ i ] . y_off ) , glyphs [ i ] . index , p_color , p_oversampling ) ;
2023-04-12 10:08:51 +03:00
} else if ( hex_codes & & ( ( glyphs [ i ] . flags & GRAPHEME_IS_VIRTUAL ) ! = GRAPHEME_IS_VIRTUAL ) & & ( ( glyphs [ i ] . flags & GRAPHEME_IS_EMBEDDED_OBJECT ) ! = GRAPHEME_IS_EMBEDDED_OBJECT ) ) {
2024-01-18 15:31:48 +02:00
TextServer : : draw_hex_code_box ( p_canvas , glyphs [ i ] . font_size , ofs + p_pos + Vector2 ( glyphs [ i ] . x_off , glyphs [ i ] . y_off ) , glyphs [ i ] . index , p_color ) ;
2020-08-05 09:25:28 +03:00
}
if ( orientation = = ORIENTATION_HORIZONTAL ) {
ofs . x + = glyphs [ i ] . advance ;
} else {
ofs . y + = glyphs [ i ] . advance ;
}
}
}
2021-08-11 00:09:48 +02:00
// Draw LTR ellipsis string when needed.
2021-08-28 00:19:51 +03:00
if ( ! rtl & & ellipsis_pos > = 0 ) {
for ( int i = 0 ; i < ellipsis_gl_size ; i + + ) {
for ( int j = 0 ; j < ellipsis_glyphs [ i ] . repeat ; j + + ) {
2025-03-30 14:20:25 +03:00
font_draw_glyph ( ellipsis_glyphs [ i ] . font_rid , p_canvas , ellipsis_glyphs [ i ] . font_size , ofs + p_pos + Vector2 ( ellipsis_glyphs [ i ] . x_off , ellipsis_glyphs [ i ] . y_off ) , ellipsis_glyphs [ i ] . index , p_color , p_oversampling ) ;
2021-08-11 00:09:48 +02:00
if ( orientation = = ORIENTATION_HORIZONTAL ) {
2021-08-28 00:19:51 +03:00
ofs . x + = ellipsis_glyphs [ i ] . advance ;
2021-08-11 00:09:48 +02:00
} else {
2021-08-28 00:19:51 +03:00
ofs . y + = ellipsis_glyphs [ i ] . advance ;
2021-08-11 00:09:48 +02:00
}
}
}
}
2020-08-05 09:25:28 +03:00
}
2025-03-30 14:20:25 +03:00
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 , float p_oversampling ) const {
2020-08-05 09:25:28 +03:00
TextServer : : Orientation orientation = shaped_text_get_orientation ( p_shaped ) ;
2022-01-10 17:24:03 +02:00
bool rtl = ( shaped_text_get_inferred_direction ( p_shaped ) = = DIRECTION_RTL ) ;
2021-08-11 00:09:48 +02:00
2021-08-28 00:19:51 +03:00
int ellipsis_pos = shaped_text_get_ellipsis_pos ( p_shaped ) ;
int trim_pos = shaped_text_get_trim_pos ( p_shaped ) ;
const Glyph * ellipsis_glyphs = shaped_text_get_ellipsis_glyphs ( p_shaped ) ;
int ellipsis_gl_size = shaped_text_get_ellipsis_glyph_count ( p_shaped ) ;
int v_size = shaped_text_get_glyph_count ( p_shaped ) ;
const Glyph * glyphs = shaped_text_get_glyphs ( p_shaped ) ;
2024-01-18 15:31:48 +02:00
Vector2 ofs ;
2021-08-11 00:09:48 +02:00
// Draw RTL ellipsis string when needed.
2021-08-28 00:19:51 +03:00
if ( rtl & & ellipsis_pos > = 0 ) {
for ( int i = ellipsis_gl_size - 1 ; i > = 0 ; i - - ) {
for ( int j = 0 ; j < ellipsis_glyphs [ i ] . repeat ; j + + ) {
2025-03-30 14:20:25 +03:00
font_draw_glyph_outline ( ellipsis_glyphs [ i ] . font_rid , p_canvas , ellipsis_glyphs [ i ] . font_size , p_outline_size , ofs + p_pos + Vector2 ( ellipsis_glyphs [ i ] . x_off , ellipsis_glyphs [ i ] . y_off ) , ellipsis_glyphs [ i ] . index , p_color , p_oversampling ) ;
2021-08-11 00:09:48 +02:00
if ( orientation = = ORIENTATION_HORIZONTAL ) {
2021-08-28 00:19:51 +03:00
ofs . x + = ellipsis_glyphs [ i ] . advance ;
2021-08-11 00:09:48 +02:00
} else {
2021-08-28 00:19:51 +03:00
ofs . y + = ellipsis_glyphs [ i ] . advance ;
2021-08-11 00:09:48 +02:00
}
}
}
}
2020-08-05 09:25:28 +03:00
// Draw at the baseline.
2020-12-01 15:03:31 +02:00
for ( int i = 0 ; i < v_size ; i + + ) {
2022-01-10 17:24:03 +02:00
if ( trim_pos > = 0 ) {
if ( rtl ) {
if ( i < trim_pos ) {
continue ;
}
} else {
if ( i > = trim_pos ) {
break ;
}
}
}
2020-08-05 09:25:28 +03:00
for ( int j = 0 ; j < glyphs [ i ] . repeat ; j + + ) {
if ( p_clip_r > 0 ) {
// Clip right / bottom.
if ( orientation = = ORIENTATION_HORIZONTAL ) {
2024-01-18 15:31:48 +02:00
if ( ofs . x + glyphs [ i ] . advance > p_clip_r ) {
2020-08-05 09:25:28 +03:00
return ;
}
} else {
2024-01-18 15:31:48 +02:00
if ( ofs . y + glyphs [ i ] . advance > p_clip_r ) {
2020-08-05 09:25:28 +03:00
return ;
}
}
}
if ( p_clip_l > 0 ) {
// Clip left / top.
if ( orientation = = ORIENTATION_HORIZONTAL ) {
2024-01-18 15:31:48 +02:00
if ( ofs . x < p_clip_l ) {
2020-08-05 09:25:28 +03:00
ofs . x + = glyphs [ i ] . advance ;
continue ;
}
} else {
2024-01-18 15:31:48 +02:00
if ( ofs . y < p_clip_l ) {
2020-08-05 09:25:28 +03:00
ofs . y + = glyphs [ i ] . advance ;
continue ;
}
}
}
if ( glyphs [ i ] . font_rid ! = RID ( ) ) {
2025-03-30 14:20:25 +03:00
font_draw_glyph_outline ( glyphs [ i ] . font_rid , p_canvas , glyphs [ i ] . font_size , p_outline_size , ofs + p_pos + Vector2 ( glyphs [ i ] . x_off , glyphs [ i ] . y_off ) , glyphs [ i ] . index , p_color , p_oversampling ) ;
2020-08-05 09:25:28 +03:00
}
if ( orientation = = ORIENTATION_HORIZONTAL ) {
ofs . x + = glyphs [ i ] . advance ;
} else {
ofs . y + = glyphs [ i ] . advance ;
}
}
}
2021-08-11 00:09:48 +02:00
// Draw LTR ellipsis string when needed.
2021-08-28 00:19:51 +03:00
if ( ! rtl & & ellipsis_pos > = 0 ) {
for ( int i = 0 ; i < ellipsis_gl_size ; i + + ) {
for ( int j = 0 ; j < ellipsis_glyphs [ i ] . repeat ; j + + ) {
2025-03-30 14:20:25 +03:00
font_draw_glyph_outline ( ellipsis_glyphs [ i ] . font_rid , p_canvas , ellipsis_glyphs [ i ] . font_size , p_outline_size , ofs + p_pos + Vector2 ( ellipsis_glyphs [ i ] . x_off , ellipsis_glyphs [ i ] . y_off ) , ellipsis_glyphs [ i ] . index , p_color , p_oversampling ) ;
2021-08-11 00:09:48 +02:00
if ( orientation = = ORIENTATION_HORIZONTAL ) {
2021-08-28 00:19:51 +03:00
ofs . x + = ellipsis_glyphs [ i ] . advance ;
2021-08-11 00:09:48 +02:00
} else {
2021-08-28 00:19:51 +03:00
ofs . y + = ellipsis_glyphs [ i ] . advance ;
2021-08-11 00:09:48 +02:00
}
}
}
}
2020-08-05 09:25:28 +03:00
}
2024-11-21 10:57:07 +02:00
# ifdef DEBUG_ENABLED
void TextServer : : debug_print_glyph ( int p_idx , const Glyph & p_glyph ) const {
String flags ;
if ( p_glyph . flags & GRAPHEME_IS_VALID ) {
flags + = " v " ;
}
if ( p_glyph . flags & GRAPHEME_IS_RTL ) {
flags + = " R " ;
}
if ( p_glyph . flags & GRAPHEME_IS_VIRTUAL ) {
flags + = " V " ;
}
if ( p_glyph . flags & GRAPHEME_IS_SPACE ) {
flags + = " w " ;
}
if ( p_glyph . flags & GRAPHEME_IS_BREAK_HARD ) {
flags + = " h " ;
}
if ( p_glyph . flags & GRAPHEME_IS_BREAK_SOFT ) {
flags + = " s " ;
}
if ( p_glyph . flags & GRAPHEME_IS_TAB ) {
flags + = " t " ;
}
if ( p_glyph . flags & GRAPHEME_IS_ELONGATION ) {
flags + = " e " ;
}
if ( p_glyph . flags & GRAPHEME_IS_PUNCTUATION ) {
flags + = " p " ;
}
if ( p_glyph . flags & GRAPHEME_IS_UNDERSCORE ) {
flags + = " u " ;
}
if ( p_glyph . flags & GRAPHEME_IS_CONNECTED ) {
flags + = " C " ;
}
if ( p_glyph . flags & GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL ) {
flags + = " S " ;
}
if ( p_glyph . flags & GRAPHEME_IS_EMBEDDED_OBJECT ) {
flags + = " E " ;
}
if ( p_glyph . flags & GRAPHEME_IS_SOFT_HYPHEN ) {
flags + = " h " ;
}
print_line ( vformat ( " %d => range: %d-%d cnt:%d index:%x font:%x(%d) offset:%fx%f adv:%f rep:%d flags:%s " , p_idx , p_glyph . start , p_glyph . end , p_glyph . count , p_glyph . index , p_glyph . font_rid . get_id ( ) , p_glyph . font_size , p_glyph . x_off , p_glyph . y_off , p_glyph . advance , p_glyph . repeat , flags ) ) ;
}
void TextServer : : shaped_text_debug_print ( const RID & p_shaped ) const {
int ellipsis_pos = shaped_text_get_ellipsis_pos ( p_shaped ) ;
int trim_pos = shaped_text_get_trim_pos ( p_shaped ) ;
const Vector2i & range = shaped_text_get_range ( p_shaped ) ;
int v_size = shaped_text_get_glyph_count ( p_shaped ) ;
const Glyph * glyphs = shaped_text_get_glyphs ( p_shaped ) ;
print_line ( vformat ( " %x: range: %d-%d glyps: %d trim: %d ellipsis: %d " , p_shaped . get_id ( ) , range . x , range . y , v_size , trim_pos , ellipsis_pos ) ) ;
for ( int i = 0 ; i < v_size ; i + + ) {
debug_print_glyph ( i , glyphs [ i ] ) ;
}
}
# endif // DEBUG_ENABLED
2021-10-12 21:36:08 +03:00
void TextServer : : _diacritics_map_add ( const String & p_from , char32_t p_to ) {
for ( int i = 0 ; i < p_from . size ( ) ; i + + ) {
diacritics_map [ p_from [ i ] ] = p_to ;
}
}
void TextServer : : _init_diacritics_map ( ) {
diacritics_map . clear ( ) ;
// Latin.
_diacritics_map_add ( U " ÀÁÂÃÄÅĀĂĄǍǞǠǺȀȂȦḀẠẢẤẦẨẪẬẮẰẲẴẶ " , U ' A ' ) ;
_diacritics_map_add ( U " àáâãäåāăąǎǟǡǻȁȃȧḁẚạảấầẩẫậắằẳẵặ " , U ' a ' ) ;
_diacritics_map_add ( U " ǢǼ " , U ' Æ ' ) ;
_diacritics_map_add ( U " ǣǽ " , U ' æ ' ) ;
_diacritics_map_add ( U " ḂḄḆ " , U ' B ' ) ;
_diacritics_map_add ( U " ḃḅḇ " , U ' b ' ) ;
_diacritics_map_add ( U " ÇĆĈĊČḈ " , U ' C ' ) ;
_diacritics_map_add ( U " çćĉċčḉ " , U ' c ' ) ;
_diacritics_map_add ( U " ĎḊḌḎḐḒ " , U ' D ' ) ;
_diacritics_map_add ( U " ďḋḍḏḑḓ " , U ' d ' ) ;
_diacritics_map_add ( U " ÈÉÊËĒĔĖĘĚȆȨḔḖḘḚḜẸẺẼẾỀỂỄỆ " , U ' E ' ) ;
_diacritics_map_add ( U " èéêëēĕėęěȇȩḕḗḙḛḝẹẻẽếềểễệ " , U ' e ' ) ;
_diacritics_map_add ( U " Ḟ " , U ' F ' ) ;
_diacritics_map_add ( U " ḟ " , U ' f ' ) ;
_diacritics_map_add ( U " ĜĞĠĢǦǴḠ " , U ' G ' ) ;
_diacritics_map_add ( U " ĝğġģǧǵḡ " , U ' g ' ) ;
_diacritics_map_add ( U " ĤȞḢḤḦḨḪ " , U ' H ' ) ;
_diacritics_map_add ( U " ĥȟḣḥḧḩḫẖ " , U ' h ' ) ;
_diacritics_map_add ( U " ÌÍÎÏĨĪĬĮİǏȈȊḬḮỈỊ " , U ' I ' ) ;
_diacritics_map_add ( U " ìíîïĩīĭįıǐȉȋḭḯỉị " , U ' i ' ) ;
_diacritics_map_add ( U " Ĵ " , U ' J ' ) ;
_diacritics_map_add ( U " ĵ " , U ' j ' ) ;
_diacritics_map_add ( U " ĶǨḰḲḴ " , U ' K ' ) ;
_diacritics_map_add ( U " ķĸǩḱḳḵ " , U ' k ' ) ;
_diacritics_map_add ( U " ĹĻĽĿḶḸḺḼ " , U ' L ' ) ;
_diacritics_map_add ( U " ĺļľŀḷḹḻḽ " , U ' l ' ) ;
_diacritics_map_add ( U " ḾṀṂ " , U ' M ' ) ;
_diacritics_map_add ( U " ḿṁṃ " , U ' m ' ) ;
_diacritics_map_add ( U " ÑŃŅŇǸṄṆṈṊ " , U ' N ' ) ;
_diacritics_map_add ( U " ñńņňʼnǹṅṇṉṋ " , U ' n ' ) ;
_diacritics_map_add ( U " ÒÓÔÕÖŌŎŐƠǑǪǬȌȎȪȬȮȰṌṎṐṒỌỎỐỒỔỖỘỚỜỞỠỢ " , U ' O ' ) ;
_diacritics_map_add ( U " òóôõöōŏőơǒǫǭȍȏȫȭȯȱṍṏṑṓọỏốồổỗộớờởỡợ " , U ' o ' ) ;
_diacritics_map_add ( U " ṔṖ " , U ' P ' ) ;
_diacritics_map_add ( U " ṗṕ " , U ' p ' ) ;
_diacritics_map_add ( U " ŔŖŘȐȒṘṚṜṞ " , U ' R ' ) ;
_diacritics_map_add ( U " ŕŗřȑȓṙṛṝṟ " , U ' r ' ) ;
_diacritics_map_add ( U " ŚŜŞŠȘṠṢṤṦṨ " , U ' S ' ) ;
_diacritics_map_add ( U " śŝşšſșṡṣṥṧṩẛẜẝ " , U ' s ' ) ;
_diacritics_map_add ( U " ŢŤȚṪṬṮṰ " , U ' T ' ) ;
_diacritics_map_add ( U " ţťțṫṭṯṱẗ " , U ' t ' ) ;
_diacritics_map_add ( U " ÙÚÛÜŨŪŬŮŰŲƯǓǕǗǙǛȔȖṲṴṶṸṺỤỦỨỪỬỮỰ " , U ' U ' ) ;
_diacritics_map_add ( U " ùúûüũūŭůűųưǔǖǘǚǜȕȗṳṵṷṹṻụủứừửữự " , U ' u ' ) ;
_diacritics_map_add ( U " ṼṾ " , U ' V ' ) ;
_diacritics_map_add ( U " ṽṿ " , U ' v ' ) ;
_diacritics_map_add ( U " ŴẀẂẄẆẈ " , U ' W ' ) ;
_diacritics_map_add ( U " ŵẁẃẅẇẉẘ " , U ' w ' ) ;
_diacritics_map_add ( U " ẊẌ " , U ' X ' ) ;
_diacritics_map_add ( U " ẋẍ " , U ' x ' ) ;
_diacritics_map_add ( U " ÝŶẎỲỴỶỸỾ " , U ' Y ' ) ;
_diacritics_map_add ( U " ýÿŷẏẙỳỵỷỹỿ " , U ' y ' ) ;
_diacritics_map_add ( U " ŹŻŽẐẒẔ " , U ' Z ' ) ;
_diacritics_map_add ( U " źżžẑẓẕ " , U ' z ' ) ;
// Greek.
_diacritics_map_add ( U " ΆἈἉἊἋἌἍἎἏᾈᾉᾊᾋᾌᾍᾎᾏᾸᾹᾺΆᾼ " , U ' Α ' ) ;
_diacritics_map_add ( U " άἀἁἂἃἄἅἆἇὰάᾀᾁᾂᾃᾄᾅᾆᾇᾰᾱᾲᾳᾴᾶᾷ " , U ' α ' ) ;
_diacritics_map_add ( U " ΈἘἙἚἛἜἝῈΈ " , U ' Ε ' ) ;
_diacritics_map_add ( U " έἐἑἒἓἔἕὲέ " , U ' ε ' ) ;
_diacritics_map_add ( U " ΉἨἩἪἫἬἭἮἯᾘᾙᾚᾛᾜᾝᾞᾟῊΉῌ " , U ' Η ' ) ;
_diacritics_map_add ( U " ήἠἡἢἣἤἥἦἧὴήᾐᾑᾒᾓᾔᾕᾖᾗῂῃῄῆῇ " , U ' η ' ) ;
_diacritics_map_add ( U " ΊΪἸἹἺἻἼἽἾἿῘῙῚΊ " , U ' Ι ' ) ;
_diacritics_map_add ( U " ίΐϊἰἱἲἳἴἵἶἷὶίῐῑῒΐῖῗ " , U ' ι ' ) ;
_diacritics_map_add ( U " ΌὈὉὊὋὌὍῸΌ " , U ' Ο ' ) ;
_diacritics_map_add ( U " όὀὁὂὃὄὅὸό " , U ' ο ' ) ;
_diacritics_map_add ( U " Ῥ " , U ' Ρ ' ) ;
_diacritics_map_add ( U " ῤῥ " , U ' ρ ' ) ;
_diacritics_map_add ( U " ΎΫϓϔὙὛὝὟῨῩῪΎ " , U ' Υ ' ) ;
_diacritics_map_add ( U " ΰϋύὐὑὒὓὔὕὖὗὺύῠῡῢΰῦῧ " , U ' υ ' ) ;
_diacritics_map_add ( U " ΏὨὩὪὫὬὭὮὯᾨᾩᾪᾫᾬᾭᾮᾯῺΏῼ " , U ' Ω ' ) ;
_diacritics_map_add ( U " ώὠὡὢὣὤὥὦὧὼώᾠᾡᾢᾣᾤᾥᾦᾧῲῳῴῶῷ " , U ' ω ' ) ;
// Cyrillic.
_diacritics_map_add ( U " ӐӒ " , U ' А ' ) ;
_diacritics_map_add ( U " ӑӓ " , U ' а ' ) ;
_diacritics_map_add ( U " ЀЁӖ " , U ' Е ' ) ;
_diacritics_map_add ( U " ѐёӗ " , U ' е ' ) ;
_diacritics_map_add ( U " Ӛ " , U ' Ә ' ) ;
_diacritics_map_add ( U " ӛ " , U ' ә ' ) ;
_diacritics_map_add ( U " Ӝ " , U ' Ж ' ) ;
_diacritics_map_add ( U " ӝ " , U ' ж ' ) ;
_diacritics_map_add ( U " Ӟ " , U ' З ' ) ;
_diacritics_map_add ( U " ӟ " , U ' з ' ) ;
_diacritics_map_add ( U " Ѓ " , U ' Г ' ) ;
_diacritics_map_add ( U " ѓ " , U ' г ' ) ;
_diacritics_map_add ( U " Ї " , U ' І ' ) ;
_diacritics_map_add ( U " ї " , U ' і ' ) ;
_diacritics_map_add ( U " ЍӢӤЙ " , U ' И ' ) ;
_diacritics_map_add ( U " ѝӣӥй " , U ' и ' ) ;
_diacritics_map_add ( U " Ќ " , U ' К ' ) ;
_diacritics_map_add ( U " ќ " , U ' к ' ) ;
_diacritics_map_add ( U " Ӧ " , U ' О ' ) ;
_diacritics_map_add ( U " ӧ " , U ' о ' ) ;
_diacritics_map_add ( U " Ӫ " , U ' Ө ' ) ;
_diacritics_map_add ( U " ӫ " , U ' ө ' ) ;
_diacritics_map_add ( U " Ӭ " , U ' Э ' ) ;
_diacritics_map_add ( U " ӭ " , U ' э ' ) ;
_diacritics_map_add ( U " ЎӮӰӲ " , U ' У ' ) ;
_diacritics_map_add ( U " ўӯӱӳ " , U ' у ' ) ;
_diacritics_map_add ( U " Ӵ " , U ' Ч ' ) ;
_diacritics_map_add ( U " ӵ " , U ' ч ' ) ;
_diacritics_map_add ( U " Ӹ " , U ' Ы ' ) ;
_diacritics_map_add ( U " ӹ " , U ' ы ' ) ;
}
String TextServer : : strip_diacritics ( const String & p_string ) const {
String result ;
for ( int i = 0 ; i < p_string . length ( ) ; i + + ) {
if ( p_string [ i ] < 0x02B0 | | p_string [ i ] > 0x036F ) { // Skip combining diacritics.
if ( diacritics_map . has ( p_string [ i ] ) ) {
result + = diacritics_map [ p_string [ i ] ] ;
} else {
result + = p_string [ i ] ;
}
}
}
return result ;
}
2023-01-18 09:33:35 +02:00
TypedArray < Vector3i > TextServer : : parse_structured_text ( StructuredTextParser p_parser_type , const Array & p_args , const String & p_text ) const {
TypedArray < Vector3i > ret ;
2022-04-19 13:27:18 +03:00
switch ( p_parser_type ) {
case STRUCTURED_TEXT_URI : {
int prev = 0 ;
for ( int i = 0 ; i < p_text . length ( ) ; i + + ) {
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 ] = = ' # ' ) ) {
if ( prev ! = i ) {
2023-01-18 09:33:35 +02:00
ret . push_back ( Vector3i ( prev , i , TextServer : : DIRECTION_AUTO ) ) ;
2022-04-19 13:27:18 +03:00
}
2023-01-18 09:33:35 +02:00
ret . push_back ( Vector3i ( i , i + 1 , TextServer : : DIRECTION_LTR ) ) ;
2022-04-19 13:27:18 +03:00
prev = i + 1 ;
}
}
if ( prev ! = p_text . length ( ) ) {
2023-01-18 09:33:35 +02:00
ret . push_back ( Vector3i ( prev , p_text . length ( ) , TextServer : : DIRECTION_AUTO ) ) ;
2022-04-19 13:27:18 +03:00
}
} break ;
case STRUCTURED_TEXT_FILE : {
int prev = 0 ;
for ( int i = 0 ; i < p_text . length ( ) ; i + + ) {
if ( ( p_text [ i ] = = ' \\ ' ) | | ( p_text [ i ] = = ' / ' ) | | ( p_text [ i ] = = ' : ' ) ) {
if ( prev ! = i ) {
2023-01-18 09:33:35 +02:00
ret . push_back ( Vector3i ( prev , i , TextServer : : DIRECTION_AUTO ) ) ;
2022-04-19 13:27:18 +03:00
}
2023-01-18 09:33:35 +02:00
ret . push_back ( Vector3i ( i , i + 1 , TextServer : : DIRECTION_LTR ) ) ;
2022-04-19 13:27:18 +03:00
prev = i + 1 ;
}
}
if ( prev ! = p_text . length ( ) ) {
2023-01-18 09:33:35 +02:00
ret . push_back ( Vector3i ( prev , p_text . length ( ) , TextServer : : DIRECTION_AUTO ) ) ;
2022-04-19 13:27:18 +03:00
}
} break ;
case STRUCTURED_TEXT_EMAIL : {
bool local = true ;
int prev = 0 ;
for ( int i = 0 ; i < p_text . length ( ) ; i + + ) {
if ( ( p_text [ i ] = = ' @ ' ) & & local ) { // Add full "local" as single context.
local = false ;
2023-01-18 09:33:35 +02:00
ret . push_back ( Vector3i ( prev , i , TextServer : : DIRECTION_AUTO ) ) ;
ret . push_back ( Vector3i ( i , i + 1 , TextServer : : DIRECTION_LTR ) ) ;
2022-04-19 13:27:18 +03:00
prev = i + 1 ;
2022-08-12 23:14:40 -06:00
} else if ( ! local & & ( p_text [ i ] = = ' . ' ) ) { // Add each dot separated "domain" part as context.
2022-04-19 13:27:18 +03:00
if ( prev ! = i ) {
2023-01-18 09:33:35 +02:00
ret . push_back ( Vector3i ( prev , i , TextServer : : DIRECTION_AUTO ) ) ;
2022-04-19 13:27:18 +03:00
}
2023-01-18 09:33:35 +02:00
ret . push_back ( Vector3i ( i , i + 1 , TextServer : : DIRECTION_LTR ) ) ;
2022-04-19 13:27:18 +03:00
prev = i + 1 ;
}
}
if ( prev ! = p_text . length ( ) ) {
2023-01-18 09:33:35 +02:00
ret . push_back ( Vector3i ( prev , p_text . length ( ) , TextServer : : DIRECTION_AUTO ) ) ;
2022-04-19 13:27:18 +03:00
}
} break ;
case STRUCTURED_TEXT_LIST : {
2023-12-28 14:44:23 -08:00
if ( p_args . size ( ) = = 1 & & p_args [ 0 ] . is_string ( ) ) {
2022-04-19 13:27:18 +03:00
Vector < String > tags = p_text . split ( String ( p_args [ 0 ] ) ) ;
int prev = 0 ;
for ( int i = 0 ; i < tags . size ( ) ; i + + ) {
if ( prev ! = i ) {
2023-01-18 09:33:35 +02:00
ret . push_back ( Vector3i ( prev , prev + tags [ i ] . length ( ) , TextServer : : DIRECTION_INHERITED ) ) ;
2022-04-19 13:27:18 +03:00
}
2023-01-18 09:33:35 +02:00
ret . push_back ( Vector3i ( prev + tags [ i ] . length ( ) , prev + tags [ i ] . length ( ) + 1 , TextServer : : DIRECTION_INHERITED ) ) ;
2022-04-19 13:27:18 +03:00
prev = prev + tags [ i ] . length ( ) + 1 ;
}
}
} break ;
2023-01-18 09:33:35 +02:00
case STRUCTURED_TEXT_GDSCRIPT : {
bool in_string_literal = false ;
bool in_string_literal_single = false ;
bool in_id = false ;
int prev = 0 ;
for ( int i = 0 ; i < p_text . length ( ) ; i + + ) {
char32_t c = p_text [ i ] ;
if ( in_string_literal ) {
if ( c = = ' \\ ' ) {
i + + ;
continue ; // Skip escaped chars.
} else if ( c = = ' \" ' ) {
// String literal end, push string and ".
if ( prev ! = i ) {
ret . push_back ( Vector3i ( prev , i , TextServer : : DIRECTION_AUTO ) ) ;
}
prev = i + 1 ;
ret . push_back ( Vector3i ( i , i + 1 , TextServer : : DIRECTION_LTR ) ) ;
in_string_literal = false ;
}
} else if ( in_string_literal_single ) {
if ( c = = ' \\ ' ) {
i + + ;
continue ; // Skip escaped chars.
} else if ( c = = ' \' ' ) {
// String literal end, push string and '.
if ( prev ! = i ) {
ret . push_back ( Vector3i ( prev , i , TextServer : : DIRECTION_AUTO ) ) ;
}
prev = i + 1 ;
ret . push_back ( Vector3i ( i , i + 1 , TextServer : : DIRECTION_LTR ) ) ;
in_string_literal_single = false ;
}
} else if ( in_id ) {
if ( ! is_unicode_identifier_continue ( c ) ) {
// End of id, push id.
if ( prev ! = i ) {
ret . push_back ( Vector3i ( prev , i , TextServer : : DIRECTION_AUTO ) ) ;
}
prev = i ;
in_id = false ;
}
} else if ( is_unicode_identifier_start ( c ) ) {
// Start of new id, push prev element.
if ( prev ! = i ) {
ret . push_back ( Vector3i ( prev , i , TextServer : : DIRECTION_AUTO ) ) ;
}
prev = i ;
in_id = true ;
} else if ( c = = ' \" ' ) {
// String literal start, push prev element and ".
if ( prev ! = i ) {
ret . push_back ( Vector3i ( prev , i , TextServer : : DIRECTION_AUTO ) ) ;
}
prev = i + 1 ;
ret . push_back ( Vector3i ( i , i + 1 , TextServer : : DIRECTION_LTR ) ) ;
in_string_literal = true ;
} else if ( c = = ' \' ' ) {
// String literal start, push prev element and '.
if ( prev ! = i ) {
ret . push_back ( Vector3i ( prev , i , TextServer : : DIRECTION_AUTO ) ) ;
}
prev = i + 1 ;
ret . push_back ( Vector3i ( i , i + 1 , TextServer : : DIRECTION_LTR ) ) ;
in_string_literal_single = true ;
} else if ( c = = ' # ' ) {
// Start of comment, push prev element and #, skip the rest of the text.
if ( prev ! = i ) {
ret . push_back ( Vector3i ( prev , i , TextServer : : DIRECTION_AUTO ) ) ;
}
2024-09-03 09:54:09 +03:00
prev = p_text . length ( ) ;
ret . push_back ( Vector3i ( i , p_text . length ( ) , TextServer : : DIRECTION_AUTO ) ) ;
2023-01-18 09:33:35 +02:00
break ;
}
}
if ( prev < p_text . length ( ) ) {
ret . push_back ( Vector3i ( prev , p_text . length ( ) , TextServer : : DIRECTION_AUTO ) ) ;
}
} break ;
2022-04-19 13:27:18 +03:00
case STRUCTURED_TEXT_CUSTOM :
case STRUCTURED_TEXT_DEFAULT :
default : {
2023-01-18 09:33:35 +02:00
ret . push_back ( Vector3i ( 0 , p_text . length ( ) , TextServer : : DIRECTION_INHERITED ) ) ;
2022-04-19 13:27:18 +03:00
}
}
return ret ;
}
2022-08-08 00:52:20 +02:00
TypedArray < Dictionary > TextServer : : _shaped_text_get_glyphs_wrapper ( const RID & p_shaped ) const {
TypedArray < Dictionary > ret ;
2020-08-05 09:25:28 +03:00
2021-08-28 00:19:51 +03:00
const Glyph * glyphs = shaped_text_get_glyphs ( p_shaped ) ;
int gl_size = shaped_text_get_glyph_count ( p_shaped ) ;
for ( int i = 0 ; i < gl_size ; i + + ) {
2020-08-05 09:25:28 +03:00
Dictionary glyph ;
glyph [ " start " ] = glyphs [ i ] . start ;
glyph [ " end " ] = glyphs [ i ] . end ;
glyph [ " repeat " ] = glyphs [ i ] . repeat ;
glyph [ " count " ] = glyphs [ i ] . count ;
glyph [ " flags " ] = glyphs [ i ] . flags ;
glyph [ " offset " ] = Vector2 ( glyphs [ i ] . x_off , glyphs [ i ] . y_off ) ;
glyph [ " advance " ] = glyphs [ i ] . advance ;
glyph [ " font_rid " ] = glyphs [ i ] . font_rid ;
glyph [ " font_size " ] = glyphs [ i ] . font_size ;
glyph [ " index " ] = glyphs [ i ] . index ;
ret . push_back ( glyph ) ;
}
return ret ;
}
2022-08-08 00:52:20 +02:00
TypedArray < Dictionary > TextServer : : _shaped_text_sort_logical_wrapper ( const RID & p_shaped ) {
2020-08-05 09:25:28 +03:00
Array ret ;
2021-08-28 00:19:51 +03:00
const Glyph * glyphs = shaped_text_sort_logical ( p_shaped ) ;
int gl_size = shaped_text_get_glyph_count ( p_shaped ) ;
for ( int i = 0 ; i < gl_size ; i + + ) {
Dictionary glyph ;
2020-08-05 09:25:28 +03:00
2021-08-28 00:19:51 +03:00
glyph [ " start " ] = glyphs [ i ] . start ;
glyph [ " end " ] = glyphs [ i ] . end ;
glyph [ " repeat " ] = glyphs [ i ] . repeat ;
glyph [ " count " ] = glyphs [ i ] . count ;
glyph [ " flags " ] = glyphs [ i ] . flags ;
glyph [ " offset " ] = Vector2 ( glyphs [ i ] . x_off , glyphs [ i ] . y_off ) ;
glyph [ " advance " ] = glyphs [ i ] . advance ;
glyph [ " font_rid " ] = glyphs [ i ] . font_rid ;
glyph [ " font_size " ] = glyphs [ i ] . font_size ;
glyph [ " index " ] = glyphs [ i ] . index ;
2020-08-05 09:25:28 +03:00
2021-08-28 00:19:51 +03:00
ret . push_back ( glyph ) ;
2020-08-05 09:25:28 +03:00
}
return ret ;
}
2022-08-08 00:52:20 +02:00
TypedArray < Dictionary > TextServer : : _shaped_text_get_ellipsis_glyphs_wrapper ( const RID & p_shaped ) const {
TypedArray < Dictionary > ret ;
2020-08-05 09:25:28 +03:00
2021-08-28 00:19:51 +03:00
const Glyph * glyphs = shaped_text_get_ellipsis_glyphs ( p_shaped ) ;
int gl_size = shaped_text_get_ellipsis_glyph_count ( p_shaped ) ;
for ( int i = 0 ; i < gl_size ; i + + ) {
Dictionary glyph ;
2020-08-05 09:25:28 +03:00
2021-08-28 00:19:51 +03:00
glyph [ " start " ] = glyphs [ i ] . start ;
glyph [ " end " ] = glyphs [ i ] . end ;
glyph [ " repeat " ] = glyphs [ i ] . repeat ;
glyph [ " count " ] = glyphs [ i ] . count ;
glyph [ " flags " ] = glyphs [ i ] . flags ;
glyph [ " offset " ] = Vector2 ( glyphs [ i ] . x_off , glyphs [ i ] . y_off ) ;
glyph [ " advance " ] = glyphs [ i ] . advance ;
glyph [ " font_rid " ] = glyphs [ i ] . font_rid ;
glyph [ " font_size " ] = glyphs [ i ] . font_size ;
glyph [ " index " ] = glyphs [ i ] . index ;
2020-08-05 09:25:28 +03:00
2021-08-28 00:19:51 +03:00
ret . push_back ( glyph ) ;
2020-08-05 09:25:28 +03:00
}
return ret ;
}
2021-10-18 15:07:11 +03:00
bool TextServer : : is_valid_identifier ( const String & p_string ) const {
2024-08-23 14:30:51 +08:00
return p_string . is_valid_unicode_identifier ( ) ;
2021-10-18 15:07:11 +03:00
}
2024-06-02 21:21:18 +03:00
bool TextServer : : is_valid_letter ( uint64_t p_unicode ) const {
2024-05-02 21:32:20 +02:00
return is_unicode_letter ( p_unicode ) ;
}
2020-08-05 09:25:28 +03:00
TextServer : : TextServer ( ) {
2025-06-12 14:34:42 +03:00
// Default font rendering related project settings.
GLOBAL_DEF_RST ( PropertyInfo ( Variant : : INT , " gui/theme/default_font_antialiasing " , PROPERTY_HINT_ENUM , " None,Grayscale,LCD Subpixel " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED ) , 1 ) ;
GLOBAL_DEF_RST ( PropertyInfo ( Variant : : INT , " gui/theme/default_font_hinting " , PROPERTY_HINT_ENUM , " None,Light,Normal " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED ) , TextServer : : HINTING_LIGHT ) ;
GLOBAL_DEF_RST ( PropertyInfo ( Variant : : INT , " gui/theme/default_font_subpixel_positioning " , PROPERTY_HINT_ENUM , " Disabled,Auto,One Half of a Pixel,One Quarter of a Pixel " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED ) , TextServer : : SUBPIXEL_POSITIONING_AUTO ) ;
GLOBAL_DEF_RST ( " gui/theme/default_font_multichannel_signed_distance_field " , false ) ;
GLOBAL_DEF_RST ( " gui/theme/default_font_generate_mipmaps " , false ) ;
GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " gui/theme/lcd_subpixel_layout " , PROPERTY_HINT_ENUM , " Disabled,Horizontal RGB,Horizontal BGR,Vertical RGB,Vertical BGR " ) , 1 ) ;
2021-10-12 21:36:08 +03:00
_init_diacritics_map ( ) ;
2020-08-05 09:25:28 +03:00
}
TextServer : : ~ TextServer ( ) {
}