Переглянути джерело

Merge pull request #52192 from bruvzg/text_server_gdext

Rémi Verschelde 3 роки тому
батько
коміт
928c002f22
58 змінених файлів з 4370 додано та 3370 видалено
  1. 17 0
      core/extension/extension_api_dump.cpp
  2. 1 1
      doc/classes/CanvasItem.xml
  3. 2 2
      doc/classes/Font.xml
  4. 1 1
      doc/classes/OS.xml
  5. 12 0
      doc/classes/RenderingServer.xml
  6. 1 1
      doc/classes/TextParagraph.xml
  7. 100 18
      doc/classes/TextServer.xml
  8. 1262 0
      doc/classes/TextServerExtension.xml
  9. 33 19
      doc/classes/TextServerManager.xml
  10. 2 3
      editor/editor_spin_slider.cpp
  11. 3 2
      editor/import/dynamicfont_import_settings.cpp
  12. 67 63
      main/main.cpp
  13. 0 1
      modules/gdnative/SCsub
  14. 0 483
      modules/gdnative/gdnative_api.json
  15. 0 1
      modules/gdnative/gdnative_builders.py
  16. 0 283
      modules/gdnative/include/text/godot_text.h
  17. 0 6
      modules/gdnative/text/SCsub
  18. 0 6
      modules/gdnative/text/config.py
  19. 0 36
      modules/gdnative/text/register_types.cpp
  20. 0 37
      modules/gdnative/text/register_types.h
  21. 0 1086
      modules/gdnative/text/text_server_gdnative.cpp
  22. 0 254
      modules/gdnative/text/text_server_gdnative.h
  23. 10 0
      modules/text_server_adv/config.py
  24. 10 0
      modules/text_server_adv/doc_classes/TextServerAdvanced.xml
  25. 6 1
      modules/text_server_adv/register_types.cpp
  26. 173 123
      modules/text_server_adv/text_server_adv.cpp
  27. 47 47
      modules/text_server_adv/text_server_adv.h
  28. 10 0
      modules/text_server_fb/config.py
  29. 10 0
      modules/text_server_fb/doc_classes/TextServerFallback.xml
  30. 6 1
      modules/text_server_fb/register_types.cpp
  31. 138 107
      modules/text_server_fb/text_server_fb.cpp
  32. 46 46
      modules/text_server_fb/text_server_fb.h
  33. 15 5
      platform/osx/os_osx.mm
  34. 2 2
      scene/gui/control.cpp
  35. 1 1
      scene/gui/control.h
  36. 41 37
      scene/gui/label.cpp
  37. 50 54
      scene/gui/line_edit.cpp
  38. 7 8
      scene/gui/rich_text_label.cpp
  39. 82 86
      scene/gui/text_edit.cpp
  40. 4 4
      scene/gui/text_edit.h
  41. 2 2
      scene/main/canvas_item.cpp
  42. 2 2
      scene/main/canvas_item.h
  43. 4 4
      scene/resources/font.cpp
  44. 4 4
      scene/resources/font.h
  45. 5 13
      scene/resources/text_line.cpp
  46. 4 6
      scene/resources/text_line.h
  47. 12 20
      scene/resources/text_paragraph.cpp
  48. 4 6
      scene/resources/text_paragraph.h
  49. 1 0
      servers/SCsub
  50. 6 12
      servers/register_server_types.cpp
  51. 1 0
      servers/rendering_server.cpp
  52. 5 0
      servers/text/SCsub
  53. 1281 0
      servers/text/text_server_extension.cpp
  54. 426 0
      servers/text/text_server_extension.h
  55. 277 284
      servers/text_server.cpp
  56. 142 152
      servers/text_server.h
  57. 1 7
      tests/test_main.cpp
  58. 34 33
      tests/test_text_server.h

+ 17 - 0
core/extension/extension_api_dump.cpp

@@ -841,6 +841,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
 	{
 		Array native_structures;
 
+		// AudioStream structures
 		{
 			Dictionary d;
 			d["name"] = "AudioFrame";
@@ -849,6 +850,22 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
 			native_structures.push_back(d);
 		}
 
+		// TextServer structures
+		{
+			Dictionary d;
+			d["name"] = "Glyph";
+			d["format"] = "int start,int end,uint8_t count,uint8_t repeat,uint16_t flags,float x_off,float y_off,float advance,RID font_rid,int font_size,int32_t index";
+
+			native_structures.push_back(d);
+		}
+		{
+			Dictionary d;
+			d["name"] = "CaretInfo";
+			d["format"] = "Rect2 leading_caret,Rect2 trailing_caret,TextServer::Direction leading_direction,TextServer::Direction trailing_direction";
+
+			native_structures.push_back(d);
+		}
+
 		api_dump["native_structures"] = native_structures;
 	}
 

+ 1 - 1
doc/classes/CanvasItem.xml

@@ -150,7 +150,7 @@
 			<argument index="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
 			<argument index="8" name="outline_size" type="int" default="0" />
 			<argument index="9" name="outline_modulate" type="Color" default="Color(1, 1, 1, 0)" />
-			<argument index="10" name="flags" type="int" default="51" />
+			<argument index="10" name="flags" type="int" default="99" />
 			<description>
 				Breaks [code]text[/code] to the lines and draws it using the specified [code]font[/code] at the [code]position[/code] (top-left corner). The text will have its color multiplied by [code]modulate[/code]. If [code]clip_w[/code] is greater than or equal to 0, the text will be clipped if it exceeds the specified width.
 			</description>

+ 2 - 2
doc/classes/Font.xml

@@ -103,7 +103,7 @@
 			<argument index="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
 			<argument index="8" name="outline_size" type="int" default="0" />
 			<argument index="9" name="outline_modulate" type="Color" default="Color(1, 1, 1, 0)" />
-			<argument index="10" name="flags" type="int" default="51" />
+			<argument index="10" name="flags" type="int" default="99" />
 			<description>
 				Breaks [code]text[/code] to the lines using rules specified by [code]flags[/code] and draws it into a canvas item using the font, at a given position, with [code]modulate[/code] color, optionally clipping the width and aligning horizontally. [code]position[/code] specifies the baseline of the first line, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis.
 				See also [method CanvasItem.draw_multiline_string].
@@ -185,7 +185,7 @@
 			<argument index="0" name="text" type="String" />
 			<argument index="1" name="width" type="float" default="-1" />
 			<argument index="2" name="size" type="int" default="-1" />
-			<argument index="3" name="flags" type="int" default="48" />
+			<argument index="3" name="flags" type="int" default="96" />
 			<description>
 				Returns the size of a bounding box of a string broken into the lines, taking kerning and advance into account.
 				See also [method draw_multiline_string].

+ 1 - 1
doc/classes/OS.xml

@@ -246,7 +246,7 @@
 		<method name="get_name" qualifiers="const">
 			<return type="String" />
 			<description>
-				Returns the name of the host OS. Possible values are: [code]"Android"[/code], [code]"iOS"[/code], [code]"HTML5"[/code], [code]"OSX"[/code], [code]"Server"[/code], [code]"Windows"[/code], [code]"UWP"[/code], [code]"X11"[/code].
+				Returns the name of the host OS. Possible values are: [code]"Android"[/code], [code]"iOS"[/code], [code]"HTML5"[/code], [code]"macOS"[/code], [code]"Server"[/code], [code]"Windows"[/code], [code]"UWP"[/code], [code]"X11"[/code].
 			</description>
 		</method>
 		<method name="get_process_id" qualifiers="const">

+ 12 - 0
doc/classes/RenderingServer.xml

@@ -185,6 +185,18 @@
 			<description>
 			</description>
 		</method>
+		<method name="canvas_item_add_msdf_texture_rect_region">
+			<return type="void" />
+			<argument index="0" name="item" type="RID" />
+			<argument index="1" name="rect" type="Rect2" />
+			<argument index="2" name="texture" type="RID" />
+			<argument index="3" name="src_rect" type="Rect2" />
+			<argument index="4" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+			<argument index="5" name="outline_size" type="int" default="0" />
+			<argument index="6" name="px_range" type="float" default="1.0" />
+			<description>
+			</description>
+		</method>
 		<method name="canvas_item_add_multimesh">
 			<return type="void" />
 			<argument index="0" name="item" type="RID" />

+ 1 - 1
doc/classes/TextParagraph.xml

@@ -281,7 +281,7 @@
 		<member name="direction" type="int" setter="set_direction" getter="get_direction" enum="TextServer.Direction" default="0">
 			Text writing direction.
 		</member>
-		<member name="flags" type="int" setter="set_flags" getter="get_flags" default="51">
+		<member name="flags" type="int" setter="set_flags" getter="get_flags" default="99">
 			Line breaking and alignment rules. For more info see [TextServer].
 		</member>
 		<member name="max_lines_visible" type="int" setter="set_max_lines_visible" getter="get_max_lines_visible" default="-1">

+ 100 - 18
doc/classes/TextServer.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<class name="TextServer" inherits="Object" version="4.0">
+<class name="TextServer" inherits="RefCounted" version="4.0">
 	<brief_description>
 		Interface for the fonts and complex text layouts.
 	</brief_description>
@@ -487,8 +487,8 @@
 		</method>
 		<method name="font_set_data">
 			<return type="void" />
-			<argument index="0" name="data" type="RID" />
-			<argument index="1" name="arg1" type="PackedByteArray" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="data" type="PackedByteArray" />
 			<description>
 				Sets font source data, e.g contents of the dynamic font source file.
 			</description>
@@ -714,12 +714,14 @@
 			<return type="Dictionary" />
 			<argument index="0" name="font_rid" type="RID" />
 			<description>
+				Returns the dictionary of the supported OpenType features.
 			</description>
 		</method>
 		<method name="font_supported_variation_list" qualifiers="const">
 			<return type="Dictionary" />
 			<argument index="0" name="font_rid" type="RID" />
 			<description>
+				Returns the dictionary of the supported OpenType variation coordinates.
 			</description>
 		</method>
 		<method name="format_number" qualifiers="const">
@@ -737,6 +739,12 @@
 				Frees an object created by this [TextServer].
 			</description>
 		</method>
+		<method name="get_features" qualifiers="const">
+			<return type="int" />
+			<description>
+				Returns text server features, see [enum Feature].
+			</description>
+		</method>
 		<method name="get_hex_code_box_size" qualifiers="const">
 			<return type="Vector2" />
 			<argument index="0" name="size" type="int" />
@@ -751,6 +759,18 @@
 				Returns the name of the server interface.
 			</description>
 		</method>
+		<method name="get_support_data_filename" qualifiers="const">
+			<return type="String" />
+			<description>
+				Returns default TextServer database (e.g. ICU break iterators and dictionaries) filename.
+			</description>
+		</method>
+		<method name="get_support_data_info" qualifiers="const">
+			<return type="String" />
+			<description>
+				Returns TextServer database (e.g. ICU break iterators and dictionaries) description.
+			</description>
+		</method>
 		<method name="has">
 			<return type="bool" />
 			<argument index="0" name="rid" type="RID" />
@@ -758,14 +778,14 @@
 				Returns [code]true[/code] if [code]rid[/code] is valid resource owned by this text server.
 			</description>
 		</method>
-		<method name="has_feature">
+		<method name="has_feature" qualifiers="const">
 			<return type="bool" />
 			<argument index="0" name="feature" type="int" enum="TextServer.Feature" />
 			<description>
 				Returns [code]true[/code] if the server supports a feature.
 			</description>
 		</method>
-		<method name="is_locale_right_to_left">
+		<method name="is_locale_right_to_left" qualifiers="const">
 			<return type="bool" />
 			<argument index="0" name="locale" type="String" />
 			<description>
@@ -802,6 +822,14 @@
 				Returns percent sign used in the [code]language[/code].
 			</description>
 		</method>
+		<method name="save_support_data" qualifiers="const">
+			<return type="bool" />
+			<argument index="0" name="filename" type="String" />
+			<description>
+				Saves optional TextServer database (e.g. ICU break iterators and dictionaries) to the file.
+				Note: This function is used by during project export, to include TextServer database.
+			</description>
+		</method>
 		<method name="shaped_text_add_object">
 			<return type="bool" />
 			<argument index="0" name="shaped" type="RID" />
@@ -898,7 +926,7 @@
 				Returns direction of the text.
 			</description>
 		</method>
-		<method name="shaped_text_get_dominant_direciton_in_range" qualifiers="const">
+		<method name="shaped_text_get_dominant_direction_in_range" qualifiers="const">
 			<return type="int" enum="TextServer.Direction" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="1" name="start" type="int" />
@@ -907,30 +935,58 @@
 				Returns dominant direction of in the range of text.
 			</description>
 		</method>
+		<method name="shaped_text_get_ellipsis_glyph_count" qualifiers="const">
+			<return type="int" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns number of glyphs in the ellipsis.
+			</description>
+		</method>
+		<method name="shaped_text_get_ellipsis_glyphs" qualifiers="const">
+			<return type="Array" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns array of the glyphs in the ellipsis.
+			</description>
+		</method>
+		<method name="shaped_text_get_ellipsis_pos" qualifiers="const">
+			<return type="int" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns position of the ellipsis.
+			</description>
+		</method>
+		<method name="shaped_text_get_glyph_count" qualifiers="const">
+			<return type="int" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns number of glyphs in the buffer.
+			</description>
+		</method>
 		<method name="shaped_text_get_glyphs" qualifiers="const">
 			<return type="Array" />
 			<argument index="0" name="shaped" type="RID" />
 			<description>
-				Returns text glyphs.
+				Returns text glyphs in the visual order.
 			</description>
 		</method>
 		<method name="shaped_text_get_line_breaks" qualifiers="const">
-			<return type="Array" />
+			<return type="PackedInt32Array" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="1" name="width" type="float" />
 			<argument index="2" name="start" type="int" default="0" />
-			<argument index="3" name="break_flags" type="int" default="48" />
+			<argument index="3" name="break_flags" type="int" default="96" />
 			<description>
 				Breaks text to the lines and returns character ranges for each line.
 			</description>
 		</method>
 		<method name="shaped_text_get_line_breaks_adv" qualifiers="const">
-			<return type="Array" />
+			<return type="PackedInt32Array" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="1" name="width" type="PackedFloat32Array" />
 			<argument index="2" name="start" type="int" default="0" />
 			<argument index="3" name="once" type="bool" default="true" />
-			<argument index="4" name="break_flags" type="int" default="48" />
+			<argument index="4" name="break_flags" type="int" default="96" />
 			<description>
 				Breaks text to the lines and columns. Returns character ranges for each segment.
 			</description>
@@ -987,7 +1043,7 @@
 			</description>
 		</method>
 		<method name="shaped_text_get_selection" qualifiers="const">
-			<return type="Array" />
+			<return type="PackedVector2Array" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="1" name="start" type="int" />
 			<argument index="2" name="end" type="int" />
@@ -1002,6 +1058,13 @@
 				Returns size of the text.
 			</description>
 		</method>
+		<method name="shaped_text_get_trim_pos" qualifiers="const">
+			<return type="int" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns position of the trim.
+			</description>
+		</method>
 		<method name="shaped_text_get_underline_position" qualifiers="const">
 			<return type="float" />
 			<argument index="0" name="shaped" type="RID" />
@@ -1024,8 +1087,9 @@
 			</description>
 		</method>
 		<method name="shaped_text_get_word_breaks" qualifiers="const">
-			<return type="Array" />
+			<return type="PackedInt32Array" />
 			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="grapheme_flags" type="int" />
 			<description>
 				Breaks text into words and returns array of character ranges.
 			</description>
@@ -1053,7 +1117,7 @@
 				Returns [code]true[/code] if buffer is successfully shaped.
 			</description>
 		</method>
-		<method name="shaped_text_next_grapheme_pos">
+		<method name="shaped_text_next_grapheme_pos" qualifiers="const">
 			<return type="int" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="1" name="pos" type="int" />
@@ -1070,7 +1134,7 @@
 				Trims text if it exceeds the given width.
 			</description>
 		</method>
-		<method name="shaped_text_prev_grapheme_pos">
+		<method name="shaped_text_prev_grapheme_pos" qualifiers="const">
 			<return type="int" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="1" name="pos" type="int" />
@@ -1139,6 +1203,13 @@
 				Note: It is not necessary to call this function manually, buffer will be shaped automatically as soon as any of its output data is requested.
 			</description>
 		</method>
+		<method name="shaped_text_sort_logical">
+			<return type="Array" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns text glyphs in the logical order.
+			</description>
+		</method>
 		<method name="shaped_text_substr" qualifiers="const">
 			<return type="RID" />
 			<argument index="0" name="shaped" type="RID" />
@@ -1196,18 +1267,24 @@
 		<constant name="JUSTIFICATION_AFTER_LAST_TAB" value="8" enum="JustificationFlag">
 			Only apply justification to the part of the text after the last tab.
 		</constant>
+		<constant name="JUSTIFICATION_CONSTRAIN_ELLIPSIS" value="16" enum="JustificationFlag">
+			Apply justification to the trimmed line with ellipsis.
+		</constant>
 		<constant name="BREAK_NONE" value="0" enum="LineBreakFlag">
 			Do not break the line.
 		</constant>
-		<constant name="BREAK_MANDATORY" value="16" enum="LineBreakFlag">
+		<constant name="BREAK_MANDATORY" value="32" enum="LineBreakFlag">
 			Break the line at the line mandatory break characters (e.g. [code]"\n"[/code]).
 		</constant>
-		<constant name="BREAK_WORD_BOUND" value="32" enum="LineBreakFlag">
+		<constant name="BREAK_WORD_BOUND" value="64" enum="LineBreakFlag">
 			Break the line between the words.
 		</constant>
-		<constant name="BREAK_GRAPHEME_BOUND" value="64" enum="LineBreakFlag">
+		<constant name="BREAK_GRAPHEME_BOUND" value="128" enum="LineBreakFlag">
 			Break the line between any unconnected graphemes.
 		</constant>
+		<constant name="BREAK_WORD_BOUND_ADAPTIVE" value="320" enum="LineBreakFlag">
+			Break the line between the words, or any unconnected graphemes if line is too short to fit the whole word.
+		</constant>
 		<constant name="OVERRUN_NO_TRIMMING" value="0" enum="TextOverrunFlag">
 			No trimming is performed.
 		</constant>
@@ -1223,6 +1300,11 @@
 		<constant name="OVERRUN_ENFORCE_ELLIPSIS" value="8" enum="TextOverrunFlag">
 			Determines whether the ellipsis at the end of the text is enforced and may not be hidden.
 		</constant>
+		<constant name="OVERRUN_JUSTIFICATION_AWARE" value="16" enum="TextOverrunFlag">
+		</constant>
+		<constant name="GRAPHEME_IS_VALID" value="1" enum="GraphemeFlag">
+			Grapheme is supprted by the font, and can be drawn.
+		</constant>
 		<constant name="GRAPHEME_IS_RTL" value="2" enum="GraphemeFlag">
 			Grapheme is part of right-to-left or bottom-to-top run.
 		</constant>

+ 1262 - 0
doc/classes/TextServerExtension.xml

@@ -0,0 +1,1262 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="TextServerExtension" inherits="TextServer" version="4.0">
+	<brief_description>
+		Base class for TextServer custom implementations (plugins).
+	</brief_description>
+	<description>
+		External TextServer implementations should inherit from this class.
+	</description>
+	<tutorials>
+	</tutorials>
+	<methods>
+		<method name="_create_font" qualifiers="virtual">
+			<return type="RID" />
+			<description>
+				Creates new, empty font cache entry resource. To free the resulting resourec, use [method _free] method.
+			</description>
+		</method>
+		<method name="_create_shaped_text" qualifiers="virtual">
+			<return type="RID" />
+			<argument index="0" name="direction" type="int" enum="TextServer.Direction" />
+			<argument index="1" name="orientation" type="int" enum="TextServer.Orientation" />
+			<description>
+				Creates new buffer for complex text layout, with the given [code]direction[/code] and [code]orientation[/code]. To free the resulting buffer, use [method _free] method.
+				Note: Direction is ignored if server does not support [code]FEATURE_BIDI_LAYOUT[/code] feature.
+				Note: Orientation is ignored if server does not support [code]FEATURE_VERTICAL_LAYOUT[/code] feature.
+			</description>
+		</method>
+		<method name="_draw_hex_code_box" qualifiers="virtual const">
+			<return type="void" />
+			<argument index="0" name="canvas" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<argument index="2" name="pos" type="Vector2" />
+			<argument index="3" name="index" type="int" />
+			<argument index="4" name="color" type="Color" />
+			<description>
+				Draws box displaying character hexadecimal code. Used for replacing missing characters.
+			</description>
+		</method>
+		<method name="_font_clear_glyphs" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<description>
+				Removes all rendered glyphs information from the cache entry. Note: This function will not remove textures associated with the glyphs, use [method _font_remove_texture] to remove them manually.
+			</description>
+		</method>
+		<method name="_font_clear_kerning_map" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<description>
+				Removes all kerning overrides.
+			</description>
+		</method>
+		<method name="_font_clear_size_cache" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Removes all font sizes from the cache entry
+			</description>
+		</method>
+		<method name="_font_clear_textures" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<description>
+				Removes all textures from font cache entry. Note: This function will not remove glyphs associated with the texture, use [method _font_remove_glyph] to remove them manually.
+			</description>
+		</method>
+		<method name="_font_draw_glyph" qualifiers="virtual const">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="canvas" type="RID" />
+			<argument index="2" name="size" type="int" />
+			<argument index="3" name="pos" type="Vector2" />
+			<argument index="4" name="index" type="int" />
+			<argument index="5" name="color" type="Color" />
+			<description>
+				Draws single glyph into a canvas item at the position, using [code]font_rid[/code] at the size [code]size[/code].
+				Note: Glyph index is specific to the font, use glyphs indices returned by [method _shaped_text_get_glyphs] or [method _font_get_glyph_index].
+			</description>
+		</method>
+		<method name="_font_draw_glyph_outline" qualifiers="virtual const">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="canvas" type="RID" />
+			<argument index="2" name="size" type="int" />
+			<argument index="3" name="outline_size" type="int" />
+			<argument index="4" name="pos" type="Vector2" />
+			<argument index="5" name="index" type="int" />
+			<argument index="6" name="color" type="Color" />
+			<description>
+				Draws single glyph outline of size [code]outline_size[/code] into a canvas item at the position, using [code]font_rid[/code] at the size [code]size[/code].
+				Note: Glyph index is specific to the font, use glyphs indices returned by [method _shaped_text_get_glyphs] or [method _font_get_glyph_index].
+			</description>
+		</method>
+		<method name="_font_get_ascent" qualifiers="virtual const">
+			<return type="float" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<description>
+				Returns the font ascent (number of pixels above the baseline).
+			</description>
+		</method>
+		<method name="_font_get_descent" qualifiers="virtual const">
+			<return type="float" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<description>
+				Returns the font descent (number of pixels below the baseline).
+			</description>
+		</method>
+		<method name="_font_get_fixed_size" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Returns bitmap font fixed size.
+			</description>
+		</method>
+		<method name="_font_get_global_oversampling" qualifiers="virtual const">
+			<return type="float" />
+			<description>
+				Returns the font oversampling factor, shared by all fonts in the TextServer.
+			</description>
+		</method>
+		<method name="_font_get_glyph_advance" qualifiers="virtual const">
+			<return type="Vector2" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<argument index="2" name="glyph" type="int" />
+			<description>
+				Returns glyph advance (offset of the next glyph). Note: advance for glyphs outlines is the same as the base glyph advance and is not saved.
+			</description>
+		</method>
+		<method name="_font_get_glyph_contours" qualifiers="virtual const">
+			<return type="Dictionary" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<argument index="2" name="index" type="int" />
+			<description>
+				Returns outline contours of the glyph as a [code]Dictionary[/code] with the following contents:
+				[code]points[/code]         - [PackedVector3Array], containing outline points. [code]x[/code] and [code]y[/code] are point coordinates. [code]z[/code] is the type of the point, using the [enum TextServer.ContourPointTag] values.
+				[code]contours[/code]       - [PackedInt32Array], containing indices the end points of each contour.
+				[code]orientation[/code]    - [bool], contour orientation. If [code]true[/code], clockwise contours must be filled.
+			</description>
+		</method>
+		<method name="_font_get_glyph_index" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<argument index="2" name="char" type="int" />
+			<argument index="3" name="variation_selector" type="int" />
+			<description>
+				Returns the glyph index of a [code]char[/code], optionally modified by the [code]variation_selector[/code].
+			</description>
+		</method>
+		<method name="_font_get_glyph_list" qualifiers="virtual const">
+			<return type="Array" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<description>
+				Returns list of rendered glyphs in the cache entry.
+			</description>
+		</method>
+		<method name="_font_get_glyph_offset" qualifiers="virtual const">
+			<return type="Vector2" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<argument index="2" name="glyph" type="int" />
+			<description>
+				Returns glyph offset from the baseline.
+			</description>
+		</method>
+		<method name="_font_get_glyph_size" qualifiers="virtual const">
+			<return type="Vector2" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<argument index="2" name="glyph" type="int" />
+			<description>
+				Returns size of the glyph.
+			</description>
+		</method>
+		<method name="_font_get_glyph_texture_idx" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<argument index="2" name="glyph" type="int" />
+			<description>
+				Returns index of the cache texture containing the glyph.
+			</description>
+		</method>
+		<method name="_font_get_glyph_uv_rect" qualifiers="virtual const">
+			<return type="Rect2" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<argument index="2" name="glyph" type="int" />
+			<description>
+				Returns rectangle in the cache texture containing the glyph.
+			</description>
+		</method>
+		<method name="_font_get_hinting" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Returns the font hinting mode. Used by dynamic fonts only.
+			</description>
+		</method>
+		<method name="_font_get_kerning" qualifiers="virtual const">
+			<return type="Vector2" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<argument index="2" name="glyph_pair" type="Vector2i" />
+			<description>
+				Returns kerning for the pair of glyphs.
+			</description>
+		</method>
+		<method name="_font_get_kerning_list" qualifiers="virtual const">
+			<return type="Array" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<description>
+				Returns list of the kerning overrides.
+			</description>
+		</method>
+		<method name="_font_get_language_support_override" qualifiers="virtual">
+			<return type="bool" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="language" type="String" />
+			<description>
+				Returns [code]true[/code] if support override is enabled for the [code]language[/code].
+			</description>
+		</method>
+		<method name="_font_get_language_support_overrides" qualifiers="virtual">
+			<return type="PackedStringArray" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Returns list of language support overrides.
+			</description>
+		</method>
+		<method name="_font_get_msdf_pixel_range" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Return the width of the range around the shape between the minimum and maximum representable signed distance.
+			</description>
+		</method>
+		<method name="_font_get_msdf_size" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Returns source font size used to generate MSDF textures.
+			</description>
+		</method>
+		<method name="_font_get_oversampling" qualifiers="virtual const">
+			<return type="float" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Returns font oversampling factor, if set to [code]0.0[/code] global oversampling factor is used instead. Used by dynamic fonts only.
+			</description>
+		</method>
+		<method name="_font_get_scale" qualifiers="virtual const">
+			<return type="float" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<description>
+				Returns scaling factor of the color bitmap font.
+			</description>
+		</method>
+		<method name="_font_get_script_support_override" qualifiers="virtual">
+			<return type="bool" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="script" type="String" />
+			<description>
+				Returns [code]true[/code] if support override is enabled for the [code]script[/code].
+			</description>
+		</method>
+		<method name="_font_get_script_support_overrides" qualifiers="virtual">
+			<return type="PackedStringArray" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Returns list of script support overrides.
+			</description>
+		</method>
+		<method name="_font_get_size_cache_list" qualifiers="virtual const">
+			<return type="Array" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Return list of the font sizes in the cache. Each size is [code]Vector2i[/code] with font size and outline size.
+			</description>
+		</method>
+		<method name="_font_get_spacing" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<argument index="2" name="spacing" type="int" enum="TextServer.SpacingType" />
+			<description>
+				Returns extra spacing added between glyphs in pixels.
+			</description>
+		</method>
+		<method name="_font_get_supported_chars" qualifiers="virtual const">
+			<return type="String" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Returns a string containing all the characters available in the font.
+			</description>
+		</method>
+		<method name="_font_get_texture_count" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<description>
+				Returns number of textures used by font cache entry.
+			</description>
+		</method>
+		<method name="_font_get_texture_image" qualifiers="virtual const">
+			<return type="Image" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<argument index="2" name="texture_index" type="int" />
+			<description>
+				Returns font cache texture image data.
+			</description>
+		</method>
+		<method name="_font_get_texture_offsets" qualifiers="virtual const">
+			<return type="PackedInt32Array" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<argument index="2" name="texture_index" type="int" />
+			<description>
+				Returns array containing the first free pixel in the each column of texture. Should be the same size as texture width or empty.
+			</description>
+		</method>
+		<method name="_font_get_underline_position" qualifiers="virtual const">
+			<return type="float" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<description>
+				Returns pixel offset of the underline below the baseline.
+			</description>
+		</method>
+		<method name="_font_get_underline_thickness" qualifiers="virtual const">
+			<return type="float" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<description>
+				Returns thickness of the underline in pixels.
+			</description>
+		</method>
+		<method name="_font_get_variation_coordinates" qualifiers="virtual const">
+			<return type="Dictionary" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Returns variation coordinates for the specified font cache entry. See [method _font_supported_variation_list] for more info.
+			</description>
+		</method>
+		<method name="_font_has_char" qualifiers="virtual const">
+			<return type="bool" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="char" type="int" />
+			<description>
+				Return [code]true[/code] if a Unicode [code]char[/code] is available in the font.
+			</description>
+		</method>
+		<method name="_font_is_antialiased" qualifiers="virtual const">
+			<return type="bool" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Returns [code]true[/code] if font 8-bit anitialiased glyph rendering is supported and enabled.
+			</description>
+		</method>
+		<method name="_font_is_force_autohinter" qualifiers="virtual const">
+			<return type="bool" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Returns [code]true[/code] if auto-hinting is supported and preffered over font built-in hinting. Used by dynamic fonts only.
+			</description>
+		</method>
+		<method name="_font_is_language_supported" qualifiers="virtual const">
+			<return type="bool" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="language" type="String" />
+			<description>
+				Returns [code]true[/code], if font supports given language ([url=https://en.wikipedia.org/wiki/ISO_639-1]ISO 639[/url] code).
+			</description>
+		</method>
+		<method name="_font_is_multichannel_signed_distance_field" qualifiers="virtual const">
+			<return type="bool" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Returns [code]true[/code] if glyphs of all sizes are rendered using single multichannel signed distance field generated from the dynamic font vector data.
+			</description>
+		</method>
+		<method name="_font_is_script_supported" qualifiers="virtual const">
+			<return type="bool" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="script" type="String" />
+			<description>
+				Returns [code]true[/code], if font supports given script (ISO 15924 code).
+			</description>
+		</method>
+		<method name="_font_remove_glyph" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<argument index="2" name="glyph" type="int" />
+			<description>
+				Removes specified rendered glyph information from the cache entry. Note: This function will not remove textures associated with the glyphs, use [method _font_remove_texture] to remove them manually.
+			</description>
+		</method>
+		<method name="_font_remove_kerning" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<argument index="2" name="glyph_pair" type="Vector2i" />
+			<description>
+				Removes kerning override for the pair of glyphs.
+			</description>
+		</method>
+		<method name="_font_remove_language_support_override" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="language" type="String" />
+			<description>
+				Remove language support override.
+			</description>
+		</method>
+		<method name="_font_remove_script_support_override" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="script" type="String" />
+			<description>
+				Removes script support override.
+			</description>
+		</method>
+		<method name="_font_remove_size_cache" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<description>
+				Removes specified font size from the cache entry.
+			</description>
+		</method>
+		<method name="_font_remove_texture" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<argument index="2" name="texture_index" type="int" />
+			<description>
+				Removes specified texture from font cache entry. Note: This function will not remove glyphs associated with the texture, remove them manually, using [method _font_remove_glyph].
+			</description>
+		</method>
+		<method name="_font_render_glyph" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<argument index="2" name="index" type="int" />
+			<description>
+				Renders specified glyph the the font cache texture.
+			</description>
+		</method>
+		<method name="_font_render_range" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<argument index="2" name="start" type="int" />
+			<argument index="3" name="end" type="int" />
+			<description>
+				Renders the range of characters to the font cache texture.
+			</description>
+		</method>
+		<method name="_font_set_antialiased" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="antialiased" type="bool" />
+			<description>
+				If set to [code]true[/code], 8-bit antialiased glyph rendering is used, otherwise 1-bit rendering is used. Used by dynamic fonts only.
+			</description>
+		</method>
+		<method name="_font_set_ascent" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<argument index="2" name="ascent" type="float" />
+			<description>
+				Sets the font ascent (number of pixels above the baseline).
+			</description>
+		</method>
+		<method name="_font_set_data" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="data" type="PackedByteArray" />
+			<description>
+				Sets font source data, e.g contents of the dynamic font source file.
+			</description>
+		</method>
+		<method name="_font_set_data_ptr" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="data_ptr" type="const uint8_t*" />
+			<argument index="2" name="data_size" type="int" />
+			<description>
+				Sets the font descent (number of pixels below the baseline).
+			</description>
+		</method>
+		<method name="_font_set_descent" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<argument index="2" name="descent" type="float" />
+			<description>
+				Sets bitmap font fixed size. If set to value greater than zero, same cache entry will be used for all font sizes.
+			</description>
+		</method>
+		<method name="_font_set_fixed_size" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="fixed_size" type="int" />
+			<description>
+				If set to [code]true[/code] auto-hinting is preffered over font built-in hinting.
+			</description>
+		</method>
+		<method name="_font_set_force_autohinter" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="force_autohinter" type="bool" />
+			<description>
+			</description>
+		</method>
+		<method name="_font_set_global_oversampling" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="oversampling" type="float" />
+			<description>
+				Sets oversampling factor, shared by all font in the TextServer.
+				Note: This value can be automaticaly changed by display server.
+			</description>
+		</method>
+		<method name="_font_set_glyph_advance" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<argument index="2" name="glyph" type="int" />
+			<argument index="3" name="advance" type="Vector2" />
+			<description>
+				Sets glyph advance (offset of the next glyph). Note: advance for glyphs outlines is the same as the base glyph advance and is not saved.
+			</description>
+		</method>
+		<method name="_font_set_glyph_offset" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<argument index="2" name="glyph" type="int" />
+			<argument index="3" name="offset" type="Vector2" />
+			<description>
+				Sets glyph offset from the baseline.
+			</description>
+		</method>
+		<method name="_font_set_glyph_size" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<argument index="2" name="glyph" type="int" />
+			<argument index="3" name="gl_size" type="Vector2" />
+			<description>
+				Sets size of the glyph.
+			</description>
+		</method>
+		<method name="_font_set_glyph_texture_idx" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<argument index="2" name="glyph" type="int" />
+			<argument index="3" name="texture_idx" type="int" />
+			<description>
+				Sets index of the cache texture containing the glyph.
+			</description>
+		</method>
+		<method name="_font_set_glyph_uv_rect" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<argument index="2" name="glyph" type="int" />
+			<argument index="3" name="uv_rect" type="Rect2" />
+			<description>
+				Sets rectangle in the cache texture containing the glyph.
+			</description>
+		</method>
+		<method name="_font_set_hinting" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="hinting" type="int" enum="TextServer.Hinting" />
+			<description>
+				Sets font hinting mode. Used by dynamic fonts only.
+			</description>
+		</method>
+		<method name="_font_set_kerning" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<argument index="2" name="glyph_pair" type="Vector2i" />
+			<argument index="3" name="kerning" type="Vector2" />
+			<description>
+				Sets kerning for the pair of glyphs.
+			</description>
+		</method>
+		<method name="_font_set_language_support_override" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="language" type="String" />
+			<argument index="2" name="supported" type="bool" />
+			<description>
+				Adds override for [method _font_is_language_supported].
+			</description>
+		</method>
+		<method name="_font_set_msdf_pixel_range" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="msdf_pixel_range" type="int" />
+			<description>
+				Sets the width of the range around the shape between the minimum and maximum representable signed distance.
+			</description>
+		</method>
+		<method name="_font_set_msdf_size" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="msdf_size" type="int" />
+			<description>
+				Sets source font size used to generate MSDF textures.
+			</description>
+		</method>
+		<method name="_font_set_multichannel_signed_distance_field" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="msdf" type="bool" />
+			<description>
+				If set to [code]true[/code], glyphs of all sizes are rendered using single multichannel signed distance field generated from the dynamic font vector data.
+			</description>
+		</method>
+		<method name="_font_set_oversampling" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="oversampling" type="float" />
+			<description>
+				Sets font oversampling factor, if set to [code]0.0[/code] global oversampling factor is used instead. Used by dynamic fonts only.
+			</description>
+		</method>
+		<method name="_font_set_scale" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<argument index="2" name="scale" type="float" />
+			<description>
+				Sets scaling factor of the color bitmap font.
+			</description>
+		</method>
+		<method name="_font_set_script_support_override" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="script" type="String" />
+			<argument index="2" name="supported" type="bool" />
+			<description>
+				Adds override for [method _font_is_script_supported].
+			</description>
+		</method>
+		<method name="_font_set_spacing" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<argument index="2" name="spacing" type="int" enum="TextServer.SpacingType" />
+			<argument index="3" name="value" type="int" />
+			<description>
+				Sets extra spacing added between glyphs in pixels.
+			</description>
+		</method>
+		<method name="_font_set_texture_image" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<argument index="2" name="texture_index" type="int" />
+			<argument index="3" name="image" type="Image" />
+			<description>
+				Sets font cache texture image data.
+			</description>
+		</method>
+		<method name="_font_set_texture_offsets" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="Vector2i" />
+			<argument index="2" name="texture_index" type="int" />
+			<argument index="3" name="offset" type="PackedInt32Array" />
+			<description>
+				Sets array containing the first free pixel in the each column of texture. Should be the same size as texture width or empty.
+			</description>
+		</method>
+		<method name="_font_set_underline_position" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<argument index="2" name="underline_position" type="float" />
+			<description>
+				Sets pixel offset of the underline below the baseline.
+			</description>
+		</method>
+		<method name="_font_set_underline_thickness" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="size" type="int" />
+			<argument index="2" name="underline_thickness" type="float" />
+			<description>
+				Sets thickness of the underline in pixels.
+			</description>
+		</method>
+		<method name="_font_set_variation_coordinates" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="font_rid" type="RID" />
+			<argument index="1" name="variation_coordinates" type="Dictionary" />
+			<description>
+				Sets variation coordinates for the specified font cache entry. See [method _font_supported_variation_list] for more info.
+			</description>
+		</method>
+		<method name="_font_supported_feature_list" qualifiers="virtual const">
+			<return type="Dictionary" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Returns the dictionary of the supported OpenType features.
+			</description>
+		</method>
+		<method name="_font_supported_variation_list" qualifiers="virtual const">
+			<return type="Dictionary" />
+			<argument index="0" name="font_rid" type="RID" />
+			<description>
+				Returns the dictionary of the supported OpenType variation coordinates.
+			</description>
+		</method>
+		<method name="_format_number" qualifiers="virtual const">
+			<return type="String" />
+			<argument index="0" name="string" type="String" />
+			<argument index="1" name="language" type="String" />
+			<description>
+				Converts a number from the Western Arabic (0..9) to the numeral systems used in [code]language[/code].
+			</description>
+		</method>
+		<method name="_free" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="rid" type="RID" />
+			<description>
+				Frees an object created by this [TextServer].
+			</description>
+		</method>
+		<method name="_get_features" qualifiers="virtual const">
+			<return type="int" />
+			<description>
+				Returns text server features, see [enum TextServer.Feature].
+			</description>
+		</method>
+		<method name="_get_hex_code_box_size" qualifiers="virtual const">
+			<return type="Vector2" />
+			<argument index="0" name="size" type="int" />
+			<argument index="1" name="index" type="int" />
+			<description>
+				Returns size of the replacement character (box with character hexadecimal code that is drawn in place of invalid characters).
+			</description>
+		</method>
+		<method name="_get_name" qualifiers="virtual const">
+			<return type="String" />
+			<description>
+				Returns the name of the server interface.
+			</description>
+		</method>
+		<method name="_get_support_data_filename" qualifiers="virtual const">
+			<return type="String" />
+			<description>
+				Returns default TextServer database (e.g. ICU break iterators and dictionaries) filename.
+			</description>
+		</method>
+		<method name="_get_support_data_info" qualifiers="virtual const">
+			<return type="String" />
+			<description>
+				Returns TextServer database (e.g. ICU break iterators and dictionaries) description.
+			</description>
+		</method>
+		<method name="_has" qualifiers="virtual">
+			<return type="bool" />
+			<argument index="0" name="rid" type="RID" />
+			<description>
+				Returns [code]true[/code] if [code]rid[/code] is valid resource owned by this text server.
+			</description>
+		</method>
+		<method name="_has_feature" qualifiers="virtual const">
+			<return type="bool" />
+			<argument index="0" name="feature" type="int" enum="TextServer.Feature" />
+			<description>
+				Returns [code]true[/code] if the server supports a feature.
+			</description>
+		</method>
+		<method name="_is_locale_right_to_left" qualifiers="virtual const">
+			<return type="bool" />
+			<argument index="0" name="locale" type="String" />
+			<description>
+				Returns [code]true[/code] if locale is right-to-left.
+			</description>
+		</method>
+		<method name="_load_support_data" qualifiers="virtual">
+			<return type="bool" />
+			<argument index="0" name="filename" type="String" />
+			<description>
+				Loads optional TextServer database (e.g. ICU break iterators and dictionaries).
+				Note: This function should be called before any other TextServer functions used, otherwise it won't have any effect.
+			</description>
+		</method>
+		<method name="_name_to_tag" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="name" type="String" />
+			<description>
+				Converts readable feature, variation, script or language name to OpenType tag.
+			</description>
+		</method>
+		<method name="_parse_number" qualifiers="virtual const">
+			<return type="String" />
+			<argument index="0" name="string" type="String" />
+			<argument index="1" name="language" type="String" />
+			<description>
+				Converts a number from the numeral systems used in [code]language[/code] to Western Arabic (0..9).
+			</description>
+		</method>
+		<method name="_percent_sign" qualifiers="virtual const">
+			<return type="String" />
+			<argument index="0" name="language" type="String" />
+			<description>
+				Returns percent sign used in the [code]language[/code].
+			</description>
+		</method>
+		<method name="_save_support_data" qualifiers="virtual const">
+			<return type="bool" />
+			<argument index="0" name="filename" type="String" />
+			<description>
+				Saves optional TextServer database (e.g. ICU break iterators and dictionaries) to the file.
+				Note: This function is used by during project export, to include TextServer database.
+			</description>
+		</method>
+		<method name="_shaped_text_add_object" qualifiers="virtual">
+			<return type="bool" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="key" type="Variant" />
+			<argument index="2" name="size" type="Vector2" />
+			<argument index="3" name="inline_align" type="int" enum="InlineAlign" />
+			<argument index="4" name="length" type="int" />
+			<description>
+				Adds inline object to the text buffer, [code]key[/code] must be unique. In the text, object is represented as [code]length[/code] object replacement characters.
+			</description>
+		</method>
+		<method name="_shaped_text_add_string" qualifiers="virtual">
+			<return type="bool" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="text" type="String" />
+			<argument index="2" name="fonts" type="Array" />
+			<argument index="3" name="size" type="int" />
+			<argument index="4" name="opentype_features" type="Dictionary" />
+			<argument index="5" name="language" type="String" />
+			<description>
+				Adds text span and font to draw it to the text buffer.
+			</description>
+		</method>
+		<method name="_shaped_text_clear" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Clears text buffer (removes text and inline objects).
+			</description>
+		</method>
+		<method name="_shaped_text_draw" qualifiers="virtual const">
+			<return type="void" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="canvas" type="RID" />
+			<argument index="2" name="pos" type="Vector2" />
+			<argument index="3" name="clip_l" type="float" />
+			<argument index="4" name="clip_r" type="float" />
+			<argument index="5" name="color" type="Color" />
+			<description>
+				Draw shaped text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the leftmost point of the baseline (for horizontal layout) or topmost point of the baseline (for vertical layout).
+			</description>
+		</method>
+		<method name="_shaped_text_draw_outline" qualifiers="virtual const">
+			<return type="void" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="canvas" type="RID" />
+			<argument index="2" name="pos" type="Vector2" />
+			<argument index="3" name="clip_l" type="float" />
+			<argument index="4" name="clip_r" type="float" />
+			<argument index="5" name="outline_size" type="int" />
+			<argument index="6" name="color" type="Color" />
+			<description>
+				Draw the outline of the shaped text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the leftmost point of the baseline (for horizontal layout) or topmost point of the baseline (for vertical layout).
+			</description>
+		</method>
+		<method name="_shaped_text_fit_to_width" qualifiers="virtual">
+			<return type="float" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="width" type="float" />
+			<argument index="2" name="jst_flags" type="int" />
+			<description>
+				Adjusts text with to fit to specified width, returns new text width
+			</description>
+		</method>
+		<method name="_shaped_text_get_ascent" qualifiers="virtual const">
+			<return type="float" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns the text ascent (number of pixels above the baseline for horizontal layout or to the left of baseline for vertical).
+				Note: overall ascent can be higher than font ascent, if some glyphs are displaced from the baseline.
+			</description>
+		</method>
+		<method name="_shaped_text_get_carets" qualifiers="virtual const">
+			<return type="void" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="position" type="int" />
+			<argument index="2" name="caret" type="CaretInfo*" />
+			<description>
+				Returns shapes of the carets corresponding to the character offset [code]position[/code] in the text. Returned caret shape is 1 pixel wide rectangle.
+			</description>
+		</method>
+		<method name="_shaped_text_get_descent" qualifiers="virtual const">
+			<return type="float" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns the text descent (number of pixels below the baseline for horizontal layout or to the right of baseline for vertical).
+				Note: overall descent can be higher than font descent, if some glyphs are displaced from the baseline.
+			</description>
+		</method>
+		<method name="_shaped_text_get_direction" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns direction of the text.
+			</description>
+		</method>
+		<method name="_shaped_text_get_dominant_direction_in_range" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="start" type="int" />
+			<argument index="2" name="end" type="int" />
+			<description>
+				Returns dominant direction of in the range of text.
+			</description>
+		</method>
+		<method name="_shaped_text_get_ellipsis_glyph_count" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns number of glyphs in the ellipsis.
+			</description>
+		</method>
+		<method name="_shaped_text_get_ellipsis_glyphs" qualifiers="virtual const">
+			<return type="void" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="r_glyphs" type="void*" />
+			<description>
+				Returns array of the glyphs in the ellipsis.
+			</description>
+		</method>
+		<method name="_shaped_text_get_ellipsis_pos" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns position of the ellipsis.
+			</description>
+		</method>
+		<method name="_shaped_text_get_glyph_count" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns text glyphs count.
+			</description>
+		</method>
+		<method name="_shaped_text_get_glyphs" qualifiers="virtual const">
+			<return type="void" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="r_glyphs" type="void*" />
+			<description>
+				Copies text glyphs in the visual order, into preallocated array of the size returned by [method _shaped_text_get_glyph_count].
+			</description>
+		</method>
+		<method name="_shaped_text_get_line_breaks" qualifiers="virtual const">
+			<return type="PackedInt32Array" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="width" type="float" />
+			<argument index="2" name="start" type="int" />
+			<argument index="3" name="break_flags" type="int" />
+			<description>
+				Breaks text to the lines and returns character ranges for each line.
+			</description>
+		</method>
+		<method name="_shaped_text_get_line_breaks_adv" qualifiers="virtual const">
+			<return type="PackedInt32Array" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="width" type="PackedFloat32Array" />
+			<argument index="2" name="start" type="int" />
+			<argument index="3" name="once" type="bool" />
+			<argument index="4" name="break_flags" type="int" />
+			<description>
+				Breaks text to the lines and columns. Returns character ranges for each segment.
+			</description>
+		</method>
+		<method name="_shaped_text_get_object_rect" qualifiers="virtual const">
+			<return type="Rect2" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="key" type="Variant" />
+			<description>
+				Returns bounding rectangle of the inline object.
+			</description>
+		</method>
+		<method name="_shaped_text_get_objects" qualifiers="virtual const">
+			<return type="Array" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns array of inline objects.
+			</description>
+		</method>
+		<method name="_shaped_text_get_orientation" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns text orientation.
+			</description>
+		</method>
+		<method name="_shaped_text_get_parent" qualifiers="virtual const">
+			<return type="RID" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Sets text orientation.
+			</description>
+		</method>
+		<method name="_shaped_text_get_preserve_control" qualifiers="virtual const">
+			<return type="bool" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns [code]true[/code] if text buffer is configured to display control characters.
+			</description>
+		</method>
+		<method name="_shaped_text_get_preserve_invalid" qualifiers="virtual const">
+			<return type="bool" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns [code]true[/code] if text buffer is configured to display hexadecimal codes in place of invalid characters.
+				Note: If set to [code]false[/code], nothing is displayed in place of invalid characters.
+			</description>
+		</method>
+		<method name="_shaped_text_get_range" qualifiers="virtual const">
+			<return type="Vector2i" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns substring buffer character range in the parent buffer.
+			</description>
+		</method>
+		<method name="_shaped_text_get_selection" qualifiers="virtual const">
+			<return type="PackedVector2Array" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="start" type="int" />
+			<argument index="2" name="end" type="int" />
+			<description>
+				Returns selection rectangles for the specified character range.
+			</description>
+		</method>
+		<method name="_shaped_text_get_size" qualifiers="virtual const">
+			<return type="Vector2" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns size of the text.
+			</description>
+		</method>
+		<method name="_shaped_text_get_trim_pos" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns ellipsis and trim positions.
+			</description>
+		</method>
+		<method name="_shaped_text_get_underline_position" qualifiers="virtual const">
+			<return type="float" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns pixel offset of the underline below the baseline.
+			</description>
+		</method>
+		<method name="_shaped_text_get_underline_thickness" qualifiers="virtual const">
+			<return type="float" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns thickness of the underline.
+			</description>
+		</method>
+		<method name="_shaped_text_get_width" qualifiers="virtual const">
+			<return type="float" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns width (for horizontal layout) or height (for vertical) of the text.
+			</description>
+		</method>
+		<method name="_shaped_text_get_word_breaks" qualifiers="virtual const">
+			<return type="PackedInt32Array" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="grapheme_flags" type="int" />
+			<description>
+				Breaks text into words and returns array of character ranges.
+			</description>
+		</method>
+		<method name="_shaped_text_hit_test_grapheme" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="coord" type="float" />
+			<description>
+				Returns grapheme index at the specified pixel offset at the baseline, or [code]-1[/code] if none is found.
+			</description>
+		</method>
+		<method name="_shaped_text_hit_test_position" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="coord" type="float" />
+			<description>
+				Returns caret character offset at the specified pixel offset at the baseline. This function always returns a valid position.
+			</description>
+		</method>
+		<method name="_shaped_text_is_ready" qualifiers="virtual const">
+			<return type="bool" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Returns [code]true[/code] if buffer is successfully shaped.
+			</description>
+		</method>
+		<method name="_shaped_text_next_grapheme_pos" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="pos" type="int" />
+			<description>
+				Returns composite character end position closest to the [code]pos[/code].
+			</description>
+		</method>
+		<method name="_shaped_text_overrun_trim_to_width" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="width" type="float" />
+			<argument index="2" name="trim_flags" type="int" />
+			<description>
+				Trims text if it exceeds the given width.
+			</description>
+		</method>
+		<method name="_shaped_text_prev_grapheme_pos" qualifiers="virtual const">
+			<return type="int" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="pos" type="int" />
+			<description>
+				Returns composite character start position closest to the [code]pos[/code].
+			</description>
+		</method>
+		<method name="_shaped_text_resize_object" qualifiers="virtual">
+			<return type="bool" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="key" type="Variant" />
+			<argument index="2" name="size" type="Vector2" />
+			<argument index="3" name="inline_align" type="int" enum="InlineAlign" />
+			<description>
+				Sets new size and alignment of embedded object.
+			</description>
+		</method>
+		<method name="_shaped_text_set_bidi_override" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="override" type="Array" />
+			<description>
+				Overrides BiDi for the structured text.
+				Override ranges should cover full source text without overlaps. BiDi algorithm will be used on each range separately.
+			</description>
+		</method>
+		<method name="_shaped_text_set_direction" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="direction" type="int" enum="TextServer.Direction" />
+			<description>
+				Sets desired text direction. If set to [code]TEXT_DIRECTION_AUTO[/code], direction will be detected based on the buffer contents and current locale.
+				Note: Direction is ignored if server does not support [code]FEATURE_BIDI_LAYOUT[/code] feature.
+			</description>
+		</method>
+		<method name="_shaped_text_set_orientation" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="orientation" type="int" enum="TextServer.Orientation" />
+			<description>
+				Sets desired text orientation.
+				Note: Orientation is ignored if server does not support [code]FEATURE_VERTICAL_LAYOUT[/code] feature.
+			</description>
+		</method>
+		<method name="_shaped_text_set_preserve_control" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="enabled" type="bool" />
+			<description>
+				If set to [code]true[/code] text buffer will display control characters.
+			</description>
+		</method>
+		<method name="_shaped_text_set_preserve_invalid" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="enabled" type="bool" />
+			<description>
+				If set to [code]true[/code] text buffer will display invalid characters as hexadecimal codes, otherwise nothing is displayed.
+			</description>
+		</method>
+		<method name="_shaped_text_shape" qualifiers="virtual">
+			<return type="bool" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Shapes buffer if it's not shaped. Returns [code]true[/code] if the string is shaped successfully.
+				Note: It is not necessary to call this function manually, buffer will be shaped automatically as soon as any of its output data is requested.
+			</description>
+		</method>
+		<method name="_shaped_text_sort_logical" qualifiers="virtual">
+			<return type="void" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="r_glyphs" type="void*" />
+			<description>
+				Copies text glyphs in the logical order, into preallocated array of the size returned by [method _shaped_text_get_glyph_count].
+			</description>
+		</method>
+		<method name="_shaped_text_substr" qualifiers="virtual const">
+			<return type="RID" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="start" type="int" />
+			<argument index="2" name="length" type="int" />
+			<description>
+				Returns text buffer for the substring of the text in the [code]shaped[/code] text buffer (including inline objects).
+			</description>
+		</method>
+		<method name="_shaped_text_tab_align" qualifiers="virtual">
+			<return type="float" />
+			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="tab_stops" type="PackedFloat32Array" />
+			<description>
+				Aligns shaped text to the given tab-stops.
+			</description>
+		</method>
+		<method name="_shaped_text_update_breaks" qualifiers="virtual">
+			<return type="bool" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Updates line and word breaks.
+			</description>
+		</method>
+		<method name="_shaped_text_update_justification_ops" qualifiers="virtual">
+			<return type="bool" />
+			<argument index="0" name="shaped" type="RID" />
+			<description>
+				Updates justification opportunities (spaces, kashidas, etc.).
+			</description>
+		</method>
+		<method name="_tag_to_name" qualifiers="virtual const">
+			<return type="String" />
+			<argument index="0" name="tag" type="int" />
+			<description>
+				Converts OpenType tag to readable feature, variation, script or language name.
+			</description>
+		</method>
+	</methods>
+</class>

+ 33 - 19
doc/classes/TextServerManager.xml

@@ -10,6 +10,13 @@
 	<tutorials>
 	</tutorials>
 	<methods>
+		<method name="add_interface">
+			<return type="void" />
+			<argument index="0" name="interface" type="TextServer" />
+			<description>
+				Registers an [TextServer] interface.
+			</description>
+		</method>
 		<method name="find_interface" qualifiers="const">
 			<return type="TextServer" />
 			<argument index="0" name="name" type="String" />
@@ -19,7 +26,7 @@
 		</method>
 		<method name="get_interface" qualifiers="const">
 			<return type="TextServer" />
-			<argument index="0" name="index" type="int" />
+			<argument index="0" name="idx" type="int" />
 			<description>
 				Returns the interface registered at a given index.
 			</description>
@@ -30,20 +37,6 @@
 				Returns the number of interfaces currently registered.
 			</description>
 		</method>
-		<method name="get_interface_features" qualifiers="const">
-			<return type="int" />
-			<argument index="0" name="index" type="int" />
-			<description>
-				Returns text server supported features (binary OR).
-			</description>
-		</method>
-		<method name="get_interface_name" qualifiers="const">
-			<return type="String" />
-			<argument index="0" name="index" type="int" />
-			<description>
-				Returns the interface name registered at a given index.
-			</description>
-		</method>
 		<method name="get_interfaces" qualifiers="const">
 			<return type="Array" />
 			<description>
@@ -53,15 +46,36 @@
 		<method name="get_primary_interface" qualifiers="const">
 			<return type="TextServer" />
 			<description>
-				Returns the primary [TextServer] interface.
+				Returns the primary [TextServer] interface currently in use.
+			</description>
+		</method>
+		<method name="remove_interface">
+			<return type="void" />
+			<argument index="0" name="interface" type="TextServer" />
+			<description>
+				Removes interface. All fonts and shaped text caches should be freed before removing interface.
 			</description>
 		</method>
 		<method name="set_primary_interface">
-			<return type="bool" />
-			<argument index="0" name="index" type="int" />
+			<return type="void" />
+			<argument index="0" name="index" type="TextServer" />
 			<description>
-				Sets (and initializes it if required) interface registered at a given index as the primary. Invalidates all references to the fonts and text buffers.
+				Sets the primary [TextServer] interface.
 			</description>
 		</method>
 	</methods>
+	<signals>
+		<signal name="interface_added">
+			<argument index="0" name="interface_name" type="StringName" />
+			<description>
+				Emitted when a new interface has been added.
+			</description>
+		</signal>
+		<signal name="interface_removed">
+			<argument index="0" name="interface_name" type="StringName" />
+			<description>
+				Emitted when an interface is removed.
+			</description>
+		</signal>
+	</signals>
 </class>

+ 2 - 3
editor/editor_spin_slider.cpp

@@ -330,9 +330,8 @@ void EditorSpinSlider::_draw_spin_slider() {
 
 	float text_start = rtl ? Math::round(sb->get_offset().x) : Math::round(sb->get_offset().x + label_width + sep);
 	Vector2 text_ofs = rtl ? Vector2(text_start + (number_width - TS->shaped_text_get_width(num_rid)), vofs) : Vector2(text_start, vofs);
-	const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(num_rid);
-	int v_size = visual.size();
-	const TextServer::Glyph *glyphs = visual.ptr();
+	int v_size = TS->shaped_text_get_glyph_count(num_rid);
+	const Glyph *glyphs = TS->shaped_text_get_glyphs(num_rid);
 	for (int i = 0; i < v_size; i++) {
 		for (int j = 0; j < glyphs[i].repeat; j++) {
 			if (text_ofs.x >= text_start && (text_ofs.x + glyphs[i].advance) <= (text_start + number_width)) {

+ 3 - 2
editor/import/dynamicfont_import_settings.cpp

@@ -1011,9 +1011,10 @@ void DynamicFontImportSettings::_glyph_text_selected() {
 	if (text_rid.is_valid()) {
 		TS->shaped_text_add_string(text_rid, text_edit->get_text(), font_main->get_rids(), 16, ftrs, text_edit->get_language());
 		TS->shaped_text_shape(text_rid);
-		const Vector<TextServer::Glyph> &gl = TS->shaped_text_get_glyphs(text_rid);
+		const Glyph *gl = TS->shaped_text_get_glyphs(text_rid);
+		const int gl_size = TS->shaped_text_get_glyph_count(text_rid);
 
-		for (int i = 0; i < gl.size(); i++) {
+		for (int i = 0; i < gl_size; i++) {
 			if (gl[i].font_rid.is_valid() && gl[i].index != 0) {
 				selected_glyphs.insert(gl[i].index);
 			}

+ 67 - 63
main/main.cpp

@@ -407,6 +407,7 @@ Error Main::test_setup() {
 	GLOBAL_DEF_RST("rendering/occlusion_culling/bvh_build_quality", 2);
 
 	translation_server = memnew(TranslationServer);
+	tsman = memnew(TextServerManager);
 
 	register_core_extensions();
 
@@ -440,6 +441,9 @@ Error Main::test_setup() {
 	register_module_types();
 	register_driver_types();
 
+	ERR_FAIL_COND_V(TextServerManager::get_singleton()->get_interface_count() == 0, ERR_CANT_CREATE);
+	TextServerManager::get_singleton()->set_primary_interface(TextServerManager::get_singleton()->get_interface(0));
+
 	ClassDB::set_current_api(ClassDB::API_NONE);
 
 	_start_success = true;
@@ -459,6 +463,7 @@ void Main::test_cleanup() {
 #ifdef TOOLS_ENABLED
 	EditorNode::unregister_editor_types();
 #endif
+
 	unregister_module_types();
 	unregister_platform_apis();
 	unregister_scene_types();
@@ -469,6 +474,9 @@ void Main::test_cleanup() {
 	if (translation_server) {
 		memdelete(translation_server);
 	}
+	if (tsman) {
+		memdelete(tsman);
+	}
 	if (globals) {
 		memdelete(globals);
 	}
@@ -1461,6 +1469,8 @@ error:
 }
 
 Error Main::setup2(Thread::ID p_main_tid_override) {
+	tsman = memnew(TextServerManager);
+
 	preregister_module_types();
 	preregister_server_types();
 
@@ -1479,64 +1489,6 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
 	}
 #endif
 
-	/* Determine text driver */
-
-	if (text_driver == "") {
-		text_driver = GLOBAL_GET("internationalization/rendering/text_driver");
-	}
-
-	if (text_driver != "") {
-		/* Load user selected text server. */
-		for (int i = 0; i < TextServerManager::get_interface_count(); i++) {
-			if (text_driver == TextServerManager::get_interface_name(i)) {
-				text_driver_idx = i;
-				break;
-			}
-		}
-	}
-
-	if (text_driver_idx < 0) {
-		/* If not selected, use one with the most features available. */
-		int max_features = 0;
-		for (int i = 0; i < TextServerManager::get_interface_count(); i++) {
-			uint32_t ftrs = TextServerManager::get_interface_features(i);
-			int features = 0;
-			while (ftrs) {
-				features += ftrs & 1;
-				ftrs >>= 1;
-			}
-			if (features >= max_features) {
-				max_features = features;
-				text_driver_idx = i;
-			}
-		}
-	}
-	print_verbose("Using \"" + TextServerManager::get_interface_name(text_driver_idx) + "\" text server...");
-
-	/* Initialize Text Server */
-
-	{
-		tsman = memnew(TextServerManager);
-		Error err;
-		TextServer *text_server = TextServerManager::initialize(text_driver_idx, err);
-		if (err != OK || text_server == nullptr) {
-			for (int i = 0; i < TextServerManager::get_interface_count(); i++) {
-				if (i == text_driver_idx) {
-					continue; //don't try the same twice
-				}
-				text_server = TextServerManager::initialize(i, err);
-				if (err == OK && text_server != nullptr) {
-					break;
-				}
-			}
-		}
-
-		if (err != OK || text_server == nullptr) {
-			ERR_PRINT("Unable to create TextServer, all text drivers failed.");
-			return err;
-		}
-	}
-
 	/* Initialize Input */
 
 	input = memnew(Input);
@@ -1781,6 +1733,57 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
 
 	ResourceLoader::load_path_remaps();
 
+	MAIN_PRINT("Main: Load TextServer");
+
+	/* Enum text drivers */
+	GLOBAL_DEF("internationalization/rendering/text_driver", "");
+	String text_driver_options;
+	for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
+		if (i > 0) {
+			text_driver_options += ",";
+		}
+		text_driver_options += TextServerManager::get_singleton()->get_interface(i)->get_name();
+	}
+	ProjectSettings::get_singleton()->set_custom_property_info("internationalization/rendering/text_driver", PropertyInfo(Variant::STRING, "internationalization/rendering/text_driver", PROPERTY_HINT_ENUM, text_driver_options));
+
+	/* Determine text driver */
+	if (text_driver == "") {
+		text_driver = GLOBAL_GET("internationalization/rendering/text_driver");
+	}
+
+	if (text_driver != "") {
+		/* Load user selected text server. */
+		for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
+			if (TextServerManager::get_singleton()->get_interface(i)->get_name() == text_driver) {
+				text_driver_idx = i;
+				break;
+			}
+		}
+	}
+
+	if (text_driver_idx < 0) {
+		/* If not selected, use one with the most features available. */
+		int max_features = 0;
+		for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
+			uint32_t features = TextServerManager::get_singleton()->get_interface(i)->get_features();
+			int feature_number = 0;
+			while (features) {
+				feature_number += features & 1;
+				features >>= 1;
+			}
+			if (feature_number >= max_features) {
+				max_features = feature_number;
+				text_driver_idx = i;
+			}
+		}
+	}
+	if (text_driver_idx >= 0) {
+		TextServerManager::get_singleton()->set_primary_interface(TextServerManager::get_singleton()->get_interface(text_driver_idx));
+	} else {
+		ERR_PRINT("TextServer: Unable to create TextServer interface.");
+		return ERR_CANT_CREATE;
+	}
+
 	MAIN_PRINT("Main: Load Scene Types");
 
 	register_scene_types();
@@ -1793,7 +1796,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
 
 #endif
 
-	MAIN_PRINT("Main: Load Modules, Physics, Drivers, Scripts");
+	MAIN_PRINT("Main: Load Modules");
 
 	register_platform_apis();
 	register_module_types();
@@ -1817,6 +1820,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
 
 	camera_server = CameraServer::create();
 
+	MAIN_PRINT("Main: Load Physics, Drivers, Scripts");
+
 	initialize_physics();
 	initialize_navigation_server();
 	register_server_singletons();
@@ -2728,10 +2733,6 @@ void Main::cleanup(bool p_force) {
 	finalize_navigation_server();
 	finalize_display();
 
-	if (tsman) {
-		memdelete(tsman);
-	}
-
 	if (input) {
 		memdelete(input);
 	}
@@ -2754,6 +2755,9 @@ void Main::cleanup(bool p_force) {
 	if (translation_server) {
 		memdelete(translation_server);
 	}
+	if (tsman) {
+		memdelete(tsman);
+	}
 	if (globals) {
 		memdelete(globals);
 	}

+ 0 - 1
modules/gdnative/SCsub

@@ -18,7 +18,6 @@ Export("env_gdnative")
 
 SConscript("pluginscript/SCsub")
 SConscript("videodecoder/SCsub")
-SConscript("text/SCsub")
 
 
 import gdnative_builders

+ 0 - 483
modules/gdnative/gdnative_api.json

@@ -5103,489 +5103,6 @@
 					]
 				}
 			]
-		},
-		{
-			"name": "text",
-			"type": "TEXT",
-			"version": {
-				"major": 1,
-				"minor": 0
-			},
-			"next": null,
-			"api": [
-				{
-					"name": "godot_text_register_interface",
-					"return_type": "void",
-					"arguments": [
-						[
-							"const godot_text_interface_gdnative *",
-							"p_interface"
-						],
-						[
-							"const godot_string *",
-							"p_name"
-						],
-						[
-							"uint32_t",
-							"p_features"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_new",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_glyph *",
-							"r_dest"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_get_range",
-					"return_type": "godot_vector2i",
-					"arguments": [
-						[
-							"const godot_glyph *",
-							"p_self"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_set_range",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_glyph *",
-							"p_self"
-						],
-						[
-							"const godot_vector2i *",
-							"p_range"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_get_count",
-					"return_type": "godot_int",
-					"arguments": [
-						[
-							"const godot_glyph *",
-							"p_self"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_set_count",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_glyph *",
-							"p_self"
-						],
-						[
-							"godot_int",
-							"p_count"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_get_repeat",
-					"return_type": "godot_int",
-					"arguments": [
-						[
-							"const godot_glyph *",
-							"p_self"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_set_repeat",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_glyph *",
-							"p_self"
-						],
-						[
-							"godot_int",
-							"p_repeat"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_get_flags",
-					"return_type": "godot_int",
-					"arguments": [
-						[
-							"const godot_glyph *",
-							"p_self"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_set_flags",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_glyph *",
-							"p_self"
-						],
-						[
-							"godot_int",
-							"p_flags"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_get_offset",
-					"return_type": "godot_vector2",
-					"arguments": [
-						[
-							"const godot_glyph *",
-							"p_self"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_set_offset",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_glyph *",
-							"p_self"
-						],
-						[
-							"const godot_vector2 *",
-							"p_offset"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_get_advance",
-					"return_type": "godot_real_t",
-					"arguments": [
-						[
-							"const godot_glyph *",
-							"p_self"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_set_advance",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_glyph *",
-							"p_self"
-						],
-						[
-							"godot_real_t",
-							"p_advance"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_get_font",
-					"return_type": "godot_rid",
-					"arguments": [
-						[
-							"const godot_glyph *",
-							"p_self"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_set_font",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_glyph *",
-							"p_self"
-						],
-						[
-							"godot_rid *",
-							"p_font"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_get_font_size",
-					"return_type": "godot_int",
-					"arguments": [
-						[
-							"const godot_glyph *",
-							"p_self"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_set_font_size",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_glyph *",
-							"p_self"
-						],
-						[
-							"godot_int",
-							"p_size"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_get_index",
-					"return_type": "godot_int",
-					"arguments": [
-						[
-							"const godot_glyph *",
-							"p_self"
-						]
-					]
-				},
-				{
-					"name": "godot_glyph_set_index",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_glyph *",
-							"p_self"
-						],
-						[
-							"godot_int",
-							"p_index"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_new",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_packed_glyph_array *",
-							"r_dest"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_new_copy",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_packed_glyph_array *",
-							"r_dest"
-						],
-						[
-							"const godot_packed_glyph_array *",
-							"p_src"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_is_empty",
-					"return_type": "godot_bool",
-					"arguments": [
-						[
-							"const godot_packed_glyph_array *",
-							"p_self"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_append",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_packed_glyph_array *",
-							"p_self"
-						],
-						[
-							"const godot_glyph *",
-							"p_data"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_append_array",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_packed_glyph_array *",
-							"p_self"
-						],
-						[
-							"const godot_packed_glyph_array *",
-							"p_array"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_insert",
-					"return_type": "godot_error",
-					"arguments": [
-						[
-							"godot_packed_glyph_array *",
-							"p_self"
-						],
-						[
-							"const godot_int",
-							"p_idx"
-						],
-						[
-							"const godot_glyph *",
-							"p_data"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_has",
-					"return_type": "godot_bool",
-					"arguments": [
-						[
-							"godot_packed_glyph_array *",
-							"p_self"
-						],
-						[
-							"const godot_glyph *",
-							"p_value"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_sort",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_packed_glyph_array *",
-							"p_self"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_reverse",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_packed_glyph_array *",
-							"p_self"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_push_back",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_packed_glyph_array *",
-							"p_self"
-						],
-						[
-							"const godot_glyph *",
-							"p_data"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_remove",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_packed_glyph_array *",
-							"p_self"
-						],
-						[
-							"const godot_int",
-							"p_idx"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_resize",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_packed_glyph_array *",
-							"p_self"
-						],
-						[
-							"const godot_int",
-							"p_size"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_ptr",
-					"return_type": "const godot_glyph *",
-					"arguments": [
-						[
-							"const godot_packed_glyph_array *",
-							"p_self"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_ptrw",
-					"return_type": "godot_glyph *",
-					"arguments": [
-						[
-							"godot_packed_glyph_array *",
-							"p_self"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_set",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_packed_glyph_array *",
-							"p_self"
-						],
-						[
-							"const godot_int",
-							"p_idx"
-						],
-						[
-							"const godot_glyph *",
-							"p_data"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_get",
-					"return_type": "godot_glyph",
-					"arguments": [
-						[
-							"const godot_packed_glyph_array *",
-							"p_self"
-						],
-						[
-							"const godot_int",
-							"p_idx"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_size",
-					"return_type": "godot_int",
-					"arguments": [
-						[
-							"const godot_packed_glyph_array *",
-							"p_self"
-						]
-					]
-				},
-				{
-					"name": "godot_packed_glyph_array_destroy",
-					"return_type": "void",
-					"arguments": [
-						[
-							"godot_packed_glyph_array *",
-							"p_self"
-						]
-					]
-				}
-			]
 		}
 	]
 }

+ 0 - 1
modules/gdnative/gdnative_builders.py

@@ -22,7 +22,6 @@ def _build_gdnative_api_struct_header(api):
         "#include <nativescript/godot_nativescript.h>",
         "#include <pluginscript/godot_pluginscript.h>",
         "#include <videodecoder/godot_videodecoder.h>",
-        "#include <text/godot_text.h>",
         "",
         "#ifdef __cplusplus",
         'extern "C" {',

+ 0 - 283
modules/gdnative/include/text/godot_text.h

@@ -1,283 +0,0 @@
-/*************************************************************************/
-/*  godot_text.h                                                         */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* 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.                */
-/*************************************************************************/
-
-#ifndef GODOT_NATIVETEXT_H
-#define GODOT_NATIVETEXT_H
-
-#include <gdnative/gdnative.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define GODOT_TEXT_API_MAJOR 1
-#define GODOT_TEXT_API_MINOR 0
-
-#define GODOT_GLYPH_SIZE 40
-
-#ifndef GODOT_TEXT_API_GODOT_GLYPH_TYPE_DEFINED
-#define GODOT_TEXT_API_GODOT_GLYPH_TYPE_DEFINED
-typedef struct {
-	uint8_t _dont_touch_that[GODOT_GLYPH_SIZE];
-} godot_glyph;
-#endif
-
-#define GODOT_PACKED_GLYPH_ARRAY_SIZE (2 * sizeof(void *))
-
-#ifndef GODOT_TEXT_API_GODOT_PACKED_GLYPH_ARRAY_TYPE_DEFINED
-#define GODOT_TEXT_API_GODOT_PACKED_GLYPH_ARRAY_TYPE_DEFINED
-typedef struct {
-	uint8_t _dont_touch_that[GODOT_PACKED_GLYPH_ARRAY_SIZE];
-} godot_packed_glyph_array;
-#endif
-
-typedef struct {
-	godot_gdnative_api_version version;
-
-	void *(*constructor)(godot_object *);
-	void (*destructor)(void *);
-
-	godot_string (*get_name)(const void *);
-	godot_bool (*has_feature)(const void *, godot_int);
-
-	void (*free)(void *, godot_rid *);
-	bool (*has)(void *, godot_rid *);
-
-	bool (*load_support_data)(void *, const godot_string *);
-	godot_string (*get_support_data_filename)(const void *);
-	godot_string (*get_support_data_info)(const void *);
-	bool (*save_support_data)(void *, const godot_string *);
-
-	bool (*is_locale_right_to_left)(void *, const godot_string *);
-	int32_t (*name_to_tag)(const void *, const godot_string *);
-	godot_string (*tag_to_name)(const void *, int32_t);
-
-	godot_rid (*create_font)(void *);
-	void (*font_set_data)(void *, godot_rid *, const godot_packed_byte_array *);
-	void (*font_set_data_ptr)(void *, godot_rid *, const uint8_t *, size_t);
-	void (*font_set_antialiased)(void *, godot_rid *, bool);
-	bool (*font_is_antialiased)(const void *, godot_rid *);
-	void (*font_set_multichannel_signed_distance_field)(void *, godot_rid *, bool);
-	bool (*font_is_multichannel_signed_distance_field)(const void *, godot_rid *);
-	void (*font_set_msdf_pixel_range)(void *, godot_rid *, godot_int);
-	godot_int (*font_get_msdf_pixel_range)(const void *, godot_rid *);
-	void (*font_set_msdf_size)(void *, godot_rid *, godot_int);
-	godot_int (*font_get_msdf_size)(const void *, godot_rid *);
-	void (*font_set_fixed_size)(void *, godot_rid *, godot_int);
-	godot_int (*font_get_fixed_size)(const void *, godot_rid *);
-	void (*font_set_force_autohinter)(void *, godot_rid *, bool);
-	bool (*font_is_force_autohinter)(const void *, godot_rid *);
-	void (*font_set_hinting)(void *, godot_rid *, godot_int);
-	godot_int (*font_get_hinting)(const void *, godot_rid *);
-	void (*font_set_variation_coordinates)(void *, godot_rid *, const godot_dictionary *);
-	godot_dictionary (*font_get_variation_coordinates)(const void *, godot_rid *);
-	void (*font_set_oversampling)(void *, godot_rid *, godot_real_t);
-	godot_real_t (*font_get_oversampling)(const void *, godot_rid *);
-	godot_array (*font_get_size_cache_list)(const void *, godot_rid *);
-	void (*font_clear_size_cache)(void *, godot_rid *);
-	void (*font_remove_size_cache)(void *, godot_rid *, const godot_vector2i *);
-	void (*font_set_ascent)(void *, godot_rid *, godot_int, godot_real_t);
-	godot_real_t (*font_get_ascent)(const void *, godot_rid *, godot_int);
-	void (*font_set_descent)(void *, godot_rid *, godot_int, godot_real_t);
-	godot_real_t (*font_get_descent)(const void *, godot_rid *, godot_int);
-	void (*font_set_underline_position)(void *, godot_rid *, godot_int, godot_real_t);
-	godot_real_t (*font_get_underline_position)(const void *, godot_rid *, godot_int);
-	void (*font_set_underline_thickness)(void *, godot_rid *, godot_int, godot_real_t);
-	godot_real_t (*font_get_underline_thickness)(const void *, godot_rid *, godot_int);
-	void (*font_set_scale)(void *, godot_rid *, godot_int, godot_real_t);
-	godot_real_t (*font_get_scale)(const void *, godot_rid *, godot_int);
-	void (*font_set_spacing)(void *, godot_rid *, godot_int, godot_int, godot_int);
-	godot_int (*font_get_spacing)(const void *, godot_rid *, godot_int, godot_int);
-	godot_int (*font_get_texture_count)(const void *, godot_rid *, const godot_vector2i *);
-	void (*font_clear_textures)(void *, godot_rid *, const godot_vector2i *);
-	void (*font_remove_texture)(void *, godot_rid *, const godot_vector2i *, godot_int);
-	void (*font_set_texture_image)(void *, godot_rid *, const godot_vector2i *, godot_int, const godot_object *);
-	godot_object *(*font_get_texture_image)(const void *, godot_rid *, const godot_vector2i *, godot_int);
-	void (*font_set_texture_offsets)(void *, godot_rid *, const godot_vector2i *, godot_int, const godot_packed_int32_array *);
-	godot_packed_int32_array (*font_get_texture_offsets)(const void *, godot_rid *, const godot_vector2i *, godot_int);
-	godot_array (*font_get_glyph_list)(const void *, godot_rid *, const godot_vector2i *);
-	void (*font_clear_glyphs)(void *, godot_rid *, const godot_vector2i *);
-	void (*font_remove_glyph)(void *, godot_rid *, const godot_vector2i *, int32_t);
-	godot_vector2 (*font_get_glyph_advance)(const void *, godot_rid *, godot_int, int32_t);
-	void (*font_set_glyph_advance)(void *, godot_rid *, godot_int, int32_t, const godot_vector2 *);
-	godot_vector2 (*font_get_glyph_offset)(const void *, godot_rid *, const godot_vector2i *, int32_t);
-	void (*font_set_glyph_offset)(void *, godot_rid *, const godot_vector2i *, int32_t, const godot_vector2 *);
-	godot_vector2 (*font_get_glyph_size)(const void *, godot_rid *, const godot_vector2i *, int32_t);
-	void (*font_set_glyph_size)(void *, godot_rid *, const godot_vector2i *, int32_t, const godot_vector2 *);
-	godot_rect2 (*font_get_glyph_uv_rect)(const void *, godot_rid *, const godot_vector2i *, int32_t);
-	void (*font_set_glyph_uv_rect)(void *, godot_rid *, const godot_vector2i *, int32_t, const godot_rect2 *);
-	godot_int (*font_get_glyph_texture_idx)(const void *, godot_rid *, const godot_vector2i *, int32_t);
-	void (*font_set_glyph_texture_idx)(void *, godot_rid *, const godot_vector2i *, int32_t, godot_int);
-	bool (*font_get_glyph_contours)(const void *, godot_rid *, godot_int, int32_t, godot_packed_vector3_array *, godot_packed_int32_array *, bool *);
-	godot_array (*font_get_kerning_list)(const void *, godot_rid *, godot_int);
-	void (*font_clear_kerning_map)(void *, godot_rid *, godot_int);
-	void (*font_remove_kerning)(void *, godot_rid *, godot_int, const godot_vector2i *);
-	void (*font_set_kerning)(void *, godot_rid *, godot_int, const godot_vector2i *, const godot_vector2 *);
-	godot_vector2 (*font_get_kerning)(const void *, godot_rid *, godot_int, const godot_vector2i *);
-	int32_t (*font_get_glyph_index)(const void *, godot_rid *, godot_int, char32_t, char32_t);
-	bool (*font_has_char)(const void *, godot_rid *, char32_t);
-	godot_string (*font_get_supported_chars)(const void *, godot_rid *);
-	void (*font_render_range)(void *, godot_rid *, const godot_vector2i *, char32_t, char32_t);
-	void (*font_render_glyph)(void *, godot_rid *, const godot_vector2i *, int32_t);
-	void (*font_draw_glyph)(const void *, godot_rid *, godot_rid *, godot_int, const godot_vector2 *, int32_t, const godot_color *);
-	void (*font_draw_glyph_outline)(const void *, godot_rid *, godot_rid *, godot_int, godot_int, const godot_vector2 *, int32_t, const godot_color *);
-	bool (*font_is_language_supported)(const void *, godot_rid *, const godot_string *);
-	void (*font_set_language_support_override)(void *, godot_rid *, const godot_string *, bool);
-	bool (*font_get_language_support_override)(const void *, godot_rid *, const godot_string *);
-	void (*font_remove_language_support_override)(void *, godot_rid *, const godot_string *);
-	godot_packed_string_array (*font_get_language_support_overrides)(const void *, godot_rid *);
-	bool (*font_is_script_supported)(const void *, godot_rid *, const godot_string *);
-	void (*font_set_script_support_override)(void *, godot_rid *, const godot_string *, bool);
-	bool (*font_get_script_support_override)(const void *, godot_rid *, const godot_string *);
-	void (*font_remove_script_support_override)(void *, godot_rid *, const godot_string *);
-	godot_packed_string_array (*font_get_script_support_overrides)(const void *, godot_rid *);
-	godot_dictionary (*font_supported_feature_list)(const void *, godot_rid *);
-	godot_dictionary (*font_supported_variation_list)(const void *, godot_rid *);
-	godot_real_t (*font_get_global_oversampling)(const void *);
-	void (*font_set_global_oversampling)(void *, godot_real_t);
-
-	godot_rid (*create_shaped_text)(void *, godot_int, godot_int);
-	void (*shaped_text_clear)(void *, godot_rid *);
-	void (*shaped_text_set_direction)(void *, godot_rid *, godot_int);
-	godot_int (*shaped_text_get_direction)(void *, godot_rid *);
-	void (*shaped_text_set_bidi_override)(void *, godot_rid *, const godot_packed_vector2i_array *);
-	void (*shaped_text_set_orientation)(void *, godot_rid *, godot_int);
-	godot_int (*shaped_text_get_orientation)(void *, godot_rid *);
-	void (*shaped_text_set_preserve_invalid)(void *, godot_rid *, bool);
-	bool (*shaped_text_get_preserve_invalid)(void *, godot_rid *);
-	void (*shaped_text_set_preserve_control)(void *, godot_rid *, bool);
-	bool (*shaped_text_get_preserve_control)(void *, godot_rid *);
-	bool (*shaped_text_add_string)(void *, godot_rid *, const godot_string *, const godot_rid **, int, const godot_dictionary *, const godot_string *);
-	bool (*shaped_text_add_object)(void *, godot_rid *, const godot_variant *, const godot_vector2 *, godot_int, godot_int);
-	bool (*shaped_text_resize_object)(void *, godot_rid *, const godot_variant *, const godot_vector2 *, godot_int);
-	godot_rid (*shaped_text_substr)(void *, godot_rid *, godot_int, godot_int);
-	godot_rid (*shaped_text_get_parent)(void *, godot_rid *);
-	godot_real_t (*shaped_text_fit_to_width)(void *, godot_rid *, godot_real_t, uint8_t);
-	godot_real_t (*shaped_text_tab_align)(void *, godot_rid *, godot_packed_float32_array *);
-	bool (*shaped_text_shape)(void *, godot_rid *);
-	bool (*shaped_text_update_breaks)(void *, godot_rid *);
-	bool (*shaped_text_update_justification_ops)(void *, godot_rid *);
-	void (*shaped_text_overrun_trim_to_width)(void *, godot_rid *, godot_real_t, uint8_t);
-	bool (*shaped_text_is_ready)(void *, godot_rid *);
-	godot_packed_glyph_array (*shaped_text_get_glyphs)(void *, godot_rid *);
-	godot_vector2i (*shaped_text_get_range)(void *, godot_rid *);
-	godot_packed_glyph_array (*shaped_text_sort_logical)(void *, godot_rid *);
-	godot_packed_vector2i_array (*shaped_text_get_line_breaks_adv)(void *, godot_rid *, godot_packed_float32_array *, int, bool, uint8_t);
-	godot_packed_vector2i_array (*shaped_text_get_line_breaks)(void *, godot_rid *, godot_real_t, int, uint8_t);
-	godot_packed_vector2i_array (*shaped_text_get_word_breaks)(void *, godot_rid *, int);
-	godot_array (*shaped_text_get_objects)(void *, godot_rid *);
-	godot_rect2 (*shaped_text_get_object_rect)(void *, godot_rid *, const godot_variant *);
-	godot_vector2 (*shaped_text_get_size)(void *, godot_rid *);
-	godot_real_t (*shaped_text_get_ascent)(void *, godot_rid *);
-	godot_real_t (*shaped_text_get_descent)(void *, godot_rid *);
-	godot_real_t (*shaped_text_get_width)(void *, godot_rid *);
-	godot_real_t (*shaped_text_get_underline_position)(void *, godot_rid *);
-	godot_real_t (*shaped_text_get_underline_thickness)(void *, godot_rid *);
-
-	godot_string (*format_number)(void *, const godot_string *, const godot_string *);
-	godot_string (*parse_number)(void *, const godot_string *, const godot_string *);
-	godot_string (*percent_sign)(void *, const godot_string *);
-} godot_text_interface_gdnative;
-
-void GDAPI godot_text_register_interface(const godot_text_interface_gdnative *p_interface, const godot_string *p_name, uint32_t p_features);
-
-// Glyph
-
-void GDAPI godot_glyph_new(godot_glyph *r_dest);
-
-godot_vector2i GDAPI godot_glyph_get_range(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_range(godot_glyph *p_self, const godot_vector2i *p_range);
-
-godot_int GDAPI godot_glyph_get_count(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_count(godot_glyph *p_self, godot_int p_count);
-
-godot_int GDAPI godot_glyph_get_repeat(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_repeat(godot_glyph *p_self, godot_int p_repeat);
-
-godot_int GDAPI godot_glyph_get_flags(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_flags(godot_glyph *p_self, godot_int p_flags);
-
-godot_vector2 GDAPI godot_glyph_get_offset(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_offset(godot_glyph *p_self, const godot_vector2 *p_offset);
-
-godot_real_t GDAPI godot_glyph_get_advance(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_advance(godot_glyph *p_self, godot_real_t p_advance);
-
-godot_rid GDAPI godot_glyph_get_font(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_font(godot_glyph *p_self, godot_rid *p_font);
-
-godot_int GDAPI godot_glyph_get_font_size(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_font_size(godot_glyph *p_self, godot_int p_size);
-
-godot_int GDAPI godot_glyph_get_index(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_index(godot_glyph *p_self, godot_int p_index);
-
-// GlyphArray
-
-void GDAPI godot_packed_glyph_array_new(godot_packed_glyph_array *r_dest);
-void GDAPI godot_packed_glyph_array_new_copy(godot_packed_glyph_array *r_dest, const godot_packed_glyph_array *p_src);
-
-const godot_glyph GDAPI *godot_packed_glyph_array_ptr(const godot_packed_glyph_array *p_self);
-godot_glyph GDAPI *godot_packed_glyph_array_ptrw(godot_packed_glyph_array *p_self);
-
-void GDAPI godot_packed_glyph_array_append(godot_packed_glyph_array *p_self, const godot_glyph *p_data);
-
-void GDAPI godot_packed_glyph_array_append_array(godot_packed_glyph_array *p_self, const godot_packed_glyph_array *p_array);
-
-godot_error GDAPI godot_packed_glyph_array_insert(godot_packed_glyph_array *p_self, const godot_int p_idx, const godot_glyph *p_data);
-
-godot_bool GDAPI godot_packed_glyph_array_has(godot_packed_glyph_array *p_self, const godot_glyph *p_value);
-
-void GDAPI godot_packed_glyph_array_sort(godot_packed_glyph_array *p_self);
-
-void GDAPI godot_packed_glyph_array_reverse(godot_packed_glyph_array *p_self);
-
-void GDAPI godot_packed_glyph_array_push_back(godot_packed_glyph_array *p_self, const godot_glyph *p_data);
-
-void GDAPI godot_packed_glyph_array_remove(godot_packed_glyph_array *p_self, godot_int p_idx);
-
-void GDAPI godot_packed_glyph_array_resize(godot_packed_glyph_array *p_self, godot_int p_size);
-
-void GDAPI godot_packed_glyph_array_set(godot_packed_glyph_array *p_self, godot_int p_idx, const godot_glyph *p_data);
-godot_glyph GDAPI godot_packed_glyph_array_get(const godot_packed_glyph_array *p_self, godot_int p_idx);
-
-godot_int GDAPI godot_packed_glyph_array_size(const godot_packed_glyph_array *p_self);
-
-godot_bool GDAPI godot_packed_glyph_array_is_empty(const godot_packed_glyph_array *p_self);
-
-void GDAPI godot_packed_glyph_array_destroy(godot_packed_glyph_array *p_self);
-
-// Grapheme
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !GODOT_NATIVETEXT_H */

+ 0 - 6
modules/gdnative/text/SCsub

@@ -1,6 +0,0 @@
-#!/usr/bin/env python
-
-Import("env")
-Import("env_gdnative")
-
-env_gdnative.add_source_files(env.modules_sources, "*.cpp")

+ 0 - 6
modules/gdnative/text/config.py

@@ -1,6 +0,0 @@
-def can_build(env, platform):
-    return True
-
-
-def configure(env):
-    pass

+ 0 - 36
modules/gdnative/text/register_types.cpp

@@ -1,36 +0,0 @@
-/*************************************************************************/
-/*  register_types.cpp                                                   */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* 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 "register_types.h"
-#include "text_server_gdnative.h"
-
-void register_text_server_gdn_types() {}
-
-void unregister_text_server_gdn_types() {}

+ 0 - 37
modules/gdnative/text/register_types.h

@@ -1,37 +0,0 @@
-/*************************************************************************/
-/*  register_types.h                                                     */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* 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.                */
-/*************************************************************************/
-
-#ifndef TEXT_REGISTER_TYPES_H
-#define TEXT_REGISTER_TYPES_H
-
-void register_text_server_gdn_types();
-void unregister_text_server_gdn_types();
-
-#endif // TEXT_REGISTER_TYPES_H

+ 0 - 1086
modules/gdnative/text/text_server_gdnative.cpp

@@ -1,1086 +0,0 @@
-/*************************************************************************/
-/*  text_server_gdnative.cpp                                             */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* 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_gdnative.h"
-
-bool TextServerGDNative::has_feature(Feature p_feature) {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->has_feature(data, (godot_int)p_feature);
-}
-
-String TextServerGDNative::get_name() const {
-	ERR_FAIL_COND_V(interface == nullptr, String());
-	godot_string result = interface->get_name(data);
-	String name = *(String *)&result;
-	godot_string_destroy(&result);
-	return name;
-}
-
-void TextServerGDNative::free(RID p_rid) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->free(data, (godot_rid *)&p_rid);
-}
-
-bool TextServerGDNative::has(RID p_rid) {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->has(data, (godot_rid *)&p_rid);
-}
-
-bool TextServerGDNative::load_support_data(const String &p_filename) {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->load_support_data(data, (godot_string *)&p_filename);
-}
-
-#ifdef TOOLS_ENABLED
-
-String TextServerGDNative::get_support_data_filename() {
-	ERR_FAIL_COND_V(interface == nullptr, String());
-	godot_string result = interface->get_support_data_filename(data);
-	String name = *(String *)&result;
-	godot_string_destroy(&result);
-	return name;
-}
-
-String TextServerGDNative::get_support_data_info() {
-	ERR_FAIL_COND_V(interface == nullptr, String());
-	godot_string result = interface->get_support_data_info(data);
-	String info = *(String *)&result;
-	godot_string_destroy(&result);
-	return info;
-}
-
-bool TextServerGDNative::save_support_data(const String &p_filename) {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->save_support_data(data, (godot_string *)&p_filename);
-}
-
-#endif
-
-bool TextServerGDNative::is_locale_right_to_left(const String &p_locale) {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->is_locale_right_to_left(data, (godot_string *)&p_locale);
-}
-
-int32_t TextServerGDNative::name_to_tag(const String &p_name) const {
-	ERR_FAIL_COND_V(interface == nullptr, 0);
-	return interface->name_to_tag(data, (godot_string *)&p_name);
-}
-
-String TextServerGDNative::tag_to_name(int32_t p_tag) const {
-	ERR_FAIL_COND_V(interface == nullptr, String());
-	godot_string result = interface->tag_to_name(data, p_tag);
-	String name = *(String *)&result;
-	godot_string_destroy(&result);
-	return name;
-}
-
-/*************************************************************************/
-/* Font                                                                  */
-/*************************************************************************/
-
-RID TextServerGDNative::create_font() {
-	ERR_FAIL_COND_V(interface == nullptr, RID());
-	godot_rid result = interface->create_font(data);
-	RID rid = *(RID *)&result;
-	return rid;
-}
-
-void TextServerGDNative::font_set_data(RID p_font_rid, const PackedByteArray &p_data) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_data(data, (godot_rid *)&p_font_rid, (const godot_packed_byte_array *)&p_data);
-}
-
-void TextServerGDNative::font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_data_ptr(data, (godot_rid *)&p_font_rid, p_data_ptr, p_data_size);
-}
-
-void TextServerGDNative::font_set_antialiased(RID p_font_rid, bool p_antialiased) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_antialiased(data, (godot_rid *)&p_font_rid, p_antialiased);
-}
-
-bool TextServerGDNative::font_is_antialiased(RID p_font_rid) const {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->font_is_antialiased(data, (godot_rid *)&p_font_rid);
-}
-
-void TextServerGDNative::font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_multichannel_signed_distance_field(data, (godot_rid *)&p_font_rid, p_msdf);
-}
-
-bool TextServerGDNative::font_is_multichannel_signed_distance_field(RID p_font_rid) const {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->font_is_multichannel_signed_distance_field(data, (godot_rid *)&p_font_rid);
-}
-
-void TextServerGDNative::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_msdf_pixel_range(data, (godot_rid *)&p_font_rid, p_msdf_pixel_range);
-}
-
-int TextServerGDNative::font_get_msdf_pixel_range(RID p_font_rid) const {
-	ERR_FAIL_COND_V(interface == nullptr, 0);
-	return interface->font_get_msdf_pixel_range(data, (godot_rid *)&p_font_rid);
-}
-
-void TextServerGDNative::font_set_msdf_size(RID p_font_rid, int p_msdf_size) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_msdf_size(data, (godot_rid *)&p_font_rid, p_msdf_size);
-}
-
-int TextServerGDNative::font_get_msdf_size(RID p_font_rid) const {
-	ERR_FAIL_COND_V(interface == nullptr, 0);
-	return interface->font_get_msdf_size(data, (godot_rid *)&p_font_rid);
-}
-
-void TextServerGDNative::font_set_fixed_size(RID p_font_rid, int p_fixed_size) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_fixed_size(data, (godot_rid *)&p_font_rid, p_fixed_size);
-}
-
-int TextServerGDNative::font_get_fixed_size(RID p_font_rid) const {
-	ERR_FAIL_COND_V(interface == nullptr, 0);
-	return interface->font_get_fixed_size(data, (godot_rid *)&p_font_rid);
-}
-
-void TextServerGDNative::font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_force_autohinter(data, (godot_rid *)&p_font_rid, p_force_autohinter);
-}
-
-bool TextServerGDNative::font_is_force_autohinter(RID p_font_rid) const {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->font_is_force_autohinter(data, (godot_rid *)&p_font_rid);
-}
-
-void TextServerGDNative::font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_hinting(data, (godot_rid *)&p_font_rid, (godot_int)p_hinting);
-}
-
-TextServer::Hinting TextServerGDNative::font_get_hinting(RID p_font_rid) const {
-	ERR_FAIL_COND_V(interface == nullptr, TextServer::HINTING_NONE);
-	return (TextServer::Hinting)interface->font_get_hinting(data, (godot_rid *)&p_font_rid);
-}
-
-void TextServerGDNative::font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_variation_coordinates(data, (godot_rid *)&p_font_rid, (const godot_dictionary *)&p_variation_coordinates);
-}
-
-Dictionary TextServerGDNative::font_get_variation_coordinates(RID p_font_rid) const {
-	ERR_FAIL_COND_V(interface == nullptr, Dictionary());
-	godot_dictionary result = interface->font_get_variation_coordinates(data, (godot_rid *)&p_font_rid);
-	Dictionary dict = *(Dictionary *)&result;
-	godot_dictionary_destroy(&result);
-	return dict;
-}
-
-void TextServerGDNative::font_set_oversampling(RID p_font_rid, real_t p_oversampling) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_oversampling(data, (godot_rid *)&p_font_rid, p_oversampling);
-}
-
-real_t TextServerGDNative::font_get_oversampling(RID p_font_rid) const {
-	ERR_FAIL_COND_V(interface == nullptr, 0.0f);
-	return interface->font_get_oversampling(data, (godot_rid *)&p_font_rid);
-}
-
-Array TextServerGDNative::font_get_size_cache_list(RID p_font_rid) const {
-	ERR_FAIL_COND_V(interface == nullptr, Array());
-	godot_array result = interface->font_get_size_cache_list(data, (godot_rid *)&p_font_rid);
-	Array list = *(Array *)&result;
-	godot_array_destroy(&result);
-	return list;
-}
-
-void TextServerGDNative::font_clear_size_cache(RID p_font_rid) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_clear_size_cache(data, (godot_rid *)&p_font_rid);
-}
-
-void TextServerGDNative::font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_remove_size_cache(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size);
-}
-
-void TextServerGDNative::font_set_ascent(RID p_font_rid, int p_size, real_t p_ascent) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_ascent(data, (godot_rid *)&p_font_rid, p_size, p_ascent);
-}
-
-real_t TextServerGDNative::font_get_ascent(RID p_font_rid, int p_size) const {
-	ERR_FAIL_COND_V(interface == nullptr, 0.0f);
-	return interface->font_get_ascent(data, (godot_rid *)&p_font_rid, p_size);
-}
-
-void TextServerGDNative::font_set_descent(RID p_font_rid, int p_size, real_t p_descent) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_descent(data, (godot_rid *)&p_font_rid, p_size, p_descent);
-}
-
-real_t TextServerGDNative::font_get_descent(RID p_font_rid, int p_size) const {
-	ERR_FAIL_COND_V(interface == nullptr, 0.0f);
-	return interface->font_get_descent(data, (godot_rid *)&p_font_rid, p_size);
-}
-
-void TextServerGDNative::font_set_underline_position(RID p_font_rid, int p_size, real_t p_underline_position) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_underline_position(data, (godot_rid *)&p_font_rid, p_size, p_underline_position);
-}
-
-real_t TextServerGDNative::font_get_underline_position(RID p_font_rid, int p_size) const {
-	ERR_FAIL_COND_V(interface == nullptr, 0.0f);
-	return interface->font_get_underline_position(data, (godot_rid *)&p_font_rid, p_size);
-}
-
-void TextServerGDNative::font_set_underline_thickness(RID p_font_rid, int p_size, real_t p_underline_thickness) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_underline_thickness(data, (godot_rid *)&p_font_rid, p_size, p_underline_thickness);
-}
-
-real_t TextServerGDNative::font_get_underline_thickness(RID p_font_rid, int p_size) const {
-	ERR_FAIL_COND_V(interface == nullptr, 0.0f);
-	return interface->font_get_underline_thickness(data, (godot_rid *)&p_font_rid, p_size);
-}
-
-void TextServerGDNative::font_set_scale(RID p_font_rid, int p_size, real_t p_scale) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_scale(data, (godot_rid *)&p_font_rid, p_size, p_scale);
-}
-
-real_t TextServerGDNative::font_get_scale(RID p_font_rid, int p_size) const {
-	ERR_FAIL_COND_V(interface == nullptr, 0.0f);
-	return interface->font_get_scale(data, (godot_rid *)&p_font_rid, p_size);
-}
-
-void TextServerGDNative::font_set_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing, int p_value) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_spacing(data, (godot_rid *)&p_font_rid, p_size, (godot_int)p_spacing, p_value);
-}
-
-int TextServerGDNative::font_get_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing) const {
-	ERR_FAIL_COND_V(interface == nullptr, 0);
-	return interface->font_get_spacing(data, (godot_rid *)&p_font_rid, p_size, (godot_int)p_spacing);
-}
-
-int TextServerGDNative::font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const {
-	ERR_FAIL_COND_V(interface == nullptr, -1);
-	return interface->font_get_texture_count(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size);
-}
-
-void TextServerGDNative::font_clear_textures(RID p_font_rid, const Vector2i &p_size) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_clear_textures(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size);
-}
-
-void TextServerGDNative::font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_remove_texture(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_texture_index);
-}
-
-void TextServerGDNative::font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_texture_image(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_texture_index, (const godot_object *)p_image.ptr());
-}
-
-Ref<Image> TextServerGDNative::font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const {
-	ERR_FAIL_COND_V(interface == nullptr, Ref<Image>());
-	godot_object *result = interface->font_get_texture_image(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_texture_index);
-	return Ref<Image>((Image *)result);
-}
-
-void TextServerGDNative::font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_texture_offsets(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_texture_index, (const godot_packed_int32_array *)&p_offset);
-}
-
-PackedInt32Array TextServerGDNative::font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const {
-	ERR_FAIL_COND_V(interface == nullptr, PackedInt32Array());
-	godot_packed_int32_array result = interface->font_get_texture_offsets(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_texture_index);
-	PackedInt32Array offset = *(PackedInt32Array *)&result;
-	godot_packed_int32_array_destroy(&result);
-	return offset;
-}
-
-Array TextServerGDNative::font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const {
-	ERR_FAIL_COND_V(interface == nullptr, Array());
-	godot_array result = interface->font_get_glyph_list(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size);
-	Array list = *(Array *)&result;
-	godot_array_destroy(&result);
-	return list;
-}
-
-void TextServerGDNative::font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_clear_glyphs(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size);
-}
-
-void TextServerGDNative::font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_remove_glyph(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph);
-}
-
-Vector2 TextServerGDNative::font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const {
-	ERR_FAIL_COND_V(interface == nullptr, Vector2());
-	godot_vector2 result = interface->font_get_glyph_advance(data, (godot_rid *)&p_font_rid, p_size, p_glyph);
-	Vector2 adv = *(Vector2 *)&result;
-	return adv;
-}
-
-void TextServerGDNative::font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_glyph_advance(data, (godot_rid *)&p_font_rid, p_size, p_glyph, (const godot_vector2 *)&p_advance);
-}
-
-Vector2 TextServerGDNative::font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
-	ERR_FAIL_COND_V(interface == nullptr, Vector2());
-	godot_vector2 result = interface->font_get_glyph_offset(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph);
-	Vector2 off = *(Vector2 *)&result;
-	return off;
-}
-
-void TextServerGDNative::font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_glyph_offset(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph, (const godot_vector2 *)&p_offset);
-}
-
-Vector2 TextServerGDNative::font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
-	ERR_FAIL_COND_V(interface == nullptr, Vector2());
-	godot_vector2 result = interface->font_get_glyph_size(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph);
-	Vector2 sz = *(Vector2 *)&result;
-	return sz;
-}
-
-void TextServerGDNative::font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_glyph_size(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph, (const godot_vector2 *)&p_gl_size);
-}
-
-Rect2 TextServerGDNative::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
-	ERR_FAIL_COND_V(interface == nullptr, Rect2());
-	godot_rect2 result = interface->font_get_glyph_uv_rect(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph);
-	Rect2 uv = *(Rect2 *)&result;
-	return uv;
-}
-
-void TextServerGDNative::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_glyph_uv_rect(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph, (const godot_rect2 *)&p_uv_rect);
-}
-
-int TextServerGDNative::font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
-	ERR_FAIL_COND_V(interface == nullptr, -1);
-	return interface->font_get_glyph_texture_idx(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph);
-}
-
-void TextServerGDNative::font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_glyph_texture_idx(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph, p_texture_idx);
-}
-
-bool TextServerGDNative::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->font_get_glyph_contours(data, (godot_rid *)&p_font_rid, p_size, p_index, (godot_packed_vector3_array *)&r_points, (godot_packed_int32_array *)&r_contours, &r_orientation);
-}
-
-Array TextServerGDNative::font_get_kerning_list(RID p_font_rid, int p_size) const {
-	ERR_FAIL_COND_V(interface == nullptr, Array());
-	godot_array result = interface->font_get_kerning_list(data, (godot_rid *)&p_font_rid, p_size);
-	Array list = *(Array *)&result;
-	godot_array_destroy(&result);
-	return list;
-}
-
-void TextServerGDNative::font_clear_kerning_map(RID p_font_rid, int p_size) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_clear_kerning_map(data, (godot_rid *)&p_font_rid, p_size);
-}
-
-void TextServerGDNative::font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_remove_kerning(data, (godot_rid *)&p_font_rid, p_size, (const godot_vector2i *)&p_glyph_pair);
-}
-
-void TextServerGDNative::font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_kerning(data, (godot_rid *)&p_font_rid, p_size, (const godot_vector2i *)&p_glyph_pair, (const godot_vector2 *)&p_kerning);
-}
-
-Vector2 TextServerGDNative::font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const {
-	ERR_FAIL_COND_V(interface == nullptr, Vector2());
-	godot_vector2 result = interface->font_get_kerning(data, (godot_rid *)&p_font_rid, p_size, (const godot_vector2i *)&p_glyph_pair);
-	Vector2 kern = *(Vector2 *)&result;
-	return kern;
-}
-
-int32_t TextServerGDNative::font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector) const {
-	ERR_FAIL_COND_V(interface == nullptr, 0);
-	return interface->font_get_glyph_index(data, (godot_rid *)&p_font_rid, p_size, p_char, p_variation_selector);
-}
-
-bool TextServerGDNative::font_has_char(RID p_font_rid, char32_t p_char) const {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->font_has_char(data, (godot_rid *)&p_font_rid, p_char);
-}
-
-String TextServerGDNative::font_get_supported_chars(RID p_font_rid) const {
-	ERR_FAIL_COND_V(interface == nullptr, String());
-	godot_string result = interface->font_get_supported_chars(data, (godot_rid *)&p_font_rid);
-	String chars = *(String *)&result;
-	godot_string_destroy(&result);
-	return chars;
-}
-
-void TextServerGDNative::font_render_range(RID p_font_rid, const Vector2i &p_size, char32_t p_start, char32_t p_end) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_render_range(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_start, p_end);
-}
-
-void TextServerGDNative::font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_render_glyph(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_index);
-}
-
-void TextServerGDNative::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_draw_glyph(data, (godot_rid *)&p_font_rid, (godot_rid *)&p_canvas, p_size, (const godot_vector2 *)&p_pos, p_index, (const godot_color *)&p_color);
-}
-
-void TextServerGDNative::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_draw_glyph_outline(data, (godot_rid *)&p_font_rid, (godot_rid *)&p_canvas, p_size, p_outline_size, (const godot_vector2 *)&p_pos, p_index, (const godot_color *)&p_color);
-}
-
-bool TextServerGDNative::font_is_language_supported(RID p_font_rid, const String &p_language) const {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->font_is_language_supported(data, (godot_rid *)&p_font_rid, (const godot_string *)&p_language);
-}
-
-void TextServerGDNative::font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_language_support_override(data, (godot_rid *)&p_font_rid, (const godot_string *)&p_language, p_supported);
-}
-
-bool TextServerGDNative::font_get_language_support_override(RID p_font_rid, const String &p_language) {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->font_get_language_support_override(data, (godot_rid *)&p_font_rid, (const godot_string *)&p_language);
-}
-
-void TextServerGDNative::font_remove_language_support_override(RID p_font_rid, const String &p_language) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_remove_language_support_override(data, (godot_rid *)&p_font_rid, (const godot_string *)&p_language);
-}
-
-Vector<String> TextServerGDNative::font_get_language_support_overrides(RID p_font_rid) {
-	ERR_FAIL_COND_V(interface == nullptr, PackedStringArray());
-	godot_packed_string_array result = interface->font_get_language_support_overrides(data, (godot_rid *)&p_font_rid);
-	PackedStringArray list = *(PackedStringArray *)&result;
-	godot_packed_string_array_destroy(&result);
-	return list;
-}
-
-bool TextServerGDNative::font_is_script_supported(RID p_font_rid, const String &p_script) const {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->font_is_script_supported(data, (godot_rid *)&p_font_rid, (const godot_string *)&p_script);
-}
-
-void TextServerGDNative::font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_script_support_override(data, (godot_rid *)&p_font_rid, (const godot_string *)&p_script, p_supported);
-}
-
-bool TextServerGDNative::font_get_script_support_override(RID p_font_rid, const String &p_script) {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->font_get_script_support_override(data, (godot_rid *)&p_font_rid, (const godot_string *)&p_script);
-}
-
-void TextServerGDNative::font_remove_script_support_override(RID p_font_rid, const String &p_script) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_remove_script_support_override(data, (godot_rid *)&p_font_rid, (const godot_string *)&p_script);
-}
-
-Vector<String> TextServerGDNative::font_get_script_support_overrides(RID p_font_rid) {
-	ERR_FAIL_COND_V(interface == nullptr, PackedStringArray());
-	godot_packed_string_array result = interface->font_get_script_support_overrides(data, (godot_rid *)&p_font_rid);
-	PackedStringArray list = *(PackedStringArray *)&result;
-	godot_packed_string_array_destroy(&result);
-	return list;
-}
-
-Dictionary TextServerGDNative::font_supported_feature_list(RID p_font_rid) const {
-	ERR_FAIL_COND_V(interface == nullptr, Dictionary());
-	godot_dictionary result = interface->font_supported_feature_list(data, (godot_rid *)&p_font_rid);
-	Dictionary dict = *(Dictionary *)&result;
-	godot_dictionary_destroy(&result);
-	return dict;
-}
-
-Dictionary TextServerGDNative::font_supported_variation_list(RID p_font_rid) const {
-	ERR_FAIL_COND_V(interface == nullptr, Dictionary());
-	godot_dictionary result = interface->font_supported_variation_list(data, (godot_rid *)&p_font_rid);
-	Dictionary dict = *(Dictionary *)&result;
-	godot_dictionary_destroy(&result);
-	return dict;
-}
-
-real_t TextServerGDNative::font_get_global_oversampling() const {
-	ERR_FAIL_COND_V(interface == nullptr, 0.0f);
-	return interface->font_get_global_oversampling(data);
-}
-
-void TextServerGDNative::font_set_global_oversampling(real_t p_oversampling) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->font_set_global_oversampling(data, p_oversampling);
-}
-
-/*************************************************************************/
-/* Shaped text buffer interface                                          */
-/*************************************************************************/
-
-RID TextServerGDNative::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
-	ERR_FAIL_COND_V(interface == nullptr, RID());
-	godot_rid result = interface->create_shaped_text(data, (godot_int)p_direction, (godot_int)p_orientation);
-	RID rid = *(RID *)&result;
-	return rid;
-}
-
-void TextServerGDNative::shaped_text_clear(RID p_shaped) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->shaped_text_clear(data, (godot_rid *)&p_shaped);
-}
-
-void TextServerGDNative::shaped_text_set_direction(RID p_shaped, TextServer::Direction p_direction) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->shaped_text_set_direction(data, (godot_rid *)&p_shaped, (godot_int)p_direction);
-}
-
-TextServer::Direction TextServerGDNative::shaped_text_get_direction(RID p_shaped) const {
-	ERR_FAIL_COND_V(interface == nullptr, TextServer::DIRECTION_LTR);
-	return (TextServer::Direction)interface->shaped_text_get_direction(data, (godot_rid *)&p_shaped);
-}
-
-void TextServerGDNative::shaped_text_set_orientation(RID p_shaped, TextServer::Orientation p_orientation) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->shaped_text_set_orientation(data, (godot_rid *)&p_shaped, (godot_int)p_orientation);
-}
-
-TextServer::Orientation TextServerGDNative::shaped_text_get_orientation(RID p_shaped) const {
-	ERR_FAIL_COND_V(interface == nullptr, TextServer::ORIENTATION_HORIZONTAL);
-	return (TextServer::Orientation)interface->shaped_text_get_orientation(data, (godot_rid *)&p_shaped);
-}
-
-void TextServerGDNative::shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->shaped_text_set_bidi_override(data, (godot_rid *)&p_shaped, (const godot_packed_vector2i_array *)&p_override);
-}
-
-void TextServerGDNative::shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->shaped_text_set_preserve_invalid(data, (godot_rid *)&p_shaped, p_enabled);
-}
-
-bool TextServerGDNative::shaped_text_get_preserve_invalid(RID p_shaped) const {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return (TextServer::Orientation)interface->shaped_text_get_preserve_invalid(data, (godot_rid *)&p_shaped);
-}
-
-void TextServerGDNative::shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->shaped_text_set_preserve_control(data, (godot_rid *)&p_shaped, p_enabled);
-}
-
-bool TextServerGDNative::shaped_text_get_preserve_control(RID p_shaped) const {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return (TextServer::Orientation)interface->shaped_text_get_preserve_control(data, (godot_rid *)&p_shaped);
-}
-
-bool TextServerGDNative::shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->shaped_text_add_string(data, (godot_rid *)&p_shaped, (const godot_string *)&p_text, (const godot_rid **)p_fonts.ptr(), p_size, (const godot_dictionary *)&p_opentype_features, (const godot_string *)&p_language);
-}
-
-bool TextServerGDNative::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->shaped_text_add_object(data, (godot_rid *)&p_shaped, (const godot_variant *)&p_key, (const godot_vector2 *)&p_size, (godot_int)p_inline_align, p_length);
-}
-
-bool TextServerGDNative::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->shaped_text_resize_object(data, (godot_rid *)&p_shaped, (const godot_variant *)&p_key, (const godot_vector2 *)&p_size, (godot_int)p_inline_align);
-}
-
-RID TextServerGDNative::shaped_text_substr(RID p_shaped, int p_start, int p_length) const {
-	ERR_FAIL_COND_V(interface == nullptr, RID());
-	godot_rid result = interface->shaped_text_substr(data, (godot_rid *)&p_shaped, (godot_int)p_start, (godot_int)p_length);
-	RID rid = *(RID *)&result;
-	return rid;
-}
-
-RID TextServerGDNative::shaped_text_get_parent(RID p_shaped) const {
-	ERR_FAIL_COND_V(interface == nullptr, RID());
-	godot_rid result = interface->shaped_text_get_parent(data, (godot_rid *)&p_shaped);
-	RID rid = *(RID *)&result;
-	return rid;
-}
-
-real_t TextServerGDNative::shaped_text_fit_to_width(RID p_shaped, real_t p_width, uint8_t p_jst_flags) {
-	ERR_FAIL_COND_V(interface == nullptr, 0.f);
-	return interface->shaped_text_fit_to_width(data, (godot_rid *)&p_shaped, p_width, p_jst_flags);
-}
-
-real_t TextServerGDNative::shaped_text_tab_align(RID p_shaped, const Vector<real_t> &p_tab_stops) {
-	ERR_FAIL_COND_V(interface == nullptr, 0.f);
-	return interface->shaped_text_tab_align(data, (godot_rid *)&p_shaped, (godot_packed_float32_array *)&p_tab_stops);
-}
-
-bool TextServerGDNative::shaped_text_shape(RID p_shaped) {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->shaped_text_shape(data, (godot_rid *)&p_shaped);
-}
-
-bool TextServerGDNative::shaped_text_update_breaks(RID p_shaped) {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->shaped_text_update_breaks(data, (godot_rid *)&p_shaped);
-}
-
-bool TextServerGDNative::shaped_text_update_justification_ops(RID p_shaped) {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->shaped_text_update_justification_ops(data, (godot_rid *)&p_shaped);
-}
-
-void TextServerGDNative::shaped_text_overrun_trim_to_width(RID p_shaped_line, real_t p_width, uint8_t p_trim_flags) {
-	ERR_FAIL_COND(interface == nullptr);
-	interface->shaped_text_overrun_trim_to_width(data, (godot_rid *)&p_shaped_line, p_width, p_trim_flags);
-};
-
-bool TextServerGDNative::shaped_text_is_ready(RID p_shaped) const {
-	ERR_FAIL_COND_V(interface == nullptr, false);
-	return interface->shaped_text_is_ready(data, (godot_rid *)&p_shaped);
-}
-
-Vector<TextServer::Glyph> TextServerGDNative::shaped_text_get_glyphs(RID p_shaped) const {
-	ERR_FAIL_COND_V(interface == nullptr, Vector<TextServer::Glyph>());
-	godot_packed_glyph_array result = interface->shaped_text_get_glyphs(data, (godot_rid *)&p_shaped);
-	Vector<TextServer::Glyph> glyphs = *(Vector<TextServer::Glyph> *)&result;
-	godot_packed_glyph_array_destroy(&result);
-	return glyphs;
-}
-
-Vector2i TextServerGDNative::shaped_text_get_range(RID p_shaped) const {
-	ERR_FAIL_COND_V(interface == nullptr, Vector2i());
-	godot_vector2i result = interface->shaped_text_get_range(data, (godot_rid *)&p_shaped);
-	Vector2i range = *(Vector2i *)&result;
-	return range;
-}
-
-Vector<TextServer::Glyph> TextServerGDNative::shaped_text_sort_logical(RID p_shaped) {
-	ERR_FAIL_COND_V(interface == nullptr, Vector<TextServer::Glyph>());
-	godot_packed_glyph_array result = interface->shaped_text_sort_logical(data, (godot_rid *)&p_shaped);
-	Vector<TextServer::Glyph> glyphs = *(Vector<TextServer::Glyph> *)&result;
-	godot_packed_glyph_array_destroy(&result);
-	return glyphs;
-}
-
-Vector<Vector2i> TextServerGDNative::shaped_text_get_line_breaks_adv(RID p_shaped, const Vector<real_t> &p_width, int p_start, bool p_once, uint8_t p_break_flags) const {
-	ERR_FAIL_COND_V(interface == nullptr, Vector<Vector2i>());
-	if (interface->shaped_text_get_line_breaks_adv != nullptr) {
-		godot_packed_vector2i_array result = interface->shaped_text_get_line_breaks_adv(data, (godot_rid *)&p_shaped, (godot_packed_float32_array *)&p_width, p_start, p_once, p_break_flags);
-		Vector<Vector2i> breaks = *(Vector<Vector2i> *)&result;
-		godot_packed_vector2i_array_destroy(&result);
-		return breaks;
-	} else {
-		return TextServer::shaped_text_get_line_breaks_adv(p_shaped, p_width, p_break_flags);
-	}
-}
-
-Vector<Vector2i> TextServerGDNative::shaped_text_get_line_breaks(RID p_shaped, real_t p_width, int p_start, uint8_t p_break_flags) const {
-	ERR_FAIL_COND_V(interface == nullptr, Vector<Vector2i>());
-	if (interface->shaped_text_get_line_breaks != nullptr) {
-		godot_packed_vector2i_array result = interface->shaped_text_get_line_breaks(data, (godot_rid *)&p_shaped, p_width, p_start, p_break_flags);
-		Vector<Vector2i> breaks = *(Vector<Vector2i> *)&result;
-		godot_packed_vector2i_array_destroy(&result);
-		return breaks;
-	} else {
-		return TextServer::shaped_text_get_line_breaks(p_shaped, p_width, p_break_flags);
-	}
-}
-
-Vector<Vector2i> TextServerGDNative::shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags) const {
-	ERR_FAIL_COND_V(interface == nullptr, Vector<Vector2i>());
-	if (interface->shaped_text_get_word_breaks != nullptr) {
-		godot_packed_vector2i_array result = interface->shaped_text_get_word_breaks(data, (godot_rid *)&p_shaped, p_grapheme_flags);
-		Vector<Vector2i> breaks = *(Vector<Vector2i> *)&result;
-		godot_packed_vector2i_array_destroy(&result);
-		return breaks;
-	} else {
-		return TextServer::shaped_text_get_word_breaks(p_shaped, p_grapheme_flags);
-	}
-}
-
-Array TextServerGDNative::shaped_text_get_objects(RID p_shaped) const {
-	ERR_FAIL_COND_V(interface == nullptr, Array());
-	godot_array result = interface->shaped_text_get_objects(data, (godot_rid *)&p_shaped);
-	Array rect = *(Array *)&result;
-	return rect;
-}
-
-Rect2 TextServerGDNative::shaped_text_get_object_rect(RID p_shaped, Variant p_key) const {
-	ERR_FAIL_COND_V(interface == nullptr, Rect2());
-	godot_rect2 result = interface->shaped_text_get_object_rect(data, (godot_rid *)&p_shaped, (const godot_variant *)&p_key);
-	Rect2 rect = *(Rect2 *)&result;
-	return rect;
-}
-
-Size2 TextServerGDNative::shaped_text_get_size(RID p_shaped) const {
-	ERR_FAIL_COND_V(interface == nullptr, Size2());
-	godot_vector2 result = interface->shaped_text_get_size(data, (godot_rid *)&p_shaped);
-	Size2 size = *(Size2 *)&result;
-	return size;
-}
-
-real_t TextServerGDNative::shaped_text_get_ascent(RID p_shaped) const {
-	ERR_FAIL_COND_V(interface == nullptr, 0.f);
-	return interface->shaped_text_get_ascent(data, (godot_rid *)&p_shaped);
-}
-
-real_t TextServerGDNative::shaped_text_get_descent(RID p_shaped) const {
-	ERR_FAIL_COND_V(interface == nullptr, 0.f);
-	return interface->shaped_text_get_descent(data, (godot_rid *)&p_shaped);
-}
-
-real_t TextServerGDNative::shaped_text_get_width(RID p_shaped) const {
-	ERR_FAIL_COND_V(interface == nullptr, 0.f);
-	return interface->shaped_text_get_width(data, (godot_rid *)&p_shaped);
-}
-
-real_t TextServerGDNative::shaped_text_get_underline_position(RID p_shaped) const {
-	ERR_FAIL_COND_V(interface == nullptr, 0.f);
-	return interface->shaped_text_get_underline_position(data, (godot_rid *)&p_shaped);
-}
-
-real_t TextServerGDNative::shaped_text_get_underline_thickness(RID p_shaped) const {
-	ERR_FAIL_COND_V(interface == nullptr, 0.f);
-	return interface->shaped_text_get_underline_thickness(data, (godot_rid *)&p_shaped);
-}
-
-String TextServerGDNative::format_number(const String &p_string, const String &p_language) const {
-	ERR_FAIL_COND_V(interface == nullptr, String());
-	godot_string result = interface->format_number(data, (const godot_string *)&p_string, (const godot_string *)&p_language);
-	if (interface->format_number == nullptr) {
-		return p_string;
-	}
-	String ret = *(String *)&result;
-	godot_string_destroy(&result);
-	return ret;
-}
-
-String TextServerGDNative::parse_number(const String &p_string, const String &p_language) const {
-	ERR_FAIL_COND_V(interface == nullptr, String());
-	if (interface->parse_number == nullptr) {
-		return p_string;
-	}
-	godot_string result = interface->parse_number(data, (const godot_string *)&p_string, (const godot_string *)&p_language);
-	String ret = *(String *)&result;
-	godot_string_destroy(&result);
-	return ret;
-}
-
-String TextServerGDNative::percent_sign(const String &p_language) const {
-	ERR_FAIL_COND_V(interface == nullptr, String());
-	if (interface->percent_sign == nullptr) {
-		return "%";
-	}
-	godot_string result = interface->percent_sign(data, (const godot_string *)&p_language);
-	String ret = *(String *)&result;
-	godot_string_destroy(&result);
-	return ret;
-}
-
-TextServer *TextServerGDNative::create_func(Error &r_error, void *p_user_data) {
-	const godot_text_interface_gdnative *interface = (const godot_text_interface_gdnative *)p_user_data;
-	r_error = OK;
-
-	TextServerGDNative *server = memnew(TextServerGDNative());
-	server->interface = interface;
-	server->data = interface->constructor((godot_object *)server);
-
-	return server;
-}
-
-TextServerGDNative::TextServerGDNative() {
-	data = nullptr;
-	interface = nullptr;
-}
-
-TextServerGDNative::~TextServerGDNative() {
-	if (interface != nullptr) {
-		interface->destructor(data);
-		data = nullptr;
-		interface = nullptr;
-	}
-}
-
-/*************************************************************************/
-/* GDNative functions                                                    */
-/*************************************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-static_assert(sizeof(godot_glyph) == sizeof(TextServer::Glyph), "Glyph size mismatch");
-static_assert(sizeof(godot_packed_glyph_array) == sizeof(Vector<TextServer::Glyph>), "Vector<Glyph> size mismatch");
-
-void GDAPI godot_text_register_interface(const godot_text_interface_gdnative *p_interface, const godot_string *p_name, uint32_t p_features) {
-	ERR_FAIL_COND(p_interface->version.major != 1);
-	String name = *(String *)p_name;
-	TextServerManager::register_create_function(name + "(GDNative)", p_features, TextServerGDNative::create_func, (void *)p_interface);
-}
-
-// Glyph
-
-void GDAPI godot_glyph_new(godot_glyph *r_dest) {
-	TextServer::Glyph *dest = (TextServer::Glyph *)r_dest;
-	*dest = TextServer::Glyph();
-}
-
-godot_vector2i GDAPI godot_glyph_get_range(const godot_glyph *p_self) {
-	godot_vector2i dest;
-	Vector2i *d = (Vector2i *)&dest;
-	const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
-	d->x = self->start;
-	d->y = self->end;
-	return dest;
-}
-
-void GDAPI godot_glyph_set_range(godot_glyph *p_self, const godot_vector2i *p_range) {
-	TextServer::Glyph *self = (TextServer::Glyph *)p_self;
-	const Vector2i *range = (const Vector2i *)p_range;
-	self->start = range->x;
-	self->end = range->y;
-}
-
-godot_int GDAPI godot_glyph_get_count(const godot_glyph *p_self) {
-	const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
-	return self->count;
-}
-
-void GDAPI godot_glyph_set_count(godot_glyph *p_self, godot_int p_count) {
-	TextServer::Glyph *self = (TextServer::Glyph *)p_self;
-	self->count = p_count;
-}
-
-godot_int GDAPI godot_glyph_get_repeat(const godot_glyph *p_self) {
-	const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
-	return self->repeat;
-}
-
-void GDAPI godot_glyph_set_repeat(godot_glyph *p_self, godot_int p_repeat) {
-	TextServer::Glyph *self = (TextServer::Glyph *)p_self;
-	self->repeat = p_repeat;
-}
-
-godot_int GDAPI godot_glyph_get_flags(const godot_glyph *p_self) {
-	const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
-	return self->flags;
-}
-
-void GDAPI godot_glyph_set_flags(godot_glyph *p_self, godot_int p_flags) {
-	TextServer::Glyph *self = (TextServer::Glyph *)p_self;
-	self->flags = p_flags;
-}
-
-godot_vector2 GDAPI godot_glyph_get_offset(const godot_glyph *p_self) {
-	godot_vector2 dest;
-	Vector2 *d = (Vector2 *)&dest;
-	const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
-	d->x = self->x_off;
-	d->y = self->y_off;
-	return dest;
-}
-
-void GDAPI godot_glyph_set_offset(godot_glyph *p_self, const godot_vector2 *p_offset) {
-	TextServer::Glyph *self = (TextServer::Glyph *)p_self;
-	const Vector2 *offset = (const Vector2 *)p_offset;
-	self->x_off = offset->x;
-	self->y_off = offset->y;
-}
-
-godot_real_t GDAPI godot_glyph_get_advance(const godot_glyph *p_self) {
-	const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
-	return self->advance;
-}
-
-void GDAPI godot_glyph_set_advance(godot_glyph *p_self, godot_real_t p_advance) {
-	TextServer::Glyph *self = (TextServer::Glyph *)p_self;
-	self->advance = p_advance;
-}
-
-godot_rid GDAPI godot_glyph_get_font(const godot_glyph *p_self) {
-	godot_rid dest;
-	RID *d = (RID *)&dest;
-	const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
-	*d = self->font_rid;
-	return dest;
-}
-
-void GDAPI godot_glyph_set_font(godot_glyph *p_self, godot_rid *p_font) {
-	TextServer::Glyph *self = (TextServer::Glyph *)p_self;
-	const RID *font = (const RID *)p_font;
-	self->font_rid = *font;
-}
-
-godot_int GDAPI godot_glyph_get_font_size(const godot_glyph *p_self) {
-	const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
-	return self->font_size;
-}
-
-void GDAPI godot_glyph_set_font_size(godot_glyph *p_self, godot_int p_size) {
-	TextServer::Glyph *self = (TextServer::Glyph *)p_self;
-	self->font_size = p_size;
-}
-
-godot_int GDAPI godot_glyph_get_index(const godot_glyph *p_self) {
-	const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
-	return self->index;
-}
-
-void GDAPI godot_glyph_set_index(godot_glyph *p_self, godot_int p_index) {
-	TextServer::Glyph *self = (TextServer::Glyph *)p_self;
-	self->index = p_index;
-}
-
-// GlyphArray
-
-void GDAPI godot_packed_glyph_array_new(godot_packed_glyph_array *r_dest) {
-	Vector<TextServer::Glyph> *dest = (Vector<TextServer::Glyph> *)r_dest;
-	memnew_placement(dest, Vector<TextServer::Glyph>);
-}
-
-void GDAPI godot_packed_glyph_array_new_copy(godot_packed_glyph_array *r_dest, const godot_packed_glyph_array *p_src) {
-	Vector<TextServer::Glyph> *dest = (Vector<TextServer::Glyph> *)r_dest;
-	const Vector<TextServer::Glyph> *src = (const Vector<TextServer::Glyph> *)p_src;
-	memnew_placement(dest, Vector<TextServer::Glyph>(*src));
-}
-
-const godot_glyph GDAPI *godot_packed_glyph_array_ptr(const godot_packed_glyph_array *p_self) {
-	const Vector<TextServer::Glyph> *self = (const Vector<TextServer::Glyph> *)p_self;
-	return (const godot_glyph *)self->ptr();
-}
-
-godot_glyph GDAPI *godot_packed_glyph_array_ptrw(godot_packed_glyph_array *p_self) {
-	Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
-	return (godot_glyph *)self->ptrw();
-}
-
-void GDAPI godot_packed_glyph_array_append(godot_packed_glyph_array *p_self, const godot_glyph *p_data) {
-	Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
-	TextServer::Glyph &s = *(TextServer::Glyph *)p_data;
-	self->push_back(s);
-}
-
-void GDAPI godot_packed_glyph_array_append_array(godot_packed_glyph_array *p_self, const godot_packed_glyph_array *p_array) {
-	Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
-	Vector<TextServer::Glyph> *array = (Vector<TextServer::Glyph> *)p_array;
-	self->append_array(*array);
-}
-
-godot_error GDAPI godot_packed_glyph_array_insert(godot_packed_glyph_array *p_self, const godot_int p_idx, const godot_glyph *p_data) {
-	Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
-	TextServer::Glyph &s = *(TextServer::Glyph *)p_data;
-	return (godot_error)self->insert(p_idx, s);
-}
-
-godot_bool GDAPI godot_packed_glyph_array_has(godot_packed_glyph_array *p_self, const godot_glyph *p_value) {
-	Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
-	TextServer::Glyph &v = *(TextServer::Glyph *)p_value;
-	return (godot_bool)self->has(v);
-}
-
-void GDAPI godot_packed_glyph_array_sort(godot_packed_glyph_array *p_self) {
-	Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
-	self->sort();
-}
-
-void GDAPI godot_packed_glyph_array_reverse(godot_packed_glyph_array *p_self) {
-	Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
-	self->reverse();
-}
-
-void GDAPI godot_packed_glyph_array_push_back(godot_packed_glyph_array *p_self, const godot_glyph *p_data) {
-	Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
-	TextServer::Glyph &s = *(TextServer::Glyph *)p_data;
-	self->push_back(s);
-}
-
-void GDAPI godot_packed_glyph_array_remove(godot_packed_glyph_array *p_self, const godot_int p_idx) {
-	Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
-	self->remove(p_idx);
-}
-
-void GDAPI godot_packed_glyph_array_resize(godot_packed_glyph_array *p_self, const godot_int p_size) {
-	Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
-	self->resize(p_size);
-}
-
-void GDAPI godot_packed_glyph_array_set(godot_packed_glyph_array *p_self, const godot_int p_idx, const godot_glyph *p_data) {
-	Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
-	TextServer::Glyph &s = *(TextServer::Glyph *)p_data;
-	self->set(p_idx, s);
-}
-
-godot_glyph GDAPI godot_packed_glyph_array_get(const godot_packed_glyph_array *p_self, const godot_int p_idx) {
-	const Vector<TextServer::Glyph> *self = (const Vector<TextServer::Glyph> *)p_self;
-	godot_glyph v;
-	TextServer::Glyph *s = (TextServer::Glyph *)&v;
-	*s = self->get(p_idx);
-	return v;
-}
-
-godot_int GDAPI godot_packed_glyph_array_size(const godot_packed_glyph_array *p_self) {
-	const Vector<TextServer::Glyph> *self = (const Vector<TextServer::Glyph> *)p_self;
-	return self->size();
-}
-
-godot_bool GDAPI godot_packed_glyph_array_is_empty(const godot_packed_glyph_array *p_self) {
-	const Vector<TextServer::Glyph> *self = (const Vector<TextServer::Glyph> *)p_self;
-	return self->is_empty();
-}
-
-void GDAPI godot_packed_glyph_array_destroy(godot_packed_glyph_array *p_self) {
-	((Vector<TextServer::Glyph> *)p_self)->~Vector();
-}
-
-#ifdef __cplusplus
-}
-#endif

+ 0 - 254
modules/gdnative/text/text_server_gdnative.h

@@ -1,254 +0,0 @@
-/*************************************************************************/
-/*  text_server_gdnative.h                                               */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* 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.                */
-/*************************************************************************/
-
-#ifndef TEXT_SERVER_GDNATIVE_H
-#define TEXT_SERVER_GDNATIVE_H
-
-#include "modules/gdnative/gdnative.h"
-
-#include "servers/text_server.h"
-
-class TextServerGDNative : public TextServer {
-	GDCLASS(TextServerGDNative, TextServer);
-
-	const godot_text_interface_gdnative *interface = nullptr;
-	void *data = nullptr;
-
-protected:
-	static void _bind_methods(){};
-
-public:
-	virtual bool has_feature(Feature p_feature) override;
-	virtual String get_name() const override;
-
-	virtual void free(RID p_rid) override;
-	virtual bool has(RID p_rid) override;
-	virtual bool load_support_data(const String &p_filename) override;
-
-#ifdef TOOLS_ENABLED
-	virtual String get_support_data_filename() override;
-	virtual String get_support_data_info() override;
-	virtual bool save_support_data(const String &p_filename) override;
-#endif
-
-	virtual bool is_locale_right_to_left(const String &p_locale) override;
-
-	virtual int32_t name_to_tag(const String &p_name) const override;
-	virtual String tag_to_name(int32_t p_tag) const override;
-
-	/* Font interface */
-	virtual RID create_font() override;
-
-	virtual void font_set_data(RID p_font_rid, const PackedByteArray &p_data) override;
-	virtual void font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) override;
-
-	virtual void font_set_antialiased(RID p_font_rid, bool p_antialiased) override;
-	virtual bool font_is_antialiased(RID p_font_rid) const override;
-
-	virtual void font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) override;
-	virtual bool font_is_multichannel_signed_distance_field(RID p_font_rid) const override;
-
-	virtual void font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) override;
-	virtual int font_get_msdf_pixel_range(RID p_font_rid) const override;
-
-	virtual void font_set_msdf_size(RID p_font_rid, int p_msdf_size) override;
-	virtual int font_get_msdf_size(RID p_font_rid) const override;
-
-	virtual void font_set_fixed_size(RID p_font_rid, int p_fixed_size) override;
-	virtual int font_get_fixed_size(RID p_font_rid) const override;
-
-	virtual void font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) override;
-	virtual bool font_is_force_autohinter(RID p_font_rid) const override;
-
-	virtual void font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) override;
-	virtual TextServer::Hinting font_get_hinting(RID p_font_rid) const override;
-
-	virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) override;
-	virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const override;
-
-	virtual void font_set_oversampling(RID p_font_rid, real_t p_oversampling) override;
-	virtual real_t font_get_oversampling(RID p_font_rid) const override;
-
-	virtual Array font_get_size_cache_list(RID p_font_rid) const override;
-	virtual void font_clear_size_cache(RID p_font_rid) override;
-	virtual void font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) override;
-
-	virtual void font_set_ascent(RID p_font_rid, int p_size, real_t p_ascent) override;
-	virtual real_t font_get_ascent(RID p_font_rid, int p_size) const override;
-
-	virtual void font_set_descent(RID p_font_rid, int p_size, real_t p_descent) override;
-	virtual real_t font_get_descent(RID p_font_rid, int p_size) const override;
-
-	virtual void font_set_underline_position(RID p_font_rid, int p_size, real_t p_underline_position) override;
-	virtual real_t font_get_underline_position(RID p_font_rid, int p_size) const override;
-
-	virtual void font_set_underline_thickness(RID p_font_rid, int p_size, real_t p_underline_thickness) override;
-	virtual real_t font_get_underline_thickness(RID p_font_rid, int p_size) const override;
-
-	virtual void font_set_scale(RID p_font_rid, int p_size, real_t p_scale) override;
-	virtual real_t font_get_scale(RID p_font_rid, int p_size) const override;
-
-	virtual void font_set_spacing(RID p_font_rid, int p_size, SpacingType p_spacing, int p_value) override;
-	virtual int font_get_spacing(RID p_font_rid, int p_size, SpacingType p_spacing) const override;
-
-	virtual int font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const override;
-	virtual void font_clear_textures(RID p_font_rid, const Vector2i &p_size) override;
-	virtual void font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) override;
-
-	virtual void font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) override;
-	virtual Ref<Image> font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override;
-
-	virtual void font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) override;
-	virtual PackedInt32Array font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override;
-
-	virtual Array font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const override;
-	virtual void font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) override;
-	virtual void font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) override;
-
-	virtual Vector2 font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const override;
-	virtual void font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) override;
-
-	virtual Vector2 font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
-	virtual void font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) override;
-
-	virtual Vector2 font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
-	virtual void font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) override;
-
-	virtual Rect2 font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
-	virtual void font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) override;
-
-	virtual int font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
-	virtual void font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) override;
-
-	virtual bool font_get_glyph_contours(RID p_font, int p_size, int32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
-
-	virtual Array font_get_kerning_list(RID p_font_rid, int p_size) const override;
-	virtual void font_clear_kerning_map(RID p_font_rid, int p_size) override;
-	virtual void font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) override;
-
-	virtual void font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) override;
-	virtual Vector2 font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const override;
-
-	virtual int32_t font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector = 0) const override;
-
-	virtual bool font_has_char(RID p_font_rid, char32_t p_char) const override;
-	virtual String font_get_supported_chars(RID p_font_rid) const override;
-
-	virtual void font_render_range(RID p_font, const Vector2i &p_size, char32_t p_start, char32_t p_end) override;
-	virtual void font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) override;
-
-	virtual void font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
-	virtual void font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
-
-	virtual bool font_is_language_supported(RID p_font_rid, const String &p_language) const override;
-	virtual void font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) override;
-	virtual bool font_get_language_support_override(RID p_font_rid, const String &p_language) override;
-	virtual void font_remove_language_support_override(RID p_font_rid, const String &p_language) override;
-	virtual Vector<String> font_get_language_support_overrides(RID p_font_rid) override;
-
-	virtual bool font_is_script_supported(RID p_font_rid, const String &p_script) const override;
-	virtual void font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) override;
-	virtual bool font_get_script_support_override(RID p_font_rid, const String &p_script) override;
-	virtual void font_remove_script_support_override(RID p_font_rid, const String &p_script) override;
-	virtual Vector<String> font_get_script_support_overrides(RID p_font_rid) override;
-
-	virtual Dictionary font_supported_feature_list(RID p_font_rid) const override;
-	virtual Dictionary font_supported_variation_list(RID p_font_rid) const override;
-
-	virtual real_t font_get_global_oversampling() const override;
-	virtual void font_set_global_oversampling(real_t p_oversampling) override;
-
-	/* Shaped text buffer interface */
-
-	virtual RID create_shaped_text(Direction p_direction = DIRECTION_AUTO, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
-
-	virtual void shaped_text_clear(RID p_shaped) override;
-
-	virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override;
-	virtual Direction shaped_text_get_direction(RID p_shaped) const override;
-
-	virtual void shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) override;
-
-	virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
-	virtual Orientation shaped_text_get_orientation(RID p_shaped) const override;
-
-	virtual void shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) override;
-	virtual bool shaped_text_get_preserve_invalid(RID p_shaped) const override;
-
-	virtual void shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) override;
-	virtual bool shaped_text_get_preserve_control(RID p_shaped) const override;
-
-	virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override;
-	virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) override;
-	virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) override;
-
-	virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
-	virtual RID shaped_text_get_parent(RID p_shaped) const override;
-
-	virtual real_t shaped_text_fit_to_width(RID p_shaped, real_t p_width, uint8_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
-	virtual real_t shaped_text_tab_align(RID p_shaped, const Vector<real_t> &p_tab_stops) override;
-
-	virtual bool shaped_text_shape(RID p_shaped) override;
-	virtual bool shaped_text_update_breaks(RID p_shaped) override;
-	virtual bool shaped_text_update_justification_ops(RID p_shaped) override;
-
-	virtual void shaped_text_overrun_trim_to_width(RID p_shaped, real_t p_width, uint8_t p_trim_flags) override;
-
-	virtual bool shaped_text_is_ready(RID p_shaped) const override;
-
-	virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const override;
-
-	virtual Vector2i shaped_text_get_range(RID p_shaped) const override;
-
-	virtual Vector<Glyph> shaped_text_sort_logical(RID p_shaped) override;
-	virtual Vector<Vector2i> shaped_text_get_line_breaks_adv(RID p_shaped, const Vector<real_t> &p_width, int p_start = 0, bool p_once = true, uint8_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const override;
-	virtual Vector<Vector2i> shaped_text_get_line_breaks(RID p_shaped, real_t p_width, int p_start = 0, uint8_t p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const override;
-	virtual Vector<Vector2i> shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION) const override;
-	virtual Array shaped_text_get_objects(RID p_shaped) const override;
-	virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const override;
-
-	virtual Size2 shaped_text_get_size(RID p_shaped) const override;
-	virtual real_t shaped_text_get_ascent(RID p_shaped) const override;
-	virtual real_t shaped_text_get_descent(RID p_shaped) const override;
-	virtual real_t shaped_text_get_width(RID p_shaped) const override;
-	virtual real_t shaped_text_get_underline_position(RID p_shaped) const override;
-	virtual real_t shaped_text_get_underline_thickness(RID p_shaped) const override;
-
-	virtual String format_number(const String &p_string, const String &p_language = "") const override;
-	virtual String parse_number(const String &p_string, const String &p_language = "") const override;
-	virtual String percent_sign(const String &p_language = "") const override;
-
-	static TextServer *create_func(Error &r_error, void *p_user_data);
-
-	TextServerGDNative();
-	~TextServerGDNative();
-};
-
-#endif // TEXT_SERVER_GDNATIVE_H

+ 10 - 0
modules/text_server_adv/config.py

@@ -4,3 +4,13 @@ def can_build(env, platform):
 
 def configure(env):
     pass
+
+
+def get_doc_classes():
+    return [
+        "TextServerAdvanced",
+    ]
+
+
+def get_doc_path():
+    return "doc_classes"

+ 10 - 0
modules/text_server_adv/doc_classes/TextServerAdvanced.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="TextServerAdvanced" inherits="TextServer" version="4.0">
+	<brief_description>
+		Text Server using HarfBuzz, ICU and SIL Graphite to support BiDi, complex text layouts and contextual OpenType features.
+	</brief_description>
+	<description>
+	</description>
+	<tutorials>
+	</tutorials>
+</class>

+ 6 - 1
modules/text_server_adv/register_types.cpp

@@ -33,7 +33,12 @@
 #include "text_server_adv.h"
 
 void preregister_text_server_adv_types() {
-	TextServerAdvanced::register_server();
+	GDREGISTER_CLASS(TextServerAdvanced);
+	if (TextServerManager::get_singleton()) {
+		Ref<TextServerAdvanced> ts;
+		ts.instantiate();
+		TextServerManager::get_singleton()->add_interface(ts);
+	}
 }
 
 void register_text_server_adv_types() {

+ 173 - 123
modules/text_server_adv/text_server_adv.cpp

@@ -322,7 +322,7 @@ _FORCE_INLINE_ bool is_underscore(char32_t p_char) {
 String TextServerAdvanced::interface_name = "ICU / HarfBuzz / Graphite";
 uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA | FEATURE_FONT_VARIABLE;
 
-bool TextServerAdvanced::has_feature(Feature p_feature) {
+bool TextServerAdvanced::has_feature(Feature p_feature) const {
 	return (interface_features & p_feature) == p_feature;
 }
 
@@ -330,6 +330,10 @@ String TextServerAdvanced::get_name() const {
 	return interface_name;
 }
 
+uint32_t TextServerAdvanced::get_features() const {
+	return interface_features;
+}
+
 void TextServerAdvanced::free(RID p_rid) {
 	_THREAD_SAFE_METHOD_
 	if (font_owner.owns(p_rid)) {
@@ -394,9 +398,23 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) {
 	return true;
 }
 
-#ifdef TOOLS_ENABLED
+String TextServerAdvanced::get_support_data_filename() const {
+#ifdef ICU_STATIC_DATA
+	return _MKSTR(ICU_DATA_NAME);
+#else
+	return String();
+#endif
+}
+
+String TextServerAdvanced::get_support_data_info() const {
+#ifdef ICU_STATIC_DATA
+	return String("ICU break iteration data (") + _MKSTR(ICU_DATA_NAME) + String(").");
+#else
+	return String();
+#endif
+}
 
-bool TextServerAdvanced::save_support_data(const String &p_filename) {
+bool TextServerAdvanced::save_support_data(const String &p_filename) const {
 	_THREAD_SAFE_METHOD_
 #ifdef ICU_STATIC_DATA
 
@@ -415,9 +433,7 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) {
 #endif
 }
 
-#endif
-
-bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) {
+bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) const {
 	String l = p_locale.get_slicec('_', 0);
 	if ((l == "ar") || (l == "dv") || (l == "he") || (l == "fa") || (l == "ff") || (l == "ku") || (l == "ur")) {
 		return true;
@@ -1142,7 +1158,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontDataAdvanced *p_font_d
 		int error = FT_Load_Glyph(fd->face, p_glyph, flags);
 		if (error) {
 			fd->glyph_map[p_glyph] = FontGlyph();
-			ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph.");
+			return false;
 		}
 
 		if (!outline) {
@@ -1236,7 +1252,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
 			fd->oversampling = 1.0f;
 			fd->size.x = p_font_data->msdf_source_size;
 		} else if (p_font_data->oversampling <= 0.0f) {
-			fd->oversampling = TS->font_get_global_oversampling();
+			fd->oversampling = font_get_global_oversampling();
 		} else {
 			fd->oversampling = p_font_data->oversampling;
 		}
@@ -1244,13 +1260,13 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
 		if (FT_HAS_COLOR(fd->face) && fd->face->num_fixed_sizes > 0) {
 			int best_match = 0;
 			int diff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[0].width));
-			fd->scale = real_t(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width;
+			fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width;
 			for (int i = 1; i < fd->face->num_fixed_sizes; i++) {
 				int ndiff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[i].width));
 				if (ndiff < diff) {
 					best_match = i;
 					diff = ndiff;
-					fd->scale = real_t(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width;
+					fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width;
 				}
 			}
 			FT_Select_Size(fd->face, best_match);
@@ -1786,7 +1802,7 @@ Dictionary TextServerAdvanced::font_get_variation_coordinates(RID p_font_rid) co
 	return fd->variation_coordinates;
 }
 
-void TextServerAdvanced::font_set_oversampling(RID p_font_rid, real_t p_oversampling) {
+void TextServerAdvanced::font_set_oversampling(RID p_font_rid, float p_oversampling) {
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 
@@ -1797,7 +1813,7 @@ void TextServerAdvanced::font_set_oversampling(RID p_font_rid, real_t p_oversamp
 	}
 }
 
-real_t TextServerAdvanced::font_get_oversampling(RID p_font_rid) const {
+float TextServerAdvanced::font_get_oversampling(RID p_font_rid) const {
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 
@@ -1839,7 +1855,7 @@ void TextServerAdvanced::font_remove_size_cache(RID p_font_rid, const Vector2i &
 	}
 }
 
-void TextServerAdvanced::font_set_ascent(RID p_font_rid, int p_size, real_t p_ascent) {
+void TextServerAdvanced::font_set_ascent(RID p_font_rid, int p_size, float p_ascent) {
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 
@@ -1850,7 +1866,7 @@ void TextServerAdvanced::font_set_ascent(RID p_font_rid, int p_size, real_t p_as
 	fd->cache[size]->ascent = p_ascent;
 }
 
-real_t TextServerAdvanced::font_get_ascent(RID p_font_rid, int p_size) const {
+float TextServerAdvanced::font_get_ascent(RID p_font_rid, int p_size) const {
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 
@@ -1860,13 +1876,13 @@ real_t TextServerAdvanced::font_get_ascent(RID p_font_rid, int p_size) const {
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 	if (fd->msdf) {
-		return fd->cache[size]->ascent * (real_t)p_size / (real_t)fd->msdf_source_size;
+		return fd->cache[size]->ascent * (float)p_size / (float)fd->msdf_source_size;
 	} else {
 		return fd->cache[size]->ascent;
 	}
 }
 
-void TextServerAdvanced::font_set_descent(RID p_font_rid, int p_size, real_t p_descent) {
+void TextServerAdvanced::font_set_descent(RID p_font_rid, int p_size, float p_descent) {
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 
@@ -1876,7 +1892,7 @@ void TextServerAdvanced::font_set_descent(RID p_font_rid, int p_size, real_t p_d
 	fd->cache[size]->descent = p_descent;
 }
 
-real_t TextServerAdvanced::font_get_descent(RID p_font_rid, int p_size) const {
+float TextServerAdvanced::font_get_descent(RID p_font_rid, int p_size) const {
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 
@@ -1886,13 +1902,13 @@ real_t TextServerAdvanced::font_get_descent(RID p_font_rid, int p_size) const {
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 	if (fd->msdf) {
-		return fd->cache[size]->descent * (real_t)p_size / (real_t)fd->msdf_source_size;
+		return fd->cache[size]->descent * (float)p_size / (float)fd->msdf_source_size;
 	} else {
 		return fd->cache[size]->descent;
 	}
 }
 
-void TextServerAdvanced::font_set_underline_position(RID p_font_rid, int p_size, real_t p_underline_position) {
+void TextServerAdvanced::font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) {
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 
@@ -1903,7 +1919,7 @@ void TextServerAdvanced::font_set_underline_position(RID p_font_rid, int p_size,
 	fd->cache[size]->underline_position = p_underline_position;
 }
 
-real_t TextServerAdvanced::font_get_underline_position(RID p_font_rid, int p_size) const {
+float TextServerAdvanced::font_get_underline_position(RID p_font_rid, int p_size) const {
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 
@@ -1913,13 +1929,13 @@ real_t TextServerAdvanced::font_get_underline_position(RID p_font_rid, int p_siz
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 	if (fd->msdf) {
-		return fd->cache[size]->underline_position * (real_t)p_size / (real_t)fd->msdf_source_size;
+		return fd->cache[size]->underline_position * (float)p_size / (float)fd->msdf_source_size;
 	} else {
 		return fd->cache[size]->underline_position;
 	}
 }
 
-void TextServerAdvanced::font_set_underline_thickness(RID p_font_rid, int p_size, real_t p_underline_thickness) {
+void TextServerAdvanced::font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) {
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 
@@ -1930,7 +1946,7 @@ void TextServerAdvanced::font_set_underline_thickness(RID p_font_rid, int p_size
 	fd->cache[size]->underline_thickness = p_underline_thickness;
 }
 
-real_t TextServerAdvanced::font_get_underline_thickness(RID p_font_rid, int p_size) const {
+float TextServerAdvanced::font_get_underline_thickness(RID p_font_rid, int p_size) const {
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 
@@ -1940,13 +1956,13 @@ real_t TextServerAdvanced::font_get_underline_thickness(RID p_font_rid, int p_si
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 	if (fd->msdf) {
-		return fd->cache[size]->underline_thickness * (real_t)p_size / (real_t)fd->msdf_source_size;
+		return fd->cache[size]->underline_thickness * (float)p_size / (float)fd->msdf_source_size;
 	} else {
 		return fd->cache[size]->underline_thickness;
 	}
 }
 
-void TextServerAdvanced::font_set_scale(RID p_font_rid, int p_size, real_t p_scale) {
+void TextServerAdvanced::font_set_scale(RID p_font_rid, int p_size, float p_scale) {
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 
@@ -1957,7 +1973,7 @@ void TextServerAdvanced::font_set_scale(RID p_font_rid, int p_size, real_t p_sca
 	fd->cache[size]->scale = p_scale;
 }
 
-real_t TextServerAdvanced::font_get_scale(RID p_font_rid, int p_size) const {
+float TextServerAdvanced::font_get_scale(RID p_font_rid, int p_size) const {
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 
@@ -1967,7 +1983,7 @@ real_t TextServerAdvanced::font_get_scale(RID p_font_rid, int p_size) const {
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 	if (fd->msdf) {
-		return fd->cache[size]->scale * (real_t)p_size / (real_t)fd->msdf_source_size;
+		return fd->cache[size]->scale * (float)p_size / (float)fd->msdf_source_size;
 	} else {
 		return fd->cache[size]->scale / fd->cache[size]->oversampling;
 	}
@@ -2006,14 +2022,14 @@ int TextServerAdvanced::font_get_spacing(RID p_font_rid, int p_size, TextServer:
 	switch (p_spacing) {
 		case TextServer::SPACING_GLYPH: {
 			if (fd->msdf) {
-				return fd->cache[size]->spacing_glyph * (real_t)p_size / (real_t)fd->msdf_source_size;
+				return fd->cache[size]->spacing_glyph * (float)p_size / (float)fd->msdf_source_size;
 			} else {
 				return fd->cache[size]->spacing_glyph;
 			}
 		} break;
 		case TextServer::SPACING_SPACE: {
 			if (fd->msdf) {
-				return fd->cache[size]->spacing_space * (real_t)p_size / (real_t)fd->msdf_source_size;
+				return fd->cache[size]->spacing_space * (float)p_size / (float)fd->msdf_source_size;
 			} else {
 				return fd->cache[size]->spacing_space;
 			}
@@ -2182,7 +2198,7 @@ Vector2 TextServerAdvanced::font_get_glyph_advance(RID p_font_rid, int p_size, i
 	const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
 
 	if (fd->msdf) {
-		return gl[p_glyph].advance * (real_t)p_size / (real_t)fd->msdf_source_size;
+		return gl[p_glyph].advance * (float)p_size / (float)fd->msdf_source_size;
 	} else {
 		return gl[p_glyph].advance;
 	}
@@ -2218,7 +2234,7 @@ Vector2 TextServerAdvanced::font_get_glyph_offset(RID p_font_rid, const Vector2i
 	const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
 
 	if (fd->msdf) {
-		return gl[p_glyph].rect.position * (real_t)p_size.x / (real_t)fd->msdf_source_size;
+		return gl[p_glyph].rect.position * (float)p_size.x / (float)fd->msdf_source_size;
 	} else {
 		return gl[p_glyph].rect.position;
 	}
@@ -2254,7 +2270,7 @@ Vector2 TextServerAdvanced::font_get_glyph_size(RID p_font_rid, const Vector2i &
 	const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
 
 	if (fd->msdf) {
-		return gl[p_glyph].rect.size * (real_t)p_size.x / (real_t)fd->msdf_source_size;
+		return gl[p_glyph].rect.size * (float)p_size.x / (float)fd->msdf_source_size;
 	} else {
 		return gl[p_glyph].rect.size;
 	}
@@ -2337,38 +2353,46 @@ void TextServerAdvanced::font_set_glyph_texture_idx(RID p_font_rid, const Vector
 	gl[p_glyph].found = true;
 }
 
-bool TextServerAdvanced::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
+Dictionary TextServerAdvanced::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index) const {
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
-	ERR_FAIL_COND_V(!fd, false);
+	ERR_FAIL_COND_V(!fd, Dictionary());
 
 	MutexLock lock(fd->mutex);
 	Vector2i size = _get_size(fd, p_size);
 
-	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), false);
+	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary());
 
+	Vector<Vector3> points;
+	Vector<int32_t> contours;
+	bool orientation;
 #ifdef MODULE_FREETYPE_ENABLED
 	int error = FT_Load_Glyph(fd->cache[size]->face, p_index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
-	ERR_FAIL_COND_V(error, false);
+	ERR_FAIL_COND_V(error, Dictionary());
 
-	r_points.clear();
-	r_contours.clear();
+	points.clear();
+	contours.clear();
 
-	real_t h = fd->cache[size]->ascent;
-	real_t scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale;
+	float h = fd->cache[size]->ascent;
+	float scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale;
 	if (fd->msdf) {
-		scale = scale * (real_t)p_size / (real_t)fd->msdf_source_size;
+		scale = scale * (float)p_size / (float)fd->msdf_source_size;
 	}
 	for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_points; i++) {
-		r_points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, h - fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i])));
+		points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, h - fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i])));
 	}
 	for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_contours; i++) {
-		r_contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]);
+		contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]);
 	}
-	r_orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
+	orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
 #else
-	return false;
+	return Dictionary();
 #endif
-	return true;
+
+	Dictionary out;
+	out["points"] = points;
+	out["contours"] = contours;
+	out["orientation"] = orientation;
+	return out;
 }
 
 Array TextServerAdvanced::font_get_kerning_list(RID p_font_rid, int p_size) const {
@@ -2433,7 +2457,7 @@ Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const V
 
 	if (kern.has(p_glyph_pair)) {
 		if (fd->msdf) {
-			return kern[p_glyph_pair] * (real_t)p_size / (real_t)fd->msdf_source_size;
+			return kern[p_glyph_pair] * (float)p_size / (float)fd->msdf_source_size;
 		} else {
 			return kern[p_glyph_pair];
 		}
@@ -2443,7 +2467,7 @@ Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const V
 			FT_Vector delta;
 			FT_Get_Kerning(fd->cache[size]->face, p_glyph_pair.x, p_glyph_pair.y, FT_KERNING_DEFAULT, &delta);
 			if (fd->msdf) {
-				return Vector2(delta.x, delta.y) * (real_t)p_size / (real_t)fd->msdf_source_size;
+				return Vector2(delta.x, delta.y) * (float)p_size / (float)fd->msdf_source_size;
 			} else {
 				return Vector2(delta.x, delta.y);
 			}
@@ -2582,8 +2606,8 @@ void TextServerAdvanced::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
 				RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
 				if (fd->msdf) {
 					Point2 cpos = p_pos;
-					cpos += gl.rect.position * (real_t)p_size / (real_t)fd->msdf_source_size;
-					Size2 csize = gl.rect.size * (real_t)p_size / (real_t)fd->msdf_source_size;
+					cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size;
+					Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
 					RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range);
 				} else {
 					Point2i cpos = p_pos;
@@ -2622,8 +2646,8 @@ void TextServerAdvanced::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
 				RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
 				if (fd->msdf) {
 					Point2 cpos = p_pos;
-					cpos += gl.rect.position * (real_t)p_size / (real_t)fd->msdf_source_size;
-					Size2 csize = gl.rect.size * (real_t)p_size / (real_t)fd->msdf_source_size;
+					cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size;
+					Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
 					RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range);
 				} else {
 					Point2i cpos = p_pos;
@@ -2694,7 +2718,7 @@ bool TextServerAdvanced::font_is_script_supported(RID p_font_rid, const String &
 	} else {
 		Vector2i size = _get_size(fd, 16);
 		ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), false);
-		return fd->supported_scripts.has(TS->name_to_tag(p_script));
+		return fd->supported_scripts.has(hb_tag_from_string(p_script.ascii().get_data(), -1));
 	}
 }
 
@@ -2754,11 +2778,11 @@ Dictionary TextServerAdvanced::font_supported_variation_list(RID p_font_rid) con
 	return fd->supported_varaitions;
 }
 
-real_t TextServerAdvanced::font_get_global_oversampling() const {
+float TextServerAdvanced::font_get_global_oversampling() const {
 	return oversampling;
 }
 
-void TextServerAdvanced::font_set_global_oversampling(real_t p_oversampling) {
+void TextServerAdvanced::font_set_global_oversampling(float p_oversampling) {
 	_THREAD_SAFE_METHOD_
 	if (oversampling != p_oversampling) {
 		oversampling = p_oversampling;
@@ -2904,7 +2928,7 @@ TextServer::Direction TextServerAdvanced::shaped_text_get_direction(RID p_shaped
 	return sd->direction;
 }
 
-void TextServerAdvanced::shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) {
+void TextServerAdvanced::shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) {
 	ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND(!sd);
 
@@ -2912,7 +2936,10 @@ void TextServerAdvanced::shaped_text_set_bidi_override(RID p_shaped, const Vecto
 	if (sd->parent != RID()) {
 		full_copy(sd);
 	}
-	sd->bidi_override = p_override;
+	sd->bidi_override.clear();
+	for (int i = 0; i < p_override.size(); i++) {
+		sd->bidi_override.push_back(p_override[i]);
+	}
 	invalidate(sd);
 }
 
@@ -3096,8 +3123,7 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
 				} 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) {
-						sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
-						sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
+						sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
 					} else {
 						sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
 						sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
@@ -3108,8 +3134,8 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
 		}
 
 		// Align embedded objects to baseline.
-		real_t full_ascent = sd->ascent;
-		real_t full_descent = sd->descent;
+		float full_ascent = sd->ascent;
+		float full_descent = sd->descent;
 		for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
 			if ((E.value.pos >= sd->start) && (E.value.pos < sd->end)) {
 				if (sd->orientation == ORIENTATION_HORIZONTAL) {
@@ -3283,8 +3309,7 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
 							} 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) {
-									new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
-									new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
+									new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
 								} else {
 									new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
 									new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
@@ -3299,8 +3324,8 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
 		}
 
 		// Align embedded objects to baseline.
-		real_t full_ascent = new_sd->ascent;
-		real_t full_descent = new_sd->descent;
+		float full_ascent = new_sd->ascent;
+		float full_descent = new_sd->descent;
 		for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : new_sd->objects) {
 			if ((E.value.pos >= new_sd->start) && (E.value.pos < new_sd->end)) {
 				if (sd->orientation == ORIENTATION_HORIZONTAL) {
@@ -3378,7 +3403,7 @@ RID TextServerAdvanced::shaped_text_get_parent(RID p_shaped) const {
 	return sd->parent;
 }
 
-real_t TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, real_t p_width, uint8_t /*JustificationFlag*/ p_jst_flags) {
+float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags) {
 	ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 
@@ -3419,7 +3444,7 @@ real_t TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, real_t p_width
 		}
 	}
 
-	real_t justification_width;
+	float justification_width;
 	if ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) == JUSTIFICATION_CONSTRAIN_ELLIPSIS) {
 		if (sd->overrun_trim_data.trim_pos >= 0) {
 			start_pos = sd->overrun_trim_data.trim_pos;
@@ -3459,7 +3484,7 @@ real_t TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, real_t p_width
 	}
 
 	if ((elongation_count > 0) && ((p_jst_flags & JUSTIFICATION_KASHIDA) == JUSTIFICATION_KASHIDA)) {
-		real_t delta_width_per_kashida = (p_width - justification_width) / elongation_count;
+		float delta_width_per_kashida = (p_width - justification_width) / elongation_count;
 		for (int i = start_pos; i <= end_pos; i++) {
 			Glyph &gl = sd->glyphs.write[i];
 			if (gl.count > 0) {
@@ -3474,15 +3499,15 @@ real_t TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, real_t p_width
 			}
 		}
 	}
-	real_t adv_remain = 0;
+	float adv_remain = 0;
 	if ((space_count > 0) && ((p_jst_flags & JUSTIFICATION_WORD_BOUND) == JUSTIFICATION_WORD_BOUND)) {
-		real_t delta_width_per_space = (p_width - justification_width) / space_count;
+		float delta_width_per_space = (p_width - justification_width) / space_count;
 		for (int i = start_pos; i <= end_pos; i++) {
 			Glyph &gl = sd->glyphs.write[i];
 			if (gl.count > 0) {
 				if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
-					real_t old_adv = gl.advance;
-					real_t new_advance;
+					float old_adv = gl.advance;
+					float new_advance;
 					if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
 						new_advance = MAX(gl.advance + delta_width_per_space, 0.f);
 					} else {
@@ -3514,7 +3539,7 @@ real_t TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, real_t p_width
 	return sd->width;
 }
 
-real_t TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<real_t> &p_tab_stops) {
+float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) {
 	ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 
@@ -3527,7 +3552,7 @@ real_t TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<real
 	}
 
 	int tab_index = 0;
-	real_t off = 0.f;
+	float off = 0.f;
 
 	int start, end, delta;
 	if (sd->para_direction == DIRECTION_LTR) {
@@ -3544,7 +3569,7 @@ real_t TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<real
 
 	for (int i = start; i != end; i += delta) {
 		if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
-			real_t tab_off = 0.f;
+			float tab_off = 0.f;
 			while (tab_off <= off) {
 				tab_off += p_tab_stops[tab_index];
 				tab_index++;
@@ -3552,7 +3577,7 @@ real_t TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<real
 					tab_index = 0;
 				}
 			}
-			real_t old_adv = gl[i].advance;
+			float old_adv = gl[i].advance;
 			gl[i].advance = tab_off - off;
 			sd->width += gl[i].advance - old_adv;
 			off = 0;
@@ -3564,7 +3589,7 @@ real_t TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<real
 	return 0.f;
 }
 
-void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, real_t p_width, uint8_t p_trim_flags) {
+void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint16_t p_trim_flags) {
 	ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped_line);
 	ERR_FAIL_COND_MSG(!sd, "ShapedTextDataAdvanced invalid.");
 
@@ -3607,7 +3632,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
 	}
 
 	int ell_min_characters = 6;
-	real_t width = sd->width;
+	float width = sd->width;
 
 	bool is_rtl = sd->direction == DIRECTION_RTL || (sd->direction == DIRECTION_AUTO && sd->para_direction == DIRECTION_RTL);
 
@@ -3663,7 +3688,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
 		if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) {
 			// Insert an additional space when cutting word bound for aesthetics.
 			if (cut_per_word && (ellipsis_pos > 0)) {
-				TextServer::Glyph gl;
+				Glyph gl;
 				gl.count = 1;
 				gl.advance = whitespace_adv.x;
 				gl.index = whitespace_gl_idx;
@@ -3674,7 +3699,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
 				sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
 			}
 			// Add ellipsis dots.
-			TextServer::Glyph gl;
+			Glyph gl;
 			gl.count = 1;
 			gl.repeat = 3;
 			gl.advance = dot_adv.x;
@@ -3691,12 +3716,36 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
 	}
 }
 
-TextServer::TrimData TextServerAdvanced::shaped_text_get_trim_data(RID p_shaped) const {
+int TextServerAdvanced::shaped_text_get_trim_pos(RID p_shaped) const {
+	ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+	ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid.");
+
+	MutexLock lock(sd->mutex);
+	return sd->overrun_trim_data.trim_pos;
+}
+
+int TextServerAdvanced::shaped_text_get_ellipsis_pos(RID p_shaped) const {
 	ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
-	ERR_FAIL_COND_V_MSG(!sd, TrimData(), "ShapedTextDataAdvanced invalid.");
+	ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid.");
 
 	MutexLock lock(sd->mutex);
-	return sd->overrun_trim_data;
+	return sd->overrun_trim_data.ellipsis_pos;
+}
+
+const Glyph *TextServerAdvanced::shaped_text_get_ellipsis_glyphs(RID p_shaped) const {
+	ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+	ERR_FAIL_COND_V_MSG(!sd, nullptr, "ShapedTextDataAdvanced invalid.");
+
+	MutexLock lock(sd->mutex);
+	return sd->overrun_trim_data.ellipsis_glyph_buf.ptr();
+}
+
+int TextServerAdvanced::shaped_text_get_ellipsis_glyph_count(RID p_shaped) const {
+	ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+	ERR_FAIL_COND_V_MSG(!sd, 0, "ShapedTextDataAdvanced invalid.");
+
+	MutexLock lock(sd->mutex);
+	return sd->overrun_trim_data.ellipsis_glyph_buf.size();
 }
 
 bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
@@ -3783,7 +3832,7 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
 					if (is_whitespace(c)) {
 						sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT;
 					} else {
-						TextServer::Glyph gl;
+						Glyph gl;
 						gl.start = sd_glyphs[i].start;
 						gl.end = sd_glyphs[i].end;
 						gl.count = 1;
@@ -3964,7 +4013,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
 							sd->glyphs.write[i].flags |= GRAPHEME_IS_ELONGATION;
 						} else {
 							if (sd->glyphs[i].font_rid != RID()) {
-								TextServer::Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size);
+								Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size);
 								if ((gl.flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {
 									gl.start = sd->glyphs[i].start;
 									gl.end = sd->glyphs[i].end;
@@ -3982,7 +4031,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
 							}
 						}
 					} else if (!is_whitespace(c)) {
-						TextServer::Glyph gl;
+						Glyph gl;
 						gl.start = sd->glyphs[i].start;
 						gl.end = sd->glyphs[i].end;
 						gl.count = 1;
@@ -4007,9 +4056,9 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
 	return sd->justification_ops_valid;
 }
 
-TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size) {
+Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size) {
 	hb_font_t *hb_font = _font_get_hb_handle(p_font, p_font_size);
-	ERR_FAIL_COND_V(hb_font == nullptr, TextServer::Glyph());
+	ERR_FAIL_COND_V(hb_font == nullptr, Glyph());
 
 	hb_buffer_clear_contents(p_sd->hb_buffer);
 	hb_buffer_set_direction(p_sd->hb_buffer, p_direction);
@@ -4024,7 +4073,7 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced
 	hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(p_sd->hb_buffer, &glyph_count);
 
 	// Process glyphs.
-	TextServer::Glyph gl;
+	Glyph gl;
 
 	if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
 		gl.flags |= TextServer::GRAPHEME_IS_RTL;
@@ -4034,7 +4083,7 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced
 	gl.font_size = p_font_size;
 
 	if (glyph_count > 0) {
-		real_t scale = font_get_scale(p_font, p_font_size);
+		float scale = font_get_scale(p_font, p_font_size);
 		if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
 			gl.advance = Math::round(glyph_pos[0].x_advance / (64.0 / scale));
 		} else {
@@ -4059,7 +4108,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
 		// Add fallback glyphs.
 		for (int i = p_start; i < p_end; i++) {
 			if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) {
-				TextServer::Glyph gl;
+				Glyph gl;
 				gl.start = i;
 				gl.end = i + 1;
 				gl.count = 1;
@@ -4071,8 +4120,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
 				}
 				if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
 					gl.advance = get_hex_code_box_size(fs, gl.index).x;
-					p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.75f));
-					p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.25f));
+					p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(fs, gl.index).y);
 				} else {
 					gl.advance = get_hex_code_box_size(fs, gl.index).y;
 					p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f));
@@ -4126,7 +4174,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
 
 	// Process glyphs.
 	if (glyph_count > 0) {
-		TextServer::Glyph *w = (TextServer::Glyph *)memalloc(glyph_count * sizeof(TextServer::Glyph));
+		Glyph *w = (Glyph *)memalloc(glyph_count * sizeof(Glyph));
 
 		int end = (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) ? p_end : 0;
 		uint32_t last_cluster_id = UINT32_MAX;
@@ -4155,8 +4203,8 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
 
 			last_cluster_id = glyph_info[i].cluster;
 
-			TextServer::Glyph &gl = w[i];
-			gl = TextServer::Glyph();
+			Glyph &gl = w[i];
+			gl = Glyph();
 
 			gl.start = glyph_info[i].cluster;
 			gl.end = end;
@@ -4171,7 +4219,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
 
 			gl.index = glyph_info[i].codepoint;
 			if (gl.index != 0) {
-				real_t scale = font_get_scale(f, fs);
+				float scale = font_get_scale(f, fs);
 				if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
 					gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / scale));
 				} else {
@@ -4411,8 +4459,8 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
 	}
 
 	// Align embedded objects to baseline.
-	real_t full_ascent = sd->ascent;
-	real_t full_descent = sd->descent;
+	float full_ascent = sd->ascent;
+	float full_descent = sd->descent;
 	for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
 		if (sd->orientation == ORIENTATION_HORIZONTAL) {
 			switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
@@ -4486,28 +4534,31 @@ bool TextServerAdvanced::shaped_text_is_ready(RID p_shaped) const {
 	return sd->valid;
 }
 
-Vector<TextServer::Glyph> TextServerAdvanced::shaped_text_get_glyphs(RID p_shaped) const {
+const Glyph *TextServerAdvanced::shaped_text_get_glyphs(RID p_shaped) const {
 	const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
-	ERR_FAIL_COND_V(!sd, Vector<TextServer::Glyph>());
+	ERR_FAIL_COND_V(!sd, nullptr);
 
 	MutexLock lock(sd->mutex);
 	if (!sd->valid) {
 		const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
 	}
-	return sd->glyphs;
+	return sd->glyphs.ptr();
 }
 
-Vector2i TextServerAdvanced::shaped_text_get_range(RID p_shaped) const {
+int TextServerAdvanced::shaped_text_get_glyph_count(RID p_shaped) const {
 	const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
-	ERR_FAIL_COND_V(!sd, Vector2i());
+	ERR_FAIL_COND_V(!sd, 0);
 
 	MutexLock lock(sd->mutex);
-	return Vector2(sd->start, sd->end);
+	if (!sd->valid) {
+		const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
+	}
+	return sd->glyphs.size();
 }
 
-Vector<TextServer::Glyph> TextServerAdvanced::shaped_text_sort_logical(RID p_shaped) {
+const Glyph *TextServerAdvanced::shaped_text_sort_logical(RID p_shaped) {
 	ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
-	ERR_FAIL_COND_V(!sd, Vector<TextServer::Glyph>());
+	ERR_FAIL_COND_V(!sd, nullptr);
 
 	MutexLock lock(sd->mutex);
 	if (!sd->valid) {
@@ -4516,11 +4567,19 @@ Vector<TextServer::Glyph> TextServerAdvanced::shaped_text_sort_logical(RID p_sha
 
 	if (!sd->sort_valid) {
 		sd->glyphs_logical = sd->glyphs;
-		sd->glyphs_logical.sort_custom<TextServer::GlyphCompare>();
+		sd->glyphs_logical.sort_custom<GlyphCompare>();
 		sd->sort_valid = true;
 	}
 
-	return sd->glyphs_logical;
+	return sd->glyphs_logical.ptr();
+}
+
+Vector2i TextServerAdvanced::shaped_text_get_range(RID p_shaped) const {
+	const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+	ERR_FAIL_COND_V(!sd, Vector2i());
+
+	MutexLock lock(sd->mutex);
+	return Vector2(sd->start, sd->end);
 }
 
 Array TextServerAdvanced::shaped_text_get_objects(RID p_shaped) const {
@@ -4563,7 +4622,7 @@ Size2 TextServerAdvanced::shaped_text_get_size(RID p_shaped) const {
 	}
 }
 
-real_t TextServerAdvanced::shaped_text_get_ascent(RID p_shaped) const {
+float TextServerAdvanced::shaped_text_get_ascent(RID p_shaped) const {
 	const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 
@@ -4574,7 +4633,7 @@ real_t TextServerAdvanced::shaped_text_get_ascent(RID p_shaped) const {
 	return sd->ascent;
 }
 
-real_t TextServerAdvanced::shaped_text_get_descent(RID p_shaped) const {
+float TextServerAdvanced::shaped_text_get_descent(RID p_shaped) const {
 	const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 
@@ -4585,7 +4644,7 @@ real_t TextServerAdvanced::shaped_text_get_descent(RID p_shaped) const {
 	return sd->descent;
 }
 
-real_t TextServerAdvanced::shaped_text_get_width(RID p_shaped) const {
+float TextServerAdvanced::shaped_text_get_width(RID p_shaped) const {
 	const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 
@@ -4596,7 +4655,7 @@ real_t TextServerAdvanced::shaped_text_get_width(RID p_shaped) const {
 	return (sd->text_trimmed ? sd->width_trimmed : sd->width);
 }
 
-real_t TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) const {
+float TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) const {
 	const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 
@@ -4608,7 +4667,7 @@ real_t TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) cons
 	return sd->upos;
 }
 
-real_t TextServerAdvanced::shaped_text_get_underline_thickness(RID p_shaped) const {
+float TextServerAdvanced::shaped_text_get_underline_thickness(RID p_shaped) const {
 	const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 
@@ -4752,15 +4811,6 @@ String TextServerAdvanced::percent_sign(const String &p_language) const {
 	return "%";
 }
 
-TextServer *TextServerAdvanced::create_func(Error &r_error, void *p_user_data) {
-	r_error = OK;
-	return memnew(TextServerAdvanced());
-}
-
-void TextServerAdvanced::register_server() {
-	TextServerManager::register_create_function(interface_name, interface_features, create_func, nullptr);
-}
-
 TextServerAdvanced::TextServerAdvanced() {
 	_insert_num_systems_lang();
 	_insert_feature_sets();

+ 47 - 47
modules/text_server_adv/text_server_adv.h

@@ -115,12 +115,12 @@ class TextServerAdvanced : public TextServer {
 	};
 
 	struct FontDataForSizeAdvanced {
-		real_t ascent = 0.f;
-		real_t descent = 0.f;
-		real_t underline_position = 0.f;
-		real_t underline_thickness = 0.f;
-		real_t scale = 1.f;
-		real_t oversampling = 1.f;
+		float ascent = 0.f;
+		float descent = 0.f;
+		float underline_position = 0.f;
+		float underline_thickness = 0.f;
+		float scale = 1.f;
+		float oversampling = 1.f;
 
 		int spacing_glyph = 0;
 		int spacing_space = 0;
@@ -161,7 +161,7 @@ class TextServerAdvanced : public TextServer {
 		bool force_autohinter = false;
 		TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
 		Dictionary variation_coordinates;
-		real_t oversampling = 0.f;
+		float oversampling = 0.f;
 
 		Map<Vector2i, FontDataForSizeAdvanced *> cache;
 
@@ -245,14 +245,14 @@ class TextServerAdvanced : public TextServer {
 
 	// Common data.
 
-	real_t oversampling = 1.f;
+	float oversampling = 1.f;
 	mutable RID_PtrOwner<FontDataAdvanced> font_owner;
 	mutable RID_PtrOwner<ShapedTextDataAdvanced> shaped_owner;
 
 	int _convert_pos(const ShapedTextDataAdvanced *p_sd, int p_pos) const;
 	int _convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int p_pos) const;
 	void _shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_start, int32_t p_end, hb_script_t p_script, hb_direction_t p_direction, Vector<RID> p_fonts, int p_span, int p_fb_index);
-	TextServer::Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size);
+	Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size);
 
 	// HarfBuzz bitmap font interface.
 
@@ -284,20 +284,19 @@ protected:
 	void invalidate(ShapedTextDataAdvanced *p_shaped);
 
 public:
-	virtual bool has_feature(Feature p_feature) override;
+	virtual bool has_feature(Feature p_feature) const override;
 	virtual String get_name() const override;
+	virtual uint32_t get_features() const override;
 
 	virtual void free(RID p_rid) override;
 	virtual bool has(RID p_rid) override;
 	virtual bool load_support_data(const String &p_filename) override;
 
-#ifdef TOOLS_ENABLED
-	virtual String get_support_data_filename() override { return _MKSTR(ICU_DATA_NAME); };
-	virtual String get_support_data_info() override { return String("ICU break iteration data (") + _MKSTR(ICU_DATA_NAME) + String(")."); };
-	virtual bool save_support_data(const String &p_filename) override;
-#endif
+	virtual String get_support_data_filename() const override;
+	virtual String get_support_data_info() const override;
+	virtual bool save_support_data(const String &p_filename) const override;
 
-	virtual bool is_locale_right_to_left(const String &p_locale) override;
+	virtual bool is_locale_right_to_left(const String &p_locale) const override;
 
 	virtual int32_t name_to_tag(const String &p_name) const override;
 	virtual String tag_to_name(int32_t p_tag) const override;
@@ -332,8 +331,8 @@ public:
 	virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) override;
 	virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const override;
 
-	virtual void font_set_oversampling(RID p_font_rid, real_t p_oversampling) override;
-	virtual real_t font_get_oversampling(RID p_font_rid) const override;
+	virtual void font_set_oversampling(RID p_font_rid, float p_oversampling) override;
+	virtual float font_get_oversampling(RID p_font_rid) const override;
 
 	virtual Array font_get_size_cache_list(RID p_font_rid) const override;
 	virtual void font_clear_size_cache(RID p_font_rid) override;
@@ -341,20 +340,20 @@ public:
 
 	hb_font_t *_font_get_hb_handle(RID p_font, int p_font_size) const;
 
-	virtual void font_set_ascent(RID p_font_rid, int p_size, real_t p_ascent) override;
-	virtual real_t font_get_ascent(RID p_font_rid, int p_size) const override;
+	virtual void font_set_ascent(RID p_font_rid, int p_size, float p_ascent) override;
+	virtual float font_get_ascent(RID p_font_rid, int p_size) const override;
 
-	virtual void font_set_descent(RID p_font_rid, int p_size, real_t p_descent) override;
-	virtual real_t font_get_descent(RID p_font_rid, int p_size) const override;
+	virtual void font_set_descent(RID p_font_rid, int p_size, float p_descent) override;
+	virtual float font_get_descent(RID p_font_rid, int p_size) const override;
 
-	virtual void font_set_underline_position(RID p_font_rid, int p_size, real_t p_underline_position) override;
-	virtual real_t font_get_underline_position(RID p_font_rid, int p_size) const override;
+	virtual void font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) override;
+	virtual float font_get_underline_position(RID p_font_rid, int p_size) const override;
 
-	virtual void font_set_underline_thickness(RID p_font_rid, int p_size, real_t p_underline_thickness) override;
-	virtual real_t font_get_underline_thickness(RID p_font_rid, int p_size) const override;
+	virtual void font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) override;
+	virtual float font_get_underline_thickness(RID p_font_rid, int p_size) const override;
 
-	virtual void font_set_scale(RID p_font_rid, int p_size, real_t p_scale) override;
-	virtual real_t font_get_scale(RID p_font_rid, int p_size) const override;
+	virtual void font_set_scale(RID p_font_rid, int p_size, float p_scale) override;
+	virtual float font_get_scale(RID p_font_rid, int p_size) const override;
 
 	virtual void font_set_spacing(RID p_font_rid, int p_size, SpacingType p_spacing, int p_value) override;
 	virtual int font_get_spacing(RID p_font_rid, int p_size, SpacingType p_spacing) const override;
@@ -388,7 +387,7 @@ public:
 	virtual int font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
 	virtual void font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) override;
 
-	virtual bool font_get_glyph_contours(RID p_font, int p_size, int32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
+	virtual Dictionary font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const override;
 
 	virtual Array font_get_kerning_list(RID p_font_rid, int p_size) const override;
 	virtual void font_clear_kerning_map(RID p_font_rid, int p_size) override;
@@ -423,8 +422,8 @@ public:
 	virtual Dictionary font_supported_feature_list(RID p_font_rid) const override;
 	virtual Dictionary font_supported_variation_list(RID p_font_rid) const override;
 
-	virtual real_t font_get_global_oversampling() const override;
-	virtual void font_set_global_oversampling(real_t p_oversampling) override;
+	virtual float font_get_global_oversampling() const override;
+	virtual void font_set_global_oversampling(float p_oversampling) override;
 
 	/* Shaped text buffer interface */
 
@@ -435,7 +434,7 @@ public:
 	virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override;
 	virtual Direction shaped_text_get_direction(RID p_shaped) const override;
 
-	virtual void shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) override;
+	virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override;
 
 	virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
 	virtual Orientation shaped_text_get_orientation(RID p_shaped) const override;
@@ -453,41 +452,42 @@ public:
 	virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
 	virtual RID shaped_text_get_parent(RID p_shaped) const override;
 
-	virtual real_t shaped_text_fit_to_width(RID p_shaped, real_t p_width, uint8_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
-	virtual real_t shaped_text_tab_align(RID p_shaped, const Vector<real_t> &p_tab_stops) override;
+	virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
+	virtual float shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) override;
 
 	virtual bool shaped_text_shape(RID p_shaped) override;
 	virtual bool shaped_text_update_breaks(RID p_shaped) override;
 	virtual bool shaped_text_update_justification_ops(RID p_shaped) override;
 
-	virtual void shaped_text_overrun_trim_to_width(RID p_shaped, real_t p_width, uint8_t p_trim_flags) override;
-	virtual TrimData shaped_text_get_trim_data(RID p_shaped) const override;
+	virtual int shaped_text_get_trim_pos(RID p_shaped) const override;
+	virtual int shaped_text_get_ellipsis_pos(RID p_shaped) const override;
+	virtual const Glyph *shaped_text_get_ellipsis_glyphs(RID p_shaped) const override;
+	virtual int shaped_text_get_ellipsis_glyph_count(RID p_shaped) const override;
+
+	virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint16_t p_trim_flags) override;
 
 	virtual bool shaped_text_is_ready(RID p_shaped) const override;
 
-	virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const override;
+	virtual const Glyph *shaped_text_get_glyphs(RID p_shaped) const override;
+	virtual const Glyph *shaped_text_sort_logical(RID p_shaped) override;
+	virtual int shaped_text_get_glyph_count(RID p_shaped) const override;
 
 	virtual Vector2i shaped_text_get_range(RID p_shaped) const override;
 
-	virtual Vector<Glyph> shaped_text_sort_logical(RID p_shaped) override;
-
 	virtual Array shaped_text_get_objects(RID p_shaped) const override;
 	virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const override;
 
 	virtual Size2 shaped_text_get_size(RID p_shaped) const override;
-	virtual real_t shaped_text_get_ascent(RID p_shaped) const override;
-	virtual real_t shaped_text_get_descent(RID p_shaped) const override;
-	virtual real_t shaped_text_get_width(RID p_shaped) const override;
-	virtual real_t shaped_text_get_underline_position(RID p_shaped) const override;
-	virtual real_t shaped_text_get_underline_thickness(RID p_shaped) const override;
+	virtual float shaped_text_get_ascent(RID p_shaped) const override;
+	virtual float shaped_text_get_descent(RID p_shaped) const override;
+	virtual float shaped_text_get_width(RID p_shaped) const override;
+	virtual float shaped_text_get_underline_position(RID p_shaped) const override;
+	virtual float shaped_text_get_underline_thickness(RID p_shaped) const override;
 
 	virtual String format_number(const String &p_string, const String &p_language = "") const override;
 	virtual String parse_number(const String &p_string, const String &p_language = "") const override;
 	virtual String percent_sign(const String &p_language = "") const override;
 
-	static TextServer *create_func(Error &r_error, void *p_user_data);
-	static void register_server();
-
 	TextServerAdvanced();
 	~TextServerAdvanced();
 };

+ 10 - 0
modules/text_server_fb/config.py

@@ -9,3 +9,13 @@ def configure(env):
 def is_enabled():
     # The module is disabled by default. Use module_text_server_fb_enabled=yes to enable it.
     return False
+
+
+def get_doc_classes():
+    return [
+        "TextServerFallback",
+    ]
+
+
+def get_doc_path():
+    return "doc_classes"

+ 10 - 0
modules/text_server_fb/doc_classes/TextServerFallback.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="TextServerFallback" inherits="TextServer" version="4.0">
+	<brief_description>
+		Fallback implementation of the Text Server, without BiDi and complex text layout support.
+	</brief_description>
+	<description>
+	</description>
+	<tutorials>
+	</tutorials>
+</class>

+ 6 - 1
modules/text_server_fb/register_types.cpp

@@ -33,7 +33,12 @@
 #include "text_server_fb.h"
 
 void preregister_text_server_fb_types() {
-	TextServerFallback::register_server();
+	GDREGISTER_CLASS(TextServerFallback);
+	if (TextServerManager::get_singleton()) {
+		Ref<TextServerFallback> ts;
+		ts.instantiate();
+		TextServerManager::get_singleton()->add_interface(ts);
+	}
 }
 
 void register_text_server_fb_types() {

+ 138 - 107
modules/text_server_fb/text_server_fb.cpp

@@ -69,7 +69,7 @@ _FORCE_INLINE_ bool is_underscore(char32_t p_char) {
 String TextServerFallback::interface_name = "Fallback";
 uint32_t TextServerFallback::interface_features = 0; // Nothing is supported.
 
-bool TextServerFallback::has_feature(Feature p_feature) {
+bool TextServerFallback::has_feature(Feature p_feature) const {
 	return (interface_features & p_feature) == p_feature;
 }
 
@@ -77,6 +77,10 @@ String TextServerFallback::get_name() const {
 	return interface_name;
 }
 
+uint32_t TextServerFallback::get_features() const {
+	return interface_features;
+}
+
 void TextServerFallback::free(RID p_rid) {
 	_THREAD_SAFE_METHOD_
 	if (font_owner.owns(p_rid)) {
@@ -99,15 +103,11 @@ bool TextServerFallback::load_support_data(const String &p_filename) {
 	return false; // No extra data used.
 }
 
-#ifdef TOOLS_ENABLED
-
-bool TextServerFallback::save_support_data(const String &p_filename) {
+bool TextServerFallback::save_support_data(const String &p_filename) const {
 	return false; // No extra data used.
 }
 
-#endif
-
-bool TextServerFallback::is_locale_right_to_left(const String &p_locale) {
+bool TextServerFallback::is_locale_right_to_left(const String &p_locale) const {
 	return false; // No RTL support.
 }
 
@@ -420,7 +420,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
 		FontTexture &tex = p_data->textures.write[tex_pos.index];
 
 		edgeColoringSimple(shape, 3.0); // Max. angle.
-		msdfgen::Bitmap<real_t, 4> image(w, h); // Texture size.
+		msdfgen::Bitmap<float, 4> image(w, h); // Texture size.
 		//msdfgen::generateMTSDF(image, shape, p_pixel_range, 1.0, msdfgen::Vector2(-bounds.l, -bounds.b)); // Range, scale, translation.
 
 		DistancePixelConversion distancePixelConversion(p_pixel_range);
@@ -620,7 +620,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontDataFallback *p_font_d
 		int error = FT_Load_Glyph(fd->face, glyph_index, flags);
 		if (error) {
 			fd->glyph_map[p_glyph] = FontGlyph();
-			ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph.");
+			return false;
 		}
 
 		if (!outline) {
@@ -714,7 +714,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
 			fd->oversampling = 1.0f;
 			fd->size.x = p_font_data->msdf_source_size;
 		} else if (p_font_data->oversampling <= 0.0f) {
-			fd->oversampling = TS->font_get_global_oversampling();
+			fd->oversampling = font_get_global_oversampling();
 		} else {
 			fd->oversampling = p_font_data->oversampling;
 		}
@@ -722,13 +722,13 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
 		if (FT_HAS_COLOR(fd->face) && fd->face->num_fixed_sizes > 0) {
 			int best_match = 0;
 			int diff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[0].width));
-			fd->scale = real_t(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width;
+			fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width;
 			for (int i = 1; i < fd->face->num_fixed_sizes; i++) {
 				int ndiff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[i].width));
 				if (ndiff < diff) {
 					best_match = i;
 					diff = ndiff;
-					fd->scale = real_t(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width;
+					fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width;
 				}
 			}
 			FT_Select_Size(fd->face, best_match);
@@ -769,7 +769,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
 			for (FT_UInt i = 0; i < amaster->num_axis; i++) {
 				// Reset to default.
 				int32_t var_tag = amaster->axis[i].tag;
-				real_t var_value = (double)amaster->axis[i].def / 65536.f;
+				float var_value = (double)amaster->axis[i].def / 65536.f;
 				coords.write[i] = amaster->axis[i].def;
 
 				if (p_font_data->variation_coordinates.has(var_tag)) {
@@ -983,7 +983,7 @@ Dictionary TextServerFallback::font_get_variation_coordinates(RID p_font_rid) co
 	return fd->variation_coordinates;
 }
 
-void TextServerFallback::font_set_oversampling(RID p_font_rid, real_t p_oversampling) {
+void TextServerFallback::font_set_oversampling(RID p_font_rid, float p_oversampling) {
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 
@@ -994,7 +994,7 @@ void TextServerFallback::font_set_oversampling(RID p_font_rid, real_t p_oversamp
 	}
 }
 
-real_t TextServerFallback::font_get_oversampling(RID p_font_rid) const {
+float TextServerFallback::font_get_oversampling(RID p_font_rid) const {
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 
@@ -1036,7 +1036,7 @@ void TextServerFallback::font_remove_size_cache(RID p_font_rid, const Vector2i &
 	}
 }
 
-void TextServerFallback::font_set_ascent(RID p_font_rid, int p_size, real_t p_ascent) {
+void TextServerFallback::font_set_ascent(RID p_font_rid, int p_size, float p_ascent) {
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 
@@ -1047,7 +1047,7 @@ void TextServerFallback::font_set_ascent(RID p_font_rid, int p_size, real_t p_as
 	fd->cache[size]->ascent = p_ascent;
 }
 
-real_t TextServerFallback::font_get_ascent(RID p_font_rid, int p_size) const {
+float TextServerFallback::font_get_ascent(RID p_font_rid, int p_size) const {
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 
@@ -1057,13 +1057,13 @@ real_t TextServerFallback::font_get_ascent(RID p_font_rid, int p_size) const {
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 	if (fd->msdf) {
-		return fd->cache[size]->ascent * (real_t)p_size / (real_t)fd->msdf_source_size;
+		return fd->cache[size]->ascent * (float)p_size / (float)fd->msdf_source_size;
 	} else {
 		return fd->cache[size]->ascent;
 	}
 }
 
-void TextServerFallback::font_set_descent(RID p_font_rid, int p_size, real_t p_descent) {
+void TextServerFallback::font_set_descent(RID p_font_rid, int p_size, float p_descent) {
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 
@@ -1073,7 +1073,7 @@ void TextServerFallback::font_set_descent(RID p_font_rid, int p_size, real_t p_d
 	fd->cache[size]->descent = p_descent;
 }
 
-real_t TextServerFallback::font_get_descent(RID p_font_rid, int p_size) const {
+float TextServerFallback::font_get_descent(RID p_font_rid, int p_size) const {
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 
@@ -1083,13 +1083,13 @@ real_t TextServerFallback::font_get_descent(RID p_font_rid, int p_size) const {
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 	if (fd->msdf) {
-		return fd->cache[size]->descent * (real_t)p_size / (real_t)fd->msdf_source_size;
+		return fd->cache[size]->descent * (float)p_size / (float)fd->msdf_source_size;
 	} else {
 		return fd->cache[size]->descent;
 	}
 }
 
-void TextServerFallback::font_set_underline_position(RID p_font_rid, int p_size, real_t p_underline_position) {
+void TextServerFallback::font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) {
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 
@@ -1100,7 +1100,7 @@ void TextServerFallback::font_set_underline_position(RID p_font_rid, int p_size,
 	fd->cache[size]->underline_position = p_underline_position;
 }
 
-real_t TextServerFallback::font_get_underline_position(RID p_font_rid, int p_size) const {
+float TextServerFallback::font_get_underline_position(RID p_font_rid, int p_size) const {
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 
@@ -1110,13 +1110,13 @@ real_t TextServerFallback::font_get_underline_position(RID p_font_rid, int p_siz
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 	if (fd->msdf) {
-		return fd->cache[size]->underline_position * (real_t)p_size / (real_t)fd->msdf_source_size;
+		return fd->cache[size]->underline_position * (float)p_size / (float)fd->msdf_source_size;
 	} else {
 		return fd->cache[size]->underline_position;
 	}
 }
 
-void TextServerFallback::font_set_underline_thickness(RID p_font_rid, int p_size, real_t p_underline_thickness) {
+void TextServerFallback::font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) {
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 
@@ -1127,7 +1127,7 @@ void TextServerFallback::font_set_underline_thickness(RID p_font_rid, int p_size
 	fd->cache[size]->underline_thickness = p_underline_thickness;
 }
 
-real_t TextServerFallback::font_get_underline_thickness(RID p_font_rid, int p_size) const {
+float TextServerFallback::font_get_underline_thickness(RID p_font_rid, int p_size) const {
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 
@@ -1137,13 +1137,13 @@ real_t TextServerFallback::font_get_underline_thickness(RID p_font_rid, int p_si
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 	if (fd->msdf) {
-		return fd->cache[size]->underline_thickness * (real_t)p_size / (real_t)fd->msdf_source_size;
+		return fd->cache[size]->underline_thickness * (float)p_size / (float)fd->msdf_source_size;
 	} else {
 		return fd->cache[size]->underline_thickness;
 	}
 }
 
-void TextServerFallback::font_set_scale(RID p_font_rid, int p_size, real_t p_scale) {
+void TextServerFallback::font_set_scale(RID p_font_rid, int p_size, float p_scale) {
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 
@@ -1154,7 +1154,7 @@ void TextServerFallback::font_set_scale(RID p_font_rid, int p_size, real_t p_sca
 	fd->cache[size]->scale = p_scale;
 }
 
-real_t TextServerFallback::font_get_scale(RID p_font_rid, int p_size) const {
+float TextServerFallback::font_get_scale(RID p_font_rid, int p_size) const {
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 
@@ -1164,7 +1164,7 @@ real_t TextServerFallback::font_get_scale(RID p_font_rid, int p_size) const {
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 	if (fd->msdf) {
-		return fd->cache[size]->scale * (real_t)p_size / (real_t)fd->msdf_source_size;
+		return fd->cache[size]->scale * (float)p_size / (float)fd->msdf_source_size;
 	} else {
 		return fd->cache[size]->scale / fd->cache[size]->oversampling;
 	}
@@ -1203,14 +1203,14 @@ int TextServerFallback::font_get_spacing(RID p_font_rid, int p_size, TextServer:
 	switch (p_spacing) {
 		case TextServer::SPACING_GLYPH: {
 			if (fd->msdf) {
-				return fd->cache[size]->spacing_glyph * (real_t)p_size / (real_t)fd->msdf_source_size;
+				return fd->cache[size]->spacing_glyph * (float)p_size / (float)fd->msdf_source_size;
 			} else {
 				return fd->cache[size]->spacing_glyph;
 			}
 		} break;
 		case TextServer::SPACING_SPACE: {
 			if (fd->msdf) {
-				return fd->cache[size]->spacing_space * (real_t)p_size / (real_t)fd->msdf_source_size;
+				return fd->cache[size]->spacing_space * (float)p_size / (float)fd->msdf_source_size;
 			} else {
 				return fd->cache[size]->spacing_space;
 			}
@@ -1379,7 +1379,7 @@ Vector2 TextServerFallback::font_get_glyph_advance(RID p_font_rid, int p_size, i
 	const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
 
 	if (fd->msdf) {
-		return gl[p_glyph].advance * (real_t)p_size / (real_t)fd->msdf_source_size;
+		return gl[p_glyph].advance * (float)p_size / (float)fd->msdf_source_size;
 	} else {
 		return gl[p_glyph].advance;
 	}
@@ -1415,7 +1415,7 @@ Vector2 TextServerFallback::font_get_glyph_offset(RID p_font_rid, const Vector2i
 	const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
 
 	if (fd->msdf) {
-		return gl[p_glyph].rect.position * (real_t)p_size.x / (real_t)fd->msdf_source_size;
+		return gl[p_glyph].rect.position * (float)p_size.x / (float)fd->msdf_source_size;
 	} else {
 		return gl[p_glyph].rect.position;
 	}
@@ -1451,7 +1451,7 @@ Vector2 TextServerFallback::font_get_glyph_size(RID p_font_rid, const Vector2i &
 	const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
 
 	if (fd->msdf) {
-		return gl[p_glyph].rect.size * (real_t)p_size.x / (real_t)fd->msdf_source_size;
+		return gl[p_glyph].rect.size * (float)p_size.x / (float)fd->msdf_source_size;
 	} else {
 		return gl[p_glyph].rect.size;
 	}
@@ -1534,38 +1534,46 @@ void TextServerFallback::font_set_glyph_texture_idx(RID p_font_rid, const Vector
 	gl[p_glyph].found = true;
 }
 
-bool TextServerFallback::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
+Dictionary TextServerFallback::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index) const {
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
-	ERR_FAIL_COND_V(!fd, false);
+	ERR_FAIL_COND_V(!fd, Dictionary());
 
 	MutexLock lock(fd->mutex);
 	Vector2i size = _get_size(fd, p_size);
 
-	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), false);
+	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary());
 
+	Vector<Vector3> points;
+	Vector<int32_t> contours;
+	bool orientation;
 #ifdef MODULE_FREETYPE_ENABLED
 	int error = FT_Load_Glyph(fd->cache[size]->face, FT_Get_Char_Index(fd->cache[size]->face, p_index), FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
-	ERR_FAIL_COND_V(error, false);
+	ERR_FAIL_COND_V(error, Dictionary());
 
-	r_points.clear();
-	r_contours.clear();
+	points.clear();
+	contours.clear();
 
-	real_t h = fd->cache[size]->ascent;
-	real_t scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale;
+	float h = fd->cache[size]->ascent;
+	float scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale;
 	if (fd->msdf) {
-		scale = scale * (real_t)p_size / (real_t)fd->msdf_source_size;
+		scale = scale * (float)p_size / (float)fd->msdf_source_size;
 	}
 	for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_points; i++) {
-		r_points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, h - fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i])));
+		points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, h - fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i])));
 	}
 	for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_contours; i++) {
-		r_contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]);
+		contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]);
 	}
-	r_orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
+	orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
 #else
-	return false;
+	return Dictionary();
 #endif
-	return true;
+
+	Dictionary out;
+	out["points"] = points;
+	out["contours"] = contours;
+	out["orientation"] = orientation;
+	return out;
 }
 
 Array TextServerFallback::font_get_kerning_list(RID p_font_rid, int p_size) const {
@@ -1630,7 +1638,7 @@ Vector2 TextServerFallback::font_get_kerning(RID p_font_rid, int p_size, const V
 
 	if (kern.has(p_glyph_pair)) {
 		if (fd->msdf) {
-			return kern[p_glyph_pair] * (real_t)p_size / (real_t)fd->msdf_source_size;
+			return kern[p_glyph_pair] * (float)p_size / (float)fd->msdf_source_size;
 		} else {
 			return kern[p_glyph_pair];
 		}
@@ -1642,7 +1650,7 @@ Vector2 TextServerFallback::font_get_kerning(RID p_font_rid, int p_size, const V
 			int32_t glyph_b = FT_Get_Char_Index(fd->cache[size]->face, p_glyph_pair.y);
 			FT_Get_Kerning(fd->cache[size]->face, glyph_a, glyph_b, FT_KERNING_DEFAULT, &delta);
 			if (fd->msdf) {
-				return Vector2(delta.x, delta.y) * (real_t)p_size / (real_t)fd->msdf_source_size;
+				return Vector2(delta.x, delta.y) * (float)p_size / (float)fd->msdf_source_size;
 			} else {
 				return Vector2(delta.x, delta.y);
 			}
@@ -1756,8 +1764,8 @@ void TextServerFallback::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
 				RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
 				if (fd->msdf) {
 					Point2 cpos = p_pos;
-					cpos += gl.rect.position * (real_t)p_size / (real_t)fd->msdf_source_size;
-					Size2 csize = gl.rect.size * (real_t)p_size / (real_t)fd->msdf_source_size;
+					cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size;
+					Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
 					RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range);
 				} else {
 					Point2i cpos = p_pos;
@@ -1796,8 +1804,8 @@ void TextServerFallback::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
 				RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
 				if (fd->msdf) {
 					Point2 cpos = p_pos;
-					cpos += gl.rect.position * (real_t)p_size / (real_t)fd->msdf_source_size;
-					Size2 csize = gl.rect.size * (real_t)p_size / (real_t)fd->msdf_source_size;
+					cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size;
+					Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
 					RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range);
 				} else {
 					Point2i cpos = p_pos;
@@ -1922,11 +1930,11 @@ Dictionary TextServerFallback::font_supported_variation_list(RID p_font_rid) con
 	return fd->supported_varaitions;
 }
 
-real_t TextServerFallback::font_get_global_oversampling() const {
+float TextServerFallback::font_get_global_oversampling() const {
 	return oversampling;
 }
 
-void TextServerFallback::font_set_global_oversampling(real_t p_oversampling) {
+void TextServerFallback::font_set_global_oversampling(float p_oversampling) {
 	_THREAD_SAFE_METHOD_
 	if (oversampling != p_oversampling) {
 		oversampling = p_oversampling;
@@ -2037,7 +2045,7 @@ void TextServerFallback::shaped_text_set_orientation(RID p_shaped, TextServer::O
 	}
 }
 
-void TextServerFallback::shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) {
+void TextServerFallback::shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) {
 	// No BiDi support, ignore.
 }
 
@@ -2223,8 +2231,7 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
 				} 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) {
-						sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
-						sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
+						sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
 					} else {
 						sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
 						sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
@@ -2235,8 +2242,8 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
 		}
 
 		// Align embedded objects to baseline.
-		real_t full_ascent = sd->ascent;
-		real_t full_descent = sd->descent;
+		float full_ascent = sd->ascent;
+		float full_descent = sd->descent;
 		for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
 			if ((E.value.pos >= sd->start) && (E.value.pos < sd->end)) {
 				if (sd->orientation == ORIENTATION_HORIZONTAL) {
@@ -2373,8 +2380,7 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
 					} 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) {
-							new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
-							new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
+							new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
 						} else {
 							new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
 							new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
@@ -2387,8 +2393,8 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
 		}
 
 		// Align embedded objects to baseline.
-		real_t full_ascent = new_sd->ascent;
-		real_t full_descent = new_sd->descent;
+		float full_ascent = new_sd->ascent;
+		float full_descent = new_sd->descent;
 		for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : new_sd->objects) {
 			if ((E.value.pos >= new_sd->start) && (E.value.pos < new_sd->end)) {
 				if (sd->orientation == ORIENTATION_HORIZONTAL) {
@@ -2466,7 +2472,7 @@ RID TextServerFallback::shaped_text_get_parent(RID p_shaped) const {
 	return sd->parent;
 }
 
-real_t TextServerFallback::shaped_text_fit_to_width(RID p_shaped, real_t p_width, uint8_t /*JustificationFlag*/ p_jst_flags) {
+float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags) {
 	ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 
@@ -2530,12 +2536,12 @@ real_t TextServerFallback::shaped_text_fit_to_width(RID p_shaped, real_t p_width
 	}
 
 	if ((space_count > 0) && ((p_jst_flags & JUSTIFICATION_WORD_BOUND) == JUSTIFICATION_WORD_BOUND)) {
-		real_t delta_width_per_space = (p_width - sd->width) / space_count;
+		float delta_width_per_space = (p_width - sd->width) / space_count;
 		for (int i = start_pos; i <= end_pos; i++) {
 			Glyph &gl = sd->glyphs.write[i];
 			if (gl.count > 0) {
 				if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
-					real_t old_adv = gl.advance;
+					float old_adv = gl.advance;
 					gl.advance = MAX(gl.advance + delta_width_per_space, Math::round(0.1 * gl.font_size));
 					sd->width += (gl.advance - old_adv);
 				}
@@ -2546,7 +2552,7 @@ real_t TextServerFallback::shaped_text_fit_to_width(RID p_shaped, real_t p_width
 	return sd->width;
 }
 
-real_t TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<real_t> &p_tab_stops) {
+float TextServerFallback::shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) {
 	ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 
@@ -2559,7 +2565,7 @@ real_t TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<real
 	}
 
 	int tab_index = 0;
-	real_t off = 0.f;
+	float off = 0.f;
 
 	int start, end, delta;
 	if (sd->para_direction == DIRECTION_LTR) {
@@ -2576,7 +2582,7 @@ real_t TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<real
 
 	for (int i = start; i != end; i += delta) {
 		if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
-			real_t tab_off = 0.f;
+			float tab_off = 0.f;
 			while (tab_off <= off) {
 				tab_off += p_tab_stops[tab_index];
 				tab_index++;
@@ -2584,7 +2590,7 @@ real_t TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<real
 					tab_index = 0;
 				}
 			}
-			real_t old_adv = gl[i].advance;
+			float old_adv = gl[i].advance;
 			gl[i].advance = tab_off - off;
 			sd->width += gl[i].advance - old_adv;
 			off = 0;
@@ -2653,7 +2659,7 @@ bool TextServerFallback::shaped_text_update_justification_ops(RID p_shaped) {
 	return true;
 }
 
-void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, real_t p_width, uint8_t p_trim_flags) {
+void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint16_t p_trim_flags) {
 	ShapedTextData *sd = shaped_owner.get_or_null(p_shaped_line);
 	ERR_FAIL_COND_MSG(!sd, "ShapedTextDataFallback invalid.");
 
@@ -2696,7 +2702,7 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
 	}
 
 	int ell_min_characters = 6;
-	real_t width = sd->width;
+	float width = sd->width;
 
 	int trim_pos = 0;
 	int ellipsis_pos = (enforce_ellipsis) ? 0 : -1;
@@ -2742,7 +2748,7 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
 		if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) {
 			// Insert an additional space when cutting word bound for aesthetics.
 			if (cut_per_word && (ellipsis_pos > 0)) {
-				TextServer::Glyph gl;
+				Glyph gl;
 				gl.count = 1;
 				gl.advance = whitespace_adv.x;
 				gl.index = whitespace_gl_idx;
@@ -2753,7 +2759,7 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
 				sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
 			}
 			// Add ellipsis dots.
-			TextServer::Glyph gl;
+			Glyph gl;
 			gl.count = 1;
 			gl.repeat = 3;
 			gl.advance = dot_adv.x;
@@ -2770,12 +2776,36 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
 	}
 }
 
-TextServer::TrimData TextServerFallback::shaped_text_get_trim_data(RID p_shaped) const {
+int TextServerFallback::shaped_text_get_trim_pos(RID p_shaped) const {
+	ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
+	ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextData invalid.");
+
+	MutexLock lock(sd->mutex);
+	return sd->overrun_trim_data.trim_pos;
+}
+
+int TextServerFallback::shaped_text_get_ellipsis_pos(RID p_shaped) const {
+	ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
+	ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextData invalid.");
+
+	MutexLock lock(sd->mutex);
+	return sd->overrun_trim_data.ellipsis_pos;
+}
+
+const Glyph *TextServerFallback::shaped_text_get_ellipsis_glyphs(RID p_shaped) const {
+	ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
+	ERR_FAIL_COND_V_MSG(!sd, nullptr, "ShapedTextData invalid.");
+
+	MutexLock lock(sd->mutex);
+	return sd->overrun_trim_data.ellipsis_glyph_buf.ptr();
+}
+
+int TextServerFallback::shaped_text_get_ellipsis_glyph_count(RID p_shaped) const {
 	ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
-	ERR_FAIL_COND_V_MSG(!sd, TrimData(), "ShapedTextDataFallback invalid.");
+	ERR_FAIL_COND_V_MSG(!sd, 0, "ShapedTextData invalid.");
 
 	MutexLock lock(sd->mutex);
-	return sd->overrun_trim_data;
+	return sd->overrun_trim_data.ellipsis_glyph_buf.size();
 }
 
 bool TextServerFallback::shaped_text_shape(RID p_shaped) {
@@ -2890,8 +2920,7 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
 					// 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;
-						sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
-						sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
+						sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
 					} else {
 						gl.advance = get_hex_code_box_size(gl.font_size, gl.index).y;
 						sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
@@ -2905,8 +2934,8 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
 	}
 
 	// Align embedded objects to baseline.
-	real_t full_ascent = sd->ascent;
-	real_t full_descent = sd->descent;
+	float full_ascent = sd->ascent;
+	float full_descent = sd->descent;
 	for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
 		if (sd->orientation == ORIENTATION_HORIZONTAL) {
 			switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
@@ -2980,35 +3009,46 @@ bool TextServerFallback::shaped_text_is_ready(RID p_shaped) const {
 	return sd->valid;
 }
 
-Vector<TextServer::Glyph> TextServerFallback::shaped_text_get_glyphs(RID p_shaped) const {
+const Glyph *TextServerFallback::shaped_text_get_glyphs(RID p_shaped) const {
 	const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
-	ERR_FAIL_COND_V(!sd, Vector<TextServer::Glyph>());
+	ERR_FAIL_COND_V(!sd, nullptr);
 
 	MutexLock lock(sd->mutex);
 	if (!sd->valid) {
 		const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
 	}
-	return sd->glyphs;
+	return sd->glyphs.ptr();
 }
 
-Vector2i TextServerFallback::shaped_text_get_range(RID p_shaped) const {
+int TextServerFallback::shaped_text_get_glyph_count(RID p_shaped) const {
 	const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
-	ERR_FAIL_COND_V(!sd, Vector2i());
+	ERR_FAIL_COND_V(!sd, 0);
 
 	MutexLock lock(sd->mutex);
-	return Vector2(sd->start, sd->end);
+	if (!sd->valid) {
+		const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+	}
+	return sd->glyphs.size();
 }
 
-Vector<TextServer::Glyph> TextServerFallback::shaped_text_sort_logical(RID p_shaped) {
+const Glyph *TextServerFallback::shaped_text_sort_logical(RID p_shaped) {
 	const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
-	ERR_FAIL_COND_V(!sd, Vector<TextServer::Glyph>());
+	ERR_FAIL_COND_V(!sd, nullptr);
 
 	MutexLock lock(sd->mutex);
 	if (!sd->valid) {
 		const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
 	}
 
-	return sd->glyphs; // Already in the logical order, return as is.
+	return sd->glyphs.ptr(); // Already in the logical order, return as is.
+}
+
+Vector2i TextServerFallback::shaped_text_get_range(RID p_shaped) const {
+	const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
+	ERR_FAIL_COND_V(!sd, Vector2i());
+
+	MutexLock lock(sd->mutex);
+	return Vector2(sd->start, sd->end);
 }
 
 Array TextServerFallback::shaped_text_get_objects(RID p_shaped) const {
@@ -3051,7 +3091,7 @@ Size2 TextServerFallback::shaped_text_get_size(RID p_shaped) const {
 	}
 }
 
-real_t TextServerFallback::shaped_text_get_ascent(RID p_shaped) const {
+float TextServerFallback::shaped_text_get_ascent(RID p_shaped) const {
 	const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 
@@ -3062,7 +3102,7 @@ real_t TextServerFallback::shaped_text_get_ascent(RID p_shaped) const {
 	return sd->ascent;
 }
 
-real_t TextServerFallback::shaped_text_get_descent(RID p_shaped) const {
+float TextServerFallback::shaped_text_get_descent(RID p_shaped) const {
 	const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 
@@ -3073,7 +3113,7 @@ real_t TextServerFallback::shaped_text_get_descent(RID p_shaped) const {
 	return sd->descent;
 }
 
-real_t TextServerFallback::shaped_text_get_width(RID p_shaped) const {
+float TextServerFallback::shaped_text_get_width(RID p_shaped) const {
 	const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 
@@ -3084,7 +3124,7 @@ real_t TextServerFallback::shaped_text_get_width(RID p_shaped) const {
 	return sd->width;
 }
 
-real_t TextServerFallback::shaped_text_get_underline_position(RID p_shaped) const {
+float TextServerFallback::shaped_text_get_underline_position(RID p_shaped) const {
 	const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 
@@ -3096,7 +3136,7 @@ real_t TextServerFallback::shaped_text_get_underline_position(RID p_shaped) cons
 	return sd->upos;
 }
 
-real_t TextServerFallback::shaped_text_get_underline_thickness(RID p_shaped) const {
+float TextServerFallback::shaped_text_get_underline_thickness(RID p_shaped) const {
 	const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 
@@ -3108,15 +3148,6 @@ real_t TextServerFallback::shaped_text_get_underline_thickness(RID p_shaped) con
 	return sd->uthk;
 }
 
-TextServer *TextServerFallback::create_func(Error &r_error, void *p_user_data) {
-	r_error = OK;
-	return memnew(TextServerFallback());
-}
-
-void TextServerFallback::register_server() {
-	TextServerManager::register_create_function(interface_name, interface_features, create_func, nullptr);
-}
-
 TextServerFallback::TextServerFallback(){};
 
 TextServerFallback::~TextServerFallback() {

+ 46 - 46
modules/text_server_fb/text_server_fb.h

@@ -93,12 +93,12 @@ class TextServerFallback : public TextServer {
 	};
 
 	struct FontDataForSizeFallback {
-		real_t ascent = 0.f;
-		real_t descent = 0.f;
-		real_t underline_position = 0.f;
-		real_t underline_thickness = 0.f;
-		real_t scale = 1.f;
-		real_t oversampling = 1.f;
+		float ascent = 0.f;
+		float descent = 0.f;
+		float underline_position = 0.f;
+		float underline_thickness = 0.f;
+		float scale = 1.f;
+		float oversampling = 1.f;
 
 		int spacing_glyph = 0;
 		int spacing_space = 0;
@@ -134,7 +134,7 @@ class TextServerFallback : public TextServer {
 		bool force_autohinter = false;
 		TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
 		Dictionary variation_coordinates;
-		real_t oversampling = 0.f;
+		float oversampling = 0.f;
 
 		Map<Vector2i, FontDataForSizeFallback *> cache;
 
@@ -194,7 +194,7 @@ class TextServerFallback : public TextServer {
 
 	// Common data.
 
-	real_t oversampling = 1.f;
+	float oversampling = 1.f;
 	mutable RID_PtrOwner<FontDataFallback> font_owner;
 	mutable RID_PtrOwner<ShapedTextData> shaped_owner;
 
@@ -205,20 +205,19 @@ protected:
 	void invalidate(ShapedTextData *p_shaped);
 
 public:
-	virtual bool has_feature(Feature p_feature) override;
+	virtual bool has_feature(Feature p_feature) const override;
 	virtual String get_name() const override;
+	virtual uint32_t get_features() const override;
 
 	virtual void free(RID p_rid) override;
 	virtual bool has(RID p_rid) override;
 	virtual bool load_support_data(const String &p_filename) override;
 
-#ifdef TOOLS_ENABLED
-	virtual String get_support_data_filename() override { return ""; };
-	virtual String get_support_data_info() override { return "Not supported"; };
-	virtual bool save_support_data(const String &p_filename) override;
-#endif
+	virtual String get_support_data_filename() const override { return ""; };
+	virtual String get_support_data_info() const override { return "Not supported"; };
+	virtual bool save_support_data(const String &p_filename) const override;
 
-	virtual bool is_locale_right_to_left(const String &p_locale) override;
+	virtual bool is_locale_right_to_left(const String &p_locale) const override;
 
 	virtual int32_t name_to_tag(const String &p_name) const override;
 	virtual String tag_to_name(int32_t p_tag) const override;
@@ -253,27 +252,27 @@ public:
 	virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) override;
 	virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const override;
 
-	virtual void font_set_oversampling(RID p_font_rid, real_t p_oversampling) override;
-	virtual real_t font_get_oversampling(RID p_font_rid) const override;
+	virtual void font_set_oversampling(RID p_font_rid, float p_oversampling) override;
+	virtual float font_get_oversampling(RID p_font_rid) const override;
 
 	virtual Array font_get_size_cache_list(RID p_font_rid) const override;
 	virtual void font_clear_size_cache(RID p_font_rid) override;
 	virtual void font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) override;
 
-	virtual void font_set_ascent(RID p_font_rid, int p_size, real_t p_ascent) override;
-	virtual real_t font_get_ascent(RID p_font_rid, int p_size) const override;
+	virtual void font_set_ascent(RID p_font_rid, int p_size, float p_ascent) override;
+	virtual float font_get_ascent(RID p_font_rid, int p_size) const override;
 
-	virtual void font_set_descent(RID p_font_rid, int p_size, real_t p_descent) override;
-	virtual real_t font_get_descent(RID p_font_rid, int p_size) const override;
+	virtual void font_set_descent(RID p_font_rid, int p_size, float p_descent) override;
+	virtual float font_get_descent(RID p_font_rid, int p_size) const override;
 
-	virtual void font_set_underline_position(RID p_font_rid, int p_size, real_t p_underline_position) override;
-	virtual real_t font_get_underline_position(RID p_font_rid, int p_size) const override;
+	virtual void font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) override;
+	virtual float font_get_underline_position(RID p_font_rid, int p_size) const override;
 
-	virtual void font_set_underline_thickness(RID p_font_rid, int p_size, real_t p_underline_thickness) override;
-	virtual real_t font_get_underline_thickness(RID p_font_rid, int p_size) const override;
+	virtual void font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) override;
+	virtual float font_get_underline_thickness(RID p_font_rid, int p_size) const override;
 
-	virtual void font_set_scale(RID p_font_rid, int p_size, real_t p_scale) override;
-	virtual real_t font_get_scale(RID p_font_rid, int p_size) const override;
+	virtual void font_set_scale(RID p_font_rid, int p_size, float p_scale) override;
+	virtual float font_get_scale(RID p_font_rid, int p_size) const override;
 
 	virtual void font_set_spacing(RID p_font_rid, int p_size, SpacingType p_spacing, int p_value) override;
 	virtual int font_get_spacing(RID p_font_rid, int p_size, SpacingType p_spacing) const override;
@@ -307,7 +306,7 @@ public:
 	virtual int font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
 	virtual void font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) override;
 
-	virtual bool font_get_glyph_contours(RID p_font, int p_size, int32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
+	virtual Dictionary font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const override;
 
 	virtual Array font_get_kerning_list(RID p_font_rid, int p_size) const override;
 	virtual void font_clear_kerning_map(RID p_font_rid, int p_size) override;
@@ -342,8 +341,8 @@ public:
 	virtual Dictionary font_supported_feature_list(RID p_font_rid) const override;
 	virtual Dictionary font_supported_variation_list(RID p_font_rid) const override;
 
-	virtual real_t font_get_global_oversampling() const override;
-	virtual void font_set_global_oversampling(real_t p_oversampling) override;
+	virtual float font_get_global_oversampling() const override;
+	virtual void font_set_global_oversampling(float p_oversampling) override;
 
 	/* Shaped text buffer interface */
 
@@ -354,7 +353,7 @@ public:
 	virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override;
 	virtual Direction shaped_text_get_direction(RID p_shaped) const override;
 
-	virtual void shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) override;
+	virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override;
 
 	virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
 	virtual Orientation shaped_text_get_orientation(RID p_shaped) const override;
@@ -372,36 +371,37 @@ public:
 	virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
 	virtual RID shaped_text_get_parent(RID p_shaped) const override;
 
-	virtual real_t shaped_text_fit_to_width(RID p_shaped, real_t p_width, uint8_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
-	virtual real_t shaped_text_tab_align(RID p_shaped, const Vector<real_t> &p_tab_stops) override;
+	virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
+	virtual float shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) override;
 
 	virtual bool shaped_text_shape(RID p_shaped) override;
 	virtual bool shaped_text_update_breaks(RID p_shaped) override;
 	virtual bool shaped_text_update_justification_ops(RID p_shaped) override;
 
-	virtual void shaped_text_overrun_trim_to_width(RID p_shaped, real_t p_width, uint8_t p_trim_flags) override;
-	virtual TrimData shaped_text_get_trim_data(RID p_shaped) const override;
+	virtual int shaped_text_get_trim_pos(RID p_shaped) const override;
+	virtual int shaped_text_get_ellipsis_pos(RID p_shaped) const override;
+	virtual const Glyph *shaped_text_get_ellipsis_glyphs(RID p_shaped) const override;
+	virtual int shaped_text_get_ellipsis_glyph_count(RID p_shaped) const override;
+
+	virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint16_t p_trim_flags) override;
 
 	virtual bool shaped_text_is_ready(RID p_shaped) const override;
 
-	virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const override;
+	virtual const Glyph *shaped_text_get_glyphs(RID p_shaped) const override;
+	virtual const Glyph *shaped_text_sort_logical(RID p_shaped) override;
+	virtual int shaped_text_get_glyph_count(RID p_shaped) const override;
 
 	virtual Vector2i shaped_text_get_range(RID p_shaped) const override;
 
-	virtual Vector<Glyph> shaped_text_sort_logical(RID p_shaped) override;
-
 	virtual Array shaped_text_get_objects(RID p_shaped) const override;
 	virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const override;
 
 	virtual Size2 shaped_text_get_size(RID p_shaped) const override;
-	virtual real_t shaped_text_get_ascent(RID p_shaped) const override;
-	virtual real_t shaped_text_get_descent(RID p_shaped) const override;
-	virtual real_t shaped_text_get_width(RID p_shaped) const override;
-	virtual real_t shaped_text_get_underline_position(RID p_shaped) const override;
-	virtual real_t shaped_text_get_underline_thickness(RID p_shaped) const override;
-
-	static TextServer *create_func(Error &r_error, void *p_user_data);
-	static void register_server();
+	virtual float shaped_text_get_ascent(RID p_shaped) const override;
+	virtual float shaped_text_get_descent(RID p_shaped) const override;
+	virtual float shaped_text_get_width(RID p_shaped) const override;
+	virtual float shaped_text_get_underline_position(RID p_shaped) const override;
+	virtual float shaped_text_get_underline_thickness(RID p_shaped) const override;
 
 	TextServerFallback();
 	~TextServerFallback();

+ 15 - 5
platform/osx/os_osx.mm

@@ -314,17 +314,27 @@ String OS_OSX::get_name() const {
 	return "macOS";
 }
 
+_FORCE_INLINE_ String _get_framework_executable(const String p_path) {
+	// Append framework executable name, or return as is if p_path is not a framework.
+	DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+	if (da->dir_exists(p_path) && da->file_exists(p_path.plus_file(p_path.get_file().get_basename()))) {
+		return p_path.plus_file(p_path.get_file().get_basename());
+	} else {
+		return p_path;
+	}
+}
+
 Error OS_OSX::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
-	String path = p_path;
+	String path = _get_framework_executable(p_path);
 
 	if (!FileAccess::exists(path)) {
-		//this code exists so gdnative can load .dylib files from within the executable path
-		path = get_executable_path().get_base_dir().plus_file(p_path.get_file());
+		// This code exists so gdnative can load .dylib files from within the executable path.
+		path = _get_framework_executable(get_executable_path().get_base_dir().plus_file(p_path.get_file()));
 	}
 
 	if (!FileAccess::exists(path)) {
-		//this code exists so gdnative can load .dylib files from a standard macOS location
-		path = get_executable_path().get_base_dir().plus_file("../Frameworks").plus_file(p_path.get_file());
+		// This code exists so gdnative can load .dylib files from a standard macOS location.
+		path = _get_framework_executable(get_executable_path().get_base_dir().plus_file("../Frameworks").plus_file(p_path.get_file()));
 	}
 
 	p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);

+ 2 - 2
scene/gui/control.cpp

@@ -2449,8 +2449,8 @@ bool Control::is_text_field() const {
 	return false;
 }
 
-Vector<Vector2i> Control::structured_text_parser(StructuredTextParser p_theme_type, const Array &p_args, const String p_text) const {
-	Vector<Vector2i> ret;
+Array Control::structured_text_parser(StructuredTextParser p_theme_type, const Array &p_args, const String p_text) const {
+	Array ret;
 	switch (p_theme_type) {
 		case STRUCTURED_TEXT_URI: {
 			int prev = 0;

+ 1 - 1
scene/gui/control.h

@@ -283,7 +283,7 @@ protected:
 
 	//virtual void _window_gui_input(InputEvent p_event);
 
-	virtual Vector<Vector2i> structured_text_parser(StructuredTextParser p_theme_type, const Array &p_args, const String p_text) const;
+	virtual Array structured_text_parser(StructuredTextParser p_theme_type, const Array &p_args, const String p_text) const;
 
 	bool _set(const StringName &p_name, const Variant &p_value);
 	bool _get(const StringName &p_name, Variant &r_ret) const;

+ 41 - 37
scene/gui/label.cpp

@@ -108,7 +108,7 @@ void Label::_shape() {
 		}
 		lines_rid.clear();
 
-		uint8_t autowrap_flags = TextServer::BREAK_MANDATORY;
+		uint16_t autowrap_flags = TextServer::BREAK_MANDATORY;
 		switch (autowrap_mode) {
 			case AUTOWRAP_WORD_SMART:
 				autowrap_flags = TextServer::BREAK_WORD_BOUND_ADAPTIVE | TextServer::BREAK_MANDATORY;
@@ -122,10 +122,10 @@ void Label::_shape() {
 			case AUTOWRAP_OFF:
 				break;
 		}
-		Vector<Vector2i> line_breaks = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags);
+		PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags);
 
-		for (int i = 0; i < line_breaks.size(); i++) {
-			RID line = TS->shaped_text_substr(text_rid, line_breaks[i].x, line_breaks[i].y - line_breaks[i].x);
+		for (int i = 0; i < line_breaks.size(); i = i + 2) {
+			RID line = TS->shaped_text_substr(text_rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]);
 			lines_rid.push_back(line);
 		}
 	}
@@ -145,7 +145,7 @@ void Label::_shape() {
 	}
 
 	if (lines_dirty) {
-		uint8_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
+		uint16_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
 		switch (overrun_behavior) {
 			case OVERRUN_TRIM_WORD_ELLIPSIS:
 				overrun_flags |= TextServer::OVERRUN_TRIM;
@@ -231,7 +231,7 @@ void Label::_update_visible() {
 	}
 }
 
-inline void draw_glyph(const TextServer::Glyph &p_gl, const RID &p_canvas, const Color &p_font_color, const Vector2 &p_ofs) {
+inline void draw_glyph(const Glyph &p_gl, const RID &p_canvas, const Color &p_font_color, const Vector2 &p_ofs) {
 	if (p_gl.font_rid != RID()) {
 		TS->font_draw_glyph(p_gl.font_rid, p_canvas, p_gl.font_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off), p_gl.index, p_font_color);
 	} else {
@@ -239,7 +239,7 @@ inline void draw_glyph(const TextServer::Glyph &p_gl, const RID &p_canvas, const
 	}
 }
 
-inline void draw_glyph_outline(const TextServer::Glyph &p_gl, const RID &p_canvas, const Color &p_font_color, const Color &p_font_shadow_color, const Color &p_font_outline_color, const int &p_shadow_outline_size, const int &p_outline_size, const Vector2 &p_ofs, const Vector2 &shadow_ofs) {
+inline void draw_glyph_outline(const Glyph &p_gl, const RID &p_canvas, const Color &p_font_color, const Color &p_font_shadow_color, const Color &p_font_outline_color, const int &p_shadow_outline_size, const int &p_outline_size, const Vector2 &p_ofs, const Vector2 &shadow_ofs) {
 	if (p_gl.font_rid != RID()) {
 		if (p_font_shadow_color.a > 0) {
 			TS->font_draw_glyph(p_gl.font_rid, p_canvas, p_gl.font_size, p_ofs + Vector2(p_gl.x_off, p_gl.y_off) + shadow_ofs, p_gl.index, p_font_shadow_color);
@@ -387,21 +387,25 @@ void Label::_notification(int p_what) {
 				} break;
 			}
 
-			const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(lines_rid[i]);
-			const TextServer::Glyph *glyphs = visual.ptr();
-			int gl_size = visual.size();
-			TextServer::TrimData trim_data = TS->shaped_text_get_trim_data(lines_rid[i]);
+			const Glyph *glyphs = TS->shaped_text_get_glyphs(lines_rid[i]);
+			int gl_size = TS->shaped_text_get_glyph_count(lines_rid[i]);
+
+			int ellipsis_pos = TS->shaped_text_get_ellipsis_pos(lines_rid[i]);
+			int trim_pos = TS->shaped_text_get_trim_pos(lines_rid[i]);
+
+			const Glyph *ellipsis_glyphs = TS->shaped_text_get_ellipsis_glyphs(lines_rid[i]);
+			int ellipsis_gl_size = TS->shaped_text_get_ellipsis_glyph_count(lines_rid[i]);
 
 			// Draw outline. Note: Do not merge this into the single loop with the main text, to prevent overlaps.
 			if (font_shadow_color.a > 0 || (font_outline_color.a != 0.0 && outline_size > 0)) {
 				Vector2 offset = ofs;
 				// Draw RTL ellipsis string when necessary.
-				if (rtl && trim_data.ellipsis_pos >= 0) {
-					for (int gl_idx = trim_data.ellipsis_glyph_buf.size() - 1; gl_idx >= 0; gl_idx--) {
-						for (int j = 0; j < trim_data.ellipsis_glyph_buf[gl_idx].repeat; j++) {
+				if (rtl && ellipsis_pos >= 0) {
+					for (int gl_idx = ellipsis_gl_size - 1; gl_idx >= 0; gl_idx--) {
+						for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) {
 							//Draw glyph outlines and shadow.
-							draw_glyph_outline(trim_data.ellipsis_glyph_buf[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs);
-							offset.x += trim_data.ellipsis_glyph_buf[gl_idx].advance;
+							draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs);
+							offset.x += ellipsis_glyphs[gl_idx].advance;
 						}
 					}
 				}
@@ -410,13 +414,13 @@ void Label::_notification(int p_what) {
 				for (int j = 0; j < gl_size; j++) {
 					for (int k = 0; k < glyphs[j].repeat; k++) {
 						// Trim when necessary.
-						if (trim_data.trim_pos >= 0) {
+						if (trim_pos >= 0) {
 							if (rtl) {
-								if (j < trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+								if (j < trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
 									continue;
 								}
 							} else {
-								if (j >= trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+								if (j >= trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
 									break;
 								}
 							}
@@ -428,12 +432,12 @@ void Label::_notification(int p_what) {
 					}
 				}
 				// Draw LTR ellipsis string when necessary.
-				if (!rtl && trim_data.ellipsis_pos >= 0) {
-					for (int gl_idx = 0; gl_idx < trim_data.ellipsis_glyph_buf.size(); gl_idx++) {
-						for (int j = 0; j < trim_data.ellipsis_glyph_buf[gl_idx].repeat; j++) {
+				if (!rtl && ellipsis_pos >= 0) {
+					for (int gl_idx = 0; gl_idx < ellipsis_gl_size; gl_idx++) {
+						for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) {
 							//Draw glyph outlines and shadow.
-							draw_glyph_outline(trim_data.ellipsis_glyph_buf[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs);
-							offset.x += trim_data.ellipsis_glyph_buf[gl_idx].advance;
+							draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs);
+							offset.x += ellipsis_glyphs[gl_idx].advance;
 						}
 					}
 				}
@@ -442,12 +446,12 @@ void Label::_notification(int p_what) {
 			// Draw main text. Note: Do not merge this into the single loop with the outline, to prevent overlaps.
 
 			// Draw RTL ellipsis string when necessary.
-			if (rtl && trim_data.ellipsis_pos >= 0) {
-				for (int gl_idx = trim_data.ellipsis_glyph_buf.size() - 1; gl_idx >= 0; gl_idx--) {
-					for (int j = 0; j < trim_data.ellipsis_glyph_buf[gl_idx].repeat; j++) {
+			if (rtl && ellipsis_pos >= 0) {
+				for (int gl_idx = ellipsis_gl_size - 1; gl_idx >= 0; gl_idx--) {
+					for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) {
 						//Draw glyph outlines and shadow.
-						draw_glyph(trim_data.ellipsis_glyph_buf[gl_idx], ci, font_color, ofs);
-						ofs.x += trim_data.ellipsis_glyph_buf[gl_idx].advance;
+						draw_glyph(ellipsis_glyphs[gl_idx], ci, font_color, ofs);
+						ofs.x += ellipsis_glyphs[gl_idx].advance;
 					}
 				}
 			}
@@ -456,13 +460,13 @@ void Label::_notification(int p_what) {
 			for (int j = 0; j < gl_size; j++) {
 				for (int k = 0; k < glyphs[j].repeat; k++) {
 					// Trim when necessary.
-					if (trim_data.trim_pos >= 0) {
+					if (trim_pos >= 0) {
 						if (rtl) {
-							if (j < trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+							if (j < trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
 								continue;
 							}
 						} else {
-							if (j >= trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+							if (j >= trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
 								break;
 							}
 						}
@@ -474,12 +478,12 @@ void Label::_notification(int p_what) {
 				}
 			}
 			// Draw LTR ellipsis string when necessary.
-			if (!rtl && trim_data.ellipsis_pos >= 0) {
-				for (int gl_idx = 0; gl_idx < trim_data.ellipsis_glyph_buf.size(); gl_idx++) {
-					for (int j = 0; j < trim_data.ellipsis_glyph_buf[gl_idx].repeat; j++) {
+			if (!rtl && ellipsis_pos >= 0) {
+				for (int gl_idx = 0; gl_idx < ellipsis_gl_size; gl_idx++) {
+					for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) {
 						//Draw glyph outlines and shadow.
-						draw_glyph(trim_data.ellipsis_glyph_buf[gl_idx], ci, font_color, ofs);
-						ofs.x += trim_data.ellipsis_glyph_buf[gl_idx].advance;
+						draw_glyph(ellipsis_glyphs[gl_idx], ci, font_color, ofs);
+						ofs.x += ellipsis_glyphs[gl_idx].advance;
 					}
 				}
 			}

+ 50 - 54
scene/gui/line_edit.cpp

@@ -67,10 +67,10 @@ void LineEdit::_move_caret_left(bool p_select, bool p_move_by_word) {
 	if (p_move_by_word) {
 		int cc = caret_column;
 
-		Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
-		for (int i = words.size() - 1; i >= 0; i--) {
-			if (words[i].x < cc) {
-				cc = words[i].x;
+		PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid);
+		for (int i = words.size() - 2; i >= 0; i = i - 2) {
+			if (words[i] < cc) {
+				cc = words[i];
 				break;
 			}
 		}
@@ -99,10 +99,10 @@ void LineEdit::_move_caret_right(bool p_select, bool p_move_by_word) {
 	if (p_move_by_word) {
 		int cc = caret_column;
 
-		Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
-		for (int i = 0; i < words.size(); i++) {
-			if (words[i].y > cc) {
-				cc = words[i].y;
+		PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid);
+		for (int i = 1; i < words.size(); i = i + 2) {
+			if (words[i] > cc) {
+				cc = words[i];
 				break;
 			}
 		}
@@ -151,10 +151,10 @@ void LineEdit::_backspace(bool p_word, bool p_all_to_left) {
 	if (p_word) {
 		int cc = caret_column;
 
-		Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
-		for (int i = words.size() - 1; i >= 0; i--) {
-			if (words[i].x < cc) {
-				cc = words[i].x;
+		PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid);
+		for (int i = words.size() - 2; i >= 0; i = i - 2) {
+			if (words[i] < cc) {
+				cc = words[i];
 				break;
 			}
 		}
@@ -194,10 +194,10 @@ void LineEdit::_delete(bool p_word, bool p_all_to_right) {
 
 	if (p_word) {
 		int cc = caret_column;
-		Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
-		for (int i = 0; i < words.size(); i++) {
-			if (words[i].y > cc) {
-				cc = words[i].y;
+		PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid);
+		for (int i = 1; i < words.size(); i = i + 2) {
+			if (words[i] > cc) {
+				cc = words[i];
 				break;
 			}
 		}
@@ -276,12 +276,12 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
 						// Double-click select word.
 						last_dblclk = OS::get_singleton()->get_ticks_msec();
 						last_dblclk_pos = b->get_position();
-						Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
-						for (int i = 0; i < words.size(); i++) {
-							if ((words[i].x < caret_column && words[i].y > caret_column) || (i == words.size() - 1 && caret_column == words[i].y)) {
+						PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid);
+						for (int i = 0; i < words.size(); i = i + 2) {
+							if ((words[i] < caret_column && words[i + 1] > caret_column) || (i == words.size() - 2 && caret_column == words[i + 1])) {
 								selection.enabled = true;
-								selection.begin = words[i].x;
-								selection.end = words[i].y;
+								selection.begin = words[i];
+								selection.end = words[i + 1];
 								selection.double_click = true;
 								caret_column = selection.end;
 								break;
@@ -737,9 +737,8 @@ void LineEdit::_notification(int p_what) {
 					RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, selection_color);
 				}
 			}
-			const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(text_rid);
-			const TextServer::Glyph *glyphs = visual.ptr();
-			int gl_size = visual.size();
+			const Glyph *glyphs = TS->shaped_text_get_glyphs(text_rid);
+			int gl_size = TS->shaped_text_get_glyph_count(text_rid);
 
 			// Draw text.
 			ofs.y += TS->shaped_text_get_ascent(text_rid);
@@ -783,38 +782,36 @@ void LineEdit::_notification(int p_what) {
 			if (draw_caret) {
 				if (ime_text.length() == 0) {
 					// Normal caret.
-					Rect2 l_caret, t_caret;
-					TextServer::Direction l_dir, t_dir;
-					TS->shaped_text_get_carets(text_rid, caret_column, l_caret, l_dir, t_caret, t_dir);
+					CaretInfo caret = TS->shaped_text_get_carets(text_rid, caret_column);
 
-					if (l_caret == Rect2() && t_caret == Rect2()) {
+					if (caret.l_caret == Rect2() && caret.t_caret == Rect2()) {
 						// No carets, add one at the start.
 						int h = get_theme_font(SNAME("font"))->get_height(get_theme_font_size(SNAME("font_size")));
 						int y = style->get_offset().y + (y_area - h) / 2;
 						if (rtl) {
-							l_dir = TextServer::DIRECTION_RTL;
-							l_caret = Rect2(Vector2(ofs_max, y), Size2(caret_width, h));
+							caret.l_dir = TextServer::DIRECTION_RTL;
+							caret.l_caret = Rect2(Vector2(ofs_max, y), Size2(caret_width, h));
 						} else {
-							l_dir = TextServer::DIRECTION_LTR;
-							l_caret = Rect2(Vector2(x_ofs, y), Size2(caret_width, h));
+							caret.l_dir = TextServer::DIRECTION_LTR;
+							caret.l_caret = Rect2(Vector2(x_ofs, y), Size2(caret_width, h));
 						}
-						RenderingServer::get_singleton()->canvas_item_add_rect(ci, l_caret, caret_color);
+						RenderingServer::get_singleton()->canvas_item_add_rect(ci, caret.l_caret, caret_color);
 					} else {
-						if (l_caret != Rect2() && l_dir == TextServer::DIRECTION_AUTO) {
+						if (caret.l_caret != Rect2() && caret.l_dir == TextServer::DIRECTION_AUTO) {
 							// Draw extra marker on top of mid caret.
-							Rect2 trect = Rect2(l_caret.position.x - 3 * caret_width, l_caret.position.y, 6 * caret_width, caret_width);
+							Rect2 trect = Rect2(caret.l_caret.position.x - 3 * caret_width, caret.l_caret.position.y, 6 * caret_width, caret_width);
 							trect.position += ofs;
 							RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color);
 						}
 
-						l_caret.position += ofs;
-						l_caret.size.x = caret_width;
-						RenderingServer::get_singleton()->canvas_item_add_rect(ci, l_caret, caret_color);
+						caret.l_caret.position += ofs;
+						caret.l_caret.size.x = caret_width;
+						RenderingServer::get_singleton()->canvas_item_add_rect(ci, caret.l_caret, caret_color);
 
-						t_caret.position += ofs;
-						t_caret.size.x = caret_width;
+						caret.t_caret.position += ofs;
+						caret.t_caret.size.x = caret_width;
 
-						RenderingServer::get_singleton()->canvas_item_add_rect(ci, t_caret, caret_color);
+						RenderingServer::get_singleton()->canvas_item_add_rect(ci, caret.t_caret, caret_color);
 					}
 				} else {
 					{
@@ -1114,32 +1111,31 @@ Vector2i LineEdit::get_caret_pixel_pos() {
 	}
 
 	Vector2i ret;
-	Rect2 l_caret, t_caret;
-	TextServer::Direction l_dir, t_dir;
+	CaretInfo caret;
 	// Get position of the start of caret.
 	if (ime_text.length() != 0 && ime_selection.x != 0) {
-		TS->shaped_text_get_carets(text_rid, caret_column + ime_selection.x, l_caret, l_dir, t_caret, t_dir);
+		caret = TS->shaped_text_get_carets(text_rid, caret_column + ime_selection.x);
 	} else {
-		TS->shaped_text_get_carets(text_rid, caret_column, l_caret, l_dir, t_caret, t_dir);
+		caret = TS->shaped_text_get_carets(text_rid, caret_column);
 	}
 
-	if ((l_caret != Rect2() && (l_dir == TextServer::DIRECTION_AUTO || l_dir == (TextServer::Direction)input_direction)) || (t_caret == Rect2())) {
-		ret.x = x_ofs + l_caret.position.x + scroll_offset;
+	if ((caret.l_caret != Rect2() && (caret.l_dir == TextServer::DIRECTION_AUTO || caret.l_dir == (TextServer::Direction)input_direction)) || (caret.t_caret == Rect2())) {
+		ret.x = x_ofs + caret.l_caret.position.x + scroll_offset;
 	} else {
-		ret.x = x_ofs + t_caret.position.x + scroll_offset;
+		ret.x = x_ofs + caret.t_caret.position.x + scroll_offset;
 	}
 
 	// Get position of the end of caret.
 	if (ime_text.length() != 0) {
 		if (ime_selection.y != 0) {
-			TS->shaped_text_get_carets(text_rid, caret_column + ime_selection.x + ime_selection.y, l_caret, l_dir, t_caret, t_dir);
+			caret = TS->shaped_text_get_carets(text_rid, caret_column + ime_selection.x + ime_selection.y);
 		} else {
-			TS->shaped_text_get_carets(text_rid, caret_column + ime_text.size(), l_caret, l_dir, t_caret, t_dir);
+			caret = TS->shaped_text_get_carets(text_rid, caret_column + ime_text.size());
 		}
-		if ((l_caret != Rect2() && (l_dir == TextServer::DIRECTION_AUTO || l_dir == (TextServer::Direction)input_direction)) || (t_caret == Rect2())) {
-			ret.y = x_ofs + l_caret.position.x + scroll_offset;
+		if ((caret.l_caret != Rect2() && (caret.l_dir == TextServer::DIRECTION_AUTO || caret.l_dir == (TextServer::Direction)input_direction)) || (caret.t_caret == Rect2())) {
+			ret.y = x_ofs + caret.l_caret.position.x + scroll_offset;
 		} else {
-			ret.y = x_ofs + t_caret.position.x + scroll_offset;
+			ret.y = x_ofs + caret.t_caret.position.x + scroll_offset;
 		}
 	} else {
 		ret.y = ret.x;
@@ -1502,7 +1498,7 @@ void LineEdit::insert_text_at_caret(String p_text) {
 	String post = text.substr(caret_column, text.length() - caret_column);
 	text = pre + p_text + post;
 	_shape();
-	TextServer::Direction dir = TS->shaped_text_get_dominant_direciton_in_range(text_rid, caret_column, caret_column + p_text.length());
+	TextServer::Direction dir = TS->shaped_text_get_dominant_direction_in_range(text_rid, caret_column, caret_column + p_text.length());
 	if (dir != TextServer::DIRECTION_AUTO) {
 		input_direction = (TextDirection)dir;
 	}

+ 7 - 8
scene/gui/rich_text_label.cpp

@@ -819,9 +819,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
 			}
 		}
 
-		const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(rid);
-		const TextServer::Glyph *glyphs = visual.ptr();
-		int gl_size = visual.size();
+		const Glyph *glyphs = TS->shaped_text_get_glyphs(rid);
+		int gl_size = TS->shaped_text_get_glyph_count(rid);
 
 		Vector2 gloff = off;
 		// Draw oulines and shadow.
@@ -1593,18 +1592,18 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
 
 				if (c_frame) {
 					const Line &l = c_frame->lines[c_line];
-					Vector<Vector2i> words = TS->shaped_text_get_word_breaks(l.text_buf->get_rid());
-					for (int i = 0; i < words.size(); i++) {
-						if (c_index >= words[i].x && c_index < words[i].y) {
+					PackedInt32Array words = TS->shaped_text_get_word_breaks(l.text_buf->get_rid());
+					for (int i = 0; i < words.size(); i = i + 2) {
+						if (c_index >= words[i] && c_index < words[i + 1]) {
 							selection.from_frame = c_frame;
 							selection.from_line = c_line;
 							selection.from_item = c_item;
-							selection.from_char = words[i].x;
+							selection.from_char = words[i];
 
 							selection.to_frame = c_frame;
 							selection.to_line = c_line;
 							selection.to_item = c_item;
-							selection.to_char = words[i].y;
+							selection.to_char = words[i + 1];
 
 							selection.active = true;
 							update();

+ 82 - 86
scene/gui/text_edit.cpp

@@ -186,7 +186,7 @@ void TextEdit::Text::_calculate_max_line_width() {
 	max_width = width;
 }
 
-void TextEdit::Text::invalidate_cache(int p_line, int p_column, const String &p_ime_text, const Vector<Vector2i> &p_bidi_override) {
+void TextEdit::Text::invalidate_cache(int p_line, int p_column, const String &p_ime_text, const Array &p_bidi_override) {
 	ERR_FAIL_INDEX(p_line, text.size());
 
 	if (font.is_null() || font_size <= 0) {
@@ -278,14 +278,14 @@ void TextEdit::Text::invalidate_all() {
 
 void TextEdit::Text::clear() {
 	text.clear();
-	insert(0, "", Vector<Vector2i>());
+	insert(0, "", Array());
 }
 
 int TextEdit::Text::get_max_width() const {
 	return max_width;
 }
 
-void TextEdit::Text::set(int p_line, const String &p_text, const Vector<Vector2i> &p_bidi_override) {
+void TextEdit::Text::set(int p_line, const String &p_text, const Array &p_bidi_override) {
 	ERR_FAIL_INDEX(p_line, text.size());
 
 	text.write[p_line].data = p_text;
@@ -293,7 +293,7 @@ void TextEdit::Text::set(int p_line, const String &p_text, const Vector<Vector2i
 	invalidate_cache(p_line);
 }
 
-void TextEdit::Text::insert(int p_at, const String &p_text, const Vector<Vector2i> &p_bidi_override) {
+void TextEdit::Text::insert(int p_at, const String &p_text, const Array &p_bidi_override) {
 	Line line;
 	line.gutters.resize(gutter_count);
 	line.hidden = false;
@@ -1076,9 +1076,8 @@ void TextEdit::_notification(int p_what) {
 
 					ofs_y += (row_height - text_height) / 2;
 
-					const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(rid);
-					const TextServer::Glyph *glyphs = visual.ptr();
-					int gl_size = visual.size();
+					const Glyph *glyphs = TS->shaped_text_get_glyphs(rid);
+					int gl_size = TS->shaped_text_get_glyph_count(rid);
 
 					ofs_y += ldata->get_line_ascent(line_wrap_index);
 					int char_ofs = 0;
@@ -1185,27 +1184,26 @@ void TextEdit::_notification(int p_what) {
 						caret.draw_pos.y = ofs_y + ldata->get_line_descent(line_wrap_index);
 
 						if (ime_text.length() == 0) {
-							Rect2 l_caret, t_caret;
-							TextServer::Direction l_dir, t_dir;
+							CaretInfo ts_caret;
 							if (str.length() != 0) {
 								// Get carets.
-								TS->shaped_text_get_carets(rid, caret.column, l_caret, l_dir, t_caret, t_dir);
+								ts_caret = TS->shaped_text_get_carets(rid, caret.column);
 							} else {
 								// No carets, add one at the start.
 								int h = font->get_height(font_size);
 								if (rtl) {
-									l_dir = TextServer::DIRECTION_RTL;
-									l_caret = Rect2(Vector2(xmargin_end - char_margin + ofs_x, -h / 2), Size2(caret_width * 4, h));
+									ts_caret.l_dir = TextServer::DIRECTION_RTL;
+									ts_caret.l_caret = Rect2(Vector2(xmargin_end - char_margin + ofs_x, -h / 2), Size2(caret_width * 4, h));
 								} else {
-									l_dir = TextServer::DIRECTION_LTR;
-									l_caret = Rect2(Vector2(char_ofs, -h / 2), Size2(caret_width * 4, h));
+									ts_caret.l_dir = TextServer::DIRECTION_LTR;
+									ts_caret.l_caret = Rect2(Vector2(char_ofs, -h / 2), Size2(caret_width * 4, h));
 								}
 							}
 
-							if ((l_caret != Rect2() && (l_dir == TextServer::DIRECTION_AUTO || l_dir == (TextServer::Direction)input_direction)) || (t_caret == Rect2())) {
-								caret.draw_pos.x = char_margin + ofs_x + l_caret.position.x;
+							if ((ts_caret.l_caret != Rect2() && (ts_caret.l_dir == TextServer::DIRECTION_AUTO || ts_caret.l_dir == (TextServer::Direction)input_direction)) || (ts_caret.t_caret == Rect2())) {
+								caret.draw_pos.x = char_margin + ofs_x + ts_caret.l_caret.position.x;
 							} else {
-								caret.draw_pos.x = char_margin + ofs_x + t_caret.position.x;
+								caret.draw_pos.x = char_margin + ofs_x + ts_caret.t_caret.position.x;
 							}
 
 							if (caret.draw_pos.x >= xmargin_beg && caret.draw_pos.x < xmargin_end) {
@@ -1215,64 +1213,64 @@ void TextEdit::_notification(int p_what) {
 										//Block or underline caret, draw trailing carets at full height.
 										int h = font->get_height(font_size);
 
-										if (t_caret != Rect2()) {
+										if (ts_caret.t_caret != Rect2()) {
 											if (overtype_mode) {
-												t_caret.position.y = TS->shaped_text_get_descent(rid);
-												t_caret.size.y = caret_width;
+												ts_caret.t_caret.position.y = TS->shaped_text_get_descent(rid);
+												ts_caret.t_caret.size.y = caret_width;
 											} else {
-												t_caret.position.y = -TS->shaped_text_get_ascent(rid);
-												t_caret.size.y = h;
+												ts_caret.t_caret.position.y = -TS->shaped_text_get_ascent(rid);
+												ts_caret.t_caret.size.y = h;
 											}
-											t_caret.position += Vector2(char_margin + ofs_x, ofs_y);
-											draw_rect(t_caret, caret_color, overtype_mode);
+											ts_caret.t_caret.position += Vector2(char_margin + ofs_x, ofs_y);
+											draw_rect(ts_caret.t_caret, caret_color, overtype_mode);
 
-											if (l_caret != Rect2() && l_dir != t_dir) {
-												l_caret.position += Vector2(char_margin + ofs_x, ofs_y);
-												l_caret.size.x = caret_width;
-												draw_rect(l_caret, caret_color * Color(1, 1, 1, 0.5));
+											if (ts_caret.l_caret != Rect2() && ts_caret.l_dir != ts_caret.t_dir) {
+												ts_caret.l_caret.position += Vector2(char_margin + ofs_x, ofs_y);
+												ts_caret.l_caret.size.x = caret_width;
+												draw_rect(ts_caret.l_caret, caret_color * Color(1, 1, 1, 0.5));
 											}
 										} else { // End of the line.
 											if (gl_size > 0) {
 												// Adjust for actual line dimensions.
 												if (overtype_mode) {
-													l_caret.position.y = TS->shaped_text_get_descent(rid);
-													l_caret.size.y = caret_width;
+													ts_caret.l_caret.position.y = TS->shaped_text_get_descent(rid);
+													ts_caret.l_caret.size.y = caret_width;
 												} else {
-													l_caret.position.y = -TS->shaped_text_get_ascent(rid);
-													l_caret.size.y = h;
+													ts_caret.l_caret.position.y = -TS->shaped_text_get_ascent(rid);
+													ts_caret.l_caret.size.y = h;
 												}
 											} else if (overtype_mode) {
-												l_caret.position.y += l_caret.size.y;
-												l_caret.size.y = caret_width;
+												ts_caret.l_caret.position.y += ts_caret.l_caret.size.y;
+												ts_caret.l_caret.size.y = caret_width;
 											}
-											if (l_caret.position.x >= TS->shaped_text_get_size(rid).x) {
-												l_caret.size.x = font->get_char_size('m', 0, font_size).x;
+											if (ts_caret.l_caret.position.x >= TS->shaped_text_get_size(rid).x) {
+												ts_caret.l_caret.size.x = font->get_char_size('m', 0, font_size).x;
 											} else {
-												l_caret.size.x = 3 * caret_width;
+												ts_caret.l_caret.size.x = 3 * caret_width;
 											}
-											l_caret.position += Vector2(char_margin + ofs_x, ofs_y);
-											if (l_dir == TextServer::DIRECTION_RTL) {
-												l_caret.position.x -= l_caret.size.x;
+											ts_caret.l_caret.position += Vector2(char_margin + ofs_x, ofs_y);
+											if (ts_caret.l_dir == TextServer::DIRECTION_RTL) {
+												ts_caret.l_caret.position.x -= ts_caret.l_caret.size.x;
 											}
-											draw_rect(l_caret, caret_color, overtype_mode);
+											draw_rect(ts_caret.l_caret, caret_color, overtype_mode);
 										}
 									} else {
 										// Normal caret.
-										if (l_caret != Rect2() && l_dir == TextServer::DIRECTION_AUTO) {
+										if (ts_caret.l_caret != Rect2() && ts_caret.l_dir == TextServer::DIRECTION_AUTO) {
 											// Draw extra marker on top of mid caret.
-											Rect2 trect = Rect2(l_caret.position.x - 3 * caret_width, l_caret.position.y, 6 * caret_width, caret_width);
+											Rect2 trect = Rect2(ts_caret.l_caret.position.x - 3 * caret_width, ts_caret.l_caret.position.y, 6 * caret_width, caret_width);
 											trect.position += Vector2(char_margin + ofs_x, ofs_y);
 											RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color);
 										}
-										l_caret.position += Vector2(char_margin + ofs_x, ofs_y);
-										l_caret.size.x = caret_width;
+										ts_caret.l_caret.position += Vector2(char_margin + ofs_x, ofs_y);
+										ts_caret.l_caret.size.x = caret_width;
 
-										draw_rect(l_caret, caret_color);
+										draw_rect(ts_caret.l_caret, caret_color);
 
-										t_caret.position += Vector2(char_margin + ofs_x, ofs_y);
-										t_caret.size.x = caret_width;
+										ts_caret.t_caret.position += Vector2(char_margin + ofs_x, ofs_y);
+										ts_caret.t_caret.size.x = caret_width;
 
-										draw_rect(t_caret, caret_color);
+										draw_rect(ts_caret.t_caret, caret_color);
 									}
 								}
 							}
@@ -1968,10 +1966,10 @@ void TextEdit::_move_caret_left(bool p_select, bool p_move_by_word) {
 			set_caret_line(caret.line - 1);
 			set_caret_column(text[caret.line].length());
 		} else {
-			Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
-			for (int i = words.size() - 1; i >= 0; i--) {
-				if (words[i].x < cc) {
-					cc = words[i].x;
+			PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
+			for (int i = words.size() - 2; i >= 0; i = i - 2) {
+				if (words[i] < cc) {
+					cc = words[i];
 					break;
 				}
 			}
@@ -2019,10 +2017,10 @@ void TextEdit::_move_caret_right(bool p_select, bool p_move_by_word) {
 			set_caret_line(caret.line + 1);
 			set_caret_column(0);
 		} else {
-			Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
-			for (int i = 0; i < words.size(); i++) {
-				if (words[i].y > cc) {
-					cc = words[i].y;
+			PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
+			for (int i = 1; i < words.size(); i = i + 2) {
+				if (words[i] > cc) {
+					cc = words[i];
 					break;
 				}
 			}
@@ -2214,10 +2212,10 @@ void TextEdit::_do_backspace(bool p_word, bool p_all_to_left) {
 		int line = caret.line;
 		int column = caret.column;
 
-		Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid());
-		for (int i = words.size() - 1; i >= 0; i--) {
-			if (words[i].x < column) {
-				column = words[i].x;
+		PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid());
+		for (int i = words.size() - 2; i >= 0; i = i - 2) {
+			if (words[i] < column) {
+				column = words[i];
 				break;
 			}
 		}
@@ -2257,10 +2255,10 @@ void TextEdit::_delete(bool p_word, bool p_all_to_right) {
 		int line = caret.line;
 		int column = caret.column;
 
-		Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid());
-		for (int i = 0; i < words.size(); i++) {
-			if (words[i].y > column) {
-				column = words[i].y;
+		PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid());
+		for (int i = 1; i < words.size(); i = i + 2) {
+			if (words[i] > column) {
+				column = words[i];
 				break;
 			}
 		}
@@ -3631,10 +3629,10 @@ int TextEdit::get_caret_wrap_index() const {
 }
 
 String TextEdit::get_word_under_caret() const {
-	Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
-	for (int i = 0; i < words.size(); i++) {
-		if (words[i].x <= caret.column && words[i].y > caret.column) {
-			return text[caret.line].substr(words[i].x, words[i].y - words[i].x);
+	PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
+	for (int i = 0; i < words.size(); i = i + 2) {
+		if (words[i] <= caret.column && words[i + 1] > caret.column) {
+			return text[caret.line].substr(words[i], words[i + 1] - words[i]);
 		}
 	}
 	return "";
@@ -3718,11 +3716,11 @@ void TextEdit::select_word_under_caret() {
 
 	int begin = 0;
 	int end = 0;
-	const Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
-	for (int i = 0; i < words.size(); i++) {
-		if ((words[i].x < caret.column && words[i].y > caret.column) || (i == words.size() - 1 && caret.column == words[i].y)) {
-			begin = words[i].x;
-			end = words[i].y;
+	const PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
+	for (int i = 0; i < words.size(); i = i + 2) {
+		if ((words[i] < caret.column && words[i + 1] > caret.column) || (i == words.size() - 2 && caret.column == words[i + 1])) {
+			begin = words[i];
+			end = words[i + 1];
 			break;
 		}
 	}
@@ -5376,14 +5374,12 @@ int TextEdit::_get_column_x_offset_for_line(int p_char, int p_line) const {
 		}
 	}
 
-	Rect2 l_caret, t_caret;
-	TextServer::Direction l_dir, t_dir;
 	RID text_rid = text.get_line_data(p_line)->get_line_rid(row);
-	TS->shaped_text_get_carets(text_rid, caret.column, l_caret, l_dir, t_caret, t_dir);
-	if ((l_caret != Rect2() && (l_dir == TextServer::DIRECTION_AUTO || l_dir == (TextServer::Direction)input_direction)) || (t_caret == Rect2())) {
-		return l_caret.position.x;
+	CaretInfo ts_caret = TS->shaped_text_get_carets(text_rid, caret.column);
+	if ((ts_caret.l_caret != Rect2() && (ts_caret.l_dir == TextServer::DIRECTION_AUTO || ts_caret.l_dir == (TextServer::Direction)input_direction)) || (ts_caret.t_caret == Rect2())) {
+		return ts_caret.l_caret.position.x;
 	} else {
-		return t_caret.position.x;
+		return ts_caret.t_caret.position.x;
 	}
 }
 
@@ -5440,11 +5436,11 @@ void TextEdit::_update_selection_mode_word() {
 	int caret_pos = CLAMP(col, 0, text[line].length());
 	int beg = caret_pos;
 	int end = beg;
-	Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid());
-	for (int i = 0; i < words.size(); i++) {
-		if ((words[i].x < caret_pos && words[i].y > caret_pos) || (i == words.size() - 1 && caret_pos == words[i].y)) {
-			beg = words[i].x;
-			end = words[i].y;
+	PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid());
+	for (int i = 0; i < words.size(); i = i + 2) {
+		if ((words[i] < caret_pos && words[i + 1] > caret_pos) || (i == words.size() - 2 && caret_pos == words[i + 1])) {
+			beg = words[i];
+			end = words[i + 1];
 			break;
 		}
 	}
@@ -6032,7 +6028,7 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
 	r_end_line = p_line + substrings.size() - 1;
 	r_end_column = text[r_end_line].length() - postinsert_text.length();
 
-	TextServer::Direction dir = TS->shaped_text_get_dominant_direciton_in_range(text.get_line_data(r_end_line)->get_rid(), (r_end_line == p_line) ? caret.column : 0, r_end_column);
+	TextServer::Direction dir = TS->shaped_text_get_dominant_direction_in_range(text.get_line_data(r_end_line)->get_rid(), (r_end_line == p_line) ? caret.column : 0, r_end_column);
 	if (dir != TextServer::DIRECTION_AUTO) {
 		input_direction = (TextDirection)dir;
 	}

+ 4 - 4
scene/gui/text_edit.h

@@ -139,7 +139,7 @@ private:
 			Vector<Gutter> gutters;
 
 			String data;
-			Vector<Vector2i> bidi_override;
+			Array bidi_override;
 			Ref<TextParagraph> data_buf;
 
 			Color background_color = Color(0, 0, 0, 0);
@@ -194,7 +194,7 @@ private:
 		Vector<Vector2i> get_line_wrap_ranges(int p_line) const;
 		const Ref<TextParagraph> get_line_data(int p_line) const;
 
-		void set(int p_line, const String &p_text, const Vector<Vector2i> &p_bidi_override);
+		void set(int p_line, const String &p_text, const Array &p_bidi_override);
 		void set_hidden(int p_line, bool p_hidden) {
 			text.write[p_line].hidden = p_hidden;
 			if (!p_hidden && text[p_line].width > max_width) {
@@ -204,12 +204,12 @@ private:
 			}
 		}
 		bool is_hidden(int p_line) const { return text[p_line].hidden; }
-		void insert(int p_at, const String &p_text, const Vector<Vector2i> &p_bidi_override);
+		void insert(int p_at, const String &p_text, const Array &p_bidi_override);
 		void remove(int p_at);
 		int size() const { return text.size(); }
 		void clear();
 
-		void invalidate_cache(int p_line, int p_column = -1, const String &p_ime_text = String(), const Vector<Vector2i> &p_bidi_override = Vector<Vector2i>());
+		void invalidate_cache(int p_line, int p_column = -1, const String &p_ime_text = String(), const Array &p_bidi_override = Array());
 		void invalidate_all();
 		void invalidate_all_lines();
 

+ 2 - 2
scene/main/canvas_item.cpp

@@ -647,13 +647,13 @@ void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Tex
 	RenderingServer::get_singleton()->canvas_item_add_multimesh(canvas_item, p_multimesh->get_rid(), texture_rid);
 }
 
-void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, real_t p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
+void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, real_t p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint16_t p_flags) const {
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND(p_font.is_null());
 	p_font->draw_string(canvas_item, p_pos, p_text, p_align, p_width, p_size, p_modulate, p_outline_size, p_outline_modulate, p_flags);
 }
 
-void CanvasItem::draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, real_t p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
+void CanvasItem::draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, real_t p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint16_t p_flags) const {
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND(p_font.is_null());
 	p_font->draw_multiline_string(canvas_item, p_pos, p_text, p_align, p_width, p_max_lines, p_size, p_modulate, p_outline_size, p_outline_modulate, p_flags);

+ 2 - 2
scene/main/canvas_item.h

@@ -235,8 +235,8 @@ public:
 	void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1));
 	void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture);
 
-	void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
-	void draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, int p_max_lines = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
+	void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint16_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
+	void draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, int p_max_lines = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint16_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
 	real_t draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0)) const;
 
 	void draw_set_transform(const Point2 &p_offset, real_t p_rot = 0.0, const Size2 &p_scale = Size2(1.0, 1.0));

+ 4 - 4
scene/resources/font.cpp

@@ -1404,7 +1404,7 @@ real_t Font::get_underline_thickness(int p_size) const {
 	return ret;
 }
 
-Size2 Font::get_string_size(const String &p_text, int p_size, HAlign p_align, real_t p_width, uint8_t p_flags) const {
+Size2 Font::get_string_size(const String &p_text, int p_size, HAlign p_align, real_t p_width, uint16_t p_flags) const {
 	ERR_FAIL_COND_V(data.is_empty(), Size2());
 
 	int size = (p_size <= 0) ? base_size : p_size;
@@ -1431,7 +1431,7 @@ Size2 Font::get_string_size(const String &p_text, int p_size, HAlign p_align, re
 	return buffer->get_size();
 }
 
-Size2 Font::get_multiline_string_size(const String &p_text, real_t p_width, int p_size, uint8_t p_flags) const {
+Size2 Font::get_multiline_string_size(const String &p_text, real_t p_width, int p_size, uint16_t p_flags) const {
 	ERR_FAIL_COND_V(data.is_empty(), Size2());
 
 	int size = (p_size <= 0) ? base_size : p_size;
@@ -1470,7 +1470,7 @@ Size2 Font::get_multiline_string_size(const String &p_text, real_t p_width, int
 	return ret;
 }
 
-void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align, real_t p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
+void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align, real_t p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint16_t p_flags) const {
 	ERR_FAIL_COND(data.is_empty());
 
 	int size = (p_size <= 0) ? base_size : p_size;
@@ -1512,7 +1512,7 @@ void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_t
 	buffer->draw(p_canvas_item, ofs, p_modulate);
 }
 
-void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align, float p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
+void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align, float p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint16_t p_flags) const {
 	ERR_FAIL_COND(data.is_empty());
 
 	int size = (p_size <= 0) ? base_size : p_size;

+ 4 - 4
scene/resources/font.h

@@ -266,11 +266,11 @@ public:
 	virtual real_t get_underline_thickness(int p_size = -1) const;
 
 	// Drawing string.
-	virtual Size2 get_string_size(const String &p_text, int p_size = -1, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, uint8_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
-	virtual Size2 get_multiline_string_size(const String &p_text, real_t p_width = -1, int p_size = -1, uint8_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND) const;
+	virtual Size2 get_string_size(const String &p_text, int p_size = -1, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, uint16_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
+	virtual Size2 get_multiline_string_size(const String &p_text, real_t p_width = -1, int p_size = -1, uint16_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND) const;
 
-	virtual void draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
-	virtual void draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, int p_max_lines = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
+	virtual void draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint16_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
+	virtual void draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, int p_max_lines = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint16_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
 
 	// Helper functions.
 	virtual bool has_char(char32_t p_char) const;

+ 5 - 13
scene/resources/text_line.cpp

@@ -53,7 +53,7 @@ void TextLine::_bind_methods() {
 
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "preserve_control"), "set_preserve_control", "get_preserve_control");
 
-	ClassDB::bind_method(D_METHOD("set_bidi_override", "override"), &TextLine::_set_bidi_override);
+	ClassDB::bind_method(D_METHOD("set_bidi_override", "override"), &TextLine::set_bidi_override);
 
 	ClassDB::bind_method(D_METHOD("add_string", "text", "fonts", "size", "opentype_features", "language"), &TextLine::add_string, DEFVAL(Dictionary()), DEFVAL(""));
 	ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextLine::add_object, DEFVAL(INLINE_ALIGN_CENTER), DEFVAL(1));
@@ -112,7 +112,7 @@ void TextLine::_shape() {
 			TS->shaped_text_tab_align(rid, tab_stops);
 		}
 
-		uint8_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
+		uint16_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
 		if (overrun_behavior != OVERRUN_NO_TRIMMING) {
 			switch (overrun_behavior) {
 				case OVERRUN_TRIM_WORD_ELLIPSIS:
@@ -195,15 +195,7 @@ TextServer::Orientation TextLine::get_orientation() const {
 	return TS->shaped_text_get_orientation(rid);
 }
 
-void TextLine::_set_bidi_override(const Array &p_override) {
-	Vector<Vector2i> overrides;
-	for (int i = 0; i < p_override.size(); i++) {
-		overrides.push_back(p_override[i]);
-	}
-	set_bidi_override(overrides);
-}
-
-void TextLine::set_bidi_override(const Vector<Vector2i> &p_override) {
+void TextLine::set_bidi_override(const Array &p_override) {
 	TS->shaped_text_set_bidi_override(rid, p_override);
 	dirty = true;
 }
@@ -256,14 +248,14 @@ void TextLine::tab_align(const Vector<float> &p_tab_stops) {
 	dirty = true;
 }
 
-void TextLine::set_flags(uint8_t p_flags) {
+void TextLine::set_flags(uint16_t p_flags) {
 	if (flags != p_flags) {
 		flags = p_flags;
 		dirty = true;
 	}
 }
 
-uint8_t TextLine::get_flags() const {
+uint16_t TextLine::get_flags() const {
 	return flags;
 }
 

+ 4 - 6
scene/resources/text_line.h

@@ -56,7 +56,7 @@ private:
 	bool dirty = true;
 
 	float width = -1.0;
-	uint8_t flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
+	uint16_t flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
 	HAlign align = HALIGN_LEFT;
 	OverrunBehavior overrun_behavior = OVERRUN_TRIM_ELLIPSIS;
 
@@ -75,7 +75,7 @@ public:
 	void set_direction(TextServer::Direction p_direction);
 	TextServer::Direction get_direction() const;
 
-	void set_bidi_override(const Vector<Vector2i> &p_override);
+	void set_bidi_override(const Array &p_override);
 
 	void set_orientation(TextServer::Orientation p_orientation);
 	TextServer::Orientation get_orientation() const;
@@ -95,8 +95,8 @@ public:
 
 	void tab_align(const Vector<float> &p_tab_stops);
 
-	void set_flags(uint8_t p_flags);
-	uint8_t get_flags() const;
+	void set_flags(uint16_t p_flags);
+	uint16_t get_flags() const;
 
 	void set_text_overrun_behavior(OverrunBehavior p_behavior);
 	OverrunBehavior get_text_overrun_behavior() const;
@@ -120,8 +120,6 @@ public:
 
 	int hit_test(float p_coords) const;
 
-	void _set_bidi_override(const Array &p_override);
-
 	TextLine(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
 	TextLine();
 	~TextLine();

+ 12 - 20
scene/resources/text_paragraph.cpp

@@ -53,7 +53,7 @@ void TextParagraph::_bind_methods() {
 
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "preserve_control"), "set_preserve_control", "get_preserve_control");
 
-	ClassDB::bind_method(D_METHOD("set_bidi_override", "override"), &TextParagraph::_set_bidi_override);
+	ClassDB::bind_method(D_METHOD("set_bidi_override", "override"), &TextParagraph::set_bidi_override);
 
 	ClassDB::bind_method(D_METHOD("set_dropcap", "text", "fonts", "size", "dropcap_margins", "opentype_features", "language"), &TextParagraph::set_dropcap, DEFVAL(Rect2()), DEFVAL(Dictionary()), DEFVAL(""));
 	ClassDB::bind_method(D_METHOD("clear_dropcap"), &TextParagraph::clear_dropcap);
@@ -158,9 +158,9 @@ void TextParagraph::_shape_lines() {
 
 		if (h_offset > 0) {
 			// Dropcap, flow around.
-			Vector<Vector2i> line_breaks = TS->shaped_text_get_line_breaks(rid, width - h_offset, 0, flags);
-			for (int i = 0; i < line_breaks.size(); i++) {
-				RID line = TS->shaped_text_substr(rid, line_breaks[i].x, line_breaks[i].y - line_breaks[i].x);
+			PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(rid, width - h_offset, 0, flags);
+			for (int i = 0; i < line_breaks.size(); i = i + 2) {
+				RID line = TS->shaped_text_substr(rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]);
 				float h = (TS->shaped_text_get_orientation(line) == TextServer::ORIENTATION_HORIZONTAL) ? TS->shaped_text_get_size(line).y : TS->shaped_text_get_size(line).x;
 				if (v_offset < h) {
 					TS->free(line);
@@ -171,21 +171,21 @@ void TextParagraph::_shape_lines() {
 				}
 				dropcap_lines++;
 				v_offset -= h;
-				start = line_breaks[i].y;
+				start = line_breaks[i + 1];
 				lines_rid.push_back(line);
 			}
 		}
 		// Use fixed for the rest of lines.
-		Vector<Vector2i> line_breaks = TS->shaped_text_get_line_breaks(rid, width, start, flags);
-		for (int i = 0; i < line_breaks.size(); i++) {
-			RID line = TS->shaped_text_substr(rid, line_breaks[i].x, line_breaks[i].y - line_breaks[i].x);
+		PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(rid, width, start, flags);
+		for (int i = 0; i < line_breaks.size(); i = i + 2) {
+			RID line = TS->shaped_text_substr(rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]);
 			if (!tab_stops.is_empty()) {
 				TS->shaped_text_tab_align(line, tab_stops);
 			}
 			lines_rid.push_back(line);
 		}
 
-		uint8_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
+		uint16_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
 		if (overrun_behavior != OVERRUN_NO_TRIMMING) {
 			switch (overrun_behavior) {
 				case OVERRUN_TRIM_WORD_ELLIPSIS:
@@ -347,15 +347,7 @@ int TextParagraph::get_spacing_bottom() const {
 	return spacing_bottom;
 }
 
-void TextParagraph::_set_bidi_override(const Array &p_override) {
-	Vector<Vector2i> overrides;
-	for (int i = 0; i < p_override.size(); i++) {
-		overrides.push_back(p_override[i]);
-	}
-	set_bidi_override(overrides);
-}
-
-void TextParagraph::set_bidi_override(const Vector<Vector2i> &p_override) {
+void TextParagraph::set_bidi_override(const Array &p_override) {
 	TS->shaped_text_set_bidi_override(rid, p_override);
 	lines_dirty = true;
 }
@@ -392,14 +384,14 @@ void TextParagraph::tab_align(const Vector<float> &p_tab_stops) {
 	lines_dirty = true;
 }
 
-void TextParagraph::set_flags(uint8_t p_flags) {
+void TextParagraph::set_flags(uint16_t p_flags) {
 	if (flags != p_flags) {
 		flags = p_flags;
 		lines_dirty = true;
 	}
 }
 
-uint8_t TextParagraph::get_flags() const {
+uint16_t TextParagraph::get_flags() const {
 	return flags;
 }
 

+ 4 - 6
scene/resources/text_paragraph.h

@@ -63,7 +63,7 @@ private:
 	float width = -1.0;
 	int max_lines_visible = -1;
 
-	uint8_t flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
+	uint16_t flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA;
 	OverrunBehavior overrun_behavior = OVERRUN_NO_TRIMMING;
 
 	HAlign align = HALIGN_LEFT;
@@ -94,7 +94,7 @@ public:
 	void set_preserve_control(bool p_enabled);
 	bool get_preserve_control() const;
 
-	void set_bidi_override(const Vector<Vector2i> &p_override);
+	void set_bidi_override(const Array &p_override);
 
 	bool set_dropcap(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "");
 	void clear_dropcap();
@@ -108,8 +108,8 @@ public:
 
 	void tab_align(const Vector<float> &p_tab_stops);
 
-	void set_flags(uint8_t p_flags);
-	uint8_t get_flags() const;
+	void set_flags(uint16_t p_flags);
+	uint16_t get_flags() const;
 
 	void set_text_overrun_behavior(OverrunBehavior p_behavior);
 	OverrunBehavior get_text_overrun_behavior() const;
@@ -153,8 +153,6 @@ public:
 
 	int hit_test(const Point2 &p_coords) const;
 
-	void _set_bidi_override(const Array &p_override);
-
 	TextParagraph(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "", float p_width = -1.f, TextServer::Direction p_direction = TextServer::DIRECTION_AUTO, TextServer::Orientation p_orientation = TextServer::ORIENTATION_HORIZONTAL);
 	TextParagraph();
 	~TextParagraph();

+ 1 - 0
servers/SCsub

@@ -11,6 +11,7 @@ SConscript("physics_3d/SCsub")
 SConscript("physics_2d/SCsub")
 SConscript("rendering/SCsub")
 SConscript("audio/SCsub")
+SConscript("text/SCsub")
 
 lib = env.add_library("servers", env.servers_sources)
 

+ 6 - 12
servers/register_server_types.cpp

@@ -70,6 +70,7 @@
 #include "rendering/rendering_device_binds.h"
 #include "rendering_server.h"
 #include "servers/rendering/shader_types.h"
+#include "text/text_server_extension.h"
 #include "text_server.h"
 #include "xr/xr_interface.h"
 #include "xr/xr_interface_extension.h"
@@ -107,15 +108,11 @@ static bool has_server_feature_callback(const String &p_feature) {
 void preregister_server_types() {
 	shader_types = memnew(ShaderTypes);
 
-	GLOBAL_DEF("internationalization/rendering/text_driver", "");
-	String text_driver_options;
-	for (int i = 0; i < TextServerManager::get_interface_count(); i++) {
-		if (i > 0) {
-			text_driver_options += ",";
-		}
-		text_driver_options += TextServerManager::get_interface_name(i);
-	}
-	ProjectSettings::get_singleton()->set_custom_property_info("internationalization/rendering/text_driver", PropertyInfo(Variant::STRING, "internationalization/rendering/text_driver", PROPERTY_HINT_ENUM, text_driver_options));
+	GDREGISTER_CLASS(TextServerManager);
+	GDREGISTER_VIRTUAL_CLASS(TextServer);
+	GDREGISTER_CLASS(TextServerExtension);
+
+	Engine::get_singleton()->add_singleton(Engine::Singleton("TextServerManager", TextServerManager::get_singleton(), "TextServerManager"));
 }
 
 void register_server_types() {
@@ -125,8 +122,6 @@ void register_server_types() {
 	GDREGISTER_VIRTUAL_CLASS(RenderingServer);
 	GDREGISTER_CLASS(AudioServer);
 
-	GDREGISTER_CLASS(TextServerManager);
-	GDREGISTER_VIRTUAL_CLASS(TextServer);
 	TextServer::initialize_hex_code_box_fonts();
 
 	GDREGISTER_VIRTUAL_CLASS(PhysicsServer2D);
@@ -255,7 +250,6 @@ void register_server_singletons() {
 	Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3D", PhysicsServer3D::get_singleton(), "PhysicsServer3D"));
 	Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer2D", NavigationServer2D::get_singleton_mut(), "NavigationServer2D"));
 	Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer3D", NavigationServer3D::get_singleton_mut(), "NavigationServer3D"));
-	Engine::get_singleton()->add_singleton(Engine::Singleton("TextServerManager", TextServerManager::get_singleton(), "TextServerManager"));
 	Engine::get_singleton()->add_singleton(Engine::Singleton("XRServer", XRServer::get_singleton(), "XRServer"));
 	Engine::get_singleton()->add_singleton(Engine::Singleton("CameraServer", CameraServer::get_singleton(), "CameraServer"));
 }

+ 1 - 0
servers/rendering_server.cpp

@@ -2539,6 +2539,7 @@ void RenderingServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("canvas_item_add_rect", "item", "rect", "color"), &RenderingServer::canvas_item_add_rect);
 	ClassDB::bind_method(D_METHOD("canvas_item_add_circle", "item", "pos", "radius", "color"), &RenderingServer::canvas_item_add_circle);
 	ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect", "item", "rect", "texture", "tile", "modulate", "transpose"), &RenderingServer::canvas_item_add_texture_rect, DEFVAL(false), DEFVAL(Color(1, 1, 1)), DEFVAL(false));
+	ClassDB::bind_method(D_METHOD("canvas_item_add_msdf_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "outline_size", "px_range"), &RenderingServer::canvas_item_add_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(1.0));
 	ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "transpose", "clip_uv"), &RenderingServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(true));
 	ClassDB::bind_method(D_METHOD("canvas_item_add_nine_patch", "item", "rect", "source", "texture", "topleft", "bottomright", "x_axis_mode", "y_axis_mode", "draw_center", "modulate"), &RenderingServer::canvas_item_add_nine_patch, DEFVAL(NINE_PATCH_STRETCH), DEFVAL(NINE_PATCH_STRETCH), DEFVAL(true), DEFVAL(Color(1, 1, 1)));
 	ClassDB::bind_method(D_METHOD("canvas_item_add_primitive", "item", "points", "colors", "uvs", "texture", "width"), &RenderingServer::canvas_item_add_primitive, DEFVAL(1.0));

+ 5 - 0
servers/text/SCsub

@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.servers_sources, "*.cpp")

+ 1281 - 0
servers/text/text_server_extension.cpp

@@ -0,0 +1,1281 @@
+/*************************************************************************/
+/*  text_server_extension.cpp                                            */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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_extension.h"
+
+void TextServerExtension::_bind_methods() {
+	GDVIRTUAL_BIND(_has_feature, "feature");
+	GDVIRTUAL_BIND(_get_name);
+	GDVIRTUAL_BIND(_get_features);
+
+	GDVIRTUAL_BIND(_free, "rid");
+	GDVIRTUAL_BIND(_has, "rid");
+	GDVIRTUAL_BIND(_load_support_data, "filename");
+
+	GDVIRTUAL_BIND(_get_support_data_filename);
+	GDVIRTUAL_BIND(_get_support_data_info);
+	GDVIRTUAL_BIND(_save_support_data, "filename");
+
+	GDVIRTUAL_BIND(_is_locale_right_to_left, "locale");
+
+	GDVIRTUAL_BIND(_name_to_tag, "name");
+	GDVIRTUAL_BIND(_tag_to_name, "tag");
+
+	/* Font interface */
+
+	GDVIRTUAL_BIND(_create_font);
+
+	GDVIRTUAL_BIND(_font_set_data, "font_rid", "data");
+	GDVIRTUAL_BIND(_font_set_data_ptr, "font_rid", "data_ptr", "data_size");
+
+	GDVIRTUAL_BIND(_font_set_antialiased, "font_rid", "antialiased");
+	GDVIRTUAL_BIND(_font_is_antialiased, "font_rid");
+
+	GDVIRTUAL_BIND(_font_set_multichannel_signed_distance_field, "font_rid", "msdf");
+	GDVIRTUAL_BIND(_font_is_multichannel_signed_distance_field, "font_rid");
+
+	GDVIRTUAL_BIND(_font_set_msdf_pixel_range, "font_rid", "msdf_pixel_range");
+	GDVIRTUAL_BIND(_font_get_msdf_pixel_range, "font_rid");
+
+	GDVIRTUAL_BIND(_font_set_msdf_size, "font_rid", "msdf_size");
+	GDVIRTUAL_BIND(_font_get_msdf_size, "font_rid");
+
+	GDVIRTUAL_BIND(_font_set_fixed_size, "font_rid", "fixed_size");
+	GDVIRTUAL_BIND(_font_get_fixed_size, "font_rid");
+
+	GDVIRTUAL_BIND(_font_set_force_autohinter, "font_rid", "force_autohinter");
+	GDVIRTUAL_BIND(_font_is_force_autohinter, "font_rid");
+
+	GDVIRTUAL_BIND(_font_set_hinting, "font_rid", "hinting");
+	GDVIRTUAL_BIND(_font_get_hinting, "font_rid");
+
+	GDVIRTUAL_BIND(_font_set_variation_coordinates, "font_rid", "variation_coordinates");
+	GDVIRTUAL_BIND(_font_get_variation_coordinates, "font_rid");
+
+	GDVIRTUAL_BIND(_font_set_oversampling, "font_rid", "oversampling");
+	GDVIRTUAL_BIND(_font_get_oversampling, "font_rid");
+
+	GDVIRTUAL_BIND(_font_get_size_cache_list, "font_rid");
+	GDVIRTUAL_BIND(_font_clear_size_cache, "font_rid");
+	GDVIRTUAL_BIND(_font_remove_size_cache, "font_rid", "size");
+
+	GDVIRTUAL_BIND(_font_set_ascent, "font_rid", "size", "ascent");
+	GDVIRTUAL_BIND(_font_get_ascent, "font_rid", "size");
+
+	GDVIRTUAL_BIND(_font_set_descent, "font_rid", "size", "descent");
+	GDVIRTUAL_BIND(_font_get_descent, "font_rid", "size");
+
+	GDVIRTUAL_BIND(_font_set_underline_position, "font_rid", "size", "underline_position");
+	GDVIRTUAL_BIND(_font_get_underline_position, "font_rid", "size");
+
+	GDVIRTUAL_BIND(_font_set_underline_thickness, "font_rid", "size", "underline_thickness");
+	GDVIRTUAL_BIND(_font_get_underline_thickness, "font_rid", "size");
+
+	GDVIRTUAL_BIND(_font_set_scale, "font_rid", "size", "scale");
+	GDVIRTUAL_BIND(_font_get_scale, "font_rid", "size");
+
+	GDVIRTUAL_BIND(_font_set_spacing, "font_rid", "size", "spacing", "value");
+	GDVIRTUAL_BIND(_font_get_spacing, "font_rid", "size", "spacing");
+
+	GDVIRTUAL_BIND(_font_get_texture_count, "font_rid", "size");
+	GDVIRTUAL_BIND(_font_clear_textures, "font_rid", "size");
+	GDVIRTUAL_BIND(_font_remove_texture, "font_rid", "size", "texture_index");
+
+	GDVIRTUAL_BIND(_font_set_texture_image, "font_rid", "size", "texture_index", "image");
+	GDVIRTUAL_BIND(_font_get_texture_image, "font_rid", "size", "texture_index");
+
+	GDVIRTUAL_BIND(_font_set_texture_offsets, "font_rid", "size", "texture_index", "offset");
+	GDVIRTUAL_BIND(_font_get_texture_offsets, "font_rid", "size", "texture_index");
+
+	GDVIRTUAL_BIND(_font_get_glyph_list, "font_rid", "size");
+	GDVIRTUAL_BIND(_font_clear_glyphs, "font_rid", "size");
+	GDVIRTUAL_BIND(_font_remove_glyph, "font_rid", "size", "glyph");
+
+	GDVIRTUAL_BIND(_font_get_glyph_advance, "font_rid", "size", "glyph");
+	GDVIRTUAL_BIND(_font_set_glyph_advance, "font_rid", "size", "glyph", "advance");
+
+	GDVIRTUAL_BIND(_font_get_glyph_offset, "font_rid", "size", "glyph");
+	GDVIRTUAL_BIND(_font_set_glyph_offset, "font_rid", "size", "glyph", "offset");
+
+	GDVIRTUAL_BIND(_font_get_glyph_size, "font_rid", "size", "glyph");
+	GDVIRTUAL_BIND(_font_set_glyph_size, "font_rid", "size", "glyph", "gl_size");
+
+	GDVIRTUAL_BIND(_font_get_glyph_uv_rect, "font_rid", "size", "glyph");
+	GDVIRTUAL_BIND(_font_set_glyph_uv_rect, "font_rid", "size", "glyph", "uv_rect");
+
+	GDVIRTUAL_BIND(_font_get_glyph_texture_idx, "font_rid", "size", "glyph");
+	GDVIRTUAL_BIND(_font_set_glyph_texture_idx, "font_rid", "size", "glyph", "texture_idx");
+
+	GDVIRTUAL_BIND(_font_get_glyph_contours, "font_rid", "size", "index");
+
+	GDVIRTUAL_BIND(_font_get_kerning_list, "font_rid", "size");
+	GDVIRTUAL_BIND(_font_clear_kerning_map, "font_rid", "size");
+	GDVIRTUAL_BIND(_font_remove_kerning, "font_rid", "size", "glyph_pair");
+
+	GDVIRTUAL_BIND(_font_set_kerning, "font_rid", "size", "glyph_pair", "kerning");
+	GDVIRTUAL_BIND(_font_get_kerning, "font_rid", "size", "glyph_pair");
+
+	GDVIRTUAL_BIND(_font_get_glyph_index, "font_rid", "size", "char", "variation_selector");
+
+	GDVIRTUAL_BIND(_font_has_char, "font_rid", "char");
+	GDVIRTUAL_BIND(_font_get_supported_chars, "font_rid");
+
+	GDVIRTUAL_BIND(_font_render_range, "font_rid", "size", "start", "end");
+	GDVIRTUAL_BIND(_font_render_glyph, "font_rid", "size", "index");
+
+	GDVIRTUAL_BIND(_font_draw_glyph, "font_rid", "canvas", "size", "pos", "index", "color");
+	GDVIRTUAL_BIND(_font_draw_glyph_outline, "font_rid", "canvas", "size", "outline_size", "pos", "index", "color");
+
+	GDVIRTUAL_BIND(_font_is_language_supported, "font_rid", "language");
+	GDVIRTUAL_BIND(_font_set_language_support_override, "font_rid", "language", "supported");
+	GDVIRTUAL_BIND(_font_get_language_support_override, "font_rid", "language");
+	GDVIRTUAL_BIND(_font_remove_language_support_override, "font_rid", "language");
+	GDVIRTUAL_BIND(_font_get_language_support_overrides, "font_rid");
+
+	GDVIRTUAL_BIND(_font_is_script_supported, "font_rid", "script");
+	GDVIRTUAL_BIND(_font_set_script_support_override, "font_rid", "script", "supported");
+	GDVIRTUAL_BIND(_font_get_script_support_override, "font_rid", "script");
+	GDVIRTUAL_BIND(_font_remove_script_support_override, "font_rid", "script");
+	GDVIRTUAL_BIND(_font_get_script_support_overrides, "font_rid");
+
+	GDVIRTUAL_BIND(_font_supported_feature_list, "font_rid");
+	GDVIRTUAL_BIND(_font_supported_variation_list, "font_rid");
+
+	GDVIRTUAL_BIND(_font_get_global_oversampling);
+	GDVIRTUAL_BIND(_font_set_global_oversampling, "oversampling");
+
+	GDVIRTUAL_BIND(_get_hex_code_box_size, "size", "index");
+	GDVIRTUAL_BIND(_draw_hex_code_box, "canvas", "size", "pos", "index", "color");
+
+	/* Shaped text buffer interface */
+
+	GDVIRTUAL_BIND(_create_shaped_text, "direction", "orientation");
+
+	GDVIRTUAL_BIND(_shaped_text_clear, "shaped");
+
+	GDVIRTUAL_BIND(_shaped_text_set_direction, "shaped", "direction");
+	GDVIRTUAL_BIND(_shaped_text_get_direction, "shaped");
+
+	GDVIRTUAL_BIND(_shaped_text_set_bidi_override, "shaped", "override");
+
+	GDVIRTUAL_BIND(_shaped_text_set_orientation, "shaped", "orientation");
+	GDVIRTUAL_BIND(_shaped_text_get_orientation, "shaped");
+
+	GDVIRTUAL_BIND(_shaped_text_set_preserve_invalid, "shaped", "enabled");
+	GDVIRTUAL_BIND(_shaped_text_get_preserve_invalid, "shaped");
+
+	GDVIRTUAL_BIND(_shaped_text_set_preserve_control, "shaped", "enabled");
+	GDVIRTUAL_BIND(_shaped_text_get_preserve_control, "shaped");
+
+	GDVIRTUAL_BIND(_shaped_text_add_string, "shaped", "text", "fonts", "size", "opentype_features", "language");
+	GDVIRTUAL_BIND(_shaped_text_add_object, "shaped", "key", "size", "inline_align", "length");
+	GDVIRTUAL_BIND(_shaped_text_resize_object, "shaped", "key", "size", "inline_align");
+
+	GDVIRTUAL_BIND(_shaped_text_substr, "shaped", "start", "length");
+	GDVIRTUAL_BIND(_shaped_text_get_parent, "shaped");
+
+	GDVIRTUAL_BIND(_shaped_text_fit_to_width, "shaped", "width", "jst_flags");
+	GDVIRTUAL_BIND(_shaped_text_tab_align, "shaped", "tab_stops");
+
+	GDVIRTUAL_BIND(_shaped_text_shape, "shaped");
+	GDVIRTUAL_BIND(_shaped_text_update_breaks, "shaped");
+	GDVIRTUAL_BIND(_shaped_text_update_justification_ops, "shaped");
+
+	GDVIRTUAL_BIND(_shaped_text_is_ready, "shaped");
+
+	GDVIRTUAL_BIND(_shaped_text_get_glyphs, "shaped", "r_glyphs");
+	GDVIRTUAL_BIND(_shaped_text_sort_logical, "shaped", "r_glyphs");
+	GDVIRTUAL_BIND(_shaped_text_get_glyph_count, "shaped");
+
+	GDVIRTUAL_BIND(_shaped_text_get_range, "shaped");
+
+	GDVIRTUAL_BIND(_shaped_text_get_line_breaks_adv, "shaped", "width", "start", "once", "break_flags");
+	GDVIRTUAL_BIND(_shaped_text_get_line_breaks, "shaped", "width", "start", "break_flags");
+	GDVIRTUAL_BIND(_shaped_text_get_word_breaks, "shaped", "grapheme_flags");
+
+	GDVIRTUAL_BIND(_shaped_text_get_trim_pos, "shaped");
+	GDVIRTUAL_BIND(_shaped_text_get_ellipsis_pos, "shaped");
+	GDVIRTUAL_BIND(_shaped_text_get_ellipsis_glyph_count, "shaped");
+	GDVIRTUAL_BIND(_shaped_text_get_ellipsis_glyphs, "shaped", "r_glyphs");
+
+	GDVIRTUAL_BIND(_shaped_text_overrun_trim_to_width, "shaped", "width", "trim_flags");
+
+	GDVIRTUAL_BIND(_shaped_text_get_objects, "shaped");
+	GDVIRTUAL_BIND(_shaped_text_get_object_rect, "shaped", "key");
+
+	GDVIRTUAL_BIND(_shaped_text_get_size, "shaped");
+	GDVIRTUAL_BIND(_shaped_text_get_ascent, "shaped");
+	GDVIRTUAL_BIND(_shaped_text_get_descent, "shaped");
+	GDVIRTUAL_BIND(_shaped_text_get_width, "shaped");
+	GDVIRTUAL_BIND(_shaped_text_get_underline_position, "shaped");
+	GDVIRTUAL_BIND(_shaped_text_get_underline_thickness, "shaped");
+
+	GDVIRTUAL_BIND(_shaped_text_get_dominant_direction_in_range, "shaped", "start", "end");
+
+	GDVIRTUAL_BIND(_shaped_text_get_carets, "shaped", "position", "caret");
+	GDVIRTUAL_BIND(_shaped_text_get_selection, "shaped", "start", "end");
+
+	GDVIRTUAL_BIND(_shaped_text_hit_test_grapheme, "shaped", "coord");
+	GDVIRTUAL_BIND(_shaped_text_hit_test_position, "shaped", "coord");
+
+	GDVIRTUAL_BIND(_shaped_text_draw, "shaped", "canvas", "pos", "clip_l", "clip_r", "color");
+	GDVIRTUAL_BIND(_shaped_text_draw_outline, "shaped", "canvas", "pos", "clip_l", "clip_r", "outline_size", "color");
+
+	GDVIRTUAL_BIND(_shaped_text_next_grapheme_pos, "shaped", "pos");
+	GDVIRTUAL_BIND(_shaped_text_prev_grapheme_pos, "shaped", "pos");
+
+	GDVIRTUAL_BIND(_format_number, "string", "language");
+	GDVIRTUAL_BIND(_parse_number, "string", "language");
+	GDVIRTUAL_BIND(_percent_sign, "language");
+}
+
+bool TextServerExtension::has_feature(Feature p_feature) const {
+	bool ret;
+	if (GDVIRTUAL_CALL(_has_feature, p_feature, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+String TextServerExtension::get_name() const {
+	String ret;
+	if (GDVIRTUAL_CALL(_get_name, ret)) {
+		return ret;
+	}
+	return "Unknown";
+}
+
+uint32_t TextServerExtension::get_features() const {
+	uint32_t ret;
+	if (GDVIRTUAL_CALL(_get_features, ret)) {
+		return ret;
+	}
+	return 0;
+}
+
+void TextServerExtension::free(RID p_rid) {
+	GDVIRTUAL_CALL(_free, p_rid);
+}
+
+bool TextServerExtension::has(RID p_rid) {
+	bool ret;
+	if (GDVIRTUAL_CALL(_has, p_rid, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+bool TextServerExtension::load_support_data(const String &p_filename) {
+	bool ret;
+	if (GDVIRTUAL_CALL(_load_support_data, p_filename, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+String TextServerExtension::get_support_data_filename() const {
+	String ret;
+	if (GDVIRTUAL_CALL(_get_support_data_filename, ret)) {
+		return ret;
+	}
+	return String();
+}
+
+String TextServerExtension::get_support_data_info() const {
+	String ret;
+	if (GDVIRTUAL_CALL(_get_support_data_info, ret)) {
+		return ret;
+	}
+	return String();
+}
+
+bool TextServerExtension::save_support_data(const String &p_filename) const {
+	bool ret;
+	if (GDVIRTUAL_CALL(_save_support_data, p_filename, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+bool TextServerExtension::is_locale_right_to_left(const String &p_locale) const {
+	bool ret;
+	if (GDVIRTUAL_CALL(_is_locale_right_to_left, p_locale, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+int32_t TextServerExtension::name_to_tag(const String &p_name) const {
+	int32_t ret;
+	if (GDVIRTUAL_CALL(_name_to_tag, p_name, ret)) {
+		return ret;
+	}
+	return 0;
+}
+
+String TextServerExtension::tag_to_name(int32_t p_tag) const {
+	String ret;
+	if (GDVIRTUAL_CALL(_tag_to_name, p_tag, ret)) {
+		return ret;
+	}
+	return "";
+}
+
+/*************************************************************************/
+/* Font                                                                  */
+/*************************************************************************/
+
+RID TextServerExtension::create_font() {
+	RID ret;
+	if (GDVIRTUAL_CALL(_create_font, ret)) {
+		return ret;
+	}
+	return RID();
+}
+
+void TextServerExtension::font_set_data(RID p_font_rid, const PackedByteArray &p_data) {
+	GDVIRTUAL_CALL(_font_set_data, p_font_rid, p_data);
+}
+
+void TextServerExtension::font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) {
+	GDVIRTUAL_CALL(_font_set_data_ptr, p_font_rid, p_data_ptr, p_data_size);
+}
+
+void TextServerExtension::font_set_antialiased(RID p_font_rid, bool p_antialiased) {
+	GDVIRTUAL_CALL(_font_set_antialiased, p_font_rid, p_antialiased);
+}
+
+bool TextServerExtension::font_is_antialiased(RID p_font_rid) const {
+	bool ret;
+	if (GDVIRTUAL_CALL(_font_is_antialiased, p_font_rid, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+void TextServerExtension::font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) {
+	GDVIRTUAL_CALL(_font_set_multichannel_signed_distance_field, p_font_rid, p_msdf);
+}
+
+bool TextServerExtension::font_is_multichannel_signed_distance_field(RID p_font_rid) const {
+	bool ret;
+	if (GDVIRTUAL_CALL(_font_is_multichannel_signed_distance_field, p_font_rid, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+void TextServerExtension::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) {
+	GDVIRTUAL_CALL(_font_set_msdf_pixel_range, p_font_rid, p_msdf_pixel_range);
+}
+
+int TextServerExtension::font_get_msdf_pixel_range(RID p_font_rid) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_font_get_msdf_pixel_range, p_font_rid, ret)) {
+		return ret;
+	}
+	return 0;
+}
+
+void TextServerExtension::font_set_msdf_size(RID p_font_rid, int p_msdf_size) {
+	GDVIRTUAL_CALL(_font_set_msdf_size, p_font_rid, p_msdf_size);
+}
+
+int TextServerExtension::font_get_msdf_size(RID p_font_rid) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_font_get_msdf_size, p_font_rid, ret)) {
+		return ret;
+	}
+	return 0;
+}
+
+void TextServerExtension::font_set_fixed_size(RID p_font_rid, int p_fixed_size) {
+	GDVIRTUAL_CALL(_font_set_fixed_size, p_font_rid, p_fixed_size);
+}
+
+int TextServerExtension::font_get_fixed_size(RID p_font_rid) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_font_get_fixed_size, p_font_rid, ret)) {
+		return ret;
+	}
+	return 0;
+}
+
+void TextServerExtension::font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) {
+	GDVIRTUAL_CALL(_font_set_force_autohinter, p_font_rid, p_force_autohinter);
+}
+
+bool TextServerExtension::font_is_force_autohinter(RID p_font_rid) const {
+	bool ret;
+	if (GDVIRTUAL_CALL(_font_is_force_autohinter, p_font_rid, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+void TextServerExtension::font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) {
+	GDVIRTUAL_CALL(_font_set_hinting, p_font_rid, p_hinting);
+}
+
+TextServer::Hinting TextServerExtension::font_get_hinting(RID p_font_rid) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_font_get_hinting, p_font_rid, ret)) {
+		return (TextServer::Hinting)ret;
+	}
+	return TextServer::Hinting::HINTING_NONE;
+}
+
+void TextServerExtension::font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) {
+	GDVIRTUAL_CALL(_font_set_variation_coordinates, p_font_rid, p_variation_coordinates);
+}
+
+Dictionary TextServerExtension::font_get_variation_coordinates(RID p_font_rid) const {
+	Dictionary ret;
+	if (GDVIRTUAL_CALL(_font_get_variation_coordinates, p_font_rid, ret)) {
+		return ret;
+	}
+	return Dictionary();
+}
+
+void TextServerExtension::font_set_oversampling(RID p_font_rid, float p_oversampling) {
+	GDVIRTUAL_CALL(_font_set_oversampling, p_font_rid, p_oversampling);
+}
+
+float TextServerExtension::font_get_oversampling(RID p_font_rid) const {
+	float ret;
+	if (GDVIRTUAL_CALL(_font_get_oversampling, p_font_rid, ret)) {
+		return ret;
+	}
+	return 0.f;
+}
+
+Array TextServerExtension::font_get_size_cache_list(RID p_font_rid) const {
+	Array ret;
+	if (GDVIRTUAL_CALL(_font_get_size_cache_list, p_font_rid, ret)) {
+		return ret;
+	}
+	return Array();
+}
+
+void TextServerExtension::font_clear_size_cache(RID p_font_rid) {
+	GDVIRTUAL_CALL(_font_clear_size_cache, p_font_rid);
+}
+
+void TextServerExtension::font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) {
+	GDVIRTUAL_CALL(_font_remove_size_cache, p_font_rid, p_size);
+}
+
+void TextServerExtension::font_set_ascent(RID p_font_rid, int p_size, float p_ascent) {
+	GDVIRTUAL_CALL(_font_set_ascent, p_font_rid, p_size, p_ascent);
+}
+
+float TextServerExtension::font_get_ascent(RID p_font_rid, int p_size) const {
+	float ret;
+	if (GDVIRTUAL_CALL(_font_get_ascent, p_font_rid, p_size, ret)) {
+		return ret;
+	}
+	return 0.f;
+}
+
+void TextServerExtension::font_set_descent(RID p_font_rid, int p_size, float p_descent) {
+	GDVIRTUAL_CALL(_font_set_descent, p_font_rid, p_size, p_descent);
+}
+
+float TextServerExtension::font_get_descent(RID p_font_rid, int p_size) const {
+	float ret;
+	if (GDVIRTUAL_CALL(_font_get_descent, p_font_rid, p_size, ret)) {
+		return ret;
+	}
+	return 0.f;
+}
+
+void TextServerExtension::font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) {
+	GDVIRTUAL_CALL(_font_set_underline_position, p_font_rid, p_size, p_underline_position);
+}
+
+float TextServerExtension::font_get_underline_position(RID p_font_rid, int p_size) const {
+	float ret;
+	if (GDVIRTUAL_CALL(_font_get_underline_position, p_font_rid, p_size, ret)) {
+		return ret;
+	}
+	return 0.f;
+}
+
+void TextServerExtension::font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) {
+	GDVIRTUAL_CALL(_font_set_underline_thickness, p_font_rid, p_size, p_underline_thickness);
+}
+
+float TextServerExtension::font_get_underline_thickness(RID p_font_rid, int p_size) const {
+	float ret;
+	if (GDVIRTUAL_CALL(_font_get_underline_thickness, p_font_rid, p_size, ret)) {
+		return ret;
+	}
+	return 0.f;
+}
+
+void TextServerExtension::font_set_scale(RID p_font_rid, int p_size, float p_scale) {
+	GDVIRTUAL_CALL(_font_set_scale, p_font_rid, p_size, p_scale);
+}
+
+float TextServerExtension::font_get_scale(RID p_font_rid, int p_size) const {
+	float ret;
+	if (GDVIRTUAL_CALL(_font_get_scale, p_font_rid, p_size, ret)) {
+		return ret;
+	}
+	return 0.f;
+}
+
+void TextServerExtension::font_set_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing, int p_value) {
+	GDVIRTUAL_CALL(_font_set_spacing, p_font_rid, p_size, p_spacing, p_value);
+}
+
+int TextServerExtension::font_get_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_font_get_spacing, p_font_rid, p_size, p_spacing, ret)) {
+		return ret;
+	}
+	return 0;
+}
+
+int TextServerExtension::font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_font_get_texture_count, p_font_rid, p_size, ret)) {
+		return ret;
+	}
+	return 0;
+}
+
+void TextServerExtension::font_clear_textures(RID p_font_rid, const Vector2i &p_size) {
+	GDVIRTUAL_CALL(_font_clear_textures, p_font_rid, p_size);
+}
+
+void TextServerExtension::font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) {
+	GDVIRTUAL_CALL(_font_remove_texture, p_font_rid, p_size, p_texture_index);
+}
+
+void TextServerExtension::font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) {
+	GDVIRTUAL_CALL(_font_set_texture_image, p_font_rid, p_size, p_texture_index, p_image);
+}
+
+Ref<Image> TextServerExtension::font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const {
+	Ref<Image> ret;
+	if (GDVIRTUAL_CALL(_font_get_texture_image, p_font_rid, p_size, p_texture_index, ret)) {
+		return ret;
+	}
+	return Ref<Image>();
+}
+
+void TextServerExtension::font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) {
+	GDVIRTUAL_CALL(_font_set_texture_offsets, p_font_rid, p_size, p_texture_index, p_offset);
+}
+
+PackedInt32Array TextServerExtension::font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const {
+	PackedInt32Array ret;
+	if (GDVIRTUAL_CALL(_font_get_texture_offsets, p_font_rid, p_size, p_texture_index, ret)) {
+		return ret;
+	}
+	return PackedInt32Array();
+}
+
+Array TextServerExtension::font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const {
+	Array ret;
+	if (GDVIRTUAL_CALL(_font_get_glyph_list, p_font_rid, p_size, ret)) {
+		return ret;
+	}
+	return Array();
+}
+
+void TextServerExtension::font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) {
+	GDVIRTUAL_CALL(_font_clear_glyphs, p_font_rid, p_size);
+}
+
+void TextServerExtension::font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) {
+	GDVIRTUAL_CALL(_font_remove_glyph, p_font_rid, p_size, p_glyph);
+}
+
+Vector2 TextServerExtension::font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const {
+	Vector2 ret;
+	if (GDVIRTUAL_CALL(_font_get_glyph_advance, p_font_rid, p_size, p_glyph, ret)) {
+		return ret;
+	}
+	return Vector2();
+}
+
+void TextServerExtension::font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) {
+	GDVIRTUAL_CALL(_font_set_glyph_advance, p_font_rid, p_size, p_glyph, p_advance);
+}
+
+Vector2 TextServerExtension::font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
+	Vector2 ret;
+	if (GDVIRTUAL_CALL(_font_get_glyph_offset, p_font_rid, p_size, p_glyph, ret)) {
+		return ret;
+	}
+	return Vector2();
+}
+
+void TextServerExtension::font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) {
+	GDVIRTUAL_CALL(_font_set_glyph_offset, p_font_rid, p_size, p_glyph, p_offset);
+}
+
+Vector2 TextServerExtension::font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
+	Vector2 ret;
+	if (GDVIRTUAL_CALL(_font_get_glyph_size, p_font_rid, p_size, p_glyph, ret)) {
+		return ret;
+	}
+	return Vector2();
+}
+
+void TextServerExtension::font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) {
+	GDVIRTUAL_CALL(_font_set_glyph_size, p_font_rid, p_size, p_glyph, p_gl_size);
+}
+
+Rect2 TextServerExtension::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
+	Rect2 ret;
+	if (GDVIRTUAL_CALL(_font_get_glyph_uv_rect, p_font_rid, p_size, p_glyph, ret)) {
+		return ret;
+	}
+	return Rect2();
+}
+
+void TextServerExtension::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) {
+	GDVIRTUAL_CALL(_font_set_glyph_uv_rect, p_font_rid, p_size, p_glyph, p_uv_rect);
+}
+
+int TextServerExtension::font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_font_get_glyph_texture_idx, p_font_rid, p_size, p_glyph, ret)) {
+		return ret;
+	}
+	return 0;
+}
+
+void TextServerExtension::font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) {
+	GDVIRTUAL_CALL(_font_set_glyph_texture_idx, p_font_rid, p_size, p_glyph, p_texture_idx);
+}
+
+Dictionary TextServerExtension::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index) const {
+	Dictionary ret;
+	if (GDVIRTUAL_CALL(_font_get_glyph_contours, p_font_rid, p_size, p_index, ret)) {
+		return ret;
+	}
+	return Dictionary();
+}
+
+Array TextServerExtension::font_get_kerning_list(RID p_font_rid, int p_size) const {
+	Array ret;
+	if (GDVIRTUAL_CALL(_font_get_kerning_list, p_font_rid, p_size, ret)) {
+		return ret;
+	}
+	return Array();
+}
+
+void TextServerExtension::font_clear_kerning_map(RID p_font_rid, int p_size) {
+	GDVIRTUAL_CALL(_font_clear_kerning_map, p_font_rid, p_size);
+}
+
+void TextServerExtension::font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) {
+	GDVIRTUAL_CALL(_font_remove_kerning, p_font_rid, p_size, p_glyph_pair);
+}
+
+void TextServerExtension::font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
+	GDVIRTUAL_CALL(_font_set_kerning, p_font_rid, p_size, p_glyph_pair, p_kerning);
+}
+
+Vector2 TextServerExtension::font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const {
+	Vector2 ret;
+	if (GDVIRTUAL_CALL(_font_get_kerning, p_font_rid, p_size, p_glyph_pair, ret)) {
+		return ret;
+	}
+	return Vector2();
+}
+
+int32_t TextServerExtension::font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector) const {
+	int32_t ret;
+	if (GDVIRTUAL_CALL(_font_get_glyph_index, p_font_rid, p_size, p_char, p_variation_selector, ret)) {
+		return ret;
+	}
+	return 0;
+}
+
+bool TextServerExtension::font_has_char(RID p_font_rid, char32_t p_char) const {
+	bool ret;
+	if (GDVIRTUAL_CALL(_font_has_char, p_font_rid, p_char, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+String TextServerExtension::font_get_supported_chars(RID p_font_rid) const {
+	String ret;
+	if (GDVIRTUAL_CALL(_font_get_supported_chars, p_font_rid, ret)) {
+		return ret;
+	}
+	return String();
+}
+
+void TextServerExtension::font_render_range(RID p_font_rid, const Vector2i &p_size, char32_t p_start, char32_t p_end) {
+	GDVIRTUAL_CALL(_font_render_range, p_font_rid, p_size, p_start, p_end);
+}
+
+void TextServerExtension::font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) {
+	GDVIRTUAL_CALL(_font_render_glyph, p_font_rid, p_size, p_index);
+}
+
+void TextServerExtension::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const {
+	GDVIRTUAL_CALL(_font_draw_glyph, p_font_rid, p_canvas, p_size, p_pos, p_index, p_color);
+}
+
+void TextServerExtension::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const {
+	GDVIRTUAL_CALL(_font_draw_glyph_outline, p_font_rid, p_canvas, p_size, p_outline_size, p_pos, p_index, p_color);
+}
+
+bool TextServerExtension::font_is_language_supported(RID p_font_rid, const String &p_language) const {
+	bool ret;
+	if (GDVIRTUAL_CALL(_font_is_language_supported, p_font_rid, p_language, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+void TextServerExtension::font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) {
+	GDVIRTUAL_CALL(_font_set_language_support_override, p_font_rid, p_language, p_supported);
+}
+
+bool TextServerExtension::font_get_language_support_override(RID p_font_rid, const String &p_language) {
+	bool ret;
+	if (GDVIRTUAL_CALL(_font_get_language_support_override, p_font_rid, p_language, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+void TextServerExtension::font_remove_language_support_override(RID p_font_rid, const String &p_language) {
+	GDVIRTUAL_CALL(_font_remove_language_support_override, p_font_rid, p_language);
+}
+
+Vector<String> TextServerExtension::font_get_language_support_overrides(RID p_font_rid) {
+	Vector<String> ret;
+	if (GDVIRTUAL_CALL(_font_get_language_support_overrides, p_font_rid, ret)) {
+		return ret;
+	}
+	return Vector<String>();
+}
+
+bool TextServerExtension::font_is_script_supported(RID p_font_rid, const String &p_script) const {
+	bool ret;
+	if (GDVIRTUAL_CALL(_font_is_script_supported, p_font_rid, p_script, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+void TextServerExtension::font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) {
+	GDVIRTUAL_CALL(_font_set_script_support_override, p_font_rid, p_script, p_supported);
+}
+
+bool TextServerExtension::font_get_script_support_override(RID p_font_rid, const String &p_script) {
+	bool ret;
+	if (GDVIRTUAL_CALL(_font_get_script_support_override, p_font_rid, p_script, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+void TextServerExtension::font_remove_script_support_override(RID p_font_rid, const String &p_script) {
+	GDVIRTUAL_CALL(_font_remove_script_support_override, p_font_rid, p_script);
+}
+
+Vector<String> TextServerExtension::font_get_script_support_overrides(RID p_font_rid) {
+	Vector<String> ret;
+	if (GDVIRTUAL_CALL(_font_get_script_support_overrides, p_font_rid, ret)) {
+		return ret;
+	}
+	return Vector<String>();
+}
+
+Dictionary TextServerExtension::font_supported_feature_list(RID p_font_rid) const {
+	Dictionary ret;
+	if (GDVIRTUAL_CALL(_font_supported_feature_list, p_font_rid, ret)) {
+		return ret;
+	}
+	return Dictionary();
+}
+
+Dictionary TextServerExtension::font_supported_variation_list(RID p_font_rid) const {
+	Dictionary ret;
+	if (GDVIRTUAL_CALL(_font_supported_variation_list, p_font_rid, ret)) {
+		return ret;
+	}
+	return Dictionary();
+}
+
+float TextServerExtension::font_get_global_oversampling() const {
+	float ret;
+	if (GDVIRTUAL_CALL(_font_get_global_oversampling, ret)) {
+		return ret;
+	}
+	return 0.f;
+}
+
+void TextServerExtension::font_set_global_oversampling(float p_oversampling) {
+	GDVIRTUAL_CALL(_font_set_global_oversampling, p_oversampling);
+}
+
+Vector2 TextServerExtension::get_hex_code_box_size(int p_size, char32_t p_index) const {
+	Vector2 ret;
+	if (GDVIRTUAL_CALL(_get_hex_code_box_size, p_size, p_index, ret)) {
+		return ret;
+	}
+	return TextServer::get_hex_code_box_size(p_size, p_index);
+}
+
+void TextServerExtension::draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_pos, char32_t p_index, const Color &p_color) const {
+	if (!GDVIRTUAL_CALL(_draw_hex_code_box, p_canvas, p_size, p_pos, p_index, p_color)) {
+		TextServer::draw_hex_code_box(p_canvas, p_size, p_pos, p_index, p_color);
+	}
+}
+
+/*************************************************************************/
+/* Shaped text buffer interface                                          */
+/*************************************************************************/
+
+RID TextServerExtension::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
+	RID ret;
+	if (GDVIRTUAL_CALL(_create_shaped_text, p_direction, p_orientation, ret)) {
+		return ret;
+	}
+	return RID();
+}
+
+void TextServerExtension::shaped_text_clear(RID p_shaped) {
+	GDVIRTUAL_CALL(_shaped_text_clear, p_shaped);
+}
+
+void TextServerExtension::shaped_text_set_direction(RID p_shaped, TextServer::Direction p_direction) {
+	GDVIRTUAL_CALL(_shaped_text_set_direction, p_shaped, p_direction);
+}
+
+TextServer::Direction TextServerExtension::shaped_text_get_direction(RID p_shaped) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_direction, p_shaped, ret)) {
+		return (TextServer::Direction)ret;
+	}
+	return TextServer::Direction::DIRECTION_AUTO;
+}
+
+void TextServerExtension::shaped_text_set_orientation(RID p_shaped, TextServer::Orientation p_orientation) {
+	GDVIRTUAL_CALL(_shaped_text_set_orientation, p_shaped, p_orientation);
+}
+
+TextServer::Orientation TextServerExtension::shaped_text_get_orientation(RID p_shaped) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_orientation, p_shaped, ret)) {
+		return (TextServer::Orientation)ret;
+	}
+	return TextServer::Orientation::ORIENTATION_HORIZONTAL;
+}
+
+void TextServerExtension::shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) {
+	GDVIRTUAL_CALL(_shaped_text_set_bidi_override, p_shaped, p_override);
+}
+
+void TextServerExtension::shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) {
+	GDVIRTUAL_CALL(_shaped_text_set_preserve_invalid, p_shaped, p_enabled);
+}
+
+bool TextServerExtension::shaped_text_get_preserve_invalid(RID p_shaped) const {
+	bool ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_preserve_invalid, p_shaped, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+void TextServerExtension::shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) {
+	GDVIRTUAL_CALL(_shaped_text_set_preserve_control, p_shaped, p_enabled);
+}
+
+bool TextServerExtension::shaped_text_get_preserve_control(RID p_shaped) const {
+	bool ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_preserve_control, p_shaped, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+bool TextServerExtension::shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) {
+	bool ret;
+	Array fonts;
+	for (int i = 0; i < p_fonts.size(); i++) {
+		fonts.push_back(p_fonts[i]);
+	}
+	if (GDVIRTUAL_CALL(_shaped_text_add_string, p_shaped, p_text, fonts, p_size, p_opentype_features, p_language, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+bool TextServerExtension::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
+	bool ret;
+	if (GDVIRTUAL_CALL(_shaped_text_add_object, p_shaped, p_key, p_size, p_inline_align, p_length, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+bool TextServerExtension::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
+	bool ret;
+	if (GDVIRTUAL_CALL(_shaped_text_resize_object, p_shaped, p_key, p_size, p_inline_align, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+RID TextServerExtension::shaped_text_substr(RID p_shaped, int p_start, int p_length) const {
+	RID ret;
+	if (GDVIRTUAL_CALL(_shaped_text_substr, p_shaped, p_start, p_length, ret)) {
+		return ret;
+	}
+	return RID();
+}
+
+RID TextServerExtension::shaped_text_get_parent(RID p_shaped) const {
+	RID ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_parent, p_shaped, ret)) {
+		return ret;
+	}
+	return RID();
+}
+
+float TextServerExtension::shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t p_jst_flags) {
+	float ret;
+	if (GDVIRTUAL_CALL(_shaped_text_fit_to_width, p_shaped, p_width, p_jst_flags, ret)) {
+		return ret;
+	}
+	return 0.f;
+}
+
+float TextServerExtension::shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) {
+	float ret;
+	if (GDVIRTUAL_CALL(_shaped_text_tab_align, p_shaped, p_tab_stops, ret)) {
+		return ret;
+	}
+	return 0.f;
+}
+
+bool TextServerExtension::shaped_text_shape(RID p_shaped) {
+	bool ret;
+	if (GDVIRTUAL_CALL(_shaped_text_shape, p_shaped, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+bool TextServerExtension::shaped_text_update_breaks(RID p_shaped) {
+	bool ret;
+	if (GDVIRTUAL_CALL(_shaped_text_update_breaks, p_shaped, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+bool TextServerExtension::shaped_text_update_justification_ops(RID p_shaped) {
+	bool ret;
+	if (GDVIRTUAL_CALL(_shaped_text_update_justification_ops, p_shaped, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+bool TextServerExtension::shaped_text_is_ready(RID p_shaped) const {
+	bool ret;
+	if (GDVIRTUAL_CALL(_shaped_text_is_ready, p_shaped, ret)) {
+		return ret;
+	}
+	return false;
+}
+
+const Glyph *TextServerExtension::shaped_text_get_glyphs(RID p_shaped) const {
+	const Glyph *ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_glyphs, p_shaped, &ret)) {
+		return ret;
+	}
+	return nullptr;
+}
+
+const Glyph *TextServerExtension::shaped_text_sort_logical(RID p_shaped) {
+	const Glyph *ret;
+	if (GDVIRTUAL_CALL(_shaped_text_sort_logical, p_shaped, &ret)) {
+		return ret;
+	}
+	return nullptr;
+}
+
+int TextServerExtension::shaped_text_get_glyph_count(RID p_shaped) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_glyph_count, p_shaped, ret)) {
+		return ret;
+	}
+	return 0;
+}
+
+Vector2i TextServerExtension::shaped_text_get_range(RID p_shaped) const {
+	Vector2i ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_range, p_shaped, ret)) {
+		return ret;
+	}
+	return Vector2i();
+}
+
+PackedInt32Array TextServerExtension::shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start, bool p_once, uint16_t p_break_flags) const {
+	PackedInt32Array ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_line_breaks_adv, p_shaped, p_width, p_start, p_once, p_break_flags, ret)) {
+		return ret;
+	}
+	return TextServer::shaped_text_get_line_breaks_adv(p_shaped, p_width, p_start, p_once, p_break_flags);
+}
+
+PackedInt32Array TextServerExtension::shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start, uint16_t p_break_flags) const {
+	PackedInt32Array ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_line_breaks, p_shaped, p_width, p_start, p_break_flags, ret)) {
+		return ret;
+	}
+	return TextServer::shaped_text_get_line_breaks(p_shaped, p_width, p_start, p_break_flags);
+}
+
+PackedInt32Array TextServerExtension::shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags) const {
+	PackedInt32Array ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_word_breaks, p_shaped, p_grapheme_flags, ret)) {
+		return ret;
+	}
+	return TextServer::shaped_text_get_word_breaks(p_shaped, p_grapheme_flags);
+}
+
+int TextServerExtension::shaped_text_get_trim_pos(RID p_shaped) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_trim_pos, p_shaped, ret)) {
+		return ret;
+	}
+	return -1;
+}
+
+int TextServerExtension::shaped_text_get_ellipsis_pos(RID p_shaped) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_ellipsis_pos, p_shaped, ret)) {
+		return ret;
+	}
+	return -1;
+}
+
+const Glyph *TextServerExtension::shaped_text_get_ellipsis_glyphs(RID p_shaped) const {
+	const Glyph *ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_ellipsis_glyphs, p_shaped, &ret)) {
+		return ret;
+	}
+	return nullptr;
+}
+
+int TextServerExtension::shaped_text_get_ellipsis_glyph_count(RID p_shaped) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_ellipsis_glyph_count, p_shaped, ret)) {
+		return ret;
+	}
+	return -1;
+}
+
+void TextServerExtension::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint16_t p_trim_flags) {
+	GDVIRTUAL_CALL(_shaped_text_overrun_trim_to_width, p_shaped_line, p_width, p_trim_flags);
+}
+
+Array TextServerExtension::shaped_text_get_objects(RID p_shaped) const {
+	Array ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_objects, p_shaped, ret)) {
+		return ret;
+	}
+	return Array();
+}
+
+Rect2 TextServerExtension::shaped_text_get_object_rect(RID p_shaped, Variant p_key) const {
+	Rect2 ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_object_rect, p_shaped, p_key, ret)) {
+		return ret;
+	}
+	return Rect2();
+}
+
+Size2 TextServerExtension::shaped_text_get_size(RID p_shaped) const {
+	Size2 ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_size, p_shaped, ret)) {
+		return ret;
+	}
+	return Size2();
+}
+
+float TextServerExtension::shaped_text_get_ascent(RID p_shaped) const {
+	float ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_ascent, p_shaped, ret)) {
+		return ret;
+	}
+	return 0.f;
+}
+
+float TextServerExtension::shaped_text_get_descent(RID p_shaped) const {
+	float ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_descent, p_shaped, ret)) {
+		return ret;
+	}
+	return 0.f;
+}
+
+float TextServerExtension::shaped_text_get_width(RID p_shaped) const {
+	float ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_width, p_shaped, ret)) {
+		return ret;
+	}
+	return 0.f;
+}
+
+float TextServerExtension::shaped_text_get_underline_position(RID p_shaped) const {
+	float ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_underline_position, p_shaped, ret)) {
+		return ret;
+	}
+	return 0.f;
+}
+
+float TextServerExtension::shaped_text_get_underline_thickness(RID p_shaped) const {
+	float ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_underline_thickness, p_shaped, ret)) {
+		return ret;
+	}
+	return 0.f;
+}
+
+TextServer::Direction TextServerExtension::shaped_text_get_dominant_direction_in_range(RID p_shaped, int p_start, int p_end) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_dominant_direction_in_range, p_shaped, p_start, p_end, ret)) {
+		return (TextServer::Direction)ret;
+	}
+	return TextServer::shaped_text_get_dominant_direction_in_range(p_shaped, p_start, p_end);
+}
+
+CaretInfo TextServerExtension::shaped_text_get_carets(RID p_shaped, int p_position) const {
+	CaretInfo ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_carets, p_shaped, p_position, &ret)) {
+		return ret;
+	}
+	return TextServer::shaped_text_get_carets(p_shaped, p_position);
+}
+
+Vector<Vector2> TextServerExtension::shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const {
+	Vector<Vector2> ret;
+	if (GDVIRTUAL_CALL(_shaped_text_get_selection, p_shaped, p_start, p_end, ret)) {
+		return ret;
+	}
+	return TextServer::shaped_text_get_selection(p_shaped, p_start, p_end);
+}
+
+int TextServerExtension::shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_shaped_text_hit_test_grapheme, p_shaped, p_coords, ret)) {
+		return ret;
+	}
+	return TextServer::shaped_text_hit_test_grapheme(p_shaped, p_coords);
+}
+
+int TextServerExtension::shaped_text_hit_test_position(RID p_shaped, float p_coords) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_shaped_text_hit_test_position, p_shaped, p_coords, ret)) {
+		return ret;
+	}
+	return TextServer::shaped_text_hit_test_position(p_shaped, p_coords);
+}
+
+void TextServerExtension::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l, float p_clip_r, const Color &p_color) const {
+	if (GDVIRTUAL_CALL(_shaped_text_draw, p_shaped, p_canvas, p_pos, p_clip_l, p_clip_r, p_color)) {
+		return;
+	}
+	TextServer::shaped_text_draw(p_shaped, p_canvas, p_pos, p_clip_l, p_clip_r, p_color);
+}
+
+void TextServerExtension::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l, float p_clip_r, int p_outline_size, const Color &p_color) const {
+	if (GDVIRTUAL_CALL(_shaped_text_draw_outline, p_shaped, p_canvas, p_pos, p_clip_l, p_clip_r, p_outline_size, p_color)) {
+		return;
+	}
+	shaped_text_draw_outline(p_shaped, p_canvas, p_pos, p_clip_l, p_clip_r, p_outline_size, p_color);
+}
+
+int TextServerExtension::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_shaped_text_next_grapheme_pos, p_shaped, p_pos, ret)) {
+		return ret;
+	}
+	return TextServer::shaped_text_next_grapheme_pos(p_shaped, p_pos);
+}
+
+int TextServerExtension::shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) const {
+	int ret;
+	if (GDVIRTUAL_CALL(_shaped_text_prev_grapheme_pos, p_shaped, p_pos, ret)) {
+		return ret;
+	}
+	return TextServer::shaped_text_prev_grapheme_pos(p_shaped, p_pos);
+}
+
+String TextServerExtension::format_number(const String &p_string, const String &p_language) const {
+	String ret;
+	if (GDVIRTUAL_CALL(_format_number, p_string, p_language, ret)) {
+		return ret;
+	}
+	return TextServer::format_number(p_string, p_language);
+}
+
+String TextServerExtension::parse_number(const String &p_string, const String &p_language) const {
+	String ret;
+	if (GDVIRTUAL_CALL(_parse_number, p_string, p_language, ret)) {
+		return ret;
+	}
+	return TextServer::parse_number(p_string, p_language);
+}
+
+String TextServerExtension::percent_sign(const String &p_language) const {
+	String ret;
+	if (GDVIRTUAL_CALL(_percent_sign, p_language, ret)) {
+		return ret;
+	}
+	return TextServer::percent_sign(p_language);
+}
+
+TextServerExtension::TextServerExtension() {
+	//NOP
+}
+
+TextServerExtension::~TextServerExtension() {
+	//NOP
+}

+ 426 - 0
servers/text/text_server_extension.h

@@ -0,0 +1,426 @@
+/*************************************************************************/
+/*  text_server_extension.h                                              */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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.                */
+/*************************************************************************/
+
+#ifndef TEXT_SERVER_EXTENSION_H
+#define TEXT_SERVER_EXTENSION_H
+
+#include "core/object/gdvirtual.gen.inc"
+#include "core/object/script_language.h"
+#include "core/variant/native_ptr.h"
+#include "servers/text_server.h"
+
+class TextServerExtension : public TextServer {
+	GDCLASS(TextServerExtension, TextServer);
+
+protected:
+	_THREAD_SAFE_CLASS_
+
+	static void _bind_methods();
+
+public:
+	virtual bool has_feature(Feature p_feature) const override;
+	virtual String get_name() const override;
+	virtual uint32_t get_features() const override;
+	GDVIRTUAL1RC(bool, _has_feature, Feature);
+	GDVIRTUAL0RC(String, _get_name);
+	GDVIRTUAL0RC(uint32_t, _get_features);
+
+	virtual void free(RID p_rid) override;
+	virtual bool has(RID p_rid) override;
+	virtual bool load_support_data(const String &p_filename) override;
+	GDVIRTUAL1(_free, RID);
+	GDVIRTUAL1R(bool, _has, RID);
+	GDVIRTUAL1R(bool, _load_support_data, const String &);
+
+	virtual String get_support_data_filename() const override;
+	virtual String get_support_data_info() const override;
+	virtual bool save_support_data(const String &p_filename) const override;
+	GDVIRTUAL0RC(String, _get_support_data_filename);
+	GDVIRTUAL0RC(String, _get_support_data_info);
+	GDVIRTUAL1RC(bool, _save_support_data, const String &);
+
+	virtual bool is_locale_right_to_left(const String &p_locale) const override;
+	GDVIRTUAL1RC(bool, _is_locale_right_to_left, const String &);
+
+	virtual int32_t name_to_tag(const String &p_name) const override;
+	virtual String tag_to_name(int32_t p_tag) const override;
+	GDVIRTUAL1RC(int32_t, _name_to_tag, const String &);
+	GDVIRTUAL1RC(String, _tag_to_name, int32_t);
+
+	/* Font interface */
+	virtual RID create_font() override;
+	GDVIRTUAL0R(RID, _create_font);
+
+	virtual void font_set_data(RID p_font_rid, const PackedByteArray &p_data) override;
+	virtual void font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) override;
+	GDVIRTUAL2(_font_set_data, RID, const PackedByteArray &);
+	GDVIRTUAL3(_font_set_data_ptr, RID, GDNativeConstPtr<const uint8_t>, uint64_t);
+
+	virtual void font_set_antialiased(RID p_font_rid, bool p_antialiased) override;
+	virtual bool font_is_antialiased(RID p_font_rid) const override;
+	GDVIRTUAL2(_font_set_antialiased, RID, bool);
+	GDVIRTUAL1RC(bool, _font_is_antialiased, RID);
+
+	virtual void font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) override;
+	virtual bool font_is_multichannel_signed_distance_field(RID p_font_rid) const override;
+	GDVIRTUAL2(_font_set_multichannel_signed_distance_field, RID, bool);
+	GDVIRTUAL1RC(bool, _font_is_multichannel_signed_distance_field, RID);
+
+	virtual void font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) override;
+	virtual int font_get_msdf_pixel_range(RID p_font_rid) const override;
+	GDVIRTUAL2(_font_set_msdf_pixel_range, RID, int);
+	GDVIRTUAL1RC(int, _font_get_msdf_pixel_range, RID);
+
+	virtual void font_set_msdf_size(RID p_font_rid, int p_msdf_size) override;
+	virtual int font_get_msdf_size(RID p_font_rid) const override;
+	GDVIRTUAL2(_font_set_msdf_size, RID, int);
+	GDVIRTUAL1RC(int, _font_get_msdf_size, RID);
+
+	virtual void font_set_fixed_size(RID p_font_rid, int p_fixed_size) override;
+	virtual int font_get_fixed_size(RID p_font_rid) const override;
+	GDVIRTUAL2(_font_set_fixed_size, RID, int);
+	GDVIRTUAL1RC(int, _font_get_fixed_size, RID);
+
+	virtual void font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) override;
+	virtual bool font_is_force_autohinter(RID p_font_rid) const override;
+	GDVIRTUAL2(_font_set_force_autohinter, RID, bool);
+	GDVIRTUAL1RC(bool, _font_is_force_autohinter, RID);
+
+	virtual void font_set_hinting(RID p_font_rid, Hinting p_hinting) override;
+	virtual Hinting font_get_hinting(RID p_font_rid) const override;
+	GDVIRTUAL2(_font_set_hinting, RID, Hinting);
+	GDVIRTUAL1RC(/*Hinting*/ int, _font_get_hinting, RID);
+
+	virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) override;
+	virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const override;
+	GDVIRTUAL2(_font_set_variation_coordinates, RID, Dictionary);
+	GDVIRTUAL1RC(Dictionary, _font_get_variation_coordinates, RID);
+
+	virtual void font_set_oversampling(RID p_font_rid, float p_oversampling) override;
+	virtual float font_get_oversampling(RID p_font_rid) const override;
+	GDVIRTUAL2(_font_set_oversampling, RID, float);
+	GDVIRTUAL1RC(float, _font_get_oversampling, RID);
+
+	virtual Array font_get_size_cache_list(RID p_font_rid) const override;
+	virtual void font_clear_size_cache(RID p_font_rid) override;
+	virtual void font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) override;
+	GDVIRTUAL1RC(Array, _font_get_size_cache_list, RID);
+	GDVIRTUAL1(_font_clear_size_cache, RID);
+	GDVIRTUAL2(_font_remove_size_cache, RID, const Vector2i &);
+
+	virtual void font_set_ascent(RID p_font_rid, int p_size, float p_ascent) override;
+	virtual float font_get_ascent(RID p_font_rid, int p_size) const override;
+	GDVIRTUAL3(_font_set_ascent, RID, int, float);
+	GDVIRTUAL2RC(float, _font_get_ascent, RID, int);
+
+	virtual void font_set_descent(RID p_font_rid, int p_size, float p_descent) override;
+	virtual float font_get_descent(RID p_font_rid, int p_size) const override;
+	GDVIRTUAL3(_font_set_descent, RID, int, float);
+	GDVIRTUAL2RC(float, _font_get_descent, RID, int);
+
+	virtual void font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) override;
+	virtual float font_get_underline_position(RID p_font_rid, int p_size) const override;
+	GDVIRTUAL3(_font_set_underline_position, RID, int, float);
+	GDVIRTUAL2RC(float, _font_get_underline_position, RID, int);
+
+	virtual void font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) override;
+	virtual float font_get_underline_thickness(RID p_font_rid, int p_size) const override;
+	GDVIRTUAL3(_font_set_underline_thickness, RID, int, float);
+	GDVIRTUAL2RC(float, _font_get_underline_thickness, RID, int);
+
+	virtual void font_set_scale(RID p_font_rid, int p_size, float p_scale) override;
+	virtual float font_get_scale(RID p_font_rid, int p_size) const override;
+	GDVIRTUAL3(_font_set_scale, RID, int, float);
+	GDVIRTUAL2RC(float, _font_get_scale, RID, int);
+
+	virtual void font_set_spacing(RID p_font_rid, int p_size, SpacingType p_spacing, int p_value) override;
+	virtual int font_get_spacing(RID p_font_rid, int p_size, SpacingType p_spacing) const override;
+	GDVIRTUAL4(_font_set_spacing, RID, int, SpacingType, int);
+	GDVIRTUAL3RC(int, _font_get_spacing, RID, int, SpacingType);
+
+	virtual int font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const override;
+	virtual void font_clear_textures(RID p_font_rid, const Vector2i &p_size) override;
+	virtual void font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) override;
+	GDVIRTUAL2RC(int, _font_get_texture_count, RID, const Vector2i &);
+	GDVIRTUAL2(_font_clear_textures, RID, const Vector2i &);
+	GDVIRTUAL3(_font_remove_texture, RID, const Vector2i &, int);
+
+	virtual void font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) override;
+	virtual Ref<Image> font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override;
+	GDVIRTUAL4(_font_set_texture_image, RID, const Vector2i &, int, const Ref<Image> &);
+	GDVIRTUAL3RC(Ref<Image>, _font_get_texture_image, RID, const Vector2i &, int);
+
+	virtual void font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) override;
+	virtual PackedInt32Array font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override;
+	GDVIRTUAL4(_font_set_texture_offsets, RID, const Vector2i &, int, const PackedInt32Array &);
+	GDVIRTUAL3RC(PackedInt32Array, _font_get_texture_offsets, RID, const Vector2i &, int);
+
+	virtual Array font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const override;
+	virtual void font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) override;
+	virtual void font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) override;
+	GDVIRTUAL2RC(Array, _font_get_glyph_list, RID, const Vector2i &);
+	GDVIRTUAL2(_font_clear_glyphs, RID, const Vector2i &);
+	GDVIRTUAL3(_font_remove_glyph, RID, const Vector2i &, int32_t);
+
+	virtual Vector2 font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const override;
+	virtual void font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) override;
+	GDVIRTUAL3RC(Vector2, _font_get_glyph_advance, RID, int, int32_t);
+	GDVIRTUAL4(_font_set_glyph_advance, RID, int, int32_t, const Vector2 &);
+
+	virtual Vector2 font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
+	virtual void font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) override;
+	GDVIRTUAL3RC(Vector2, _font_get_glyph_offset, RID, const Vector2i &, int32_t);
+	GDVIRTUAL4(_font_set_glyph_offset, RID, const Vector2i &, int32_t, const Vector2 &);
+
+	virtual Vector2 font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
+	virtual void font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) override;
+	GDVIRTUAL3RC(Vector2, _font_get_glyph_size, RID, const Vector2i &, int32_t);
+	GDVIRTUAL4(_font_set_glyph_size, RID, const Vector2i &, int32_t, const Vector2 &);
+
+	virtual Rect2 font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
+	virtual void font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) override;
+	GDVIRTUAL3RC(Rect2, _font_get_glyph_uv_rect, RID, const Vector2i &, int32_t);
+	GDVIRTUAL4(_font_set_glyph_uv_rect, RID, const Vector2i &, int32_t, const Rect2 &);
+
+	virtual int font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
+	virtual void font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) override;
+	GDVIRTUAL3RC(int, _font_get_glyph_texture_idx, RID, const Vector2i &, int32_t);
+	GDVIRTUAL4(_font_set_glyph_texture_idx, RID, const Vector2i &, int32_t, int);
+
+	virtual Dictionary font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const override;
+	GDVIRTUAL3RC(Dictionary, _font_get_glyph_contours, RID, int, int32_t);
+
+	virtual Array font_get_kerning_list(RID p_font_rid, int p_size) const override;
+	virtual void font_clear_kerning_map(RID p_font_rid, int p_size) override;
+	virtual void font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) override;
+	GDVIRTUAL2RC(Array, _font_get_kerning_list, RID, int);
+	GDVIRTUAL2(_font_clear_kerning_map, RID, int);
+	GDVIRTUAL3(_font_remove_kerning, RID, int, const Vector2i &);
+
+	virtual void font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) override;
+	virtual Vector2 font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const override;
+	GDVIRTUAL4(_font_set_kerning, RID, int, const Vector2i &, const Vector2 &);
+	GDVIRTUAL3RC(Vector2, _font_get_kerning, RID, int, const Vector2i &);
+
+	virtual int32_t font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector = 0) const override;
+	GDVIRTUAL4RC(int32_t, _font_get_glyph_index, RID, int, char32_t, char32_t);
+
+	virtual bool font_has_char(RID p_font_rid, char32_t p_char) const override;
+	virtual String font_get_supported_chars(RID p_font_rid) const override;
+	GDVIRTUAL2RC(bool, _font_has_char, RID, char32_t);
+	GDVIRTUAL1RC(String, _font_get_supported_chars, RID);
+
+	virtual void font_render_range(RID p_font, const Vector2i &p_size, char32_t p_start, char32_t p_end) override;
+	virtual void font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) override;
+	GDVIRTUAL4(_font_render_range, RID, const Vector2i &, char32_t, char32_t);
+	GDVIRTUAL3(_font_render_glyph, RID, const Vector2i &, int32_t);
+
+	virtual void font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+	virtual void font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+	GDVIRTUAL6C(_font_draw_glyph, RID, RID, int, const Vector2 &, int32_t, const Color &);
+	GDVIRTUAL7C(_font_draw_glyph_outline, RID, RID, int, int, const Vector2 &, int32_t, const Color &);
+
+	virtual bool font_is_language_supported(RID p_font_rid, const String &p_language) const override;
+	virtual void font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) override;
+	virtual bool font_get_language_support_override(RID p_font_rid, const String &p_language) override;
+	virtual void font_remove_language_support_override(RID p_font_rid, const String &p_language) override;
+	virtual Vector<String> font_get_language_support_overrides(RID p_font_rid) override;
+	GDVIRTUAL2RC(bool, _font_is_language_supported, RID, const String &);
+	GDVIRTUAL3(_font_set_language_support_override, RID, const String &, bool);
+	GDVIRTUAL2R(bool, _font_get_language_support_override, RID, const String &);
+	GDVIRTUAL2(_font_remove_language_support_override, RID, const String &);
+	GDVIRTUAL1R(Vector<String>, _font_get_language_support_overrides, RID);
+
+	virtual bool font_is_script_supported(RID p_font_rid, const String &p_script) const override;
+	virtual void font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) override;
+	virtual bool font_get_script_support_override(RID p_font_rid, const String &p_script) override;
+	virtual void font_remove_script_support_override(RID p_font_rid, const String &p_script) override;
+	virtual Vector<String> font_get_script_support_overrides(RID p_font_rid) override;
+	GDVIRTUAL2RC(bool, _font_is_script_supported, RID, const String &);
+	GDVIRTUAL3(_font_set_script_support_override, RID, const String &, bool);
+	GDVIRTUAL2R(bool, _font_get_script_support_override, RID, const String &);
+	GDVIRTUAL2(_font_remove_script_support_override, RID, const String &);
+	GDVIRTUAL1R(Vector<String>, _font_get_script_support_overrides, RID);
+
+	virtual Dictionary font_supported_feature_list(RID p_font_rid) const override;
+	virtual Dictionary font_supported_variation_list(RID p_font_rid) const override;
+	GDVIRTUAL1RC(Dictionary, _font_supported_feature_list, RID);
+	GDVIRTUAL1RC(Dictionary, _font_supported_variation_list, RID);
+
+	virtual float font_get_global_oversampling() const override;
+	virtual void font_set_global_oversampling(float p_oversampling) override;
+	GDVIRTUAL0RC(float, _font_get_global_oversampling);
+	GDVIRTUAL1(_font_set_global_oversampling, float);
+
+	virtual Vector2 get_hex_code_box_size(int p_size, char32_t p_index) const override;
+	virtual void draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_pos, char32_t p_index, const Color &p_color) const override;
+	GDVIRTUAL2RC(Vector2, _get_hex_code_box_size, int, char32_t);
+	GDVIRTUAL5C(_draw_hex_code_box, RID, int, const Vector2 &, char32_t, const Color &);
+
+	/* Shaped text buffer interface */
+
+	virtual RID create_shaped_text(Direction p_direction = DIRECTION_AUTO, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
+	GDVIRTUAL2R(RID, _create_shaped_text, Direction, Orientation);
+
+	virtual void shaped_text_clear(RID p_shaped) override;
+	GDVIRTUAL1(_shaped_text_clear, RID);
+
+	virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override;
+	virtual Direction shaped_text_get_direction(RID p_shaped) const override;
+	GDVIRTUAL2(_shaped_text_set_direction, RID, Direction);
+	GDVIRTUAL1RC(/*Direction*/ int, _shaped_text_get_direction, RID);
+
+	virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override;
+	GDVIRTUAL2(_shaped_text_set_bidi_override, RID, const Array &);
+
+	virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
+	virtual Orientation shaped_text_get_orientation(RID p_shaped) const override;
+	GDVIRTUAL2(_shaped_text_set_orientation, RID, Orientation);
+	GDVIRTUAL1RC(/*Orientation*/ int, _shaped_text_get_orientation, RID);
+
+	virtual void shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) override;
+	virtual bool shaped_text_get_preserve_invalid(RID p_shaped) const override;
+	GDVIRTUAL2(_shaped_text_set_preserve_invalid, RID, bool);
+	GDVIRTUAL1RC(bool, _shaped_text_get_preserve_invalid, RID);
+
+	virtual void shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) override;
+	virtual bool shaped_text_get_preserve_control(RID p_shaped) const override;
+	GDVIRTUAL2(_shaped_text_set_preserve_control, RID, bool);
+	GDVIRTUAL1RC(bool, _shaped_text_get_preserve_control, RID);
+
+	virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override;
+	virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) override;
+	virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) override;
+	GDVIRTUAL6R(bool, _shaped_text_add_string, RID, const String &, const Array &, int, const Dictionary &, const String &);
+	GDVIRTUAL5R(bool, _shaped_text_add_object, RID, Variant, const Size2 &, InlineAlign, int);
+	GDVIRTUAL4R(bool, _shaped_text_resize_object, RID, Variant, const Size2 &, InlineAlign);
+
+	virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
+	virtual RID shaped_text_get_parent(RID p_shaped) const override;
+	GDVIRTUAL3RC(RID, _shaped_text_substr, RID, int, int);
+	GDVIRTUAL1RC(RID, _shaped_text_get_parent, RID);
+
+	virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
+	virtual float shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) override;
+	GDVIRTUAL3R(float, _shaped_text_fit_to_width, RID, float, uint16_t);
+	GDVIRTUAL2R(float, _shaped_text_tab_align, RID, const PackedFloat32Array &);
+
+	virtual bool shaped_text_shape(RID p_shaped) override;
+	virtual bool shaped_text_update_breaks(RID p_shaped) override;
+	virtual bool shaped_text_update_justification_ops(RID p_shaped) override;
+	GDVIRTUAL1R(bool, _shaped_text_shape, RID);
+	GDVIRTUAL1R(bool, _shaped_text_update_breaks, RID);
+	GDVIRTUAL1R(bool, _shaped_text_update_justification_ops, RID);
+
+	virtual bool shaped_text_is_ready(RID p_shaped) const override;
+	GDVIRTUAL1RC(bool, _shaped_text_is_ready, RID);
+
+	virtual const Glyph *shaped_text_get_glyphs(RID p_shaped) const override;
+	virtual const Glyph *shaped_text_sort_logical(RID p_shaped) override;
+	virtual int shaped_text_get_glyph_count(RID p_shaped) const override;
+	GDVIRTUAL2C(_shaped_text_get_glyphs, RID, GDNativePtr<const Glyph *>);
+	GDVIRTUAL2(_shaped_text_sort_logical, RID, GDNativePtr<const Glyph *>);
+	GDVIRTUAL1RC(int, _shaped_text_get_glyph_count, RID);
+
+	virtual Vector2i shaped_text_get_range(RID p_shaped) const override;
+	GDVIRTUAL1RC(Vector2i, _shaped_text_get_range, RID);
+
+	virtual PackedInt32Array shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start = 0, bool p_once = true, uint16_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const override;
+	virtual PackedInt32Array shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start = 0, uint16_t p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const override;
+	virtual PackedInt32Array shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION) const override;
+	GDVIRTUAL5RC(PackedInt32Array, _shaped_text_get_line_breaks_adv, RID, const PackedFloat32Array &, int, bool, uint16_t);
+	GDVIRTUAL4RC(PackedInt32Array, _shaped_text_get_line_breaks, RID, float, int, uint16_t);
+	GDVIRTUAL2RC(PackedInt32Array, _shaped_text_get_word_breaks, RID, int);
+
+	virtual int shaped_text_get_trim_pos(RID p_shaped) const override;
+	virtual int shaped_text_get_ellipsis_pos(RID p_shaped) const override;
+	virtual const Glyph *shaped_text_get_ellipsis_glyphs(RID p_shaped) const override;
+	virtual int shaped_text_get_ellipsis_glyph_count(RID p_shaped) const override;
+	GDVIRTUAL1RC(int, _shaped_text_get_trim_pos, RID);
+	GDVIRTUAL1RC(int, _shaped_text_get_ellipsis_pos, RID);
+	GDVIRTUAL2C(_shaped_text_get_ellipsis_glyphs, RID, GDNativePtr<const Glyph *>);
+	GDVIRTUAL1RC(int, _shaped_text_get_ellipsis_glyph_count, RID);
+
+	virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint16_t p_trim_flags) override;
+	GDVIRTUAL3(_shaped_text_overrun_trim_to_width, RID, float, uint16_t);
+
+	virtual Array shaped_text_get_objects(RID p_shaped) const override;
+	virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const override;
+	GDVIRTUAL1RC(Array, _shaped_text_get_objects, RID);
+	GDVIRTUAL2RC(Rect2, _shaped_text_get_object_rect, RID, Variant);
+
+	virtual Size2 shaped_text_get_size(RID p_shaped) const override;
+	virtual float shaped_text_get_ascent(RID p_shaped) const override;
+	virtual float shaped_text_get_descent(RID p_shaped) const override;
+	virtual float shaped_text_get_width(RID p_shaped) const override;
+	virtual float shaped_text_get_underline_position(RID p_shaped) const override;
+	virtual float shaped_text_get_underline_thickness(RID p_shaped) const override;
+	GDVIRTUAL1RC(Size2, _shaped_text_get_size, RID);
+	GDVIRTUAL1RC(float, _shaped_text_get_ascent, RID);
+	GDVIRTUAL1RC(float, _shaped_text_get_descent, RID);
+	GDVIRTUAL1RC(float, _shaped_text_get_width, RID);
+	GDVIRTUAL1RC(float, _shaped_text_get_underline_position, RID);
+	GDVIRTUAL1RC(float, _shaped_text_get_underline_thickness, RID);
+
+	virtual Direction shaped_text_get_dominant_direction_in_range(RID p_shaped, int p_start, int p_end) const override;
+	GDVIRTUAL3RC(int, _shaped_text_get_dominant_direction_in_range, RID, int, int);
+
+	virtual CaretInfo shaped_text_get_carets(RID p_shaped, int p_position) const override;
+	virtual Vector<Vector2> shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const override;
+	GDVIRTUAL3C(_shaped_text_get_carets, RID, int, GDNativePtr<CaretInfo>);
+	GDVIRTUAL3RC(Vector<Vector2>, _shaped_text_get_selection, RID, int, int);
+
+	virtual int shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) const override;
+	virtual int shaped_text_hit_test_position(RID p_shaped, float p_coords) const override;
+	GDVIRTUAL2RC(int, _shaped_text_hit_test_grapheme, RID, float);
+	GDVIRTUAL2RC(int, _shaped_text_hit_test_position, RID, float);
+
+	virtual void shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l = -1.f, float p_clip_r = -1.f, const Color &p_color = Color(1, 1, 1)) const override;
+	virtual void shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l = -1.f, float p_clip_r = -1.f, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1)) const override;
+	GDVIRTUAL6C(_shaped_text_draw, RID, RID, const Vector2 &, float, float, const Color &);
+	GDVIRTUAL7C(_shaped_text_draw_outline, RID, RID, const Vector2 &, float, float, int, const Color &);
+
+	virtual int shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) const override;
+	virtual int shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) const override;
+	GDVIRTUAL2RC(int, _shaped_text_next_grapheme_pos, RID, int);
+	GDVIRTUAL2RC(int, _shaped_text_prev_grapheme_pos, RID, int);
+
+	virtual String format_number(const String &p_string, const String &p_language = "") const override;
+	virtual String parse_number(const String &p_string, const String &p_language = "") const override;
+	virtual String percent_sign(const String &p_language = "") const override;
+	GDVIRTUAL2RC(String, _format_number, const String &, const String &);
+	GDVIRTUAL2RC(String, _parse_number, const String &, const String &);
+	GDVIRTUAL1RC(String, _percent_sign, const String &);
+
+	TextServerExtension();
+	~TextServerExtension();
+};
+
+#endif // TEXT_SERVER_EXTENSION_H

+ 277 - 284
servers/text_server.cpp

@@ -32,122 +32,108 @@
 #include "scene/main/canvas_item.h"
 
 TextServerManager *TextServerManager::singleton = nullptr;
-TextServer *TextServerManager::server = nullptr;
-TextServerManager::TextServerCreate TextServerManager::server_create_functions[TextServerManager::MAX_SERVERS];
-int TextServerManager::server_create_count = 0;
 
 void TextServerManager::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("get_interface_count"), &TextServerManager::_get_interface_count);
-	ClassDB::bind_method(D_METHOD("get_interface_name", "index"), &TextServerManager::_get_interface_name);
-	ClassDB::bind_method(D_METHOD("get_interface_features", "index"), &TextServerManager::_get_interface_features);
-	ClassDB::bind_method(D_METHOD("get_interface", "index"), &TextServerManager::_get_interface);
-	ClassDB::bind_method(D_METHOD("get_interfaces"), &TextServerManager::_get_interfaces);
-	ClassDB::bind_method(D_METHOD("find_interface", "name"), &TextServerManager::_find_interface);
-
-	ClassDB::bind_method(D_METHOD("set_primary_interface", "index"), &TextServerManager::_set_primary_interface);
+	ClassDB::bind_method(D_METHOD("add_interface", "interface"), &TextServerManager::add_interface);
+	ClassDB::bind_method(D_METHOD("get_interface_count"), &TextServerManager::get_interface_count);
+	ClassDB::bind_method(D_METHOD("remove_interface", "interface"), &TextServerManager::remove_interface);
+	ClassDB::bind_method(D_METHOD("get_interface", "idx"), &TextServerManager::get_interface);
+	ClassDB::bind_method(D_METHOD("get_interfaces"), &TextServerManager::get_interfaces);
+	ClassDB::bind_method(D_METHOD("find_interface", "name"), &TextServerManager::find_interface);
+
+	ClassDB::bind_method(D_METHOD("set_primary_interface", "index"), &TextServerManager::set_primary_interface);
 	ClassDB::bind_method(D_METHOD("get_primary_interface"), &TextServerManager::_get_primary_interface);
-}
 
-void TextServerManager::register_create_function(const String &p_name, uint32_t p_features, TextServerManager::CreateFunction p_function, void *p_user_data) {
-	ERR_FAIL_COND(server_create_count == MAX_SERVERS);
-	server_create_functions[server_create_count].name = p_name;
-	server_create_functions[server_create_count].create_function = p_function;
-	server_create_functions[server_create_count].user_data = p_user_data;
-	server_create_functions[server_create_count].features = p_features;
-	server_create_count++;
+	ADD_SIGNAL(MethodInfo("interface_added", PropertyInfo(Variant::STRING_NAME, "interface_name")));
+	ADD_SIGNAL(MethodInfo("interface_removed", PropertyInfo(Variant::STRING_NAME, "interface_name")));
 }
 
-int TextServerManager::get_interface_count() {
-	return server_create_count;
-}
+void TextServerManager::add_interface(const Ref<TextServer> &p_interface) {
+	ERR_FAIL_COND(p_interface.is_null());
 
-String TextServerManager::get_interface_name(int p_index) {
-	ERR_FAIL_INDEX_V(p_index, server_create_count, String());
-	return server_create_functions[p_index].name;
-}
+	for (int i = 0; i < interfaces.size(); i++) {
+		if (interfaces[i] == p_interface) {
+			ERR_PRINT("TextServer: Interface was already added.");
+			return;
+		};
+	};
 
-uint32_t TextServerManager::get_interface_features(int p_index) {
-	ERR_FAIL_INDEX_V(p_index, server_create_count, 0);
-	return server_create_functions[p_index].features;
+	interfaces.push_back(p_interface);
+	print_verbose("TextServer: Added interface \"" + p_interface->get_name() + "\"");
+	emit_signal(SNAME("interface_added"), p_interface->get_name());
 }
 
-TextServer *TextServerManager::initialize(int p_index, Error &r_error) {
-	ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr);
-	if (server_create_functions[p_index].instance == nullptr) {
-		server_create_functions[p_index].instance = server_create_functions[p_index].create_function(r_error, server_create_functions[p_index].user_data);
-		if (server_create_functions[p_index].instance != nullptr) {
-			server_create_functions[p_index].instance->load_support_data(""); // Try loading default data.
-		}
-	}
-	if (server_create_functions[p_index].instance != nullptr) {
-		server = server_create_functions[p_index].instance;
-		if (OS::get_singleton()->get_main_loop()) {
-			OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TEXT_SERVER_CHANGED);
-		}
-	}
-	return server_create_functions[p_index].instance;
-}
+void TextServerManager::remove_interface(const Ref<TextServer> &p_interface) {
+	ERR_FAIL_COND(p_interface.is_null());
+	ERR_FAIL_COND_MSG(p_interface == primary_interface, "TextServer: Can't remove primary interface.");
 
-TextServer *TextServerManager::get_primary_interface() {
-	return server;
-}
+	int idx = -1;
+	for (int i = 0; i < interfaces.size(); i++) {
+		if (interfaces[i] == p_interface) {
+			idx = i;
+			break;
+		};
+	};
 
-int TextServerManager::_get_interface_count() const {
-	return server_create_count;
+	ERR_FAIL_COND(idx == -1);
+	print_verbose("TextServer: Removed interface \"" + p_interface->get_name() + "\"");
+	emit_signal(SNAME("interface_removed"), p_interface->get_name());
+	interfaces.remove(idx);
 }
 
-String TextServerManager::_get_interface_name(int p_index) const {
-	return get_interface_name(p_index);
+int TextServerManager::get_interface_count() const {
+	return interfaces.size();
 }
 
-uint32_t TextServerManager::_get_interface_features(int p_index) const {
-	return get_interface_features(p_index);
+Ref<TextServer> TextServerManager::get_interface(int p_index) const {
+	ERR_FAIL_INDEX_V(p_index, interfaces.size(), nullptr);
+	return interfaces[p_index];
 }
 
-TextServer *TextServerManager::_get_interface(int p_index) const {
-	ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr);
-	if (server_create_functions[p_index].instance == nullptr) {
-		Error error;
-		server_create_functions[p_index].instance = server_create_functions[p_index].create_function(error, server_create_functions[p_index].user_data);
-		if (server_create_functions[p_index].instance != nullptr) {
-			server_create_functions[p_index].instance->load_support_data(""); // Try loading default data.
-		}
-	}
-	return server_create_functions[p_index].instance;
-}
+Ref<TextServer> TextServerManager::find_interface(const String &p_name) const {
+	int idx = -1;
+	for (int i = 0; i < interfaces.size(); i++) {
+		if (interfaces[i]->get_name() == p_name) {
+			idx = i;
+			break;
+		};
+	};
 
-TextServer *TextServerManager::_find_interface(const String &p_name) const {
-	for (int i = 0; i < server_create_count; i++) {
-		if (server_create_functions[i].name == p_name) {
-			return _get_interface(i);
-		}
-	}
-	return nullptr;
+	ERR_FAIL_COND_V(idx == -1, nullptr);
+	return interfaces[idx];
 }
 
-Array TextServerManager::_get_interfaces() const {
+Array TextServerManager::get_interfaces() const {
 	Array ret;
 
-	for (int i = 0; i < server_create_count; i++) {
+	for (int i = 0; i < interfaces.size(); i++) {
 		Dictionary iface_info;
 
 		iface_info["id"] = i;
-		iface_info["name"] = server_create_functions[i].name;
+		iface_info["name"] = interfaces[i]->get_name();
 
 		ret.push_back(iface_info);
 	};
 
 	return ret;
-};
+}
 
-bool TextServerManager::_set_primary_interface(int p_index) {
-	Error error;
-	TextServerManager::initialize(p_index, error);
-	return (error == OK);
+Ref<TextServer> TextServerManager::_get_primary_interface() const {
+	return primary_interface;
 }
 
-TextServer *TextServerManager::_get_primary_interface() const {
-	return server;
+void TextServerManager::set_primary_interface(const Ref<TextServer> &p_primary_interface) {
+	if (p_primary_interface.is_null()) {
+		print_verbose("TextServer: Clearing primary interface");
+		primary_interface.unref();
+	} else {
+		primary_interface = p_primary_interface;
+		print_verbose("TextServer: Primary interface set to: \"" + primary_interface->get_name() + "\".");
+
+		if (OS::get_singleton()->get_main_loop()) {
+			OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TEXT_SERVER_CHANGED);
+		}
+	}
 }
 
 TextServerManager::TextServerManager() {
@@ -155,29 +141,29 @@ TextServerManager::TextServerManager() {
 }
 
 TextServerManager::~TextServerManager() {
-	singleton = nullptr;
-	for (int i = 0; i < server_create_count; i++) {
-		if (server_create_functions[i].instance != nullptr) {
-			memdelete(server_create_functions[i].instance);
-			server_create_functions[i].instance = nullptr;
-		}
+	if (primary_interface.is_valid()) {
+		primary_interface.unref();
 	}
+	while (interfaces.size() > 0) {
+		interfaces.remove(0);
+	}
+	singleton = nullptr;
 }
 
 /*************************************************************************/
 
-bool TextServer::Glyph::operator==(const Glyph &p_a) const {
+bool Glyph::operator==(const Glyph &p_a) const {
 	return (p_a.index == index) && (p_a.font_rid == font_rid) && (p_a.font_size == font_size) && (p_a.start == start);
 }
 
-bool TextServer::Glyph::operator!=(const Glyph &p_a) const {
+bool Glyph::operator!=(const Glyph &p_a) const {
 	return (p_a.index != index) || (p_a.font_rid != font_rid) || (p_a.font_size != font_size) || (p_a.start != start);
 }
 
-bool TextServer::Glyph::operator<(const Glyph &p_a) const {
+bool Glyph::operator<(const Glyph &p_a) const {
 	if (p_a.start == start) {
 		if (p_a.count == count) {
-			if ((p_a.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
+			if ((p_a.flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL) {
 				return true;
 			} else {
 				return false;
@@ -188,10 +174,10 @@ bool TextServer::Glyph::operator<(const Glyph &p_a) const {
 	return p_a.start < start;
 }
 
-bool TextServer::Glyph::operator>(const Glyph &p_a) const {
+bool Glyph::operator>(const Glyph &p_a) const {
 	if (p_a.start == start) {
 		if (p_a.count == count) {
-			if ((p_a.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
+			if ((p_a.flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL) {
 				return false;
 			} else {
 				return true;
@@ -205,8 +191,13 @@ bool TextServer::Glyph::operator>(const Glyph &p_a) const {
 void TextServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("has_feature", "feature"), &TextServer::has_feature);
 	ClassDB::bind_method(D_METHOD("get_name"), &TextServer::get_name);
+	ClassDB::bind_method(D_METHOD("get_features"), &TextServer::get_features);
 	ClassDB::bind_method(D_METHOD("load_support_data", "filename"), &TextServer::load_support_data);
 
+	ClassDB::bind_method(D_METHOD("get_support_data_filename"), &TextServer::get_support_data_filename);
+	ClassDB::bind_method(D_METHOD("get_support_data_info"), &TextServer::get_support_data_info);
+	ClassDB::bind_method(D_METHOD("save_support_data", "filename"), &TextServer::save_support_data);
+
 	ClassDB::bind_method(D_METHOD("is_locale_right_to_left", "locale"), &TextServer::is_locale_right_to_left);
 
 	ClassDB::bind_method(D_METHOD("name_to_tag", "name"), &TextServer::name_to_tag);
@@ -219,7 +210,7 @@ void TextServer::_bind_methods() {
 
 	ClassDB::bind_method(D_METHOD("create_font"), &TextServer::create_font);
 
-	ClassDB::bind_method(D_METHOD("font_set_data", "data"), &TextServer::font_set_data);
+	ClassDB::bind_method(D_METHOD("font_set_data", "font_rid", "data"), &TextServer::font_set_data);
 
 	ClassDB::bind_method(D_METHOD("font_set_antialiased", "font_rid", "antialiased"), &TextServer::font_set_antialiased);
 	ClassDB::bind_method(D_METHOD("font_is_antialiased", "font_rid"), &TextServer::font_is_antialiased);
@@ -299,7 +290,7 @@ void TextServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("font_get_glyph_texture_idx", "font_rid", "size", "glyph"), &TextServer::font_get_glyph_texture_idx);
 	ClassDB::bind_method(D_METHOD("font_set_glyph_texture_idx", "font_rid", "size", "glyph", "texture_idx"), &TextServer::font_set_glyph_texture_idx);
 
-	ClassDB::bind_method(D_METHOD("font_get_glyph_contours", "font", "size", "index"), &TextServer::_font_get_glyph_contours);
+	ClassDB::bind_method(D_METHOD("font_get_glyph_contours", "font", "size", "index"), &TextServer::font_get_glyph_contours);
 
 	ClassDB::bind_method(D_METHOD("font_get_kerning_list", "font_rid", "size"), &TextServer::font_get_kerning_list);
 	ClassDB::bind_method(D_METHOD("font_clear_kerning_map", "font_rid", "size"), &TextServer::font_clear_kerning_map);
@@ -349,7 +340,7 @@ void TextServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("shaped_text_set_direction", "shaped", "direction"), &TextServer::shaped_text_set_direction, DEFVAL(DIRECTION_AUTO));
 	ClassDB::bind_method(D_METHOD("shaped_text_get_direction", "shaped"), &TextServer::shaped_text_get_direction);
 
-	ClassDB::bind_method(D_METHOD("shaped_text_set_bidi_override", "shaped", "override"), &TextServer::_shaped_text_set_bidi_override);
+	ClassDB::bind_method(D_METHOD("shaped_text_set_bidi_override", "shaped", "override"), &TextServer::shaped_text_set_bidi_override);
 
 	ClassDB::bind_method(D_METHOD("shaped_text_set_orientation", "shaped", "orientation"), &TextServer::shaped_text_set_orientation, DEFVAL(ORIENTATION_HORIZONTAL));
 	ClassDB::bind_method(D_METHOD("shaped_text_get_orientation", "shaped"), &TextServer::shaped_text_get_orientation);
@@ -372,12 +363,19 @@ void TextServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("shaped_text_shape", "shaped"), &TextServer::shaped_text_shape);
 	ClassDB::bind_method(D_METHOD("shaped_text_is_ready", "shaped"), &TextServer::shaped_text_is_ready);
 
-	ClassDB::bind_method(D_METHOD("shaped_text_get_glyphs", "shaped"), &TextServer::_shaped_text_get_glyphs);
+	ClassDB::bind_method(D_METHOD("shaped_text_get_glyphs", "shaped"), &TextServer::_shaped_text_get_glyphs_wrapper);
+	ClassDB::bind_method(D_METHOD("shaped_text_sort_logical", "shaped"), &TextServer::_shaped_text_sort_logical_wrapper);
+	ClassDB::bind_method(D_METHOD("shaped_text_get_glyph_count", "shaped"), &TextServer::shaped_text_get_glyph_count);
 
 	ClassDB::bind_method(D_METHOD("shaped_text_get_range", "shaped"), &TextServer::shaped_text_get_range);
-	ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks_adv", "shaped", "width", "start", "once", "break_flags"), &TextServer::_shaped_text_get_line_breaks_adv, DEFVAL(0), DEFVAL(true), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND));
-	ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks", "shaped", "width", "start", "break_flags"), &TextServer::_shaped_text_get_line_breaks, DEFVAL(0), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND));
-	ClassDB::bind_method(D_METHOD("shaped_text_get_word_breaks", "shaped"), &TextServer::_shaped_text_get_word_breaks);
+	ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks_adv", "shaped", "width", "start", "once", "break_flags"), &TextServer::shaped_text_get_line_breaks_adv, DEFVAL(0), DEFVAL(true), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND));
+	ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks", "shaped", "width", "start", "break_flags"), &TextServer::shaped_text_get_line_breaks, DEFVAL(0), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND));
+	ClassDB::bind_method(D_METHOD("shaped_text_get_word_breaks", "shaped", "grapheme_flags"), &TextServer::shaped_text_get_word_breaks);
+
+	ClassDB::bind_method(D_METHOD("shaped_text_get_trim_pos", "shaped"), &TextServer::shaped_text_get_trim_pos);
+	ClassDB::bind_method(D_METHOD("shaped_text_get_ellipsis_pos", "shaped"), &TextServer::shaped_text_get_ellipsis_pos);
+	ClassDB::bind_method(D_METHOD("shaped_text_get_ellipsis_glyphs", "shaped"), &TextServer::_shaped_text_get_ellipsis_glyphs_wrapper);
+	ClassDB::bind_method(D_METHOD("shaped_text_get_ellipsis_glyph_count", "shaped"), &TextServer::shaped_text_get_ellipsis_glyph_count);
 
 	ClassDB::bind_method(D_METHOD("shaped_text_overrun_trim_to_width", "shaped", "width", "overrun_trim_flags"), &TextServer::shaped_text_overrun_trim_to_width, DEFVAL(0), DEFVAL(OVERRUN_NO_TRIMMING));
 
@@ -391,8 +389,8 @@ void TextServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("shaped_text_get_underline_position", "shaped"), &TextServer::shaped_text_get_underline_position);
 	ClassDB::bind_method(D_METHOD("shaped_text_get_underline_thickness", "shaped"), &TextServer::shaped_text_get_underline_thickness);
 
-	ClassDB::bind_method(D_METHOD("shaped_text_get_carets", "shaped", "position"), &TextServer::_shaped_text_get_carets);
-	ClassDB::bind_method(D_METHOD("shaped_text_get_selection", "shaped", "start", "end"), &TextServer::_shaped_text_get_selection);
+	ClassDB::bind_method(D_METHOD("shaped_text_get_carets", "shaped", "position"), &TextServer::_shaped_text_get_carets_wrapper);
+	ClassDB::bind_method(D_METHOD("shaped_text_get_selection", "shaped", "start", "end"), &TextServer::shaped_text_get_selection);
 
 	ClassDB::bind_method(D_METHOD("shaped_text_hit_test_grapheme", "shaped", "coords"), &TextServer::shaped_text_hit_test_grapheme);
 	ClassDB::bind_method(D_METHOD("shaped_text_hit_test_position", "shaped", "coords"), &TextServer::shaped_text_hit_test_position);
@@ -403,7 +401,7 @@ void TextServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("shaped_text_draw", "shaped", "canvas", "pos", "clip_l", "clip_r", "color"), &TextServer::shaped_text_draw, DEFVAL(-1), DEFVAL(-1), DEFVAL(Color(1, 1, 1)));
 	ClassDB::bind_method(D_METHOD("shaped_text_draw_outline", "shaped", "canvas", "pos", "clip_l", "clip_r", "outline_size", "color"), &TextServer::shaped_text_draw_outline, DEFVAL(-1), DEFVAL(-1), DEFVAL(1), DEFVAL(Color(1, 1, 1)));
 
-	ClassDB::bind_method(D_METHOD("shaped_text_get_dominant_direciton_in_range", "shaped", "start", "end"), &TextServer::shaped_text_get_dominant_direciton_in_range);
+	ClassDB::bind_method(D_METHOD("shaped_text_get_dominant_direction_in_range", "shaped", "start", "end"), &TextServer::shaped_text_get_dominant_direction_in_range);
 
 	ClassDB::bind_method(D_METHOD("format_number", "number", "language"), &TextServer::format_number, DEFVAL(""));
 	ClassDB::bind_method(D_METHOD("parse_number", "number", "language"), &TextServer::parse_number, DEFVAL(""));
@@ -424,12 +422,14 @@ void TextServer::_bind_methods() {
 	BIND_ENUM_CONSTANT(JUSTIFICATION_WORD_BOUND);
 	BIND_ENUM_CONSTANT(JUSTIFICATION_TRIM_EDGE_SPACES);
 	BIND_ENUM_CONSTANT(JUSTIFICATION_AFTER_LAST_TAB);
+	BIND_ENUM_CONSTANT(JUSTIFICATION_CONSTRAIN_ELLIPSIS);
 
 	/* LineBreakFlag */
 	BIND_ENUM_CONSTANT(BREAK_NONE);
 	BIND_ENUM_CONSTANT(BREAK_MANDATORY);
 	BIND_ENUM_CONSTANT(BREAK_WORD_BOUND);
 	BIND_ENUM_CONSTANT(BREAK_GRAPHEME_BOUND);
+	BIND_ENUM_CONSTANT(BREAK_WORD_BOUND_ADAPTIVE);
 
 	/* TextOverrunFlag */
 	BIND_ENUM_CONSTANT(OVERRUN_NO_TRIMMING);
@@ -437,8 +437,10 @@ void TextServer::_bind_methods() {
 	BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD_ONLY);
 	BIND_ENUM_CONSTANT(OVERRUN_ADD_ELLIPSIS);
 	BIND_ENUM_CONSTANT(OVERRUN_ENFORCE_ELLIPSIS);
+	BIND_ENUM_CONSTANT(OVERRUN_JUSTIFICATION_AWARE);
 
 	/* GraphemeFlag */
+	BIND_ENUM_CONSTANT(GRAPHEME_IS_VALID);
 	BIND_ENUM_CONSTANT(GRAPHEME_IS_RTL);
 	BIND_ENUM_CONSTANT(GRAPHEME_IS_VIRTUAL);
 	BIND_ENUM_CONSTANT(GRAPHEME_IS_SPACE);
@@ -578,6 +580,9 @@ void TextServer::draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_po
 	int fnt = (p_size < 20) ? 0 : 1;
 
 	ERR_FAIL_COND(hex_code_box_font_tex[fnt].is_null());
+	if (p_index == 0) {
+		return;
+	}
 
 	uint8_t a = p_index & 0x0F;
 	uint8_t b = (p_index >> 4) & 0x0F;
@@ -592,12 +597,12 @@ void TextServer::draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_po
 	real_t w = ((p_index <= 0xFF) ? 1 : ((p_index <= 0xFFFF) ? 2 : 3)) * hex_code_box_font_size[fnt].x;
 	real_t h = 2 * hex_code_box_font_size[fnt].y;
 
-	pos.y -= Math::floor((h + 3 + hex_code_box_font_size[fnt].z) * 0.75);
+	pos.y -= Math::floor((h + 3 + hex_code_box_font_size[fnt].z));
 
 	RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, 0), Size2(1, h + 2 + 2 * hex_code_box_font_size[fnt].z)), p_color);
 	RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(w + 2, 0), Size2(1, h + 2 + 2 * hex_code_box_font_size[fnt].z)), p_color);
-	RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, 0), Size2(w + 2, 1)), p_color);
-	RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, h + 2 + 2 * hex_code_box_font_size[fnt].z), Size2(w + 2, 1)), p_color);
+	RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, 0), Size2(w + 3, 1)), p_color);
+	RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, h + 2 + 2 * hex_code_box_font_size[fnt].z), Size2(w + 3, 1)), p_color);
 
 	pos += Point2(2, 2);
 	if (p_index <= 0xFF) {
@@ -630,13 +635,12 @@ void TextServer::draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_po
 	}
 }
 
-Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const Vector<real_t> &p_width, int p_start, bool p_once, uint8_t /*TextBreakFlag*/ p_break_flags) const {
-	Vector<Vector2i> lines;
+PackedInt32Array TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start, bool p_once, uint16_t /*TextBreakFlag*/ p_break_flags) const {
+	PackedInt32Array lines;
 
 	ERR_FAIL_COND_V(p_width.is_empty(), lines);
 
 	const_cast<TextServer *>(this)->shaped_text_update_breaks(p_shaped);
-	const Vector<Glyph> &logical = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped);
 	const Vector2i &range = shaped_text_get_range(p_shaped);
 
 	real_t width = 0.f;
@@ -644,8 +648,8 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const
 	int last_safe_break = -1;
 	int chunk = 0;
 
-	int l_size = logical.size();
-	const Glyph *l_gl = logical.ptr();
+	int l_size = shaped_text_get_glyph_count(p_shaped);
+	const Glyph *l_gl = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped);
 
 	for (int i = 0; i < l_size; i++) {
 		if (l_gl[i].start < p_start) {
@@ -653,7 +657,8 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const
 		}
 		if (l_gl[i].count > 0) {
 			if ((p_width[chunk] > 0) && (width + l_gl[i].advance > p_width[chunk]) && (last_safe_break >= 0)) {
-				lines.push_back(Vector2i(line_start, l_gl[last_safe_break].end));
+				lines.push_back(line_start);
+				lines.push_back(l_gl[last_safe_break].end);
 				line_start = l_gl[last_safe_break].end;
 				i = last_safe_break;
 				last_safe_break = -1;
@@ -669,7 +674,8 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const
 			}
 			if ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) {
 				if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) {
-					lines.push_back(Vector2i(line_start, l_gl[i].end));
+					lines.push_back(line_start);
+					lines.push_back(l_gl[i].end);
 					line_start = l_gl[i].end;
 					last_safe_break = -1;
 					width = 0;
@@ -693,27 +699,31 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const
 	}
 
 	if (l_size > 0) {
-		lines.push_back(Vector2i(line_start, range.y));
+		if (lines.size() == 0 || lines[lines.size() - 1] < range.y) {
+			lines.push_back(line_start);
+			lines.push_back(range.y);
+		}
 	} else {
-		lines.push_back(Vector2i(0, 0));
+		lines.push_back(0);
+		lines.push_back(0);
 	}
 
 	return lines;
 }
 
-Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, real_t p_width, int p_start, uint8_t /*TextBreakFlag*/ p_break_flags) const {
-	Vector<Vector2i> lines;
+PackedInt32Array TextServer::shaped_text_get_line_breaks(RID p_shaped, real_t p_width, int p_start, uint16_t /*TextBreakFlag*/ p_break_flags) const {
+	PackedInt32Array lines;
 
 	const_cast<TextServer *>(this)->shaped_text_update_breaks(p_shaped);
-	const Vector<Glyph> &logical = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped);
 	const Vector2i &range = shaped_text_get_range(p_shaped);
 
 	real_t width = 0.f;
 	int line_start = MAX(p_start, range.x);
 	int last_safe_break = -1;
 	int word_count = 0;
-	int l_size = logical.size();
-	const Glyph *l_gl = logical.ptr();
+
+	int l_size = shaped_text_get_glyph_count(p_shaped);
+	const Glyph *l_gl = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped);
 
 	for (int i = 0; i < l_size; i++) {
 		if (l_gl[i].start < p_start) {
@@ -721,7 +731,8 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, real_t p_
 		}
 		if (l_gl[i].count > 0) {
 			if ((p_width > 0) && (width + l_gl[i].advance * l_gl[i].repeat > p_width) && (last_safe_break >= 0)) {
-				lines.push_back(Vector2i(line_start, l_gl[last_safe_break].end));
+				lines.push_back(line_start);
+				lines.push_back(l_gl[last_safe_break].end);
 				line_start = l_gl[last_safe_break].end;
 				i = last_safe_break;
 				last_safe_break = -1;
@@ -731,7 +742,8 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, real_t p_
 			}
 			if ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) {
 				if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) {
-					lines.push_back(Vector2i(line_start, l_gl[i].end));
+					lines.push_back(line_start);
+					lines.push_back(l_gl[i].end);
 					line_start = l_gl[i].end;
 					last_safe_break = -1;
 					width = 0;
@@ -755,51 +767,49 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, real_t p_
 	}
 
 	if (l_size > 0) {
-		if (lines.size() == 0 || lines[lines.size() - 1].y < range.y) {
-			lines.push_back(Vector2i(line_start, range.y));
+		if (lines.size() == 0 || lines[lines.size() - 1] < range.y) {
+			lines.push_back(line_start);
+			lines.push_back(range.y);
 		}
 	} else {
-		lines.push_back(Vector2i(0, 0));
+		lines.push_back(0);
+		lines.push_back(0);
 	}
 
 	return lines;
 }
 
-Vector<Vector2i> TextServer::shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags) const {
-	Vector<Vector2i> words;
+PackedInt32Array TextServer::shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags) const {
+	PackedInt32Array words;
 
 	const_cast<TextServer *>(this)->shaped_text_update_justification_ops(p_shaped);
-	const Vector<Glyph> &logical = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped);
 	const Vector2i &range = shaped_text_get_range(p_shaped);
 
 	int word_start = range.x;
 
-	int l_size = logical.size();
-	const Glyph *l_gl = logical.ptr();
+	int l_size = shaped_text_get_glyph_count(p_shaped);
+	const Glyph *l_gl = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped);
 
 	for (int i = 0; i < l_size; i++) {
 		if (l_gl[i].count > 0) {
 			if ((l_gl[i].flags & p_grapheme_flags) != 0) {
-				words.push_back(Vector2i(word_start, l_gl[i].start));
+				words.push_back(word_start);
+				words.push_back(l_gl[i].start);
 				word_start = l_gl[i].end;
 			}
 		}
 	}
 	if (l_size > 0) {
-		words.push_back(Vector2i(word_start, range.y));
+		words.push_back(word_start);
+		words.push_back(range.y);
 	}
 
 	return words;
 }
 
-TextServer::TrimData TextServer::shaped_text_get_trim_data(RID p_shaped) const {
-	WARN_PRINT("Getting overrun data not supported by this TextServer.");
-	return TrimData();
-}
-
-void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_leading_caret, Direction &p_leading_dir, Rect2 &p_trailing_caret, Direction &p_trailing_dir) const {
+CaretInfo TextServer::shaped_text_get_carets(RID p_shaped, int p_position) const {
 	Vector<Rect2> carets;
-	const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
+
 	TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
 	const Vector2 &range = shaped_text_get_range(p_shaped);
 	real_t ascent = shaped_text_get_ascent(p_shaped);
@@ -807,11 +817,12 @@ void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_l
 	real_t height = (ascent + descent) / 2;
 
 	real_t off = 0.0f;
-	p_leading_dir = DIRECTION_AUTO;
-	p_trailing_dir = DIRECTION_AUTO;
+	CaretInfo caret;
+	caret.l_dir = DIRECTION_AUTO;
+	caret.t_dir = DIRECTION_AUTO;
 
-	int v_size = visual.size();
-	const Glyph *glyphs = visual.ptr();
+	int v_size = shaped_text_get_glyph_count(p_shaped);
+	const Glyph *glyphs = shaped_text_get_glyphs(p_shaped);
 
 	for (int i = 0; i < v_size; i++) {
 		if (glyphs[i].count > 0) {
@@ -827,13 +838,13 @@ void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_l
 					cr.position.y = -ascent;
 					cr.position.x = off;
 					if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
-						p_trailing_dir = DIRECTION_RTL;
+						caret.t_dir = DIRECTION_RTL;
 						for (int j = 0; j < glyphs[i].count; j++) {
 							cr.position.x += glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.size.x -= glyphs[i + j].advance * glyphs[i + j].repeat;
 						}
 					} else {
-						p_trailing_dir = DIRECTION_LTR;
+						caret.t_dir = DIRECTION_LTR;
 						for (int j = 0; j < glyphs[i].count; j++) {
 							cr.size.x += glyphs[i + j].advance * glyphs[i + j].repeat;
 						}
@@ -847,19 +858,19 @@ void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_l
 					cr.position.x = -ascent;
 					cr.position.y = off;
 					if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
-						p_trailing_dir = DIRECTION_RTL;
+						caret.t_dir = DIRECTION_RTL;
 						for (int j = 0; j < glyphs[i].count; j++) {
 							cr.position.y += glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.size.y -= glyphs[i + j].advance * glyphs[i + j].repeat;
 						}
 					} else {
-						p_trailing_dir = DIRECTION_LTR;
+						caret.t_dir = DIRECTION_LTR;
 						for (int j = 0; j < glyphs[i].count; j++) {
 							cr.size.y += glyphs[i + j].advance * glyphs[i + j].repeat;
 						}
 					}
 				}
-				p_trailing_caret = cr;
+				caret.t_caret = cr;
 			}
 			// Caret after grapheme (bottom / right).
 			if (p_position == glyphs[i].end && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) {
@@ -874,13 +885,13 @@ void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_l
 					}
 					cr.position.x = off;
 					if ((glyphs[i].flags & GRAPHEME_IS_RTL) != GRAPHEME_IS_RTL) {
-						p_leading_dir = DIRECTION_LTR;
+						caret.l_dir = DIRECTION_LTR;
 						for (int j = 0; j < glyphs[i].count; j++) {
 							cr.position.x += glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.size.x -= glyphs[i + j].advance * glyphs[i + j].repeat;
 						}
 					} else {
-						p_leading_dir = DIRECTION_RTL;
+						caret.l_dir = DIRECTION_RTL;
 						for (int j = 0; j < glyphs[i].count; j++) {
 							cr.size.x += glyphs[i + j].advance * glyphs[i + j].repeat;
 						}
@@ -896,19 +907,19 @@ void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_l
 					}
 					cr.position.y = off;
 					if ((glyphs[i].flags & GRAPHEME_IS_RTL) != GRAPHEME_IS_RTL) {
-						p_leading_dir = DIRECTION_LTR;
+						caret.l_dir = DIRECTION_LTR;
 						for (int j = 0; j < glyphs[i].count; j++) {
 							cr.position.y += glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.size.y -= glyphs[i + j].advance * glyphs[i + j].repeat;
 						}
 					} else {
-						p_leading_dir = DIRECTION_RTL;
+						caret.l_dir = DIRECTION_RTL;
 						for (int j = 0; j < glyphs[i].count; j++) {
 							cr.size.y += glyphs[i + j].advance * glyphs[i + j].repeat;
 						}
 					}
 				}
-				p_leading_caret = cr;
+				caret.l_caret = cr;
 			}
 			// Caret inside grapheme (middle).
 			if (p_position > glyphs[i].start && p_position < glyphs[i].end && (glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL) {
@@ -937,17 +948,29 @@ void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_l
 						cr.position.y = off + char_adv * (p_position - glyphs[i].start);
 					}
 				}
-				p_trailing_caret = cr;
-				p_leading_caret = cr;
+				caret.t_caret = cr;
+				caret.l_caret = cr;
 			}
 		}
 		off += glyphs[i].advance * glyphs[i].repeat;
 	}
+	return caret;
 }
 
-TextServer::Direction TextServer::shaped_text_get_dominant_direciton_in_range(RID p_shaped, int p_start, int p_end) const {
-	const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
+Dictionary TextServer::_shaped_text_get_carets_wrapper(RID p_shaped, int p_position) const {
+	Dictionary ret;
+
+	CaretInfo caret = shaped_text_get_carets(p_shaped, p_position);
+
+	ret["leading_rect"] = caret.l_caret;
+	ret["leading_direction"] = caret.l_dir;
+	ret["trailing_rect"] = caret.t_caret;
+	ret["trailing_direction"] = caret.t_dir;
+
+	return ret;
+}
 
+TextServer::Direction TextServer::shaped_text_get_dominant_direction_in_range(RID p_shaped, int p_start, int p_end) const {
 	if (p_start == p_end) {
 		return DIRECTION_AUTO;
 	}
@@ -958,8 +981,8 @@ TextServer::Direction TextServer::shaped_text_get_dominant_direciton_in_range(RI
 	int rtl = 0;
 	int ltr = 0;
 
-	int v_size = visual.size();
-	const Glyph *glyphs = visual.ptr();
+	int v_size = shaped_text_get_glyph_count(p_shaped);
+	const Glyph *glyphs = shaped_text_get_glyphs(p_shaped);
 
 	for (int i = 0; i < v_size; i++) {
 		if ((glyphs[i].end > start) && (glyphs[i].start < end)) {
@@ -983,7 +1006,6 @@ TextServer::Direction TextServer::shaped_text_get_dominant_direciton_in_range(RI
 
 Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const {
 	Vector<Vector2> ranges;
-	const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
 
 	if (p_start == p_end) {
 		return ranges;
@@ -992,8 +1014,8 @@ Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start,
 	int start = MIN(p_start, p_end);
 	int end = MAX(p_start, p_end);
 
-	int v_size = visual.size();
-	const Glyph *glyphs = visual.ptr();
+	int v_size = shaped_text_get_glyph_count(p_shaped);
+	const Glyph *glyphs = shaped_text_get_glyphs(p_shaped);
 
 	real_t off = 0.0f;
 	for (int i = 0; i < v_size; i++) {
@@ -1076,13 +1098,11 @@ Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start,
 }
 
 int TextServer::shaped_text_hit_test_grapheme(RID p_shaped, real_t p_coords) const {
-	const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
-
 	// Exact grapheme hit test, return -1 if missed.
 	real_t off = 0.0f;
 
-	int v_size = visual.size();
-	const Glyph *glyphs = visual.ptr();
+	int v_size = shaped_text_get_glyph_count(p_shaped);
+	const Glyph *glyphs = shaped_text_get_glyphs(p_shaped);
 
 	for (int i = 0; i < v_size; i++) {
 		for (int j = 0; j < glyphs[i].repeat; j++) {
@@ -1096,10 +1116,8 @@ int TextServer::shaped_text_hit_test_grapheme(RID p_shaped, real_t p_coords) con
 }
 
 int TextServer::shaped_text_hit_test_position(RID p_shaped, real_t p_coords) const {
-	const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
-
-	int v_size = visual.size();
-	const Glyph *glyphs = visual.ptr();
+	int v_size = shaped_text_get_glyph_count(p_shaped);
+	const Glyph *glyphs = shaped_text_get_glyphs(p_shaped);
 
 	// Cursor placement hit test.
 
@@ -1165,10 +1183,9 @@ int TextServer::shaped_text_hit_test_position(RID p_shaped, real_t p_coords) con
 	return 0;
 }
 
-int TextServer::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) {
-	const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
-	int v_size = visual.size();
-	const Glyph *glyphs = visual.ptr();
+int TextServer::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) const {
+	int v_size = shaped_text_get_glyph_count(p_shaped);
+	const Glyph *glyphs = shaped_text_get_glyphs(p_shaped);
 	for (int i = 0; i < v_size; i++) {
 		if (p_pos >= glyphs[i].start && p_pos < glyphs[i].end) {
 			return glyphs[i].end;
@@ -1177,10 +1194,9 @@ int TextServer::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) {
 	return p_pos;
 }
 
-int TextServer::shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) {
-	const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
-	int v_size = visual.size();
-	const Glyph *glyphs = visual.ptr();
+int TextServer::shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) const {
+	int v_size = shaped_text_get_glyph_count(p_shaped);
+	const Glyph *glyphs = shaped_text_get_glyphs(p_shaped);
 	for (int i = 0; i < v_size; i++) {
 		if (p_pos > glyphs[i].start && p_pos <= glyphs[i].end) {
 			return glyphs[i].start;
@@ -1191,26 +1207,30 @@ int TextServer::shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) {
 }
 
 void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, real_t p_clip_l, real_t p_clip_r, const Color &p_color) const {
-	const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
 	TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
 	bool hex_codes = shaped_text_get_preserve_control(p_shaped) || shaped_text_get_preserve_invalid(p_shaped);
 
 	bool rtl = shaped_text_get_direction(p_shaped) == DIRECTION_RTL;
-	TrimData trim_data = shaped_text_get_trim_data(p_shaped);
 
-	int v_size = visual.size();
-	const Glyph *glyphs = visual.ptr();
+	int ellipsis_pos = shaped_text_get_ellipsis_pos(p_shaped);
+	int trim_pos = shaped_text_get_trim_pos(p_shaped);
+
+	const Glyph *ellipsis_glyphs = shaped_text_get_ellipsis_glyphs(p_shaped);
+	int ellipsis_gl_size = shaped_text_get_ellipsis_glyph_count(p_shaped);
+
+	int v_size = shaped_text_get_glyph_count(p_shaped);
+	const Glyph *glyphs = shaped_text_get_glyphs(p_shaped);
 
 	Vector2 ofs = p_pos;
 	// Draw RTL ellipsis string when needed.
-	if (rtl && trim_data.ellipsis_pos >= 0) {
-		for (int i = trim_data.ellipsis_glyph_buf.size() - 1; i >= 0; i--) {
-			for (int j = 0; j < trim_data.ellipsis_glyph_buf[i].repeat; j++) {
-				font_draw_glyph(trim_data.ellipsis_glyph_buf[i].font_rid, p_canvas, trim_data.ellipsis_glyph_buf[i].font_size, ofs + Vector2(trim_data.ellipsis_glyph_buf[i].x_off, trim_data.ellipsis_glyph_buf[i].y_off), trim_data.ellipsis_glyph_buf[i].index, p_color);
+	if (rtl && ellipsis_pos >= 0) {
+		for (int i = ellipsis_gl_size - 1; i >= 0; i--) {
+			for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) {
+				font_draw_glyph(ellipsis_glyphs[i].font_rid, p_canvas, ellipsis_glyphs[i].font_size, ofs + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color);
 				if (orientation == ORIENTATION_HORIZONTAL) {
-					ofs.x += trim_data.ellipsis_glyph_buf[i].advance;
+					ofs.x += ellipsis_glyphs[i].advance;
 				} else {
-					ofs.y += trim_data.ellipsis_glyph_buf[i].advance;
+					ofs.y += ellipsis_glyphs[i].advance;
 				}
 			}
 		}
@@ -1244,13 +1264,13 @@ void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_p
 					}
 				}
 			}
-			if (trim_data.trim_pos >= 0) {
+			if (trim_pos >= 0) {
 				if (rtl) {
-					if (i < trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+					if (i < trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
 						continue;
 					}
 				} else {
-					if (i >= trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+					if (i >= trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
 						break;
 					}
 				}
@@ -1269,14 +1289,14 @@ void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_p
 		}
 	}
 	// Draw LTR ellipsis string when needed.
-	if (!rtl && trim_data.ellipsis_pos >= 0) {
-		for (int i = 0; i < trim_data.ellipsis_glyph_buf.size(); i++) {
-			for (int j = 0; j < trim_data.ellipsis_glyph_buf[i].repeat; j++) {
-				font_draw_glyph(trim_data.ellipsis_glyph_buf[i].font_rid, p_canvas, trim_data.ellipsis_glyph_buf[i].font_size, ofs + Vector2(trim_data.ellipsis_glyph_buf[i].x_off, trim_data.ellipsis_glyph_buf[i].y_off), trim_data.ellipsis_glyph_buf[i].index, p_color);
+	if (!rtl && ellipsis_pos >= 0) {
+		for (int i = 0; i < ellipsis_gl_size; i++) {
+			for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) {
+				font_draw_glyph(ellipsis_glyphs[i].font_rid, p_canvas, ellipsis_glyphs[i].font_size, ofs + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color);
 				if (orientation == ORIENTATION_HORIZONTAL) {
-					ofs.x += trim_data.ellipsis_glyph_buf[i].advance;
+					ofs.x += ellipsis_glyphs[i].advance;
 				} else {
-					ofs.y += trim_data.ellipsis_glyph_buf[i].advance;
+					ofs.y += ellipsis_glyphs[i].advance;
 				}
 			}
 		}
@@ -1284,24 +1304,28 @@ void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_p
 }
 
 void TextServer::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, real_t p_clip_l, real_t p_clip_r, int p_outline_size, const Color &p_color) const {
-	const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
 	TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
 
 	bool rtl = (shaped_text_get_direction(p_shaped) == DIRECTION_RTL);
-	TrimData trim_data = shaped_text_get_trim_data(p_shaped);
 
-	int v_size = visual.size();
-	const Glyph *glyphs = visual.ptr();
+	int ellipsis_pos = shaped_text_get_ellipsis_pos(p_shaped);
+	int trim_pos = shaped_text_get_trim_pos(p_shaped);
+
+	const Glyph *ellipsis_glyphs = shaped_text_get_ellipsis_glyphs(p_shaped);
+	int ellipsis_gl_size = shaped_text_get_ellipsis_glyph_count(p_shaped);
+
+	int v_size = shaped_text_get_glyph_count(p_shaped);
+	const Glyph *glyphs = shaped_text_get_glyphs(p_shaped);
 	Vector2 ofs = p_pos;
 	// Draw RTL ellipsis string when needed.
-	if (rtl && trim_data.ellipsis_pos >= 0) {
-		for (int i = trim_data.ellipsis_glyph_buf.size() - 1; i >= 0; i--) {
-			for (int j = 0; j < trim_data.ellipsis_glyph_buf[i].repeat; j++) {
-				font_draw_glyph(trim_data.ellipsis_glyph_buf[i].font_rid, p_canvas, trim_data.ellipsis_glyph_buf[i].font_size, ofs + Vector2(trim_data.ellipsis_glyph_buf[i].x_off, trim_data.ellipsis_glyph_buf[i].y_off), trim_data.ellipsis_glyph_buf[i].index, p_color);
+	if (rtl && ellipsis_pos >= 0) {
+		for (int i = ellipsis_gl_size - 1; i >= 0; i--) {
+			for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) {
+				font_draw_glyph(ellipsis_glyphs[i].font_rid, p_canvas, ellipsis_glyphs[i].font_size, ofs + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color);
 				if (orientation == ORIENTATION_HORIZONTAL) {
-					ofs.x += trim_data.ellipsis_glyph_buf[i].advance;
+					ofs.x += ellipsis_glyphs[i].advance;
 				} else {
-					ofs.y += trim_data.ellipsis_glyph_buf[i].advance;
+					ofs.y += ellipsis_glyphs[i].advance;
 				}
 			}
 		}
@@ -1335,13 +1359,13 @@ void TextServer::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vect
 					}
 				}
 			}
-			if (trim_data.trim_pos >= 0) {
+			if (trim_pos >= 0) {
 				if (rtl) {
-					if (i < trim_data.trim_pos) {
+					if (i < trim_pos) {
 						continue;
 					}
 				} else {
-					if (i >= trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
+					if (i >= trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
 						break;
 					}
 				}
@@ -1357,48 +1381,26 @@ void TextServer::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vect
 		}
 	}
 	// Draw LTR ellipsis string when needed.
-	if (!rtl && trim_data.ellipsis_pos >= 0) {
-		for (int i = 0; i < trim_data.ellipsis_glyph_buf.size(); i++) {
-			for (int j = 0; j < trim_data.ellipsis_glyph_buf[i].repeat; j++) {
-				font_draw_glyph(trim_data.ellipsis_glyph_buf[i].font_rid, p_canvas, trim_data.ellipsis_glyph_buf[i].font_size, ofs + Vector2(trim_data.ellipsis_glyph_buf[i].x_off, trim_data.ellipsis_glyph_buf[i].y_off), trim_data.ellipsis_glyph_buf[i].index, p_color);
+	if (!rtl && ellipsis_pos >= 0) {
+		for (int i = 0; i < ellipsis_gl_size; i++) {
+			for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) {
+				font_draw_glyph(ellipsis_glyphs[i].font_rid, p_canvas, ellipsis_glyphs[i].font_size, ofs + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color);
 				if (orientation == ORIENTATION_HORIZONTAL) {
-					ofs.x += trim_data.ellipsis_glyph_buf[i].advance;
+					ofs.x += ellipsis_glyphs[i].advance;
 				} else {
-					ofs.y += trim_data.ellipsis_glyph_buf[i].advance;
+					ofs.y += ellipsis_glyphs[i].advance;
 				}
 			}
 		}
 	}
 }
 
-Dictionary TextServer::_font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const {
-	Vector<Vector3> points;
-	Vector<int32_t> contours;
-	bool orientation;
-	bool ok = font_get_glyph_contours(p_font, p_size, p_index, points, contours, orientation);
-	Dictionary out;
-
-	if (ok) {
-		out["points"] = points;
-		out["contours"] = contours;
-		out["orientation"] = orientation;
-	}
-	return out;
-}
-
-void TextServer::_shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) {
-	Vector<Vector2i> overrides;
-	for (int i = 0; i < p_override.size(); i++) {
-		overrides.push_back(p_override[i]);
-	}
-	shaped_text_set_bidi_override(p_shaped, overrides);
-}
-
-Array TextServer::_shaped_text_get_glyphs(RID p_shaped) const {
+Array TextServer::_shaped_text_get_glyphs_wrapper(RID p_shaped) const {
 	Array ret;
 
-	Vector<Glyph> glyphs = shaped_text_get_glyphs(p_shaped);
-	for (int i = 0; i < glyphs.size(); i++) {
+	const Glyph *glyphs = shaped_text_get_glyphs(p_shaped);
+	int gl_size = shaped_text_get_glyph_count(p_shaped);
+	for (int i = 0; i < gl_size; i++) {
 		Dictionary glyph;
 
 		glyph["start"] = glyphs[i].start;
@@ -1418,60 +1420,51 @@ Array TextServer::_shaped_text_get_glyphs(RID p_shaped) const {
 	return ret;
 }
 
-Array TextServer::_shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start, bool p_once, uint8_t p_break_flags) const {
+Array TextServer::_shaped_text_sort_logical_wrapper(RID p_shaped) {
 	Array ret;
 
-	Vector<Vector2i> lines = shaped_text_get_line_breaks_adv(p_shaped, p_width, p_start, p_once, p_break_flags);
-	for (int i = 0; i < lines.size(); i++) {
-		ret.push_back(lines[i]);
-	}
-
-	return ret;
-}
+	const Glyph *glyphs = shaped_text_sort_logical(p_shaped);
+	int gl_size = shaped_text_get_glyph_count(p_shaped);
+	for (int i = 0; i < gl_size; i++) {
+		Dictionary glyph;
 
-Array TextServer::_shaped_text_get_line_breaks(RID p_shaped, real_t p_width, int p_start, uint8_t p_break_flags) const {
-	Array ret;
+		glyph["start"] = glyphs[i].start;
+		glyph["end"] = glyphs[i].end;
+		glyph["repeat"] = glyphs[i].repeat;
+		glyph["count"] = glyphs[i].count;
+		glyph["flags"] = glyphs[i].flags;
+		glyph["offset"] = Vector2(glyphs[i].x_off, glyphs[i].y_off);
+		glyph["advance"] = glyphs[i].advance;
+		glyph["font_rid"] = glyphs[i].font_rid;
+		glyph["font_size"] = glyphs[i].font_size;
+		glyph["index"] = glyphs[i].index;
 
-	Vector<Vector2i> lines = shaped_text_get_line_breaks(p_shaped, p_width, p_start, p_break_flags);
-	for (int i = 0; i < lines.size(); i++) {
-		ret.push_back(lines[i]);
+		ret.push_back(glyph);
 	}
 
 	return ret;
 }
 
-Array TextServer::_shaped_text_get_word_breaks(RID p_shaped) const {
+Array TextServer::_shaped_text_get_ellipsis_glyphs_wrapper(RID p_shaped) const {
 	Array ret;
 
-	Vector<Vector2i> words = shaped_text_get_word_breaks(p_shaped);
-	for (int i = 0; i < words.size(); i++) {
-		ret.push_back(words[i]);
-	}
-
-	return ret;
-}
-
-Dictionary TextServer::_shaped_text_get_carets(RID p_shaped, int p_position) const {
-	Dictionary ret;
-
-	Rect2 l_caret, t_caret;
-	Direction l_dir, t_dir;
-	shaped_text_get_carets(p_shaped, p_position, l_caret, l_dir, t_caret, t_dir);
-
-	ret["leading_rect"] = l_caret;
-	ret["leading_direction"] = l_dir;
-	ret["trailing_rect"] = t_caret;
-	ret["trailing_direction"] = t_dir;
-
-	return ret;
-}
+	const Glyph *glyphs = shaped_text_get_ellipsis_glyphs(p_shaped);
+	int gl_size = shaped_text_get_ellipsis_glyph_count(p_shaped);
+	for (int i = 0; i < gl_size; i++) {
+		Dictionary glyph;
 
-Array TextServer::_shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const {
-	Array ret;
+		glyph["start"] = glyphs[i].start;
+		glyph["end"] = glyphs[i].end;
+		glyph["repeat"] = glyphs[i].repeat;
+		glyph["count"] = glyphs[i].count;
+		glyph["flags"] = glyphs[i].flags;
+		glyph["offset"] = Vector2(glyphs[i].x_off, glyphs[i].y_off);
+		glyph["advance"] = glyphs[i].advance;
+		glyph["font_rid"] = glyphs[i].font_rid;
+		glyph["font_size"] = glyphs[i].font_size;
+		glyph["index"] = glyphs[i].index;
 
-	Vector<Vector2> ranges = shaped_text_get_selection(p_shaped, p_start, p_end);
-	for (int i = 0; i < ranges.size(); i++) {
-		ret.push_back(ranges[i]);
+		ret.push_back(glyph);
 	}
 
 	return ret;

+ 142 - 152
servers/text_server.h

@@ -34,13 +34,17 @@
 #include "core/object/ref_counted.h"
 #include "core/os/os.h"
 #include "core/templates/rid.h"
+#include "core/variant/native_ptr.h"
 #include "core/variant/variant.h"
 #include "scene/resources/texture.h"
 
 class CanvasTexture;
 
-class TextServer : public Object {
-	GDCLASS(TextServer, Object);
+struct Glyph;
+struct CaretInfo;
+
+class TextServer : public RefCounted {
+	GDCLASS(TextServer, RefCounted);
 
 public:
 	enum Direction {
@@ -63,12 +67,12 @@ public:
 		JUSTIFICATION_CONSTRAIN_ELLIPSIS = 1 << 4,
 	};
 
-	enum LineBreakFlag {
+	enum LineBreakFlag { // LineBreakFlag can be passed in the same value as the JustificationFlag, do not use the same values.
 		BREAK_NONE = 0,
-		BREAK_MANDATORY = 1 << 4,
-		BREAK_WORD_BOUND = 1 << 5,
-		BREAK_GRAPHEME_BOUND = 1 << 6,
-		BREAK_WORD_BOUND_ADAPTIVE = 1 << 5 | 1 << 7,
+		BREAK_MANDATORY = 1 << 5,
+		BREAK_WORD_BOUND = 1 << 6,
+		BREAK_GRAPHEME_BOUND = 1 << 7,
+		BREAK_WORD_BOUND_ADAPTIVE = 1 << 6 | 1 << 8,
 	};
 
 	enum TextOverrunFlag {
@@ -124,50 +128,11 @@ public:
 		SPACING_BOTTOM,
 	};
 
-	struct Glyph {
-		int start = -1; // Start offset in the source string.
-		int end = -1; // End offset in the source string.
-
-		uint8_t count = 0; // Number of glyphs in the grapheme, set in the first glyph only.
-		uint8_t repeat = 1; // Draw multiple times in the row.
-		uint16_t flags = 0; // Grapheme flags (valid, rtl, virtual), set in the first glyph only.
-
-		real_t x_off = 0.f; // Offset from the origin of the glyph on baseline.
-		real_t y_off = 0.f;
-		real_t advance = 0.f; // Advance to the next glyph along baseline(x for horizontal layout, y for vertical).
-
-		RID font_rid; // Font resource.
-		int font_size = 0; // Font size;
-		int32_t index = 0; // Glyph index (font specific) or UTF-32 codepoint (for the invalid glyphs).
-
-		bool operator==(const Glyph &p_a) const;
-		bool operator!=(const Glyph &p_a) const;
-
-		bool operator<(const Glyph &p_a) const;
-		bool operator>(const Glyph &p_a) const;
-	};
-
-	struct GlyphCompare { // For line breaking reordering.
-		_FORCE_INLINE_ bool operator()(const Glyph &l, const Glyph &r) const {
-			if (l.start == r.start) {
-				if (l.count == r.count) {
-					if ((l.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
-						return false;
-					} else {
-						return true;
-					}
-				}
-				return l.count > r.count; // Sort first glyph with count & flags, order of the rest are irrelevant.
-			} else {
-				return l.start < r.start;
-			}
-		}
-	};
-
+protected:
 	struct TrimData {
 		int trim_pos = -1;
 		int ellipsis_pos = -1;
-		Vector<TextServer::Glyph> ellipsis_glyph_buf;
+		Vector<Glyph> ellipsis_glyph_buf;
 	};
 
 	struct ShapedTextData {
@@ -215,22 +180,21 @@ public:
 		bool preserve_invalid = true; // Draw hex code box instead of missing characters.
 		bool preserve_control = false; // Draw control characters.
 
-		real_t ascent = 0.f; // Ascent for horizontal layout, 1/2 of width for vertical.
-		real_t descent = 0.f; // Descent for horizontal layout, 1/2 of width for vertical.
-		real_t width = 0.f; // Width for horizontal layout, height for vertical.
-		real_t width_trimmed = 0.f;
+		float ascent = 0.f; // Ascent for horizontal layout, 1/2 of width for vertical.
+		float descent = 0.f; // Descent for horizontal layout, 1/2 of width for vertical.
+		float width = 0.f; // Width for horizontal layout, height for vertical.
+		float width_trimmed = 0.f;
 
-		real_t upos = 0.f;
-		real_t uthk = 0.f;
+		float upos = 0.f;
+		float uthk = 0.f;
 
 		TrimData overrun_trim_data;
 		bool fit_width_minimum_reached = false;
 
-		Vector<TextServer::Glyph> glyphs;
-		Vector<TextServer::Glyph> glyphs_logical;
+		Vector<Glyph> glyphs;
+		Vector<Glyph> glyphs_logical;
 	};
 
-protected:
 	static void _bind_methods();
 
 	static Vector3 hex_code_box_font_size[2];
@@ -240,20 +204,19 @@ public:
 	static void initialize_hex_code_box_fonts();
 	static void finish_hex_code_box_fonts();
 
-	virtual bool has_feature(Feature p_feature) = 0;
+	virtual bool has_feature(Feature p_feature) const = 0;
 	virtual String get_name() const = 0;
+	virtual uint32_t get_features() const = 0;
 
 	virtual void free(RID p_rid) = 0;
 	virtual bool has(RID p_rid) = 0;
 	virtual bool load_support_data(const String &p_filename) = 0;
 
-#ifdef TOOLS_ENABLED
-	virtual String get_support_data_filename() = 0;
-	virtual String get_support_data_info() = 0;
-	virtual bool save_support_data(const String &p_filename) = 0;
-#endif
+	virtual String get_support_data_filename() const = 0;
+	virtual String get_support_data_info() const = 0;
+	virtual bool save_support_data(const String &p_filename) const = 0;
 
-	virtual bool is_locale_right_to_left(const String &p_locale) = 0;
+	virtual bool is_locale_right_to_left(const String &p_locale) const = 0;
 
 	virtual int32_t name_to_tag(const String &p_name) const { return 0; };
 	virtual String tag_to_name(int32_t p_tag) const { return ""; };
@@ -282,33 +245,33 @@ public:
 	virtual void font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) = 0;
 	virtual bool font_is_force_autohinter(RID p_font_rid) const = 0;
 
-	virtual void font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) = 0;
-	virtual TextServer::Hinting font_get_hinting(RID p_font_rid) const = 0;
+	virtual void font_set_hinting(RID p_font_rid, Hinting p_hinting) = 0;
+	virtual Hinting font_get_hinting(RID p_font_rid) const = 0;
 
 	virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) = 0;
 	virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const = 0;
 
-	virtual void font_set_oversampling(RID p_font_rid, real_t p_oversampling) = 0;
-	virtual real_t font_get_oversampling(RID p_font_rid) const = 0;
+	virtual void font_set_oversampling(RID p_font_rid, float p_oversampling) = 0;
+	virtual float font_get_oversampling(RID p_font_rid) const = 0;
 
 	virtual Array font_get_size_cache_list(RID p_font_rid) const = 0;
 	virtual void font_clear_size_cache(RID p_font_rid) = 0;
 	virtual void font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) = 0;
 
-	virtual void font_set_ascent(RID p_font_rid, int p_size, real_t p_ascent) = 0;
-	virtual real_t font_get_ascent(RID p_font_rid, int p_size) const = 0;
+	virtual void font_set_ascent(RID p_font_rid, int p_size, float p_ascent) = 0;
+	virtual float font_get_ascent(RID p_font_rid, int p_size) const = 0;
 
-	virtual void font_set_descent(RID p_font_rid, int p_size, real_t p_descent) = 0;
-	virtual real_t font_get_descent(RID p_font_rid, int p_size) const = 0;
+	virtual void font_set_descent(RID p_font_rid, int p_size, float p_descent) = 0;
+	virtual float font_get_descent(RID p_font_rid, int p_size) const = 0;
 
-	virtual void font_set_underline_position(RID p_font_rid, int p_size, real_t p_underline_position) = 0;
-	virtual real_t font_get_underline_position(RID p_font_rid, int p_size) const = 0;
+	virtual void font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) = 0;
+	virtual float font_get_underline_position(RID p_font_rid, int p_size) const = 0;
 
-	virtual void font_set_underline_thickness(RID p_font_rid, int p_size, real_t p_underline_thickness) = 0;
-	virtual real_t font_get_underline_thickness(RID p_font_rid, int p_size) const = 0;
+	virtual void font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) = 0;
+	virtual float font_get_underline_thickness(RID p_font_rid, int p_size) const = 0;
 
-	virtual void font_set_scale(RID p_font_rid, int p_size, real_t p_scale) = 0;
-	virtual real_t font_get_scale(RID p_font_rid, int p_size) const = 0;
+	virtual void font_set_scale(RID p_font_rid, int p_size, float p_scale) = 0;
+	virtual float font_get_scale(RID p_font_rid, int p_size) const = 0;
 
 	virtual void font_set_spacing(RID p_font_rid, int p_size, SpacingType p_spacing, int p_value) = 0;
 	virtual int font_get_spacing(RID p_font_rid, int p_size, SpacingType p_spacing) const = 0;
@@ -342,7 +305,7 @@ public:
 	virtual int font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const = 0;
 	virtual void font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) = 0;
 
-	virtual bool font_get_glyph_contours(RID p_font, int p_size, int32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const = 0;
+	virtual Dictionary font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const = 0;
 
 	virtual Array font_get_kerning_list(RID p_font_rid, int p_size) const = 0;
 	virtual void font_clear_kerning_map(RID p_font_rid, int p_size) = 0;
@@ -377,11 +340,11 @@ public:
 	virtual Dictionary font_supported_feature_list(RID p_font_rid) const = 0;
 	virtual Dictionary font_supported_variation_list(RID p_font_rid) const = 0;
 
-	virtual real_t font_get_global_oversampling() const = 0;
-	virtual void font_set_global_oversampling(real_t p_oversampling) = 0;
+	virtual float font_get_global_oversampling() const = 0;
+	virtual void font_set_global_oversampling(float p_oversampling) = 0;
 
-	Vector2 get_hex_code_box_size(int p_size, char32_t p_index) const;
-	void draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_pos, char32_t p_index, const Color &p_color) const;
+	virtual Vector2 get_hex_code_box_size(int p_size, char32_t p_index) const;
+	virtual void draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_pos, char32_t p_index, const Color &p_color) const;
 
 	/* Shaped text buffer interface */
 
@@ -392,7 +355,7 @@ public:
 	virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) = 0;
 	virtual Direction shaped_text_get_direction(RID p_shaped) const = 0;
 
-	virtual void shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) = 0;
+	virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) = 0;
 
 	virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) = 0;
 	virtual Orientation shaped_text_get_orientation(RID p_shaped) const = 0;
@@ -410,8 +373,8 @@ public:
 	virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const = 0; // Copy shaped substring (e.g. line break) without reshaping, but correctly reordered, preservers range.
 	virtual RID shaped_text_get_parent(RID p_shaped) const = 0;
 
-	virtual real_t shaped_text_fit_to_width(RID p_shaped, real_t p_width, uint8_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) = 0;
-	virtual real_t shaped_text_tab_align(RID p_shaped, const Vector<real_t> &p_tab_stops) = 0;
+	virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) = 0;
+	virtual float shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) = 0;
 
 	virtual bool shaped_text_shape(RID p_shaped) = 0;
 	virtual bool shaped_text_update_breaks(RID p_shaped) = 0;
@@ -419,66 +382,109 @@ public:
 
 	virtual bool shaped_text_is_ready(RID p_shaped) const = 0;
 
-	virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const = 0;
+	virtual const Glyph *shaped_text_get_glyphs(RID p_shaped) const = 0;
+	Array _shaped_text_get_glyphs_wrapper(RID p_shaped) const;
+	virtual const Glyph *shaped_text_sort_logical(RID p_shaped) = 0;
+	Array _shaped_text_sort_logical_wrapper(RID p_shaped);
+	virtual int shaped_text_get_glyph_count(RID p_shaped) const = 0;
 
 	virtual Vector2i shaped_text_get_range(RID p_shaped) const = 0;
 
-	virtual Vector<Glyph> shaped_text_sort_logical(RID p_shaped) = 0;
+	virtual PackedInt32Array shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start = 0, bool p_once = true, uint16_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const;
+	virtual PackedInt32Array shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start = 0, uint16_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const;
+	virtual PackedInt32Array shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION) const;
 
-	virtual Vector<Vector2i> shaped_text_get_line_breaks_adv(RID p_shaped, const Vector<real_t> &p_width, int p_start = 0, bool p_once = true, uint8_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const;
-	virtual Vector<Vector2i> shaped_text_get_line_breaks(RID p_shaped, real_t p_width, int p_start = 0, uint8_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const;
-	virtual Vector<Vector2i> shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION) const;
+	virtual int shaped_text_get_trim_pos(RID p_shaped) const = 0;
+	virtual int shaped_text_get_ellipsis_pos(RID p_shaped) const = 0;
+	virtual const Glyph *shaped_text_get_ellipsis_glyphs(RID p_shaped) const = 0;
+	Array _shaped_text_get_ellipsis_glyphs_wrapper(RID p_shaped) const;
+	virtual int shaped_text_get_ellipsis_glyph_count(RID p_shaped) const = 0;
+
+	virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint16_t p_trim_flags) = 0;
 
-	virtual TrimData shaped_text_get_trim_data(RID p_shaped) const;
-	virtual void shaped_text_overrun_trim_to_width(RID p_shaped, real_t p_width, uint8_t p_trim_flags) = 0;
 	virtual Array shaped_text_get_objects(RID p_shaped) const = 0;
 	virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const = 0;
 
 	virtual Size2 shaped_text_get_size(RID p_shaped) const = 0;
-	virtual real_t shaped_text_get_ascent(RID p_shaped) const = 0;
-	virtual real_t shaped_text_get_descent(RID p_shaped) const = 0;
-	virtual real_t shaped_text_get_width(RID p_shaped) const = 0;
-	virtual real_t shaped_text_get_underline_position(RID p_shaped) const = 0;
-	virtual real_t shaped_text_get_underline_thickness(RID p_shaped) const = 0;
+	virtual float shaped_text_get_ascent(RID p_shaped) const = 0;
+	virtual float shaped_text_get_descent(RID p_shaped) const = 0;
+	virtual float shaped_text_get_width(RID p_shaped) const = 0;
+	virtual float shaped_text_get_underline_position(RID p_shaped) const = 0;
+	virtual float shaped_text_get_underline_thickness(RID p_shaped) const = 0;
+
+	virtual Direction shaped_text_get_dominant_direction_in_range(RID p_shaped, int p_start, int p_end) const;
 
-	virtual Direction shaped_text_get_dominant_direciton_in_range(RID p_shaped, int p_start, int p_end) const;
+	virtual CaretInfo shaped_text_get_carets(RID p_shaped, int p_position) const;
+	Dictionary _shaped_text_get_carets_wrapper(RID p_shaped, int p_position) const;
 
-	virtual void shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_leading_caret, Direction &p_leading_dir, Rect2 &p_trailing_caret, Direction &p_trailing_dir) const;
 	virtual Vector<Vector2> shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const;
 
-	virtual int shaped_text_hit_test_grapheme(RID p_shaped, real_t p_coords) const; // Return grapheme index.
-	virtual int shaped_text_hit_test_position(RID p_shaped, real_t p_coords) const; // Return caret/selection position.
+	virtual int shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) const; // Return grapheme index.
+	virtual int shaped_text_hit_test_position(RID p_shaped, float p_coords) const; // Return caret/selection position.
 
-	virtual int shaped_text_next_grapheme_pos(RID p_shaped, int p_pos);
-	virtual int shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos);
+	virtual int shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) const;
+	virtual int shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) const;
 
 	// The pen position is always placed on the baseline and moveing left to right.
-	virtual void shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, real_t p_clip_l = -1.f, real_t p_clip_r = -1.f, const Color &p_color = Color(1, 1, 1)) const;
-	virtual void shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, real_t p_clip_l = -1.f, real_t p_clip_r = -1.f, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1)) const;
+	virtual void shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l = -1.f, float p_clip_r = -1.f, const Color &p_color = Color(1, 1, 1)) const;
+	virtual void shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l = -1.f, float p_clip_r = -1.f, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1)) const;
 
 	// Number conversion.
 	virtual String format_number(const String &p_string, const String &p_language = "") const { return p_string; };
 	virtual String parse_number(const String &p_string, const String &p_language = "") const { return p_string; };
 	virtual String percent_sign(const String &p_language = "") const { return "%"; };
 
-	/* GDScript wrappers */
-	RID _create_font_memory(const PackedByteArray &p_data, int p_base_size = 16);
+	TextServer();
+	~TextServer();
+};
+
+/*************************************************************************/
 
-	Dictionary _font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const;
+struct Glyph {
+	int start = -1; // Start offset in the source string.
+	int end = -1; // End offset in the source string.
 
-	Array _shaped_text_get_glyphs(RID p_shaped) const;
-	Dictionary _shaped_text_get_carets(RID p_shaped, int p_position) const;
+	uint8_t count = 0; // Number of glyphs in the grapheme, set in the first glyph only.
+	uint8_t repeat = 1; // Draw multiple times in the row.
+	uint16_t flags = 0; // Grapheme flags (valid, rtl, virtual), set in the first glyph only.
 
-	void _shaped_text_set_bidi_override(RID p_shaped, const Array &p_override);
+	float x_off = 0.f; // Offset from the origin of the glyph on baseline.
+	float y_off = 0.f;
+	float advance = 0.f; // Advance to the next glyph along baseline(x for horizontal layout, y for vertical).
 
-	Array _shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start, bool p_once, uint8_t p_break_flags) const;
-	Array _shaped_text_get_line_breaks(RID p_shaped, real_t p_width, int p_start, uint8_t p_break_flags) const;
-	Array _shaped_text_get_word_breaks(RID p_shaped) const;
+	RID font_rid; // Font resource.
+	int font_size = 0; // Font size;
+	int32_t index = 0; // Glyph index (font specific) or UTF-32 codepoint (for the invalid glyphs).
 
-	Array _shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const;
+	bool operator==(const Glyph &p_a) const;
+	bool operator!=(const Glyph &p_a) const;
 
-	TextServer();
-	~TextServer();
+	bool operator<(const Glyph &p_a) const;
+	bool operator>(const Glyph &p_a) const;
+};
+
+struct CaretInfo {
+	Rect2 l_caret;
+	Rect2 t_caret;
+	TextServer::Direction l_dir;
+	TextServer::Direction t_dir;
+};
+
+struct GlyphCompare { // For line breaking reordering.
+	_FORCE_INLINE_ bool operator()(const Glyph &l, const Glyph &r) const {
+		if (l.start == r.start) {
+			if (l.count == r.count) {
+				if ((l.flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL) {
+					return false;
+				} else {
+					return true;
+				}
+			}
+			return l.count > r.count; // Sort first glyph with count & flags, order of the rest are irrelevant.
+		} else {
+			return l.start < r.start;
+		}
+	}
 };
 
 /*************************************************************************/
@@ -486,52 +492,32 @@ public:
 class TextServerManager : public Object {
 	GDCLASS(TextServerManager, Object);
 
-public:
-	typedef TextServer *(*CreateFunction)(Error &r_error, void *p_user_data);
-
 protected:
 	static void _bind_methods();
 
 private:
 	static TextServerManager *singleton;
-	static TextServer *server;
-	enum {
-		MAX_SERVERS = 64
-	};
 
-	struct TextServerCreate {
-		String name;
-		CreateFunction create_function = nullptr;
-		uint32_t features = 0;
-		TextServer *instance = nullptr;
-		void *user_data = nullptr;
-	};
-
-	static TextServerCreate server_create_functions[MAX_SERVERS];
-	static int server_create_count;
+	Ref<TextServer> primary_interface;
+	Vector<Ref<TextServer>> interfaces;
 
 public:
 	_FORCE_INLINE_ static TextServerManager *get_singleton() {
 		return singleton;
 	}
 
-	static void register_create_function(const String &p_name, uint32_t p_features, CreateFunction p_function, void *p_user_data);
-	static int get_interface_count();
-	static String get_interface_name(int p_index);
-	static uint32_t get_interface_features(int p_index);
-	static TextServer *initialize(int p_index, Error &r_error);
-	static TextServer *get_primary_interface();
-
-	/* GDScript wrappers */
-	int _get_interface_count() const;
-	String _get_interface_name(int p_index) const;
-	uint32_t _get_interface_features(int p_index) const;
-	TextServer *_get_interface(int p_index) const;
-	Array _get_interfaces() const;
-	TextServer *_find_interface(const String &p_name) const;
+	void add_interface(const Ref<TextServer> &p_interface);
+	void remove_interface(const Ref<TextServer> &p_interface);
+	int get_interface_count() const;
+	Ref<TextServer> get_interface(int p_index) const;
+	Ref<TextServer> find_interface(const String &p_name) const;
+	Array get_interfaces() const;
 
-	bool _set_primary_interface(int p_index);
-	TextServer *_get_primary_interface() const;
+	_FORCE_INLINE_ Ref<TextServer> get_primary_interface() const {
+		return primary_interface;
+	}
+	Ref<TextServer> _get_primary_interface() const;
+	void set_primary_interface(const Ref<TextServer> &p_primary_interface);
 
 	TextServerManager();
 	~TextServerManager();
@@ -539,7 +525,7 @@ public:
 
 /*************************************************************************/
 
-#define TS TextServerManager::get_primary_interface()
+#define TS TextServerManager::get_singleton()->get_primary_interface()
 
 VARIANT_ENUM_CAST(TextServer::Direction);
 VARIANT_ENUM_CAST(TextServer::Orientation);
@@ -552,4 +538,8 @@ VARIANT_ENUM_CAST(TextServer::Feature);
 VARIANT_ENUM_CAST(TextServer::ContourPointTag);
 VARIANT_ENUM_CAST(TextServer::SpacingType);
 
+GDVIRTUAL_NATIVE_PTR(Glyph);
+GDVIRTUAL_NATIVE_PTR(Glyph *);
+GDVIRTUAL_NATIVE_PTR(CaretInfo);
+
 #endif // TEXT_SERVER_H

+ 1 - 7
tests/test_main.cpp

@@ -174,10 +174,8 @@ struct GodotTestCaseListener : public doctest::IReporter {
 			memnew(MessageQueue);
 
 			GLOBAL_DEF("internationalization/rendering/force_right_to_left_layout_direction", false);
-			memnew(TextServerManager);
-			Error err = OK;
-			TextServerManager::initialize(0, err);
 
+			Error err = OK;
 			OS::get_singleton()->set_has_server_feature_callback(nullptr);
 			for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
 				if (String("headless") == DisplayServer::get_create_function_name(i)) {
@@ -224,10 +222,6 @@ struct GodotTestCaseListener : public doctest::IReporter {
 
 		clear_default_theme();
 
-		if (TextServerManager::get_singleton()) {
-			memdelete(TextServerManager::get_singleton());
-		}
-
 		if (navigation_3d_server) {
 			memdelete(navigation_3d_server);
 			navigation_3d_server = nullptr;

+ 34 - 33
tests/test_text_server.h

@@ -41,19 +41,10 @@ namespace TestTextServer {
 
 TEST_SUITE("[[TextServer]") {
 	TEST_CASE("[TextServer] Init, font loading and shaping") {
-		TextServerManager *tsman = memnew(TextServerManager);
-		Error err = OK;
-
-		SUBCASE("[TextServer] Init") {
-			for (int i = 0; i < TextServerManager::get_interface_count(); i++) {
-				TextServer *ts = TextServerManager::initialize(i, err);
-				TEST_FAIL_COND((err != OK || ts == nullptr), "Text server ", TextServerManager::get_interface_name(i), " init failed.");
-			}
-		}
-
 		SUBCASE("[TextServer] Loading fonts") {
-			for (int i = 0; i < TextServerManager::get_interface_count(); i++) {
-				TextServer *ts = TextServerManager::initialize(i, err);
+			for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
+				Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i);
+				TEST_FAIL_COND(ts.is_null(), "Invalid TS interface.");
 
 				RID font = ts->create_font();
 				ts->font_set_data_ptr(font, _font_NotoSans_Regular, _font_NotoSans_Regular_size);
@@ -63,8 +54,9 @@ TEST_SUITE("[[TextServer]") {
 		}
 
 		SUBCASE("[TextServer] Text layout: Font fallback") {
-			for (int i = 0; i < TextServerManager::get_interface_count(); i++) {
-				TextServer *ts = TextServerManager::initialize(i, err);
+			for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
+				Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i);
+				TEST_FAIL_COND(ts.is_null(), "Invalid TS interface.");
 
 				RID font1 = ts->create_font();
 				ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size);
@@ -83,9 +75,10 @@ TEST_SUITE("[[TextServer]") {
 				bool ok = ts->shaped_text_add_string(ctx, test, font, 16);
 				TEST_FAIL_COND(!ok, "Adding text to the buffer failed.");
 
-				Vector<TextServer::Glyph> glyphs = ts->shaped_text_get_glyphs(ctx);
-				TEST_FAIL_COND(glyphs.size() == 0, "Shaping failed");
-				for (int j = 0; j < glyphs.size(); j++) {
+				const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx);
+				int gl_size = ts->shaped_text_get_glyph_count(ctx);
+				TEST_FAIL_COND(gl_size == 0, "Shaping failed");
+				for (int j = 0; j < gl_size; j++) {
 					if (glyphs[j].start < 6) {
 						TEST_FAIL_COND(glyphs[j].font_rid != font[1], "Incorrect font selected.");
 					}
@@ -110,8 +103,9 @@ TEST_SUITE("[[TextServer]") {
 		}
 
 		SUBCASE("[TextServer] Text layout: BiDi") {
-			for (int i = 0; i < TextServerManager::get_interface_count(); i++) {
-				TextServer *ts = TextServerManager::initialize(i, err);
+			for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
+				Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i);
+				TEST_FAIL_COND(ts.is_null(), "Invalid TS interface.");
 
 				if (!ts->has_feature(TextServer::FEATURE_BIDI_LAYOUT)) {
 					continue;
@@ -134,9 +128,10 @@ TEST_SUITE("[[TextServer]") {
 				bool ok = ts->shaped_text_add_string(ctx, test, font, 16);
 				TEST_FAIL_COND(!ok, "Adding text to the buffer failed.");
 
-				Vector<TextServer::Glyph> glyphs = ts->shaped_text_get_glyphs(ctx);
-				TEST_FAIL_COND(glyphs.size() == 0, "Shaping failed");
-				for (int j = 0; j < glyphs.size(); j++) {
+				const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx);
+				int gl_size = ts->shaped_text_get_glyph_count(ctx);
+				TEST_FAIL_COND(gl_size == 0, "Shaping failed");
+				for (int j = 0; j < gl_size; j++) {
 					if (glyphs[j].count > 0) {
 						if (glyphs[j].start < 7) {
 							TEST_FAIL_COND(((glyphs[j].flags & TextServer::GRAPHEME_IS_RTL) == TextServer::GRAPHEME_IS_RTL), "Incorrect direction.");
@@ -160,8 +155,9 @@ TEST_SUITE("[[TextServer]") {
 		}
 
 		SUBCASE("[TextServer] Text layout: Line breaking") {
-			for (int i = 0; i < TextServerManager::get_interface_count(); i++) {
-				TextServer *ts = TextServerManager::initialize(i, err);
+			for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
+				Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i);
+				TEST_FAIL_COND(ts.is_null(), "Invalid TS interface.");
 
 				String test_1 = U"test test test";
 				//                   5^  10^
@@ -180,12 +176,17 @@ TEST_SUITE("[[TextServer]") {
 				bool ok = ts->shaped_text_add_string(ctx, test_1, font, 16);
 				TEST_FAIL_COND(!ok, "Adding text to the buffer failed.");
 
-				Vector<Vector2i> brks = ts->shaped_text_get_line_breaks(ctx, 1);
-				TEST_FAIL_COND(brks.size() != 3, "Invalid line breaks number.");
-				if (brks.size() == 3) {
-					TEST_FAIL_COND(brks[0] != Vector2i(0, 5), "Invalid line break position.");
-					TEST_FAIL_COND(brks[1] != Vector2i(5, 10), "Invalid line break position.");
-					TEST_FAIL_COND(brks[2] != Vector2i(10, 14), "Invalid line break position.");
+				PackedInt32Array brks = ts->shaped_text_get_line_breaks(ctx, 1);
+				TEST_FAIL_COND(brks.size() != 6, "Invalid line breaks number.");
+				if (brks.size() == 6) {
+					TEST_FAIL_COND(brks[0] != 0, "Invalid line break position.");
+					TEST_FAIL_COND(brks[1] != 5, "Invalid line break position.");
+
+					TEST_FAIL_COND(brks[2] != 5, "Invalid line break position.");
+					TEST_FAIL_COND(brks[3] != 10, "Invalid line break position.");
+
+					TEST_FAIL_COND(brks[4] != 10, "Invalid line break position.");
+					TEST_FAIL_COND(brks[5] != 14, "Invalid line break position.");
 				}
 
 				ts->free(ctx);
@@ -198,8 +199,9 @@ TEST_SUITE("[[TextServer]") {
 		}
 
 		SUBCASE("[TextServer] Text layout: Justification") {
-			for (int i = 0; i < TextServerManager::get_interface_count(); i++) {
-				TextServer *ts = TextServerManager::initialize(i, err);
+			for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
+				Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i);
+				TEST_FAIL_COND(ts.is_null(), "Invalid TS interface.");
 
 				RID font1 = ts->create_font();
 				ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size);
@@ -263,7 +265,6 @@ TEST_SUITE("[[TextServer]") {
 				font.clear();
 			}
 		}
-		memdelete(tsman);
 	}
 }
 }; // namespace TestTextServer