Browse Source

Merge pull request #52192 from bruvzg/text_server_gdext

Rémi Verschelde 3 years ago
parent
commit
928c002f22
58 changed files with 4370 additions and 3370 deletions
  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;
 		Array native_structures;
 
 
+		// AudioStream structures
 		{
 		{
 			Dictionary d;
 			Dictionary d;
 			d["name"] = "AudioFrame";
 			d["name"] = "AudioFrame";
@@ -849,6 +850,22 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
 			native_structures.push_back(d);
 			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;
 		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="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
 			<argument index="8" name="outline_size" type="int" default="0" />
 			<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="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>
 			<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.
 				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>
 			</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="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
 			<argument index="8" name="outline_size" type="int" default="0" />
 			<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="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>
 			<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.
 				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].
 				See also [method CanvasItem.draw_multiline_string].
@@ -185,7 +185,7 @@
 			<argument index="0" name="text" type="String" />
 			<argument index="0" name="text" type="String" />
 			<argument index="1" name="width" type="float" default="-1" />
 			<argument index="1" name="width" type="float" default="-1" />
 			<argument index="2" name="size" type="int" 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>
 			<description>
 				Returns the size of a bounding box of a string broken into the lines, taking kerning and advance into account.
 				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].
 				See also [method draw_multiline_string].

+ 1 - 1
doc/classes/OS.xml

@@ -246,7 +246,7 @@
 		<method name="get_name" qualifiers="const">
 		<method name="get_name" qualifiers="const">
 			<return type="String" />
 			<return type="String" />
 			<description>
 			<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>
 			</description>
 		</method>
 		</method>
 		<method name="get_process_id" qualifiers="const">
 		<method name="get_process_id" qualifiers="const">

+ 12 - 0
doc/classes/RenderingServer.xml

@@ -185,6 +185,18 @@
 			<description>
 			<description>
 			</description>
 			</description>
 		</method>
 		</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">
 		<method name="canvas_item_add_multimesh">
 			<return type="void" />
 			<return type="void" />
 			<argument index="0" name="item" type="RID" />
 			<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">
 		<member name="direction" type="int" setter="set_direction" getter="get_direction" enum="TextServer.Direction" default="0">
 			Text writing direction.
 			Text writing direction.
 		</member>
 		</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].
 			Line breaking and alignment rules. For more info see [TextServer].
 		</member>
 		</member>
 		<member name="max_lines_visible" type="int" setter="set_max_lines_visible" getter="get_max_lines_visible" default="-1">
 		<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" ?>
 <?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>
 	<brief_description>
 		Interface for the fonts and complex text layouts.
 		Interface for the fonts and complex text layouts.
 	</brief_description>
 	</brief_description>
@@ -487,8 +487,8 @@
 		</method>
 		</method>
 		<method name="font_set_data">
 		<method name="font_set_data">
 			<return type="void" />
 			<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>
 			<description>
 				Sets font source data, e.g contents of the dynamic font source file.
 				Sets font source data, e.g contents of the dynamic font source file.
 			</description>
 			</description>
@@ -714,12 +714,14 @@
 			<return type="Dictionary" />
 			<return type="Dictionary" />
 			<argument index="0" name="font_rid" type="RID" />
 			<argument index="0" name="font_rid" type="RID" />
 			<description>
 			<description>
+				Returns the dictionary of the supported OpenType features.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="font_supported_variation_list" qualifiers="const">
 		<method name="font_supported_variation_list" qualifiers="const">
 			<return type="Dictionary" />
 			<return type="Dictionary" />
 			<argument index="0" name="font_rid" type="RID" />
 			<argument index="0" name="font_rid" type="RID" />
 			<description>
 			<description>
+				Returns the dictionary of the supported OpenType variation coordinates.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="format_number" qualifiers="const">
 		<method name="format_number" qualifiers="const">
@@ -737,6 +739,12 @@
 				Frees an object created by this [TextServer].
 				Frees an object created by this [TextServer].
 			</description>
 			</description>
 		</method>
 		</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">
 		<method name="get_hex_code_box_size" qualifiers="const">
 			<return type="Vector2" />
 			<return type="Vector2" />
 			<argument index="0" name="size" type="int" />
 			<argument index="0" name="size" type="int" />
@@ -751,6 +759,18 @@
 				Returns the name of the server interface.
 				Returns the name of the server interface.
 			</description>
 			</description>
 		</method>
 		</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">
 		<method name="has">
 			<return type="bool" />
 			<return type="bool" />
 			<argument index="0" name="rid" type="RID" />
 			<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.
 				Returns [code]true[/code] if [code]rid[/code] is valid resource owned by this text server.
 			</description>
 			</description>
 		</method>
 		</method>
-		<method name="has_feature">
+		<method name="has_feature" qualifiers="const">
 			<return type="bool" />
 			<return type="bool" />
 			<argument index="0" name="feature" type="int" enum="TextServer.Feature" />
 			<argument index="0" name="feature" type="int" enum="TextServer.Feature" />
 			<description>
 			<description>
 				Returns [code]true[/code] if the server supports a feature.
 				Returns [code]true[/code] if the server supports a feature.
 			</description>
 			</description>
 		</method>
 		</method>
-		<method name="is_locale_right_to_left">
+		<method name="is_locale_right_to_left" qualifiers="const">
 			<return type="bool" />
 			<return type="bool" />
 			<argument index="0" name="locale" type="String" />
 			<argument index="0" name="locale" type="String" />
 			<description>
 			<description>
@@ -802,6 +822,14 @@
 				Returns percent sign used in the [code]language[/code].
 				Returns percent sign used in the [code]language[/code].
 			</description>
 			</description>
 		</method>
 		</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">
 		<method name="shaped_text_add_object">
 			<return type="bool" />
 			<return type="bool" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="0" name="shaped" type="RID" />
@@ -898,7 +926,7 @@
 				Returns direction of the text.
 				Returns direction of the text.
 			</description>
 			</description>
 		</method>
 		</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" />
 			<return type="int" enum="TextServer.Direction" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="1" name="start" type="int" />
 			<argument index="1" name="start" type="int" />
@@ -907,30 +935,58 @@
 				Returns dominant direction of in the range of text.
 				Returns dominant direction of in the range of text.
 			</description>
 			</description>
 		</method>
 		</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">
 		<method name="shaped_text_get_glyphs" qualifiers="const">
 			<return type="Array" />
 			<return type="Array" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="0" name="shaped" type="RID" />
 			<description>
 			<description>
-				Returns text glyphs.
+				Returns text glyphs in the visual order.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="shaped_text_get_line_breaks" qualifiers="const">
 		<method name="shaped_text_get_line_breaks" qualifiers="const">
-			<return type="Array" />
+			<return type="PackedInt32Array" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="1" name="width" type="float" />
 			<argument index="1" name="width" type="float" />
 			<argument index="2" name="start" type="int" default="0" />
 			<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>
 			<description>
 				Breaks text to the lines and returns character ranges for each line.
 				Breaks text to the lines and returns character ranges for each line.
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="shaped_text_get_line_breaks_adv" qualifiers="const">
 		<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="0" name="shaped" type="RID" />
 			<argument index="1" name="width" type="PackedFloat32Array" />
 			<argument index="1" name="width" type="PackedFloat32Array" />
 			<argument index="2" name="start" type="int" default="0" />
 			<argument index="2" name="start" type="int" default="0" />
 			<argument index="3" name="once" type="bool" default="true" />
 			<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>
 			<description>
 				Breaks text to the lines and columns. Returns character ranges for each segment.
 				Breaks text to the lines and columns. Returns character ranges for each segment.
 			</description>
 			</description>
@@ -987,7 +1043,7 @@
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="shaped_text_get_selection" qualifiers="const">
 		<method name="shaped_text_get_selection" qualifiers="const">
-			<return type="Array" />
+			<return type="PackedVector2Array" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="1" name="start" type="int" />
 			<argument index="1" name="start" type="int" />
 			<argument index="2" name="end" type="int" />
 			<argument index="2" name="end" type="int" />
@@ -1002,6 +1058,13 @@
 				Returns size of the text.
 				Returns size of the text.
 			</description>
 			</description>
 		</method>
 		</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">
 		<method name="shaped_text_get_underline_position" qualifiers="const">
 			<return type="float" />
 			<return type="float" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="0" name="shaped" type="RID" />
@@ -1024,8 +1087,9 @@
 			</description>
 			</description>
 		</method>
 		</method>
 		<method name="shaped_text_get_word_breaks" qualifiers="const">
 		<method name="shaped_text_get_word_breaks" qualifiers="const">
-			<return type="Array" />
+			<return type="PackedInt32Array" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="0" name="shaped" type="RID" />
+			<argument index="1" name="grapheme_flags" type="int" />
 			<description>
 			<description>
 				Breaks text into words and returns array of character ranges.
 				Breaks text into words and returns array of character ranges.
 			</description>
 			</description>
@@ -1053,7 +1117,7 @@
 				Returns [code]true[/code] if buffer is successfully shaped.
 				Returns [code]true[/code] if buffer is successfully shaped.
 			</description>
 			</description>
 		</method>
 		</method>
-		<method name="shaped_text_next_grapheme_pos">
+		<method name="shaped_text_next_grapheme_pos" qualifiers="const">
 			<return type="int" />
 			<return type="int" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="1" name="pos" type="int" />
 			<argument index="1" name="pos" type="int" />
@@ -1070,7 +1134,7 @@
 				Trims text if it exceeds the given width.
 				Trims text if it exceeds the given width.
 			</description>
 			</description>
 		</method>
 		</method>
-		<method name="shaped_text_prev_grapheme_pos">
+		<method name="shaped_text_prev_grapheme_pos" qualifiers="const">
 			<return type="int" />
 			<return type="int" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="1" name="pos" type="int" />
 			<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.
 				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>
 			</description>
 		</method>
 		</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">
 		<method name="shaped_text_substr" qualifiers="const">
 			<return type="RID" />
 			<return type="RID" />
 			<argument index="0" name="shaped" type="RID" />
 			<argument index="0" name="shaped" type="RID" />
@@ -1196,18 +1267,24 @@
 		<constant name="JUSTIFICATION_AFTER_LAST_TAB" value="8" enum="JustificationFlag">
 		<constant name="JUSTIFICATION_AFTER_LAST_TAB" value="8" enum="JustificationFlag">
 			Only apply justification to the part of the text after the last tab.
 			Only apply justification to the part of the text after the last tab.
 		</constant>
 		</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">
 		<constant name="BREAK_NONE" value="0" enum="LineBreakFlag">
 			Do not break the line.
 			Do not break the line.
 		</constant>
 		</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]).
 			Break the line at the line mandatory break characters (e.g. [code]"\n"[/code]).
 		</constant>
 		</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.
 			Break the line between the words.
 		</constant>
 		</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.
 			Break the line between any unconnected graphemes.
 		</constant>
 		</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">
 		<constant name="OVERRUN_NO_TRIMMING" value="0" enum="TextOverrunFlag">
 			No trimming is performed.
 			No trimming is performed.
 		</constant>
 		</constant>
@@ -1223,6 +1300,11 @@
 		<constant name="OVERRUN_ENFORCE_ELLIPSIS" value="8" enum="TextOverrunFlag">
 		<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.
 			Determines whether the ellipsis at the end of the text is enforced and may not be hidden.
 		</constant>
 		</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">
 		<constant name="GRAPHEME_IS_RTL" value="2" enum="GraphemeFlag">
 			Grapheme is part of right-to-left or bottom-to-top run.
 			Grapheme is part of right-to-left or bottom-to-top run.
 		</constant>
 		</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>
 	</tutorials>
 	</tutorials>
 	<methods>
 	<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">
 		<method name="find_interface" qualifiers="const">
 			<return type="TextServer" />
 			<return type="TextServer" />
 			<argument index="0" name="name" type="String" />
 			<argument index="0" name="name" type="String" />
@@ -19,7 +26,7 @@
 		</method>
 		</method>
 		<method name="get_interface" qualifiers="const">
 		<method name="get_interface" qualifiers="const">
 			<return type="TextServer" />
 			<return type="TextServer" />
-			<argument index="0" name="index" type="int" />
+			<argument index="0" name="idx" type="int" />
 			<description>
 			<description>
 				Returns the interface registered at a given index.
 				Returns the interface registered at a given index.
 			</description>
 			</description>
@@ -30,20 +37,6 @@
 				Returns the number of interfaces currently registered.
 				Returns the number of interfaces currently registered.
 			</description>
 			</description>
 		</method>
 		</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">
 		<method name="get_interfaces" qualifiers="const">
 			<return type="Array" />
 			<return type="Array" />
 			<description>
 			<description>
@@ -53,15 +46,36 @@
 		<method name="get_primary_interface" qualifiers="const">
 		<method name="get_primary_interface" qualifiers="const">
 			<return type="TextServer" />
 			<return type="TextServer" />
 			<description>
 			<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>
 			</description>
 		</method>
 		</method>
 		<method name="set_primary_interface">
 		<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>
 			<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>
 			</description>
 		</method>
 		</method>
 	</methods>
 	</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>
 </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);
 	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);
 	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 i = 0; i < v_size; i++) {
 		for (int j = 0; j < glyphs[i].repeat; j++) {
 		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)) {
 			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()) {
 	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_add_string(text_rid, text_edit->get_text(), font_main->get_rids(), 16, ftrs, text_edit->get_language());
 		TS->shaped_text_shape(text_rid);
 		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) {
 			if (gl[i].font_rid.is_valid() && gl[i].index != 0) {
 				selected_glyphs.insert(gl[i].index);
 				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);
 	GLOBAL_DEF_RST("rendering/occlusion_culling/bvh_build_quality", 2);
 
 
 	translation_server = memnew(TranslationServer);
 	translation_server = memnew(TranslationServer);
+	tsman = memnew(TextServerManager);
 
 
 	register_core_extensions();
 	register_core_extensions();
 
 
@@ -440,6 +441,9 @@ Error Main::test_setup() {
 	register_module_types();
 	register_module_types();
 	register_driver_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);
 	ClassDB::set_current_api(ClassDB::API_NONE);
 
 
 	_start_success = true;
 	_start_success = true;
@@ -459,6 +463,7 @@ void Main::test_cleanup() {
 #ifdef TOOLS_ENABLED
 #ifdef TOOLS_ENABLED
 	EditorNode::unregister_editor_types();
 	EditorNode::unregister_editor_types();
 #endif
 #endif
+
 	unregister_module_types();
 	unregister_module_types();
 	unregister_platform_apis();
 	unregister_platform_apis();
 	unregister_scene_types();
 	unregister_scene_types();
@@ -469,6 +474,9 @@ void Main::test_cleanup() {
 	if (translation_server) {
 	if (translation_server) {
 		memdelete(translation_server);
 		memdelete(translation_server);
 	}
 	}
+	if (tsman) {
+		memdelete(tsman);
+	}
 	if (globals) {
 	if (globals) {
 		memdelete(globals);
 		memdelete(globals);
 	}
 	}
@@ -1461,6 +1469,8 @@ error:
 }
 }
 
 
 Error Main::setup2(Thread::ID p_main_tid_override) {
 Error Main::setup2(Thread::ID p_main_tid_override) {
+	tsman = memnew(TextServerManager);
+
 	preregister_module_types();
 	preregister_module_types();
 	preregister_server_types();
 	preregister_server_types();
 
 
@@ -1479,64 +1489,6 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
 	}
 	}
 #endif
 #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 */
 	/* Initialize Input */
 
 
 	input = memnew(Input);
 	input = memnew(Input);
@@ -1781,6 +1733,57 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
 
 
 	ResourceLoader::load_path_remaps();
 	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");
 	MAIN_PRINT("Main: Load Scene Types");
 
 
 	register_scene_types();
 	register_scene_types();
@@ -1793,7 +1796,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
 
 
 #endif
 #endif
 
 
-	MAIN_PRINT("Main: Load Modules, Physics, Drivers, Scripts");
+	MAIN_PRINT("Main: Load Modules");
 
 
 	register_platform_apis();
 	register_platform_apis();
 	register_module_types();
 	register_module_types();
@@ -1817,6 +1820,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
 
 
 	camera_server = CameraServer::create();
 	camera_server = CameraServer::create();
 
 
+	MAIN_PRINT("Main: Load Physics, Drivers, Scripts");
+
 	initialize_physics();
 	initialize_physics();
 	initialize_navigation_server();
 	initialize_navigation_server();
 	register_server_singletons();
 	register_server_singletons();
@@ -2728,10 +2733,6 @@ void Main::cleanup(bool p_force) {
 	finalize_navigation_server();
 	finalize_navigation_server();
 	finalize_display();
 	finalize_display();
 
 
-	if (tsman) {
-		memdelete(tsman);
-	}
-
 	if (input) {
 	if (input) {
 		memdelete(input);
 		memdelete(input);
 	}
 	}
@@ -2754,6 +2755,9 @@ void Main::cleanup(bool p_force) {
 	if (translation_server) {
 	if (translation_server) {
 		memdelete(translation_server);
 		memdelete(translation_server);
 	}
 	}
+	if (tsman) {
+		memdelete(tsman);
+	}
 	if (globals) {
 	if (globals) {
 		memdelete(globals);
 		memdelete(globals);
 	}
 	}

+ 0 - 1
modules/gdnative/SCsub

@@ -18,7 +18,6 @@ Export("env_gdnative")
 
 
 SConscript("pluginscript/SCsub")
 SConscript("pluginscript/SCsub")
 SConscript("videodecoder/SCsub")
 SConscript("videodecoder/SCsub")
-SConscript("text/SCsub")
 
 
 
 
 import gdnative_builders
 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 <nativescript/godot_nativescript.h>",
         "#include <pluginscript/godot_pluginscript.h>",
         "#include <pluginscript/godot_pluginscript.h>",
         "#include <videodecoder/godot_videodecoder.h>",
         "#include <videodecoder/godot_videodecoder.h>",
-        "#include <text/godot_text.h>",
         "",
         "",
         "#ifdef __cplusplus",
         "#ifdef __cplusplus",
         'extern "C" {',
         '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):
 def configure(env):
     pass
     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"
 #include "text_server_adv.h"
 
 
 void preregister_text_server_adv_types() {
 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() {
 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";
 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;
 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;
 	return (interface_features & p_feature) == p_feature;
 }
 }
 
 
@@ -330,6 +330,10 @@ String TextServerAdvanced::get_name() const {
 	return interface_name;
 	return interface_name;
 }
 }
 
 
+uint32_t TextServerAdvanced::get_features() const {
+	return interface_features;
+}
+
 void TextServerAdvanced::free(RID p_rid) {
 void TextServerAdvanced::free(RID p_rid) {
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 	if (font_owner.owns(p_rid)) {
 	if (font_owner.owns(p_rid)) {
@@ -394,9 +398,23 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) {
 	return true;
 	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_
 	_THREAD_SAFE_METHOD_
 #ifdef ICU_STATIC_DATA
 #ifdef ICU_STATIC_DATA
 
 
@@ -415,9 +433,7 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) {
 #endif
 #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);
 	String l = p_locale.get_slicec('_', 0);
 	if ((l == "ar") || (l == "dv") || (l == "he") || (l == "fa") || (l == "ff") || (l == "ku") || (l == "ur")) {
 	if ((l == "ar") || (l == "dv") || (l == "he") || (l == "fa") || (l == "ff") || (l == "ku") || (l == "ur")) {
 		return true;
 		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);
 		int error = FT_Load_Glyph(fd->face, p_glyph, flags);
 		if (error) {
 		if (error) {
 			fd->glyph_map[p_glyph] = FontGlyph();
 			fd->glyph_map[p_glyph] = FontGlyph();
-			ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph.");
+			return false;
 		}
 		}
 
 
 		if (!outline) {
 		if (!outline) {
@@ -1236,7 +1252,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
 			fd->oversampling = 1.0f;
 			fd->oversampling = 1.0f;
 			fd->size.x = p_font_data->msdf_source_size;
 			fd->size.x = p_font_data->msdf_source_size;
 		} else if (p_font_data->oversampling <= 0.0f) {
 		} else if (p_font_data->oversampling <= 0.0f) {
-			fd->oversampling = TS->font_get_global_oversampling();
+			fd->oversampling = font_get_global_oversampling();
 		} else {
 		} else {
 			fd->oversampling = p_font_data->oversampling;
 			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) {
 		if (FT_HAS_COLOR(fd->face) && fd->face->num_fixed_sizes > 0) {
 			int best_match = 0;
 			int best_match = 0;
 			int diff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[0].width));
 			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++) {
 			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));
 				int ndiff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[i].width));
 				if (ndiff < diff) {
 				if (ndiff < diff) {
 					best_match = i;
 					best_match = i;
 					diff = ndiff;
 					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);
 			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;
 	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);
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 	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);
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 	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);
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 	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;
 	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);
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 	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);
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 
 	if (fd->msdf) {
 	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 {
 	} else {
 		return fd->cache[size]->ascent;
 		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);
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 	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;
 	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);
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 	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);
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 
 	if (fd->msdf) {
 	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 {
 	} else {
 		return fd->cache[size]->descent;
 		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);
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 	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;
 	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);
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 	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);
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 
 	if (fd->msdf) {
 	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 {
 	} else {
 		return fd->cache[size]->underline_position;
 		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);
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 	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;
 	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);
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 	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);
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 
 	if (fd->msdf) {
 	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 {
 	} else {
 		return fd->cache[size]->underline_thickness;
 		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);
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 	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;
 	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);
 	FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 	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);
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 
 	if (fd->msdf) {
 	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 {
 	} else {
 		return fd->cache[size]->scale / fd->cache[size]->oversampling;
 		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) {
 	switch (p_spacing) {
 		case TextServer::SPACING_GLYPH: {
 		case TextServer::SPACING_GLYPH: {
 			if (fd->msdf) {
 			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 {
 			} else {
 				return fd->cache[size]->spacing_glyph;
 				return fd->cache[size]->spacing_glyph;
 			}
 			}
 		} break;
 		} break;
 		case TextServer::SPACING_SPACE: {
 		case TextServer::SPACING_SPACE: {
 			if (fd->msdf) {
 			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 {
 			} else {
 				return fd->cache[size]->spacing_space;
 				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;
 	const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
 
 
 	if (fd->msdf) {
 	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 {
 	} else {
 		return gl[p_glyph].advance;
 		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;
 	const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
 
 
 	if (fd->msdf) {
 	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 {
 	} else {
 		return gl[p_glyph].rect.position;
 		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;
 	const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
 
 
 	if (fd->msdf) {
 	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 {
 	} else {
 		return gl[p_glyph].rect.size;
 		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;
 	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);
 	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);
 	MutexLock lock(fd->mutex);
 	Vector2i size = _get_size(fd, p_size);
 	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
 #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));
 	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) {
 	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++) {
 	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++) {
 	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
 #else
-	return false;
+	return Dictionary();
 #endif
 #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 {
 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 (kern.has(p_glyph_pair)) {
 		if (fd->msdf) {
 		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 {
 		} else {
 			return kern[p_glyph_pair];
 			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_Vector delta;
 			FT_Get_Kerning(fd->cache[size]->face, p_glyph_pair.x, p_glyph_pair.y, FT_KERNING_DEFAULT, &delta);
 			FT_Get_Kerning(fd->cache[size]->face, p_glyph_pair.x, p_glyph_pair.y, FT_KERNING_DEFAULT, &delta);
 			if (fd->msdf) {
 			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 {
 			} else {
 				return Vector2(delta.x, delta.y);
 				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();
 				RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
 				if (fd->msdf) {
 				if (fd->msdf) {
 					Point2 cpos = p_pos;
 					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);
 					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 {
 				} else {
 					Point2i cpos = p_pos;
 					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();
 				RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
 				if (fd->msdf) {
 				if (fd->msdf) {
 					Point2 cpos = p_pos;
 					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);
 					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 {
 				} else {
 					Point2i cpos = p_pos;
 					Point2i cpos = p_pos;
@@ -2694,7 +2718,7 @@ bool TextServerAdvanced::font_is_script_supported(RID p_font_rid, const String &
 	} else {
 	} else {
 		Vector2i size = _get_size(fd, 16);
 		Vector2i size = _get_size(fd, 16);
 		ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), false);
 		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;
 	return fd->supported_varaitions;
 }
 }
 
 
-real_t TextServerAdvanced::font_get_global_oversampling() const {
+float TextServerAdvanced::font_get_global_oversampling() const {
 	return oversampling;
 	return oversampling;
 }
 }
 
 
-void TextServerAdvanced::font_set_global_oversampling(real_t p_oversampling) {
+void TextServerAdvanced::font_set_global_oversampling(float p_oversampling) {
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 	if (oversampling != p_oversampling) {
 	if (oversampling != p_oversampling) {
 		oversampling = p_oversampling;
 		oversampling = p_oversampling;
@@ -2904,7 +2928,7 @@ TextServer::Direction TextServerAdvanced::shaped_text_get_direction(RID p_shaped
 	return sd->direction;
 	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);
 	ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND(!sd);
 	ERR_FAIL_COND(!sd);
 
 
@@ -2912,7 +2936,10 @@ void TextServerAdvanced::shaped_text_set_bidi_override(RID p_shaped, const Vecto
 	if (sd->parent != RID()) {
 	if (sd->parent != RID()) {
 		full_copy(sd);
 		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);
 	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))) {
 				} else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) {
 					// Glyph not found, replace with hex code box.
 					// Glyph not found, replace with hex code box.
 					if (sd->orientation == ORIENTATION_HORIZONTAL) {
 					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 {
 					} else {
 						sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
 						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));
 						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.
 		// 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) {
 		for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
 			if ((E.value.pos >= sd->start) && (E.value.pos < sd->end)) {
 			if ((E.value.pos >= sd->start) && (E.value.pos < sd->end)) {
 				if (sd->orientation == ORIENTATION_HORIZONTAL) {
 				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))) {
 							} else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) {
 								// Glyph not found, replace with hex code box.
 								// Glyph not found, replace with hex code box.
 								if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
 								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 {
 								} 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->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));
 									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.
 		// 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) {
 		for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : new_sd->objects) {
 			if ((E.value.pos >= new_sd->start) && (E.value.pos < new_sd->end)) {
 			if ((E.value.pos >= new_sd->start) && (E.value.pos < new_sd->end)) {
 				if (sd->orientation == ORIENTATION_HORIZONTAL) {
 				if (sd->orientation == ORIENTATION_HORIZONTAL) {
@@ -3378,7 +3403,7 @@ RID TextServerAdvanced::shaped_text_get_parent(RID p_shaped) const {
 	return sd->parent;
 	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);
 	ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 	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 ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) == JUSTIFICATION_CONSTRAIN_ELLIPSIS) {
 		if (sd->overrun_trim_data.trim_pos >= 0) {
 		if (sd->overrun_trim_data.trim_pos >= 0) {
 			start_pos = sd->overrun_trim_data.trim_pos;
 			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)) {
 	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++) {
 		for (int i = start_pos; i <= end_pos; i++) {
 			Glyph &gl = sd->glyphs.write[i];
 			Glyph &gl = sd->glyphs.write[i];
 			if (gl.count > 0) {
 			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)) {
 	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++) {
 		for (int i = start_pos; i <= end_pos; i++) {
 			Glyph &gl = sd->glyphs.write[i];
 			Glyph &gl = sd->glyphs.write[i];
 			if (gl.count > 0) {
 			if (gl.count > 0) {
 				if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
 				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) {
 					if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
 						new_advance = MAX(gl.advance + delta_width_per_space, 0.f);
 						new_advance = MAX(gl.advance + delta_width_per_space, 0.f);
 					} else {
 					} else {
@@ -3514,7 +3539,7 @@ real_t TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, real_t p_width
 	return sd->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);
 	ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 	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;
 	int tab_index = 0;
-	real_t off = 0.f;
+	float off = 0.f;
 
 
 	int start, end, delta;
 	int start, end, delta;
 	if (sd->para_direction == DIRECTION_LTR) {
 	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) {
 	for (int i = start; i != end; i += delta) {
 		if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
 		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) {
 			while (tab_off <= off) {
 				tab_off += p_tab_stops[tab_index];
 				tab_off += p_tab_stops[tab_index];
 				tab_index++;
 				tab_index++;
@@ -3552,7 +3577,7 @@ real_t TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<real
 					tab_index = 0;
 					tab_index = 0;
 				}
 				}
 			}
 			}
-			real_t old_adv = gl[i].advance;
+			float old_adv = gl[i].advance;
 			gl[i].advance = tab_off - off;
 			gl[i].advance = tab_off - off;
 			sd->width += gl[i].advance - old_adv;
 			sd->width += gl[i].advance - old_adv;
 			off = 0;
 			off = 0;
@@ -3564,7 +3589,7 @@ real_t TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<real
 	return 0.f;
 	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);
 	ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped_line);
 	ERR_FAIL_COND_MSG(!sd, "ShapedTextDataAdvanced invalid.");
 	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;
 	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);
 	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)) {
 		if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) {
 			// Insert an additional space when cutting word bound for aesthetics.
 			// Insert an additional space when cutting word bound for aesthetics.
 			if (cut_per_word && (ellipsis_pos > 0)) {
 			if (cut_per_word && (ellipsis_pos > 0)) {
-				TextServer::Glyph gl;
+				Glyph gl;
 				gl.count = 1;
 				gl.count = 1;
 				gl.advance = whitespace_adv.x;
 				gl.advance = whitespace_adv.x;
 				gl.index = whitespace_gl_idx;
 				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);
 				sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
 			}
 			}
 			// Add ellipsis dots.
 			// Add ellipsis dots.
-			TextServer::Glyph gl;
+			Glyph gl;
 			gl.count = 1;
 			gl.count = 1;
 			gl.repeat = 3;
 			gl.repeat = 3;
 			gl.advance = dot_adv.x;
 			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);
 	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);
 	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) {
 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)) {
 					if (is_whitespace(c)) {
 						sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT;
 						sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT;
 					} else {
 					} else {
-						TextServer::Glyph gl;
+						Glyph gl;
 						gl.start = sd_glyphs[i].start;
 						gl.start = sd_glyphs[i].start;
 						gl.end = sd_glyphs[i].end;
 						gl.end = sd_glyphs[i].end;
 						gl.count = 1;
 						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;
 							sd->glyphs.write[i].flags |= GRAPHEME_IS_ELONGATION;
 						} else {
 						} else {
 							if (sd->glyphs[i].font_rid != RID()) {
 							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) {
 								if ((gl.flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {
 									gl.start = sd->glyphs[i].start;
 									gl.start = sd->glyphs[i].start;
 									gl.end = sd->glyphs[i].end;
 									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)) {
 					} else if (!is_whitespace(c)) {
-						TextServer::Glyph gl;
+						Glyph gl;
 						gl.start = sd->glyphs[i].start;
 						gl.start = sd->glyphs[i].start;
 						gl.end = sd->glyphs[i].end;
 						gl.end = sd->glyphs[i].end;
 						gl.count = 1;
 						gl.count = 1;
@@ -4007,9 +4056,9 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
 	return sd->justification_ops_valid;
 	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);
 	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_clear_contents(p_sd->hb_buffer);
 	hb_buffer_set_direction(p_sd->hb_buffer, p_direction);
 	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);
 	hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(p_sd->hb_buffer, &glyph_count);
 
 
 	// Process glyphs.
 	// Process glyphs.
-	TextServer::Glyph gl;
+	Glyph gl;
 
 
 	if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
 	if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
 		gl.flags |= TextServer::GRAPHEME_IS_RTL;
 		gl.flags |= TextServer::GRAPHEME_IS_RTL;
@@ -4034,7 +4083,7 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced
 	gl.font_size = p_font_size;
 	gl.font_size = p_font_size;
 
 
 	if (glyph_count > 0) {
 	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) {
 		if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
 			gl.advance = Math::round(glyph_pos[0].x_advance / (64.0 / scale));
 			gl.advance = Math::round(glyph_pos[0].x_advance / (64.0 / scale));
 		} else {
 		} else {
@@ -4059,7 +4108,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
 		// Add fallback glyphs.
 		// Add fallback glyphs.
 		for (int i = p_start; i < p_end; i++) {
 		for (int i = p_start; i < p_end; i++) {
 			if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[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.start = i;
 				gl.end = i + 1;
 				gl.end = i + 1;
 				gl.count = 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) {
 				if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
 					gl.advance = get_hex_code_box_size(fs, gl.index).x;
 					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 {
 				} else {
 					gl.advance = get_hex_code_box_size(fs, gl.index).y;
 					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));
 					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.
 	// Process glyphs.
 	if (glyph_count > 0) {
 	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;
 		int end = (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) ? p_end : 0;
 		uint32_t last_cluster_id = UINT32_MAX;
 		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;
 			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.start = glyph_info[i].cluster;
 			gl.end = end;
 			gl.end = end;
@@ -4171,7 +4219,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
 
 
 			gl.index = glyph_info[i].codepoint;
 			gl.index = glyph_info[i].codepoint;
 			if (gl.index != 0) {
 			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) {
 				if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
 					gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / scale));
 					gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / scale));
 				} else {
 				} else {
@@ -4411,8 +4459,8 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
 	}
 	}
 
 
 	// Align embedded objects to baseline.
 	// 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) {
 	for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
 		if (sd->orientation == ORIENTATION_HORIZONTAL) {
 		if (sd->orientation == ORIENTATION_HORIZONTAL) {
 			switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
 			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;
 	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);
 	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);
 	MutexLock lock(sd->mutex);
 	if (!sd->valid) {
 	if (!sd->valid) {
 		const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
 		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);
 	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);
 	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);
 	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);
 	MutexLock lock(sd->mutex);
 	if (!sd->valid) {
 	if (!sd->valid) {
@@ -4516,11 +4567,19 @@ Vector<TextServer::Glyph> TextServerAdvanced::shaped_text_sort_logical(RID p_sha
 
 
 	if (!sd->sort_valid) {
 	if (!sd->sort_valid) {
 		sd->glyphs_logical = sd->glyphs;
 		sd->glyphs_logical = sd->glyphs;
-		sd->glyphs_logical.sort_custom<TextServer::GlyphCompare>();
+		sd->glyphs_logical.sort_custom<GlyphCompare>();
 		sd->sort_valid = true;
 		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 {
 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);
 	const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 	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;
 	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);
 	const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 	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;
 	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);
 	const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 	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);
 	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);
 	const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 	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;
 	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);
 	const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 	ERR_FAIL_COND_V(!sd, 0.f);
 
 
@@ -4752,15 +4811,6 @@ String TextServerAdvanced::percent_sign(const String &p_language) const {
 	return "%";
 	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() {
 TextServerAdvanced::TextServerAdvanced() {
 	_insert_num_systems_lang();
 	_insert_num_systems_lang();
 	_insert_feature_sets();
 	_insert_feature_sets();

+ 47 - 47
modules/text_server_adv/text_server_adv.h

@@ -115,12 +115,12 @@ class TextServerAdvanced : public TextServer {
 	};
 	};
 
 
 	struct FontDataForSizeAdvanced {
 	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_glyph = 0;
 		int spacing_space = 0;
 		int spacing_space = 0;
@@ -161,7 +161,7 @@ class TextServerAdvanced : public TextServer {
 		bool force_autohinter = false;
 		bool force_autohinter = false;
 		TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
 		TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
 		Dictionary variation_coordinates;
 		Dictionary variation_coordinates;
-		real_t oversampling = 0.f;
+		float oversampling = 0.f;
 
 
 		Map<Vector2i, FontDataForSizeAdvanced *> cache;
 		Map<Vector2i, FontDataForSizeAdvanced *> cache;
 
 
@@ -245,14 +245,14 @@ class TextServerAdvanced : public TextServer {
 
 
 	// Common data.
 	// Common data.
 
 
-	real_t oversampling = 1.f;
+	float oversampling = 1.f;
 	mutable RID_PtrOwner<FontDataAdvanced> font_owner;
 	mutable RID_PtrOwner<FontDataAdvanced> font_owner;
 	mutable RID_PtrOwner<ShapedTextDataAdvanced> shaped_owner;
 	mutable RID_PtrOwner<ShapedTextDataAdvanced> shaped_owner;
 
 
 	int _convert_pos(const ShapedTextDataAdvanced *p_sd, int p_pos) const;
 	int _convert_pos(const ShapedTextDataAdvanced *p_sd, int p_pos) const;
 	int _convert_pos_inv(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);
 	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.
 	// HarfBuzz bitmap font interface.
 
 
@@ -284,20 +284,19 @@ protected:
 	void invalidate(ShapedTextDataAdvanced *p_shaped);
 	void invalidate(ShapedTextDataAdvanced *p_shaped);
 
 
 public:
 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 String get_name() const override;
+	virtual uint32_t get_features() const override;
 
 
 	virtual void free(RID p_rid) override;
 	virtual void free(RID p_rid) override;
 	virtual bool has(RID p_rid) override;
 	virtual bool has(RID p_rid) override;
 	virtual bool load_support_data(const String &p_filename) 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 int32_t name_to_tag(const String &p_name) const override;
 	virtual String tag_to_name(int32_t p_tag) 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 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 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 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_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;
 	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 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_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 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 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 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_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_feature_list(RID p_font_rid) const override;
 	virtual Dictionary font_supported_variation_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 */
 	/* 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 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 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 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 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_substr(RID p_shaped, int p_start, int p_length) const override;
 	virtual RID shaped_text_get_parent(RID p_shaped) 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_shape(RID p_shaped) override;
 	virtual bool shaped_text_update_breaks(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 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 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 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 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 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 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 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 parse_number(const String &p_string, const String &p_language = "") const override;
 	virtual String percent_sign(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();
 	~TextServerAdvanced();
 	~TextServerAdvanced();
 };
 };

+ 10 - 0
modules/text_server_fb/config.py

@@ -9,3 +9,13 @@ def configure(env):
 def is_enabled():
 def is_enabled():
     # The module is disabled by default. Use module_text_server_fb_enabled=yes to enable it.
     # The module is disabled by default. Use module_text_server_fb_enabled=yes to enable it.
     return False
     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"
 #include "text_server_fb.h"
 
 
 void preregister_text_server_fb_types() {
 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() {
 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";
 String TextServerFallback::interface_name = "Fallback";
 uint32_t TextServerFallback::interface_features = 0; // Nothing is supported.
 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;
 	return (interface_features & p_feature) == p_feature;
 }
 }
 
 
@@ -77,6 +77,10 @@ String TextServerFallback::get_name() const {
 	return interface_name;
 	return interface_name;
 }
 }
 
 
+uint32_t TextServerFallback::get_features() const {
+	return interface_features;
+}
+
 void TextServerFallback::free(RID p_rid) {
 void TextServerFallback::free(RID p_rid) {
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 	if (font_owner.owns(p_rid)) {
 	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.
 	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.
 	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.
 	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];
 		FontTexture &tex = p_data->textures.write[tex_pos.index];
 
 
 		edgeColoringSimple(shape, 3.0); // Max. angle.
 		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.
 		//msdfgen::generateMTSDF(image, shape, p_pixel_range, 1.0, msdfgen::Vector2(-bounds.l, -bounds.b)); // Range, scale, translation.
 
 
 		DistancePixelConversion distancePixelConversion(p_pixel_range);
 		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);
 		int error = FT_Load_Glyph(fd->face, glyph_index, flags);
 		if (error) {
 		if (error) {
 			fd->glyph_map[p_glyph] = FontGlyph();
 			fd->glyph_map[p_glyph] = FontGlyph();
-			ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph.");
+			return false;
 		}
 		}
 
 
 		if (!outline) {
 		if (!outline) {
@@ -714,7 +714,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
 			fd->oversampling = 1.0f;
 			fd->oversampling = 1.0f;
 			fd->size.x = p_font_data->msdf_source_size;
 			fd->size.x = p_font_data->msdf_source_size;
 		} else if (p_font_data->oversampling <= 0.0f) {
 		} else if (p_font_data->oversampling <= 0.0f) {
-			fd->oversampling = TS->font_get_global_oversampling();
+			fd->oversampling = font_get_global_oversampling();
 		} else {
 		} else {
 			fd->oversampling = p_font_data->oversampling;
 			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) {
 		if (FT_HAS_COLOR(fd->face) && fd->face->num_fixed_sizes > 0) {
 			int best_match = 0;
 			int best_match = 0;
 			int diff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[0].width));
 			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++) {
 			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));
 				int ndiff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[i].width));
 				if (ndiff < diff) {
 				if (ndiff < diff) {
 					best_match = i;
 					best_match = i;
 					diff = ndiff;
 					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);
 			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++) {
 			for (FT_UInt i = 0; i < amaster->num_axis; i++) {
 				// Reset to default.
 				// Reset to default.
 				int32_t var_tag = amaster->axis[i].tag;
 				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;
 				coords.write[i] = amaster->axis[i].def;
 
 
 				if (p_font_data->variation_coordinates.has(var_tag)) {
 				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;
 	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);
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 	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);
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 	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);
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 	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;
 	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);
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 	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);
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 
 	if (fd->msdf) {
 	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 {
 	} else {
 		return fd->cache[size]->ascent;
 		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);
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 	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;
 	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);
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 	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);
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 
 	if (fd->msdf) {
 	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 {
 	} else {
 		return fd->cache[size]->descent;
 		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);
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 	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;
 	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);
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 	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);
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 
 	if (fd->msdf) {
 	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 {
 	} else {
 		return fd->cache[size]->underline_position;
 		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);
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 	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;
 	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);
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 	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);
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 
 	if (fd->msdf) {
 	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 {
 	} else {
 		return fd->cache[size]->underline_thickness;
 		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);
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND(!fd);
 	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;
 	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);
 	FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
 	ERR_FAIL_COND_V(!fd, 0.f);
 	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);
 	ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
 
 
 	if (fd->msdf) {
 	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 {
 	} else {
 		return fd->cache[size]->scale / fd->cache[size]->oversampling;
 		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) {
 	switch (p_spacing) {
 		case TextServer::SPACING_GLYPH: {
 		case TextServer::SPACING_GLYPH: {
 			if (fd->msdf) {
 			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 {
 			} else {
 				return fd->cache[size]->spacing_glyph;
 				return fd->cache[size]->spacing_glyph;
 			}
 			}
 		} break;
 		} break;
 		case TextServer::SPACING_SPACE: {
 		case TextServer::SPACING_SPACE: {
 			if (fd->msdf) {
 			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 {
 			} else {
 				return fd->cache[size]->spacing_space;
 				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;
 	const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
 
 
 	if (fd->msdf) {
 	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 {
 	} else {
 		return gl[p_glyph].advance;
 		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;
 	const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
 
 
 	if (fd->msdf) {
 	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 {
 	} else {
 		return gl[p_glyph].rect.position;
 		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;
 	const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
 
 
 	if (fd->msdf) {
 	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 {
 	} else {
 		return gl[p_glyph].rect.size;
 		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;
 	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);
 	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);
 	MutexLock lock(fd->mutex);
 	Vector2i size = _get_size(fd, p_size);
 	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
 #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));
 	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) {
 	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++) {
 	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++) {
 	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
 #else
-	return false;
+	return Dictionary();
 #endif
 #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 {
 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 (kern.has(p_glyph_pair)) {
 		if (fd->msdf) {
 		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 {
 		} else {
 			return kern[p_glyph_pair];
 			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);
 			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);
 			FT_Get_Kerning(fd->cache[size]->face, glyph_a, glyph_b, FT_KERNING_DEFAULT, &delta);
 			if (fd->msdf) {
 			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 {
 			} else {
 				return Vector2(delta.x, delta.y);
 				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();
 				RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
 				if (fd->msdf) {
 				if (fd->msdf) {
 					Point2 cpos = p_pos;
 					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);
 					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 {
 				} else {
 					Point2i cpos = p_pos;
 					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();
 				RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
 				if (fd->msdf) {
 				if (fd->msdf) {
 					Point2 cpos = p_pos;
 					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);
 					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 {
 				} else {
 					Point2i cpos = p_pos;
 					Point2i cpos = p_pos;
@@ -1922,11 +1930,11 @@ Dictionary TextServerFallback::font_supported_variation_list(RID p_font_rid) con
 	return fd->supported_varaitions;
 	return fd->supported_varaitions;
 }
 }
 
 
-real_t TextServerFallback::font_get_global_oversampling() const {
+float TextServerFallback::font_get_global_oversampling() const {
 	return oversampling;
 	return oversampling;
 }
 }
 
 
-void TextServerFallback::font_set_global_oversampling(real_t p_oversampling) {
+void TextServerFallback::font_set_global_oversampling(float p_oversampling) {
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 	if (oversampling != p_oversampling) {
 	if (oversampling != p_oversampling) {
 		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.
 	// 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))) {
 				} else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) {
 					// Glyph not found, replace with hex code box.
 					// Glyph not found, replace with hex code box.
 					if (sd->orientation == ORIENTATION_HORIZONTAL) {
 					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 {
 					} else {
 						sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
 						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));
 						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.
 		// 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) {
 		for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
 			if ((E.value.pos >= sd->start) && (E.value.pos < sd->end)) {
 			if ((E.value.pos >= sd->start) && (E.value.pos < sd->end)) {
 				if (sd->orientation == ORIENTATION_HORIZONTAL) {
 				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))) {
 					} else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) {
 						// Glyph not found, replace with hex code box.
 						// Glyph not found, replace with hex code box.
 						if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
 						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 {
 						} 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->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));
 							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.
 		// 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) {
 		for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : new_sd->objects) {
 			if ((E.value.pos >= new_sd->start) && (E.value.pos < new_sd->end)) {
 			if ((E.value.pos >= new_sd->start) && (E.value.pos < new_sd->end)) {
 				if (sd->orientation == ORIENTATION_HORIZONTAL) {
 				if (sd->orientation == ORIENTATION_HORIZONTAL) {
@@ -2466,7 +2472,7 @@ RID TextServerFallback::shaped_text_get_parent(RID p_shaped) const {
 	return sd->parent;
 	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);
 	ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 	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)) {
 	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++) {
 		for (int i = start_pos; i <= end_pos; i++) {
 			Glyph &gl = sd->glyphs.write[i];
 			Glyph &gl = sd->glyphs.write[i];
 			if (gl.count > 0) {
 			if (gl.count > 0) {
 				if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
 				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));
 					gl.advance = MAX(gl.advance + delta_width_per_space, Math::round(0.1 * gl.font_size));
 					sd->width += (gl.advance - old_adv);
 					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;
 	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);
 	ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 	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;
 	int tab_index = 0;
-	real_t off = 0.f;
+	float off = 0.f;
 
 
 	int start, end, delta;
 	int start, end, delta;
 	if (sd->para_direction == DIRECTION_LTR) {
 	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) {
 	for (int i = start; i != end; i += delta) {
 		if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
 		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) {
 			while (tab_off <= off) {
 				tab_off += p_tab_stops[tab_index];
 				tab_off += p_tab_stops[tab_index];
 				tab_index++;
 				tab_index++;
@@ -2584,7 +2590,7 @@ real_t TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<real
 					tab_index = 0;
 					tab_index = 0;
 				}
 				}
 			}
 			}
-			real_t old_adv = gl[i].advance;
+			float old_adv = gl[i].advance;
 			gl[i].advance = tab_off - off;
 			gl[i].advance = tab_off - off;
 			sd->width += gl[i].advance - old_adv;
 			sd->width += gl[i].advance - old_adv;
 			off = 0;
 			off = 0;
@@ -2653,7 +2659,7 @@ bool TextServerFallback::shaped_text_update_justification_ops(RID p_shaped) {
 	return true;
 	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);
 	ShapedTextData *sd = shaped_owner.get_or_null(p_shaped_line);
 	ERR_FAIL_COND_MSG(!sd, "ShapedTextDataFallback invalid.");
 	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;
 	int ell_min_characters = 6;
-	real_t width = sd->width;
+	float width = sd->width;
 
 
 	int trim_pos = 0;
 	int trim_pos = 0;
 	int ellipsis_pos = (enforce_ellipsis) ? 0 : -1;
 	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)) {
 		if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) {
 			// Insert an additional space when cutting word bound for aesthetics.
 			// Insert an additional space when cutting word bound for aesthetics.
 			if (cut_per_word && (ellipsis_pos > 0)) {
 			if (cut_per_word && (ellipsis_pos > 0)) {
-				TextServer::Glyph gl;
+				Glyph gl;
 				gl.count = 1;
 				gl.count = 1;
 				gl.advance = whitespace_adv.x;
 				gl.advance = whitespace_adv.x;
 				gl.index = whitespace_gl_idx;
 				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);
 				sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
 			}
 			}
 			// Add ellipsis dots.
 			// Add ellipsis dots.
-			TextServer::Glyph gl;
+			Glyph gl;
 			gl.count = 1;
 			gl.count = 1;
 			gl.repeat = 3;
 			gl.repeat = 3;
 			gl.advance = dot_adv.x;
 			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);
 	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);
 	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) {
 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.
 					// Glyph not found, replace with hex code box.
 					if (sd->orientation == ORIENTATION_HORIZONTAL) {
 					if (sd->orientation == ORIENTATION_HORIZONTAL) {
 						gl.advance = get_hex_code_box_size(gl.font_size, gl.index).x;
 						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 {
 					} else {
 						gl.advance = get_hex_code_box_size(gl.font_size, gl.index).y;
 						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));
 						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.
 	// 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) {
 	for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
 		if (sd->orientation == ORIENTATION_HORIZONTAL) {
 		if (sd->orientation == ORIENTATION_HORIZONTAL) {
 			switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
 			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;
 	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);
 	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);
 	MutexLock lock(sd->mutex);
 	if (!sd->valid) {
 	if (!sd->valid) {
 		const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
 		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);
 	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);
 	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);
 	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);
 	MutexLock lock(sd->mutex);
 	if (!sd->valid) {
 	if (!sd->valid) {
 		const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
 		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 {
 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);
 	const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 	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;
 	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);
 	const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 	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;
 	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);
 	const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 	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;
 	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);
 	const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 	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;
 	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);
 	const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
 	ERR_FAIL_COND_V(!sd, 0.f);
 	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;
 	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(){};
 
 
 TextServerFallback::~TextServerFallback() {
 TextServerFallback::~TextServerFallback() {

+ 46 - 46
modules/text_server_fb/text_server_fb.h

@@ -93,12 +93,12 @@ class TextServerFallback : public TextServer {
 	};
 	};
 
 
 	struct FontDataForSizeFallback {
 	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_glyph = 0;
 		int spacing_space = 0;
 		int spacing_space = 0;
@@ -134,7 +134,7 @@ class TextServerFallback : public TextServer {
 		bool force_autohinter = false;
 		bool force_autohinter = false;
 		TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
 		TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
 		Dictionary variation_coordinates;
 		Dictionary variation_coordinates;
-		real_t oversampling = 0.f;
+		float oversampling = 0.f;
 
 
 		Map<Vector2i, FontDataForSizeFallback *> cache;
 		Map<Vector2i, FontDataForSizeFallback *> cache;
 
 
@@ -194,7 +194,7 @@ class TextServerFallback : public TextServer {
 
 
 	// Common data.
 	// Common data.
 
 
-	real_t oversampling = 1.f;
+	float oversampling = 1.f;
 	mutable RID_PtrOwner<FontDataFallback> font_owner;
 	mutable RID_PtrOwner<FontDataFallback> font_owner;
 	mutable RID_PtrOwner<ShapedTextData> shaped_owner;
 	mutable RID_PtrOwner<ShapedTextData> shaped_owner;
 
 
@@ -205,20 +205,19 @@ protected:
 	void invalidate(ShapedTextData *p_shaped);
 	void invalidate(ShapedTextData *p_shaped);
 
 
 public:
 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 String get_name() const override;
+	virtual uint32_t get_features() const override;
 
 
 	virtual void free(RID p_rid) override;
 	virtual void free(RID p_rid) override;
 	virtual bool has(RID p_rid) override;
 	virtual bool has(RID p_rid) override;
 	virtual bool load_support_data(const String &p_filename) 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 int32_t name_to_tag(const String &p_name) const override;
 	virtual String tag_to_name(int32_t p_tag) 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 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 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 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_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_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 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_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 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 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 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_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_feature_list(RID p_font_rid) const override;
 	virtual Dictionary font_supported_variation_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 */
 	/* 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 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 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 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 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_substr(RID p_shaped, int p_start, int p_length) const override;
 	virtual RID shaped_text_get_parent(RID p_shaped) 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_shape(RID p_shaped) override;
 	virtual bool shaped_text_update_breaks(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 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 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 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 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 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 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();
 	~TextServerFallback();
 	~TextServerFallback();

+ 15 - 5
platform/osx/os_osx.mm

@@ -314,17 +314,27 @@ String OS_OSX::get_name() const {
 	return "macOS";
 	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) {
 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)) {
 	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)) {
 	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);
 	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;
 	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) {
 	switch (p_theme_type) {
 		case STRUCTURED_TEXT_URI: {
 		case STRUCTURED_TEXT_URI: {
 			int prev = 0;
 			int prev = 0;

+ 1 - 1
scene/gui/control.h

@@ -283,7 +283,7 @@ protected:
 
 
 	//virtual void _window_gui_input(InputEvent p_event);
 	//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 _set(const StringName &p_name, const Variant &p_value);
 	bool _get(const StringName &p_name, Variant &r_ret) const;
 	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();
 		lines_rid.clear();
 
 
-		uint8_t autowrap_flags = TextServer::BREAK_MANDATORY;
+		uint16_t autowrap_flags = TextServer::BREAK_MANDATORY;
 		switch (autowrap_mode) {
 		switch (autowrap_mode) {
 			case AUTOWRAP_WORD_SMART:
 			case AUTOWRAP_WORD_SMART:
 				autowrap_flags = TextServer::BREAK_WORD_BOUND_ADAPTIVE | TextServer::BREAK_MANDATORY;
 				autowrap_flags = TextServer::BREAK_WORD_BOUND_ADAPTIVE | TextServer::BREAK_MANDATORY;
@@ -122,10 +122,10 @@ void Label::_shape() {
 			case AUTOWRAP_OFF:
 			case AUTOWRAP_OFF:
 				break;
 				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);
 			lines_rid.push_back(line);
 		}
 		}
 	}
 	}
@@ -145,7 +145,7 @@ void Label::_shape() {
 	}
 	}
 
 
 	if (lines_dirty) {
 	if (lines_dirty) {
-		uint8_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
+		uint16_t overrun_flags = TextServer::OVERRUN_NO_TRIMMING;
 		switch (overrun_behavior) {
 		switch (overrun_behavior) {
 			case OVERRUN_TRIM_WORD_ELLIPSIS:
 			case OVERRUN_TRIM_WORD_ELLIPSIS:
 				overrun_flags |= TextServer::OVERRUN_TRIM;
 				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()) {
 	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);
 		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 {
 	} 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_gl.font_rid != RID()) {
 		if (p_font_shadow_color.a > 0) {
 		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);
 			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;
 				} 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.
 			// 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)) {
 			if (font_shadow_color.a > 0 || (font_outline_color.a != 0.0 && outline_size > 0)) {
 				Vector2 offset = ofs;
 				Vector2 offset = ofs;
 				// Draw RTL ellipsis string when necessary.
 				// 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 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 j = 0; j < gl_size; j++) {
 					for (int k = 0; k < glyphs[j].repeat; k++) {
 					for (int k = 0; k < glyphs[j].repeat; k++) {
 						// Trim when necessary.
 						// Trim when necessary.
-						if (trim_data.trim_pos >= 0) {
+						if (trim_pos >= 0) {
 							if (rtl) {
 							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;
 									continue;
 								}
 								}
 							} else {
 							} 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;
 									break;
 								}
 								}
 							}
 							}
@@ -428,12 +432,12 @@ void Label::_notification(int p_what) {
 					}
 					}
 				}
 				}
 				// Draw LTR ellipsis string when necessary.
 				// 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 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 main text. Note: Do not merge this into the single loop with the outline, to prevent overlaps.
 
 
 			// Draw RTL ellipsis string when necessary.
 			// 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 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 j = 0; j < gl_size; j++) {
 				for (int k = 0; k < glyphs[j].repeat; k++) {
 				for (int k = 0; k < glyphs[j].repeat; k++) {
 					// Trim when necessary.
 					// Trim when necessary.
-					if (trim_data.trim_pos >= 0) {
+					if (trim_pos >= 0) {
 						if (rtl) {
 						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;
 								continue;
 							}
 							}
 						} else {
 						} 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;
 								break;
 							}
 							}
 						}
 						}
@@ -474,12 +478,12 @@ void Label::_notification(int p_what) {
 				}
 				}
 			}
 			}
 			// Draw LTR ellipsis string when necessary.
 			// 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 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) {
 	if (p_move_by_word) {
 		int cc = caret_column;
 		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;
 				break;
 			}
 			}
 		}
 		}
@@ -99,10 +99,10 @@ void LineEdit::_move_caret_right(bool p_select, bool p_move_by_word) {
 	if (p_move_by_word) {
 	if (p_move_by_word) {
 		int cc = caret_column;
 		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;
 				break;
 			}
 			}
 		}
 		}
@@ -151,10 +151,10 @@ void LineEdit::_backspace(bool p_word, bool p_all_to_left) {
 	if (p_word) {
 	if (p_word) {
 		int cc = caret_column;
 		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;
 				break;
 			}
 			}
 		}
 		}
@@ -194,10 +194,10 @@ void LineEdit::_delete(bool p_word, bool p_all_to_right) {
 
 
 	if (p_word) {
 	if (p_word) {
 		int cc = caret_column;
 		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;
 				break;
 			}
 			}
 		}
 		}
@@ -276,12 +276,12 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
 						// Double-click select word.
 						// Double-click select word.
 						last_dblclk = OS::get_singleton()->get_ticks_msec();
 						last_dblclk = OS::get_singleton()->get_ticks_msec();
 						last_dblclk_pos = b->get_position();
 						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.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;
 								selection.double_click = true;
 								caret_column = selection.end;
 								caret_column = selection.end;
 								break;
 								break;
@@ -737,9 +737,8 @@ void LineEdit::_notification(int p_what) {
 					RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, selection_color);
 					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.
 			// Draw text.
 			ofs.y += TS->shaped_text_get_ascent(text_rid);
 			ofs.y += TS->shaped_text_get_ascent(text_rid);
@@ -783,38 +782,36 @@ void LineEdit::_notification(int p_what) {
 			if (draw_caret) {
 			if (draw_caret) {
 				if (ime_text.length() == 0) {
 				if (ime_text.length() == 0) {
 					// Normal caret.
 					// 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.
 						// No carets, add one at the start.
 						int h = get_theme_font(SNAME("font"))->get_height(get_theme_font_size(SNAME("font_size")));
 						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;
 						int y = style->get_offset().y + (y_area - h) / 2;
 						if (rtl) {
 						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 {
 						} 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 {
 					} 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.
 							// 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;
 							trect.position += ofs;
 							RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color);
 							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 {
 				} else {
 					{
 					{
@@ -1114,32 +1111,31 @@ Vector2i LineEdit::get_caret_pixel_pos() {
 	}
 	}
 
 
 	Vector2i ret;
 	Vector2i ret;
-	Rect2 l_caret, t_caret;
-	TextServer::Direction l_dir, t_dir;
+	CaretInfo caret;
 	// Get position of the start of caret.
 	// Get position of the start of caret.
 	if (ime_text.length() != 0 && ime_selection.x != 0) {
 	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 {
 	} 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 {
 	} 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.
 	// Get position of the end of caret.
 	if (ime_text.length() != 0) {
 	if (ime_text.length() != 0) {
 		if (ime_selection.y != 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 {
 		} 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 {
 		} else {
-			ret.y = x_ofs + t_caret.position.x + scroll_offset;
+			ret.y = x_ofs + caret.t_caret.position.x + scroll_offset;
 		}
 		}
 	} else {
 	} else {
 		ret.y = ret.x;
 		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);
 	String post = text.substr(caret_column, text.length() - caret_column);
 	text = pre + p_text + post;
 	text = pre + p_text + post;
 	_shape();
 	_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) {
 	if (dir != TextServer::DIRECTION_AUTO) {
 		input_direction = (TextDirection)dir;
 		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;
 		Vector2 gloff = off;
 		// Draw oulines and shadow.
 		// Draw oulines and shadow.
@@ -1593,18 +1592,18 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
 
 
 				if (c_frame) {
 				if (c_frame) {
 					const Line &l = c_frame->lines[c_line];
 					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_frame = c_frame;
 							selection.from_line = c_line;
 							selection.from_line = c_line;
 							selection.from_item = c_item;
 							selection.from_item = c_item;
-							selection.from_char = words[i].x;
+							selection.from_char = words[i];
 
 
 							selection.to_frame = c_frame;
 							selection.to_frame = c_frame;
 							selection.to_line = c_line;
 							selection.to_line = c_line;
 							selection.to_item = c_item;
 							selection.to_item = c_item;
-							selection.to_char = words[i].y;
+							selection.to_char = words[i + 1];
 
 
 							selection.active = true;
 							selection.active = true;
 							update();
 							update();

+ 82 - 86
scene/gui/text_edit.cpp

@@ -186,7 +186,7 @@ void TextEdit::Text::_calculate_max_line_width() {
 	max_width = 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());
 	ERR_FAIL_INDEX(p_line, text.size());
 
 
 	if (font.is_null() || font_size <= 0) {
 	if (font.is_null() || font_size <= 0) {
@@ -278,14 +278,14 @@ void TextEdit::Text::invalidate_all() {
 
 
 void TextEdit::Text::clear() {
 void TextEdit::Text::clear() {
 	text.clear();
 	text.clear();
-	insert(0, "", Vector<Vector2i>());
+	insert(0, "", Array());
 }
 }
 
 
 int TextEdit::Text::get_max_width() const {
 int TextEdit::Text::get_max_width() const {
 	return max_width;
 	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());
 	ERR_FAIL_INDEX(p_line, text.size());
 
 
 	text.write[p_line].data = p_text;
 	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);
 	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 line;
 	line.gutters.resize(gutter_count);
 	line.gutters.resize(gutter_count);
 	line.hidden = false;
 	line.hidden = false;
@@ -1076,9 +1076,8 @@ void TextEdit::_notification(int p_what) {
 
 
 					ofs_y += (row_height - text_height) / 2;
 					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);
 					ofs_y += ldata->get_line_ascent(line_wrap_index);
 					int char_ofs = 0;
 					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);
 						caret.draw_pos.y = ofs_y + ldata->get_line_descent(line_wrap_index);
 
 
 						if (ime_text.length() == 0) {
 						if (ime_text.length() == 0) {
-							Rect2 l_caret, t_caret;
-							TextServer::Direction l_dir, t_dir;
+							CaretInfo ts_caret;
 							if (str.length() != 0) {
 							if (str.length() != 0) {
 								// Get carets.
 								// 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 {
 							} else {
 								// No carets, add one at the start.
 								// No carets, add one at the start.
 								int h = font->get_height(font_size);
 								int h = font->get_height(font_size);
 								if (rtl) {
 								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 {
 								} 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 {
 							} 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) {
 							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.
 										//Block or underline caret, draw trailing carets at full height.
 										int h = font->get_height(font_size);
 										int h = font->get_height(font_size);
 
 
-										if (t_caret != Rect2()) {
+										if (ts_caret.t_caret != Rect2()) {
 											if (overtype_mode) {
 											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 {
 											} 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.
 										} else { // End of the line.
 											if (gl_size > 0) {
 											if (gl_size > 0) {
 												// Adjust for actual line dimensions.
 												// Adjust for actual line dimensions.
 												if (overtype_mode) {
 												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 {
 												} 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) {
 											} 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 {
 											} 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 {
 									} else {
 										// Normal caret.
 										// 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.
 											// 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);
 											trect.position += Vector2(char_margin + ofs_x, ofs_y);
 											RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color);
 											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_line(caret.line - 1);
 			set_caret_column(text[caret.line].length());
 			set_caret_column(text[caret.line].length());
 		} else {
 		} 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;
 					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_line(caret.line + 1);
 			set_caret_column(0);
 			set_caret_column(0);
 		} else {
 		} 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;
 					break;
 				}
 				}
 			}
 			}
@@ -2214,10 +2212,10 @@ void TextEdit::_do_backspace(bool p_word, bool p_all_to_left) {
 		int line = caret.line;
 		int line = caret.line;
 		int column = caret.column;
 		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;
 				break;
 			}
 			}
 		}
 		}
@@ -2257,10 +2255,10 @@ void TextEdit::_delete(bool p_word, bool p_all_to_right) {
 		int line = caret.line;
 		int line = caret.line;
 		int column = caret.column;
 		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;
 				break;
 			}
 			}
 		}
 		}
@@ -3631,10 +3629,10 @@ int TextEdit::get_caret_wrap_index() const {
 }
 }
 
 
 String TextEdit::get_word_under_caret() 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 "";
 	return "";
@@ -3718,11 +3716,11 @@ void TextEdit::select_word_under_caret() {
 
 
 	int begin = 0;
 	int begin = 0;
 	int end = 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;
 			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);
 	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 {
 	} 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 caret_pos = CLAMP(col, 0, text[line].length());
 	int beg = caret_pos;
 	int beg = caret_pos;
 	int end = beg;
 	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;
 			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_line = p_line + substrings.size() - 1;
 	r_end_column = text[r_end_line].length() - postinsert_text.length();
 	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) {
 	if (dir != TextServer::DIRECTION_AUTO) {
 		input_direction = (TextDirection)dir;
 		input_direction = (TextDirection)dir;
 	}
 	}

+ 4 - 4
scene/gui/text_edit.h

@@ -139,7 +139,7 @@ private:
 			Vector<Gutter> gutters;
 			Vector<Gutter> gutters;
 
 
 			String data;
 			String data;
-			Vector<Vector2i> bidi_override;
+			Array bidi_override;
 			Ref<TextParagraph> data_buf;
 			Ref<TextParagraph> data_buf;
 
 
 			Color background_color = Color(0, 0, 0, 0);
 			Color background_color = Color(0, 0, 0, 0);
@@ -194,7 +194,7 @@ private:
 		Vector<Vector2i> get_line_wrap_ranges(int p_line) const;
 		Vector<Vector2i> get_line_wrap_ranges(int p_line) const;
 		const Ref<TextParagraph> get_line_data(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) {
 		void set_hidden(int p_line, bool p_hidden) {
 			text.write[p_line].hidden = p_hidden;
 			text.write[p_line].hidden = p_hidden;
 			if (!p_hidden && text[p_line].width > max_width) {
 			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; }
 		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);
 		void remove(int p_at);
 		int size() const { return text.size(); }
 		int size() const { return text.size(); }
 		void clear();
 		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();
 		void invalidate_all_lines();
 		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);
 	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_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND(p_font.is_null());
 	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);
 	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_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 	ERR_FAIL_COND(p_font.is_null());
 	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);
 	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_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_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;
 	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));
 	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;
 	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());
 	ERR_FAIL_COND_V(data.is_empty(), Size2());
 
 
 	int size = (p_size <= 0) ? base_size : p_size;
 	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();
 	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());
 	ERR_FAIL_COND_V(data.is_empty(), Size2());
 
 
 	int size = (p_size <= 0) ? base_size : p_size;
 	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;
 	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());
 	ERR_FAIL_COND(data.is_empty());
 
 
 	int size = (p_size <= 0) ? base_size : p_size;
 	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);
 	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());
 	ERR_FAIL_COND(data.is_empty());
 
 
 	int size = (p_size <= 0) ? base_size : p_size;
 	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;
 	virtual real_t get_underline_thickness(int p_size = -1) const;
 
 
 	// Drawing string.
 	// 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.
 	// Helper functions.
 	virtual bool has_char(char32_t p_char) const;
 	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");
 	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_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));
 	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);
 			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) {
 		if (overrun_behavior != OVERRUN_NO_TRIMMING) {
 			switch (overrun_behavior) {
 			switch (overrun_behavior) {
 				case OVERRUN_TRIM_WORD_ELLIPSIS:
 				case OVERRUN_TRIM_WORD_ELLIPSIS:
@@ -195,15 +195,7 @@ TextServer::Orientation TextLine::get_orientation() const {
 	return TS->shaped_text_get_orientation(rid);
 	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);
 	TS->shaped_text_set_bidi_override(rid, p_override);
 	dirty = true;
 	dirty = true;
 }
 }
@@ -256,14 +248,14 @@ void TextLine::tab_align(const Vector<float> &p_tab_stops) {
 	dirty = true;
 	dirty = true;
 }
 }
 
 
-void TextLine::set_flags(uint8_t p_flags) {
+void TextLine::set_flags(uint16_t p_flags) {
 	if (flags != p_flags) {
 	if (flags != p_flags) {
 		flags = p_flags;
 		flags = p_flags;
 		dirty = true;
 		dirty = true;
 	}
 	}
 }
 }
 
 
-uint8_t TextLine::get_flags() const {
+uint16_t TextLine::get_flags() const {
 	return flags;
 	return flags;
 }
 }
 
 

+ 4 - 6
scene/resources/text_line.h

@@ -56,7 +56,7 @@ private:
 	bool dirty = true;
 	bool dirty = true;
 
 
 	float width = -1.0;
 	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;
 	HAlign align = HALIGN_LEFT;
 	OverrunBehavior overrun_behavior = OVERRUN_TRIM_ELLIPSIS;
 	OverrunBehavior overrun_behavior = OVERRUN_TRIM_ELLIPSIS;
 
 
@@ -75,7 +75,7 @@ public:
 	void set_direction(TextServer::Direction p_direction);
 	void set_direction(TextServer::Direction p_direction);
 	TextServer::Direction get_direction() const;
 	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);
 	void set_orientation(TextServer::Orientation p_orientation);
 	TextServer::Orientation get_orientation() const;
 	TextServer::Orientation get_orientation() const;
@@ -95,8 +95,8 @@ public:
 
 
 	void tab_align(const Vector<float> &p_tab_stops);
 	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);
 	void set_text_overrun_behavior(OverrunBehavior p_behavior);
 	OverrunBehavior get_text_overrun_behavior() const;
 	OverrunBehavior get_text_overrun_behavior() const;
@@ -120,8 +120,6 @@ public:
 
 
 	int hit_test(float p_coords) const;
 	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(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();
 	~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");
 	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("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);
 	ClassDB::bind_method(D_METHOD("clear_dropcap"), &TextParagraph::clear_dropcap);
@@ -158,9 +158,9 @@ void TextParagraph::_shape_lines() {
 
 
 		if (h_offset > 0) {
 		if (h_offset > 0) {
 			// Dropcap, flow around.
 			// 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;
 				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) {
 				if (v_offset < h) {
 					TS->free(line);
 					TS->free(line);
@@ -171,21 +171,21 @@ void TextParagraph::_shape_lines() {
 				}
 				}
 				dropcap_lines++;
 				dropcap_lines++;
 				v_offset -= h;
 				v_offset -= h;
-				start = line_breaks[i].y;
+				start = line_breaks[i + 1];
 				lines_rid.push_back(line);
 				lines_rid.push_back(line);
 			}
 			}
 		}
 		}
 		// Use fixed for the rest of lines.
 		// 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()) {
 			if (!tab_stops.is_empty()) {
 				TS->shaped_text_tab_align(line, tab_stops);
 				TS->shaped_text_tab_align(line, tab_stops);
 			}
 			}
 			lines_rid.push_back(line);
 			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) {
 		if (overrun_behavior != OVERRUN_NO_TRIMMING) {
 			switch (overrun_behavior) {
 			switch (overrun_behavior) {
 				case OVERRUN_TRIM_WORD_ELLIPSIS:
 				case OVERRUN_TRIM_WORD_ELLIPSIS:
@@ -347,15 +347,7 @@ int TextParagraph::get_spacing_bottom() const {
 	return spacing_bottom;
 	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);
 	TS->shaped_text_set_bidi_override(rid, p_override);
 	lines_dirty = true;
 	lines_dirty = true;
 }
 }
@@ -392,14 +384,14 @@ void TextParagraph::tab_align(const Vector<float> &p_tab_stops) {
 	lines_dirty = true;
 	lines_dirty = true;
 }
 }
 
 
-void TextParagraph::set_flags(uint8_t p_flags) {
+void TextParagraph::set_flags(uint16_t p_flags) {
 	if (flags != p_flags) {
 	if (flags != p_flags) {
 		flags = p_flags;
 		flags = p_flags;
 		lines_dirty = true;
 		lines_dirty = true;
 	}
 	}
 }
 }
 
 
-uint8_t TextParagraph::get_flags() const {
+uint16_t TextParagraph::get_flags() const {
 	return flags;
 	return flags;
 }
 }
 
 

+ 4 - 6
scene/resources/text_paragraph.h

@@ -63,7 +63,7 @@ private:
 	float width = -1.0;
 	float width = -1.0;
 	int max_lines_visible = -1;
 	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;
 	OverrunBehavior overrun_behavior = OVERRUN_NO_TRIMMING;
 
 
 	HAlign align = HALIGN_LEFT;
 	HAlign align = HALIGN_LEFT;
@@ -94,7 +94,7 @@ public:
 	void set_preserve_control(bool p_enabled);
 	void set_preserve_control(bool p_enabled);
 	bool get_preserve_control() const;
 	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 = "");
 	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();
 	void clear_dropcap();
@@ -108,8 +108,8 @@ public:
 
 
 	void tab_align(const Vector<float> &p_tab_stops);
 	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);
 	void set_text_overrun_behavior(OverrunBehavior p_behavior);
 	OverrunBehavior get_text_overrun_behavior() const;
 	OverrunBehavior get_text_overrun_behavior() const;
@@ -153,8 +153,6 @@ public:
 
 
 	int hit_test(const Point2 &p_coords) const;
 	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(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();
 	~TextParagraph();
 	~TextParagraph();

+ 1 - 0
servers/SCsub

@@ -11,6 +11,7 @@ SConscript("physics_3d/SCsub")
 SConscript("physics_2d/SCsub")
 SConscript("physics_2d/SCsub")
 SConscript("rendering/SCsub")
 SConscript("rendering/SCsub")
 SConscript("audio/SCsub")
 SConscript("audio/SCsub")
+SConscript("text/SCsub")
 
 
 lib = env.add_library("servers", env.servers_sources)
 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/rendering_device_binds.h"
 #include "rendering_server.h"
 #include "rendering_server.h"
 #include "servers/rendering/shader_types.h"
 #include "servers/rendering/shader_types.h"
+#include "text/text_server_extension.h"
 #include "text_server.h"
 #include "text_server.h"
 #include "xr/xr_interface.h"
 #include "xr/xr_interface.h"
 #include "xr/xr_interface_extension.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() {
 void preregister_server_types() {
 	shader_types = memnew(ShaderTypes);
 	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() {
 void register_server_types() {
@@ -125,8 +122,6 @@ void register_server_types() {
 	GDREGISTER_VIRTUAL_CLASS(RenderingServer);
 	GDREGISTER_VIRTUAL_CLASS(RenderingServer);
 	GDREGISTER_CLASS(AudioServer);
 	GDREGISTER_CLASS(AudioServer);
 
 
-	GDREGISTER_CLASS(TextServerManager);
-	GDREGISTER_VIRTUAL_CLASS(TextServer);
 	TextServer::initialize_hex_code_box_fonts();
 	TextServer::initialize_hex_code_box_fonts();
 
 
 	GDREGISTER_VIRTUAL_CLASS(PhysicsServer2D);
 	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("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("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("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("XRServer", XRServer::get_singleton(), "XRServer"));
 	Engine::get_singleton()->add_singleton(Engine::Singleton("CameraServer", CameraServer::get_singleton(), "CameraServer"));
 	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_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_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_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_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_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));
 	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"
 #include "scene/main/canvas_item.h"
 
 
 TextServerManager *TextServerManager::singleton = nullptr;
 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() {
 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);
 	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;
 	Array ret;
 
 
-	for (int i = 0; i < server_create_count; i++) {
+	for (int i = 0; i < interfaces.size(); i++) {
 		Dictionary iface_info;
 		Dictionary iface_info;
 
 
 		iface_info["id"] = i;
 		iface_info["id"] = i;
-		iface_info["name"] = server_create_functions[i].name;
+		iface_info["name"] = interfaces[i]->get_name();
 
 
 		ret.push_back(iface_info);
 		ret.push_back(iface_info);
 	};
 	};
 
 
 	return ret;
 	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() {
 TextServerManager::TextServerManager() {
@@ -155,29 +141,29 @@ TextServerManager::TextServerManager() {
 }
 }
 
 
 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);
 	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);
 	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.start == start) {
 		if (p_a.count == count) {
 		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;
 				return true;
 			} else {
 			} else {
 				return false;
 				return false;
@@ -188,10 +174,10 @@ bool TextServer::Glyph::operator<(const Glyph &p_a) const {
 	return p_a.start < start;
 	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.start == start) {
 		if (p_a.count == count) {
 		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;
 				return false;
 			} else {
 			} else {
 				return true;
 				return true;
@@ -205,8 +191,13 @@ bool TextServer::Glyph::operator>(const Glyph &p_a) const {
 void TextServer::_bind_methods() {
 void TextServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("has_feature", "feature"), &TextServer::has_feature);
 	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_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("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("is_locale_right_to_left", "locale"), &TextServer::is_locale_right_to_left);
 
 
 	ClassDB::bind_method(D_METHOD("name_to_tag", "name"), &TextServer::name_to_tag);
 	ClassDB::bind_method(D_METHOD("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("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_set_antialiased", "font_rid", "antialiased"), &TextServer::font_set_antialiased);
 	ClassDB::bind_method(D_METHOD("font_is_antialiased", "font_rid"), &TextServer::font_is_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_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_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_get_kerning_list", "font_rid", "size"), &TextServer::font_get_kerning_list);
 	ClassDB::bind_method(D_METHOD("font_clear_kerning_map", "font_rid", "size"), &TextServer::font_clear_kerning_map);
 	ClassDB::bind_method(D_METHOD("font_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_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_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_set_orientation", "shaped", "orientation"), &TextServer::shaped_text_set_orientation, DEFVAL(ORIENTATION_HORIZONTAL));
 	ClassDB::bind_method(D_METHOD("shaped_text_get_orientation", "shaped"), &TextServer::shaped_text_get_orientation);
 	ClassDB::bind_method(D_METHOD("shaped_text_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_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_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_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));
 	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_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_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_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);
 	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", "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_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("format_number", "number", "language"), &TextServer::format_number, DEFVAL(""));
 	ClassDB::bind_method(D_METHOD("parse_number", "number", "language"), &TextServer::parse_number, DEFVAL(""));
 	ClassDB::bind_method(D_METHOD("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_WORD_BOUND);
 	BIND_ENUM_CONSTANT(JUSTIFICATION_TRIM_EDGE_SPACES);
 	BIND_ENUM_CONSTANT(JUSTIFICATION_TRIM_EDGE_SPACES);
 	BIND_ENUM_CONSTANT(JUSTIFICATION_AFTER_LAST_TAB);
 	BIND_ENUM_CONSTANT(JUSTIFICATION_AFTER_LAST_TAB);
+	BIND_ENUM_CONSTANT(JUSTIFICATION_CONSTRAIN_ELLIPSIS);
 
 
 	/* LineBreakFlag */
 	/* LineBreakFlag */
 	BIND_ENUM_CONSTANT(BREAK_NONE);
 	BIND_ENUM_CONSTANT(BREAK_NONE);
 	BIND_ENUM_CONSTANT(BREAK_MANDATORY);
 	BIND_ENUM_CONSTANT(BREAK_MANDATORY);
 	BIND_ENUM_CONSTANT(BREAK_WORD_BOUND);
 	BIND_ENUM_CONSTANT(BREAK_WORD_BOUND);
 	BIND_ENUM_CONSTANT(BREAK_GRAPHEME_BOUND);
 	BIND_ENUM_CONSTANT(BREAK_GRAPHEME_BOUND);
+	BIND_ENUM_CONSTANT(BREAK_WORD_BOUND_ADAPTIVE);
 
 
 	/* TextOverrunFlag */
 	/* TextOverrunFlag */
 	BIND_ENUM_CONSTANT(OVERRUN_NO_TRIMMING);
 	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_TRIM_WORD_ONLY);
 	BIND_ENUM_CONSTANT(OVERRUN_ADD_ELLIPSIS);
 	BIND_ENUM_CONSTANT(OVERRUN_ADD_ELLIPSIS);
 	BIND_ENUM_CONSTANT(OVERRUN_ENFORCE_ELLIPSIS);
 	BIND_ENUM_CONSTANT(OVERRUN_ENFORCE_ELLIPSIS);
+	BIND_ENUM_CONSTANT(OVERRUN_JUSTIFICATION_AWARE);
 
 
 	/* GraphemeFlag */
 	/* GraphemeFlag */
+	BIND_ENUM_CONSTANT(GRAPHEME_IS_VALID);
 	BIND_ENUM_CONSTANT(GRAPHEME_IS_RTL);
 	BIND_ENUM_CONSTANT(GRAPHEME_IS_RTL);
 	BIND_ENUM_CONSTANT(GRAPHEME_IS_VIRTUAL);
 	BIND_ENUM_CONSTANT(GRAPHEME_IS_VIRTUAL);
 	BIND_ENUM_CONSTANT(GRAPHEME_IS_SPACE);
 	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;
 	int fnt = (p_size < 20) ? 0 : 1;
 
 
 	ERR_FAIL_COND(hex_code_box_font_tex[fnt].is_null());
 	ERR_FAIL_COND(hex_code_box_font_tex[fnt].is_null());
+	if (p_index == 0) {
+		return;
+	}
 
 
 	uint8_t a = p_index & 0x0F;
 	uint8_t a = p_index & 0x0F;
 	uint8_t b = (p_index >> 4) & 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 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;
 	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(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(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);
 	pos += Point2(2, 2);
 	if (p_index <= 0xFF) {
 	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);
 	ERR_FAIL_COND_V(p_width.is_empty(), lines);
 
 
 	const_cast<TextServer *>(this)->shaped_text_update_breaks(p_shaped);
 	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);
 	const Vector2i &range = shaped_text_get_range(p_shaped);
 
 
 	real_t width = 0.f;
 	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 last_safe_break = -1;
 	int chunk = 0;
 	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++) {
 	for (int i = 0; i < l_size; i++) {
 		if (l_gl[i].start < p_start) {
 		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 (l_gl[i].count > 0) {
 			if ((p_width[chunk] > 0) && (width + l_gl[i].advance > p_width[chunk]) && (last_safe_break >= 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;
 				line_start = l_gl[last_safe_break].end;
 				i = last_safe_break;
 				i = last_safe_break;
 				last_safe_break = -1;
 				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 ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) {
 				if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) {
 				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;
 					line_start = l_gl[i].end;
 					last_safe_break = -1;
 					last_safe_break = -1;
 					width = 0;
 					width = 0;
@@ -693,27 +699,31 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const
 	}
 	}
 
 
 	if (l_size > 0) {
 	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 {
 	} else {
-		lines.push_back(Vector2i(0, 0));
+		lines.push_back(0);
+		lines.push_back(0);
 	}
 	}
 
 
 	return lines;
 	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_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);
 	const Vector2i &range = shaped_text_get_range(p_shaped);
 
 
 	real_t width = 0.f;
 	real_t width = 0.f;
 	int line_start = MAX(p_start, range.x);
 	int line_start = MAX(p_start, range.x);
 	int last_safe_break = -1;
 	int last_safe_break = -1;
 	int word_count = 0;
 	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++) {
 	for (int i = 0; i < l_size; i++) {
 		if (l_gl[i].start < p_start) {
 		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 (l_gl[i].count > 0) {
 			if ((p_width > 0) && (width + l_gl[i].advance * l_gl[i].repeat > p_width) && (last_safe_break >= 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;
 				line_start = l_gl[last_safe_break].end;
 				i = last_safe_break;
 				i = last_safe_break;
 				last_safe_break = -1;
 				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 ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) {
 				if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) {
 				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;
 					line_start = l_gl[i].end;
 					last_safe_break = -1;
 					last_safe_break = -1;
 					width = 0;
 					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 (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 {
 	} else {
-		lines.push_back(Vector2i(0, 0));
+		lines.push_back(0);
+		lines.push_back(0);
 	}
 	}
 
 
 	return lines;
 	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_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);
 	const Vector2i &range = shaped_text_get_range(p_shaped);
 
 
 	int word_start = range.x;
 	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++) {
 	for (int i = 0; i < l_size; i++) {
 		if (l_gl[i].count > 0) {
 		if (l_gl[i].count > 0) {
 			if ((l_gl[i].flags & p_grapheme_flags) != 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;
 				word_start = l_gl[i].end;
 			}
 			}
 		}
 		}
 	}
 	}
 	if (l_size > 0) {
 	if (l_size > 0) {
-		words.push_back(Vector2i(word_start, range.y));
+		words.push_back(word_start);
+		words.push_back(range.y);
 	}
 	}
 
 
 	return words;
 	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;
 	Vector<Rect2> carets;
-	const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
+
 	TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
 	TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
 	const Vector2 &range = shaped_text_get_range(p_shaped);
 	const Vector2 &range = shaped_text_get_range(p_shaped);
 	real_t ascent = shaped_text_get_ascent(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 height = (ascent + descent) / 2;
 
 
 	real_t off = 0.0f;
 	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++) {
 	for (int i = 0; i < v_size; i++) {
 		if (glyphs[i].count > 0) {
 		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.y = -ascent;
 					cr.position.x = off;
 					cr.position.x = off;
 					if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
 					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++) {
 						for (int j = 0; j < glyphs[i].count; j++) {
 							cr.position.x += glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.position.x += glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.size.x -= glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.size.x -= glyphs[i + j].advance * glyphs[i + j].repeat;
 						}
 						}
 					} else {
 					} else {
-						p_trailing_dir = DIRECTION_LTR;
+						caret.t_dir = DIRECTION_LTR;
 						for (int j = 0; j < glyphs[i].count; j++) {
 						for (int j = 0; j < glyphs[i].count; j++) {
 							cr.size.x += glyphs[i + j].advance * glyphs[i + j].repeat;
 							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.x = -ascent;
 					cr.position.y = off;
 					cr.position.y = off;
 					if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
 					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++) {
 						for (int j = 0; j < glyphs[i].count; j++) {
 							cr.position.y += glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.position.y += glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.size.y -= glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.size.y -= glyphs[i + j].advance * glyphs[i + j].repeat;
 						}
 						}
 					} else {
 					} else {
-						p_trailing_dir = DIRECTION_LTR;
+						caret.t_dir = DIRECTION_LTR;
 						for (int j = 0; j < glyphs[i].count; j++) {
 						for (int j = 0; j < glyphs[i].count; j++) {
 							cr.size.y += glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.size.y += glyphs[i + j].advance * glyphs[i + j].repeat;
 						}
 						}
 					}
 					}
 				}
 				}
-				p_trailing_caret = cr;
+				caret.t_caret = cr;
 			}
 			}
 			// Caret after grapheme (bottom / right).
 			// Caret after grapheme (bottom / right).
 			if (p_position == glyphs[i].end && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) {
 			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;
 					cr.position.x = off;
 					if ((glyphs[i].flags & GRAPHEME_IS_RTL) != GRAPHEME_IS_RTL) {
 					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++) {
 						for (int j = 0; j < glyphs[i].count; j++) {
 							cr.position.x += glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.position.x += glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.size.x -= glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.size.x -= glyphs[i + j].advance * glyphs[i + j].repeat;
 						}
 						}
 					} else {
 					} else {
-						p_leading_dir = DIRECTION_RTL;
+						caret.l_dir = DIRECTION_RTL;
 						for (int j = 0; j < glyphs[i].count; j++) {
 						for (int j = 0; j < glyphs[i].count; j++) {
 							cr.size.x += glyphs[i + j].advance * glyphs[i + j].repeat;
 							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;
 					cr.position.y = off;
 					if ((glyphs[i].flags & GRAPHEME_IS_RTL) != GRAPHEME_IS_RTL) {
 					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++) {
 						for (int j = 0; j < glyphs[i].count; j++) {
 							cr.position.y += glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.position.y += glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.size.y -= glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.size.y -= glyphs[i + j].advance * glyphs[i + j].repeat;
 						}
 						}
 					} else {
 					} else {
-						p_leading_dir = DIRECTION_RTL;
+						caret.l_dir = DIRECTION_RTL;
 						for (int j = 0; j < glyphs[i].count; j++) {
 						for (int j = 0; j < glyphs[i].count; j++) {
 							cr.size.y += glyphs[i + j].advance * glyphs[i + j].repeat;
 							cr.size.y += glyphs[i + j].advance * glyphs[i + j].repeat;
 						}
 						}
 					}
 					}
 				}
 				}
-				p_leading_caret = cr;
+				caret.l_caret = cr;
 			}
 			}
 			// Caret inside grapheme (middle).
 			// Caret inside grapheme (middle).
 			if (p_position > glyphs[i].start && p_position < glyphs[i].end && (glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL) {
 			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);
 						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;
 		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) {
 	if (p_start == p_end) {
 		return DIRECTION_AUTO;
 		return DIRECTION_AUTO;
 	}
 	}
@@ -958,8 +981,8 @@ TextServer::Direction TextServer::shaped_text_get_dominant_direciton_in_range(RI
 	int rtl = 0;
 	int rtl = 0;
 	int ltr = 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++) {
 	for (int i = 0; i < v_size; i++) {
 		if ((glyphs[i].end > start) && (glyphs[i].start < end)) {
 		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> TextServer::shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const {
 	Vector<Vector2> ranges;
 	Vector<Vector2> ranges;
-	const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped);
 
 
 	if (p_start == p_end) {
 	if (p_start == p_end) {
 		return ranges;
 		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 start = MIN(p_start, p_end);
 	int end = MAX(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;
 	real_t off = 0.0f;
 	for (int i = 0; i < v_size; i++) {
 	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 {
 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.
 	// Exact grapheme hit test, return -1 if missed.
 	real_t off = 0.0f;
 	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 i = 0; i < v_size; i++) {
 		for (int j = 0; j < glyphs[i].repeat; j++) {
 		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 {
 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.
 	// 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;
 	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++) {
 	for (int i = 0; i < v_size; i++) {
 		if (p_pos >= glyphs[i].start && p_pos < glyphs[i].end) {
 		if (p_pos >= glyphs[i].start && p_pos < glyphs[i].end) {
 			return 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;
 	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++) {
 	for (int i = 0; i < v_size; i++) {
 		if (p_pos > glyphs[i].start && p_pos <= glyphs[i].end) {
 		if (p_pos > glyphs[i].start && p_pos <= glyphs[i].end) {
 			return glyphs[i].start;
 			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 {
 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);
 	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 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;
 	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;
 	Vector2 ofs = p_pos;
 	// Draw RTL ellipsis string when needed.
 	// 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) {
 				if (orientation == ORIENTATION_HORIZONTAL) {
-					ofs.x += trim_data.ellipsis_glyph_buf[i].advance;
+					ofs.x += ellipsis_glyphs[i].advance;
 				} else {
 				} 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 (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;
 						continue;
 					}
 					}
 				} else {
 				} 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;
 						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.
 	// 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) {
 				if (orientation == ORIENTATION_HORIZONTAL) {
-					ofs.x += trim_data.ellipsis_glyph_buf[i].advance;
+					ofs.x += ellipsis_glyphs[i].advance;
 				} else {
 				} 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 {
 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);
 	TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped);
 
 
 	bool rtl = (shaped_text_get_direction(p_shaped) == DIRECTION_RTL);
 	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;
 	Vector2 ofs = p_pos;
 	// Draw RTL ellipsis string when needed.
 	// 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) {
 				if (orientation == ORIENTATION_HORIZONTAL) {
-					ofs.x += trim_data.ellipsis_glyph_buf[i].advance;
+					ofs.x += ellipsis_glyphs[i].advance;
 				} else {
 				} 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 (rtl) {
-					if (i < trim_data.trim_pos) {
+					if (i < trim_pos) {
 						continue;
 						continue;
 					}
 					}
 				} else {
 				} 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;
 						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.
 	// 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) {
 				if (orientation == ORIENTATION_HORIZONTAL) {
-					ofs.x += trim_data.ellipsis_glyph_buf[i].advance;
+					ofs.x += ellipsis_glyphs[i].advance;
 				} else {
 				} 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;
 	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;
 		Dictionary glyph;
 
 
 		glyph["start"] = glyphs[i].start;
 		glyph["start"] = glyphs[i].start;
@@ -1418,60 +1420,51 @@ Array TextServer::_shaped_text_get_glyphs(RID p_shaped) const {
 	return ret;
 	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;
 	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;
 	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;
 	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;
 	return ret;

+ 142 - 152
servers/text_server.h

@@ -34,13 +34,17 @@
 #include "core/object/ref_counted.h"
 #include "core/object/ref_counted.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
 #include "core/templates/rid.h"
 #include "core/templates/rid.h"
+#include "core/variant/native_ptr.h"
 #include "core/variant/variant.h"
 #include "core/variant/variant.h"
 #include "scene/resources/texture.h"
 #include "scene/resources/texture.h"
 
 
 class CanvasTexture;
 class CanvasTexture;
 
 
-class TextServer : public Object {
-	GDCLASS(TextServer, Object);
+struct Glyph;
+struct CaretInfo;
+
+class TextServer : public RefCounted {
+	GDCLASS(TextServer, RefCounted);
 
 
 public:
 public:
 	enum Direction {
 	enum Direction {
@@ -63,12 +67,12 @@ public:
 		JUSTIFICATION_CONSTRAIN_ELLIPSIS = 1 << 4,
 		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_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 {
 	enum TextOverrunFlag {
@@ -124,50 +128,11 @@ public:
 		SPACING_BOTTOM,
 		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 {
 	struct TrimData {
 		int trim_pos = -1;
 		int trim_pos = -1;
 		int ellipsis_pos = -1;
 		int ellipsis_pos = -1;
-		Vector<TextServer::Glyph> ellipsis_glyph_buf;
+		Vector<Glyph> ellipsis_glyph_buf;
 	};
 	};
 
 
 	struct ShapedTextData {
 	struct ShapedTextData {
@@ -215,22 +180,21 @@ public:
 		bool preserve_invalid = true; // Draw hex code box instead of missing characters.
 		bool preserve_invalid = true; // Draw hex code box instead of missing characters.
 		bool preserve_control = false; // Draw control 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;
 		TrimData overrun_trim_data;
 		bool fit_width_minimum_reached = false;
 		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 void _bind_methods();
 
 
 	static Vector3 hex_code_box_font_size[2];
 	static Vector3 hex_code_box_font_size[2];
@@ -240,20 +204,19 @@ public:
 	static void initialize_hex_code_box_fonts();
 	static void initialize_hex_code_box_fonts();
 	static void finish_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 String get_name() const = 0;
+	virtual uint32_t get_features() const = 0;
 
 
 	virtual void free(RID p_rid) = 0;
 	virtual void free(RID p_rid) = 0;
 	virtual bool has(RID p_rid) = 0;
 	virtual bool has(RID p_rid) = 0;
 	virtual bool load_support_data(const String &p_filename) = 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 int32_t name_to_tag(const String &p_name) const { return 0; };
 	virtual String tag_to_name(int32_t p_tag) const { return ""; };
 	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 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 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 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 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 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_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_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 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;
 	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 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 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 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;
 	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_feature_list(RID p_font_rid) const = 0;
 	virtual Dictionary font_supported_variation_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 */
 	/* 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 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 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 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;
 	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_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 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_shape(RID p_shaped) = 0;
 	virtual bool shaped_text_update_breaks(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 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 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 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 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 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 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.
 	// 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.
 	// Number conversion.
 	virtual String format_number(const String &p_string, const String &p_language = "") const { return p_string; };
 	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 parse_number(const String &p_string, const String &p_language = "") const { return p_string; };
 	virtual String percent_sign(const String &p_language = "") const { return "%"; };
 	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 {
 class TextServerManager : public Object {
 	GDCLASS(TextServerManager, Object);
 	GDCLASS(TextServerManager, Object);
 
 
-public:
-	typedef TextServer *(*CreateFunction)(Error &r_error, void *p_user_data);
-
 protected:
 protected:
 	static void _bind_methods();
 	static void _bind_methods();
 
 
 private:
 private:
 	static TextServerManager *singleton;
 	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:
 public:
 	_FORCE_INLINE_ static TextServerManager *get_singleton() {
 	_FORCE_INLINE_ static TextServerManager *get_singleton() {
 		return 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();
 	~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::Direction);
 VARIANT_ENUM_CAST(TextServer::Orientation);
 VARIANT_ENUM_CAST(TextServer::Orientation);
@@ -552,4 +538,8 @@ VARIANT_ENUM_CAST(TextServer::Feature);
 VARIANT_ENUM_CAST(TextServer::ContourPointTag);
 VARIANT_ENUM_CAST(TextServer::ContourPointTag);
 VARIANT_ENUM_CAST(TextServer::SpacingType);
 VARIANT_ENUM_CAST(TextServer::SpacingType);
 
 
+GDVIRTUAL_NATIVE_PTR(Glyph);
+GDVIRTUAL_NATIVE_PTR(Glyph *);
+GDVIRTUAL_NATIVE_PTR(CaretInfo);
+
 #endif // TEXT_SERVER_H
 #endif // TEXT_SERVER_H

+ 1 - 7
tests/test_main.cpp

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

+ 34 - 33
tests/test_text_server.h

@@ -41,19 +41,10 @@ namespace TestTextServer {
 
 
 TEST_SUITE("[[TextServer]") {
 TEST_SUITE("[[TextServer]") {
 	TEST_CASE("[TextServer] Init, font loading and shaping") {
 	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") {
 		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();
 				RID font = ts->create_font();
 				ts->font_set_data_ptr(font, _font_NotoSans_Regular, _font_NotoSans_Regular_size);
 				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") {
 		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();
 				RID font1 = ts->create_font();
 				ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size);
 				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);
 				bool ok = ts->shaped_text_add_string(ctx, test, font, 16);
 				TEST_FAIL_COND(!ok, "Adding text to the buffer failed.");
 				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) {
 					if (glyphs[j].start < 6) {
 						TEST_FAIL_COND(glyphs[j].font_rid != font[1], "Incorrect font selected.");
 						TEST_FAIL_COND(glyphs[j].font_rid != font[1], "Incorrect font selected.");
 					}
 					}
@@ -110,8 +103,9 @@ TEST_SUITE("[[TextServer]") {
 		}
 		}
 
 
 		SUBCASE("[TextServer] Text layout: BiDi") {
 		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)) {
 				if (!ts->has_feature(TextServer::FEATURE_BIDI_LAYOUT)) {
 					continue;
 					continue;
@@ -134,9 +128,10 @@ TEST_SUITE("[[TextServer]") {
 				bool ok = ts->shaped_text_add_string(ctx, test, font, 16);
 				bool ok = ts->shaped_text_add_string(ctx, test, font, 16);
 				TEST_FAIL_COND(!ok, "Adding text to the buffer failed.");
 				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].count > 0) {
 						if (glyphs[j].start < 7) {
 						if (glyphs[j].start < 7) {
 							TEST_FAIL_COND(((glyphs[j].flags & TextServer::GRAPHEME_IS_RTL) == TextServer::GRAPHEME_IS_RTL), "Incorrect direction.");
 							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") {
 		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";
 				String test_1 = U"test test test";
 				//                   5^  10^
 				//                   5^  10^
@@ -180,12 +176,17 @@ TEST_SUITE("[[TextServer]") {
 				bool ok = ts->shaped_text_add_string(ctx, test_1, font, 16);
 				bool ok = ts->shaped_text_add_string(ctx, test_1, font, 16);
 				TEST_FAIL_COND(!ok, "Adding text to the buffer failed.");
 				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);
 				ts->free(ctx);
@@ -198,8 +199,9 @@ TEST_SUITE("[[TextServer]") {
 		}
 		}
 
 
 		SUBCASE("[TextServer] Text layout: Justification") {
 		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();
 				RID font1 = ts->create_font();
 				ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size);
 				ts->font_set_data_ptr(font1, _font_NotoSans_Regular, _font_NotoSans_Regular_size);
@@ -263,7 +265,6 @@ TEST_SUITE("[[TextServer]") {
 				font.clear();
 				font.clear();
 			}
 			}
 		}
 		}
-		memdelete(tsman);
 	}
 	}
 }
 }
 }; // namespace TestTextServer
 }; // namespace TestTextServer