2020-08-05 09:25:28 +03:00
/**************************************************************************/
/* text_server_fb.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 "text_server_fb.h"
2022-08-12 14:03:28 +03:00
# include "core/config/project_settings.h"
2021-09-15 10:11:31 +02:00
# include "core/error/error_macros.h"
2025-10-05 17:05:56 +09:00
# include "core/io/file_access.h"
2026-03-12 21:17:06 +01:00
# include "core/math/math_funcs_binary.h"
2026-03-04 14:28:13 +01:00
# include "core/object/callable_mp.h"
2026-03-12 21:17:06 +01:00
# include "core/object/worker_thread_pool.h"
2026-03-03 17:32:44 +01:00
# include "core/os/os.h"
2020-12-27 15:30:33 +02:00
# include "core/string/print_string.h"
2024-08-15 15:00:47 +08:00
# include "core/string/translation_server.h"
2020-12-27 15:30:33 +02:00
2022-06-14 10:29:58 +03:00
# include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg.
2021-11-12 13:42:58 +01:00
2022-02-13 14:41:29 +02:00
// Thirdparty headers.
2020-12-27 15:30:33 +02:00
# ifdef MODULE_MSDFGEN_ENABLED
2025-10-06 13:16:02 -05:00
GODOT_GCC_WARNING_PUSH_AND_IGNORE ( " -Wshadow " )
2025-10-06 11:52:22 -05:00
GODOT_MSVC_WARNING_PUSH_AND_IGNORE ( 4458 ) // "Declaration of 'identifier' hides class member".
2025-01-09 21:16:08 +01:00
# include <core/EdgeHolder.h>
2023-06-13 16:56:21 +02:00
# include <core/ShapeDistanceFinder.h>
# include <core/contour-combiners.h>
# include <core/edge-selectors.h>
# include <msdfgen.h>
2025-10-06 11:52:22 -05:00
2025-10-06 13:16:02 -05:00
GODOT_GCC_WARNING_POP
2025-10-06 11:52:22 -05:00
GODOT_MSVC_WARNING_POP
2020-12-27 15:30:33 +02:00
# endif
2023-03-07 16:02:41 +01:00
# ifdef MODULE_FREETYPE_ENABLED
2024-03-24 01:18:50 +08:00
# include FT_SFNT_NAMES_H
# include FT_TRUETYPE_IDS_H
# ifdef MODULE_SVG_ENABLED
2022-06-14 10:29:58 +03:00
# include "thorvg_svg_in_ot.h"
# endif
2023-03-07 16:02:41 +01:00
# endif
2022-06-14 10:29:58 +03:00
2020-08-05 09:25:28 +03:00
/*************************************************************************/
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _has_feature ( Feature p_feature ) const {
2022-02-13 14:41:29 +02:00
switch ( p_feature ) {
case FEATURE_SIMPLE_LAYOUT :
case FEATURE_FONT_BITMAP :
# ifdef MODULE_FREETYPE_ENABLED
case FEATURE_FONT_DYNAMIC :
# endif
# ifdef MODULE_MSDFGEN_ENABLED
case FEATURE_FONT_MSDF :
# endif
return true ;
default : {
}
}
return false ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
String TextServerFallback : : _get_name ( ) const {
2022-02-13 14:41:29 +02:00
return " Fallback (Built-in) " ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
int64_t TextServerFallback : : _get_features ( ) const {
2022-02-13 14:41:29 +02:00
int64_t interface_features = FEATURE_SIMPLE_LAYOUT | FEATURE_FONT_BITMAP ;
# ifdef MODULE_FREETYPE_ENABLED
interface_features | = FEATURE_FONT_DYNAMIC ;
# endif
# ifdef MODULE_MSDFGEN_ENABLED
interface_features | = FEATURE_FONT_MSDF ;
# endif
2021-08-28 00:19:51 +03:00
return interface_features ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _free_rid ( const RID & p_rid ) {
2020-08-05 09:25:28 +03:00
_THREAD_SAFE_METHOD_
if ( font_owner . owns ( p_rid ) ) {
2023-02-26 17:55:04 +02:00
MutexLock ftlock ( ft_mutex ) ;
2022-05-09 12:47:10 +03:00
FontFallback * fd = font_owner . get_or_null ( p_rid ) ;
2025-05-26 22:38:47 +05:30
for ( const KeyValue < Vector2i , FontForSizeFallback * > & ffsd : fd - > cache ) {
OversamplingLevel * ol = oversampling_levels . getptr ( ffsd . value - > viewport_oversampling ) ;
if ( ol ! = nullptr ) {
ol - > fonts . erase ( ffsd . value ) ;
}
}
2023-01-02 21:59:05 +02:00
{
MutexLock lock ( fd - > mutex ) ;
font_owner . free ( p_rid ) ;
}
2020-08-05 09:25:28 +03:00
memdelete ( fd ) ;
2023-09-28 10:45:09 +03:00
} else if ( font_var_owner . owns ( p_rid ) ) {
MutexLock ftlock ( ft_mutex ) ;
FontFallbackLinkedVariation * fdv = font_var_owner . get_or_null ( p_rid ) ;
{
font_var_owner . free ( p_rid ) ;
}
memdelete ( fdv ) ;
2020-08-05 09:25:28 +03:00
} else if ( shaped_owner . owns ( p_rid ) ) {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_rid ) ;
2023-01-02 21:59:05 +02:00
{
MutexLock lock ( sd - > mutex ) ;
shaped_owner . free ( p_rid ) ;
}
2020-08-05 09:25:28 +03:00
memdelete ( sd ) ;
}
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _has ( const RID & p_rid ) {
2020-08-05 09:25:28 +03:00
_THREAD_SAFE_METHOD_
return font_owner . owns ( p_rid ) | | shaped_owner . owns ( p_rid ) ;
}
2022-09-27 11:23:34 +03:00
String TextServerFallback : : _get_support_data_filename ( ) const {
return " " ;
}
String TextServerFallback : : _get_support_data_info ( ) const {
return " Not supported " ;
}
bool TextServerFallback : : _load_support_data ( const String & p_filename ) {
2020-08-05 09:25:28 +03:00
return false ; // No extra data used.
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _save_support_data ( const String & p_filename ) const {
2020-08-05 09:25:28 +03:00
return false ; // No extra data used.
}
2024-11-13 08:03:40 +02:00
PackedByteArray TextServerFallback : : _get_support_data ( ) const {
return PackedByteArray ( ) ; // No extra data used.
}
2025-09-30 11:34:07 +03:00
bool TextServerFallback : : _is_locale_using_support_data ( const String & p_locale ) const {
return false ; // No data support.
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _is_locale_right_to_left ( const String & p_locale ) const {
2020-08-05 09:25:28 +03:00
return false ; // No RTL support.
}
2022-02-13 14:41:29 +02:00
_FORCE_INLINE_ void TextServerFallback : : _insert_feature ( const StringName & p_name , int32_t p_tag ) {
feature_sets . insert ( p_name , p_tag ) ;
feature_sets_inv . insert ( p_tag , p_name ) ;
}
2021-10-12 08:45:54 +03:00
void TextServerFallback : : _insert_feature_sets ( ) {
// Registered OpenType variation tag.
2022-02-13 14:41:29 +02:00
_insert_feature ( " italic " , OT_TAG ( ' i ' , ' t ' , ' a ' , ' l ' ) ) ;
_insert_feature ( " optical_size " , OT_TAG ( ' o ' , ' p ' , ' s ' , ' z ' ) ) ;
_insert_feature ( " slant " , OT_TAG ( ' s ' , ' l ' , ' n ' , ' t ' ) ) ;
_insert_feature ( " width " , OT_TAG ( ' w ' , ' d ' , ' t ' , ' h ' ) ) ;
_insert_feature ( " weight " , OT_TAG ( ' w ' , ' g ' , ' h ' , ' t ' ) ) ;
2021-10-12 08:45:54 +03:00
}
2020-12-27 15:30:33 +02:00
_FORCE_INLINE_ int32_t ot_tag_from_string ( const char * p_str , int p_len ) {
char tag [ 4 ] ;
uint32_t i ;
2022-01-27 10:34:33 -06:00
if ( ! p_str | | ! p_len | | ! * p_str ) {
2020-12-27 15:30:33 +02:00
return OT_TAG ( 0 , 0 , 0 , 0 ) ;
2022-01-27 10:34:33 -06:00
}
2020-12-27 15:30:33 +02:00
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 ] ) ;
}
2022-09-27 11:23:34 +03:00
int64_t TextServerFallback : : _name_to_tag ( const String & p_name ) const {
2021-10-12 08:45:54 +03:00
if ( feature_sets . has ( p_name ) ) {
return feature_sets [ p_name ] ;
2020-12-27 15:30:33 +02:00
}
// 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 ) ;
}
2022-09-27 11:23:34 +03:00
String TextServerFallback : : _tag_to_name ( int64_t p_tag ) const {
2022-02-13 14:41:29 +02:00
if ( feature_sets_inv . has ( p_tag ) ) {
return feature_sets_inv [ p_tag ] ;
2020-12-27 15:30:33 +02:00
}
// 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 ) ;
}
2020-08-05 09:25:28 +03:00
/*************************************************************************/
2020-12-27 15:30:33 +02:00
/* Font Glyph Rendering */
2020-08-05 09:25:28 +03:00
/*************************************************************************/
2022-05-09 12:47:10 +03:00
_FORCE_INLINE_ TextServerFallback : : FontTexturePosition TextServerFallback : : find_texture_pos_for_glyph ( FontForSizeFallback * p_data , int p_color_size , Image : : Format p_image_format , int p_width , int p_height , bool p_msdf ) const {
2020-12-27 15:30:33 +02:00
FontTexturePosition ret ;
int mw = p_width ;
int mh = p_height ;
2022-10-18 10:10:24 +03:00
ShelfPackTexture * ct = p_data - > textures . ptrw ( ) ;
for ( int32_t i = 0 ; i < p_data - > textures . size ( ) ; i + + ) {
2024-02-05 10:38:32 +02:00
if ( ct [ i ] . image . is_null ( ) ) {
continue ;
}
if ( p_image_format ! = ct [ i ] . image - > get_format ( ) ) {
2022-08-12 14:03:28 +03:00
continue ;
}
2022-10-18 10:10:24 +03:00
if ( mw > ct [ i ] . texture_w | | mh > ct [ i ] . texture_h ) { // Too big for this texture.
2020-12-27 15:30:33 +02:00
continue ;
}
2022-10-18 10:10:24 +03:00
ret = ct [ i ] . pack_rect ( i , mh , mw ) ;
if ( ret . index ! = - 1 ) {
break ;
2021-10-15 18:36:00 +03:00
}
2020-12-27 15:30:33 +02:00
}
if ( ret . index = = - 1 ) {
// Could not find texture to fit, create one.
2025-03-30 14:20:25 +03:00
int texsize = MAX ( p_data - > size . x * 0.125 , 256 ) ;
2020-12-27 15:30:33 +02:00
2025-06-13 01:43:35 +02:00
texsize = Math : : next_power_of_2 ( ( uint32_t ) texsize ) ;
2020-12-27 15:30:33 +02:00
2022-03-11 09:31:16 +02:00
if ( p_msdf ) {
texsize = MIN ( texsize , 2048 ) ;
} else {
texsize = MIN ( texsize , 1024 ) ;
}
2022-04-04 10:31:07 +03:00
if ( mw > texsize ) { // Special case, adapt to it?
2025-06-13 01:43:35 +02:00
texsize = Math : : next_power_of_2 ( ( uint32_t ) mw ) ;
2022-04-04 10:31:07 +03:00
}
if ( mh > texsize ) { // Special case, adapt to it?
2025-06-13 01:43:35 +02:00
texsize = Math : : next_power_of_2 ( ( uint32_t ) mh ) ;
2022-04-04 10:31:07 +03:00
}
2020-12-27 15:30:33 +02:00
2022-10-18 10:10:24 +03:00
ShelfPackTexture tex = ShelfPackTexture ( texsize , texsize ) ;
2024-02-05 10:38:32 +02:00
tex . image = Image : : create_empty ( texsize , texsize , false , p_image_format ) ;
2020-12-27 15:30:33 +02:00
{
// Zero texture.
2024-02-05 10:38:32 +02:00
uint8_t * w = tex . image - > ptrw ( ) ;
2024-06-02 21:21:18 +03:00
ERR_FAIL_COND_V ( texsize * texsize * p_color_size > tex . image - > get_data_size ( ) , ret ) ;
2020-12-27 15:30:33 +02:00
// Initialize the texture to all-white pixels to prevent artifacts when the
// font is displayed at a non-default scale with filtering enabled.
if ( p_color_size = = 2 ) {
for ( int i = 0 ; i < texsize * texsize * p_color_size ; i + = 2 ) { // FORMAT_LA8, BW font.
w [ i + 0 ] = 255 ;
w [ i + 1 ] = 0 ;
}
} else if ( p_color_size = = 4 ) {
for ( int i = 0 ; i < texsize * texsize * p_color_size ; i + = 4 ) { // FORMAT_RGBA8, Color font, Multichannel(+True) SDF.
2025-08-08 20:56:15 +03:00
if ( p_msdf ) {
w [ i + 0 ] = 0 ;
w [ i + 1 ] = 0 ;
w [ i + 2 ] = 0 ;
} else {
w [ i + 0 ] = 255 ;
w [ i + 1 ] = 255 ;
w [ i + 2 ] = 255 ;
}
2020-12-27 15:30:33 +02:00
w [ i + 3 ] = 0 ;
}
} else {
ERR_FAIL_V ( ret ) ;
}
}
p_data - > textures . push_back ( tex ) ;
2022-10-18 10:10:24 +03:00
int32_t idx = p_data - > textures . size ( ) - 1 ;
ret = p_data - > textures . write [ idx ] . pack_rect ( idx , mh , mw ) ;
2020-12-27 15:30:33 +02:00
}
return ret ;
}
# ifdef MODULE_MSDFGEN_ENABLED
struct MSContext {
msdfgen : : Point2 position ;
2022-05-02 16:28:25 +02:00
msdfgen : : Shape * shape = nullptr ;
msdfgen : : Contour * contour = nullptr ;
2020-12-27 15:30:33 +02:00
} ;
class DistancePixelConversion {
double invRange ;
public :
_FORCE_INLINE_ explicit DistancePixelConversion ( double range ) :
invRange ( 1 / range ) { }
_FORCE_INLINE_ void operator ( ) ( float * pixels , const msdfgen : : MultiAndTrueDistance & distance ) const {
pixels [ 0 ] = float ( invRange * distance . r + .5 ) ;
pixels [ 1 ] = float ( invRange * distance . g + .5 ) ;
pixels [ 2 ] = float ( invRange * distance . b + .5 ) ;
pixels [ 3 ] = float ( invRange * distance . a + .5 ) ;
}
} ;
struct MSDFThreadData {
msdfgen : : Bitmap < float , 4 > * output ;
msdfgen : : Shape * shape ;
msdfgen : : Projection * projection ;
DistancePixelConversion * distancePixelConversion ;
} ;
static msdfgen : : Point2 ft_point2 ( const FT_Vector & vector ) {
return msdfgen : : Point2 ( vector . x / 60.0f , vector . y / 60.0f ) ;
2020-08-05 09:25:28 +03:00
}
2020-12-27 15:30:33 +02:00
static int ft_move_to ( const FT_Vector * to , void * user ) {
2022-04-05 13:40:26 +03:00
MSContext * context = static_cast < MSContext * > ( user ) ;
2020-12-27 15:30:33 +02:00
if ( ! ( context - > contour & & context - > contour - > edges . empty ( ) ) ) {
context - > contour = & context - > shape - > addContour ( ) ;
}
context - > position = ft_point2 ( * to ) ;
return 0 ;
}
static int ft_line_to ( const FT_Vector * to , void * user ) {
2022-04-05 13:40:26 +03:00
MSContext * context = static_cast < MSContext * > ( user ) ;
2020-12-27 15:30:33 +02:00
msdfgen : : Point2 endpoint = ft_point2 ( * to ) ;
if ( endpoint ! = context - > position ) {
context - > contour - > addEdge ( new msdfgen : : LinearSegment ( context - > position , endpoint ) ) ;
context - > position = endpoint ;
}
return 0 ;
}
static int ft_conic_to ( const FT_Vector * control , const FT_Vector * to , void * user ) {
2022-04-05 13:40:26 +03:00
MSContext * context = static_cast < MSContext * > ( user ) ;
2020-12-27 15:30:33 +02:00
context - > contour - > addEdge ( new msdfgen : : QuadraticSegment ( context - > position , ft_point2 ( * control ) , ft_point2 ( * to ) ) ) ;
context - > position = ft_point2 ( * to ) ;
return 0 ;
}
static int ft_cubic_to ( const FT_Vector * control1 , const FT_Vector * control2 , const FT_Vector * to , void * user ) {
2022-04-05 13:40:26 +03:00
MSContext * context = static_cast < MSContext * > ( user ) ;
2020-12-27 15:30:33 +02:00
context - > contour - > addEdge ( new msdfgen : : CubicSegment ( context - > position , ft_point2 ( * control1 ) , ft_point2 ( * control2 ) , ft_point2 ( * to ) ) ) ;
context - > position = ft_point2 ( * to ) ;
return 0 ;
}
2022-11-28 11:00:48 +02:00
void TextServerFallback : : _generateMTSDF_threaded ( void * p_td , uint32_t p_y ) {
2022-04-05 13:40:26 +03:00
MSDFThreadData * td = static_cast < MSDFThreadData * > ( p_td ) ;
2020-12-27 15:30:33 +02:00
msdfgen : : ShapeDistanceFinder < msdfgen : : OverlappingContourCombiner < msdfgen : : MultiAndTrueDistanceSelector > > distanceFinder ( * td - > shape ) ;
2022-11-28 11:00:48 +02:00
int row = td - > shape - > inverseYAxis ? td - > output - > height ( ) - p_y - 1 : p_y ;
2020-12-27 15:30:33 +02:00
for ( int col = 0 ; col < td - > output - > width ( ) ; + + col ) {
2022-11-28 11:00:48 +02:00
int x = ( p_y % 2 ) ? td - > output - > width ( ) - col - 1 : col ;
msdfgen : : Point2 p = td - > projection - > unproject ( msdfgen : : Point2 ( x + .5 , p_y + .5 ) ) ;
2020-12-27 15:30:33 +02:00
msdfgen : : MultiAndTrueDistance distance = distanceFinder . distance ( p ) ;
td - > distancePixelConversion - > operator ( ) ( td - > output - > operator ( ) ( x , row ) , distance ) ;
}
}
2024-04-07 17:54:03 +03:00
_FORCE_INLINE_ TextServerFallback : : FontGlyph TextServerFallback : : rasterize_msdf ( FontFallback * p_font_data , FontForSizeFallback * p_data , int p_pixel_range , int p_rect_margin , FT_Outline * p_outline , const Vector2 & p_advance ) const {
2020-12-27 15:30:33 +02:00
msdfgen : : Shape shape ;
shape . contours . clear ( ) ;
shape . inverseYAxis = false ;
MSContext context = { } ;
context . shape = & shape ;
FT_Outline_Funcs ft_functions ;
ft_functions . move_to = & ft_move_to ;
ft_functions . line_to = & ft_line_to ;
ft_functions . conic_to = & ft_conic_to ;
ft_functions . cubic_to = & ft_cubic_to ;
ft_functions . shift = 0 ;
ft_functions . delta = 0 ;
2024-04-07 17:54:03 +03:00
int error = FT_Outline_Decompose ( p_outline , & ft_functions , & context ) ;
2020-12-27 15:30:33 +02:00
ERR_FAIL_COND_V_MSG ( error , FontGlyph ( ) , " FreeType: Outline decomposition error: ' " + String ( FT_Error_String ( error ) ) + " '. " ) ;
if ( ! shape . contours . empty ( ) & & shape . contours . back ( ) . edges . empty ( ) ) {
shape . contours . pop_back ( ) ;
}
2024-04-07 17:54:03 +03:00
if ( FT_Outline_Get_Orientation ( p_outline ) = = 1 ) {
2020-12-27 15:30:33 +02:00
for ( int i = 0 ; i < ( int ) shape . contours . size ( ) ; + + i ) {
shape . contours [ i ] . reverse ( ) ;
}
}
shape . inverseYAxis = true ;
shape . normalize ( ) ;
msdfgen : : Shape : : Bounds bounds = shape . getBounds ( p_pixel_range ) ;
FontGlyph chr ;
chr . found = true ;
2024-04-07 17:54:03 +03:00
chr . advance = p_advance ;
2020-12-27 15:30:33 +02:00
if ( shape . validate ( ) & & shape . contours . size ( ) > 0 ) {
int w = ( bounds . r - bounds . l ) ;
int h = ( bounds . t - bounds . b ) ;
2024-04-07 17:54:03 +03:00
if ( w = = 0 | | h = = 0 ) {
chr . texture_idx = - 1 ;
chr . uv_rect = Rect2 ( ) ;
chr . rect = Rect2 ( ) ;
return chr ;
}
2022-04-19 13:27:18 +03:00
int mw = w + p_rect_margin * 4 ;
int mh = h + p_rect_margin * 4 ;
2020-12-27 15:30:33 +02:00
2022-04-04 10:31:07 +03:00
ERR_FAIL_COND_V ( mw > 4096 , FontGlyph ( ) ) ;
ERR_FAIL_COND_V ( mh > 4096 , FontGlyph ( ) ) ;
2020-12-27 15:30:33 +02:00
2022-03-11 09:31:16 +02:00
FontTexturePosition tex_pos = find_texture_pos_for_glyph ( p_data , 4 , Image : : FORMAT_RGBA8 , mw , mh , true ) ;
2020-12-27 15:30:33 +02:00
ERR_FAIL_COND_V ( tex_pos . index < 0 , FontGlyph ( ) ) ;
2022-10-18 10:10:24 +03:00
ShelfPackTexture & tex = p_data - > textures . write [ tex_pos . index ] ;
2020-12-27 15:30:33 +02:00
edgeColoringSimple ( shape , 3.0 ) ; // Max. angle.
2021-08-28 00:19:51 +03:00
msdfgen : : Bitmap < float , 4 > image ( w , h ) ; // Texture size.
2020-12-27 15:30:33 +02:00
DistancePixelConversion distancePixelConversion ( p_pixel_range ) ;
msdfgen : : Projection projection ( msdfgen : : Vector2 ( 1.0 , 1.0 ) , msdfgen : : Vector2 ( - bounds . l , - bounds . b ) ) ;
msdfgen : : MSDFGeneratorConfig config ( true , msdfgen : : ErrorCorrectionConfig ( ) ) ;
MSDFThreadData td ;
td . output = & image ;
td . shape = & shape ;
td . projection = & projection ;
td . distancePixelConversion = & distancePixelConversion ;
2022-11-28 11:00:48 +02:00
WorkerThreadPool : : GroupID group_task = WorkerThreadPool : : get_singleton ( ) - > add_native_group_task ( & TextServerFallback : : _generateMTSDF_threaded , & td , h , - 1 , true , String ( " TextServerFBRenderMSDF " ) ) ;
WorkerThreadPool : : get_singleton ( ) - > wait_for_group_task_completion ( group_task ) ;
2020-12-27 15:30:33 +02:00
msdfgen : : msdfErrorCorrection ( image , shape , projection , p_pixel_range , config ) ;
{
2024-02-05 10:38:32 +02:00
uint8_t * wr = tex . image - > ptrw ( ) ;
2020-12-27 15:30:33 +02:00
for ( int i = 0 ; i < h ; i + + ) {
for ( int j = 0 ; j < w ; j + + ) {
2022-04-19 13:27:18 +03:00
int ofs = ( ( i + tex_pos . y + p_rect_margin * 2 ) * tex . texture_w + j + tex_pos . x + p_rect_margin * 2 ) * 4 ;
2024-06-02 21:21:18 +03:00
ERR_FAIL_COND_V ( ofs > = tex . image - > get_data_size ( ) , FontGlyph ( ) ) ;
2020-12-27 15:30:33 +02:00
wr [ ofs + 0 ] = ( uint8_t ) ( CLAMP ( image ( j , i ) [ 0 ] * 256.f , 0.f , 255.f ) ) ;
wr [ ofs + 1 ] = ( uint8_t ) ( CLAMP ( image ( j , i ) [ 1 ] * 256.f , 0.f , 255.f ) ) ;
wr [ ofs + 2 ] = ( uint8_t ) ( CLAMP ( image ( j , i ) [ 2 ] * 256.f , 0.f , 255.f ) ) ;
wr [ ofs + 3 ] = ( uint8_t ) ( CLAMP ( image ( j , i ) [ 3 ] * 256.f , 0.f , 255.f ) ) ;
}
}
}
2022-04-04 10:31:07 +03:00
tex . dirty = true ;
2020-12-27 15:30:33 +02:00
chr . texture_idx = tex_pos . index ;
2022-04-19 13:27:18 +03:00
chr . uv_rect = Rect2 ( tex_pos . x + p_rect_margin , tex_pos . y + p_rect_margin , w + p_rect_margin * 2 , h + p_rect_margin * 2 ) ;
chr . rect . position = Vector2 ( bounds . l - p_rect_margin , - bounds . t - p_rect_margin ) ;
2020-12-27 15:30:33 +02:00
chr . rect . size = chr . uv_rect . size ;
}
return chr ;
}
# endif
# ifdef MODULE_FREETYPE_ENABLED
2024-04-07 17:54:03 +03:00
_FORCE_INLINE_ TextServerFallback : : FontGlyph TextServerFallback : : rasterize_bitmap ( FontForSizeFallback * p_data , int p_rect_margin , FT_Bitmap p_bitmap , int p_yofs , int p_xofs , const Vector2 & p_advance , bool p_bgra ) const {
FontGlyph chr ;
2025-03-30 14:20:25 +03:00
chr . advance = p_advance * p_data - > scale ;
2024-04-07 17:54:03 +03:00
chr . found = true ;
int w = p_bitmap . width ;
int h = p_bitmap . rows ;
if ( w = = 0 | | h = = 0 ) {
chr . texture_idx = - 1 ;
chr . uv_rect = Rect2 ( ) ;
chr . rect = Rect2 ( ) ;
return chr ;
}
2022-08-12 14:03:28 +03:00
int color_size = 2 ;
2024-04-07 17:54:03 +03:00
switch ( p_bitmap . pixel_mode ) {
2022-08-12 14:03:28 +03:00
case FT_PIXEL_MODE_MONO :
case FT_PIXEL_MODE_GRAY : {
color_size = 2 ;
} break ;
case FT_PIXEL_MODE_BGRA : {
color_size = 4 ;
} break ;
case FT_PIXEL_MODE_LCD : {
color_size = 4 ;
w / = 3 ;
} break ;
case FT_PIXEL_MODE_LCD_V : {
color_size = 4 ;
h / = 3 ;
} break ;
}
2020-12-27 15:30:33 +02:00
2022-04-19 13:27:18 +03:00
int mw = w + p_rect_margin * 4 ;
int mh = h + p_rect_margin * 4 ;
2020-12-27 15:30:33 +02:00
2022-04-04 10:31:07 +03:00
ERR_FAIL_COND_V ( mw > 4096 , FontGlyph ( ) ) ;
ERR_FAIL_COND_V ( mh > 4096 , FontGlyph ( ) ) ;
2020-12-27 15:30:33 +02:00
Image : : Format require_format = color_size = = 4 ? Image : : FORMAT_RGBA8 : Image : : FORMAT_LA8 ;
2022-03-11 09:31:16 +02:00
FontTexturePosition tex_pos = find_texture_pos_for_glyph ( p_data , color_size , require_format , mw , mh , false ) ;
2020-12-27 15:30:33 +02:00
ERR_FAIL_COND_V ( tex_pos . index < 0 , FontGlyph ( ) ) ;
// Fit character in char texture.
2022-10-18 10:10:24 +03:00
ShelfPackTexture & tex = p_data - > textures . write [ tex_pos . index ] ;
2020-12-27 15:30:33 +02:00
{
2024-02-05 10:38:32 +02:00
uint8_t * wr = tex . image - > ptrw ( ) ;
2020-12-27 15:30:33 +02:00
for ( int i = 0 ; i < h ; i + + ) {
for ( int j = 0 ; j < w ; j + + ) {
2022-04-19 13:27:18 +03:00
int ofs = ( ( i + tex_pos . y + p_rect_margin * 2 ) * tex . texture_w + j + tex_pos . x + p_rect_margin * 2 ) * color_size ;
2024-06-02 21:21:18 +03:00
ERR_FAIL_COND_V ( ofs > = tex . image - > get_data_size ( ) , FontGlyph ( ) ) ;
2024-04-07 17:54:03 +03:00
switch ( p_bitmap . pixel_mode ) {
2020-12-27 15:30:33 +02:00
case FT_PIXEL_MODE_MONO : {
2024-04-07 17:54:03 +03:00
int byte = i * p_bitmap . pitch + ( j > > 3 ) ;
2020-12-27 15:30:33 +02:00
int bit = 1 < < ( 7 - ( j % 8 ) ) ;
2021-10-12 08:45:54 +03:00
wr [ ofs + 0 ] = 255 ; // grayscale as 1
2024-04-07 17:54:03 +03:00
wr [ ofs + 1 ] = ( p_bitmap . buffer [ byte ] & bit ) ? 255 : 0 ;
2020-12-27 15:30:33 +02:00
} break ;
case FT_PIXEL_MODE_GRAY :
2021-10-12 08:45:54 +03:00
wr [ ofs + 0 ] = 255 ; // grayscale as 1
2024-04-07 17:54:03 +03:00
wr [ ofs + 1 ] = p_bitmap . buffer [ i * p_bitmap . pitch + j ] ;
2020-12-27 15:30:33 +02:00
break ;
case FT_PIXEL_MODE_BGRA : {
2024-04-07 17:54:03 +03:00
int ofs_color = i * p_bitmap . pitch + ( j < < 2 ) ;
wr [ ofs + 2 ] = p_bitmap . buffer [ ofs_color + 0 ] ;
wr [ ofs + 1 ] = p_bitmap . buffer [ ofs_color + 1 ] ;
wr [ ofs + 0 ] = p_bitmap . buffer [ ofs_color + 2 ] ;
wr [ ofs + 3 ] = p_bitmap . buffer [ ofs_color + 3 ] ;
2020-12-27 15:30:33 +02:00
} break ;
2022-08-12 14:03:28 +03:00
case FT_PIXEL_MODE_LCD : {
2024-04-07 17:54:03 +03:00
int ofs_color = i * p_bitmap . pitch + ( j * 3 ) ;
2022-08-12 14:03:28 +03:00
if ( p_bgra ) {
2024-04-07 17:54:03 +03:00
wr [ ofs + 0 ] = p_bitmap . buffer [ ofs_color + 2 ] ;
wr [ ofs + 1 ] = p_bitmap . buffer [ ofs_color + 1 ] ;
wr [ ofs + 2 ] = p_bitmap . buffer [ ofs_color + 0 ] ;
2022-08-12 14:03:28 +03:00
wr [ ofs + 3 ] = 255 ;
} else {
2024-04-07 17:54:03 +03:00
wr [ ofs + 0 ] = p_bitmap . buffer [ ofs_color + 0 ] ;
wr [ ofs + 1 ] = p_bitmap . buffer [ ofs_color + 1 ] ;
wr [ ofs + 2 ] = p_bitmap . buffer [ ofs_color + 2 ] ;
2022-08-12 14:03:28 +03:00
wr [ ofs + 3 ] = 255 ;
}
} break ;
case FT_PIXEL_MODE_LCD_V : {
2024-04-07 17:54:03 +03:00
int ofs_color = i * p_bitmap . pitch * 3 + j ;
2022-08-12 14:03:28 +03:00
if ( p_bgra ) {
2024-04-07 17:54:03 +03:00
wr [ ofs + 0 ] = p_bitmap . buffer [ ofs_color + p_bitmap . pitch * 2 ] ;
wr [ ofs + 1 ] = p_bitmap . buffer [ ofs_color + p_bitmap . pitch ] ;
wr [ ofs + 2 ] = p_bitmap . buffer [ ofs_color + 0 ] ;
2022-08-12 14:03:28 +03:00
wr [ ofs + 3 ] = 255 ;
} else {
2024-04-07 17:54:03 +03:00
wr [ ofs + 0 ] = p_bitmap . buffer [ ofs_color + 0 ] ;
wr [ ofs + 1 ] = p_bitmap . buffer [ ofs_color + p_bitmap . pitch ] ;
wr [ ofs + 2 ] = p_bitmap . buffer [ ofs_color + p_bitmap . pitch * 2 ] ;
2022-08-12 14:03:28 +03:00
wr [ ofs + 3 ] = 255 ;
}
} break ;
2020-12-27 15:30:33 +02:00
default :
2024-04-07 17:54:03 +03:00
ERR_FAIL_V_MSG ( FontGlyph ( ) , " Font uses unsupported pixel format: " + String : : num_int64 ( p_bitmap . pixel_mode ) + " . " ) ;
2020-12-27 15:30:33 +02:00
break ;
}
}
}
}
2022-04-04 10:31:07 +03:00
tex . dirty = true ;
2020-12-27 15:30:33 +02:00
chr . texture_idx = tex_pos . index ;
2022-04-19 13:27:18 +03:00
chr . uv_rect = Rect2 ( tex_pos . x + p_rect_margin , tex_pos . y + p_rect_margin , w + p_rect_margin * 2 , h + p_rect_margin * 2 ) ;
2025-03-30 14:20:25 +03:00
chr . rect . position = Vector2 ( p_xofs - p_rect_margin , - p_yofs - p_rect_margin ) * p_data - > scale ;
chr . rect . size = chr . uv_rect . size * p_data - > scale ;
2020-12-27 15:30:33 +02:00
return chr ;
}
# endif
/*************************************************************************/
/* Font Cache */
/*************************************************************************/
2025-05-06 12:39:12 -04:00
bool TextServerFallback : : _ensure_glyph ( FontFallback * p_font_data , const Vector2i & p_size , int32_t p_glyph , FontGlyph & r_glyph , uint32_t p_oversampling ) const {
2024-05-30 22:57:28 -07:00
FontForSizeFallback * fd = nullptr ;
2025-03-30 14:20:25 +03:00
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( p_font_data , p_size , fd , false , p_oversampling ) , false ) ;
2020-12-27 15:30:33 +02:00
2022-02-13 14:41:29 +02:00
int32_t glyph_index = p_glyph & 0xffffff ; // Remove subpixel shifts.
2022-01-10 10:13:22 +02:00
2024-05-30 22:57:28 -07:00
HashMap < int32_t , FontGlyph > : : Iterator E = fd - > glyph_map . find ( p_glyph ) ;
if ( E ) {
2025-09-07 21:00:55 +03:00
bool tx_valid = true ;
if ( E - > value . texture_idx > = 0 ) {
if ( E - > value . texture_idx < fd - > textures . size ( ) ) {
tx_valid = fd - > textures [ E - > value . texture_idx ] . image . is_valid ( ) ;
} else {
tx_valid = false ;
}
}
if ( tx_valid ) {
r_glyph = E - > value ;
return E - > value . found ;
# ifdef DEBUG_ENABLED
} else {
WARN_PRINT ( vformat ( " Invalid texture cache for glyph %x in font %s, glyph will be re-rendered. Re-import this font to regenerate textures. " , glyph_index , p_font_data - > font_name ) ) ;
# endif
}
2020-12-27 15:30:33 +02:00
}
2022-01-10 10:13:22 +02:00
if ( glyph_index = = 0 ) { // Non graphical or invalid glyph, do not render.
2024-05-30 22:57:28 -07:00
E = fd - > glyph_map . insert ( p_glyph , FontGlyph ( ) ) ;
r_glyph = E - > value ;
2020-12-27 15:30:33 +02:00
return true ;
}
2021-02-18 15:45:28 +02:00
# ifdef MODULE_FREETYPE_ENABLED
2020-12-27 15:30:33 +02:00
FontGlyph gl ;
2026-02-02 11:36:42 +02:00
if ( p_font_data - > face ) {
2020-12-27 15:30:33 +02:00
FT_Int32 flags = FT_LOAD_DEFAULT ;
bool outline = p_size . y > 0 ;
switch ( p_font_data - > hinting ) {
case TextServer : : HINTING_NONE :
flags | = FT_LOAD_NO_HINTING ;
break ;
case TextServer : : HINTING_LIGHT :
flags | = FT_LOAD_TARGET_LIGHT ;
break ;
default :
flags | = FT_LOAD_TARGET_NORMAL ;
break ;
}
if ( p_font_data - > force_autohinter ) {
flags | = FT_LOAD_FORCE_AUTOHINT ;
}
2026-02-02 11:36:42 +02:00
if ( outline | | ( p_font_data - > disable_embedded_bitmaps & & ! FT_HAS_COLOR ( p_font_data - > face ) ) ) {
2020-12-27 15:30:33 +02:00
flags | = FT_LOAD_NO_BITMAP ;
2026-02-02 11:36:42 +02:00
} else if ( FT_HAS_COLOR ( p_font_data - > face ) ) {
2020-12-27 15:30:33 +02:00
flags | = FT_LOAD_COLOR ;
}
2026-02-02 11:36:42 +02:00
glyph_index = FT_Get_Char_Index ( p_font_data - > face , glyph_index ) ;
2022-03-11 09:31:16 +02:00
2020-12-27 15:30:33 +02:00
FT_Fixed v , h ;
2026-02-02 11:36:42 +02:00
FT_Get_Advance ( p_font_data - > face , glyph_index , flags , & h ) ;
FT_Get_Advance ( p_font_data - > face , glyph_index , flags | FT_LOAD_VERTICAL_LAYOUT , & v ) ;
2020-12-27 15:30:33 +02:00
2026-02-02 11:36:42 +02:00
int error = FT_Load_Glyph ( p_font_data - > face , glyph_index , flags ) ;
2020-12-27 15:30:33 +02:00
if ( error ) {
2024-05-30 22:57:28 -07:00
E = fd - > glyph_map . insert ( p_glyph , FontGlyph ( ) ) ;
r_glyph = E - > value ;
2021-08-28 00:19:51 +03:00
return false ;
2020-12-27 15:30:33 +02:00
}
2022-01-10 10:13:22 +02:00
if ( ! p_font_data - > msdf ) {
2025-03-30 14:20:25 +03:00
if ( ( p_font_data - > subpixel_positioning = = SUBPIXEL_POSITIONING_ONE_QUARTER ) | | ( p_font_data - > subpixel_positioning = = SUBPIXEL_POSITIONING_AUTO & & p_size . x < = SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64 ) ) {
2022-01-10 10:13:22 +02:00
FT_Pos xshift = ( int ) ( ( p_glyph > > 27 ) & 3 ) < < 4 ;
2026-02-02 11:36:42 +02:00
FT_Outline_Translate ( & p_font_data - > face - > glyph - > outline , xshift , 0 ) ;
2025-03-30 14:20:25 +03:00
} else if ( ( p_font_data - > subpixel_positioning = = SUBPIXEL_POSITIONING_ONE_HALF ) | | ( p_font_data - > subpixel_positioning = = SUBPIXEL_POSITIONING_AUTO & & p_size . x < = SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64 ) ) {
2022-01-10 10:13:22 +02:00
FT_Pos xshift = ( int ) ( ( p_glyph > > 27 ) & 3 ) < < 5 ;
2026-02-02 11:36:42 +02:00
FT_Outline_Translate ( & p_font_data - > face - > glyph - > outline , xshift , 0 ) ;
2022-01-10 10:13:22 +02:00
}
}
2022-03-11 09:31:16 +02:00
if ( p_font_data - > embolden ! = 0.f ) {
2025-03-30 14:20:25 +03:00
FT_Pos strength = p_font_data - > embolden * p_size . x / 16 ; // 26.6 fractional units (1 / 64).
2026-02-02 11:36:42 +02:00
FT_Outline_Embolden ( & p_font_data - > face - > glyph - > outline , strength ) ;
2022-03-11 09:31:16 +02:00
}
if ( p_font_data - > transform ! = Transform2D ( ) ) {
FT_Matrix mat = { FT_Fixed ( p_font_data - > transform [ 0 ] [ 0 ] * 65536 ) , FT_Fixed ( p_font_data - > transform [ 0 ] [ 1 ] * 65536 ) , FT_Fixed ( p_font_data - > transform [ 1 ] [ 0 ] * 65536 ) , FT_Fixed ( p_font_data - > transform [ 1 ] [ 1 ] * 65536 ) } ; // 16.16 fractional units (1 / 65536).
2026-02-02 11:36:42 +02:00
FT_Outline_Transform ( & p_font_data - > face - > glyph - > outline , & mat ) ;
2022-03-11 09:31:16 +02:00
}
2022-08-12 14:03:28 +03:00
FT_Render_Mode aa_mode = FT_RENDER_MODE_NORMAL ;
bool bgra = false ;
switch ( p_font_data - > antialiasing ) {
case FONT_ANTIALIASING_NONE : {
aa_mode = FT_RENDER_MODE_MONO ;
} break ;
case FONT_ANTIALIASING_GRAY : {
aa_mode = FT_RENDER_MODE_NORMAL ;
} break ;
case FONT_ANTIALIASING_LCD : {
int aa_layout = ( int ) ( ( p_glyph > > 24 ) & 7 ) ;
switch ( aa_layout ) {
case FONT_LCD_SUBPIXEL_LAYOUT_HRGB : {
aa_mode = FT_RENDER_MODE_LCD ;
bgra = false ;
} break ;
case FONT_LCD_SUBPIXEL_LAYOUT_HBGR : {
aa_mode = FT_RENDER_MODE_LCD ;
bgra = true ;
} break ;
case FONT_LCD_SUBPIXEL_LAYOUT_VRGB : {
aa_mode = FT_RENDER_MODE_LCD_V ;
bgra = false ;
} break ;
case FONT_LCD_SUBPIXEL_LAYOUT_VBGR : {
aa_mode = FT_RENDER_MODE_LCD_V ;
bgra = true ;
} break ;
default : {
aa_mode = FT_RENDER_MODE_NORMAL ;
} break ;
}
} break ;
}
2026-02-02 11:36:42 +02:00
FT_GlyphSlot slot = p_font_data - > face - > glyph ;
2025-02-14 20:20:12 -08:00
bool from_svg = ( slot - > format = = FT_GLYPH_FORMAT_SVG ) ; // Need to check before FT_Render_Glyph as it will change format to bitmap.
2020-12-27 15:30:33 +02:00
if ( ! outline ) {
if ( ! p_font_data - > msdf ) {
2025-02-14 20:20:12 -08:00
error = FT_Render_Glyph ( slot , aa_mode ) ;
2020-12-27 15:30:33 +02:00
}
if ( ! error ) {
if ( p_font_data - > msdf ) {
# ifdef MODULE_MSDFGEN_ENABLED
gl = rasterize_msdf ( p_font_data , fd , p_font_data - > msdf_range , rect_range , & slot - > outline , Vector2 ( ( h + ( 1 < < 9 ) ) > > 10 , ( v + ( 1 < < 9 ) ) > > 10 ) / 64.0 ) ;
# else
fd - > glyph_map [ p_glyph ] = FontGlyph ( ) ;
ERR_FAIL_V_MSG ( false , " Compiled without MSDFGEN support! " ) ;
2021-02-18 15:45:28 +02:00
# endif
2020-12-27 15:30:33 +02:00
} else {
2022-08-12 14:03:28 +03:00
gl = rasterize_bitmap ( fd , rect_range , slot - > bitmap , slot - > bitmap_top , slot - > bitmap_left , Vector2 ( ( h + ( 1 < < 9 ) ) > > 10 , ( v + ( 1 < < 9 ) ) > > 10 ) / 64.0 , bgra ) ;
2020-12-27 15:30:33 +02:00
}
}
} else {
FT_Stroker stroker ;
2022-02-13 14:41:29 +02:00
if ( FT_Stroker_New ( ft_library , & stroker ) ! = 0 ) {
2020-12-27 15:30:33 +02:00
fd - > glyph_map [ p_glyph ] = FontGlyph ( ) ;
ERR_FAIL_V_MSG ( false , " FreeType: Failed to load glyph stroker. " ) ;
}
2025-03-30 14:20:25 +03:00
FT_Stroker_Set ( stroker , ( int ) ( fd - > size . y * 16.0 ) , FT_STROKER_LINECAP_BUTT , FT_STROKER_LINEJOIN_ROUND , 0 ) ;
2020-12-27 15:30:33 +02:00
FT_Glyph glyph ;
FT_BitmapGlyph glyph_bitmap ;
2026-02-02 11:36:42 +02:00
if ( FT_Get_Glyph ( p_font_data - > face - > glyph , & glyph ) ! = 0 ) {
2020-12-27 15:30:33 +02:00
goto cleanup_stroker ;
}
if ( FT_Glyph_Stroke ( & glyph , stroker , 1 ) ! = 0 ) {
goto cleanup_glyph ;
}
2022-08-12 14:03:28 +03:00
if ( FT_Glyph_To_Bitmap ( & glyph , aa_mode , nullptr , 1 ) ! = 0 ) {
2020-12-27 15:30:33 +02:00
goto cleanup_glyph ;
}
glyph_bitmap = ( FT_BitmapGlyph ) glyph ;
2022-08-12 14:03:28 +03:00
gl = rasterize_bitmap ( fd , rect_range , glyph_bitmap - > bitmap , glyph_bitmap - > top , glyph_bitmap - > left , Vector2 ( ) , bgra ) ;
2020-12-27 15:30:33 +02:00
cleanup_glyph :
FT_Done_Glyph ( glyph ) ;
cleanup_stroker :
FT_Stroker_Done ( stroker ) ;
}
2025-02-14 20:20:12 -08:00
gl . from_svg = from_svg ;
2024-05-30 22:57:28 -07:00
E = fd - > glyph_map . insert ( p_glyph , gl ) ;
r_glyph = E - > value ;
2020-12-27 15:30:33 +02:00
return gl . found ;
}
# endif
2024-05-30 22:57:28 -07:00
E = fd - > glyph_map . insert ( p_glyph , FontGlyph ( ) ) ;
r_glyph = E - > value ;
2020-12-27 15:30:33 +02:00
return false ;
}
2025-05-06 12:39:12 -04:00
bool TextServerFallback : : _ensure_cache_for_size ( FontFallback * p_font_data , const Vector2i & p_size , FontForSizeFallback * & r_cache_for_size , bool p_silent , uint32_t p_oversampling ) const {
2021-10-25 11:49:18 +03:00
ERR_FAIL_COND_V ( p_size . x < = 0 , false ) ;
2024-05-30 22:57:28 -07:00
HashMap < Vector2i , FontForSizeFallback * > : : Iterator E = p_font_data - > cache . find ( p_size ) ;
if ( E ) {
2026-02-02 11:36:42 +02:00
# ifdef MODULE_FREETYPE_ENABLED
if ( E - > value - > fsize ! = nullptr ) {
FT_Activate_Size ( E - > value - > fsize ) ;
}
# endif
2024-05-30 22:57:28 -07:00
r_cache_for_size = E - > value ;
2025-03-30 14:20:25 +03:00
// Size used directly, remove from oversampling list.
if ( p_oversampling = = 0 & & E - > value - > viewport_oversampling ! = 0 ) {
OversamplingLevel * ol = oversampling_levels . getptr ( E - > value - > viewport_oversampling ) ;
if ( ol ) {
ol - > fonts . erase ( E - > value ) ;
}
}
2020-12-27 15:30:33 +02:00
return true ;
2020-08-05 09:25:28 +03:00
}
2024-05-30 22:57:28 -07:00
r_cache_for_size = nullptr ;
2022-05-09 12:47:10 +03:00
FontForSizeFallback * fd = memnew ( FontForSizeFallback ) ;
2020-12-27 15:30:33 +02:00
fd - > size = p_size ;
2021-10-15 18:36:00 +03:00
if ( p_font_data - > data_ptr & & ( p_font_data - > data_size > 0 ) ) {
2020-12-27 15:30:33 +02:00
// Init dynamic font.
# ifdef MODULE_FREETYPE_ENABLED
int error = 0 ;
2023-02-26 17:55:04 +02:00
{
MutexLock ftlock ( ft_mutex ) ;
if ( ! ft_library ) {
error = FT_Init_FreeType ( & ft_library ) ;
if ( error ! = 0 ) {
memdelete ( fd ) ;
2024-10-01 17:22:16 +03:00
if ( p_silent ) {
return false ;
} else {
ERR_FAIL_V_MSG ( false , " FreeType: Error initializing library: ' " + String ( FT_Error_String ( error ) ) + " '. " ) ;
}
2023-02-26 17:55:04 +02:00
}
2022-06-14 10:29:58 +03:00
# ifdef MODULE_SVG_ENABLED
2023-02-26 17:55:04 +02:00
FT_Property_Set ( ft_library , " ot-svg " , " svg-hooks " , get_tvg_svg_in_ot_hooks ( ) ) ;
2022-06-14 10:29:58 +03:00
# endif
2023-02-26 17:55:04 +02:00
}
2022-06-07 11:35:59 +03:00
2026-02-02 11:36:42 +02:00
if ( p_font_data - > face = = nullptr ) {
memset ( & p_font_data - > stream , 0 , sizeof ( FT_StreamRec ) ) ;
p_font_data - > stream . base = ( unsigned char * ) p_font_data - > data_ptr ;
p_font_data - > stream . size = p_font_data - > data_size ;
p_font_data - > stream . pos = 0 ;
FT_Open_Args fargs ;
memset ( & fargs , 0 , sizeof ( FT_Open_Args ) ) ;
fargs . memory_base = ( unsigned char * ) p_font_data - > data_ptr ;
fargs . memory_size = p_font_data - > data_size ;
fargs . flags = FT_OPEN_MEMORY ;
fargs . stream = & p_font_data - > stream ;
int max_index = 0 ;
FT_Face tmp_face = nullptr ;
error = FT_Open_Face ( ft_library , & fargs , - 1 , & tmp_face ) ;
if ( tmp_face & & error = = 0 ) {
max_index = tmp_face - > num_faces - 1 ;
}
if ( tmp_face ) {
FT_Done_Face ( tmp_face ) ;
}
2022-06-07 11:35:59 +03:00
2026-02-02 11:36:42 +02:00
error = FT_Open_Face ( ft_library , & fargs , CLAMP ( p_font_data - > face_index , 0 , max_index ) , & p_font_data - > face ) ;
if ( error ) {
FT_Done_Face ( p_font_data - > face ) ;
p_font_data - > face = nullptr ;
memdelete ( fd ) ;
if ( p_silent ) {
return false ;
} else {
ERR_FAIL_V_MSG ( false , " FreeType: Error loading font: ' " + String ( FT_Error_String ( error ) ) + " '. " ) ;
}
2024-10-01 17:22:16 +03:00
}
2023-02-26 17:55:04 +02:00
}
2026-02-02 11:36:42 +02:00
FT_New_Size ( p_font_data - > face , & fd - > fsize ) ;
FT_Activate_Size ( fd - > fsize ) ;
2020-12-27 15:30:33 +02:00
}
2025-03-30 14:20:25 +03:00
double sz = double ( fd - > size . x ) / 64.0 ;
2020-12-27 15:30:33 +02:00
if ( p_font_data - > msdf ) {
2025-03-30 14:20:25 +03:00
sz = p_font_data - > msdf_source_size ;
2020-12-27 15:30:33 +02:00
}
2026-02-02 11:36:42 +02:00
if ( FT_HAS_COLOR ( p_font_data - > face ) & & p_font_data - > face - > num_fixed_sizes > 0 ) {
2020-12-27 15:30:33 +02:00
int best_match = 0 ;
2026-02-02 11:36:42 +02:00
int diff = Math : : abs ( sz - ( ( int64_t ) p_font_data - > face - > available_sizes [ 0 ] . width ) ) ;
fd - > scale = sz / p_font_data - > face - > available_sizes [ 0 ] . width ;
for ( int i = 1 ; i < p_font_data - > face - > num_fixed_sizes ; i + + ) {
int ndiff = Math : : abs ( sz - ( ( int64_t ) p_font_data - > face - > available_sizes [ i ] . width ) ) ;
2020-12-27 15:30:33 +02:00
if ( ndiff < diff ) {
best_match = i ;
diff = ndiff ;
2026-02-02 11:36:42 +02:00
fd - > scale = sz / p_font_data - > face - > available_sizes [ i ] . width ;
2020-12-27 15:30:33 +02:00
}
}
2026-02-02 11:36:42 +02:00
FT_Select_Size ( p_font_data - > face , best_match ) ;
2020-12-27 15:30:33 +02:00
} else {
2025-03-30 14:20:25 +03:00
FT_Size_RequestRec req ;
req . type = FT_SIZE_REQUEST_TYPE_NOMINAL ;
2026-02-06 11:26:05 +02:00
req . width = MIN ( 2048.0 , sz ) * 64.0 ;
req . height = MIN ( 2048.0 , sz ) * 64.0 ;
2025-03-30 14:20:25 +03:00
req . horiResolution = 0 ;
req . vertResolution = 0 ;
2026-02-02 11:36:42 +02:00
FT_Request_Size ( p_font_data - > face , & req ) ;
if ( p_font_data - > face - > size - > metrics . y_ppem ! = 0 ) {
fd - > scale = sz / ( double ) p_font_data - > face - > size - > metrics . y_ppem ;
2023-03-10 09:10:12 +02:00
}
2020-12-27 15:30:33 +02:00
}
2026-02-02 11:36:42 +02:00
fd - > ascent = ( p_font_data - > face - > size - > metrics . ascender / 64.0 ) * fd - > scale ;
fd - > descent = ( - p_font_data - > face - > size - > metrics . descender / 64.0 ) * fd - > scale ;
fd - > underline_position = ( - FT_MulFix ( p_font_data - > face - > underline_position , p_font_data - > face - > size - > metrics . y_scale ) / 64.0 ) * fd - > scale ;
fd - > underline_thickness = ( FT_MulFix ( p_font_data - > face - > underline_thickness , p_font_data - > face - > size - > metrics . y_scale ) / 64.0 ) * fd - > scale ;
2020-12-27 15:30:33 +02:00
if ( ! p_font_data - > face_init ) {
2024-03-24 01:18:50 +08:00
// When a font does not provide a `family_name`, FreeType tries to synthesize one based on other names.
// FreeType automatically converts non-ASCII characters to "?" in the synthesized name.
// To avoid that behavior, use the format-specific name directly if available.
2026-02-02 11:36:42 +02:00
if ( FT_IS_SFNT ( p_font_data - > face ) ) {
int name_count = FT_Get_Sfnt_Name_Count ( p_font_data - > face ) ;
2024-03-24 01:18:50 +08:00
for ( int i = 0 ; i < name_count ; i + + ) {
FT_SfntName sfnt_name ;
2026-02-02 11:36:42 +02:00
if ( FT_Get_Sfnt_Name ( p_font_data - > face , i , & sfnt_name ) ! = 0 ) {
2024-03-24 01:18:50 +08:00
continue ;
}
if ( sfnt_name . name_id ! = TT_NAME_ID_FONT_FAMILY & & sfnt_name . name_id ! = TT_NAME_ID_TYPOGRAPHIC_FAMILY ) {
continue ;
}
if ( ! p_font_data - > font_name . is_empty ( ) & & sfnt_name . language_id ! = TT_MS_LANGID_ENGLISH_UNITED_STATES ) {
continue ;
}
switch ( sfnt_name . platform_id ) {
case TT_PLATFORM_APPLE_UNICODE : {
2025-03-24 12:25:48 +01:00
p_font_data - > font_name . clear ( ) ;
p_font_data - > font_name . append_utf16 ( ( const char16_t * ) sfnt_name . string , sfnt_name . string_len / 2 , false ) ;
2024-03-24 01:18:50 +08:00
} break ;
case TT_PLATFORM_MICROSOFT : {
if ( sfnt_name . encoding_id = = TT_MS_ID_UNICODE_CS | | sfnt_name . encoding_id = = TT_MS_ID_UCS_4 ) {
2025-03-24 12:25:48 +01:00
p_font_data - > font_name . clear ( ) ;
p_font_data - > font_name . append_utf16 ( ( const char16_t * ) sfnt_name . string , sfnt_name . string_len / 2 , false ) ;
2024-03-24 01:18:50 +08:00
}
} break ;
}
}
}
2026-02-02 11:36:42 +02:00
if ( p_font_data - > font_name . is_empty ( ) & & p_font_data - > face - > family_name ! = nullptr ) {
p_font_data - > font_name = String : : utf8 ( ( const char * ) p_font_data - > face - > family_name ) ;
2021-10-26 09:40:11 +03:00
}
2026-02-02 11:36:42 +02:00
if ( p_font_data - > face - > style_name ! = nullptr ) {
p_font_data - > style_name = String : : utf8 ( ( const char * ) p_font_data - > face - > style_name ) ;
2021-10-26 09:40:11 +03:00
}
2022-11-21 15:04:01 +02:00
p_font_data - > weight = _font_get_weight_by_name ( p_font_data - > style_name . to_lower ( ) ) ;
p_font_data - > stretch = _font_get_stretch_by_name ( p_font_data - > style_name . to_lower ( ) ) ;
2021-10-26 09:40:11 +03:00
p_font_data - > style_flags = 0 ;
2026-02-02 11:36:42 +02:00
if ( ( p_font_data - > face - > style_flags & FT_STYLE_FLAG_BOLD ) | | p_font_data - > weight > = 700 ) {
2022-07-11 12:40:31 +03:00
p_font_data - > style_flags . set_flag ( FONT_BOLD ) ;
2021-10-26 09:40:11 +03:00
}
2026-02-02 11:36:42 +02:00
if ( ( p_font_data - > face - > style_flags & FT_STYLE_FLAG_ITALIC ) | | _is_ital_style ( p_font_data - > style_name . to_lower ( ) ) ) {
2022-07-11 12:40:31 +03:00
p_font_data - > style_flags . set_flag ( FONT_ITALIC ) ;
2021-10-26 09:40:11 +03:00
}
2026-02-02 11:36:42 +02:00
if ( p_font_data - > face - > face_flags & FT_FACE_FLAG_FIXED_WIDTH ) {
2022-07-11 12:40:31 +03:00
p_font_data - > style_flags . set_flag ( FONT_FIXED_WIDTH ) ;
2021-10-26 09:40:11 +03:00
}
2020-12-27 15:30:33 +02:00
// Read OpenType variations.
p_font_data - > supported_varaitions . clear ( ) ;
2026-02-02 11:36:42 +02:00
if ( p_font_data - > face - > face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS ) {
2020-12-27 15:30:33 +02:00
FT_MM_Var * amaster ;
2026-02-02 11:36:42 +02:00
FT_Get_MM_Var ( p_font_data - > face , & amaster ) ;
2020-12-27 15:30:33 +02:00
for ( FT_UInt i = 0 ; i < amaster - > num_axis ; i + + ) {
p_font_data - > supported_varaitions [ ( int32_t ) amaster - > axis [ i ] . tag ] = Vector3i ( amaster - > axis [ i ] . minimum / 65536 , amaster - > axis [ i ] . maximum / 65536 , amaster - > axis [ i ] . def / 65536 ) ;
}
2022-02-13 14:41:29 +02:00
FT_Done_MM_Var ( ft_library , amaster ) ;
2020-12-27 15:30:33 +02:00
}
p_font_data - > face_init = true ;
}
2025-05-21 12:11:31 +03:00
# if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
if ( p_font_data - > font_name = = " .Apple Color Emoji UI " | | p_font_data - > font_name = = " Apple Color Emoji " ) {
// The baseline offset is missing from the Apple Color Emoji UI font data, so add it manually.
// This issue doesn't occur with other system emoji fonts.
2026-02-02 11:36:42 +02:00
if ( ! FT_Load_Glyph ( p_font_data - > face , FT_Get_Char_Index ( p_font_data - > face , 0x1F92E ) , FT_LOAD_DEFAULT | FT_LOAD_COLOR ) ) {
if ( p_font_data - > face - > glyph - > metrics . horiBearingY = = p_font_data - > face - > glyph - > metrics . height ) {
2025-05-21 12:11:31 +03:00
p_font_data - > baseline_offset = 0.15 ;
}
}
}
# endif
2020-12-27 15:30:33 +02:00
// Write variations.
2026-02-02 11:36:42 +02:00
if ( p_font_data - > face - > face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS ) {
2020-12-27 15:30:33 +02:00
FT_MM_Var * amaster ;
2026-02-02 11:36:42 +02:00
FT_Get_MM_Var ( p_font_data - > face , & amaster ) ;
2020-12-27 15:30:33 +02:00
Vector < FT_Fixed > coords ;
coords . resize ( amaster - > num_axis ) ;
2026-02-02 11:36:42 +02:00
FT_Get_Var_Design_Coordinates ( p_font_data - > face , coords . size ( ) , coords . ptrw ( ) ) ;
2020-12-27 15:30:33 +02:00
for ( FT_UInt i = 0 ; i < amaster - > num_axis ; i + + ) {
// Reset to default.
int32_t var_tag = amaster - > axis [ i ] . tag ;
2022-02-13 14:41:29 +02:00
double var_value = ( double ) amaster - > axis [ i ] . def / 65536.0 ;
2020-12-27 15:30:33 +02:00
coords . write [ i ] = amaster - > axis [ i ] . def ;
if ( p_font_data - > variation_coordinates . has ( var_tag ) ) {
var_value = p_font_data - > variation_coordinates [ var_tag ] ;
2022-02-13 14:41:29 +02:00
coords . write [ i ] = CLAMP ( var_value * 65536.0 , amaster - > axis [ i ] . minimum , amaster - > axis [ i ] . maximum ) ;
2020-12-27 15:30:33 +02:00
}
2024-02-22 12:10:37 +02:00
if ( p_font_data - > variation_coordinates . has ( tag_to_name ( var_tag ) ) ) {
var_value = p_font_data - > variation_coordinates [ tag_to_name ( var_tag ) ] ;
2022-02-13 14:41:29 +02:00
coords . write [ i ] = CLAMP ( var_value * 65536.0 , amaster - > axis [ i ] . minimum , amaster - > axis [ i ] . maximum ) ;
2020-12-27 15:30:33 +02:00
}
}
2026-02-02 11:36:42 +02:00
FT_Set_Var_Design_Coordinates ( p_font_data - > face , coords . size ( ) , coords . ptrw ( ) ) ;
2022-02-13 14:41:29 +02:00
FT_Done_MM_Var ( ft_library , amaster ) ;
2020-12-27 15:30:33 +02:00
}
# else
2022-10-17 09:09:46 +08:00
memdelete ( fd ) ;
2024-10-01 17:22:16 +03:00
if ( p_silent ) {
return false ;
} else {
ERR_FAIL_V_MSG ( false , " FreeType: Can't load dynamic font, engine is compiled without FreeType support! " ) ;
}
2020-12-27 15:30:33 +02:00
# endif
}
2024-05-30 22:57:28 -07:00
2025-03-30 14:20:25 +03:00
fd - > owner = p_font_data ;
2024-05-30 22:57:28 -07:00
p_font_data - > cache . insert ( p_size , fd ) ;
r_cache_for_size = fd ;
2025-03-30 14:20:25 +03:00
if ( p_oversampling ! = 0 ) {
OversamplingLevel * ol = oversampling_levels . getptr ( p_oversampling ) ;
if ( ol ) {
fd - > viewport_oversampling = p_oversampling ;
ol - > fonts . insert ( fd ) ;
}
}
2020-12-27 15:30:33 +02:00
return true ;
}
2025-03-30 14:20:25 +03:00
void TextServerFallback : : _reference_oversampling_level ( double p_oversampling ) {
uint32_t oversampling = CLAMP ( p_oversampling , 0.1 , 100.0 ) * 64 ;
if ( oversampling = = 64 ) {
return ;
}
OversamplingLevel * ol = oversampling_levels . getptr ( oversampling ) ;
if ( ol ) {
ol - > refcount + + ;
} else {
OversamplingLevel new_ol ;
oversampling_levels . insert ( oversampling , new_ol ) ;
}
}
void TextServerFallback : : _unreference_oversampling_level ( double p_oversampling ) {
uint32_t oversampling = CLAMP ( p_oversampling , 0.1 , 100.0 ) * 64 ;
if ( oversampling = = 64 ) {
return ;
}
OversamplingLevel * ol = oversampling_levels . getptr ( oversampling ) ;
if ( ol ) {
ol - > refcount - - ;
if ( ol - > refcount = = 0 ) {
for ( FontForSizeFallback * fd : ol - > fonts ) {
fd - > owner - > cache . erase ( fd - > size ) ;
memdelete ( fd ) ;
}
ol - > fonts . clear ( ) ;
oversampling_levels . erase ( oversampling ) ;
}
}
}
2024-10-01 17:22:16 +03:00
_FORCE_INLINE_ bool TextServerFallback : : _font_validate ( const RID & p_font_rid ) const {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL_V ( fd , false ) ;
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , 16 ) ;
FontForSizeFallback * ffsd = nullptr ;
return _ensure_cache_for_size ( fd , size , ffsd , true ) ;
}
2022-05-09 12:47:10 +03:00
_FORCE_INLINE_ void TextServerFallback : : _font_clear_cache ( FontFallback * p_font_data ) {
2023-02-26 17:55:04 +02:00
MutexLock ftlock ( ft_mutex ) ;
2022-05-09 12:47:10 +03:00
for ( const KeyValue < Vector2i , FontForSizeFallback * > & E : p_font_data - > cache ) {
2025-03-30 14:20:25 +03:00
if ( E . value - > viewport_oversampling ! = 0 ) {
OversamplingLevel * ol = oversampling_levels . getptr ( E . value - > viewport_oversampling ) ;
if ( ol ) {
ol - > fonts . erase ( E . value ) ;
}
}
2021-08-09 14:13:42 -06:00
memdelete ( E . value ) ;
2020-08-05 09:25:28 +03:00
}
2020-12-27 15:30:33 +02:00
p_font_data - > cache . clear ( ) ;
p_font_data - > face_init = false ;
p_font_data - > supported_varaitions . clear ( ) ;
}
2022-09-27 11:23:34 +03:00
RID TextServerFallback : : _create_font ( ) {
2022-05-18 10:17:55 +03:00
_THREAD_SAFE_METHOD_
2022-05-09 12:47:10 +03:00
FontFallback * fd = memnew ( FontFallback ) ;
2020-12-27 15:30:33 +02:00
2020-08-05 09:25:28 +03:00
return font_owner . make_rid ( fd ) ;
}
2023-09-28 10:45:09 +03:00
RID TextServerFallback : : _create_font_linked_variation ( const RID & p_font_rid ) {
_THREAD_SAFE_METHOD_
RID rid = p_font_rid ;
FontFallbackLinkedVariation * fdv = font_var_owner . get_or_null ( rid ) ;
if ( unlikely ( fdv ) ) {
rid = fdv - > base_font ;
}
ERR_FAIL_COND_V ( ! font_owner . owns ( rid ) , RID ( ) ) ;
FontFallbackLinkedVariation * new_fdv = memnew ( FontFallbackLinkedVariation ) ;
new_fdv - > base_font = rid ;
return font_var_owner . make_rid ( new_fdv ) ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_data ( const RID & p_font_rid , const PackedByteArray & p_data ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
_font_clear_cache ( fd ) ;
fd - > data = p_data ;
fd - > data_ptr = fd - > data . ptr ( ) ;
fd - > data_size = fd - > data . size ( ) ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_data_ptr ( const RID & p_font_rid , const uint8_t * p_data_ptr , int64_t p_data_size ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
_font_clear_cache ( fd ) ;
2022-02-13 14:41:29 +02:00
fd - > data . resize ( 0 ) ;
2020-12-27 15:30:33 +02:00
fd - > data_ptr = p_data_ptr ;
fd - > data_size = p_data_size ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_style ( const RID & p_font_rid , BitField < FontStyle > p_style ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2021-10-26 09:40:11 +03:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , 16 ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2021-10-26 09:40:11 +03:00
fd - > style_flags = p_style ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_face_index ( const RID & p_font_rid , int64_t p_face_index ) {
2022-06-07 11:35:59 +03:00
ERR_FAIL_COND ( p_face_index < 0 ) ;
ERR_FAIL_COND ( p_face_index > = 0x7FFF ) ;
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2022-06-07 11:35:59 +03:00
MutexLock lock ( fd - > mutex ) ;
if ( fd - > face_index ! = p_face_index ) {
fd - > face_index = p_face_index ;
_font_clear_cache ( fd ) ;
}
}
2022-09-27 11:23:34 +03:00
int64_t TextServerFallback : : _font_get_face_index ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , 0 ) ;
2022-06-07 11:35:59 +03:00
MutexLock lock ( fd - > mutex ) ;
return fd - > face_index ;
}
2022-09-27 11:23:34 +03:00
int64_t TextServerFallback : : _font_get_face_count ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , 0 ) ;
2022-06-07 11:35:59 +03:00
MutexLock lock ( fd - > mutex ) ;
int face_count = 0 ;
if ( fd - > data_ptr & & ( fd - > data_size > 0 ) ) {
// Init dynamic font.
# ifdef MODULE_FREETYPE_ENABLED
int error = 0 ;
if ( ! ft_library ) {
error = FT_Init_FreeType ( & ft_library ) ;
ERR_FAIL_COND_V_MSG ( error ! = 0 , false , " FreeType: Error initializing library: ' " + String ( FT_Error_String ( error ) ) + " '. " ) ;
2022-06-14 10:29:58 +03:00
# ifdef MODULE_SVG_ENABLED
FT_Property_Set ( ft_library , " ot-svg " , " svg-hooks " , get_tvg_svg_in_ot_hooks ( ) ) ;
# endif
2022-06-07 11:35:59 +03:00
}
FT_StreamRec stream ;
memset ( & stream , 0 , sizeof ( FT_StreamRec ) ) ;
stream . base = ( unsigned char * ) fd - > data_ptr ;
stream . size = fd - > data_size ;
stream . pos = 0 ;
FT_Open_Args fargs ;
memset ( & fargs , 0 , sizeof ( FT_Open_Args ) ) ;
fargs . memory_base = ( unsigned char * ) fd - > data_ptr ;
fargs . memory_size = fd - > data_size ;
fargs . flags = FT_OPEN_MEMORY ;
fargs . stream = & stream ;
2023-02-26 17:55:04 +02:00
MutexLock ftlock ( ft_mutex ) ;
2022-09-18 14:33:28 +08:00
FT_Face tmp_face = nullptr ;
2022-06-07 11:35:59 +03:00
error = FT_Open_Face ( ft_library , & fargs , - 1 , & tmp_face ) ;
if ( error = = 0 ) {
face_count = tmp_face - > num_faces ;
2022-09-18 14:33:28 +08:00
FT_Done_Face ( tmp_face ) ;
2022-06-07 11:35:59 +03:00
}
# endif
}
return face_count ;
}
2022-09-27 11:23:34 +03:00
BitField < TextServer : : FontStyle > TextServerFallback : : _font_get_style ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , 0 ) ;
2021-10-26 09:40:11 +03:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , 16 ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , 0 ) ;
2021-10-26 09:40:11 +03:00
return fd - > style_flags ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_style_name ( const RID & p_font_rid , const String & p_name ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2021-10-26 09:40:11 +03:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , 16 ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2021-10-26 09:40:11 +03:00
fd - > style_name = p_name ;
}
2022-09-27 11:23:34 +03:00
String TextServerFallback : : _font_get_style_name ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , String ( ) ) ;
2021-10-26 09:40:11 +03:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , 16 ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , String ( ) ) ;
2021-10-26 09:40:11 +03:00
return fd - > style_name ;
}
2022-11-21 15:04:01 +02:00
void TextServerFallback : : _font_set_weight ( const RID & p_font_rid , int64_t p_weight ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2022-11-21 15:04:01 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , 16 ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2022-11-21 15:04:01 +02:00
fd - > weight = CLAMP ( p_weight , 100 , 999 ) ;
}
int64_t TextServerFallback : : _font_get_weight ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , 400 ) ;
2022-11-21 15:04:01 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , 16 ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , 400 ) ;
2022-11-21 15:04:01 +02:00
return fd - > weight ;
}
void TextServerFallback : : _font_set_stretch ( const RID & p_font_rid , int64_t p_stretch ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2022-11-21 15:04:01 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , 16 ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2022-11-21 15:04:01 +02:00
fd - > stretch = CLAMP ( p_stretch , 50 , 200 ) ;
}
int64_t TextServerFallback : : _font_get_stretch ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , 100 ) ;
2022-11-21 15:04:01 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , 16 ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , 100 ) ;
2022-11-21 15:04:01 +02:00
return fd - > stretch ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_name ( const RID & p_font_rid , const String & p_name ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2021-10-26 09:40:11 +03:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , 16 ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2021-10-26 09:40:11 +03:00
fd - > font_name = p_name ;
}
2022-09-27 11:23:34 +03:00
String TextServerFallback : : _font_get_name ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , String ( ) ) ;
2021-10-26 09:40:11 +03:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , 16 ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , String ( ) ) ;
2021-10-26 09:40:11 +03:00
return fd - > font_name ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_antialiasing ( const RID & p_font_rid , TextServer : : FontAntialiasing p_antialiasing ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
2022-08-12 14:03:28 +03:00
if ( fd - > antialiasing ! = p_antialiasing ) {
2020-12-27 15:30:33 +02:00
_font_clear_cache ( fd ) ;
2022-08-12 14:03:28 +03:00
fd - > antialiasing = p_antialiasing ;
2020-12-27 15:30:33 +02:00
}
}
2022-09-27 11:23:34 +03:00
TextServer : : FontAntialiasing TextServerFallback : : _font_get_antialiasing ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , TextServer : : FONT_ANTIALIASING_NONE ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
2022-08-12 14:03:28 +03:00
return fd - > antialiasing ;
2020-12-27 15:30:33 +02:00
}
2024-03-11 13:42:16 +02:00
void TextServerFallback : : _font_set_disable_embedded_bitmaps ( const RID & p_font_rid , bool p_disable_embedded_bitmaps ) {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL ( fd ) ;
MutexLock lock ( fd - > mutex ) ;
if ( fd - > disable_embedded_bitmaps ! = p_disable_embedded_bitmaps ) {
_font_clear_cache ( fd ) ;
fd - > disable_embedded_bitmaps = p_disable_embedded_bitmaps ;
}
}
bool TextServerFallback : : _font_get_disable_embedded_bitmaps ( const RID & p_font_rid ) const {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL_V ( fd , false ) ;
MutexLock lock ( fd - > mutex ) ;
return fd - > disable_embedded_bitmaps ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_generate_mipmaps ( const RID & p_font_rid , bool p_generate_mipmaps ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2022-04-19 13:27:18 +03:00
MutexLock lock ( fd - > mutex ) ;
if ( fd - > mipmaps ! = p_generate_mipmaps ) {
2022-05-09 12:47:10 +03:00
for ( KeyValue < Vector2i , FontForSizeFallback * > & E : fd - > cache ) {
2022-04-19 13:27:18 +03:00
for ( int i = 0 ; i < E . value - > textures . size ( ) ; i + + ) {
E . value - > textures . write [ i ] . dirty = true ;
2022-09-28 12:43:34 +03:00
E . value - > textures . write [ i ] . texture = Ref < ImageTexture > ( ) ;
2022-04-19 13:27:18 +03:00
}
}
fd - > mipmaps = p_generate_mipmaps ;
}
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _font_get_generate_mipmaps ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , false ) ;
2022-04-19 13:27:18 +03:00
MutexLock lock ( fd - > mutex ) ;
return fd - > mipmaps ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_multichannel_signed_distance_field ( const RID & p_font_rid , bool p_msdf ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
if ( fd - > msdf ! = p_msdf ) {
_font_clear_cache ( fd ) ;
fd - > msdf = p_msdf ;
}
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _font_is_multichannel_signed_distance_field ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , false ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
return fd - > msdf ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_msdf_pixel_range ( const RID & p_font_rid , int64_t p_msdf_pixel_range ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
if ( fd - > msdf_range ! = p_msdf_pixel_range ) {
_font_clear_cache ( fd ) ;
fd - > msdf_range = p_msdf_pixel_range ;
}
}
2022-09-27 11:23:34 +03:00
int64_t TextServerFallback : : _font_get_msdf_pixel_range ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , false ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
return fd - > msdf_range ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_msdf_size ( const RID & p_font_rid , int64_t p_msdf_size ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
if ( fd - > msdf_source_size ! = p_msdf_size ) {
_font_clear_cache ( fd ) ;
fd - > msdf_source_size = p_msdf_size ;
}
}
2022-09-27 11:23:34 +03:00
int64_t TextServerFallback : : _font_get_msdf_size ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-08-14 10:42:49 +03:00
ERR_FAIL_NULL_V ( fd , 0 ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
return fd - > msdf_source_size ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_fixed_size ( const RID & p_font_rid , int64_t p_fixed_size ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
2022-04-05 13:40:26 +03:00
fd - > fixed_size = p_fixed_size ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
int64_t TextServerFallback : : _font_get_fixed_size ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-08-14 10:42:49 +03:00
ERR_FAIL_NULL_V ( fd , 0 ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
return fd - > fixed_size ;
}
2023-08-14 10:42:49 +03:00
void TextServerFallback : : _font_set_fixed_size_scale_mode ( const RID & p_font_rid , TextServer : : FixedSizeScaleMode p_fixed_size_scale_mode ) {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL ( fd ) ;
MutexLock lock ( fd - > mutex ) ;
fd - > fixed_size_scale_mode = p_fixed_size_scale_mode ;
}
TextServer : : FixedSizeScaleMode TextServerFallback : : _font_get_fixed_size_scale_mode ( const RID & p_font_rid ) const {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL_V ( fd , FIXED_SIZE_SCALE_DISABLE ) ;
MutexLock lock ( fd - > mutex ) ;
return fd - > fixed_size_scale_mode ;
}
2022-11-21 15:04:01 +02:00
void TextServerFallback : : _font_set_allow_system_fallback ( const RID & p_font_rid , bool p_allow_system_fallback ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2022-11-21 15:04:01 +02:00
MutexLock lock ( fd - > mutex ) ;
2022-12-10 17:07:42 +02:00
fd - > allow_system_fallback = p_allow_system_fallback ;
2022-11-21 15:04:01 +02:00
}
bool TextServerFallback : : _font_is_allow_system_fallback ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , false ) ;
2022-11-21 15:04:01 +02:00
MutexLock lock ( fd - > mutex ) ;
return fd - > allow_system_fallback ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_force_autohinter ( const RID & p_font_rid , bool p_force_autohinter ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
if ( fd - > force_autohinter ! = p_force_autohinter ) {
_font_clear_cache ( fd ) ;
fd - > force_autohinter = p_force_autohinter ;
}
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _font_is_force_autohinter ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , false ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
return fd - > force_autohinter ;
}
2025-04-01 13:36:10 +03:00
void TextServerFallback : : _font_set_modulate_color_glyphs ( const RID & p_font_rid , bool p_modulate ) {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL ( fd ) ;
MutexLock lock ( fd - > mutex ) ;
if ( fd - > modulate_color_glyphs ! = p_modulate ) {
fd - > modulate_color_glyphs = p_modulate ;
}
}
bool TextServerFallback : : _font_is_modulate_color_glyphs ( const RID & p_font_rid ) const {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL_V ( fd , false ) ;
MutexLock lock ( fd - > mutex ) ;
return fd - > modulate_color_glyphs ;
}
2026-03-06 17:20:04 +02:00
int64_t TextServerFallback : : _font_get_palette_count ( const RID & p_font_rid ) const {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL_V ( fd , 0 ) ;
return 0 ;
}
String TextServerFallback : : _font_get_palette_name ( const RID & p_font_rid , int64_t p_index ) const {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL_V ( fd , String ( ) ) ;
return String ( ) ;
}
Vector < Color > TextServerFallback : : _font_get_palette_colors ( const RID & p_font_rid , int64_t p_index ) const {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL_V ( fd , Vector < Color > ( ) ) ;
return Vector < Color > ( ) ;
}
void TextServerFallback : : _font_set_palette_custom_colors ( const RID & p_font_rid , const Vector < Color > & p_colors ) {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL ( fd ) ;
}
Vector < Color > TextServerFallback : : _font_get_palette_custom_colors ( const RID & p_font_rid ) const {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL_V ( fd , Vector < Color > ( ) ) ;
return Vector < Color > ( ) ;
}
int64_t TextServerFallback : : _font_get_used_palette ( const RID & p_font_rid ) const {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL_V ( fd , 0 ) ;
return 0 ;
}
void TextServerFallback : : _font_set_used_palette ( const RID & p_font_rid , int64_t p_index ) {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL ( fd ) ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_hinting ( const RID & p_font_rid , TextServer : : Hinting p_hinting ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
if ( fd - > hinting ! = p_hinting ) {
_font_clear_cache ( fd ) ;
fd - > hinting = p_hinting ;
}
}
2022-09-27 11:23:34 +03:00
TextServer : : Hinting TextServerFallback : : _font_get_hinting ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , HINTING_NONE ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
return fd - > hinting ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_subpixel_positioning ( const RID & p_font_rid , TextServer : : SubpixelPositioning p_subpixel ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2022-01-10 10:13:22 +02:00
MutexLock lock ( fd - > mutex ) ;
2022-04-05 13:40:26 +03:00
fd - > subpixel_positioning = p_subpixel ;
2022-01-10 10:13:22 +02:00
}
2022-09-27 11:23:34 +03:00
TextServer : : SubpixelPositioning TextServerFallback : : _font_get_subpixel_positioning ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , SUBPIXEL_POSITIONING_DISABLED ) ;
2022-01-10 10:13:22 +02:00
MutexLock lock ( fd - > mutex ) ;
return fd - > subpixel_positioning ;
}
2024-10-30 11:14:11 +02:00
void TextServerFallback : : _font_set_keep_rounding_remainders ( const RID & p_font_rid , bool p_keep_rounding_remainders ) {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL ( fd ) ;
MutexLock lock ( fd - > mutex ) ;
fd - > keep_rounding_remainders = p_keep_rounding_remainders ;
}
bool TextServerFallback : : _font_get_keep_rounding_remainders ( const RID & p_font_rid ) const {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL_V ( fd , false ) ;
MutexLock lock ( fd - > mutex ) ;
return fd - > keep_rounding_remainders ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_embolden ( const RID & p_font_rid , double p_strength ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2022-03-11 09:31:16 +02:00
MutexLock lock ( fd - > mutex ) ;
if ( fd - > embolden ! = p_strength ) {
_font_clear_cache ( fd ) ;
fd - > embolden = p_strength ;
}
}
2022-09-27 11:23:34 +03:00
double TextServerFallback : : _font_get_embolden ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , 0.0 ) ;
2022-03-11 09:31:16 +02:00
MutexLock lock ( fd - > mutex ) ;
return fd - > embolden ;
}
2023-08-24 11:56:50 +03:00
void TextServerFallback : : _font_set_spacing ( const RID & p_font_rid , SpacingType p_spacing , int64_t p_value ) {
ERR_FAIL_INDEX ( ( int ) p_spacing , 4 ) ;
2023-09-28 10:45:09 +03:00
FontFallbackLinkedVariation * fdv = font_var_owner . get_or_null ( p_font_rid ) ;
if ( fdv ) {
if ( fdv - > extra_spacing [ p_spacing ] ! = p_value ) {
fdv - > extra_spacing [ p_spacing ] = p_value ;
}
} else {
FontFallback * fd = font_owner . get_or_null ( p_font_rid ) ;
ERR_FAIL_NULL ( fd ) ;
2023-08-24 11:56:50 +03:00
2023-09-28 10:45:09 +03:00
MutexLock lock ( fd - > mutex ) ;
if ( fd - > extra_spacing [ p_spacing ] ! = p_value ) {
_font_clear_cache ( fd ) ;
fd - > extra_spacing [ p_spacing ] = p_value ;
}
2023-08-24 11:56:50 +03:00
}
}
int64_t TextServerFallback : : _font_get_spacing ( const RID & p_font_rid , SpacingType p_spacing ) const {
ERR_FAIL_INDEX_V ( ( int ) p_spacing , 4 , 0 ) ;
2023-09-28 10:45:09 +03:00
FontFallbackLinkedVariation * fdv = font_var_owner . get_or_null ( p_font_rid ) ;
if ( fdv ) {
return fdv - > extra_spacing [ p_spacing ] ;
} else {
FontFallback * fd = font_owner . get_or_null ( p_font_rid ) ;
ERR_FAIL_NULL_V ( fd , 0 ) ;
2023-08-24 11:56:50 +03:00
2023-09-28 10:45:09 +03:00
MutexLock lock ( fd - > mutex ) ;
return fd - > extra_spacing [ p_spacing ] ;
}
2023-08-24 11:56:50 +03:00
}
2024-06-02 21:21:18 +03:00
void TextServerFallback : : _font_set_baseline_offset ( const RID & p_font_rid , double p_baseline_offset ) {
2024-01-28 12:34:56 +02:00
FontFallbackLinkedVariation * fdv = font_var_owner . get_or_null ( p_font_rid ) ;
if ( fdv ) {
if ( fdv - > baseline_offset ! = p_baseline_offset ) {
fdv - > baseline_offset = p_baseline_offset ;
}
} else {
FontFallback * fd = font_owner . get_or_null ( p_font_rid ) ;
ERR_FAIL_NULL ( fd ) ;
MutexLock lock ( fd - > mutex ) ;
if ( fd - > baseline_offset ! = p_baseline_offset ) {
_font_clear_cache ( fd ) ;
fd - > baseline_offset = p_baseline_offset ;
}
}
}
2024-06-02 21:21:18 +03:00
double TextServerFallback : : _font_get_baseline_offset ( const RID & p_font_rid ) const {
2024-01-28 12:34:56 +02:00
FontFallbackLinkedVariation * fdv = font_var_owner . get_or_null ( p_font_rid ) ;
if ( fdv ) {
return fdv - > baseline_offset ;
} else {
FontFallback * fd = font_owner . get_or_null ( p_font_rid ) ;
ERR_FAIL_NULL_V ( fd , 0.0 ) ;
MutexLock lock ( fd - > mutex ) ;
return fd - > baseline_offset ;
}
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_transform ( const RID & p_font_rid , const Transform2D & p_transform ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2022-03-11 09:31:16 +02:00
MutexLock lock ( fd - > mutex ) ;
if ( fd - > transform ! = p_transform ) {
_font_clear_cache ( fd ) ;
fd - > transform = p_transform ;
}
}
2022-09-27 11:23:34 +03:00
Transform2D TextServerFallback : : _font_get_transform ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , Transform2D ( ) ) ;
2022-03-11 09:31:16 +02:00
MutexLock lock ( fd - > mutex ) ;
return fd - > transform ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_variation_coordinates ( const RID & p_font_rid , const Dictionary & p_variation_coordinates ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
2023-09-07 11:59:51 +03:00
if ( ! fd - > variation_coordinates . recursive_equal ( p_variation_coordinates , 1 ) ) {
_font_clear_cache ( fd ) ;
fd - > variation_coordinates = p_variation_coordinates . duplicate ( ) ;
}
2020-12-27 15:30:33 +02:00
}
2025-06-19 15:05:52 +03:00
double TextServerFallback : : _font_get_oversampling ( const RID & p_font_rid ) const {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL_V ( fd , - 1.0 ) ;
MutexLock lock ( fd - > mutex ) ;
return fd - > oversampling_override ;
}
void TextServerFallback : : _font_set_oversampling ( const RID & p_font_rid , double p_oversampling ) {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL ( fd ) ;
MutexLock lock ( fd - > mutex ) ;
if ( fd - > oversampling_override ! = p_oversampling ) {
_font_clear_cache ( fd ) ;
fd - > oversampling_override = p_oversampling ;
}
}
2022-09-27 11:23:34 +03:00
Dictionary TextServerFallback : : _font_get_variation_coordinates ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , Dictionary ( ) ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
return fd - > variation_coordinates ;
}
2025-03-30 14:20:25 +03:00
TypedArray < Vector2i > TextServerFallback : : _font_get_size_cache_list ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2025-03-30 14:20:25 +03:00
ERR_FAIL_NULL_V ( fd , TypedArray < Vector2i > ( ) ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
2025-03-30 14:20:25 +03:00
TypedArray < Vector2i > ret ;
for ( const KeyValue < Vector2i , FontForSizeFallback * > & E : fd - > cache ) {
if ( ( E . key . x % 64 = = 0 ) & & ( E . value - > viewport_oversampling = = 0 ) ) {
ret . push_back ( Vector2i ( E . key . x / 64 , E . key . y ) ) ;
}
2020-12-27 15:30:33 +02:00
}
2025-03-30 14:20:25 +03:00
return ret ;
2020-12-27 15:30:33 +02:00
}
2025-03-30 14:20:25 +03:00
TypedArray < Dictionary > TextServerFallback : : _font_get_size_cache_info ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2025-03-30 14:20:25 +03:00
ERR_FAIL_NULL_V ( fd , TypedArray < Dictionary > ( ) ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
2025-03-30 14:20:25 +03:00
TypedArray < Dictionary > ret ;
2022-05-09 12:47:10 +03:00
for ( const KeyValue < Vector2i , FontForSizeFallback * > & E : fd - > cache ) {
2025-03-30 14:20:25 +03:00
Dictionary size_info ;
size_info [ " size_px " ] = Vector2i ( E . key . x / 64 , E . key . y ) ;
if ( E . value - > viewport_oversampling ) {
size_info [ " viewport_oversampling " ] = double ( E . value - > viewport_oversampling ) / 64.0 ;
}
size_info [ " glyphs " ] = E . value - > glyph_map . size ( ) ;
size_info [ " textures " ] = E . value - > textures . size ( ) ;
uint64_t sz = 0 ;
for ( const ShelfPackTexture & tx : E . value - > textures ) {
sz + = tx . image - > get_data_size ( ) * 2 ;
}
size_info [ " textures_size " ] = sz ;
ret . push_back ( size_info ) ;
2020-12-27 15:30:33 +02:00
}
2025-03-30 14:20:25 +03:00
2020-12-27 15:30:33 +02:00
return ret ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_clear_size_cache ( const RID & p_font_rid ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
2023-02-26 17:55:04 +02:00
MutexLock ftlock ( ft_mutex ) ;
2022-05-09 12:47:10 +03:00
for ( const KeyValue < Vector2i , FontForSizeFallback * > & E : fd - > cache ) {
2025-03-30 14:20:25 +03:00
if ( E . value - > viewport_oversampling ! = 0 ) {
OversamplingLevel * ol = oversampling_levels . getptr ( E . value - > viewport_oversampling ) ;
if ( ol ) {
ol - > fonts . erase ( E . value ) ;
}
}
2021-08-09 14:13:42 -06:00
memdelete ( E . value ) ;
2020-12-27 15:30:33 +02:00
}
fd - > cache . clear ( ) ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_remove_size_cache ( const RID & p_font_rid , const Vector2i & p_size ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
2023-02-26 17:55:04 +02:00
MutexLock ftlock ( ft_mutex ) ;
2025-03-30 14:20:25 +03:00
Vector2i size = Vector2i ( p_size . x * 64 , p_size . y ) ;
if ( fd - > cache . has ( size ) ) {
if ( fd - > cache [ size ] - > viewport_oversampling ! = 0 ) {
OversamplingLevel * ol = oversampling_levels . getptr ( fd - > cache [ size ] - > viewport_oversampling ) ;
if ( ol ) {
ol - > fonts . erase ( fd - > cache [ size ] ) ;
}
}
memdelete ( fd - > cache [ size ] ) ;
fd - > cache . erase ( size ) ;
2020-12-27 15:30:33 +02:00
}
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_ascent ( const RID & p_font_rid , int64_t p_size , double p_ascent ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
ffsd - > ascent = p_ascent ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
double TextServerFallback : : _font_get_ascent ( const RID & p_font_rid , int64_t p_size ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , 0.0 ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , 0.0 ) ;
2020-12-27 15:30:33 +02:00
if ( fd - > msdf ) {
2024-05-30 22:57:28 -07:00
return ffsd - > ascent * ( double ) p_size / ( double ) fd - > msdf_source_size ;
2025-03-30 14:20:25 +03:00
} else if ( fd - > fixed_size > 0 & & fd - > fixed_size_scale_mode ! = FIXED_SIZE_SCALE_DISABLE & & size . x ! = p_size * 64 ) {
2023-08-14 10:42:49 +03:00
if ( fd - > fixed_size_scale_mode = = FIXED_SIZE_SCALE_ENABLED ) {
2024-05-30 22:57:28 -07:00
return ffsd - > ascent * ( double ) p_size / ( double ) fd - > fixed_size ;
2023-08-14 10:42:49 +03:00
} else {
2024-05-30 22:57:28 -07:00
return ffsd - > ascent * Math : : round ( ( double ) p_size / ( double ) fd - > fixed_size ) ;
2023-08-14 10:42:49 +03:00
}
2020-12-27 15:30:33 +02:00
} else {
2024-05-30 22:57:28 -07:00
return ffsd - > ascent ;
2020-12-27 15:30:33 +02:00
}
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_descent ( const RID & p_font_rid , int64_t p_size , double p_descent ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
Vector2i size = _get_size ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
ffsd - > descent = p_descent ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
double TextServerFallback : : _font_get_descent ( const RID & p_font_rid , int64_t p_size ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , 0.0 ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , 0.0 ) ;
2020-12-27 15:30:33 +02:00
if ( fd - > msdf ) {
2024-05-30 22:57:28 -07:00
return ffsd - > descent * ( double ) p_size / ( double ) fd - > msdf_source_size ;
2025-03-30 14:20:25 +03:00
} else if ( fd - > fixed_size > 0 & & fd - > fixed_size_scale_mode ! = FIXED_SIZE_SCALE_DISABLE & & size . x ! = p_size * 64 ) {
2023-08-14 10:42:49 +03:00
if ( fd - > fixed_size_scale_mode = = FIXED_SIZE_SCALE_ENABLED ) {
2024-05-30 22:57:28 -07:00
return ffsd - > descent * ( double ) p_size / ( double ) fd - > fixed_size ;
2023-08-14 10:42:49 +03:00
} else {
2024-05-30 22:57:28 -07:00
return ffsd - > descent * Math : : round ( ( double ) p_size / ( double ) fd - > fixed_size ) ;
2023-08-14 10:42:49 +03:00
}
2020-12-27 15:30:33 +02:00
} else {
2024-05-30 22:57:28 -07:00
return ffsd - > descent ;
2020-12-27 15:30:33 +02:00
}
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_underline_position ( const RID & p_font_rid , int64_t p_size , double p_underline_position ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
ffsd - > underline_position = p_underline_position ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
double TextServerFallback : : _font_get_underline_position ( const RID & p_font_rid , int64_t p_size ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , 0.0 ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , 0.0 ) ;
2020-12-27 15:30:33 +02:00
if ( fd - > msdf ) {
2024-05-30 22:57:28 -07:00
return ffsd - > underline_position * ( double ) p_size / ( double ) fd - > msdf_source_size ;
2025-03-30 14:20:25 +03:00
} else if ( fd - > fixed_size > 0 & & fd - > fixed_size_scale_mode ! = FIXED_SIZE_SCALE_DISABLE & & size . x ! = p_size * 64 ) {
2023-08-14 10:42:49 +03:00
if ( fd - > fixed_size_scale_mode = = FIXED_SIZE_SCALE_ENABLED ) {
2024-05-30 22:57:28 -07:00
return ffsd - > underline_position * ( double ) p_size / ( double ) fd - > fixed_size ;
2023-08-14 10:42:49 +03:00
} else {
2024-05-30 22:57:28 -07:00
return ffsd - > underline_position * Math : : round ( ( double ) p_size / ( double ) fd - > fixed_size ) ;
2023-08-14 10:42:49 +03:00
}
2020-12-27 15:30:33 +02:00
} else {
2024-05-30 22:57:28 -07:00
return ffsd - > underline_position ;
2020-12-27 15:30:33 +02:00
}
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_underline_thickness ( const RID & p_font_rid , int64_t p_size , double p_underline_thickness ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
ffsd - > underline_thickness = p_underline_thickness ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
double TextServerFallback : : _font_get_underline_thickness ( const RID & p_font_rid , int64_t p_size ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , 0.0 ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , 0.0 ) ;
2020-12-27 15:30:33 +02:00
if ( fd - > msdf ) {
2024-05-30 22:57:28 -07:00
return ffsd - > underline_thickness * ( double ) p_size / ( double ) fd - > msdf_source_size ;
2025-03-30 14:20:25 +03:00
} else if ( fd - > fixed_size > 0 & & fd - > fixed_size_scale_mode ! = FIXED_SIZE_SCALE_DISABLE & & size . x ! = p_size * 64 ) {
2023-08-14 10:42:49 +03:00
if ( fd - > fixed_size_scale_mode = = FIXED_SIZE_SCALE_ENABLED ) {
2024-05-30 22:57:28 -07:00
return ffsd - > underline_thickness * ( double ) p_size / ( double ) fd - > fixed_size ;
2023-08-14 10:42:49 +03:00
} else {
2024-05-30 22:57:28 -07:00
return ffsd - > underline_thickness * Math : : round ( ( double ) p_size / ( double ) fd - > fixed_size ) ;
2023-08-14 10:42:49 +03:00
}
2020-12-27 15:30:33 +02:00
} else {
2024-05-30 22:57:28 -07:00
return ffsd - > underline_thickness ;
2020-12-27 15:30:33 +02:00
}
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_scale ( const RID & p_font_rid , int64_t p_size , double p_scale ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2022-05-10 13:57:18 +03:00
# ifdef MODULE_FREETYPE_ENABLED
2026-02-02 11:36:42 +02:00
if ( fd - > face ) {
2022-05-10 13:57:18 +03:00
return ; // Do not override scale for dynamic fonts, it's calculated automatically.
}
# endif
2024-05-30 22:57:28 -07:00
ffsd - > scale = p_scale ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
double TextServerFallback : : _font_get_scale ( const RID & p_font_rid , int64_t p_size ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , 0.0 ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , 0.0 ) ;
2020-12-27 15:30:33 +02:00
if ( fd - > msdf ) {
2024-05-30 22:57:28 -07:00
return ffsd - > scale * ( double ) p_size / ( double ) fd - > msdf_source_size ;
2025-03-30 14:20:25 +03:00
} else if ( fd - > fixed_size > 0 & & fd - > fixed_size_scale_mode ! = FIXED_SIZE_SCALE_DISABLE & & size . x ! = p_size * 64 ) {
2023-08-14 10:42:49 +03:00
if ( fd - > fixed_size_scale_mode = = FIXED_SIZE_SCALE_ENABLED ) {
2024-05-30 22:57:28 -07:00
return ffsd - > scale * ( double ) p_size / ( double ) fd - > fixed_size ;
2023-08-14 10:42:49 +03:00
} else {
2024-05-30 22:57:28 -07:00
return ffsd - > scale * Math : : round ( ( double ) p_size / ( double ) fd - > fixed_size ) ;
2023-08-14 10:42:49 +03:00
}
2020-12-27 15:30:33 +02:00
} else {
2025-03-30 14:20:25 +03:00
return ffsd - > scale ;
2020-12-27 15:30:33 +02:00
}
}
2022-09-27 11:23:34 +03:00
int64_t TextServerFallback : : _font_get_texture_count ( const RID & p_font_rid , const Vector2i & p_size ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , 0 ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , 0 ) ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
return ffsd - > textures . size ( ) ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_clear_textures ( const RID & p_font_rid , const Vector2i & p_size ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
ffsd - > textures . clear ( ) ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_remove_texture ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_texture_index ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
ERR_FAIL_INDEX ( p_texture_index , ffsd - > textures . size ( ) ) ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
ffsd - > textures . remove_at ( p_texture_index ) ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_texture_image ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_texture_index , const Ref < Image > & p_image ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
ERR_FAIL_COND ( p_image . is_null ( ) ) ;
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2020-12-27 15:30:33 +02:00
ERR_FAIL_COND ( p_texture_index < 0 ) ;
2024-05-30 22:57:28 -07:00
if ( p_texture_index > = ffsd - > textures . size ( ) ) {
ffsd - > textures . resize ( p_texture_index + 1 ) ;
2020-12-27 15:30:33 +02:00
}
2024-05-30 22:57:28 -07:00
ShelfPackTexture & tex = ffsd - > textures . write [ p_texture_index ] ;
2020-12-27 15:30:33 +02:00
2024-02-05 10:38:32 +02:00
tex . image = p_image ;
2020-12-27 15:30:33 +02:00
tex . texture_w = p_image - > get_width ( ) ;
tex . texture_h = p_image - > get_height ( ) ;
2024-02-05 10:38:32 +02:00
Ref < Image > img = p_image ;
if ( fd - > mipmaps & & ! img - > has_mipmaps ( ) ) {
img = p_image - > duplicate ( ) ;
2022-04-19 13:27:18 +03:00
img - > generate_mipmaps ( ) ;
}
2022-05-04 01:49:20 +02:00
tex . texture = ImageTexture : : create_from_image ( img ) ;
2022-04-04 10:31:07 +03:00
tex . dirty = false ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
Ref < Image > TextServerFallback : : _font_get_texture_image ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_texture_index ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , Ref < Image > ( ) ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , Ref < Image > ( ) ) ;
ERR_FAIL_INDEX_V ( p_texture_index , ffsd - > textures . size ( ) , Ref < Image > ( ) ) ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
const ShelfPackTexture & tex = ffsd - > textures [ p_texture_index ] ;
2024-02-05 10:38:32 +02:00
return tex . image ;
2020-12-27 15:30:33 +02:00
}
2022-10-18 10:10:24 +03:00
void TextServerFallback : : _font_set_texture_offsets ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_texture_index , const PackedInt32Array & p_offsets ) {
ERR_FAIL_COND ( p_offsets . size ( ) % 4 ! = 0 ) ;
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2021-10-15 18:36:00 +03:00
ERR_FAIL_COND ( p_texture_index < 0 ) ;
2024-05-30 22:57:28 -07:00
if ( p_texture_index > = ffsd - > textures . size ( ) ) {
ffsd - > textures . resize ( p_texture_index + 1 ) ;
2020-12-27 15:30:33 +02:00
}
2024-05-30 22:57:28 -07:00
ShelfPackTexture & tex = ffsd - > textures . write [ p_texture_index ] ;
2022-10-18 10:10:24 +03:00
tex . shelves . clear ( ) ;
for ( int32_t i = 0 ; i < p_offsets . size ( ) ; i + = 4 ) {
tex . shelves . push_back ( Shelf ( p_offsets [ i ] , p_offsets [ i + 1 ] , p_offsets [ i + 2 ] , p_offsets [ i + 3 ] ) ) ;
}
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
PackedInt32Array TextServerFallback : : _font_get_texture_offsets ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_texture_index ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , PackedInt32Array ( ) ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , PackedInt32Array ( ) ) ;
ERR_FAIL_INDEX_V ( p_texture_index , ffsd - > textures . size ( ) , PackedInt32Array ( ) ) ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
const ShelfPackTexture & tex = ffsd - > textures [ p_texture_index ] ;
2022-10-18 10:10:24 +03:00
PackedInt32Array ret ;
ret . resize ( tex . shelves . size ( ) * 4 ) ;
int32_t * wr = ret . ptrw ( ) ;
int32_t i = 0 ;
for ( const Shelf & E : tex . shelves ) {
wr [ i * 4 ] = E . x ;
wr [ i * 4 + 1 ] = E . y ;
wr [ i * 4 + 2 ] = E . w ;
wr [ i * 4 + 3 ] = E . h ;
i + + ;
}
return ret ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
PackedInt32Array TextServerFallback : : _font_get_glyph_list ( const RID & p_font_rid , const Vector2i & p_size ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , PackedInt32Array ( ) ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , PackedInt32Array ( ) ) ;
2020-12-27 15:30:33 +02:00
2022-08-05 03:41:48 +02:00
PackedInt32Array ret ;
2024-05-30 22:57:28 -07:00
const HashMap < int32_t , FontGlyph > & gl = ffsd - > glyph_map ;
2022-05-08 10:09:19 +02:00
for ( const KeyValue < int32_t , FontGlyph > & E : gl ) {
ret . push_back ( E . key ) ;
2020-12-27 15:30:33 +02:00
}
return ret ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_clear_glyphs ( const RID & p_font_rid , const Vector2i & p_size ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
ffsd - > glyph_map . clear ( ) ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_remove_glyph ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_glyph ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
ffsd - > glyph_map . erase ( p_glyph ) ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
Vector2 TextServerFallback : : _font_get_glyph_advance ( const RID & p_font_rid , int64_t p_size , int64_t p_glyph ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , Vector2 ( ) ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , Vector2 ( ) ) ;
2022-08-12 14:03:28 +03:00
int mod = 0 ;
if ( fd - > antialiasing = = FONT_ANTIALIASING_LCD ) {
2024-05-30 22:57:28 -07:00
TextServer : : FontLCDSubpixelLayout layout = lcd_subpixel_layout . get ( ) ;
2022-08-12 14:03:28 +03:00
if ( layout ! = FONT_LCD_SUBPIXEL_LAYOUT_NONE ) {
mod = ( layout < < 24 ) ;
}
}
2024-05-30 22:57:28 -07:00
FontGlyph fgl ;
if ( ! _ensure_glyph ( fd , size , p_glyph | mod , fgl ) ) {
2020-12-27 15:30:33 +02:00
return Vector2 ( ) ; // Invalid or non graphicl glyph, do not display errors.
}
2022-03-13 14:50:36 +02:00
Vector2 ea ;
if ( fd - > embolden ! = 0.0 ) {
2025-03-30 14:20:25 +03:00
ea . x = fd - > embolden * double ( size . x ) / 4096.0 ;
2022-03-13 14:50:36 +02:00
}
2022-10-14 23:16:59 +03:00
double scale = _font_get_scale ( p_font_rid , p_size ) ;
2020-12-27 15:30:33 +02:00
if ( fd - > msdf ) {
2024-05-30 22:57:28 -07:00
return ( fgl . advance + ea ) * ( double ) p_size / ( double ) fd - > msdf_source_size ;
2025-03-30 14:20:25 +03:00
} else if ( fd - > fixed_size > 0 & & fd - > fixed_size_scale_mode ! = FIXED_SIZE_SCALE_DISABLE & & size . x ! = p_size * 64 ) {
2023-08-14 10:42:49 +03:00
if ( fd - > fixed_size_scale_mode = = FIXED_SIZE_SCALE_ENABLED ) {
2024-05-30 22:57:28 -07:00
return ( fgl . advance + ea ) * ( double ) p_size / ( double ) fd - > fixed_size ;
2023-08-14 10:42:49 +03:00
} else {
2024-05-30 22:57:28 -07:00
return ( fgl . advance + ea ) * Math : : round ( ( double ) p_size / ( double ) fd - > fixed_size ) ;
2023-08-14 10:42:49 +03:00
}
2025-03-30 14:20:25 +03:00
} else if ( ( scale = = 1.0 ) & & ( ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_DISABLED ) | | ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_AUTO & & size . x > SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64 ) ) ) {
2024-05-30 22:57:28 -07:00
return ( fgl . advance + ea ) . round ( ) ;
2020-12-27 15:30:33 +02:00
} else {
2024-05-30 22:57:28 -07:00
return fgl . advance + ea ;
2020-12-27 15:30:33 +02:00
}
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_glyph_advance ( const RID & p_font_rid , int64_t p_size , int64_t p_glyph , const Vector2 & p_advance ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
FontGlyph & fgl = ffsd - > glyph_map [ p_glyph ] ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
fgl . advance = p_advance ;
fgl . found = true ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
Vector2 TextServerFallback : : _font_get_glyph_offset ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_glyph ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , Vector2 ( ) ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , Vector2 ( ) ) ;
2022-08-12 14:03:28 +03:00
int mod = 0 ;
if ( fd - > antialiasing = = FONT_ANTIALIASING_LCD ) {
2024-05-30 22:57:28 -07:00
TextServer : : FontLCDSubpixelLayout layout = lcd_subpixel_layout . get ( ) ;
2022-08-12 14:03:28 +03:00
if ( layout ! = FONT_LCD_SUBPIXEL_LAYOUT_NONE ) {
mod = ( layout < < 24 ) ;
}
}
2024-05-30 22:57:28 -07:00
FontGlyph fgl ;
if ( ! _ensure_glyph ( fd , size , p_glyph | mod , fgl ) ) {
2020-12-27 15:30:33 +02:00
return Vector2 ( ) ; // Invalid or non graphicl glyph, do not display errors.
}
if ( fd - > msdf ) {
2024-05-30 22:57:28 -07:00
return fgl . rect . position * ( double ) p_size . x / ( double ) fd - > msdf_source_size ;
2025-03-30 14:20:25 +03:00
} else if ( fd - > fixed_size > 0 & & fd - > fixed_size_scale_mode ! = FIXED_SIZE_SCALE_DISABLE & & size . x ! = p_size . x * 64 ) {
2023-08-14 10:42:49 +03:00
if ( fd - > fixed_size_scale_mode = = FIXED_SIZE_SCALE_ENABLED ) {
2024-05-30 22:57:28 -07:00
return fgl . rect . position * ( double ) p_size . x / ( double ) fd - > fixed_size ;
2023-08-14 10:42:49 +03:00
} else {
2024-05-30 22:57:28 -07:00
return fgl . rect . position * Math : : round ( ( double ) p_size . x / ( double ) fd - > fixed_size ) ;
2023-08-14 10:42:49 +03:00
}
2020-12-27 15:30:33 +02:00
} else {
2024-05-30 22:57:28 -07:00
return fgl . rect . position ;
2020-12-27 15:30:33 +02:00
}
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_glyph_offset ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_glyph , const Vector2 & p_offset ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
FontGlyph & fgl = ffsd - > glyph_map [ p_glyph ] ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
fgl . rect . position = p_offset ;
fgl . found = true ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
Vector2 TextServerFallback : : _font_get_glyph_size ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_glyph ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , Vector2 ( ) ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , Vector2 ( ) ) ;
2022-08-12 14:03:28 +03:00
int mod = 0 ;
if ( fd - > antialiasing = = FONT_ANTIALIASING_LCD ) {
2024-05-30 22:57:28 -07:00
TextServer : : FontLCDSubpixelLayout layout = lcd_subpixel_layout . get ( ) ;
2022-08-12 14:03:28 +03:00
if ( layout ! = FONT_LCD_SUBPIXEL_LAYOUT_NONE ) {
mod = ( layout < < 24 ) ;
}
}
2024-05-30 22:57:28 -07:00
FontGlyph fgl ;
if ( ! _ensure_glyph ( fd , size , p_glyph | mod , fgl ) ) {
2020-12-27 15:30:33 +02:00
return Vector2 ( ) ; // Invalid or non graphicl glyph, do not display errors.
}
if ( fd - > msdf ) {
2024-05-30 22:57:28 -07:00
return fgl . rect . size * ( double ) p_size . x / ( double ) fd - > msdf_source_size ;
2025-03-30 14:20:25 +03:00
} else if ( fd - > fixed_size > 0 & & fd - > fixed_size_scale_mode ! = FIXED_SIZE_SCALE_DISABLE & & size . x ! = p_size . x * 64 ) {
2023-08-14 10:42:49 +03:00
if ( fd - > fixed_size_scale_mode = = FIXED_SIZE_SCALE_ENABLED ) {
2024-05-30 22:57:28 -07:00
return fgl . rect . size * ( double ) p_size . x / ( double ) fd - > fixed_size ;
2023-08-14 10:42:49 +03:00
} else {
2024-05-30 22:57:28 -07:00
return fgl . rect . size * Math : : round ( ( double ) p_size . x / ( double ) fd - > fixed_size ) ;
2023-08-14 10:42:49 +03:00
}
2020-12-27 15:30:33 +02:00
} else {
2024-05-30 22:57:28 -07:00
return fgl . rect . size ;
2020-12-27 15:30:33 +02:00
}
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_glyph_size ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_glyph , const Vector2 & p_gl_size ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
FontGlyph & fgl = ffsd - > glyph_map [ p_glyph ] ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
fgl . rect . size = p_gl_size ;
fgl . found = true ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
Rect2 TextServerFallback : : _font_get_glyph_uv_rect ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_glyph ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , Rect2 ( ) ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , Rect2 ( ) ) ;
2022-08-12 14:03:28 +03:00
int mod = 0 ;
if ( fd - > antialiasing = = FONT_ANTIALIASING_LCD ) {
2024-05-30 22:57:28 -07:00
TextServer : : FontLCDSubpixelLayout layout = lcd_subpixel_layout . get ( ) ;
2022-08-12 14:03:28 +03:00
if ( layout ! = FONT_LCD_SUBPIXEL_LAYOUT_NONE ) {
mod = ( layout < < 24 ) ;
}
}
2024-05-30 22:57:28 -07:00
FontGlyph fgl ;
if ( ! _ensure_glyph ( fd , size , p_glyph | mod , fgl ) ) {
2020-12-27 15:30:33 +02:00
return Rect2 ( ) ; // Invalid or non graphicl glyph, do not display errors.
}
2024-05-30 22:57:28 -07:00
return fgl . uv_rect ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_glyph_uv_rect ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_glyph , const Rect2 & p_uv_rect ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
FontGlyph & fgl = ffsd - > glyph_map [ p_glyph ] ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
fgl . uv_rect = p_uv_rect ;
fgl . found = true ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
int64_t TextServerFallback : : _font_get_glyph_texture_idx ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_glyph ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , - 1 ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , - 1 ) ;
2022-08-12 14:03:28 +03:00
int mod = 0 ;
if ( fd - > antialiasing = = FONT_ANTIALIASING_LCD ) {
2024-05-30 22:57:28 -07:00
TextServer : : FontLCDSubpixelLayout layout = lcd_subpixel_layout . get ( ) ;
2022-08-12 14:03:28 +03:00
if ( layout ! = FONT_LCD_SUBPIXEL_LAYOUT_NONE ) {
mod = ( layout < < 24 ) ;
}
}
2024-05-30 22:57:28 -07:00
FontGlyph fgl ;
if ( ! _ensure_glyph ( fd , size , p_glyph | mod , fgl ) ) {
2020-12-27 15:30:33 +02:00
return - 1 ; // Invalid or non graphicl glyph, do not display errors.
}
2024-05-30 22:57:28 -07:00
return fgl . texture_idx ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_glyph_texture_idx ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_glyph , int64_t p_texture_idx ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
FontGlyph & fgl = ffsd - > glyph_map [ p_glyph ] ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
fgl . texture_idx = p_texture_idx ;
fgl . found = true ;
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
RID TextServerFallback : : _font_get_glyph_texture_rid ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_glyph ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , RID ( ) ) ;
2022-04-19 13:27:18 +03:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , RID ( ) ) ;
2022-08-12 14:03:28 +03:00
int mod = 0 ;
if ( fd - > antialiasing = = FONT_ANTIALIASING_LCD ) {
2024-05-30 22:57:28 -07:00
TextServer : : FontLCDSubpixelLayout layout = lcd_subpixel_layout . get ( ) ;
2022-08-12 14:03:28 +03:00
if ( layout ! = FONT_LCD_SUBPIXEL_LAYOUT_NONE ) {
mod = ( layout < < 24 ) ;
}
}
2024-05-30 22:57:28 -07:00
FontGlyph fgl ;
if ( ! _ensure_glyph ( fd , size , p_glyph | mod , fgl ) ) {
2022-04-19 13:27:18 +03:00
return RID ( ) ; // Invalid or non graphicl glyph, do not display errors.
}
2024-05-30 22:57:28 -07:00
ERR_FAIL_COND_V ( fgl . texture_idx < - 1 | | fgl . texture_idx > = ffsd - > textures . size ( ) , RID ( ) ) ;
2022-04-19 13:27:18 +03:00
2026-02-26 10:25:59 +02:00
if ( fgl . texture_idx ! = - 1 ) {
if ( ffsd - > textures [ fgl . texture_idx ] . dirty ) {
ShelfPackTexture & tex = ffsd - > textures . write [ fgl . texture_idx ] ;
Ref < Image > img = tex . image ;
if ( fgl . from_svg ) {
// Same as the "fix alpha border" process option when importing SVGs
img - > fix_alpha_edges ( ) ;
}
if ( fd - > mipmaps & & ! img - > has_mipmaps ( ) ) {
img = tex . image - > duplicate ( ) ;
img - > generate_mipmaps ( ) ;
}
if ( tex . texture . is_null ( ) ) {
tex . texture = ImageTexture : : create_from_image ( img ) ;
} else {
tex . texture - > update ( img ) ;
2022-04-19 13:27:18 +03:00
}
2026-02-26 10:25:59 +02:00
tex . dirty = false ;
2022-04-19 13:27:18 +03:00
}
2026-02-26 10:25:59 +02:00
return ffsd - > textures [ fgl . texture_idx ] . texture - > get_rid ( ) ;
2022-04-19 13:27:18 +03:00
}
return RID ( ) ;
}
2022-09-27 11:23:34 +03:00
Size2 TextServerFallback : : _font_get_glyph_texture_size ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_glyph ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , Size2 ( ) ) ;
2022-04-19 13:27:18 +03:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , Size2 ( ) ) ;
2022-08-12 14:03:28 +03:00
int mod = 0 ;
if ( fd - > antialiasing = = FONT_ANTIALIASING_LCD ) {
2024-05-30 22:57:28 -07:00
TextServer : : FontLCDSubpixelLayout layout = lcd_subpixel_layout . get ( ) ;
2022-08-12 14:03:28 +03:00
if ( layout ! = FONT_LCD_SUBPIXEL_LAYOUT_NONE ) {
mod = ( layout < < 24 ) ;
}
}
2024-05-30 22:57:28 -07:00
FontGlyph fgl ;
if ( ! _ensure_glyph ( fd , size , p_glyph | mod , fgl ) ) {
2022-04-19 13:27:18 +03:00
return Size2 ( ) ; // Invalid or non graphicl glyph, do not display errors.
}
2024-05-30 22:57:28 -07:00
ERR_FAIL_COND_V ( fgl . texture_idx < - 1 | | fgl . texture_idx > = ffsd - > textures . size ( ) , Size2 ( ) ) ;
2022-04-19 13:27:18 +03:00
2026-02-26 10:25:59 +02:00
if ( fgl . texture_idx ! = - 1 ) {
if ( ffsd - > textures [ fgl . texture_idx ] . dirty ) {
ShelfPackTexture & tex = ffsd - > textures . write [ fgl . texture_idx ] ;
Ref < Image > img = tex . image ;
if ( fgl . from_svg ) {
// Same as the "fix alpha border" process option when importing SVGs
img - > fix_alpha_edges ( ) ;
}
if ( fd - > mipmaps & & ! img - > has_mipmaps ( ) ) {
img = tex . image - > duplicate ( ) ;
img - > generate_mipmaps ( ) ;
2022-04-19 13:27:18 +03:00
}
2026-02-26 10:25:59 +02:00
if ( tex . texture . is_null ( ) ) {
tex . texture = ImageTexture : : create_from_image ( img ) ;
} else {
tex . texture - > update ( img ) ;
}
tex . dirty = false ;
2022-04-19 13:27:18 +03:00
}
2026-02-26 10:25:59 +02:00
return ffsd - > textures [ fgl . texture_idx ] . texture - > get_size ( ) ;
2022-04-19 13:27:18 +03:00
}
return Size2 ( ) ;
}
2022-09-27 11:23:34 +03:00
Dictionary TextServerFallback : : _font_get_glyph_contours ( const RID & p_font_rid , int64_t p_size , int64_t p_index ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , Dictionary ( ) ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , Dictionary ( ) ) ;
2020-12-27 15:30:33 +02:00
2022-04-05 13:40:26 +03:00
# ifdef MODULE_FREETYPE_ENABLED
2022-02-13 14:41:29 +02:00
PackedVector3Array points ;
PackedInt32Array contours ;
2022-04-05 13:40:26 +03:00
2022-02-13 14:41:29 +02:00
int32_t index = p_index & 0xffffff ; // Remove subpixel shifts.
2020-12-27 15:30:33 +02:00
2026-02-02 11:36:42 +02:00
int error = FT_Load_Glyph ( fd - > face , FT_Get_Char_Index ( fd - > face , index ) , FT_LOAD_NO_BITMAP | ( fd - > force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0 ) ) ;
2022-02-13 14:41:29 +02:00
ERR_FAIL_COND_V ( error , Dictionary ( ) ) ;
2020-12-27 15:30:33 +02:00
2022-04-25 13:14:30 +03:00
if ( fd - > embolden ! = 0.f ) {
2025-03-30 14:20:25 +03:00
FT_Pos strength = fd - > embolden * size . x / 16 ; // 26.6 fractional units (1 / 64).
2026-02-02 11:36:42 +02:00
FT_Outline_Embolden ( & fd - > face - > glyph - > outline , strength ) ;
2022-04-25 13:14:30 +03:00
}
if ( fd - > transform ! = Transform2D ( ) ) {
FT_Matrix mat = { FT_Fixed ( fd - > transform [ 0 ] [ 0 ] * 65536 ) , FT_Fixed ( fd - > transform [ 0 ] [ 1 ] * 65536 ) , FT_Fixed ( fd - > transform [ 1 ] [ 0 ] * 65536 ) , FT_Fixed ( fd - > transform [ 1 ] [ 1 ] * 65536 ) } ; // 16.16 fractional units (1 / 65536).
2026-02-02 11:36:42 +02:00
FT_Outline_Transform ( & fd - > face - > glyph - > outline , & mat ) ;
2022-04-25 13:14:30 +03:00
}
2025-03-30 14:20:25 +03:00
double scale = ( 1.0 / 64.0 ) * ffsd - > scale ;
2020-12-27 15:30:33 +02:00
if ( fd - > msdf ) {
2022-02-13 14:41:29 +02:00
scale = scale * ( double ) p_size / ( double ) fd - > msdf_source_size ;
2025-03-30 14:20:25 +03:00
} else if ( fd - > fixed_size > 0 & & fd - > fixed_size_scale_mode ! = FIXED_SIZE_SCALE_DISABLE & & size . x ! = p_size * 64 ) {
2023-08-14 10:42:49 +03:00
if ( fd - > fixed_size_scale_mode = = FIXED_SIZE_SCALE_ENABLED ) {
scale = scale * ( double ) p_size / ( double ) fd - > fixed_size ;
} else {
scale = scale * Math : : round ( ( double ) p_size / ( double ) fd - > fixed_size ) ;
}
2020-12-27 15:30:33 +02:00
}
2026-02-02 11:36:42 +02:00
for ( short i = 0 ; i < fd - > face - > glyph - > outline . n_points ; i + + ) {
points . push_back ( Vector3 ( fd - > face - > glyph - > outline . points [ i ] . x * scale , - fd - > face - > glyph - > outline . points [ i ] . y * scale , FT_CURVE_TAG ( fd - > face - > glyph - > outline . tags [ i ] ) ) ) ;
2020-12-27 15:30:33 +02:00
}
2026-02-02 11:36:42 +02:00
for ( short i = 0 ; i < fd - > face - > glyph - > outline . n_contours ; i + + ) {
contours . push_back ( fd - > face - > glyph - > outline . contours [ i ] ) ;
2020-12-27 15:30:33 +02:00
}
2026-02-02 11:36:42 +02:00
bool orientation = ( FT_Outline_Get_Orientation ( & fd - > face - > glyph - > outline ) = = FT_ORIENTATION_FILL_RIGHT ) ;
2021-08-28 00:19:51 +03:00
Dictionary out ;
out [ " points " ] = points ;
out [ " contours " ] = contours ;
out [ " orientation " ] = orientation ;
return out ;
2022-04-05 13:40:26 +03:00
# else
return Dictionary ( ) ;
# endif
2020-12-27 15:30:33 +02:00
}
2022-09-27 11:23:34 +03:00
TypedArray < Vector2i > TextServerFallback : : _font_get_kerning_list ( const RID & p_font_rid , int64_t p_size ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , TypedArray < Vector2i > ( ) ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , p_size ) ;
2020-08-05 09:25:28 +03:00
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , TypedArray < Vector2i > ( ) ) ;
2020-08-05 09:25:28 +03:00
2022-08-05 03:41:48 +02:00
TypedArray < Vector2i > ret ;
2024-05-30 22:57:28 -07:00
for ( const KeyValue < Vector2i , Vector2 > & E : ffsd - > kerning_map ) {
2021-08-09 14:13:42 -06:00
ret . push_back ( E . key ) ;
2021-02-06 16:34:06 +02:00
}
2020-12-27 15:30:33 +02:00
return ret ;
2021-02-06 16:34:06 +02:00
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_clear_kerning_map ( const RID & p_font_rid , int64_t p_size ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
ffsd - > kerning_map . clear ( ) ;
2021-02-06 16:34:06 +02:00
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_remove_kerning ( const RID & p_font_rid , int64_t p_size , const Vector2i & p_glyph_pair ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
ffsd - > kerning_map . erase ( p_glyph_pair ) ;
2021-02-06 16:34:06 +02:00
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_kerning ( const RID & p_font_rid , int64_t p_size , const Vector2i & p_glyph_pair , const Vector2 & p_kerning ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2021-02-06 16:34:06 +02:00
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , p_size ) ;
2020-08-05 09:25:28 +03:00
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
ffsd - > kerning_map [ p_glyph_pair ] = p_kerning ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
Vector2 TextServerFallback : : _font_get_kerning ( const RID & p_font_rid , int64_t p_size , const Vector2i & p_glyph_pair ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , Vector2 ( ) ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , p_size ) ;
2020-08-05 09:25:28 +03:00
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , Vector2 ( ) ) ;
2020-08-05 09:25:28 +03:00
2024-05-30 22:57:28 -07:00
const HashMap < Vector2i , Vector2 > & kern = ffsd - > kerning_map ;
2021-02-15 10:46:23 +02:00
2020-12-27 15:30:33 +02:00
if ( kern . has ( p_glyph_pair ) ) {
if ( fd - > msdf ) {
2022-02-13 14:41:29 +02:00
return kern [ p_glyph_pair ] * ( double ) p_size / ( double ) fd - > msdf_source_size ;
2025-03-30 14:20:25 +03:00
} else if ( fd - > fixed_size > 0 & & fd - > fixed_size_scale_mode ! = FIXED_SIZE_SCALE_DISABLE & & size . x ! = p_size * 64 ) {
2023-08-14 10:42:49 +03:00
if ( fd - > fixed_size_scale_mode = = FIXED_SIZE_SCALE_ENABLED ) {
return kern [ p_glyph_pair ] * ( double ) p_size / ( double ) fd - > fixed_size ;
} else {
return kern [ p_glyph_pair ] * Math : : round ( ( double ) p_size / ( double ) fd - > fixed_size ) ;
}
2020-12-27 15:30:33 +02:00
} else {
return kern [ p_glyph_pair ] ;
}
} else {
# ifdef MODULE_FREETYPE_ENABLED
2026-02-02 11:36:42 +02:00
if ( fd - > face ) {
2020-12-27 15:30:33 +02:00
FT_Vector delta ;
2026-02-02 11:36:42 +02:00
int32_t glyph_a = FT_Get_Char_Index ( fd - > face , p_glyph_pair . x ) ;
int32_t glyph_b = FT_Get_Char_Index ( fd - > face , p_glyph_pair . y ) ;
FT_Get_Kerning ( fd - > face , glyph_a , glyph_b , FT_KERNING_DEFAULT , & delta ) ;
2020-12-27 15:30:33 +02:00
if ( fd - > msdf ) {
2022-02-13 14:41:29 +02:00
return Vector2 ( delta . x , delta . y ) * ( double ) p_size / ( double ) fd - > msdf_source_size ;
2025-03-30 14:20:25 +03:00
} else if ( fd - > fixed_size > 0 & & fd - > fixed_size_scale_mode ! = FIXED_SIZE_SCALE_DISABLE & & size . x ! = p_size * 64 ) {
2023-08-14 10:42:49 +03:00
if ( fd - > fixed_size_scale_mode = = FIXED_SIZE_SCALE_ENABLED ) {
return Vector2 ( delta . x , delta . y ) * ( double ) p_size / ( double ) fd - > fixed_size ;
} else {
return Vector2 ( delta . x , delta . y ) * Math : : round ( ( double ) p_size / ( double ) fd - > fixed_size ) ;
}
2020-12-27 15:30:33 +02:00
} else {
return Vector2 ( delta . x , delta . y ) ;
}
}
# endif
}
return Vector2 ( ) ;
2021-02-15 10:46:23 +02:00
}
2022-09-27 11:23:34 +03:00
int64_t TextServerFallback : : _font_get_glyph_index ( const RID & p_font_rid , int64_t p_size , int64_t p_char , int64_t p_variation_selector ) const {
2021-10-15 18:36:00 +03:00
ERR_FAIL_COND_V_MSG ( ( p_char > = 0xd800 & & p_char < = 0xdfff ) | | ( p_char > 0x10ffff ) , 0 , " Unicode parsing error: Invalid unicode codepoint " + String : : num_int64 ( p_char , 16 ) + " . " ) ;
2022-02-13 14:41:29 +02:00
return ( int64_t ) p_char ;
2020-08-05 09:25:28 +03:00
}
2023-02-27 16:21:28 +02:00
int64_t TextServerFallback : : _font_get_char_from_glyph_index ( const RID & p_font_rid , int64_t p_size , int64_t p_glyph_index ) const {
return p_glyph_index ;
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _font_has_char ( const RID & p_font_rid , int64_t p_char ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2021-10-15 18:36:00 +03:00
ERR_FAIL_COND_V_MSG ( ( p_char > = 0xd800 & & p_char < = 0xdfff ) | | ( p_char > 0x10ffff ) , false , " Unicode parsing error: Invalid unicode codepoint " + String : : num_int64 ( p_char , 16 ) + " . " ) ;
2022-09-16 19:46:11 +03:00
if ( ! fd ) {
return false ;
}
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
2020-12-27 15:30:33 +02:00
if ( fd - > cache . is_empty ( ) ) {
2025-03-30 14:20:25 +03:00
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , fd - > msdf ? Vector2i ( fd - > msdf_source_size * 64 , 0 ) : Vector2i ( 16 * 64 , 0 ) , ffsd ) , false ) ;
2024-05-30 22:57:28 -07:00
} else {
ffsd = fd - > cache . begin ( ) - > value ;
2020-12-27 15:30:33 +02:00
}
# ifdef MODULE_FREETYPE_ENABLED
2026-02-02 11:36:42 +02:00
if ( fd - > face ) {
return FT_Get_Char_Index ( fd - > face , p_char ) ! = 0 ;
2020-12-27 15:30:33 +02:00
}
# endif
2024-05-30 22:57:28 -07:00
return ffsd - > glyph_map . has ( ( int32_t ) p_char ) ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
String TextServerFallback : : _font_get_supported_chars ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , String ( ) ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
2020-12-27 15:30:33 +02:00
if ( fd - > cache . is_empty ( ) ) {
2025-03-30 14:20:25 +03:00
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , fd - > msdf ? Vector2i ( fd - > msdf_source_size * 64 , 0 ) : Vector2i ( 16 * 64 , 0 ) , ffsd ) , String ( ) ) ;
2024-05-30 22:57:28 -07:00
} else {
ffsd = fd - > cache . begin ( ) - > value ;
2020-12-27 15:30:33 +02:00
}
String chars ;
# ifdef MODULE_FREETYPE_ENABLED
2026-02-02 11:36:42 +02:00
if ( fd - > face ) {
2020-12-27 15:30:33 +02:00
FT_UInt gindex ;
2026-02-02 11:36:42 +02:00
FT_ULong charcode = FT_Get_First_Char ( fd - > face , & gindex ) ;
2020-12-27 15:30:33 +02:00
while ( gindex ! = 0 ) {
if ( charcode ! = 0 ) {
2022-02-13 14:41:29 +02:00
chars = chars + String : : chr ( charcode ) ;
2020-12-27 15:30:33 +02:00
}
2026-02-02 11:36:42 +02:00
charcode = FT_Get_Next_Char ( fd - > face , charcode , & gindex ) ;
2020-12-27 15:30:33 +02:00
}
return chars ;
}
# endif
2024-05-30 22:57:28 -07:00
const HashMap < int32_t , FontGlyph > & gl = ffsd - > glyph_map ;
for ( const KeyValue < int32_t , FontGlyph > & E : gl ) {
chars = chars + String : : chr ( E . key ) ;
2020-12-27 15:30:33 +02:00
}
return chars ;
2020-08-05 09:25:28 +03:00
}
2024-07-22 10:12:00 +03:00
PackedInt32Array TextServerFallback : : _font_get_supported_glyphs ( const RID & p_font_rid ) const {
FontFallback * fd = _get_font_data ( p_font_rid ) ;
ERR_FAIL_NULL_V ( fd , PackedInt32Array ( ) ) ;
MutexLock lock ( fd - > mutex ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * at_size = nullptr ;
2024-07-22 10:12:00 +03:00
if ( fd - > cache . is_empty ( ) ) {
2025-03-30 14:20:25 +03:00
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , fd - > msdf ? Vector2i ( fd - > msdf_source_size * 64 , 0 ) : Vector2i ( 16 * 64 , 0 ) , at_size ) , PackedInt32Array ( ) ) ;
2024-05-30 22:57:28 -07:00
} else {
at_size = fd - > cache . begin ( ) - > value ;
2024-07-22 10:12:00 +03:00
}
PackedInt32Array glyphs ;
# ifdef MODULE_FREETYPE_ENABLED
2026-02-02 11:36:42 +02:00
if ( fd - > face ) {
2024-07-22 10:12:00 +03:00
FT_UInt gindex ;
2026-02-02 11:36:42 +02:00
FT_ULong charcode = FT_Get_First_Char ( fd - > face , & gindex ) ;
2024-07-22 10:12:00 +03:00
while ( gindex ! = 0 ) {
glyphs . push_back ( gindex ) ;
2026-02-02 11:36:42 +02:00
charcode = FT_Get_Next_Char ( fd - > face , charcode , & gindex ) ;
2024-07-22 10:12:00 +03:00
}
return glyphs ;
}
# endif
if ( at_size ) {
const HashMap < int32_t , FontGlyph > & gl = at_size - > glyph_map ;
for ( const KeyValue < int32_t , FontGlyph > & E : gl ) {
glyphs . push_back ( E . key ) ;
}
}
return glyphs ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_render_range ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_start , int64_t p_end ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2021-10-15 18:36:00 +03:00
ERR_FAIL_COND_MSG ( ( p_start > = 0xd800 & & p_start < = 0xdfff ) | | ( p_start > 0x10ffff ) , " Unicode parsing error: Invalid unicode codepoint " + String : : num_int64 ( p_start , 16 ) + " . " ) ;
ERR_FAIL_COND_MSG ( ( p_end > = 0xd800 & & p_end < = 0xdfff ) | | ( p_end > 0x10ffff ) , " Unicode parsing error: Invalid unicode codepoint " + String : : num_int64 ( p_end , 16 ) + " . " ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2022-02-13 14:41:29 +02:00
for ( int64_t i = p_start ; i < = p_end ; i + + ) {
2022-01-10 10:13:22 +02:00
# ifdef MODULE_FREETYPE_ENABLED
int32_t idx = i ;
2026-02-02 11:36:42 +02:00
if ( fd - > face ) {
2024-05-30 22:57:28 -07:00
FontGlyph fgl ;
2022-01-10 10:13:22 +02:00
if ( fd - > msdf ) {
2024-05-30 22:57:28 -07:00
_ensure_glyph ( fd , size , ( int32_t ) idx , fgl ) ;
2022-01-10 10:13:22 +02:00
} else {
2022-08-12 14:03:28 +03:00
for ( int aa = 0 ; aa < ( ( fd - > antialiasing = = FONT_ANTIALIASING_LCD ) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1 ) ; aa + + ) {
2025-03-30 14:20:25 +03:00
if ( ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_ONE_QUARTER ) | | ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_AUTO & & size . x < = SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64 ) ) {
2024-05-30 22:57:28 -07:00
_ensure_glyph ( fd , size , ( int32_t ) idx | ( 0 < < 27 ) | ( aa < < 24 ) , fgl ) ;
_ensure_glyph ( fd , size , ( int32_t ) idx | ( 1 < < 27 ) | ( aa < < 24 ) , fgl ) ;
_ensure_glyph ( fd , size , ( int32_t ) idx | ( 2 < < 27 ) | ( aa < < 24 ) , fgl ) ;
_ensure_glyph ( fd , size , ( int32_t ) idx | ( 3 < < 27 ) | ( aa < < 24 ) , fgl ) ;
2025-03-30 14:20:25 +03:00
} else if ( ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_ONE_HALF ) | | ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_AUTO & & size . x < = SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64 ) ) {
2024-05-30 22:57:28 -07:00
_ensure_glyph ( fd , size , ( int32_t ) idx | ( 1 < < 27 ) | ( aa < < 24 ) , fgl ) ;
_ensure_glyph ( fd , size , ( int32_t ) idx | ( 0 < < 27 ) | ( aa < < 24 ) , fgl ) ;
2022-08-12 14:03:28 +03:00
} else {
2024-05-30 22:57:28 -07:00
_ensure_glyph ( fd , size , ( int32_t ) idx | ( aa < < 24 ) , fgl ) ;
2022-08-12 14:03:28 +03:00
}
2022-01-10 10:13:22 +02:00
}
}
}
# endif
2020-12-27 15:30:33 +02:00
}
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_render_glyph ( const RID & p_font_rid , const Vector2i & p_size , int64_t p_index ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size_outline ( fd , p_size ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2022-01-10 10:13:22 +02:00
# ifdef MODULE_FREETYPE_ENABLED
2022-02-13 14:41:29 +02:00
int32_t idx = p_index & 0xffffff ; // Remove subpixel shifts.
2026-02-02 11:36:42 +02:00
if ( fd - > face ) {
2024-05-30 22:57:28 -07:00
FontGlyph fgl ;
2022-01-10 10:13:22 +02:00
if ( fd - > msdf ) {
2024-05-30 22:57:28 -07:00
_ensure_glyph ( fd , size , ( int32_t ) idx , fgl ) ;
2022-01-10 10:13:22 +02:00
} else {
2022-08-12 14:03:28 +03:00
for ( int aa = 0 ; aa < ( ( fd - > antialiasing = = FONT_ANTIALIASING_LCD ) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1 ) ; aa + + ) {
2025-03-30 14:20:25 +03:00
if ( ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_ONE_QUARTER ) | | ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_AUTO & & size . x < = SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64 ) ) {
2024-05-30 22:57:28 -07:00
_ensure_glyph ( fd , size , ( int32_t ) idx | ( 0 < < 27 ) | ( aa < < 24 ) , fgl ) ;
_ensure_glyph ( fd , size , ( int32_t ) idx | ( 1 < < 27 ) | ( aa < < 24 ) , fgl ) ;
_ensure_glyph ( fd , size , ( int32_t ) idx | ( 2 < < 27 ) | ( aa < < 24 ) , fgl ) ;
_ensure_glyph ( fd , size , ( int32_t ) idx | ( 3 < < 27 ) | ( aa < < 24 ) , fgl ) ;
2025-03-30 14:20:25 +03:00
} else if ( ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_ONE_HALF ) | | ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_AUTO & & size . x < = SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64 ) ) {
2024-05-30 22:57:28 -07:00
_ensure_glyph ( fd , size , ( int32_t ) idx | ( 1 < < 27 ) | ( aa < < 24 ) , fgl ) ;
_ensure_glyph ( fd , size , ( int32_t ) idx | ( 0 < < 27 ) | ( aa < < 24 ) , fgl ) ;
2022-08-12 14:03:28 +03:00
} else {
2024-05-30 22:57:28 -07:00
_ensure_glyph ( fd , size , ( int32_t ) idx | ( aa < < 24 ) , fgl ) ;
2022-08-12 14:03:28 +03:00
}
2022-01-10 10:13:22 +02:00
}
}
}
# endif
2020-08-05 09:25:28 +03:00
}
2025-03-30 14:20:25 +03:00
void TextServerFallback : : _font_draw_glyph ( const RID & p_font_rid , const RID & p_canvas , int64_t p_size , const Vector2 & p_pos , int64_t p_index , const Color & p_color , float p_oversampling ) const {
2023-12-12 12:08:42 +02:00
if ( p_index = = 0 ) {
return ; // Non visual character, skip.
}
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
2025-03-30 14:20:25 +03:00
// Oversampling.
bool viewport_oversampling = false ;
float oversampling_factor = p_oversampling ;
if ( p_oversampling < = 0.0 ) {
2025-06-19 15:05:52 +03:00
if ( fd - > oversampling_override > 0.0 ) {
oversampling_factor = fd - > oversampling_override ;
} else if ( vp_oversampling > 0.0 ) {
2025-03-30 14:20:25 +03:00
oversampling_factor = vp_oversampling ;
viewport_oversampling = true ;
} else {
oversampling_factor = 1.0 ;
}
}
bool skip_oversampling = fd - > msdf | | fd - > fixed_size > 0 ;
2025-04-28 19:10:56 +03:00
if ( skip_oversampling ) {
oversampling_factor = 1.0 ;
} else {
uint64_t oversampling_level = CLAMP ( oversampling_factor , 0.1 , 100.0 ) * 64 ;
oversampling_factor = double ( oversampling_level ) / 64.0 ;
}
2025-03-30 14:20:25 +03:00
Vector2i size ;
if ( skip_oversampling ) {
size = _get_size ( fd , p_size ) ;
} else {
size = Vector2i ( p_size * 64 * oversampling_factor , 0 ) ;
}
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
2025-03-30 14:20:25 +03:00
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd , false , viewport_oversampling ? 64 * oversampling_factor : 0 ) ) ;
2022-01-10 10:13:22 +02:00
2022-02-13 14:41:29 +02:00
int32_t index = p_index & 0xffffff ; // Remove subpixel shifts.
2022-08-12 14:03:28 +03:00
bool lcd_aa = false ;
2022-01-10 10:13:22 +02:00
# ifdef MODULE_FREETYPE_ENABLED
2026-02-02 11:36:42 +02:00
if ( ! fd - > msdf & & fd - > face ) {
2022-08-12 14:03:28 +03:00
// LCD layout, bits 24, 25, 26
if ( fd - > antialiasing = = FONT_ANTIALIASING_LCD ) {
2024-05-30 22:57:28 -07:00
TextServer : : FontLCDSubpixelLayout layout = lcd_subpixel_layout . get ( ) ;
2022-08-12 14:03:28 +03:00
if ( layout ! = FONT_LCD_SUBPIXEL_LAYOUT_NONE ) {
lcd_aa = true ;
index = index | ( layout < < 24 ) ;
}
}
// Subpixel X-shift, bits 27, 28
2025-03-30 14:20:25 +03:00
if ( ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_ONE_QUARTER ) | | ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_AUTO & & size . x < = SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64 ) ) {
2022-01-10 10:13:22 +02:00
int xshift = ( int ) ( Math : : floor ( 4 * ( p_pos . x + 0.125 ) ) - 4 * Math : : floor ( p_pos . x + 0.125 ) ) ;
index = index | ( xshift < < 27 ) ;
2025-03-30 14:20:25 +03:00
} else if ( ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_ONE_HALF ) | | ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_AUTO & & size . x < = SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64 ) ) {
2022-01-10 10:13:22 +02:00
int xshift = ( int ) ( Math : : floor ( 2 * ( p_pos . x + 0.25 ) ) - 2 * Math : : floor ( p_pos . x + 0.25 ) ) ;
index = index | ( xshift < < 27 ) ;
}
}
# endif
2024-05-30 22:57:28 -07:00
FontGlyph fgl ;
2025-03-30 14:20:25 +03:00
if ( ! _ensure_glyph ( fd , size , index , fgl , viewport_oversampling ? 64 * oversampling_factor : 0 ) ) {
2021-12-13 18:31:16 +02:00
return ; // Invalid or non-graphical glyph, do not display errors, nothing to draw.
2020-12-27 15:30:33 +02:00
}
2020-08-05 09:25:28 +03:00
2024-05-30 22:57:28 -07:00
if ( fgl . found ) {
ERR_FAIL_COND ( fgl . texture_idx < - 1 | | fgl . texture_idx > = ffsd - > textures . size ( ) ) ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
if ( fgl . texture_idx ! = - 1 ) {
2020-12-27 15:30:33 +02:00
Color modulate = p_color ;
# ifdef MODULE_FREETYPE_ENABLED
2026-02-02 11:36:42 +02:00
if ( ! fd - > modulate_color_glyphs & & fd - > face & & ffsd - > textures [ fgl . texture_idx ] . image . is_valid ( ) & & ( ffsd - > textures [ fgl . texture_idx ] . image - > get_format ( ) = = Image : : FORMAT_RGBA8 ) & & ! lcd_aa & & ! fd - > msdf ) {
2020-12-27 15:30:33 +02:00
modulate . r = modulate . g = modulate . b = 1.0 ;
}
# endif
2026-02-26 10:25:59 +02:00
if ( ffsd - > textures [ fgl . texture_idx ] . dirty ) {
ShelfPackTexture & tex = ffsd - > textures . write [ fgl . texture_idx ] ;
Ref < Image > img = tex . image ;
if ( fgl . from_svg ) {
// Same as the "fix alpha border" process option when importing SVGs
img - > fix_alpha_edges ( ) ;
2022-04-04 10:31:07 +03:00
}
2026-02-26 10:25:59 +02:00
if ( fd - > mipmaps & & ! img - > has_mipmaps ( ) ) {
img = tex . image - > duplicate ( ) ;
img - > generate_mipmaps ( ) ;
}
if ( tex . texture . is_null ( ) ) {
tex . texture = ImageTexture : : create_from_image ( img ) ;
2020-12-27 15:30:33 +02:00
} else {
2026-02-26 10:25:59 +02:00
tex . texture - > update ( img ) ;
}
tex . dirty = false ;
}
if ( fd - > msdf ) {
Point2 cpos = p_pos ;
cpos + = fgl . rect . position * ( double ) p_size / ( double ) fd - > msdf_source_size ;
Size2 csize = fgl . rect . size * ( double ) p_size / ( double ) fd - > msdf_source_size ;
ffsd - > textures [ fgl . texture_idx ] . texture - > draw_msdf_rect_region ( p_canvas , Rect2 ( cpos , csize ) , fgl . uv_rect , modulate , 0 , fd - > msdf_range , ( double ) p_size / ( double ) fd - > msdf_source_size ) ;
} else {
Point2 cpos = p_pos ;
double scale = _font_get_scale ( p_font_rid , p_size ) / oversampling_factor ;
if ( ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_ONE_QUARTER ) | | ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_AUTO & & size . x < = SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE ) ) {
cpos . x = cpos . x + 0.125 ;
} else if ( ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_ONE_HALF ) | | ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_AUTO & & size . x < = SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE ) ) {
cpos . x = cpos . x + 0.25 ;
}
if ( scale = = 1.0 ) {
cpos . y = Math : : floor ( cpos . y ) ;
cpos . x = Math : : floor ( cpos . x ) ;
}
Vector2 gpos = fgl . rect . position ;
Size2 csize = fgl . rect . size ;
if ( fd - > fixed_size > 0 & & fd - > fixed_size_scale_mode ! = FIXED_SIZE_SCALE_DISABLE ) {
if ( size . x ! = p_size * 64 ) {
if ( fd - > fixed_size_scale_mode = = FIXED_SIZE_SCALE_ENABLED ) {
double gl_scale = ( double ) p_size / ( double ) fd - > fixed_size ;
gpos * = gl_scale ;
csize * = gl_scale ;
} else {
double gl_scale = Math : : round ( ( double ) p_size / ( double ) fd - > fixed_size ) ;
gpos * = gl_scale ;
csize * = gl_scale ;
2023-08-14 10:42:49 +03:00
}
2022-08-12 14:03:28 +03:00
}
2026-02-26 10:25:59 +02:00
} else {
gpos / = oversampling_factor ;
csize / = oversampling_factor ;
}
cpos + = gpos ;
if ( lcd_aa ) {
ffsd - > textures [ fgl . texture_idx ] . texture - > draw_lcd_rect_region ( p_canvas , Rect2 ( cpos , csize ) , fgl . uv_rect , modulate ) ;
} else {
ffsd - > textures [ fgl . texture_idx ] . texture - > draw_rect_region ( p_canvas , Rect2 ( cpos , csize ) , fgl . uv_rect , modulate , false , false ) ;
2020-12-27 15:30:33 +02:00
}
}
}
}
2020-08-05 09:25:28 +03:00
}
2025-03-30 14:20:25 +03:00
void TextServerFallback : : _font_draw_glyph_outline ( const RID & p_font_rid , const RID & p_canvas , int64_t p_size , int64_t p_outline_size , const Vector2 & p_pos , int64_t p_index , const Color & p_color , float p_oversampling ) const {
2023-12-12 12:08:42 +02:00
if ( p_index = = 0 ) {
return ; // Non visual character, skip.
}
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
2025-03-30 14:20:25 +03:00
// Oversampling.
bool viewport_oversampling = false ;
float oversampling_factor = p_oversampling ;
if ( p_oversampling < = 0.0 ) {
2025-06-19 15:05:52 +03:00
if ( fd - > oversampling_override > 0.0 ) {
oversampling_factor = fd - > oversampling_override ;
} else if ( vp_oversampling > 0.0 ) {
2025-03-30 14:20:25 +03:00
oversampling_factor = vp_oversampling ;
viewport_oversampling = true ;
} else {
oversampling_factor = 1.0 ;
}
}
bool skip_oversampling = fd - > msdf | | fd - > fixed_size > 0 ;
2025-04-28 19:10:56 +03:00
if ( skip_oversampling ) {
oversampling_factor = 1.0 ;
} else {
uint64_t oversampling_level = CLAMP ( oversampling_factor , 0.1 , 100.0 ) * 64 ;
oversampling_factor = double ( oversampling_level ) / 64.0 ;
}
2025-03-30 14:20:25 +03:00
Vector2i size ;
if ( skip_oversampling ) {
size = _get_size_outline ( fd , Vector2i ( p_size , p_outline_size ) ) ;
} else {
2025-04-28 19:10:56 +03:00
size = Vector2i ( p_size * 64 * oversampling_factor , p_outline_size * oversampling_factor ) ;
2025-03-30 14:20:25 +03:00
}
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
2025-03-30 14:20:25 +03:00
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd , false , viewport_oversampling ? 64 * oversampling_factor : 0 ) ) ;
2022-01-10 10:13:22 +02:00
2022-02-13 14:41:29 +02:00
int32_t index = p_index & 0xffffff ; // Remove subpixel shifts.
2022-08-12 14:03:28 +03:00
bool lcd_aa = false ;
2022-01-10 10:13:22 +02:00
# ifdef MODULE_FREETYPE_ENABLED
2026-02-02 11:36:42 +02:00
if ( ! fd - > msdf & & fd - > face ) {
2022-08-12 14:03:28 +03:00
// LCD layout, bits 24, 25, 26
if ( fd - > antialiasing = = FONT_ANTIALIASING_LCD ) {
2024-05-30 22:57:28 -07:00
TextServer : : FontLCDSubpixelLayout layout = lcd_subpixel_layout . get ( ) ;
2022-08-12 14:03:28 +03:00
if ( layout ! = FONT_LCD_SUBPIXEL_LAYOUT_NONE ) {
lcd_aa = true ;
index = index | ( layout < < 24 ) ;
}
}
// Subpixel X-shift, bits 27, 28
2025-03-30 14:20:25 +03:00
if ( ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_ONE_QUARTER ) | | ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_AUTO & & size . x < = SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE * 64 ) ) {
2022-01-10 10:13:22 +02:00
int xshift = ( int ) ( Math : : floor ( 4 * ( p_pos . x + 0.125 ) ) - 4 * Math : : floor ( p_pos . x + 0.125 ) ) ;
index = index | ( xshift < < 27 ) ;
2025-03-30 14:20:25 +03:00
} else if ( ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_ONE_HALF ) | | ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_AUTO & & size . x < = SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE * 64 ) ) {
2022-01-10 10:13:22 +02:00
int xshift = ( int ) ( Math : : floor ( 2 * ( p_pos . x + 0.25 ) ) - 2 * Math : : floor ( p_pos . x + 0.25 ) ) ;
index = index | ( xshift < < 27 ) ;
}
}
# endif
2024-05-30 22:57:28 -07:00
FontGlyph fgl ;
2025-03-30 14:20:25 +03:00
if ( ! _ensure_glyph ( fd , size , index , fgl , viewport_oversampling ? 64 * oversampling_factor : 0 ) ) {
2021-12-13 18:31:16 +02:00
return ; // Invalid or non-graphical glyph, do not display errors, nothing to draw.
2020-12-27 15:30:33 +02:00
}
2024-05-30 22:57:28 -07:00
if ( fgl . found ) {
ERR_FAIL_COND ( fgl . texture_idx < - 1 | | fgl . texture_idx > = ffsd - > textures . size ( ) ) ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
if ( fgl . texture_idx ! = - 1 ) {
2020-12-27 15:30:33 +02:00
Color modulate = p_color ;
# ifdef MODULE_FREETYPE_ENABLED
2026-02-02 11:36:42 +02:00
if ( fd - > face & & ffsd - > textures [ fgl . texture_idx ] . image . is_valid ( ) & & ( ffsd - > textures [ fgl . texture_idx ] . image - > get_format ( ) = = Image : : FORMAT_RGBA8 ) & & ! lcd_aa & & ! fd - > msdf ) {
2020-12-27 15:30:33 +02:00
modulate . r = modulate . g = modulate . b = 1.0 ;
}
# endif
2026-02-26 10:25:59 +02:00
if ( ffsd - > textures [ fgl . texture_idx ] . dirty ) {
ShelfPackTexture & tex = ffsd - > textures . write [ fgl . texture_idx ] ;
Ref < Image > img = tex . image ;
if ( fd - > mipmaps & & ! img - > has_mipmaps ( ) ) {
img = tex . image - > duplicate ( ) ;
img - > generate_mipmaps ( ) ;
2022-04-04 10:31:07 +03:00
}
2026-02-26 10:25:59 +02:00
if ( tex . texture . is_null ( ) ) {
tex . texture = ImageTexture : : create_from_image ( img ) ;
2020-12-27 15:30:33 +02:00
} else {
2026-02-26 10:25:59 +02:00
tex . texture - > update ( img ) ;
}
tex . dirty = false ;
}
if ( fd - > msdf ) {
Point2 cpos = p_pos ;
cpos + = fgl . rect . position * ( double ) p_size / ( double ) fd - > msdf_source_size ;
Size2 csize = fgl . rect . size * ( double ) p_size / ( double ) fd - > msdf_source_size ;
ffsd - > textures [ fgl . texture_idx ] . texture - > draw_msdf_rect_region ( p_canvas , Rect2 ( cpos , csize ) , fgl . uv_rect , modulate , p_outline_size , fd - > msdf_range , ( double ) p_size / ( double ) fd - > msdf_source_size ) ;
} else {
Point2 cpos = p_pos ;
double scale = _font_get_scale ( p_font_rid , p_size ) / oversampling_factor ;
if ( ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_ONE_QUARTER ) | | ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_AUTO & & size . x < = SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE ) ) {
cpos . x = cpos . x + 0.125 ;
} else if ( ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_ONE_HALF ) | | ( fd - > subpixel_positioning = = SUBPIXEL_POSITIONING_AUTO & & size . x < = SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE ) ) {
cpos . x = cpos . x + 0.25 ;
}
if ( scale = = 1.0 ) {
cpos . y = Math : : floor ( cpos . y ) ;
cpos . x = Math : : floor ( cpos . x ) ;
}
Vector2 gpos = fgl . rect . position ;
Size2 csize = fgl . rect . size ;
if ( fd - > fixed_size > 0 & & fd - > fixed_size_scale_mode ! = FIXED_SIZE_SCALE_DISABLE ) {
if ( size . x ! = p_size * 64 ) {
if ( fd - > fixed_size_scale_mode = = FIXED_SIZE_SCALE_ENABLED ) {
double gl_scale = ( double ) p_size / ( double ) fd - > fixed_size ;
gpos * = gl_scale ;
csize * = gl_scale ;
} else {
double gl_scale = Math : : round ( ( double ) p_size / ( double ) fd - > fixed_size ) ;
gpos * = gl_scale ;
csize * = gl_scale ;
2023-08-14 10:42:49 +03:00
}
2022-08-12 14:03:28 +03:00
}
2026-02-26 10:25:59 +02:00
} else {
gpos / = oversampling_factor ;
csize / = oversampling_factor ;
}
cpos + = gpos ;
if ( lcd_aa ) {
ffsd - > textures [ fgl . texture_idx ] . texture - > draw_lcd_rect_region ( p_canvas , Rect2 ( cpos , csize ) , fgl . uv_rect , modulate ) ;
} else {
ffsd - > textures [ fgl . texture_idx ] . texture - > draw_rect_region ( p_canvas , Rect2 ( cpos , csize ) , fgl . uv_rect , modulate , false , false ) ;
2020-12-27 15:30:33 +02:00
}
}
}
}
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _font_is_language_supported ( const RID & p_font_rid , const String & p_language ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , false ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
if ( fd - > language_support_overrides . has ( p_language ) ) {
return fd - > language_support_overrides [ p_language ] ;
2020-08-05 09:25:28 +03:00
} else {
2025-11-12 10:52:46 +02:00
if ( fd - > language_support_overrides . has ( " * " ) ) {
return fd - > language_support_overrides [ " * " ] ;
}
2020-12-27 15:30:33 +02:00
return true ;
2020-08-05 09:25:28 +03:00
}
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_language_support_override ( const RID & p_font_rid , const String & p_language , bool p_supported ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
fd - > language_support_overrides [ p_language ] = p_supported ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _font_get_language_support_override ( const RID & p_font_rid , const String & p_language ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , false ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
return fd - > language_support_overrides [ p_language ] ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_remove_language_support_override ( const RID & p_font_rid , const String & p_language ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
fd - > language_support_overrides . erase ( p_language ) ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
PackedStringArray TextServerFallback : : _font_get_language_support_overrides ( const RID & p_font_rid ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , PackedStringArray ( ) ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
2022-02-13 14:41:29 +02:00
PackedStringArray out ;
2021-08-09 14:13:42 -06:00
for ( const KeyValue < String , bool > & E : fd - > language_support_overrides ) {
out . push_back ( E . key ) ;
2020-08-05 09:25:28 +03:00
}
2020-12-27 15:30:33 +02:00
return out ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _font_is_script_supported ( const RID & p_font_rid , const String & p_script ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , false ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
2020-08-05 09:25:28 +03:00
if ( fd - > script_support_overrides . has ( p_script ) ) {
return fd - > script_support_overrides [ p_script ] ;
} else {
2025-11-12 10:52:46 +02:00
if ( fd - > script_support_overrides . has ( " * " ) ) {
return fd - > script_support_overrides [ " * " ] ;
}
2020-08-05 09:25:28 +03:00
return true ;
}
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_script_support_override ( const RID & p_font_rid , const String & p_script , bool p_supported ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
2020-08-05 09:25:28 +03:00
fd - > script_support_overrides [ p_script ] = p_supported ;
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _font_get_script_support_override ( const RID & p_font_rid , const String & p_script ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , false ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
2020-08-05 09:25:28 +03:00
return fd - > script_support_overrides [ p_script ] ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_remove_script_support_override ( const RID & p_font_rid , const String & p_script ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , 16 ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2020-08-05 09:25:28 +03:00
fd - > script_support_overrides . erase ( p_script ) ;
}
2022-09-27 11:23:34 +03:00
PackedStringArray TextServerFallback : : _font_get_script_support_overrides ( const RID & p_font_rid ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , PackedStringArray ( ) ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
2022-02-13 14:41:29 +02:00
PackedStringArray out ;
2021-08-09 14:13:42 -06:00
for ( const KeyValue < String , bool > & E : fd - > script_support_overrides ) {
out . push_back ( E . key ) ;
2020-12-27 15:30:33 +02:00
}
return out ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _font_set_opentype_feature_overrides ( const RID & p_font_rid , const Dictionary & p_overrides ) {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( fd ) ;
2021-11-18 23:36:22 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , 16 ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND ( ! _ensure_cache_for_size ( fd , size , ffsd ) ) ;
2021-11-18 23:36:22 +02:00
fd - > feature_overrides = p_overrides ;
}
2022-09-27 11:23:34 +03:00
Dictionary TextServerFallback : : _font_get_opentype_feature_overrides ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , Dictionary ( ) ) ;
2021-11-18 23:36:22 +02:00
MutexLock lock ( fd - > mutex ) ;
return fd - > feature_overrides ;
}
2022-09-27 11:23:34 +03:00
Dictionary TextServerFallback : : _font_supported_feature_list ( const RID & p_font_rid ) const {
2020-12-27 15:30:33 +02:00
return Dictionary ( ) ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
Dictionary TextServerFallback : : _font_supported_variation_list ( const RID & p_font_rid ) const {
2023-09-28 10:45:09 +03:00
FontFallback * fd = _get_font_data ( p_font_rid ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( fd , Dictionary ( ) ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , 16 ) ;
2024-05-30 22:57:28 -07:00
FontForSizeFallback * ffsd = nullptr ;
ERR_FAIL_COND_V ( ! _ensure_cache_for_size ( fd , size , ffsd ) , Dictionary ( ) ) ;
2020-12-27 15:30:33 +02:00
return fd - > supported_varaitions ;
2020-12-10 17:30:25 +02:00
}
2020-08-05 09:25:28 +03:00
/*************************************************************************/
/* Shaped text buffer interface */
/*************************************************************************/
2022-01-20 09:30:42 +02:00
void TextServerFallback : : invalidate ( ShapedTextDataFallback * p_shaped ) {
2024-05-30 22:57:28 -07:00
p_shaped - > valid . clear ( ) ;
2020-08-05 09:25:28 +03:00
p_shaped - > sort_valid = false ;
p_shaped - > line_breaks_valid = false ;
p_shaped - > justification_ops_valid = false ;
2022-02-13 14:41:29 +02:00
p_shaped - > ascent = 0.0 ;
p_shaped - > descent = 0.0 ;
p_shaped - > width = 0.0 ;
p_shaped - > upos = 0.0 ;
p_shaped - > uthk = 0.0 ;
2020-08-05 09:25:28 +03:00
p_shaped - > glyphs . clear ( ) ;
p_shaped - > glyphs_logical . clear ( ) ;
2025-03-21 16:42:23 +02:00
p_shaped - > runs . clear ( ) ;
p_shaped - > runs_dirty = true ;
2020-08-05 09:25:28 +03:00
}
2022-01-20 09:30:42 +02:00
void TextServerFallback : : full_copy ( ShapedTextDataFallback * p_shaped ) {
ShapedTextDataFallback * parent = shaped_owner . get_or_null ( p_shaped - > parent ) ;
2020-08-05 09:25:28 +03:00
2022-01-20 09:30:42 +02:00
for ( const KeyValue < Variant , ShapedTextDataFallback : : EmbeddedObject > & E : parent - > objects ) {
2024-03-11 16:28:58 +02:00
if ( E . value . start > = p_shaped - > start & & E . value . start < p_shaped - > end ) {
2021-08-09 14:13:42 -06:00
p_shaped - > objects [ E . key ] = E . value ;
2020-08-05 09:25:28 +03:00
}
}
2025-09-09 10:35:16 +03:00
for ( int i = MAX ( 0 , p_shaped - > first_span ) ; i < = MIN ( p_shaped - > last_span , parent - > spans . size ( ) - 1 ) ; i + + ) {
2024-09-26 09:37:47 +03:00
ShapedTextDataFallback : : Span span = parent - > spans [ i ] ;
2020-08-05 09:25:28 +03:00
span . start = MAX ( p_shaped - > start , span . start ) ;
span . end = MIN ( p_shaped - > end , span . end ) ;
p_shaped - > spans . push_back ( span ) ;
}
2024-09-26 09:37:47 +03:00
p_shaped - > first_span = 0 ;
p_shaped - > last_span = 0 ;
2020-08-05 09:25:28 +03:00
p_shaped - > parent = RID ( ) ;
}
2022-09-27 11:23:34 +03:00
RID TextServerFallback : : _create_shaped_text ( TextServer : : Direction p_direction , TextServer : : Orientation p_orientation ) {
2020-08-05 09:25:28 +03:00
_THREAD_SAFE_METHOD_
2023-01-18 09:33:35 +02:00
ERR_FAIL_COND_V_MSG ( p_direction = = DIRECTION_INHERITED , RID ( ) , " Invalid text direction. " ) ;
2022-05-18 10:17:55 +03:00
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = memnew ( ShapedTextDataFallback ) ;
2020-08-05 09:25:28 +03:00
sd - > direction = p_direction ;
sd - > orientation = p_orientation ;
return shaped_owner . make_rid ( sd ) ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _shaped_text_clear ( const RID & p_shaped ) {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( sd ) ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2020-08-05 09:25:28 +03:00
sd - > parent = RID ( ) ;
sd - > start = 0 ;
sd - > end = 0 ;
sd - > text = String ( ) ;
sd - > spans . clear ( ) ;
2024-09-26 09:37:47 +03:00
sd - > first_span = 0 ;
sd - > last_span = 0 ;
2020-08-05 09:25:28 +03:00
sd - > objects . clear ( ) ;
invalidate ( sd ) ;
}
2025-09-09 10:35:16 +03:00
RID TextServerFallback : : _shaped_text_duplicate ( const RID & p_shaped ) {
_THREAD_SAFE_METHOD_
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , RID ( ) ) ;
MutexLock lock ( sd - > mutex ) ;
ShapedTextDataFallback * new_sd = memnew ( ShapedTextDataFallback ) ;
new_sd - > parent = p_shaped ;
new_sd - > start = sd - > start ;
new_sd - > end = sd - > end ;
2025-12-11 21:50:22 +02:00
new_sd - > first_span = sd - > first_span ;
new_sd - > last_span = sd - > last_span ;
2025-09-09 10:35:16 +03:00
new_sd - > text = sd - > text ;
new_sd - > orientation = sd - > orientation ;
new_sd - > direction = sd - > direction ;
new_sd - > custom_punct = sd - > custom_punct ;
new_sd - > para_direction = sd - > para_direction ;
new_sd - > line_breaks_valid = sd - > line_breaks_valid ;
new_sd - > justification_ops_valid = sd - > justification_ops_valid ;
new_sd - > sort_valid = false ;
new_sd - > upos = sd - > upos ;
new_sd - > uthk = sd - > uthk ;
new_sd - > runs . clear ( ) ;
new_sd - > runs_dirty = true ;
for ( int i = 0 ; i < TextServer : : SPACING_MAX ; i + + ) {
new_sd - > extra_spacing [ i ] = sd - > extra_spacing [ i ] ;
}
2025-12-11 21:50:22 +02:00
for ( const KeyValue < Variant , ShapedTextDataFallback : : EmbeddedObject > & E : sd - > objects ) {
new_sd - > objects [ E . key ] = E . value ;
}
for ( int i = 0 ; i < sd - > spans . size ( ) ; i + + ) {
new_sd - > spans . push_back ( sd - > spans [ i ] ) ;
}
2025-09-09 10:35:16 +03:00
new_sd - > valid . clear ( ) ;
return shaped_owner . make_rid ( new_sd ) ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _shaped_text_set_direction ( const RID & p_shaped , TextServer : : Direction p_direction ) {
2023-01-18 09:33:35 +02:00
ERR_FAIL_COND_MSG ( p_direction = = DIRECTION_INHERITED , " Invalid text direction. " ) ;
2020-08-05 09:25:28 +03:00
if ( p_direction = = DIRECTION_RTL ) {
ERR_PRINT_ONCE ( " Right-to-left layout is not supported by this text server. " ) ;
}
}
2022-09-27 11:23:34 +03:00
TextServer : : Direction TextServerFallback : : _shaped_text_get_direction ( const RID & p_shaped ) const {
2020-08-05 09:25:28 +03:00
return TextServer : : DIRECTION_LTR ;
}
2022-09-27 11:23:34 +03:00
TextServer : : Direction TextServerFallback : : _shaped_text_get_inferred_direction ( const RID & p_shaped ) const {
2022-01-10 17:24:03 +02:00
return TextServer : : DIRECTION_LTR ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _shaped_text_set_custom_punctuation ( const RID & p_shaped , const String & p_punct ) {
2021-03-06 11:52:16 +02:00
_THREAD_SAFE_METHOD_
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( sd ) ;
2021-03-06 11:52:16 +02:00
if ( sd - > custom_punct ! = p_punct ) {
if ( sd - > parent ! = RID ( ) ) {
full_copy ( sd ) ;
}
sd - > custom_punct = p_punct ;
invalidate ( sd ) ;
}
}
2022-09-27 11:23:34 +03:00
String TextServerFallback : : _shaped_text_get_custom_punctuation ( const RID & p_shaped ) const {
2021-03-06 11:52:16 +02:00
_THREAD_SAFE_METHOD_
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , String ( ) ) ;
2021-03-06 11:52:16 +02:00
return sd - > custom_punct ;
}
2023-10-01 13:39:13 +03:00
void TextServerFallback : : _shaped_text_set_custom_ellipsis ( const RID & p_shaped , int64_t p_char ) {
_THREAD_SAFE_METHOD_
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL ( sd ) ;
sd - > el_char = p_char ;
}
int64_t TextServerFallback : : _shaped_text_get_custom_ellipsis ( const RID & p_shaped ) const {
_THREAD_SAFE_METHOD_
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , 0 ) ;
return sd - > el_char ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _shaped_text_set_orientation ( const RID & p_shaped , TextServer : : Orientation p_orientation ) {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( sd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2020-08-05 09:25:28 +03:00
if ( sd - > orientation ! = p_orientation ) {
if ( sd - > parent ! = RID ( ) ) {
full_copy ( sd ) ;
}
sd - > orientation = p_orientation ;
invalidate ( sd ) ;
}
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _shaped_text_set_bidi_override ( const RID & p_shaped , const Array & p_override ) {
2021-08-11 00:09:48 +02:00
// No BiDi support, ignore.
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
TextServer : : Orientation TextServerFallback : : _shaped_text_get_orientation ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , TextServer : : ORIENTATION_HORIZONTAL ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2020-08-05 09:25:28 +03:00
return sd - > orientation ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _shaped_text_set_preserve_invalid ( const RID & p_shaped , bool p_enabled ) {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( sd ) ;
2020-08-05 09:25:28 +03:00
if ( sd - > preserve_invalid ! = p_enabled ) {
if ( sd - > parent ! = RID ( ) ) {
full_copy ( sd ) ;
}
sd - > preserve_invalid = p_enabled ;
invalidate ( sd ) ;
}
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _shaped_text_get_preserve_invalid ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , false ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2020-08-05 09:25:28 +03:00
return sd - > preserve_invalid ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _shaped_text_set_preserve_control ( const RID & p_shaped , bool p_enabled ) {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( sd ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2020-08-05 09:25:28 +03:00
if ( sd - > preserve_control ! = p_enabled ) {
if ( sd - > parent ! = RID ( ) ) {
full_copy ( sd ) ;
}
sd - > preserve_control = p_enabled ;
invalidate ( sd ) ;
}
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _shaped_text_get_preserve_control ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , false ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2020-08-05 09:25:28 +03:00
return sd - > preserve_control ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _shaped_text_set_spacing ( const RID & p_shaped , SpacingType p_spacing , int64_t p_value ) {
2022-05-09 12:47:10 +03:00
ERR_FAIL_INDEX ( ( int ) p_spacing , 4 ) ;
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( sd ) ;
2022-05-09 12:47:10 +03:00
MutexLock lock ( sd - > mutex ) ;
if ( sd - > extra_spacing [ p_spacing ] ! = p_value ) {
if ( sd - > parent ! = RID ( ) ) {
full_copy ( sd ) ;
}
sd - > extra_spacing [ p_spacing ] = p_value ;
invalidate ( sd ) ;
}
}
2022-09-27 11:23:34 +03:00
int64_t TextServerFallback : : _shaped_text_get_spacing ( const RID & p_shaped , SpacingType p_spacing ) const {
2022-05-09 12:47:10 +03:00
ERR_FAIL_INDEX_V ( ( int ) p_spacing , 4 , 0 ) ;
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , 0 ) ;
2022-05-09 12:47:10 +03:00
MutexLock lock ( sd - > mutex ) ;
return sd - > extra_spacing [ p_spacing ] ;
}
2022-09-27 11:23:34 +03:00
int64_t TextServerFallback : : _shaped_get_span_count ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , 0 ) ;
2024-09-26 09:37:47 +03:00
if ( sd - > parent ! = RID ( ) ) {
return sd - > last_span - sd - > first_span + 1 ;
} else {
return sd - > spans . size ( ) ;
}
2022-01-20 09:30:42 +02:00
}
2022-09-27 11:23:34 +03:00
Variant TextServerFallback : : _shaped_get_span_meta ( const RID & p_shaped , int64_t p_index ) const {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , Variant ( ) ) ;
2024-09-26 09:37:47 +03:00
if ( sd - > parent ! = RID ( ) ) {
ShapedTextDataFallback * parent_sd = shaped_owner . get_or_null ( sd - > parent ) ;
ERR_FAIL_COND_V ( ! parent_sd - > valid . is_set ( ) , Variant ( ) ) ;
ERR_FAIL_INDEX_V ( p_index + sd - > first_span , parent_sd - > spans . size ( ) , Variant ( ) ) ;
return parent_sd - > spans [ p_index + sd - > first_span ] . meta ;
} else {
ERR_FAIL_INDEX_V ( p_index , sd - > spans . size ( ) , Variant ( ) ) ;
return sd - > spans [ p_index ] . meta ;
}
}
Variant TextServerFallback : : _shaped_get_span_embedded_object ( const RID & p_shaped , int64_t p_index ) const {
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , Variant ( ) ) ;
if ( sd - > parent ! = RID ( ) ) {
ShapedTextDataFallback * parent_sd = shaped_owner . get_or_null ( sd - > parent ) ;
ERR_FAIL_COND_V ( ! parent_sd - > valid . is_set ( ) , Variant ( ) ) ;
ERR_FAIL_INDEX_V ( p_index + sd - > first_span , parent_sd - > spans . size ( ) , Variant ( ) ) ;
return parent_sd - > spans [ p_index + sd - > first_span ] . embedded_key ;
} else {
ERR_FAIL_INDEX_V ( p_index , sd - > spans . size ( ) , Variant ( ) ) ;
return sd - > spans [ p_index ] . embedded_key ;
}
2022-01-20 09:30:42 +02:00
}
2025-03-21 16:42:23 +02:00
String TextServerFallback : : _shaped_get_span_text ( const RID & p_shaped , int64_t p_index ) const {
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , String ( ) ) ;
ShapedTextDataFallback * span_sd = sd ;
if ( sd - > parent . is_valid ( ) ) {
span_sd = shaped_owner . get_or_null ( sd - > parent ) ;
ERR_FAIL_NULL_V ( span_sd , String ( ) ) ;
}
ERR_FAIL_INDEX_V ( p_index , span_sd - > spans . size ( ) , String ( ) ) ;
return span_sd - > text . substr ( span_sd - > spans [ p_index ] . start , span_sd - > spans [ p_index ] . end - span_sd - > spans [ p_index ] . start ) ;
}
Variant TextServerFallback : : _shaped_get_span_object ( const RID & p_shaped , int64_t p_index ) const {
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , Variant ( ) ) ;
ShapedTextDataFallback * span_sd = sd ;
if ( sd - > parent . is_valid ( ) ) {
span_sd = shaped_owner . get_or_null ( sd - > parent ) ;
ERR_FAIL_NULL_V ( span_sd , Variant ( ) ) ;
}
ERR_FAIL_INDEX_V ( p_index , span_sd - > spans . size ( ) , Variant ( ) ) ;
return span_sd - > spans [ p_index ] . embedded_key ;
}
void TextServerFallback : : _generate_runs ( ShapedTextDataFallback * p_sd ) const {
ERR_FAIL_NULL ( p_sd ) ;
p_sd - > runs . clear ( ) ;
ShapedTextDataFallback * span_sd = p_sd ;
if ( p_sd - > parent . is_valid ( ) ) {
span_sd = shaped_owner . get_or_null ( p_sd - > parent ) ;
ERR_FAIL_NULL ( span_sd ) ;
}
int sd_size = p_sd - > glyphs . size ( ) ;
Glyph * sd_gl = p_sd - > glyphs . ptrw ( ) ;
int span_count = span_sd - > spans . size ( ) ;
int span = - 1 ;
int span_start = - 1 ;
int span_end = - 1 ;
TextRun run ;
for ( int i = 0 ; i < sd_size ; i + = sd_gl [ i ] . count ) {
const Glyph & gl = sd_gl [ i ] ;
if ( gl . start < 0 | | gl . end < 0 ) {
continue ;
}
if ( gl . start < span_start | | gl . start > = span_end ) {
span = - 1 ;
span_start = - 1 ;
span_end = - 1 ;
for ( int j = 0 ; j < span_count ; j + + ) {
if ( gl . start > = span_sd - > spans [ j ] . start & & gl . end < = span_sd - > spans [ j ] . end ) {
span = j ;
span_start = span_sd - > spans [ j ] . start ;
span_end = span_sd - > spans [ j ] . end ;
break ;
}
}
}
if ( run . font_rid ! = gl . font_rid | | run . font_size ! = gl . font_size | | run . span_index ! = span ) {
if ( run . span_index > = 0 ) {
p_sd - > runs . push_back ( run ) ;
}
run . range = Vector2i ( gl . start , gl . end ) ;
2026-01-04 14:16:59 +02:00
run . gl_range = Vector2i ( i , i ) ;
2025-03-21 16:42:23 +02:00
run . font_rid = gl . font_rid ;
run . font_size = gl . font_size ;
run . span_index = span ;
}
run . range . x = MIN ( run . range . x , gl . start ) ;
run . range . y = MAX ( run . range . y , gl . end ) ;
2026-01-04 14:16:59 +02:00
run . gl_range . x = MIN ( run . gl_range . x , i ) ;
run . gl_range . y = MAX ( run . gl_range . y , i ) ;
2025-03-21 16:42:23 +02:00
}
if ( run . span_index > = 0 ) {
p_sd - > runs . push_back ( run ) ;
}
p_sd - > runs_dirty = false ;
}
int64_t TextServerFallback : : _shaped_get_run_count ( const RID & p_shaped ) const {
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , 0 ) ;
MutexLock lock ( sd - > mutex ) ;
if ( ! sd - > valid . is_set ( ) ) {
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
}
if ( sd - > runs_dirty ) {
_generate_runs ( sd ) ;
}
return sd - > runs . size ( ) ;
}
String TextServerFallback : : _shaped_get_run_text ( const RID & p_shaped , int64_t p_index ) const {
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , String ( ) ) ;
MutexLock lock ( sd - > mutex ) ;
if ( ! sd - > valid . is_set ( ) ) {
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
}
if ( sd - > runs_dirty ) {
_generate_runs ( sd ) ;
}
ERR_FAIL_INDEX_V ( p_index , sd - > runs . size ( ) , String ( ) ) ;
return sd - > text . substr ( sd - > runs [ p_index ] . range . x - sd - > start , sd - > runs [ p_index ] . range . y - sd - > runs [ p_index ] . range . x ) ;
}
Vector2i TextServerFallback : : _shaped_get_run_range ( const RID & p_shaped , int64_t p_index ) const {
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , Vector2i ( ) ) ;
MutexLock lock ( sd - > mutex ) ;
if ( ! sd - > valid . is_set ( ) ) {
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
}
if ( sd - > runs_dirty ) {
_generate_runs ( sd ) ;
}
ERR_FAIL_INDEX_V ( p_index , sd - > runs . size ( ) , Vector2i ( ) ) ;
return sd - > runs [ p_index ] . range ;
}
2026-01-04 14:16:59 +02:00
Vector2i TextServerFallback : : _shaped_get_run_glyph_range ( const RID & p_shaped , int64_t p_index ) const {
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , Vector2i ( ) ) ;
MutexLock lock ( sd - > mutex ) ;
if ( ! sd - > valid . is_set ( ) ) {
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
}
if ( sd - > runs_dirty ) {
_generate_runs ( sd ) ;
}
ERR_FAIL_INDEX_V ( p_index , sd - > runs . size ( ) , Vector2i ( ) ) ;
return sd - > runs [ p_index ] . gl_range ;
}
2025-03-21 16:42:23 +02:00
RID TextServerFallback : : _shaped_get_run_font_rid ( const RID & p_shaped , int64_t p_index ) const {
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , RID ( ) ) ;
MutexLock lock ( sd - > mutex ) ;
if ( ! sd - > valid . is_set ( ) ) {
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
}
if ( sd - > runs_dirty ) {
_generate_runs ( sd ) ;
}
ERR_FAIL_INDEX_V ( p_index , sd - > runs . size ( ) , RID ( ) ) ;
return sd - > runs [ p_index ] . font_rid ;
}
int TextServerFallback : : _shaped_get_run_font_size ( const RID & p_shaped , int64_t p_index ) const {
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , 0 ) ;
MutexLock lock ( sd - > mutex ) ;
if ( ! sd - > valid . is_set ( ) ) {
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
}
if ( sd - > runs_dirty ) {
_generate_runs ( sd ) ;
}
ERR_FAIL_INDEX_V ( p_index , sd - > runs . size ( ) , 0 ) ;
return sd - > runs [ p_index ] . font_size ;
}
String TextServerFallback : : _shaped_get_run_language ( const RID & p_shaped , int64_t p_index ) const {
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , String ( ) ) ;
MutexLock lock ( sd - > mutex ) ;
if ( ! sd - > valid . is_set ( ) ) {
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
}
if ( sd - > runs_dirty ) {
_generate_runs ( sd ) ;
}
ERR_FAIL_INDEX_V ( p_index , sd - > runs . size ( ) , String ( ) ) ;
int span_idx = sd - > runs [ p_index ] . span_index ;
ShapedTextDataFallback * span_sd = sd ;
if ( sd - > parent . is_valid ( ) ) {
span_sd = shaped_owner . get_or_null ( sd - > parent ) ;
ERR_FAIL_NULL_V ( span_sd , String ( ) ) ;
}
ERR_FAIL_INDEX_V ( span_idx , span_sd - > spans . size ( ) , String ( ) ) ;
return span_sd - > spans [ span_idx ] . language ;
}
TextServer : : Direction TextServerFallback : : _shaped_get_run_direction ( const RID & p_shaped , int64_t p_index ) const {
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , TextServer : : DIRECTION_LTR ) ;
MutexLock lock ( sd - > mutex ) ;
if ( ! sd - > valid . is_set ( ) ) {
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
}
if ( sd - > runs_dirty ) {
_generate_runs ( sd ) ;
}
ERR_FAIL_INDEX_V ( p_index , sd - > runs . size ( ) , TextServer : : DIRECTION_LTR ) ;
return TextServer : : DIRECTION_LTR ;
}
Variant TextServerFallback : : _shaped_get_run_object ( const RID & p_shaped , int64_t p_index ) const {
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , Variant ( ) ) ;
MutexLock lock ( sd - > mutex ) ;
if ( ! sd - > valid . is_set ( ) ) {
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
}
if ( sd - > runs_dirty ) {
_generate_runs ( sd ) ;
}
ERR_FAIL_INDEX_V ( p_index , sd - > runs . size ( ) , Variant ( ) ) ;
int span_idx = sd - > runs [ p_index ] . span_index ;
ShapedTextDataFallback * span_sd = sd ;
if ( sd - > parent . is_valid ( ) ) {
span_sd = shaped_owner . get_or_null ( sd - > parent ) ;
ERR_FAIL_NULL_V ( span_sd , Variant ( ) ) ;
}
ERR_FAIL_INDEX_V ( span_idx , span_sd - > spans . size ( ) , Variant ( ) ) ;
return span_sd - > spans [ span_idx ] . embedded_key ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _shaped_set_span_update_font ( const RID & p_shaped , int64_t p_index , const TypedArray < RID > & p_fonts , int64_t p_size , const Dictionary & p_opentype_features ) {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL ( sd ) ;
2024-09-26 09:37:47 +03:00
if ( sd - > parent ! = RID ( ) ) {
full_copy ( sd ) ;
}
2022-01-20 09:30:42 +02:00
ERR_FAIL_INDEX ( p_index , sd - > spans . size ( ) ) ;
2022-02-13 14:41:29 +02:00
ShapedTextDataFallback : : Span & span = sd - > spans . ptrw ( ) [ p_index ] ;
2022-01-20 09:30:42 +02:00
span . fonts . clear ( ) ;
// Pre-sort fonts, push fonts with the language support first.
2022-02-13 14:41:29 +02:00
Array fonts_no_match ;
2022-01-20 09:30:42 +02:00
int font_count = p_fonts . size ( ) ;
for ( int i = 0 ; i < font_count ; i + + ) {
2022-09-27 11:23:34 +03:00
if ( _font_is_language_supported ( p_fonts [ i ] , span . language ) ) {
2022-01-20 09:30:42 +02:00
span . fonts . push_back ( p_fonts [ i ] ) ;
} else {
fonts_no_match . push_back ( p_fonts [ i ] ) ;
}
}
span . fonts . append_array ( fonts_no_match ) ;
span . font_size = p_size ;
span . features = p_opentype_features ;
2024-05-30 22:57:28 -07:00
sd - > valid . clear ( ) ;
2022-01-20 09:30:42 +02:00
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _shaped_text_add_string ( const RID & p_shaped , const String & p_text , const TypedArray < RID > & p_fonts , int64_t p_size , const Dictionary & p_opentype_features , const String & p_language , const Variant & p_meta ) {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , false ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2020-08-05 09:25:28 +03:00
ERR_FAIL_COND_V ( p_size < = 0 , false ) ;
2020-12-27 15:30:33 +02:00
for ( int i = 0 ; i < p_fonts . size ( ) ; i + + ) {
2023-09-28 11:40:18 +02:00
ERR_FAIL_NULL_V ( _get_font_data ( p_fonts [ i ] ) , false ) ;
2020-12-27 15:30:33 +02:00
}
2020-12-29 09:54:59 +01:00
if ( p_text . is_empty ( ) ) {
2020-08-05 09:25:28 +03:00
return true ;
}
if ( sd - > parent ! = RID ( ) ) {
full_copy ( sd ) ;
}
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback : : Span span ;
2020-08-05 09:25:28 +03:00
span . start = sd - > text . length ( ) ;
span . end = span . start + p_text . length ( ) ;
2020-12-27 15:30:33 +02:00
2020-08-05 09:25:28 +03:00
// Pre-sort fonts, push fonts with the language support first.
2022-02-13 14:41:29 +02:00
Array fonts_no_match ;
2021-06-10 22:25:32 +03:00
int font_count = p_fonts . size ( ) ;
2022-09-25 23:05:17 +03:00
if ( font_count > 0 ) {
span . fonts . push_back ( p_fonts [ 0 ] ) ;
}
for ( int i = 1 ; i < font_count ; i + + ) {
2022-09-27 11:23:34 +03:00
if ( _font_is_language_supported ( p_fonts [ i ] , p_language ) ) {
2020-08-05 09:25:28 +03:00
span . fonts . push_back ( p_fonts [ i ] ) ;
2021-06-10 22:25:32 +03:00
} else {
fonts_no_match . push_back ( p_fonts [ i ] ) ;
2020-08-05 09:25:28 +03:00
}
}
2021-06-10 22:25:32 +03:00
span . fonts . append_array ( fonts_no_match ) ;
2020-12-29 09:54:59 +01:00
ERR_FAIL_COND_V ( span . fonts . is_empty ( ) , false ) ;
2020-08-05 09:25:28 +03:00
span . font_size = p_size ;
span . language = p_language ;
2022-01-20 09:30:42 +02:00
span . meta = p_meta ;
2020-08-05 09:25:28 +03:00
sd - > spans . push_back ( span ) ;
2022-02-13 14:41:29 +02:00
sd - > text = sd - > text + p_text ;
2020-08-05 09:25:28 +03:00
sd - > end + = p_text . length ( ) ;
invalidate ( sd ) ;
return true ;
}
2023-01-31 11:08:11 +02:00
bool TextServerFallback : : _shaped_text_add_object ( const RID & p_shaped , const Variant & p_key , const Size2 & p_size , InlineAlignment p_inline_align , int64_t p_length , double p_baseline ) {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , false ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2020-08-05 09:25:28 +03:00
ERR_FAIL_COND_V ( p_key = = Variant ( ) , false ) ;
ERR_FAIL_COND_V ( sd - > objects . has ( p_key ) , false ) ;
if ( sd - > parent ! = RID ( ) ) {
full_copy ( sd ) ;
}
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback : : Span span ;
2021-12-13 18:31:16 +02:00
span . start = sd - > start + sd - > text . length ( ) ;
2020-08-05 09:25:28 +03:00
span . end = span . start + p_length ;
span . embedded_key = p_key ;
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback : : EmbeddedObject obj ;
2020-08-05 09:25:28 +03:00
obj . inline_align = p_inline_align ;
obj . rect . size = p_size ;
2024-03-11 16:28:58 +02:00
obj . start = span . start ;
obj . end = span . end ;
2022-12-08 22:01:07 +02:00
obj . baseline = p_baseline ;
2020-08-05 09:25:28 +03:00
sd - > spans . push_back ( span ) ;
2022-02-13 14:41:29 +02:00
sd - > text = sd - > text + String : : chr ( 0xfffc ) . repeat ( p_length ) ;
2020-08-05 09:25:28 +03:00
sd - > end + = p_length ;
sd - > objects [ p_key ] = obj ;
invalidate ( sd ) ;
return true ;
}
2025-03-21 16:42:23 +02:00
String TextServerFallback : : _shaped_get_text ( const RID & p_shaped ) const {
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , String ( ) ) ;
return sd - > text ;
}
2025-09-09 10:35:16 +03:00
bool TextServerFallback : : _shaped_text_has_object ( const RID & p_shaped , const Variant & p_key ) const {
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , false ) ;
MutexLock lock ( sd - > mutex ) ;
return sd - > objects . has ( p_key ) ;
}
2023-01-31 11:08:11 +02:00
bool TextServerFallback : : _shaped_text_resize_object ( const RID & p_shaped , const Variant & p_key , const Size2 & p_size , InlineAlignment p_inline_align , double p_baseline ) {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , false ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2020-08-05 09:25:28 +03:00
ERR_FAIL_COND_V ( ! sd - > objects . has ( p_key ) , false ) ;
sd - > objects [ p_key ] . rect . size = p_size ;
sd - > objects [ p_key ] . inline_align = p_inline_align ;
2022-12-08 22:01:07 +02:00
sd - > objects [ p_key ] . baseline = p_baseline ;
2024-05-30 22:57:28 -07:00
if ( sd - > valid . is_set ( ) ) {
2020-08-05 09:25:28 +03:00
// Recalc string metrics.
sd - > ascent = 0 ;
sd - > descent = 0 ;
sd - > width = 0 ;
sd - > upos = 0 ;
sd - > uthk = 0 ;
2024-09-26 09:37:47 +03:00
Vector < ShapedTextDataFallback : : Span > & spans = sd - > spans ;
if ( sd - > parent ! = RID ( ) ) {
ShapedTextDataFallback * parent_sd = shaped_owner . get_or_null ( sd - > parent ) ;
ERR_FAIL_COND_V ( ! parent_sd - > valid . is_set ( ) , false ) ;
spans = parent_sd - > spans ;
}
2020-12-01 15:03:31 +02:00
int sd_size = sd - > glyphs . size ( ) ;
2024-09-26 09:37:47 +03:00
int span_size = spans . size ( ) ;
2020-12-01 15:03:31 +02:00
for ( int i = 0 ; i < sd_size ; i + + ) {
2020-08-05 09:25:28 +03:00
Glyph gl = sd - > glyphs [ i ] ;
Variant key ;
2024-09-26 09:37:47 +03:00
if ( ( gl . flags & GRAPHEME_IS_EMBEDDED_OBJECT ) = = GRAPHEME_IS_EMBEDDED_OBJECT & & gl . span_index + sd - > first_span > = 0 & & gl . span_index + sd - > first_span < span_size ) {
key = spans [ gl . span_index + sd - > first_span ] . embedded_key ;
2020-08-05 09:25:28 +03:00
}
if ( key ! = Variant ( ) ) {
if ( sd - > orientation = = ORIENTATION_HORIZONTAL ) {
sd - > objects [ key ] . rect . position . x = sd - > width ;
sd - > width + = sd - > objects [ key ] . rect . size . x ;
sd - > glyphs . write [ i ] . advance = sd - > objects [ key ] . rect . size . x ;
} else {
sd - > objects [ key ] . rect . position . y = sd - > width ;
sd - > width + = sd - > objects [ key ] . rect . size . y ;
sd - > glyphs . write [ i ] . advance = sd - > objects [ key ] . rect . size . y ;
}
} else {
2020-12-27 15:30:33 +02:00
if ( gl . font_rid . is_valid ( ) ) {
2020-08-05 09:25:28 +03:00
if ( sd - > orientation = = ORIENTATION_HORIZONTAL ) {
2023-08-24 11:56:50 +03:00
sd - > ascent = MAX ( sd - > ascent , _font_get_ascent ( gl . font_rid , gl . font_size ) + _font_get_spacing ( gl . font_rid , SPACING_TOP ) ) ;
sd - > descent = MAX ( sd - > descent , _font_get_descent ( gl . font_rid , gl . font_size ) + _font_get_spacing ( gl . font_rid , SPACING_BOTTOM ) ) ;
2020-08-05 09:25:28 +03:00
} else {
2022-09-27 11:23:34 +03:00
sd - > ascent = MAX ( sd - > ascent , Math : : round ( _font_get_glyph_advance ( gl . font_rid , gl . font_size , gl . index ) . x * 0.5 ) ) ;
sd - > descent = MAX ( sd - > descent , Math : : round ( _font_get_glyph_advance ( gl . font_rid , gl . font_size , gl . index ) . x * 0.5 ) ) ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
sd - > upos = MAX ( sd - > upos , _font_get_underline_position ( gl . font_rid , gl . font_size ) ) ;
sd - > uthk = MAX ( sd - > uthk , _font_get_underline_thickness ( gl . font_rid , gl . font_size ) ) ;
2020-08-05 09:25:28 +03:00
} else if ( sd - > preserve_invalid | | ( sd - > preserve_control & & is_control ( gl . index ) ) ) {
// Glyph not found, replace with hex code box.
if ( sd - > orientation = = ORIENTATION_HORIZONTAL ) {
2025-05-20 08:53:40 +03:00
sd - > ascent = MAX ( sd - > ascent , get_hex_code_box_size ( gl . font_size , gl . index ) . y * 0.85 ) ;
sd - > descent = MAX ( sd - > descent , get_hex_code_box_size ( gl . font_size , gl . index ) . y * 0.15 ) ;
2020-08-05 09:25:28 +03:00
} else {
2022-02-13 14:41:29 +02:00
sd - > ascent = MAX ( sd - > ascent , Math : : round ( get_hex_code_box_size ( gl . font_size , gl . index ) . x * 0.5 ) ) ;
sd - > descent = MAX ( sd - > descent , Math : : round ( get_hex_code_box_size ( gl . font_size , gl . index ) . x * 0.5 ) ) ;
2020-08-05 09:25:28 +03:00
}
}
sd - > width + = gl . advance * gl . repeat ;
}
}
2022-01-20 09:30:42 +02:00
_realign ( sd ) ;
}
return true ;
}
2020-08-05 09:25:28 +03:00
2022-01-20 09:30:42 +02:00
void TextServerFallback : : _realign ( ShapedTextDataFallback * p_sd ) const {
// Align embedded objects to baseline.
2022-02-13 14:41:29 +02:00
double full_ascent = p_sd - > ascent ;
double full_descent = p_sd - > descent ;
2022-01-20 09:30:42 +02:00
for ( KeyValue < Variant , ShapedTextDataFallback : : EmbeddedObject > & E : p_sd - > objects ) {
2024-03-11 16:28:58 +02:00
if ( ( E . value . start > = p_sd - > start ) & & ( E . value . start < p_sd - > end ) ) {
2022-01-20 09:30:42 +02:00
if ( p_sd - > orientation = = ORIENTATION_HORIZONTAL ) {
switch ( E . value . inline_align & INLINE_ALIGNMENT_TEXT_MASK ) {
case INLINE_ALIGNMENT_TO_TOP : {
E . value . rect . position . y = - p_sd - > ascent ;
} break ;
case INLINE_ALIGNMENT_TO_CENTER : {
E . value . rect . position . y = ( - p_sd - > ascent + p_sd - > descent ) / 2 ;
} break ;
case INLINE_ALIGNMENT_TO_BASELINE : {
E . value . rect . position . y = 0 ;
} break ;
case INLINE_ALIGNMENT_TO_BOTTOM : {
E . value . rect . position . y = p_sd - > descent ;
} break ;
}
switch ( E . value . inline_align & INLINE_ALIGNMENT_IMAGE_MASK ) {
case INLINE_ALIGNMENT_BOTTOM_TO : {
E . value . rect . position . y - = E . value . rect . size . y ;
} break ;
case INLINE_ALIGNMENT_CENTER_TO : {
E . value . rect . position . y - = E . value . rect . size . y / 2 ;
} break ;
2022-12-08 22:01:07 +02:00
case INLINE_ALIGNMENT_BASELINE_TO : {
E . value . rect . position . y - = E . value . baseline ;
} break ;
2022-01-20 09:30:42 +02:00
case INLINE_ALIGNMENT_TOP_TO : {
// NOP
} break ;
2020-08-05 09:25:28 +03:00
}
2022-01-20 09:30:42 +02:00
full_ascent = MAX ( full_ascent , - E . value . rect . position . y ) ;
full_descent = MAX ( full_descent , E . value . rect . position . y + E . value . rect . size . y ) ;
} else {
switch ( E . value . inline_align & INLINE_ALIGNMENT_TEXT_MASK ) {
case INLINE_ALIGNMENT_TO_TOP : {
E . value . rect . position . x = - p_sd - > ascent ;
} break ;
case INLINE_ALIGNMENT_TO_CENTER : {
E . value . rect . position . x = ( - p_sd - > ascent + p_sd - > descent ) / 2 ;
} break ;
case INLINE_ALIGNMENT_TO_BASELINE : {
E . value . rect . position . x = 0 ;
} break ;
case INLINE_ALIGNMENT_TO_BOTTOM : {
E . value . rect . position . x = p_sd - > descent ;
} break ;
}
switch ( E . value . inline_align & INLINE_ALIGNMENT_IMAGE_MASK ) {
case INLINE_ALIGNMENT_BOTTOM_TO : {
E . value . rect . position . x - = E . value . rect . size . x ;
} break ;
case INLINE_ALIGNMENT_CENTER_TO : {
E . value . rect . position . x - = E . value . rect . size . x / 2 ;
} break ;
2022-12-08 22:01:07 +02:00
case INLINE_ALIGNMENT_BASELINE_TO : {
E . value . rect . position . x - = E . value . baseline ;
} break ;
2022-01-20 09:30:42 +02:00
case INLINE_ALIGNMENT_TOP_TO : {
// NOP
} break ;
}
full_ascent = MAX ( full_ascent , - E . value . rect . position . x ) ;
full_descent = MAX ( full_descent , E . value . rect . position . x + E . value . rect . size . x ) ;
2020-08-05 09:25:28 +03:00
}
}
}
2022-01-20 09:30:42 +02:00
p_sd - > ascent = full_ascent ;
p_sd - > descent = full_descent ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
RID TextServerFallback : : _shaped_text_substr ( const RID & p_shaped , int64_t p_start , int64_t p_length ) const {
2022-05-18 10:17:55 +03:00
_THREAD_SAFE_METHOD_
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , RID ( ) ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2020-08-05 09:25:28 +03:00
if ( sd - > parent ! = RID ( ) ) {
2022-09-27 11:23:34 +03:00
return _shaped_text_substr ( sd - > parent , p_start , p_length ) ;
2020-08-05 09:25:28 +03:00
}
2024-05-30 22:57:28 -07:00
if ( ! sd - > valid . is_set ( ) ) {
2022-09-27 11:23:34 +03:00
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
}
ERR_FAIL_COND_V ( p_start < 0 | | p_length < 0 , RID ( ) ) ;
ERR_FAIL_COND_V ( sd - > start > p_start | | sd - > end < p_start , RID ( ) ) ;
ERR_FAIL_COND_V ( sd - > end < p_start + p_length , RID ( ) ) ;
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * new_sd = memnew ( ShapedTextDataFallback ) ;
2020-08-05 09:25:28 +03:00
new_sd - > parent = p_shaped ;
new_sd - > start = p_start ;
new_sd - > end = p_start + p_length ;
new_sd - > orientation = sd - > orientation ;
new_sd - > direction = sd - > direction ;
2021-03-06 11:52:16 +02:00
new_sd - > custom_punct = sd - > custom_punct ;
2020-08-05 09:25:28 +03:00
new_sd - > para_direction = sd - > para_direction ;
new_sd - > line_breaks_valid = sd - > line_breaks_valid ;
new_sd - > justification_ops_valid = sd - > justification_ops_valid ;
new_sd - > sort_valid = false ;
new_sd - > upos = sd - > upos ;
new_sd - > uthk = sd - > uthk ;
2022-05-09 12:47:10 +03:00
for ( int i = 0 ; i < TextServer : : SPACING_MAX ; i + + ) {
new_sd - > extra_spacing [ i ] = sd - > extra_spacing [ i ] ;
}
2020-08-05 09:25:28 +03:00
if ( p_length > 0 ) {
2021-12-13 18:31:16 +02:00
new_sd - > text = sd - > text . substr ( p_start - sd - > start , p_length ) ;
2024-09-26 09:37:47 +03:00
int span_size = sd - > spans . size ( ) ;
new_sd - > first_span = 0 ;
new_sd - > last_span = span_size - 1 ;
for ( int i = 0 ; i < span_size ; i + + ) {
const ShapedTextDataFallback : : Span & span = sd - > spans [ i ] ;
if ( span . end < = p_start ) {
new_sd - > first_span = i + 1 ;
} else if ( span . start > = p_start + p_length ) {
new_sd - > last_span = i - 1 ;
break ;
}
}
2020-12-01 15:03:31 +02:00
int sd_size = sd - > glyphs . size ( ) ;
const Glyph * sd_glyphs = sd - > glyphs . ptr ( ) ;
2020-08-05 09:25:28 +03:00
2020-12-01 15:03:31 +02:00
for ( int i = 0 ; i < sd_size ; i + + ) {
if ( ( sd_glyphs [ i ] . start > = new_sd - > start ) & & ( sd_glyphs [ i ] . end < = new_sd - > end ) ) {
Glyph gl = sd_glyphs [ i ] ;
2024-09-26 09:37:47 +03:00
if ( gl . span_index > = 0 ) {
gl . span_index - = new_sd - > first_span ;
}
2023-12-08 12:30:56 +02:00
if ( gl . end = = p_start + p_length & & ( ( gl . flags & GRAPHEME_IS_SOFT_HYPHEN ) = = GRAPHEME_IS_SOFT_HYPHEN ) ) {
gl . index = 0x00ad ;
gl . advance = font_get_glyph_advance ( gl . font_rid , gl . font_size , 0x00ad ) . x ;
}
2025-01-19 10:18:16 +02:00
if ( ( gl . flags & GRAPHEME_IS_EMBEDDED_OBJECT ) = = GRAPHEME_IS_EMBEDDED_OBJECT & & gl . span_index + new_sd - > first_span > = 0 & & gl . span_index + new_sd - > first_span < span_size ) {
Variant key = sd - > spans [ gl . span_index + new_sd - > first_span ] . embedded_key ;
2024-09-26 09:37:47 +03:00
if ( key ! = Variant ( ) ) {
ShapedTextDataFallback : : EmbeddedObject obj = sd - > objects [ key ] ;
if ( new_sd - > orientation = = ORIENTATION_HORIZONTAL ) {
obj . rect . position . x = new_sd - > width ;
new_sd - > width + = obj . rect . size . x ;
} else {
obj . rect . position . y = new_sd - > width ;
new_sd - > width + = obj . rect . size . y ;
2020-08-05 09:25:28 +03:00
}
2024-09-26 09:37:47 +03:00
new_sd - > objects [ key ] = obj ;
2020-08-05 09:25:28 +03:00
}
} else {
2020-12-27 15:30:33 +02:00
if ( gl . font_rid . is_valid ( ) ) {
2020-08-05 09:25:28 +03:00
if ( new_sd - > orientation = = ORIENTATION_HORIZONTAL ) {
2023-08-24 11:56:50 +03:00
new_sd - > ascent = MAX ( new_sd - > ascent , _font_get_ascent ( gl . font_rid , gl . font_size ) + _font_get_spacing ( gl . font_rid , SPACING_TOP ) ) ;
new_sd - > descent = MAX ( new_sd - > descent , _font_get_descent ( gl . font_rid , gl . font_size ) + _font_get_spacing ( gl . font_rid , SPACING_BOTTOM ) ) ;
2020-08-05 09:25:28 +03:00
} else {
2022-09-27 11:23:34 +03:00
new_sd - > ascent = MAX ( new_sd - > ascent , Math : : round ( _font_get_glyph_advance ( gl . font_rid , gl . font_size , gl . index ) . x * 0.5 ) ) ;
new_sd - > descent = MAX ( new_sd - > descent , Math : : round ( _font_get_glyph_advance ( gl . font_rid , gl . font_size , gl . index ) . x * 0.5 ) ) ;
2020-08-05 09:25:28 +03:00
}
} else if ( new_sd - > preserve_invalid | | ( new_sd - > preserve_control & & is_control ( gl . index ) ) ) {
// Glyph not found, replace with hex code box.
if ( new_sd - > orientation = = ORIENTATION_HORIZONTAL ) {
2025-05-20 08:53:40 +03:00
new_sd - > ascent = MAX ( new_sd - > ascent , get_hex_code_box_size ( gl . font_size , gl . index ) . y * 0.85 ) ;
new_sd - > descent = MAX ( new_sd - > descent , get_hex_code_box_size ( gl . font_size , gl . index ) . y * 0.15 ) ;
2020-08-05 09:25:28 +03:00
} else {
2022-02-13 14:41:29 +02:00
new_sd - > ascent = MAX ( new_sd - > ascent , Math : : round ( get_hex_code_box_size ( gl . font_size , gl . index ) . x * 0.5 ) ) ;
new_sd - > descent = MAX ( new_sd - > descent , Math : : round ( get_hex_code_box_size ( gl . font_size , gl . index ) . x * 0.5 ) ) ;
2020-08-05 09:25:28 +03:00
}
}
2025-11-16 20:59:26 +02:00
if ( new_sd - > glyphs . is_empty ( ) & & gl . x_off < 0.0 ) {
gl . advance + = - gl . x_off ;
gl . x_off = 0.0 ;
}
2020-08-05 09:25:28 +03:00
new_sd - > width + = gl . advance * gl . repeat ;
}
new_sd - > glyphs . push_back ( gl ) ;
}
}
2022-02-13 14:41:29 +02:00
_realign ( new_sd ) ;
2020-08-05 09:25:28 +03:00
}
2024-05-30 22:57:28 -07:00
new_sd - > valid . set ( ) ;
2020-08-05 09:25:28 +03:00
return shaped_owner . make_rid ( new_sd ) ;
}
2022-09-27 11:23:34 +03:00
RID TextServerFallback : : _shaped_text_get_parent ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , RID ( ) ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2020-08-05 09:25:28 +03:00
return sd - > parent ;
}
2022-09-27 11:23:34 +03:00
double TextServerFallback : : _shaped_text_fit_to_width ( const RID & p_shaped , double p_width , BitField < JustificationFlag > p_jst_flags ) {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , 0.0 ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2024-05-30 22:57:28 -07:00
if ( ! sd - > valid . is_set ( ) ) {
2024-07-29 21:23:12 -07:00
_shaped_text_shape ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
}
if ( ! sd - > justification_ops_valid ) {
2024-07-29 21:23:12 -07:00
_shaped_text_update_justification_ops ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
}
int start_pos = 0 ;
int end_pos = sd - > glyphs . size ( ) - 1 ;
2022-07-11 12:40:31 +03:00
if ( p_jst_flags . has_flag ( JUSTIFICATION_AFTER_LAST_TAB ) ) {
2020-08-05 09:25:28 +03:00
int start , end , delta ;
if ( sd - > para_direction = = DIRECTION_LTR ) {
start = sd - > glyphs . size ( ) - 1 ;
end = - 1 ;
delta = - 1 ;
} else {
start = 0 ;
end = sd - > glyphs . size ( ) ;
delta = + 1 ;
}
for ( int i = start ; i ! = end ; i + = delta ) {
if ( ( sd - > glyphs [ i ] . flags & GRAPHEME_IS_TAB ) = = GRAPHEME_IS_TAB ) {
if ( sd - > para_direction = = DIRECTION_LTR ) {
start_pos = i ;
break ;
} else {
end_pos = i ;
break ;
}
}
}
}
2022-02-13 14:41:29 +02:00
double justification_width ;
2022-07-11 12:40:31 +03:00
if ( p_jst_flags . has_flag ( JUSTIFICATION_CONSTRAIN_ELLIPSIS ) ) {
2022-01-10 17:24:03 +02:00
if ( sd - > overrun_trim_data . trim_pos > = 0 ) {
end_pos = sd - > overrun_trim_data . trim_pos ;
justification_width = sd - > width_trimmed ;
} else {
2022-01-10 10:13:22 +02:00
return Math : : ceil ( sd - > width ) ;
2022-01-10 17:24:03 +02:00
}
} else {
justification_width = sd - > width ;
}
2022-07-11 12:40:31 +03:00
if ( p_jst_flags . has_flag ( JUSTIFICATION_TRIM_EDGE_SPACES ) ) {
2022-01-10 17:24:03 +02:00
// Trim spaces.
2023-12-08 12:30:56 +02:00
while ( ( start_pos < end_pos ) & & ( ( sd - > glyphs [ start_pos ] . flags & GRAPHEME_IS_SOFT_HYPHEN ) ! = GRAPHEME_IS_SOFT_HYPHEN ) & & ( ( sd - > glyphs [ start_pos ] . flags & GRAPHEME_IS_SPACE ) = = GRAPHEME_IS_SPACE | | ( sd - > glyphs [ start_pos ] . flags & GRAPHEME_IS_BREAK_HARD ) = = GRAPHEME_IS_BREAK_HARD | | ( sd - > glyphs [ start_pos ] . flags & GRAPHEME_IS_BREAK_SOFT ) = = GRAPHEME_IS_BREAK_SOFT ) ) {
2022-01-10 17:24:03 +02:00
justification_width - = sd - > glyphs [ start_pos ] . advance * sd - > glyphs [ start_pos ] . repeat ;
2020-08-05 09:25:28 +03:00
sd - > glyphs . write [ start_pos ] . advance = 0 ;
start_pos + = sd - > glyphs [ start_pos ] . count ;
}
2023-12-08 12:30:56 +02:00
while ( ( start_pos < end_pos ) & & ( ( sd - > glyphs [ end_pos ] . flags & GRAPHEME_IS_SOFT_HYPHEN ) ! = GRAPHEME_IS_SOFT_HYPHEN ) & & ( ( sd - > glyphs [ end_pos ] . flags & GRAPHEME_IS_SPACE ) = = GRAPHEME_IS_SPACE | | ( sd - > glyphs [ end_pos ] . flags & GRAPHEME_IS_BREAK_HARD ) = = GRAPHEME_IS_BREAK_HARD | | ( sd - > glyphs [ end_pos ] . flags & GRAPHEME_IS_BREAK_SOFT ) = = GRAPHEME_IS_BREAK_SOFT ) ) {
2022-01-10 17:24:03 +02:00
justification_width - = sd - > glyphs [ end_pos ] . advance * sd - > glyphs [ end_pos ] . repeat ;
2020-08-05 09:25:28 +03:00
sd - > glyphs . write [ end_pos ] . advance = 0 ;
end_pos - = sd - > glyphs [ end_pos ] . count ;
}
2022-01-10 17:24:03 +02:00
} else {
// Skip breaks, but do not reset size.
2023-12-08 12:30:56 +02:00
while ( ( start_pos < end_pos ) & & ( ( sd - > glyphs [ start_pos ] . flags & GRAPHEME_IS_SOFT_HYPHEN ) ! = GRAPHEME_IS_SOFT_HYPHEN ) & & ( ( sd - > glyphs [ start_pos ] . flags & GRAPHEME_IS_BREAK_HARD ) = = GRAPHEME_IS_BREAK_HARD | | ( sd - > glyphs [ start_pos ] . flags & GRAPHEME_IS_BREAK_SOFT ) = = GRAPHEME_IS_BREAK_SOFT ) ) {
2022-01-10 17:24:03 +02:00
start_pos + = sd - > glyphs [ start_pos ] . count ;
}
2023-12-08 12:30:56 +02:00
while ( ( start_pos < end_pos ) & & ( ( sd - > glyphs [ end_pos ] . flags & GRAPHEME_IS_SOFT_HYPHEN ) ! = GRAPHEME_IS_SOFT_HYPHEN ) & & ( ( sd - > glyphs [ end_pos ] . flags & GRAPHEME_IS_BREAK_HARD ) = = GRAPHEME_IS_BREAK_HARD | | ( sd - > glyphs [ end_pos ] . flags & GRAPHEME_IS_BREAK_SOFT ) = = GRAPHEME_IS_BREAK_SOFT ) ) {
2022-01-10 17:24:03 +02:00
end_pos - = sd - > glyphs [ end_pos ] . count ;
}
2020-08-05 09:25:28 +03:00
}
int space_count = 0 ;
for ( int i = start_pos ; i < = end_pos ; i + + ) {
const Glyph & gl = sd - > glyphs [ i ] ;
if ( gl . count > 0 ) {
2023-12-08 12:30:56 +02:00
if ( ( gl . flags & GRAPHEME_IS_SOFT_HYPHEN ) ! = GRAPHEME_IS_SOFT_HYPHEN & & ( gl . flags & GRAPHEME_IS_SPACE ) = = GRAPHEME_IS_SPACE & & ( gl . flags & GRAPHEME_IS_PUNCTUATION ) ! = GRAPHEME_IS_PUNCTUATION ) {
2020-08-05 09:25:28 +03:00
space_count + + ;
}
}
}
2022-07-11 12:40:31 +03:00
if ( ( space_count > 0 ) & & p_jst_flags . has_flag ( JUSTIFICATION_WORD_BOUND ) ) {
2022-02-13 14:41:29 +02:00
double delta_width_per_space = ( p_width - justification_width ) / space_count ;
2020-08-05 09:25:28 +03:00
for ( int i = start_pos ; i < = end_pos ; i + + ) {
Glyph & gl = sd - > glyphs . write [ i ] ;
if ( gl . count > 0 ) {
2023-12-08 12:30:56 +02:00
if ( ( gl . flags & GRAPHEME_IS_SOFT_HYPHEN ) ! = GRAPHEME_IS_SOFT_HYPHEN & & ( gl . flags & GRAPHEME_IS_SPACE ) = = GRAPHEME_IS_SPACE & & ( gl . flags & GRAPHEME_IS_PUNCTUATION ) ! = GRAPHEME_IS_PUNCTUATION ) {
2022-02-13 14:41:29 +02:00
double old_adv = gl . advance ;
2020-12-27 15:30:33 +02:00
gl . advance = MAX ( gl . advance + delta_width_per_space , Math : : round ( 0.1 * gl . font_size ) ) ;
2022-01-10 17:24:03 +02:00
justification_width + = ( gl . advance - old_adv ) ;
2020-08-05 09:25:28 +03:00
}
}
}
}
2022-01-10 17:24:03 +02:00
if ( Math : : floor ( p_width ) < Math : : floor ( justification_width ) ) {
sd - > fit_width_minimum_reached = true ;
}
2022-07-11 12:40:31 +03:00
if ( ! p_jst_flags . has_flag ( JUSTIFICATION_CONSTRAIN_ELLIPSIS ) ) {
2022-01-10 17:24:03 +02:00
sd - > width = justification_width ;
}
2022-01-10 10:13:22 +02:00
return Math : : ceil ( justification_width ) ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
double TextServerFallback : : _shaped_text_tab_align ( const RID & p_shaped , const PackedFloat32Array & p_tab_stops ) {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , 0.0 ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2024-05-30 22:57:28 -07:00
if ( ! sd - > valid . is_set ( ) ) {
2024-07-29 21:23:12 -07:00
_shaped_text_shape ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
}
if ( ! sd - > line_breaks_valid ) {
2024-07-29 21:23:12 -07:00
_shaped_text_update_breaks ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
}
2022-01-10 12:19:29 +02:00
for ( int i = 0 ; i < p_tab_stops . size ( ) ; i + + ) {
if ( p_tab_stops [ i ] < = 0 ) {
2022-02-13 14:41:29 +02:00
return 0.0 ;
2022-01-10 12:19:29 +02:00
}
}
2020-08-05 09:25:28 +03:00
int tab_index = 0 ;
2022-02-13 14:41:29 +02:00
double off = 0.0 ;
2020-08-05 09:25:28 +03:00
int start , end , delta ;
if ( sd - > para_direction = = DIRECTION_LTR ) {
start = 0 ;
end = sd - > glyphs . size ( ) ;
delta = + 1 ;
} else {
start = sd - > glyphs . size ( ) - 1 ;
end = - 1 ;
delta = - 1 ;
}
2020-12-01 15:03:31 +02:00
Glyph * gl = sd - > glyphs . ptrw ( ) ;
2020-08-05 09:25:28 +03:00
for ( int i = start ; i ! = end ; i + = delta ) {
2020-12-01 15:03:31 +02:00
if ( ( gl [ i ] . flags & GRAPHEME_IS_TAB ) = = GRAPHEME_IS_TAB ) {
2022-02-13 14:41:29 +02:00
double tab_off = 0.0 ;
2020-08-05 09:25:28 +03:00
while ( tab_off < = off ) {
tab_off + = p_tab_stops [ tab_index ] ;
tab_index + + ;
if ( tab_index > = p_tab_stops . size ( ) ) {
tab_index = 0 ;
}
}
2022-02-13 14:41:29 +02:00
double old_adv = gl [ i ] . advance ;
2020-12-01 15:03:31 +02:00
gl [ i ] . advance = tab_off - off ;
sd - > width + = gl [ i ] . advance - old_adv ;
2020-08-05 09:25:28 +03:00
off = 0 ;
continue ;
}
2020-12-01 15:03:31 +02:00
off + = gl [ i ] . advance * gl [ i ] . repeat ;
2020-08-05 09:25:28 +03:00
}
2022-02-13 14:41:29 +02:00
return 0.0 ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _shaped_text_update_breaks ( const RID & p_shaped ) {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , false ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2024-05-30 22:57:28 -07:00
if ( ! sd - > valid . is_set ( ) ) {
2022-09-27 11:23:34 +03:00
_shaped_text_shape ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
}
if ( sd - > line_breaks_valid ) {
2021-03-12 19:05:16 +05:30
return true ; // Nothing to do.
2020-08-05 09:25:28 +03:00
}
2020-12-01 15:03:31 +02:00
int sd_size = sd - > glyphs . size ( ) ;
2021-03-06 11:52:16 +02:00
Glyph * sd_glyphs = sd - > glyphs . ptrw ( ) ;
int c_punct_size = sd - > custom_punct . length ( ) ;
const char32_t * c_punct = sd - > custom_punct . ptr ( ) ;
2020-12-01 15:03:31 +02:00
for ( int i = 0 ; i < sd_size ; i + + ) {
2021-03-06 11:52:16 +02:00
if ( sd_glyphs [ i ] . count > 0 ) {
2021-12-13 18:31:16 +02:00
char32_t c = sd - > text [ sd_glyphs [ i ] . start - sd - > start ] ;
2024-03-05 09:15:11 +02:00
char32_t c_next = i < sd_size ? sd - > text [ sd_glyphs [ i ] . start - sd - > start + 1 ] : 0x0000 ;
2021-03-06 11:52:16 +02:00
if ( c_punct_size = = 0 ) {
2023-03-06 11:54:54 +02:00
if ( is_punct ( c ) & & c ! = 0x005F & & c ! = ' ' ) {
2021-03-06 11:52:16 +02:00
sd_glyphs [ i ] . flags | = GRAPHEME_IS_PUNCTUATION ;
}
} else {
for ( int j = 0 ; j < c_punct_size ; j + + ) {
if ( c_punct [ j ] = = c ) {
sd_glyphs [ i ] . flags | = GRAPHEME_IS_PUNCTUATION ;
break ;
}
}
2020-12-14 10:30:32 +02:00
}
2021-04-03 12:17:51 -03:00
if ( is_underscore ( c ) ) {
sd - > glyphs . write [ i ] . flags | = GRAPHEME_IS_UNDERSCORE ;
}
2020-08-05 09:25:28 +03:00
if ( is_whitespace ( c ) & & ! is_linebreak ( c ) ) {
2021-03-06 11:52:16 +02:00
sd_glyphs [ i ] . flags | = GRAPHEME_IS_SPACE ;
2024-02-14 20:16:07 +02:00
if ( c ! = 0x00A0 & & c ! = 0x202F & & c ! = 0x2060 & & c ! = 0x2007 ) { // Skip for non-breaking space variants.
sd_glyphs [ i ] . flags | = GRAPHEME_IS_BREAK_SOFT ;
}
2020-08-05 09:25:28 +03:00
}
if ( is_linebreak ( c ) ) {
2022-01-10 17:24:03 +02:00
sd_glyphs [ i ] . flags | = GRAPHEME_IS_SPACE ;
2024-03-05 09:15:11 +02:00
if ( c ! = 0x000D | | c_next ! = 0x000A ) { // Skip first hard break in CR-LF pair.
sd_glyphs [ i ] . flags | = GRAPHEME_IS_BREAK_HARD ;
}
2020-08-05 09:25:28 +03:00
}
if ( c = = 0x0009 | | c = = 0x000b ) {
2021-03-06 11:52:16 +02:00
sd_glyphs [ i ] . flags | = GRAPHEME_IS_TAB ;
2020-08-05 09:25:28 +03:00
}
2023-12-08 12:30:56 +02:00
if ( c = = 0x00ad ) {
sd_glyphs [ i ] . flags | = GRAPHEME_IS_SOFT_HYPHEN ;
}
2020-08-05 09:25:28 +03:00
2021-03-06 11:52:16 +02:00
i + = ( sd_glyphs [ i ] . count - 1 ) ;
2020-08-05 09:25:28 +03:00
}
}
sd - > line_breaks_valid = true ;
return sd - > line_breaks_valid ;
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _shaped_text_update_justification_ops ( const RID & p_shaped ) {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , false ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2024-05-30 22:57:28 -07:00
if ( ! sd - > valid . is_set ( ) ) {
2022-09-27 11:23:34 +03:00
_shaped_text_shape ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
}
if ( ! sd - > line_breaks_valid ) {
2022-09-27 11:23:34 +03:00
_shaped_text_update_breaks ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
}
sd - > justification_ops_valid = true ; // Not supported by fallback server.
return true ;
}
2023-10-01 13:39:13 +03:00
RID TextServerFallback : : _find_sys_font_for_text ( const RID & p_fdef , const String & p_script_code , const String & p_language , const String & p_text ) {
RID f ;
// Try system fallback.
if ( _font_is_allow_system_fallback ( p_fdef ) ) {
String font_name = _font_get_name ( p_fdef ) ;
BitField < FontStyle > font_style = _font_get_style ( p_fdef ) ;
int font_weight = _font_get_weight ( p_fdef ) ;
int font_stretch = _font_get_stretch ( p_fdef ) ;
Dictionary dvar = _font_get_variation_coordinates ( p_fdef ) ;
2024-02-22 12:10:37 +02:00
static int64_t wgth_tag = name_to_tag ( " weight " ) ;
static int64_t wdth_tag = name_to_tag ( " width " ) ;
static int64_t ital_tag = name_to_tag ( " italic " ) ;
2023-10-01 13:39:13 +03:00
if ( dvar . has ( wgth_tag ) ) {
font_weight = dvar [ wgth_tag ] . operator int ( ) ;
}
if ( dvar . has ( wdth_tag ) ) {
font_stretch = dvar [ wdth_tag ] . operator int ( ) ;
}
if ( dvar . has ( ital_tag ) & & dvar [ ital_tag ] . operator int ( ) = = 1 ) {
font_style . set_flag ( TextServer : : FONT_ITALIC ) ;
}
String locale = ( p_language . is_empty ( ) ) ? TranslationServer : : get_singleton ( ) - > get_tool_locale ( ) : p_language ;
PackedStringArray fallback_font_name = OS : : get_singleton ( ) - > get_system_font_path_for_text ( font_name , p_text , locale , p_script_code , font_weight , font_stretch , font_style & TextServer : : FONT_ITALIC ) ;
for ( const String & E : fallback_font_name ) {
SystemFontKey key = SystemFontKey ( E , font_style & TextServer : : FONT_ITALIC , font_weight , font_stretch , p_fdef , this ) ;
if ( system_fonts . has ( key ) ) {
const SystemFontCache & sysf_cache = system_fonts [ key ] ;
int best_score = 0 ;
int best_match = - 1 ;
for ( int face_idx = 0 ; face_idx < sysf_cache . var . size ( ) ; face_idx + + ) {
const SystemFontCacheRec & F = sysf_cache . var [ face_idx ] ;
if ( unlikely ( ! _font_has_char ( F . rid , p_text [ 0 ] ) ) ) {
continue ;
}
BitField < FontStyle > style = _font_get_style ( F . rid ) ;
int weight = _font_get_weight ( F . rid ) ;
int stretch = _font_get_stretch ( F . rid ) ;
int score = ( 20 - Math : : abs ( weight - font_weight ) / 50 ) ;
score + = ( 20 - Math : : abs ( stretch - font_stretch ) / 10 ) ;
if ( bool ( style & TextServer : : FONT_ITALIC ) = = bool ( font_style & TextServer : : FONT_ITALIC ) ) {
score + = 30 ;
}
if ( score > = best_score ) {
best_score = score ;
best_match = face_idx ;
}
if ( best_score = = 70 ) {
break ;
}
}
if ( best_match ! = - 1 ) {
f = sysf_cache . var [ best_match ] . rid ;
}
}
if ( ! f . is_valid ( ) ) {
if ( system_fonts . has ( key ) ) {
const SystemFontCache & sysf_cache = system_fonts [ key ] ;
if ( sysf_cache . max_var = = sysf_cache . var . size ( ) ) {
// All subfonts already tested, skip.
continue ;
}
}
if ( ! system_font_data . has ( E ) ) {
system_font_data [ E ] = FileAccess : : get_file_as_bytes ( E ) ;
}
const PackedByteArray & font_data = system_font_data [ E ] ;
SystemFontCacheRec sysf ;
sysf . rid = _create_font ( ) ;
_font_set_data_ptr ( sysf . rid , font_data . ptr ( ) , font_data . size ( ) ) ;
2024-10-01 17:22:16 +03:00
if ( ! _font_validate ( sysf . rid ) ) {
_free_rid ( sysf . rid ) ;
continue ;
}
2023-10-01 13:39:13 +03:00
Dictionary var = dvar ;
// Select matching style from collection.
int best_score = 0 ;
int best_match = - 1 ;
for ( int face_idx = 0 ; face_idx < _font_get_face_count ( sysf . rid ) ; face_idx + + ) {
_font_set_face_index ( sysf . rid , face_idx ) ;
if ( unlikely ( ! _font_has_char ( sysf . rid , p_text [ 0 ] ) ) ) {
continue ;
}
BitField < FontStyle > style = _font_get_style ( sysf . rid ) ;
int weight = _font_get_weight ( sysf . rid ) ;
int stretch = _font_get_stretch ( sysf . rid ) ;
int score = ( 20 - Math : : abs ( weight - font_weight ) / 50 ) ;
score + = ( 20 - Math : : abs ( stretch - font_stretch ) / 10 ) ;
if ( bool ( style & TextServer : : FONT_ITALIC ) = = bool ( font_style & TextServer : : FONT_ITALIC ) ) {
score + = 30 ;
}
if ( score > = best_score ) {
best_score = score ;
best_match = face_idx ;
}
if ( best_score = = 70 ) {
break ;
}
}
if ( best_match = = - 1 ) {
_free_rid ( sysf . rid ) ;
continue ;
} else {
_font_set_face_index ( sysf . rid , best_match ) ;
}
sysf . index = best_match ;
// If it's a variable font, apply weight, stretch and italic coordinates to match requested style.
if ( best_score ! = 70 ) {
Dictionary ftr = _font_supported_variation_list ( sysf . rid ) ;
if ( ftr . has ( wdth_tag ) ) {
var [ wdth_tag ] = font_stretch ;
_font_set_stretch ( sysf . rid , font_stretch ) ;
}
if ( ftr . has ( wgth_tag ) ) {
var [ wgth_tag ] = font_weight ;
_font_set_weight ( sysf . rid , font_weight ) ;
}
if ( ( font_style & TextServer : : FONT_ITALIC ) & & ftr . has ( ital_tag ) ) {
var [ ital_tag ] = 1 ;
_font_set_style ( sysf . rid , _font_get_style ( sysf . rid ) | TextServer : : FONT_ITALIC ) ;
}
}
2025-07-31 09:40:10 +03:00
bool fb_use_msdf = key . msdf ;
2025-09-28 17:08:51 +03:00
# ifdef MODULE_FREETYPE_ENABLED
2025-07-31 09:40:10 +03:00
if ( fb_use_msdf ) {
FontFallback * fd = _get_font_data ( sysf . rid ) ;
if ( fd ) {
MutexLock lock ( fd - > mutex ) ;
Vector2i size = _get_size ( fd , 16 ) ;
FontForSizeFallback * ffsd = nullptr ;
if ( _ensure_cache_for_size ( fd , size , ffsd ) ) {
2026-02-02 11:36:42 +02:00
if ( ffsd & & ( FT_HAS_COLOR ( fd - > face ) | | ! FT_IS_SCALABLE ( fd - > face ) ) ) {
2025-07-31 09:40:10 +03:00
fb_use_msdf = false ;
}
}
}
}
2025-09-28 17:08:51 +03:00
# endif
2025-07-31 09:40:10 +03:00
2023-10-01 13:39:13 +03:00
_font_set_antialiasing ( sysf . rid , key . antialiasing ) ;
2024-03-11 13:42:16 +02:00
_font_set_disable_embedded_bitmaps ( sysf . rid , key . disable_embedded_bitmaps ) ;
2023-10-01 13:39:13 +03:00
_font_set_generate_mipmaps ( sysf . rid , key . mipmaps ) ;
2025-07-31 09:40:10 +03:00
_font_set_multichannel_signed_distance_field ( sysf . rid , fb_use_msdf ) ;
2023-10-01 13:39:13 +03:00
_font_set_msdf_pixel_range ( sysf . rid , key . msdf_range ) ;
_font_set_msdf_size ( sysf . rid , key . msdf_source_size ) ;
_font_set_fixed_size ( sysf . rid , key . fixed_size ) ;
_font_set_force_autohinter ( sysf . rid , key . force_autohinter ) ;
_font_set_hinting ( sysf . rid , key . hinting ) ;
_font_set_subpixel_positioning ( sysf . rid , key . subpixel_positioning ) ;
2024-10-30 11:14:11 +02:00
_font_set_keep_rounding_remainders ( sysf . rid , key . keep_rounding_remainders ) ;
2023-10-01 13:39:13 +03:00
_font_set_variation_coordinates ( sysf . rid , var ) ;
_font_set_embolden ( sysf . rid , key . embolden ) ;
_font_set_transform ( sysf . rid , key . transform ) ;
_font_set_spacing ( sysf . rid , SPACING_TOP , key . extra_spacing [ SPACING_TOP ] ) ;
_font_set_spacing ( sysf . rid , SPACING_BOTTOM , key . extra_spacing [ SPACING_BOTTOM ] ) ;
_font_set_spacing ( sysf . rid , SPACING_SPACE , key . extra_spacing [ SPACING_SPACE ] ) ;
_font_set_spacing ( sysf . rid , SPACING_GLYPH , key . extra_spacing [ SPACING_GLYPH ] ) ;
if ( system_fonts . has ( key ) ) {
system_fonts [ key ] . var . push_back ( sysf ) ;
} else {
SystemFontCache & sysf_cache = system_fonts [ key ] ;
sysf_cache . max_var = _font_get_face_count ( sysf . rid ) ;
sysf_cache . var . push_back ( sysf ) ;
}
f = sysf . rid ;
}
break ;
}
}
return f ;
}
2022-09-27 11:23:34 +03:00
void TextServerFallback : : _shaped_text_overrun_trim_to_width ( const RID & p_shaped_line , double p_width , BitField < TextServer : : TextOverrunFlag > p_trim_flags ) {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped_line ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_MSG ( sd , " ShapedTextDataFallback invalid. " ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2024-05-30 22:57:28 -07:00
if ( ! sd - > valid . is_set ( ) ) {
2022-09-27 11:23:34 +03:00
_shaped_text_shape ( p_shaped_line ) ;
2021-07-04 16:43:55 +02:00
}
2021-09-27 21:51:18 +03:00
sd - > text_trimmed = false ;
2021-08-11 00:09:48 +02:00
sd - > overrun_trim_data . ellipsis_glyph_buf . clear ( ) ;
2022-07-11 12:40:31 +03:00
bool add_ellipsis = p_trim_flags . has_flag ( OVERRUN_ADD_ELLIPSIS ) ;
bool cut_per_word = p_trim_flags . has_flag ( OVERRUN_TRIM_WORD_ONLY ) ;
bool enforce_ellipsis = p_trim_flags . has_flag ( OVERRUN_ENFORCE_ELLIPSIS ) ;
2025-09-11 13:05:31 +03:00
bool short_string_ellipsis = p_trim_flags . has_flag ( OVERRUN_SHORT_STRING_ELLIPSIS ) ;
2022-07-11 12:40:31 +03:00
bool justification_aware = p_trim_flags . has_flag ( OVERRUN_JUSTIFICATION_AWARE ) ;
2021-07-04 16:43:55 +02:00
Glyph * sd_glyphs = sd - > glyphs . ptrw ( ) ;
2022-08-04 22:58:28 +03:00
if ( ( p_trim_flags & OVERRUN_TRIM ) = = OVERRUN_NO_TRIM | | sd_glyphs = = nullptr | | p_width < = 0 | | ! ( sd - > width > p_width | | enforce_ellipsis ) ) {
2021-08-11 00:09:48 +02:00
sd - > overrun_trim_data . trim_pos = - 1 ;
sd - > overrun_trim_data . ellipsis_pos = - 1 ;
return ;
}
if ( justification_aware & & ! sd - > fit_width_minimum_reached ) {
2021-07-04 16:43:55 +02:00
return ;
}
2022-01-20 09:30:42 +02:00
Vector < ShapedTextDataFallback : : Span > & spans = sd - > spans ;
2022-01-10 17:24:03 +02:00
if ( sd - > parent ! = RID ( ) ) {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * parent_sd = shaped_owner . get_or_null ( sd - > parent ) ;
2024-05-30 22:57:28 -07:00
ERR_FAIL_COND ( ! parent_sd - > valid . is_set ( ) ) ;
2022-01-10 17:24:03 +02:00
spans = parent_sd - > spans ;
}
2024-09-26 09:37:47 +03:00
int span_size = spans . size ( ) ;
if ( span_size = = 0 ) {
2022-01-10 17:24:03 +02:00
return ;
}
2021-07-04 16:43:55 +02:00
int sd_size = sd - > glyphs . size ( ) ;
int last_gl_font_size = sd_glyphs [ sd_size - 1 ] . font_size ;
2023-10-01 13:39:13 +03:00
bool found_el_char = false ;
2022-01-10 17:24:03 +02:00
// Find usable fonts, if fonts from the last glyph do not have required chars.
RID dot_gl_font_rid = sd_glyphs [ sd_size - 1 ] . font_rid ;
2025-09-11 13:05:31 +03:00
if ( add_ellipsis | | enforce_ellipsis | | short_string_ellipsis ) {
2024-11-05 11:04:48 +02:00
if ( ! _font_has_char ( dot_gl_font_rid , sd - > el_char ) ) {
2024-09-26 09:37:47 +03:00
const Array & fonts = spans [ span_size - 1 ] . fonts ;
2023-10-01 13:39:13 +03:00
for ( int i = 0 ; i < fonts . size ( ) ; i + + ) {
2024-11-05 11:04:48 +02:00
if ( _font_has_char ( fonts [ i ] , sd - > el_char ) ) {
2023-10-01 13:39:13 +03:00
dot_gl_font_rid = fonts [ i ] ;
2024-11-05 11:04:48 +02:00
found_el_char = true ;
2023-10-01 13:39:13 +03:00
break ;
}
}
2024-11-05 11:04:48 +02:00
if ( ! found_el_char & & OS : : get_singleton ( ) - > has_feature ( " system_fonts " ) & & fonts . size ( ) > 0 & & _font_is_allow_system_fallback ( fonts [ 0 ] ) ) {
const char32_t u32str [ ] = { sd - > el_char , 0 } ;
2024-09-26 09:37:47 +03:00
RID rid = _find_sys_font_for_text ( fonts [ 0 ] , String ( ) , spans [ span_size - 1 ] . language , u32str ) ;
2023-10-01 13:39:13 +03:00
if ( rid . is_valid ( ) ) {
dot_gl_font_rid = rid ;
2024-11-05 11:04:48 +02:00
found_el_char = true ;
}
}
} else {
found_el_char = true ;
}
if ( ! found_el_char ) {
bool found_dot_char = false ;
dot_gl_font_rid = sd_glyphs [ sd_size - 1 ] . font_rid ;
if ( ! _font_has_char ( dot_gl_font_rid , ' . ' ) ) {
2024-09-26 09:37:47 +03:00
const Array & fonts = spans [ span_size - 1 ] . fonts ;
2024-11-05 11:04:48 +02:00
for ( int i = 0 ; i < fonts . size ( ) ; i + + ) {
if ( _font_has_char ( fonts [ i ] , ' . ' ) ) {
dot_gl_font_rid = fonts [ i ] ;
found_dot_char = true ;
break ;
}
}
if ( ! found_dot_char & & OS : : get_singleton ( ) - > has_feature ( " system_fonts " ) & & fonts . size ( ) > 0 & & _font_is_allow_system_fallback ( fonts [ 0 ] ) ) {
2024-09-26 09:37:47 +03:00
RID rid = _find_sys_font_for_text ( fonts [ 0 ] , String ( ) , spans [ span_size - 1 ] . language , " . " ) ;
2024-11-05 11:04:48 +02:00
if ( rid . is_valid ( ) ) {
dot_gl_font_rid = rid ;
}
2023-10-01 13:39:13 +03:00
}
}
}
2022-01-10 17:24:03 +02:00
}
RID whitespace_gl_font_rid = sd_glyphs [ sd_size - 1 ] . font_rid ;
2023-10-01 13:39:13 +03:00
if ( ! _font_has_char ( whitespace_gl_font_rid , ' ' ) ) {
2024-09-26 09:37:47 +03:00
const Array & fonts = spans [ span_size - 1 ] . fonts ;
2022-02-13 14:41:29 +02:00
for ( int i = 0 ; i < fonts . size ( ) ; i + + ) {
2022-09-27 11:23:34 +03:00
if ( _font_has_char ( fonts [ i ] , ' ' ) ) {
2022-02-13 14:41:29 +02:00
whitespace_gl_font_rid = fonts [ i ] ;
2022-01-10 17:24:03 +02:00
break ;
}
}
}
2025-09-11 13:05:31 +03:00
int32_t dot_gl_idx = ( ( add_ellipsis | | enforce_ellipsis | | short_string_ellipsis ) & & dot_gl_font_rid . is_valid ( ) ) ? _font_get_glyph_index ( dot_gl_font_rid , last_gl_font_size , ( found_el_char ? sd - > el_char : ' . ' ) , 0 ) : - 1 ;
Vector2 dot_adv = ( ( add_ellipsis | | enforce_ellipsis | | short_string_ellipsis ) & & dot_gl_font_rid . is_valid ( ) ) ? _font_get_glyph_advance ( dot_gl_font_rid , last_gl_font_size , dot_gl_idx ) : Vector2 ( ) ;
2023-10-01 13:39:13 +03:00
int32_t whitespace_gl_idx = whitespace_gl_font_rid . is_valid ( ) ? _font_get_glyph_index ( whitespace_gl_font_rid , last_gl_font_size , ' ' , 0 ) : - 1 ;
2022-09-27 11:23:34 +03:00
Vector2 whitespace_adv = whitespace_gl_font_rid . is_valid ( ) ? _font_get_glyph_advance ( whitespace_gl_font_rid , last_gl_font_size , whitespace_gl_idx ) : Vector2 ( ) ;
2021-07-04 16:43:55 +02:00
2021-08-11 00:09:48 +02:00
int ellipsis_width = 0 ;
2022-01-10 17:24:03 +02:00
if ( add_ellipsis & & whitespace_gl_font_rid . is_valid ( ) ) {
2023-10-01 13:39:13 +03:00
ellipsis_width = ( found_el_char ? 1 : 3 ) * dot_adv . x + sd - > extra_spacing [ SPACING_GLYPH ] + _font_get_spacing ( dot_gl_font_rid , SPACING_GLYPH ) + ( cut_per_word ? whitespace_adv . x : 0 ) ;
2021-07-04 16:43:55 +02:00
}
int ell_min_characters = 6 ;
2022-02-13 14:41:29 +02:00
double width = sd - > width ;
2025-02-09 22:33:46 +02:00
double width_without_el = width ;
2021-07-04 16:43:55 +02:00
2021-08-11 00:09:48 +02:00
int trim_pos = 0 ;
2025-09-11 13:05:31 +03:00
int ellipsis_pos = ( enforce_ellipsis | | short_string_ellipsis ) ? 0 : - 1 ;
2021-07-04 16:43:55 +02:00
2025-02-09 22:33:46 +02:00
int last_valid_cut = - 1 ;
int last_valid_cut_witout_el = - 1 ;
2021-07-04 16:43:55 +02:00
2025-09-11 13:05:31 +03:00
if ( ( enforce_ellipsis | | short_string_ellipsis ) & & ( width + ellipsis_width < = p_width ) ) {
2022-09-16 19:46:11 +03:00
trim_pos = - 1 ;
ellipsis_pos = sd_size ;
} else {
for ( int i = sd_size - 1 ; i ! = - 1 ; i - - ) {
width - = sd_glyphs [ i ] . advance * sd_glyphs [ i ] . repeat ;
2021-07-04 16:43:55 +02:00
2022-09-16 19:46:11 +03:00
if ( sd_glyphs [ i ] . count > 0 ) {
bool above_min_char_threshold = ( i > = ell_min_characters ) ;
2025-02-09 22:33:46 +02:00
if ( ! above_min_char_threshold & & last_valid_cut_witout_el ! = - 1 ) {
trim_pos = last_valid_cut_witout_el ;
ellipsis_pos = - 1 ;
width = width_without_el ;
break ;
}
2025-09-11 13:05:31 +03:00
if ( ! ( enforce_ellipsis | | short_string_ellipsis ) & & width < = p_width & & last_valid_cut_witout_el = = - 1 ) {
2025-02-09 22:33:46 +02:00
if ( cut_per_word & & above_min_char_threshold ) {
if ( ( sd_glyphs [ i ] . flags & GRAPHEME_IS_BREAK_SOFT ) = = GRAPHEME_IS_BREAK_SOFT ) {
last_valid_cut_witout_el = i ;
width_without_el = width ;
}
} else {
last_valid_cut_witout_el = i ;
width_without_el = width ;
}
}
2025-09-11 13:05:31 +03:00
if ( width + ( ( ( above_min_char_threshold & & add_ellipsis ) | | enforce_ellipsis | | short_string_ellipsis ) ? ellipsis_width : 0 ) < = p_width ) {
2022-09-16 19:46:11 +03:00
if ( cut_per_word & & above_min_char_threshold ) {
if ( ( sd_glyphs [ i ] . flags & GRAPHEME_IS_BREAK_SOFT ) = = GRAPHEME_IS_BREAK_SOFT ) {
last_valid_cut = i ;
}
} else {
2021-07-04 16:43:55 +02:00
last_valid_cut = i ;
}
2025-02-09 22:33:46 +02:00
if ( last_valid_cut ! = - 1 ) {
2022-09-16 19:46:11 +03:00
trim_pos = last_valid_cut ;
2021-07-04 16:43:55 +02:00
2025-09-11 13:05:31 +03:00
if ( add_ellipsis & & ( above_min_char_threshold | | enforce_ellipsis | | short_string_ellipsis ) & & width - ellipsis_width < = p_width ) {
2022-09-16 19:46:11 +03:00
ellipsis_pos = trim_pos ;
}
break ;
2021-07-04 16:43:55 +02:00
}
}
}
}
2021-08-11 00:09:48 +02:00
}
sd - > overrun_trim_data . trim_pos = trim_pos ;
sd - > overrun_trim_data . ellipsis_pos = ellipsis_pos ;
2025-09-11 13:05:31 +03:00
if ( trim_pos = = 0 & & ( enforce_ellipsis | | short_string_ellipsis ) & & add_ellipsis ) {
2021-08-11 00:09:48 +02:00
sd - > overrun_trim_data . ellipsis_pos = 0 ;
2021-07-04 16:43:55 +02:00
}
2025-09-11 13:05:31 +03:00
if ( ( trim_pos > = 0 & & sd - > width > p_width ) | | enforce_ellipsis | | short_string_ellipsis ) {
if ( add_ellipsis & & ( ellipsis_pos > 0 | | enforce_ellipsis | | short_string_ellipsis ) ) {
2024-07-05 16:03:01 -04:00
// Insert an additional space when cutting word bound for aesthetics.
2021-07-04 16:43:55 +02:00
if ( cut_per_word & & ( ellipsis_pos > 0 ) ) {
2021-08-28 00:19:51 +03:00
Glyph gl ;
2021-07-04 16:43:55 +02:00
gl . count = 1 ;
gl . advance = whitespace_adv . x ;
gl . index = whitespace_gl_idx ;
2022-01-10 17:24:03 +02:00
gl . font_rid = whitespace_gl_font_rid ;
2021-07-04 16:43:55 +02:00
gl . font_size = last_gl_font_size ;
2021-08-11 00:09:48 +02:00
gl . flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL ;
2021-07-04 16:43:55 +02:00
2021-08-11 00:09:48 +02:00
sd - > overrun_trim_data . ellipsis_glyph_buf . append ( gl ) ;
2021-07-04 16:43:55 +02:00
}
// Add ellipsis dots.
2022-01-10 17:24:03 +02:00
if ( dot_gl_idx ! = 0 ) {
Glyph gl ;
gl . count = 1 ;
2023-10-01 13:39:13 +03:00
gl . repeat = ( found_el_char ? 1 : 3 ) ;
2022-01-10 17:24:03 +02:00
gl . advance = dot_adv . x ;
gl . index = dot_gl_idx ;
gl . font_rid = dot_gl_font_rid ;
gl . font_size = last_gl_font_size ;
gl . flags = GRAPHEME_IS_PUNCTUATION | GRAPHEME_IS_VIRTUAL ;
sd - > overrun_trim_data . ellipsis_glyph_buf . append ( gl ) ;
}
2021-07-04 16:43:55 +02:00
}
2021-08-11 00:09:48 +02:00
sd - > text_trimmed = true ;
sd - > width_trimmed = width + ( ( ellipsis_pos ! = - 1 ) ? ellipsis_width : 0 ) ;
2021-07-04 16:43:55 +02:00
}
}
2022-09-27 11:23:34 +03:00
int64_t TextServerFallback : : _shaped_text_get_trim_pos ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V_MSG ( sd , - 1 , " ShapedTextDataFallback invalid. " ) ;
2021-08-28 00:19:51 +03:00
MutexLock lock ( sd - > mutex ) ;
return sd - > overrun_trim_data . trim_pos ;
}
2022-09-27 11:23:34 +03:00
int64_t TextServerFallback : : _shaped_text_get_ellipsis_pos ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V_MSG ( sd , - 1 , " ShapedTextDataFallback invalid. " ) ;
2021-08-28 00:19:51 +03:00
MutexLock lock ( sd - > mutex ) ;
return sd - > overrun_trim_data . ellipsis_pos ;
}
2022-09-27 11:23:34 +03:00
const Glyph * TextServerFallback : : _shaped_text_get_ellipsis_glyphs ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V_MSG ( sd , nullptr , " ShapedTextDataFallback invalid. " ) ;
2021-08-28 00:19:51 +03:00
MutexLock lock ( sd - > mutex ) ;
return sd - > overrun_trim_data . ellipsis_glyph_buf . ptr ( ) ;
}
2022-09-27 11:23:34 +03:00
int64_t TextServerFallback : : _shaped_text_get_ellipsis_glyph_count ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V_MSG ( sd , 0 , " ShapedTextDataFallback invalid. " ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2021-08-28 00:19:51 +03:00
return sd - > overrun_trim_data . ellipsis_glyph_buf . size ( ) ;
2021-08-11 00:09:48 +02:00
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _shaped_text_shape ( const RID & p_shaped ) {
2022-01-20 09:30:42 +02:00
ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , false ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2024-05-30 22:57:28 -07:00
if ( sd - > valid . is_set ( ) ) {
2020-08-05 09:25:28 +03:00
return true ;
}
if ( sd - > parent ! = RID ( ) ) {
full_copy ( sd ) ;
}
// Cleanup.
sd - > justification_ops_valid = false ;
sd - > line_breaks_valid = false ;
2022-02-13 14:41:29 +02:00
sd - > ascent = 0.0 ;
sd - > descent = 0.0 ;
sd - > width = 0.0 ;
2020-08-05 09:25:28 +03:00
sd - > glyphs . clear ( ) ;
2025-03-21 16:42:23 +02:00
sd - > runs . clear ( ) ;
sd - > runs_dirty = true ;
2020-08-05 09:25:28 +03:00
if ( sd - > text . length ( ) = = 0 ) {
2024-05-30 22:57:28 -07:00
sd - > valid . set ( ) ;
2020-08-05 09:25:28 +03:00
return true ;
}
// "Shape" string.
for ( int i = 0 ; i < sd - > spans . size ( ) ; i + + ) {
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback : : Span & span = sd - > spans [ i ] ;
2020-08-05 09:25:28 +03:00
if ( span . embedded_key ! = Variant ( ) ) {
// Embedded object.
if ( sd - > orientation = = ORIENTATION_HORIZONTAL ) {
sd - > objects [ span . embedded_key ] . rect . position . x = sd - > width ;
sd - > width + = sd - > objects [ span . embedded_key ] . rect . size . x ;
} else {
sd - > objects [ span . embedded_key ] . rect . position . y = sd - > width ;
sd - > width + = sd - > objects [ span . embedded_key ] . rect . size . y ;
}
Glyph gl ;
2024-09-26 09:37:47 +03:00
gl . span_index = i ;
2020-08-05 09:25:28 +03:00
gl . start = span . start ;
gl . end = span . end ;
gl . count = 1 ;
gl . index = 0 ;
2023-04-12 10:08:51 +03:00
gl . flags = GRAPHEME_IS_VALID | GRAPHEME_IS_EMBEDDED_OBJECT ;
2020-08-05 09:25:28 +03:00
if ( sd - > orientation = = ORIENTATION_HORIZONTAL ) {
gl . advance = sd - > objects [ span . embedded_key ] . rect . size . x ;
} else {
gl . advance = sd - > objects [ span . embedded_key ] . rect . size . y ;
}
sd - > glyphs . push_back ( gl ) ;
} else {
// Text span.
2025-09-08 10:06:28 +03:00
int last_non_zero_w = sd - > end - 1 ;
if ( i = = sd - > spans . size ( ) - 1 ) {
2025-10-23 21:39:22 +03:00
for ( int j = span . end - 1 ; j > = span . start ; j - - ) {
2025-09-08 10:06:28 +03:00
last_non_zero_w = j ;
uint32_t idx = ( int32_t ) sd - > text [ j - sd - > start ] ;
if ( ! is_control ( idx ) & & ! ( idx > = 0x200B & & idx < = 0x200D ) ) {
break ;
}
}
}
2022-11-21 15:04:01 +02:00
RID prev_font ;
2020-08-05 09:25:28 +03:00
for ( int j = span . start ; j < span . end ; j + + ) {
Glyph gl ;
2024-09-26 09:37:47 +03:00
gl . span_index = i ;
2020-08-05 09:25:28 +03:00
gl . start = j ;
gl . end = j + 1 ;
gl . count = 1 ;
gl . font_size = span . font_size ;
2021-12-13 18:31:16 +02:00
gl . index = ( int32_t ) sd - > text [ j - sd - > start ] ; // Use codepoint.
2025-09-08 10:06:28 +03:00
bool zw = ( gl . index > = 0x200b & & gl . index < = 0x200d ) ;
if ( gl . index = = 0x0009 | | gl . index = = 0x000b | | zw ) {
2020-08-05 09:25:28 +03:00
gl . index = 0x0020 ;
}
if ( ! sd - > preserve_control & & is_control ( gl . index ) ) {
gl . index = 0x0020 ;
}
// Select first font which has character (font are already sorted by span language).
for ( int k = 0 ; k < span . fonts . size ( ) ; k + + ) {
2022-09-27 11:23:34 +03:00
if ( _font_has_char ( span . fonts [ k ] , gl . index ) ) {
2020-08-05 09:25:28 +03:00
gl . font_rid = span . fonts [ k ] ;
break ;
}
}
2022-11-21 15:04:01 +02:00
if ( ! gl . font_rid . is_valid ( ) & & prev_font . is_valid ( ) ) {
if ( _font_has_char ( prev_font , gl . index ) ) {
gl . font_rid = prev_font ;
}
}
if ( ! gl . font_rid . is_valid ( ) & & OS : : get_singleton ( ) - > has_feature ( " system_fonts " ) & & span . fonts . size ( ) > 0 ) {
// Try system fallback.
RID fdef = span . fonts [ 0 ] ;
if ( _font_is_allow_system_fallback ( fdef ) ) {
String text = sd - > text . substr ( j , 1 ) ;
2023-10-01 13:39:13 +03:00
gl . font_rid = _find_sys_font_for_text ( fdef , String ( ) , span . language , text ) ;
2022-11-21 15:04:01 +02:00
}
}
prev_font = gl . font_rid ;
2020-08-05 09:25:28 +03:00
2020-12-27 15:30:33 +02:00
if ( gl . font_rid . is_valid ( ) ) {
2023-05-09 15:50:48 +02:00
double scale = _font_get_scale ( gl . font_rid , gl . font_size ) ;
2022-10-14 23:16:59 +03:00
bool subpos = ( scale ! = 1.0 ) | | ( _font_get_subpixel_positioning ( gl . font_rid ) = = SUBPIXEL_POSITIONING_ONE_HALF ) | | ( _font_get_subpixel_positioning ( gl . font_rid ) = = SUBPIXEL_POSITIONING_ONE_QUARTER ) | | ( _font_get_subpixel_positioning ( gl . font_rid ) = = SUBPIXEL_POSITIONING_AUTO & & gl . font_size < = SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE ) ;
2021-12-13 18:31:16 +02:00
if ( sd - > text [ j - sd - > start ] ! = 0 & & ! is_linebreak ( sd - > text [ j - sd - > start ] ) ) {
2020-08-05 09:25:28 +03:00
if ( sd - > orientation = = ORIENTATION_HORIZONTAL ) {
2022-10-14 23:16:59 +03:00
gl . advance = _font_get_glyph_advance ( gl . font_rid , gl . font_size , gl . index ) . x ;
2020-08-05 09:25:28 +03:00
gl . x_off = 0 ;
2024-01-28 12:34:56 +02:00
gl . y_off = _font_get_baseline_offset ( gl . font_rid ) * ( double ) ( _font_get_ascent ( gl . font_rid , gl . font_size ) + _font_get_descent ( gl . font_rid , gl . font_size ) ) ;
2023-08-24 11:56:50 +03:00
sd - > ascent = MAX ( sd - > ascent , _font_get_ascent ( gl . font_rid , gl . font_size ) + _font_get_spacing ( gl . font_rid , SPACING_TOP ) ) ;
sd - > descent = MAX ( sd - > descent , _font_get_descent ( gl . font_rid , gl . font_size ) + _font_get_spacing ( gl . font_rid , SPACING_BOTTOM ) ) ;
2020-08-05 09:25:28 +03:00
} else {
2022-10-14 23:16:59 +03:00
gl . advance = _font_get_glyph_advance ( gl . font_rid , gl . font_size , gl . index ) . y ;
2024-01-28 12:34:56 +02:00
gl . x_off = - Math : : round ( _font_get_glyph_advance ( gl . font_rid , gl . font_size , gl . index ) . x * 0.5 ) + _font_get_baseline_offset ( gl . font_rid ) * ( double ) ( _font_get_ascent ( gl . font_rid , gl . font_size ) + _font_get_descent ( gl . font_rid , gl . font_size ) ) ;
2022-09-27 11:23:34 +03:00
gl . y_off = _font_get_ascent ( gl . font_rid , gl . font_size ) ;
sd - > ascent = MAX ( sd - > ascent , Math : : round ( _font_get_glyph_advance ( gl . font_rid , gl . font_size , gl . index ) . x * 0.5 ) ) ;
sd - > descent = MAX ( sd - > descent , Math : : round ( _font_get_glyph_advance ( gl . font_rid , gl . font_size , gl . index ) . x * 0.5 ) ) ;
2020-08-05 09:25:28 +03:00
}
}
2025-09-08 10:06:28 +03:00
if ( zw ) {
gl . advance = 0.0 ;
}
if ( ( j < last_non_zero_w ) & & ! Math : : is_zero_approx ( gl . advance ) ) {
// Do not add extra spacing to the last glyph of the string and zero width glyphs.
2022-05-09 12:47:10 +03:00
if ( is_whitespace ( sd - > text [ j - sd - > start ] ) ) {
2023-08-24 11:56:50 +03:00
gl . advance + = sd - > extra_spacing [ SPACING_SPACE ] + _font_get_spacing ( gl . font_rid , SPACING_SPACE ) ;
2022-05-09 12:47:10 +03:00
} else {
2023-08-24 11:56:50 +03:00
gl . advance + = sd - > extra_spacing [ SPACING_GLYPH ] + _font_get_spacing ( gl . font_rid , SPACING_GLYPH ) ;
2022-05-09 12:47:10 +03:00
}
2021-02-15 10:46:23 +02:00
}
2022-09-27 11:23:34 +03:00
sd - > upos = MAX ( sd - > upos , _font_get_underline_position ( gl . font_rid , gl . font_size ) ) ;
sd - > uthk = MAX ( sd - > uthk , _font_get_underline_thickness ( gl . font_rid , gl . font_size ) ) ;
2020-08-05 09:25:28 +03:00
// Add kerning to previous glyph.
if ( sd - > glyphs . size ( ) > 0 ) {
Glyph & prev_gl = sd - > glyphs . write [ sd - > glyphs . size ( ) - 1 ] ;
if ( prev_gl . font_rid = = gl . font_rid & & prev_gl . font_size = = gl . font_size ) {
if ( sd - > orientation = = ORIENTATION_HORIZONTAL ) {
2022-09-27 11:23:34 +03:00
prev_gl . advance + = _font_get_kerning ( gl . font_rid , gl . font_size , Vector2i ( prev_gl . index , gl . index ) ) . x ;
2020-08-05 09:25:28 +03:00
} else {
2022-09-27 11:23:34 +03:00
prev_gl . advance + = _font_get_kerning ( gl . font_rid , gl . font_size , Vector2i ( prev_gl . index , gl . index ) ) . y ;
2020-08-05 09:25:28 +03:00
}
}
}
2022-01-10 10:13:22 +02:00
if ( sd - > orientation = = ORIENTATION_HORIZONTAL & & ! subpos ) {
gl . advance = Math : : round ( gl . advance ) ;
}
2020-08-05 09:25:28 +03:00
} else if ( sd - > preserve_invalid | | ( sd - > preserve_control & & is_control ( gl . index ) ) ) {
// Glyph not found, replace with hex code box.
if ( sd - > orientation = = ORIENTATION_HORIZONTAL ) {
gl . advance = get_hex_code_box_size ( gl . font_size , gl . index ) . x ;
2025-05-20 08:53:40 +03:00
sd - > ascent = MAX ( sd - > ascent , get_hex_code_box_size ( gl . font_size , gl . index ) . y * 0.85 ) ;
sd - > descent = MAX ( sd - > descent , get_hex_code_box_size ( gl . font_size , gl . index ) . y * 0.15 ) ;
2020-08-05 09:25:28 +03:00
} else {
gl . advance = get_hex_code_box_size ( gl . font_size , gl . index ) . y ;
2022-02-13 14:41:29 +02:00
sd - > ascent = MAX ( sd - > ascent , Math : : round ( get_hex_code_box_size ( gl . font_size , gl . index ) . x * 0.5 ) ) ;
sd - > descent = MAX ( sd - > descent , Math : : round ( get_hex_code_box_size ( gl . font_size , gl . index ) . x * 0.5 ) ) ;
2020-08-05 09:25:28 +03:00
}
}
sd - > width + = gl . advance ;
sd - > glyphs . push_back ( gl ) ;
}
}
}
// Align embedded objects to baseline.
2022-02-13 14:41:29 +02:00
_realign ( sd ) ;
2024-05-30 22:57:28 -07:00
sd - > valid . set ( ) ;
return sd - > valid . is_set ( ) ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
bool TextServerFallback : : _shaped_text_is_ready ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , false ) ;
2020-12-27 15:30:33 +02:00
2024-05-30 22:57:28 -07:00
return sd - > valid . is_set ( ) ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
const Glyph * TextServerFallback : : _shaped_text_get_glyphs ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , nullptr ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2024-05-30 22:57:28 -07:00
if ( ! sd - > valid . is_set ( ) ) {
2022-09-27 11:23:34 +03:00
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
}
2021-08-28 00:19:51 +03:00
return sd - > glyphs . ptr ( ) ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
int64_t TextServerFallback : : _shaped_text_get_glyph_count ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , 0 ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2024-05-30 22:57:28 -07:00
if ( ! sd - > valid . is_set ( ) ) {
2022-09-27 11:23:34 +03:00
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
2021-08-28 00:19:51 +03:00
}
return sd - > glyphs . size ( ) ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
const Glyph * TextServerFallback : : _shaped_text_sort_logical ( const RID & p_shaped ) {
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , nullptr ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2024-05-30 22:57:28 -07:00
if ( ! sd - > valid . is_set ( ) ) {
2024-07-29 21:23:12 -07:00
_shaped_text_shape ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
}
2021-08-28 00:19:51 +03:00
return sd - > glyphs . ptr ( ) ; // Already in the logical order, return as is.
}
2022-09-27 11:23:34 +03:00
Vector2i TextServerFallback : : _shaped_text_get_range ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , Vector2i ( ) ) ;
2021-08-28 00:19:51 +03:00
MutexLock lock ( sd - > mutex ) ;
return Vector2 ( sd - > start , sd - > end ) ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
Array TextServerFallback : : _shaped_text_get_objects ( const RID & p_shaped ) const {
2020-08-05 09:25:28 +03:00
Array ret ;
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , ret ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2022-01-20 09:30:42 +02:00
for ( const KeyValue < Variant , ShapedTextDataFallback : : EmbeddedObject > & E : sd - > objects ) {
2021-08-09 14:13:42 -06:00
ret . push_back ( E . key ) ;
2020-08-05 09:25:28 +03:00
}
return ret ;
}
2022-09-27 11:23:34 +03:00
Rect2 TextServerFallback : : _shaped_text_get_object_rect ( const RID & p_shaped , const Variant & p_key ) const {
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , Rect2 ( ) ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2020-08-05 09:25:28 +03:00
ERR_FAIL_COND_V ( ! sd - > objects . has ( p_key ) , Rect2 ( ) ) ;
2024-05-30 22:57:28 -07:00
if ( ! sd - > valid . is_set ( ) ) {
2022-09-27 11:23:34 +03:00
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
}
return sd - > objects [ p_key ] . rect ;
}
2024-03-11 16:28:58 +02:00
Vector2i TextServerFallback : : _shaped_text_get_object_range ( const RID & p_shaped , const Variant & p_key ) const {
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , Vector2i ( ) ) ;
MutexLock lock ( sd - > mutex ) ;
ERR_FAIL_COND_V ( ! sd - > objects . has ( p_key ) , Vector2i ( ) ) ;
return Vector2i ( sd - > objects [ p_key ] . start , sd - > objects [ p_key ] . end ) ;
}
int64_t TextServerFallback : : _shaped_text_get_object_glyph ( const RID & p_shaped , const Variant & p_key ) const {
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
ERR_FAIL_NULL_V ( sd , - 1 ) ;
MutexLock lock ( sd - > mutex ) ;
ERR_FAIL_COND_V ( ! sd - > objects . has ( p_key ) , - 1 ) ;
const ShapedTextDataFallback : : EmbeddedObject & obj = sd - > objects [ p_key ] ;
int sd_size = sd - > glyphs . size ( ) ;
const Glyph * sd_glyphs = sd - > glyphs . ptr ( ) ;
for ( int i = 0 ; i < sd_size ; i + + ) {
if ( obj . start = = sd_glyphs [ i ] . start ) {
return i ;
}
}
return - 1 ;
}
2022-09-27 11:23:34 +03:00
Size2 TextServerFallback : : _shaped_text_get_size ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , Size2 ( ) ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2024-05-30 22:57:28 -07:00
if ( ! sd - > valid . is_set ( ) ) {
2022-09-27 11:23:34 +03:00
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
}
if ( sd - > orientation = = TextServer : : ORIENTATION_HORIZONTAL ) {
2022-05-09 12:47:10 +03:00
return Size2 ( sd - > width , sd - > ascent + sd - > descent + sd - > extra_spacing [ SPACING_TOP ] + sd - > extra_spacing [ SPACING_BOTTOM ] ) . ceil ( ) ;
2020-08-05 09:25:28 +03:00
} else {
2022-05-09 12:47:10 +03:00
return Size2 ( sd - > ascent + sd - > descent + sd - > extra_spacing [ SPACING_TOP ] + sd - > extra_spacing [ SPACING_BOTTOM ] , sd - > width ) . ceil ( ) ;
2020-08-05 09:25:28 +03:00
}
}
2022-09-27 11:23:34 +03:00
double TextServerFallback : : _shaped_text_get_ascent ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , 0.0 ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2024-05-30 22:57:28 -07:00
if ( ! sd - > valid . is_set ( ) ) {
2022-09-27 11:23:34 +03:00
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
}
2022-05-09 12:47:10 +03:00
return sd - > ascent + sd - > extra_spacing [ SPACING_TOP ] ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
double TextServerFallback : : _shaped_text_get_descent ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , 0.0 ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2024-05-30 22:57:28 -07:00
if ( ! sd - > valid . is_set ( ) ) {
2022-09-27 11:23:34 +03:00
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
}
2022-05-09 12:47:10 +03:00
return sd - > descent + sd - > extra_spacing [ SPACING_BOTTOM ] ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
double TextServerFallback : : _shaped_text_get_width ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , 0.0 ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2024-05-30 22:57:28 -07:00
if ( ! sd - > valid . is_set ( ) ) {
2022-09-27 11:23:34 +03:00
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
}
2022-01-10 10:13:22 +02:00
return Math : : ceil ( sd - > width ) ;
2020-08-05 09:25:28 +03:00
}
2022-09-27 11:23:34 +03:00
double TextServerFallback : : _shaped_text_get_underline_position ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , 0.0 ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2024-05-30 22:57:28 -07:00
if ( ! sd - > valid . is_set ( ) ) {
2022-09-27 11:23:34 +03:00
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
}
return sd - > upos ;
}
2022-09-27 11:23:34 +03:00
double TextServerFallback : : _shaped_text_get_underline_thickness ( const RID & p_shaped ) const {
2022-01-20 09:30:42 +02:00
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , 0.0 ) ;
2020-12-27 15:30:33 +02:00
MutexLock lock ( sd - > mutex ) ;
2024-05-30 22:57:28 -07:00
if ( ! sd - > valid . is_set ( ) ) {
2022-09-27 11:23:34 +03:00
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
2020-08-05 09:25:28 +03:00
}
return sd - > uthk ;
}
2023-08-15 11:42:40 +03:00
PackedInt32Array TextServerFallback : : _shaped_text_get_character_breaks ( const RID & p_shaped ) const {
const ShapedTextDataFallback * sd = shaped_owner . get_or_null ( p_shaped ) ;
2023-09-09 17:40:07 +02:00
ERR_FAIL_NULL_V ( sd , PackedInt32Array ( ) ) ;
2023-08-15 11:42:40 +03:00
MutexLock lock ( sd - > mutex ) ;
2024-05-30 22:57:28 -07:00
if ( ! sd - > valid . is_set ( ) ) {
2023-08-19 11:19:09 +03:00
const_cast < TextServerFallback * > ( this ) - > _shaped_text_shape ( p_shaped ) ;
}
2023-08-15 11:42:40 +03:00
PackedInt32Array ret ;
2023-08-19 11:19:09 +03:00
int size = sd - > end - sd - > start ;
if ( size > 0 ) {
ret . resize ( size ) ;
for ( int i = 0 ; i < size ; i + + ) {
ret . write [ i ] = i + 1 + sd - > start ;
}
2023-08-15 11:42:40 +03:00
}
return ret ;
}
2022-09-27 11:23:34 +03:00
String TextServerFallback : : _string_to_upper ( const String & p_string , const String & p_language ) const {
2023-01-19 14:54:58 +02:00
return p_string . to_upper ( ) ;
2022-01-17 10:54:45 +02:00
}
2022-09-27 11:23:34 +03:00
String TextServerFallback : : _string_to_lower ( const String & p_string , const String & p_language ) const {
2023-01-19 14:54:58 +02:00
return p_string . to_lower ( ) ;
2022-01-17 10:54:45 +02:00
}
2024-04-04 10:56:49 +03:00
String TextServerFallback : : _string_to_title ( const String & p_string , const String & p_language ) const {
return p_string . capitalize ( ) ;
}
2023-01-31 11:08:11 +02:00
PackedInt32Array TextServerFallback : : _string_get_word_breaks ( const String & p_string , const String & p_language , int64_t p_chars_per_line ) const {
2021-11-04 14:33:37 +02:00
PackedInt32Array ret ;
2022-08-18 16:20:20 +08:00
2023-07-05 12:49:16 +03:00
if ( p_chars_per_line > 0 ) {
int line_start = 0 ;
int last_break = - 1 ;
int line_length = 0 ;
2022-08-18 16:20:20 +08:00
2023-07-05 12:49:16 +03:00
for ( int i = 0 ; i < p_string . length ( ) ; i + + ) {
const char32_t c = p_string [ i ] ;
2022-08-18 16:20:20 +08:00
2023-07-05 12:49:16 +03:00
bool is_lb = is_linebreak ( c ) ;
bool is_ws = is_whitespace ( c ) ;
bool is_p = ( is_punct ( c ) & & c ! = 0x005F ) | | is_underscore ( c ) | | c = = ' \t ' | | c = = 0xfffc ;
if ( is_lb ) {
if ( line_length > 0 ) {
2022-08-18 16:20:20 +08:00
ret . push_back ( line_start ) ;
2023-07-05 12:49:16 +03:00
ret . push_back ( i ) ;
2022-08-18 16:20:20 +08:00
}
2023-07-05 12:49:16 +03:00
line_start = i ;
line_length = 0 ;
last_break = - 1 ;
continue ;
} else if ( is_ws | | is_p ) {
last_break = i ;
2022-08-18 16:20:20 +08:00
}
2023-07-05 12:49:16 +03:00
if ( line_length = = p_chars_per_line ) {
if ( last_break ! = - 1 ) {
int last_break_w_spaces = last_break ;
while ( last_break > line_start & & is_whitespace ( p_string [ last_break - 1 ] ) ) {
last_break - - ;
}
if ( line_start ! = last_break ) {
ret . push_back ( line_start ) ;
ret . push_back ( last_break ) ;
}
while ( last_break_w_spaces < p_string . length ( ) & & is_whitespace ( p_string [ last_break_w_spaces ] ) ) {
last_break_w_spaces + + ;
}
line_start = last_break_w_spaces ;
if ( last_break_w_spaces < i ) {
line_length = i - last_break_w_spaces ;
} else {
i = last_break_w_spaces ;
line_length = 0 ;
}
} else {
2022-08-18 16:20:20 +08:00
ret . push_back ( line_start ) ;
ret . push_back ( i ) ;
line_start = i ;
2023-07-05 12:49:16 +03:00
line_length = 0 ;
}
last_break = - 1 ;
}
line_length + + ;
}
if ( line_length > 0 ) {
ret . push_back ( line_start ) ;
ret . push_back ( p_string . length ( ) ) ;
}
} else {
int word_start = 0 ; // -1 if no word encountered. Leading spaces are part of a word.
int word_length = 0 ;
for ( int i = 0 ; i < p_string . length ( ) ; i + + ) {
const char32_t c = p_string [ i ] ;
bool is_lb = is_linebreak ( c ) ;
bool is_ws = is_whitespace ( c ) ;
bool is_p = ( is_punct ( c ) & & c ! = 0x005F ) | | is_underscore ( c ) | | c = = ' \t ' | | c = = 0xfffc ;
if ( word_start = = - 1 ) {
if ( ! is_lb & & ! is_ws & & ! is_p ) {
2022-08-18 16:20:20 +08:00
word_start = i ;
}
2023-07-05 12:49:16 +03:00
continue ;
2022-08-18 16:20:20 +08:00
}
2023-07-05 12:49:16 +03:00
if ( is_lb ) {
if ( word_start ! = - 1 & & word_length > 0 ) {
ret . push_back ( word_start ) ;
ret . push_back ( i ) ;
}
word_start = - 1 ;
word_length = 0 ;
} else if ( is_ws | | is_p ) {
if ( word_start ! = - 1 & & word_length > 0 ) {
ret . push_back ( word_start ) ;
ret . push_back ( i ) ;
}
word_start = - 1 ;
word_length = 0 ;
}
word_length + + ;
}
if ( word_start ! = - 1 & & word_length > 0 ) {
ret . push_back ( word_start ) ;
ret . push_back ( p_string . length ( ) ) ;
2021-11-04 14:33:37 +02:00
}
2022-08-18 16:20:20 +08:00
}
2021-11-04 14:33:37 +02:00
return ret ;
}
2024-05-30 22:57:28 -07:00
void TextServerFallback : : _update_settings ( ) {
lcd_subpixel_layout . set ( ( TextServer : : FontLCDSubpixelLayout ) ( int ) GLOBAL_GET ( " gui/theme/lcd_subpixel_layout " ) ) ;
}
2021-10-12 08:45:54 +03:00
TextServerFallback : : TextServerFallback ( ) {
_insert_feature_sets ( ) ;
2024-05-30 22:57:28 -07:00
ProjectSettings : : get_singleton ( ) - > connect ( " settings_changed " , callable_mp ( this , & TextServerFallback : : _update_settings ) ) ;
2021-10-12 08:45:54 +03:00
}
2020-12-27 15:30:33 +02:00
2025-03-30 14:20:25 +03:00
void TextServerFallback : : _font_clear_system_fallback_cache ( ) {
2022-11-21 15:04:01 +02:00
for ( const KeyValue < SystemFontKey , SystemFontCache > & E : system_fonts ) {
const Vector < SystemFontCacheRec > & sysf_cache = E . value . var ;
for ( const SystemFontCacheRec & F : sysf_cache ) {
_free_rid ( F . rid ) ;
}
}
system_fonts . clear ( ) ;
system_font_data . clear ( ) ;
}
2025-03-30 14:20:25 +03:00
void TextServerFallback : : _cleanup ( ) {
font_clear_system_fallback_cache ( ) ;
}
2020-12-27 15:30:33 +02:00
TextServerFallback : : ~ TextServerFallback ( ) {
2021-11-12 09:30:34 -06:00
# ifdef MODULE_FREETYPE_ENABLED
2022-02-13 14:41:29 +02:00
if ( ft_library ! = nullptr ) {
FT_Done_FreeType ( ft_library ) ;
2020-12-27 15:30:33 +02:00
}
2021-11-12 09:30:34 -06:00
# endif
2020-12-27 15:30:33 +02:00
}